diff options
author | Jari Vetoniemi <jari.vetoniemi@indooratlas.com> | 2020-03-16 18:49:26 +0900 |
---|---|---|
committer | Jari Vetoniemi <jari.vetoniemi@indooratlas.com> | 2020-03-30 00:39:06 +0900 |
commit | fcbf63e62c627deae76c1b8cb8c0876c536ed811 (patch) | |
tree | 64cb17de3f41a2b6fef2368028fbd00349946994 /jni/ruby/test/rdoc |
Fresh start
Diffstat (limited to 'jni/ruby/test/rdoc')
111 files changed, 32382 insertions, 0 deletions
diff --git a/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Amps and angle encoding.text b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Amps and angle encoding.text new file mode 100644 index 0000000..0e9527f --- /dev/null +++ b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Amps and angle encoding.text @@ -0,0 +1,21 @@ +AT&T has an ampersand in their name. + +AT&T is another way to write it. + +This & that. + +4 < 5. + +6 > 5. + +Here's a [link] [1] with an ampersand in the URL. + +Here's a link with an amersand in the link text: [AT&T] [2]. + +Here's an inline [link](/script?foo=1&bar=2). + +Here's an inline [link](</script?foo=1&bar=2>). + + +[1]: http://example.com/?foo=1&bar=2 +[2]: http://att.com/ "AT&T"
\ No newline at end of file diff --git a/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Auto links.text b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Auto links.text new file mode 100644 index 0000000..abbc488 --- /dev/null +++ b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Auto links.text @@ -0,0 +1,13 @@ +Link: <http://example.com/>. + +With an ampersand: <http://example.com/?foo=1&bar=2> + +* In a list? +* <http://example.com/> +* It should. + +> Blockquoted: <http://example.com/> + +Auto-links should not occur here: `<http://example.com/>` + + or here: <http://example.com/>
\ No newline at end of file diff --git a/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Backslash escapes.text b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Backslash escapes.text new file mode 100644 index 0000000..5b014cb --- /dev/null +++ b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Backslash escapes.text @@ -0,0 +1,120 @@ +These should all get escaped: + +Backslash: \\ + +Backtick: \` + +Asterisk: \* + +Underscore: \_ + +Left brace: \{ + +Right brace: \} + +Left bracket: \[ + +Right bracket: \] + +Left paren: \( + +Right paren: \) + +Greater-than: \> + +Hash: \# + +Period: \. + +Bang: \! + +Plus: \+ + +Minus: \- + + + +These should not, because they occur within a code block: + + Backslash: \\ + + Backtick: \` + + Asterisk: \* + + Underscore: \_ + + Left brace: \{ + + Right brace: \} + + Left bracket: \[ + + Right bracket: \] + + Left paren: \( + + Right paren: \) + + Greater-than: \> + + Hash: \# + + Period: \. + + Bang: \! + + Plus: \+ + + Minus: \- + + +Nor should these, which occur in code spans: + +Backslash: `\\` + +Backtick: `` \` `` + +Asterisk: `\*` + +Underscore: `\_` + +Left brace: `\{` + +Right brace: `\}` + +Left bracket: `\[` + +Right bracket: `\]` + +Left paren: `\(` + +Right paren: `\)` + +Greater-than: `\>` + +Hash: `\#` + +Period: `\.` + +Bang: `\!` + +Plus: `\+` + +Minus: `\-` + + +These should get escaped, even though they're matching pairs for +other Markdown constructs: + +\*asterisks\* + +\_underscores\_ + +\`backticks\` + +This is a code span with a literal backslash-backtick sequence: `` \` `` + +This is a tag with unescaped backticks <span attr='`ticks`'>bar</span>. + +This is a tag with backslashes <span attr='\\backslashes\\'>bar</span>. diff --git a/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Blockquotes with code blocks.text b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Blockquotes with code blocks.text new file mode 100644 index 0000000..c31d171 --- /dev/null +++ b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Blockquotes with code blocks.text @@ -0,0 +1,11 @@ +> Example: +> +> sub status { +> print "working"; +> } +> +> Or: +> +> sub status { +> return "working"; +> } diff --git a/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Code Blocks.text b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Code Blocks.text new file mode 100644 index 0000000..b54b092 --- /dev/null +++ b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Code Blocks.text @@ -0,0 +1,14 @@ + code block on the first line + +Regular text. + + code block indented by spaces + +Regular text. + + the lines in this block + all contain trailing spaces + +Regular Text. + + code block on the last line
\ No newline at end of file diff --git a/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Code Spans.text b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Code Spans.text new file mode 100644 index 0000000..750a197 --- /dev/null +++ b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Code Spans.text @@ -0,0 +1,6 @@ +`<test a="` content of attribute `">` + +Fix for backticks within HTML tag: <span attr='`ticks`'>like this</span> + +Here's how you put `` `backticks` `` in a code span. + diff --git a/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Hard-wrapped paragraphs with list-like lines.text b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Hard-wrapped paragraphs with list-like lines.text new file mode 100644 index 0000000..f8a5b27 --- /dev/null +++ b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Hard-wrapped paragraphs with list-like lines.text @@ -0,0 +1,8 @@ +In Markdown 1.0.0 and earlier. Version +8. This line turns into a list item. +Because a hard-wrapped line in the +middle of a paragraph looked like a +list item. + +Here's one with a bullet. +* criminey. diff --git a/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Horizontal rules.text b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Horizontal rules.text new file mode 100644 index 0000000..1594bda --- /dev/null +++ b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Horizontal rules.text @@ -0,0 +1,67 @@ +Dashes: + +--- + + --- + + --- + + --- + + --- + +- - - + + - - - + + - - - + + - - - + + - - - + + +Asterisks: + +*** + + *** + + *** + + *** + + *** + +* * * + + * * * + + * * * + + * * * + + * * * + + +Underscores: + +___ + + ___ + + ___ + + ___ + + ___ + +_ _ _ + + _ _ _ + + _ _ _ + + _ _ _ + + _ _ _ diff --git a/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Inline HTML (Advanced).text b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Inline HTML (Advanced).text new file mode 100644 index 0000000..86b7206 --- /dev/null +++ b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Inline HTML (Advanced).text @@ -0,0 +1,15 @@ +Simple block on one line: + +<div>foo</div> + +And nested without indentation: + +<div> +<div> +<div> +foo +</div> +<div style=">"/> +</div> +<div>bar</div> +</div> diff --git a/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Inline HTML (Simple).text b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Inline HTML (Simple).text new file mode 100644 index 0000000..14aa2dc --- /dev/null +++ b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Inline HTML (Simple).text @@ -0,0 +1,69 @@ +Here's a simple block: + +<div> + foo +</div> + +This should be a code block, though: + + <div> + foo + </div> + +As should this: + + <div>foo</div> + +Now, nested: + +<div> + <div> + <div> + foo + </div> + </div> +</div> + +This should just be an HTML comment: + +<!-- Comment --> + +Multiline: + +<!-- +Blah +Blah +--> + +Code block: + + <!-- Comment --> + +Just plain comment, with trailing spaces on the line: + +<!-- foo --> + +Code: + + <hr /> + +Hr's: + +<hr> + +<hr/> + +<hr /> + +<hr> + +<hr/> + +<hr /> + +<hr class="foo" id="bar" /> + +<hr class="foo" id="bar"/> + +<hr class="foo" id="bar" > + diff --git a/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Inline HTML comments.text b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Inline HTML comments.text new file mode 100644 index 0000000..41d830d --- /dev/null +++ b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Inline HTML comments.text @@ -0,0 +1,13 @@ +Paragraph one. + +<!-- This is a simple comment --> + +<!-- + This is another comment. +--> + +Paragraph two. + +<!-- one comment block -- -- with two comments --> + +The end. diff --git a/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Links, inline style.text b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Links, inline style.text new file mode 100644 index 0000000..09017a9 --- /dev/null +++ b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Links, inline style.text @@ -0,0 +1,12 @@ +Just a [URL](/url/). + +[URL and title](/url/ "title"). + +[URL and title](/url/ "title preceded by two spaces"). + +[URL and title](/url/ "title preceded by a tab"). + +[URL and title](/url/ "title has spaces afterward" ). + + +[Empty](). diff --git a/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Links, reference style.text b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Links, reference style.text new file mode 100644 index 0000000..341ec88 --- /dev/null +++ b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Links, reference style.text @@ -0,0 +1,71 @@ +Foo [bar] [1]. + +Foo [bar][1]. + +Foo [bar] +[1]. + +[1]: /url/ "Title" + + +With [embedded [brackets]] [b]. + + +Indented [once][]. + +Indented [twice][]. + +Indented [thrice][]. + +Indented [four][] times. + + [once]: /url + + [twice]: /url + + [thrice]: /url + + [four]: /url + + +[b]: /url/ + +* * * + +[this] [this] should work + +So should [this][this]. + +And [this] []. + +And [this][]. + +And [this]. + +But not [that] []. + +Nor [that][]. + +Nor [that]. + +[Something in brackets like [this][] should work] + +[Same with [this].] + +In this case, [this](/somethingelse/) points to something else. + +Backslashing should suppress \[this] and [this\]. + +[this]: foo + + +* * * + +Here's one where the [link +breaks] across lines. + +Here's another where the [link +breaks] across lines, but with a line-ending space. + + +[link breaks]: /url/ diff --git a/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Links, shortcut references.text b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Links, shortcut references.text new file mode 100644 index 0000000..8c44c98 --- /dev/null +++ b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Links, shortcut references.text @@ -0,0 +1,20 @@ +This is the [simple case]. + +[simple case]: /simple + + + +This one has a [line +break]. + +This one has a [line +break] with a line-ending space. + +[line break]: /foo + + +[this] [that] and the [other] + +[this]: /this +[that]: /that +[other]: /other diff --git a/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Literal quotes in titles.text b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Literal quotes in titles.text new file mode 100644 index 0000000..29d0e42 --- /dev/null +++ b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Literal quotes in titles.text @@ -0,0 +1,7 @@ +Foo [bar][]. + +Foo [bar](/url/ "Title with "quotes" inside"). + + + [bar]: /url/ "Title with "quotes" inside" + diff --git a/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Markdown Documentation - Basics.text b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Markdown Documentation - Basics.text new file mode 100644 index 0000000..486055c --- /dev/null +++ b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Markdown Documentation - Basics.text @@ -0,0 +1,306 @@ +Markdown: Basics +================ + +<ul id="ProjectSubmenu"> + <li><a href="/projects/markdown/" title="Markdown Project Page">Main</a></li> + <li><a class="selected" title="Markdown Basics">Basics</a></li> + <li><a href="/projects/markdown/syntax" title="Markdown Syntax Documentation">Syntax</a></li> + <li><a href="/projects/markdown/license" title="Pricing and License Information">License</a></li> + <li><a href="/projects/markdown/dingus" title="Online Markdown Web Form">Dingus</a></li> +</ul> + + +Getting the Gist of Markdown's Formatting Syntax +------------------------------------------------ + +This page offers a brief overview of what it's like to use Markdown. +The [syntax page] [s] provides complete, detailed documentation for +every feature, but Markdown should be very easy to pick up simply by +looking at a few examples of it in action. The examples on this page +are written in a before/after style, showing example syntax and the +HTML output produced by Markdown. + +It's also helpful to simply try Markdown out; the [Dingus] [d] is a +web application that allows you type your own Markdown-formatted text +and translate it to XHTML. + +**Note:** This document is itself written using Markdown; you +can [see the source for it by adding '.text' to the URL] [src]. + + [s]: /projects/markdown/syntax "Markdown Syntax" + [d]: /projects/markdown/dingus "Markdown Dingus" + [src]: /projects/markdown/basics.text + + +## Paragraphs, Headers, Blockquotes ## + +A paragraph is simply one or more consecutive lines of text, separated +by one or more blank lines. (A blank line is any line that looks like a +blank line -- a line containing nothing spaces or tabs is considered +blank.) Normal paragraphs should not be intended with spaces or tabs. + +Markdown offers two styles of headers: *Setext* and *atx*. +Setext-style headers for `<h1>` and `<h2>` are created by +"underlining" with equal signs (`=`) and hyphens (`-`), respectively. +To create an atx-style header, you put 1-6 hash marks (`#`) at the +beginning of the line -- the number of hashes equals the resulting +HTML header level. + +Blockquotes are indicated using email-style '`>`' angle brackets. + +Markdown: + + A First Level Header + ==================== + + A Second Level Header + --------------------- + + Now is the time for all good men to come to + the aid of their country. This is just a + regular paragraph. + + The quick brown fox jumped over the lazy + dog's back. + + ### Header 3 + + > This is a blockquote. + > + > This is the second paragraph in the blockquote. + > + > ## This is an H2 in a blockquote + + +Output: + + <h1>A First Level Header</h1> + + <h2>A Second Level Header</h2> + + <p>Now is the time for all good men to come to + the aid of their country. This is just a + regular paragraph.</p> + + <p>The quick brown fox jumped over the lazy + dog's back.</p> + + <h3>Header 3</h3> + + <blockquote> + <p>This is a blockquote.</p> + + <p>This is the second paragraph in the blockquote.</p> + + <h2>This is an H2 in a blockquote</h2> + </blockquote> + + + +### Phrase Emphasis ### + +Markdown uses asterisks and underscores to indicate spans of emphasis. + +Markdown: + + Some of these words *are emphasized*. + Some of these words _are emphasized also_. + + Use two asterisks for **strong emphasis**. + Or, if you prefer, __use two underscores instead__. + +Output: + + <p>Some of these words <em>are emphasized</em>. + Some of these words <em>are emphasized also</em>.</p> + + <p>Use two asterisks for <strong>strong emphasis</strong>. + Or, if you prefer, <strong>use two underscores instead</strong>.</p> + + + +## Lists ## + +Unordered (bulleted) lists use asterisks, pluses, and hyphens (`*`, +`+`, and `-`) as list markers. These three markers are +interchangable; this: + + * Candy. + * Gum. + * Booze. + +this: + + + Candy. + + Gum. + + Booze. + +and this: + + - Candy. + - Gum. + - Booze. + +all produce the same output: + + <ul> + <li>Candy.</li> + <li>Gum.</li> + <li>Booze.</li> + </ul> + +Ordered (numbered) lists use regular numbers, followed by periods, as +list markers: + + 1. Red + 2. Green + 3. Blue + +Output: + + <ol> + <li>Red</li> + <li>Green</li> + <li>Blue</li> + </ol> + +If you put blank lines between items, you'll get `<p>` tags for the +list item text. You can create multi-paragraph list items by indenting +the paragraphs by 4 spaces or 1 tab: + + * A list item. + + With multiple paragraphs. + + * Another item in the list. + +Output: + + <ul> + <li><p>A list item.</p> + <p>With multiple paragraphs.</p></li> + <li><p>Another item in the list.</p></li> + </ul> + + + +### Links ### + +Markdown supports two styles for creating links: *inline* and +*reference*. With both styles, you use square brackets to delimit the +text you want to turn into a link. + +Inline-style links use parentheses immediately after the link text. +For example: + + This is an [example link](http://example.com/). + +Output: + + <p>This is an <a href="http://example.com/"> + example link</a>.</p> + +Optionally, you may include a title attribute in the parentheses: + + This is an [example link](http://example.com/ "With a Title"). + +Output: + + <p>This is an <a href="http://example.com/" title="With a Title"> + example link</a>.</p> + +Reference-style links allow you to refer to your links by names, which +you define elsewhere in your document: + + I get 10 times more traffic from [Google][1] than from + [Yahoo][2] or [MSN][3]. + + [1]: http://google.com/ "Google" + [2]: http://search.yahoo.com/ "Yahoo Search" + [3]: http://search.msn.com/ "MSN Search" + +Output: + + <p>I get 10 times more traffic from <a href="http://google.com/" + title="Google">Google</a> than from <a href="http://search.yahoo.com/" + title="Yahoo Search">Yahoo</a> or <a href="http://search.msn.com/" + title="MSN Search">MSN</a>.</p> + +The title attribute is optional. Link names may contain letters, +numbers and spaces, but are *not* case sensitive: + + I start my morning with a cup of coffee and + [The New York Times][NY Times]. + + [ny times]: http://www.nytimes.com/ + +Output: + + <p>I start my morning with a cup of coffee and + <a href="http://www.nytimes.com/">The New York Times</a>.</p> + + +### Images ### + +Image syntax is very much like link syntax. + +Inline (titles are optional): + + ![alt text](/path/to/img.jpg "Title") + +Reference-style: + + ![alt text][id] + + [id]: /path/to/img.jpg "Title" + +Both of the above examples produce the same output: + + <img src="/path/to/img.jpg" alt="alt text" title="Title" /> + + + +### Code ### + +In a regular paragraph, you can create code span by wrapping text in +backtick quotes. Any ampersands (`&`) and angle brackets (`<` or +`>`) will automatically be translated into HTML entities. This makes +it easy to use Markdown to write about HTML example code: + + I strongly recommend against using any `<blink>` tags. + + I wish SmartyPants used named entities like `—` + instead of decimal-encoded entites like `—`. + +Output: + + <p>I strongly recommend against using any + <code><blink></code> tags.</p> + + <p>I wish SmartyPants used named entities like + <code>&mdash;</code> instead of decimal-encoded + entites like <code>&#8212;</code>.</p> + + +To specify an entire block of pre-formatted code, indent every line of +the block by 4 spaces or 1 tab. Just like with code spans, `&`, `<`, +and `>` characters will be escaped automatically. + +Markdown: + + If you want your page to validate under XHTML 1.0 Strict, + you've got to put paragraph tags in your blockquotes: + + <blockquote> + <p>For example.</p> + </blockquote> + +Output: + + <p>If you want your page to validate under XHTML 1.0 Strict, + you've got to put paragraph tags in your blockquotes:</p> + + <pre><code><blockquote> + <p>For example.</p> + </blockquote> + </code></pre> diff --git a/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Markdown Documentation - Syntax.text b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Markdown Documentation - Syntax.text new file mode 100644 index 0000000..57360a1 --- /dev/null +++ b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Markdown Documentation - Syntax.text @@ -0,0 +1,888 @@ +Markdown: Syntax +================ + +<ul id="ProjectSubmenu"> + <li><a href="/projects/markdown/" title="Markdown Project Page">Main</a></li> + <li><a href="/projects/markdown/basics" title="Markdown Basics">Basics</a></li> + <li><a class="selected" title="Markdown Syntax Documentation">Syntax</a></li> + <li><a href="/projects/markdown/license" title="Pricing and License Information">License</a></li> + <li><a href="/projects/markdown/dingus" title="Online Markdown Web Form">Dingus</a></li> +</ul> + + +* [Overview](#overview) + * [Philosophy](#philosophy) + * [Inline HTML](#html) + * [Automatic Escaping for Special Characters](#autoescape) +* [Block Elements](#block) + * [Paragraphs and Line Breaks](#p) + * [Headers](#header) + * [Blockquotes](#blockquote) + * [Lists](#list) + * [Code Blocks](#precode) + * [Horizontal Rules](#hr) +* [Span Elements](#span) + * [Links](#link) + * [Emphasis](#em) + * [Code](#code) + * [Images](#img) +* [Miscellaneous](#misc) + * [Backslash Escapes](#backslash) + * [Automatic Links](#autolink) + + +**Note:** This document is itself written using Markdown; you +can [see the source for it by adding '.text' to the URL][src]. + + [src]: /projects/markdown/syntax.text + +* * * + +<h2 id="overview">Overview</h2> + +<h3 id="philosophy">Philosophy</h3> + +Markdown is intended to be as easy-to-read and easy-to-write as is feasible. + +Readability, however, is emphasized above all else. A Markdown-formatted +document should be publishable as-is, as plain text, without looking +like it's been marked up with tags or formatting instructions. While +Markdown's syntax has been influenced by several existing text-to-HTML +filters -- including [Setext] [1], [atx] [2], [Textile] [3], [reStructuredText] [4], +[Grutatext] [5], and [EtText] [6] -- the single biggest source of +inspiration for Markdown's syntax is the format of plain text email. + + [1]: http://docutils.sourceforge.net/mirror/setext.html + [2]: http://www.aaronsw.com/2002/atx/ + [3]: http://textism.com/tools/textile/ + [4]: http://docutils.sourceforge.net/rst.html + [5]: http://www.triptico.com/software/grutatxt.html + [6]: http://ettext.taint.org/doc/ + +To this end, Markdown's syntax is comprised entirely of punctuation +characters, which punctuation characters have been carefully chosen so +as to look like what they mean. E.g., asterisks around a word actually +look like \*emphasis\*. Markdown lists look like, well, lists. Even +blockquotes look like quoted passages of text, assuming you've ever +used email. + + + +<h3 id="html">Inline HTML</h3> + +Markdown's syntax is intended for one purpose: to be used as a +format for *writing* for the web. + +Markdown is not a replacement for HTML, or even close to it. Its +syntax is very small, corresponding only to a very small subset of +HTML tags. The idea is *not* to create a syntax that makes it easier +to insert HTML tags. In my opinion, HTML tags are already easy to +insert. The idea for Markdown is to make it easy to read, write, and +edit prose. HTML is a *publishing* format; Markdown is a *writing* +format. Thus, Markdown's formatting syntax only addresses issues that +can be conveyed in plain text. + +For any markup that is not covered by Markdown's syntax, you simply +use HTML itself. There's no need to preface it or delimit it to +indicate that you're switching from Markdown to HTML; you just use +the tags. + +The only restrictions are that block-level HTML elements -- e.g. `<div>`, +`<table>`, `<pre>`, `<p>`, etc. -- must be separated from surrounding +content by blank lines, and the start and end tags of the block should +not be indented with tabs or spaces. Markdown is smart enough not +to add extra (unwanted) `<p>` tags around HTML block-level tags. + +For example, to add an HTML table to a Markdown article: + + This is a regular paragraph. + + <table> + <tr> + <td>Foo</td> + </tr> + </table> + + This is another regular paragraph. + +Note that Markdown formatting syntax is not processed within block-level +HTML tags. E.g., you can't use Markdown-style `*emphasis*` inside an +HTML block. + +Span-level HTML tags -- e.g. `<span>`, `<cite>`, or `<del>` -- can be +used anywhere in a Markdown paragraph, list item, or header. If you +want, you can even use HTML tags instead of Markdown formatting; e.g. if +you'd prefer to use HTML `<a>` or `<img>` tags instead of Markdown's +link or image syntax, go right ahead. + +Unlike block-level HTML tags, Markdown syntax *is* processed within +span-level tags. + + +<h3 id="autoescape">Automatic Escaping for Special Characters</h3> + +In HTML, there are two characters that demand special treatment: `<` +and `&`. Left angle brackets are used to start tags; ampersands are +used to denote HTML entities. If you want to use them as literal +characters, you must escape them as entities, e.g. `<`, and +`&`. + +Ampersands in particular are bedeviling for web writers. If you want to +write about 'AT&T', you need to write '`AT&T`'. You even need to +escape ampersands within URLs. Thus, if you want to link to: + + http://images.google.com/images?num=30&q=larry+bird + +you need to encode the URL as: + + http://images.google.com/images?num=30&q=larry+bird + +in your anchor tag `href` attribute. Needless to say, this is easy to +forget, and is probably the single most common source of HTML validation +errors in otherwise well-marked-up web sites. + +Markdown allows you to use these characters naturally, taking care of +all the necessary escaping for you. If you use an ampersand as part of +an HTML entity, it remains unchanged; otherwise it will be translated +into `&`. + +So, if you want to include a copyright symbol in your article, you can write: + + © + +and Markdown will leave it alone. But if you write: + + AT&T + +Markdown will translate it to: + + AT&T + +Similarly, because Markdown supports [inline HTML](#html), if you use +angle brackets as delimiters for HTML tags, Markdown will treat them as +such. But if you write: + + 4 < 5 + +Markdown will translate it to: + + 4 < 5 + +However, inside Markdown code spans and blocks, angle brackets and +ampersands are *always* encoded automatically. This makes it easy to use +Markdown to write about HTML code. (As opposed to raw HTML, which is a +terrible format for writing about HTML syntax, because every single `<` +and `&` in your example code needs to be escaped.) + + +* * * + + +<h2 id="block">Block Elements</h2> + + +<h3 id="p">Paragraphs and Line Breaks</h3> + +A paragraph is simply one or more consecutive lines of text, separated +by one or more blank lines. (A blank line is any line that looks like a +blank line -- a line containing nothing but spaces or tabs is considered +blank.) Normal paragraphs should not be intended with spaces or tabs. + +The implication of the "one or more consecutive lines of text" rule is +that Markdown supports "hard-wrapped" text paragraphs. This differs +significantly from most other text-to-HTML formatters (including Movable +Type's "Convert Line Breaks" option) which translate every line break +character in a paragraph into a `<br />` tag. + +When you *do* want to insert a `<br />` break tag using Markdown, you +end a line with two or more spaces, then type return. + +Yes, this takes a tad more effort to create a `<br />`, but a simplistic +"every line break is a `<br />`" rule wouldn't work for Markdown. +Markdown's email-style [blockquoting][bq] and multi-paragraph [list items][l] +work best -- and look better -- when you format them with hard breaks. + + [bq]: #blockquote + [l]: #list + + + +<h3 id="header">Headers</h3> + +Markdown supports two styles of headers, [Setext] [1] and [atx] [2]. + +Setext-style headers are "underlined" using equal signs (for first-level +headers) and dashes (for second-level headers). For example: + + This is an H1 + ============= + + This is an H2 + ------------- + +Any number of underlining `=`'s or `-`'s will work. + +Atx-style headers use 1-6 hash characters at the start of the line, +corresponding to header levels 1-6. For example: + + # This is an H1 + + ## This is an H2 + + ###### This is an H6 + +Optionally, you may "close" atx-style headers. This is purely +cosmetic -- you can use this if you think it looks better. The +closing hashes don't even need to match the number of hashes +used to open the header. (The number of opening hashes +determines the header level.) : + + # This is an H1 # + + ## This is an H2 ## + + ### This is an H3 ###### + + +<h3 id="blockquote">Blockquotes</h3> + +Markdown uses email-style `>` characters for blockquoting. If you're +familiar with quoting passages of text in an email message, then you +know how to create a blockquote in Markdown. It looks best if you hard +wrap the text and put a `>` before every line: + + > This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet, + > consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus. + > Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus. + > + > Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse + > id sem consectetuer libero luctus adipiscing. + +Markdown allows you to be lazy and only put the `>` before the first +line of a hard-wrapped paragraph: + + > This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet, + consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus. + Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus. + + > Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse + id sem consectetuer libero luctus adipiscing. + +Blockquotes can be nested (i.e. a blockquote-in-a-blockquote) by +adding additional levels of `>`: + + > This is the first level of quoting. + > + > > This is nested blockquote. + > + > Back to the first level. + +Blockquotes can contain other Markdown elements, including headers, lists, +and code blocks: + + > ## This is a header. + > + > 1. This is the first list item. + > 2. This is the second list item. + > + > Here's some example code: + > + > return shell_exec("echo $input | $markdown_script"); + +Any decent text editor should make email-style quoting easy. For +example, with BBEdit, you can make a selection and choose Increase +Quote Level from the Text menu. + + +<h3 id="list">Lists</h3> + +Markdown supports ordered (numbered) and unordered (bulleted) lists. + +Unordered lists use asterisks, pluses, and hyphens -- interchangably +-- as list markers: + + * Red + * Green + * Blue + +is equivalent to: + + + Red + + Green + + Blue + +and: + + - Red + - Green + - Blue + +Ordered lists use numbers followed by periods: + + 1. Bird + 2. McHale + 3. Parish + +It's important to note that the actual numbers you use to mark the +list have no effect on the HTML output Markdown produces. The HTML +Markdown produces from the above list is: + + <ol> + <li>Bird</li> + <li>McHale</li> + <li>Parish</li> + </ol> + +If you instead wrote the list in Markdown like this: + + 1. Bird + 1. McHale + 1. Parish + +or even: + + 3. Bird + 1. McHale + 8. Parish + +you'd get the exact same HTML output. The point is, if you want to, +you can use ordinal numbers in your ordered Markdown lists, so that +the numbers in your source match the numbers in your published HTML. +But if you want to be lazy, you don't have to. + +If you do use lazy list numbering, however, you should still start the +list with the number 1. At some point in the future, Markdown may support +starting ordered lists at an arbitrary number. + +List markers typically start at the left margin, but may be indented by +up to three spaces. List markers must be followed by one or more spaces +or a tab. + +To make lists look nice, you can wrap items with hanging indents: + + * Lorem ipsum dolor sit amet, consectetuer adipiscing elit. + Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi, + viverra nec, fringilla in, laoreet vitae, risus. + * Donec sit amet nisl. Aliquam semper ipsum sit amet velit. + Suspendisse id sem consectetuer libero luctus adipiscing. + +But if you want to be lazy, you don't have to: + + * Lorem ipsum dolor sit amet, consectetuer adipiscing elit. + Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi, + viverra nec, fringilla in, laoreet vitae, risus. + * Donec sit amet nisl. Aliquam semper ipsum sit amet velit. + Suspendisse id sem consectetuer libero luctus adipiscing. + +If list items are separated by blank lines, Markdown will wrap the +items in `<p>` tags in the HTML output. For example, this input: + + * Bird + * Magic + +will turn into: + + <ul> + <li>Bird</li> + <li>Magic</li> + </ul> + +But this: + + * Bird + + * Magic + +will turn into: + + <ul> + <li><p>Bird</p></li> + <li><p>Magic</p></li> + </ul> + +List items may consist of multiple paragraphs. Each subsequent +paragraph in a list item must be intended by either 4 spaces +or one tab: + + 1. This is a list item with two paragraphs. Lorem ipsum dolor + sit amet, consectetuer adipiscing elit. Aliquam hendrerit + mi posuere lectus. + + Vestibulum enim wisi, viverra nec, fringilla in, laoreet + vitae, risus. Donec sit amet nisl. Aliquam semper ipsum + sit amet velit. + + 2. Suspendisse id sem consectetuer libero luctus adipiscing. + +It looks nice if you indent every line of the subsequent +paragraphs, but here again, Markdown will allow you to be +lazy: + + * This is a list item with two paragraphs. + + This is the second paragraph in the list item. You're + only required to indent the first line. Lorem ipsum dolor + sit amet, consectetuer adipiscing elit. + + * Another item in the same list. + +To put a blockquote within a list item, the blockquote's `>` +delimiters need to be indented: + + * A list item with a blockquote: + + > This is a blockquote + > inside a list item. + +To put a code block within a list item, the code block needs +to be indented *twice* -- 8 spaces or two tabs: + + * A list item with a code block: + + <code goes here> + + +It's worth noting that it's possible to trigger an ordered list by +accident, by writing something like this: + + 1986. What a great season. + +In other words, a *number-period-space* sequence at the beginning of a +line. To avoid this, you can backslash-escape the period: + + 1986\. What a great season. + + + +<h3 id="precode">Code Blocks</h3> + +Pre-formatted code blocks are used for writing about programming or +markup source code. Rather than forming normal paragraphs, the lines +of a code block are interpreted literally. Markdown wraps a code block +in both `<pre>` and `<code>` tags. + +To produce a code block in Markdown, simply indent every line of the +block by at least 4 spaces or 1 tab. For example, given this input: + + This is a normal paragraph: + + This is a code block. + +Markdown will generate: + + <p>This is a normal paragraph:</p> + + <pre><code>This is a code block. + </code></pre> + +One level of indentation -- 4 spaces or 1 tab -- is removed from each +line of the code block. For example, this: + + Here is an example of AppleScript: + + tell application "Foo" + beep + end tell + +will turn into: + + <p>Here is an example of AppleScript:</p> + + <pre><code>tell application "Foo" + beep + end tell + </code></pre> + +A code block continues until it reaches a line that is not indented +(or the end of the article). + +Within a code block, ampersands (`&`) and angle brackets (`<` and `>`) +are automatically converted into HTML entities. This makes it very +easy to include example HTML source code using Markdown -- just paste +it and indent it, and Markdown will handle the hassle of encoding the +ampersands and angle brackets. For example, this: + + <div class="footer"> + © 2004 Foo Corporation + </div> + +will turn into: + + <pre><code><div class="footer"> + &copy; 2004 Foo Corporation + </div> + </code></pre> + +Regular Markdown syntax is not processed within code blocks. E.g., +asterisks are just literal asterisks within a code block. This means +it's also easy to use Markdown to write about Markdown's own syntax. + + + +<h3 id="hr">Horizontal Rules</h3> + +You can produce a horizontal rule tag (`<hr />`) by placing three or +more hyphens, asterisks, or underscores on a line by themselves. If you +wish, you may use spaces between the hyphens or asterisks. Each of the +following lines will produce a horizontal rule: + + * * * + + *** + + ***** + + - - - + + --------------------------------------- + + _ _ _ + + +* * * + +<h2 id="span">Span Elements</h2> + +<h3 id="link">Links</h3> + +Markdown supports two style of links: *inline* and *reference*. + +In both styles, the link text is delimited by [square brackets]. + +To create an inline link, use a set of regular parentheses immediately +after the link text's closing square bracket. Inside the parentheses, +put the URL where you want the link to point, along with an *optional* +title for the link, surrounded in quotes. For example: + + This is [an example](http://example.com/ "Title") inline link. + + [This link](http://example.net/) has no title attribute. + +Will produce: + + <p>This is <a href="http://example.com/" title="Title"> + an example</a> inline link.</p> + + <p><a href="http://example.net/">This link</a> has no + title attribute.</p> + +If you're referring to a local resource on the same server, you can +use relative paths: + + See my [About](/about/) page for details. + +Reference-style links use a second set of square brackets, inside +which you place a label of your choosing to identify the link: + + This is [an example][id] reference-style link. + +You can optionally use a space to separate the sets of brackets: + + This is [an example] [id] reference-style link. + +Then, anywhere in the document, you define your link label like this, +on a line by itself: + + [id]: http://example.com/ "Optional Title Here" + +That is: + +* Square brackets containing the link identifier (optionally + indented from the left margin using up to three spaces); +* followed by a colon; +* followed by one or more spaces (or tabs); +* followed by the URL for the link; +* optionally followed by a title attribute for the link, enclosed + in double or single quotes. + +The link URL may, optionally, be surrounded by angle brackets: + + [id]: <http://example.com/> "Optional Title Here" + +You can put the title attribute on the next line and use extra spaces +or tabs for padding, which tends to look better with longer URLs: + + [id]: http://example.com/longish/path/to/resource/here + "Optional Title Here" + +Link definitions are only used for creating links during Markdown +processing, and are stripped from your document in the HTML output. + +Link definition names may constist of letters, numbers, spaces, and punctuation -- but they are *not* case sensitive. E.g. these two links: + + [link text][a] + [link text][A] + +are equivalent. + +The *implicit link name* shortcut allows you to omit the name of the +link, in which case the link text itself is used as the name. +Just use an empty set of square brackets -- e.g., to link the word +"Google" to the google.com web site, you could simply write: + + [Google][] + +And then define the link: + + [Google]: http://google.com/ + +Because link names may contain spaces, this shortcut even works for +multiple words in the link text: + + Visit [Daring Fireball][] for more information. + +And then define the link: + + [Daring Fireball]: http://daringfireball.net/ + +Link definitions can be placed anywhere in your Markdown document. I +tend to put them immediately after each paragraph in which they're +used, but if you want, you can put them all at the end of your +document, sort of like footnotes. + +Here's an example of reference links in action: + + I get 10 times more traffic from [Google] [1] than from + [Yahoo] [2] or [MSN] [3]. + + [1]: http://google.com/ "Google" + [2]: http://search.yahoo.com/ "Yahoo Search" + [3]: http://search.msn.com/ "MSN Search" + +Using the implicit link name shortcut, you could instead write: + + I get 10 times more traffic from [Google][] than from + [Yahoo][] or [MSN][]. + + [google]: http://google.com/ "Google" + [yahoo]: http://search.yahoo.com/ "Yahoo Search" + [msn]: http://search.msn.com/ "MSN Search" + +Both of the above examples will produce the following HTML output: + + <p>I get 10 times more traffic from <a href="http://google.com/" + title="Google">Google</a> than from + <a href="http://search.yahoo.com/" title="Yahoo Search">Yahoo</a> + or <a href="http://search.msn.com/" title="MSN Search">MSN</a>.</p> + +For comparison, here is the same paragraph written using +Markdown's inline link style: + + I get 10 times more traffic from [Google](http://google.com/ "Google") + than from [Yahoo](http://search.yahoo.com/ "Yahoo Search") or + [MSN](http://search.msn.com/ "MSN Search"). + +The point of reference-style links is not that they're easier to +write. The point is that with reference-style links, your document +source is vastly more readable. Compare the above examples: using +reference-style links, the paragraph itself is only 81 characters +long; with inline-style links, it's 176 characters; and as raw HTML, +it's 234 characters. In the raw HTML, there's more markup than there +is text. + +With Markdown's reference-style links, a source document much more +closely resembles the final output, as rendered in a browser. By +allowing you to move the markup-related metadata out of the paragraph, +you can add links without interrupting the narrative flow of your +prose. + + +<h3 id="em">Emphasis</h3> + +Markdown treats asterisks (`*`) and underscores (`_`) as indicators of +emphasis. Text wrapped with one `*` or `_` will be wrapped with an +HTML `<em>` tag; double `*`'s or `_`'s will be wrapped with an HTML +`<strong>` tag. E.g., this input: + + *single asterisks* + + _single underscores_ + + **double asterisks** + + __double underscores__ + +will produce: + + <em>single asterisks</em> + + <em>single underscores</em> + + <strong>double asterisks</strong> + + <strong>double underscores</strong> + +You can use whichever style you prefer; the lone restriction is that +the same character must be used to open and close an emphasis span. + +Emphasis can be used in the middle of a word: + + un*fucking*believable + +But if you surround an `*` or `_` with spaces, it'll be treated as a +literal asterisk or underscore. + +To produce a literal asterisk or underscore at a position where it +would otherwise be used as an emphasis delimiter, you can backslash +escape it: + + \*this text is surrounded by literal asterisks\* + + + +<h3 id="code">Code</h3> + +To indicate a span of code, wrap it with backtick quotes (`` ` ``). +Unlike a pre-formatted code block, a code span indicates code within a +normal paragraph. For example: + + Use the `printf()` function. + +will produce: + + <p>Use the <code>printf()</code> function.</p> + +To include a literal backtick character within a code span, you can use +multiple backticks as the opening and closing delimiters: + + ``There is a literal backtick (`) here.`` + +which will produce this: + + <p><code>There is a literal backtick (`) here.</code></p> + +The backtick delimiters surrounding a code span may include spaces -- +one after the opening, one before the closing. This allows you to place +literal backtick characters at the beginning or end of a code span: + + A single backtick in a code span: `` ` `` + + A backtick-delimited string in a code span: `` `foo` `` + +will produce: + + <p>A single backtick in a code span: <code>`</code></p> + + <p>A backtick-delimited string in a code span: <code>`foo`</code></p> + +With a code span, ampersands and angle brackets are encoded as HTML +entities automatically, which makes it easy to include example HTML +tags. Markdown will turn this: + + Please don't use any `<blink>` tags. + +into: + + <p>Please don't use any <code><blink></code> tags.</p> + +You can write this: + + `—` is the decimal-encoded equivalent of `—`. + +to produce: + + <p><code>&#8212;</code> is the decimal-encoded + equivalent of <code>&mdash;</code>.</p> + + + +<h3 id="img">Images</h3> + +Admittedly, it's fairly difficult to devise a "natural" syntax for +placing images into a plain text document format. + +Markdown uses an image syntax that is intended to resemble the syntax +for links, allowing for two styles: *inline* and *reference*. + +Inline image syntax looks like this: + + ![Alt text](/path/to/img.jpg) + + ![Alt text](/path/to/img.jpg "Optional title") + +That is: + +* An exclamation mark: `!`; +* followed by a set of square brackets, containing the `alt` + attribute text for the image; +* followed by a set of parentheses, containing the URL or path to + the image, and an optional `title` attribute enclosed in double + or single quotes. + +Reference-style image syntax looks like this: + + ![Alt text][id] + +Where "id" is the name of a defined image reference. Image references +are defined using syntax identical to link references: + + [id]: url/to/image "Optional title attribute" + +As of this writing, Markdown has no syntax for specifying the +dimensions of an image; if this is important to you, you can simply +use regular HTML `<img>` tags. + + +* * * + + +<h2 id="misc">Miscellaneous</h2> + +<h3 id="autolink">Automatic Links</h3> + +Markdown supports a shortcut style for creating "automatic" links for URLs and email addresses: simply surround the URL or email address with angle brackets. What this means is that if you want to show the actual text of a URL or email address, and also have it be a clickable link, you can do this: + + <http://example.com/> + +Markdown will turn this into: + + <a href="http://example.com/">http://example.com/</a> + +Automatic links for email addresses work similarly, except that +Markdown will also perform a bit of randomized decimal and hex +entity-encoding to help obscure your address from address-harvesting +spambots. For example, Markdown will turn this: + + <address@example.com> + +into something like this: + + <a href="mailto:addre + ss@example.co + m">address@exa + mple.com</a> + +which will render in a browser as a clickable link to "address@example.com". + +(This sort of entity-encoding trick will indeed fool many, if not +most, address-harvesting bots, but it definitely won't fool all of +them. It's better than nothing, but an address published in this way +will probably eventually start receiving spam.) + + + +<h3 id="backslash">Backslash Escapes</h3> + +Markdown allows you to use backslash escapes to generate literal +characters which would otherwise have special meaning in Markdown's +formatting syntax. For example, if you wanted to surround a word with +literal asterisks (instead of an HTML `<em>` tag), you can backslashes +before the asterisks, like this: + + \*literal asterisks\* + +Markdown provides backslash escapes for the following characters: + + \ backslash + ` backtick + * asterisk + _ underscore + {} curly braces + [] square brackets + () parentheses + # hash mark + + plus sign + - minus sign (hyphen) + . dot + ! exclamation mark + diff --git a/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Nested blockquotes.text b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Nested blockquotes.text new file mode 100644 index 0000000..ed3c624 --- /dev/null +++ b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Nested blockquotes.text @@ -0,0 +1,5 @@ +> foo +> +> > bar +> +> foo diff --git a/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Ordered and unordered lists.text b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Ordered and unordered lists.text new file mode 100644 index 0000000..7f3b497 --- /dev/null +++ b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Ordered and unordered lists.text @@ -0,0 +1,131 @@ +## Unordered + +Asterisks tight: + +* asterisk 1 +* asterisk 2 +* asterisk 3 + + +Asterisks loose: + +* asterisk 1 + +* asterisk 2 + +* asterisk 3 + +* * * + +Pluses tight: + ++ Plus 1 ++ Plus 2 ++ Plus 3 + + +Pluses loose: + ++ Plus 1 + ++ Plus 2 + ++ Plus 3 + +* * * + + +Minuses tight: + +- Minus 1 +- Minus 2 +- Minus 3 + + +Minuses loose: + +- Minus 1 + +- Minus 2 + +- Minus 3 + + +## Ordered + +Tight: + +1. First +2. Second +3. Third + +and: + +1. One +2. Two +3. Three + + +Loose using tabs: + +1. First + +2. Second + +3. Third + +and using spaces: + +1. One + +2. Two + +3. Three + +Multiple paragraphs: + +1. Item 1, graf one. + + Item 2. graf two. The quick brown fox jumped over the lazy dog's + back. + +2. Item 2. + +3. Item 3. + + + +## Nested + +* Tab + * Tab + * Tab + +Here's another: + +1. First +2. Second: + * Fee + * Fie + * Foe +3. Third + +Same thing but with paragraphs: + +1. First + +2. Second: + * Fee + * Fie + * Foe + +3. Third + + +This was an error in Markdown 1.0.1: + +* this + + * sub + + that diff --git a/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Strong and em together.text b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Strong and em together.text new file mode 100644 index 0000000..95ee690 --- /dev/null +++ b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Strong and em together.text @@ -0,0 +1,7 @@ +***This is strong and em.*** + +So is ***this*** word. + +___This is strong and em.___ + +So is ___this___ word. diff --git a/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Tabs.text b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Tabs.text new file mode 100644 index 0000000..589d113 --- /dev/null +++ b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Tabs.text @@ -0,0 +1,21 @@ ++ this is a list item + indented with tabs + ++ this is a list item + indented with spaces + +Code: + + this code block is indented by one tab + +And: + + this code block is indented by two tabs + +And: + + + this is an example list item + indented with tabs + + + this is an example list item + indented with spaces diff --git a/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Tidyness.text b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Tidyness.text new file mode 100644 index 0000000..5f18b8d --- /dev/null +++ b/jni/ruby/test/rdoc/MarkdownTest_1.0.3/Tidyness.text @@ -0,0 +1,5 @@ +> A list within a blockquote: +> +> * asterisk 1 +> * asterisk 2 +> * asterisk 3 diff --git a/jni/ruby/test/rdoc/README b/jni/ruby/test/rdoc/README new file mode 100644 index 0000000..4ef17a7 --- /dev/null +++ b/jni/ruby/test/rdoc/README @@ -0,0 +1 @@ +you don't have to diff --git a/jni/ruby/test/rdoc/binary.dat b/jni/ruby/test/rdoc/binary.dat Binary files differnew file mode 100644 index 0000000..371950e --- /dev/null +++ b/jni/ruby/test/rdoc/binary.dat diff --git a/jni/ruby/test/rdoc/hidden.zip.txt b/jni/ruby/test/rdoc/hidden.zip.txt new file mode 100644 index 0000000..2400e38 --- /dev/null +++ b/jni/ruby/test/rdoc/hidden.zip.txt @@ -0,0 +1 @@ +PK diff --git a/jni/ruby/test/rdoc/test.ja.largedoc b/jni/ruby/test/rdoc/test.ja.largedoc new file mode 100644 index 0000000..a9c6c46 --- /dev/null +++ b/jni/ruby/test/rdoc/test.ja.largedoc @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + 吾輩(わがはい)は猫である。名前はまだ無い。 + どこで生れたかとんと見当(けんとう)がつかぬ。何でも薄暗いじめじめした所でニャーニャー泣いていた事だけは記憶している。吾輩はここで始めて人間というものを見た。しかもあとで聞くとそれは書生という人間中で一番獰悪(どうあく)な種族であったそうだ。この書生というのは時々我々を捕(つかま)えて煮(に)て食うという話である。しかしその当時は何という考もなかったから別段恐しいとも思わなかった。ただ彼の掌(てのひら)に載せられてスーと持ち上げられた時何だかフワフワした感じがあったばかりである。掌の上で少し落ちついて書生の顔を見たのがいわゆる人間というものの見始(みはじめ)であろう。この時妙なものだと思った感じが今でも残っている。第一毛をもって装飾されべきはずの顔がつるつるしてまるで薬缶(やかん)だ。その後(ご)猫にもだいぶ逢(あ)ったがこんな片輪(かたわ)には一度も出会(でく)わした事がない。のみならず顔の真中があまりに突起している。そうしてその穴の中から時々ぷうぷうと煙(けむり)を吹く。どうも咽(む)せぽくて実に弱った。これが人間の飲む煙草(たばこ)というものである事はようやくこの頃知った。 diff --git a/jni/ruby/test/rdoc/test.ja.rdoc b/jni/ruby/test/rdoc/test.ja.rdoc new file mode 100644 index 0000000..cd01cab --- /dev/null +++ b/jni/ruby/test/rdoc/test.ja.rdoc @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- + +こんにちは! + +初めまして。アーロンと申します。 + +どんな食べ物が好きですか?私はフランスの料理が大好きです。 +日本の料理も大好きです。 + +食べ物を食べるのが大好きだけど、お皿を洗うのが大嫌いです。 diff --git a/jni/ruby/test/rdoc/test.ja.txt b/jni/ruby/test/rdoc/test.ja.txt new file mode 100644 index 0000000..96e1db9 --- /dev/null +++ b/jni/ruby/test/rdoc/test.ja.txt @@ -0,0 +1,8 @@ +こんにちは! + +初めまして。アーロンと申します。 + +どんな食べ物が好きですか?私はフランスの料理が大好きです。 +日本の料理も大好きです。 + +食べ物を食べるのが大好きだけど、お皿を洗うのが大嫌いです。 diff --git a/jni/ruby/test/rdoc/test.txt b/jni/ruby/test/rdoc/test.txt new file mode 100644 index 0000000..16b14f5 --- /dev/null +++ b/jni/ruby/test/rdoc/test.txt @@ -0,0 +1 @@ +test file diff --git a/jni/ruby/test/rdoc/test_rdoc_alias.rb b/jni/ruby/test/rdoc/test_rdoc_alias.rb new file mode 100644 index 0000000..ff499af --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_alias.rb @@ -0,0 +1,13 @@ +require File.expand_path '../xref_test_case', __FILE__ + +class TestRDocAlias < XrefTestCase + + def test_to_s + a = RDoc::Alias.new nil, 'a', 'b', '' + a.parent = @c2 + + assert_equal 'alias: b -> #a in: RDoc::NormalClass C2 < Object', a.to_s + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_any_method.rb b/jni/ruby/test/rdoc/test_rdoc_any_method.rb new file mode 100644 index 0000000..9030580 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_any_method.rb @@ -0,0 +1,460 @@ +require File.expand_path '../xref_test_case', __FILE__ + +class TestRDocAnyMethod < XrefTestCase + + def test_aref + m = RDoc::AnyMethod.new nil, 'method?' + + assert_equal 'method-i-method-3F', m.aref + + m.singleton = true + + assert_equal 'method-c-method-3F', m.aref + end + + def test_arglists + m = RDoc::AnyMethod.new nil, 'method' + + assert_nil m.arglists + + m.params = "(a, b)" + m.block_params = "c, d" + + assert_equal "method(a, b) { |c, d| ... }", m.arglists + + call_seq = <<-SEQ +method(a) { |c| ... } +method(a, b) { |c, d| ... } + SEQ + + m.call_seq = call_seq.dup + + assert_equal call_seq, m.arglists + end + + def test_c_function + @c1_m.c_function = 'my_c1_m' + + assert_equal 'my_c1_m', @c1_m.c_function + end + + def test_call_seq_equals + m = RDoc::AnyMethod.new nil, nil + + m.call_seq = '' + + assert_nil m.call_seq + + m.call_seq = 'foo' + + assert_equal 'foo', m.call_seq + end + + def test_full_name + assert_equal 'C1::m', @c1.method_list.first.full_name + end + + def test_is_alias_for + assert_equal @c2_b, @c2_a.is_alias_for + + # set string on instance variable + loaded = Marshal.load Marshal.dump @c2_a + + loaded.store = @store + + assert_equal @c2_b, loaded.is_alias_for, 'Marshal.load' + + m1 = RDoc::AnyMethod.new nil, 'm1' + m1.store = @store + m1.instance_variable_set :@is_alias_for, ['Missing', false, 'method'] + + assert_nil m1.is_alias_for, 'missing alias' + end + + def test_markup_code + tokens = [ + RDoc::RubyToken::TkCONSTANT. new(0, 0, 0, 'CONSTANT'), + ] + + @c2_a.collect_tokens + @c2_a.add_tokens(*tokens) + + expected = '<span class="ruby-constant">CONSTANT</span>' + + assert_equal expected, @c2_a.markup_code + end + + def test_markup_code_empty + assert_equal '', @c2_a.markup_code + end + + def test_marshal_dump + @store.path = Dir.tmpdir + top_level = @store.add_file 'file.rb' + + m = RDoc::AnyMethod.new nil, 'method' + m.block_params = 'some_block' + m.call_seq = 'call_seq' + m.comment = 'this is a comment' + m.params = 'param' + m.record_location top_level + + cm = top_level.add_class RDoc::ClassModule, 'Klass' + cm.add_method m + + section = cm.sections.first + + al = RDoc::Alias.new nil, 'method', 'aliased', 'alias comment' + al_m = m.add_alias al, cm + + loaded = Marshal.load Marshal.dump m + loaded.store = @store + + comment = RDoc::Markup::Document.new( + RDoc::Markup::Paragraph.new('this is a comment')) + + assert_equal m, loaded + + assert_equal [al_m.name], loaded.aliases.map { |alas| alas.name } + assert_equal 'some_block', loaded.block_params + assert_equal 'call_seq', loaded.call_seq + assert_equal comment, loaded.comment + assert_equal top_level, loaded.file + assert_equal 'Klass#method', loaded.full_name + assert_equal 'method', loaded.name + assert_equal 'param', loaded.params + assert_equal nil, loaded.singleton # defaults to nil + assert_equal :public, loaded.visibility + assert_equal cm, loaded.parent + assert_equal section, loaded.section + end + + def test_marshal_load_aliased_method + aliased_method = Marshal.load Marshal.dump(@c2_a) + + aliased_method.store = @store + + assert_equal 'C2#a', aliased_method.full_name + assert_equal 'C2', aliased_method.parent_name + assert_equal '()', aliased_method.params + assert_equal @c2_b, aliased_method.is_alias_for, 'is_alias_for' + assert aliased_method.display? + end + + def test_marshal_load_class_method + class_method = Marshal.load Marshal.dump(@c1.method_list.first) + + assert_equal 'C1::m', class_method.full_name + assert_equal 'C1', class_method.parent_name + assert_equal '()', class_method.params + assert class_method.display? + end + + def test_marshal_load_instance_method + instance_method = Marshal.load Marshal.dump(@c1.method_list.last) + + assert_equal 'C1#m', instance_method.full_name + assert_equal 'C1', instance_method.parent_name + assert_equal '(foo)', instance_method.params + assert instance_method.display? + end + + def test_marshal_load_version_0 + @store.path = Dir.tmpdir + top_level = @store.add_file 'file.rb' + + m = RDoc::AnyMethod.new nil, 'method' + + cm = top_level.add_class RDoc::ClassModule, 'Klass' + cm.add_method m + + section = cm.sections.first + + al = RDoc::Alias.new nil, 'method', 'aliased', 'alias comment' + al_m = m.add_alias al, cm + + loaded = Marshal.load "\x04\bU:\x14RDoc::AnyMethod[\x0Fi\x00I" + + "\"\vmethod\x06:\x06EF\"\x11Klass#method0:\vpublic" + + "o:\eRDoc::Markup::Document\x06:\v@parts[\x06" + + "o:\x1CRDoc::Markup::Paragraph\x06;\t[\x06I" + + "\"\x16this is a comment\x06;\x06FI" + + "\"\rcall_seq\x06;\x06FI\"\x0Fsome_block\x06;\x06F" + + "[\x06[\aI\"\faliased\x06;\x06Fo;\b\x06;\t[\x06" + + "o;\n\x06;\t[\x06I\"\x12alias comment\x06;\x06FI" + + "\"\nparam\x06;\x06F" + + loaded.store = @store + + comment = RDoc::Markup::Document.new( + RDoc::Markup::Paragraph.new('this is a comment')) + + assert_equal m, loaded + + assert_equal [al_m.name], loaded.aliases.map { |alas| alas.name } + assert_equal 'some_block', loaded.block_params + assert_equal 'call_seq', loaded.call_seq + assert_equal comment, loaded.comment + assert_equal 'Klass#method', loaded.full_name + assert_equal 'method', loaded.name + assert_equal 'param', loaded.params + assert_equal nil, loaded.singleton # defaults to nil + assert_equal :public, loaded.visibility + assert_equal nil, loaded.file + assert_equal cm, loaded.parent + assert_equal section, loaded.section + assert_nil loaded.is_alias_for + + assert loaded.display? + end + + def test_marshal_dump_version_2 + @store.path = Dir.tmpdir + top_level = @store.add_file 'file.rb' + + m = RDoc::AnyMethod.new nil, 'method' + m.block_params = 'some_block' + m.call_seq = 'call_seq' + m.comment = 'this is a comment' + m.params = 'param' + m.record_location top_level + + cm = top_level.add_class RDoc::ClassModule, 'Klass' + cm.add_method m + + section = cm.sections.first + + al = RDoc::Alias.new nil, 'method', 'aliased', 'alias comment' + al_m = m.add_alias al, cm + + loaded = Marshal.load "\x04\bU:\x14RDoc::AnyMethod[\x14i\bI" + + "\"\vmethod\x06:\x06ETI" + + "\"\x11Klass#method\x06;\x06T0:\vpublic" + + "o:\eRDoc::Markup::Document\b:\v@parts[\x06" + + "o:\x1CRDoc::Markup::Paragraph\x06;\t[\x06I" + + "\"\x16this is a comment\x06;\x06T:\n@file0" + + ":0@omit_headings_from_table_of_contents_below0" + + "I\"\rcall_seq\x06;\x06TI\"\x0Fsome_block\x06" + + ";\x06T[\x06[\aI\"\faliased\x06;\x06To;\b\b;\t" + + "[\x06o;\n\x06;\t[\x06I\"\x12alias comment\x06" + + ";\x06T;\v0;\f0I\"\nparam\x06;\x06TI" + + "\"\ffile.rb\x06;\x06TFI\"\nKlass\x06;\x06T" + + "c\x16RDoc::ClassModule0" + + loaded.store = @store + + comment = doc(para('this is a comment')) + + assert_equal m, loaded + + assert_equal [al_m.name], loaded.aliases.map { |alas| alas.name } + assert_equal 'some_block', loaded.block_params + assert_equal 'call_seq', loaded.call_seq + assert_equal comment, loaded.comment + assert_equal top_level, loaded.file + assert_equal 'Klass#method', loaded.full_name + assert_equal 'method', loaded.name + assert_equal 'param', loaded.params + assert_equal nil, loaded.singleton # defaults to nil + assert_equal :public, loaded.visibility + assert_equal cm, loaded.parent + assert_equal section, loaded.section + assert_nil loaded.is_alias_for + end + + def test_name + m = RDoc::AnyMethod.new nil, nil + + assert_nil m.name + end + + def test_name_call_seq + m = RDoc::AnyMethod.new nil, nil + + m.call_seq = "yields(name)\nyields(name, description)" + + assert_equal 'yields', m.name + end + + def test_name_call_seq_dot + m = RDoc::AnyMethod.new nil, nil + + m.call_seq = "obj.yields(name)\nobj.yields(name, description)" + + assert_equal 'yields', m.name + end + + def test_param_list_block_params + m = RDoc::AnyMethod.new nil, 'method' + m.parent = @c1 + + m.block_params = 'c, d' + + assert_equal %w[c d], m.param_list + end + + def test_param_list_call_seq + m = RDoc::AnyMethod.new nil, 'method' + m.parent = @c1 + + call_seq = <<-SEQ +method(a) { |c| ... } +method(a, b) { |c, d| ... } + SEQ + + m.call_seq = call_seq + + assert_equal %w[a b c d], m.param_list + end + + def test_param_list_default + m = RDoc::AnyMethod.new nil, 'method' + m.parent = @c1 + + m.params = '(b = default)' + + assert_equal %w[b], m.param_list + end + + def test_param_list_params + m = RDoc::AnyMethod.new nil, 'method' + m.parent = @c1 + + m.params = '(a, b)' + + assert_equal %w[a b], m.param_list + end + + def test_param_list_params_block_params + m = RDoc::AnyMethod.new nil, 'method' + m.parent = @c1 + + m.params = '(a, b)' + m.block_params = 'c, d' + + assert_equal %w[a b c d], m.param_list + end + + def test_param_list_empty_params_with_block + m = RDoc::AnyMethod.new nil, 'method' + m.parent = @c1 + + m.params = '()' + m.block_params = 'a, b' + + assert_equal %w[a b], m.param_list + end + + def test_param_list_ampersand_param_block_params + m = RDoc::AnyMethod.new nil, 'method' + m.parent = @c1 + + m.params = '(a, b, &block)' + m.block_params = 'c, d' + + assert_equal %w[a b c d], m.param_list + end + + def test_param_list_ampersand_param + m = RDoc::AnyMethod.new nil, 'method' + m.parent = @c1 + + m.params = '(a, b, &block)' + + assert_equal %w[a b block], m.param_list + end + + def test_param_seq + m = RDoc::AnyMethod.new nil, 'method' + m.parent = @c1 + m.params = 'a' + + assert_equal '(a)', m.param_seq + + m.params = '(a)' + + assert_equal '(a)', m.param_seq + + m.params = "(a,\n b)" + + assert_equal '(a, b)', m.param_seq + + m.block_params = "c,\n d" + + assert_equal '(a, b) { |c, d| ... }', m.param_seq + end + + def test_param_seq_call_seq + m = RDoc::AnyMethod.new nil, 'method' + m.parent = @c1 + + call_seq = <<-SEQ +method(a) { |c| ... } +method(a, b) { |c, d| ... } + SEQ + + m.call_seq = call_seq + + assert_equal '(a, b) { |c, d| }', m.param_seq + + end + + def test_parent_name + assert_equal 'C1', @c1.method_list.first.parent_name + assert_equal 'C1', @c1.method_list.last.parent_name + end + + def test_store_equals + loaded = Marshal.load Marshal.dump(@c1.method_list.last) + + loaded.store = @store + + assert_equal @store, loaded.file.store + end + + def test_superclass_method + m3 = RDoc::AnyMethod.new '', 'no_super' + + m2 = RDoc::AnyMethod.new '', 'supers' + m2.calls_super = true + + m1 = RDoc::AnyMethod.new '', 'supers' + + c1 = RDoc::NormalClass.new 'Outer' + c1.store = @store + c1.add_method m1 + + c2 = RDoc::NormalClass.new 'Inner', c1 + c2.store = @store + c2.add_method m2 + c2.add_method m3 + + assert_nil m3.superclass_method, + 'no superclass method for no_super' + + assert_equal m1, m2.superclass_method, + 'superclass method missing for supers' + end + + def test_superclass_method_multilevel + m2 = RDoc::AnyMethod.new '', 'supers' + m2.calls_super = true + + m1 = RDoc::AnyMethod.new '', 'supers' + + c1 = RDoc::NormalClass.new 'Outer' + c1.store = @store + c1.add_method m1 + + c2 = RDoc::NormalClass.new 'Middle', c1 + c2.store = @store + + c3 = RDoc::NormalClass.new 'Inner', c2 + c3.store = @store + c3.add_method m2 + + assert_equal m1, m2.superclass_method, + 'superclass method missing for supers' + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_attr.rb b/jni/ruby/test/rdoc/test_rdoc_attr.rb new file mode 100644 index 0000000..a4922df --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_attr.rb @@ -0,0 +1,190 @@ +require 'rdoc/test_case' + +class TestRDocAttr < RDoc::TestCase + + def setup + super + + @a = RDoc::Attr.new nil, 'attr', 'RW', '' + end + + def test_aref + m = RDoc::Attr.new nil, 'attr', 'RW', nil + + assert_equal 'attribute-i-attr', m.aref + end + + def test_arglists + assert_nil @a.arglists + end + + def test_block_params + assert_nil @a.block_params + end + + def test_call_seq + assert_nil @a.call_seq + end + + def test_definition + assert_equal 'attr_accessor', @a.definition + + @a.rw = 'R' + + assert_equal 'attr_reader', @a.definition + + @a.rw = 'W' + + assert_equal 'attr_writer', @a.definition + end + + def test_full_name + assert_equal '(unknown)#attr', @a.full_name + end + + def test_marshal_dump + tl = @store.add_file 'file.rb' + + @a.comment = 'this is a comment' + @a.record_location tl + + cm = tl.add_class RDoc::NormalClass, 'Klass' + cm.add_attribute @a + + section = cm.sections.first + + loaded = Marshal.load Marshal.dump @a + loaded.store = @store + + assert_equal @a, loaded + + comment = RDoc::Markup::Document.new( + RDoc::Markup::Paragraph.new('this is a comment')) + + assert_equal comment, loaded.comment + assert_equal 'file.rb', loaded.file.relative_name + assert_equal 'Klass#attr', loaded.full_name + assert_equal 'attr', loaded.name + assert_equal 'RW', loaded.rw + assert_equal false, loaded.singleton + assert_equal :public, loaded.visibility + assert_equal tl, loaded.file + assert_equal cm, loaded.parent + assert_equal section, loaded.section + end + + def test_marshal_dump_singleton + tl = @store.add_file 'file.rb' + + @a.comment = 'this is a comment' + @a.record_location tl + + cm = tl.add_class RDoc::NormalClass, 'Klass' + cm.add_attribute @a + + section = cm.sections.first + + @a.rw = 'R' + @a.singleton = true + @a.visibility = :protected + + loaded = Marshal.load Marshal.dump @a + loaded.store = @store + + assert_equal @a, loaded + + comment = RDoc::Markup::Document.new( + RDoc::Markup::Paragraph.new('this is a comment')) + + assert_equal comment, loaded.comment + assert_equal 'Klass::attr', loaded.full_name + assert_equal 'attr', loaded.name + assert_equal 'R', loaded.rw + assert_equal true, loaded.singleton + assert_equal :protected, loaded.visibility + assert_equal tl, loaded.file + assert_equal cm, loaded.parent + assert_equal section, loaded.section + end + + def test_marshal_load_version_1 + tl = @store.add_file 'file.rb' + cm = tl.add_class RDoc::NormalClass, 'Klass' + section = cm.sections.first + + data = "\x04\bU:\x0FRDoc::Attr[\fi\x06I\"\tattr\x06:\x06EF" + + "\"\x0FKlass#attrI\"\aRW\x06;\x06F:\vpublic" + + "o:\eRDoc::Markup::Document\x06:\v@parts[\x06" + + "o:\x1CRDoc::Markup::Paragraph\x06;\t[\x06I" + + "\"\x16this is a comment\x06;\x06FF" + + loaded = Marshal.load data + loaded.store = @store + + comment = RDoc::Markup::Document.new( + RDoc::Markup::Paragraph.new('this is a comment')) + + assert_equal comment, loaded.comment + assert_equal 'Klass#attr', loaded.full_name + assert_equal 'attr', loaded.name + assert_equal 'RW', loaded.rw + assert_equal false, loaded.singleton + assert_equal :public, loaded.visibility + + # version 2 + assert_nil loaded.file + + # version 3 + assert_equal cm, loaded.parent + assert_equal section, loaded.section + + assert loaded.display? + end + + def test_marshal_load_version_2 + tl = @store.add_file 'file.rb' + cm = tl.add_class RDoc::NormalClass, 'Klass' + section = cm.sections.first + + loaded = Marshal.load "\x04\bU:\x0FRDoc::Attr[\ri\aI\"\tattr\x06" + + ":\x06ETI\"\x0FKlass#attr\x06;\x06TI\"\aRW\x06" + + ";\x06T:\vpublico:\eRDoc::Markup::Document\a" + + ":\v@parts[\x06o:\x1CRDoc::Markup::Paragraph\x06;" + + "\t[\x06I\"\x16this is a comment\x06;\x06T:\n" + + "@file0FI\"\ffile.rb\x06;\x06T" + loaded.store = @store + + comment = doc(para('this is a comment')) + + assert_equal comment, loaded.comment + assert_equal 'Klass#attr', loaded.full_name + assert_equal 'attr', loaded.name + assert_equal 'RW', loaded.rw + assert_equal false, loaded.singleton + assert_equal :public, loaded.visibility + assert_equal tl, loaded.file + + # version 3 + assert_equal cm, loaded.parent + assert_equal section, loaded.section + + assert loaded.display? + end + + def test_params + assert_nil @a.params + end + + def test_singleton + refute @a.singleton + end + + def test_type + assert_equal 'instance', @a.type + + @a.singleton = true + assert_equal 'class', @a.type + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_class_module.rb b/jni/ruby/test/rdoc/test_rdoc_class_module.rb new file mode 100644 index 0000000..0e06587 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_class_module.rb @@ -0,0 +1,1492 @@ +require File.expand_path '../xref_test_case', __FILE__ + +class TestRDocClassModule < XrefTestCase + + def test_add_comment + tl1 = @store.add_file 'one.rb' + tl2 = @store.add_file 'two.rb' + tl3 = @store.add_file 'three.rb' + + cm = RDoc::ClassModule.new 'Klass' + cm.add_comment '# comment 1', tl1 + + assert_equal [['comment 1', tl1]], cm.comment_location + assert_equal 'comment 1', cm.comment + + cm.add_comment '# comment 2', tl2 + + assert_equal [['comment 1', tl1], ['comment 2', tl2]], cm.comment_location + assert_equal "comment 1\n---\ncomment 2", cm.comment + + cm.add_comment "# * comment 3", tl3 + + assert_equal [['comment 1', tl1], + ['comment 2', tl2], + ['* comment 3', tl3]], cm.comment_location + assert_equal "comment 1\n---\ncomment 2\n---\n* comment 3", cm.comment + end + + def test_add_comment_comment + cm = RDoc::ClassModule.new 'Klass' + + cm.add_comment comment('comment'), @top_level + + assert_equal 'comment', cm.comment.text + end + + def test_add_comment_duplicate + tl1 = @store.add_file 'one.rb' + + cm = RDoc::ClassModule.new 'Klass' + cm.add_comment '# comment 1', tl1 + cm.add_comment '# comment 2', tl1 + + assert_equal [['comment 2', tl1]], cm.comment_location + end + + def test_add_comment_stopdoc + tl = @store.add_file 'file.rb' + + cm = RDoc::ClassModule.new 'Klass' + cm.stop_doc + + cm.add_comment '# comment 1', tl + + assert_empty cm.comment + end + + def test_ancestors + assert_equal [@parent, "Object"], @child.ancestors + end + + def test_comment_equals + cm = RDoc::ClassModule.new 'Klass' + cm.comment = '# comment 1' + + assert_equal 'comment 1', cm.comment + + cm.comment = '# comment 2' + + assert_equal "comment 1\n---\ncomment 2", cm.comment + + cm.comment = "# * comment 3" + + assert_equal "comment 1\n---\ncomment 2\n---\n* comment 3", cm.comment + end + + def test_comment_equals_comment + cm = RDoc::ClassModule.new 'Klass' + + cm.comment = comment 'comment' + + assert_equal 'comment', cm.comment.text + end + + def test_docuent_self_or_methods + assert @c1.document_self_or_methods + + @c1.document_self = false + + assert @c1.document_self_or_methods + + @c1_m.document_self = false + + assert @c1.document_self_or_methods + + @c1__m.document_self = false + + refute @c1.document_self_or_methods + end + + def test_documented_eh + cm = RDoc::ClassModule.new 'C' + + refute cm.documented?, 'no comments, no markers' + + cm.add_comment '', @top_level + + refute cm.documented?, 'empty comment' + + cm.add_comment 'hi', @top_level + + assert cm.documented?, 'commented' + + cm.comment_location.clear + + refute cm.documented?, 'no comment' + + cm.document_self = nil # notify :nodoc: + + assert cm.documented?, ':nodoc:' + end + + def test_each_ancestor + assert_equal [@parent], @child.each_ancestor.to_a + end + + def test_each_ancestor_cycle + m_incl = RDoc::Include.new 'M', nil + + m = @top_level.add_module RDoc::NormalModule, 'M' + m.add_include m_incl + + assert_empty m.each_ancestor.to_a + end + + # handle making a short module alias of yourself + + def test_find_class_named + @c2.classes_hash['C2'] = @c2 + + assert_nil @c2.find_class_named('C1') + end + + def test_from_module_comment + tl = @store.add_file 'file.rb' + klass = tl.add_class RDoc::NormalModule, 'Klass' + klass.add_comment 'really a class', tl + + klass = RDoc::ClassModule.from_module RDoc::NormalClass, klass + + assert_equal [['really a class', tl]], klass.comment_location + end + + def test_marshal_dump + @store.path = Dir.tmpdir + tl = @store.add_file 'file.rb' + + ns = tl.add_module RDoc::NormalModule, 'Namespace' + + cm = ns.add_class RDoc::NormalClass, 'Klass', 'Super' + cm.document_self = true + cm.record_location tl + + a1 = RDoc::Attr.new nil, 'a1', 'RW', '' + a1.record_location tl + a2 = RDoc::Attr.new nil, 'a2', 'RW', '', true + a2.record_location tl + + m1 = RDoc::AnyMethod.new nil, 'm1' + m1.record_location tl + + c1 = RDoc::Constant.new 'C1', nil, '' + c1.record_location tl + + i1 = RDoc::Include.new 'I1', '' + i1.record_location tl + + e1 = RDoc::Extend.new 'E1', '' + e1.record_location tl + + section_comment = RDoc::Comment.new('section comment') + section_comment.location = tl + + assert_equal 1, cm.sections.length, 'sanity, default section only' + s0 = cm.sections.first + s1 = cm.add_section 'section', section_comment + + cm.add_attribute a1 + cm.add_attribute a2 + cm.add_method m1 + cm.add_constant c1 + cm.add_include i1 + cm.add_extend e1 + cm.add_comment 'this is a comment', tl + + loaded = Marshal.load Marshal.dump cm + loaded.store = @store + + assert_equal cm, loaded + + inner = RDoc::Markup::Document.new( + RDoc::Markup::Paragraph.new('this is a comment')) + inner.file = tl + + comment = RDoc::Markup::Document.new inner + + assert_equal [a2, a1], loaded.attributes.sort + assert_equal comment, loaded.comment + assert_equal [c1], loaded.constants + assert_equal 'Namespace::Klass', loaded.full_name + assert_equal [i1], loaded.includes + assert_equal [e1], loaded.extends + assert_equal [m1], loaded.method_list + assert_equal 'Klass', loaded.name + assert_equal 'Super', loaded.superclass + assert_equal [tl], loaded.in_files + assert_equal 'Namespace', loaded.parent.name + + expected = { nil => s0, 'section' => s1 } + assert_equal expected, loaded.sections_hash + + assert_equal tl, loaded.attributes.first.file + + assert_equal tl, loaded.constants.first.file + + assert_equal tl, loaded.includes.first.file + + assert_equal tl, loaded.extends.first.file + + assert_equal tl, loaded.method_list.first.file + end + + def test_marshal_dump_visibilty + @store.path = Dir.tmpdir + tl = @store.add_file 'file.rb' + + ns = tl.add_module RDoc::NormalModule, 'Namespace' + + cm = ns.add_class RDoc::NormalClass, 'Klass', 'Super' + cm.record_location tl + + a1 = RDoc::Attr.new nil, 'a1', 'RW', '' + a1.record_location tl + a1.document_self = false + + m1 = RDoc::AnyMethod.new nil, 'm1' + m1.record_location tl + m1.document_self = false + + c1 = RDoc::Constant.new 'C1', nil, '' + c1.record_location tl + c1.document_self = false + + i1 = RDoc::Include.new 'I1', '' + i1.record_location tl + i1.document_self = false + + e1 = RDoc::Extend.new 'E1', '' + e1.record_location tl + e1.document_self = false + + section_comment = RDoc::Comment.new('section comment') + section_comment.location = tl + + assert_equal 1, cm.sections.length, 'sanity, default section only' + + cm.add_attribute a1 + cm.add_method m1 + cm.add_constant c1 + cm.add_include i1 + cm.add_extend e1 + cm.add_comment 'this is a comment', tl + + loaded = Marshal.load Marshal.dump cm + loaded.store = @store + + assert_equal cm, loaded + + assert_empty loaded.attributes + assert_empty loaded.constants + assert_empty loaded.includes + assert_empty loaded.extends + assert_empty loaded.method_list + end + + def test_marshal_load_version_0 + tl = @store.add_file 'file.rb' + ns = tl.add_module RDoc::NormalModule, 'Namespace' + cm = ns.add_class RDoc::NormalClass, 'Klass', 'Super' + + a = RDoc::Attr.new(nil, 'a1', 'RW', '') + m = RDoc::AnyMethod.new(nil, 'm1') + c = RDoc::Constant.new('C1', nil, '') + i = RDoc::Include.new('I1', '') + + s0 = cm.sections.first + + cm.add_attribute a + cm.add_method m + cm.add_constant c + cm.add_include i + cm.add_comment 'this is a comment', tl + + loaded = Marshal.load "\x04\bU:\x16RDoc::NormalClass[\x0Ei\x00\"\nKlass" + + "\"\x15Namespace::KlassI\"\nSuper\x06:\x06EF" + + "o:\eRDoc::Markup::Document\x06:\v@parts[\x06" + + "o:\x1CRDoc::Markup::Paragraph\x06;\b[\x06I" + + "\"\x16this is a comment\x06;\x06F[\x06[\aI" + + "\"\aa1\x06;\x06FI\"\aRW\x06;\x06F[\x06[\aI" + + "\"\aC1\x06;\x06Fo;\a\x06;\b[\x00[\x06[\aI" + + "\"\aI1\x06;\x06Fo;\a\x06;\b[\x00[\a[\aI" + + "\"\nclass\x06;\x06F[\b[\a:\vpublic[\x00[\a" + + ":\x0Eprotected[\x00[\a:\fprivate[\x00[\aI" + + "\"\rinstance\x06;\x06F[\b[\a;\n[\x06I" + + "\"\am1\x06;\x06F[\a;\v[\x00[\a;\f[\x00" + + loaded.store = @store + + assert_equal cm, loaded + + comment = RDoc::Markup::Document.new( + RDoc::Markup::Paragraph.new('this is a comment')) + + assert_equal [a], loaded.attributes + assert_equal comment, loaded.comment + assert_equal [c], loaded.constants + assert_equal 'Namespace::Klass', loaded.full_name + assert_equal [i], loaded.includes + assert_equal [m], loaded.method_list + assert_equal 'Klass', loaded.name + assert_equal 'Super', loaded.superclass + assert_nil loaded.file + assert_empty loaded.in_files + assert_nil loaded.parent + assert loaded.current_section + + expected = { nil => s0 } + assert_equal expected, loaded.sections_hash + + assert loaded.display? + end + + def test_marshal_load_version_1 + tl = @store.add_file 'file.rb' + + ns = tl.add_module RDoc::NormalModule, 'Namespace' + + cm = ns.add_class RDoc::NormalClass, 'Klass', 'Super' + cm.record_location tl + + a1 = RDoc::Attr.new nil, 'a1', 'RW', '' + a1.record_location tl + a2 = RDoc::Attr.new nil, 'a2', 'RW', '', true + a2.record_location tl + + m1 = RDoc::AnyMethod.new nil, 'm1' + m1.record_location tl + + c1 = RDoc::Constant.new 'C1', nil, '' + c1.record_location tl + + i1 = RDoc::Include.new 'I1', '' + i1.record_location tl + + s0 = cm.sections.first + + cm.add_attribute a1 + cm.add_attribute a2 + cm.add_method m1 + cm.add_constant c1 + cm.add_include i1 + cm.add_comment 'this is a comment', tl + + loaded = Marshal.load "\x04\bU:\x16RDoc::NormalClass[\x0Ei\x06I\"\nKlass" + + "\x06:\x06EFI\"\x15Namespace::Klass\x06;\x06FI" + + "\"\nSuper\x06;\x06Fo:\eRDoc::Markup::Document\a" + + ":\v@parts[\x06o;\a\a;\b[\x06o" + + ":\x1CRDoc::Markup::Paragraph\x06;\b" + + "[\x06I\"\x16this is a comment\x06;\x06F" + + ":\n@fileI\"\ffile.rb\x06;\x06F;\n0[\a[\nI" + + "\"\aa2\x06;\x06FI\"\aRW\x06;\x06F:\vpublicT@\x11" + + "[\nI\"\aa1\x06;\x06FI\"\aRW\x06;\x06F;\vF@\x11" + + "[\x06[\bI\"\aC1\x06;\x06Fo;\a\a;\b[\x00;\n0@\x11" + + "[\x06[\bI\"\aI1\x06;\x06Fo;\a\a;\b[\x00;\n0@\x11" + + "[\a[\aI\"\nclass\x06;\x06F[\b[\a;\v[\x00" + + "[\a:\x0Eprotected[\x00[\a:\fprivate[\x00[\aI" + + "\"\rinstance\x06;\x06F[\b[\a;\v[\x06[\aI" + + "\"\am1\x06;\x06F@\x11[\a;\f[\x00[\a;\r[\x00" + + loaded.store = @store + + assert_equal cm, loaded + + inner = RDoc::Markup::Document.new( + RDoc::Markup::Paragraph.new('this is a comment')) + inner.file = tl + + comment = RDoc::Markup::Document.new inner + + assert_equal [a2, a1], loaded.attributes.sort + assert_equal comment, loaded.comment + assert_equal [c1], loaded.constants + assert_equal 'Namespace::Klass', loaded.full_name + assert_equal [i1], loaded.includes + assert_empty loaded.extends + assert_equal [m1], loaded.method_list + assert_equal 'Klass', loaded.name + assert_equal 'Super', loaded.superclass + assert_empty loaded.in_files + assert_nil loaded.parent + assert loaded.current_section + + assert_equal tl, loaded.attributes.first.file + assert_equal tl, loaded.constants.first.file + assert_equal tl, loaded.includes.first.file + assert_equal tl, loaded.method_list.first.file + + expected = { nil => s0 } + assert_equal expected, loaded.sections_hash + end + + def test_marshal_load_version_2 + tl = @store.add_file 'file.rb' + + ns = tl.add_module RDoc::NormalModule, 'Namespace' + + cm = ns.add_class RDoc::NormalClass, 'Klass', 'Super' + cm.record_location tl + + a1 = RDoc::Attr.new nil, 'a1', 'RW', '' + a1.record_location tl + a2 = RDoc::Attr.new nil, 'a2', 'RW', '', true + a2.record_location tl + + m1 = RDoc::AnyMethod.new nil, 'm1' + m1.record_location tl + + c1 = RDoc::Constant.new 'C1', nil, '' + c1.record_location tl + + i1 = RDoc::Include.new 'I1', '' + i1.record_location tl + + e1 = RDoc::Extend.new 'E1', '' + e1.record_location tl + + s0 = cm.sections.first + + cm.add_attribute a1 + cm.add_attribute a2 + cm.add_method m1 + cm.add_constant c1 + cm.add_include i1 + cm.add_extend e1 + cm.add_comment 'this is a comment', tl + + loaded = Marshal.load "\x04\bU:\x16RDoc::NormalClass[\x0Fi\aI\"\nKlass" + + "\x06:\x06EFI\"\x15Namespace::Klass\x06;\x06FI" + + "\"\nSuper\x06;\x06Fo:\eRDoc::Markup::Document\a" + + ":\v@parts[\x06o;\a\a;\b[\x06o" + + ":\x1CRDoc::Markup::Paragraph\x06;\b" + + "[\x06I\"\x16this is a comment\x06;\x06F" + + ":\n@fileI\"\ffile.rb\x06;\x06F;\n0[\a[\nI" + + "\"\aa2\x06;\x06FI\"\aRW\x06;\x06F:\vpublicT@\x11" + + "[\nI\"\aa1\x06;\x06FI\"\aRW\x06;\x06F;\vF@\x11" + + "[\x06[\bI\"\aC1\x06;\x06Fo;\a\a;\b[\x00;\n0@\x11" + + "[\x06[\bI\"\aI1\x06;\x06Fo;\a\a;\b[\x00;\n0@\x11" + + "[\a[\aI\"\nclass\x06;\x06F[\b[\a;\v[\x00" + + "[\a:\x0Eprotected[\x00[\a:\fprivate[\x00[\aI" + + "\"\rinstance\x06;\x06F[\b[\a;\v[\x06[\aI" + + "\"\am1\x06;\x06F@\x11[\a;\f[\x00[\a;\r[\x00" + + "[\x06[\bI\"\aE1\x06;\x06Fo;\a\a;\b[\x00;\n0@\x11" + + loaded.store = @store + + assert_equal cm, loaded + + inner = RDoc::Markup::Document.new( + RDoc::Markup::Paragraph.new('this is a comment')) + inner.file = tl + + comment = RDoc::Markup::Document.new inner + + assert_equal [a2, a1], loaded.attributes.sort + assert_equal comment, loaded.comment + assert_equal [c1], loaded.constants + assert_equal 'Namespace::Klass', loaded.full_name + assert_equal [i1], loaded.includes + assert_equal [e1], loaded.extends + assert_equal [m1], loaded.method_list + assert_equal 'Klass', loaded.name + assert_equal 'Super', loaded.superclass + assert_empty loaded.in_files + assert_nil loaded.parent + assert loaded.current_section + + assert_equal tl, loaded.attributes. first.file + assert_equal tl, loaded.constants. first.file + assert_equal tl, loaded.includes. first.file + assert_equal tl, loaded.extends. first.file + assert_equal tl, loaded.method_list.first.file + + expected = { nil => s0 } + assert_equal expected, loaded.sections_hash + end + + def test_marshal_load_version_3 + tl = @store.add_file 'file.rb' + + ns = tl.add_module RDoc::NormalModule, 'Namespace' + + cm = ns.add_class RDoc::NormalClass, 'Klass', 'Super' + cm.record_location tl + + a1 = RDoc::Attr.new nil, 'a1', 'RW', '' + a1.record_location tl + a2 = RDoc::Attr.new nil, 'a2', 'RW', '', true + a2.record_location tl + + m1 = RDoc::AnyMethod.new nil, 'm1' + m1.record_location tl + + c1 = RDoc::Constant.new 'C1', nil, '' + c1.record_location tl + + i1 = RDoc::Include.new 'I1', '' + i1.record_location tl + + e1 = RDoc::Extend.new 'E1', '' + e1.record_location tl + + section_comment = RDoc::Comment.new('section comment') + section_comment.location = tl + + assert_equal 1, cm.sections.length, 'sanity, default section only' + s0 = cm.sections.first + s1 = cm.add_section 'section', section_comment + + cm.add_attribute a1 + cm.add_attribute a2 + cm.add_method m1 + cm.add_constant c1 + cm.add_include i1 + cm.add_extend e1 + cm.add_comment 'this is a comment', tl + + loaded = Marshal.load "\x04\bU:\x16RDoc::NormalClass[\x13i\bI\"\nKlass" + + "\x06:\x06ETI\"\x15Namespace::Klass\x06;\x06TI" + + "\"\nSuper\x06;\x06To:\eRDoc::Markup::Document\a" + + ":\v@parts[\x06o;\a\a;\b[\x06o" + + ":\x1CRDoc::Markup::Paragraph\x06;\b[\x06I" + + "\"\x16this is a comment\x06;\x06T:\n@fileI" + + "\"\ffile.rb\x06;\x06T;\n0[\a[\nI\"\aa2\x06;" + + "\x06TI\"\aRW\x06;\x06T:\vpublicT@\x11[\nI" + + "\"\aa1\x06;\x06TI\"\aRW\x06;\x06T;\vF@\x11" + + "[\x06U:\x13RDoc::Constant[\x0Fi\x00I\"\aC1\x06" + + ";\x06TI\"\x19Namespace::Klass::C1\x06;\x06T00o" + + ";\a\a;\b[\x00;\n0@\x11@\ac\x16RDoc::NormalClass0" + + "[\x06[\bI\"\aI1\x06;\x06To;\a\a;\b[\x00;\n0@\x11" + + "[\a[\aI\"\nclass\x06;\x06T[\b[\a;\v[\x00[\a" + + ":\x0Eprotected[\x00[\a:\fprivate[\x00[\aI" + + "\"\rinstance\x06;\x06T[\b[\a;\v[\x06[\aI" + + "\"\am1\x06;\x06T@\x11[\a;\r[\x00[\a;\x0E[\x00" + + "[\x06[\bI\"\aE1\x06;\x06To;\a\a;\b[\x00;\n0@\x11" + + "[\aU:\eRDoc::Context::Section[\bi\x000o;\a\a;\b" + + "[\x00;\n0U;\x0F[\bi\x00I\"\fsection\x06;\x06To" + + ";\a\a;\b[\x06o;\a\a;\b[\x06o;\t\x06;\b[\x06I" + + "\"\x14section comment\x06;\x06T;\n@\x11;\n0" + + "[\x06@\x11I\"\x0ENamespace\x06" + + ";\x06Tc\x17RDoc::NormalModule" + + loaded.store = @store + + assert_equal cm, loaded + + inner = RDoc::Markup::Document.new( + RDoc::Markup::Paragraph.new('this is a comment')) + inner.file = tl + + comment = RDoc::Markup::Document.new inner + + assert_equal [a2, a1], loaded.attributes.sort + assert_equal comment, loaded.comment + assert_equal [c1], loaded.constants + assert_equal 'Namespace::Klass', loaded.full_name + assert_equal [i1], loaded.includes + assert_equal [e1], loaded.extends + assert_equal [m1], loaded.method_list + assert_equal 'Klass', loaded.name + assert_equal 'Super', loaded.superclass + assert_equal 'Namespace', loaded.parent.name + assert loaded.current_section + + expected = { + nil => s0, + 'section' => s1, + } + + assert_equal expected, loaded.sections_hash + assert_equal [tl], loaded.in_files + + assert_equal tl, loaded.attributes. first.file + assert_equal tl, loaded.constants. first.file + assert_equal tl, loaded.includes. first.file + assert_equal tl, loaded.extends. first.file + assert_equal tl, loaded.method_list.first.file + end + + def test_merge + tl = @store.add_file 'one.rb' + p1 = tl.add_class RDoc::NormalClass, 'Parent' + c1 = p1.add_class RDoc::NormalClass, 'Klass' + + c2 = RDoc::NormalClass.new 'Klass' + + c2.merge c1 + + assert_equal 'Parent', c1.parent_name, 'original parent name' + assert_equal 'Parent', c2.parent_name, 'merged parent name' + + assert c1.current_section, 'original current_section' + assert c2.current_section, 'merged current_section' + end + + def test_merge_attributes + tl1 = @store.add_file 'one.rb' + tl2 = @store.add_file 'two.rb' + + cm1 = RDoc::ClassModule.new 'Klass' + + attr = cm1.add_attribute RDoc::Attr.new(nil, 'a1', 'RW', '') + attr.record_location tl1 + attr = cm1.add_attribute RDoc::Attr.new(nil, 'a3', 'R', '') + attr.record_location tl1 + attr = cm1.add_attribute RDoc::Attr.new(nil, 'a4', 'R', '') + attr.record_location tl1 + + cm2 = RDoc::ClassModule.new 'Klass' + # TODO allow merging when comment == '' + cm2.instance_variable_set :@comment, @RM::Document.new + + attr = cm2.add_attribute RDoc::Attr.new(nil, 'a2', 'RW', '') + attr.record_location tl2 + attr = cm2.add_attribute RDoc::Attr.new(nil, 'a3', 'W', '') + attr.record_location tl1 + attr = cm2.add_attribute RDoc::Attr.new(nil, 'a4', 'W', '') + attr.record_location tl1 + + cm1.merge cm2 + + expected = [ + RDoc::Attr.new(nil, 'a2', 'RW', ''), + RDoc::Attr.new(nil, 'a3', 'W', ''), + RDoc::Attr.new(nil, 'a4', 'W', ''), + ] + + expected.each do |a| a.parent = cm1 end + assert_equal expected, cm1.attributes.sort + end + + def test_merge_attributes_version_0 + tl1 = @store.add_file 'one.rb' + + cm1 = RDoc::ClassModule.new 'Klass' + + attr = cm1.add_attribute RDoc::Attr.new(nil, 'a1', 'RW', '') + attr.record_location tl1 + attr = cm1.add_attribute RDoc::Attr.new(nil, 'a3', 'R', '') + attr.record_location tl1 + attr = cm1.add_attribute RDoc::Attr.new(nil, 'a4', 'R', '') + attr.record_location tl1 + + cm2 = RDoc::ClassModule.new 'Klass' + # TODO allow merging when comment == '' + cm2.instance_variable_set :@comment, @RM::Document.new + + attr = cm2.add_attribute RDoc::Attr.new(nil, 'a2', 'RW', '') + attr = cm2.add_attribute RDoc::Attr.new(nil, 'a3', 'W', '') + attr = cm2.add_attribute RDoc::Attr.new(nil, 'a4', 'W', '') + + cm1.merge cm2 + + expected = [ + RDoc::Attr.new(nil, 'a1', 'RW', ''), + RDoc::Attr.new(nil, 'a2', 'RW', ''), + RDoc::Attr.new(nil, 'a3', 'RW', ''), + RDoc::Attr.new(nil, 'a4', 'RW', ''), + ] + + expected.each do |a| a.parent = cm1 end + assert_equal expected, cm1.attributes.sort + end + + def test_merge_collections_drop + tl = @store.add_file 'file' + + cm1 = RDoc::ClassModule.new 'C' + cm1.record_location tl + + const = cm1.add_constant RDoc::Constant.new('CONST', nil, nil) + const.record_location tl + + cm2 = RDoc::ClassModule.new 'C' + cm2.record_location tl + + added = [] + removed = [] + + cm1.merge_collections cm1.constants, cm2.constants, cm2.in_files do |add, c| + if add then + added << c + else + removed << c + end + end + + assert_empty added + assert_equal [const], removed + end + + def test_merge_comment + tl1 = @store.add_file 'one.rb' + tl2 = @store.add_file 'two.rb' + + cm1 = tl1.add_class RDoc::ClassModule, 'Klass' + cm1.add_comment 'klass 1', tl1 + cm1.record_location tl1 + + cm2 = tl1.add_class RDoc::NormalClass, 'Klass' + cm2.add_comment 'klass 2', tl2 + cm2.add_comment 'klass 3', tl1 + cm2.record_location tl1 + cm2.record_location tl2 + + cm2 = Marshal.load Marshal.dump cm2 + cm2.store = @store + + cm1.merge cm2 + + inner1 = @RM::Document.new @RM::Paragraph.new 'klass 3' + inner1.file = 'one.rb' + inner2 = @RM::Document.new @RM::Paragraph.new 'klass 2' + inner2.file = 'two.rb' + + expected = @RM::Document.new inner2, inner1 + + assert_equal expected, cm1.comment + end + + def test_merge_comment_version_0 + tl = @store.add_file 'file.rb' + + cm1 = RDoc::ClassModule.new 'Klass' + cm1.add_comment 'klass 1', tl + + cm2 = RDoc::ClassModule.new 'Klass' + + cm2.instance_variable_set(:@comment, + @RM::Document.new( + @RM::Paragraph.new('klass 2'))) + cm2.instance_variable_set :@comment_location, @RM::Document.new(cm2.comment) + + cm1.merge cm2 + + inner = @RM::Document.new @RM::Paragraph.new 'klass 1' + inner.file = 'file.rb' + + expected = @RM::Document.new \ + inner, + @RM::Document.new(@RM::Paragraph.new('klass 2')) + + assert_equal expected, cm1.comment + end + + def test_merge_constants + tl1 = @store.add_file 'one.rb' + tl2 = @store.add_file 'two.rb' + + cm1 = tl1.add_class RDoc::ClassModule, 'Klass' + + const = cm1.add_constant RDoc::Constant.new('C1', nil, 'one') + const.record_location tl1 + const = cm1.add_constant RDoc::Constant.new('C3', nil, 'one') + const.record_location tl1 + + store = RDoc::Store.new + tl = store.add_file 'one.rb' + cm2 = tl.add_class RDoc::ClassModule, 'Klass' + cm2.instance_variable_set :@comment, @RM::Document.new + + const = cm2.add_constant RDoc::Constant.new('C2', nil, 'two') + const.record_location tl2 + const = cm2.add_constant RDoc::Constant.new('C3', nil, 'one') + const.record_location tl1 + const = cm2.add_constant RDoc::Constant.new('C4', nil, 'one') + const.record_location tl1 + + cm1.merge cm2 + + expected = [ + RDoc::Constant.new('C2', nil, 'two'), + RDoc::Constant.new('C3', nil, 'one'), + RDoc::Constant.new('C4', nil, 'one'), + ] + + expected.each do |a| a.parent = cm1 end + + assert_equal expected, cm1.constants.sort + end + + def test_merge_constants_version_0 + tl1 = @store.add_file 'one.rb' + + cm1 = tl1.add_class RDoc::ClassModule, 'Klass' + + const = cm1.add_constant RDoc::Constant.new('C1', nil, 'one') + const.record_location tl1 + const = cm1.add_constant RDoc::Constant.new('C3', nil, 'one') + const.record_location tl1 + + store = RDoc::Store.new + tl = store.add_file 'one.rb' + cm2 = tl.add_class RDoc::ClassModule, 'Klass' + cm2.instance_variable_set :@comment, @RM::Document.new + + const = cm2.add_constant RDoc::Constant.new('C2', nil, 'two') + const = cm2.add_constant RDoc::Constant.new('C3', nil, 'two') + const = cm2.add_constant RDoc::Constant.new('C4', nil, 'two') + + cm1.merge cm2 + + expected = [ + RDoc::Constant.new('C1', nil, 'one'), + RDoc::Constant.new('C2', nil, 'two'), + RDoc::Constant.new('C3', nil, 'one'), + RDoc::Constant.new('C4', nil, 'two'), + ] + + expected.each do |a| a.parent = cm1 end + + assert_equal expected, cm1.constants.sort + end + + def test_merge_extends + tl1 = @store.add_file 'one.rb' + cm1 = tl1.add_class RDoc::ClassModule, 'Klass' + + ext = cm1.add_extend RDoc::Extend.new('I1', 'one') + ext.record_location tl1 + ext = cm1.add_extend RDoc::Extend.new('I3', 'one') + ext.record_location tl1 + + tl2 = @store.add_file 'two.rb' + tl2.store = RDoc::Store.new + + cm2 = tl2.add_class RDoc::ClassModule, 'Klass' + cm2.instance_variable_set :@comment, @RM::Document.new + + ext = cm2.add_extend RDoc::Extend.new('I2', 'two') + ext.record_location tl2 + ext = cm2.add_extend RDoc::Extend.new('I3', 'one') + ext.record_location tl1 + ext = cm2.add_extend RDoc::Extend.new('I4', 'one') + ext.record_location tl1 + + cm1.merge cm2 + + expected = [ + RDoc::Extend.new('I2', 'two'), + RDoc::Extend.new('I3', 'one'), + RDoc::Extend.new('I4', 'one'), + ] + + expected.each do |a| a.parent = cm1 end + + assert_equal expected, cm1.extends.sort + end + + def test_merge_includes + tl1 = @store.add_file 'one.rb' + + cm1 = tl1.add_class RDoc::ClassModule, 'Klass' + + incl = cm1.add_include RDoc::Include.new('I1', 'one') + incl.record_location tl1 + incl = cm1.add_include RDoc::Include.new('I3', 'one') + incl.record_location tl1 + + tl2 = @store.add_file 'two.rb' + tl2.store = RDoc::Store.new + + cm2 = tl2.add_class RDoc::ClassModule, 'Klass' + cm2.instance_variable_set :@comment, @RM::Document.new + + incl = cm2.add_include RDoc::Include.new('I2', 'two') + incl.record_location tl2 + incl = cm2.add_include RDoc::Include.new('I3', 'one') + incl.record_location tl1 + incl = cm2.add_include RDoc::Include.new('I4', 'one') + incl.record_location tl1 + + cm1.merge cm2 + + expected = [ + RDoc::Include.new('I2', 'two'), + RDoc::Include.new('I3', 'one'), + RDoc::Include.new('I4', 'one'), + ] + + expected.each do |a| a.parent = cm1 end + + assert_equal expected, cm1.includes.sort + end + + def test_merge_includes_version_0 + tl1 = @store.add_file 'one.rb' + + cm1 = tl1.add_class RDoc::ClassModule, 'Klass' + + incl = cm1.add_include RDoc::Include.new('I1', 'one') + incl.record_location tl1 + incl = cm1.add_include RDoc::Include.new('I3', 'one') + incl.record_location tl1 + + tl2 = @store.add_file 'one.rb' + tl2.store = RDoc::Store.new + + cm2 = tl2.add_class RDoc::ClassModule, 'Klass' + cm2.instance_variable_set :@comment, @RM::Document.new + + incl = cm2.add_include RDoc::Include.new('I2', 'two') + incl = cm2.add_include RDoc::Include.new('I3', 'two') + incl = cm2.add_include RDoc::Include.new('I4', 'two') + + cm1.merge cm2 + + expected = [ + RDoc::Include.new('I1', 'one'), + RDoc::Include.new('I2', 'two'), + RDoc::Include.new('I3', 'one'), + RDoc::Include.new('I4', 'two'), + ] + + expected.each do |a| a.parent = cm1 end + + assert_equal expected, cm1.includes.sort + end + + def test_merge_methods + tl1 = @store.add_file 'one.rb' + tl2 = @store.add_file 'two.rb' + + cm1 = tl1.add_class RDoc::NormalClass, 'Klass' + + meth = cm1.add_method RDoc::AnyMethod.new(nil, 'm1') + meth.record_location tl1 + meth = cm1.add_method RDoc::AnyMethod.new(nil, 'm3') + meth.record_location tl1 + + cm2 = RDoc::ClassModule.new 'Klass' + cm2.store = @store + cm2.instance_variable_set :@comment, @RM::Document.new + + meth = cm2.add_method RDoc::AnyMethod.new(nil, 'm2') + meth.record_location tl2 + meth = cm2.add_method RDoc::AnyMethod.new(nil, 'm3') + meth.record_location tl1 + meth = cm2.add_method RDoc::AnyMethod.new(nil, 'm4') + meth.record_location tl1 + + cm1.merge cm2 + + expected = [ + RDoc::AnyMethod.new(nil, 'm2'), + RDoc::AnyMethod.new(nil, 'm3'), + RDoc::AnyMethod.new(nil, 'm4'), + ] + + expected.each do |a| a.parent = cm1 end + + assert_equal expected, cm1.method_list.sort + end + + def test_merge_methods_version_0 + tl1 = @store.add_file 'one.rb' + + cm1 = tl1.add_class RDoc::NormalClass, 'Klass' + + meth = cm1.add_method RDoc::AnyMethod.new(nil, 'm1') + meth.record_location tl1 + meth = cm1.add_method RDoc::AnyMethod.new(nil, 'm3') + meth.record_location tl1 + + cm2 = RDoc::ClassModule.new 'Klass' + cm2.store = @store + cm2.instance_variable_set :@comment, @RM::Document.new + + meth = cm2.add_method RDoc::AnyMethod.new(nil, 'm2') + meth = cm2.add_method RDoc::AnyMethod.new(nil, 'm3') + meth = cm2.add_method RDoc::AnyMethod.new(nil, 'm4') + + cm1.merge cm2 + + expected = [ + RDoc::AnyMethod.new(nil, 'm1'), + RDoc::AnyMethod.new(nil, 'm2'), + RDoc::AnyMethod.new(nil, 'm3'), + RDoc::AnyMethod.new(nil, 'm4'), + ] + + expected.each do |a| a.parent = cm1 end + + assert_equal expected, cm1.method_list.sort + end + + def test_merge_sections + store1 = @store + + tl1_1 = store1.add_file 'one.rb' + + cm1 = tl1_1.add_class RDoc::ClassModule, 'Klass' + cm1.record_location tl1_1 + + s1_0 = cm1.sections.first + s1_1 = cm1.add_section 'section 1', comment('comment 1', tl1_1) + cm1.add_section 'section 2', comment('comment 2 a', tl1_1) + cm1.add_section 'section 4', comment('comment 4 a', tl1_1) + + store2 = RDoc::Store.new + tl2_1 = store2.add_file 'one.rb' + tl2_2 = store2.add_file 'two.rb' + + cm2 = tl2_1.add_class RDoc::ClassModule, 'Klass' + cm2.record_location tl2_1 + cm2.record_location tl2_2 + + cm2.sections.first + s2_2 = cm2.add_section 'section 2', comment('comment 2 b', tl2_1) + s2_3 = cm2.add_section 'section 3', comment('comment 3', tl2_2) + cm2.add_section 'section 4', comment('comment 4 b', tl2_2) + + cm1.merge cm2 + + expected = [ + s1_0, + s1_1, + s2_2, + s2_3, + RDoc::Context::Section.new(cm1, 'section 4', nil) + ] + + merged_sections = cm1.sections.sort_by do |s| + s.title || '' + end + + assert_equal expected, merged_sections + + assert_equal [comment('comment 2 b', tl2_1)], + cm1.sections_hash['section 2'].comments + + expected_s4_comments = [ + comment('comment 4 a', tl2_1), + comment('comment 4 b', tl2_2), + ] + + assert_equal expected_s4_comments, cm1.sections_hash['section 4'].comments + end + + def test_merge_sections_overlap + store1 = @store + + tl1_1 = store1.add_file 'one.rb' + tl1_3 = store1.add_file 'three.rb' + + cm1 = tl1_1.add_class RDoc::ClassModule, 'Klass' + cm1.record_location tl1_1 + + cm1.add_section 'section', comment('comment 1 a', tl1_1) + cm1.add_section 'section', comment('comment 3', tl1_3) + + store2 = RDoc::Store.new + tl2_1 = store2.add_file 'one.rb' + tl2_2 = store2.add_file 'two.rb' + tl2_3 = store2.add_file 'three.rb' + + cm2 = tl2_1.add_class RDoc::ClassModule, 'Klass' + cm2.record_location tl2_1 + cm2.record_location tl2_2 + + s2_0 = cm2.sections.first + s2_1 = cm2.add_section 'section', comment('comment 1 b', tl1_1) + cm2.add_section 'section', comment('comment 2', tl2_2) + + cm1.merge_sections cm2 + + expected = [ + s2_0, + s2_1, + ] + + merged_sections = cm1.sections.sort_by do |s| + s.title || '' + end + + assert_equal expected, merged_sections + + expected = [ + comment('comment 1 b', tl2_1), + comment('comment 3', tl2_3), + comment('comment 2', tl2_2), + ] + + comments = cm1.sections_hash['section'].comments + + assert_equal expected, comments.sort_by { |c| c.file.name } + end + + def test_parse + tl1 = @store.add_file 'one.rb' + tl2 = @store.add_file 'two.rb' + + cm = RDoc::ClassModule.new 'Klass' + cm.add_comment 'comment 1', tl1 + cm.add_comment 'comment 2', tl2 + + doc1 = @RM::Document.new @RM::Paragraph.new 'comment 1' + doc1.file = tl1 + doc2 = @RM::Document.new @RM::Paragraph.new 'comment 2' + doc2.file = tl2 + + expected = @RM::Document.new doc1, doc2 + + assert_equal expected, cm.parse(cm.comment_location) + end + + def test_parse_comment + tl1 = @store.add_file 'one.rb' + + cm = RDoc::ClassModule.new 'Klass' + cm.comment = comment 'comment 1', tl1 + + doc = @RM::Document.new @RM::Paragraph.new 'comment 1' + doc.file = tl1 + + assert_equal doc, cm.parse(cm.comment) + end + + def test_parse_comment_format + tl1 = @store.add_file 'one.rb' + + cm = RDoc::ClassModule.new 'Klass' + cm.comment = comment 'comment ((*1*))', tl1 + cm.comment.format = 'rd' + + doc = @RM::Document.new @RM::Paragraph.new 'comment <em>1</em>' + doc.file = tl1 + + assert_equal doc, cm.parse(cm.comment) + end + + def test_parse_comment_location + tl1 = @store.add_file 'one.rb' + tl2 = @store.add_file 'two.rb' + + cm = tl1.add_class RDoc::NormalClass, 'Klass' + cm.add_comment 'comment 1', tl1 + cm.add_comment 'comment 2', tl2 + + cm = Marshal.load Marshal.dump cm + + doc1 = @RM::Document.new @RM::Paragraph.new 'comment 1' + doc1.file = tl1 + doc2 = @RM::Document.new @RM::Paragraph.new 'comment 2' + doc2.file = tl2 + + assert_same cm.comment_location, cm.parse(cm.comment_location) + end + + def test_remove_nodoc_children + parent = @top_level.add_class RDoc::ClassModule, 'A' + parent.modules_hash.replace 'B' => true, 'C' => true + @store.modules_hash.replace 'A::B' => true + + parent.classes_hash.replace 'D' => true, 'E' => true + @store.classes_hash.replace 'A::D' => true + + parent.remove_nodoc_children + + assert_equal %w[B], parent.modules_hash.keys + assert_equal %w[D], parent.classes_hash.keys + end + + def test_search_record + @c2_c3.add_comment 'This is a comment.', @xref_data + + expected = [ + 'C3', + 'C2::C3', + 'C2::C3', + '', + 'C2/C3.html', + '', + "<p>This is a comment.\n" + ] + + assert_equal expected, @c2_c3.search_record + end + + def test_search_record_merged + @c2_c3.add_comment 'comment A', @store.add_file('a.rb') + @c2_c3.add_comment 'comment B', @store.add_file('b.rb') + + expected = [ + 'C3', + 'C2::C3', + 'C2::C3', + '', + 'C2/C3.html', + '', + "<p>comment A\n<p>comment B\n" + ] + + assert_equal expected, @c2_c3.search_record + end + + def test_store_equals + # version 2 + loaded = Marshal.load "\x04\bU:\x16RDoc::NormalClass[\x0Fi\aI\"\nKlass" + + "\x06:\x06EFI\"\x15Namespace::Klass\x06;\x06FI" + + "\"\nSuper\x06;\x06Fo:\eRDoc::Markup::Document\a" + + ":\v@parts[\x06o;\a\a;\b[\x06o" + + ":\x1CRDoc::Markup::Paragraph\x06;\b" + + "[\x06I\"\x16this is a comment\x06;\x06F" + + ":\n@fileI\"\ffile.rb\x06;\x06F;\n0[\a[\nI" + + "\"\aa2\x06;\x06FI\"\aRW\x06;\x06F:\vpublicT@\x11" + + "[\nI\"\aa1\x06;\x06FI\"\aRW\x06;\x06F;\vF@\x11" + + "[\x06[\bI\"\aC1\x06;\x06Fo;\a\a;\b[\x00;\n0@\x11" + + "[\x06[\bI\"\aI1\x06;\x06Fo;\a\a;\b[\x00;\n0@\x11" + + "[\a[\aI\"\nclass\x06;\x06F[\b[\a;\v[\x00" + + "[\a:\x0Eprotected[\x00[\a:\fprivate[\x00[\aI" + + "\"\rinstance\x06;\x06F[\b[\a;\v[\x06[\aI" + + "\"\am1\x06;\x06F@\x11[\a;\f[\x00[\a;\r[\x00" + + "[\x06[\bI\"\aE1\x06;\x06Fo;\a\a;\b[\x00;\n0@\x11" + + loaded.store = @store + + assert_same @store, loaded.store + + a = loaded.attributes.first + assert_same @store, a.store + assert_same @store, a.file.store + + c = loaded.constants.first + assert_same @store, c.store + assert_same @store, c.file.store + + i = loaded.includes.first + assert_same @store, i.store + assert_same @store, i.file.store + + e = loaded.extends.first + assert_same @store, e.store + assert_same @store, e.file.store + + m = loaded.method_list.first + assert_same @store, m.store + assert_same @store, m.file.store + end + + def test_superclass + assert_equal @c3_h1, @c3_h2.superclass + end + + def test_update_aliases_class + n1 = @xref_data.add_module RDoc::NormalClass, 'N1' + n1_k2 = n1.add_module RDoc::NormalClass, 'N2' + + n1.add_module_alias n1_k2, 'A1', @xref_data + + n1_a1_c = n1.constants.find { |c| c.name == 'A1' } + refute_nil n1_a1_c + assert_equal n1_k2, n1_a1_c.is_alias_for, 'sanity check' + + n1.update_aliases + + n1_a1_k = @xref_data.find_class_or_module 'N1::A1' + refute_nil n1_a1_k + assert_equal n1_k2, n1_a1_k.is_alias_for + refute_equal n1_k2, n1_a1_k + + assert_equal 1, n1_k2.aliases.length + assert_equal n1_a1_k, n1_k2.aliases.first + + assert_equal 'N1::N2', n1_k2.full_name + assert_equal 'N1::A1', n1_a1_k.full_name + end + + def test_update_aliases_module + n1 = @xref_data.add_module RDoc::NormalModule, 'N1' + n1_n2 = n1.add_module RDoc::NormalModule, 'N2' + + n1.add_module_alias n1_n2, 'A1', @xref_data + + n1_a1_c = n1.constants.find { |c| c.name == 'A1' } + refute_nil n1_a1_c + assert_equal n1_n2, n1_a1_c.is_alias_for, 'sanity check' + + n1.update_aliases + + n1_a1_m = @xref_data.find_class_or_module 'N1::A1' + refute_nil n1_a1_m + assert_equal n1_n2, n1_a1_m.is_alias_for + refute_equal n1_n2, n1_a1_m + + assert_equal 1, n1_n2.aliases.length + assert_equal n1_a1_m, n1_n2.aliases.first + + assert_equal 'N1::N2', n1_n2.full_name + assert_equal 'N1::A1', n1_a1_m.full_name + end + + def test_update_aliases_reparent + l1 = @xref_data.add_module RDoc::NormalModule, 'L1' + l1_l2 = l1.add_module RDoc::NormalModule, 'L2' + o1 = @xref_data.add_module RDoc::NormalModule, 'O1' + + o1.add_module_alias l1_l2, 'A1', @xref_data + + o1_a1_c = o1.constants.find { |c| c.name == 'A1' } + refute_nil o1_a1_c + assert_equal l1_l2, o1_a1_c.is_alias_for + refute_equal l1_l2, o1_a1_c + + o1.update_aliases + + o1_a1_m = @xref_data.find_class_or_module 'O1::A1' + refute_nil o1_a1_m + assert_equal l1_l2, o1_a1_m.is_alias_for + + assert_equal 1, l1_l2.aliases.length + assert_equal o1_a1_m, l1_l2.aliases[0] + + assert_equal 'L1::L2', l1_l2.full_name + assert_equal 'O1::A1', o1_a1_m.full_name + end + + def test_update_aliases_reparent_root + store = RDoc::Store.new + + top_level = store.add_file 'file.rb' + + klass = top_level.add_class RDoc::NormalClass, 'Klass' + object = top_level.add_class RDoc::NormalClass, 'Object' + + const = RDoc::Constant.new 'A', nil, '' + const.record_location top_level + const.is_alias_for = klass + + top_level.add_module_alias klass, 'A', top_level + + object.add_constant const + + object.update_aliases + + assert_equal %w[A Klass Object], store.classes_hash.keys.sort + + assert_equal 'A', store.classes_hash['A'].full_name + assert_equal 'Klass', store.classes_hash['Klass'].full_name + end + + def test_update_includes + a = RDoc::Include.new 'M1', nil + b = RDoc::Include.new 'M2', nil + c = RDoc::Include.new 'C', nil + + @c1.add_include a + @c1.add_include b + @c1.add_include c + @c1.ancestors # cache included modules + + @m1_m2.document_self = nil + assert @m1_m2.remove_from_documentation? + + assert @store.modules_hash.key? @m1_m2.full_name + refute @store.modules_hash[@m1_m2.full_name].nil? + + @store.remove_nodoc @store.modules_hash + refute @store.modules_hash.key? @m1_m2.full_name + + @c1.update_includes + + assert_equal [a, c], @c1.includes + end + + def test_update_includes_trim + a = RDoc::Include.new 'D::M', nil + b = RDoc::Include.new 'D::M', nil + + @c1.add_include a + @c1.add_include b + @c1.ancestors # cache included modules + + @c1.update_includes + + assert_equal [a], @c1.includes + end + + def test_update_includes_with_colons + a = RDoc::Include.new 'M1', nil + b = RDoc::Include.new 'M1::M2', nil + c = RDoc::Include.new 'C', nil + + @c1.add_include a + @c1.add_include b + @c1.add_include c + @c1.ancestors # cache included modules + + @m1_m2.document_self = nil + assert @m1_m2.remove_from_documentation? + + assert @store.modules_hash.key? @m1_m2.full_name + refute @store.modules_hash[@m1_m2.full_name].nil? + @store.remove_nodoc @store.modules_hash + refute @store.modules_hash.key? @m1_m2.full_name + + @c1.update_includes + + assert_equal [a, c], @c1.includes + end + + def test_update_extends + a = RDoc::Extend.new 'M1', nil + b = RDoc::Extend.new 'M2', nil + c = RDoc::Extend.new 'C', nil + + @c1.add_extend a + @c1.add_extend b + @c1.add_extend c + @c1.each_extend do |extend| extend.module end # cache extended modules + + @m1_m2.document_self = nil + assert @m1_m2.remove_from_documentation? + + assert @store.modules_hash.key? @m1_m2.full_name + refute @store.modules_hash[@m1_m2.full_name].nil? + @store.remove_nodoc @store.modules_hash + refute @store.modules_hash.key? @m1_m2.full_name + + @c1.update_extends + + assert_equal [a, b, c], @c1.extends + end + + def test_update_extends_trim + a = RDoc::Extend.new 'D::M', nil + b = RDoc::Extend.new 'D::M', nil + + @c1.add_extend a + @c1.add_extend b + @c1.each_extend do |extend| extend.module end # cache extended modules + + @c1.update_extends + + assert_equal [a], @c1.extends + end + + def test_update_extends_with_colons + a = RDoc::Extend.new 'M1', nil + b = RDoc::Extend.new 'M1::M2', nil + c = RDoc::Extend.new 'C', nil + + @c1.add_extend a + @c1.add_extend b + @c1.add_extend c + @c1.each_extend do |extend| extend.module end # cache extended modules + + @m1_m2.document_self = nil + assert @m1_m2.remove_from_documentation? + + assert @store.modules_hash.key? @m1_m2.full_name + refute @store.modules_hash[@m1_m2.full_name].nil? + + @store.remove_nodoc @store.modules_hash + refute @store.modules_hash.key? @m1_m2.full_name + + @c1.update_extends + + assert_equal [a, c], @c1.extends + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_code_object.rb b/jni/ruby/test/rdoc/test_rdoc_code_object.rb new file mode 100644 index 0000000..2fb6ac2 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_code_object.rb @@ -0,0 +1,450 @@ +# coding: US-ASCII + +require File.expand_path '../xref_test_case', __FILE__ + +class TestRDocCodeObject < XrefTestCase + + def setup + super + + @co = RDoc::CodeObject.new + end + + def test_initialize + assert @co.document_self, 'document_self' + assert @co.document_children, 'document_children' + refute @co.force_documentation, 'force_documentation' + refute @co.done_documenting, 'done_documenting' + refute @co.received_nodoc, 'received_nodoc' + assert_equal '', @co.comment, 'comment is empty' + end + + def test_comment_equals + @co.comment = '' + + assert_equal '', @co.comment + + @co.comment = 'I am a comment' + + assert_equal 'I am a comment', @co.comment + end + + def test_comment_equals_comment + @co.comment = comment '' + + assert_equal '', @co.comment.text + + @co.comment = comment 'I am a comment' + + assert_equal 'I am a comment', @co.comment.text + end + + def test_comment_equals_document + doc = RDoc::Markup::Document.new + @co.comment = doc + + @co.comment = '' + + assert_equal doc, @co.comment + end + + def test_comment_equals_encoding + skip "Encoding not implemented" unless Object.const_defined? :Encoding + + refute_equal Encoding::UTF_8, ''.encoding, 'Encoding sanity check' + + input = 'text' + input.force_encoding Encoding::UTF_8 + + @co.comment = input + + assert_equal 'text', @co.comment + assert_equal Encoding::UTF_8, @co.comment.encoding + end + + def test_comment_equals_encoding_blank + skip "Encoding not implemented" unless Object.const_defined? :Encoding + + refute_equal Encoding::UTF_8, ''.encoding, 'Encoding sanity check' + + input = '' + input.force_encoding Encoding::UTF_8 + + @co.comment = input + + assert_equal '', @co.comment + assert_equal Encoding::UTF_8, @co.comment.encoding + end + + def test_display_eh_document_self + assert @co.display? + + @co.document_self = false + + refute @co.display? + end + + def test_display_eh_ignore + assert @co.display? + + @co.ignore + + refute @co.display? + + @co.stop_doc + + refute @co.display? + + @co.done_documenting = false + + refute @co.display? + end + + def test_display_eh_suppress + assert @co.display? + + @co.suppress + + refute @co.display? + + @co.comment = comment('hi') + + refute @co.display? + + @co.done_documenting = false + + assert @co.display? + + @co.ignore + @co.done_documenting = false + + refute @co.display? + end + + def test_document_children_equals + @co.document_children = false + + refute @co.document_children + + @store.rdoc.options.visibility = :nodoc + + @co.store = @store + + assert @co.document_children + + @co.document_children = false + + assert @co.document_children + end + + def test_document_self_equals + @co.document_self = false + refute @co.document_self + + @store.rdoc.options.visibility = :nodoc + + @co.store = @store + + assert @co.document_self + + @co.document_self = false + + assert @co.document_self + end + + def test_documented_eh + refute @co.documented? + + @co.comment = 'hi' + + assert @co.documented? + + @co.comment.replace '' + + refute @co.documented? + + @co.document_self = nil # notify :nodoc: + + assert @co.documented? + end + + def test_done_documenting + # once done_documenting is set, other properties refuse to go to "true" + @co.done_documenting = true + + @co.document_self = true + refute @co.document_self + + @co.document_children = true + refute @co.document_children + + @co.force_documentation = true + refute @co.force_documentation + + @co.start_doc + refute @co.document_self + refute @co.document_children + + # turning done_documenting on + # resets others to true + + @co.done_documenting = false + assert @co.document_self + assert @co.document_children + + @co.done_documenting = true + + @store.rdoc.options.visibility = :nodoc + + @co.store = @store + + refute @co.done_documenting + + @co.done_documenting = true + + refute @co.done_documenting + end + + def test_each_parent + parents = [] + + @parent_m.each_parent do |code_object| + parents << code_object + end + + assert_equal [@parent, @xref_data], parents + end + + def test_file_name + assert_equal nil, @co.file_name + + @co.record_location @store.add_file 'lib/file.rb' + + assert_equal 'lib/file.rb', @co.file_name + end + + def test_full_name_equals + @co.full_name = 'hi' + + assert_equal 'hi', @co.instance_variable_get(:@full_name) + + @co.full_name = nil + + assert_nil @co.instance_variable_get(:@full_name) + end + + def test_ignore + @co.ignore + + refute @co.document_self + refute @co.document_children + assert @co.ignored? + + @store.rdoc.options.visibility = :nodoc + + @co.store = @store + + assert @co.document_self + assert @co.document_children + refute @co.ignored? + + @co.ignore + + refute @co.ignored? + end + + def test_ignore_eh + refute @co.ignored? + + @co.ignore + + assert @co.ignored? + end + + def test_line + @c1_m.line = 5 + + assert_equal 5, @c1_m.line + end + + def test_metadata + assert_empty @co.metadata + + @co.metadata['markup'] = 'not_rdoc' + + expected = { 'markup' => 'not_rdoc' } + + assert_equal expected, @co.metadata + + assert_equal 'not_rdoc', @co.metadata['markup'] + end + + def test_offset + @c1_m.offset = 5 + + assert_equal 5, @c1_m.offset + end + + def test_options + assert_kind_of RDoc::Options, @co.options + + @co.store = @store + + assert_same @options, @co.options + end + + def test_parent_file_name + assert_equal '(unknown)', @co.parent_file_name + assert_equal 'xref_data.rb', @c1.parent_file_name + end + + def test_parent_name + assert_equal '(unknown)', @co.parent_name + assert_equal 'xref_data.rb', @c1.parent_name + assert_equal 'C2', @c2_c3.parent_name + end + + def test_received_ndoc + @co.document_self = false + refute @co.received_nodoc + + @co.document_self = nil + assert @co.received_nodoc + + @co.document_self = true + end + + def test_record_location + @co.record_location @xref_data + + assert_equal 'xref_data.rb', @co.file.relative_name + end + + def test_record_location_ignored + @co.ignore + @co.record_location @xref_data + + refute @co.ignored? + end + + def test_record_location_suppressed + @co.suppress + @co.record_location @xref_data + + refute @co.suppressed? + end + + def test_section + parent = RDoc::Context.new + section = parent.sections.first + + @co.parent = parent + @co.instance_variable_set :@section, section + + assert_equal section, @co.section + + @co.instance_variable_set :@section, nil + @co.instance_variable_set :@section_title, nil + + assert_equal section, @co.section + + @co.instance_variable_set :@section, nil + @co.instance_variable_set :@section_title, 'new title' + + assert_equal 'new title', @co.section.title + end + + def test_start_doc + @co.document_self = false + @co.document_children = false + + @co.start_doc + + assert @co.document_self + assert @co.document_children + end + + def test_start_doc_ignored + @co.ignore + + @co.start_doc + + assert @co.document_self + assert @co.document_children + refute @co.ignored? + end + + def test_start_doc_suppressed + @co.suppress + + @co.start_doc + + assert @co.document_self + assert @co.document_children + refute @co.suppressed? + end + + def test_store_equals + @co.document_self = false + + @co.store = @store + + refute @co.document_self + + @store.rdoc.options.visibility = :nodoc + + @co.store = @store + + assert @co.document_self + end + + def test_stop_doc + @co.document_self = true + @co.document_children = true + + @co.stop_doc + + refute @co.document_self + refute @co.document_children + + @store.rdoc.options.visibility = :nodoc + + @co.store = @store + + assert @co.document_self + assert @co.document_children + + @co.stop_doc + + assert @co.document_self + assert @co.document_children + end + + def test_suppress + @co.suppress + + refute @co.document_self + refute @co.document_children + assert @co.suppressed? + + @store.rdoc.options.visibility = :nodoc + + @co.store = @store + + refute @co.suppressed? + + @co.suppress + + refute @co.suppressed? + end + + def test_suppress_eh + refute @co.suppressed? + + @co.suppress + + assert @co.suppressed? + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_comment.rb b/jni/ruby/test/rdoc/test_rdoc_comment.rb new file mode 100644 index 0000000..2a1318b --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_comment.rb @@ -0,0 +1,504 @@ +# coding: us-ascii + +require 'rdoc/test_case' + +class TestRDocComment < RDoc::TestCase + + def setup + super + + @top_level = @store.add_file 'file.rb' + @comment = RDoc::Comment.new + @comment.location = @top_level + @comment.text = 'this is a comment' + end + + def test_empty_eh + refute_empty @comment + + @comment = '' + + assert_empty @comment + end + + def test_equals2 + assert_equal @comment, @comment.dup + + c2 = @comment.dup + c2.text = nil + + refute_equal @comment, c2 + + c3 = @comment.dup + c3.location = nil + + refute_equal @comment, c3 + end + + def test_extract_call_seq + m = RDoc::AnyMethod.new nil, 'm' + + comment = RDoc::Comment.new <<-COMMENT, @top_level +call-seq: + bla => true or false + +moar comment + COMMENT + + comment.extract_call_seq m + + assert_equal "bla => true or false\n", m.call_seq + end + + def test_extract_call_seq_blank + m = RDoc::AnyMethod.new nil, 'm' + + comment = RDoc::Comment.new <<-COMMENT, @top_level +call-seq: + bla => true or false + + COMMENT + + comment.extract_call_seq m + + assert_equal "bla => true or false\n", m.call_seq + end + + def test_extract_call_seq_commented + m = RDoc::AnyMethod.new nil, 'm' + + comment = RDoc::Comment.new <<-COMMENT, @top_level +# call-seq: +# bla => true or false +# +# moar comment + COMMENT + + comment.extract_call_seq m + + assert_equal nil, m.call_seq + end + + def test_extract_call_seq_no_blank + m = RDoc::AnyMethod.new nil, 'm' + + comment = RDoc::Comment.new <<-COMMENT, @top_level +call-seq: + bla => true or false + COMMENT + + comment.extract_call_seq m + + assert_equal "bla => true or false\n", m.call_seq + end + + def test_extract_call_seq_undent + m = RDoc::AnyMethod.new nil, 'm' + + comment = RDoc::Comment.new <<-COMMENT, @top_level +call-seq: + bla => true or false +moar comment + COMMENT + + comment.extract_call_seq m + + assert_equal "bla => true or false\nmoar comment\n", m.call_seq + end + + def test_extract_call_seq_c + comment = RDoc::Comment.new <<-COMMENT +call-seq: + commercial() -> Date <br /> + commercial(cwyear, cweek=41, cwday=5, sg=nil) -> Date [ruby 1.8] <br /> + commercial(cwyear, cweek=1, cwday=1, sg=nil) -> Date [ruby 1.9] + +If no arguments are given: +* ruby 1.8: returns a +Date+ for 1582-10-15 (the Day of Calendar Reform in + Italy) +* ruby 1.9: returns a +Date+ for julian day 0 + +Otherwise, returns a +Date+ for the commercial week year, commercial week, +and commercial week day given. Ignores the 4th argument. + COMMENT + + method_obj = RDoc::AnyMethod.new nil, 'blah' + + comment.extract_call_seq method_obj + + expected = <<-CALL_SEQ.chomp +commercial() -> Date <br /> +commercial(cwyear, cweek=41, cwday=5, sg=nil) -> Date [ruby 1.8] <br /> +commercial(cwyear, cweek=1, cwday=1, sg=nil) -> Date [ruby 1.9] + + CALL_SEQ + + assert_equal expected, method_obj.call_seq + end + + def test_extract_call_seq_c_no_blank + comment = RDoc::Comment.new <<-COMMENT +call-seq: + commercial() -> Date <br /> + commercial(cwyear, cweek=41, cwday=5, sg=nil) -> Date [ruby 1.8] <br /> + commercial(cwyear, cweek=1, cwday=1, sg=nil) -> Date [ruby 1.9] + COMMENT + + method_obj = RDoc::AnyMethod.new nil, 'blah' + + comment.extract_call_seq method_obj + + expected = <<-CALL_SEQ.chomp +commercial() -> Date <br /> +commercial(cwyear, cweek=41, cwday=5, sg=nil) -> Date [ruby 1.8] <br /> +commercial(cwyear, cweek=1, cwday=1, sg=nil) -> Date [ruby 1.9] + + CALL_SEQ + + assert_equal expected, method_obj.call_seq + end + + def test_extract_call_seq_c_separator + comment = RDoc::Comment.new <<-'COMMENT' +call-seq: + ARGF.readlines(sep=$/) -> array + ARGF.readlines(limit) -> array + ARGF.readlines(sep, limit) -> array + + ARGF.to_a(sep=$/) -> array + ARGF.to_a(limit) -> array + ARGF.to_a(sep, limit) -> array + +Reads +ARGF+'s current file in its entirety, returning an +Array+ of its +lines, one line per element. Lines are assumed to be separated by _sep_. + + lines = ARGF.readlines + lines[0] #=> "This is line one\n" + + COMMENT + + method_obj = RDoc::AnyMethod.new nil, 'blah' + + comment.extract_call_seq method_obj + + expected = <<-CALL_SEQ +ARGF.readlines(sep=$/) -> array +ARGF.readlines(limit) -> array +ARGF.readlines(sep, limit) -> array +ARGF.to_a(sep=$/) -> array +ARGF.to_a(limit) -> array +ARGF.to_a(sep, limit) -> array + CALL_SEQ + + assert_equal expected, method_obj.call_seq + + expected = <<-'COMMENT' + +Reads +ARGF+'s current file in its entirety, returning an +Array+ of its +lines, one line per element. Lines are assumed to be separated by _sep_. + + lines = ARGF.readlines + lines[0] #=> "This is line one\n" + + COMMENT + + assert_equal expected, comment.text + end + + def test_force_encoding + skip "Encoding not implemented" unless Object.const_defined? :Encoding + + @comment.force_encoding Encoding::UTF_8 + + assert_equal Encoding::UTF_8, @comment.text.encoding + end + + def test_format + assert_equal 'rdoc', @comment.format + end + + def test_format_equals + c = comment 'content' + document = c.parse + + c.format = RDoc::RD + + assert_equal RDoc::RD, c.format + refute_same document, c.parse + end + + def test_initialize_copy + copy = @comment.dup + + refute_same @comment.text, copy.text + assert_same @comment.location, copy.location + end + + def test_location + assert_equal @top_level, @comment.location + end + + def test_normalize + @comment.text = <<-TEXT + # comment + TEXT + + assert_same @comment, @comment.normalize + + assert_equal 'comment', @comment.text + end + + def test_normalize_twice + @comment.text = <<-TEXT + # comment + TEXT + + @comment.normalize + + text = @comment.text + + @comment.normalize + + assert_same text, @comment.text, 'normalize not cached' + end + + def test_normalize_document + @comment.text = nil + @comment.document = @RM::Document.new + + assert_same @comment, @comment.normalize + + assert_nil @comment.text + end + + def test_normalize_eh + refute @comment.normalized? + + @comment.normalize + + assert @comment.normalized? + end + + def test_text + assert_equal 'this is a comment', @comment.text + end + + def test_text_equals + @comment.text = 'other' + + assert_equal 'other', @comment.text + refute @comment.normalized? + end + + def test_text_equals_no_text + c = RDoc::Comment.new nil, @top_level + c.document = @RM::Document.new + + e = assert_raises RDoc::Error do + c.text = 'other' + end + + assert_equal 'replacing document-only comment is not allowed', e.message + end + + def test_text_equals_parsed + document = @comment.parse + + @comment.text = 'other' + + refute_equal document, @comment.parse + end + + def test_tomdoc_eh + refute @comment.tomdoc? + + @comment.format = 'tomdoc' + + assert @comment.tomdoc? + end + + def test_parse + parsed = @comment.parse + + expected = @RM::Document.new( + @RM::Paragraph.new('this is a comment')) + + expected.file = @top_level + + assert_equal expected, parsed + assert_same parsed, @comment.parse + end + + def test_parse_rd + c = comment 'it ((*works*))' + c.format = 'rd' + + expected = + @RM::Document.new( + @RM::Paragraph.new('it <em>works</em>')) + expected.file = @top_level + + assert_equal expected, c.parse + end + + def test_remove_private_encoding + skip "Encoding not implemented" unless Object.const_defined? :Encoding + + comment = RDoc::Comment.new <<-EOS, @top_level +# This is text +#-- +# this is private + EOS + + comment.force_encoding Encoding::IBM437 + + comment.remove_private + + assert_equal Encoding::IBM437, comment.text.encoding + end + + def test_remove_private_hash + @comment.text = <<-TEXT +#-- +# private +#++ +# public + TEXT + + @comment.remove_private + + assert_equal "# public\n", @comment.text + end + + def test_remove_private_hash_trail + comment = RDoc::Comment.new <<-EOS, @top_level +# This is text +#-- +# this is private + EOS + + expected = RDoc::Comment.new <<-EOS, @top_level +# This is text + EOS + + comment.remove_private + + assert_equal expected, comment + end + + def test_remove_private_long + comment = RDoc::Comment.new <<-EOS, @top_level +#----- +#++ +# this is text +#----- + EOS + + expected = RDoc::Comment.new <<-EOS, @top_level +# this is text + EOS + + comment.remove_private + + assert_equal expected, comment + end + + def test_remove_private_rule + comment = RDoc::Comment.new <<-EOS, @top_level +# This is text with a rule: +# --- +# this is also text + EOS + + expected = comment.dup + + comment.remove_private + + assert_equal expected, comment + end + + def test_remove_private_star + @comment.text = <<-TEXT +/* + *-- + * private + *++ + * public + */ + TEXT + + @comment.remove_private + + assert_equal "/*\n * public\n */\n", @comment.text + end + + def test_remove_private_star2 + @comment.text = <<-TEXT +/*-- + * private + *++ + * public + */ + TEXT + + @comment.remove_private + + assert_equal "/*--\n * private\n *++\n * public\n */\n", @comment.text + end + + def test_remove_private_toggle + comment = RDoc::Comment.new <<-EOS, @top_level +# This is text +#-- +# this is private +#++ +# This is text again. + EOS + + expected = RDoc::Comment.new <<-EOS, @top_level +# This is text +# This is text again. + EOS + + comment.remove_private + + assert_equal expected, comment + end + + def test_remove_private_toggle_encoding + skip "Encoding not implemented" unless Object.const_defined? :Encoding + + comment = RDoc::Comment.new <<-EOS, @top_level +# This is text +#-- +# this is private +#++ +# This is text again. + EOS + + comment.force_encoding Encoding::IBM437 + + comment.remove_private + + assert_equal Encoding::IBM437, comment.text.encoding + end + + def test_remove_private_toggle_encoding_ruby_bug? + skip "Encoding not implemented" unless Object.const_defined? :Encoding + + comment = RDoc::Comment.new <<-EOS, @top_level +#-- +# this is private +#++ +# This is text again. + EOS + + comment.force_encoding Encoding::IBM437 + + comment.remove_private + + assert_equal Encoding::IBM437, comment.text.encoding + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_constant.rb b/jni/ruby/test/rdoc/test_rdoc_constant.rb new file mode 100644 index 0000000..171963d --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_constant.rb @@ -0,0 +1,181 @@ +require File.expand_path '../xref_test_case', __FILE__ + +class TestRDocConstant < XrefTestCase + + def setup + super + + @const = @c1.constants.first + end + + def test_documented_eh + top_level = @store.add_file 'file.rb' + + const = RDoc::Constant.new 'CONST', nil, nil + top_level.add_constant const + + refute const.documented? + + const.comment = comment 'comment' + + assert const.documented? + end + + def test_documented_eh_alias + top_level = @store.add_file 'file.rb' + + const = RDoc::Constant.new 'CONST', nil, nil + top_level.add_constant const + + refute const.documented? + + const.is_alias_for = 'C1' + + refute const.documented? + + @c1.add_comment comment('comment'), @top_level + + assert const.documented? + end + + def test_full_name + assert_equal 'C1::CONST', @const.full_name + end + + def test_is_alias_for + top_level = @store.add_file 'file.rb' + + c = RDoc::Constant.new 'CONST', nil, 'comment' + top_level.add_constant c + + assert_nil c.is_alias_for + + c.is_alias_for = 'C1' + + assert_equal @c1, c.is_alias_for + + c.is_alias_for = 'unknown' + + assert_equal 'unknown', c.is_alias_for + end + + def test_marshal_dump + top_level = @store.add_file 'file.rb' + + c = RDoc::Constant.new 'CONST', nil, 'this is a comment' + c.record_location top_level + + aliased = top_level.add_class RDoc::NormalClass, 'Aliased' + c.is_alias_for = aliased + + cm = top_level.add_class RDoc::NormalClass, 'Klass' + cm.add_constant c + + section = cm.sections.first + + loaded = Marshal.load Marshal.dump c + loaded.store = @store + + comment = doc(para('this is a comment')) + + assert_equal c, loaded + + assert_equal aliased, loaded.is_alias_for + assert_equal comment, loaded.comment + assert_equal top_level, loaded.file + assert_equal 'Klass::CONST', loaded.full_name + assert_equal 'CONST', loaded.name + assert_nil loaded.visibility + assert_equal cm, loaded.parent + assert_equal section, loaded.section + end + + def test_marshal_load + top_level = @store.add_file 'file.rb' + + c = RDoc::Constant.new 'CONST', nil, 'this is a comment' + c.record_location top_level + + cm = top_level.add_class RDoc::NormalClass, 'Klass' + cm.add_constant c + + section = cm.sections.first + + loaded = Marshal.load Marshal.dump c + loaded.store = @store + + comment = doc(para('this is a comment')) + + assert_equal c, loaded + + assert_nil loaded.is_alias_for + assert_equal comment, loaded.comment + assert_equal top_level, loaded.file + assert_equal 'Klass::CONST', loaded.full_name + assert_equal 'CONST', loaded.name + assert_nil loaded.visibility + assert_equal cm, loaded.parent + assert_equal section, loaded.section + + assert loaded.display? + end + + def test_marshal_load_version_0 + top_level = @store.add_file 'file.rb' + + aliased = top_level.add_class RDoc::NormalClass, 'Aliased' + cm = top_level.add_class RDoc::NormalClass, 'Klass' + section = cm.sections.first + + loaded = Marshal.load "\x04\bU:\x13RDoc::Constant[\x0Fi\x00I" + + "\"\nCONST\x06:\x06ETI\"\x11Klass::CONST\x06" + + ";\x06T0I\"\fAliased\x06;\x06To" + + ":\eRDoc::Markup::Document\a:\v@parts[\x06o" + + ":\x1CRDoc::Markup::Paragraph\x06;\b[\x06I" + + "\"\x16this is a comment\x06;\x06T:\n@file0I" + + "\"\ffile.rb\x06;\x06TI\"\nKlass\x06" + + ";\x06Tc\x16RDoc::NormalClass0" + + loaded.store = @store + + comment = doc(para('this is a comment')) + + assert_equal aliased, loaded.is_alias_for + assert_equal comment, loaded.comment + assert_equal top_level, loaded.file + assert_equal 'Klass::CONST', loaded.full_name + assert_equal 'CONST', loaded.name + assert_nil loaded.visibility + assert_equal cm, loaded.parent + assert_equal section, loaded.section + + assert loaded.display? + end + + def test_marshal_round_trip + top_level = @store.add_file 'file.rb' + + c = RDoc::Constant.new 'CONST', nil, 'this is a comment' + c.record_location top_level + c.is_alias_for = 'Unknown' + + cm = top_level.add_class RDoc::NormalClass, 'Klass' + cm.add_constant c + + section = cm.sections.first + + loaded = Marshal.load Marshal.dump c + loaded.store = @store + + reloaded = Marshal.load Marshal.dump loaded + reloaded.store = @store + + assert_equal section, reloaded.section + assert_equal 'Unknown', reloaded.is_alias_for + end + + def test_path + assert_equal 'C1.html#CONST', @const.path + end + +end diff --git a/jni/ruby/test/rdoc/test_rdoc_context.rb b/jni/ruby/test/rdoc/test_rdoc_context.rb new file mode 100644 index 0000000..c981cf3 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_context.rb @@ -0,0 +1,901 @@ +require File.expand_path '../xref_test_case', __FILE__ + +class TestRDocContext < XrefTestCase + + def setup + super + + @context = RDoc::Context.new + @context.store = @store + + @enumerator = # 1.8 vs 1.9 + Object.const_defined?(:Enumerator) ? Enumerator : Enumerable::Enumerator + end + + def test_initialize + assert_empty @context.in_files + assert_equal 'unknown', @context.name + assert_equal '', @context.comment + assert_equal nil, @context.parent + assert_equal :public, @context.visibility + assert_equal 1, @context.sections.length + assert_equal nil, @context.temporary_section + + assert_empty @context.classes_hash + assert_empty @context.modules_hash + + assert_empty @context.method_list + assert_empty @context.attributes + assert_empty @context.aliases + assert_empty @context.requires + assert_empty @context.includes + assert_empty @context.constants + end + + def test_add_alias + as = RDoc::Alias.new nil, 'old_name', 'new_name', 'comment' + + @context.add_alias as + + assert_equal [as], @context.external_aliases + assert_equal [as], @context.unmatched_alias_lists['#old_name'] + end + + def test_add + @context.add RDoc::Extend, 'Ext', 'comment' + @context.add RDoc::Include, 'Incl', 'comment' + + refute_empty @context.extends + refute_empty @context.includes + end + + def test_add_alias_method_attr + top_level = @store.add_file 'file.rb' + + attr = RDoc::Attr.new nil, 'old_name', 'R', '' + + as = RDoc::Alias.new nil, 'old_name', 'new_name', 'comment' + as.record_location top_level + as.parent = @context + + @context.add_attribute attr + @context.add_alias as + + assert_empty @context.aliases + assert_empty @context.unmatched_alias_lists + assert_equal %w[old_name new_name], @context.attributes.map { |m| m.name } + + new = @context.attributes.last + assert_equal top_level, new.file + end + + def test_add_alias_method + top_level = @store.add_file 'file.rb' + + meth = RDoc::AnyMethod.new nil, 'old_name' + meth.singleton = false + + as = RDoc::Alias.new nil, 'old_name', 'new_name', 'comment' + as.record_location top_level + as.parent = @context + + @context.add_method meth + @context.add_alias as + + assert_empty @context.aliases + assert_empty @context.unmatched_alias_lists + assert_equal %w[old_name new_name], @context.method_list.map { |m| m.name } + + new = @context.method_list.last + assert_equal top_level, new.file + end + + def test_add_alias_method_singleton + meth = RDoc::AnyMethod.new nil, 'old_name' + meth.singleton = true + + as = RDoc::Alias.new nil, 'old_name', 'new_name', 'comment' + as.singleton = true + + as.parent = @context + + @context.add_method meth + @context.add_alias as + + assert_empty @context.aliases + assert_empty @context.unmatched_alias_lists + assert_equal %w[old_name new_name], @context.method_list.map { |m| m.name } + + assert @context.method_list.last.singleton + end + + def test_add_class + @c1.add_class RDoc::NormalClass, 'Klass', 'Object' + + assert_includes @c1.classes.map { |k| k.full_name }, 'C1::Klass' + assert_includes @store.all_classes.map { |k| k.full_name }, 'C1::Klass' + end + + def test_add_class_basic_object + skip 'BasicObject is 1.9 only' unless defined?(BasicObject) + + @xref_data.add_class RDoc::NormalClass, 'BasicObject' + + basic = @xref_data.find_module_named 'BasicObject' + + assert_nil basic.superclass + + @c1.add_class RDoc::NormalClass, 'BasicObject' + + basic = @c1.find_module_named 'BasicObject' + + assert_equal 'Object', basic.superclass + end + + def test_add_class_object + root_class = defined?(BasicObject) ? 'BasicObject' : nil + + @xref_data.add_class RDoc::NormalClass, 'Object' + + object = @xref_data.find_module_named 'Object' + + assert_equal root_class, object.superclass + + @c1.add_class RDoc::NormalClass, 'Object' + + object = @c1.find_module_named 'Object' + + assert_equal 'Object', object.superclass.full_name + end + + def test_add_class_singleton + @c1.add_class RDoc::NormalClass, 'Klass', 'Object' + + assert_includes @c1.classes.map { |k| k.full_name }, 'C1::Klass' + assert_includes @store.all_classes.map { |k| k.full_name }, 'C1::Klass' + end + + def test_add_class_superclass + @c1.add_class RDoc::NormalClass, 'Klass', 'Object' + @c1.add_class RDoc::NormalClass, 'Klass', 'Other' + @c1.add_class RDoc::NormalClass, 'Klass', 'Object' + + klass = @c1.find_module_named 'Klass' + assert_equal 'Other', klass.superclass + end + + def test_add_class_upgrade + @c1.add_module RDoc::NormalModule, 'Klass' + @c1.add_class RDoc::NormalClass, 'Klass', nil + + assert_includes @c1.classes.map { |k| k.full_name }, 'C1::Klass', + 'c1 classes' + refute_includes @c1.modules.map { |k| k.full_name }, 'C1::Klass', + 'c1 modules' + + assert_includes @store.all_classes.map { |k| k.full_name }, 'C1::Klass', + 'TopLevel classes' + refute_includes @store.all_modules.map { |k| k.full_name }, 'C1::Klass', + 'TopLevel modules' + end + + def test_add_constant + const = RDoc::Constant.new 'NAME', 'value', 'comment' + @context.add_constant const + + assert_equal [const], @context.constants + end + + def test_add_extend + ext = RDoc::Extend.new 'Name', 'comment' + @context.add_extend ext + + assert_equal [ext], @context.extends + end + + def test_add_include + incl = RDoc::Include.new 'Name', 'comment' + @context.add_include incl + + assert_equal [incl], @context.includes + end + + def test_add_method + meth = RDoc::AnyMethod.new nil, 'old_name' + meth.visibility = nil + + @context.add_method meth + + assert_equal [meth], @context.method_list + assert_equal :public, meth.visibility + end + + def test_add_method_alias + as = RDoc::Alias.new nil, 'old_name', 'new_name', 'comment' + meth = RDoc::AnyMethod.new nil, 'old_name' + + @context.add_alias as + refute_empty @context.external_aliases + + @context.add_method meth + + assert_empty @context.external_aliases + assert_empty @context.unmatched_alias_lists + assert_equal %w[old_name new_name], @context.method_list.map { |m| m.name } + end + + def test_add_method_duplicate + @store.rdoc.options.verbosity = 2 + + meth1 = RDoc::AnyMethod.new nil, 'name' + meth1.record_location @store.add_file 'first.rb' + meth1.visibility = nil + meth1.comment = comment 'first' + + @context.add_method meth1 + + meth2 = RDoc::AnyMethod.new nil, 'name' + meth2.record_location @store.add_file 'second.rb' + meth2.comment = comment 'second' + + _, err = verbose_capture_io do + @context.add_method meth2 + end + + expected = 'Duplicate method (unknown)#name in file second.rb, ' \ + 'previously in file first.rb' + + assert_equal expected, err.chomp + + method = @context.method_list.first + + assert_equal 'first', method.comment.text + end + + def test_add_method_duplicate_loading + @context.store = nil + + meth1 = RDoc::AnyMethod.new nil, 'name' + meth1.record_location @store.add_file 'first.rb' + meth1.visibility = nil + meth1.comment = comment 'first' + + @context.add_method meth1 + + meth2 = RDoc::AnyMethod.new nil, 'name' + meth2.record_location @store.add_file 'second.rb' + meth2.comment = comment 'second' + + _, err = verbose_capture_io do + @context.add_method meth2 + end + + assert_empty err + + method = @context.method_list.first + + assert_equal 'first', method.comment.text + end + + def test_add_module + @c1.add_module RDoc::NormalModule, 'Mod' + + assert_includes @c1.modules.map { |m| m.full_name }, 'C1::Mod' + end + + def test_add_module_alias + tl = @store.add_file 'file.rb' + + c3_c4 = @c2.add_module_alias @c2_c3, 'C4', tl + + alias_constant = @c2.constants.first + + assert_equal 'C2::C4', c3_c4.full_name + assert_equal tl, alias_constant.file + end + + def test_add_module_alias_top_level + store = RDoc::Store.new + + top_level = store.add_file 'file.rb' + + klass = top_level.add_class RDoc::NormalClass, 'Klass' + klass.comment = 'klass comment' + + object = top_level.add_class RDoc::NormalClass, 'Object' + + top_level.add_module_alias klass, 'A', top_level + + refute_empty object.constants + + constant = object.constants.first + + assert_equal 'klass comment', constant.comment + end + + def test_add_module_class + k = @c1.add_class RDoc::NormalClass, 'Klass', nil + m = @c1.add_module RDoc::NormalModule, 'Klass' + + assert_equal k, m, 'returns class' + assert_empty @c1.modules + end + + def test_add_require + req = RDoc::Require.new 'require', 'comment' + @c1.add_require req + + assert_empty @c1.requires + assert_includes @c1.top_level.requires, req + end + + def test_add_section + default_section = @context.sections.first + + @context.add_section nil, comment('comment', @top_level) + + assert_equal 1, @context.sections.length + assert_equal [comment("comment", @top_level)], + @context.sections.first.comments + + @context.add_section nil, comment('new comment', @top_level) + + assert_equal 1, @context.sections.length + assert_equal [comment('comment', @top_level), + comment('new comment', @top_level)], + @context.sections.first.comments + + @context.add_section 'other', comment('', @top_level) + + assert_equal 2, @context.sections.length + + new_section = @context.sections.find { |section| section.title == 'other' } + assert new_section + assert_equal default_section, @context.current_section + end + + def test_add_section_no_comment + default_section = @context.sections.first + + @context.add_section nil + + assert_equal 1, @context.sections.length + + @context.add_section 'other' + + assert_equal 2, @context.sections.length + + new_section = @context.sections.find { |section| section.title == 'other' } + + assert new_section + assert_equal default_section, @context.current_section + end + + def test_add_to + incl = RDoc::Include.new 'Name', 'comment' + arr = [] + @context.add_to arr, incl + + assert_includes arr, incl + assert_equal @context, incl.parent + assert_equal @context.current_section, incl.section + end + + def test_add_to_temporary_section + incl = RDoc::Include.new 'Name', 'comment' + arr = [] + section = + @context.add_section 'temporary', RDoc::Comment.new('', @top_level) + @context.temporary_section = section + + @context.add_to arr, incl + + assert_includes arr, incl + assert_equal @context, incl.parent + assert_equal section, incl.section + end + + def test_add_to_no_document_self + incl = RDoc::Include.new 'Name', 'comment' + arr = [] + @context.document_self = false + @context.add_to arr, incl + + refute_includes arr, incl + end + + def test_add_to_done_documenting + incl = RDoc::Include.new 'Name', 'comment' + arr = [] + @context.done_documenting = true + @context.add_to arr, incl + + refute_includes arr, incl + end + + def bench_add_include + cm = RDoc::ClassModule.new 'Klass' + + assert_performance_linear 0.9 do |count| + count.times do |i| + cm.add_include RDoc::Include.new("N::M#{i}", nil) + end + end + end + + def test_child_name + assert_equal 'C1::C1', @c1.child_name('C1') + end + + def test_classes + assert_equal %w[C2::C3], @c2.classes.map { |k| k.full_name } + assert_equal %w[C3::H1 C3::H2], @c3.classes.map { |k| k.full_name }.sort + end + + def test_current_section + default_section = @context.current_section + + new_section = + @context.add_section 'other', RDoc::Comment.new('', @top_level) + @context.temporary_section = new_section + + assert_equal new_section, @context.current_section + assert_equal default_section, @context.current_section + end + + def test_defined_in_eh + assert @c1.defined_in?(@c1.top_level) + + refute @c1.defined_in?(@store.add_file('name.rb')) + end + + def test_equals2 + assert_equal @c3, @c3 + refute_equal @c2, @c3 + refute_equal @c2_c3, @c3 + end + + def test_each_method_enumerator + assert_kind_of @enumerator, @c1.each_method + end + + def test_each_section + sects = [] + consts = [] + attrs = [] + + @c1.each_section do |section, constants, attributes| + sects << section + consts << constants + attrs << attributes + end + + assert_equal [nil, 'separate'], sects.map { |section| section.title } + + expected_consts = [ + [@c1.constants.first], + [], + ] + + assert_equal expected_consts, consts + + expected_attrs = [ + [@c1.attributes[0], @c1.attributes[3]], + [@c1.attributes[1], @c1.attributes[2]], + ] + + assert_equal expected_attrs, attrs + end + + def test_each_section_enumerator + assert_kind_of @enumerator, @c1.each_section + end + + def test_find_attribute_named + assert_equal nil, @c1.find_attribute_named('none') + assert_equal 'R', @c1.find_attribute_named('attr').rw + assert_equal 'R', @c1.find_attribute_named('attr_reader').rw + assert_equal 'W', @c1.find_attribute_named('attr_writer').rw + assert_equal 'RW', @c1.find_attribute_named('attr_accessor').rw + end + + def test_find_class_method_named + assert_equal nil, @c1.find_class_method_named('none') + + m = @c1.find_class_method_named('m') + assert_instance_of RDoc::AnyMethod, m + assert m.singleton + end + + def test_find_constant_named + assert_equal nil, @c1.find_constant_named('NONE') + assert_equal ':const', @c1.find_constant_named('CONST').value + end + + def test_find_enclosing_module_named + assert_equal nil, @c2_c3.find_enclosing_module_named('NONE') + assert_equal @c1, @c2_c3.find_enclosing_module_named('C1') + assert_equal @c2, @c2_c3.find_enclosing_module_named('C2') + end + + def test_find_file_named + assert_equal nil, @c1.find_file_named('nonexistent.rb') + assert_equal @xref_data, @c1.find_file_named(@file_name) + end + + def test_find_instance_method_named + assert_equal nil, @c1.find_instance_method_named('none') + + m = @c1.find_instance_method_named('m') + assert_instance_of RDoc::AnyMethod, m + refute m.singleton + end + + def test_find_local_symbol + assert_equal true, @c1.find_local_symbol('m').singleton + assert_equal ':const', @c1.find_local_symbol('CONST').value + assert_equal 'R', @c1.find_local_symbol('attr').rw + assert_equal @xref_data, @c1.find_local_symbol(@file_name) + assert_equal @c2_c3, @c2.find_local_symbol('C3') + end + + def test_find_method_named + assert_equal true, @c1.find_method_named('m').singleton + end + + def test_find_module_named + assert_equal @c2_c3, @c2.find_module_named('C3') + assert_equal @c2, @c2.find_module_named('C2') + assert_equal @c1, @c2.find_module_named('C1') + + assert_equal 'C2::C3', @c2.find_module_named('C3').full_name + end + + def test_find_symbol + c3 = @xref_data.find_module_named('C3') + assert_equal c3, @xref_data.find_symbol('C3') + assert_equal c3, @c2.find_symbol('::C3') + assert_equal @c2_c3, @c2.find_symbol('C3') + end + + def test_find_symbol_method + assert_equal @c1__m, @c1.find_symbol('m') + assert_equal @c1_m, @c1.find_symbol('#m') + assert_equal @c1__m, @c1.find_symbol('::m') + end + + def test_find_symbol_module + assert_nil @m1_m2.find_symbol_module 'N' + assert_nil @m1_m2.find_symbol_module 'M2::M1' + + @m1_m2.parent = nil # loaded from legacy ri store + + assert_nil @m1_m2.find_symbol_module 'N' + assert_nil @m1_m2.find_symbol_module 'M2::M1' + end + + def test_fully_documented_eh + context = RDoc::Context.new + + refute context.fully_documented? + + context.comment = 'hi' + + assert context.fully_documented? + + m = @c1_m + + context.add_method m + + refute context.fully_documented? + + m.comment = 'hi' + + assert context.fully_documented? + + c = RDoc::Constant.new 'C', '0', nil + + context.add_constant c + + refute context.fully_documented? + + c.comment = 'hi' + + assert context.fully_documented? + + a = RDoc::Attr.new '', 'a', 'RW', nil + + context.add_attribute a + + refute context.fully_documented? + + a.comment = 'hi' + + assert context.fully_documented? + end + + def test_spaceship + assert_equal(-1, @c2.<=>(@c3)) + assert_equal 0, @c2.<=>(@c2) + assert_equal 1, @c3.<=>(@c2) + + assert_equal 1, @c2_c3.<=>(@c2) + assert_equal(-1, @c2_c3.<=>(@c3)) + + assert_nil @c2.<=>(Gem.loaded_specs.values.first) + end + + def test_methods_by_type + expected = { + 'instance' => { + :private => [], + :protected => [], + :public => [@c1_m], + }, + 'class' => { + :private => [], + :protected => [], + :public => [@c1__m], + }, + } + + assert_equal expected, @c1.methods_by_type + end + + def test_methods_by_type_section + separate = @c1.sections_hash['separate'] + @c1_m.section = separate + + expected = { + 'instance' => { + :private => [], + :protected => [], + :public => [@c1_m], + }, + 'class' => { + :private => [], + :protected => [], + :public => [], + }, + } + + assert_equal expected, @c1.methods_by_type(separate) + end + + def test_methods_matching + methods = [] + + @parent.methods_matching 'm' do |m| + methods << m + end + + assert_equal [@parent_m], methods + end + + def test_methods_matching_singleton + methods = [] + + @parent.methods_matching 'm', true do |m| + methods << m + end + + assert_equal [@parent__m], methods + end + + def test_methods_matching_inherit + methods = [] + + @child.methods_matching 'm' do |m| + methods << m + end + + assert_equal [@parent_m], methods + end + + def test_remove_invisible_private + util_visibilities + + @vis.remove_invisible :private + + assert_equal [@pub, @prot, @priv], @vis.method_list + assert_equal [@apub, @aprot, @apriv], @vis.attributes + end + + def test_remove_invisible_nodoc + util_visibilities + + @vis.remove_invisible :nodoc + + assert_equal [@pub, @prot, @priv], @vis.method_list + assert_equal [@apub, @aprot, @apriv], @vis.attributes + end + + def test_remove_invisible_protected + util_visibilities + + @vis.remove_invisible :protected + + assert_equal [@pub, @prot], @vis.method_list + assert_equal [@apub, @aprot], @vis.attributes + end + + def test_remove_invisible_public + util_visibilities + + @vis.remove_invisible :public + + assert_equal [@pub], @vis.method_list + assert_equal [@apub], @vis.attributes + end + + def test_remove_invisible_public_force + util_visibilities + + @priv.force_documentation = true + @prot.force_documentation = true + @apriv.force_documentation = true + @aprot.force_documentation = true + + @vis.remove_invisible :public + + assert_equal [@pub, @prot, @priv], @vis.method_list + assert_equal [@apub, @aprot, @apriv], @vis.attributes + end + + def test_remove_invisible_in_protected + util_visibilities + + methods = [@pub, @prot, @priv] + + @c1.remove_invisible_in methods, :protected + + assert_equal [@pub, @prot], methods + end + + def test_remove_invisible_in_protected_force + util_visibilities + + @priv.force_documentation = true + + methods = [@pub, @prot, @priv] + + @c1.remove_invisible_in methods, :protected + + assert_equal [@pub, @prot, @priv], methods + end + + def test_remove_invisible_in_public + util_visibilities + + methods = [@pub, @prot, @priv] + + @c1.remove_invisible_in methods, :public + + assert_equal [@pub], methods + end + + def test_remove_invisible_in_public_force + util_visibilities + + @prot.force_documentation = true + @priv.force_documentation = true + + methods = [@pub, @prot, @priv] + + @c1.remove_invisible_in methods, :public + + assert_equal [@pub, @prot, @priv], methods + end + + def test_section_contents + default = @context.sections.first + @context.add_method RDoc::AnyMethod.new(nil, 'm1') + + b = @context.add_section 'B' + m = @context.add_method RDoc::AnyMethod.new(nil, 'm2') + m.section = b + + assert_equal [default, b], @context.section_contents + end + + def test_section_contents_no_default + @context = RDoc::Context.new + b = @context.add_section 'B' + m = @context.add_method RDoc::AnyMethod.new(nil, 'm') + m.section = b + + assert_equal [b], @context.section_contents + end + + def test_section_contents_only_default + @context = RDoc::Context.new + + @context.add_method RDoc::AnyMethod.new(nil, 'm') + + assert_empty @context.section_contents + end + + def test_section_contents_unused + @context = RDoc::Context.new + + @context.add_method RDoc::AnyMethod.new(nil, 'm') + @context.add_section 'B' + + assert_empty @context.section_contents + end + + def test_set_current_section + default_section = @context.sections.first + + @context.set_current_section nil, RDoc::Comment.new('', @top_level) + + assert_equal default_section, @context.current_section + + @context.set_current_section 'other', RDoc::Comment.new('', @top_level) + + new_section = @context.sections.find { |section| + section != default_section + } + + assert_equal new_section, @context.current_section + end + + def test_sort_sections + c = RDoc::Context.new + c.add_section 'C' + c.add_section 'A' + c.add_section 'B' + + titles = c.sort_sections.map { |section| section.title } + + assert_equal [nil, 'A', 'B', 'C'], titles + end + + def test_sort_sections_tomdoc + c = RDoc::Context.new + c.add_section 'Public' + c.add_section 'Internal' + c.add_section 'Deprecated' + + titles = c.sort_sections.map { |section| section.title } + + assert_equal [nil, 'Public', 'Internal', 'Deprecated'], titles + end + + def test_sort_sections_tomdoc_missing + c = RDoc::Context.new + c.add_section 'Internal' + c.add_section 'Public' + + titles = c.sort_sections.map { |section| section.title } + + assert_equal [nil, 'Public', 'Internal'], titles + end + + def util_visibilities + @pub = RDoc::AnyMethod.new nil, 'pub' + @prot = RDoc::AnyMethod.new nil, 'prot' + @priv = RDoc::AnyMethod.new nil, 'priv' + + @apub = RDoc::Attr.new nil, 'pub', 'RW', nil + @aprot = RDoc::Attr.new nil, 'prot', 'RW', nil + @apriv = RDoc::Attr.new nil, 'priv', 'RW', nil + + @vis = RDoc::NormalClass.new 'Vis' + @vis.add_method @pub + @vis.add_method @prot + @vis.add_method @priv + + @vis.add_attribute @apub + @vis.add_attribute @aprot + @vis.add_attribute @apriv + + @prot.visibility = :protected + @priv.visibility = :private + + @aprot.visibility = :protected + @apriv.visibility = :private + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_context_section.rb b/jni/ruby/test/rdoc/test_rdoc_context_section.rb new file mode 100644 index 0000000..b8f8c7f --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_context_section.rb @@ -0,0 +1,130 @@ +require 'rdoc/test_case' + +class TestRDocContextSection < RDoc::TestCase + + def setup + super + + @top_level = @store.add_file 'file.rb' + + @klass = @top_level.add_class RDoc::NormalClass, 'Object' + + @S = RDoc::Context::Section + @s = @S.new @klass, 'section', comment('# comment', @top_level) + end + + def test_add_comment + file1 = @store.add_file 'file1.rb' + + klass = file1.add_class RDoc::NormalClass, 'Klass' + + c1 = RDoc::Comment.new "# :section: section\n", file1 + c2 = RDoc::Comment.new "# hello\n", file1 + c3 = RDoc::Comment.new "# world\n", file1 + + s = @S.new klass, 'section', c1 + + assert_empty s.comments + + s.add_comment nil + + assert_empty s.comments + + s.add_comment c2 + + assert_equal [c2], s.comments + + s.add_comment c3 + + assert_equal [c2, c3], s.comments + end + + def test_aref + assert_equal 'section', @s.aref + + assert_equal '5Buntitled-5D', @S.new(nil, nil, nil).aref + + assert_equal 'one+two', @S.new(nil, 'one two', nil).aref + end + + def test_extract_comment + assert_equal '', @s.extract_comment(comment('')).text + assert_equal '', @s.extract_comment(comment("# :section: b\n")).text + assert_equal '# c', @s.extract_comment(comment("# :section: b\n# c")).text + assert_equal '# c', + @s.extract_comment(comment("# a\n# :section: b\n# c")).text + end + + def test_marshal_dump + loaded = Marshal.load Marshal.dump @s + + expected = RDoc::Comment.new('comment', @top_level).parse + expected = doc(expected) + + assert_equal 'section', loaded.title + assert_equal expected, loaded.comments + assert_nil loaded.parent, 'parent is set manually' + end + + def test_marshal_dump_no_comment + s = @S.new @klass, 'section', comment('') + + loaded = Marshal.load Marshal.dump s + + assert_equal 'section', loaded.title + assert_empty loaded.comments + assert_nil loaded.parent, 'parent is set manually' + end + + def test_marshal_load_version_0 + loaded = Marshal.load "\x04\bU:\eRDoc::Context::Section" + + "[\bi\x00I\"\fsection\x06:\x06EFo" + + ":\eRDoc::Markup::Document\a:\v@parts" + + "[\x06o;\a\a;\b[\x06o" + + ":\x1CRDoc::Markup::Paragraph\x06;\b" + + "[\x06I\"\fcomment\x06;\x06F:\n@fileI" + + "\"\ffile.rb\x06;\x06F;\n0" + + expected = doc RDoc::Comment.new('comment', @top_level).parse + + assert_equal 'section', loaded.title + assert_equal expected, loaded.comments + assert_nil loaded.parent, 'parent is set manually' + end + + def test_remove_comment_array + other = @store.add_file 'other.rb' + + other_comment = comment('bogus', other) + + @s.add_comment other_comment + + @s.remove_comment comment('bogus', @top_level) + + assert_equal [other_comment], @s.comments + end + + def test_remove_comment_document + other = @store.add_file 'other.rb' + + other_comment = comment('bogus', other) + + @s.add_comment other_comment + + loaded = Marshal.load Marshal.dump @s + + loaded.remove_comment comment('bogus', @top_level) + + assert_equal doc(other_comment.parse), loaded.comments + end + + def test_sequence + _, err = verbose_capture_io do + assert_match(/\ASEC\d{5}\Z/, @s.sequence) + end + + assert_equal "#{@S}#sequence is deprecated, use #aref\n", err + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_cross_reference.rb b/jni/ruby/test/rdoc/test_rdoc_cross_reference.rb new file mode 100644 index 0000000..99fc224 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_cross_reference.rb @@ -0,0 +1,192 @@ +require File.expand_path '../xref_test_case', __FILE__ + +class TestRDocCrossReference < XrefTestCase + + def setup + super + + @xref = RDoc::CrossReference.new @c1 + end + + def assert_ref expected, name + assert_equal expected, @xref.resolve(name, 'fail') + end + + def refute_ref name + assert_equal name, @xref.resolve(name, name) + end + + def test_METHOD_REGEXP_STR + re = /#{RDoc::CrossReference::METHOD_REGEXP_STR}/ + + %w'=== [] []= << >>'.each do |x| + re =~ x + assert_equal x, $& + end + end + + def test_resolve_C2 + @xref = RDoc::CrossReference.new @c2 + + refute_ref '#m' + + assert_ref @c1__m, 'C1::m' + assert_ref @c2_c3, 'C2::C3' + assert_ref @c2_c3_m, 'C2::C3#m' + assert_ref @c2_c3_h1, 'C3::H1' + assert_ref @c4, 'C4' + + assert_ref @c3_h2, 'C3::H2' + refute_ref 'H1' + end + + def test_resolve_C2_C3 + @xref = RDoc::CrossReference.new @c2_c3 + + assert_ref @c2_c3_m, '#m' + + assert_ref @c2_c3, 'C3' + assert_ref @c2_c3_m, 'C3#m' + + assert_ref @c2_c3_h1, 'H1' + assert_ref @c2_c3_h1, 'C3::H1' + + assert_ref @c4, 'C4' + + assert_ref @c3_h2, 'C3::H2' + end + + def test_resolve_C3 + @xref = RDoc::CrossReference.new @c3 + + assert_ref @c3, 'C3' + + refute_ref '#m' + refute_ref 'C3#m' + + assert_ref @c3_h1, 'H1' + + assert_ref @c3_h1, 'C3::H1' + assert_ref @c3_h2, 'C3::H2' + + assert_ref @c4, 'C4' + end + + def test_resolve_C4 + @xref = RDoc::CrossReference.new @c4 + + # C4 ref inside a C4 containing a C4 should resolve to the contained class + assert_ref @c4_c4, 'C4' + end + + def test_resolve_C4_C4 + @xref = RDoc::CrossReference.new @c4_c4 + + # A C4 reference inside a C4 class contained within a C4 class should + # resolve to the inner C4 class. + assert_ref @c4_c4, 'C4' + end + + def test_resolve_class + assert_ref @c1, 'C1' + refute_ref 'H1' + + assert_ref @c2, 'C2' + assert_ref @c2_c3, 'C2::C3' + assert_ref @c2_c3_h1, 'C2::C3::H1' + + assert_ref @c3, '::C3' + assert_ref @c3_h1, '::C3::H1' + + assert_ref @c4_c4, 'C4::C4' + end + + def test_resolve_file + refute_ref 'xref_data.rb' + end + + def test_resolve_method + assert_ref @c1__m, 'm' + assert_ref @c1_m, '#m' + assert_ref @c1__m, '::m' + + assert_ref @c1_m, 'C1#m' + assert_ref @c1__m, 'C1.m' + assert_ref @c1__m, 'C1::m' + + assert_ref @c1_m, 'C1#m' + assert_ref @c1_m, 'C1#m()' + assert_ref @c1_m, 'C1#m(*)' + + assert_ref @c1__m, 'C1.m' + assert_ref @c1__m, 'C1.m()' + assert_ref @c1__m, 'C1.m(*)' + + assert_ref @c1__m, 'C1::m' + assert_ref @c1__m, 'C1::m()' + assert_ref @c1__m, 'C1::m(*)' + + assert_ref @c2_c3_m, 'C2::C3#m' + + assert_ref @c2_c3_m, 'C2::C3.m' + + # TODO stop escaping - HTML5 allows anything but space + assert_ref @c2_c3_h1_meh, 'C2::C3::H1#m?' + + assert_ref @c2_c3_m, '::C2::C3#m' + assert_ref @c2_c3_m, '::C2::C3#m()' + assert_ref @c2_c3_m, '::C2::C3#m(*)' + end + + def test_resolve_method_equals3 + m = RDoc::AnyMethod.new '', '===' + @c1.add_method m + + assert_ref m, '===' + end + + def test_resolve_page + page = @store.add_file 'README.txt' + page.parser = RDoc::Parser::Simple + + assert_ref page, 'README' + end + + def test_resolve_percent + i_percent = RDoc::AnyMethod.new nil, '%' + i_percent.singleton = false + @c1.add_method i_percent + + c_percent = RDoc::AnyMethod.new nil, '%' + c_percent.singleton = true + @c1.add_method c_percent + + assert_ref i_percent, '%' + assert_ref i_percent, '#%' + assert_ref c_percent, '::%' + + assert_ref i_percent, 'C1#%' + assert_ref c_percent, 'C1::%' + end + + def test_resolve_no_ref + assert_equal '', @xref.resolve('', '') + + assert_equal "bogus", @xref.resolve("bogus", "bogus") + assert_equal "\\bogus", @xref.resolve("\\bogus", "\\bogus") + assert_equal "\\\\bogus", @xref.resolve("\\\\bogus", "\\\\bogus") + + assert_equal "\\#n", @xref.resolve("\\#n", "fail") + assert_equal "\\#n()", @xref.resolve("\\#n()", "fail") + assert_equal "\\#n(*)", @xref.resolve("\\#n(*)", "fail") + + assert_equal "C1", @xref.resolve("\\C1", "fail") + assert_equal "::C3", @xref.resolve("\\::C3", "fail") + + assert_equal "succeed", @xref.resolve("::C3::H1#n", "succeed") + assert_equal "succeed", @xref.resolve("::C3::H1#n(*)", "succeed") + assert_equal "\\::C3::H1#n", @xref.resolve("\\::C3::H1#n", "fail") + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_encoding.rb b/jni/ruby/test/rdoc/test_rdoc_encoding.rb new file mode 100644 index 0000000..7ec39f8 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_encoding.rb @@ -0,0 +1,227 @@ +# coding: US-ASCII + +require 'rdoc/test_case' + +class TestRDocEncoding < RDoc::TestCase + + def setup + super + + @tempfile = Tempfile.new 'test_rdoc_encoding' + end + + def teardown + @tempfile.close! + + super + end + + def test_class_read_file + @tempfile.write "hi everybody" + @tempfile.flush + + assert_equal "hi everybody", RDoc::Encoding.read_file(@tempfile.path, nil) + end + + def test_class_read_file_encoding + skip "Encoding not implemented" unless Object.const_defined? :Encoding + + expected = "# coding: utf-8\nhi everybody" + + @tempfile.write expected + @tempfile.flush + + contents = RDoc::Encoding.read_file @tempfile.path, Encoding::UTF_8 + assert_equal "hi everybody", contents + assert_equal Encoding::UTF_8, contents.encoding + end + + def test_class_read_file_encoding_convert + skip "Encoding not implemented" unless Object.const_defined? :Encoding + + content = "" + content.encode! 'ISO-8859-1' + content << "# coding: ISO-8859-1\nhi \xE9verybody" + + @tempfile.write content + @tempfile.flush + + contents = RDoc::Encoding.read_file @tempfile.path, Encoding::UTF_8 + assert_equal Encoding::UTF_8, contents.encoding + assert_equal "hi \u00e9verybody", contents.sub("\r", '') + end + + def test_class_read_file_encoding_fail + skip "Encoding not implemented" unless Object.const_defined? :Encoding + + @tempfile.write "# coding: utf-8\n\317\200" # pi + @tempfile.flush + + contents = :junk + + _, err = verbose_capture_io do + contents = RDoc::Encoding.read_file @tempfile.path, Encoding::US_ASCII + end + + assert_nil contents + + assert_match %r%^unable to convert%, err + end + + def test_class_read_file_encoding_fancy + skip "Encoding not implemented" unless Object.const_defined? :Encoding + + expected = "# -*- coding: utf-8; fill-column: 74 -*-\nhi everybody" + expected.encode! Encoding::UTF_8 + + @tempfile.write expected + @tempfile.flush + + contents = RDoc::Encoding.read_file @tempfile.path, Encoding::UTF_8 + assert_equal "hi everybody", contents + assert_equal Encoding::UTF_8, contents.encoding + end + + def test_class_read_file_encoding_force_transcode + skip "Encoding not implemented" unless Object.const_defined? :Encoding + + @tempfile.write "# coding: utf-8\n\317\200" # pi + @tempfile.flush + + contents = RDoc::Encoding.read_file @tempfile.path, Encoding::US_ASCII, true + + assert_equal '?', contents + assert_equal Encoding::US_ASCII, contents.encoding + end + + def test_class_read_file_encoding_guess + skip "Encoding not implemented" unless Object.const_defined? :Encoding + + path = File.expand_path '../test.ja.txt', __FILE__ + content = RDoc::Encoding.read_file path, Encoding::UTF_8 + + assert_equal Encoding::UTF_8, content.encoding + end + + def test_class_read_file_encoding_invalid + skip "Encoding not implemented" unless Object.const_defined? :Encoding + + @tempfile.write "# coding: ascii\nM\xE4r" + @tempfile.flush + + contents = :junk + _, err = verbose_capture_io do + contents = RDoc::Encoding.read_file @tempfile.path, Encoding::UTF_8 + end + + assert_equal "unable to convert \"\\xE4\" on US-ASCII for #{@tempfile.path}, skipping\n", err + + assert_nil contents + end + + def test_class_read_file_encoding_with_signature + skip "Encoding not implemented" unless defined? ::Encoding + + @tempfile.write "\xEF\xBB\xBFhi everybody" + @tempfile.flush + + bug3360 = '[ruby-dev:41452]' + content = RDoc::Encoding.read_file @tempfile.path, Encoding::UTF_8 + assert_equal Encoding::UTF_8, content.encoding, bug3360 + assert_equal "hi everybody", content, bug3360 + end + + def test_class_read_file_encoding_iso_2022_jp + skip "Encoding not implemented" unless Object.const_defined? :Encoding + + input = "# coding: ISO-2022-JP\n:\e$B%3%^%s%I\e(B:" + + @tempfile.write input + @tempfile.flush + + contents = RDoc::Encoding.read_file @tempfile.path, Encoding::UTF_8 + + expected = ":\xe3\x82\xb3\xe3\x83\x9e\xe3\x83\xb3\xe3\x83\x89:" + expected.force_encoding Encoding::UTF_8 + + assert_equal expected, contents + assert_equal Encoding::UTF_8, contents.encoding + end + + def test_class_set_encoding + s = "# coding: UTF-8\n" + RDoc::Encoding.set_encoding s + + # sanity check for 1.8 + + skip "Encoding not implemented" unless Object.const_defined? :Encoding + + assert_equal Encoding::UTF_8, s.encoding + + s = "#!/bin/ruby\n# coding: UTF-8\n" + RDoc::Encoding.set_encoding s + + assert_equal Encoding::UTF_8, s.encoding + + s = "<?xml version='1.0' encoding='UTF-8'?>\n" + expected = s.encoding + RDoc::Encoding.set_encoding s + + assert_equal Encoding::UTF_8, s.encoding + + s = "<?xml version='1.0' encoding=\"UTF-8\"?>\n" + expected = s.encoding + RDoc::Encoding.set_encoding s + + assert_equal Encoding::UTF_8, s.encoding + end + + def test_class_set_encoding_strip + s = "# coding: UTF-8\n# more comments" + + RDoc::Encoding.set_encoding s + + assert_equal "# more comments", s + + s = "#!/bin/ruby\n# coding: UTF-8\n# more comments" + + RDoc::Encoding.set_encoding s + + assert_equal "#!/bin/ruby\n# more comments", s + end + + def test_class_set_encoding_bad + skip "Encoding not implemented" unless Object.const_defined? :Encoding + + s = "" + expected = s.encoding + RDoc::Encoding.set_encoding s + + assert_equal expected, s.encoding + + s = "# vim:set fileencoding=utf-8:\n" + expected = s.encoding + RDoc::Encoding.set_encoding s + + assert_equal expected, s.encoding + + s = "# vim:set fileencoding=utf-8:\n" + expected = s.encoding + RDoc::Encoding.set_encoding s + + assert_equal expected, s.encoding + + assert_raises ArgumentError do + RDoc::Encoding.set_encoding "# -*- encoding: undecided -*-\n" + end + end + + def test_sanity + skip "Encoding not implemented" unless Object.const_defined? :Encoding + + assert_equal Encoding::US_ASCII, ''.encoding, + 'If this file is not ASCII tests may incorrectly pass' + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_extend.rb b/jni/ruby/test/rdoc/test_rdoc_extend.rb new file mode 100644 index 0000000..1499315 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_extend.rb @@ -0,0 +1,94 @@ +require File.expand_path '../xref_test_case', __FILE__ + +class TestRDocExtend < XrefTestCase + + def setup + super + + @ext = RDoc::Extend.new 'M1', 'comment' + @ext.parent = @m1 + @ext.store = @store + end + + def test_module + assert_equal @m1, @ext.module + assert_equal 'Unknown', RDoc::Extend.new('Unknown', 'comment').module + end + + def test_module_extended + m1 = @xref_data.add_module RDoc::NormalModule, 'Mod1' + m1.add_module RDoc::NormalModule, 'Mod3' + m1_m2 = m1.add_module RDoc::NormalModule, 'Mod2' + m1_m2_m3 = m1_m2.add_module RDoc::NormalModule, 'Mod3' + m1_m2_m3.add_module RDoc::NormalModule, 'Mod4' + m1_m2.add_module RDoc::NormalModule, 'Mod4' + m1_m2_k0 = m1_m2.add_class RDoc::NormalClass, 'Klass0' + m1_m2_k0_m4 = m1_m2_k0.add_module RDoc::NormalModule, 'Mod4' + m1_m2_k0_m4.add_module RDoc::NormalModule, 'Mod6' + m1_m2_k0.add_module RDoc::NormalModule, 'Mod5' + + e0_m4 = RDoc::Extend.new 'Mod4', nil + e0_m5 = RDoc::Extend.new 'Mod5', nil + e0_m6 = RDoc::Extend.new 'Mod6', nil + e0_m1 = RDoc::Extend.new 'Mod1', nil + e0_m2 = RDoc::Extend.new 'Mod2', nil + e0_m3 = RDoc::Extend.new 'Mod3', nil + + m1_m2_k0.add_extend e0_m4 + m1_m2_k0.add_extend e0_m5 + m1_m2_k0.add_extend e0_m6 + m1_m2_k0.add_extend e0_m1 + m1_m2_k0.add_extend e0_m2 + m1_m2_k0.add_extend e0_m3 + + assert_equal [e0_m4, e0_m5, e0_m6, e0_m1, e0_m2, e0_m3], m1_m2_k0.extends + assert_equal ['Object'], m1_m2_k0.ancestors + + m1_k1 = m1.add_class RDoc::NormalClass, 'Klass1' + + e1_m1 = RDoc::Extend.new 'Mod1', nil + e1_m2 = RDoc::Extend.new 'Mod2', nil + e1_m3 = RDoc::Extend.new 'Mod3', nil + e1_m4 = RDoc::Extend.new 'Mod4', nil + e1_k0_m4 = RDoc::Extend.new 'Klass0::Mod4', nil + + m1_k1.add_extend e1_m1 + m1_k1.add_extend e1_m2 + m1_k1.add_extend e1_m3 + m1_k1.add_extend e1_m4 + m1_k1.add_extend e1_k0_m4 + + assert_equal [e1_m1, e1_m2, e1_m3, e1_m4, e1_k0_m4], m1_k1.extends + assert_equal ['Object'], m1_k1.ancestors + + m1_k2 = m1.add_class RDoc::NormalClass, 'Klass2' + + e2_m1 = RDoc::Extend.new 'Mod1', nil + e2_m2 = RDoc::Extend.new 'Mod2', nil + e2_m3 = RDoc::Extend.new 'Mod3', nil + e2_k0_m4 = RDoc::Extend.new 'Klass0::Mod4', nil + + m1_k2.add_extend e2_m1 + m1_k2.add_extend e2_m3 + m1_k2.add_extend e2_m2 + m1_k2.add_extend e2_k0_m4 + + assert_equal [e2_m1, e2_m3, e2_m2, e2_k0_m4], m1_k2.extends + assert_equal ['Object'], m1_k2.ancestors + + m1_k3 = m1.add_class RDoc::NormalClass, 'Klass3' + + e3_m1 = RDoc::Extend.new 'Mod1', nil + e3_m2 = RDoc::Extend.new 'Mod2', nil + e3_m4 = RDoc::Extend.new 'Mod4', nil + + m1_k3.add_extend e3_m1 + m1_k3.add_extend e3_m2 + m1_k3.add_extend e3_m4 + + assert_equal [e3_m1, e3_m2, e3_m4], m1_k3.extends + assert_equal ['Object'], m1_k3.ancestors + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_generator_darkfish.rb b/jni/ruby/test/rdoc/test_rdoc_generator_darkfish.rb new file mode 100644 index 0000000..fc77e4b --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_generator_darkfish.rb @@ -0,0 +1,229 @@ +require 'rdoc/test_case' + +class TestRDocGeneratorDarkfish < RDoc::TestCase + + def setup + super + + @lib_dir = "#{@pwd}/lib" + $LOAD_PATH.unshift @lib_dir # ensure we load from this RDoc + + @options = RDoc::Options.new + @options.option_parser = OptionParser.new + + @tmpdir = File.join Dir.tmpdir, "test_rdoc_generator_darkfish_#{$$}" + FileUtils.mkdir_p @tmpdir + Dir.chdir @tmpdir + @options.op_dir = @tmpdir + @options.generator = RDoc::Generator::Darkfish + + $LOAD_PATH.each do |path| + darkfish_dir = File.join path, 'rdoc/generator/template/darkfish/' + next unless File.directory? darkfish_dir + @options.template_dir = darkfish_dir + break + end + + @rdoc.options = @options + + @g = @options.generator.new @store, @options + @rdoc.generator = @g + + @top_level = @store.add_file 'file.rb' + @top_level.parser = RDoc::Parser::Ruby + @klass = @top_level.add_class RDoc::NormalClass, 'Klass' + + @alias_constant = RDoc::Constant.new 'A', nil, '' + @alias_constant.record_location @top_level + + @top_level.add_constant @alias_constant + + @klass.add_module_alias @klass, 'A', @top_level + + @meth = RDoc::AnyMethod.new nil, 'method' + @meth_bang = RDoc::AnyMethod.new nil, 'method!' + @attr = RDoc::Attr.new nil, 'attr', 'RW', '' + + @klass.add_method @meth + @klass.add_method @meth_bang + @klass.add_attribute @attr + + @ignored = @top_level.add_class RDoc::NormalClass, 'Ignored' + @ignored.ignore + + @store.complete :private + + @object = @store.find_class_or_module 'Object' + @klass_alias = @store.find_class_or_module 'Klass::A' + end + + def teardown + super + + $LOAD_PATH.shift + Dir.chdir @pwd + FileUtils.rm_rf @tmpdir + end + + def test_generate + top_level = @store.add_file 'file.rb' + top_level.add_class @klass.class, @klass.name + + @g.generate + + assert_file 'index.html' + assert_file 'Object.html' + assert_file 'table_of_contents.html' + assert_file 'js/search_index.js' + + assert_hard_link 'css/rdoc.css' + assert_hard_link 'css/fonts.css' + + assert_hard_link 'fonts/SourceCodePro-Bold.ttf' + assert_hard_link 'fonts/SourceCodePro-Regular.ttf' + + encoding = if Object.const_defined? :Encoding then + Regexp.escape Encoding::UTF_8.name + else + Regexp.escape 'UTF-8' + end + + assert_match %r%<meta charset="#{encoding}">%, File.read('index.html') + assert_match %r%<meta charset="#{encoding}">%, File.read('Object.html') + + refute_match(/Ignored/, File.read('index.html')) + end + + def test_generate_dry_run + @g.dry_run = true + top_level = @store.add_file 'file.rb' + top_level.add_class @klass.class, @klass.name + + @g.generate + + refute_file 'index.html' + refute_file 'Object.html' + end + + def test_generate_static + FileUtils.mkdir_p 'dir/images' + FileUtils.touch 'dir/images/image.png' + FileUtils.mkdir_p 'file' + FileUtils.touch 'file/file.txt' + + @options.static_path = [ + File.expand_path('dir'), + File.expand_path('file/file.txt'), + ] + + @g.generate + + assert_file 'images/image.png' + assert_file 'file.txt' + end + + def test_generate_static_dry_run + FileUtils.mkdir 'static' + FileUtils.touch 'static/image.png' + + @options.static_path = [File.expand_path('static')] + @g.dry_run = true + + @g.generate + + refute_file 'image.png' + end + + def test_install_rdoc_static_file + src = Pathname(__FILE__) + dst = File.join @tmpdir, File.basename(src) + options = {} + + @g.install_rdoc_static_file src, dst, options + + assert_file dst + + begin + assert_hard_link dst + rescue MiniTest::Assertion + return # hard links are not supported, no further tests needed + end + + @g.install_rdoc_static_file src, dst, options + + assert_hard_link dst + end + + def test_install_rdoc_static_file_missing + src = Pathname(__FILE__) + 'nonexistent' + dst = File.join @tmpdir, File.basename(src) + options = {} + + @g.install_rdoc_static_file src, dst, options + + refute_file dst + end + + def test_setup + @g.setup + + assert_equal [@klass_alias, @ignored, @klass, @object], + @g.classes.sort_by { |klass| klass.full_name } + assert_equal [@top_level], @g.files + assert_equal [@meth, @meth, @meth_bang, @meth_bang], @g.methods + assert_equal [@klass_alias, @klass, @object], @g.modsort + end + + def test_template_for + classpage = Pathname.new @options.template_dir + 'class.rhtml' + + template = @g.send(:template_for, classpage, true, RDoc::ERBIO) + assert_kind_of RDoc::ERBIO, template + + assert_same template, @g.send(:template_for, classpage) + end + + def test_template_for_dry_run + classpage = Pathname.new @options.template_dir + 'class.rhtml' + + template = @g.send(:template_for, classpage, true, ERB) + assert_kind_of ERB, template + + assert_same template, @g.send(:template_for, classpage) + end + + def test_template_for_partial + partial = Pathname.new @options.template_dir + '_sidebar_classes.rhtml' + + template = @g.send(:template_for, partial, false, RDoc::ERBPartial) + + assert_kind_of RDoc::ERBPartial, template + + assert_same template, @g.send(:template_for, partial) + end + + ## + # Asserts that +filename+ has a link count greater than 1 if hard links to + # @tmpdir are supported. + + def assert_hard_link filename + assert_file filename + + src = @g.template_dir + '_head.rhtml' + dst = File.join @tmpdir, 'hardlinktest' + + begin + FileUtils.ln src, dst + nlink = File.stat(dst).nlink if File.identical? src, dst + FileUtils.rm dst + return if nlink == 1 + rescue SystemCallError + return + end + + assert_operator File.stat(filename).nlink, :>, 1, + "#{filename} is not hard-linked" + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_generator_json_index.rb b/jni/ruby/test/rdoc/test_rdoc_generator_json_index.rb new file mode 100644 index 0000000..06a5ddc --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_generator_json_index.rb @@ -0,0 +1,320 @@ +# coding: US-ASCII + +require 'rdoc/test_case' + +class TestRDocGeneratorJsonIndex < RDoc::TestCase + + def setup + super + + @tmpdir = File.join Dir.tmpdir, "test_rdoc_generator_darkfish_#{$$}" + FileUtils.mkdir_p @tmpdir + + @options = RDoc::Options.new + @options.files = [] + # JsonIndex is used in conjunction with another generator + @options.setup_generator 'darkfish' + @options.template_dir = '' + @options.op_dir = @tmpdir + @options.option_parser = OptionParser.new + @options.finish + + @darkfish = RDoc::Generator::Darkfish.new @store, @options + @g = RDoc::Generator::JsonIndex.new @darkfish, @options + + @rdoc.options = @options + @rdoc.generator = @g + + @top_level = @store.add_file 'file.rb' + @top_level.parser = RDoc::Parser::Ruby + + @klass = @top_level.add_class RDoc::NormalClass, 'C' + + @meth = @klass.add_method RDoc::AnyMethod.new(nil, 'meth') + @meth.record_location @top_level + + @nest_klass = @klass.add_class RDoc::NormalClass, 'D' + @nest_klass.record_location @top_level + + @nest_meth = @nest_klass.add_method RDoc::AnyMethod.new(nil, 'meth') + + @ignored = @top_level.add_class RDoc::NormalClass, 'Ignored' + @ignored.ignore + + @page = @store.add_file 'page.rdoc' + @page.parser = RDoc::Parser::Simple + + @top_levels = [@top_level, @page].sort + @klasses = [@klass, @nest_klass, @ignored] + + Dir.chdir @tmpdir + end + + def teardown + super + + Dir.chdir @pwd + FileUtils.rm_rf @tmpdir + end + + def test_build_index + index = @g.build_index + + expected = { + :index => { + :searchIndex => %w[c d meth() meth() page], + :longSearchIndex => %w[c c::d c#meth() c::d#meth()], + :info => [ + @klass.search_record[2..-1], + @nest_klass.search_record[2..-1], + @meth.search_record[2..-1], + @nest_meth.search_record[2..-1], + @page.search_record[2..-1], + ], + }, + } + + expected[:index][:longSearchIndex] << '' + + assert_equal expected, index + end + + def test_class_dir + assert_equal @darkfish.class_dir, @g.class_dir + end + + def test_file_dir + assert_equal @darkfish.file_dir, @g.file_dir + end + + def test_generate + @g.generate + + assert_file 'js/searcher.js' + assert_file 'js/navigation.js' + assert_file 'js/search_index.js' + + json = File.read 'js/search_index.js' + + json =~ /\Avar search_data = / + + assignment = $& + index = $' + + refute_empty assignment + + index = JSON.parse index + + info = [ + @klass.search_record[2..-1], + @nest_klass.search_record[2..-1], + @meth.search_record[2..-1], + @nest_meth.search_record[2..-1], + @page.search_record[2..-1], + ] + + expected = { + 'index' => { + 'searchIndex' => [ + 'c', + 'd', + 'meth()', + 'meth()', + 'page', + ], + 'longSearchIndex' => [ + 'c', + 'c::d', + 'c#meth()', + 'c::d#meth()', + '', + ], + 'info' => info, + }, + } + + assert_equal expected, index + end + + def test_generate_gzipped + require 'zlib' + @g.generate + @g.generate_gzipped + + assert_file 'js/searcher.js' + assert_file 'js/searcher.js.gz' + assert_file 'js/navigation.js' + assert_file 'js/navigation.js.gz' + assert_file 'js/search_index.js' + assert_file 'js/search_index.js.gz' + + json = File.open('js/search_index.js.gz') {|gzip| + Zlib::GzipReader.new(gzip).read + } + + json =~ /\Avar search_data = / + + assignment = $& + index = $' + + refute_empty assignment + + index = JSON.parse index + + info = [ + @klass.search_record[2..-1], + @nest_klass.search_record[2..-1], + @meth.search_record[2..-1], + @nest_meth.search_record[2..-1], + @page.search_record[2..-1], + ] + + expected = { + 'index' => { + 'searchIndex' => [ + 'c', + 'd', + 'meth()', + 'meth()', + 'page', + ], + 'longSearchIndex' => [ + 'c', + 'c::d', + 'c#meth()', + 'c::d#meth()', + '', + ], + 'info' => info, + }, + } + + assert_equal expected, index + end + + def test_generate_utf_8 + skip "Encoding not implemented" unless Object.const_defined? :Encoding + + text = "5\xB0" + text.force_encoding Encoding::ISO_8859_1 + @klass.add_comment comment(text), @top_level + + @g.generate + + json = File.read 'js/search_index.js' + json.force_encoding Encoding::UTF_8 + + json =~ /\Avar search_data = / + + index = $' + + index = JSON.parse index + + klass_record = @klass.search_record[2..-1] + klass_record[-1] = "<p>5\xc2\xb0\n" + klass_record.last.force_encoding Encoding::UTF_8 + + info = [ + klass_record, + @nest_klass.search_record[2..-1], + @meth.search_record[2..-1], + @nest_meth.search_record[2..-1], + @page.search_record[2..-1], + ] + + expected = { + 'index' => { + 'searchIndex' => [ + 'c', + 'd', + 'meth()', + 'meth()', + 'page', + ], + 'longSearchIndex' => [ + 'c', + 'c::d', + 'c#meth()', + 'c::d#meth()', + '', + ], + 'info' => info, + }, + } + + assert_equal expected, index + end + + def test_index_classes + @g.reset @top_levels, @klasses + + @g.index_classes + + expected = { + :searchIndex => %w[c d], + :longSearchIndex => %w[c c::d], + :info => [ + @klass.search_record[2..-1], + @nest_klass.search_record[2..-1], + ], + } + + assert_equal expected, @g.index + end + + def test_index_classes_nodoc + @klass.document_self = false + @nest_klass.document_self = false + @meth.document_self = false + @nest_meth.document_self = false + + @g.reset @top_levels, @klasses + + @g.index_classes + + expected = { + :searchIndex => [], + :longSearchIndex => [], + :info => [], + } + + assert_equal expected, @g.index + end + + def test_index_methods + @g.reset @top_levels, @klasses + + @g.index_methods + + expected = { + :searchIndex => %w[meth() meth()], + :longSearchIndex => %w[c#meth() c::d#meth()], + :info => [ + @meth.search_record[2..-1], + @nest_meth.search_record[2..-1], + ], + } + + assert_equal expected, @g.index + end + + def test_index_pages + @g.reset @top_levels, @klasses + + @g.index_pages + + expected = { + :searchIndex => %w[page], + :longSearchIndex => [''], + :info => [@page.search_record[2..-1]], + } + + assert_equal expected, @g.index + end + + def test_search_string + assert_equal 'cd', @g.search_string('C d') + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_generator_markup.rb b/jni/ruby/test/rdoc/test_rdoc_generator_markup.rb new file mode 100644 index 0000000..5f8a45b --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_generator_markup.rb @@ -0,0 +1,59 @@ +require 'rdoc/test_case' + +class TestRDocGeneratorMarkup < RDoc::TestCase + + include RDoc::Text + include RDoc::Generator::Markup + + attr_reader :store + + def setup + super + + @options = RDoc::Options.new + @rdoc.options = @options + + @parent = self + @path = '/index.html' + @symbols = {} + end + + def test_aref_to + assert_equal 'Foo/Bar.html', aref_to('Foo/Bar.html') + end + + def test_as_href + assert_equal '../index.html', as_href('Foo/Bar.html') + end + + def test_cvs_url + assert_equal 'http://example/this_page', + cvs_url('http://example/', 'this_page') + + assert_equal 'http://example/?page=this_page&foo=bar', + cvs_url('http://example/?page=%s&foo=bar', 'this_page') + end + + def test_description + @comment = '= Hello' + + links = '<span><a href="#label-Hello">¶</a> ' + + '<a href="#top">↑</a></span>' + + assert_equal "\n<h1 id=\"label-Hello\">Hello#{links}</h1>\n", description + end + + def test_formatter + assert_kind_of RDoc::Markup::ToHtmlCrossref, formatter + refute formatter.show_hash + assert_same self, formatter.context + end + + attr_reader :path + + def find_symbol name + @symbols[name] + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_generator_pot.rb b/jni/ruby/test/rdoc/test_rdoc_generator_pot.rb new file mode 100644 index 0000000..d028ce7 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_generator_pot.rb @@ -0,0 +1,91 @@ +require 'rdoc/test_case' + +class TestRDocGeneratorPOT < RDoc::TestCase + + def setup + super + + @options = RDoc::Options.new + @tmpdir = File.join Dir.tmpdir, "test_rdoc_generator_pot_#{$$}" + FileUtils.mkdir_p @tmpdir + + @generator = RDoc::Generator::POT.new @store, @options + + @top_level = @store.add_file 'file.rb' + @klass = @top_level.add_class RDoc::NormalClass, 'Object' + @klass.add_comment 'This is a class', @top_level + @klass.add_section 'This is a section', comment('This is a section comment') + + @const = RDoc::Constant.new "CONSTANT", "29", "This is a constant" + + @meth = RDoc::AnyMethod.new nil, 'method' + @meth.record_location @top_level + @meth.comment = 'This is a method' + + @attr = RDoc::Attr.new nil, 'attr', 'RW', '' + @attr.record_location @top_level + @attr.comment = 'This is an attribute' + + @klass.add_constant @const + @klass.add_method @meth + @klass.add_attribute @attr + + Dir.chdir @tmpdir + end + + def teardown + super + + Dir.chdir @pwd + FileUtils.rm_rf @tmpdir + end + + def test_generate + @generator.generate + + assert_equal <<-POT, File.read(File.join(@tmpdir, 'rdoc.pot')) +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSEION\\n" +"Report-Msgid-Bugs-To:\\n" +"PO-Revision-Date: YEAR-MO_DA HO:MI+ZONE\\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n" +"Language-Team: LANGUAGE <LL@li.org>\\n" +"Language:\\n" +"MIME-Version: 1.0\\n" +"Content-Type: text/plain; charset=CHARSET\\n" +"Content-Transfer-Encoding: 8bit\\n" +"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\\n" + +#. Object +msgid "This is a class" +msgstr "" + +#. Object::CONSTANT +msgid "This is a constant" +msgstr "" + +#. Object#method +msgid "This is a method" +msgstr "" + +#. Object: section title +msgid "This is a section" +msgstr "" + +#. Object: This is a section +msgid "This is a section comment" +msgstr "" + +#. Object#attr +msgid "This is an attribute" +msgstr "" + POT + end + +end diff --git a/jni/ruby/test/rdoc/test_rdoc_generator_pot_po.rb b/jni/ruby/test/rdoc/test_rdoc_generator_pot_po.rb new file mode 100644 index 0000000..fae7f7e --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_generator_pot_po.rb @@ -0,0 +1,51 @@ +require 'rdoc/test_case' + +class TestRDocGeneratorPOTPO < RDoc::TestCase + + def setup + super + @po = RDoc::Generator::POT::PO.new + end + + def test_empty + assert_equal header, @po.to_s + end + + def test_have_entry + @po.add(entry("Hello", {})) + assert_equal <<-PO, @po.to_s +#{header} +msgid "Hello" +msgstr "" + PO + end + + private + + def entry(msgid, options) + RDoc::Generator::POT::POEntry.new(msgid, options) + end + + def header + <<-'HEADER' +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSEION\n" +"Report-Msgid-Bugs-To:\n" +"PO-Revision-Date: YEAR-MO_DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"Language:\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" + HEADER + end + +end diff --git a/jni/ruby/test/rdoc/test_rdoc_generator_pot_po_entry.rb b/jni/ruby/test/rdoc/test_rdoc_generator_pot_po_entry.rb new file mode 100644 index 0000000..8620d98 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_generator_pot_po_entry.rb @@ -0,0 +1,139 @@ +require 'rdoc/test_case' + +class TestRDocGeneratorPOTPOEntry < RDoc::TestCase + + def test_msgid_normal + assert_equal <<-'ENTRY', entry("Hello", {}).to_s +msgid "Hello" +msgstr "" + ENTRY + end + + def test_msgid_multiple_lines + assert_equal <<-'ENTRY', entry("Hello\nWorld", {}).to_s +msgid "" +"Hello\n" +"World" +msgstr "" + ENTRY + end + + def test_msgid_tab + assert_equal <<-'ENTRY', entry("Hello\tWorld", {}).to_s +msgid "Hello\tWorld" +msgstr "" + ENTRY + end + + def test_msgid_back_slash + assert_equal <<-'ENTRY', entry("Hello \\ World", {}).to_s +msgid "Hello \\ World" +msgstr "" + ENTRY + end + + def test_msgid_double_quote + assert_equal <<-'ENTRY', entry("Hello \"World\"!", {}).to_s +msgid "Hello \"World\"!" +msgstr "" + ENTRY + end + + def test_translator_comment_normal + options = {:translator_comment => "Greeting"} + assert_equal <<-'ENTRY', entry("Hello", options).to_s +# Greeting +msgid "Hello" +msgstr "" + ENTRY + end + + def test_translator_comment_multiple_lines + options = {:translator_comment => "Greeting\nfor morning"} + assert_equal <<-'ENTRY', entry("Hello", options).to_s +# Greeting +# for morning +msgid "Hello" +msgstr "" + ENTRY + end + + def test_extracted_comment_normal + options = {:extracted_comment => "Object"} + assert_equal <<-'ENTRY', entry("Hello", options).to_s +#. Object +msgid "Hello" +msgstr "" + ENTRY + end + + def test_extracted_comment_multiple_lines + options = {:extracted_comment => "Object\nMorning#greeting"} + assert_equal <<-'ENTRY', entry("Hello", options).to_s +#. Object +#. Morning#greeting +msgid "Hello" +msgstr "" + ENTRY + end + + def test_references_normal + options = {:references => [["lib/rdoc.rb", 29]]} + assert_equal <<-'ENTRY', entry("Hello", options).to_s +#: lib/rdoc.rb:29 +msgid "Hello" +msgstr "" + ENTRY + end + + def test_references_multiple + options = {:references => [["lib/rdoc.rb", 29], ["lib/rdoc/i18n.rb", 9]]} + assert_equal <<-'ENTRY', entry("Hello", options).to_s +#: lib/rdoc.rb:29 +#: lib/rdoc/i18n.rb:9 +msgid "Hello" +msgstr "" + ENTRY + end + + def test_flags_normal + options = {:flags => ["fuzzy"]} + assert_equal <<-'ENTRY', entry("Hello", options).to_s +#, fuzzy +msgid "Hello" +msgstr "" + ENTRY + end + + def test_flags_multiple + options = {:flags => ["fuzzy", "ruby-format"]} + assert_equal <<-'ENTRY', entry("Hello", options).to_s +#, fuzzy,ruby-format +msgid "Hello" +msgstr "" + ENTRY + end + + def test_full + options = { + :translator_comment => "Greeting", + :extracted_comment => "Morning#greeting", + :references => [["lib/rdoc.rb", 29]], + :flags => ["fuzzy"], + } + assert_equal <<-'ENTRY', entry("Hello", options).to_s +# Greeting +#. Morning#greeting +#: lib/rdoc.rb:29 +#, fuzzy +msgid "Hello" +msgstr "" + ENTRY + end + + private + def entry(msgid, options) + RDoc::Generator::POT::POEntry.new(msgid, options) + end + +end diff --git a/jni/ruby/test/rdoc/test_rdoc_generator_ri.rb b/jni/ruby/test/rdoc/test_rdoc_generator_ri.rb new file mode 100644 index 0000000..f8ac973 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_generator_ri.rb @@ -0,0 +1,78 @@ +require 'rdoc/test_case' + +class TestRDocGeneratorRI < RDoc::TestCase + + def setup + super + + @options = RDoc::Options.new + if Object.const_defined? :Encoding then + @options.encoding = Encoding::UTF_8 + @store.encoding = Encoding::UTF_8 + end + + @tmpdir = File.join Dir.tmpdir, "test_rdoc_generator_ri_#{$$}" + FileUtils.mkdir_p @tmpdir + + @g = RDoc::Generator::RI.new @store, @options + + @top_level = @store.add_file 'file.rb' + @klass = @top_level.add_class RDoc::NormalClass, 'Object' + + @meth = RDoc::AnyMethod.new nil, 'method' + @meth.record_location @top_level + + @meth_bang = RDoc::AnyMethod.new nil, 'method!' + @meth_bang.record_location @top_level + + @attr = RDoc::Attr.new nil, 'attr', 'RW', '' + @attr.record_location @top_level + + @klass.add_method @meth + @klass.add_method @meth_bang + @klass.add_attribute @attr + + Dir.chdir @tmpdir + end + + def teardown + super + + Dir.chdir @pwd + FileUtils.rm_rf @tmpdir + end + + def test_generate + @g.generate + + assert_file File.join(@tmpdir, 'cache.ri') + + assert_file File.join(@tmpdir, 'Object', 'cdesc-Object.ri') + + assert_file File.join(@tmpdir, 'Object', 'attr-i.ri') + assert_file File.join(@tmpdir, 'Object', 'method-i.ri') + assert_file File.join(@tmpdir, 'Object', 'method%21-i.ri') + + store = RDoc::RI::Store.new @tmpdir + store.load_cache + + encoding = Object.const_defined?(:Encoding) ? Encoding::UTF_8 : nil + + assert_equal encoding, store.encoding + end + + def test_generate_dry_run + @store.dry_run = true + @g = RDoc::Generator::RI.new @store, @options + + top_level = @store.add_file 'file.rb' + top_level.add_class @klass.class, @klass.name + + @g.generate + + refute_file File.join(@tmpdir, 'cache.ri') + refute_file File.join(@tmpdir, 'Object') + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_i18n_locale.rb b/jni/ruby/test/rdoc/test_rdoc_i18n_locale.rb new file mode 100644 index 0000000..69de88a --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_i18n_locale.rb @@ -0,0 +1,73 @@ +require 'rdoc/test_case' + +class TestRDocI18nLocale < RDoc::TestCase + + def setup + super + @locale = locale('fr') + + @tmpdir = File.join Dir.tmpdir, "test_rdoc_i18n_locale_#{$$}" + FileUtils.mkdir_p @tmpdir + + @locale_dir = @tmpdir + end + + def teardown + FileUtils.rm_rf @tmpdir + super + end + + def test_name + assert_equal 'fr', locale('fr').name + end + + def test_load_nonexistent_po + File.stub(:exist?, false) do + refute @locale.load('nonexsitent-locale') + end + end + + def test_load_existent_po + begin + require 'gettext/po_parser' + rescue LoadError + skip 'gettext gem is not found' + end + + fr_locale_dir = File.join @locale_dir, 'fr' + FileUtils.mkdir_p fr_locale_dir + File.open File.join(fr_locale_dir, 'rdoc.po'), 'w' do |po| + po.puts <<-PO +msgid "" +msgstr "" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "Hello" +msgstr "Bonjour" + PO + end + + assert @locale.load(@locale_dir) + assert_equal 'Bonjour', @locale.translate('Hello') + end + + def test_translate_existent_message + messages = @locale.instance_variable_get(:@messages) + messages['Hello'] = 'Bonjour' + assert_equal 'Bonjour', @locale.translate('Hello') + end + + def test_translate_nonexistent_message + assert_equal 'Hello', @locale.translate('Hello') + end + + private + + def locale(name) + RDoc::I18n::Locale.new(name) + end + +end diff --git a/jni/ruby/test/rdoc/test_rdoc_i18n_text.rb b/jni/ruby/test/rdoc/test_rdoc_i18n_text.rb new file mode 100644 index 0000000..c47f03c --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_i18n_text.rb @@ -0,0 +1,123 @@ +require 'rdoc/test_case' + +class TestRDocI18nText < RDoc::TestCase + + def test_multiple_paragraphs + paragraph1 = <<-PARAGRAPH.strip +RDoc produces HTML and command-line documentation for Ruby projects. RDoc +includes the +rdoc+ and +ri+ tools for generating and displaying documentation +from the command-line. + PARAGRAPH + + paragraph2 = <<-PARAGRAPH.strip +This command generates documentation for all the Ruby and C source +files in and below the current directory. These will be stored in a +documentation tree starting in the subdirectory +doc+. + PARAGRAPH + + raw = <<-RAW +#{paragraph1} + +#{paragraph2} + RAW + + expected = [ + { + :type => :paragraph, + :paragraph => paragraph1, + :line_no => 1, + }, + { + :type => :paragraph, + :paragraph => paragraph2, + :line_no => 5, + }, + ] + assert_equal expected, extract_messages(raw) + end + + def test_translate_multiple_paragraphs + paragraph1 = <<-PARAGRAPH.strip +Paragraph 1. + PARAGRAPH + paragraph2 = <<-PARAGRAPH.strip +Paragraph 2. + PARAGRAPH + + raw = <<-RAW +#{paragraph1} + +#{paragraph2} + RAW + + expected = <<-TRANSLATED +Paragraphe 1. + +Paragraphe 2. + TRANSLATED + assert_equal expected, translate(raw) + end + + def test_translate_not_transalted_message + nonexistent_paragraph = <<-PARAGRAPH.strip +Nonexistent paragraph. + PARAGRAPH + + raw = <<-RAW +#{nonexistent_paragraph} + RAW + + expected = <<-TRANSLATED +#{nonexistent_paragraph} + TRANSLATED + assert_equal expected, translate(raw) + end + + def test_translate_keep_empty_lines + raw = <<-RAW +Paragraph 1. + + + + +Paragraph 2. + RAW + + expected = <<-TRANSLATED +Paragraphe 1. + + + + +Paragraphe 2. + TRANSLATED + assert_equal expected, translate(raw) + end + + private + + def extract_messages(raw) + text = RDoc::I18n::Text.new(raw) + messages = [] + text.extract_messages do |message| + messages << message + end + messages + end + + def locale + locale = RDoc::I18n::Locale.new('fr') + messages = locale.instance_variable_get(:@messages) + messages['markdown'] = 'markdown (markdown in fr)' + messages['Hello'] = 'Bonjour (Hello in fr)' + messages['Paragraph 1.'] = 'Paragraphe 1.' + messages['Paragraph 2.'] = 'Paragraphe 2.' + locale + end + + def translate(raw) + text = RDoc::I18n::Text.new(raw) + text.translate(locale) + end + +end diff --git a/jni/ruby/test/rdoc/test_rdoc_include.rb b/jni/ruby/test/rdoc/test_rdoc_include.rb new file mode 100644 index 0000000..464a698 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_include.rb @@ -0,0 +1,108 @@ +require File.expand_path '../xref_test_case', __FILE__ + +class TestRDocInclude < XrefTestCase + + def setup + super + + @inc = RDoc::Include.new 'M1', 'comment' + @inc.parent = @m1 + @inc.record_location @top_level + @inc.store = @store + end + + def test_module + assert_equal @m1, @inc.module + assert_equal 'Unknown', RDoc::Include.new('Unknown', 'comment').module + end + + def test_module_extended + m1 = @xref_data.add_module RDoc::NormalModule, 'Mod1' + m1_m3 = m1.add_module RDoc::NormalModule, 'Mod3' + m1_m2 = m1.add_module RDoc::NormalModule, 'Mod2' + m1_m2_m3 = m1_m2.add_module RDoc::NormalModule, 'Mod3' + m1_m2_m3_m4 = m1_m2_m3.add_module RDoc::NormalModule, 'Mod4' + m1_m2_m4 = m1_m2.add_module RDoc::NormalModule, 'Mod4' + m1_m2_k0 = m1_m2.add_class RDoc::NormalClass, 'Klass0' + m1_m2_k0_m4 = m1_m2_k0.add_module RDoc::NormalModule, 'Mod4' + #m1_m2_k0_m4_m5 = m1_m2_k0_m4.add_module RDoc::NormalModule, 'Mod5' + m1_m2_k0_m4_m6 = m1_m2_k0_m4.add_module RDoc::NormalModule, 'Mod6' + m1_m2_k0_m5 = m1_m2_k0.add_module RDoc::NormalModule, 'Mod5' + + i0_m4 = RDoc::Include.new 'Mod4', nil + i0_m5 = RDoc::Include.new 'Mod5', nil + i0_m6 = RDoc::Include.new 'Mod6', nil + i0_m1 = RDoc::Include.new 'Mod1', nil + i0_m2 = RDoc::Include.new 'Mod2', nil + i0_m3 = RDoc::Include.new 'Mod3', nil + + m1_m2_k0.add_include i0_m4 + m1_m2_k0.add_include i0_m5 + m1_m2_k0.add_include i0_m6 + m1_m2_k0.add_include i0_m1 + m1_m2_k0.add_include i0_m2 + m1_m2_k0.add_include i0_m3 + + assert_equal [i0_m4, i0_m5, i0_m6, i0_m1, i0_m2, i0_m3], m1_m2_k0.includes + assert_equal [m1_m2_m3, m1_m2, m1, m1_m2_k0_m4_m6, m1_m2_k0_m5, + m1_m2_k0_m4, 'Object'], m1_m2_k0.ancestors + + m1_k1 = m1.add_class RDoc::NormalClass, 'Klass1' + + i1_m1 = RDoc::Include.new 'Mod1', nil + i1_m2 = RDoc::Include.new 'Mod2', nil + i1_m3 = RDoc::Include.new 'Mod3', nil + i1_m4 = RDoc::Include.new 'Mod4', nil + i1_k0_m4 = RDoc::Include.new 'Klass0::Mod4', nil + + m1_k1.add_include i1_m1 + m1_k1.add_include i1_m2 + m1_k1.add_include i1_m3 + m1_k1.add_include i1_m4 + m1_k1.add_include i1_k0_m4 + + assert_equal [i1_m1, i1_m2, i1_m3, i1_m4, i1_k0_m4], m1_k1.includes + assert_equal [m1_m2_k0_m4, m1_m2_m3_m4, m1_m2_m3, m1_m2, m1, 'Object'], + m1_k1.ancestors + + m1_k2 = m1.add_class RDoc::NormalClass, 'Klass2' + + i2_m1 = RDoc::Include.new 'Mod1', nil + i2_m2 = RDoc::Include.new 'Mod2', nil + i2_m3 = RDoc::Include.new 'Mod3', nil + i2_k0_m4 = RDoc::Include.new 'Klass0::Mod4', nil + + m1_k2.add_include i2_m1 + m1_k2.add_include i2_m3 + m1_k2.add_include i2_m2 + m1_k2.add_include i2_k0_m4 + + assert_equal [i2_m1, i2_m3, i2_m2, i2_k0_m4], m1_k2.includes + assert_equal [m1_m2_k0_m4, m1_m2, m1_m3, m1, 'Object'], m1_k2.ancestors + + m1_k3 = m1.add_class RDoc::NormalClass, 'Klass3' + + i3_m1 = RDoc::Include.new 'Mod1', nil + i3_m2 = RDoc::Include.new 'Mod2', nil + i3_m4 = RDoc::Include.new 'Mod4', nil + + m1_k3.add_include i3_m1 + m1_k3.add_include i3_m2 + m1_k3.add_include i3_m4 + + assert_equal [i3_m1, i3_m2, i3_m4], m1_k3.includes + assert_equal [m1_m2_m4, m1_m2, m1, 'Object'], m1_k3.ancestors + end + + def test_store_equals + incl = RDoc::Include.new 'M', nil + incl.record_location RDoc::TopLevel.new @top_level.name + + incl.store = @store + + assert_same @top_level, incl.file + assert_same @store, incl.file.store + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_markdown.rb b/jni/ruby/test/rdoc/test_rdoc_markdown.rb new file mode 100644 index 0000000..ea5dc73 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_markdown.rb @@ -0,0 +1,980 @@ +# coding: UTF-8 + +require 'rdoc/test_case' +require 'rdoc/markup/block_quote' +require 'rdoc/markdown' + +class TestRDocMarkdown < RDoc::TestCase + + def setup + @RM = RDoc::Markup + + @parser = RDoc::Markdown.new + + @to_html = RDoc::Markup::ToHtml.new(RDoc::Options.new, nil) + end + + def test_class_parse + doc = RDoc::Markdown.parse "hello\n\nworld" + + expected = doc(para("hello"), para("world")) + + assert_equal expected, doc + end + + def test_emphasis + assert_equal '_word_', @parser.emphasis('word') + assert_equal '<em>two words</em>', @parser.emphasis('two words') + assert_equal '<em>*bold*</em>', @parser.emphasis('*bold*') + end + + def test_parse_auto_link_email + doc = parse "Autolink: <nobody-0+_./!%~$@example>" + + expected = doc(para("Autolink: mailto:nobody-0+_./!%~$@example")) + + assert_equal expected, doc + end + + def test_parse_auto_link_url + doc = parse "Autolink: <http://example>" + + expected = doc(para("Autolink: http://example")) + + assert_equal expected, doc + end + + def test_parse_block_quote + doc = parse <<-BLOCK_QUOTE +> this is +> a block quote + BLOCK_QUOTE + + expected = + doc( + block( + para("this is\na block quote"))) + + assert_equal expected, doc + end + + def test_parse_block_quote_continue + doc = parse <<-BLOCK_QUOTE +> this is +a block quote + BLOCK_QUOTE + + expected = + doc( + block( + para("this is\na block quote"))) + + assert_equal expected, doc + end + + def test_parse_block_quote_list + doc = parse <<-BLOCK_QUOTE +> text +> +> * one +> * two + BLOCK_QUOTE + + expected = + doc( + block( + para("text"), + list(:BULLET, + item(nil, para("one")), + item(nil, para("two"))))) + + assert_equal expected, doc + end + + def test_parse_block_quote_newline + doc = parse <<-BLOCK_QUOTE +> this is +a block quote + + BLOCK_QUOTE + + expected = + doc( + block( + para("this is\na block quote"))) + + assert_equal expected, doc + end + + def test_parse_block_quote_separate + doc = parse <<-BLOCK_QUOTE +> this is +a block quote + +> that continues + BLOCK_QUOTE + + expected = + doc( + block( + para("this is\na block quote"), + para("that continues"))) + + assert_equal expected, doc + end + + def test_parse_char_entity + doc = parse 'π &nn;' + + expected = doc(para('π &nn;')) + + assert_equal expected, doc + end + + def test_parse_code + doc = parse "Code: `text`" + + expected = doc(para("Code: <code>text</code>")) + + assert_equal expected, doc + end + + def test_parse_code_github + doc = parse <<-MD +Example: + +``` +code goes here +``` + MD + + expected = + doc( + para("Example:"), + verb("code goes here\n")) + + assert_equal expected, doc + end + + def test_parse_code_github_format + doc = parse <<-MD +Example: + +``` ruby +code goes here +``` + MD + + code = verb("code goes here\n") + code.format = :ruby + + expected = + doc( + para("Example:"), + code) + + assert_equal expected, doc + end + + def test_parse_definition_list + doc = parse <<-MD +one +: This is a definition + +two +: This is another definition + MD + + expected = doc( + list(:NOTE, + item(%w[one], para("This is a definition")), + item(%w[two], para("This is another definition")))) + + assert_equal expected, doc + end + + def test_parse_definition_list_indents + doc = parse <<-MD +zero +: Indented zero characters + +one + : Indented one characters + +two + : Indented two characters + +three + : Indented three characters + +four + : Indented four characters + + MD + + expected = doc( + list(:NOTE, + item(%w[zero], para("Indented zero characters")), + item(%w[one], para("Indented one characters")), + item(%w[two], para("Indented two characters")), + item(%w[three], para("Indented three characters"))), + para("four\n : Indented four characters")) + + assert_equal expected, doc + end + + def test_parse_definition_list_multi_description + doc = parse <<-MD +label +: This is a definition + +: This is another definition + MD + + expected = doc( + list(:NOTE, + item(%w[label], para("This is a definition")), + item(nil, para("This is another definition")))) + + assert_equal expected, doc + end + + def test_parse_definition_list_multi_label + doc = parse <<-MD +one +two +: This is a definition + MD + + expected = doc( + list(:NOTE, + item(%w[one two], para("This is a definition")))) + + assert_equal expected, doc + end + + def test_parse_definition_list_multi_line + doc = parse <<-MD +one +: This is a definition +that extends to two lines + +two +: This is another definition +that also extends to two lines + MD + + expected = doc( + list(:NOTE, + item(%w[one], + para("This is a definition\nthat extends to two lines")), + item(%w[two], + para("This is another definition\nthat also extends to two lines")))) + + assert_equal expected, doc + end + + def test_parse_definition_list_no + @parser.definition_lists = false + + doc = parse <<-MD +one +: This is a definition + +two +: This is another definition + MD + + expected = doc( + para("one\n: This is a definition"), + para("two\n: This is another definition")) + + assert_equal expected, doc + end + + def test_parse_entity_dec + doc = parse "Entity: A" + + expected = doc(para("Entity: A")) + + assert_equal expected, doc + end + + def test_parse_entity_hex + doc = parse "Entity: A" + + expected = doc(para("Entity: A")) + + assert_equal expected, doc + end + + def test_parse_entity_named + doc = parse "Entity: π" + + expected = doc(para("Entity: π")) + + assert_equal expected, doc + end + + def test_parse_emphasis_star + doc = parse "it *works*\n" + + expected = @RM::Document.new( + @RM::Paragraph.new("it _works_")) + + assert_equal expected, doc + end + + def test_parse_emphasis_underscore + doc = parse "it _works_\n" + + expected = + doc( + para("it _works_")) + + assert_equal expected, doc + end + + def test_parse_emphasis_underscore_embedded + doc = parse "foo_bar bar_baz\n" + + expected = + doc( + para("foo_bar bar_baz")) + + assert_equal expected, doc + end + + def test_parse_emphasis_underscore_in_word + doc = parse "it foo_bar_baz\n" + + expected = + doc( + para("it foo_bar_baz")) + + assert_equal expected, doc + end + + def test_parse_escape + assert_equal doc(para("Backtick: `")), parse("Backtick: \\`") + + assert_equal doc(para("Backslash: \\")), parse("Backslash: \\\\") + + assert_equal doc(para("Colon: :")), parse("Colon: \\:") + end + + def test_parse_heading_atx + doc = parse "# heading\n" + + expected = @RM::Document.new( + @RM::Heading.new(1, "heading")) + + assert_equal expected, doc + end + + def test_parse_heading_setext_dash + doc = parse <<-MD +heading +--- + MD + + expected = @RM::Document.new( + @RM::Heading.new(2, "heading")) + + assert_equal expected, doc + end + + def test_parse_heading_setext_equals + doc = parse <<-MD +heading +=== + MD + + expected = @RM::Document.new( + @RM::Heading.new(1, "heading")) + + assert_equal expected, doc + end + + def test_parse_html + @parser.html = true + + doc = parse "<address>Links here</address>\n" + + expected = doc( + @RM::Raw.new("<address>Links here</address>")) + + assert_equal expected, doc + end + + def test_parse_html_hr + @parser.html = true + + doc = parse "<hr>\n" + + expected = doc(raw("<hr>")) + + assert_equal expected, doc + end + + def test_parse_html_no_html + @parser.html = false + + doc = parse "<address>Links here</address>\n" + + expected = doc() + + assert_equal expected, doc + end + + def test_parse_image + doc = parse "image ![alt text](path/to/image.jpg)" + + expected = doc(para("image rdoc-image:path/to/image.jpg")) + + assert_equal expected, doc + end + + def test_parse_image_link + @parser.html = true + + doc = parse "[![alt text](path/to/image.jpg)](http://example.com)" + + expected = + doc( + para('{rdoc-image:path/to/image.jpg}[http://example.com]')) + + assert_equal expected, doc + end + + def test_parse_line_break + doc = parse "Some text \nwith extra lines" + + expected = doc( + para("Some text", hard_break, "with extra lines")) + + assert_equal expected, doc + end + + def test_parse_link_reference_id + doc = parse <<-MD +This is [an example][id] reference-style link. + +[id]: http://example.com "Optional Title Here" + MD + + expected = doc( + para("This is {an example}[http://example.com] reference-style link.")) + + assert_equal expected, doc + end + + def test_parse_link_reference_id_adjacent + doc = parse <<-MD +[this] [this] should work + +[this]: example + MD + + expected = doc( + para("{this}[example] should work")) + + assert_equal expected, doc + end + + def test_parse_link_reference_id_eof + doc = parse <<-MD.chomp +This is [an example][id] reference-style link. + +[id]: http://example.com "Optional Title Here" + MD + + expected = doc( + para("This is {an example}[http://example.com] reference-style link.")) + + assert_equal expected, doc + end + + def test_parse_link_reference_id_many + doc = parse <<-MD +This is [an example][id] reference-style link. + +And [another][id]. + +[id]: http://example.com "Optional Title Here" + MD + + expected = doc( + para("This is {an example}[http://example.com] reference-style link."), + para("And {another}[http://example.com].")) + + assert_equal expected, doc + end + + def test_parse_link_reference_implicit + doc = parse <<-MD +This is [an example][] reference-style link. + +[an example]: http://example.com "Optional Title Here" + MD + + expected = doc( + para("This is {an example}[http://example.com] reference-style link.")) + + assert_equal expected, doc + end + + def test_parse_list_bullet + doc = parse <<-MD +* one +* two + MD + + expected = doc( + list(:BULLET, + item(nil, para("one")), + item(nil, para("two")))) + + assert_equal expected, doc + end + + def test_parse_list_bullet_auto_link + doc = parse <<-MD +* <http://example/> + MD + + expected = doc( + list(:BULLET, + item(nil, para("http://example/")))) + + assert_equal expected, doc + end + + def test_parse_list_bullet_continue + doc = parse <<-MD +* one + +* two + MD + + expected = doc( + list(:BULLET, + item(nil, para("one")), + item(nil, para("two")))) + + assert_equal expected, doc + end + + def test_parse_list_bullet_multiline + doc = parse <<-MD +* one + two + MD + + expected = doc( + list(:BULLET, + item(nil, para("one\n two")))) + + assert_equal expected, doc + end + + def test_parse_list_bullet_nest + doc = parse <<-MD +* outer + * inner + MD + + expected = doc( + list(:BULLET, + item(nil, + para("outer"), + list(:BULLET, + item(nil, + para("inner")))))) + + assert_equal expected, doc + end + + def test_parse_list_bullet_nest_loose + doc = parse <<-MD +* outer + + * inner + MD + + expected = doc( + list(:BULLET, + item(nil, + para("outer"), + list(:BULLET, + item(nil, para("inner")))))) + + assert_equal expected, doc + end + + def test_parse_list_bullet_nest_continue + doc = parse <<-MD +* outer + * inner + continue inner +* outer 2 + MD + + expected = doc( + list(:BULLET, + item(nil, + para("outer"), + list(:BULLET, + item(nil, + para("inner\n continue inner")))), + item(nil, + para("outer 2")))) + + assert_equal expected, doc + end + + def test_parse_list_number + doc = parse <<-MD +1. one +1. two + MD + + expected = doc( + list(:NUMBER, + item(nil, para("one")), + item(nil, para("two")))) + + assert_equal expected, doc + end + + def test_parse_list_number_continue + doc = parse <<-MD +1. one + +1. two + MD + + expected = doc( + list(:NUMBER, + item(nil, para("one")), + item(nil, para("two")))) + + assert_equal expected, doc + end + + def test_parse_note + @parser.notes = true + + doc = parse <<-MD +Some text.[^1] + +[^1]: With a footnote + MD + + expected = doc( + para("Some text.{*1}[rdoc-label:foottext-1:footmark-1]"), + @RM::Rule.new(1), + para("{^1}[rdoc-label:footmark-1:foottext-1] With a footnote")) + + assert_equal expected, doc + end + + def test_parse_note_indent + @parser.notes = true + + doc = parse <<-MD +Some text.[^1] + +[^1]: With a footnote + + more + MD + + expected = doc( + para("Some text.{*1}[rdoc-label:foottext-1:footmark-1]"), + rule(1), + para("{^1}[rdoc-label:footmark-1:foottext-1] With a footnote\n\nmore")) + + assert_equal expected, doc + end + + def test_parse_note_inline + @parser.notes = true + + doc = parse <<-MD +Some text. ^[With a footnote] + MD + + expected = doc( + para("Some text. {*1}[rdoc-label:foottext-1:footmark-1]"), + @RM::Rule.new(1), + para("{^1}[rdoc-label:footmark-1:foottext-1] With a footnote")) + + assert_equal expected, doc + end + + def test_parse_note_no_notes + @parser.notes = false + + assert_raises RuntimeError do # TODO use a real error + parse "Some text.[^1]" + end + end + + def test_parse_note_multiple + @parser.notes = true + + doc = parse <<-MD +Some text[^1] +with inline notes^[like this] +and an extra note.[^2] + +[^1]: With a footnote + +[^2]: Which should be numbered correctly + MD + + expected = doc( + para("Some text{*1}[rdoc-label:foottext-1:footmark-1]\n" + + "with inline notes{*2}[rdoc-label:foottext-2:footmark-2]\n" + + "and an extra note.{*3}[rdoc-label:foottext-3:footmark-3]"), + + rule(1), + + para("{^1}[rdoc-label:footmark-1:foottext-1] With a footnote"), + para("{^2}[rdoc-label:footmark-2:foottext-2] like this"), + para("{^3}[rdoc-label:footmark-3:foottext-3] " + + "Which should be numbered correctly")) + + assert_equal expected, doc + end + + def test_parse_paragraph + doc = parse "it worked\n" + + expected = doc(para("it worked")) + + assert_equal expected, doc + end + + def test_parse_paragraph_break_on_newline + @parser.break_on_newline = true + + doc = parse "one\ntwo\n" + + expected = doc(para("one", hard_break, "two")) + + assert_equal expected, doc + + doc = parse "one \ntwo\nthree\n" + + expected = doc(para("one", hard_break, "two", hard_break, "three")) + + assert_equal expected, doc + end + + def test_parse_paragraph_stars + doc = parse "it worked ****\n" + + expected = @RM::Document.new( + @RM::Paragraph.new("it worked ****")) + + assert_equal expected, doc + end + + def test_parse_paragraph_html + @parser.html = true + + doc = parse "<address>Links here</address>" + + expected = doc(raw("<address>Links here</address>")) + + assert_equal expected, doc + end + + def test_parse_paragraph_html_no_html + @parser.html = false + + doc = parse "<address>Links here</address>" + + expected = doc() + + assert_equal expected, doc + end + + def test_parse_paragraph_indent_one + doc = parse <<-MD + text + MD + + expected = doc(para("text")) + + assert_equal expected, doc + end + + def test_parse_paragraph_indent_two + doc = parse <<-MD + text + MD + + expected = doc(para("text")) + + assert_equal expected, doc + end + + def test_parse_paragraph_indent_three + doc = parse <<-MD + text + MD + + expected = doc(para("text")) + + assert_equal expected, doc + end + + def test_parse_paragraph_multiline + doc = parse "one\ntwo" + + expected = doc(para("one\ntwo")) + + assert_equal expected, doc + end + + def test_parse_paragraph_two + doc = parse "one\n\ntwo" + + expected = @RM::Document.new( + @RM::Paragraph.new("one"), + @RM::Paragraph.new("two")) + + assert_equal expected, doc + end + + def test_parse_plain + doc = parse "it worked" + + expected = @RM::Document.new( + @RM::Paragraph.new("it worked")) + + assert_equal expected, doc + end + + def test_parse_reference_link_embedded_bracket + doc = parse "With [embedded [brackets]] [b].\n\n[b]: /url/\n" + + expected = + doc( + para("With {embedded [brackets]}[/url/].")) + + assert_equal expected, doc + end + + def test_parse_rule_dash + doc = parse "- - -\n\n" + + expected = @RM::Document.new(@RM::Rule.new(1)) + + assert_equal expected, doc + end + + def test_parse_rule_underscore + doc = parse "_ _ _\n\n" + + expected = @RM::Document.new(@RM::Rule.new(1)) + + assert_equal expected, doc + end + + def test_parse_rule_star + doc = parse "* * *\n\n" + + expected = @RM::Document.new(@RM::Rule.new(1)) + + assert_equal expected, doc + end + + def test_parse_strong_star + doc = parse "it **works**\n" + + expected = @RM::Document.new( + @RM::Paragraph.new("it *works*")) + + assert_equal expected, doc + end + + def test_parse_strong_underscore + doc = parse "it __works__\n" + + expected = @RM::Document.new( + @RM::Paragraph.new("it *works*")) + + assert_equal expected, doc + end + + def test_parse_strong_emphasis_star + doc = parse "it ***works***\n" + + expected = @RM::Document.new( + @RM::Paragraph.new("it <b>_works_</b>")) + + assert_equal expected, doc + end + + def test_parse_strong_emphasis_underscore + doc = parse "it ___works___\n" + + expected = @RM::Document.new( + @RM::Paragraph.new("it <b>_works_</b>")) + + assert_equal expected, doc + end + + def test_parse_style + @parser.css = true + + doc = parse "<style>h1 { color: red }</style>\n" + + expected = doc( + @RM::Raw.new("<style>h1 { color: red }</style>")) + + assert_equal expected, doc + end + + def test_parse_style_disabled + doc = parse "<style>h1 { color: red }</style>\n" + + expected = doc() + + assert_equal expected, doc + end + + def test_parse_verbatim + doc = parse <<-MD + text + MD + + expected = doc(verb("text\n")) + + assert_equal expected, doc + end + + def test_parse_verbatim_eof + doc = parse " text" + + expected = doc(verb("text\n")) + + assert_equal expected, doc + end + + def test_strong + assert_equal '*word*', @parser.strong('word') + assert_equal '<b>two words</b>', @parser.strong('two words') + assert_equal '<b>_emphasis_</b>', @parser.strong('_emphasis_') + end + + def parse text + @parser.parse text + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_markdown_test.rb b/jni/ruby/test/rdoc/test_rdoc_markdown_test.rb new file mode 100644 index 0000000..d464cba --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_markdown_test.rb @@ -0,0 +1,1884 @@ +require 'rubygems' +require 'minitest/autorun' +require 'pp' + +require 'rdoc' +require 'rdoc/markdown' + +class TestRDocMarkdownTest < RDoc::TestCase + + MARKDOWN_TEST_PATH = File.expand_path '../MarkdownTest_1.0.3/', __FILE__ + + def setup + super + + @parser = RDoc::Markdown.new + end + + def test_amps_and_angle_encoding + input = File.read "#{MARKDOWN_TEST_PATH}/Amps and angle encoding.text" + + doc = @parser.parse input + + expected = + doc( + para("AT&T has an ampersand in their name."), + para("AT&T is another way to write it."), + para("This & that."), + para("4 < 5."), + para("6 > 5."), + para("Here's a {link}[http://example.com/?foo=1&bar=2] with " + + "an ampersand in the URL."), + para("Here's a link with an amersand in the link text: " + + "{AT&T}[http://att.com/]."), + para("Here's an inline {link}[/script?foo=1&bar=2]."), + para("Here's an inline {link}[/script?foo=1&bar=2].")) + + assert_equal expected, doc + end + + def test_auto_links + input = File.read "#{MARKDOWN_TEST_PATH}/Auto links.text" + + doc = @parser.parse input + + # TODO verify rdoc auto-links too + expected = + doc( + para("Link: http://example.com/."), + para("With an ampersand: http://example.com/?foo=1&bar=2"), + list(:BULLET, + item(nil, para("In a list?")), + item(nil, para("http://example.com/")), + item(nil, para("It should."))), + block( + para("Blockquoted: http://example.com/")), + para("Auto-links should not occur here: " + + "<code><http://example.com/></code>"), + verb("or here: <http://example.com/>\n")) + + assert_equal expected, doc + end + + def test_backslash_escapes + input = File.read "#{MARKDOWN_TEST_PATH}/Backslash escapes.text" + + doc = @parser.parse input + + expected = + doc( + para("These should all get escaped:"), + + para("Backslash: \\"), + para("Backtick: `"), + para("Asterisk: *"), + para("Underscore: _"), + para("Left brace: {"), + para("Right brace: }"), + para("Left bracket: ["), + para("Right bracket: ]"), + para("Left paren: ("), + para("Right paren: )"), + para("Greater-than: >"), + para("Hash: #"), + para("Period: ."), + para("Bang: !"), + para("Plus: +"), + para("Minus: -"), + + para("These should not, because they occur within a code block:"), + + verb("Backslash: \\\\\n", + "\n", + "Backtick: \\`\n", + "\n", + "Asterisk: \\*\n", + "\n", + "Underscore: \\_\n", + "\n", + "Left brace: \\{\n", + "\n", + "Right brace: \\}\n", + "\n", + "Left bracket: \\[\n", + "\n", + "Right bracket: \\]\n", + "\n", + "Left paren: \\(\n", + "\n", + "Right paren: \\)\n", + "\n", + "Greater-than: \\>\n", + "\n", + "Hash: \\#\n", + "\n", + "Period: \\.\n", + "\n", + "Bang: \\!\n", + "\n", + "Plus: \\+\n", + "\n", + "Minus: \\-\n"), + + para("Nor should these, which occur in code spans:"), + + para("Backslash: <code>\\\\</code>"), + para("Backtick: <code>\\`</code>"), + para("Asterisk: <code>\\*</code>"), + para("Underscore: <code>\\_</code>"), + para("Left brace: <code>\\{</code>"), + para("Right brace: <code>\\}</code>"), + para("Left bracket: <code>\\[</code>"), + para("Right bracket: <code>\\]</code>"), + para("Left paren: <code>\\(</code>"), + para("Right paren: <code>\\)</code>"), + para("Greater-than: <code>\\></code>"), + para("Hash: <code>\\#</code>"), + para("Period: <code>\\.</code>"), + para("Bang: <code>\\!</code>"), + para("Plus: <code>\\+</code>"), + para("Minus: <code>\\-</code>"), + + para("These should get escaped, even though they're matching pairs for\n" + + "other Markdown constructs:"), + + para("\*asterisks\*"), + para("\_underscores\_"), + para("`backticks`"), + + para("This is a code span with a literal backslash-backtick " + + "sequence: <code>\\`</code>"), + + para("This is a tag with unescaped backticks " + + "<span attr='`ticks`'>bar</span>."), + + para("This is a tag with backslashes " + + "<span attr='\\\\backslashes\\\\'>bar</span>.")) + + assert_equal expected, doc + end + + def test_blockquotes_with_code_blocks + input = File.read "#{MARKDOWN_TEST_PATH}/Blockquotes with code blocks.text" + + doc = @parser.parse input + + expected = + doc( + block( + para("Example:"), + verb("sub status {\n", + " print \"working\";\n", + "}\n"), + para("Or:"), + verb("sub status {\n", + " return \"working\";\n", + "}\n"))) + + assert_equal expected, doc + end + + def test_code_blocks + input = File.read "#{MARKDOWN_TEST_PATH}/Code Blocks.text" + + doc = @parser.parse input + + expected = + doc( + verb("code block on the first line\n"), + para("Regular text."), + + verb("code block indented by spaces\n"), + para("Regular text."), + + verb("the lines in this block \n", + "all contain trailing spaces \n"), + para("Regular Text."), + + verb("code block on the last line\n")) + + assert_equal expected, doc + end + + def test_code_spans + input = File.read "#{MARKDOWN_TEST_PATH}/Code Spans.text" + + doc = @parser.parse input + + expected = doc( + para("<code><test a=\"</code> content of attribute <code>\"></code>"), + para("Fix for backticks within HTML tag: " + + "<span attr='`ticks`'>like this</span>"), + para("Here's how you put <code>`backticks`</code> in a code span.")) + + assert_equal expected, doc + end + + def test_hard_wrapped_paragraphs_with_list_like_lines + input = File.read "#{MARKDOWN_TEST_PATH}/Hard-wrapped paragraphs with list-like lines.text" + + doc = @parser.parse input + + expected = + doc( + para("In Markdown 1.0.0 and earlier. Version\n" + + "8. This line turns into a list item.\n" + + "Because a hard-wrapped line in the\n" + + "middle of a paragraph looked like a\n" + + "list item."), + para("Here's one with a bullet.\n" + + "* criminey.")) + + assert_equal expected, doc + end + + def test_horizontal_rules + input = File.read "#{MARKDOWN_TEST_PATH}/Horizontal rules.text" + + doc = @parser.parse input + + expected = + doc( + para("Dashes:"), + + rule(1), + rule(1), + rule(1), + rule(1), + verb("---\n"), + + rule(1), + rule(1), + rule(1), + rule(1), + verb("- - -\n"), + + para("Asterisks:"), + + rule(1), + rule(1), + rule(1), + rule(1), + verb("***\n"), + + rule(1), + rule(1), + rule(1), + rule(1), + verb("* * *\n"), + + para("Underscores:"), + + rule(1), + rule(1), + rule(1), + rule(1), + verb("___\n"), + + rule(1), + rule(1), + rule(1), + rule(1), + verb("_ _ _\n")) + + assert_equal expected, doc + end + + def test_inline_html_advanced + input = File.read "#{MARKDOWN_TEST_PATH}/Inline HTML (Advanced).text" + + @parser.html = true + + doc = @parser.parse input + + expected = + doc( + para("Simple block on one line:"), + raw("<div>foo</div>"), + para("And nested without indentation:"), + raw(<<-RAW.chomp)) +<div> +<div> +<div> +foo +</div> +<div style=">"/> +</div> +<div>bar</div> +</div> + RAW + + assert_equal expected, doc + end + + def test_inline_html_simple + input = File.read "#{MARKDOWN_TEST_PATH}/Inline HTML (Simple).text" + + @parser.html = true + + doc = @parser.parse input + + expected = + doc( + para("Here's a simple block:"), + raw("<div>\n\tfoo\n</div>"), + + para("This should be a code block, though:"), + verb("<div>\n", + "\tfoo\n", + "</div>\n"), + + para("As should this:"), + verb("<div>foo</div>\n"), + + para("Now, nested:"), + raw("<div>\n\t<div>\n\t\t<div>\n\t\t\tfoo\n" + + "\t\t</div>\n\t</div>\n</div>"), + + para("This should just be an HTML comment:"), + raw("<!-- Comment -->"), + + para("Multiline:"), + raw("<!--\nBlah\nBlah\n-->"), + + para("Code block:"), + verb("<!-- Comment -->\n"), + + para("Just plain comment, with trailing spaces on the line:"), + raw("<!-- foo -->"), + + para("Code:"), + verb("<hr />\n"), + + para("Hr's:"), + raw("<hr>"), + raw("<hr/>"), + raw("<hr />"), + + raw("<hr>"), + raw("<hr/>"), + raw("<hr />"), + + raw("<hr class=\"foo\" id=\"bar\" />"), + raw("<hr class=\"foo\" id=\"bar\"/>"), + raw("<hr class=\"foo\" id=\"bar\" >")) + + assert_equal expected, doc + end + + def test_inline_html_comments + input = File.read "#{MARKDOWN_TEST_PATH}/Inline HTML comments.text" + + doc = @parser.parse input + + expected = + doc( + para("Paragraph one."), + + raw("<!-- This is a simple comment -->"), + + raw("<!--\n\tThis is another comment.\n-->"), + + para("Paragraph two."), + + raw("<!-- one comment block -- -- with two comments -->"), + + para("The end.")) + + assert_equal expected, doc + end + + def test_links_inline_style + input = File.read "#{MARKDOWN_TEST_PATH}/Links, inline style.text" + + doc = @parser.parse input + + expected = + doc( + para("Just a {URL}[/url/]."), + para("{URL and title}[/url/]."), + para("{URL and title}[/url/]."), + para("{URL and title}[/url/]."), + para("{URL and title}[/url/]."), + para("{Empty}[].")) + + assert_equal expected, doc + end + + def test_links_reference_style + input = File.read "#{MARKDOWN_TEST_PATH}/Links, reference style.text" + + doc = @parser.parse input + + expected = + doc( + para("Foo {bar}[/url/]."), + para("Foo {bar}[/url/]."), + para("Foo {bar}[/url/]."), + + para("With {embedded [brackets]}[/url/]."), + + para("Indented {once}[/url]."), + para("Indented {twice}[/url]."), + para("Indented {thrice}[/url]."), + para("Indented [four][] times."), + + verb("[four]: /url\n"), + + rule(1), + + para("{this}[foo] should work"), + para("So should {this}[foo]."), + para("And {this}[foo]."), + para("And {this}[foo]."), + para("And {this}[foo]."), + + para("But not [that] []."), + para("Nor [that][]."), + para("Nor [that]."), + + para("[Something in brackets like {this}[foo] should work]"), + para("[Same with {this}[foo].]"), + + para("In this case, {this}[/somethingelse/] points to something else."), + para("Backslashing should suppress [this] and [this]."), + + rule(1), + + para("Here's one where the {link breaks}[/url/] across lines."), + para("Here's another where the {link breaks}[/url/] across lines, " + + "but with a line-ending space.")) + + assert_equal expected, doc + end + + def test_links_shortcut_references + input = File.read "#{MARKDOWN_TEST_PATH}/Links, shortcut references.text" + + doc = @parser.parse input + + expected = + doc( + para("This is the {simple case}[/simple]."), + para("This one has a {line break}[/foo]."), + para("This one has a {line break}[/foo] with a line-ending space."), + para("{this}[/that] and the {other}[/other]")) + + assert_equal expected, doc + end + + def test_literal_quotes_in_titles + input = File.read "#{MARKDOWN_TEST_PATH}/Literal quotes in titles.text" + + doc = @parser.parse input + + # TODO support title attribute + expected = + doc( + para("Foo {bar}[/url/]."), + para("Foo {bar}[/url/].")) + + assert_equal expected, doc + end + + def test_markdown_documentation_basics + input = File.read "#{MARKDOWN_TEST_PATH}/Markdown Documentation - Basics.text" + + doc = @parser.parse input + + expected = + doc( + head(1, "Markdown: Basics"), + + raw(<<-RAW.chomp), +<ul id="ProjectSubmenu"> + <li><a href="/projects/markdown/" title="Markdown Project Page">Main</a></li> + <li><a class="selected" title="Markdown Basics">Basics</a></li> + <li><a href="/projects/markdown/syntax" title="Markdown Syntax Documentation">Syntax</a></li> + <li><a href="/projects/markdown/license" title="Pricing and License Information">License</a></li> + <li><a href="/projects/markdown/dingus" title="Online Markdown Web Form">Dingus</a></li> +</ul> + RAW + + head(2, "Getting the Gist of Markdown's Formatting Syntax"), + + para("This page offers a brief overview of what it's like to use Markdown.\n" + + "The {syntax page}[/projects/markdown/syntax] provides complete, detailed documentation for\n" + + "every feature, but Markdown should be very easy to pick up simply by\n" + + "looking at a few examples of it in action. The examples on this page\n" + + "are written in a before/after style, showing example syntax and the\n" + + "HTML output produced by Markdown."), + + para("It's also helpful to simply try Markdown out; the {Dingus}[/projects/markdown/dingus] is a\n" + + "web application that allows you type your own Markdown-formatted text\n" + + "and translate it to XHTML."), + + para("<b>Note:</b> This document is itself written using Markdown; you\n" + + "can {see the source for it by adding '.text' to the URL}[/projects/markdown/basics.text]."), + + head(2, "Paragraphs, Headers, Blockquotes"), + + para("A paragraph is simply one or more consecutive lines of text, separated\n" + + "by one or more blank lines. (A blank line is any line that looks like a\n" + + "blank line -- a line containing nothing spaces or tabs is considered\n" + + "blank.) Normal paragraphs should not be intended with spaces or tabs."), + + para("Markdown offers two styles of headers: _Setext_ and _atx_.\n" + + "Setext-style headers for <code><h1></code> and <code><h2></code> are created by\n" + + "\"underlining\" with equal signs (<code>=</code>) and hyphens (<code>-</code>), respectively.\n" + + "To create an atx-style header, you put 1-6 hash marks (<code>#</code>) at the\n" + + "beginning of the line -- the number of hashes equals the resulting\n" + + "HTML header level."), + + para("Blockquotes are indicated using email-style '<code>></code>' angle brackets."), + + para("Markdown:"), + + verb("A First Level Header\n", + "====================\n", + "\n", + "A Second Level Header\n", + "---------------------\n", + "\n", + "Now is the time for all good men to come to\n", + "the aid of their country. This is just a\n", + "regular paragraph.\n", + "\n", + "The quick brown fox jumped over the lazy\n", + "dog's back.\n", + "\n", + "### Header 3\n", + "\n", + "> This is a blockquote.\n", + "> \n", + "> This is the second paragraph in the blockquote.\n", + ">\n", + "> ## This is an H2 in a blockquote\n"), + + para("Output:"), + + verb("<h1>A First Level Header</h1>\n", + "\n", + "<h2>A Second Level Header</h2>\n", + "\n", + "<p>Now is the time for all good men to come to\n", + "the aid of their country. This is just a\n", + "regular paragraph.</p>\n", + "\n", + "<p>The quick brown fox jumped over the lazy\n", + "dog's back.</p>\n", + "\n", + "<h3>Header 3</h3>\n", + "\n", + "<blockquote>\n", + " <p>This is a blockquote.</p>\n", + "\n", + " <p>This is the second paragraph in the blockquote.</p>\n", + "\n", + " <h2>This is an H2 in a blockquote</h2>\n", + "</blockquote>\n"), + + head(3, "Phrase Emphasis"), + para("Markdown uses asterisks and underscores to indicate spans of emphasis."), + + para("Markdown:"), + + verb("Some of these words *are emphasized*.\n", + "Some of these words _are emphasized also_.\n", + "\n", + "Use two asterisks for **strong emphasis**.\n", + "Or, if you prefer, __use two underscores instead__.\n"), + + para("Output:"), + + verb("<p>Some of these words <em>are emphasized</em>.\n", + "Some of these words <em>are emphasized also</em>.</p>\n", + "\n", + "<p>Use two asterisks for <strong>strong emphasis</strong>.\n", + "Or, if you prefer, <strong>use two underscores instead</strong>.</p>\n"), + + head(2, "Lists"), + + para("Unordered (bulleted) lists use asterisks, pluses, and hyphens (<code>*</code>,\n" + + "<code>+</code>, and <code>-</code>) as list markers. These three markers are\n" + + "interchangable; this:"), + + verb("* Candy.\n", + "* Gum.\n", + "* Booze.\n"), + + para("this:"), + + verb("+ Candy.\n", + "+ Gum.\n", + "+ Booze.\n"), + + para("and this:"), + + verb("- Candy.\n", + "- Gum.\n", + "- Booze.\n"), + + para("all produce the same output:"), + + verb("<ul>\n", + "<li>Candy.</li>\n", + "<li>Gum.</li>\n", + "<li>Booze.</li>\n", + "</ul>\n"), + + para("Ordered (numbered) lists use regular numbers, followed by periods, as\n" + + "list markers:"), + + verb("1. Red\n", + "2. Green\n", + "3. Blue\n"), + + para("Output:"), + + verb("<ol>\n", + "<li>Red</li>\n", + "<li>Green</li>\n", + "<li>Blue</li>\n", + "</ol>\n"), + + para("If you put blank lines between items, you'll get <code><p></code> tags for the\n" + + "list item text. You can create multi-paragraph list items by indenting\n" + + "the paragraphs by 4 spaces or 1 tab:"), + + verb("* A list item.\n", + "\n", + " With multiple paragraphs.\n", + "\n", + "* Another item in the list.\n"), + + para("Output:"), + + verb("<ul>\n", + "<li><p>A list item.</p>\n", + "<p>With multiple paragraphs.</p></li>\n", + "<li><p>Another item in the list.</p></li>\n", + "</ul>\n"), + + head(3, "Links"), + + para("Markdown supports two styles for creating links: _inline_ and\n" + + "_reference_. With both styles, you use square brackets to delimit the\n" + + "text you want to turn into a link."), + + para("Inline-style links use parentheses immediately after the link text.\n" + + "For example:"), + + verb("This is an [example link](http://example.com/).\n"), + + para("Output:"), + + verb("<p>This is an <a href=\"http://example.com/\">\n", + "example link</a>.</p>\n"), + + para("Optionally, you may include a title attribute in the parentheses:"), + + verb("This is an [example link](http://example.com/ \"With a Title\").\n"), + + para("Output:"), + + verb("<p>This is an <a href=\"http://example.com/\" title=\"With a Title\">\n", + "example link</a>.</p>\n"), + + para("Reference-style links allow you to refer to your links by names, which\n" + + "you define elsewhere in your document:"), + + verb("I get 10 times more traffic from [Google][1] than from\n", + "[Yahoo][2] or [MSN][3].\n", + "\n", + "[1]: http://google.com/ \"Google\"\n", + "[2]: http://search.yahoo.com/ \"Yahoo Search\"\n", + "[3]: http://search.msn.com/ \"MSN Search\"\n"), + + para("Output:"), + + verb("<p>I get 10 times more traffic from <a href=\"http://google.com/\"\n", + "title=\"Google\">Google</a> than from <a href=\"http://search.yahoo.com/\"\n", + "title=\"Yahoo Search\">Yahoo</a> or <a href=\"http://search.msn.com/\"\n", + "title=\"MSN Search\">MSN</a>.</p>\n"), + + para("The title attribute is optional. Link names may contain letters,\n" + + "numbers and spaces, but are _not_ case sensitive:"), + + verb("I start my morning with a cup of coffee and\n", + "[The New York Times][NY Times].\n", + "\n", + "[ny times]: http://www.nytimes.com/\n"), + + para("Output:"), + + verb("<p>I start my morning with a cup of coffee and\n", + "<a href=\"http://www.nytimes.com/\">The New York Times</a>.</p>\n"), + + head(3, "Images"), + + para("Image syntax is very much like link syntax."), + + para("Inline (titles are optional):"), + + verb("![alt text](/path/to/img.jpg \"Title\")\n"), + + para("Reference-style:"), + + verb("![alt text][id]\n", + "\n", + "[id]: /path/to/img.jpg \"Title\"\n"), + + para("Both of the above examples produce the same output:"), + + verb("<img src=\"/path/to/img.jpg\" alt=\"alt text\" title=\"Title\" />\n"), + + head(3, "Code"), + + para("In a regular paragraph, you can create code span by wrapping text in\n" + + "backtick quotes. Any ampersands (<code>&</code>) and angle brackets (<code><</code> or\n" + + "<code>></code>) will automatically be translated into HTML entities. This makes\n" + + "it easy to use Markdown to write about HTML example code:"), + + verb( + "I strongly recommend against using any `<blink>` tags.\n", + "\n", + "I wish SmartyPants used named entities like `—`\n", + "instead of decimal-encoded entites like `—`.\n"), + + para("Output:"), + + verb("<p>I strongly recommend against using any\n", + "<code><blink></code> tags.</p>\n", + "\n", + "<p>I wish SmartyPants used named entities like\n", + "<code>&mdash;</code> instead of decimal-encoded\n", + "entites like <code>&#8212;</code>.</p>\n"), + + para("To specify an entire block of pre-formatted code, indent every line of\n" + + "the block by 4 spaces or 1 tab. Just like with code spans, <code>&</code>, <code><</code>,\n" + + "and <code>></code> characters will be escaped automatically."), + + para("Markdown:"), + + verb("If you want your page to validate under XHTML 1.0 Strict,\n", + "you've got to put paragraph tags in your blockquotes:\n", + "\n", + " <blockquote>\n", + " <p>For example.</p>\n", + " </blockquote>\n"), + + para("Output:"), + + verb("<p>If you want your page to validate under XHTML 1.0 Strict,\n", + "you've got to put paragraph tags in your blockquotes:</p>\n", + "\n", + "<pre><code><blockquote>\n", + " <p>For example.</p>\n", + "</blockquote>\n", + "</code></pre>\n")) + + assert_equal expected, doc + end + + def test_markdown_documentation_syntax + input = File.read "#{MARKDOWN_TEST_PATH}/Markdown Documentation - Syntax.text" + + doc = @parser.parse input + + expected = + doc( + head(1, "Markdown: Syntax"), + + raw(<<-RAW.chomp), +<ul id="ProjectSubmenu"> + <li><a href="/projects/markdown/" title="Markdown Project Page">Main</a></li> + <li><a href="/projects/markdown/basics" title="Markdown Basics">Basics</a></li> + <li><a class="selected" title="Markdown Syntax Documentation">Syntax</a></li> + <li><a href="/projects/markdown/license" title="Pricing and License Information">License</a></li> + <li><a href="/projects/markdown/dingus" title="Online Markdown Web Form">Dingus</a></li> +</ul> + RAW + + list(:BULLET, + item(nil, + para("{Overview}[#overview]"), + list(:BULLET, + item(nil, + para("{Philosophy}[#philosophy]")), + item(nil, + para("{Inline HTML}[#html]")), + item(nil, + para("{Automatic Escaping for Special Characters}[#autoescape]")))), + item(nil, + para("{Block Elements}[#block]"), + list(:BULLET, + item(nil, + para("{Paragraphs and Line Breaks}[#p]")), + item(nil, + para("{Headers}[#header]")), + item(nil, + para("{Blockquotes}[#blockquote]")), + item(nil, + para("{Lists}[#list]")), + item(nil, + para("{Code Blocks}[#precode]")), + item(nil, + para("{Horizontal Rules}[#hr]")))), + item(nil, + para("{Span Elements}[#span]"), + list(:BULLET, + item(nil, + para("{Links}[#link]")), + item(nil, + para("{Emphasis}[#em]")), + item(nil, + para("{Code}[#code]")), + item(nil, + para("{Images}[#img]")))), + item(nil, + para("{Miscellaneous}[#misc]"), + list(:BULLET, + item(nil, + para("{Backslash Escapes}[#backslash]")), + item(nil, + para("{Automatic Links}[#autolink]"))))), + + para("<b>Note:</b> This document is itself written using Markdown; you\n" + + "can {see the source for it by adding '.text' to the URL}[/projects/markdown/syntax.text]."), + + rule(1), + + raw("<h2 id=\"overview\">Overview</h2>"), + + raw("<h3 id=\"philosophy\">Philosophy</h3>"), + + para("Markdown is intended to be as easy-to-read and easy-to-write as is feasible."), + + para("Readability, however, is emphasized above all else. A Markdown-formatted\n" + + "document should be publishable as-is, as plain text, without looking\n" + + "like it's been marked up with tags or formatting instructions. While\n" + + "Markdown's syntax has been influenced by several existing text-to-HTML\n" + + "filters -- including {Setext}[http://docutils.sourceforge.net/mirror/setext.html], {atx}[http://www.aaronsw.com/2002/atx/], {Textile}[http://textism.com/tools/textile/], {reStructuredText}[http://docutils.sourceforge.net/rst.html],\n" + + "{Grutatext}[http://www.triptico.com/software/grutatxt.html], and {EtText}[http://ettext.taint.org/doc/] -- the single biggest source of\n" + + "inspiration for Markdown's syntax is the format of plain text email."), + + para("To this end, Markdown's syntax is comprised entirely of punctuation\n" + + "characters, which punctuation characters have been carefully chosen so\n" + + "as to look like what they mean. E.g., asterisks around a word actually\n" + + "look like \*emphasis\*. Markdown lists look like, well, lists. Even\n" + + "blockquotes look like quoted passages of text, assuming you've ever\n" + + "used email."), + + raw("<h3 id=\"html\">Inline HTML</h3>"), + + para("Markdown's syntax is intended for one purpose: to be used as a\n" + + "format for _writing_ for the web."), + + para("Markdown is not a replacement for HTML, or even close to it. Its\n" + + "syntax is very small, corresponding only to a very small subset of\n" + + "HTML tags. The idea is _not_ to create a syntax that makes it easier\n" + + "to insert HTML tags. In my opinion, HTML tags are already easy to\n" + + "insert. The idea for Markdown is to make it easy to read, write, and\n" + + "edit prose. HTML is a _publishing_ format; Markdown is a _writing_\n" + + "format. Thus, Markdown's formatting syntax only addresses issues that\n" + + "can be conveyed in plain text."), + + para("For any markup that is not covered by Markdown's syntax, you simply\n" + + "use HTML itself. There's no need to preface it or delimit it to\n" + + "indicate that you're switching from Markdown to HTML; you just use\n" + + "the tags."), + + para("The only restrictions are that block-level HTML elements -- e.g. <code><div></code>,\n" + + "<code><table></code>, <code><pre></code>, <code><p></code>, etc. -- must be separated from surrounding\n" + + "content by blank lines, and the start and end tags of the block should\n" + + "not be indented with tabs or spaces. Markdown is smart enough not\n" + + "to add extra (unwanted) <code><p></code> tags around HTML block-level tags."), + + para("For example, to add an HTML table to a Markdown article:"), + + verb("This is a regular paragraph.\n", + "\n", + "<table>\n", + " <tr>\n", + " <td>Foo</td>\n", + " </tr>\n", + "</table>\n", + "\n", + "This is another regular paragraph.\n"), + + para("Note that Markdown formatting syntax is not processed within block-level\n" + + "HTML tags. E.g., you can't use Markdown-style <code>*emphasis*</code> inside an\n" + + "HTML block."), + + para("Span-level HTML tags -- e.g. <code><span></code>, <code><cite></code>, or <code><del></code> -- can be\n" + + "used anywhere in a Markdown paragraph, list item, or header. If you\n" + + "want, you can even use HTML tags instead of Markdown formatting; e.g. if\n" + + "you'd prefer to use HTML <code><a></code> or <code><img></code> tags instead of Markdown's\n" + + "link or image syntax, go right ahead."), + + para("Unlike block-level HTML tags, Markdown syntax _is_ processed within\n" + + "span-level tags."), + + raw("<h3 id=\"autoescape\">Automatic Escaping for Special Characters</h3>"), + + para("In HTML, there are two characters that demand special treatment: <code><</code>\n" + + "and <code>&</code>. Left angle brackets are used to start tags; ampersands are\n" + + "used to denote HTML entities. If you want to use them as literal\n" + + "characters, you must escape them as entities, e.g. <code><</code>, and\n" + + "<code>&</code>."), + + para("Ampersands in particular are bedeviling for web writers. If you want to\n" + + "write about 'AT&T', you need to write '<code>AT&T</code>'. You even need to\n" + + "escape ampersands within URLs. Thus, if you want to link to:"), + + verb("http://images.google.com/images?num=30&q=larry+bird\n"), + + para("you need to encode the URL as:"), + + verb("http://images.google.com/images?num=30&q=larry+bird\n"), + + para("in your anchor tag <code>href</code> attribute. Needless to say, this is easy to\n" + + "forget, and is probably the single most common source of HTML validation\n" + + "errors in otherwise well-marked-up web sites."), + + para("Markdown allows you to use these characters naturally, taking care of\n" + + "all the necessary escaping for you. If you use an ampersand as part of\n" + + "an HTML entity, it remains unchanged; otherwise it will be translated\n" + + "into <code>&</code>."), + + para("So, if you want to include a copyright symbol in your article, you can write:"), + + verb("©\n"), + + para("and Markdown will leave it alone. But if you write:"), + + verb("AT&T\n"), + + para("Markdown will translate it to:"), + + verb("AT&T\n"), + + para("Similarly, because Markdown supports {inline HTML}[#html], if you use\n" + + "angle brackets as delimiters for HTML tags, Markdown will treat them as\n" + + "such. But if you write:"), + + verb("4 < 5\n"), + + para("Markdown will translate it to:"), + + verb("4 < 5\n"), + + para("However, inside Markdown code spans and blocks, angle brackets and\n" + + "ampersands are _always_ encoded automatically. This makes it easy to use\n" + + "Markdown to write about HTML code. (As opposed to raw HTML, which is a\n" + + "terrible format for writing about HTML syntax, because every single <code><</code>\n" + + "and <code>&</code> in your example code needs to be escaped.)"), + + rule(1), + + raw("<h2 id=\"block\">Block Elements</h2>"), + + raw("<h3 id=\"p\">Paragraphs and Line Breaks</h3>"), + + para("A paragraph is simply one or more consecutive lines of text, separated\n" + + "by one or more blank lines. (A blank line is any line that looks like a\n" + + "blank line -- a line containing nothing but spaces or tabs is considered\n" + + "blank.) Normal paragraphs should not be intended with spaces or tabs."), + + para("The implication of the \"one or more consecutive lines of text\" rule is\n" + + "that Markdown supports \"hard-wrapped\" text paragraphs. This differs\n" + + "significantly from most other text-to-HTML formatters (including Movable\n" + + "Type's \"Convert Line Breaks\" option) which translate every line break\n" + + "character in a paragraph into a <code><br /></code> tag."), + + para("When you _do_ want to insert a <code><br /></code> break tag using Markdown, you\n" + + "end a line with two or more spaces, then type return."), + + para("Yes, this takes a tad more effort to create a <code><br /></code>, but a simplistic\n" + + "\"every line break is a <code><br /></code>\" rule wouldn't work for Markdown.\n" + + "Markdown's email-style {blockquoting}[#blockquote] and multi-paragraph {list items}[#list]\n" + + "work best -- and look better -- when you format them with hard breaks."), + + raw("<h3 id=\"header\">Headers</h3>"), + + para("Markdown supports two styles of headers, {Setext}[http://docutils.sourceforge.net/mirror/setext.html] and {atx}[http://www.aaronsw.com/2002/atx/]."), + + para("Setext-style headers are \"underlined\" using equal signs (for first-level\n" + + "headers) and dashes (for second-level headers). For example:"), + + verb("This is an H1\n", + "=============\n", + "\n", + "This is an H2\n", + "-------------\n"), + + para("Any number of underlining <code>=</code>'s or <code>-</code>'s will work."), + + para("Atx-style headers use 1-6 hash characters at the start of the line,\n" + + "corresponding to header levels 1-6. For example:"), + + verb("# This is an H1\n", + "\n", + "## This is an H2\n", + "\n", + "###### This is an H6\n"), + + para("Optionally, you may \"close\" atx-style headers. This is purely\n" + + "cosmetic -- you can use this if you think it looks better. The\n" + + "closing hashes don't even need to match the number of hashes\n" + + "used to open the header. (The number of opening hashes\n" + + "determines the header level.) :"), + + verb("# This is an H1 #\n", + "\n", + "## This is an H2 ##\n", + "\n", + "### This is an H3 ######\n"), + + raw("<h3 id=\"blockquote\">Blockquotes</h3>"), + + para( + "Markdown uses email-style <code>></code> characters for blockquoting. If you're\n" + + "familiar with quoting passages of text in an email message, then you\n" + + "know how to create a blockquote in Markdown. It looks best if you hard\n" + + "wrap the text and put a <code>></code> before every line:"), + + verb("> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,\n", + "> consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.\n", + "> Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.\n", + "> \n", + "> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse\n", + "> id sem consectetuer libero luctus adipiscing.\n"), + + para("Markdown allows you to be lazy and only put the <code>></code> before the first\n" + + "line of a hard-wrapped paragraph:"), + + verb("> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,\n", + "consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.\n", + "Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.\n", + "\n", + "> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse\n", + "id sem consectetuer libero luctus adipiscing.\n"), + + para("Blockquotes can be nested (i.e. a blockquote-in-a-blockquote) by\n" + + "adding additional levels of <code>></code>:"), + + verb("> This is the first level of quoting.\n", + ">\n", + "> > This is nested blockquote.\n", + ">\n", + "> Back to the first level.\n"), + + para("Blockquotes can contain other Markdown elements, including headers, lists,\n" + + "and code blocks:"), + + verb("> ## This is a header.\n", + "> \n", + "> 1. This is the first list item.\n", + "> 2. This is the second list item.\n", + "> \n", + "> Here's some example code:\n", + "> \n", + "> return shell_exec(\"echo $input | $markdown_script\");\n"), + + para("Any decent text editor should make email-style quoting easy. For\n" + + "example, with BBEdit, you can make a selection and choose Increase\n" + + "Quote Level from the Text menu."), + + raw("<h3 id=\"list\">Lists</h3>"), + + para("Markdown supports ordered (numbered) and unordered (bulleted) lists."), + + para("Unordered lists use asterisks, pluses, and hyphens -- interchangably\n" + + "-- as list markers:"), + + verb("* Red\n", + "* Green\n", + "* Blue\n"), + + para("is equivalent to:"), + + verb("+ Red\n", + "+ Green\n", + "+ Blue\n"), + + para("and:"), + + verb("- Red\n", + "- Green\n", + "- Blue\n"), + + para("Ordered lists use numbers followed by periods:"), + + verb("1. Bird\n", + "2. McHale\n", + "3. Parish\n"), + + para("It's important to note that the actual numbers you use to mark the\n" + + "list have no effect on the HTML output Markdown produces. The HTML\n" + + "Markdown produces from the above list is:"), + + verb("<ol>\n", + "<li>Bird</li>\n", + "<li>McHale</li>\n", + "<li>Parish</li>\n", + "</ol>\n"), + + para("If you instead wrote the list in Markdown like this:"), + + verb("1. Bird\n", + "1. McHale\n", + "1. Parish\n"), + + para("or even:"), + + verb("3. Bird\n", + "1. McHale\n", + "8. Parish\n"), + + para("you'd get the exact same HTML output. The point is, if you want to,\n" + + "you can use ordinal numbers in your ordered Markdown lists, so that\n" + + "the numbers in your source match the numbers in your published HTML.\n" + + "But if you want to be lazy, you don't have to."), + + para("If you do use lazy list numbering, however, you should still start the\n" + + "list with the number 1. At some point in the future, Markdown may support\n" + + "starting ordered lists at an arbitrary number."), + + para("List markers typically start at the left margin, but may be indented by\n" + + "up to three spaces. List markers must be followed by one or more spaces\n" + + "or a tab."), + + para("To make lists look nice, you can wrap items with hanging indents:"), + + verb("* Lorem ipsum dolor sit amet, consectetuer adipiscing elit.\n", + " Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,\n", + " viverra nec, fringilla in, laoreet vitae, risus.\n", + "* Donec sit amet nisl. Aliquam semper ipsum sit amet velit.\n", + " Suspendisse id sem consectetuer libero luctus adipiscing.\n"), + + para("But if you want to be lazy, you don't have to:"), + + verb("* Lorem ipsum dolor sit amet, consectetuer adipiscing elit.\n", + "Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,\n", + "viverra nec, fringilla in, laoreet vitae, risus.\n", + "* Donec sit amet nisl. Aliquam semper ipsum sit amet velit.\n", + "Suspendisse id sem consectetuer libero luctus adipiscing.\n"), + + para("If list items are separated by blank lines, Markdown will wrap the\n" + + "items in <code><p></code> tags in the HTML output. For example, this input:"), + + verb("* Bird\n", + "* Magic\n"), + + para("will turn into:"), + + verb("<ul>\n", + "<li>Bird</li>\n", + "<li>Magic</li>\n", + "</ul>\n"), + + para("But this:"), + + verb("* Bird\n", + "\n", + "* Magic\n"), + + para("will turn into:"), + + verb("<ul>\n", + "<li><p>Bird</p></li>\n", + "<li><p>Magic</p></li>\n", + "</ul>\n"), + + para("List items may consist of multiple paragraphs. Each subsequent\n" + + "paragraph in a list item must be intended by either 4 spaces\n" + + "or one tab:"), + + verb("1. This is a list item with two paragraphs. Lorem ipsum dolor\n", + " sit amet, consectetuer adipiscing elit. Aliquam hendrerit\n", + " mi posuere lectus.\n", + "\n", + " Vestibulum enim wisi, viverra nec, fringilla in, laoreet\n", + " vitae, risus. Donec sit amet nisl. Aliquam semper ipsum\n", + " sit amet velit.\n", + "\n", + "2. Suspendisse id sem consectetuer libero luctus adipiscing.\n"), + + para("It looks nice if you indent every line of the subsequent\n" + + "paragraphs, but here again, Markdown will allow you to be\n" + + "lazy:"), + + verb("* This is a list item with two paragraphs.\n", + "\n", + " This is the second paragraph in the list item. You're\n", + "only required to indent the first line. Lorem ipsum dolor\n", + "sit amet, consectetuer adipiscing elit.\n", + "\n", + "* Another item in the same list.\n"), + + para("To put a blockquote within a list item, the blockquote's <code>></code>\n" + + "delimiters need to be indented:"), + + verb("* A list item with a blockquote:\n", + "\n", + " > This is a blockquote\n", + " > inside a list item.\n"), + + para( + "To put a code block within a list item, the code block needs\n" + + "to be indented _twice_ -- 8 spaces or two tabs:"), + + verb("* A list item with a code block:\n", + "\n", + " <code goes here>\n"), + + para("It's worth noting that it's possible to trigger an ordered list by\n" + + "accident, by writing something like this:"), + + verb("1986. What a great season.\n"), + + para("In other words, a <em>number-period-space</em> sequence at the beginning of a\n" + + "line. To avoid this, you can backslash-escape the period:"), + + verb("1986\\. What a great season.\n"), + + raw("<h3 id=\"precode\">Code Blocks</h3>"), + + para("Pre-formatted code blocks are used for writing about programming or\n" + + "markup source code. Rather than forming normal paragraphs, the lines\n" + + "of a code block are interpreted literally. Markdown wraps a code block\n" + + "in both <code><pre></code> and <code><code></code> tags."), + + para("To produce a code block in Markdown, simply indent every line of the\n" + + "block by at least 4 spaces or 1 tab. For example, given this input:"), + + verb("This is a normal paragraph:\n", + "\n", + " This is a code block.\n"), + + para("Markdown will generate:"), + + verb("<p>This is a normal paragraph:</p>\n", + "\n", + "<pre><code>This is a code block.\n", + "</code></pre>\n"), + + para("One level of indentation -- 4 spaces or 1 tab -- is removed from each\n" + + "line of the code block. For example, this:"), + + verb("Here is an example of AppleScript:\n", + "\n", + " tell application \"Foo\"\n", + " beep\n", + " end tell\n"), + + para("will turn into:"), + + verb("<p>Here is an example of AppleScript:</p>\n", + "\n", + "<pre><code>tell application \"Foo\"\n", + " beep\n", + "end tell\n", + "</code></pre>\n"), + + para("A code block continues until it reaches a line that is not indented\n" + + "(or the end of the article)."), + + para("Within a code block, ampersands (<code>&</code>) and angle brackets (<code><</code> and <code>></code>)\n" + + "are automatically converted into HTML entities. This makes it very\n" + + "easy to include example HTML source code using Markdown -- just paste\n" + + "it and indent it, and Markdown will handle the hassle of encoding the\n" + + "ampersands and angle brackets. For example, this:"), + + verb(" <div class=\"footer\">\n", + " © 2004 Foo Corporation\n", + " </div>\n"), + + para("will turn into:"), + + verb("<pre><code><div class=\"footer\">\n", + " &copy; 2004 Foo Corporation\n", + "</div>\n", + "</code></pre>\n"), + + para("Regular Markdown syntax is not processed within code blocks. E.g.,\n" + + "asterisks are just literal asterisks within a code block. This means\n" + + "it's also easy to use Markdown to write about Markdown's own syntax."), + + raw("<h3 id=\"hr\">Horizontal Rules</h3>"), + + para("You can produce a horizontal rule tag (<code><hr /></code>) by placing three or\n" + + "more hyphens, asterisks, or underscores on a line by themselves. If you\n" + + "wish, you may use spaces between the hyphens or asterisks. Each of the\n" + + "following lines will produce a horizontal rule:"), + + verb("* * *\n", + "\n", + "***\n", + "\n", + "*****\n", + "\n", + "- - -\n", + "\n", + "---------------------------------------\n", + "\n", + "_ _ _\n"), + + rule(1), + + raw("<h2 id=\"span\">Span Elements</h2>"), + + raw("<h3 id=\"link\">Links</h3>"), + + para("Markdown supports two style of links: _inline_ and _reference_."), + + para("In both styles, the link text is delimited by [square brackets]."), + + para("To create an inline link, use a set of regular parentheses immediately\n" + + "after the link text's closing square bracket. Inside the parentheses,\n" + + "put the URL where you want the link to point, along with an _optional_\n" + + "title for the link, surrounded in quotes. For example:"), + + verb("This is [an example](http://example.com/ \"Title\") inline link.\n", + "\n", + "[This link](http://example.net/) has no title attribute.\n"), + + para("Will produce:"), + + verb("<p>This is <a href=\"http://example.com/\" title=\"Title\">\n", + "an example</a> inline link.</p>\n", + "\n", + "<p><a href=\"http://example.net/\">This link</a> has no\n", + "title attribute.</p>\n"), + + para("If you're referring to a local resource on the same server, you can\n" + + "use relative paths:"), + + verb("See my [About](/about/) page for details.\n"), + + para("Reference-style links use a second set of square brackets, inside\n" + + "which you place a label of your choosing to identify the link:"), + + verb("This is [an example][id] reference-style link.\n"), + + para("You can optionally use a space to separate the sets of brackets:"), + + verb("This is [an example] [id] reference-style link.\n"), + + para("Then, anywhere in the document, you define your link label like this,\n" + + "on a line by itself:"), + + verb("[id]: http://example.com/ \"Optional Title Here\"\n"), + + para("That is:"), + + list(:BULLET, + item(nil, + para("Square brackets containing the link identifier (optionally\n" + + "indented from the left margin using up to three spaces);")), + item(nil, + para("followed by a colon;")), + item(nil, + para("followed by one or more spaces (or tabs);")), + item(nil, + para("followed by the URL for the link;")), + item(nil, + para("optionally followed by a title attribute for the link, enclosed\n" + + "in double or single quotes."))), + + para("The link URL may, optionally, be surrounded by angle brackets:"), + + verb("[id]: <http://example.com/> \"Optional Title Here\"\n"), + + para("You can put the title attribute on the next line and use extra spaces\n" + + "or tabs for padding, which tends to look better with longer URLs:"), + + verb("[id]: http://example.com/longish/path/to/resource/here\n", + " \"Optional Title Here\"\n"), + + para("Link definitions are only used for creating links during Markdown\n" + + "processing, and are stripped from your document in the HTML output."), + + para("Link definition names may constist of letters, numbers, spaces, and punctuation -- but they are _not_ case sensitive. E.g. these two links:"), + + verb("[link text][a]\n", + "[link text][A]\n"), + + para("are equivalent."), + + para("The <em>implicit link name</em> shortcut allows you to omit the name of the\n" + + "link, in which case the link text itself is used as the name.\n" + + "Just use an empty set of square brackets -- e.g., to link the word\n" + + "\"Google\" to the google.com web site, you could simply write:"), + + verb("[Google][]\n"), + + para("And then define the link:"), + + verb("[Google]: http://google.com/\n"), + + para("Because link names may contain spaces, this shortcut even works for\n" + + "multiple words in the link text:"), + + + verb("Visit [Daring Fireball][] for more information.\n"), + + para("And then define the link:"), + + verb("[Daring Fireball]: http://daringfireball.net/\n"), + + para("Link definitions can be placed anywhere in your Markdown document. I\n" + + "tend to put them immediately after each paragraph in which they're\n" + + "used, but if you want, you can put them all at the end of your\n" + + "document, sort of like footnotes."), + + para("Here's an example of reference links in action:"), + + verb("I get 10 times more traffic from [Google] [1] than from\n", + "[Yahoo] [2] or [MSN] [3].\n", + "\n", + " [1]: http://google.com/ \"Google\"\n", + " [2]: http://search.yahoo.com/ \"Yahoo Search\"\n", + " [3]: http://search.msn.com/ \"MSN Search\"\n"), + + para("Using the implicit link name shortcut, you could instead write:"), + + verb("I get 10 times more traffic from [Google][] than from\n", + "[Yahoo][] or [MSN][].\n", + "\n", + " [google]: http://google.com/ \"Google\"\n", + " [yahoo]: http://search.yahoo.com/ \"Yahoo Search\"\n", + " [msn]: http://search.msn.com/ \"MSN Search\"\n"), + + para("Both of the above examples will produce the following HTML output:"), + + verb("<p>I get 10 times more traffic from <a href=\"http://google.com/\"\n", + "title=\"Google\">Google</a> than from\n", + "<a href=\"http://search.yahoo.com/\" title=\"Yahoo Search\">Yahoo</a>\n", + "or <a href=\"http://search.msn.com/\" title=\"MSN Search\">MSN</a>.</p>\n"), + + para("For comparison, here is the same paragraph written using\n" + + "Markdown's inline link style:"), + + verb("I get 10 times more traffic from [Google](http://google.com/ \"Google\")\n", + "than from [Yahoo](http://search.yahoo.com/ \"Yahoo Search\") or\n", + "[MSN](http://search.msn.com/ \"MSN Search\").\n"), + + para("The point of reference-style links is not that they're easier to\n" + + "write. The point is that with reference-style links, your document\n" + + "source is vastly more readable. Compare the above examples: using\n" + + "reference-style links, the paragraph itself is only 81 characters\n" + + "long; with inline-style links, it's 176 characters; and as raw HTML,\n" + + "it's 234 characters. In the raw HTML, there's more markup than there\n" + + "is text."), + + para("With Markdown's reference-style links, a source document much more\n" + + "closely resembles the final output, as rendered in a browser. By\n" + + "allowing you to move the markup-related metadata out of the paragraph,\n" + + "you can add links without interrupting the narrative flow of your\n" + + "prose."), + + raw("<h3 id=\"em\">Emphasis</h3>"), + + para("Markdown treats asterisks (<code>*</code>) and underscores (<code>_</code>) as indicators of\n" + + "emphasis. Text wrapped with one <code>*</code> or <code>_</code> will be wrapped with an\n" + + "HTML <code><em></code> tag; double <code>*</code>'s or <code>_</code>'s will be wrapped with an HTML\n" + + "<code><strong></code> tag. E.g., this input:"), + + verb("*single asterisks*\n", + "\n", + "_single underscores_\n", + "\n", + "**double asterisks**\n", + "\n", + "__double underscores__\n"), + + para("will produce:"), + + verb("<em>single asterisks</em>\n", + "\n", + "<em>single underscores</em>\n", + "\n", + "<strong>double asterisks</strong>\n", + "\n", + "<strong>double underscores</strong>\n"), + + para("You can use whichever style you prefer; the lone restriction is that\n" + + "the same character must be used to open and close an emphasis span."), + + para("Emphasis can be used in the middle of a word:"), + + verb("un*fucking*believable\n"), + + para("But if you surround an <code>*</code> or <code>_</code> with spaces, it'll be treated as a\n" + + "literal asterisk or underscore."), + + para("To produce a literal asterisk or underscore at a position where it\n" + + "would otherwise be used as an emphasis delimiter, you can backslash\n" + + "escape it:"), + + verb("\\*this text is surrounded by literal asterisks\\*\n"), + + raw("<h3 id=\"code\">Code</h3>"), + + para("To indicate a span of code, wrap it with backtick quotes (<code>`</code>).\n" + + "Unlike a pre-formatted code block, a code span indicates code within a\n" + + "normal paragraph. For example:"), + + verb("Use the `printf()` function.\n"), + + para("will produce:"), + + verb("<p>Use the <code>printf()</code> function.</p>\n"), + + para("To include a literal backtick character within a code span, you can use\n" + + "multiple backticks as the opening and closing delimiters:"), + + verb("``There is a literal backtick (`) here.``\n"), + + para("which will produce this:"), + + verb("<p><code>There is a literal backtick (`) here.</code></p>\n"), + + para("The backtick delimiters surrounding a code span may include spaces --\n" + + "one after the opening, one before the closing. This allows you to place\n" + + "literal backtick characters at the beginning or end of a code span:"), + + verb("A single backtick in a code span: `` ` ``\n", + "\n", + "A backtick-delimited string in a code span: `` `foo` ``\n"), + + para("will produce:"), + + verb("<p>A single backtick in a code span: <code>`</code></p>\n", + "\n", + "<p>A backtick-delimited string in a code span: <code>`foo`</code></p>\n"), + + para("With a code span, ampersands and angle brackets are encoded as HTML\n" + + "entities automatically, which makes it easy to include example HTML\n" + + "tags. Markdown will turn this:"), + + verb("Please don't use any `<blink>` tags.\n"), + + para("into:"), + + verb("<p>Please don't use any <code><blink></code> tags.</p>\n"), + + para("You can write this:"), + + verb("`—` is the decimal-encoded equivalent of `—`.\n"), + + para("to produce:"), + + verb( "<p><code>&#8212;</code> is the decimal-encoded\n", + "equivalent of <code>&mdash;</code>.</p>\n"), + + raw("<h3 id=\"img\">Images</h3>"), + + para("Admittedly, it's fairly difficult to devise a \"natural\" syntax for\n" + + "placing images into a plain text document format."), + + para("Markdown uses an image syntax that is intended to resemble the syntax\n" + + "for links, allowing for two styles: _inline_ and _reference_."), + + para("Inline image syntax looks like this:"), + + verb("![Alt text](/path/to/img.jpg)\n", + "\n", + "![Alt text](/path/to/img.jpg \"Optional title\")\n"), + + para("That is:"), + + list(:BULLET, + item(nil, + para("An exclamation mark: <code>!</code>;")), + item(nil, + para("followed by a set of square brackets, containing the <code>alt</code>\n" + + "attribute text for the image;")), + item(nil, + para("followed by a set of parentheses, containing the URL or path to\n" + + "the image, and an optional <code>title</code> attribute enclosed in double\n" + + "or single quotes."))), + + para("Reference-style image syntax looks like this:"), + + verb("![Alt text][id]\n"), + + para("Where \"id\" is the name of a defined image reference. Image references\n" + + "are defined using syntax identical to link references:"), + + verb("[id]: url/to/image \"Optional title attribute\"\n"), + + para("As of this writing, Markdown has no syntax for specifying the\n" + + "dimensions of an image; if this is important to you, you can simply\n" + + "use regular HTML <code><img></code> tags."), + + rule(1), + + raw("<h2 id=\"misc\">Miscellaneous</h2>"), + + raw("<h3 id=\"autolink\">Automatic Links</h3>"), + + para("Markdown supports a shortcut style for creating \"automatic\" links for URLs and email addresses: simply surround the URL or email address with angle brackets. What this means is that if you want to show the actual text of a URL or email address, and also have it be a clickable link, you can do this:"), + + verb("<http://example.com/>\n"), + + para("Markdown will turn this into:"), + + verb("<a href=\"http://example.com/\">http://example.com/</a>\n"), + + para("Automatic links for email addresses work similarly, except that\n" + + "Markdown will also perform a bit of randomized decimal and hex\n" + + "entity-encoding to help obscure your address from address-harvesting\n" + + "spambots. For example, Markdown will turn this:"), + + verb("<address@example.com>\n"), + + para("into something like this:"), + + verb("<a href=\"mailto:addre\n", + "ss@example.co\n", + "m\">address@exa\n", + "mple.com</a>\n"), + + para("which will render in a browser as a clickable link to \"address@example.com\"."), + + para("(This sort of entity-encoding trick will indeed fool many, if not\n" + + "most, address-harvesting bots, but it definitely won't fool all of\n" + + "them. It's better than nothing, but an address published in this way\n" + + "will probably eventually start receiving spam.)"), + + raw("<h3 id=\"backslash\">Backslash Escapes</h3>"), + + para("Markdown allows you to use backslash escapes to generate literal\n" + + "characters which would otherwise have special meaning in Markdown's\n" + + "formatting syntax. For example, if you wanted to surround a word with\n" + + "literal asterisks (instead of an HTML <code><em></code> tag), you can backslashes\n" + + "before the asterisks, like this:"), + + verb("\\*literal asterisks\\*\n"), + + para("Markdown provides backslash escapes for the following characters:"), + + verb("\\ backslash\n", + "` backtick\n", + "* asterisk\n", + "_ underscore\n", + "{} curly braces\n", + "[] square brackets\n", + "() parentheses\n", + "# hash mark\n", + "+ plus sign\n", + "- minus sign (hyphen)\n", + ". dot\n", + "! exclamation mark\n")) + + assert_equal expected, doc + end + + def test_nested_blockquotes + input = File.read "#{MARKDOWN_TEST_PATH}/Nested blockquotes.text" + + doc = @parser.parse input + + expected = + doc( + block( + para("foo"), + block( + para("bar")), + para("foo"))) + + assert_equal expected, doc + end + + def test_ordered_and_unordered_lists + input = File.read "#{MARKDOWN_TEST_PATH}/Ordered and unordered lists.text" + + doc = @parser.parse input + + expected = + doc( + head(2, 'Unordered'), + + para('Asterisks tight:'), + list(:BULLET, + item(nil, para("asterisk 1")), + item(nil, para("asterisk 2")), + item(nil, para("asterisk 3"))), + para('Asterisks loose:'), + list(:BULLET, + item(nil, para("asterisk 1")), + item(nil, para("asterisk 2")), + item(nil, para("asterisk 3"))), + + rule(1), + + para("Pluses tight:"), + list(:BULLET, + item(nil, para("Plus 1")), + item(nil, para("Plus 2")), + item(nil, para("Plus 3"))), + para("Pluses loose:"), + list(:BULLET, + item(nil, para("Plus 1")), + item(nil, para("Plus 2")), + item(nil, para("Plus 3"))), + + rule(1), + + para("Minuses tight:"), + list(:BULLET, + item(nil, para("Minus 1")), + item(nil, para("Minus 2")), + item(nil, para("Minus 3"))), + para("Minuses loose:"), + list(:BULLET, + item(nil, para("Minus 1")), + item(nil, para("Minus 2")), + item(nil, para("Minus 3"))), + + head(2, "Ordered"), + + para("Tight:"), + list(:NUMBER, + item(nil, para("First")), + item(nil, para("Second")), + item(nil, para("Third"))), + para("and:"), + list(:NUMBER, + item(nil, para("One")), + item(nil, para("Two")), + item(nil, para("Three"))), + + para("Loose using tabs:"), + list(:NUMBER, + item(nil, para("First")), + item(nil, para("Second")), + item(nil, para("Third"))), + para("and using spaces:"), + list(:NUMBER, + item(nil, para("One")), + item(nil, para("Two")), + item(nil, para("Three"))), + + para("Multiple paragraphs:"), + list(:NUMBER, + item(nil, + para("Item 1, graf one."), + para("Item 2. graf two. The quick brown fox " + + "jumped over the lazy dog's\nback.")), + item(nil, para("Item 2.")), + item(nil, para("Item 3."))), + + head(2, "Nested"), + list(:BULLET, + item(nil, + para("Tab"), + list(:BULLET, + item(nil, + para("Tab"), + list(:BULLET, + item(nil, + para("Tab"))))))), + + para("Here's another:"), + list(:NUMBER, + item(nil, para("First")), + item(nil, para("Second:"), + list(:BULLET, + item(nil, para("Fee")), + item(nil, para("Fie")), + item(nil, para("Foe")))), + item(nil, para("Third"))), + + para("Same thing but with paragraphs:"), + list(:NUMBER, + item(nil, para("First")), + item(nil, para("Second:"), + list(:BULLET, + item(nil, para("Fee")), + item(nil, para("Fie")), + item(nil, para("Foe")))), + item(nil, para("Third"))), + + para("This was an error in Markdown 1.0.1:"), + list(:BULLET, + item(nil, + para("this"), + list(:BULLET, + item(nil, para("sub"))), + para("that")))) + + assert_equal expected, doc + end + + def test_strong_and_em_together + input = File.read "#{MARKDOWN_TEST_PATH}/Strong and em together.text" + + doc = @parser.parse input + + expected = + doc( + para("<b><em>This is strong and em.</em></b>"), + para("So is <b>_this_</b> word."), + para("<b><em>This is strong and em.</em></b>"), + para("So is <b>_this_</b> word.")) + + assert_equal expected, doc + end + + def test_tabs + input = File.read "#{MARKDOWN_TEST_PATH}/Tabs.text" + + doc = @parser.parse input + + expected = + doc( + list(:BULLET, + item(nil, + para("this is a list item\nindented with tabs")), + item(nil, + para("this is a list item\nindented with spaces"))), + + para("Code:"), + + verb("this code block is indented by one tab\n"), + + para("And:"), + + verb("\tthis code block is indented by two tabs\n"), + + para("And:"), + + verb( + "+\tthis is an example list item\n", + "\tindented with tabs\n", + "\n", + "+ this is an example list item\n", + " indented with spaces\n")) + + assert_equal expected, doc + end + + def test_tidyness + input = File.read "#{MARKDOWN_TEST_PATH}/Tidyness.text" + + doc = @parser.parse input + + expected = + doc( + block( + para("A list within a blockquote:"), + list(:BULLET, + item(nil, para("asterisk 1")), + item(nil, para("asterisk 2")), + item(nil, para("asterisk 3"))))) + + assert_equal expected, doc + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_markup.rb b/jni/ruby/test/rdoc/test_rdoc_markup.rb new file mode 100644 index 0000000..5c28a2c --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_markup.rb @@ -0,0 +1,95 @@ +require 'rdoc/test_case' + +class TestRDocMarkup < RDoc::TestCase + + def test_class_parse + expected = @RM::Document.new( + @RM::Paragraph.new('hello')) + + assert_equal expected, RDoc::Markup.parse('hello') + end + + def test_convert + str = <<-STR +now is +the time + + hello + dave + +1. l1 +2. l2 + STR + + m = RDoc::Markup.new + + tt = RDoc::Markup::ToTest.new m + + out = m.convert str, tt + + expected = [ + "now is the time", + "\n", + " hello\n dave\n", + "1: ", + "l1", + "1: ", + "l2", + ] + + assert_equal expected, out + end + + def test_convert_custom_markup + str = <<-STR +{stricken} + STR + + m = RDoc::Markup.new + m.add_word_pair '{', '}', :STRIKE + + tt = RDoc::Markup::ToTest.new nil, m + tt.add_tag :STRIKE, 'STRIKE ', ' STRIKE' + + out = m.convert str, tt + + expected = [ + "STRIKE stricken STRIKE", + ] + + assert_equal expected, out + end + + def test_convert_document + doc = RDoc::Markup::Parser.parse <<-STR +now is +the time + + hello + dave + +1. l1 +2. l2 + STR + + m = RDoc::Markup.new + + tt = RDoc::Markup::ToTest.new m + + out = m.convert doc, tt + + expected = [ + "now is the time", + "\n", + " hello\n dave\n", + "1: ", + "l1", + "1: ", + "l2", + ] + + assert_equal expected, out + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_markup_attribute_manager.rb b/jni/ruby/test/rdoc/test_rdoc_markup_attribute_manager.rb new file mode 100644 index 0000000..6a085fe --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_markup_attribute_manager.rb @@ -0,0 +1,364 @@ +require 'rdoc/test_case' + +class TestRDocMarkupAttributeManager < RDoc::TestCase + + def setup + super + + @am = RDoc::Markup::AttributeManager.new + + @bold_on = @am.changed_attribute_by_name([], [:BOLD]) + @bold_off = @am.changed_attribute_by_name([:BOLD], []) + + @tt_on = @am.changed_attribute_by_name([], [:TT]) + @tt_off = @am.changed_attribute_by_name([:TT], []) + + @em_on = @am.changed_attribute_by_name([], [:EM]) + @em_off = @am.changed_attribute_by_name([:EM], []) + + @bold_em_on = @am.changed_attribute_by_name([], [:BOLD] | [:EM]) + @bold_em_off = @am.changed_attribute_by_name([:BOLD] | [:EM], []) + + @em_then_bold = @am.changed_attribute_by_name([:EM], [:EM] | [:BOLD]) + + @em_to_bold = @am.changed_attribute_by_name([:EM], [:BOLD]) + + @am.add_word_pair("{", "}", :WOMBAT) + @wombat_on = @am.changed_attribute_by_name([], [:WOMBAT]) + @wombat_off = @am.changed_attribute_by_name([:WOMBAT], []) + + @klass = RDoc::Markup::AttributeManager + @formatter = RDoc::Markup::Formatter.new @rdoc.options + @formatter.add_tag :BOLD, '<B>', '</B>' + @formatter.add_tag :EM, '<EM>', '</EM>' + @formatter.add_tag :TT, '<CODE>', '</CODE>' + end + + def crossref(text) + crossref_bitmap = @am.attributes.bitmap_for(:_SPECIAL_) | + @am.attributes.bitmap_for(:CROSSREF) + + [ @am.changed_attribute_by_name([], [:CROSSREF, :_SPECIAL_]), + RDoc::Markup::Special.new(crossref_bitmap, text), + @am.changed_attribute_by_name([:CROSSREF, :_SPECIAL_], []) + ] + end + + def test_adding + assert_equal(["cat ", @wombat_on, "and", @wombat_off, " dog" ], + @am.flow("cat {and} dog")) + #assert_equal(["cat {and} dog" ], @am.flow("cat \\{and} dog")) + end + + def test_add_html_tag + @am.add_html("Test", :TEST) + tags = @am.html_tags + assert_equal(6, tags.size) + assert(tags.has_key?("test")) + end + + def test_add_special + @am.add_special "WikiWord", :WIKIWORD + specials = @am.special + + assert_equal 1, specials.size + assert specials.assoc "WikiWord" + end + + def test_add_word_pair + @am.add_word_pair '%', '&', 'percent and' + + assert @am.word_pair_map.include?(/(%)(\S+)(&)/) + assert @am.protectable.include?('%') + assert !@am.protectable.include?('&') + end + + def test_add_word_pair_angle + e = assert_raises ArgumentError do + @am.add_word_pair '<', '>', 'angles' + end + + assert_equal "Word flags may not start with '<'", e.message + end + + def test_add_word_pair_invalid + assert_raises ArgumentError do + @am.add_word_pair("<", "<", :TEST) + end + end + + def test_add_word_pair_map + @am.add_word_pair("x", "y", :TEST) + + word_pair_map = @am.word_pair_map + + assert_includes word_pair_map.keys.map { |r| r.source }, "(x)(\\S+)(y)" + end + + def test_add_word_pair_matching + @am.add_word_pair '^', '^', 'caret' + + assert @am.matching_word_pairs.include?('^') + assert @am.protectable.include?('^') + end + + def test_basic + assert_equal(["cat"], @am.flow("cat")) + + assert_equal(["cat ", @bold_on, "and", @bold_off, " dog"], + @am.flow("cat *and* dog")) + + assert_equal(["cat ", @bold_on, "AND", @bold_off, " dog"], + @am.flow("cat *AND* dog")) + + assert_equal(["cat ", @em_on, "And", @em_off, " dog"], + @am.flow("cat _And_ dog")) + + assert_equal(["cat *and dog*"], @am.flow("cat *and dog*")) + + assert_equal(["*cat and* dog"], @am.flow("*cat and* dog")) + + assert_equal(["cat *and ", @bold_on, "dog", @bold_off], + @am.flow("cat *and *dog*")) + + assert_equal(["cat ", @em_on, "and", @em_off, " dog"], + @am.flow("cat _and_ dog")) + + assert_equal(["cat_and_dog"], + @am.flow("cat_and_dog")) + + assert_equal(["cat ", @tt_on, "and", @tt_off, " dog"], + @am.flow("cat +and+ dog")) + + assert_equal(["cat ", @tt_on, "X::Y", @tt_off, " dog"], + @am.flow("cat +X::Y+ dog")) + + assert_equal(["cat ", @bold_on, "a_b_c", @bold_off, " dog"], + @am.flow("cat *a_b_c* dog")) + + assert_equal(["cat __ dog"], + @am.flow("cat __ dog")) + + assert_equal(["cat ", @em_on, "_", @em_off, " dog"], + @am.flow("cat ___ dog")) + + assert_equal(["cat and ", @em_on, "5", @em_off, " dogs"], + @am.flow("cat and _5_ dogs")) + end + + def test_bold + assert_equal [@bold_on, 'bold', @bold_off], + @am.flow("*bold*") + + assert_equal [@bold_on, 'Bold:', @bold_off], + @am.flow("*Bold:*") + + assert_equal [@bold_on, '\\bold', @bold_off], + @am.flow("*\\bold*") + end + + def test_bold_html_escaped + assert_equal ['cat <b>dog</b>'], @am.flow('cat \<b>dog</b>') + end + + def test_combined + assert_equal(["cat ", @em_on, "and", @em_off, " ", @bold_on, "dog", @bold_off], + @am.flow("cat _and_ *dog*")) + + assert_equal(["cat ", @em_on, "a__nd", @em_off, " ", @bold_on, "dog", @bold_off], + @am.flow("cat _a__nd_ *dog*")) + end + + def test_convert_attrs + str = '+foo+' + attrs = RDoc::Markup::AttrSpan.new str.length + + @am.convert_attrs str, attrs + + assert_equal "\000foo\000", str + + str = '+:foo:+' + attrs = RDoc::Markup::AttrSpan.new str.length + + @am.convert_attrs str, attrs + + assert_equal "\000:foo:\000", str + + str = '+x-y+' + attrs = RDoc::Markup::AttrSpan.new str.length + + @am.convert_attrs str, attrs + + assert_equal "\000x-y\000", str + end + + def test_convert_attrs_ignores_code + assert_equal 'foo <CODE>__send__</CODE> bar', output('foo <code>__send__</code> bar') + end + + def test_convert_attrs_ignores_tt + assert_equal 'foo <CODE>__send__</CODE> bar', output('foo <tt>__send__</tt> bar') + end + + def test_convert_attrs_preserves_double + assert_equal 'foo.__send__ :bar', output('foo.__send__ :bar') + assert_equal 'use __FILE__ to', output('use __FILE__ to') + end + + def test_convert_attrs_does_not_ignore_after_tt + assert_equal 'the <CODE>IF:</CODE><EM>key</EM> directive', output('the <tt>IF:</tt>_key_ directive') + end + + def test_escapes + assert_equal '<CODE>text</CODE>', output('<tt>text</tt>') + assert_equal '<tt>text</tt>', output('\\<tt>text</tt>') + assert_equal '<tt>', output('\\<tt>') + assert_equal '<CODE><tt></CODE>', output('<tt>\\<tt></tt>') + assert_equal '<CODE>\\<tt></CODE>', output('<tt>\\\\<tt></tt>') + assert_equal '<B>text</B>', output('*text*') + assert_equal '*text*', output('\\*text*') + assert_equal '\\', output('\\') + assert_equal '\\text', output('\\text') + assert_equal '\\\\text', output('\\\\text') + assert_equal 'text \\ text', output('text \\ text') + + assert_equal 'and <CODE>\\s</CODE> matches space', + output('and <tt>\\s</tt> matches space') + assert_equal 'use <CODE><tt>text</CODE></tt> for code', + output('use <tt>\\<tt>text</tt></tt> for code') + assert_equal 'use <CODE><tt>text</tt></CODE> for code', + output('use <tt>\\<tt>text\\</tt></tt> for code') + assert_equal 'use <tt><tt>text</tt></tt> for code', + output('use \\<tt>\\<tt>text</tt></tt> for code') + assert_equal 'use <tt><CODE>text</CODE></tt> for code', + output('use \\<tt><tt>text</tt></tt> for code') + assert_equal 'use <CODE>+text+</CODE> for code', + output('use <tt>\\+text+</tt> for code') + assert_equal 'use <tt><CODE>text</CODE></tt> for code', + output('use \\<tt>+text+</tt> for code') + assert_equal 'illegal <tag>not</tag> changed', + output('illegal <tag>not</tag> changed') + assert_equal 'unhandled <p>tag</p> unchanged', + output('unhandled <p>tag</p> unchanged') + end + + def test_html_like_em_bold + assert_equal ["cat ", @em_on, "and ", @em_to_bold, "dog", @bold_off], + @am.flow("cat <i>and </i><b>dog</b>") + end + + def test_html_like_em_bold_SGML + assert_equal ["cat ", @em_on, "and ", @em_to_bold, "dog", @bold_off], + @am.flow("cat <i>and <b></i>dog</b>") + end + + def test_html_like_em_bold_nested_1 + assert_equal(["cat ", @bold_em_on, "and", @bold_em_off, " dog"], + @am.flow("cat <i><b>and</b></i> dog")) + end + + def test_html_like_em_bold_nested_2 + assert_equal ["cat ", @em_on, "and ", @em_then_bold, "dog", @bold_em_off], + @am.flow("cat <i>and <b>dog</b></i>") + end + + def test_html_like_em_bold_nested_mixed_case + assert_equal ["cat ", @em_on, "and ", @em_then_bold, "dog", @bold_em_off], + @am.flow("cat <i>and <B>dog</B></I>") + end + + def test_html_like_em_bold_mixed_case + assert_equal ["cat ", @em_on, "and", @em_off, " ", @bold_on, "dog", @bold_off], + @am.flow("cat <i>and</i> <B>dog</b>") + end + + def test_html_like_teletype + assert_equal ["cat ", @tt_on, "dog", @tt_off], + @am.flow("cat <tt>dog</Tt>") + end + + def test_html_like_teletype_em_bold_SGML + assert_equal [@tt_on, "cat", @tt_off, " ", @em_on, "and ", @em_to_bold, "dog", @bold_off], + @am.flow("<tt>cat</tt> <i>and <b></i>dog</b>") + end + + def test_initial_html + html_tags = @am.html_tags + assert html_tags.is_a?(Hash) + assert_equal(5, html_tags.size) + end + + def test_initial_word_pairs + word_pairs = @am.matching_word_pairs + assert word_pairs.is_a?(Hash) + assert_equal(3, word_pairs.size) + end + + def test_mask_protected_sequence + def @am.str() @str end + def @am.str=(str) @str = str end + + @am.str = '<code>foo</code>' + @am.mask_protected_sequences + + assert_equal "<code>foo</code>", @am.str + + @am.str = '<code>foo\\</code>' + @am.mask_protected_sequences + + assert_equal "<code>foo<\x04/code>", @am.str, 'escaped close' + + @am.str = '<code>foo\\\\</code>' + @am.mask_protected_sequences + + assert_equal "<code>foo\\</code>", @am.str, 'escaped backslash' + end + + def test_protect + assert_equal(['cat \\ dog'], + @am.flow('cat \\ dog')) + + assert_equal(["cat <tt>dog</Tt>"], + @am.flow("cat \\<tt>dog</Tt>")) + + assert_equal(["cat ", @em_on, "and", @em_off, " <B>dog</b>"], + @am.flow("cat <i>and</i> \\<B>dog</b>")) + + assert_equal(["*word* or <b>text</b>"], + @am.flow("\\*word* or \\<b>text</b>")) + + assert_equal(["_cat_", @em_on, "dog", @em_off], + @am.flow("\\_cat_<i>dog</i>")) + end + + def test_special + @am.add_special(RDoc::CrossReference::CROSSREF_REGEXP, :CROSSREF) + + # + # The apostrophes in "cats'" and "dogs'" suppress the flagging of these + # words as potential cross-references, which is necessary for the unit + # tests. Unfortunately, the markup engine right now does not actually + # check whether a cross-reference is valid before flagging it. + # + assert_equal(["cats'"], @am.flow("cats'")) + + assert_equal(["cats' ", crossref("#fred"), " dogs'"].flatten, + @am.flow("cats' #fred dogs'")) + + assert_equal([crossref("#fred"), " dogs'"].flatten, + @am.flow("#fred dogs'")) + + assert_equal(["cats' ", crossref("#fred")].flatten, @am.flow("cats' #fred")) + end + + def test_tt_html + assert_equal [@tt_on, '"\n"', @tt_off], + @am.flow('<tt>"\n"</tt>') + end + + def output str + @formatter.convert_flow @am.flow str + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_markup_attributes.rb b/jni/ruby/test/rdoc/test_rdoc_markup_attributes.rb new file mode 100644 index 0000000..636e0cc --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_markup_attributes.rb @@ -0,0 +1,39 @@ +require 'rdoc/test_case' + +class TestRDocMarkupAttributes < RDoc::TestCase + + def setup + super + + @as = RDoc::Markup::Attributes.new + end + + def test_bitmap_for + assert_equal 2, @as.bitmap_for('two') + assert_equal 2, @as.bitmap_for('two') + assert_equal 4, @as.bitmap_for('three') + end + + def test_as_string + @as.bitmap_for 'two' + @as.bitmap_for 'three' + + assert_equal 'none', @as.as_string(0) + assert_equal '_SPECIAL_', @as.as_string(1) + assert_equal 'two', @as.as_string(2) + assert_equal '_SPECIAL_,two', @as.as_string(3) + end + + def test_each_name_of + @as.bitmap_for 'two' + @as.bitmap_for 'three' + + assert_equal %w[], @as.each_name_of(0).to_a + assert_equal %w[], @as.each_name_of(1).to_a + assert_equal %w[two], @as.each_name_of(2).to_a + assert_equal %w[three], @as.each_name_of(4).to_a + assert_equal %w[two three], @as.each_name_of(6).to_a + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_markup_document.rb b/jni/ruby/test/rdoc/test_rdoc_markup_document.rb new file mode 100644 index 0000000..718ae6d --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_markup_document.rb @@ -0,0 +1,207 @@ +require 'rdoc/test_case' + +class TestRDocMarkupDocument < RDoc::TestCase + + def setup + super + + @d = @RM::Document.new + end + + def test_append + @d << @RM::Paragraph.new('hi') + + expected = @RM::Document.new @RM::Paragraph.new('hi') + + assert_equal expected, @d + end + + def test_append_document + @d << @RM::Document.new + + assert_empty @d + + @d << @RM::Document.new(@RM::Paragraph.new('hi')) + + expected = @RM::Document.new @RM::Paragraph.new('hi'), @RM::BlankLine.new + + assert_equal expected, @d + end + + def test_append_string + @d << '' + + assert_empty @d + + assert_raises ArgumentError do + @d << 'hi' + end + end + + def test_concat + @d.concat [@RM::BlankLine.new, @RM::BlankLine.new] + + refute_empty @d + end + + def test_each + a = @RM::Document.new + b = @RM::Document.new(@RM::Paragraph.new('hi')) + + @d.push a, b + + assert_equal [a, b], @d.map { |sub_doc| sub_doc } + end + + def test_empty_eh + assert_empty @d + + @d << @RM::BlankLine.new + + refute_empty @d + end + + def test_empty_eh_document + d = @RM::Document.new @d + + assert_empty d + end + + def test_equals2 + d2 = @RM::Document.new + + assert_equal @d, d2 + + d2 << @RM::BlankLine.new + + refute_equal @d, d2 + end + + def test_equals2_file + d2 = @RM::Document.new + d2.file = 'file.rb' + + refute_equal @d, d2 + + @d.file = 'file.rb' + + assert_equal @d, d2 + end + + def test_file_equals + @d.file = 'file.rb' + + assert_equal 'file.rb', @d.file + end + + def test_file_equals_top_level + @d.file = @store.add_file 'file.rb' + + assert_equal 'file.rb', @d.file + end + + def test_lt2 + @d << @RM::BlankLine.new + + refute_empty @d + end + + def test_merge + original = @RM::Document.new @RM::Paragraph.new 'original' + original.file = 'file.rb' + root = @RM::Document.new original + + replace = @RM::Document.new @RM::Paragraph.new 'replace' + replace.file = 'file.rb' + + other = @RM::Document.new replace + + result = root.merge other + + inner = @RM::Document.new @RM::Paragraph.new 'replace' + inner.file = 'file.rb' + expected = @RM::Document.new inner + + assert_equal expected, result + end + + def test_merge_add + original = @RM::Document.new @RM::Paragraph.new 'original' + original.file = 'file.rb' + root = @RM::Document.new original + + addition = @RM::Document.new @RM::Paragraph.new 'addition' + addition.file = 'other.rb' + + other = @RM::Document.new addition + + result = root.merge other + + expected = @RM::Document.new original, addition + + assert_equal expected, result + end + + def test_merge_empty + original = @RM::Document.new + root = @RM::Document.new original + + replace = @RM::Document.new @RM::Paragraph.new 'replace' + replace.file = 'file.rb' + + other = @RM::Document.new replace + + result = root.merge other + + inner = @RM::Document.new @RM::Paragraph.new 'replace' + inner.file = 'file.rb' + expected = @RM::Document.new inner + + assert_equal expected, result + end + + def test_push + @d.push @RM::BlankLine.new, @RM::BlankLine.new + + refute_empty @d + end + + def test_table_of_contents + doc = @RM::Document.new( + @RM::Heading.new(1, 'A'), + @RM::Paragraph.new('B'), + @RM::Heading.new(2, 'C'), + @RM::Paragraph.new('D'), + @RM::Heading.new(1, 'E'), + @RM::Paragraph.new('F')) + + expected = [ + @RM::Heading.new(1, 'A'), + @RM::Heading.new(2, 'C'), + @RM::Heading.new(1, 'E'), + ] + + assert_equal expected, doc.table_of_contents + end + + def test_table_of_contents_omit_headings_below + document = doc( + head(1, 'A'), + para('B'), + head(2, 'C'), + para('D'), + head(1, 'E'), + para('F')) + + document.omit_headings_below = 1 + + expected = [ + head(1, 'A'), + head(1, 'E'), + ] + + assert_equal expected, document.table_of_contents + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_markup_formatter.rb b/jni/ruby/test/rdoc/test_rdoc_markup_formatter.rb new file mode 100644 index 0000000..d01a42f --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_markup_formatter.rb @@ -0,0 +1,175 @@ +require 'rdoc/test_case' + +class TestRDocMarkupFormatter < RDoc::TestCase + + class ToTest < RDoc::Markup::Formatter + + def initialize markup + super nil, markup + + add_tag :TT, '<code>', '</code>' + end + + def accept_paragraph paragraph + @res << attributes(paragraph.text) + end + + def attributes text + convert_flow @am.flow text.dup + end + + def handle_special_CAPS special + "handled #{special.text}" + end + + def start_accepting + @res = "" + end + + def end_accepting + @res + end + + end + + def setup + super + + @markup = @RM.new + @markup.add_special(/[A-Z]+/, :CAPS) + + @attribute_manager = @markup.attribute_manager + @attributes = @attribute_manager.attributes + + @to = ToTest.new @markup + + @caps = @attributes.bitmap_for :CAPS + @special = @attributes.bitmap_for :_SPECIAL_ + @tt = @attributes.bitmap_for :TT + end + + def test_class_gen_relative_url + def gen(from, to) + RDoc::Markup::ToHtml.gen_relative_url from, to + end + + assert_equal 'a.html', gen('a.html', 'a.html') + assert_equal 'b.html', gen('a.html', 'b.html') + + assert_equal 'd.html', gen('a/c.html', 'a/d.html') + assert_equal '../a.html', gen('a/c.html', 'a.html') + assert_equal 'a/c.html', gen('a.html', 'a/c.html') + end + + def special_names + @attribute_manager.special.map do |_, mask| + @attributes.as_string mask + end + end + + def test_add_special_RDOCLINK + @to.add_special_RDOCLINK + + assert_includes special_names, 'RDOCLINK' + + def @to.handle_special_RDOCLINK special + "<#{special.text}>" + end + + document = doc(para('{foo}[rdoc-label:bar].')) + + formatted = document.accept @to + + assert_equal '{foo}[<rdoc-label:bar>].', formatted + end + + def test_add_special_TIDYLINK + @to.add_special_TIDYLINK + + assert_includes special_names, 'TIDYLINK' + + def @to.handle_special_TIDYLINK special + "<#{special.text}>" + end + + document = doc(para('foo[rdoc-label:bar].')) + + formatted = document.accept @to + + assert_equal '<foo[rdoc-label:bar]>.', formatted + + document = doc(para('{foo}[rdoc-label:bar].')) + + formatted = document.accept @to + + assert_equal '<{foo}[rdoc-label:bar]>.', formatted + end + + def test_parse_url + scheme, url, id = @to.parse_url 'example/foo' + + assert_equal 'http', scheme + assert_equal 'example/foo', url + assert_equal nil, id + end + + def test_parse_url_anchor + scheme, url, id = @to.parse_url '#foottext-1' + + assert_equal nil, scheme + assert_equal '#foottext-1', url + assert_equal nil, id + end + + def test_parse_url_link + scheme, url, id = @to.parse_url 'link:README.txt' + + assert_equal 'link', scheme + assert_equal 'README.txt', url + assert_equal nil, id + end + + def test_parse_url_link_id + scheme, url, id = @to.parse_url 'link:README.txt#label-foo' + + assert_equal 'link', scheme + assert_equal 'README.txt#label-foo', url + assert_equal nil, id + end + + def test_parse_url_rdoc_label + scheme, url, id = @to.parse_url 'rdoc-label:foo' + + assert_equal 'link', scheme + assert_equal '#foo', url + assert_equal nil, id + + scheme, url, id = @to.parse_url 'rdoc-label:foo:bar' + + assert_equal 'link', scheme + assert_equal '#foo', url + assert_equal ' id="bar"', id + end + + def test_parse_url_scheme + scheme, url, id = @to.parse_url 'http://example/foo' + + assert_equal 'http', scheme + assert_equal 'http://example/foo', url + assert_equal nil, id + + scheme, url, id = @to.parse_url 'https://example/foo' + + assert_equal 'https', scheme + assert_equal 'https://example/foo', url + assert_equal nil, id + end + + def test_convert_tt_special + converted = @to.convert '<code>AAA</code>' + + assert_equal '<code>AAA</code>', converted + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_markup_hard_break.rb b/jni/ruby/test/rdoc/test_rdoc_markup_hard_break.rb new file mode 100644 index 0000000..b9f7873 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_markup_hard_break.rb @@ -0,0 +1,31 @@ +require 'rdoc/test_case' + +class TestRDocMarkupHardBreak < RDoc::TestCase + + def setup + super + + @hb = RDoc::Markup::HardBreak.new + end + + def test_accept + visitor = Object.new + + def visitor.accept_hard_break(obj) @obj = obj end + def visitor.obj() @obj end + + @hb.accept visitor + + assert_same @hb, visitor.obj + end + + def test_equals2 + other = RDoc::Markup::HardBreak.new + + assert_equal @hb, other + + refute_equal @hb, Object.new + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_markup_heading.rb b/jni/ruby/test/rdoc/test_rdoc_markup_heading.rb new file mode 100644 index 0000000..26d4b5b --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_markup_heading.rb @@ -0,0 +1,29 @@ +require 'rdoc/test_case' + +class TestRDocMarkupHeading < RDoc::TestCase + + def setup + super + + @h = RDoc::Markup::Heading.new 1, 'Hello *Friend*!' + end + + def test_aref + assert_equal 'label-Hello+Friend-21', @h.aref + end + + def test_label + assert_equal 'label-Hello+Friend-21', @h.label + assert_equal 'label-Hello+Friend-21', @h.label(nil) + + context = RDoc::NormalClass.new 'Foo' + + assert_equal 'class-Foo-label-Hello+Friend-21', @h.label(context) + end + + def test_plain_html + assert_equal 'Hello <strong>Friend</strong>!', @h.plain_html + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_markup_include.rb b/jni/ruby/test/rdoc/test_rdoc_markup_include.rb new file mode 100644 index 0000000..37a5b32 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_markup_include.rb @@ -0,0 +1,19 @@ +require 'rdoc/test_case' + +class TestRDocMarkupInclude < RDoc::TestCase + + def setup + super + + @include = @RM::Include.new 'file', [Dir.tmpdir] + end + + def test_equals2 + assert_equal @include, @RM::Include.new('file', [Dir.tmpdir]) + refute_equal @include, @RM::Include.new('file', %w[.]) + refute_equal @include, @RM::Include.new('other', [Dir.tmpdir]) + refute_equal @include, Object.new + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_markup_indented_paragraph.rb b/jni/ruby/test/rdoc/test_rdoc_markup_indented_paragraph.rb new file mode 100644 index 0000000..d8dd795 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_markup_indented_paragraph.rb @@ -0,0 +1,53 @@ +require 'rdoc/test_case' + +class TestRDocMarkupIndentedParagraph < RDoc::TestCase + + def setup + super + + @IP = RDoc::Markup::IndentedParagraph + end + + def test_initialize + ip = @IP.new 2, 'a', 'b' + + assert_equal 2, ip.indent + assert_equal %w[a b], ip.parts + end + + def test_accept + visitor = Object.new + def visitor.accept_indented_paragraph(obj) @obj = obj end + def visitor.obj() @obj end + + paragraph = @IP.new 0 + + paragraph.accept visitor + + assert_equal paragraph, visitor.obj + end + + def test_equals2 + one = @IP.new 1 + two = @IP.new 2 + + assert_equal one, one + refute_equal one, two + end + + def test_text + paragraph = @IP.new(2, 'hello', ' world') + + assert_equal 'hello world', paragraph.text + end + + def test_text_break + paragraph = @IP.new(2, 'hello', hard_break, 'world') + + assert_equal 'helloworld', paragraph.text + + assert_equal "hello\n world", paragraph.text("\n") + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_markup_paragraph.rb b/jni/ruby/test/rdoc/test_rdoc_markup_paragraph.rb new file mode 100644 index 0000000..8de1c3c --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_markup_paragraph.rb @@ -0,0 +1,32 @@ +require 'rdoc/test_case' + +class TestRDocMarkupParagraph < RDoc::TestCase + + def test_accept + visitor = Object.new + def visitor.accept_paragraph(obj) @obj = obj end + def visitor.obj() @obj end + + paragraph = RDoc::Markup::Paragraph.new + + paragraph.accept visitor + + assert_same paragraph, visitor.obj + end + + def test_text + paragraph = para('hello', ' world') + + assert_equal 'hello world', paragraph.text + end + + def test_text_break + paragraph = para('hello', hard_break, 'world') + + assert_equal 'helloworld', paragraph.text + + assert_equal "hello\nworld", paragraph.text("\n") + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_markup_parser.rb b/jni/ruby/test/rdoc/test_rdoc_markup_parser.rb new file mode 100644 index 0000000..d27fb42 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_markup_parser.rb @@ -0,0 +1,1680 @@ +# coding: utf-8 + +require 'rdoc/test_case' + +class TestRDocMarkupParser < RDoc::TestCase + + def setup + super + + @have_byteslice = ''.respond_to? :byteslice + + @RMP = @RM::Parser + end + + def test_build_heading + parser = @RMP.new + + parser.tokens.replace [ + [:TEXT, 'heading three', 4, 0], + [:NEWLINE, "\n", 17, 0], + ] + + assert_equal @RM::Heading.new(3, 'heading three'), parser.build_heading(3) + end + + def test_char_pos + parser = @RMP.new + s = parser.setup_scanner 'cät' + + s.scan(/\S+/) + + if @have_byteslice or @have_encoding then + assert_equal 3, parser.char_pos(s.pos) + else + assert_equal 4, parser.char_pos(s.pos) + end + end + + def test_get + parser = util_parser + + assert_equal [:HEADER, 1, 0, 0], parser.get + + assert_equal 7, parser.tokens.length + end + + def test_parse_bullet + str = <<-STR +* l1 +* l2 + STR + + expected = [ + @RM::List.new(:BULLET, *[ + @RM::ListItem.new(nil, + @RM::Paragraph.new('l1')), + @RM::ListItem.new(nil, + @RM::Paragraph.new('l2'))])] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_bullet_utf_8 + str = <<-STR +* 新しい機能 + STR + + expected = [ + @RM::List.new(:BULLET, *[ + @RM::ListItem.new(nil, + @RM::Paragraph.new('新しい機能'))])] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_bullet_verbatim_heading + str = <<-STR +* l1 + v + += H + STR + + expected = [ + @RM::List.new(:BULLET, *[ + @RM::ListItem.new(nil, + @RM::Paragraph.new('l1'), + @RM::Verbatim.new("v\n"))]), + @RM::Heading.new(1, 'H')] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_bullet_heading + str = <<-STR +* = l1 + STR + + expected = [ + @RM::List.new(:BULLET, *[ + @RM::ListItem.new(nil, + @RM::Heading.new(1, 'l1'))])] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_bullet_indent + str = <<-STR +* l1 + * l1.1 +* l2 + STR + + expected = [ + @RM::List.new(:BULLET, *[ + @RM::ListItem.new(nil, + @RM::Paragraph.new('l1'), + @RM::List.new(:BULLET, *[ + @RM::ListItem.new(nil, + @RM::Paragraph.new('l1.1'))])), + @RM::ListItem.new(nil, + @RM::Paragraph.new('l2'))])] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_bullet_paragraph + str = <<-STR +now is +* l1 +* l2 +the time + STR + + expected = [ + @RM::Paragraph.new('now is'), + @RM::List.new(:BULLET, *[ + @RM::ListItem.new(nil, + @RM::Paragraph.new('l1')), + @RM::ListItem.new(nil, + @RM::Paragraph.new('l2')), + ]), + @RM::Paragraph.new('the time'), + ] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_bullet_multiline + str = <<-STR +* l1 + l1+ +* l2 + STR + + expected = [ + list(:BULLET, + item(nil, + para('l1 ', 'l1+')), + item(nil, + para('l2')))] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_bullet_multiparagraph + str = <<-STR +* l1 + + l1+ + STR + + expected = [ + @RM::List.new(:BULLET, *[ + @RM::ListItem.new(nil, + @RM::Paragraph.new('l1'), + @RM::BlankLine.new, + @RM::Paragraph.new('l1+')), + ]), + ] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_bullet_indent_verbatim + str = <<-STR +* l1 + * l1.1 + text + code + code + + text +* l2 + STR + + expected = [ + list(:BULLET, + item(nil, + para('l1'), + list(:BULLET, + item(nil, + para('l1.1 ', 'text'), + verb("code\n", " code\n"), + para('text')))), + item(nil, + para('l2')))] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_dash + str = <<-STR +- one +- two + STR + + expected = [ + @RM::List.new(:BULLET, *[ + @RM::ListItem.new(nil, + @RM::Paragraph.new('one')), + @RM::ListItem.new(nil, + @RM::Paragraph.new('two'))])] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_heading + str = '= heading one' + + expected = [ + @RM::Heading.new(1, 'heading one')] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_heading_three + str = '=== heading three' + + expected = [ + @RM::Heading.new(3, 'heading three')] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_heading_bullet + str = '= * heading one' + + expected = [ + @RM::Heading.new(1, '* heading one')] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_heading_empty + str = <<-STR +=== +* bullet + STR + + expected = [ + @RM::Heading.new(3, ''), + @RM::BlankLine.new, + @RM::List.new(:BULLET, *[ + @RM::ListItem.new(nil, + @RM::Paragraph.new('bullet'))]), + ] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_heading_heading + str = '= =' + + expected = [ + @RM::Heading.new(1, '=')] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_heading_lalpha + str = '= b. heading one' + + expected = [ + @RM::Heading.new(1, 'b. heading one')] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_heading_label + str = '= [heading one]' + + expected = [ + @RM::Heading.new(1, '[heading one]')] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_heading_note + str = '= heading one::' + + expected = [ + @RM::Heading.new(1, 'heading one::')] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_heading_number + str = '= 5. heading one' + + expected = [ + @RM::Heading.new(1, '5. heading one')] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_heading_ualpha + str = '= B. heading one' + + expected = [ + @RM::Heading.new(1, 'B. heading one')] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_label + str = <<-STR +[one] item one +[two] item two + STR + + expected = [ + list(:LABEL, + item(%w[one], + para('item one')), + item(%w[two], + para('item two')))] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_label_bullet + str = <<-STR +[cat] l1 + * l1.1 +[dog] l2 + STR + + expected = [ + list(:LABEL, + item(%w[cat], + para('l1'), + list(:BULLET, + item(nil, + para('l1.1')))), + item(%w[dog], + para('l2')))] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_label_multi_label + str = <<-STR +[one] +[two] some description + STR + + expected = [ + list(:LABEL, + item(%w[one two], + para('some description')))] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_label_multi_line + str = <<-STR +[cat] l1 + continuation +[dog] l2 + STR + + expected = [ + list(:LABEL, + item(%w[cat], + para('l1 ', 'continuation')), + item(%w[dog], + para('l2')))] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_label_newline + str = <<-STR +[one] + item one +[two] + item two + STR + + expected = [ + list(:LABEL, + item(%w[one], + para('item one')), + item(%w[two], + para('item two')))] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_lalpha + str = <<-STR +a. l1 +b. l2 + STR + + expected = [ + @RM::List.new(:LALPHA, *[ + @RM::ListItem.new(nil, + @RM::Paragraph.new('l1')), + @RM::ListItem.new(nil, + @RM::Paragraph.new('l2'))])] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_lalpha_ualpha + str = <<-STR +a. l1 +b. l2 +A. l3 +A. l4 + STR + + expected = [ + @RM::List.new(:LALPHA, *[ + @RM::ListItem.new(nil, + @RM::Paragraph.new('l1')), + @RM::ListItem.new(nil, + @RM::Paragraph.new('l2'))]), + @RM::List.new(:UALPHA, *[ + @RM::ListItem.new(nil, + @RM::Paragraph.new('l3')), + @RM::ListItem.new(nil, + @RM::Paragraph.new('l4'))])] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_lalpha_utf_8 + str = <<-STR +a. 新しい機能 + STR + + expected = [ + @RM::List.new(:LALPHA, *[ + @RM::ListItem.new(nil, + @RM::Paragraph.new('新しい機能'))])] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_line_break + str = "now is\nthe time \nfor all" + + expected = [ + para('now is ', 'the time'), + blank_line, + para('for all')] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_list_list_1 + str = <<-STR +10. para 1 + + [label 1] + para 1.1 + + code + + para 1.2 + STR + + expected = [ + list(:NUMBER, + item(nil, + para('para 1'), + blank_line, + list(:LABEL, + item(%w[label\ 1], + para('para 1.1'), + blank_line, + verb("code\n"), + para('para 1.2')))))] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_list_list_2 + str = <<-STR +6. para + + label 1:: text 1 + label 2:: text 2 + STR + + expected = [ + list(:NUMBER, + item(nil, + para('para'), + blank_line, + list(:NOTE, + item(%w[label\ 1], + para('text 1')), + item(%w[label\ 2], + para('text 2')))))] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_list_verbatim + str = <<-STR +* one + verb1 + verb2 +* two + STR + + expected = [ + @RM::List.new(:BULLET, *[ + @RM::ListItem.new(nil, + @RM::Paragraph.new('one'), + @RM::Verbatim.new("verb1\n", "verb2\n")), + @RM::ListItem.new(nil, + @RM::Paragraph.new('two'))])] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_lists + str = <<-STR +now is +* l1 +1. n1 +2. n2 +* l2 +the time + STR + + expected = [ + @RM::Paragraph.new('now is'), + @RM::List.new(:BULLET, *[ + @RM::ListItem.new(nil, + @RM::Paragraph.new('l1'))]), + @RM::List.new(:NUMBER, *[ + @RM::ListItem.new(nil, + @RM::Paragraph.new('n1')), + @RM::ListItem.new(nil, + @RM::Paragraph.new('n2'))]), + @RM::List.new(:BULLET, *[ + @RM::ListItem.new(nil, + @RM::Paragraph.new('l2'))]), + @RM::Paragraph.new('the time')] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_note + str = <<-STR +one:: item one +two:: item two + STR + + expected = [ + list(:NOTE, + item(%w[one], + para('item one')), + item(%w[two], + para('item two')))] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_note_empty + str = <<-STR +one:: +two:: + STR + + expected = [ + list(:NOTE, + item(%w[one two], + blank_line))] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_note_note + str = <<-STR +one:: two:: + STR + + expected = [ + list(:NOTE, + item(%w[one], + list(:NOTE, + item(%w[two], + blank_line))))] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_number_bullet + str = <<-STR +1. l1 + * l1.1 +2. l2 + STR + + expected = [ + list(:NUMBER, + item(nil, + para('l1'), + list(:BULLET, + item(nil, + para('l1.1')))), + item(nil, + para('l2')))] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_paragraph + str = <<-STR +now is the time + +for all good men + STR + + expected = [ + @RM::Paragraph.new('now is the time'), + @RM::BlankLine.new, + @RM::Paragraph.new('for all good men')] + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_paragraph_multiline + str = "now is the time\nfor all good men" + + expected = @RM::Paragraph.new 'now is the time ', 'for all good men' + assert_equal [expected], @RMP.parse(str).parts + end + + def test_parse_paragraph_verbatim + str = <<-STR +now is the time + code _line_ here +for all good men + STR + + expected = [ + @RM::Paragraph.new('now is the time'), + @RM::Verbatim.new("code _line_ here\n"), + @RM::Paragraph.new('for all good men'), + ] + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_rule + str = <<-STR +now is the time + +--- + +for all good men + STR + + expected = [ + @RM::Paragraph.new('now is the time'), + @RM::BlankLine.new, + @RM::Rule.new(1), + @RM::BlankLine.new, + @RM::Paragraph.new('for all good men')] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_ualpha + str = <<-STR +A. l1 +B. l2 + STR + + expected = [ + @RM::List.new(:UALPHA, *[ + @RM::ListItem.new(nil, + @RM::Paragraph.new('l1')), + @RM::ListItem.new(nil, + @RM::Paragraph.new('l2'))])] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_trailing_cr + expected = [ @RM::Paragraph.new('Text') ] + # FIXME hangs the parser: + assert_equal expected, @RMP.parse("Text\r").parts + end + + def test_parse_verbatim + str = <<-STR +now is + code +the time + STR + + expected = [ + @RM::Paragraph.new('now is'), + @RM::Verbatim.new("code\n"), + @RM::Paragraph.new('the time'), + ] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_verbatim_bullet + str = <<-STR + * blah + STR + + expected = [ + @RM::Verbatim.new("* blah\n")] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_verbatim_dash + str = <<-STR + - blah + STR + + expected = [ + @RM::Verbatim.new("- blah\n")] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_verbatim_fold + str = <<-STR +now is + code + + + code1 + +the time + STR + + expected = [ + @RM::Paragraph.new('now is'), + @RM::Verbatim.new("code\n", "\n", "code1\n"), + @RM::Paragraph.new('the time'), + ] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_verbatim_heading + str = <<-STR +text + === heading three + STR + + expected = [ + @RM::Paragraph.new('text'), + @RM::Verbatim.new("=== heading three\n")] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_verbatim_heading2 + str = "text\n code\n=== heading three" + + expected = [ + @RM::Paragraph.new('text'), + @RM::Verbatim.new("code\n"), + @RM::Heading.new(3, 'heading three')] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_verbatim_label + str = <<-STR + [blah] blah + STR + + expected = [ + @RM::Verbatim.new("[blah] blah\n")] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_verbatim_lalpha + str = <<-STR + b. blah + STR + + expected = [ + @RM::Verbatim.new("b. blah\n")] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_verbatim_markup_example + str = <<-STR +text + code + === heading three + STR + + expected = [ + @RM::Paragraph.new('text'), + @RM::Verbatim.new("code\n", "=== heading three\n")] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_verbatim_merge + str = <<-STR +now is + code + + code1 +the time + STR + + expected = [ + @RM::Paragraph.new('now is'), + @RM::Verbatim.new("code\n", "\n", "code1\n"), + @RM::Paragraph.new('the time'), + ] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_verbatim_merge2 + str = <<-STR +now is + code + + code1 + + code2 +the time + STR + + expected = [ + @RM::Paragraph.new('now is'), + @RM::Verbatim.new("code\n", "\n", "code1\n", "\n", "code2\n"), + @RM::Paragraph.new('the time'), + ] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_verbatim_multiline + str = <<-STR +now is + code + code1 +the time + STR + + expected = [ + @RM::Paragraph.new('now is'), + @RM::Verbatim.new("code\n", "code1\n"), + @RM::Paragraph.new('the time'), + ] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_verbatim_multilevel + str = <<-STR +now is the time + code + more code +for all good men + STR + + expected = [ + @RM::Paragraph.new('now is the time'), + @RM::Verbatim.new(" code\n", + "more code\n"), + @RM::Paragraph.new('for all good men'), + ] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_verbatim_note + str = <<-STR + blah:: blah + STR + + expected = [ + @RM::Verbatim.new("blah:: blah\n")] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_verbatim_number + str = <<-STR + 2. blah + STR + + expected = [ + @RM::Verbatim.new("2. blah\n")] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_verbatim_rule + str = <<-STR +text + + --- lib/blah.rb.orig + +++ lib/blah.rb + STR + + expected = [ + @RM::Paragraph.new('text'), + @RM::BlankLine.new, + @RM::Verbatim.new("--- lib/blah.rb.orig\n", + "+++ lib/blah.rb\n")] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_verbatim_rule2 + str = <<-STR.chomp +text + + --- + STR + + expected = [ + @RM::Paragraph.new('text'), + @RM::BlankLine.new, + @RM::Verbatim.new("---")] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_verbatim_trim + str = <<-STR +now is + code + + code1 + +the time + STR + + expected = [ + @RM::Paragraph.new('now is'), + @RM::Verbatim.new("code\n", + "\n", + "code1\n"), + @RM::Paragraph.new('the time'), + ] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_verbatim_ualpha + str = <<-STR + B. blah + STR + + expected = [ + @RM::Verbatim.new("B. blah\n")] + + assert_equal expected, @RMP.parse(str).parts + end + + def test_parse_whitespace + expected = [ + @RM::Paragraph.new('hello'), + ] + + assert_equal expected, @RMP.parse('hello').parts + + expected = [ + @RM::Verbatim.new('hello '), + ] + + assert_equal expected, @RMP.parse(' hello ').parts + + expected = [ + @RM::Verbatim.new('hello '), + ] + + assert_equal expected, @RMP.parse(' hello ').parts + + expected = [ + @RM::Paragraph.new('1'), + @RM::Verbatim.new("2\n", ' 3'), + ] + + assert_equal expected, @RMP.parse("1\n 2\n 3").parts + + expected = [ + @RM::Verbatim.new("1\n", + " 2\n", + " 3"), + ] + + assert_equal expected, @RMP.parse(" 1\n 2\n 3").parts + + expected = [ + @RM::Paragraph.new('1'), + @RM::Verbatim.new("2\n", + " 3\n"), + @RM::Paragraph.new('1'), + @RM::Verbatim.new('2'), + ] + + assert_equal expected, @RMP.parse("1\n 2\n 3\n1\n 2").parts + + expected = [ + @RM::Verbatim.new("1\n", + " 2\n", + " 3\n", + "1\n", + ' 2'), + ] + + assert_equal expected, @RMP.parse(" 1\n 2\n 3\n 1\n 2").parts + + expected = [ + @RM::Verbatim.new("1\n", + " 2\n", + "\n", + ' 3'), + ] + + assert_equal expected, @RMP.parse(" 1\n 2\n\n 3").parts + end + + def test_peek_token + parser = util_parser + + assert_equal [:HEADER, 1, 0, 0], parser.peek_token + + assert_equal 8, parser.tokens.length + end + + def test_skip + parser = util_parser + + assert_equal [:HEADER, 1, 0, 0], parser.skip(:HEADER) + + assert_equal [:TEXT, 'Heading', 2, 0], parser.get + + assert_equal [:NEWLINE, "\n", 9, 0], parser.peek_token + + assert_raises RDoc::Markup::Parser::ParseError do + parser.skip :NONE + end + + assert_equal [:NEWLINE, "\n", 9, 0], parser.peek_token + + assert_equal nil, parser.skip(:NONE, false) + + assert_equal [:NEWLINE, "\n", 9, 0], parser.peek_token + end + + def test_tokenize_bullet + str = <<-STR +* l1 + STR + + expected = [ + [:BULLET, '*', 0, 0], + [:TEXT, 'l1', 2, 0], + [:NEWLINE, "\n", 4, 0], + ] + + assert_equal expected, @RMP.tokenize(str) + end + + def test_tokenize_bullet_indent + str = <<-STR +* l1 + * l1.1 + STR + + expected = [ + [:BULLET, '*', 0, 0], + [:TEXT, 'l1', 2, 0], + [:NEWLINE, "\n", 4, 0], + [:BULLET, '*', 2, 1], + [:TEXT, 'l1.1', 4, 1], + [:NEWLINE, "\n", 8, 1], + ] + + assert_equal expected, @RMP.tokenize(str) + end + + def test_tokenize_heading + str = <<-STR += Heading +== Heading 2 + STR + + expected = [ + [:HEADER, 1, 0, 0], + [:TEXT, 'Heading', 2, 0], + [:NEWLINE, "\n", 9, 0], + [:HEADER, 2, 0, 1], + [:TEXT, 'Heading 2', 3, 1], + [:NEWLINE, "\n", 12, 1], + ] + + assert_equal expected, @RMP.tokenize(str) + end + + def test_tokenize_heading_empty + str = <<-STR +=== +* bullet + STR + + expected = [ + [:HEADER, 3, 0, 0], + [:NEWLINE, "\n", 3, 0], + [:BULLET, "*", 0, 1], + [:TEXT, "bullet", 2, 1], + [:NEWLINE, "\n", 8, 1], + ] + + assert_equal expected, @RMP.tokenize(str) + end + + def test_tokenize_heading_heading + str = <<-STR += = + STR + + expected = [ + [:HEADER, 1, 0, 0], + [:TEXT, '=', 2, 0], + [:NEWLINE, "\n", 3, 0], + ] + + assert_equal expected, @RMP.tokenize(str) + end + + def test_tokenize_heading_no_space + str = <<-STR +=Heading +==Heading 2 + STR + + expected = [ + [:HEADER, 1, 0, 0], + [:TEXT, 'Heading', 1, 0], + [:NEWLINE, "\n", 8, 0], + [:HEADER, 2, 0, 1], + [:TEXT, 'Heading 2', 2, 1], + [:NEWLINE, "\n", 11, 1], + ] + + assert_equal expected, @RMP.tokenize(str) + end + + def test_tokenize_label + str = <<-STR +[cat] l1 +[dog] l1.1 + STR + + expected = [ + [:LABEL, 'cat', 0, 0], + [:TEXT, 'l1', 6, 0], + [:NEWLINE, "\n", 8, 0], + [:LABEL, 'dog', 0, 1], + [:TEXT, 'l1.1', 6, 1], + [:NEWLINE, "\n", 10, 1], + ] + + assert_equal expected, @RMP.tokenize(str) + end + + def test_tokenize_label_note + str = <<-STR +[label] + note:: + STR + + expected = [ + [:LABEL, 'label', 0, 0], + [:NEWLINE, "\n", 7, 0], + [:NOTE, 'note', 2, 1], + [:NEWLINE, "\n", 8, 1], + ] + + assert_equal expected, @RMP.tokenize(str) + end + + def test_tokenize_label_newline + str = <<-STR +[cat] + l1 + STR + + expected = [ + [:LABEL, 'cat', 0, 0], + [:NEWLINE, "\n", 5, 0], + [:TEXT, 'l1', 2, 1], + [:NEWLINE, "\n", 4, 1], + ] + + assert_equal expected, @RMP.tokenize(str) + end + + def test_tokenize_label_newline_windows + str = <<-STR +[cat]\r + l1\r + STR + + expected = [ + [:LABEL, 'cat', 0, 0], + [:NEWLINE, "\n", 6, 0], + [:TEXT, 'l1', 2, 1], + [:NEWLINE, "\n", 5, 1], + ] + + assert_equal expected, @RMP.tokenize(str) + end + + def test_tokenize_lalpha + str = <<-STR +a. l1 +b. l1.1 + STR + + expected = [ + [:LALPHA, 'a', 0, 0], + [:TEXT, 'l1', 3, 0], + [:NEWLINE, "\n", 5, 0], + [:LALPHA, 'b', 0, 1], + [:TEXT, 'l1.1', 3, 1], + [:NEWLINE, "\n", 7, 1], + ] + + assert_equal expected, @RMP.tokenize(str) + end + + def test_tokenize_line_break + str = "now is\nthe time \nfor all\n" + + expected = [ + [:TEXT, 'now is', 0, 0], + [:NEWLINE, "\n", 6, 0], + [:TEXT, 'the time', 0, 1], + [:BREAK, " ", 8, 1], + [:NEWLINE, "\n", 10, 1], + [:TEXT, 'for all', 0, 2], + [:NEWLINE, "\n", 7, 2], + ] + + assert_equal expected, @RMP.tokenize(str) + end + + def test_tokenize_line_break_long + str = "now is\nthe time \nfor all\n" + + expected = [ + [:TEXT, 'now is', 0, 0], + [:NEWLINE, "\n", 6, 0], + [:TEXT, 'the time ', 0, 1], + [:BREAK, ' ', 9, 1], + [:NEWLINE, "\n", 11, 1], + [:TEXT, 'for all', 0, 2], + [:NEWLINE, "\n", 7, 2], + ] + + assert_equal expected, @RMP.tokenize(str) + end + + def test_tokenize_line_break_no_short + str = "now is\nthe time \nfor all\n" + + expected = [ + [:TEXT, 'now is', 0, 0], + [:NEWLINE, "\n", 6, 0], + [:TEXT, 'the time ', 0, 1], + [:NEWLINE, "\n", 9, 1], + [:TEXT, 'for all', 0, 2], + [:NEWLINE, "\n", 7, 2], + ] + + assert_equal expected, @RMP.tokenize(str) + end + + def test_tokenize_note + str = <<-STR +cat:: l1 +dog:: l1.1 + STR + + expected = [ + [:NOTE, 'cat', 0, 0], + [:TEXT, 'l1', 6, 0], + [:NEWLINE, "\n", 8, 0], + [:NOTE, 'dog', 0, 1], + [:TEXT, 'l1.1', 6, 1], + [:NEWLINE, "\n", 10, 1], + ] + + assert_equal expected, @RMP.tokenize(str) + end + + def test_tokenize_note_empty + str = <<-STR +cat:: +dog:: + STR + + expected = [ + [:NOTE, 'cat', 0, 0], + [:NEWLINE, "\n", 5, 0], + [:NOTE, 'dog', 0, 1], + [:NEWLINE, "\n", 5, 1], + ] + + assert_equal expected, @RMP.tokenize(str) + end + + def test_tokenize_note_newline + str = <<-STR +cat:: + l1 + STR + + expected = [ + [:NOTE, 'cat', 0, 0], + [:NEWLINE, "\n", 5, 0], + [:TEXT, 'l1', 2, 1], + [:NEWLINE, "\n", 4, 1], + ] + + assert_equal expected, @RMP.tokenize(str) + end + + def test_tokenize_note_utf_8 + skip 'Encoding not implemented' unless @have_encoding + + str = <<-STR +cät:: l1a + l1b +døg:: l2a + l2b + STR + + expected = [ + [:NOTE, 'cät', 0, 0], + [:TEXT, 'l1a', 6, 0], + [:NEWLINE, "\n", 9, 0], + [:TEXT, 'l1b', 6, 1], + [:NEWLINE, "\n", 9, 1], + [:NOTE, 'døg', 0, 2], + [:TEXT, 'l2a', 6, 2], + [:NEWLINE, "\n", 9, 2], + [:TEXT, 'l2b', 6, 3], + [:NEWLINE, "\n", 9, 3], + ] + + assert_equal expected, @RMP.tokenize(str) + end + + def test_tokenize_note_newline_windows + str = <<-STR +cat::\r + l1\r + STR + + expected = [ + [:NOTE, 'cat', 0, 0], + [:NEWLINE, "\n", 6, 0], + [:TEXT, 'l1', 2, 1], + [:NEWLINE, "\n", 5, 1], + ] + + assert_equal expected, @RMP.tokenize(str) + end + + def test_tokenize_note_not + str = <<-STR +Cat::Dog + STR + + expected = [ + [:TEXT, 'Cat::Dog', 0, 0], + [:NEWLINE, "\n", 8, 0], + ] + + assert_equal expected, @RMP.tokenize(str) + end + + def test_tokenize_number + str = <<-STR +1. l1 +2. l1.1 + STR + + expected = [ + [:NUMBER, '1', 0, 0], + [:TEXT, 'l1', 3, 0], + [:NEWLINE, "\n", 5, 0], + [:NUMBER, '2', 0, 1], + [:TEXT, 'l1.1', 3, 1], + [:NEWLINE, "\n", 7, 1], + ] + + assert_equal expected, @RMP.tokenize(str) + end + + def test_tokenize_number_period + str = <<-STR +1. blah blah blah + l. +2. blah blah blah blah + d. + STR + + expected = [ + [:NUMBER, "1", 0, 0], + [:TEXT, "blah blah blah", 3, 0], + [:NEWLINE, "\n", 17, 0], + + [:TEXT, "l.", 3, 1], + [:NEWLINE, "\n", 5, 1], + + [:NUMBER, "2", 0, 2], + [:TEXT, "blah blah blah blah", 3, 2], + [:NEWLINE, "\n", 22, 2], + + [:TEXT, "d.", 3, 3], + [:NEWLINE, "\n", 5, 3] + ] + + assert_equal expected, @RMP.tokenize(str) + end + + def test_tokenize_number_period_continue + str = <<-STR +1. blah blah blah + l. more stuff +2. blah blah blah blah + d. other stuff + STR + + expected = [ + [:NUMBER, "1", 0, 0], + [:TEXT, "blah blah blah", 3, 0], + [:NEWLINE, "\n", 17, 0], + + [:LALPHA, "l", 3, 1], + [:TEXT, "more stuff", 7, 1], + [:NEWLINE, "\n", 17, 1], + + [:NUMBER, "2", 0, 2], + [:TEXT, "blah blah blah blah", 3, 2], + [:NEWLINE, "\n", 22, 2], + + [:LALPHA, "d", 3, 3], + [:TEXT, "other stuff", 6, 3], + [:NEWLINE, "\n", 17, 3] + ] + + assert_equal expected, @RMP.tokenize(str) + end + + def test_tokenize_paragraphs + str = <<-STR +now is +the time + +for all + STR + + expected = [ + [:TEXT, 'now is', 0, 0], + [:NEWLINE, "\n", 6, 0], + [:TEXT, 'the time', 0, 1], + [:NEWLINE, "\n", 8, 1], + [:NEWLINE, "\n", 0, 2], + [:TEXT, 'for all', 0, 3], + [:NEWLINE, "\n", 7, 3], + ] + + assert_equal expected, @RMP.tokenize(str) + end + + def test_tokenize_rule + str = <<-STR +--- + +--- blah --- + STR + + expected = [ + [:RULE, 1, 0, 0], + [:NEWLINE, "\n", 3, 0], + [:NEWLINE, "\n", 0, 1], + [:TEXT, "--- blah ---", 0, 2], + [:NEWLINE, "\n", 12, 2], + ] + + assert_equal expected, @RMP.tokenize(str) + end + + def test_tokenize_rule_windows + str = <<-STR +---\r + +--- blah ---\r + STR + + expected = [ + [:RULE, 1, 0, 0], + [:NEWLINE, "\n", 4, 0], + [:NEWLINE, "\n", 0, 1], + [:TEXT, "--- blah ---", 0, 2], + [:NEWLINE, "\n", 13, 2], + ] + + assert_equal expected, @RMP.tokenize(str) + end + + def test_tokenize_ualpha + str = <<-STR +A. l1 +B. l1.1 + STR + + expected = [ + [:UALPHA, 'A', 0, 0], + [:TEXT, 'l1', 3, 0], + [:NEWLINE, "\n", 5, 0], + [:UALPHA, 'B', 0, 1], + [:TEXT, 'l1.1', 3, 1], + [:NEWLINE, "\n", 7, 1], + ] + + assert_equal expected, @RMP.tokenize(str) + end + + def test_tokenize_verbatim_heading + str = <<-STR +Example heading: + + === heading three + STR + + expected = [ + [:TEXT, 'Example heading:', 0, 0], + [:NEWLINE, "\n", 16, 0], + [:NEWLINE, "\n", 0, 1], + [:HEADER, 3, 3, 2], + [:TEXT, 'heading three', 7, 2], + [:NEWLINE, "\n", 20, 2], + ] + + assert_equal expected, @RMP.tokenize(str) + end + + def test_tokenize_verbatim_rule + str = <<-STR + Verbatim section here that is double-underlined + =============================================== + STR + + expected = [ + [:TEXT, 'Verbatim section here that is double-underlined', 2, 0], + [:NEWLINE, "\n", 49, 0], + [:HEADER, 47, 2, 1], + [:NEWLINE, "\n", 49, 1], + ] + + assert_equal expected, @RMP.tokenize(str) + end + + def test_tokenize_verbatim_rule_fancy + str = <<-STR + A + b + =============================================== + c + STR + + expected = [ + [:TEXT, 'A', 2, 0], + [:NEWLINE, "\n", 3, 0], + [:TEXT, 'b', 4, 1], + [:NEWLINE, "\n", 5, 1], + [:HEADER, 47, 2, 2], + [:NEWLINE, "\n", 49, 2], + [:TEXT, 'c', 4, 3], + [:NEWLINE, "\n", 5, 3], + ] + + assert_equal expected, @RMP.tokenize(str) + end + + def test_token_pos + parser = @RMP.new + s = parser.setup_scanner 'cät' + + s.scan(/\S+/) + + if @have_encoding or @have_byteslice then + assert_equal [3, 0], parser.token_pos(s.pos) + else + assert_equal [4, 0], parser.token_pos(s.pos) + end + end + + # HACK move to Verbatim test case + def test_verbatim_normalize + v = @RM::Verbatim.new "foo\n", "\n", "\n", "bar\n" + + v.normalize + + assert_equal ["foo\n", "\n", "bar\n"], v.parts + + v = @RM::Verbatim.new "foo\n", "\n" + + v.normalize + + assert_equal ["foo\n"], v.parts + end + + def test_unget + parser = util_parser + + parser.get + + parser.unget + + assert_equal [:HEADER, 1, 0, 0], parser.peek_token + + assert_raises @RMP::Error do + parser.unget + end + + assert_equal 8, parser.tokens.length + end + + def util_parser + str = <<-STR += Heading + +Some text here +some more text over here + STR + + @parser = @RMP.new + @parser.tokenize str + @parser + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_markup_pre_process.rb b/jni/ruby/test/rdoc/test_rdoc_markup_pre_process.rb new file mode 100644 index 0000000..7cbe29c --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_markup_pre_process.rb @@ -0,0 +1,473 @@ +# coding: utf-8 + +require 'rdoc/test_case' + +class TestRDocMarkupPreProcess < RDoc::TestCase + + def setup + super + + @tempfile = Tempfile.new 'test_rdoc_markup_pre_process' + @file_name = File.basename @tempfile.path + @dir = File.dirname @tempfile.path + + @pp = RDoc::Markup::PreProcess.new @tempfile.path, [@dir, File.dirname(__FILE__)] + end + + def teardown + super + + @tempfile.close! + end + + def test_class_register + RDoc::Markup::PreProcess.register 'for_test' do raise 'fail' end + + assert_equal %w[for_test], RDoc::Markup::PreProcess.registered.keys + end + + def test_class_post_process + RDoc::Markup::PreProcess.post_process do end + + assert_equal 1, RDoc::Markup::PreProcess.post_processors.length + end + + def test_include_file + @tempfile.write <<-INCLUDE +# -*- mode: rdoc; coding: utf-8; fill-column: 74; -*- + +Regular expressions (<i>regexp</i>s) are patterns which describe the +contents of a string. + INCLUDE + + @tempfile.flush + @tempfile.rewind + + content = @pp.include_file @file_name, '', nil + + expected = <<-EXPECTED +Regular expressions (<i>regexp</i>s) are patterns which describe the +contents of a string. + EXPECTED + + assert_equal expected, content + end + + def test_include_file_encoding_incompatible + skip "Encoding not implemented" unless Object.const_defined? :Encoding + + @tempfile.write <<-INCLUDE +# -*- mode: rdoc; coding: utf-8; fill-column: 74; -*- + +π + INCLUDE + + @tempfile.flush + @tempfile.rewind + + content = @pp.include_file @file_name, '', Encoding::US_ASCII + + expected = "?\n" + + assert_equal expected, content + end + + def test_include_file_in_other_directory + content = nil + out, err = capture_io do + content = @pp.include_file "test.txt", '', nil + end + + assert_empty out + assert_empty err + + assert_equal "test file\n", content + end + + def test_handle + text = "# :main: M\n" + out = @pp.handle text + + assert_same out, text + assert_equal "#\n", text + end + + def test_handle_comment + text = "# :main: M\n" + c = comment text + + out = @pp.handle c + + assert_same out, text + assert_equal "#\n", text + end + + def test_handle_markup + c = comment ':markup: rd' + + @pp.handle c + + assert_equal 'rd', c.format + end + + def test_handle_markup_empty + c = comment ':markup:' + + @pp.handle c + + assert_equal 'rdoc', c.format + end + + def test_handle_post_process + cd = RDoc::CodeObject.new + + RDoc::Markup::PreProcess.post_process do |text, code_object| + code_object.metadata[:stuff] = text + + :junk + end + + text = "# a b c\n" + + out = @pp.handle text, cd + + assert_same out, text + assert_equal "# a b c\n", text + assert_equal "# a b c\n", cd.metadata[:stuff] + end + + def test_handle_unregistered + text = "# :x: y\n" + out = @pp.handle text + + assert_same out, text + assert_equal "# :x: y\n", text + end + + def test_handle_directive_blankline + result = @pp.handle_directive '#', 'arg', 'a, b' + + assert_equal "#:arg: a, b\n", result + end + + def test_handle_directive_downcase + method = RDoc::AnyMethod.new nil, 'm' + + @pp.handle_directive '', 'ARG', 'a, b', method + + assert_equal 'a, b', method.params + end + + def test_handle_directive_arg + method = RDoc::AnyMethod.new nil, 'm' + + @pp.handle_directive '', 'arg', 'a, b', method + + assert_equal 'a, b', method.params + end + + def test_handle_directive_arg_no_context + result = @pp.handle_directive '', 'arg', 'a, b', nil + + assert_equal ":arg: a, b\n", result + end + + def test_handle_directive_args + method = RDoc::AnyMethod.new nil, 'm' + + @pp.handle_directive '', 'args', 'a, b', method + + assert_equal 'a, b', method.params + end + + def test_handle_directive_block + result = @pp.handle_directive '', 'x', 'y' do |directive, param| + '' + end + + assert_empty result + end + + def test_handle_directive_block_false + result = @pp.handle_directive '', 'x', 'y' do |directive, param| + false + end + + assert_equal ":x: y\n", result + end + + def test_handle_directive_block_nil + result = @pp.handle_directive '', 'x', 'y' do |directive, param| + nil + end + + assert_equal ":x: y\n", result + end + + def test_handle_directive_category + context = RDoc::Context.new + original_section = context.current_section + + @pp.handle_directive '', 'category', 'other', context + + refute_equal original_section, context.current_section + end + + def test_handle_directive_doc + code_object = RDoc::CodeObject.new + code_object.document_self = false + code_object.force_documentation = false + + @pp.handle_directive '', 'doc', nil, code_object + + assert code_object.document_self + assert code_object.force_documentation + end + + def test_handle_directive_doc_no_context + result = @pp.handle_directive '', 'doc', nil + + assert_equal "\n", result + end + + def test_handle_directive_enddoc + code_object = RDoc::CodeObject.new + + @pp.handle_directive '', 'enddoc', nil, code_object + + assert code_object.done_documenting + end + + def test_handle_directive_include + @tempfile.write 'included' + @tempfile.flush + + result = @pp.handle_directive '', 'include', @file_name + + assert_equal 'included', result + end + + def test_handle_directive_main + @pp.options = RDoc::Options.new + + @pp.handle_directive '', 'main', 'M' + + assert_equal 'M', @pp.options.main_page + end + + def test_handle_directive_notnew + m = RDoc::AnyMethod.new nil, 'm' + + @pp.handle_directive '', 'notnew', nil, m + + assert m.dont_rename_initialize + end + + def test_handle_directive_not_new + m = RDoc::AnyMethod.new nil, 'm' + + @pp.handle_directive '', 'not_new', nil, m + + assert m.dont_rename_initialize + end + + def test_handle_directive_not_dash_new + m = RDoc::AnyMethod.new nil, 'm' + + @pp.handle_directive '', 'not-new', nil, m + + assert m.dont_rename_initialize + end + + def test_handle_directive_nodoc + code_object = RDoc::CodeObject.new + code_object.document_self = true + code_object.document_children = true + + @pp.handle_directive '', 'nodoc', nil, code_object + + refute code_object.document_self + assert code_object.document_children + end + + def test_handle_directive_nodoc_all + code_object = RDoc::CodeObject.new + code_object.document_self = true + code_object.document_children = true + + @pp.handle_directive '', 'nodoc', 'all', code_object + + refute code_object.document_self + refute code_object.document_children + end + + def test_handle_directive_nodoc_no_context + result = @pp.handle_directive '', 'nodoc', nil + + assert_equal "\n", result + end + + def test_handle_directive_registered + RDoc::Markup::PreProcess.register 'x' + + result = @pp.handle_directive '', 'x', 'y' + + assert_nil result + + result = @pp.handle_directive '', 'x', 'y' do |directive, param| + false + end + + assert_equal ":x: y\n", result + + result = @pp.handle_directive '', 'x', 'y' do |directive, param| + '' + end + + assert_equal '', result + end + + def test_handle_directive_registered_block + called = nil + + RDoc::Markup::PreProcess.register 'x' do |directive, param| + called = [directive, param] + 'blah' + end + + result = @pp.handle_directive '', 'x', 'y' + + assert_equal 'blah', result + assert_equal %w[x y], called + end + + def test_handle_directive_registered_code_object + RDoc::Markup::PreProcess.register 'x' + code_object = RDoc::CodeObject.new + + @pp.handle_directive '', 'x', 'y', code_object + + assert_equal 'y', code_object.metadata['x'] + + code_object.metadata.clear + + result = @pp.handle_directive '', 'x', 'y' do |directive, param| + false + end + + assert_equal ":x: y\n", result + assert_empty code_object.metadata + + result = @pp.handle_directive '', 'x', 'y' do |directive, param| + '' + end + + assert_equal '', result + assert_empty code_object.metadata + end + + def test_handle_directive_startdoc + code_object = RDoc::CodeObject.new + code_object.stop_doc + code_object.force_documentation = false + + @pp.handle_directive '', 'startdoc', nil, code_object + + assert code_object.document_self + assert code_object.document_children + assert code_object.force_documentation + end + + def test_handle_directive_stopdoc + code_object = RDoc::CodeObject.new + + @pp.handle_directive '', 'stopdoc', nil, code_object + + refute code_object.document_self + refute code_object.document_children + end + + def test_handle_directive_title + @pp.options = RDoc::Options.new + + @pp.handle_directive '', 'title', 'T' + + assert_equal 'T', @pp.options.title + end + + def test_handle_directive_unhandled + code_object = RDoc::CodeObject.new + + @pp.handle_directive '', 'x', 'y', code_object + + assert_equal 'y', code_object.metadata['x'] + + code_object.metadata.clear + + @pp.handle_directive '', 'x', '', code_object + + assert_includes code_object.metadata, 'x' + end + + def test_handle_directive_unhandled_block + code_object = RDoc::CodeObject.new + + @pp.handle_directive '', 'x', 'y', code_object do + false + end + + assert_empty code_object.metadata + + @pp.handle_directive '', 'x', 'y', code_object do + nil + end + + assert_equal 'y', code_object.metadata['x'] + + code_object.metadata.clear + + @pp.handle_directive '', 'x', 'y', code_object do + '' + end + + assert_empty code_object.metadata + end + + def test_handle_directive_yield + method = RDoc::AnyMethod.new nil, 'm' + method.params = 'index, &block' + + @pp.handle_directive '', 'yield', 'item', method + + assert_equal 'item', method.block_params + assert_equal 'index', method.params + end + + def test_handle_directive_yield_block_param + method = RDoc::AnyMethod.new nil, 'm' + method.params = '&block' + + @pp.handle_directive '', 'yield', 'item', method + + assert_equal 'item', method.block_params + assert_empty method.params + end + + def test_handle_directive_yield_no_context + method = RDoc::AnyMethod.new nil, 'm' + + @pp.handle_directive '', 'yield', 'item', method + + assert_equal 'item', method.block_params + end + + def test_handle_directive_yields + method = RDoc::AnyMethod.new nil, 'm' + + @pp.handle_directive '', 'yields', 'item', method + + assert_equal 'item', method.block_params + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_markup_raw.rb b/jni/ruby/test/rdoc/test_rdoc_markup_raw.rb new file mode 100644 index 0000000..43bfe0c --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_markup_raw.rb @@ -0,0 +1,22 @@ +require 'rdoc/test_case' + +class TestRDocMarkupRaw < RDoc::TestCase + + def setup + super + + @p = @RM::Raw.new + end + + def test_push + @p.push 'hi', 'there' + + assert_equal @RM::Raw.new('hi', 'there'), @p + end + + def test_pretty_print + assert_equal '[raw: ]', mu_pp(@p) + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_markup_to_ansi.rb b/jni/ruby/test/rdoc/test_rdoc_markup_to_ansi.rb new file mode 100644 index 0000000..5afaf94 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_markup_to_ansi.rb @@ -0,0 +1,369 @@ +require 'rdoc/test_case' + +class TestRDocMarkupToAnsi < RDoc::Markup::TextFormatterTestCase + + add_visitor_tests + add_text_tests + + def setup + super + + @to = RDoc::Markup::ToAnsi.new + end + + def accept_blank_line + assert_equal "\e[0m\n", @to.res.join + end + + def accept_block_quote + assert_equal "\e[0m> quote\n", @to.res.join + end + + def accept_document + assert_equal "\e[0mhello\n", @to.res.join + end + + def accept_heading + assert_equal "\e[0mHello\n", @to.res.join + end + + def accept_list_end_bullet + assert_empty @to.list_index + assert_empty @to.list_type + assert_empty @to.list_width + end + + def accept_list_end_label + assert_empty @to.list_index + assert_empty @to.list_type + assert_empty @to.list_width + end + + def accept_list_end_lalpha + assert_empty @to.list_index + assert_empty @to.list_type + assert_empty @to.list_width + end + + def accept_list_end_note + assert_empty @to.list_index + assert_empty @to.list_type + assert_empty @to.list_width + end + + def accept_list_end_number + assert_empty @to.list_index + assert_empty @to.list_type + assert_empty @to.list_width + end + + def accept_list_end_ualpha + assert_empty @to.list_index + assert_empty @to.list_type + assert_empty @to.list_width + end + + def accept_list_item_end_bullet + assert_equal 0, @to.indent, 'indent' + end + + def accept_list_item_end_label + assert_equal "\e[0mcat:\n", @to.res.join + assert_equal 0, @to.indent, 'indent' + end + + def accept_list_item_end_lalpha + assert_equal 0, @to.indent, 'indent' + assert_equal 'b', @to.list_index.last + end + + def accept_list_item_end_note + assert_equal "\e[0mcat:\n", @to.res.join + assert_equal 0, @to.indent, 'indent' + end + + def accept_list_item_end_number + assert_equal 0, @to.indent, 'indent' + assert_equal 2, @to.list_index.last + end + + def accept_list_item_end_ualpha + assert_equal 0, @to.indent, 'indent' + assert_equal 'B', @to.list_index.last + end + + def accept_list_item_start_bullet + assert_equal %W"\e[0m", @to.res + assert_equal '* ', @to.prefix + end + + def accept_list_item_start_label + assert_equal %W"\e[0m", @to.res + assert_equal "cat:\n ", @to.prefix + + assert_equal 2, @to.indent + end + + def accept_list_item_start_lalpha + assert_equal %W"\e[0m", @to.res + assert_equal 'a. ', @to.prefix + + assert_equal 'a', @to.list_index.last + assert_equal 3, @to.indent + end + + def accept_list_item_start_note + assert_equal %W"\e[0m", @to.res + assert_equal "cat:\n ", @to.prefix + + assert_equal 2, @to.indent + end + + def accept_list_item_start_number + assert_equal %W"\e[0m", @to.res + assert_equal '1. ', @to.prefix + + assert_equal 1, @to.list_index.last + assert_equal 3, @to.indent + end + + def accept_list_item_start_ualpha + assert_equal %W"\e[0m", @to.res + assert_equal 'A. ', @to.prefix + + assert_equal 'A', @to.list_index.last + assert_equal 3, @to.indent + end + + def accept_list_start_bullet + assert_equal "\e[0m", @to.res.join + assert_equal [nil], @to.list_index + assert_equal [:BULLET], @to.list_type + assert_equal [1], @to.list_width + end + + def accept_list_start_label + assert_equal "\e[0m", @to.res.join + assert_equal [nil], @to.list_index + assert_equal [:LABEL], @to.list_type + assert_equal [2], @to.list_width + end + + def accept_list_start_lalpha + assert_equal "\e[0m", @to.res.join + assert_equal ['a'], @to.list_index + assert_equal [:LALPHA], @to.list_type + assert_equal [1], @to.list_width + end + + def accept_list_start_note + assert_equal "\e[0m", @to.res.join + assert_equal [nil], @to.list_index + assert_equal [:NOTE], @to.list_type + assert_equal [2], @to.list_width + end + + def accept_list_start_number + assert_equal "\e[0m", @to.res.join + assert_equal [1], @to.list_index + assert_equal [:NUMBER], @to.list_type + assert_equal [1], @to.list_width + end + + def accept_list_start_ualpha + assert_equal "\e[0m", @to.res.join + assert_equal ['A'], @to.list_index + assert_equal [:UALPHA], @to.list_type + assert_equal [1], @to.list_width + end + + def accept_paragraph + assert_equal "\e[0mhi\n", @to.res.join + end + + def accept_raw + raw = <<-RAW.rstrip +\e[0m<table> +<tr><th>Name<th>Count +<tr><td>a<td>1 +<tr><td>b<td>2 +</table> + RAW + + assert_equal raw, @to.res.join + end + + def accept_rule + assert_equal "\e[0m#{'-' * 78}\n", @to.res.join + end + + def accept_verbatim + assert_equal "\e[0m hi\n world\n\n", @to.res.join + end + + def end_accepting + assert_equal "\e[0mhi", @to.end_accepting + end + + def start_accepting + assert_equal 0, @to.indent + assert_equal %W"\e[0m", @to.res + assert_empty @to.list_index + assert_empty @to.list_type + assert_empty @to.list_width + end + + def accept_heading_1 + assert_equal "\e[0m\e[1;32mHello\e[m\n", @to.end_accepting + end + + def accept_heading_2 + assert_equal "\e[0m\e[4;32mHello\e[m\n", @to.end_accepting + end + + def accept_heading_3 + assert_equal "\e[0m\e[32mHello\e[m\n", @to.end_accepting + end + + def accept_heading_4 + assert_equal "\e[0mHello\n", @to.end_accepting + end + + def accept_heading_indent + assert_equal "\e[0m \e[1;32mHello\e[m\n", @to.end_accepting + end + + def accept_heading_b + assert_equal "\e[0m\e[1;32m\e[1mHello\e[m\e[m\n", @to.end_accepting + end + + def accept_heading_suppressed_crossref + assert_equal "\e[0m\e[1;32mHello\e[m\n", @to.end_accepting + end + + def accept_list_item_start_note_2 + assert_equal "\e[0m\e[7mteletype\e[m:\n teletype description\n\n", + @to.res.join + end + + def accept_list_item_start_note_multi_description + assert_equal "\e[0mlabel:\n description one\n\n description two\n\n", + @to.res.join + end + + def accept_list_item_start_note_multi_label + assert_equal "\e[0mone\ntwo:\n two headers\n\n", + @to.res.join + end + + def accept_paragraph_b + assert_equal "\e[0mreg \e[1mbold words\e[m reg\n", @to.end_accepting + end + + def accept_paragraph_br + assert_equal "\e[0mone\ntwo\n", @to.end_accepting + end + + def accept_paragraph_break + assert_equal "\e[0mhello\nworld\n", @to.end_accepting + end + + def accept_paragraph_i + assert_equal "\e[0mreg \e[4mitalic words\e[m reg\n", @to.end_accepting + end + + def accept_paragraph_indent + expected = <<-EXPECTED +\e[0m words words words words words words words words words words words words + words words words words words words words words words words words words + words words words words words words + EXPECTED + + assert_equal expected, @to.end_accepting + end + + def accept_paragraph_plus + assert_equal "\e[0mreg \e[7mteletype\e[m reg\n", @to.end_accepting + end + + def accept_paragraph_star + assert_equal "\e[0mreg \e[1mbold\e[m reg\n", @to.end_accepting + end + + def accept_paragraph_underscore + assert_equal "\e[0mreg \e[4mitalic\e[m reg\n", @to.end_accepting + end + + def accept_paragraph_wrap + expected = <<-EXPECTED +\e[0mwords words words words words words words words words words words words words +words words words words words words words words words words words words words +words words words words + EXPECTED + + assert_equal expected, @to.end_accepting + end + + def accept_rule_indent + assert_equal "\e[0m #{'-' * 75}\n", @to.end_accepting + end + + def accept_verbatim_indent + assert_equal "\e[0m hi\n world\n\n", @to.end_accepting + end + + def accept_verbatim_big_indent + assert_equal "\e[0m hi\n world\n\n", @to.end_accepting + end + + def list_nested + expected = <<-EXPECTED +\e[0m* l1 + * l1.1 +* l2 + EXPECTED + + assert_equal expected, @to.end_accepting + end + + def list_verbatim + expected = <<-EXPECTED # HACK overblown +\e[0m* list stuff + + * list + with + + second + + 1. indented + 2. numbered + + third + + * second + + EXPECTED + + assert_equal expected, @to.end_accepting + end + + # functional test + def test_convert_list_note + note_list = <<-NOTE_LIST +foo :: +bar :: + hi + NOTE_LIST + + expected = <<-EXPECTED +\e[0mfoo +bar: + hi + + EXPECTED + + assert_equal expected, @to.convert(note_list) + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_markup_to_bs.rb b/jni/ruby/test/rdoc/test_rdoc_markup_to_bs.rb new file mode 100644 index 0000000..f2e6352 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_markup_to_bs.rb @@ -0,0 +1,366 @@ +require 'rdoc/test_case' + +class TestRDocMarkupToBs < RDoc::Markup::TextFormatterTestCase + + add_visitor_tests + add_text_tests + + def setup + super + + @to = RDoc::Markup::ToBs.new + end + + def accept_blank_line + assert_equal "\n", @to.res.join + end + + def accept_block_quote + assert_equal "> quote\n", @to.res.join + end + + def accept_document + assert_equal "hello\n", @to.res.join + end + + def accept_heading + skip "No String#chars, upgrade your ruby" unless ''.respond_to? :chars + assert_equal "===== H\bHe\bel\bll\blo\bo\n", @to.res.join + end + + def accept_list_end_bullet + assert_empty @to.list_index + assert_empty @to.list_type + assert_empty @to.list_width + end + + def accept_list_end_label + assert_empty @to.list_index + assert_empty @to.list_type + assert_empty @to.list_width + end + + def accept_list_end_lalpha + assert_empty @to.list_index + assert_empty @to.list_type + assert_empty @to.list_width + end + + def accept_list_end_note + assert_empty @to.list_index + assert_empty @to.list_type + assert_empty @to.list_width + end + + def accept_list_end_number + assert_empty @to.list_index + assert_empty @to.list_type + assert_empty @to.list_width + end + + def accept_list_end_ualpha + assert_empty @to.list_index + assert_empty @to.list_type + assert_empty @to.list_width + end + + def accept_list_item_end_bullet + assert_equal 0, @to.indent, 'indent' + end + + def accept_list_item_end_label + assert_equal "cat:\n", @to.res.join + assert_equal 0, @to.indent, 'indent' + end + + def accept_list_item_end_lalpha + assert_equal 0, @to.indent, 'indent' + assert_equal 'b', @to.list_index.last + end + + def accept_list_item_end_note + assert_equal "cat:\n", @to.res.join + assert_equal 0, @to.indent, 'indent' + end + + def accept_list_item_end_number + assert_equal 0, @to.indent, 'indent' + assert_equal 2, @to.list_index.last + end + + def accept_list_item_end_ualpha + assert_equal 0, @to.indent, 'indent' + assert_equal 'B', @to.list_index.last + end + + def accept_list_item_start_bullet + assert_equal [''], @to.res + assert_equal '* ', @to.prefix + end + + def accept_list_item_start_label + assert_equal [''], @to.res + assert_equal "cat:\n ", @to.prefix + + assert_equal 2, @to.indent + end + + def accept_list_item_start_lalpha + assert_equal [''], @to.res + assert_equal 'a. ', @to.prefix + + assert_equal 'a', @to.list_index.last + assert_equal 3, @to.indent + end + + def accept_list_item_start_note + assert_equal [''], @to.res + assert_equal "cat:\n ", @to.prefix + + assert_equal 2, @to.indent + end + + def accept_list_item_start_number + assert_equal [''], @to.res + assert_equal '1. ', @to.prefix + + assert_equal 1, @to.list_index.last + assert_equal 3, @to.indent + end + + def accept_list_item_start_ualpha + assert_equal [''], @to.res + assert_equal 'A. ', @to.prefix + + assert_equal 'A', @to.list_index.last + assert_equal 3, @to.indent + end + + def accept_list_start_bullet + assert_equal "", @to.res.join + assert_equal [nil], @to.list_index + assert_equal [:BULLET], @to.list_type + assert_equal [1], @to.list_width + end + + def accept_list_start_label + assert_equal "", @to.res.join + assert_equal [nil], @to.list_index + assert_equal [:LABEL], @to.list_type + assert_equal [2], @to.list_width + end + + def accept_list_start_lalpha + assert_equal "", @to.res.join + assert_equal ['a'], @to.list_index + assert_equal [:LALPHA], @to.list_type + assert_equal [1], @to.list_width + end + + def accept_list_start_note + assert_equal "", @to.res.join + assert_equal [nil], @to.list_index + assert_equal [:NOTE], @to.list_type + assert_equal [2], @to.list_width + end + + def accept_list_start_number + assert_equal "", @to.res.join + assert_equal [1], @to.list_index + assert_equal [:NUMBER], @to.list_type + assert_equal [1], @to.list_width + end + + def accept_list_start_ualpha + assert_equal "", @to.res.join + assert_equal ['A'], @to.list_index + assert_equal [:UALPHA], @to.list_type + assert_equal [1], @to.list_width + end + + def accept_paragraph + assert_equal "hi\n", @to.res.join + end + + def accept_raw + raw = <<-RAW.rstrip +<table> +<tr><th>Name<th>Count +<tr><td>a<td>1 +<tr><td>b<td>2 +</table> + RAW + + assert_equal raw, @to.res.join + end + + def accept_rule + assert_equal "#{'-' * 78}\n", @to.res.join + end + + def accept_verbatim + assert_equal " hi\n world\n\n", @to.res.join + end + + def end_accepting + assert_equal "hi", @to.end_accepting + end + + def start_accepting + assert_equal 0, @to.indent + assert_equal [''], @to.res + assert_empty @to.list_index + assert_empty @to.list_type + assert_empty @to.list_width + end + + def accept_heading_1 + skip "No String#chars, upgrade your ruby" unless ''.respond_to? :chars + assert_equal "= H\bHe\bel\bll\blo\bo\n", @to.end_accepting + end + + def accept_heading_2 + skip "No String#chars, upgrade your ruby" unless ''.respond_to? :chars + assert_equal "== H\bHe\bel\bll\blo\bo\n", @to.end_accepting + end + + def accept_heading_3 + skip "No String#chars, upgrade your ruby" unless ''.respond_to? :chars + assert_equal "=== H\bHe\bel\bll\blo\bo\n", @to.end_accepting + end + + def accept_heading_4 + skip "No String#chars, upgrade your ruby" unless ''.respond_to? :chars + assert_equal "==== H\bHe\bel\bll\blo\bo\n", @to.end_accepting + end + + def accept_heading_indent + skip "No String#chars, upgrade your ruby" unless ''.respond_to? :chars + assert_equal " = H\bHe\bel\bll\blo\bo\n", @to.end_accepting + end + + def accept_heading_b + skip "No String#chars, upgrade your ruby" unless ''.respond_to? :chars + assert_equal "= H\bHe\bel\bll\blo\bo\n", @to.end_accepting + end + + def accept_heading_suppressed_crossref + skip "No String#chars, upgrade your ruby" unless ''.respond_to? :chars + assert_equal "= H\bHe\bel\bll\blo\bo\n", @to.end_accepting + end + + def accept_list_item_start_note_2 + assert_equal "teletype:\n teletype description\n\n", @to.res.join + end + + def accept_list_item_start_note_multi_description + assert_equal "label:\n description one\n\n description two\n\n", + @to.res.join + end + + def accept_list_item_start_note_multi_label + assert_equal "one\ntwo:\n two headers\n\n", @to.res.join + end + + def accept_paragraph_b + skip "No String#chars, upgrade your ruby" unless ''.respond_to? :chars + assert_equal "reg b\bbo\bol\bld\bd \b w\bwo\bor\brd\bds\bs reg\n", + @to.end_accepting + end + + def accept_paragraph_br + skip "No String#chars, upgrade your ruby" unless ''.respond_to? :chars + assert_equal "one\ntwo\n", @to.end_accepting + end + + def accept_paragraph_break + skip "No String#chars, upgrade your ruby" unless ''.respond_to? :chars + assert_equal "hello\nworld\n", + @to.end_accepting + end + + def accept_paragraph_i + skip "No String#chars, upgrade your ruby" unless ''.respond_to? :chars + assert_equal "reg _\bi_\bt_\ba_\bl_\bi_\bc_\b _\bw_\bo_\br_\bd_\bs reg\n", + @to.end_accepting + end + + def accept_paragraph_indent + expected = <<-EXPECTED + words words words words words words words words words words words words + words words words words words words words words words words words words + words words words words words words + EXPECTED + + assert_equal expected, @to.end_accepting + end + + def accept_paragraph_plus + assert_equal "reg teletype reg\n", @to.end_accepting + end + + def accept_paragraph_star + skip "No String#chars, upgrade your ruby" unless ''.respond_to? :chars + assert_equal "reg b\bbo\bol\bld\bd reg\n", @to.end_accepting + end + + def accept_paragraph_underscore + skip "No String#chars, upgrade your ruby" unless ''.respond_to? :chars + assert_equal "reg _\bi_\bt_\ba_\bl_\bi_\bc reg\n", @to.end_accepting + end + + def accept_paragraph_wrap + expected = <<-EXPECTED +words words words words words words words words words words words words words +words words words words words words words words words words words words words +words words words words + EXPECTED + + assert_equal expected, @to.end_accepting + end + + def accept_rule_indent + assert_equal " #{'-' * 75}\n", @to.end_accepting + end + + def accept_verbatim_indent + assert_equal " hi\n world\n\n", @to.end_accepting + end + + def accept_verbatim_big_indent + assert_equal " hi\n world\n\n", @to.end_accepting + end + + def list_nested + expected = <<-EXPECTED +* l1 + * l1.1 +* l2 + EXPECTED + + assert_equal expected, @to.end_accepting + end + + def list_verbatim + expected = <<-EXPECTED # HACK overblown +* list stuff + + * list + with + + second + + 1. indented + 2. numbered + + third + + * second + + EXPECTED + + assert_equal expected, @to.end_accepting + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_markup_to_html.rb b/jni/ruby/test/rdoc/test_rdoc_markup_to_html.rb new file mode 100644 index 0000000..1e4b84f --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_markup_to_html.rb @@ -0,0 +1,663 @@ +require 'rdoc/test_case' + +class TestRDocMarkupToHtml < RDoc::Markup::FormatterTestCase + + add_visitor_tests + + def setup + super + + @to = RDoc::Markup::ToHtml.new @options + end + + def accept_blank_line + assert_empty @to.res.join + end + + def accept_block_quote + assert_equal "\n<blockquote>\n<p>quote</p>\n</blockquote>\n", @to.res.join + end + + def accept_document + assert_equal "\n<p>hello</p>\n", @to.res.join + end + + def accept_heading + links = '<span><a href="#label-Hello">¶</a> ' + + '<a href="#top">↑</a></span>' + expected = "\n<h5 id=\"label-Hello\">Hello#{links}</h5>\n" + + assert_equal expected, @to.res.join + end + + def accept_heading_1 + links = '<span><a href="#label-Hello">¶</a> ' + + '<a href="#top">↑</a></span>' + + assert_equal "\n<h1 id=\"label-Hello\">Hello#{links}</h1>\n", @to.res.join + end + + def accept_heading_2 + links = '<span><a href="#label-Hello">¶</a> ' + + '<a href="#top">↑</a></span>' + + assert_equal "\n<h2 id=\"label-Hello\">Hello#{links}</h2>\n", @to.res.join + end + + def accept_heading_3 + links = '<span><a href="#label-Hello">¶</a> ' + + '<a href="#top">↑</a></span>' + + assert_equal "\n<h3 id=\"label-Hello\">Hello#{links}</h3>\n", @to.res.join + end + + def accept_heading_4 + links = '<span><a href="#label-Hello">¶</a> ' + + '<a href="#top">↑</a></span>' + + assert_equal "\n<h4 id=\"label-Hello\">Hello#{links}</h4>\n", @to.res.join + end + + def accept_heading_b + links = '<span><a href="#label-Hello">¶</a> ' + + '<a href="#top">↑</a></span>' + inner = "<strong>Hello</strong>" + + assert_equal "\n<h1 id=\"label-Hello\">#{inner}#{links}</h1>\n", + @to.res.join + end + + def accept_heading_suppressed_crossref + links = '<span><a href="#label-Hello">¶</a> ' + + '<a href="#top">↑</a></span>' + + assert_equal "\n<h1 id=\"label-Hello\">Hello#{links}</h1>\n", @to.res.join + end + + def accept_list_end_bullet + assert_equal [], @to.list + assert_equal [], @to.in_list_entry + + assert_equal "<ul></ul>\n", @to.res.join + end + + def accept_list_end_label + assert_equal [], @to.list + assert_equal [], @to.in_list_entry + + assert_equal "<dl class=\"rdoc-list label-list\"></dl>\n", @to.res.join + end + + def accept_list_end_lalpha + assert_equal [], @to.list + assert_equal [], @to.in_list_entry + + assert_equal "<ol style=\"list-style-type: lower-alpha\"></ol>\n", @to.res.join + end + + def accept_list_end_number + assert_equal [], @to.list + assert_equal [], @to.in_list_entry + + assert_equal "<ol></ol>\n", @to.res.join + end + + def accept_list_end_note + assert_equal [], @to.list + assert_equal [], @to.in_list_entry + + assert_equal "<dl class=\"rdoc-list note-list\"></dl>\n", @to.res.join + end + + def accept_list_end_ualpha + assert_equal [], @to.list + assert_equal [], @to.in_list_entry + + assert_equal "<ol style=\"list-style-type: upper-alpha\"></ol>\n", @to.res.join + end + + def accept_list_item_end_bullet + assert_equal %w[</li>], @to.in_list_entry + end + + def accept_list_item_end_label + assert_equal %w[</dd>], @to.in_list_entry + end + + def accept_list_item_end_lalpha + assert_equal %w[</li>], @to.in_list_entry + end + + def accept_list_item_end_note + assert_equal %w[</dd>], @to.in_list_entry + end + + def accept_list_item_end_number + assert_equal %w[</li>], @to.in_list_entry + end + + def accept_list_item_end_ualpha + assert_equal %w[</li>], @to.in_list_entry + end + + def accept_list_item_start_bullet + assert_equal "<ul><li>", @to.res.join + end + + def accept_list_item_start_label + assert_equal "<dl class=\"rdoc-list label-list\"><dt>cat\n<dd>", @to.res.join + end + + def accept_list_item_start_lalpha + assert_equal "<ol style=\"list-style-type: lower-alpha\"><li>", @to.res.join + end + + def accept_list_item_start_note + assert_equal "<dl class=\"rdoc-list note-list\"><dt>cat\n<dd>", + @to.res.join + end + + def accept_list_item_start_note_2 + expected = <<-EXPECTED +<dl class="rdoc-list note-list"><dt><code>teletype</code> +<dd> +<p>teletype description</p> +</dd></dl> + EXPECTED + + assert_equal expected, @to.res.join + end + + def accept_list_item_start_note_multi_description + expected = <<-EXPECTED +<dl class="rdoc-list note-list"><dt>label +<dd> +<p>description one</p> +</dd><dd> +<p>description two</p> +</dd></dl> + EXPECTED + + assert_equal expected, @to.res.join + end + + def accept_list_item_start_note_multi_label + expected = <<-EXPECTED +<dl class="rdoc-list note-list"><dt>one +<dt>two +<dd> +<p>two headers</p> +</dd></dl> + EXPECTED + + assert_equal expected, @to.res.join + end + + def accept_list_item_start_number + assert_equal "<ol><li>", @to.res.join + end + + def accept_list_item_start_ualpha + assert_equal "<ol style=\"list-style-type: upper-alpha\"><li>", @to.res.join + end + + def accept_list_start_bullet + assert_equal [:BULLET], @to.list + assert_equal [false], @to.in_list_entry + + assert_equal "<ul>", @to.res.join + end + + def accept_list_start_label + assert_equal [:LABEL], @to.list + assert_equal [false], @to.in_list_entry + + assert_equal '<dl class="rdoc-list label-list">', @to.res.join + end + + def accept_list_start_lalpha + assert_equal [:LALPHA], @to.list + assert_equal [false], @to.in_list_entry + + assert_equal "<ol style=\"list-style-type: lower-alpha\">", @to.res.join + end + + def accept_list_start_note + assert_equal [:NOTE], @to.list + assert_equal [false], @to.in_list_entry + + assert_equal "<dl class=\"rdoc-list note-list\">", @to.res.join + end + + def accept_list_start_number + assert_equal [:NUMBER], @to.list + assert_equal [false], @to.in_list_entry + + assert_equal "<ol>", @to.res.join + end + + def accept_list_start_ualpha + assert_equal [:UALPHA], @to.list + assert_equal [false], @to.in_list_entry + + assert_equal "<ol style=\"list-style-type: upper-alpha\">", @to.res.join + end + + def accept_paragraph + assert_equal "\n<p>hi</p>\n", @to.res.join + end + + def accept_paragraph_b + assert_equal "\n<p>reg <strong>bold words</strong> reg</p>\n", @to.res.join + end + + def accept_paragraph_br + assert_equal "\n<p>one<br>two</p>\n", @to.res.join + end + + def accept_paragraph_break + assert_equal "\n<p>hello<br> world</p>\n", @to.res.join + end + + def accept_paragraph_i + assert_equal "\n<p>reg <em>italic words</em> reg</p>\n", @to.res.join + end + + def accept_paragraph_plus + assert_equal "\n<p>reg <code>teletype</code> reg</p>\n", @to.res.join + end + + def accept_paragraph_star + assert_equal "\n<p>reg <strong>bold</strong> reg</p>\n", @to.res.join + end + + def accept_paragraph_underscore + assert_equal "\n<p>reg <em>italic</em> reg</p>\n", @to.res.join + end + + def accept_raw + raw = <<-RAW.rstrip +<table> +<tr><th>Name<th>Count +<tr><td>a<td>1 +<tr><td>b<td>2 +</table> + RAW + + assert_equal raw, @to.res.join + end + + def accept_rule + assert_equal "<hr>\n", @to.res.join + end + + def accept_verbatim + assert_equal "\n<pre class=\"ruby\"><span class=\"ruby-identifier\">hi</span>\n <span class=\"ruby-identifier\">world</span>\n</pre>\n", @to.res.join + end + + def end_accepting + assert_equal 'hi', @to.end_accepting + end + + def start_accepting + assert_equal [], @to.res + assert_equal [], @to.in_list_entry + assert_equal [], @to.list + end + + def list_nested + expected = <<-EXPECTED +<ul><li> +<p>l1</p> +<ul><li> +<p>l1.1</p> +</li></ul> +</li><li> +<p>l2</p> +</li></ul> + EXPECTED + + assert_equal expected, @to.res.join + end + + def list_verbatim + expected = <<-EXPECTED +<ul><li> +<p>list stuff</p> + +<pre>* list + with + + second + + 1. indented + 2. numbered + + third + +* second</pre> +</li></ul> + EXPECTED + + assert_equal expected, @to.end_accepting + end + + def test_accept_heading_7 + @to.start_accepting + + @to.accept_heading @RM::Heading.new(7, 'Hello') + + links = '<span><a href="#label-Hello">¶</a> ' + + '<a href="#top">↑</a></span>' + + assert_equal "\n<h6 id=\"label-Hello\">Hello#{links}</h6>\n", @to.res.join + end + + def test_accept_heading_aref_class + @to.code_object = RDoc::NormalClass.new 'Foo' + @to.start_accepting + + @to.accept_heading head(1, 'Hello') + + links = '<span><a href="#class-Foo-label-Hello">¶</a> ' + + '<a href="#top">↑</a></span>' + + assert_equal "\n<h1 id=\"class-Foo-label-Hello\">Hello#{links}</h1>\n", + @to.res.join + end + + def test_accept_heading_aref_method + @to.code_object = RDoc::AnyMethod.new nil, 'foo' + @to.start_accepting + + @to.accept_heading @RM::Heading.new(1, 'Hello') + + links = '<span><a href="#method-i-foo-label-Hello">¶</a> ' + + '<a href="#top">↑</a></span>' + + assert_equal "\n<h1 id=\"method-i-foo-label-Hello\">Hello#{links}</h1>\n", + @to.res.join + end + + def test_accept_heading_pipe + @options.pipe = true + + @to.start_accepting + + @to.accept_heading @RM::Heading.new(1, 'Hello') + + assert_equal "\n<h1 id=\"label-Hello\">Hello</h1>\n", @to.res.join + end + + def test_accept_paragraph_newline + @to.start_accepting + + @to.accept_paragraph para("hello\n", "world\n") + + assert_equal "\n<p>hello world</p>\n", @to.res.join + end + + def test_accept_heading_output_decoration + @options.output_decoration = false + + @to.start_accepting + + @to.accept_heading @RM::Heading.new(1, 'Hello') + + assert_equal "\n<h1>Hello<span><a href=\"#label-Hello\">¶</a> <a href=\"#top\">↑</a></span></h1>\n", @to.res.join + end + + def test_accept_heading_output_decoration_with_pipe + @options.pipe = true + @options.output_decoration = false + + @to.start_accepting + + @to.accept_heading @RM::Heading.new(1, 'Hello') + + assert_equal "\n<h1>Hello</h1>\n", @to.res.join + end + + def test_accept_verbatim_parseable + verb = @RM::Verbatim.new("class C\n", "end\n") + + @to.start_accepting + @to.accept_verbatim verb + + expected = <<-EXPECTED + +<pre class="ruby"><span class="ruby-keyword">class</span> <span class="ruby-constant">C</span> +<span class="ruby-keyword">end</span> +</pre> + EXPECTED + + assert_equal expected, @to.res.join + end + + def test_accept_verbatim_parseable_error + verb = @RM::Verbatim.new("a % 09 # => blah\n") + + @to.start_accepting + @to.accept_verbatim verb + + inner = CGI.escapeHTML "a % 09 # => blah" + + expected = <<-EXPECTED + +<pre>#{inner}</pre> + EXPECTED + + assert_equal expected, @to.res.join + end + + def test_accept_verbatim_pipe + @options.pipe = true + + verb = @RM::Verbatim.new("1 + 1\n") + verb.format = :ruby + + @to.start_accepting + @to.accept_verbatim verb + + expected = <<-EXPECTED + +<pre><code>1 + 1 +</code></pre> + EXPECTED + + assert_equal expected, @to.res.join + end + + def test_accept_verbatim_ruby + verb = @RM::Verbatim.new("1 + 1\n") + verb.format = :ruby + + @to.start_accepting + @to.accept_verbatim verb + + expected = <<-EXPECTED + +<pre class="ruby"><span class="ruby-value">1</span> <span class="ruby-operator">+</span> <span class="ruby-value">1</span> +</pre> + EXPECTED + + assert_equal expected, @to.res.join + end + + def test_convert_string + assert_equal '<>', @to.convert_string('<>') + end + + def test_convert_HYPERLINK_irc + result = @to.convert 'irc://irc.freenode.net/#ruby-lang' + + assert_equal "\n<p><a href=\"irc://irc.freenode.net/#ruby-lang\">irc.freenode.net/#ruby-lang</a></p>\n", result + end + + def test_convert_RDOCLINK_label_label + result = @to.convert 'rdoc-label:label-One' + + assert_equal "\n<p><a href=\"#label-One\">One</a></p>\n", result + end + + def test_convert_RDOCLINK_label_foottext + result = @to.convert 'rdoc-label:foottext-1' + + assert_equal "\n<p><a href=\"#foottext-1\">1</a></p>\n", result + end + + def test_convert_RDOCLINK_label_footmark + result = @to.convert 'rdoc-label:footmark-1' + + assert_equal "\n<p><a href=\"#footmark-1\">1</a></p>\n", result + end + + def test_convert_RDOCLINK_ref + result = @to.convert 'rdoc-ref:C' + + assert_equal "\n<p>C</p>\n", result + end + + def test_convert_TIDYLINK_footnote + result = @to.convert 'text{*1}[rdoc-label:foottext-1:footmark-1]' + + assert_equal "\n<p>text<sup><a id=\"footmark-1\" href=\"#foottext-1\">1</a></sup></p>\n", result + end + + def test_convert_TIDYLINK_multiple + result = @to.convert '{a}[http://example] {b}[http://example]' + + expected = <<-EXPECTED + +<p><a href=\"http://example\">a</a> <a href=\"http://example\">b</a></p> + EXPECTED + + assert_equal expected, result + end + + def test_convert_TIDYLINK_image + result = + @to.convert '{rdoc-image:path/to/image.jpg}[http://example.com]' + + expected = + "\n<p><a href=\"http://example.com\"><img src=\"path/to/image.jpg\"></a></p>\n" + + assert_equal expected, result + end + + def test_convert_TIDYLINK_rdoc_label + result = @to.convert '{foo}[rdoc-label:foottext-1]' + + assert_equal "\n<p><a href=\"#foottext-1\">foo</a></p>\n", result + end + + def test_convert_TIDYLINK_irc + result = @to.convert '{ruby-lang}[irc://irc.freenode.net/#ruby-lang]' + + assert_equal "\n<p><a href=\"irc://irc.freenode.net/#ruby-lang\">ruby-lang</a></p>\n", result + end + + def test_gen_url + assert_equal '<a href="example">example</a>', + @to.gen_url('link:example', 'example') + end + + def test_gen_url_rdoc_label + assert_equal '<a href="#foottext-1">example</a>', + @to.gen_url('rdoc-label:foottext-1', 'example') + end + + def test_gen_url_rdoc_label_id + assert_equal '<sup><a id="footmark-1" href="#foottext-1">example</a></sup>', + @to.gen_url('rdoc-label:foottext-1:footmark-1', 'example') + end + + def test_gen_url_image_url + assert_equal '<img src="http://example.com/image.png" />', @to.gen_url('http://example.com/image.png', 'ignored') + end + + def test_gen_url_ssl_image_url + assert_equal '<img src="https://example.com/image.png" />', @to.gen_url('https://example.com/image.png', 'ignored') + end + + def test_handle_special_HYPERLINK_link + special = RDoc::Markup::Special.new 0, 'link:README.txt' + + link = @to.handle_special_HYPERLINK special + + assert_equal '<a href="README.txt">README.txt</a>', link + end + + def test_handle_special_HYPERLINK_irc + special = RDoc::Markup::Special.new 0, 'irc://irc.freenode.net/#ruby-lang' + + link = @to.handle_special_HYPERLINK special + + assert_equal '<a href="irc://irc.freenode.net/#ruby-lang">irc.freenode.net/#ruby-lang</a>', link + end + + def test_list_verbatim_2 + str = "* one\n verb1\n verb2\n* two\n" + + expected = <<-EXPECTED +<ul><li> +<p>one</p> + +<pre class=\"ruby\"><span class=\"ruby-identifier\">verb1</span> +<span class=\"ruby-identifier\">verb2</span> +</pre> +</li><li> +<p>two</p> +</li></ul> + EXPECTED + + assert_equal expected, @m.convert(str, @to) + end + + def test_parseable_eh + valid_syntax = [ + 'def x() end', + 'def x; end', + 'class C; end', + "module M end", + 'a # => blah', + 'x { |y| nil }', + 'x do |y| nil end', + '# only a comment', + 'require "foo"', + 'cls="foo"' + ] + invalid_syntax = [ + 'def x end', + 'class C end', + 'class C < end', + 'module M < C end', + 'a=># blah', + 'x { |y| ... }', + 'x do |y| ... end', + '// only a comment', + '<% require "foo" %>', + 'class="foo"' + ] + valid_syntax.each do |t| + assert @to.parseable?(t), "valid syntax considered invalid: #{t}" + end + invalid_syntax.each do |t| + refute @to.parseable?(t), "invalid syntax considered valid: #{t}" + end + end + + def test_to_html + assert_equal "\n<p><code>--</code></p>\n", util_format("<tt>--</tt>") + end + + def util_format text + paragraph = RDoc::Markup::Paragraph.new text + + @to.start_accepting + @to.accept_paragraph paragraph + @to.end_accepting + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_markup_to_html_crossref.rb b/jni/ruby/test/rdoc/test_rdoc_markup_to_html_crossref.rb new file mode 100644 index 0000000..872daea --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_markup_to_html_crossref.rb @@ -0,0 +1,225 @@ +require File.expand_path '../xref_test_case', __FILE__ + +class TestRDocMarkupToHtmlCrossref < XrefTestCase + + def setup + super + + @options.hyperlink_all = true + + @to = RDoc::Markup::ToHtmlCrossref.new @options, 'index.html', @c1 + end + + def test_convert_CROSSREF + result = @to.convert 'C1' + + assert_equal para("<a href=\"C1.html\">C1</a>"), result + end + + def test_convert_CROSSREF_label + result = @to.convert 'C1@foo' + assert_equal para("<a href=\"C1.html#label-foo\">foo at C1</a>"), result + + result = @to.convert 'C1#m@foo' + assert_equal para("<a href=\"C1.html#method-i-m-label-foo\">foo at C1#m</a>"), + result + end + + def test_convert_CROSSREF_label_period + result = @to.convert 'C1@foo.' + assert_equal para("<a href=\"C1.html#label-foo\">foo at C1</a>."), result + end + + def test_convert_CROSSREF_label_space + result = @to.convert 'C1@foo+bar' + assert_equal para("<a href=\"C1.html#label-foo+bar\">foo bar at C1</a>"), + result + end + + def test_convert_CROSSREF_section + @c1.add_section 'Section' + + result = @to.convert 'C1@Section' + assert_equal para("<a href=\"C1.html#Section\">Section at C1</a>"), result + end + + def test_convert_RDOCLINK_rdoc_ref + result = @to.convert 'rdoc-ref:C1' + + assert_equal para("<a href=\"C1.html\">C1</a>"), result + end + + def test_convert_RDOCLINK_rdoc_ref_method + result = @to.convert 'rdoc-ref:C1#m' + + assert_equal para("<a href=\"C1.html#method-i-m\">#m</a>"), result + end + + def test_convert_RDOCLINK_rdoc_ref_method_label + result = @to.convert 'rdoc-ref:C1#m@foo' + + assert_equal para("<a href=\"C1.html#method-i-m-label-foo\">foo at C1#m</a>"), + result, 'rdoc-ref:C1#m@foo' + end + + def test_convert_RDOCLINK_rdoc_ref_method_percent + m = @c1.add_method RDoc::AnyMethod.new nil, '%' + m.singleton = false + + result = @to.convert 'rdoc-ref:C1#%' + + assert_equal para("<a href=\"C1.html#method-i-25\">#%</a>"), result + + m.singleton = true + + result = @to.convert 'rdoc-ref:C1::%' + + assert_equal para("<a href=\"C1.html#method-c-25\">::%</a>"), result + end + + def test_convert_RDOCLINK_rdoc_ref_method_percent_label + m = @c1.add_method RDoc::AnyMethod.new nil, '%' + m.singleton = false + + result = @to.convert 'rdoc-ref:C1#%@f' + + assert_equal para("<a href=\"C1.html#method-i-25-label-f\">f at C1#%</a>"), + result + + m.singleton = true + + result = @to.convert 'rdoc-ref:C1::%@f' + + assert_equal para("<a href=\"C1.html#method-c-25-label-f\">f at C1::%</a>"), + result + end + + def test_convert_RDOCLINK_rdoc_ref_label + result = @to.convert 'rdoc-ref:C1@foo' + + assert_equal para("<a href=\"C1.html#label-foo\">foo at C1</a>"), result, + 'rdoc-ref:C1@foo' + end + + def test_gen_url + assert_equal '<a href="C1.html">Some class</a>', + @to.gen_url('rdoc-ref:C1', 'Some class') + + assert_equal '<a href="http://example">HTTP example</a>', + @to.gen_url('http://example', 'HTTP example') + end + + def test_handle_special_CROSSREF + assert_equal "<a href=\"C2/C3.html\">C2::C3</a>", SPECIAL('C2::C3') + end + + def test_handle_special_CROSSREF_label + assert_equal "<a href=\"C1.html#method-i-m-label-foo\">foo at C1#m</a>", + SPECIAL('C1#m@foo') + end + + def test_handle_special_CROSSREF_show_hash_false + @to.show_hash = false + + assert_equal "<a href=\"C1.html#method-i-m\">m</a>", + SPECIAL('#m') + end + + def test_handle_special_HYPERLINK_rdoc + readme = @store.add_file 'README.txt' + readme.parser = RDoc::Parser::Simple + + @to = RDoc::Markup::ToHtmlCrossref.new @options, 'C2.html', @c2 + + link = @to.handle_special_HYPERLINK hyper 'C2::C3' + + assert_equal '<a href="C2/C3.html">C2::C3</a>', link + + link = @to.handle_special_HYPERLINK hyper 'C4' + + assert_equal '<a href="C4.html">C4</a>', link + + link = @to.handle_special_HYPERLINK hyper 'README.txt' + + assert_equal '<a href="README_txt.html">README.txt</a>', link + end + + def test_handle_special_TIDYLINK_rdoc + readme = @store.add_file 'README.txt' + readme.parser = RDoc::Parser::Simple + + @to = RDoc::Markup::ToHtmlCrossref.new @options, 'C2.html', @c2 + + link = @to.handle_special_TIDYLINK tidy 'C2::C3' + + assert_equal '<a href="C2/C3.html">tidy</a>', link + + link = @to.handle_special_TIDYLINK tidy 'C4' + + assert_equal '<a href="C4.html">tidy</a>', link + + link = @to.handle_special_TIDYLINK tidy 'C1#m' + + assert_equal '<a href="C1.html#method-i-m">tidy</a>', link + + link = @to.handle_special_TIDYLINK tidy 'README.txt' + + assert_equal '<a href="README_txt.html">tidy</a>', link + end + + def test_handle_special_TIDYLINK_label + link = @to.handle_special_TIDYLINK tidy 'C1#m@foo' + + assert_equal "<a href=\"C1.html#method-i-m-label-foo\">tidy</a>", + link, 'C1#m@foo' + end + + def test_to_html_CROSSREF_email + @options.hyperlink_all = false + + @to = RDoc::Markup::ToHtmlCrossref.new @options, 'index.html', @c1 + + result = @to.to_html 'first.last@example.com' + + assert_equal 'first.last@example.com', result + end + + def test_to_html_CROSSREF_email_hyperlink_all + result = @to.to_html 'first.last@example.com' + + assert_equal 'first.last@example.com', result + end + + def test_link + assert_equal 'n', @to.link('n', 'n') + + assert_equal '<a href="C1.html#method-c-m">::m</a>', @to.link('m', 'm') + end + + def test_link_class_method_full + assert_equal '<a href="Parent.html#method-c-m">Parent.m</a>', + @to.link('Parent::m', 'Parent::m') + end + + def para text + "\n<p>#{text}</p>\n" + end + + def SPECIAL text + @to.handle_special_CROSSREF special text + end + + def hyper reference + RDoc::Markup::Special.new 0, "rdoc-ref:#{reference}" + end + + def special text + RDoc::Markup::Special.new 0, text + end + + def tidy reference + RDoc::Markup::Special.new 0, "{tidy}[rdoc-ref:#{reference}]" + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_markup_to_html_snippet.rb b/jni/ruby/test/rdoc/test_rdoc_markup_to_html_snippet.rb new file mode 100644 index 0000000..f861db1 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_markup_to_html_snippet.rb @@ -0,0 +1,711 @@ +require 'rdoc/test_case' + +class TestRDocMarkupToHtmlSnippet < RDoc::Markup::FormatterTestCase + + add_visitor_tests + + def setup + super + + @to = RDoc::Markup::ToHtmlSnippet.new @options, 100, 100 + @ellipsis = @to.to_html '...' + end + + def accept_blank_line + assert_empty @to.res.join + end + + def accept_block_quote + assert_equal "\n<blockquote><p>quote\n</blockquote>\n", @to.res.join + + assert_equal 5, @to.characters + end + + def accept_document + assert_equal "<p>hello\n", @to.res.join + assert_equal 5, @to.characters + end + + def accept_heading + assert_equal "<p>Hello\n", @to.res.join + assert_equal 5, @to.characters + end + + def accept_heading_1 + assert_equal "<p>Hello\n", @to.res.join + assert_equal 5, @to.characters + end + + def accept_heading_2 + assert_equal "<p>Hello\n", @to.res.join + assert_equal 5, @to.characters + end + + def accept_heading_3 + assert_equal "<p>Hello\n", @to.res.join + assert_equal 5, @to.characters + end + + def accept_heading_4 + assert_equal "<p>Hello\n", @to.res.join + assert_equal 5, @to.characters + end + + def accept_heading_b + assert_equal "<p><strong>Hello</strong>\n", + @to.res.join + assert_equal 5, @to.characters + end + + def accept_heading_suppressed_crossref + assert_equal "<p>Hello\n", @to.res.join + assert_equal 5, @to.characters + end + + def accept_list_end_bullet + assert_equal [], @to.list + assert_equal [], @to.in_list_entry + + assert_equal "\n", @to.res.join + assert_equal 0, @to.characters + end + + def accept_list_end_label + assert_equal [], @to.list + assert_equal [], @to.in_list_entry + + assert_equal "\n", @to.res.join + assert_equal 0, @to.characters + end + + def accept_list_end_lalpha + assert_equal [], @to.list + assert_equal [], @to.in_list_entry + + assert_equal "\n", @to.res.join + assert_equal 0, @to.characters + end + + def accept_list_end_number + assert_equal [], @to.list + assert_equal [], @to.in_list_entry + + assert_equal "\n", @to.res.join + assert_equal 0, @to.characters + end + + def accept_list_end_note + assert_equal [], @to.list + assert_equal [], @to.in_list_entry + + assert_equal "\n", @to.res.join + assert_equal 0, @to.characters + end + + def accept_list_end_ualpha + assert_equal [], @to.list + assert_equal [], @to.in_list_entry + + assert_equal "\n", @to.res.join + assert_equal 0, @to.characters + end + + def accept_list_item_end_bullet + assert_equal [''], @to.in_list_entry + assert_equal 0, @to.characters + end + + def accept_list_item_end_label + assert_equal [''], @to.in_list_entry + assert_equal 4, @to.characters + end + + def accept_list_item_end_lalpha + assert_equal [''], @to.in_list_entry + assert_equal 0, @to.characters + end + + def accept_list_item_end_note + assert_equal [''], @to.in_list_entry + assert_equal 4, @to.characters + end + + def accept_list_item_end_number + assert_equal [''], @to.in_list_entry + assert_equal 0, @to.characters + end + + def accept_list_item_end_ualpha + assert_equal [''], @to.in_list_entry + assert_equal 0, @to.characters + end + + def accept_list_item_start_bullet + assert_equal "<p>", @to.res.join + assert_equal 0, @to.characters + end + + def accept_list_item_start_label + assert_equal "<p>cat — ", @to.res.join + assert_equal 4, @to.characters + end + + def accept_list_item_start_lalpha + assert_equal "<p>", @to.res.join + assert_equal 0, @to.characters + end + + def accept_list_item_start_note + assert_equal "<p>cat — ", + @to.res.join + assert_equal 4, @to.characters + end + + def accept_list_item_start_note_2 + expected = <<-EXPECTED +<p><code>teletype</code> — teletype description + + EXPECTED + + assert_equal expected, @to.res.join + assert_equal 29, @to.characters + end + + def accept_list_item_start_note_multi_description + expected = <<-EXPECTED +<p>label — description one +<p>description two + + EXPECTED + + assert_equal expected, @to.res.join + assert_equal 37, @to.characters + end + + def accept_list_item_start_note_multi_label + expected = <<-EXPECTED +<p>one, two — two headers + + EXPECTED + + assert_equal expected, @to.res.join + assert_equal 18, @to.characters + end + + def accept_list_item_start_number + assert_equal "<p>", @to.res.join + assert_equal 0, @to.characters + end + + def accept_list_item_start_ualpha + assert_equal "<p>", @to.res.join + assert_equal 0, @to.characters + end + + def accept_list_start_bullet + assert_equal [:BULLET], @to.list + assert_equal [''], @to.in_list_entry + + assert_equal '', @to.res.join + assert_equal 0, @to.characters + end + + def accept_list_start_label + assert_equal [:LABEL], @to.list + assert_equal [''], @to.in_list_entry + + assert_equal '', @to.res.join + assert_equal 0, @to.characters + end + + def accept_list_start_lalpha + assert_equal [:LALPHA], @to.list + assert_equal [''], @to.in_list_entry + + assert_equal '', @to.res.join + assert_equal 0, @to.characters + end + + def accept_list_start_note + assert_equal [:NOTE], @to.list + assert_equal [''], @to.in_list_entry + + assert_equal '', @to.res.join + assert_equal 0, @to.characters + end + + def accept_list_start_number + assert_equal [:NUMBER], @to.list + assert_equal [''], @to.in_list_entry + + assert_equal '', @to.res.join + assert_equal 0, @to.characters + end + + def accept_list_start_ualpha + assert_equal [:UALPHA], @to.list + assert_equal [''], @to.in_list_entry + + assert_equal '', @to.res.join + assert_equal 0, @to.characters + end + + def accept_paragraph + assert_equal "<p>hi\n", @to.res.join + + assert_equal 2, @to.characters + end + + def accept_paragraph_b + assert_equal "<p>reg <strong>bold words</strong> reg\n", @to.res.join + + assert_equal 18, @to.characters + end + + def accept_paragraph_br + assert_equal "<p>one<br>two\n", @to.res.join + + assert_equal 6, @to.characters + end + + def accept_paragraph_break + assert_equal "<p>hello<br>\nworld\n", @to.res.join + + assert_equal 11, @to.characters + end + + def accept_paragraph_i + assert_equal "<p>reg <em>italic words</em> reg\n", @to.res.join + + assert_equal 20, @to.characters + end + + def accept_paragraph_plus + assert_equal "<p>reg <code>teletype</code> reg\n", @to.res.join + + assert_equal 16, @to.characters + end + + def accept_paragraph_star + assert_equal "<p>reg <strong>bold</strong> reg\n", @to.res.join + + assert_equal 12, @to.characters + end + + def accept_paragraph_underscore + assert_equal "<p>reg <em>italic</em> reg\n", @to.res.join + + assert_equal 14, @to.characters + end + + def accept_raw + assert_equal '', @to.res.join + assert_equal 0, @to.characters + end + + def accept_rule + assert_empty @to.res + assert_equal 0, @to.characters + end + + def accept_verbatim + assert_equal "\n<pre class=\"ruby\"><span class=\"ruby-identifier\">hi</span>\n <span class=\"ruby-identifier\">world</span>\n</pre>\n", @to.res.join + assert_equal 10, @to.characters + end + + def end_accepting + assert_equal 'hi', @to.res.join + end + + def start_accepting + assert_equal [], @to.res + assert_equal [], @to.in_list_entry + assert_equal [], @to.list + assert_equal 0, @to.characters + end + + def list_nested + expected = <<-EXPECTED +<p>l1 +<p>l1.1 + +<p>l2 + + EXPECTED + + assert_equal expected, @to.res.join + assert_equal 8, @to.characters + end + + def list_verbatim + expected = <<-EXPECTED +<p>list stuff + +<pre>* list + with + + second + + 1. indented + 2. numbered + + third + +* second</pre> + + EXPECTED + + assert_equal expected, @to.end_accepting + assert_equal 81, @to.characters + end + + def test_accept_heading_7 + @to.start_accepting + + @to.accept_heading @RM::Heading.new(7, 'Hello') + + assert_equal "<p>Hello\n", @to.res.join + assert_equal 5, @to.characters + end + + def test_accept_heading_aref_class + @to.code_object = RDoc::NormalClass.new 'Foo' + @to.start_accepting + + @to.accept_heading @RM::Heading.new(1, 'Hello') + + assert_equal "<p>Hello\n", + @to.res.join + assert_equal 5, @to.characters + end + + def test_accept_heading_aref_method + @to.code_object = RDoc::AnyMethod.new nil, 'foo' + @to.start_accepting + + @to.accept_heading @RM::Heading.new(1, 'Hello') + + assert_equal "<p>Hello\n", + @to.res.join + assert_equal 5, @to.characters + end + + def test_accept_verbatim_ruby + options = RDoc::Options.new + rdoc = RDoc::RDoc.new + rdoc.options = options + RDoc::RDoc.current = rdoc + + verb = @RM::Verbatim.new("class C\n", "end\n") + + @to.start_accepting + @to.accept_verbatim verb + + expected = <<-EXPECTED + +<pre class="ruby"><span class="ruby-keyword">class</span> <span class="ruby-constant">C</span> +<span class="ruby-keyword">end</span> +</pre> + EXPECTED + + assert_equal expected, @to.res.join + assert_equal 11, @to.characters + end + + def test_accept_verbatim_ruby_error + options = RDoc::Options.new + rdoc = RDoc::RDoc.new + rdoc.options = options + RDoc::RDoc.current = rdoc + + verb = @RM::Verbatim.new("a % 09 # => blah\n") + + @to.start_accepting + @to.accept_verbatim verb + + inner = CGI.escapeHTML "a % 09 # => blah" + + expected = <<-EXPECTED + +<pre>#{inner}</pre> + EXPECTED + + assert_equal expected, @to.res.join + assert_equal 16, @to.characters + end + + def test_add_paragraph + @to = RDoc::Markup::ToHtmlSnippet.new @options, 0, 3 + assert_throws :done do + @to.add_paragraph + @to.add_paragraph + @to.add_paragraph + end + + assert_equal 3, @to.paragraphs + end + + def test_convert_limit + rdoc = <<-RDOC += Hello + +This is some text, it *will* be cut off after 100 characters and an ellipsis +must follow + +So there you have it + RDOC + + expected = <<-EXPECTED +<p>Hello +<p>This is some text, it <strong>will</strong> be cut off after 100 characters +and an ellipsis must follow +<p>So there you #{@ellipsis} + EXPECTED + + actual = @to.convert rdoc + + assert_equal expected, actual + assert_equal 111, @to.characters, 'snippet character length' + end + + def test_convert_limit_2 + rdoc = <<-RDOC +Outputs formatted RI data for the class or method +name+. + +Returns true if +name+ was found, false if it was not an alternative could +be guessed, raises an error if +name+ couldn't be guessed. + RDOC + + expected = <<-EXPECTED +<p>Outputs formatted RI data for the class or method <code>name</code>. +<p>Returns true if <code>name</code> was found, false if it was #{@ellipsis} + EXPECTED + + actual = @to.convert rdoc + + assert_equal expected, actual + assert_equal 159, @to.characters, 'snippet character length' + end + + def test_convert_limit_paragraphs + @to = RDoc::Markup::ToHtmlSnippet.new @options, 100, 3 + + rdoc = <<-RDOC += \RDoc - Ruby Documentation System + +* {RDoc Project Page}[https://github.com/rdoc/rdoc/] +* {RDoc Documentation}[http://docs.seattlerb.org/rdoc] +* {RDoc Bug Tracker}[https://github.com/rdoc/rdoc/issues] + +== DESCRIPTION: + +RDoc produces HTML and command-line documentation for Ruby projects. RDoc +includes the +rdoc+ and +ri+ tools for generating and displaying online +documentation. + +See RDoc for a description of RDoc's markup and basic use. + RDOC + + expected = <<-EXPECTED +<p>RDoc - Ruby Documentation System +<p>RDoc Project Page +<p>RDoc Documentation + EXPECTED + + actual = @to.convert rdoc + + assert_equal expected, actual + assert_equal 67, @to.characters + end + + def test_convert_limit_in_tag + @to = RDoc::Markup::ToHtmlSnippet.new @options, 4 + rdoc = "* ab *c* d\n" + + expected = "<p>ab <strong>c</strong> #{@ellipsis}\n\n" + + actual = @to.convert rdoc + + assert_equal 4, @to.characters + assert_equal expected, actual + end + + def test_convert_limit_verbatim + rdoc = <<-RDOC += Hello There + +This is some text, it *will* be cut off after 100 characters + + This one is cut off in this verbatim section + RDOC + + expected = <<-EXPECTED +<p>Hello There +<p>This is some text, it <strong>will</strong> be cut off after 100 characters + +<pre>This one is cut off in this verbatim ...</pre> + EXPECTED + + actual = @to.convert rdoc + + assert_equal expected, actual + assert_equal 113, @to.characters + end + + def test_convert_limit_verbatim_2 + rdoc = <<-RDOC +Extracts the class, selector and method name parts from +name+ like +Foo::Bar#baz. + +NOTE: Given Foo::Bar, Bar is considered a class even though it may be a + method + RDOC + + expected = <<-EXPECTED +<p>Extracts the class, selector and method name parts from <code>name</code> +like Foo::Bar#baz. +<p>NOTE: Given Foo::Bar, #{@ellipsis} + EXPECTED + + actual = @to.convert rdoc + + assert_equal expected, actual + assert_equal 101, @to.characters + end + + def test_convert_limit_verbatim_multiline + rdoc = <<-RDOC +Look for directives in a normal comment block: + + # :stopdoc: + # Don't display comment from this point forward + +This routine modifies its +comment+ parameter. + RDOC + + inner = CGI.escapeHTML "# Don't display comment from this point forward" + expected = <<-EXPECTED +<p>Look for directives in a normal comment block: + +<pre class=\"ruby\"><span class=\"ruby-comment\"># :stopdoc:</span> +<span class=\"ruby-comment\">#{inner}</span> +</pre> + EXPECTED + + actual = @to.convert rdoc + + assert_equal expected, actual + assert_equal 105, @to.characters + end + + def test_convert_limit_over + @to = RDoc::Markup::ToHtmlSnippet.new @options, 4 + rdoc = "* text\n" * 2 + + expected = "<p>text\n" + expected.chomp! + expected << " #{@ellipsis}\n" + + actual = @to.convert rdoc + + assert_equal 4, @to.characters + assert_equal expected, actual + end + + def test_convert_string + assert_equal '<>', @to.convert_string('<>') + end + + def test_convert_RDOCLINK_label_label + result = @to.convert 'rdoc-label:label-One' + + assert_equal "<p>One\n", result + assert_equal 3, @to.characters + end + + def test_convert_RDOCLINK_label_foottext + result = @to.convert 'rdoc-label:foottext-1' + + assert_equal "<p>1\n", result + assert_equal 1, @to.characters + end + + def test_convert_RDOCLINK_label_footmark + result = @to.convert 'rdoc-label:footmark-1' + + assert_equal "<p>1\n", result + assert_equal 1, @to.characters + end + + def test_convert_RDOCLINK_ref + result = @to.convert 'rdoc-ref:C' + + assert_equal "<p>C\n", result + assert_equal 1, @to.characters + end + + def test_convert_TIDYLINK_rdoc_label + result = @to.convert '{foo}[rdoc-label:foottext-1]' + + assert_equal "<p>foo\n", result + assert_equal 3, @to.characters + end + + def test_handle_special_HYPERLINK_link + special = RDoc::Markup::Special.new 0, 'link:README.txt' + + link = @to.handle_special_HYPERLINK special + + assert_equal 'README.txt', link + end + + def test_list_verbatim_2 + str = "* one\n verb1\n verb2\n* two\n" + + expected = <<-EXPECTED +<p>one + +<pre class=\"ruby\"><span class=\"ruby-identifier\">verb1</span> +<span class=\"ruby-identifier\">verb2</span> +</pre> +<p>two + + EXPECTED + + assert_equal expected, @m.convert(str, @to) + assert_equal 17, @to.characters + end + + def test_on_tags + on = RDoc::Markup::AttrChanger.new 2, 0 + + @to.on_tags [], on + + assert_equal 2, @to.mask + end + + def test_off_tags + on = RDoc::Markup::AttrChanger.new 2, 0 + off = RDoc::Markup::AttrChanger.new 0, 2 + + @to.on_tags [], on + @to.off_tags [], off + + assert_equal 0, @to.mask + end + + def test_to_html + assert_equal "<p><code>--</code>\n", util_format("<tt>--</tt>") + assert_equal 2, @to.characters + end + + def util_format text + paragraph = RDoc::Markup::Paragraph.new text + + @to.start_accepting + @to.accept_paragraph paragraph + @to.end_accepting + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_markup_to_joined_paragraph.rb b/jni/ruby/test/rdoc/test_rdoc_markup_to_joined_paragraph.rb new file mode 100644 index 0000000..148edb1 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_markup_to_joined_paragraph.rb @@ -0,0 +1,32 @@ +require 'rdoc/test_case' + +class TestRDocMarkupToJoinedParagraph < RDoc::TestCase + + def setup + super + + @to = RDoc::Markup::ToJoinedParagraph.new + end + + def test_accept_paragraph + parsed = para('hello', ' ', 'world') + + @to.accept_paragraph parsed + + expected = para('hello world') + + assert_equal expected, parsed + end + + def test_accept_paragraph_break + parsed = para('hello', ' ', 'world', hard_break, 'everyone') + + @to.accept_paragraph parsed + + expected = para('hello world', hard_break, 'everyone') + + assert_equal expected, parsed + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_markup_to_label.rb b/jni/ruby/test/rdoc/test_rdoc_markup_to_label.rb new file mode 100644 index 0000000..d8cc365 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_markup_to_label.rb @@ -0,0 +1,112 @@ +require 'rdoc/test_case' + +class TestRDocMarkupToLabel < RDoc::Markup::FormatterTestCase + + add_visitor_tests + + def setup + super + + @to = RDoc::Markup::ToLabel.new + end + + def empty + assert_empty @to.res + end + + def end_accepting + assert_equal %w[hi], @to.res + end + + alias accept_blank_line empty + alias accept_block_quote empty + alias accept_document empty + alias accept_heading empty + alias accept_heading_1 empty + alias accept_heading_2 empty + alias accept_heading_3 empty + alias accept_heading_4 empty + alias accept_heading_b empty + alias accept_heading_suppressed_crossref empty + alias accept_list_end_bullet empty + alias accept_list_end_label empty + alias accept_list_end_lalpha empty + alias accept_list_end_note empty + alias accept_list_end_number empty + alias accept_list_end_ualpha empty + alias accept_list_item_end_bullet empty + alias accept_list_item_end_label empty + alias accept_list_item_end_lalpha empty + alias accept_list_item_end_note empty + alias accept_list_item_end_number empty + alias accept_list_item_end_ualpha empty + alias accept_list_item_start_bullet empty + alias accept_list_item_start_label empty + alias accept_list_item_start_lalpha empty + alias accept_list_item_start_note empty + alias accept_list_item_start_note_2 empty + alias accept_list_item_start_note_multi_description empty + alias accept_list_item_start_note_multi_label empty + alias accept_list_item_start_number empty + alias accept_list_item_start_ualpha empty + alias accept_list_start_bullet empty + alias accept_list_start_label empty + alias accept_list_start_lalpha empty + alias accept_list_start_note empty + alias accept_list_start_number empty + alias accept_list_start_ualpha empty + alias accept_paragraph empty + alias accept_paragraph_b empty + alias accept_paragraph_br empty + alias accept_paragraph_break empty + alias accept_paragraph_i empty + alias accept_paragraph_plus empty + alias accept_paragraph_star empty + alias accept_paragraph_underscore empty + alias accept_raw empty + alias accept_rule empty + alias accept_verbatim empty + alias list_nested empty + alias list_verbatim empty + alias start_accepting empty + + def test_convert_bold + assert_equal 'bold', @to.convert('<b>bold</b>') + assert_equal 'bold', @to.convert('*bold*') + end + + def test_convert_crossref + assert_equal 'SomeClass', @to.convert('SomeClass') + assert_equal 'SomeClass', @to.convert('\\SomeClass') + + assert_equal 'some_method', @to.convert('some_method') + assert_equal 'some_method', @to.convert('\\some_method') + + assert_equal '23some_method', @to.convert('#some_method') + assert_equal '23some_method', @to.convert('\\#some_method') + end + + def test_convert_em + assert_equal 'em', @to.convert('<em>em</em>') + assert_equal 'em', @to.convert('*em*') + end + + def test_convert_em_dash # for HTML conversion + assert_equal '-', @to.convert('--') + end + + def test_convert_escape + assert_equal 'a+-3E+b', @to.convert('a > b') + end + + def test_convert_tidylink + assert_equal 'text', @to.convert('{text}[stuff]') + assert_equal 'text', @to.convert('text[stuff]') + end + + def test_convert_tt + assert_equal 'tt', @to.convert('<tt>tt</tt>') + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_markup_to_markdown.rb b/jni/ruby/test/rdoc/test_rdoc_markup_to_markdown.rb new file mode 100644 index 0000000..442bb19 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_markup_to_markdown.rb @@ -0,0 +1,389 @@ +require 'rdoc/test_case' + +class TestRDocMarkupToMarkdown < RDoc::Markup::TextFormatterTestCase + + add_visitor_tests + add_text_tests + + def setup + super + + @to = RDoc::Markup::ToMarkdown.new + end + + def accept_blank_line + assert_equal "\n", @to.res.join + end + + def accept_block_quote + assert_equal "> quote\n", @to.res.join + end + + def accept_document + assert_equal "hello\n", @to.res.join + end + + def accept_heading + assert_equal "##### Hello\n", @to.res.join + end + + def accept_list_end_bullet + assert_empty @to.list_index + assert_empty @to.list_type + assert_empty @to.list_width + end + + def accept_list_end_label + assert_empty @to.list_index + assert_empty @to.list_type + assert_empty @to.list_width + end + + def accept_list_end_lalpha + assert_empty @to.list_index + assert_empty @to.list_type + assert_empty @to.list_width + end + + def accept_list_end_note + assert_empty @to.list_index + assert_empty @to.list_type + assert_empty @to.list_width + end + + def accept_list_end_number + assert_empty @to.list_index + assert_empty @to.list_type + assert_empty @to.list_width + end + + def accept_list_end_ualpha + assert_empty @to.list_index + assert_empty @to.list_type + assert_empty @to.list_width + end + + def accept_list_item_end_bullet + assert_equal 0, @to.indent, 'indent' + end + + def accept_list_item_end_label + assert_equal "cat\n: ", @to.res.join + assert_equal 0, @to.indent, 'indent' + end + + def accept_list_item_end_lalpha + assert_equal 0, @to.indent, 'indent' + assert_equal 2, @to.list_index.last + end + + def accept_list_item_end_note + assert_equal "cat\n: ", @to.res.join + assert_equal 0, @to.indent, 'indent' + end + + def accept_list_item_end_number + assert_equal 0, @to.indent, 'indent' + assert_equal 2, @to.list_index.last + end + + def accept_list_item_end_ualpha + assert_equal 0, @to.indent, 'indent' + assert_equal 2, @to.list_index.last + end + + def accept_list_item_start_bullet + assert_equal [""], @to.res + assert_equal '* ', @to.prefix + end + + def accept_list_item_start_label + assert_equal [""], @to.res + assert_equal "cat\n: ", @to.prefix + + assert_equal 4, @to.indent + end + + def accept_list_item_start_lalpha + assert_equal [""], @to.res + assert_equal '1. ', @to.prefix + + assert_equal 1, @to.list_index.last + assert_equal 4, @to.indent + end + + def accept_list_item_start_note + assert_equal [""], @to.res + assert_equal "cat\n: ", @to.prefix + + assert_equal 4, @to.indent + end + + def accept_list_item_start_number + assert_equal [""], @to.res + assert_equal '1. ', @to.prefix + + assert_equal 1, @to.list_index.last + assert_equal 4, @to.indent + end + + def accept_list_item_start_ualpha + assert_equal [""], @to.res + assert_equal '1. ', @to.prefix + + assert_equal 1, @to.list_index.last + assert_equal 4, @to.indent + end + + def accept_list_start_bullet + assert_equal "", @to.res.join + assert_equal [nil], @to.list_index + assert_equal [:BULLET], @to.list_type + assert_equal [4], @to.list_width + end + + def accept_list_start_label + assert_equal "", @to.res.join + assert_equal [nil], @to.list_index + assert_equal [:LABEL], @to.list_type + assert_equal [4], @to.list_width + end + + def accept_list_start_lalpha + assert_equal "", @to.res.join + assert_equal [1], @to.list_index + assert_equal [:LALPHA], @to.list_type + assert_equal [4], @to.list_width + end + + def accept_list_start_note + assert_equal "", @to.res.join + assert_equal [nil], @to.list_index + assert_equal [:NOTE], @to.list_type + assert_equal [4], @to.list_width + end + + def accept_list_start_number + assert_equal "", @to.res.join + assert_equal [1], @to.list_index + assert_equal [:NUMBER], @to.list_type + assert_equal [4], @to.list_width + end + + def accept_list_start_ualpha + assert_equal "", @to.res.join + assert_equal [1], @to.list_index + assert_equal [:UALPHA], @to.list_type + assert_equal [4], @to.list_width + end + + def accept_paragraph + assert_equal "hi\n", @to.res.join + end + + def accept_raw + raw = <<-RAW.rstrip +<table> +<tr><th>Name<th>Count +<tr><td>a<td>1 +<tr><td>b<td>2 +</table> + RAW + + assert_equal raw, @to.res.join + end + + def accept_rule + assert_equal "---\n", @to.res.join + end + + def accept_verbatim + assert_equal " hi\n world\n\n", @to.res.join + end + + def end_accepting + assert_equal "hi", @to.end_accepting + end + + def start_accepting + assert_equal 0, @to.indent + assert_equal [""], @to.res + assert_empty @to.list_index + assert_empty @to.list_type + assert_empty @to.list_width + end + + def accept_heading_1 + assert_equal "# Hello\n", @to.end_accepting + end + + def accept_heading_2 + assert_equal "## Hello\n", @to.end_accepting + end + + def accept_heading_3 + assert_equal "### Hello\n", @to.end_accepting + end + + def accept_heading_4 + assert_equal "#### Hello\n", @to.end_accepting + end + + def accept_heading_indent + assert_equal " # Hello\n", @to.end_accepting + end + + def accept_heading_b + assert_equal "# **Hello**\n", @to.end_accepting + end + + def accept_heading_suppressed_crossref + assert_equal "# Hello\n", @to.end_accepting + end + + def accept_list_item_start_note_2 + assert_equal "`teletype`\n: teletype description\n\n", @to.res.join + end + + def accept_list_item_start_note_multi_description + assert_equal "label\n: description one\n\n: description two\n\n", + @to.res.join + end + + def accept_list_item_start_note_multi_label + assert_equal "one\ntwo\n: two headers\n\n", @to.res.join + end + + def accept_paragraph_b + assert_equal "reg **bold words** reg\n", @to.end_accepting + end + + def accept_paragraph_br + assert_equal "one \ntwo\n", @to.end_accepting + end + + def accept_paragraph_break + assert_equal "hello \nworld\n", @to.end_accepting + end + + def accept_paragraph_i + assert_equal "reg *italic words* reg\n", @to.end_accepting + end + + def accept_paragraph_indent + expected = <<-EXPECTED + words words words words words words words words words words words words + words words words words words words words words words words words words + words words words words words words + EXPECTED + + assert_equal expected, @to.end_accepting + end + + def accept_paragraph_plus + assert_equal "reg `teletype` reg\n", @to.end_accepting + end + + def accept_paragraph_star + assert_equal "reg **bold** reg\n", @to.end_accepting + end + + def accept_paragraph_underscore + assert_equal "reg *italic* reg\n", @to.end_accepting + end + + def accept_paragraph_wrap + expected = <<-EXPECTED +words words words words words words words words words words words words words +words words words words words words words words words words words words words +words words words words + EXPECTED + + assert_equal expected, @to.end_accepting + end + + def accept_rule_indent + assert_equal " ---\n", @to.end_accepting + end + + def accept_verbatim_indent + assert_equal " hi\n world\n\n", @to.end_accepting + end + + def accept_verbatim_big_indent + assert_equal " hi\n world\n\n", @to.end_accepting + end + + def list_nested + expected = <<-EXPECTED +* l1 + * l1.1 + +* l2 + + EXPECTED + + assert_equal expected, @to.end_accepting + end + + def list_verbatim + expected = <<-EXPECTED # HACK overblown +* list stuff + + * list + with + + second + + 1. indented + 2. numbered + + third + + * second + + + EXPECTED + + assert_equal expected, @to.end_accepting + end + + def test_convert_RDOCLINK + result = @to.convert 'rdoc-garbage:C' + + assert_equal "C\n", result + end + + def test_convert_RDOCLINK_image + result = @to.convert 'rdoc-image:/path/to/image.jpg' + + assert_equal "![](/path/to/image.jpg)\n", result + end + + def test_convert_TIDYLINK + result = @to.convert \ + '{DSL}[http://en.wikipedia.org/wiki/Domain-specific_language]' + + expected = "[DSL](http://en.wikipedia.org/wiki/Domain-specific_language)\n" + + assert_equal expected, result + end + + def test_handle_rdoc_link_label_footmark + assert_equal '[^1]:', @to.handle_rdoc_link('rdoc-label:footmark-1:x') + end + + def test_handle_rdoc_link_label_foottext + assert_equal '[^1]', @to.handle_rdoc_link('rdoc-label:foottext-1:x') + end + + def test_handle_rdoc_link_label_label + assert_equal '[x](#label-x)', @to.handle_rdoc_link('rdoc-label:label-x') + end + + def test_handle_rdoc_link_ref + assert_equal 'x', @to.handle_rdoc_link('rdoc-ref:x') + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_markup_to_rdoc.rb b/jni/ruby/test/rdoc/test_rdoc_markup_to_rdoc.rb new file mode 100644 index 0000000..4b60d01 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_markup_to_rdoc.rb @@ -0,0 +1,377 @@ +require 'rdoc/test_case' + +class TestRDocMarkupToRDoc < RDoc::Markup::TextFormatterTestCase + + add_visitor_tests + add_text_tests + + def setup + super + + @to = RDoc::Markup::ToRdoc.new + end + + def accept_blank_line + assert_equal "\n", @to.res.join + end + + def accept_block_quote + assert_equal "> quote\n", @to.res.join + end + + def accept_document + assert_equal "hello\n", @to.res.join + end + + def accept_heading + assert_equal "===== Hello\n", @to.res.join + end + + def accept_list_end_bullet + assert_empty @to.list_index + assert_empty @to.list_type + assert_empty @to.list_width + end + + def accept_list_end_label + assert_empty @to.list_index + assert_empty @to.list_type + assert_empty @to.list_width + end + + def accept_list_end_lalpha + assert_empty @to.list_index + assert_empty @to.list_type + assert_empty @to.list_width + end + + def accept_list_end_note + assert_empty @to.list_index + assert_empty @to.list_type + assert_empty @to.list_width + end + + def accept_list_end_number + assert_empty @to.list_index + assert_empty @to.list_type + assert_empty @to.list_width + end + + def accept_list_end_ualpha + assert_empty @to.list_index + assert_empty @to.list_type + assert_empty @to.list_width + end + + def accept_list_item_end_bullet + assert_equal 0, @to.indent, 'indent' + end + + def accept_list_item_end_label + assert_equal "cat:\n", @to.res.join + assert_equal 0, @to.indent, 'indent' + end + + def accept_list_item_end_lalpha + assert_equal 0, @to.indent, 'indent' + assert_equal 'b', @to.list_index.last + end + + def accept_list_item_end_note + assert_equal "cat:\n", @to.res.join + assert_equal 0, @to.indent, 'indent' + end + + def accept_list_item_end_number + assert_equal 0, @to.indent, 'indent' + assert_equal 2, @to.list_index.last + end + + def accept_list_item_end_ualpha + assert_equal 0, @to.indent, 'indent' + assert_equal 'B', @to.list_index.last + end + + def accept_list_item_start_bullet + assert_equal [""], @to.res + assert_equal '* ', @to.prefix + end + + def accept_list_item_start_label + assert_equal [""], @to.res + assert_equal "cat:\n ", @to.prefix + + assert_equal 2, @to.indent + end + + def accept_list_item_start_lalpha + assert_equal [""], @to.res + assert_equal 'a. ', @to.prefix + + assert_equal 'a', @to.list_index.last + assert_equal 3, @to.indent + end + + def accept_list_item_start_note + assert_equal [""], @to.res + assert_equal "cat:\n ", @to.prefix + + assert_equal 2, @to.indent + end + + def accept_list_item_start_number + assert_equal [""], @to.res + assert_equal '1. ', @to.prefix + + assert_equal 1, @to.list_index.last + assert_equal 3, @to.indent + end + + def accept_list_item_start_ualpha + assert_equal [""], @to.res + assert_equal 'A. ', @to.prefix + + assert_equal 'A', @to.list_index.last + assert_equal 3, @to.indent + end + + def accept_list_start_bullet + assert_equal "", @to.res.join + assert_equal [nil], @to.list_index + assert_equal [:BULLET], @to.list_type + assert_equal [1], @to.list_width + end + + def accept_list_start_label + assert_equal "", @to.res.join + assert_equal [nil], @to.list_index + assert_equal [:LABEL], @to.list_type + assert_equal [2], @to.list_width + end + + def accept_list_start_lalpha + assert_equal "", @to.res.join + assert_equal ['a'], @to.list_index + assert_equal [:LALPHA], @to.list_type + assert_equal [1], @to.list_width + end + + def accept_list_start_note + assert_equal "", @to.res.join + assert_equal [nil], @to.list_index + assert_equal [:NOTE], @to.list_type + assert_equal [2], @to.list_width + end + + def accept_list_start_number + assert_equal "", @to.res.join + assert_equal [1], @to.list_index + assert_equal [:NUMBER], @to.list_type + assert_equal [1], @to.list_width + end + + def accept_list_start_ualpha + assert_equal "", @to.res.join + assert_equal ['A'], @to.list_index + assert_equal [:UALPHA], @to.list_type + assert_equal [1], @to.list_width + end + + def accept_paragraph + assert_equal "hi\n", @to.res.join + end + + def accept_raw + raw = <<-RAW.rstrip +<table> +<tr><th>Name<th>Count +<tr><td>a<td>1 +<tr><td>b<td>2 +</table> + RAW + + assert_equal raw, @to.res.join + end + + def accept_rule + assert_equal "#{'-' * 78}\n", @to.res.join + end + + def accept_verbatim + assert_equal " hi\n world\n\n", @to.res.join + end + + def end_accepting + assert_equal "hi", @to.end_accepting + end + + def start_accepting + assert_equal 0, @to.indent + assert_equal [""], @to.res + assert_empty @to.list_index + assert_empty @to.list_type + assert_empty @to.list_width + end + + def accept_heading_1 + assert_equal "= Hello\n", @to.end_accepting + end + + def accept_heading_2 + assert_equal "== Hello\n", @to.end_accepting + end + + def accept_heading_3 + assert_equal "=== Hello\n", @to.end_accepting + end + + def accept_heading_4 + assert_equal "==== Hello\n", @to.end_accepting + end + + def accept_heading_indent + assert_equal " = Hello\n", @to.end_accepting + end + + def accept_heading_b + assert_equal "= <b>Hello</b>\n", @to.end_accepting + end + + def accept_heading_suppressed_crossref + assert_equal "= Hello\n", @to.end_accepting + end + + def accept_list_item_start_note_2 + assert_equal "<tt>teletype</tt>:\n teletype description\n\n", @to.res.join + end + + def accept_list_item_start_note_multi_description + assert_equal "label:\n description one\n\n description two\n\n", + @to.res.join + end + + def accept_list_item_start_note_multi_label + assert_equal "one\ntwo:\n two headers\n\n", @to.res.join + end + + def accept_paragraph_b + assert_equal "reg <b>bold words</b> reg\n", @to.end_accepting + end + + def accept_paragraph_br + assert_equal "one\ntwo\n", @to.end_accepting + end + + def accept_paragraph_break + assert_equal "hello\nworld\n", @to.end_accepting + end + + def accept_paragraph_i + assert_equal "reg <em>italic words</em> reg\n", @to.end_accepting + end + + def accept_paragraph_indent + expected = <<-EXPECTED + words words words words words words words words words words words words + words words words words words words words words words words words words + words words words words words words + EXPECTED + + assert_equal expected, @to.end_accepting + end + + def accept_paragraph_plus + assert_equal "reg <tt>teletype</tt> reg\n", @to.end_accepting + end + + def accept_paragraph_star + assert_equal "reg <b>bold</b> reg\n", @to.end_accepting + end + + def accept_paragraph_underscore + assert_equal "reg <em>italic</em> reg\n", @to.end_accepting + end + + def accept_paragraph_wrap + expected = <<-EXPECTED +words words words words words words words words words words words words words +words words words words words words words words words words words words words +words words words words + EXPECTED + + assert_equal expected, @to.end_accepting + end + + def accept_rule_indent + assert_equal " #{'-' * 75}\n", @to.end_accepting + end + + def accept_verbatim_indent + assert_equal " hi\n world\n\n", @to.end_accepting + end + + def accept_verbatim_big_indent + assert_equal " hi\n world\n\n", @to.end_accepting + end + + def list_nested + expected = <<-EXPECTED +* l1 + * l1.1 +* l2 + EXPECTED + + assert_equal expected, @to.end_accepting + end + + def list_verbatim + expected = <<-EXPECTED # HACK overblown +* list stuff + + * list + with + + second + + 1. indented + 2. numbered + + third + + * second + + EXPECTED + + assert_equal expected, @to.end_accepting + end + + # functional test + def test_convert_list_note + note_list = <<-NOTE_LIST +foo :: +bar :: + hi + NOTE_LIST + + expected = <<-EXPECTED +foo +bar: + hi + + EXPECTED + + assert_equal expected, @to.convert(note_list) + end + + def test_accept_indented_paragraph + ip = RDoc::Markup::IndentedParagraph.new 2, 'cats are cool' + + @to.start_accepting + + @to.accept_indented_paragraph ip + + assert_equal " cats are cool\n", @to.end_accepting + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_markup_to_table_of_contents.rb b/jni/ruby/test/rdoc/test_rdoc_markup_to_table_of_contents.rb new file mode 100644 index 0000000..ba17b84 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_markup_to_table_of_contents.rb @@ -0,0 +1,126 @@ +require 'rdoc/test_case' + +class TestRDocMarkupToTableOfContents < RDoc::Markup::FormatterTestCase + + add_visitor_tests + + def setup + super + + @to = RDoc::Markup::ToTableOfContents.new + end + + def end_accepting + assert_equal %w[hi], @to.res + end + + def empty + assert_empty @to.res + end + + def accept_heading + assert_equal [@RM::Heading.new(5, 'Hello')], @to.res + end + + def accept_heading_1 + assert_equal [@RM::Heading.new(1, 'Hello')], @to.res + end + + def accept_heading_2 + assert_equal [@RM::Heading.new(2, 'Hello')], @to.res + end + + def accept_heading_3 + assert_equal [@RM::Heading.new(3, 'Hello')], @to.res + end + + def accept_heading_4 + assert_equal [@RM::Heading.new(4, 'Hello')], @to.res + end + + def accept_heading_b + assert_equal [@RM::Heading.new(1, '*Hello*')], @to.res + end + + def accept_heading_suppressed_crossref + assert_equal [@RM::Heading.new(1, '\\Hello')], @to.res + end + + alias accept_blank_line empty + alias accept_block_quote empty + alias accept_document empty + alias accept_list_end_bullet empty + alias accept_list_end_label empty + alias accept_list_end_lalpha empty + alias accept_list_end_note empty + alias accept_list_end_number empty + alias accept_list_end_ualpha empty + alias accept_list_item_end_bullet empty + alias accept_list_item_end_label empty + alias accept_list_item_end_lalpha empty + alias accept_list_item_end_note empty + alias accept_list_item_end_number empty + alias accept_list_item_end_ualpha empty + alias accept_list_item_start_bullet empty + alias accept_list_item_start_label empty + alias accept_list_item_start_lalpha empty + alias accept_list_item_start_note empty + alias accept_list_item_start_note_2 empty + alias accept_list_item_start_note_multi_description empty + alias accept_list_item_start_note_multi_label empty + alias accept_list_item_start_number empty + alias accept_list_item_start_ualpha empty + alias accept_list_start_bullet empty + alias accept_list_start_label empty + alias accept_list_start_lalpha empty + alias accept_list_start_note empty + alias accept_list_start_number empty + alias accept_list_start_ualpha empty + alias accept_paragraph empty + alias accept_paragraph_b empty + alias accept_paragraph_br empty + alias accept_paragraph_break empty + alias accept_paragraph_i empty + alias accept_paragraph_plus empty + alias accept_paragraph_star empty + alias accept_paragraph_underscore empty + alias accept_raw empty + alias accept_rule empty + alias accept_verbatim empty + alias list_nested empty + alias list_verbatim empty + alias start_accepting empty + + def test_accept_document_omit_headings_below + document = doc + document.omit_headings_below = 2 + + @to.accept_document document + + assert_equal 2, @to.omit_headings_below + end + + def test_accept_heading_suppressed + @to.start_accepting + @to.omit_headings_below = 4 + + suppressed = head 5, 'Hello' + + @to.accept_heading suppressed + + assert_empty @to.res + end + + def test_suppressed_eh + @to.omit_headings_below = nil + + refute @to.suppressed? head(1, '') + + @to.omit_headings_below = 1 + + refute @to.suppressed? head(1, '') + assert @to.suppressed? head(2, '') + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_markup_to_tt_only.rb b/jni/ruby/test/rdoc/test_rdoc_markup_to_tt_only.rb new file mode 100644 index 0000000..2e950dd --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_markup_to_tt_only.rb @@ -0,0 +1,246 @@ +require 'rdoc/test_case' + +class TestRDocMarkupToTtOnly < RDoc::Markup::FormatterTestCase + + add_visitor_tests + + def setup + super + + @to = RDoc::Markup::ToTtOnly.new + end + + def accept_blank_line + assert_empty @to.end_accepting + end + + def accept_block_quote + assert_empty @to.end_accepting + end + + def accept_document + assert_equal [], @to.res + end + + def accept_heading + assert_empty @to.end_accepting + end + + def accept_list_end_bullet + assert_empty @to.res + end + + def accept_list_end_label + assert_empty @to.res + end + + def accept_list_end_lalpha + assert_empty @to.res + end + + def accept_list_end_note + assert_empty @to.res + end + + def accept_list_end_number + assert_empty @to.res + end + + def accept_list_end_ualpha + assert_empty @to.res + end + + def accept_list_item_end_bullet + assert_empty @to.res + end + + def accept_list_item_end_label + assert_empty @to.res + end + + def accept_list_item_end_lalpha + assert_empty @to.res + end + + def accept_list_item_end_note + assert_empty @to.res + end + + def accept_list_item_end_number + assert_empty @to.res + end + + def accept_list_item_end_ualpha + assert_empty @to.res + end + + def accept_list_item_start_bullet + assert_empty @to.res + end + + def accept_list_item_start_label + assert_empty @to.res + end + + def accept_list_item_start_lalpha + assert_empty @to.res + end + + def accept_list_item_start_note + assert_empty @to.res + end + + def accept_list_item_start_number + assert_empty @to.res + end + + def accept_list_item_start_ualpha + assert_empty @to.res + end + + def accept_list_start_bullet + assert_empty @to.res + end + + def accept_list_start_label + assert_empty @to.res + end + + def accept_list_start_lalpha + assert_empty @to.res + end + + def accept_list_start_note + assert_empty @to.res + end + + def accept_list_start_number + assert_empty @to.res + end + + def accept_list_start_ualpha + assert_empty @to.res + end + + def accept_paragraph + assert_empty @to.end_accepting + end + + def accept_paragraph_break + assert_empty @to.end_accepting + end + + def accept_raw + assert_empty @to.end_accepting + end + + def accept_rule + assert_empty @to.end_accepting + end + + def accept_verbatim + assert_empty @to.end_accepting + end + + def end_accepting + assert_equal %w[hi], @to.end_accepting + end + + def start_accepting + assert_empty @to.end_accepting + end + + def accept_heading_1 + assert_empty @to.end_accepting + end + + def accept_heading_2 + assert_empty @to.end_accepting + end + + def accept_heading_3 + assert_empty @to.end_accepting + end + + def accept_heading_4 + assert_empty @to.end_accepting + end + + def accept_heading_indent + assert_empty @to.end_accepting + end + + def accept_heading_b + assert_empty @to.end_accepting + end + + def accept_heading_suppressed_crossref + assert_empty @to.end_accepting + end + + def accept_list_item_start_note_2 + assert_equal [nil, 'teletype', nil], @to.res + end + + def accept_list_item_start_note_multi_description + assert_empty @to.res + end + + def accept_list_item_start_note_multi_label + assert_empty @to.res + end + + def accept_paragraph_b + assert_empty @to.end_accepting + end + + def accept_paragraph_br + assert_empty @to.end_accepting + end + + def accept_paragraph_i + assert_empty @to.end_accepting + end + + def accept_paragraph_indent + assert_empty @to.end_accepting + end + + def accept_paragraph_plus + assert_equal %w[teletype], @to.end_accepting + end + + def accept_paragraph_star + assert_empty @to.end_accepting + end + + def accept_paragraph_underscore + assert_empty @to.end_accepting + end + + def accept_paragraph_wrap + assert_empty @to.end_accepting + end + + def accept_rule_indent + assert_empty @to.end_accepting + end + + def accept_verbatim_indent + assert_empty @to.end_accepting + end + + def accept_verbatim_big_indent + assert_empty @to.end_accepting + end + + def list_nested + assert_empty @to.end_accepting + end + + def list_verbatim + assert_empty @to.end_accepting + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_markup_verbatim.rb b/jni/ruby/test/rdoc/test_rdoc_markup_verbatim.rb new file mode 100644 index 0000000..781d528 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_markup_verbatim.rb @@ -0,0 +1,29 @@ +require 'rdoc/test_case' + +class TestRDocMarkupVerbatim < RDoc::TestCase + + def test_equals2 + v1 = verb('1 + 1') + v2 = verb('1 + 1') + v3 = verb('1 + 2') + v4 = verb('1 + 1') + v4.format = :ruby + + assert_equal v1, v2 + + refute_equal v1, v3 + refute_equal v1, v4 + end + + def test_ruby_eh + verbatim = RDoc::Markup::Verbatim.new + + refute verbatim.ruby? + + verbatim.format = :ruby + + assert verbatim.ruby? + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_method_attr.rb b/jni/ruby/test/rdoc/test_rdoc_method_attr.rb new file mode 100644 index 0000000..e93e81c --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_method_attr.rb @@ -0,0 +1,193 @@ +require File.expand_path '../xref_test_case', __FILE__ + +class TestRDocMethodAttr < XrefTestCase + + def test_initialize_copy + refute_same @c1_m.full_name, @c1_m.dup.full_name + end + + def test_block_params_equal + m = RDoc::MethodAttr.new(nil, 'foo') + + m.block_params = '' + assert_equal '', m.block_params + + m.block_params = 'a_var' + assert_equal 'a_var', m.block_params + + m.block_params = '()' + assert_equal '', m.block_params + + m.block_params = '(a_var, b_var)' + assert_equal 'a_var, b_var', m.block_params + + m.block_params = '.to_s + "</#{element.upcase}>"' + assert_equal '', m.block_params + + m.block_params = 'i.name' + assert_equal 'name', m.block_params + + m.block_params = 'attr.expanded_name, attr.value' + assert_equal 'expanded_name, value', m.block_params + + m.block_params = 'expanded_name, attr.value' + assert_equal 'expanded_name, value', m.block_params + + m.block_params = 'attr.expanded_name, value' + assert_equal 'expanded_name, value', m.block_params + + m.block_params = '(@base_notifier)' + assert_equal 'base_notifier', m.block_params + + m.block_params = 'if @signal_status == :IN_LOAD' + assert_equal '', m.block_params + + m.block_params = 'e if e.kind_of? Element' + assert_equal 'e', m.block_params + + m.block_params = '(e, f) if e.kind_of? Element' + assert_equal 'e, f', m.block_params + + m.block_params = 'back_path, back_name' + assert_equal 'back_path, back_name', m.block_params + + m.block_params = '(*a[1..-1])' + assert_equal '*a', m.block_params + + m.block_params = '@@context[:node] if defined? @@context[:node].namespace' + assert_equal 'context', m.block_params + + m.block_params = '(result, klass.const_get(constant_name))' + assert_equal 'result, const', m.block_params + + m.block_params = 'name.to_s if (bitmap & bit) != 0' + assert_equal 'name', m.block_params + + m.block_params = 'line unless line.deleted' + assert_equal 'line', m.block_params + + m.block_params = 'str + rs' + assert_equal 'str', m.block_params + + m.block_params = 'f+rs' + assert_equal 'f', m.block_params + + m.block_params = '[user, realm, hash[user]]' + assert_equal 'user, realm, hash', m.block_params + + m.block_params = 'proc{|rc| rc == "rc" ? irbrc : irbrc+rc| ... }' + assert_equal 'proc', m.block_params + + m.block_params = 'lambda { |x| x.to_i }' + assert_equal 'lambda', m.block_params + + m.block_params = '$&' + assert_equal 'str', m.block_params + + m.block_params = 'Inflections.instance' + assert_equal 'instance', m.block_params + + m.block_params = 'self.class::STARTED' + assert_equal 'STARTED', m.block_params + + m.block_params = 'Test::Unit::TestCase::STARTED' + assert_equal 'STARTED', m.block_params + + m.block_params = 'ActiveSupport::OptionMerger.new(self, options)' + assert_equal 'option_merger', m.block_params + + m.block_params = ', msg' + assert_equal '', m.block_params + + m.block_params = '[size.to_s(16), term, chunk, term].join' + assert_equal '[size, term, chunk, term].join', m.block_params + + m.block_params = 'YPath.new( path )' + assert_equal 'y_path', m.block_params + + end + + def test_find_method_or_attribute_recursive + inc = RDoc::Include.new 'M1', nil + @m1.add_include inc # M1 now includes itself + + assert_nil @m1_m.find_method_or_attribute 'm' + end + + def test_full_name + assert_equal 'C1#m', @c1_m.full_name + assert_equal 'C1::m', @c1__m.full_name + end + + def test_is_alias_for + assert_equal @c2_b, @c2_a.is_alias_for + end + + def test_output_name + assert_equal '#m', @c1_m.output_name(@c1) + assert_equal '::m', @c1__m.output_name(@c1) + + assert_equal 'C1#m', @c1_m.output_name(@c2) + assert_equal 'C1.m', @c1__m.output_name(@c2) + end + + def test_search_record + @c1_m.comment = 'This is a comment.' + + expected = [ + 'm', + 'C1#m', + 'm', + 'C1', + 'C1.html#method-i-m', + '(foo)', + "<p>This is a comment.\n", + ] + + assert_equal expected, @c1_m.search_record + end + + def test_spaceship + assert_nil @c1_m.<=>(RDoc::CodeObject.new) + end + + def test_equals2 + assert_equal @c1_m, @c1_m + refute_equal @c1_m, @parent_m + end + + def test_pretty_print + temp_dir do |tmpdir| + s = RDoc::RI::Store.new tmpdir + s.rdoc = @rdoc + + top_level = s.add_file 'file.rb' + meth_bang = RDoc::AnyMethod.new nil, 'method!' + meth_bang.record_location top_level + + meth_bang_alias = RDoc::Alias.new nil, 'method!', 'method_bang', '' + meth_bang_alias.record_location top_level + + klass = top_level.add_class RDoc::NormalClass, 'Object' + klass.add_method meth_bang + + meth_bang.add_alias meth_bang_alias, klass + + s.save + + meth_alias_from_store = s.load_method 'Object', '#method_bang' + + expected = "[RDoc::AnyMethod Object#method_bang public alias for method!]" + actual = mu_pp meth_alias_from_store + assert_equal expected, actual + end + end + + def test_to_s + assert_equal 'RDoc::AnyMethod: C1#m', @c1_m.to_s + assert_equal 'RDoc::AnyMethod: C2#b', @c2_b.to_s + assert_equal 'RDoc::AnyMethod: C1::m', @c1__m.to_s + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_normal_class.rb b/jni/ruby/test/rdoc/test_rdoc_normal_class.rb new file mode 100644 index 0000000..ab31a8d --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_normal_class.rb @@ -0,0 +1,47 @@ +require File.expand_path '../xref_test_case', __FILE__ + +class TestRDocNormalClass < XrefTestCase + + def test_ancestors + klass = @top_level.add_class RDoc::NormalClass, 'Klass' + incl = RDoc::Include.new 'Incl', '' + + sub_klass = @top_level.add_class RDoc::NormalClass, 'SubClass' + sub_klass.superclass = klass + sub_klass.add_include incl + + assert_equal [incl.name, klass, 'Object'], sub_klass.ancestors + end + + def test_ancestors_multilevel + c1 = @top_level.add_class RDoc::NormalClass, 'Outer' + c2 = @top_level.add_class RDoc::NormalClass, 'Middle', c1.full_name + c3 = @top_level.add_class RDoc::NormalClass, 'Inner', c2.full_name + + assert_equal [c2, c1, 'Object'], c3.ancestors + end + + def test_aref + assert_equal 'class-C1', @c1.aref + assert_equal 'class-C2::C3', @c2_c3.aref + end + + def test_direct_ancestors + incl = RDoc::Include.new 'Incl', '' + + c1 = @top_level.add_class RDoc::NormalClass, 'Outer' + c2 = @top_level.add_class RDoc::NormalClass, 'Middle', c1.full_name + c3 = @top_level.add_class RDoc::NormalClass, 'Inner', c2.full_name + c3.add_include incl + + assert_equal [incl.name, c2], c3.direct_ancestors + end + + def test_definition + c = RDoc::NormalClass.new 'C' + + assert_equal 'class C', c.definition + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_normal_module.rb b/jni/ruby/test/rdoc/test_rdoc_normal_module.rb new file mode 100644 index 0000000..1944564 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_normal_module.rb @@ -0,0 +1,42 @@ +require File.expand_path '../xref_test_case', __FILE__ + +class TestRDocNormalModule < XrefTestCase + + def setup + super + + @mod = RDoc::NormalModule.new 'Mod' + end + + def test_ancestors_module + top_level = @store.add_file 'file.rb' + mod = top_level.add_module RDoc::NormalModule, 'Mod' + incl = RDoc::Include.new 'Incl', '' + + mod.add_include incl + + assert_equal [incl.name], mod.ancestors + + mod2 = top_level.add_module RDoc::NormalModule, 'Inc2' + inc2 = RDoc::Include.new 'Inc2', '' + mod.add_include inc2 + assert_equal [mod2, incl.name], mod.ancestors + end + + def test_aref + assert_equal 'module-M1', @m1.aref + assert_equal 'module-M1::M2', @m1_m2.aref + end + + def test_definition + m = RDoc::NormalModule.new 'M' + + assert_equal 'module M', m.definition + end + + def test_module_eh + assert @mod.module? + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_options.rb b/jni/ruby/test/rdoc/test_rdoc_options.rb new file mode 100644 index 0000000..67053e3 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_options.rb @@ -0,0 +1,766 @@ +require 'rdoc/test_case' + +class TestRDocOptions < RDoc::TestCase + + def setup + super + + @options = RDoc::Options.new + @generators = RDoc::RDoc::GENERATORS.dup + end + + def teardown + super + + RDoc::RDoc::GENERATORS.replace @generators + end + + def test_check_files + skip "assumes UNIX permission model" if /mswin|mingw/ =~ RUBY_PLATFORM + + out, err = capture_io do + temp_dir do + FileUtils.touch 'unreadable' + FileUtils.chmod 0, 'unreadable' + + @options.files = %w[nonexistent unreadable] + + @options.check_files + end + end + + assert_empty @options.files + + assert_empty out + assert_empty err + end + + def test_check_files_warn + @options.verbosity = 2 + + out, err = verbose_capture_io do + @options.files = %w[nonexistent] + + @options.check_files + end + + assert_empty out + assert_equal "file 'nonexistent' not found\n", err + assert_empty @options.files + end + + def test_dry_run_default + refute @options.dry_run + end + + def test_encode_with + coder = {} + class << coder; alias add []=; end + + @options.encode_with coder + + encoding = Object.const_defined?(:Encoding) ? 'UTF-8' : nil + + expected = { + 'charset' => 'UTF-8', + 'encoding' => encoding, + 'exclude' => [], + 'hyperlink_all' => false, + 'line_numbers' => false, + 'locale' => nil, + 'locale_dir' => 'locale', + 'locale_name' => nil, + 'main_page' => nil, + 'markup' => 'rdoc', + 'output_decoration' => true, + 'page_dir' => nil, + 'rdoc_include' => [], + 'show_hash' => false, + 'static_path' => [], + 'tab_width' => 8, + 'template_stylesheets' => [], + 'title' => nil, + 'visibility' => :protected, + 'webcvs' => nil, + } + + assert_equal expected, coder + end + + def test_encode_with_trim_paths + subdir = nil + coder = {} + class << coder; alias add []=; end + + temp_dir do |dir| + FileUtils.mkdir 'project' + FileUtils.mkdir 'dir' + FileUtils.touch 'file' + + Dir.chdir 'project' do + subdir = File.expand_path 'subdir' + FileUtils.mkdir 'subdir' + @options.parse %w[ + --copy subdir + --copy ../file + --copy ../ + --copy / + --include subdir + --include ../dir + --include ../ + --include / + ] + + @options.encode_with coder + end + end + + assert_equal [subdir], coder['rdoc_include'] + + assert_equal [subdir], coder['static_path'] + end + + def test_encoding_default + skip "Encoding not implemented" unless Object.const_defined? :Encoding + + assert_equal Encoding::UTF_8, @options.encoding + end + + def test_generator_descriptions + # HACK autotest/isolate should take care of this + RDoc::RDoc::GENERATORS.clear + RDoc::RDoc::GENERATORS['darkfish'] = RDoc::Generator::Darkfish + RDoc::RDoc::GENERATORS['ri'] = RDoc::Generator::RI + + expected = <<-EXPECTED.chomp + darkfish - HTML generator, written by Michael Granger + ri - creates ri data files + EXPECTED + + assert_equal expected, @options.generator_descriptions + end + + def test_init_with_encoding + skip "Encoding not implemented" unless Object.const_defined? :Encoding + RDoc.load_yaml + + @options.encoding = Encoding::IBM437 + + options = YAML.load YAML.dump @options + + assert_equal Encoding::IBM437, options.encoding + end + + def test_init_with_trim_paths + RDoc.load_yaml + + yaml = <<-YAML +--- !ruby/object:RDoc::Options +static_path: +- /etc +rdoc_include: +- /etc + YAML + + options = YAML.load yaml + + assert_empty options.rdoc_include + assert_empty options.static_path + end + + def test_parse_copy_files_file_relative + file = File.basename __FILE__ + expected = File.expand_path __FILE__ + + Dir.chdir File.expand_path('..', __FILE__) do + @options.parse %W[--copy-files #{file}] + + assert_equal [expected], @options.static_path + end + end + + def test_parse_copy_files_file_absolute + @options.parse %W[--copy-files #{File.expand_path __FILE__}] + + assert_equal [File.expand_path(__FILE__)], @options.static_path + end + + def test_parse_copy_files_directory_relative + @options.parse %w[--copy-files .] + + assert_equal [@pwd], @options.static_path + end + + def test_parse_copy_files_directory_absolute + @options.parse %w[--copy-files /] + + assert_equal 1, @options.static_path.length + + assert_match %r%^([A-Z]:)?/$%i, @options.static_path.first + end + + def test_parse_coverage + @options.parse %w[--dcov] + + assert @options.coverage_report + assert @options.force_update + end + + def test_parse_coverage_no + @options.parse %w[--no-dcov] + + refute @options.coverage_report + end + + def test_parse_coverage_level_1 + @options.parse %w[--dcov=1] + + assert_equal 1, @options.coverage_report + end + + def test_parse_dash_p + out, err = capture_io do + @options.parse %w[-p] + end + + assert @options.pipe + refute_match %r%^Usage: %, err + refute_match %r%^invalid options%, err + + assert_empty out + end + + def test_parse_dash_p_files + out, err = capture_io do + @options.parse ['-p', File.expand_path(__FILE__)] + end + + refute @options.pipe + refute_match %r%^Usage: %, err + assert_match %r%^invalid options: -p .with files.%, err + + assert_empty out + end + + def test_parse_default + @options.parse [] + + assert_equal RDoc::Generator::Darkfish, @options.generator + assert_equal 'darkfish', @options.template + assert_match %r%rdoc/generator/template/darkfish$%, @options.template_dir + end + + def test_parse_deprecated + dep_hash = RDoc::Options::DEPRECATED + options = dep_hash.keys.sort + + out, err = capture_io do + @options.parse options + end + + dep_hash.each_pair do |opt, message| + assert_match %r%.*#{opt}.+#{message}%, err + end + + assert_empty out + end + + def test_parse_dry_run + @options.parse %w[--dry-run] + + assert @options.dry_run + end + + def test_parse_encoding + skip "Encoding not implemented" unless Object.const_defined? :Encoding + + @options.parse %w[--encoding Big5] + + assert_equal Encoding::Big5, @options.encoding + assert_equal 'Big5', @options.charset + end + + def test_parse_encoding_invalid + skip "Encoding not implemented" unless Object.const_defined? :Encoding + + out, err = capture_io do + @options.parse %w[--encoding invalid] + end + + assert_match %r%^invalid options: --encoding invalid%, err + + assert_empty out + end + + def test_parse_formatter + e = assert_raises OptionParser::InvalidOption do + @options.parse %w[--format darkfish --format ri] + end + + assert_equal 'invalid option: --format generator already set to darkfish', + e.message + end + + def test_parse_formatter_ri + e = assert_raises OptionParser::InvalidOption do + @options.parse %w[--format darkfish --ri] + end + + assert_equal 'invalid option: --ri generator already set to darkfish', + e.message + + @options = RDoc::Options.new + + e = assert_raises OptionParser::InvalidOption do + @options.parse %w[--format darkfish -r] + end + + assert_equal 'invalid option: -r generator already set to darkfish', + e.message + end + + def test_parse_formatter_ri_site + e = assert_raises OptionParser::InvalidOption do + @options.parse %w[--format darkfish --ri-site] + end + + assert_equal 'invalid option: --ri-site generator already set to darkfish', + e.message + + @options = RDoc::Options.new + + e = assert_raises OptionParser::InvalidOption do + @options.parse %w[--format darkfish -R] + end + + assert_equal 'invalid option: -R generator already set to darkfish', + e.message + end + + def test_parse_h + out, = capture_io do + begin + @options.parse %w[-h] + rescue SystemExit + end + end + + assert_equal 1, out.scan(/HTML generator options:/).length + assert_equal 1, out.scan(/ri generator options:/). length + end + + def test_parse_help + out, = capture_io do + begin + @options.parse %w[--help] + rescue SystemExit + end + end + + assert_equal 1, out.scan(/HTML generator options:/).length + assert_equal 1, out.scan(/ri generator options:/). length + end + + def test_parse_help_extra_generator + RDoc::RDoc::GENERATORS['test'] = Class.new do + def self.setup_options options + op = options.option_parser + + op.separator 'test generator options:' + end + end + + out, = capture_io do + begin + @options.parse %w[--help] + rescue SystemExit + end + end + + assert_equal 1, out.scan(/HTML generator options:/).length + assert_equal 1, out.scan(/ri generator options:/). length + assert_equal 1, out.scan(/test generator options:/).length + end + + def test_parse_format_for_extra_generator + RDoc::RDoc::GENERATORS['test'] = Class.new do + def self.setup_options options + op = options.option_parser + + op.separator 'test generator options:' + end + end + + @options.setup_generator 'test' + + assert_equal @options.generator_name, 'test' + end + + def test_parse_ignore_invalid + out, err = capture_io do + @options.parse %w[--ignore-invalid --bogus] + end + + refute_match %r%^Usage: %, err + assert_match %r%^invalid options: --bogus%, err + + assert_empty out + end + + def test_parse_ignore_invalid_default + out, err = capture_io do + @options.parse %w[--bogus --main BLAH] + end + + refute_match %r%^Usage: %, err + assert_match %r%^invalid options: --bogus%, err + + assert_equal 'BLAH', @options.main_page + + assert_empty out + end + + def test_parse_ignore_invalid_no + out, err = capture_io do + assert_raises SystemExit do + @options.parse %w[--no-ignore-invalid --bogus=arg --bobogus --visibility=extended] + end + end + + assert_match %r%^Usage: %, err + assert_match %r%^invalid options: --bogus=arg, --bobogus, --visibility=extended%, err + + assert_empty out + end + + def test_parse_ignore_invalid_no_quiet + out, err = capture_io do + assert_raises SystemExit do + @options.parse %w[--quiet --no-ignore-invalid --bogus=arg --bobogus --visibility=extended] + end + end + + refute_match %r%^Usage: %, err + assert_match %r%^invalid options: --bogus=arg, --bobogus, --visibility=extended%, err + + assert_empty out + end + + def test_ignore_needless_arg + out, err = capture_io do + @options.parse %w[--ri=foo] + end + + assert_match %r%^invalid options: --ri=foo%, err + + assert_empty out + end + + def test_ignore_missing_arg + out, err = capture_io do + @options.parse %w[--copy-files] + end + + assert_match %r%^invalid options: --copy-files%, err + + assert_empty out + end + + def test_parse_main + out, err = capture_io do + @options.parse %w[--main MAIN] + end + + assert_empty out + assert_empty err + + assert_equal 'MAIN', @options.main_page + end + + def test_parse_markup + out, err = capture_io do + @options.parse %w[--markup tomdoc] + end + + assert_empty out + assert_empty err + + assert_equal 'tomdoc', @options.markup + end + + def test_parse_page_dir + assert_nil @options.page_dir + + out, err = capture_io do + @options.parse %W[--page-dir #{Dir.tmpdir}] + end + + assert_empty out + assert_empty err + + expected = + Pathname(Dir.tmpdir).expand_path.relative_path_from @options.root + + assert_equal expected, @options.page_dir + assert_equal [Dir.tmpdir], @options.files + end + + def test_parse_page_dir_root + assert_nil @options.page_dir + + Dir.mktmpdir do |dir| + abs_root = dir + abs_page_dir = File.join dir, 'pages' + FileUtils.mkdir abs_page_dir + + out, err = capture_io do + @options.parse %W[--page-dir #{abs_page_dir} --root #{abs_root}] + end + + assert_empty out + assert_empty err + + assert_equal Pathname('pages'), @options.page_dir + assert_equal [abs_page_dir], @options.files + end + end + + def test_parse_ri_site + @options.parse %w[--ri-site] + + assert_equal RDoc::Generator::RI, @options.generator + assert_equal RDoc::RI::Paths.site_dir, @options.op_dir + end + + def test_parse_root + assert_equal Pathname(Dir.pwd), @options.root + + out, err = capture_io do + @options.parse %W[--root #{Dir.tmpdir}] + end + + assert_empty out + assert_empty err + + assert_equal Pathname(Dir.tmpdir), @options.root + assert_includes @options.rdoc_include, @options.root.to_s + end + + def test_parse_tab_width + @options.parse %w[--tab-width=1] + assert_equal 1, @options.tab_width + + @options.parse %w[-w2] + assert_equal 2, @options.tab_width + + _, err = capture_io do + @options.parse %w[-w=2] + end + + assert_match 'invalid options', err + + _, err = capture_io do + @options.parse %w[-w0] + end + + assert_match 'invalid options', err + end + + def test_parse_template + out, err = capture_io do + @options.parse %w[--template darkfish] + end + + assert_empty out + assert_empty err + + assert_equal 'darkfish', @options.template + + assert_match %r%rdoc/generator/template/darkfish$%, @options.template_dir + end + + def test_parse_template_nonexistent + out, err = capture_io do + @options.parse %w[--template NONEXISTENT] + end + + assert_empty out + assert_equal "could not find template NONEXISTENT\n", err + + assert_equal 'darkfish', @options.template + assert_match %r%rdoc/generator/template/darkfish$%, @options.template_dir + end + + def test_parse_template_load_path + orig_LOAD_PATH = $LOAD_PATH.dup + + template_dir = nil + + Dir.mktmpdir do |dir| + $LOAD_PATH << dir + + template_dir = File.join dir, 'rdoc', 'generator', 'template', 'load_path' + + FileUtils.mkdir_p template_dir + + out, err = capture_io do + @options.parse %w[--template load_path] + end + + assert_empty out + assert_empty err + end + + assert_equal 'load_path', @options.template + assert_equal template_dir, @options.template_dir + ensure + $LOAD_PATH.replace orig_LOAD_PATH + end + + def test_parse_visibility + @options.parse %w[--visibility=public] + assert_equal :public, @options.visibility + + @options.parse %w[--visibility=protected] + assert_equal :protected, @options.visibility + + @options.parse %w[--visibility=private] + assert_equal :private, @options.visibility + + @options.parse %w[--visibility=nodoc] + assert_equal :nodoc, @options.visibility + end + + def test_parse_write_options + tmpdir = File.join Dir.tmpdir, "test_rdoc_options_#{$$}" + FileUtils.mkdir_p tmpdir + + Dir.chdir tmpdir do + e = assert_raises SystemExit do + @options.parse %w[--write-options] + end + + assert_equal 0, e.status + + assert File.exist? '.rdoc_options' + end + ensure + FileUtils.rm_rf tmpdir + end + + def test_parse_extension_alias + out, err = capture_io do + @options.parse %w[--extension foobar=rdoc] + end + + assert_includes RDoc::Parser.parsers, [/\.foobar$/, RDoc::Parser::Simple] + + assert_empty out + assert_empty err + end + + def test_setup_generator + test_generator = Class.new do + def self.setup_options op + @op = op + end + + def self.op() @op end + end + + RDoc::RDoc::GENERATORS['test'] = test_generator + + @options.setup_generator 'test' + + assert_equal test_generator, @options.generator + assert_equal [test_generator], @options.generator_options + + assert_equal @options, test_generator.op + ensure + RDoc::RDoc::GENERATORS.delete 'test' + end + + def test_setup_generator_no_option_parser + test_generator = Class.new do + def self.setup_options op + op.option_parser.separator nil + @op = op + end + + def self.op() @op end + end + + RDoc::RDoc::GENERATORS['test'] = test_generator + + @options.setup_generator 'test' + + assert_equal test_generator, @options.generator + assert_equal [test_generator], @options.generator_options + + assert_equal @options, test_generator.op + ensure + RDoc::RDoc::GENERATORS.delete 'test' + end + + def test_update_output_dir + assert @options.update_output_dir + + @options.update_output_dir = false + + refute @options.update_output_dir + end + + def test_warn + out, err = capture_io do + @options.warn "warnings off" + end + + assert_empty out + assert_empty err + + @options.verbosity = 2 + + out, err = verbose_capture_io do + @options.warn "warnings on" + end + + assert_empty out + assert_equal "warnings on\n", err + end + + def test_write_options + temp_dir do |dir| + @options.write_options + + assert File.exist? '.rdoc_options' + + assert_equal @options, YAML.load(File.read('.rdoc_options')) + end + end + + def test_version + out, _ = capture_io do + begin + @options.parse %w[--version] + rescue SystemExit + end + end + + assert out.include?(RDoc::VERSION) + + out, _ = capture_io do + begin + @options.parse %w[-v] + rescue SystemExit + end + end + + assert out.include?(RDoc::VERSION) + end + + def test_visibility + @options.visibility = :all + assert_equal :private, @options.visibility + end +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_parser.rb b/jni/ruby/test/rdoc/test_rdoc_parser.rb new file mode 100644 index 0000000..34d4486 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_parser.rb @@ -0,0 +1,327 @@ +# -*- coding: us-ascii -*- + +require 'rdoc/test_case' + +class TestRDocParser < RDoc::TestCase + + def setup + super + + @RP = RDoc::Parser + @binary_dat = File.expand_path '../binary.dat', __FILE__ + + @fn = 'file.rb' + @top_level = RDoc::TopLevel.new @fn + @options = RDoc::Options.new + end + + def test_class_binary_eh_ISO_2022_JP + iso_2022_jp = File.join Dir.tmpdir, "test_rdoc_parser_#{$$}.rd" + + open iso_2022_jp, 'wb' do |io| + io.write "# coding: ISO-2022-JP\n" + io.write ":\e$B%3%^%s%I\e(B:\n" + end + + refute @RP.binary? iso_2022_jp + ensure + File.unlink iso_2022_jp + end + + def test_class_binary_eh_marshal + marshal = File.join Dir.tmpdir, "test_rdoc_parser_#{$$}.marshal" + open marshal, 'wb' do |io| + io.write Marshal.dump('') + io.write 'lots of text ' * 500 + end + + assert @RP.binary?(marshal) + ensure + File.unlink marshal + end + + def test_class_binary_japanese_text + file_name = File.expand_path '../test.ja.txt', __FILE__ + refute @RP.binary?(file_name) + end + + def test_class_binary_large_japanese_rdoc + skip "Encoding not implemented" unless Object.const_defined? :Encoding + + capture_io do + begin + extenc, Encoding.default_external = + Encoding.default_external, Encoding::US_ASCII + file_name = File.expand_path '../test.ja.largedoc', __FILE__ + assert !@RP.binary?(file_name) + ensure + Encoding.default_external = extenc + end + end + end + + def test_class_binary_japanese_rdoc + skip "Encoding not implemented" unless Object.const_defined? :Encoding + + file_name = File.expand_path '../test.ja.rdoc', __FILE__ + refute @RP.binary?(file_name) + end + + def test_class_can_parse + assert_equal @RP.can_parse(__FILE__), @RP::Ruby + + readme_file_name = File.expand_path '../test.txt', __FILE__ + + assert_equal @RP::Simple, @RP.can_parse(readme_file_name) + + assert_equal @RP::Simple, @RP.can_parse(@binary_dat) + + jtest_file_name = File.expand_path '../test.ja.txt', __FILE__ + assert_equal @RP::Simple, @RP.can_parse(jtest_file_name) + + jtest_rdoc_file_name = File.expand_path '../test.ja.rdoc', __FILE__ + assert_equal @RP::Simple, @RP.can_parse(jtest_rdoc_file_name) + + readme_file_name = File.expand_path '../README', __FILE__ + assert_equal @RP::Simple, @RP.can_parse(readme_file_name) + + jtest_largerdoc_file_name = File.expand_path '../test.ja.largedoc', __FILE__ + assert_equal @RP::Simple, @RP.can_parse(jtest_largerdoc_file_name) + + @RP.alias_extension 'rdoc', 'largedoc' + assert_equal @RP::Simple, @RP.can_parse(jtest_largerdoc_file_name) + end + + def test_class_for_executable + temp_dir do + content = "#!/usr/bin/env ruby -w\n" + open 'app', 'w' do |io| io.write content end + app = @store.add_file 'app' + + parser = @RP.for app, 'app', content, @options, :stats + + assert_kind_of RDoc::Parser::Ruby, parser + + assert_equal 'app', parser.file_name + end + end + + def test_class_for_forbidden + skip 'chmod not supported' if Gem.win_platform? + + tf = Tempfile.open 'forbidden' do |io| + begin + File.chmod 0000, io.path + forbidden = @store.add_file io.path + + parser = @RP.for forbidden, 'forbidden', '', @options, :stats + + assert_nil parser + ensure + File.chmod 0400, io.path + end + io + end + tf.close! if tf.respond_to? :close! + end + + def test_class_for_modeline + temp_dir do + content = "# -*- rdoc -*-\n= NEWS\n" + + open 'NEWS', 'w' do |io| io.write content end + app = @store.add_file 'NEWS' + + parser = @RP.for app, 'NEWS', content, @options, :stats + + assert_kind_of RDoc::Parser::Simple, parser + + assert_equal "= NEWS\n", parser.content + end + end + + def test_can_parse_modeline + readme_ext = File.join Dir.tmpdir, "README.EXT.#{$$}" + + open readme_ext, 'w' do |io| + io.puts "# README.EXT - -*- rdoc -*- created at: Mon Aug 7 16:45:54 JST 1995" + io.puts + io.puts "This document explains how to make extension libraries for Ruby." + end + + assert_equal RDoc::Parser::Simple, @RP.can_parse(readme_ext) + ensure + File.unlink readme_ext + end + + ## + # Selenium hides a .jar file using a .txt extension. + + def test_class_can_parse_zip + hidden_zip = File.expand_path '../hidden.zip.txt', __FILE__ + assert_nil @RP.can_parse(hidden_zip) + end + + def test_check_modeline + readme_ext = File.join Dir.tmpdir, "README.EXT.#{$$}" + + open readme_ext, 'w' do |io| + io.puts "# README.EXT - -*- RDoc -*- created at: Mon Aug 7 16:45:54 JST 1995" + io.puts + io.puts "This document explains how to make extension libraries for Ruby." + end + + assert_equal 'rdoc', @RP.check_modeline(readme_ext) + ensure + File.unlink readme_ext + end + + def test_check_modeline_coding + readme_ext = File.join Dir.tmpdir, "README.EXT.#{$$}" + + open readme_ext, 'w' do |io| + io.puts "# -*- coding: utf-8 -*-" + end + + assert_nil @RP.check_modeline readme_ext + ensure + File.unlink readme_ext + end + + def test_check_modeline_with_other + readme_ext = File.join Dir.tmpdir, "README.EXT.#{$$}" + + open readme_ext, 'w' do |io| + io.puts "# README.EXT - -*- mode: RDoc; indent-tabs-mode: nil -*-" + io.puts + io.puts "This document explains how to make extension libraries for Ruby." + end + + assert_equal 'rdoc', @RP.check_modeline(readme_ext) + ensure + File.unlink readme_ext + end + + def test_check_modeline_no_modeline + readme_ext = File.join Dir.tmpdir, "README.EXT.#{$$}" + + open readme_ext, 'w' do |io| + io.puts "This document explains how to make extension libraries for Ruby." + end + + assert_nil @RP.check_modeline(readme_ext) + ensure + File.unlink readme_ext + end + + def test_class_for_binary + rp = @RP.dup + + class << rp + alias old_can_parse can_parse + end + + def rp.can_parse(*args) nil end + + assert_nil @RP.for(nil, @binary_dat, nil, nil, nil) + end + + def test_class_for_markup + content = <<-CONTENT +# coding: utf-8 markup: rd + CONTENT + + parser = @RP.for @top_level, __FILE__, content, @options, nil + + assert_kind_of @RP::RD, parser + end + + def test_class_use_markup + content = <<-CONTENT +# coding: utf-8 markup: rd + CONTENT + + parser = @RP.use_markup content + + assert_equal @RP::RD, parser + end + + def test_class_use_markup_markdown + content = <<-CONTENT +# coding: utf-8 markup: markdown + CONTENT + + parser = @RP.use_markup content + + assert_equal @RP::Ruby, parser + end + + def test_class_use_markup_modeline + content = <<-CONTENT +# -*- coding: utf-8 -*- +# markup: rd + CONTENT + + parser = @RP.use_markup content + + assert_equal @RP::RD, parser + end + + def test_class_use_markup_modeline_shebang + content = <<-CONTENT +#!/bin/sh +/* -*- coding: utf-8 -*- + * markup: rd + */ + CONTENT + + parser = @RP.use_markup content + + assert_equal @RP::RD, parser + end + + def test_class_use_markup_shebang + content = <<-CONTENT +#!/usr/bin/env ruby +# coding: utf-8 markup: rd + CONTENT + + parser = @RP.use_markup content + + assert_equal @RP::RD, parser + end + + def test_class_use_markup_tomdoc + content = <<-CONTENT +# coding: utf-8 markup: tomdoc + CONTENT + + parser = @RP.use_markup content + + assert_equal @RP::Ruby, parser + end + + def test_class_use_markup_none + parser = @RP.use_markup '' + + assert_nil parser + end + + def test_class_use_markup_unknown + content = <<-CONTENT +# :markup: RDoc + CONTENT + + parser = @RP.use_markup content + + assert_nil parser + end + + def test_initialize + @RP.new @top_level, @fn, '', @options, nil + + assert_equal @RP, @top_level.parser + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_parser_c.rb b/jni/ruby/test/rdoc/test_rdoc_parser_c.rb new file mode 100644 index 0000000..71ffce5 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_parser_c.rb @@ -0,0 +1,1896 @@ +require 'rdoc/test_case' + +=begin + TODO: test call-seq parsing + +/* + * call-seq: + * ARGF.readlines(sep=$/) -> array + * ARGF.readlines(limit) -> array + * ARGF.readlines(sep, limit) -> array + * + * ARGF.to_a(sep=$/) -> array + * ARGF.to_a(limit) -> array + * ARGF.to_a(sep, limit) -> array + * + * Reads +ARGF+'s current file in its entirety, returning an +Array+ of its + * lines, one line per element. Lines are assumed to be separated by _sep_. + * + * lines = ARGF.readlines + * lines[0] #=> "This is line one\n" + */ + +assert call-seq did not stop at first empty line + +/* + * call-seq: + * + * flt ** other -> float + * + * Raises <code>float</code> the <code>other</code> power. + * + * 2.0**3 #=> 8.0 + */ + +assert call-seq correct (bug: was empty) + +/* call-seq: flt ** other -> float */ + +assert call-seq correct + +=end + +class TestRDocParserC < RDoc::TestCase + + def setup + super + + @tempfile = Tempfile.new self.class.name + filename = @tempfile.path + + @top_level = @store.add_file filename + @fn = filename + @options = RDoc::Options.new + @options.verbosity = 2 + @stats = RDoc::Stats.new @store, 0 + end + + def teardown + super + + @tempfile.close! + end + + def test_class_can_parse + c_parser = RDoc::Parser::C + + temp_dir do + FileUtils.touch 'file.C' + assert_equal c_parser, c_parser.can_parse('file.C') + + FileUtils.touch 'file.CC' + assert_equal c_parser, c_parser.can_parse('file.CC') + + FileUtils.touch 'file.H' + assert_equal c_parser, c_parser.can_parse('file.H') + + FileUtils.touch 'file.HH' + assert_equal c_parser, c_parser.can_parse('file.HH') + + FileUtils.touch 'file.c' + assert_equal c_parser, c_parser.can_parse('file.c') + + FileUtils.touch 'file.cc' + assert_equal c_parser, c_parser.can_parse('file.cc') + + FileUtils.touch 'file.cpp' + assert_equal c_parser, c_parser.can_parse('file.cpp') + + FileUtils.touch 'file.cxx' + assert_equal c_parser, c_parser.can_parse('file.cxx') + + FileUtils.touch 'file.h' + assert_equal c_parser, c_parser.can_parse('file.h') + + FileUtils.touch 'file.hh' + assert_equal c_parser, c_parser.can_parse('file.hh') + + FileUtils.touch 'file.y' + assert_equal c_parser, c_parser.can_parse('file.y') + end + end + + def test_initialize + some_ext = @top_level.add_class RDoc::NormalClass, 'SomeExt' + @top_level.add_class RDoc::SingleClass, 'SomeExtSingle' + + @store.cache[:c_class_variables] = { + @fn => { 'cSomeExt' => 'SomeExt' } + } + + @store.cache[:c_singleton_class_variables] = { + @fn => { 'cSomeExtSingle' => 'SomeExtSingle' } + } + + parser = RDoc::Parser::C.new @top_level, @fn, '', @options, @stats + + expected = { 'cSomeExt' => some_ext } + assert_equal expected, parser.classes + + expected = { 'cSomeExtSingle' => 'SomeExtSingle' } + assert_equal expected, parser.singleton_classes + + expected = { + 'cSomeExt' => 'SomeExt', + 'cSomeExtSingle' => 'SomeExtSingle', + } + known_classes = parser.known_classes.delete_if do |key, _| + RDoc::KNOWN_CLASSES.keys.include? key + end + + assert_equal expected, known_classes + end + + def test_do_attr_rb_attr + content = <<-EOF +void Init_Blah(void) { + cBlah = rb_define_class("Blah", rb_cObject); + + /* + * This is an accessor + */ + rb_attr(cBlah, rb_intern("accessor"), 1, 1, Qfalse); + + /* + * This is a reader + */ + rb_attr(cBlah, rb_intern("reader"), 1, 0, Qfalse); + + /* + * This is a writer + */ + rb_attr(cBlah, rb_intern("writer"), 0, 1, Qfalse); +} + EOF + + klass = util_get_class content, 'cBlah' + + attrs = klass.attributes + assert_equal 3, attrs.length, attrs.inspect + + accessor = attrs.shift + assert_equal 'accessor', accessor.name + assert_equal 'RW', accessor.rw + assert_equal 'This is an accessor', accessor.comment.text + assert_equal @top_level, accessor.file + + reader = attrs.shift + assert_equal 'reader', reader.name + assert_equal 'R', reader.rw + assert_equal 'This is a reader', reader.comment.text + + writer = attrs.shift + assert_equal 'writer', writer.name + assert_equal 'W', writer.rw + assert_equal 'This is a writer', writer.comment.text + end + + def test_do_attr_rb_define_attr + content = <<-EOF +void Init_Blah(void) { + cBlah = rb_define_class("Blah", rb_cObject); + + /* + * This is an accessor + */ + rb_define_attr(cBlah, "accessor", 1, 1); +} + EOF + + klass = util_get_class content, 'cBlah' + + attrs = klass.attributes + assert_equal 1, attrs.length, attrs.inspect + + accessor = attrs.shift + assert_equal 'accessor', accessor.name + assert_equal 'RW', accessor.rw + assert_equal 'This is an accessor', accessor.comment.text + assert_equal @top_level, accessor.file + end + + def test_do_aliases + content = <<-EOF +/* + * This should show up as an alias with documentation + */ +VALUE blah(VALUE klass, VALUE year) { +} + +void Init_Blah(void) { + cDate = rb_define_class("Date", rb_cObject); + + rb_define_method(cDate, "blah", blah, 1); + + rb_define_alias(cDate, "bleh", "blah"); +} + EOF + + klass = util_get_class content, 'cDate' + + methods = klass.method_list + assert_equal 2, methods.length + assert_equal 'bleh', methods.last.name + assert_equal 'blah', methods.last.is_alias_for.name + + assert_equal @top_level, methods.last.is_alias_for.file + assert_equal @top_level, methods.last.file + end + + def test_do_aliases_singleton + content = <<-EOF +/* + * This should show up as a method with documentation + */ +VALUE blah(VALUE klass, VALUE year) { +} + +void Init_Blah(void) { + cDate = rb_define_class("Date", rb_cObject); + sDate = rb_singleton_class(cDate); + + rb_define_method(sDate, "blah", blah, 1); + + /* + * This should show up as an alias + */ + rb_define_alias(sDate, "bleh", "blah"); +} + EOF + + klass = util_get_class content, 'cDate' + + methods = klass.method_list + + assert_equal 2, methods.length + assert_equal 'bleh', methods.last.name + assert methods.last.singleton + assert_equal 'blah', methods.last.is_alias_for.name + assert_equal 'This should show up as an alias', methods.last.comment.text + end + + def test_do_classes_boot_class + content = <<-EOF +/* Document-class: Foo + * this is the Foo boot class + */ +VALUE cFoo = boot_defclass("Foo", rb_cObject); + EOF + + klass = util_get_class content, 'cFoo' + assert_equal "this is the Foo boot class", klass.comment.text + assert_equal 'Object', klass.superclass + end + + def test_do_classes_boot_class_nil + content = <<-EOF +/* Document-class: Foo + * this is the Foo boot class + */ +VALUE cFoo = boot_defclass("Foo", 0); + EOF + + klass = util_get_class content, 'cFoo' + assert_equal "this is the Foo boot class", klass.comment.text + assert_equal nil, klass.superclass + end + + def test_do_aliases_missing_class + content = <<-EOF +void Init_Blah(void) { + rb_define_alias(cDate, "b", "a"); +} + EOF + + _, err = verbose_capture_io do + refute util_get_class(content, 'cDate') + end + + assert_equal "Enclosing class or module \"cDate\" for alias b a is not known\n", + err + end + + def test_do_classes_class + content = <<-EOF +/* Document-class: Foo + * this is the Foo class + */ +VALUE cFoo = rb_define_class("Foo", rb_cObject); + EOF + + klass = util_get_class content, 'cFoo' + assert_equal "this is the Foo class", klass.comment.text + end + + def test_do_classes_struct + content = <<-EOF +/* Document-class: Foo + * this is the Foo class + */ +VALUE cFoo = rb_struct_define_without_accessor( + "Foo", rb_cObject, foo_alloc, + "some", "various", "fields", NULL); + EOF + + klass = util_get_class content, 'cFoo' + assert_equal "this is the Foo class", klass.comment.text + end + + def test_do_classes_class_under + content = <<-EOF +/* Document-class: Kernel::Foo + * this is the Foo class under Kernel + */ +VALUE cFoo = rb_define_class_under(rb_mKernel, "Foo", rb_cObject); + EOF + + klass = util_get_class content, 'cFoo' + assert_equal 'Kernel::Foo', klass.full_name + assert_equal "this is the Foo class under Kernel", klass.comment.text + end + + def test_do_classes_class_under_rb_path2class + content = <<-EOF +/* Document-class: Kernel::Foo + * this is Kernel::Foo < A::B + */ +VALUE cFoo = rb_define_class_under(rb_mKernel, "Foo", rb_path2class("A::B")); + EOF + + klass = util_get_class content, 'cFoo' + + assert_equal 'Kernel::Foo', klass.full_name + assert_equal 'A::B', klass.superclass + assert_equal 'this is Kernel::Foo < A::B', klass.comment.text + end + + def test_do_classes_singleton + content = <<-EOF +VALUE cFoo = rb_define_class("Foo", rb_cObject); +VALUE cFooS = rb_singleton_class(cFoo); + EOF + + util_get_class content, 'cFooS' + + assert_equal 'Foo', @parser.singleton_classes['cFooS'] + end + + def test_do_classes_module + content = <<-EOF +/* Document-module: Foo + * this is the Foo module + */ +VALUE mFoo = rb_define_module("Foo"); + EOF + + klass = util_get_class content, 'mFoo' + assert_equal "this is the Foo module", klass.comment.text + end + + def test_do_classes_module_under + content = <<-EOF +/* Document-module: Kernel::Foo + * this is the Foo module under Kernel + */ +VALUE mFoo = rb_define_module_under(rb_mKernel, "Foo"); + EOF + + klass = util_get_class content, 'mFoo' + assert_equal "this is the Foo module under Kernel", klass.comment.text + end + + def test_do_constants + content = <<-EOF +#include <ruby.h> + +void Init_foo(){ + VALUE cFoo = rb_define_class("Foo", rb_cObject); + + /* 300: The highest possible score in bowling */ + rb_define_const(cFoo, "PERFECT", INT2FIX(300)); + + /* Huzzah!: What you cheer when you roll a perfect game */ + rb_define_const(cFoo, "CHEER", rb_str_new2("Huzzah!")); + + /* TEST\:TEST: Checking to see if escaped colon works */ + rb_define_const(cFoo, "TEST", rb_str_new2("TEST:TEST")); + + /* \\: The file separator on MS Windows */ + rb_define_const(cFoo, "MSEPARATOR", rb_str_new2("\\")); + + /* /: The file separator on Unix */ + rb_define_const(cFoo, "SEPARATOR", rb_str_new2("/")); + + /* C:\\Program Files\\Stuff: A directory on MS Windows */ + rb_define_const(cFoo, "STUFF", rb_str_new2("C:\\Program Files\\Stuff")); + + /* Default definition */ + rb_define_const(cFoo, "NOSEMI", INT2FIX(99)); + + rb_define_const(cFoo, "NOCOMMENT", rb_str_new2("No comment")); + + /* + * Multiline comment goes here because this comment spans multiple lines. + * Multiline comment goes here because this comment spans multiple lines. + */ + rb_define_const(cFoo, "MULTILINE", INT2FIX(1)); + + /* + * 1: Multiline comment goes here because this comment spans multiple lines. + * Multiline comment goes here because this comment spans multiple lines. + */ + rb_define_const(cFoo, "MULTILINE_VALUE", INT2FIX(1)); + + /* Multiline comment goes here because this comment spans multiple lines. + * Multiline comment goes here because this comment spans multiple lines. + */ + rb_define_const(cFoo, "MULTILINE_NOT_EMPTY", INT2FIX(1)); + + /* + * Multiline comment goes here because this comment spans multiple lines. + * 1: However, the value extraction should only happen for the first line + */ + rb_define_const(cFoo, "MULTILINE_COLON_ON_SECOND_LINE", INT2FIX(1)); + +} + EOF + + @parser = util_parser content + + @parser.do_classes + @parser.do_constants + + klass = @parser.classes['cFoo'] + assert klass + + constants = klass.constants + assert !klass.constants.empty? + + assert_equal @top_level, constants.first.file + + constants = constants.map { |c| [c.name, c.value, c.comment.text] } + + assert_equal ['PERFECT', '300', 'The highest possible score in bowling '], + constants.shift + assert_equal ['CHEER', 'Huzzah!', + 'What you cheer when you roll a perfect game '], + constants.shift + assert_equal ['TEST', 'TEST:TEST', + 'Checking to see if escaped colon works '], + constants.shift + assert_equal ['MSEPARATOR', '\\', + 'The file separator on MS Windows '], + constants.shift + assert_equal ['SEPARATOR', '/', + 'The file separator on Unix '], + constants.shift + assert_equal ['STUFF', 'C:\\Program Files\\Stuff', + 'A directory on MS Windows '], + constants.shift + assert_equal ['NOSEMI', 'INT2FIX(99)', + 'Default definition '], + constants.shift + assert_equal ['NOCOMMENT', 'rb_str_new2("No comment")', ''], + constants.shift + + comment = <<-EOF.chomp +Multiline comment goes here because this comment spans multiple lines. +Multiline comment goes here because this comment spans multiple lines. + EOF + assert_equal ['MULTILINE', 'INT2FIX(1)', comment], constants.shift + assert_equal ['MULTILINE_VALUE', '1', comment], constants.shift + assert_equal ['MULTILINE_NOT_EMPTY', 'INT2FIX(1)', comment], constants.shift + + comment = <<-EOF.chomp +Multiline comment goes here because this comment spans multiple lines. +1: However, the value extraction should only happen for the first line + EOF + assert_equal ['MULTILINE_COLON_ON_SECOND_LINE', 'INT2FIX(1)', comment], + constants.shift + + assert constants.empty?, constants.inspect + end + + def test_do_constants_curses + content = <<-EOF +void Init_curses(){ + mCurses = rb_define_module("Curses"); + + /* + * Document-const: Curses::COLOR_BLACK + * + * Value of the color black + */ + rb_curses_define_const(COLOR_BLACK); +} + EOF + + @parser = util_parser content + + @parser.do_modules + @parser.do_classes + @parser.do_constants + + klass = @parser.classes['mCurses'] + + constants = klass.constants + refute_empty klass.constants + + assert_equal 'COLOR_BLACK', constants.first.name + assert_equal 'UINT2NUM(COLOR_BLACK)', constants.first.value + assert_equal 'Value of the color black', constants.first.comment.text + end + + def test_do_constants_file + content = <<-EOF +void Init_File(void) { + /* Document-const: LOCK_SH + * + * Shared lock + */ + rb_file_const("LOCK_SH", INT2FIX(LOCK_SH)); +} + EOF + + @parser = util_parser content + + @parser.do_modules + @parser.do_classes + @parser.do_constants + + klass = @parser.classes['rb_mFConst'] + + constants = klass.constants + refute_empty klass.constants + + constant = constants.first + + assert_equal 'LOCK_SH', constant.name + assert_equal 'INT2FIX(LOCK_SH)', constant.value + assert_equal 'Shared lock', constant.comment.text + end + + def test_do_includes + content = <<-EOF +Init_foo() { + VALUE cFoo = rb_define_class("Foo", rb_cObject); + VALUE mInc = rb_define_module("Inc"); + + rb_include_module(cFoo, mInc); +} + EOF + + klass = util_get_class content, 'cFoo' + + incl = klass.includes.first + assert_equal 'Inc', incl.name + assert_equal '', incl.comment.text + assert_equal @top_level, incl.file + end + + # HACK parsing warning instead of setting up in file + def test_do_methods_in_c + content = <<-EOF +VALUE blah(VALUE klass, VALUE year) { +} + +void Init_Blah(void) { + cDate = rb_define_class("Date", rb_cObject); + + rb_define_method(cDate, "blah", blah, 1); /* in blah.c */ +} + EOF + + klass = nil + + _, err = verbose_capture_io do + klass = util_get_class content, 'cDate' + end + + assert_match ' blah.c ', err + end + + # HACK parsing warning instead of setting up in file + def test_do_methods_in_cpp + content = <<-EOF +VALUE blah(VALUE klass, VALUE year) { +} + +void Init_Blah(void) { + cDate = rb_define_class("Date", rb_cObject); + + rb_define_method(cDate, "blah", blah, 1); /* in blah.cpp */ +} + EOF + + klass = nil + + _, err = verbose_capture_io do + klass = util_get_class content, 'cDate' + end + + assert_match ' blah.cpp ', err + end + + # HACK parsing warning instead of setting up in file + def test_do_methods_in_y + content = <<-EOF +VALUE blah(VALUE klass, VALUE year) { +} + +void Init_Blah(void) { + cDate = rb_define_class("Date", rb_cObject); + + rb_define_method(cDate, "blah", blah, 1); /* in blah.y */ +} + EOF + + klass = nil + + _, err = verbose_capture_io do + klass = util_get_class content, 'cDate' + end + + assert_match ' blah.y ', err + end + + def test_do_methods_singleton_class + content = <<-EOF +VALUE blah(VALUE klass, VALUE year) { +} + +void Init_Blah(void) { + cDate = rb_define_class("Date", rb_cObject); + sDate = rb_singleton_class(cDate); + + rb_define_method(sDate, "blah", blah, 1); +} + EOF + + klass = util_get_class content, 'cDate' + + methods = klass.method_list + assert_equal 1, methods.length + assert_equal 'blah', methods.first.name + assert methods.first.singleton + end + + def test_do_missing + parser = util_parser + + klass_a = @top_level.add_class RDoc::ClassModule, 'A' + parser.classes['a'] = klass_a + + parser.enclosure_dependencies['c'] << 'b' + parser.enclosure_dependencies['b'] << 'a' + parser.enclosure_dependencies['d'] << 'a' + + parser.missing_dependencies['d'] = ['d', :class, 'D', 'Object', 'a'] + parser.missing_dependencies['c'] = ['c', :class, 'C', 'Object', 'b'] + parser.missing_dependencies['b'] = ['b', :class, 'B', 'Object', 'a'] + + parser.do_missing + + assert_equal %w[A A::B A::B::C A::D], + @store.all_classes_and_modules.map { |m| m.full_name }.sort + end + + def test_do_missing_cycle + parser = util_parser + + klass_a = @top_level.add_class RDoc::ClassModule, 'A' + parser.classes['a'] = klass_a + + parser.enclosure_dependencies['c'] << 'b' + parser.enclosure_dependencies['b'] << 'a' + + parser.missing_dependencies['c'] = ['c', :class, 'C', 'Object', 'b'] + parser.missing_dependencies['b'] = ['b', :class, 'B', 'Object', 'a'] + + parser.enclosure_dependencies['y'] << 'z' + parser.enclosure_dependencies['z'] << 'y' + + parser.missing_dependencies['y'] = ['y', :class, 'Y', 'Object', 'z'] + parser.missing_dependencies['z'] = ['z', :class, 'Z', 'Object', 'y'] + + _, err = verbose_capture_io do + parser.do_missing + end + + expected = 'Unable to create class Y (y), class Z (z) ' + + 'due to a cyclic class or module creation' + + assert_equal expected, err.chomp + + assert_equal %w[A A::B A::B::C], + @store.all_classes_and_modules.map { |m| m.full_name }.sort + end + + def test_find_alias_comment + parser = util_parser + + comment = parser.find_alias_comment 'C', '[]', 'index' + + assert_equal '', comment.text + + parser = util_parser <<-C +/* + * comment + */ + +rb_define_alias(C, "[]", "index"); + C + + comment = parser.find_alias_comment 'C', '[]', 'index' + + assert_equal "/*\n * comment\n */\n\n", comment.text + end + + def test_find_attr_comment_document_attr + parser= util_parser <<-C +/* + * Document-attr: y + * comment + */ + C + + comment = parser.find_attr_comment nil, 'y' + + assert_equal "/*\n * \n * comment\n */", comment.text + end + + def test_find_attr_comment_document_attr_oneline + parser= util_parser <<-C +/* Document-attr: y + * comment + */ + C + + comment = parser.find_attr_comment nil, 'y' + + assert_equal "/* \n * comment\n */", comment.text + end + + def test_find_attr_comment_document_attr_overlap + parser= util_parser <<-C +/* Document-attr: x + * comment + */ + +/* Document-attr: y + * comment + */ + C + + comment = parser.find_attr_comment nil, 'y' + + assert_equal "/* \n * comment\n */", comment.text + end + + def test_find_class_comment + @options.rdoc_include << File.dirname(__FILE__) + + content = <<-EOF +/* + * Comment 1 + */ +foo = rb_define_class("MyClassName1", rb_cObject); + +/* + * Comment 2 + */ +bar = rb_define_class("MyClassName2", rb_cObject); + EOF + + util_get_class content + + assert_equal "Comment 1", @parser.classes['foo'].comment.text + assert_equal "Comment 2", @parser.classes['bar'].comment.text + end + + def test_find_class_comment_init + content = <<-EOF +/* + * a comment for class Foo + */ +void +Init_Foo(void) { + VALUE foo = rb_define_class("Foo", rb_cObject); +} + EOF + + klass = util_get_class content, 'foo' + + assert_equal "a comment for class Foo", klass.comment.text + end + + def test_find_class_comment_define_class + content = <<-EOF +/* + * a comment for class Foo + */ +VALUE foo = rb_define_class("Foo", rb_cObject); + EOF + + klass = util_get_class content, 'foo' + + assert_equal "a comment for class Foo", klass.comment.text + end + + def test_find_class_comment_define_class_Init_Foo + content = <<-EOF +/* + * a comment for class Foo on Init + */ +void +Init_Foo(void) { + /* + * a comment for class Foo on rb_define_class + */ + VALUE foo = rb_define_class("Foo", rb_cObject); +} + EOF + + klass = util_get_class content, 'foo' + + assert_equal "a comment for class Foo on Init", klass.comment.text + end + + def test_find_class_comment_define_class_Init_Foo_no_void + content = <<-EOF +/* + * a comment for class Foo on Init + */ +void +Init_Foo() { + /* + * a comment for class Foo on rb_define_class + */ + VALUE foo = rb_define_class("Foo", rb_cObject); +} + EOF + + klass = util_get_class content, 'foo' + + assert_equal "a comment for class Foo on Init", klass.comment.text + end + + def test_find_class_comment_define_class_bogus_comment + content = <<-EOF +/* + * a comment for other_function + */ +void +other_function() { +} + +void +Init_Foo(void) { + VALUE foo = rb_define_class("Foo", rb_cObject); +} + EOF + + klass = util_get_class content, 'foo' + + assert_equal '', klass.comment.text + end + + def test_find_class_comment_define_class_under + content = <<-EOF +/* + * a comment for class Foo + */ +VALUE foo = rb_define_class_under(rb_cObject, "Foo", rb_cObject); + EOF + + klass = util_get_class content, 'foo' + + assert_equal "a comment for class Foo", klass.comment.text + end + + def test_find_class_comment_define_class_under_Init + content = <<-EOF +/* + * a comment for class Foo on Init + */ +void +Init_Foo(void) { + /* + * a comment for class Foo on rb_define_class + */ + VALUE foo = rb_define_class_under(rb_cObject, "Foo", rb_cObject); +} + EOF + + klass = util_get_class content, 'foo' + + # the inner comment is used since Object::Foo is not necessarily the same + # thing as "Foo" for Init_ + assert_equal "a comment for class Foo on rb_define_class", + klass.comment.text + end + + def test_find_const_comment_rb_define + content = <<-EOF +/* + * A comment + */ +rb_define_const(cFoo, "CONST", value); + EOF + + parser = util_parser content + + comment = parser.find_const_comment 'const', 'CONST' + + assert_equal "/*\n * A comment\n */\n", comment.text + end + + def test_find_const_comment_document_const + content = <<-EOF +/* + * Document-const: CONST + * + * A comment + */ + EOF + + parser = util_parser content + + comment = parser.find_const_comment nil, 'CONST' + + assert_equal "/*\n *\n * A comment\n */", comment.text + end + + def test_find_const_comment_document_const_full_name + content = <<-EOF +/* + * Document-const: Foo::CONST + * + * A comment + */ + EOF + + parser = util_parser content + + comment = parser.find_const_comment nil, 'CONST', 'Foo' + + assert_equal "/*\n *\n * A comment\n */", comment.text + end + + def test_find_body + content = <<-EOF +/* + * a comment for other_function + */ +VALUE +other_function() { +} + +void +Init_Foo(void) { + VALUE foo = rb_define_class("Foo", rb_cObject); + + rb_define_method(foo, "my_method", other_function, 0); +} + EOF + + klass = util_get_class content, 'foo' + other_function = klass.method_list.first + + assert_equal 'my_method', other_function.name + assert_equal "a comment for other_function", + other_function.comment.text + assert_equal '()', other_function.params + + code = other_function.token_stream.first.text + + assert_equal "VALUE\nother_function() {\n}", code + end + + def test_find_body_2 + content = <<-CONTENT +/* Copyright (C) 2010 Sven Herzberg + * + * This file is free software; the author(s) gives unlimited + * permission to copy and/or distribute it, with or without + * modifications, as long as this notice is preserved. + */ + +#include <ruby.h> + +static VALUE +wrap_initialize (VALUE self) +{ + return self; +} + +/* */ +static VALUE +wrap_shift (VALUE self, + VALUE arg) +{ + return self; +} + +void +init_gi_repository (void) +{ + VALUE mTest = rb_define_module ("Test"); + VALUE cTest = rb_define_class_under (mTest, "Test", rb_cObject); + + rb_define_method (cTest, "initialize", wrap_initialize, 0); + rb_define_method (cTest, "shift", wrap_shift, 0); +} + CONTENT + + klass = util_get_class content, 'cTest' + assert_equal 2, klass.method_list.length + end + + def test_find_body_cast + content = <<-EOF +/* + * a comment for other_function + */ +VALUE +other_function() { +} + +void +Init_Foo(void) { + VALUE foo = rb_define_class("Foo", rb_cObject); + + rb_define_method(foo, "my_method", (METHOD)other_function, 0); +} + EOF + + klass = util_get_class content, 'foo' + other_function = klass.method_list.first + + assert_equal 'my_method', other_function.name + assert_equal "a comment for other_function", + other_function.comment.text + assert_equal '()', other_function.params + + code = other_function.token_stream.first.text + + assert_equal "VALUE\nother_function() {\n}", code + end + + def test_find_body_define + content = <<-EOF +#define something something_else + +#define other_function rb_other_function + +/* + * a comment for rb_other_function + */ +VALUE +rb_other_function() { +} + +void +Init_Foo(void) { + VALUE foo = rb_define_class("Foo", rb_cObject); + + rb_define_method(foo, "my_method", other_function, 0); +} + EOF + + klass = util_get_class content, 'foo' + other_function = klass.method_list.first + + assert_equal 'my_method', other_function.name + assert_equal 'a comment for rb_other_function', other_function.comment.text + assert_equal '()', other_function.params + assert_equal 118, other_function.offset + assert_equal 8, other_function.line + + code = other_function.token_stream.first.text + + assert_equal "VALUE\nrb_other_function() {\n}", code + end + + def test_find_body_define_comment + content = <<-EOF +/* + * a comment for other_function + */ +#define other_function rb_other_function + +/* */ +VALUE +rb_other_function() { +} + +void +Init_Foo(void) { + VALUE foo = rb_define_class("Foo", rb_cObject); + + rb_define_method(foo, "my_method", other_function, 0); +} + EOF + + klass = util_get_class content, 'foo' + other_function = klass.method_list.first + + assert_equal 'my_method', other_function.name + assert_equal 'a comment for other_function', other_function.comment.text + assert_equal '()', other_function.params + assert_equal 39, other_function.offset + assert_equal 4, other_function.line + + code = other_function.token_stream.first.text + + assert_equal "#define other_function rb_other_function", code + end + + def test_find_body_document_method + content = <<-EOF +/* + * Document-method: bar + * Document-method: baz + * + * a comment for bar + */ +VALUE +bar() { +} + +void +Init_Foo(void) { + VALUE foo = rb_define_class("Foo", rb_cObject); + + rb_define_method(foo, "bar", bar, 0); + rb_define_method(foo, "baz", bar, 0); +} + EOF + + klass = util_get_class content, 'foo' + assert_equal 2, klass.method_list.length + + methods = klass.method_list.sort + + bar = methods.first + assert_equal 'Foo#bar', bar.full_name + assert_equal "a comment for bar", bar.comment.text + + baz = methods.last + assert_equal 'Foo#baz', baz.full_name + assert_equal "a comment for bar", baz.comment.text + end + + def test_find_body_document_method_equals + content = <<-EOF +/* + * Document-method: Zlib::GzipFile#mtime= + * + * A comment + */ +static VALUE +rb_gzfile_set_mtime(VALUE obj, VALUE mtime) +{ + +void +Init_zlib() { + mZlib = rb_define_module("Zlib"); + cGzipFile = rb_define_class_under(mZlib, "GzipFile", rb_cObject); + cGzipWriter = rb_define_class_under(mZlib, "GzipWriter", cGzipFile); + rb_define_method(cGzipWriter, "mtime=", rb_gzfile_set_mtime, 1); +} + EOF + + klass = util_get_class content, 'cGzipWriter' + assert_equal 1, klass.method_list.length + + methods = klass.method_list.sort + + bar = methods.first + assert_equal 'Zlib::GzipWriter#mtime=', bar.full_name + assert_equal 'A comment', bar.comment.text + end + + def test_find_body_document_method_same + content = <<-EOF +VALUE +s_bar() { +} + +VALUE +bar() { +} + +/* + * Document-method: Foo::bar + * + * a comment for Foo::bar + */ + +/* + * Document-method: Foo#bar + * + * a comment for Foo#bar + */ + +void +Init_Foo(void) { + VALUE foo = rb_define_class("Foo", rb_cObject); + + rb_define_singleton_method(foo, "bar", s_bar, 0); + rb_define_method(foo, "bar", bar, 0); +} + EOF + + klass = util_get_class content, 'foo' + assert_equal 2, klass.method_list.length + + methods = klass.method_list.sort + + s_bar = methods.first + assert_equal 'Foo::bar', s_bar.full_name + assert_equal "a comment for Foo::bar", s_bar.comment.text + + bar = methods.last + assert_equal 'Foo#bar', bar.full_name + assert_equal "a comment for Foo#bar", bar.comment.text + end + + def test_find_body_macro + content = <<-EOF +/* + * a comment for other_function + */ +DLL_LOCAL VALUE +other_function() { +} + +void +Init_Foo(void) { + VALUE foo = rb_define_class("Foo", rb_cObject); + + rb_define_method(foo, "my_method", other_function, 0); +} + EOF + + klass = util_get_class content, 'foo' + other_function = klass.method_list.first + + assert_equal 'my_method', other_function.name + assert_equal "a comment for other_function", + other_function.comment.text + assert_equal '()', other_function.params + + code = other_function.token_stream.first.text + + assert_equal "DLL_LOCAL VALUE\nother_function() {\n}", code + end + + def test_find_modifiers_call_seq + comment = RDoc::Comment.new <<-COMMENT +call-seq: + commercial() -> Date <br /> + +If no arguments are given: + + COMMENT + + parser = util_parser + method_obj = RDoc::AnyMethod.new nil, 'blah' + + parser.find_modifiers comment, method_obj + + expected = <<-CALL_SEQ.chomp +commercial() -> Date <br /> + + CALL_SEQ + + assert_equal expected, method_obj.call_seq + end + + def test_find_modifiers_nodoc + comment = RDoc::Comment.new <<-COMMENT +/* :nodoc: + * + * Blah + */ + + COMMENT + + parser = util_parser + method_obj = RDoc::AnyMethod.new nil, 'blah' + + parser.find_modifiers comment, method_obj + + assert_equal nil, method_obj.document_self + end + + def test_find_modifiers_yields + comment = RDoc::Comment.new <<-COMMENT +/* :yields: a, b + * + * Blah + */ + + COMMENT + + parser = util_parser + method_obj = RDoc::AnyMethod.new nil, 'blah' + + parser.find_modifiers comment, method_obj + + assert_equal 'a, b', method_obj.block_params + + assert_equal "\n\nBlah", comment.text + end + + def test_handle_method_args_minus_1 + parser = util_parser "Document-method: Object#m\n blah */" + + parser.content = <<-BODY +VALUE +rb_other(VALUE obj) { + rb_funcall(obj, rb_intern("other"), 0); + return rb_str_new2("blah, blah, blah"); +} + +VALUE +rb_m(int argc, VALUE *argv, VALUE obj) { + VALUE o1, o2; + rb_scan_args(argc, argv, "1", &o1, &o2); +} + BODY + + parser.handle_method 'method', 'rb_cObject', 'm', 'rb_m', -1 + + m = @top_level.find_module_named('Object').method_list.first + + assert_equal 'm', m.name + assert_equal @top_level, m.file + assert_equal 115, m.offset + assert_equal 7, m.line + + assert_equal '(p1)', m.params + end + + def test_handle_method_args_0 + parser = util_parser "Document-method: BasicObject#==\n blah */" + + parser.handle_method 'method', 'rb_cBasicObject', '==', 'rb_obj_equal', 0 + + bo = @top_level.find_module_named 'BasicObject' + + assert_equal 1, bo.method_list.length + + equals2 = bo.method_list.first + + assert_equal '()', equals2.params + end + + def test_handle_method_args_1 + parser = util_parser "Document-method: BasicObject#==\n blah */" + + parser.handle_method 'method', 'rb_cBasicObject', '==', 'rb_obj_equal', 1 + + bo = @top_level.find_module_named 'BasicObject' + + assert_equal 1, bo.method_list.length + + equals2 = bo.method_list.first + + assert_equal '(p1)', equals2.params + end + + def test_handle_method_args_2 + parser = util_parser "Document-method: BasicObject#==\n blah */" + + parser.handle_method 'method', 'rb_cBasicObject', '==', 'rb_obj_equal', 2 + + bo = @top_level.find_module_named 'BasicObject' + + assert_equal 1, bo.method_list.length + + equals2 = bo.method_list.first + + assert_equal '(p1, p2)', equals2.params + end + + # test_handle_args_minus_1 handled by test_handle_method + + def test_handle_method_args_minus_2 + parser = util_parser "Document-method: BasicObject#==\n blah */" + + parser.handle_method 'method', 'rb_cBasicObject', '==', 'rb_obj_equal', -2 + + bo = @top_level.find_module_named 'BasicObject' + + assert_equal 1, bo.method_list.length + + equals2 = bo.method_list.first + + assert_equal '(*args)', equals2.params + end + + def test_handle_method_initialize + parser = util_parser "Document-method: BasicObject::new\n blah */" + + parser.handle_method('private_method', 'rb_cBasicObject', + 'initialize', 'rb_obj_dummy', -1) + + bo = @top_level.find_module_named 'BasicObject' + + assert_equal 1, bo.method_list.length + + new = bo.method_list.first + + assert_equal 'new', new.name + assert_equal :public, new.visibility + end + + def test_handle_singleton + parser = util_parser <<-SINGLE +void Init_Blah(void) { + cDate = rb_define_class("Date", rb_cObject); + sDate = rb_singleton_class(cDate); +} + SINGLE + + parser.scan + + assert_equal 'Date', parser.known_classes['sDate'] + assert_equal 'Date', parser.singleton_classes['sDate'] + end + + def test_look_for_directives_in + parser = util_parser + + comment = RDoc::Comment.new "# :other: not_handled\n" + + parser.look_for_directives_in @top_level, comment + + assert_equal "# :other: not_handled\n", comment.text + assert_equal 'not_handled', @top_level.metadata['other'] + end + + def test_load_variable_map + some_ext = @top_level.add_class RDoc::NormalClass, 'SomeExt' + @top_level.add_class RDoc::NormalClass, 'OtherExt' + + @store.cache[:c_class_variables][@fn] = { 'cSomeExt' => 'SomeExt' } + @store.cache[:c_class_variables]['other.c'] = { 'cOtherExt' => 'OtherExt' } + + parser = util_parser + + map = parser.load_variable_map :c_class_variables + + expected = { 'cSomeExt' => some_ext } + + assert_equal expected, map + + assert_equal 'SomeExt', parser.known_classes['cSomeExt'] + assert_nil parser.known_classes['cOtherExt'] + end + + def test_load_variable_map_empty + parser = util_parser + + map = parser.load_variable_map :c_class_variables + + assert_empty map + end + + def test_load_variable_map_legacy + @store.cache[:c_class_variables] = nil + + parser = util_parser + + map = parser.load_variable_map :c_class_variables + + assert_empty map + end + + def test_load_variable_map_singleton + @top_level.add_class RDoc::NormalClass, 'SomeExt' + @top_level.add_class RDoc::NormalClass, 'OtherExt' + + @store.cache[:c_singleton_class_variables][@fn] = + { 'cSomeExt' => 'SomeExt' } + @store.cache[:c_singleton_class_variables]['other.c'] = + { 'cOtherExt' => 'OtherExt' } + + parser = util_parser + + map = parser.load_variable_map :c_singleton_class_variables + + expected = { 'cSomeExt' => 'SomeExt' } + + assert_equal expected, map + + assert_equal 'SomeExt', parser.known_classes['cSomeExt'] + assert_nil parser.known_classes['cOtherExt'] + end + + def test_load_variable_map_trim + a = @top_level.add_class RDoc::NormalClass, 'A' + + @store.cache[:c_class_variables][@fn] = { + 'cA' => 'A', + 'cB' => 'B', + } + + parser = util_parser + + map = parser.load_variable_map :c_class_variables + + expected = { 'cA' => a } + + assert_equal expected, map + end + + def test_define_method + content = <<-EOF +/*Method Comment! */ +static VALUE +rb_io_s_read(argc, argv, io) + int argc; + VALUE *argv; + VALUE io; +{ +} + +void +Init_IO(void) { + /* + * a comment for class Foo on rb_define_class + */ + VALUE rb_cIO = rb_define_class("IO", rb_cObject); + rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1); +} + EOF + + klass = util_get_class content, 'rb_cIO' + read_method = klass.method_list.first + assert_equal "read", read_method.name + assert_equal "Method Comment! ", read_method.comment.text + assert_equal "rb_io_s_read", read_method.c_function + assert read_method.singleton + end + + def test_define_method_with_prototype + content = <<-EOF +static VALUE rb_io_s_read(int, VALUE*, VALUE); + +/* Method Comment! */ +static VALUE +rb_io_s_read(argc, argv, io) + int argc; + VALUE *argv; + VALUE io; +{ +} + +void +Init_IO(void) { + /* + * a comment for class Foo on rb_define_class + */ + VALUE rb_cIO = rb_define_class("IO", rb_cObject); + rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1); +} + EOF + + klass = util_get_class content, 'rb_cIO' + read_method = klass.method_list.first + assert_equal "read", read_method.name + assert_equal "Method Comment! ", read_method.comment.text + assert_equal "rb_io_s_read", read_method.c_function + assert read_method.singleton + end + + def test_define_method_private + content = <<-EOF +/*Method Comment! */ +static VALUE +rb_io_s_read(argc, argv, io) + int argc; + VALUE *argv; + VALUE io; +{ +} + +void +Init_IO(void) { + /* + * a comment for class Foo on rb_define_class + */ + VALUE rb_cIO = rb_define_class("IO", rb_cObject); + rb_define_private_method(rb_cIO, "read", rb_io_s_read, -1); +} + EOF + + klass = util_get_class content, 'rb_cIO' + read_method = klass.method_list.first + assert_equal 'IO#read', read_method.full_name + assert_equal :private, read_method.visibility + assert_equal "Method Comment! ", read_method.comment.text + end + + def test_define_method_private_singleton + content = <<-EOF +/*Method Comment! */ +static VALUE +rb_io_s_read(argc, argv, io) + int argc; + VALUE *argv; + VALUE io; +{ +} + +void +Init_IO(void) { + /* + * a comment for class Foo on rb_define_class + */ + VALUE rb_cIO = rb_define_class("IO", rb_cObject); + VALUE rb_cIO_s = rb_singleton_class(rb_cIO); + rb_define_private_method(rb_cIO_s, "read", rb_io_s_read, -1); +} + EOF + + klass = util_get_class content, 'rb_cIO' + read_method = klass.method_list.first + assert_equal "read", read_method.name + assert_equal "Method Comment! ", read_method.comment.text + assert_equal :private, read_method.visibility + assert read_method.singleton + end + + def test_define_method_singleton + content = <<-EOF +/*Method Comment! */ +static VALUE +rb_io_s_read(argc, argv, io) + int argc; + VALUE *argv; + VALUE io; +{ +} + +void +Init_IO(void) { + /* + * a comment for class Foo on rb_define_class + */ + VALUE rb_cIO = rb_define_class("IO", rb_cObject); + VALUE rb_cIO_s = rb_singleton_class(rb_cIO); + rb_define_method(rb_cIO_s, "read", rb_io_s_read, -1); +} + EOF + + klass = util_get_class content, 'rb_cIO' + read_method = klass.method_list.first + assert_equal "read", read_method.name + assert_equal "Method Comment! ", read_method.comment.text + assert read_method.singleton + end + + def test_rb_scan_args + parser = util_parser + + assert_equal '(p1)', + parser.rb_scan_args('rb_scan_args(a, b, "1",)') + assert_equal '(p1, p2)', + parser.rb_scan_args('rb_scan_args(a, b, "2",)') + + assert_equal '(p1 = v1)', + parser.rb_scan_args('rb_scan_args(a, b, "01",)') + assert_equal '(p1 = v1, p2 = v2)', + parser.rb_scan_args('rb_scan_args(a, b, "02",)') + + assert_equal '(p1, p2 = v2)', + parser.rb_scan_args('rb_scan_args(a, b, "11",)') + + assert_equal '(p1, *args)', + parser.rb_scan_args('rb_scan_args(a, b, "1*",)') + assert_equal '(p1, p2 = {})', + parser.rb_scan_args('rb_scan_args(a, b, "1:",)') + assert_equal '(p1, &block)', + parser.rb_scan_args('rb_scan_args(a, b, "1&",)') + + assert_equal '(p1, p2)', + parser.rb_scan_args('rb_scan_args(a, b, "101",)') + + assert_equal '(p1, p2 = v2, p3)', + parser.rb_scan_args('rb_scan_args(a, b, "111",)') + + assert_equal '(p1, *args, p3)', + parser.rb_scan_args('rb_scan_args(a, b, "1*1",)') + + assert_equal '(p1, p2 = v2, *args)', + parser.rb_scan_args('rb_scan_args(a, b, "11*",)') + assert_equal '(p1, p2 = v2, p3 = {})', + parser.rb_scan_args('rb_scan_args(a, b, "11:",)') + assert_equal '(p1, p2 = v2, &block)', + parser.rb_scan_args('rb_scan_args(a, b, "11&",)') + + assert_equal '(p1, p2 = v2, *args, p4, p5 = {}, &block)', + parser.rb_scan_args('rb_scan_args(a, b, "11*1:&",)') + + # The following aren't valid according to spec but are according to the + # implementation. + assert_equal '(*args)', + parser.rb_scan_args('rb_scan_args(a, b, "*",)') + assert_equal '(p1 = {})', + parser.rb_scan_args('rb_scan_args(a, b, ":",)') + assert_equal '(&block)', + parser.rb_scan_args('rb_scan_args(a, b, "&",)') + + assert_equal '(*args, p2 = {})', + parser.rb_scan_args('rb_scan_args(a, b, "*:",)') + assert_equal '(p1 = {}, &block)', + parser.rb_scan_args('rb_scan_args(a, b, ":&",)') + assert_equal '(*args, p2 = {}, &block)', + parser.rb_scan_args('rb_scan_args(a, b, "*:&",)') + end + + def test_scan + parser = util_parser <<-C +void Init(void) { + mM = rb_define_module("M"); + cC = rb_define_class("C", rb_cObject); + sC = rb_singleton_class(cC); +} + C + + parser.scan + + expected = { + @fn => { + 'mM' => 'M', + 'cC' => 'C', }} + assert_equal expected, @store.c_class_variables + + expected = { + @fn => { + 'sC' => 'C' } } + assert_equal expected, @store.c_singleton_class_variables + end + + def test_scan_method_copy + parser = util_parser <<-C +/* + * call-seq: + * pathname.to_s -> string + * pathname.to_path -> string + * + * Return the path as a String. + * + * to_path is implemented so Pathname objects are usable with File.open, etc. + */ +static VALUE +path_to_s(VALUE self) { } + +/* + * call-seq: + * str[index] -> new_str or nil + * str[start, length] -> new_str or nil + * str.slice(index) -> new_str or nil + * str.slice(start, length) -> new_str or nil + */ +static VALUE +path_aref_m(int argc, VALUE *argv, VALUE str) { } + +/* + * call-seq: + * string <=> other_string -> -1, 0, +1 or nil + */ +static VALUE +path_cmp_m(VALUE str1, VALUE str2) { } + +/* + * call-seq: + * str == obj -> true or false + * str === obj -> true or false + */ +VALUE +rb_str_equal(VALUE str1, VALUE str2) { } + +Init_pathname() +{ + rb_cPathname = rb_define_class("Pathname", rb_cObject); + + rb_define_method(rb_cPathname, "to_s", path_to_s, 0); + rb_define_method(rb_cPathname, "to_path", path_to_s, 0); + rb_define_method(rb_cPathname, "[]", path_aref_m, -1); + rb_define_method(rb_cPathname, "slice", path_aref_m, -1); + rb_define_method(rb_cPathname, "<=>", path_cmp_m, 1); + rb_define_method(rb_cPathname, "==", rb_str_equal), 2); + rb_define_method(rb_cPathname, "===", rb_str_equal), 2); +} + C + + parser.scan + + pathname = @store.classes_hash['Pathname'] + + to_path = pathname.method_list.find { |m| m.name == 'to_path' } + assert_equal "pathname.to_path -> string", to_path.call_seq + + to_s = pathname.method_list.find { |m| m.name == 'to_s' } + assert_equal "pathname.to_s -> string", to_s.call_seq + + index_expected = <<-EXPECTED.chomp +str[index] -> new_str or nil +str[start, length] -> new_str or nil + EXPECTED + + index = pathname.method_list.find { |m| m.name == '[]' } + assert_equal index_expected, index.call_seq, '[]' + + slice_expected = <<-EXPECTED.chomp +str.slice(index) -> new_str or nil +str.slice(start, length) -> new_str or nil + EXPECTED + + slice = pathname.method_list.find { |m| m.name == 'slice' } + assert_equal slice_expected, slice.call_seq + + spaceship = pathname.method_list.find { |m| m.name == '<=>' } + assert_equal "string <=> other_string -> -1, 0, +1 or nil", + spaceship.call_seq + + equals2 = pathname.method_list.find { |m| m.name == '==' } + assert_match 'str == obj', equals2.call_seq + + equals3 = pathname.method_list.find { |m| m.name == '===' } + assert_match 'str === obj', equals3.call_seq + end + + def test_scan_order_dependent + parser = util_parser <<-C +void a(void) { + mA = rb_define_module("A"); +} + +void b(void) { + cB = rb_define_class_under(mA, "B", rb_cObject); +} + +void c(void) { + mC = rb_define_module_under(cB, "C"); +} + +void d(void) { + mD = rb_define_class_under(mC, "D"); +} + C + + parser.scan + + assert_equal %w[A A::B A::B::C], + @store.all_classes_and_modules.map { |m| m.full_name }.sort + end + + def util_get_class content, name = nil + @parser = util_parser content + @parser.scan + + @parser.classes[name] if name + end + + def util_parser content = '' + RDoc::Parser::C.new @top_level, @fn, content, @options, @stats + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_parser_changelog.rb b/jni/ruby/test/rdoc/test_rdoc_parser_changelog.rb new file mode 100644 index 0000000..4d83983 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_parser_changelog.rb @@ -0,0 +1,315 @@ +require 'rdoc/test_case' + +class TestRDocParserChangeLog < RDoc::TestCase + + def setup + super + + @tempfile = Tempfile.new 'ChangeLog' + @top_level = @store.add_file @tempfile.path + @options = RDoc::Options.new + @stats = RDoc::Stats.new @store, 0 + end + + def teardown + @tempfile.close! + end + + def test_class_can_parse + parser = RDoc::Parser::ChangeLog + + temp_dir do + FileUtils.touch 'ChangeLog' + assert_equal parser, parser.can_parse('ChangeLog') + + assert_equal parser, parser.can_parse(@tempfile.path) + + FileUtils.touch 'ChangeLog.rb' + assert_equal RDoc::Parser::Ruby, parser.can_parse('ChangeLog.rb') + end + end + + def test_continue_entry_body + parser = util_parser + + entry_body = ['a'] + + parser.continue_entry_body entry_body, 'b' + + assert_equal ['a b'], entry_body + end + + def test_continue_entry_body_empty + parser = util_parser + + entry_body = [] + + parser.continue_entry_body entry_body, '' + + assert_empty entry_body + end + + def test_continue_entry_body_function + parser = util_parser + + entry_body = ['file: (func1)'] + + parser.continue_entry_body entry_body, '(func2): blah' + + assert_equal ['file: (func1, func2): blah'], entry_body + end + + def test_create_document + parser = util_parser + + groups = { + '2012-12-04' => [ + ['Tue Dec 4 08:33:46 2012 Eric Hodel <drbrain@segment7.net>', + %w[a:one b:two]], + ['Tue Dec 4 08:32:10 2012 Eric Hodel <drbrain@segment7.net>', + %w[c:three d:four]]], + '2012-12-03' => [ + ['Mon Dec 3 20:28:02 2012 Koichi Sasada <ko1@atdot.net>', + %w[e:five f:six]]], + } + + expected = + doc( + head(1, File.basename(@tempfile.path)), + blank_line, + head(2, '2012-12-04'), + blank_line, + head(3, 'Tue Dec 4 08:33:46 2012 Eric Hodel <drbrain@segment7.net>'), + blank_line, + list(:NOTE, item('a', para('one')), item('b', para('two'))), + head(3, 'Tue Dec 4 08:32:10 2012 Eric Hodel <drbrain@segment7.net>'), + blank_line, + list(:NOTE, item('c', para('three')), item('d', para('four'))), + head(2, '2012-12-03'), + blank_line, + head(3, 'Mon Dec 3 20:28:02 2012 Koichi Sasada <ko1@atdot.net>'), + blank_line, + list(:NOTE, item('e', para('five')), item('f', para('six')))) + + expected.file = @top_level + + document = parser.create_document(groups) + + assert_equal expected, document + + assert_equal 2, document.omit_headings_below + + headings = document.parts.select do |part| + RDoc::Markup::Heading === part and part.level == 2 + end + + refute headings.all? { |heading| heading.text.frozen? } + end + + def test_create_entries + parser = util_parser + + entries = [ + ['Tue Dec 1 02:03:04 2012 Eric Hodel <drbrain@segment7.net>', + %w[a:one b:two]], + ['Tue Dec 5 06:07:08 2012 Eric Hodel <drbrain@segment7.net>', + %w[c:three d:four]], + ] + + expected = [ + head(3, 'Tue Dec 1 02:03:04 2012 Eric Hodel <drbrain@segment7.net>'), + blank_line, + list(:NOTE, item('a', para('one')), item('b', para('two'))), + head(3, 'Tue Dec 5 06:07:08 2012 Eric Hodel <drbrain@segment7.net>'), + blank_line, + list(:NOTE, item('c', para('three')), item('d', para('four'))), + ] + + entries = parser.create_entries(entries) + assert_equal expected, entries + end + + def test_create_entries_colons + parser = util_parser + + entries = [ + ['Wed Dec 5 12:17:11 2012 Naohisa Goto <ngotogenome@gmail.com>', + ['func.rb (DL::Function#bind): log stuff [ruby-core:50562]']], + ] + + expected = [ + head(3, + 'Wed Dec 5 12:17:11 2012 Naohisa Goto <ngotogenome@gmail.com>'), + blank_line, + list(:NOTE, + item('func.rb (DL::Function#bind)', + para('log stuff [ruby-core:50562]')))] + + assert_equal expected, parser.create_entries(entries) + end + + def test_create_items + parser = util_parser + + items = [ + 'README.EXT: Converted to RDoc format', + 'README.EXT.ja: ditto', + ] + + expected = + list(:NOTE, + item('README.EXT', + para('Converted to RDoc format')), + item('README.EXT.ja', + para('ditto'))) + + assert_equal expected, parser.create_items(items) + end + + def test_group_entries + parser = util_parser + + entries = [ + [ 'Tue Dec 4 08:33:46 2012 Eric Hodel <drbrain@segment7.net>', + %w[one two]], + [ 'Tue Dec 4 08:32:10 2012 Eric Hodel <drbrain@segment7.net>', + %w[three four]], + [ 'Mon Dec 3 20:28:02 2012 Koichi Sasada <ko1@atdot.net>', + %w[five six]], + [ '2008-01-30 H.J. Lu <hongjiu.lu@intel.com>', + %w[seven eight]]] + + expected = { + '2012-12-04' => [ + ['Tue Dec 4 08:33:46 2012 Eric Hodel <drbrain@segment7.net>', + %w[one two]], + ['Tue Dec 4 08:32:10 2012 Eric Hodel <drbrain@segment7.net>', + %w[three four]]], + '2012-12-03' => [ + ['Mon Dec 3 20:28:02 2012 Koichi Sasada <ko1@atdot.net>', + %w[five six]]], + '2008-01-30' => [ + ['2008-01-30 H.J. Lu <hongjiu.lu@intel.com>', + %w[seven eight]]], + } + + assert_equal expected, parser.group_entries(entries) + end + + def test_parse_entries + parser = util_parser <<-ChangeLog +Tue Dec 4 08:33:46 2012 Eric Hodel <drbrain@segment7.net> + + * README.EXT: Converted to RDoc format + * README.EXT.ja: ditto + +Mon Dec 3 20:28:02 2012 Koichi Sasada <ko1@atdot.net> + + * compile.c (iseq_specialized_instruction): + change condition of using `opt_send_simple'. + More method invocations can be simple. + +Other note that will be ignored + + ChangeLog + + expected = [ + [ 'Tue Dec 4 08:33:46 2012 Eric Hodel <drbrain@segment7.net>', + [ 'README.EXT: Converted to RDoc format', + 'README.EXT.ja: ditto']], + [ 'Mon Dec 3 20:28:02 2012 Koichi Sasada <ko1@atdot.net>', + [ 'compile.c (iseq_specialized_instruction): change condition of ' + + 'using `opt_send_simple\'. More method invocations can be simple.']]] + + assert_equal expected, parser.parse_entries + end + + def test_parse_entries_bad_time + parser = util_parser <<-ChangeLog +2008-01-30 H.J. Lu <hongjiu.lu@intel.com> + + PR libffi/34612 + * src/x86/sysv.S (ffi_closure_SYSV): Pop 4 byte from stack when + returning struct. + + ChangeLog + + expected = [ + [ '2008-01-30 H.J. Lu <hongjiu.lu@intel.com>', + [ 'src/x86/sysv.S (ffi_closure_SYSV): Pop 4 byte from stack when ' + + 'returning struct.']] + ] + + assert_equal expected, parser.parse_entries + end + + def test_parse_entries_gnu + parser = util_parser <<-ChangeLog +1998-08-17 Richard Stallman <rms@gnu.org> + +* register.el (insert-register): Return nil. +(jump-to-register): Likewise. + +* sort.el (sort-subr): Return nil. + +* keyboard.c (menu_bar_items, tool_bar_items) +(Fexecute_extended_command): Deal with 'keymap' property. + ChangeLog + + expected = [ + [ '1998-08-17 Richard Stallman <rms@gnu.org>', + [ 'register.el (insert-register): Return nil.', + '(jump-to-register): Likewise.', + 'sort.el (sort-subr): Return nil.', + 'keyboard.c (menu_bar_items, tool_bar_items, ' + + 'Fexecute_extended_command): Deal with \'keymap\' property.']]] + + assert_equal expected, parser.parse_entries + end + + def test_scan + parser = util_parser <<-ChangeLog +Tue Dec 4 08:32:10 2012 Eric Hodel <drbrain@segment7.net> + + * lib/rdoc/ri/driver.rb: Fixed ri page display for files with + extensions. + * test/rdoc/test_rdoc_ri_driver.rb: Test for above + +Mon Dec 3 20:37:22 2012 Koichi Sasada <ko1@atdot.net> + + * vm_exec.c: check VM_COLLECT_USAGE_DETAILS. + + ChangeLog + + parser.scan + + expected = doc( + head(1, File.basename(@tempfile.path)), + blank_line, + head(2, '2012-12-04'), + blank_line, + head(3, 'Tue Dec 4 08:32:10 2012 Eric Hodel <drbrain@segment7.net>'), + blank_line, + list(:NOTE, + item('lib/rdoc/ri/driver.rb', para('Fixed ri page display for ' + + 'files with extensions.')), + item('test/rdoc/test_rdoc_ri_driver.rb', para('Test for above'))), + head(2, '2012-12-03'), + blank_line, + head(3, 'Mon Dec 3 20:37:22 2012 Koichi Sasada <ko1@atdot.net>'), + blank_line, + list(:NOTE, + item('vm_exec.c', para('check VM_COLLECT_USAGE_DETAILS.')))) + + expected.file = @top_level + + assert_equal expected, @top_level.comment + end + + def util_parser content = '' + RDoc::Parser::ChangeLog.new \ + @top_level, @tempfile.path, content, @options, @stats + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_parser_markdown.rb b/jni/ruby/test/rdoc/test_rdoc_parser_markdown.rb new file mode 100644 index 0000000..b17e144 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_parser_markdown.rb @@ -0,0 +1,61 @@ +require 'rdoc/test_case' + +class TestRDocParserMarkdown < RDoc::TestCase + + def setup + super + + @RP = RDoc::Parser + + @tempfile = Tempfile.new self.class.name + filename = @tempfile.path + + @top_level = @store.add_file filename + @fn = filename + @options = RDoc::Options.new + @stats = RDoc::Stats.new @store, 0 + end + + def teardown + super + + @tempfile.close! + end + + def test_file + assert_kind_of RDoc::Parser::Text, util_parser('') + end + + def test_class_can_parse + temp_dir do + FileUtils.touch 'foo.md' + assert_equal @RP::Markdown, @RP.can_parse('foo.md') + FileUtils.touch 'foo.md.ja' + assert_equal @RP::Markdown, @RP.can_parse('foo.md.ja') + + FileUtils.touch 'foo.markdown' + assert_equal @RP::Markdown, @RP.can_parse('foo.markdown') + FileUtils.touch 'foo.markdown.ja' + assert_equal @RP::Markdown, @RP.can_parse('foo.markdown.ja') + end + end + + def test_scan + parser = util_parser 'it *really* works' + + expected = + @RM::Document.new( + @RM::Paragraph.new('it _really_ works')) + expected.file = @top_level + + parser.scan + + assert_equal expected, @top_level.comment.parse + end + + def util_parser content + RDoc::Parser::Markdown.new @top_level, @fn, content, @options, @stats + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_parser_rd.rb b/jni/ruby/test/rdoc/test_rdoc_parser_rd.rb new file mode 100644 index 0000000..9be0d7d --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_parser_rd.rb @@ -0,0 +1,55 @@ +require 'rdoc/test_case' + +class TestRDocParserRd < RDoc::TestCase + + def setup + super + + @RP = RDoc::Parser + + @tempfile = Tempfile.new self.class.name + filename = @tempfile.path + + @top_level = @store.add_file filename + @fn = filename + @options = RDoc::Options.new + @stats = RDoc::Stats.new @store, 0 + end + + def teardown + super + + @tempfile.close! + end + + def test_file + assert_kind_of RDoc::Parser::Text, util_parser('') + end + + def test_class_can_parse + temp_dir do + FileUtils.touch 'foo.rd' + assert_equal @RP::RD, @RP.can_parse('foo.rd') + + FileUtils.touch 'foo.rd.ja' + assert_equal @RP::RD, @RP.can_parse('foo.rd.ja') + end + end + + def test_scan + parser = util_parser 'it ((*really*)) works' + + expected = doc(para('it <em>really</em> works')) + expected.file = @top_level + + parser.scan + + assert_equal expected, @top_level.comment.parse + end + + def util_parser content + RDoc::Parser::RD.new @top_level, @fn, content, @options, @stats + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_parser_ruby.rb b/jni/ruby/test/rdoc/test_rdoc_parser_ruby.rb new file mode 100644 index 0000000..8750433 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_parser_ruby.rb @@ -0,0 +1,3322 @@ +# coding: utf-8 + +require 'rdoc/test_case' + +class TestRDocParserRuby < RDoc::TestCase + + def setup + super + + @tempfile = Tempfile.new self.class.name + @filename = @tempfile.path + + # Some tests need two paths. + @tempfile2 = Tempfile.new self.class.name + @filename2 = @tempfile2.path + + @top_level = @store.add_file @filename + @top_level2 = @store.add_file @filename2 + + @options = RDoc::Options.new + @options.quiet = true + @options.option_parser = OptionParser.new + + @comment = RDoc::Comment.new '', @top_level + + @stats = RDoc::Stats.new @store, 0 + end + + def teardown + super + + @tempfile.close! + @tempfile2.close! + end + + def test_collect_first_comment + p = util_parser <<-CONTENT +# first + +# second +class C; end + CONTENT + + comment = p.collect_first_comment + + assert_equal RDoc::Comment.new("# first\n", @top_level), comment + end + + def test_collect_first_comment_encoding + skip "Encoding not implemented" unless Object.const_defined? :Encoding + + @options.encoding = Encoding::CP852 + + p = util_parser <<-CONTENT +# first + +# second +class C; end + CONTENT + + comment = p.collect_first_comment + + assert_equal Encoding::CP852, comment.text.encoding + end + + def test_collect_first_comment_rd_hash + parser = util_parser <<-CONTENT +=begin +first +=end + +# second +class C; end + CONTENT + + comment = parser.collect_first_comment + + assert_equal RDoc::Comment.new("first\n\n", @top_level), comment + end + + def test_get_class_or_module + ctxt = RDoc::Context.new + ctxt.store = @store + + cont, name_t, given_name = util_parser('A') .get_class_or_module ctxt + + assert_equal ctxt, cont + assert_equal 'A', name_t.text + assert_equal 'A', given_name + + cont, name_t, given_name = util_parser('B::C') .get_class_or_module ctxt + + b = @store.find_module_named('B') + assert_equal b, cont + assert_equal [@top_level], b.in_files + assert_equal 'C', name_t.text + assert_equal 'B::C', given_name + + cont, name_t, given_name = util_parser('D:: E').get_class_or_module ctxt + + assert_equal @store.find_module_named('D'), cont + assert_equal 'E', name_t.text + assert_equal 'D::E', given_name + + assert_raises NoMethodError do + util_parser("A::\nB").get_class_or_module ctxt + end + end + + def test_get_class_or_module_document_children + ctxt = @top_level.add_class RDoc::NormalClass, 'A' + ctxt.stop_doc + + util_parser('B::C').get_class_or_module ctxt + + b = @store.find_module_named('A::B') + assert b.ignored? + + d = @top_level.add_class RDoc::NormalClass, 'A::D' + + util_parser('D::E').get_class_or_module ctxt + + refute d.ignored? + end + + def test_get_class_or_module_ignore_constants + ctxt = RDoc::Context.new + ctxt.store = @store + + util_parser('A') .get_class_or_module ctxt, true + util_parser('A::B').get_class_or_module ctxt, true + + assert_empty ctxt.constants + assert_empty @store.modules_hash.keys + assert_empty @store.classes_hash.keys + end + + def test_get_class_specification + assert_equal 'A', util_parser('A') .get_class_specification + assert_equal 'A::B', util_parser('A::B').get_class_specification + assert_equal '::A', util_parser('::A').get_class_specification + + assert_equal 'self', util_parser('self').get_class_specification + + assert_equal '', util_parser('').get_class_specification + + assert_equal '', util_parser('$g').get_class_specification + end + + def test_get_symbol_or_name + util_parser "* & | + 5 / 4" + + assert_equal '*', @parser.get_symbol_or_name + + @parser.skip_tkspace + + assert_equal '&', @parser.get_symbol_or_name + + @parser.skip_tkspace + + assert_equal '|', @parser.get_symbol_or_name + + @parser.skip_tkspace + + assert_equal '+', @parser.get_symbol_or_name + + @parser.skip_tkspace + @parser.get_tk + @parser.skip_tkspace + + assert_equal '/', @parser.get_symbol_or_name + end + + def test_suppress_parents + a = @top_level.add_class RDoc::NormalClass, 'A' + b = a.add_class RDoc::NormalClass, 'B' + c = b.add_class RDoc::NormalClass, 'C' + + util_parser '' + + @parser.suppress_parents c, a + + assert c.suppressed? + assert b.suppressed? + refute a.suppressed? + end + + def test_suppress_parents_documented + a = @top_level.add_class RDoc::NormalClass, 'A' + b = a.add_class RDoc::NormalClass, 'B' + b.add_comment RDoc::Comment.new("hello"), @top_level + c = b.add_class RDoc::NormalClass, 'C' + + util_parser '' + + @parser.suppress_parents c, a + + assert c.suppressed? + refute b.suppressed? + refute a.suppressed? + end + + def test_look_for_directives_in_attr + util_parser "" + + comment = RDoc::Comment.new "# :attr: my_attr\n", @top_level + + @parser.look_for_directives_in @top_level, comment + + assert_equal "# :attr: my_attr\n", comment.text + + comment = RDoc::Comment.new "# :attr_reader: my_method\n", @top_level + + @parser.look_for_directives_in @top_level, comment + + assert_equal "# :attr_reader: my_method\n", comment.text + + comment = RDoc::Comment.new "# :attr_writer: my_method\n", @top_level + + @parser.look_for_directives_in @top_level, comment + + assert_equal "# :attr_writer: my_method\n", comment.text + end + + def test_look_for_directives_in_commented + util_parser "" + + comment = RDoc::Comment.new <<-COMMENT, @top_level +# how to make a section: +# # :section: new section + COMMENT + + @parser.look_for_directives_in @top_level, comment + + section = @top_level.current_section + assert_equal nil, section.title + assert_equal nil, section.comment + + assert_equal "# how to make a section:\n# # :section: new section\n", + comment.text + end + + def test_look_for_directives_in_method + util_parser "" + + comment = RDoc::Comment.new "# :method: my_method\n", @top_level + + @parser.look_for_directives_in @top_level, comment + + assert_equal "# :method: my_method\n", comment.text + + comment = RDoc::Comment.new "# :singleton-method: my_method\n", @top_level + + @parser.look_for_directives_in @top_level, comment + + assert_equal "# :singleton-method: my_method\n", comment.text + end + + def test_look_for_directives_in_section + util_parser "" + + comment = RDoc::Comment.new <<-COMMENT, @top_level +# :section: new section +# woo stuff + COMMENT + + @parser.look_for_directives_in @top_level, comment + + section = @top_level.current_section + assert_equal 'new section', section.title + assert_equal [comment("# woo stuff\n", @top_level)], section.comments + + assert_empty comment + end + + def test_look_for_directives_in_unhandled + util_parser "" + + comment = RDoc::Comment.new "# :unhandled: blah\n", @top_level + + @parser.look_for_directives_in @top_level, comment + + assert_equal 'blah', @top_level.metadata['unhandled'] + end + + def test_parse_alias + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + util_parser "alias :next= :bar" + + tk = @parser.get_tk + + alas = @parser.parse_alias klass, RDoc::Parser::Ruby::NORMAL, tk, 'comment' + + assert_equal 'bar', alas.old_name + assert_equal 'next=', alas.new_name + assert_equal klass, alas.parent + assert_equal 'comment', alas.comment + assert_equal @top_level, alas.file + assert_equal 0, alas.offset + assert_equal 1, alas.line + end + + def test_parse_alias_singleton + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + util_parser "alias :next= :bar" + + tk = @parser.get_tk + + alas = @parser.parse_alias klass, RDoc::Parser::Ruby::SINGLE, tk, 'comment' + + assert_equal 'bar', alas.old_name + assert_equal 'next=', alas.new_name + assert_equal klass, alas.parent + assert_equal 'comment', alas.comment + assert_equal @top_level, alas.file + assert alas.singleton + end + + def test_parse_alias_stopdoc + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + klass.stop_doc + + util_parser "alias :next= :bar" + + tk = @parser.get_tk + + @parser.parse_alias klass, RDoc::Parser::Ruby::NORMAL, tk, 'comment' + + assert_empty klass.aliases + assert_empty klass.unmatched_alias_lists + end + + def test_parse_alias_meta + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + util_parser "alias m.chop m" + + tk = @parser.get_tk + + alas = @parser.parse_alias klass, RDoc::Parser::Ruby::NORMAL, tk, 'comment' + + assert_nil alas + end + + def test_parse_attr + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + comment = RDoc::Comment.new "##\n# my attr\n", @top_level + + util_parser "attr :foo, :bar" + + tk = @parser.get_tk + + @parser.parse_attr klass, RDoc::Parser::Ruby::NORMAL, tk, comment + + assert_equal 1, klass.attributes.length + + foo = klass.attributes.first + assert_equal 'foo', foo.name + assert_equal 'my attr', foo.comment.text + assert_equal @top_level, foo.file + assert_equal 0, foo.offset + assert_equal 1, foo.line + end + + def test_parse_attr_stopdoc + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + klass.stop_doc + + comment = RDoc::Comment.new "##\n# my attr\n", @top_level + + util_parser "attr :foo, :bar" + + tk = @parser.get_tk + + @parser.parse_attr klass, RDoc::Parser::Ruby::NORMAL, tk, comment + + assert_empty klass.attributes + end + + def test_parse_attr_accessor + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + comment = RDoc::Comment.new "##\n# my attr\n", @top_level + + util_parser "attr_accessor :foo, :bar" + + tk = @parser.get_tk + + @parser.parse_attr_accessor klass, RDoc::Parser::Ruby::NORMAL, tk, comment + + assert_equal 2, klass.attributes.length + + foo = klass.attributes.first + assert_equal 'foo', foo.name + assert_equal 'RW', foo.rw + assert_equal 'my attr', foo.comment.text + assert_equal @top_level, foo.file + assert_equal 0, foo.offset + assert_equal 1, foo.line + + bar = klass.attributes.last + assert_equal 'bar', bar.name + assert_equal 'RW', bar.rw + assert_equal 'my attr', bar.comment.text + end + + def test_parse_attr_accessor_nodoc + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + comment = RDoc::Comment.new "##\n# my attr\n", @top_level + + util_parser "attr_accessor :foo, :bar # :nodoc:" + + tk = @parser.get_tk + + @parser.parse_attr_accessor klass, RDoc::Parser::Ruby::NORMAL, tk, comment + + assert_equal 0, klass.attributes.length + end + + def test_parse_attr_accessor_nodoc_track + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + comment = RDoc::Comment.new "##\n# my attr\n", @top_level + + @options.visibility = :nodoc + + util_parser "attr_accessor :foo, :bar # :nodoc:" + + tk = @parser.get_tk + + @parser.parse_attr_accessor klass, RDoc::Parser::Ruby::NORMAL, tk, comment + + refute_empty klass.attributes + end + + def test_parse_attr_accessor_stopdoc + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + klass.stop_doc + + comment = RDoc::Comment.new "##\n# my attr\n", @top_level + + util_parser "attr_accessor :foo, :bar" + + tk = @parser.get_tk + + @parser.parse_attr_accessor klass, RDoc::Parser::Ruby::NORMAL, tk, comment + + assert_empty klass.attributes + end + + def test_parse_attr_accessor_writer + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + comment = RDoc::Comment.new "##\n# my attr\n", @top_level + + util_parser "attr_writer :foo, :bar" + + tk = @parser.get_tk + + @parser.parse_attr_accessor klass, RDoc::Parser::Ruby::NORMAL, tk, comment + + assert_equal 2, klass.attributes.length + + foo = klass.attributes.first + assert_equal 'foo', foo.name + assert_equal 'W', foo.rw + assert_equal "my attr", foo.comment.text + assert_equal @top_level, foo.file + + bar = klass.attributes.last + assert_equal 'bar', bar.name + assert_equal 'W', bar.rw + assert_equal "my attr", bar.comment.text + end + + def test_parse_meta_attr + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + comment = RDoc::Comment.new "##\n# :attr: \n# my method\n", @top_level + + util_parser "add_my_method :foo, :bar" + + tk = @parser.get_tk + + @parser.parse_meta_attr klass, RDoc::Parser::Ruby::NORMAL, tk, comment + + assert_equal 2, klass.attributes.length + foo = klass.attributes.first + assert_equal 'foo', foo.name + assert_equal 'RW', foo.rw + assert_equal "my method", foo.comment.text + assert_equal @top_level, foo.file + end + + def test_parse_meta_attr_accessor + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + comment = + RDoc::Comment.new "##\n# :attr_accessor: \n# my method\n", @top_level + + util_parser "add_my_method :foo, :bar" + + tk = @parser.get_tk + + @parser.parse_meta_attr klass, RDoc::Parser::Ruby::NORMAL, tk, comment + + assert_equal 2, klass.attributes.length + foo = klass.attributes.first + assert_equal 'foo', foo.name + assert_equal 'RW', foo.rw + assert_equal 'my method', foo.comment.text + assert_equal @top_level, foo.file + end + + def test_parse_meta_attr_named + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + comment = RDoc::Comment.new "##\n# :attr: foo\n# my method\n", @top_level + + util_parser "add_my_method :foo, :bar" + + tk = @parser.get_tk + + @parser.parse_meta_attr klass, RDoc::Parser::Ruby::NORMAL, tk, comment + + assert_equal 1, klass.attributes.length + foo = klass.attributes.first + assert_equal 'foo', foo.name + assert_equal 'RW', foo.rw + assert_equal 'my method', foo.comment.text + assert_equal @top_level, foo.file + end + + def test_parse_meta_attr_reader + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + comment = + RDoc::Comment.new "##\n# :attr_reader: \n# my method\n", @top_level + + util_parser "add_my_method :foo, :bar" + + tk = @parser.get_tk + + @parser.parse_meta_attr klass, RDoc::Parser::Ruby::NORMAL, tk, comment + + foo = klass.attributes.first + assert_equal 'foo', foo.name + assert_equal 'R', foo.rw + assert_equal 'my method', foo.comment.text + assert_equal @top_level, foo.file + end + + def test_parse_meta_attr_stopdoc + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + klass.stop_doc + + comment = RDoc::Comment.new "##\n# :attr: \n# my method\n", @top_level + + util_parser "add_my_method :foo, :bar" + + tk = @parser.get_tk + + @parser.parse_meta_attr klass, RDoc::Parser::Ruby::NORMAL, tk, comment + + assert_empty klass.attributes + end + + def test_parse_meta_attr_writer + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + comment = + RDoc::Comment.new "##\n# :attr_writer: \n# my method\n", @top_level + + util_parser "add_my_method :foo, :bar" + + tk = @parser.get_tk + + @parser.parse_meta_attr klass, RDoc::Parser::Ruby::NORMAL, tk, comment + + foo = klass.attributes.first + assert_equal 'foo', foo.name + assert_equal 'W', foo.rw + assert_equal "my method", foo.comment.text + assert_equal @top_level, foo.file + end + + def test_parse_class + comment = RDoc::Comment.new "##\n# my class\n", @top_level + + util_parser "class Foo\nend" + + tk = @parser.get_tk + + @parser.parse_class @top_level, RDoc::Parser::Ruby::NORMAL, tk, comment + + foo = @top_level.classes.first + assert_equal 'Foo', foo.full_name + assert_equal 'my class', foo.comment.text + assert_equal [@top_level], foo.in_files + assert_equal 0, foo.offset + assert_equal 1, foo.line + end + + def test_parse_class_singleton + comment = RDoc::Comment.new "##\n# my class\n", @top_level + + util_parser <<-RUBY +class C + class << self + end +end + RUBY + + tk = @parser.get_tk + + @parser.parse_class @top_level, RDoc::Parser::Ruby::NORMAL, tk, comment + + c = @top_level.classes.first + assert_equal 'C', c.full_name + assert_equal 0, c.offset + assert_equal 1, c.line + end + + def test_parse_class_ghost_method + util_parser <<-CLASS +class Foo + ## + # :method: blah + # my method +end + CLASS + + tk = @parser.get_tk + + @parser.parse_class @top_level, RDoc::Parser::Ruby::NORMAL, tk, @comment + + foo = @top_level.classes.first + assert_equal 'Foo', foo.full_name + + blah = foo.method_list.first + assert_equal 'Foo#blah', blah.full_name + assert_equal @top_level, blah.file + end + + def test_parse_class_ghost_method_yields + util_parser <<-CLASS +class Foo + ## + # :method: + # :call-seq: + # yields(name) +end + CLASS + + tk = @parser.get_tk + + @parser.parse_class @top_level, RDoc::Parser::Ruby::NORMAL, tk, @comment + + foo = @top_level.classes.first + assert_equal 'Foo', foo.full_name + + blah = foo.method_list.first + assert_equal 'Foo#yields', blah.full_name + assert_equal 'yields(name)', blah.call_seq + assert_equal @top_level, blah.file + end + + def test_parse_class_multi_ghost_methods + util_parser <<-'CLASS' +class Foo + ## + # :method: one + # + # my method + + ## + # :method: two + # + # my method + + [:one, :two].each do |t| + eval("def #{t}; \"#{t}\"; end") + end +end + CLASS + + tk = @parser.get_tk + + @parser.parse_class @top_level, RDoc::Parser::Ruby::NORMAL, tk, @comment + + foo = @top_level.classes.first + assert_equal 'Foo', foo.full_name + + assert_equal 2, foo.method_list.length + end + + def test_parse_class_nodoc + comment = RDoc::Comment.new "##\n# my class\n", @top_level + + util_parser "class Foo # :nodoc:\nend" + + tk = @parser.get_tk + + @parser.parse_class @top_level, RDoc::Parser::Ruby::NORMAL, tk, comment + + foo = @top_level.classes.first + assert_equal 'Foo', foo.full_name + assert_empty foo.comment + assert_equal [@top_level], foo.in_files + assert_equal 0, foo.offset + assert_equal 1, foo.line + end + + def test_parse_class_single_root + comment = RDoc::Comment.new "##\n# my class\n", @top_level + + util_parser "class << ::Foo\nend" + + tk = @parser.get_tk + + @parser.parse_class @top_level, RDoc::Parser::Ruby::NORMAL, tk, comment + + foo = @store.all_modules.first + assert_equal 'Foo', foo.full_name + end + + def test_parse_class_stopdoc + @top_level.stop_doc + + comment = RDoc::Comment.new "##\n# my class\n", @top_level + + util_parser "class Foo\nend" + + tk = @parser.get_tk + + @parser.parse_class @top_level, RDoc::Parser::Ruby::NORMAL, tk, comment + + assert_empty @top_level.classes.first.comment + end + + def test_parse_multi_ghost_methods + util_parser <<-'CLASS' +class Foo + ## + # :method: one + # + # my method + + ## + # :method: two + # + # my method + + [:one, :two].each do |t| + eval("def #{t}; \"#{t}\"; end") + end +end + CLASS + + tk = @parser.get_tk + + @parser.parse_class @top_level, RDoc::Parser::Ruby::NORMAL, tk, @comment + + foo = @top_level.classes.first + assert_equal 'Foo', foo.full_name + + assert_equal 2, foo.method_list.length + end + + def test_parse_const_fail_w_meta + util_parser <<-CLASS +class ConstFailMeta + ## + # :attr: one + # + # an attribute + + OtherModule.define_attr(self, :one) +end + CLASS + + tk = @parser.get_tk + + @parser.parse_class @top_level, RDoc::Parser::Ruby::NORMAL, tk, @comment + + const_fail_meta = @top_level.classes.first + assert_equal 'ConstFailMeta', const_fail_meta.full_name + + assert_equal 1, const_fail_meta.attributes.length + end + + def test_parse_class_nested_superclass + foo = @top_level.add_module RDoc::NormalModule, 'Foo' + + util_parser "class Bar < Super\nend" + + tk = @parser.get_tk + + @parser.parse_class foo, RDoc::Parser::Ruby::NORMAL, tk, @comment + + bar = foo.classes.first + assert_equal 'Super', bar.superclass + end + + def test_parse_module + comment = RDoc::Comment.new "##\n# my module\n", @top_level + + util_parser "module Foo\nend" + + tk = @parser.get_tk + + @parser.parse_module @top_level, RDoc::Parser::Ruby::NORMAL, tk, comment + + foo = @top_level.modules.first + assert_equal 'Foo', foo.full_name + assert_equal 'my module', foo.comment.text + end + + def test_parse_module_nodoc + @top_level.stop_doc + + comment = RDoc::Comment.new "##\n# my module\n", @top_level + + util_parser "module Foo # :nodoc:\nend" + + tk = @parser.get_tk + + @parser.parse_module @top_level, RDoc::Parser::Ruby::NORMAL, tk, comment + + foo = @top_level.modules.first + assert_equal 'Foo', foo.full_name + assert_empty foo.comment + end + + def test_parse_module_stopdoc + @top_level.stop_doc + + comment = RDoc::Comment.new "##\n# my module\n", @top_level + + util_parser "module Foo\nend" + + tk = @parser.get_tk + + @parser.parse_module @top_level, RDoc::Parser::Ruby::NORMAL, tk, comment + + foo = @top_level.modules.first + assert_equal 'Foo', foo.full_name + assert_empty foo.comment + end + + def test_parse_class_colon3 + code = <<-CODE +class A + class ::B + end +end + CODE + + util_parser code + + @parser.parse_class @top_level, false, @parser.get_tk, @comment + + assert_equal %w[A B], @store.all_classes.map { |c| c.full_name }.sort + end + + def test_parse_class_colon3_self_reference + code = <<-CODE +class A::B + class ::A + end +end + CODE + + util_parser code + + @parser.parse_class @top_level, false, @parser.get_tk, @comment + + assert_equal %w[A A::B], @store.all_classes.map { |c| c.full_name }.sort + end + + def test_parse_class_single + code = <<-CODE +class A + class << B + end + class << d = Object.new + def foo; end + alias bar foo + end +end + CODE + + util_parser code + + @parser.parse_class @top_level, false, @parser.get_tk, @comment + + assert_equal %w[A], @store.all_classes.map { |c| c.full_name } + + modules = @store.all_modules.sort_by { |c| c.full_name } + assert_equal %w[A::B A::d], modules.map { |c| c.full_name } + + b = modules.first + assert_equal 10, b.offset + assert_equal 2, b.line + + # make sure method/alias was not added to enclosing class/module + a = @store.classes_hash['A'] + assert_empty a.method_list + + # make sure non-constant-named module will be removed from documentation + d = @store.modules_hash['A::d'] + assert d.remove_from_documentation? + end + + def test_parse_class_single_gvar + code = <<-CODE +class << $g + def m + end +end + CODE + + util_parser code + + @parser.parse_class @top_level, false, @parser.get_tk, '' + + assert_empty @store.all_classes + mod = @store.all_modules.first + + refute mod.document_self + + assert_empty mod.method_list + end + + # TODO this is really a Context#add_class test + def test_parse_class_object + code = <<-CODE +module A + class B + end + class Object + end + class C < Object + end +end + CODE + + util_parser code + + @parser.parse_module @top_level, false, @parser.get_tk, @comment + + assert_equal %w[A], + @store.all_modules.map { |c| c.full_name } + assert_equal %w[A::B A::C A::Object], + @store.all_classes.map { |c| c.full_name }.sort + + assert_equal 'Object', @store.classes_hash['A::B'].superclass + assert_equal 'Object', @store.classes_hash['A::Object'].superclass + assert_equal 'A::Object', @store.classes_hash['A::C'].superclass.full_name + end + + def test_parse_class_mistaken_for_module + # The code below is not strictly legal Ruby (Foo must have been defined + # before Foo::Bar is encountered), but RDoc might encounter Foo::Bar + # before Foo if they live in different files. + + code = <<-RUBY +class Foo::Bar +end + +module Foo::Baz +end + +class Foo +end + RUBY + + util_parser code + + @parser.scan + + assert_equal %w[Foo::Baz], @store.modules_hash.keys + assert_empty @top_level.modules + + foo = @top_level.classes.first + assert_equal 'Foo', foo.full_name + + bar = foo.classes.first + assert_equal 'Foo::Bar', bar.full_name + + baz = foo.modules.first + assert_equal 'Foo::Baz', baz.full_name + end + + def test_parse_class_definition_encountered_after_class_reference + # The code below is not legal Ruby (Foo must have been defined before + # Foo.bar is encountered), but RDoc might encounter Foo.bar before Foo if + # they live in different files. + + code = <<-EOF +def Foo.bar +end + +class Foo < IO +end + EOF + + util_parser code + + @parser.scan + + assert_empty @store.modules_hash + assert_empty @store.all_modules + + foo = @top_level.classes.first + assert_equal 'Foo', foo.full_name + assert_equal 'IO', foo.superclass + + bar = foo.method_list.first + assert_equal 'bar', bar.name + end + + def test_parse_module_relative_to_top_level_namespace + comment = RDoc::Comment.new <<-EOF, @top_level +# +# Weirdly named module +# +EOF + + code = <<-EOF +#{comment.text} +module ::Foo + class Helper + end +end +EOF + + util_parser code + @parser.scan() + + foo = @top_level.modules.first + assert_equal 'Foo', foo.full_name + assert_equal 'Weirdly named module', foo.comment.text + + helper = foo.classes.first + assert_equal 'Foo::Helper', helper.full_name + end + + def test_parse_comment_attr + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + comment = RDoc::Comment.new "##\n# :attr: foo\n# my attr\n", @top_level + + util_parser "\n" + + tk = @parser.get_tk + + @parser.parse_comment klass, tk, comment + + foo = klass.attributes.first + assert_equal 'foo', foo.name + assert_equal 'RW', foo.rw + assert_equal 'my attr', foo.comment.text + assert_equal @top_level, foo.file + assert_equal 0, foo.offset + assert_equal 1, foo.line + + assert_equal nil, foo.viewer + assert_equal true, foo.document_children + assert_equal true, foo.document_self + assert_equal false, foo.done_documenting + assert_equal false, foo.force_documentation + assert_equal klass, foo.parent + assert_equal :public, foo.visibility + assert_equal "\n", foo.text + + assert_equal klass.current_section, foo.section + end + + def test_parse_comment_attr_attr_reader + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + comment = RDoc::Comment.new "##\n# :attr_reader: foo\n", @top_level + + util_parser "\n" + + tk = @parser.get_tk + + @parser.parse_comment klass, tk, comment + + foo = klass.attributes.first + assert_equal 'foo', foo.name + assert_equal 'R', foo.rw + end + + def test_parse_comment_attr_stopdoc + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + klass.stop_doc + + comment = RDoc::Comment.new "##\n# :attr: foo\n# my attr\n", @top_level + + util_parser "\n" + + tk = @parser.get_tk + + @parser.parse_comment klass, tk, comment + + assert_empty klass.attributes + end + + def test_parse_comment_method + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + comment = RDoc::Comment.new "##\n# :method: foo\n# my method\n", @top_level + + util_parser "\n" + + tk = @parser.get_tk + + @parser.parse_comment klass, tk, comment + + foo = klass.method_list.first + assert_equal 'foo', foo.name + assert_equal 'my method', foo.comment.text + assert_equal @top_level, foo.file + assert_equal 0, foo.offset + assert_equal 1, foo.line + + assert_equal [], foo.aliases + assert_equal nil, foo.block_params + assert_equal nil, foo.call_seq + assert_equal nil, foo.is_alias_for + assert_equal nil, foo.viewer + assert_equal true, foo.document_children + assert_equal true, foo.document_self + assert_equal '', foo.params + assert_equal false, foo.done_documenting + assert_equal false, foo.dont_rename_initialize + assert_equal false, foo.force_documentation + assert_equal klass, foo.parent + assert_equal false, foo.singleton + assert_equal :public, foo.visibility + assert_equal "\n", foo.text + assert_equal klass.current_section, foo.section + + stream = [ + tk(:COMMENT, 0, 1, 1, nil, + "# File #{@top_level.relative_name}, line 1"), + RDoc::Parser::Ruby::NEWLINE_TOKEN, + tk(:SPACE, 0, 1, 1, nil, ''), + ] + + assert_equal stream, foo.token_stream + end + + def test_parse_comment_method_args + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + + util_parser "\n" + + tk = @parser.get_tk + + @parser.parse_comment klass, tk, + comment("##\n# :method: foo\n# :args: a, b\n") + + foo = klass.method_list.first + assert_equal 'foo', foo.name + assert_equal 'a, b', foo.params + end + + def test_parse_comment_method_stopdoc + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + klass.stop_doc + + comment = RDoc::Comment.new "##\n# :method: foo\n# my method\n", @top_level + + util_parser "\n" + + tk = @parser.get_tk + + @parser.parse_comment klass, tk, comment + + assert_empty klass.method_list + end + + def test_parse_constant + klass = @top_level.add_class RDoc::NormalClass, 'Foo' + + util_parser "A = v" + + tk = @parser.get_tk + + @parser.parse_constant klass, tk, @comment + + foo = klass.constants.first + + assert_equal 'A', foo.name + assert_equal @top_level, foo.file + assert_equal 0, foo.offset + assert_equal 1, foo.line + end + + def test_parse_constant_attrasgn + klass = @top_level.add_class RDoc::NormalClass, 'Foo' + + util_parser "A[k] = v" + + tk = @parser.get_tk + + @parser.parse_constant klass, tk, @comment + + assert klass.constants.empty? + end + + def test_parse_constant_alias + klass = @top_level.add_class RDoc::NormalClass, 'Foo' + klass.add_class RDoc::NormalClass, 'B' + + util_parser "A = B" + + tk = @parser.get_tk + + @parser.parse_constant klass, tk, @comment + + assert_equal 'Foo::A', klass.find_module_named('A').full_name + end + + def test_parse_constant_alias_same_name + foo = @top_level.add_class RDoc::NormalClass, 'Foo' + @top_level.add_class RDoc::NormalClass, 'Bar' + bar = foo.add_class RDoc::NormalClass, 'Bar' + + assert @store.find_class_or_module('::Bar') + + util_parser "A = ::Bar" + + tk = @parser.get_tk + + @parser.parse_constant foo, tk, @comment + + assert_equal 'A', bar.find_module_named('A').full_name + end + + def test_parse_constant_in_method + klass = @top_level.add_class RDoc::NormalClass, 'Foo' + + util_parser 'A::B = v' + + tk = @parser.get_tk + + @parser.parse_constant klass, tk, @comment, true + + assert_empty klass.constants + + assert_empty @store.modules_hash.keys + assert_equal %w[Foo], @store.classes_hash.keys + end + + def test_parse_constant_rescue + klass = @top_level.add_class RDoc::NormalClass, 'Foo' + + util_parser "A => e" + + tk = @parser.get_tk + + @parser.parse_constant klass, tk, @comment + + assert_empty klass.constants + assert_empty klass.modules + + assert_empty @store.modules_hash.keys + assert_equal %w[Foo], @store.classes_hash.keys + end + + def test_parse_constant_stopdoc + klass = @top_level.add_class RDoc::NormalClass, 'Foo' + klass.stop_doc + + util_parser "A = v" + + tk = @parser.get_tk + + @parser.parse_constant klass, tk, @comment + + assert_empty klass.constants + end + + def test_parse_comment_nested + content = <<-CONTENT +A::B::C = 1 + CONTENT + + util_parser content + + tk = @parser.get_tk + + parsed = @parser.parse_constant @top_level, tk, 'comment' + + assert parsed + + a = @top_level.find_module_named 'A' + b = a.find_module_named 'B' + c = b.constants.first + + assert_equal 'A::B::C', c.full_name + assert_equal 'comment', c.comment + end + + def test_parse_extend_or_include_extend + klass = RDoc::NormalClass.new 'C' + klass.parent = @top_level + + comment = RDoc::Comment.new "# my extend\n", @top_level + + util_parser "extend I" + + @parser.get_tk # extend + + @parser.parse_extend_or_include RDoc::Extend, klass, comment + + assert_equal 1, klass.extends.length + + ext = klass.extends.first + assert_equal 'I', ext.name + assert_equal 'my extend', ext.comment.text + assert_equal @top_level, ext.file + end + + def test_parse_extend_or_include_include + klass = RDoc::NormalClass.new 'C' + klass.parent = @top_level + + comment = RDoc::Comment.new "# my include\n", @top_level + + util_parser "include I" + + @parser.get_tk # include + + @parser.parse_extend_or_include RDoc::Include, klass, comment + + assert_equal 1, klass.includes.length + + incl = klass.includes.first + assert_equal 'I', incl.name + assert_equal 'my include', incl.comment.text + assert_equal @top_level, incl.file + end + + def test_parse_meta_method + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + comment = RDoc::Comment.new "##\n# my method\n", @top_level + + util_parser "add_my_method :foo, :bar\nadd_my_method :baz" + + tk = @parser.get_tk + + @parser.parse_meta_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment + + foo = klass.method_list.first + assert_equal 'foo', foo.name + assert_equal 'my method', foo.comment.text + assert_equal @top_level, foo.file + assert_equal 0, foo.offset + assert_equal 1, foo.line + + assert_equal [], foo.aliases + assert_equal nil, foo.block_params + assert_equal nil, foo.call_seq + assert_equal true, foo.document_children + assert_equal true, foo.document_self + assert_equal false, foo.done_documenting + assert_equal false, foo.dont_rename_initialize + assert_equal false, foo.force_documentation + assert_equal nil, foo.is_alias_for + assert_equal '', foo.params + assert_equal klass, foo.parent + assert_equal false, foo.singleton + assert_equal 'add_my_method :foo', foo.text + assert_equal nil, foo.viewer + assert_equal :public, foo.visibility + assert_equal klass.current_section, foo.section + + stream = [ + tk(:COMMENT, 0, 1, 1, nil, + "# File #{@top_level.relative_name}, line 1"), + RDoc::Parser::Ruby::NEWLINE_TOKEN, + tk(:SPACE, 0, 1, 1, nil, ''), + tk(:IDENTIFIER, 0, 1, 0, 'add_my_method', 'add_my_method'), + tk(:SPACE, 0, 1, 13, nil, ' '), + tk(:SYMBOL, 0, 1, 14, nil, ':foo'), + tk(:COMMA, 0, 1, 18, nil, ','), + tk(:SPACE, 0, 1, 19, nil, ' '), + tk(:SYMBOL, 0, 1, 20, nil, ':bar'), + tk(:NL, 0, 1, 24, nil, "\n"), + ] + + assert_equal stream, foo.token_stream + end + + def test_parse_meta_method_block + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + comment = RDoc::Comment.new "##\n# my method\n", @top_level + + content = <<-CONTENT +inline(:my_method) do |*args| + "this method causes z to disappear" +end + CONTENT + + util_parser content + + tk = @parser.get_tk + + @parser.parse_meta_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment + + assert_equal tk(:NL, 0, 3, 3, 3, "\n"), @parser.get_tk + end + + def test_parse_meta_method_define_method + klass = RDoc::NormalClass.new 'Foo' + comment = RDoc::Comment.new "##\n# my method\n", @top_level + + util_parser "define_method :foo do end" + + tk = @parser.get_tk + + @parser.parse_meta_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment + + foo = klass.method_list.first + assert_equal 'foo', foo.name + assert_equal 'my method', foo.comment.text + assert_equal @top_level, foo.file + end + + def test_parse_meta_method_name + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + comment = + RDoc::Comment.new "##\n# :method: woo_hoo!\n# my method\n", @top_level + + util_parser "add_my_method :foo, :bar\nadd_my_method :baz" + + tk = @parser.get_tk + + @parser.parse_meta_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment + + foo = klass.method_list.first + assert_equal 'woo_hoo!', foo.name + assert_equal 'my method', foo.comment.text + assert_equal @top_level, foo.file + end + + def test_parse_meta_method_singleton + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + comment = + RDoc::Comment.new "##\n# :singleton-method:\n# my method\n", @top_level + + util_parser "add_my_method :foo, :bar\nadd_my_method :baz" + + tk = @parser.get_tk + + @parser.parse_meta_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment + + foo = klass.method_list.first + assert_equal 'foo', foo.name + assert_equal true, foo.singleton, 'singleton method' + assert_equal 'my method', foo.comment.text + assert_equal @top_level, foo.file + end + + def test_parse_meta_method_singleton_name + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + comment = + RDoc::Comment.new "##\n# :singleton-method: woo_hoo!\n# my method\n", + @top_level + + util_parser "add_my_method :foo, :bar\nadd_my_method :baz" + + tk = @parser.get_tk + + @parser.parse_meta_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment + + foo = klass.method_list.first + assert_equal 'woo_hoo!', foo.name + assert_equal true, foo.singleton, 'singleton method' + assert_equal 'my method', foo.comment.text + assert_equal @top_level, foo.file + end + + def test_parse_meta_method_string_name + klass = RDoc::NormalClass.new 'Foo' + comment = RDoc::Comment.new "##\n# my method\n", @top_level + + util_parser "add_my_method 'foo'" + + tk = @parser.get_tk + + @parser.parse_meta_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment + + foo = klass.method_list.first + assert_equal 'foo', foo.name + assert_equal 'my method', foo.comment.text + assert_equal @top_level, foo.file + end + + def test_parse_meta_method_stopdoc + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + klass.stop_doc + + comment = RDoc::Comment.new "##\n# my method\n", @top_level + + util_parser "add_my_method :foo, :bar\nadd_my_method :baz" + + tk = @parser.get_tk + + @parser.parse_meta_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment + + assert_empty klass.method_list + end + + def test_parse_meta_method_unknown + klass = RDoc::NormalClass.new 'Foo' + comment = RDoc::Comment.new "##\n# my method\n", @top_level + + util_parser "add_my_method ('foo')" + + tk = @parser.get_tk + + @parser.parse_meta_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment + + foo = klass.method_list.first + assert_equal 'unknown', foo.name + assert_equal 'my method', foo.comment.text + assert_equal @top_level, foo.file + end + + def test_parse_method + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + comment = RDoc::Comment.new "##\n# my method\n", @top_level + + util_parser "def foo() :bar end" + + tk = @parser.get_tk + + @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment + + foo = klass.method_list.first + assert_equal 'foo', foo.name + assert_equal 'my method', foo.comment.text + assert_equal @top_level, foo.file + assert_equal 0, foo.offset + assert_equal 1, foo.line + + assert_equal [], foo.aliases + assert_equal nil, foo.block_params + assert_equal nil, foo.call_seq + assert_equal nil, foo.is_alias_for + assert_equal nil, foo.viewer + assert_equal true, foo.document_children + assert_equal true, foo.document_self + assert_equal '()', foo.params + assert_equal false, foo.done_documenting + assert_equal false, foo.dont_rename_initialize + assert_equal false, foo.force_documentation + assert_equal klass, foo.parent + assert_equal false, foo.singleton + assert_equal :public, foo.visibility + assert_equal 'def foo', foo.text + assert_equal klass.current_section, foo.section + + stream = [ + tk(:COMMENT, 0, 1, 1, nil, + "# File #{@top_level.relative_name}, line 1"), + RDoc::Parser::Ruby::NEWLINE_TOKEN, + tk(:SPACE, 0, 1, 1, nil, ''), + tk(:DEF, 0, 1, 0, 'def', 'def'), + tk(:SPACE, 3, 1, 3, nil, ' '), + tk(:IDENTIFIER, 4, 1, 4, 'foo', 'foo'), + tk(:LPAREN, 7, 1, 7, nil, '('), + tk(:RPAREN, 8, 1, 8, nil, ')'), + tk(:SPACE, 9, 1, 9, nil, ' '), + tk(:COLON, 10, 1, 10, nil, ':'), + tk(:IDENTIFIER, 11, 1, 11, 'bar', 'bar'), + tk(:SPACE, 14, 1, 14, nil, ' '), + tk(:END, 15, 1, 15, 'end', 'end'), + ] + + assert_equal stream, foo.token_stream + end + + def test_parse_method_alias + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + util_parser "def m() alias a b; end" + + tk = @parser.get_tk + + @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, @comment + + assert klass.aliases.empty? + end + + def test_parse_method_ampersand + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + util_parser "def self.&\nend" + + tk = @parser.get_tk + + @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, @comment + + ampersand = klass.method_list.first + assert_equal '&', ampersand.name + assert ampersand.singleton + end + + def test_parse_method_constant + c = RDoc::Constant.new 'CONST', nil, '' + m = @top_level.add_class RDoc::NormalModule, 'M' + m.add_constant c + + util_parser "def CONST.m() end" + + tk = @parser.get_tk + + @parser.parse_method m, RDoc::Parser::Ruby::NORMAL, tk, @comment + + assert_empty @store.modules_hash.keys + assert_equal %w[M], @store.classes_hash.keys + end + + def test_parse_method_false + util_parser "def false.foo() :bar end" + + tk = @parser.get_tk + + @parser.parse_method @top_level, RDoc::Parser::Ruby::NORMAL, tk, @comment + + klass = @store.find_class_named 'FalseClass' + + foo = klass.method_list.first + assert_equal 'foo', foo.name + end + + def test_parse_method_funky + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + util_parser "def (blah).foo() :bar end" + + tk = @parser.get_tk + + @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, @comment + + assert_empty klass.method_list + end + + def test_parse_method_gvar + util_parser "def $stdout.foo() :bar end" + + tk = @parser.get_tk + + @parser.parse_method @top_level, RDoc::Parser::Ruby::NORMAL, tk, @comment + + assert @top_level.method_list.empty? + end + + def test_parse_method_gvar_insane + util_parser "def $stdout.foo() class << $other; end; end" + + tk = @parser.get_tk + + @parser.parse_method @top_level, RDoc::Parser::Ruby::NORMAL, tk, @comment + + assert @top_level.method_list.empty? + + assert_empty @store.all_classes + + assert_equal 1, @store.all_modules.length + + refute @store.all_modules.first.document_self + end + + def test_parse_method_internal_gvar + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + util_parser "def foo() def $blah.bar() end end" + + tk = @parser.get_tk + + @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, @comment + + assert_equal 1, klass.method_list.length + end + + def test_parse_method_internal_ivar + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + util_parser "def foo() def @blah.bar() end end" + + tk = @parser.get_tk + + @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, @comment + + assert_equal 1, klass.method_list.length + end + + def test_parse_method_internal_lvar + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + util_parser "def foo() def blah.bar() end end" + + tk = @parser.get_tk + + @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, @comment + + assert_equal 1, klass.method_list.length + end + + def test_parse_method_nil + util_parser "def nil.foo() :bar end" + + tk = @parser.get_tk + + @parser.parse_method @top_level, RDoc::Parser::Ruby::NORMAL, tk, @comment + + klass = @store.find_class_named 'NilClass' + + foo = klass.method_list.first + assert_equal 'foo', foo.name + end + + def test_parse_method_nodoc + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + util_parser "def foo # :nodoc:\nend" + + tk = @parser.get_tk + + @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment('') + + assert_empty klass.method_list + end + + def test_parse_method_nodoc_track + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + @options.visibility = :nodoc + + util_parser "def foo # :nodoc:\nend" + + tk = @parser.get_tk + + @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment('') + + refute_empty klass.method_list + end + + def test_parse_method_no_parens + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + util_parser "def foo arg1, arg2 = {}\nend" + + tk = @parser.get_tk + + @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, @comment + + foo = klass.method_list.first + assert_equal '(arg1, arg2 = {})', foo.params + assert_equal @top_level, foo.file + end + + def test_parse_method_parameters_comment + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + util_parser "def foo arg1, arg2 # some useful comment\nend" + + tk = @parser.get_tk + + @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, @comment + + foo = klass.method_list.first + assert_equal '(arg1, arg2)', foo.params + end + + def test_parse_method_parameters_comment_continue + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + util_parser "def foo arg1, arg2, # some useful comment\narg3\nend" + + tk = @parser.get_tk + + @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, @comment + + foo = klass.method_list.first + assert_equal '(arg1, arg2, arg3)', foo.params + end + + def test_parse_method_star + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + util_parser "def self.*\nend" + + tk = @parser.get_tk + + @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, @comment + + ampersand = klass.method_list.first + assert_equal '*', ampersand.name + assert ampersand.singleton + end + + def test_parse_method_stopdoc + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + klass.stop_doc + + comment = RDoc::Comment.new "##\n# my method\n", @top_level + + util_parser "def foo() :bar end" + + tk = @parser.get_tk + + @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment + + assert_empty klass.method_list + end + + def test_parse_method_toplevel + klass = @top_level + + util_parser "def foo arg1, arg2\nend" + + tk = @parser.get_tk + + @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, @comment + + object = @store.find_class_named 'Object' + + foo = object.method_list.first + assert_equal 'Object#foo', foo.full_name + assert_equal @top_level, foo.file + end + + def test_parse_method_toplevel_class + klass = @top_level + + util_parser "def Object.foo arg1, arg2\nend" + + tk = @parser.get_tk + + @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, @comment + + object = @store.find_class_named 'Object' + + foo = object.method_list.first + assert_equal 'Object::foo', foo.full_name + end + + def test_parse_method_true + util_parser "def true.foo() :bar end" + + tk = @parser.get_tk + + @parser.parse_method @top_level, RDoc::Parser::Ruby::NORMAL, tk, @comment + + klass = @store.find_class_named 'TrueClass' + + foo = klass.method_list.first + assert_equal 'foo', foo.name + end + + def test_parse_method_utf8 + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + method = "def ω() end" + + assert_equal Encoding::UTF_8, method.encoding if + Object.const_defined? :Encoding + + util_parser method + + tk = @parser.get_tk + + @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, @comment + + omega = klass.method_list.first + assert_equal "def \317\211", omega.text + end + + def test_parse_method_dummy + util_parser ".method() end" + + @parser.parse_method_dummy @top_level + + assert_nil @parser.get_tk + end + + def test_parse_method_or_yield_parameters_hash + util_parser "({})\n" + + m = RDoc::AnyMethod.new nil, 'm' + + result = @parser.parse_method_or_yield_parameters m + + assert_equal '({})', result + end + + def test_parse_statements_class_if + util_parser <<-CODE +module Foo + X = if TRUE then + '' + end + + def blah + end +end + CODE + + @parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL, nil + + foo = @top_level.modules.first + assert_equal 'Foo', foo.full_name, 'module Foo' + + methods = foo.method_list + assert_equal 1, methods.length + assert_equal 'Foo#blah', methods.first.full_name + end + + def test_parse_statements_class_nested + comment = RDoc::Comment.new "##\n# my method\n", @top_level + + util_parser "module Foo\n#{comment.text}class Bar\nend\nend" + + @parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL + + foo = @top_level.modules.first + assert_equal 'Foo', foo.full_name, 'module Foo' + + bar = foo.classes.first + assert_equal 'Foo::Bar', bar.full_name, 'class Foo::Bar' + assert_equal 'my method', bar.comment.text + end + + def test_parse_statements_def_percent_string_pound + util_parser "class C\ndef a\n%r{#}\nend\ndef b() end\nend" + + @parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL + + x = @top_level.classes.first + + assert_equal 2, x.method_list.length + a = x.method_list.first + + expected = [ + tk(:COMMENT, 0, 2, 1, nil, "# File #{@filename}, line 2"), + tk(:NL, 0, 0, 0, nil, "\n"), + tk(:SPACE, 0, 1, 1, nil, ''), + tk(:DEF, 8, 2, 0, 'def', 'def'), + tk(:SPACE, 11, 2, 3, nil, ' '), + tk(:IDENTIFIER, 12, 2, 4, 'a', 'a'), + tk(:NL, 13, 2, 5, nil, "\n"), + tk(:DREGEXP, 14, 3, 0, nil, '%r{#}'), + tk(:NL, 19, 3, 5, nil, "\n"), + tk(:END, 20, 4, 0, 'end', 'end'), + ] + + assert_equal expected, a.token_stream + end + + def test_parse_statements_encoding + skip "Encoding not implemented" unless Object.const_defined? :Encoding + @options.encoding = Encoding::CP852 + + content = <<-EOF +class Foo + ## + # this is my method + add_my_method :foo +end + EOF + + util_parser content + + @parser.parse_statements @top_level + + foo = @top_level.classes.first.method_list.first + assert_equal 'foo', foo.name + assert_equal 'this is my method', foo.comment.text + assert_equal Encoding::CP852, foo.comment.text.encoding + end + + def test_parse_statements_enddoc + klass = @top_level.add_class RDoc::NormalClass, 'Foo' + + util_parser "\n# :enddoc:" + + @parser.parse_statements klass, RDoc::Parser::Ruby::NORMAL, nil + + assert klass.done_documenting + end + + def test_parse_statements_enddoc_top_level + util_parser "\n# :enddoc:" + + assert_throws :eof do + @parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL, nil + end + end + + def test_parse_statements_identifier_meta_method + content = <<-EOF +class Foo + ## + # this is my method + add_my_method :foo +end + EOF + + util_parser content + + @parser.parse_statements @top_level + + foo = @top_level.classes.first.method_list.first + assert_equal 'foo', foo.name + end + + def test_parse_statements_identifier_alias_method + content = <<-RUBY +class Foo + def foo() end + alias_method :foo2, :foo +end + RUBY + + util_parser content + + @parser.parse_statements @top_level + + foo = @top_level.classes.first.method_list[0] + assert_equal 'foo', foo.name + + foo2 = @top_level.classes.first.method_list.last + assert_equal 'foo2', foo2.name + assert_equal 'foo', foo2.is_alias_for.name + assert @top_level.classes.first.aliases.empty? + end + + def test_parse_statements_identifier_alias_method_before_original_method + # This is not strictly legal Ruby code, but it simulates finding an alias + # for a method before finding the original method, which might happen + # to rdoc if the alias is in a different file than the original method + # and rdoc processes the alias' file first. + content = <<-EOF +class Foo + alias_method :foo2, :foo + + alias_method :foo3, :foo + + def foo() + end + + alias_method :foo4, :foo + + alias_method :foo5, :unknown +end +EOF + + util_parser content + + @parser.parse_statements @top_level + + foo = @top_level.classes.first.method_list[0] + assert_equal 'foo', foo.name + + foo2 = @top_level.classes.first.method_list[1] + assert_equal 'foo2', foo2.name + assert_equal 'foo', foo2.is_alias_for.name + + foo3 = @top_level.classes.first.method_list[2] + assert_equal 'foo3', foo3.name + assert_equal 'foo', foo3.is_alias_for.name + + foo4 = @top_level.classes.first.method_list.last + assert_equal 'foo4', foo4.name + assert_equal 'foo', foo4.is_alias_for.name + + assert_equal 'unknown', @top_level.classes.first.external_aliases[0].old_name + end + + def test_parse_statements_identifier_args + comment = "##\n# :args: x\n# :method: b\n# my method\n" + + util_parser "module M\n#{comment}def_delegator :a, :b, :b\nend" + + @parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL + + m = @top_level.modules.first + assert_equal 'M', m.full_name + + b = m.method_list.first + assert_equal 'M#b', b.full_name + assert_equal 'x', b.params + assert_equal 'my method', b.comment.text + + assert_nil m.params, 'Module parameter not removed' + end + + def test_parse_statements_identifier_constant + sixth_constant = <<-EOF +Class.new do + rule :file do + all(x, y, z) { + def value + find(:require).each {|r| require r.value } + find(:grammar).map {|g| g.value } + end + def min; end + } + end +end + EOF + + content = <<-EOF +class Foo + FIRST_CONSTANT = 5 + + SECOND_CONSTANT = [ + 1, + 2, + 3 + ] + + THIRD_CONSTANT = { + :foo => 'bar', + :x => 'y' + } + + FOURTH_CONSTANT = SECOND_CONSTANT.map do |element| + element + 1 + element + 2 + end + + FIFTH_CONSTANT = SECOND_CONSTANT.map { |element| element + 1 } + + SIXTH_CONSTANT = #{sixth_constant} + + SEVENTH_CONSTANT = proc { |i| begin i end } +end +EOF + + util_parser content + + @parser.parse_statements @top_level + + constants = @top_level.classes.first.constants + + constant = constants[0] + assert_equal 'FIRST_CONSTANT', constant.name + assert_equal '5', constant.value + assert_equal @top_level, constant.file + + constant = constants[1] + assert_equal 'SECOND_CONSTANT', constant.name + assert_equal "[\n1,\n2,\n3\n]", constant.value + assert_equal @top_level, constant.file + + constant = constants[2] + assert_equal 'THIRD_CONSTANT', constant.name + assert_equal "{\n:foo => 'bar',\n:x => 'y'\n}", constant.value + assert_equal @top_level, constant.file + + constant = constants[3] + assert_equal 'FOURTH_CONSTANT', constant.name + assert_equal "SECOND_CONSTANT.map do |element|\nelement + 1\nelement + 2\nend", constant.value + assert_equal @top_level, constant.file + + constant = constants[4] + assert_equal 'FIFTH_CONSTANT', constant.name + assert_equal 'SECOND_CONSTANT.map { |element| element + 1 }', constant.value + assert_equal @top_level, constant.file + + # TODO: parse as class + constant = constants[5] + assert_equal 'SIXTH_CONSTANT', constant.name + assert_equal sixth_constant.lines.map(&:strip).join("\n"), constant.value + assert_equal @top_level, constant.file + + # TODO: parse as method + constant = constants[6] + assert_equal 'SEVENTH_CONSTANT', constant.name + assert_equal "proc { |i| begin i end }", constant.value + assert_equal @top_level, constant.file + end + + def test_parse_statements_identifier_attr + content = "class Foo\nattr :foo\nend" + + util_parser content + + @parser.parse_statements @top_level + + foo = @top_level.classes.first.attributes.first + assert_equal 'foo', foo.name + assert_equal 'R', foo.rw + end + + def test_parse_statements_identifier_attr_accessor + content = "class Foo\nattr_accessor :foo\nend" + + util_parser content + + @parser.parse_statements @top_level + + foo = @top_level.classes.first.attributes.first + assert_equal 'foo', foo.name + assert_equal 'RW', foo.rw + end + + def test_parse_statements_identifier_define_method + util_parser <<-RUBY +class C + ## + # :method: a + define_method :a do end + ## + # :method: b + define_method :b do end +end + RUBY + + @parser.parse_statements @top_level + c = @top_level.classes.first + + assert_equal %w[a b], c.method_list.map { |m| m.name } + end + + def test_parse_statements_identifier_include + content = "class Foo\ninclude Bar\nend" + + util_parser content + + @parser.parse_statements @top_level + + foo = @top_level.classes.first + assert_equal 'Foo', foo.name + assert_equal 1, foo.includes.length + end + + def test_parse_statements_identifier_module_function + content = "module Foo\ndef foo() end\nmodule_function :foo\nend" + + util_parser content + + @parser.parse_statements @top_level + + foo, s_foo = @top_level.modules.first.method_list + assert_equal 'foo', foo.name, 'instance method name' + assert_equal :private, foo.visibility, 'instance method visibility' + assert_equal false, foo.singleton, 'instance method singleton' + + assert_equal 'foo', s_foo.name, 'module function name' + assert_equal :public, s_foo.visibility, 'module function visibility' + assert_equal true, s_foo.singleton, 'module function singleton' + end + + def test_parse_statements_identifier_private + content = "class Foo\nprivate\ndef foo() end\nend" + + util_parser content + + @parser.parse_statements @top_level + + foo = @top_level.classes.first.method_list.first + assert_equal 'foo', foo.name + assert_equal :private, foo.visibility + end + + def test_parse_statements_identifier_public_class_method + content = <<-CONTENT +class Date + def self.now; end + private_class_method :now +end + +class DateTime < Date + public_class_method :now +end + CONTENT + + util_parser content + + @parser.parse_statements @top_level + + date, date_time = @top_level.classes.sort_by { |c| c.full_name } + + date_now = date.method_list.first + date_time_now = date_time.method_list.sort_by { |m| m.full_name }.first + + assert_equal :private, date_now.visibility + assert_equal :public, date_time_now.visibility + end + + def test_parse_statements_identifier_private_class_method + content = <<-CONTENT +class Date + def self.now; end + public_class_method :now +end + +class DateTime < Date + private_class_method :now +end + CONTENT + + util_parser content + + @parser.parse_statements @top_level + + # TODO sort classes by default + date, date_time = @top_level.classes.sort_by { |c| c.full_name } + + date_now = date.method_list.first + date_time_now = date_time.method_list.sort_by { |m| m.full_name }.first + + assert_equal :public, date_now.visibility, date_now.full_name + assert_equal :private, date_time_now.visibility, date_time_now.full_name + end + + def test_parse_statements_identifier_require + content = "require 'bar'" + + util_parser content + + @parser.parse_statements @top_level + + assert_equal 1, @top_level.requires.length + end + + def test_parse_statements_identifier_yields + comment = "##\n# :yields: x\n# :method: b\n# my method\n" + + util_parser "module M\n#{comment}def_delegator :a, :b, :b\nend" + + @parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL + + m = @top_level.modules.first + assert_equal 'M', m.full_name + + b = m.method_list.first + assert_equal 'M#b', b.full_name + assert_equal 'x', b.block_params + assert_equal 'my method', b.comment.text + + assert_nil m.params, 'Module parameter not removed' + end + + def test_parse_statements_stopdoc_TkALIAS + klass = @top_level.add_class RDoc::NormalClass, 'Foo' + + util_parser "\n# :stopdoc:\nalias old new" + + @parser.parse_statements klass, RDoc::Parser::Ruby::NORMAL, nil + + assert_empty klass.aliases + assert_empty klass.unmatched_alias_lists + end + + def test_parse_statements_stopdoc_TkIDENTIFIER_alias_method + klass = @top_level.add_class RDoc::NormalClass, 'Foo' + + util_parser "\n# :stopdoc:\nalias_method :old :new" + + @parser.parse_statements klass, RDoc::Parser::Ruby::NORMAL, nil + + assert_empty klass.aliases + assert_empty klass.unmatched_alias_lists + end + + def test_parse_statements_stopdoc_TkIDENTIFIER_metaprogrammed + klass = @top_level.add_class RDoc::NormalClass, 'Foo' + + util_parser "\n# :stopdoc:\n# attr :meta" + + @parser.parse_statements klass, RDoc::Parser::Ruby::NORMAL, nil + + assert_empty klass.method_list + assert_empty klass.attributes + end + + def test_parse_statements_stopdoc_TkCONSTANT + klass = @top_level.add_class RDoc::NormalClass, 'Foo' + + util_parser "\n# :stopdoc:\nA = v" + + @parser.parse_statements klass, RDoc::Parser::Ruby::NORMAL, nil + + assert_empty klass.constants + end + + def test_parse_statements_stopdoc_TkDEF + klass = @top_level.add_class RDoc::NormalClass, 'Foo' + + util_parser "\n# :stopdoc:\ndef m\n end" + + @parser.parse_statements klass, RDoc::Parser::Ruby::NORMAL, nil + + assert_empty klass.method_list + end + + def test_parse_statements_super + m = RDoc::AnyMethod.new '', 'm' + util_parser 'super' + + @parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL, m + + assert m.calls_super + end + + def test_parse_statements_super_no_method + content = "super" + + util_parser content + + @parser.parse_statements @top_level + + assert_nil @parser.get_tk + end + + def test_parse_statements_while_begin + util_parser <<-RUBY +class A + def a + while begin a; b end + end + end + + def b + end +end + RUBY + + @parser.parse_statements @top_level + + c_a = @top_level.classes.first + assert_equal 'A', c_a.full_name + + assert_equal 1, @top_level.classes.length + + m_a = c_a.method_list.first + m_b = c_a.method_list.last + + assert_equal 'A#a', m_a.full_name + assert_equal 'A#b', m_b.full_name + end + + def test_parse_symbol_in_arg + util_parser ':blah "blah" "#{blah}" blah' + + assert_equal 'blah', @parser.parse_symbol_in_arg + + @parser.skip_tkspace + + assert_equal 'blah', @parser.parse_symbol_in_arg + + @parser.skip_tkspace + + assert_equal nil, @parser.parse_symbol_in_arg + + @parser.skip_tkspace + + assert_equal nil, @parser.parse_symbol_in_arg + end + + def test_parse_statements_alias_method + content = <<-CONTENT +class A + alias_method :a, :[] unless c +end + +B = A + +class C +end + CONTENT + + util_parser content + + @parser.parse_statements @top_level + + # HACK where are the assertions? + end + + def test_parse_top_level_statements_enddoc + util_parser <<-CONTENT +# :enddoc: + CONTENT + + assert_throws :eof do + @parser.parse_top_level_statements @top_level + end + end + + def test_parse_top_level_statements_stopdoc + @top_level.stop_doc + content = "# this is the top-level comment" + + util_parser content + + @parser.parse_top_level_statements @top_level + + assert_empty @top_level.comment + end + + def test_parse_top_level_statements_stopdoc_integration + content = <<-CONTENT +# :stopdoc: + +class Example + def method_name + end +end + CONTENT + + util_parser content + + @parser.parse_top_level_statements @top_level + + assert_equal 1, @top_level.classes.length + assert_empty @top_level.modules + + assert @top_level.find_module_named('Example').ignored? + end + + # This tests parse_comment + def test_parse_top_level_statements_constant_nodoc_integration + content = <<-CONTENT +class A + C = A # :nodoc: +end + CONTENT + + util_parser content + + @parser.parse_top_level_statements @top_level + + klass = @top_level.find_module_named('A') + + c = klass.constants.first + + assert_nil c.document_self, 'C should not be documented' + end + + def test_parse_yield_in_braces_with_parens + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + util_parser "def foo\nn.times { |i| yield nth(i) }\nend" + + tk = @parser.get_tk + + @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, @comment + + foo = klass.method_list.first + assert_equal 'nth(i)', foo.block_params + end + + def test_read_directive + parser = util_parser '# :category: test' + + directive, value = parser.read_directive %w[category] + + assert_equal 'category', directive + assert_equal 'test', value + + assert_kind_of RDoc::RubyToken::TkNL, parser.get_tk + end + + def test_read_directive_allow + parser = util_parser '# :category: test' + + directive = parser.read_directive [] + + assert_nil directive + + assert_kind_of RDoc::RubyToken::TkNL, parser.get_tk + end + + def test_read_directive_empty + parser = util_parser '# test' + + directive = parser.read_directive %w[category] + + assert_nil directive + + assert_kind_of RDoc::RubyToken::TkNL, parser.get_tk + end + + def test_read_directive_no_comment + parser = util_parser '' + + directive = parser.read_directive %w[category] + + assert_nil directive + + assert_kind_of RDoc::RubyToken::TkNL, parser.get_tk + end + + def test_read_directive_one_liner + parser = util_parser '; end # :category: test' + + directive, value = parser.read_directive %w[category] + + assert_equal 'category', directive + assert_equal 'test', value + + assert_kind_of RDoc::RubyToken::TkSEMICOLON, parser.get_tk + end + + def test_read_documentation_modifiers + c = RDoc::Context.new + + parser = util_parser '# :category: test' + + parser.read_documentation_modifiers c, %w[category] + + assert_equal 'test', c.current_section.title + end + + def test_read_documentation_modifiers_notnew + m = RDoc::AnyMethod.new nil, 'initialize' + + parser = util_parser '# :notnew: test' + + parser.read_documentation_modifiers m, %w[notnew] + + assert m.dont_rename_initialize + end + + def test_read_documentation_modifiers_not_dash_new + m = RDoc::AnyMethod.new nil, 'initialize' + + parser = util_parser '# :not-new: test' + + parser.read_documentation_modifiers m, %w[not-new] + + assert m.dont_rename_initialize + end + + def test_read_documentation_modifiers_not_new + m = RDoc::AnyMethod.new nil, 'initialize' + + parser = util_parser '# :not_new: test' + + parser.read_documentation_modifiers m, %w[not_new] + + assert m.dont_rename_initialize + end + + def test_sanity_integer + util_parser '1' + assert_equal '1', @parser.get_tk.text + + util_parser '1.0' + assert_equal '1.0', @parser.get_tk.text + end + + def test_sanity_interpolation + last_tk = nil + util_parser 'class A; B = "#{c}"; end' + + while tk = @parser.get_tk do last_tk = tk end + + assert_equal "\n", last_tk.text + end + + # If you're writing code like this you're doing it wrong + + def test_sanity_interpolation_crazy + util_parser '"#{"#{"a")}" if b}"' + + assert_equal '"#{"#{"a")}" if b}"', @parser.get_tk.text + assert_equal RDoc::RubyToken::TkNL, @parser.get_tk.class + end + + def test_sanity_interpolation_curly + util_parser '%{ #{} }' + + assert_equal '%Q{ #{} }', @parser.get_tk.text + assert_equal RDoc::RubyToken::TkNL, @parser.get_tk.class + end + + def test_sanity_interpolation_format + util_parser '"#{stftime("%m-%d")}"' + + while @parser.get_tk do end + end + + def test_sanity_symbol_interpolation + util_parser ':"#{bar}="' + + while @parser.get_tk do end + end + + def test_scan_cr + content = <<-CONTENT +class C\r + def m\r + a=\\\r + 123\r + end\r +end\r + CONTENT + + util_parser content + + @parser.scan + + c = @top_level.classes.first + + assert_equal 1, c.method_list.length + end + + def test_scan_block_comment + content = <<-CONTENT +=begin rdoc +Foo comment +=end + +class Foo + +=begin +m comment +=end + + def m() end +end + CONTENT + + util_parser content + + @parser.scan + + foo = @top_level.classes.first + + assert_equal 'Foo comment', foo.comment.text + + m = foo.method_list.first + + assert_equal 'm comment', m.comment.text + end + + def test_scan_block_comment_nested # Issue #41 + content = <<-CONTENT +require 'something' +=begin rdoc +findmeindoc +=end +module Foo + class Bar + end +end + CONTENT + + util_parser content + + @parser.scan + + foo = @top_level.modules.first + + assert_equal 'Foo', foo.full_name + assert_equal 'findmeindoc', foo.comment.text + + bar = foo.classes.first + + assert_equal 'Foo::Bar', bar.full_name + assert_equal '', bar.comment.text + end + + def test_scan_block_comment_notflush + ## + # + # The previous test assumes that between the =begin/=end blocs that there is + # only one line, or minima formatting directives. This test tests for those + # who use the =begin bloc with longer / more advanced formatting within. + # + ## + content = <<-CONTENT +=begin rdoc + += DESCRIPTION + +This is a simple test class + += RUMPUS + +Is a silly word + +=end +class StevenSimpleClass + # A band on my iPhone as I wrote this test + FRUIT_BATS="Make nice music" + +=begin rdoc +A nice girl +=end + + def lauren + puts "Summoning Lauren!" + end +end + CONTENT + util_parser content + + @parser.scan + + foo = @top_level.classes.first + + assert_equal "= DESCRIPTION\n\nThis is a simple test class\n\n= RUMPUS\n\nIs a silly word", + foo.comment.text + + m = foo.method_list.first + + assert_equal 'A nice girl', m.comment.text + end + + def test_scan_class_nested_nodoc + content = <<-CONTENT +class A::B # :nodoc: +end + CONTENT + + util_parser content + + @parser.scan + + visible = @store.all_classes_and_modules.select { |mod| mod.display? } + + assert_empty visible.map { |mod| mod.full_name } + end + + def test_scan_constant_in_method + content = <<-CONTENT # newline is after M is important +module M + def m + A + B::C + end +end + CONTENT + + util_parser content + + @parser.scan + + m = @top_level.modules.first + + assert_empty m.constants + + assert_empty @store.classes_hash.keys + assert_equal %w[M], @store.modules_hash.keys + end + + def test_scan_constant_in_rescue + content = <<-CONTENT # newline is after M is important +module M + def m + rescue A::B + rescue A::C => e + rescue A::D, A::E + rescue A::F, + A::G + rescue H + rescue I => e + rescue J, K + rescue L => + e + rescue M; + rescue N, + O => e + end +end + CONTENT + + util_parser content + + @parser.scan + + m = @top_level.modules.first + + assert_empty m.constants + + assert_empty @store.classes_hash.keys + assert_equal %w[M], @store.modules_hash.keys + end + + def test_scan_constant_nodoc + content = <<-CONTENT # newline is after M is important +module M + + C = v # :nodoc: +end + CONTENT + + util_parser content + + @parser.scan + + c = @top_level.modules.first.constants.first + + assert c.documented? + end + + def test_scan_constant_nodoc_block + content = <<-CONTENT # newline is after M is important +module M + + C = v do # :nodoc: + end +end + CONTENT + + util_parser content + + @parser.scan + + c = @top_level.modules.first.constants.first + + assert c.documented? + end + + def test_scan_duplicate_module + content = <<-CONTENT +# comment a +module Foo +end + +# comment b +module Foo +end + CONTENT + + util_parser content + + @parser.scan + + foo = @top_level.modules.first + + expected = [ + RDoc::Comment.new('comment b', @top_level) + ] + + assert_equal expected, foo.comment_location.map { |c, l| c } + end + + def test_scan_meta_method_block + content = <<-CONTENT +class C + + ## + # my method + + inline(:my_method) do |*args| + "this method used to cause z to disappear" + end + + def z + end + CONTENT + + util_parser content + + @parser.scan + + assert_equal 2, @top_level.classes.first.method_list.length + end + + def test_scan_method_semi_method + content = <<-CONTENT +class A + def self.m() end; def self.m=() end +end + +class B + def self.m() end +end + CONTENT + + util_parser content + + @parser.scan + + a = @store.find_class_named 'A' + assert a, 'missing A' + + assert_equal 2, a.method_list.length + + b = @store.find_class_named 'B' + assert b, 'missing B' + + assert_equal 1, b.method_list.length + end + + def test_scan_markup_override + content = <<-CONTENT +# *awesome* +class C + # :markup: rd + # ((*radical*)) + def m + end +end + CONTENT + + util_parser content + + @parser.scan + + c = @top_level.classes.first + + assert_equal 'rdoc', c.comment.format + + assert_equal 'rd', c.method_list.first.comment.format + end + + def test_scan_markup_first_comment + content = <<-CONTENT +# :markup: rd + +# ((*awesome*)) +class C + # ((*radical*)) + def m + end +end + CONTENT + + util_parser content + + @parser.scan + + c = @top_level.classes.first + + assert_equal 'rd', c.comment.format + + assert_equal 'rd', c.method_list.first.comment.format + end + + def test_scan_rails_routes + util_parser <<-ROUTES_RB +namespace :api do + scope module: :v1 do + end +end + ROUTES_RB + + @parser.scan + + assert_empty @top_level.classes + assert_empty @top_level.modules + end + + def test_scan_tomdoc_meta + util_parser <<-RUBY +# :markup: tomdoc + +class C + + # Signature + # + # find_by_<field>[_and_<field>...](args) + # + # field - A field name. + +end + + RUBY + + @parser.scan + + c = @top_level.classes.first + + m = c.method_list.first + + assert_equal "find_by_<field>[_and_<field>...]", m.name + assert_equal "find_by_<field>[_and_<field>...](args)\n", m.call_seq + + expected = + doc( + head(3, 'Signature'), + list(:NOTE, + item(%w[field], + para('A field name.')))) + expected.file = @top_level + + assert_equal expected, m.comment.parse + end + + def test_scan_stopdoc + util_parser <<-RUBY +class C + # :stopdoc: + class Hidden + end +end + RUBY + + @parser.scan + + c = @top_level.classes.first + + hidden = c.classes.first + + refute hidden.document_self + assert hidden.ignored? + end + + def test_scan_stopdoc_class_alias + util_parser <<-RUBY +# :stopdoc: +module A + B = C +end + RUBY + + @parser.scan + + assert_empty @store.all_classes + + assert_equal 1, @store.all_modules.length + m = @store.all_modules.first + + assert m.ignored? + end + + def test_scan_stopdoc_nested + util_parser <<-RUBY +# :stopdoc: +class A::B +end + RUBY + + @parser.scan + + a = @store.modules_hash['A'] + a_b = @store.classes_hash['A::B'] + + refute a.document_self, 'A is inside stopdoc' + assert a.ignored?, 'A is inside stopdoc' + + refute a_b.document_self, 'A::B is inside stopdoc' + assert a_b.ignored?, 'A::B is inside stopdoc' + end + + def test_scan_struct_self_brackets + util_parser <<-RUBY +class C < M.m + def self.[] + end +end + RUBY + + @parser.scan + + c = @store.find_class_named 'C' + assert_equal %w[C::[]], c.method_list.map { |m| m.full_name } + end + + def test_scan_visibility + util_parser <<-RUBY +class C + def a() end + + private :a + + class << self + def b() end + private :b + end +end + RUBY + + @parser.scan + + c = @store.find_class_named 'C' + + c_a = c.find_method_named 'a' + + assert_equal :private, c_a.visibility + refute c_a.singleton + + c_b = c.find_method_named 'b' + + assert_equal :private, c_b.visibility + assert c_b.singleton + end + + def test_singleton_method_via_eigenclass + util_parser <<-RUBY +class C + class << self + def a() end + end +end + RUBY + + @parser.scan + + c = @store.find_class_named 'C' + c_a = c.find_method_named 'a' + + assert_equal :public, c_a.visibility + assert c_a.singleton + end + + def test_stopdoc_after_comment + util_parser <<-EOS + module Bar + # hello + module Foo + # :stopdoc: + end + # there + class Baz + # :stopdoc: + end + end + EOS + + @parser.parse_statements @top_level + + foo = @top_level.modules.first.modules.first + assert_equal 'Foo', foo.name + assert_equal 'hello', foo.comment.text + + baz = @top_level.modules.first.classes.first + assert_equal 'Baz', baz.name + assert_equal 'there', baz.comment.text + end + + def tk klass, scan, line, char, name, text + klass = RDoc::RubyToken.const_get "Tk#{klass.to_s.upcase}" + + token = if klass.instance_method(:initialize).arity == 3 then + raise ArgumentError, "name not used for #{klass}" if name + klass.new scan, line, char + else + klass.new scan, line, char, name + end + + token.set_text text + + token + end + + def util_parser(content) + @parser = RDoc::Parser::Ruby.new @top_level, @filename, content, @options, + @stats + end + + def util_two_parsers(first_file_content, second_file_content) + util_parser first_file_content + + @parser2 = RDoc::Parser::Ruby.new @top_level2, @filename, + second_file_content, @options, @stats + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_parser_simple.rb b/jni/ruby/test/rdoc/test_rdoc_parser_simple.rb new file mode 100644 index 0000000..d45a993 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_parser_simple.rb @@ -0,0 +1,115 @@ +require 'rdoc/test_case' + +class TestRDocParserSimple < RDoc::TestCase + + def setup + super + + @tempfile = Tempfile.new self.class.name + filename = @tempfile.path + + @top_level = @store.add_file filename + @fn = filename + @options = RDoc::Options.new + @stats = RDoc::Stats.new @store, 0 + end + + def teardown + super + + @tempfile.close! + end + + def test_initialize_metadata + parser = util_parser ":unhandled: \n" + + assert_includes @top_level.metadata, 'unhandled' + + assert_equal ":unhandled: \n", parser.content + end + + def test_remove_coding_comment + parser = util_parser <<-TEXT +# -*- mode: rdoc; coding: utf-8; fill-column: 74; -*- + +Regular expressions (<i>regexp</i>s) are patterns which describe the +contents of a string. + TEXT + + parser.scan + + expected = <<-TEXT.strip +Regular expressions (<i>regexp</i>s) are patterns which describe the +contents of a string. + TEXT + + assert_equal expected, @top_level.comment.text + end + + # RDoc stops processing comments if it finds a comment line CONTAINING + # '<tt>#--</tt>'. This can be used to separate external from internal + # comments, or to stop a comment being associated with a method, + # class, or module. Commenting CAN be turned back on with + # a line that STARTS '<tt>#++</tt>'. + # + # I've seen guys that comment their code like this: + # # This method.... + # #----------------- + # def method + # + # => either we do it only in ruby code, or we require the leading # + # (to avoid conflict with rules). + # + # TODO: require the leading #, to provide the feature in simple text files. + # Note: in ruby & C code, we require '#--' & '#++' or '*--' & '*++', + # to allow rules: + # + # # this is a comment + # #--- + # # private text + # #+++ + # # this is a rule: + # # --- + + def test_remove_private_comments + parser = util_parser "foo\n\n--\nbar\n++\n\nbaz\n" + + parser.scan + + expected = "foo\n\n\nbaz" + + assert_equal expected, @top_level.comment.text + end + + def test_remove_private_comments_rule + parser = util_parser "foo\n---\nbar" + + parser.scan + + expected = "foo\n---\nbar" + + assert_equal expected, @top_level.comment.text + end + + def test_remove_private_comments_star + parser = util_parser "* foo\n* bar\n" + + parser.scan + + assert_equal "* foo\n* bar", @top_level.comment.text + end + + def test_scan + parser = util_parser 'it *really* works' + + parser.scan + + assert_equal 'it *really* works', @top_level.comment.text + end + + def util_parser(content) + RDoc::Parser::Simple.new @top_level, @fn, content, @options, @stats + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_rd.rb b/jni/ruby/test/rdoc/test_rdoc_rd.rb new file mode 100644 index 0000000..d917a63 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_rd.rb @@ -0,0 +1,30 @@ +require 'rdoc/test_case' + +class TestRDocRd < RDoc::TestCase + + def test_class_parse + expected = + @RM::Document.new( + @RM::Paragraph.new('hello')) + + assert_equal expected, RDoc::RD.parse("hello") + end + + def test_class_parse_begin_end + expected = + @RM::Document.new( + @RM::Paragraph.new('hello')) + + assert_equal expected, RDoc::RD.parse("=begin\nhello\n=end\n") + end + + def test_class_parse_newline + expected = + @RM::Document.new( + @RM::Paragraph.new('hello')) + + assert_equal expected, RDoc::RD.parse("hello\n") + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_rd_block_parser.rb b/jni/ruby/test/rdoc/test_rdoc_rd_block_parser.rb new file mode 100644 index 0000000..956f3d2 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_rd_block_parser.rb @@ -0,0 +1,535 @@ +require 'rdoc/test_case' + +class TestRDocRdBlockParser < RDoc::TestCase + + def setup + super + + @block_parser = RDoc::RD::BlockParser.new + end + + def test_add_footnote + index = @block_parser.add_footnote 'context' + + assert_equal 1, index + + expected = [ + para('{^1}[rdoc-label:footmark-1:foottext-1]', ' ', 'context'), + blank_line, + ] + + assert_equal expected, @block_parser.footnotes + + index = @block_parser.add_footnote 'other' + + assert_equal 2, index + end + + def test_parse_desclist + list = <<-LIST +:one + desc one +:two + desc two + LIST + + expected = + doc( + list(:NOTE, + item("one", para("desc one")), + item("two", para("desc two")))) + + assert_equal expected, parse(list) + end + + def test_parse_enumlist + list = <<-LIST +(1) one +(1) two + LIST + + expected = + doc( + list(:NUMBER, + item(nil, para("one")), + item(nil, para("two")))) + + assert_equal expected, parse(list) + end + + def test_parse_enumlist_paragraphs + list = <<-LIST +(1) one + + two + LIST + + expected = + doc( + list(:NUMBER, + item(nil, + para("one"), + para("two")))) + + assert_equal expected, parse(list) + end + + def test_parse_enumlist_multiline + list = <<-LIST +(1) one + two + LIST + + contents = "one\n two" # 1.8 vs 1.9 + + expected = + doc( + list(:NUMBER, + item(nil, para(*contents)))) + + assert_equal expected, parse(list) + end + + def test_parse_enumlist_verbatim + list = <<-LIST +(1) item + verbatim + LIST + + expected = + doc( + list(:NUMBER, + item(nil, + para("item"), + verb("verbatim\n")))) + + assert_equal expected, parse(list) + end + + def test_parse_enumlist_verbatim_continue + list = <<-LIST +(1) one + verbatim + two + LIST + + expected = + doc( + list(:NUMBER, + item(nil, + para("one"), + verb("verbatim\n"), + para("two")))) + + assert_equal expected, parse(list) + end + + def test_parse_footnote + expected = + doc( + para("{*1}[rdoc-label:foottext-1:footmark-1]"), + rule(1), + para("{^1}[rdoc-label:footmark-1:foottext-1]", " ", "text"), + blank_line) + + assert_equal expected, parse("((-text-))") + end + + def test_parse_include + @block_parser.include_path = [Dir.tmpdir] + + expected = doc(@RM::Include.new("parse_include", [Dir.tmpdir])) + + assert_equal expected, parse("<<< parse_include") + end + + def test_parse_include_subtree + @block_parser.include_path = [Dir.tmpdir] + + expected = + doc( + blank_line, + para("include <em>worked</em>"), + blank_line, + blank_line) + + tf = Tempfile.open %w[parse_include .rd] do |io| + io.puts "=begin\ninclude ((*worked*))\n=end" + io.flush + + str = <<-STR +<<< #{File.basename io.path} + STR + + assert_equal expected, parse(str) + io + end + tf.close! if tf.respond_to? :close! + end + + def test_parse_heading + assert_equal doc(head(1, "H")), parse("= H") + assert_equal doc(head(2, "H")), parse("== H") + assert_equal doc(head(3, "H")), parse("=== H") + assert_equal doc(head(4, "H")), parse("==== H") + assert_equal doc(head(5, "H")), parse("+ H") + assert_equal doc(head(6, "H")), parse("++ H") + end + + def test_parse_itemlist + list = <<-LIST +* one +* two + LIST + + expected = + doc( + list(:BULLET, + item(nil, para("one")), + item(nil, para("two")))) + + assert_equal expected, parse(list) + end + + def test_parse_itemlist_multiline + list = <<-LIST +* one + two + LIST + + contents = "one\n two" # 1.8 vs 1.9 + + expected = + doc( + list(:BULLET, + item(nil, para(*contents)))) + + assert_equal expected, parse(list) + end + + def test_parse_itemlist_nest + list = <<-LIST +* one + * inner +* two + LIST + + expected = + doc( + list(:BULLET, + item(nil, + para("one"), + list(:BULLET, + item(nil, para("inner")))), + item(nil, + para("two")))) + + assert_equal expected, parse(list) + end + + def test_parse_itemlist_paragraphs + list = <<-LIST +* one + + two + LIST + + expected = + doc( + list(:BULLET, + item(nil, + para("one"), + para("two")))) + + assert_equal expected, parse(list) + end + + def test_parse_itemlist_verbatim + list = <<-LIST +* item + verbatim + LIST + + expected = + doc( + list(:BULLET, + item(nil, + para("item"), + verb("verbatim\n")))) + + assert_equal expected, parse(list) + end + + def test_parse_itemlist_verbatim_continue + list = <<-LIST +* one + verbatim + two + LIST + + expected = + doc( + list(:BULLET, + item(nil, + para("one"), + verb("verbatim\n"), + para("two")))) + + assert_equal expected, parse(list) + end + + def test_parse_lists + list = <<-LIST +(1) one +(1) two +* three +* four +(1) five +(1) six + LIST + + expected = + doc( + list(:NUMBER, + item(nil, para("one")), + item(nil, para("two"))), + list(:BULLET, + item(nil, para("three")), + item(nil, para("four"))), + list(:NUMBER, + item(nil, para("five")), + item(nil, para("six")))) + + assert_equal expected, parse(list) + end + + def test_parse_lists_nest + list = <<-LIST +(1) one +(1) two + * three + * four +(1) five +(1) six + LIST + + expected = + doc( + list(:NUMBER, + item(nil, para("one")), + item(nil, + para("two"), + list(:BULLET, + item(nil, para("three")), + item(nil, para("four")))), + item(nil, para("five")), + item(nil, para("six")))) + + assert_equal expected, parse(list) + end + + def test_parse_lists_nest_verbatim + list = <<-LIST +(1) one +(1) two + * three + * four + verbatim +(1) five +(1) six + LIST + + expected = + doc( + list(:NUMBER, + item(nil, para("one")), + item(nil, + para("two"), + list(:BULLET, + item(nil, para("three")), + item(nil, para("four"))), + verb("verbatim\n")), + item(nil, para("five")), + item(nil, para("six")))) + + assert_equal expected, parse(list) + end + + def test_parse_lists_nest_verbatim2 + list = <<-LIST +(1) one +(1) two + * three + * four + verbatim +(1) five +(1) six + LIST + + expected = + doc( + list(:NUMBER, + item(nil, para("one")), + item(nil, + para("two"), + list(:BULLET, + item(nil, para("three")), + item(nil, para("four"))), + verb("verbatim\n")), + item(nil, para("five")), + item(nil, para("six")))) + + assert_equal expected, parse(list) + end + + def test_parse_methodlist + list = <<-LIST +--- Array#each {|i| ... } + yield block for each item. +--- Array#index(val) + return index of first item which equals with val. if it hasn't + same item, return nil. + LIST + + expected = + doc( + list(:LABEL, + item( + "<tt>Array#each {|i| ... }</tt>", + para("yield block for each item.")), + item( + "<tt>Array#index(val)</tt>", + para("return index of first item which equals with val. if it hasn't same item, return nil.")))) + + assert_equal expected, parse(list) + end + + def test_parse_methodlist_empty + list = <<-LIST +--- A#b + + LIST + + expected = + doc( + list(:LABEL, + item("<tt>A#b</tt>"))) + + assert_equal expected, parse(list) + end + + def test_parse_methodlist_paragraph + list = <<-LIST +--- A#b + + one + LIST + + expected = + doc( + list(:LABEL, + item( + "<tt>A#b</tt>", + para("one")))) + + assert_equal expected, parse(list) + end + + def test_parse_methodlist_paragraph2 + list = <<-LIST.chomp +--- A#b + + one +two + LIST + + expected = + doc( + list(:LABEL, + item( + "<tt>A#b</tt>", + para("one"))), + para("two")) + + assert_equal expected, parse(list) + end + + def test_parse_methodlist_paragraph_verbatim + list = <<-LIST.chomp +--- A#b + + text + verbatim + LIST + + expected = + doc( + list(:LABEL, + item( + "<tt>A#b</tt>", + para("text"), + verb("verbatim\n")))) + + assert_equal expected, parse(list) + end + + def test_parse_verbatim + assert_equal doc(verb("verbatim\n")), parse(" verbatim") + end + + def test_parse_verbatim_blankline + expected = doc(verb("one\n", "\n", "two\n")) + + verbatim = <<-VERBATIM + one + + two + VERBATIM + + assert_equal expected, parse(verbatim) + end + + def test_parse_verbatim_indent + expected = doc(verb("one\n", " two\n")) + + verbatim = <<-VERBATIM + one + two + VERBATIM + + assert_equal expected, parse(verbatim) + end + + def test_parse_verbatim_multi + expected = doc(verb("one\n", "two\n")) + + verbatim = <<-VERBATIM + one + two + VERBATIM + + assert_equal expected, parse(verbatim) + end + + def test_parse_textblock + assert_equal doc(para("text")), parse("text") + end + + def test_parse_textblock_multi + expected = doc(para("one two")) + + assert_equal expected, parse("one\ntwo") + end + + def parse text + text = ["=begin", text, "=end"].join "\n" + + doc = @block_parser.parse text.lines.to_a + + assert_equal blank_line, doc.parts.shift, "=begin blankline" + assert_equal blank_line, doc.parts.pop, "=end blankline" + + doc + end + +end diff --git a/jni/ruby/test/rdoc/test_rdoc_rd_inline.rb b/jni/ruby/test/rdoc/test_rdoc_rd_inline.rb new file mode 100644 index 0000000..d601ecc --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_rd_inline.rb @@ -0,0 +1,63 @@ +require 'rdoc/test_case' + +class TestRDocRdInline < RDoc::TestCase + + def setup + super + + @inline = RDoc::RD::Inline.new '+text+', 'text' + end + + def test_class_new + inline = RDoc::RD::Inline.new @inline + + refute_equal inline.rdoc, inline.reference + end + + def test_initialize + inline = RDoc::RD::Inline.new 'text' + + assert_equal inline.rdoc, inline.reference + refute_same inline.rdoc, inline.reference + end + + def test_initialize_inline + inline = RDoc::RD::Inline.new @inline + + assert_equal '+text+', inline.rdoc + assert_equal 'text', inline.reference + end + + def test_append_inline + out = @inline.append @inline + + assert_same @inline, out + + assert_equal '+text++text+', @inline.rdoc + assert_equal 'texttext', @inline.reference + end + + def test_append_string + @inline.append ' more' + + assert_equal '+text+ more', @inline.rdoc + assert_equal 'text more', @inline.reference + end + + def test_equals2 + assert_equal @inline, RDoc::RD::Inline.new('+text+', 'text') + refute_equal @inline, RDoc::RD::Inline.new('+text+', 'other') + refute_equal @inline, RDoc::RD::Inline.new('+other+', 'text') + refute_equal @inline, Object.new + end + + def test_inspect + assert_equal '(inline: +text+)', @inline.inspect + end + + def test_to_s + assert_equal '+text+', @inline.to_s + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_rd_inline_parser.rb b/jni/ruby/test/rdoc/test_rdoc_rd_inline_parser.rb new file mode 100644 index 0000000..e4a765b --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_rd_inline_parser.rb @@ -0,0 +1,177 @@ +require 'rdoc/test_case' + +class TestRDocRdInlineParser < RDoc::TestCase + + def setup + super + + @block_parser = RDoc::RD::BlockParser.new + @block_parser.instance_variable_set :@i, 0 + @inline_parser = RDoc::RD::InlineParser.new @block_parser + end + + def test_parse + assert_equal 'regular <em>emphasis</em>', parse('regular ((*emphasis*))') + end + + def test_parse_code + assert_equal '<code>text</code>', parse('(({text}))') + end + + def test_parse_em + assert_equal '<em>text</em>', parse('((*text*))') + end + + def test_parse_footnote + assert_equal '{*1}[rdoc-label:foottext-1:footmark-1]', parse('((-text-))') + + expected = [ + @RM::Paragraph.new('{^1}[rdoc-label:footmark-1:foottext-1]', ' ', 'text'), + blank_line, + ] + + assert_equal expected, @block_parser.footnotes + end + + def test_parse_index + assert_equal '<span id="label-text">text</span>', parse('((:text:))') + + assert_includes @block_parser.labels, 'text' + end + + def test_parse_kbd + assert_equal '<tt>text</tt>', parse('((%text%))') + end + + def test_parse_multiple + assert_equal '<em>one</em> <em>two</em>', parse('((*one*)) ((*two*))') + end + + def test_parse_newline + assert_equal "one\ntwo", parse("one\ntwo") + end + + def test_parse_quote + assert_equal 'one " two', parse('one " two') + end + + def test_parse_ref + assert_equal '{text}[rdoc-label:text]', parse('((<text>))') + end + + def test_parse_ref_em + assert_equal '{<em>text</em>}[rdoc-label:text]', parse('((<((*text*))>))') + end + + def test_parse_ref_filename_quote + assert_equal '{RD/foo}[rdoc-label:RD/foo]', parse('((<RD/"foo">))') + end + + def test_parse_ref_filename + assert_equal '{RD}[rdoc-label:RD/]', parse('((<RD/>))') + end + + def test_parse_ref_quote + assert_equal '{text \\"}[rdoc-label:text \\"]', parse('((<text \">))') + end + + def test_parse_ref_quote_content + assert_equal '{<em>text</em>}[rdoc-label:text]', + parse('((<"((*text*))">))') + end + + def test_parse_ref_quote_content_multi + assert_equal '{<em>one</em> <em>two</em>}[rdoc-label:one two]', + parse('((<"((*one*)) ((*two*))">))') + end + + def test_parse_ref_substitute + assert_equal '{text}[rdoc-label:thing]', parse('((<text|thing>))') + end + + def test_parse_ref_substitute_element_quote + assert_equal '{text}[rdoc-label:"RD"]', + parse('((<text|"RD">))') + end + + def test_parse_ref_substitute_filename + assert_equal '{text}[rdoc-label:RD/]', parse('((<text|RD/>))') + end + + def test_parse_ref_substitute_filename_label + assert_equal '{text}[rdoc-label:RD/label]', + parse('((<text|RD/label>))') + end + + def test_parse_ref_substitute_filename_quote + assert_equal '{text}[rdoc-label:"RD"/]', parse('((<text|"RD"/>))') + end + + def test_parse_ref_substitute_multi_content + assert_equal '{<em>one</em> two}[rdoc-label:thing]', + parse('((<((*one*)) two|thing>))') + end + + def test_parse_ref_substitute_multi_content2 + assert_equal '{<em>one</em> \\" two}[rdoc-label:thing]', + parse('((<((*one*)) \" two|thing>))') + end + + def test_parse_ref_substitute_multi_content3 + assert_equal '{<em>one</em> \\" <em>two</em>}[rdoc-label:thing]', + parse('((<((*one*)) \" ((*two*))|thing>))') + end + + def test_parse_ref_substitute_quote + assert_equal '{one | two}[rdoc-label:thing]', + parse('((<"one | two"|thing>))') + end + + def test_parse_ref_substitute_quote_content + assert_equal '{<em>text</em>}[rdoc-label:thing]', + parse('((<"((*text*))"|thing>))') + end + + def test_parse_ref_substitute_url + assert_equal '{text}[http://example]', + parse('((<text|URL:http://example>))') + end + + def test_parse_ref_url + assert_equal '{http://example}[http://example]', + parse('((<URL:http://example>))') + end + + def test_parse_var + assert_equal '+text+', parse('((|text|))') + end + + def test_parse_verb + assert_equal '<tt>text</tt>', parse("(('text'))") + end + + def test_parse_verb_backslash + assert_equal "<tt>(('text'))</tt>", parse("(('(('text\\'))'))") + end + + def test_parse_verb_backslash_backslash + assert_equal '<tt>text \\</tt>', parse("(('text \\\\'))") + end + + def test_parse_verb_backslash_quote + assert_equal '<tt>text "</tt>', parse("(('text \\\"'))") + end + + def test_parse_verb_emphasis + assert_equal '<tt>((*emphasis*))</tt>', parse("(('((*emphasis*))'))") + end + + def test_parse_verb_multiple + assert_equal '<tt>((*text*))</tt>', parse("(('((*text*))'))") + end + + def parse text + @inline_parser.parse text + end + +end diff --git a/jni/ruby/test/rdoc/test_rdoc_rdoc.rb b/jni/ruby/test/rdoc/test_rdoc_rdoc.rb new file mode 100644 index 0000000..230c18f --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_rdoc.rb @@ -0,0 +1,455 @@ +require 'rdoc/test_case' + +class TestRDocRDoc < RDoc::TestCase + + def setup + super + + @rdoc = RDoc::RDoc.new + @rdoc.options = RDoc::Options.new + + @stats = RDoc::Stats.new @store, 0, 0 + @rdoc.instance_variable_set :@stats, @stats + end + + def test_document # functional test + options = RDoc::Options.new + options.files = [File.expand_path('../xref_data.rb', __FILE__)] + options.setup_generator 'ri' + options.main_page = 'MAIN_PAGE.rdoc' + options.root = Pathname File.expand_path('..', __FILE__) + options.title = 'title' + + rdoc = RDoc::RDoc.new + + temp_dir do + options.op_dir = 'ri' + + capture_io do + rdoc.document options + end + + assert File.directory? 'ri' + assert_equal rdoc, rdoc.store.rdoc + end + + store = rdoc.store + + assert_equal 'MAIN_PAGE.rdoc', store.main + assert_equal 'title', store.title + end + + def test_gather_files + a = File.expand_path __FILE__ + b = File.expand_path '../test_rdoc_text.rb', __FILE__ + + assert_equal [a, b], @rdoc.gather_files([b, a, b]) + end + + def test_handle_pipe + $stdin = StringIO.new "hello" + + out, = capture_io do + @rdoc.handle_pipe + end + + assert_equal "\n<p>hello</p>\n", out + ensure + $stdin = STDIN + end + + def test_handle_pipe_rd + $stdin = StringIO.new "=begin\nhello\n=end" + + @rdoc.options.markup = 'rd' + + out, = capture_io do + @rdoc.handle_pipe + end + + assert_equal "\n<p>hello</p>\n", out + ensure + $stdin = STDIN + end + + def test_load_options + temp_dir do + options = RDoc::Options.new + options.markup = 'tomdoc' + options.write_options + + options = @rdoc.load_options + + assert_equal 'tomdoc', options.markup + end + end + + def test_load_options_invalid + temp_dir do + open '.rdoc_options', 'w' do |io| + io.write "a: !ruby.yaml.org,2002:str |\nfoo" + end + + e = assert_raises RDoc::Error do + @rdoc.load_options + end + + options_file = File.expand_path '.rdoc_options' + assert_equal "#{options_file} is not a valid rdoc options file", e.message + end + end + + def load_options_no_file + temp_dir do + options = @rdoc.load_options + + assert_kind_of RDoc::Options, options + end + end + + def test_normalized_file_list + files = temp_dir do |dir| + flag_file = @rdoc.output_flag_file dir + + FileUtils.touch flag_file + + @rdoc.normalized_file_list [__FILE__, flag_file] + end + + files = files.map { |file| File.expand_path file } + + assert_equal [File.expand_path(__FILE__)], files + end + + def test_normalized_file_list_not_modified + files = [__FILE__] + + @rdoc.last_modified[__FILE__] = File.stat(__FILE__).mtime + + files = @rdoc.normalized_file_list [__FILE__] + + assert_empty files + end + + def test_normalized_file_list_non_file_directory + dev = defined?(File::NULL) ? File::NULL : '/dev/stdin' + skip "#{dev} is not a character special" unless + File.chardev? dev + + files = nil + + out, err = verbose_capture_io do + files = @rdoc.normalized_file_list [dev] + end + + files = files.map { |file| File.expand_path file } + + assert_empty files + + assert_empty out + assert_match %r"^rdoc can't parse", err + assert_match %r"#{dev}$", err + end + + def test_parse_file + @rdoc.store = RDoc::Store.new + + temp_dir do |dir| + @rdoc.options.root = Pathname(Dir.pwd) + + open 'test.txt', 'w' do |io| + io.puts 'hi' + end + + top_level = @rdoc.parse_file 'test.txt' + + assert_equal 'test.txt', top_level.absolute_name + assert_equal 'test.txt', top_level.relative_name + end + end + + def test_parse_file_binary + @rdoc.store = RDoc::Store.new + + root = File.dirname __FILE__ + + @rdoc.options.root = Pathname root + + out, err = capture_io do + Dir.chdir root do + assert_nil @rdoc.parse_file 'binary.dat' + end + end + + assert_empty out + assert_empty err + end + + def test_parse_file_include_root + @rdoc.store = RDoc::Store.new + + top_level = nil + temp_dir do |dir| + @rdoc.options.parse %W[--root #{File.dirname(__FILE__)}] + + open 'include.txt', 'w' do |io| + io.puts ':include: test.txt' + end + + out, err = capture_io do + top_level = @rdoc.parse_file 'include.txt' + end + assert_empty out + assert_empty err + end + assert_equal "test file", top_level.comment.text + end + + def test_parse_file_page_dir + @rdoc.store = RDoc::Store.new + + temp_dir do |dir| + FileUtils.mkdir 'pages' + @rdoc.options.page_dir = Pathname('pages') + @rdoc.options.root = Pathname(Dir.pwd) + + open 'pages/test.txt', 'w' do |io| + io.puts 'hi' + end + + top_level = @rdoc.parse_file 'pages/test.txt' + + assert_equal 'pages/test.txt', top_level.absolute_name + assert_equal 'test.txt', top_level.relative_name + end + end + + def test_parse_file_relative + pwd = Dir.pwd + + @rdoc.store = RDoc::Store.new + + temp_dir do |dir| + @rdoc.options.root = Pathname(dir) + + open 'test.txt', 'w' do |io| + io.puts 'hi' + end + + test_txt = File.join dir, 'test.txt' + + Dir.chdir pwd do + top_level = @rdoc.parse_file test_txt + + assert_equal test_txt, top_level.absolute_name + assert_equal 'test.txt', top_level.relative_name + end + end + end + + def test_parse_file_encoding + skip "Encoding not implemented" unless Object.const_defined? :Encoding + @rdoc.options.encoding = Encoding::ISO_8859_1 + @rdoc.store = RDoc::Store.new + + tf = Tempfile.open 'test.txt' do |io| + io.write 'hi' + io.rewind + + top_level = @rdoc.parse_file io.path + + assert_equal Encoding::ISO_8859_1, top_level.absolute_name.encoding + io + end + tf.close! if tf.respond_to? :close! + end + + def test_parse_file_forbidden + skip 'chmod not supported' if Gem.win_platform? + + @rdoc.store = RDoc::Store.new + + tf = Tempfile.open 'test.txt' do |io| + io.write 'hi' + io.rewind + + File.chmod 0000, io.path + + begin + top_level = :bug + + _, err = capture_io do + top_level = @rdoc.parse_file io.path + end + + assert_match "Unable to read #{io.path},", err + + assert_nil top_level + ensure + File.chmod 0400, io.path + end + io + end + tf.close! if tf.respond_to? :close! + end + + def test_remove_unparseable + file_list = %w[ + blah.class + blah.eps + blah.erb + blah.scpt.txt + blah.ttf + blah.yml + ] + + assert_empty @rdoc.remove_unparseable file_list + end + + def test_remove_unparseable_tags_emacs + temp_dir do + open 'TAGS', 'wb' do |io| # emacs + io.write "\f\nlib/foo.rb,43\n" + end + + file_list = %w[ + TAGS + ] + + assert_empty @rdoc.remove_unparseable file_list + end + end + + def test_remove_unparseable_tags_vim + temp_dir do + open 'TAGS', 'w' do |io| # emacs + io.write "!_TAG_" + end + + file_list = %w[ + TAGS + ] + + assert_empty @rdoc.remove_unparseable file_list + end + end + + def test_setup_output_dir + Dir.mktmpdir {|d| + path = File.join d, 'testdir' + + last = @rdoc.setup_output_dir path, false + + assert_empty last + + assert File.directory? path + assert File.exist? @rdoc.output_flag_file path + } + end + + def test_setup_output_dir_dry_run + @rdoc.options.dry_run = true + + Dir.mktmpdir do |d| + path = File.join d, 'testdir' + + @rdoc.setup_output_dir path, false + + refute File.exist? path + end + end + + def test_setup_output_dir_exists + Dir.mktmpdir {|path| + open @rdoc.output_flag_file(path), 'w' do |io| + io.puts Time.at 0 + io.puts "./lib/rdoc.rb\t#{Time.at 86400}" + end + + last = @rdoc.setup_output_dir path, false + + assert_equal 1, last.size + assert_equal Time.at(86400), last['./lib/rdoc.rb'] + } + end + + def test_setup_output_dir_exists_empty_created_rid + Dir.mktmpdir {|path| + open @rdoc.output_flag_file(path), 'w' do end + + e = assert_raises RDoc::Error do + @rdoc.setup_output_dir path, false + end + + assert_match %r%Directory #{Regexp.escape path} already exists%, e.message + } + end + + def test_setup_output_dir_exists_file + tf = Tempfile.open 'test_rdoc_rdoc' do |tempfile| + path = tempfile.path + + e = assert_raises RDoc::Error do + @rdoc.setup_output_dir path, false + end + + assert_match(%r%#{Regexp.escape path} exists and is not a directory%, + e.message) + tempfile + end + tf.close! if tf.respond_to? :close! + end + + def test_setup_output_dir_exists_not_rdoc + Dir.mktmpdir do |dir| + e = assert_raises RDoc::Error do + @rdoc.setup_output_dir dir, false + end + + assert_match %r%Directory #{Regexp.escape dir} already exists%, e.message + end + end + + def test_update_output_dir + Dir.mktmpdir do |d| + @rdoc.update_output_dir d, Time.now, {} + + assert File.exist? "#{d}/created.rid" + end + end + + def test_update_output_dir_dont + Dir.mktmpdir do |d| + @rdoc.options.update_output_dir = false + @rdoc.update_output_dir d, Time.now, {} + + refute File.exist? "#{d}/created.rid" + end + end + + def test_update_output_dir_dry_run + Dir.mktmpdir do |d| + @rdoc.options.dry_run = true + @rdoc.update_output_dir d, Time.now, {} + + refute File.exist? "#{d}/created.rid" + end + end + + def test_normalized_file_list_removes_created_rid_dir + temp_dir do |d| + FileUtils.mkdir "doc" + flag_file = @rdoc.output_flag_file "doc" + file = File.join "doc", "test" + FileUtils.touch flag_file + FileUtils.touch file + + file_list = ["doc"] + + output = @rdoc.normalized_file_list file_list + + assert_empty output + end + end +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_require.rb b/jni/ruby/test/rdoc/test_rdoc_require.rb new file mode 100644 index 0000000..b7995af --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_require.rb @@ -0,0 +1,25 @@ +require File.expand_path '../xref_test_case', __FILE__ + +class TestRDocRequire < XrefTestCase + + def setup + super + + @req = RDoc::Require.new 'foo', 'comment' + end + + def test_initialize + assert_equal 'foo', @req.name + + req = RDoc::Require.new '"foo"', '' + assert_equal 'foo', @req.name + + req = RDoc::Require.new '\'foo\'', '' + assert_equal 'foo', @req.name + + req = RDoc::Require.new '|foo|', '' + assert_equal 'foo', @req.name, 'for fortran?' + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_ri_driver.rb b/jni/ruby/test/rdoc/test_rdoc_ri_driver.rb new file mode 100644 index 0000000..d0987a0 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_ri_driver.rb @@ -0,0 +1,1436 @@ +require 'rdoc/test_case' + +class TestRDocRIDriver < RDoc::TestCase + + def setup + super + + @tmpdir = File.join Dir.tmpdir, "test_rdoc_ri_driver_#{$$}" + @home_ri = File.join @tmpdir, 'dot_ri' + + FileUtils.mkdir_p @tmpdir + FileUtils.mkdir_p @home_ri + + @orig_ri = ENV['RI'] + @orig_home = ENV['HOME'] + ENV['HOME'] = @tmpdir + ENV.delete 'RI' + + @options = RDoc::RI::Driver.default_options + @options[:use_system] = false + @options[:use_site] = false + @options[:use_home] = false + @options[:use_gems] = false + + @options[:home] = @tmpdir + @options[:use_stdout] = true + @options[:formatter] = @RM::ToRdoc + + @driver = RDoc::RI::Driver.new @options + end + + def teardown + super + + ENV['HOME'] = @orig_home + ENV['RI'] = @orig_ri + FileUtils.rm_rf @tmpdir + end + + DUMMY_PAGER = ":;\n" + + def with_dummy_pager + pager_env, ENV['RI_PAGER'] = ENV['RI_PAGER'], DUMMY_PAGER + yield + ensure + ENV['RI_PAGER'] = pager_env + end + + def test_self_dump + util_store + + out, = capture_io do + RDoc::RI::Driver.dump @store1.cache_path + end + + assert_match %r%:class_methods%, out + assert_match %r%:modules%, out + assert_match %r%:instance_methods%, out + assert_match %r%:ancestors%, out + end + + def test_add_also_in_empty + out = @RM::Document.new + + @driver.add_also_in out, [] + + assert_empty out + end + + def test_add_also_in + util_multi_store + @store1.type = :system + @store2.type = :home + + out = @RM::Document.new + + @driver.add_also_in out, [@store1, @store2] + + expected = @RM::Document.new( + @RM::Rule.new(1), + @RM::Paragraph.new('Also found in:'), + @RM::Verbatim.new("ruby core", "\n", + "~/.rdoc", "\n")) + + assert_equal expected, out + end + + def test_add_class + util_multi_store + + out = @RM::Document.new + + @driver.add_class out, 'Bar', [@cBar] + + expected = @RM::Document.new( + @RM::Heading.new(1, 'Bar < Foo'), + @RM::BlankLine.new) + + assert_equal expected, out + end + + def test_add_from + util_store + @store1.type = :system + + out = @RM::Document.new + + @driver.add_from out, @store1 + + expected = @RM::Document.new @RM::Paragraph.new("(from ruby core)") + + assert_equal expected, out + end + + def test_add_extends + util_store + + out = @RM::Document.new + + @driver.add_extends out, [[[@cFooExt], @store1]] + + expected = @RM::Document.new( + @RM::Rule.new(1), + @RM::Heading.new(1, "Extended by:"), + @RM::Paragraph.new("Ext (from #{@store1.friendly_path})"), + @RM::BlankLine.new, + @RM::Paragraph.new("Extend thingy"), + @RM::BlankLine.new) + + assert_equal expected, out + end + + def test_add_extension_modules_empty + out = @RM::Document.new + + @driver.add_extension_modules out, 'Includes', [] + + assert_empty out + end + + def test_add_extension_modules_many + util_store + + out = @RM::Document.new + + enum = RDoc::Include.new 'Enumerable', nil + @cFoo.add_include enum + + @driver.add_extension_modules out, 'Includes', [[[@cFooInc, enum], @store1]] + + expected = @RM::Document.new( + @RM::Rule.new(1), + @RM::Heading.new(1, "Includes:"), + @RM::Paragraph.new("(from #{@store1.friendly_path})"), + @RM::BlankLine.new, + @RM::Paragraph.new("Inc"), + @RM::BlankLine.new, + @RM::Paragraph.new("Include thingy"), + @RM::BlankLine.new, + @RM::Verbatim.new("Enumerable", "\n")) + + assert_equal expected, out + end + + def test_add_extension_modules_many_no_doc + util_store + + out = @RM::Document.new + + enum = RDoc::Include.new 'Enumerable', nil + @cFoo.add_include enum + @cFooInc.instance_variable_set :@comment, '' + + @driver.add_extension_modules out, 'Includes', [[[@cFooInc, enum], @store1]] + + expected = @RM::Document.new( + @RM::Rule.new(1), + @RM::Heading.new(1, "Includes:"), + @RM::Paragraph.new("(from #{@store1.friendly_path})"), + @RM::Verbatim.new("Inc", "\n", + "Enumerable", "\n")) + + assert_equal expected, out + end + + def test_add_extension_modules_one + util_store + + out = @RM::Document.new + + @driver.add_extension_modules out, 'Includes', [[[@cFooInc], @store1]] + + expected = @RM::Document.new( + @RM::Rule.new(1), + @RM::Heading.new(1, "Includes:"), + @RM::Paragraph.new("Inc (from #{@store1.friendly_path})"), + @RM::BlankLine.new, + @RM::Paragraph.new("Include thingy"), + @RM::BlankLine.new) + + assert_equal expected, out + end + + def test_add_includes + util_store + + out = @RM::Document.new + + @driver.add_includes out, [[[@cFooInc], @store1]] + + expected = @RM::Document.new( + @RM::Rule.new(1), + @RM::Heading.new(1, "Includes:"), + @RM::Paragraph.new("Inc (from #{@store1.friendly_path})"), + @RM::BlankLine.new, + @RM::Paragraph.new("Include thingy"), + @RM::BlankLine.new) + + assert_equal expected, out + end + + def test_add_method + util_store + + out = doc + + @driver.add_method out, 'Foo::Bar#blah' + + expected = + doc( + head(1, 'Foo::Bar#blah'), + blank_line, + para('(from ~/.rdoc)'), + head(3, 'Implementation from Bar'), + rule(1), + verb("blah(5) => 5\n", + "blah(6) => 6\n"), + rule(1), + blank_line, + blank_line) + + assert_equal expected, out + end + + def test_add_method_attribute + util_store + + out = doc + + @driver.add_method out, 'Foo::Bar#attr' + + expected = + doc( + head(1, 'Foo::Bar#attr'), + blank_line, + para('(from ~/.rdoc)'), + rule(1), + blank_line, + blank_line) + + assert_equal expected, out + end + + def test_add_method_inherited + util_multi_store + + out = doc + + @driver.add_method out, 'Bar#inherit' + + expected = + doc( + head(1, 'Bar#inherit'), + blank_line, + para('(from ~/.rdoc)'), + head(3, 'Implementation from Foo'), + rule(1), + blank_line, + blank_line) + + assert_equal expected, out + end + + def test_add_method_overriden + util_multi_store + + out = doc + + @driver.add_method out, 'Bar#override' + + expected = + doc( + head(1, 'Bar#override'), + blank_line, + para("(from #{@store2.path})"), + rule(1), + blank_line, + para('must be displayed'), + blank_line, + blank_line) + + assert_equal expected, out + end + + def test_add_method_documentation + util_store + + out = doc() + + missing = RDoc::AnyMethod.new nil, 'missing' + @cFoo.add_method missing + + @driver.add_method_documentation out, @cFoo + + expected = + doc( + head(1, 'Foo#inherit'), + blank_line, + para('(from ~/.rdoc)'), + rule(1), + blank_line, + blank_line, + head(1, 'Foo#override'), + blank_line, + para('(from ~/.rdoc)'), + rule(1), + blank_line, + para('must not be displayed in Bar#override'), + blank_line, + blank_line) + + assert_equal expected, out + end + + def test_add_method_list + out = @RM::Document.new + + @driver.add_method_list out, %w[new parse], 'Class methods' + + expected = @RM::Document.new( + @RM::Heading.new(1, 'Class methods:'), + @RM::BlankLine.new, + @RM::Verbatim.new('new'), + @RM::Verbatim.new('parse'), + @RM::BlankLine.new) + + assert_equal expected, out + end + + def test_add_method_list_interative + @options[:interactive] = true + driver = RDoc::RI::Driver.new @options + + out = @RM::Document.new + + driver.add_method_list out, %w[new parse], 'Class methods' + + expected = @RM::Document.new( + @RM::Heading.new(1, 'Class methods:'), + @RM::BlankLine.new, + @RM::IndentedParagraph.new(2, 'new, parse'), + @RM::BlankLine.new) + + assert_equal expected, out + end + + def test_add_method_list_none + out = @RM::Document.new + + @driver.add_method_list out, [], 'Class' + + assert_equal @RM::Document.new, out + end + + def test_ancestors_of + util_ancestors_store + + assert_equal %w[X Mixin Object Foo], @driver.ancestors_of('Foo::Bar') + end + + def test_classes + util_multi_store + + expected = { + 'Ambiguous' => [@store1, @store2], + 'Bar' => [@store2], + 'Ext' => [@store1], + 'Foo' => [@store1, @store2], + 'Foo::Bar' => [@store1], + 'Foo::Baz' => [@store1, @store2], + 'Inc' => [@store1], + } + + classes = @driver.classes + + assert_equal expected.keys.sort, classes.keys.sort + + expected.each do |klass, stores| + assert_equal stores, classes[klass].sort_by { |store| store.path }, + "mismatch for #{klass}" + end + end + + def test_class_document + util_store + + tl1 = @store1.add_file 'one.rb' + tl2 = @store1.add_file 'two.rb' + + @cFoo.add_comment 'one', tl1 + @cFoo.add_comment 'two', tl2 + + @store1.save_class @cFoo + + found = [ + [@store1, @store1.load_class(@cFoo.full_name)] + ] + + extends = [[[@cFooExt], @store1]] + includes = [[[@cFooInc], @store1]] + + out = @driver.class_document @cFoo.full_name, found, [], includes, extends + + expected = @RM::Document.new + @driver.add_class expected, 'Foo', [] + @driver.add_includes expected, includes + @driver.add_extends expected, extends + @driver.add_from expected, @store1 + expected << @RM::Rule.new(1) + + doc = @RM::Document.new(@RM::Paragraph.new('one')) + doc.file = 'one.rb' + expected.push doc + expected << @RM::BlankLine.new + doc = @RM::Document.new(@RM::Paragraph.new('two')) + doc.file = 'two.rb' + expected.push doc + + expected << @RM::Rule.new(1) + expected << @RM::Heading.new(1, 'Instance methods:') + expected << @RM::BlankLine.new + expected << @RM::Verbatim.new('inherit') + expected << @RM::Verbatim.new('override') + expected << @RM::BlankLine.new + + assert_equal expected, out + end + + def test_complete + store = RDoc::RI::Store.new @home_ri + store.cache[:ancestors] = { + 'Foo' => %w[Object], + 'Foo::Bar' => %w[Object], + } + store.cache[:class_methods] = { + 'Foo' => %w[bar] + } + store.cache[:instance_methods] = { + 'Foo' => %w[Bar] + } + store.cache[:modules] = %w[ + Foo + Foo::Bar + ] + + @driver.stores = [store] + + assert_equal %w[Foo ], @driver.complete('F') + assert_equal %w[ Foo::Bar], @driver.complete('Foo::B') + + assert_equal %w[Foo#Bar], @driver.complete('Foo#'), 'Foo#' + assert_equal %w[Foo#Bar Foo::bar], @driver.complete('Foo.'), 'Foo.' + assert_equal %w[Foo::Bar Foo::bar], @driver.complete('Foo::'), 'Foo::' + + assert_equal %w[ Foo::bar], @driver.complete('Foo::b'), 'Foo::b' + end + + def test_complete_ancestor + util_ancestors_store + + assert_equal %w[Foo::Bar#i_method], @driver.complete('Foo::Bar#') + + assert_equal %w[Foo::Bar#i_method Foo::Bar::c_method Foo::Bar::new], + @driver.complete('Foo::Bar.') + end + + def test_complete_classes + util_store + + assert_equal %w[ ], @driver.complete('[') + assert_equal %w[ ], @driver.complete('[::') + assert_equal %w[Foo ], @driver.complete('F') + assert_equal %w[Foo:: Foo::Bar Foo::Baz], @driver.complete('Foo::') + assert_equal %w[ Foo::Bar Foo::Baz], @driver.complete('Foo::B') + end + + def test_complete_multistore + util_multi_store + + assert_equal %w[Bar], @driver.complete('B') + assert_equal %w[Foo], @driver.complete('F') + assert_equal %w[Foo::Bar Foo::Baz], @driver.complete('Foo::B') + end + + def test_display + doc = @RM::Document.new( + @RM::Paragraph.new('hi')) + + out, = capture_io do + @driver.display doc + end + + assert_equal "hi\n", out + end + + def test_display_class + util_store + + out, = capture_io do + @driver.display_class 'Foo::Bar' + end + + assert_match %r%^= Foo::Bar%, out + assert_match %r%^\(from%, out + + assert_match %r%^= Class methods:%, out + assert_match %r%^ new%, out + assert_match %r%^= Instance methods:%, out + assert_match %r%^ blah%, out + assert_match %r%^= Attributes:%, out + assert_match %r%^ attr_accessor attr%, out + + assert_equal 1, out.scan(/-\n/).length + + refute_match %r%Foo::Bar#blah%, out + end + + def test_display_class_all + util_store + + @driver.show_all = true + + out, = capture_io do + @driver.display_class 'Foo::Bar' + end + + assert_match %r%^= Foo::Bar%, out + assert_match %r%^\(from%, out + + assert_match %r%^= Class methods:%, out + assert_match %r%^ new%, out + assert_match %r%^= Instance methods:%, out + assert_match %r%^ blah%, out + assert_match %r%^= Attributes:%, out + assert_match %r%^ attr_accessor attr%, out + + assert_equal 6, out.scan(/-\n/).length + + assert_match %r%Foo::Bar#blah%, out + end + + def test_display_class_ambiguous + util_multi_store + + out, = capture_io do + @driver.display_class 'Ambiguous' + end + + assert_match %r%^= Ambiguous < Object$%, out + end + + def test_display_class_multi_no_doc + util_multi_store + + out, = capture_io do + @driver.display_class 'Foo::Baz' + end + + assert_match %r%^= Foo::Baz%, out + assert_match %r%-\n%, out + assert_match %r%Also found in:%, out + assert_match %r%#{Regexp.escape @home_ri}%, out + assert_match %r%#{Regexp.escape @home_ri2}%, out + end + + def test_display_class_superclass + util_multi_store + + out, = capture_io do + @driver.display_class 'Bar' + end + + assert_match %r%^= Bar < Foo%, out + end + + def test_display_class_module + util_store + + out, = capture_io do + @driver.display_class 'Inc' + end + + assert_match %r%^= Inc$%, out + end + + def test_display_class_page + out, = capture_io do + @driver.display_class 'ruby:README' + end + + assert_empty out + end + + def test_display_method + util_store + + out, = capture_io do + @driver.display_method 'Foo::Bar#blah' + end + + assert_match %r%Foo::Bar#blah%, out + assert_match %r%blah.5%, out + assert_match %r%blah.6%, out + end + + def test_display_method_attribute + util_store + + out, = capture_io do + @driver.display_method 'Foo::Bar#attr' + end + + assert_match %r%Foo::Bar#attr%, out + refute_match %r%Implementation from%, out + end + + def test_display_method_inherited + util_multi_store + + out, = capture_io do + @driver.display_method 'Bar#inherit' + end + + assert_match %r%^= Bar#inherit%, out + assert_match %r%^=== Implementation from Foo%, out + end + + def test_display_method_overriden + util_multi_store + + out, = capture_io do + @driver.display_method 'Bar#override' + end + + refute_match %r%must not be displayed%, out + end + + def test_display_name_not_found_class + util_store + + out, = capture_io do + assert_equal false, @driver.display_name('Foo::B') + end + + expected = <<-EXPECTED +Foo::B not found, maybe you meant: + +Foo::Bar +Foo::Baz + EXPECTED + + assert_equal expected, out + end + + def test_display_name_not_found_method + util_store + + out, = capture_io do + assert_equal false, @driver.display_name('Foo::Bar#b') + end + + expected = <<-EXPECTED +Foo::Bar#b not found, maybe you meant: + +Foo::Bar#blah +Foo::Bar#bother + EXPECTED + + assert_equal expected, out + end + + def test_display_name_not_found_special + util_store + + assert_raises RDoc::RI::Driver::NotFoundError do + assert_equal false, @driver.display_name('Set#[]') + end + end + + def test_display_method_params + util_store + + out, = capture_io do + @driver.display_method 'Foo::Bar#bother' + end + + assert_match %r%things.*stuff%, out + end + + def test_display_page + util_store + + out, = capture_io do + @driver.display_page 'home:README.rdoc' + end + + assert_match %r%= README%, out + end + + def test_display_page_add_extension + util_store + + out, = capture_io do + @driver.display_page 'home:README' + end + + assert_match %r%= README%, out + end + + def test_display_page_ambiguous + util_store + + other = @store1.add_file 'README.md' + other.parser = RDoc::Parser::Simple + other.comment = + doc( + head(1, 'README.md'), + para('This is the other README')) + + @store1.save_page other + + out, = capture_io do + @driver.display_page 'home:README' + end + + assert_match %r%= README pages in ~/\.rdoc%, out + assert_match %r%README\.rdoc%, out + assert_match %r%README\.md%, out + end + + def test_display_page_extension + util_store + + other = @store1.add_file 'README.EXT' + other.parser = RDoc::Parser::Simple + other.comment = + doc( + head(1, 'README.EXT'), + para('This is the other README')) + + @store1.save_page other + + out, = capture_io do + @driver.display_page 'home:README.EXT' + end + + assert_match 'other README', out + end + + def test_display_page_ignore_directory + util_store + + other = @store1.add_file 'doc/globals.rdoc' + other.parser = RDoc::Parser::Simple + other.comment = + doc( + head(1, 'globals.rdoc'), + para('Globals go here')) + + @store1.save_page other + + out, = capture_io do + @driver.display_page 'home:globals' + end + + assert_match %r%= globals\.rdoc%, out + end + + def test_display_page_missing + util_store + + out, = capture_io do + @driver.display_page 'home:missing' + end + + out, = capture_io do + @driver.display_page_list @store1 + end + + assert_match %r%= Pages in ~/\.rdoc%, out + assert_match %r%README\.rdoc%, out + end + + def test_display_page_list + util_store + + other = @store1.add_file 'OTHER.rdoc' + other.parser = RDoc::Parser::Simple + other.comment = + doc( + head(1, 'OTHER'), + para('This is OTHER')) + + @store1.save_page other + + out, = capture_io do + @driver.display_page_list @store1 + end + + assert_match %r%= Pages in ~/\.rdoc%, out + assert_match %r%README\.rdoc%, out + assert_match %r%OTHER\.rdoc%, out + end + + def test_expand_class + util_store + + assert_equal 'Foo', @driver.expand_class('F') + assert_equal 'Foo::Bar', @driver.expand_class('F::Bar') + + assert_raises RDoc::RI::Driver::NotFoundError do + @driver.expand_class 'F::B' + end + end + + def test_expand_name + util_store + + assert_equal '.b', @driver.expand_name('b') + assert_equal 'Foo', @driver.expand_name('F') + assert_equal 'Foo::Bar#', @driver.expand_name('F::Bar#') + + e = assert_raises RDoc::RI::Driver::NotFoundError do + @driver.expand_name 'Z' + end + + assert_equal 'Z', e.name + + @driver.stores << RDoc::Store.new(nil, :system) + + assert_equal 'ruby:README', @driver.expand_name('ruby:README') + assert_equal 'ruby:', @driver.expand_name('ruby:') + + e = assert_raises RDoc::RI::Driver::NotFoundError do + @driver.expand_name 'nonexistent_gem:' + end + + assert_equal 'nonexistent_gem', e.name + end + + def test_find_methods + util_store + + items = [] + + @driver.find_methods 'Foo::Bar.' do |store, klass, ancestor, types, method| + items << [store, klass, ancestor, types, method] + end + + expected = [ + [@store1, 'Foo::Bar', 'Foo::Bar', :both, nil], + ] + + assert_equal expected, items + end + + def test_find_methods_method + util_store + + items = [] + + @driver.find_methods '.blah' do |store, klass, ancestor, types, method| + items << [store, klass, ancestor, types, method] + end + + expected = [ + [@store1, 'Ambiguous', 'Ambiguous', :both, 'blah'], + [@store1, 'Ext', 'Ext', :both, 'blah'], + [@store1, 'Foo', 'Foo', :both, 'blah'], + [@store1, 'Foo::Bar', 'Foo::Bar', :both, 'blah'], + [@store1, 'Foo::Baz', 'Foo::Baz', :both, 'blah'], + [@store1, 'Inc', 'Inc', :both, 'blah'], + ] + + assert_equal expected, items + end + + def test_filter_methods + util_multi_store + + name = 'Bar#override' + + found = @driver.load_methods_matching name + + sorted = @driver.filter_methods found, name + + expected = [[@store2, [@override]]] + + assert_equal expected, sorted + end + + def test_filter_methods_not_found + util_multi_store + + name = 'Bar#inherit' + + found = @driver.load_methods_matching name + + sorted = @driver.filter_methods found, name + + assert_equal found, sorted + end + + def test_find_store + @driver.stores << RDoc::Store.new(nil, :system) + @driver.stores << RDoc::Store.new('doc/gem-1.0/ri', :gem) + + assert_equal 'ruby', @driver.find_store('ruby') + assert_equal 'gem-1.0', @driver.find_store('gem-1.0') + assert_equal 'gem-1.0', @driver.find_store('gem') + + e = assert_raises RDoc::RI::Driver::NotFoundError do + @driver.find_store 'nonexistent' + end + + assert_equal 'nonexistent', e.name + end + + def test_formatter + tty = Object.new + def tty.tty?() true; end + + @options.delete :use_stdout + @options.delete :formatter + + driver = RDoc::RI::Driver.new @options + + assert_instance_of @RM::ToAnsi, driver.formatter(tty) + + assert_instance_of @RM::ToBs, driver.formatter(StringIO.new) + + driver.instance_variable_set :@paging, true + + assert_instance_of @RM::ToBs, driver.formatter(StringIO.new) + end + + def test_in_path_eh + path = ENV['PATH'] + + test_path = File.expand_path '..', __FILE__ + + temp_dir do |dir| + nonexistent = File.join dir, 'nonexistent' + refute @driver.in_path?(nonexistent) + + ENV['PATH'] = test_path + + assert @driver.in_path?(File.basename(__FILE__)) + end + ensure + ENV['PATH'] = path + end + + def test_method_type + assert_equal :both, @driver.method_type(nil) + assert_equal :both, @driver.method_type('.') + assert_equal :instance, @driver.method_type('#') + assert_equal :class, @driver.method_type('::') + end + + def test_name_regexp + assert_equal %r%^RDoc::AnyMethod#new$%, + @driver.name_regexp('RDoc::AnyMethod#new') + + assert_equal %r%^RDoc::AnyMethod::new$%, + @driver.name_regexp('RDoc::AnyMethod::new') + + assert_equal %r%^RDoc::AnyMethod(#|::)new$%, + @driver.name_regexp('RDoc::AnyMethod.new') + + assert_equal %r%^Hash(#|::)\[\]$%, + @driver.name_regexp('Hash.[]') + + assert_equal %r%^Hash::\[\]$%, + @driver.name_regexp('Hash::[]') + end + + def test_list_known_classes + util_store + + out, = capture_io do + @driver.list_known_classes + end + + assert_equal "Ambiguous\nExt\nFoo\nFoo::Bar\nFoo::Baz\nInc\n", out + end + + def test_list_known_classes_name + util_store + + out, = capture_io do + @driver.list_known_classes %w[F I] + end + + assert_equal "Foo\nFoo::Bar\nFoo::Baz\nInc\n", out + end + + def test_list_methods_matching + util_store + + assert_equal %w[ + Foo::Bar#attr + Foo::Bar#blah + Foo::Bar#bother + Foo::Bar::new + ], + @driver.list_methods_matching('Foo::Bar.').sort + end + + def test_list_methods_matching_inherit + util_multi_store + + assert_equal %w[ + Bar#baz + Bar#inherit + Bar#override + ], + @driver.list_methods_matching('Bar.').sort + end + + def test_list_methods_matching_regexp + util_store + + index = RDoc::AnyMethod.new nil, '[]' + index.record_location @top_level + @cFoo.add_method index + @store1.save_method @cFoo, index + + c_index = RDoc::AnyMethod.new nil, '[]' + c_index.singleton = true + c_index.record_location @top_level + @cFoo.add_method c_index + @store1.save_method @cFoo, c_index + + @store1.save_cache + + assert_equal %w[Foo#[]], @driver.list_methods_matching('Foo#[]') + assert_equal %w[Foo::[]], @driver.list_methods_matching('Foo::[]') + end + + def test_load_method + util_store + + method = @driver.load_method(@store1, :instance_methods, 'Foo', '#', + 'inherit') + + assert_equal @inherit, method + end + + def test_load_method_inherited + util_multi_store + + method = @driver.load_method(@store2, :instance_methods, 'Bar', '#', + 'inherit') + + assert_equal nil, method + end + + def test_load_methods_matching + util_store + + expected = [[@store1, [@inherit]]] + + assert_equal expected, @driver.load_methods_matching('Foo#inherit') + + expected = [[@store1, [@blah]]] + + assert_equal expected, @driver.load_methods_matching('.blah') + + assert_empty @driver.load_methods_matching('.b') + end + + def test_load_methods_matching_inherited + util_multi_store + + expected = [[@store1, [@inherit]]] + + assert_equal expected, @driver.load_methods_matching('Bar#inherit') + end + + def test_load_method_missing + util_store + + FileUtils.rm @store1.method_file 'Foo', '#inherit' + + method = @driver.load_method(@store1, :instance_methods, 'Foo', '#', + 'inherit') + + assert_equal '(unknown)#inherit', method.full_name + end + + def _test_page # this test doesn't do anything anymore :( + @driver.use_stdout = false + + with_dummy_pager do + @driver.page do |io| + skip "couldn't find a standard pager" if io == $stdout + + assert @driver.paging? + end + end + + refute @driver.paging? + end + + # this test is too fragile. Perhaps using Process.spawn will make this + # reliable + def _test_page_in_presence_of_child_status + skip 'this test hangs on travis-ci.org' if ENV['CI'] + @driver.use_stdout = false + + with_dummy_pager do + @driver.page do |io| + refute_equal $stdout, io + assert @driver.paging? + end + end + end + + def test_page_stdout + @driver.use_stdout = true + + @driver.page do |io| + assert_equal $stdout, io + end + + refute @driver.paging? + end + + def test_parse_name_method + klass, type, meth = @driver.parse_name 'foo' + + assert_equal '', klass, 'foo class' + assert_equal '.', type, 'foo type' + assert_equal 'foo', meth, 'foo method' + + klass, type, meth = @driver.parse_name '#foo' + + assert_equal '', klass, '#foo class' + assert_equal '#', type, '#foo type' + assert_equal 'foo', meth, '#foo method' + + klass, type, meth = @driver.parse_name '::foo' + + assert_equal '', klass, '::foo class' + assert_equal '::', type, '::foo type' + assert_equal 'foo', meth, '::foo method' + end + + def test_parse_name_page + klass, type, meth = @driver.parse_name 'ruby:README' + + assert_equal 'ruby', klass, 'ruby project' + assert_equal ':', type, 'ruby type' + assert_equal 'README', meth, 'ruby page' + + klass, type, meth = @driver.parse_name 'ruby:' + + assert_equal 'ruby', klass, 'ruby project' + assert_equal ':', type, 'ruby type' + assert_equal nil, meth, 'ruby page' + end + + def test_parse_name_page_extenson + klass, type, meth = @driver.parse_name 'ruby:README.EXT' + + assert_equal 'ruby', klass, 'ruby project' + assert_equal ':', type, 'ruby type' + assert_equal 'README.EXT', meth, 'ruby page' + end + + def test_parse_name_single_class + klass, type, meth = @driver.parse_name 'Foo' + + assert_equal 'Foo', klass, 'Foo class' + assert_equal nil, type, 'Foo type' + assert_equal nil, meth, 'Foo method' + + klass, type, meth = @driver.parse_name 'Foo#' + + assert_equal 'Foo', klass, 'Foo# class' + assert_equal '#', type, 'Foo# type' + assert_equal nil, meth, 'Foo# method' + + klass, type, meth = @driver.parse_name 'Foo::' + + assert_equal 'Foo', klass, 'Foo:: class' + assert_equal '::', type, 'Foo:: type' + assert_equal nil, meth, 'Foo:: method' + + klass, type, meth = @driver.parse_name 'Foo.' + + assert_equal 'Foo', klass, 'Foo. class' + assert_equal '.', type, 'Foo. type' + assert_equal nil, meth, 'Foo. method' + + klass, type, meth = @driver.parse_name 'Foo#Bar' + + assert_equal 'Foo', klass, 'Foo#Bar class' + assert_equal '#', type, 'Foo#Bar type' + assert_equal 'Bar', meth, 'Foo#Bar method' + + klass, type, meth = @driver.parse_name 'Foo.Bar' + + assert_equal 'Foo', klass, 'Foo.Bar class' + assert_equal '.', type, 'Foo.Bar type' + assert_equal 'Bar', meth, 'Foo.Bar method' + + klass, type, meth = @driver.parse_name 'Foo::bar' + + assert_equal 'Foo', klass, 'Foo::bar class' + assert_equal '::', type, 'Foo::bar type' + assert_equal 'bar', meth, 'Foo::bar method' + end + + def test_parse_name_namespace + klass, type, meth = @driver.parse_name 'Foo::Bar' + + assert_equal 'Foo::Bar', klass, 'Foo::Bar class' + assert_equal nil, type, 'Foo::Bar type' + assert_equal nil, meth, 'Foo::Bar method' + + klass, type, meth = @driver.parse_name 'Foo::Bar#' + + assert_equal 'Foo::Bar', klass, 'Foo::Bar# class' + assert_equal '#', type, 'Foo::Bar# type' + assert_equal nil, meth, 'Foo::Bar# method' + + klass, type, meth = @driver.parse_name 'Foo::Bar#baz' + + assert_equal 'Foo::Bar', klass, 'Foo::Bar#baz class' + assert_equal '#', type, 'Foo::Bar#baz type' + assert_equal 'baz', meth, 'Foo::Bar#baz method' + end + + def test_parse_name_special + specials = %w[ + % + & + * + + + +@ + - + -@ + / + < + << + <= + <=> + == + === + => + =~ + > + >> + [] + []= + ^ + ` + | + ~ + ~@ + ] + + specials.each do |special| + parsed = @driver.parse_name special + + assert_equal ['', '.', special], parsed + end + end + + def _test_setup_pager # this test doesn't do anything anymore :( + @driver.use_stdout = false + + pager = with_dummy_pager do @driver.setup_pager end + + skip "couldn't find a standard pager" unless pager + + assert @driver.paging? + ensure + pager.close if pager + end + + def util_ancestors_store + store1 = RDoc::RI::Store.new @home_ri + store1.cache[:ancestors] = { + 'Foo' => %w[Object], + 'Foo::Bar' => %w[Foo], + } + store1.cache[:class_methods] = { + 'Foo' => %w[c_method new], + 'Foo::Bar' => %w[new], + } + store1.cache[:instance_methods] = { + 'Foo' => %w[i_method], + } + store1.cache[:modules] = %w[ + Foo + Foo::Bar + ] + + store2 = RDoc::RI::Store.new @home_ri + store2.cache[:ancestors] = { + 'Foo' => %w[Mixin Object], + 'Mixin' => %w[], + 'Object' => %w[X Object], + 'X' => %w[Object], + } + store2.cache[:class_methods] = { + 'Foo' => %w[c_method new], + 'Mixin' => %w[], + 'X' => %w[], + 'Object' => %w[], + } + store2.cache[:instance_methods] = { + 'Foo' => %w[i_method], + 'Mixin' => %w[], + } + store2.cache[:modules] = %w[ + Foo + Mixin + Object + X + ] + + @driver.stores = store1, store2 + end + + def util_multi_store + util_store + + @home_ri2 = "#{@home_ri}2" + @store2 = RDoc::RI::Store.new @home_ri2 + + @top_level = @store2.add_file 'file.rb' + + # as if seen in a namespace like class Ambiguous::Other + @mAmbiguous = @top_level.add_module RDoc::NormalModule, 'Ambiguous' + + @cFoo = @top_level.add_class RDoc::NormalClass, 'Foo' + + @cBar = @top_level.add_class RDoc::NormalClass, 'Bar', 'Foo' + @cFoo_Baz = @cFoo.add_class RDoc::NormalClass, 'Baz' + + @baz = @cBar.add_method RDoc::AnyMethod.new(nil, 'baz') + @baz.record_location @top_level + + @override = @cBar.add_method RDoc::AnyMethod.new(nil, 'override') + @override.comment = 'must be displayed' + @override.record_location @top_level + + @store2.save + + @driver.stores = [@store1, @store2] + end + + def util_store + @store1 = RDoc::RI::Store.new @home_ri, :home + + @top_level = @store1.add_file 'file.rb' + + @readme = @store1.add_file 'README.rdoc' + @readme.parser = RDoc::Parser::Simple + @readme.comment = + doc( + head(1, 'README'), + para('This is a README')) + + @cFoo = @top_level.add_class RDoc::NormalClass, 'Foo' + @mExt = @top_level.add_module RDoc::NormalModule, 'Ext' + @mInc = @top_level.add_module RDoc::NormalModule, 'Inc' + @cAmbiguous = @top_level.add_class RDoc::NormalClass, 'Ambiguous' + + doc = @RM::Document.new @RM::Paragraph.new('Extend thingy') + @cFooExt = @cFoo.add_extend RDoc::Extend.new('Ext', doc) + @cFooExt.record_location @top_level + doc = @RM::Document.new @RM::Paragraph.new('Include thingy') + @cFooInc = @cFoo.add_include RDoc::Include.new('Inc', doc) + @cFooInc.record_location @top_level + + @cFoo_Bar = @cFoo.add_class RDoc::NormalClass, 'Bar' + + @blah = @cFoo_Bar.add_method RDoc::AnyMethod.new(nil, 'blah') + @blah.call_seq = "blah(5) => 5\nblah(6) => 6\n" + @blah.record_location @top_level + + @bother = @cFoo_Bar.add_method RDoc::AnyMethod.new(nil, 'bother') + @bother.block_params = "stuff" + @bother.params = "(things)" + @bother.record_location @top_level + + @new = @cFoo_Bar.add_method RDoc::AnyMethod.new nil, 'new' + @new.record_location @top_level + @new.singleton = true + + @attr = @cFoo_Bar.add_attribute RDoc::Attr.new nil, 'attr', 'RW', '' + @attr.record_location @top_level + + @cFoo_Baz = @cFoo.add_class RDoc::NormalClass, 'Baz' + @cFoo_Baz.record_location @top_level + + @inherit = @cFoo.add_method RDoc::AnyMethod.new(nil, 'inherit') + @inherit.record_location @top_level + + # overriden by Bar in multi_store + @overriden = @cFoo.add_method RDoc::AnyMethod.new(nil, 'override') + @overriden.comment = 'must not be displayed in Bar#override' + @overriden.record_location @top_level + + @store1.save + + @driver.stores = [@store1] + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_ri_paths.rb b/jni/ruby/test/rdoc/test_rdoc_ri_paths.rb new file mode 100644 index 0000000..e377b0b --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_ri_paths.rb @@ -0,0 +1,155 @@ +require 'rdoc/test_case' + +class TestRDocRIPaths < RDoc::TestCase + + def setup + super + + @orig_gem_path = Gem.path + + @tempdir = File.join Dir.tmpdir, "test_rdoc_ri_paths_#{$$}" + Gem.use_paths @tempdir + Gem.ensure_gem_subdirectories @tempdir + + specs = [ + @rake_10 = Gem::Specification.new('rake', '10.0.1'), + @rdoc_4_0 = Gem::Specification.new('rdoc', '4.0'), + @rdoc_3_12 = Gem::Specification.new('rdoc', '3.12'), + @nodoc = Gem::Specification.new('nodoc', '1.0'), + ] + + specs.each do |spec| + spec.loaded_from = spec.spec_file + + open spec.spec_file, 'w' do |file| + file.write spec.to_ruby_for_cache + end + + FileUtils.mkdir_p File.join(spec.doc_dir, 'ri') unless + spec.name == 'nodoc' + end + + Gem::Specification.reset + Gem::Specification.all = specs + end + + def teardown + super + + Gem.use_paths(*@orig_gem_path) + Gem::Specification.reset + FileUtils.rm_rf @tempdir + end + + def test_class_each + enum = RDoc::RI::Paths.each true, true, true, :all + + path = enum.map { |dir,| dir } + + assert_equal RDoc::RI::Paths.system_dir, path.shift + assert_equal RDoc::RI::Paths.site_dir, path.shift + assert_equal RDoc::RI::Paths.home_dir, path.shift + assert_equal File.join(@nodoc.doc_dir, 'ri'), path.shift + assert_equal File.join(@rake_10.doc_dir, 'ri'), path.shift + assert_equal File.join(@rdoc_4_0.doc_dir, 'ri'), path.shift + assert_equal File.join(@rdoc_3_12.doc_dir, 'ri'), path.shift + assert_empty path + end + + def test_class_gemdirs_latest + Dir.chdir @tempdir do + gemdirs = RDoc::RI::Paths.gemdirs :latest + + expected = [ + File.join(@rake_10.doc_dir, 'ri'), + File.join(@rdoc_4_0.doc_dir, 'ri'), + ] + + assert_equal expected, gemdirs + end + end + + def test_class_gemdirs_legacy + Dir.chdir @tempdir do + gemdirs = RDoc::RI::Paths.gemdirs true + + expected = [ + File.join(@rake_10.doc_dir, 'ri'), + File.join(@rdoc_4_0.doc_dir, 'ri'), + ] + + assert_equal expected, gemdirs + end + end + + def test_class_gemdirs_all + Dir.chdir @tempdir do + gemdirs = RDoc::RI::Paths.gemdirs :all + + expected = [ + File.join(@nodoc.doc_dir, 'ri'), + File.join(@rake_10.doc_dir, 'ri'), + File.join(@rdoc_4_0.doc_dir, 'ri'), + File.join(@rdoc_3_12.doc_dir, 'ri'), + ] + + assert_equal expected, gemdirs + end + end + + def test_class_gem_dir + dir = RDoc::RI::Paths.gem_dir 'rake', '10.0.1' + + expected = File.join @rake_10.doc_dir, 'ri' + + assert_equal expected, dir + end + + def test_class_home_dir + dir = RDoc::RI::Paths.home_dir + + assert_equal RDoc::RI::Paths::HOMEDIR, dir + end + + def test_class_path_nonexistent + temp_dir do |dir| + nonexistent = File.join dir, 'nonexistent' + dir = RDoc::RI::Paths.path true, true, true, true, nonexistent + + refute_includes dir, nonexistent + end + end + + def test_class_raw_path + path = RDoc::RI::Paths.raw_path true, true, true, true + + assert_equal RDoc::RI::Paths.system_dir, path.shift + assert_equal RDoc::RI::Paths.site_dir, path.shift + assert_equal RDoc::RI::Paths.home_dir, path.shift + assert_equal File.join(@rake_10.doc_dir, 'ri'), path.shift + end + + def test_class_raw_path_extra_dirs + path = RDoc::RI::Paths.raw_path true, true, true, true, '/nonexistent' + + assert_equal '/nonexistent', path.shift + assert_equal RDoc::RI::Paths.system_dir, path.shift + assert_equal RDoc::RI::Paths.site_dir, path.shift + assert_equal RDoc::RI::Paths.home_dir, path.shift + assert_equal File.join(@rake_10.doc_dir, 'ri'), path.shift + end + + def test_class_site_dir + dir = RDoc::RI::Paths.site_dir + + assert_equal File.join(RDoc::RI::Paths::BASE, 'site'), dir + end + + def test_class_system_dir + dir = RDoc::RI::Paths.system_dir + + assert_equal File.join(RDoc::RI::Paths::BASE, 'system'), dir + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_ruby_lex.rb b/jni/ruby/test/rdoc/test_rdoc_ruby_lex.rb new file mode 100644 index 0000000..8871b4f --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_ruby_lex.rb @@ -0,0 +1,421 @@ +# coding: UTF-8 + +require 'rdoc/test_case' + +class TestRDocRubyLex < RDoc::TestCase + + def setup + @TK = RDoc::RubyToken + end + + def test_class_tokenize + tokens = RDoc::RubyLex.tokenize "def x() end", nil + + expected = [ + @TK::TkDEF .new( 0, 1, 0, "def"), + @TK::TkSPACE .new( 3, 1, 3, " "), + @TK::TkIDENTIFIER.new( 4, 1, 4, "x"), + @TK::TkLPAREN .new( 5, 1, 5, "("), + @TK::TkRPAREN .new( 6, 1, 6, ")"), + @TK::TkSPACE .new( 7, 1, 7, " "), + @TK::TkEND .new( 8, 1, 8, "end"), + @TK::TkNL .new(11, 1, 11, "\n"), + ] + + assert_equal expected, tokens + end + + def test_class_tokenize___END__ + tokens = RDoc::RubyLex.tokenize '__END__', nil + + expected = [ + @TK::TkEND_OF_SCRIPT.new(0, 1, 0, '__END__'), + @TK::TkNL .new(7, 1, 7, "\n"), + ] + + assert_equal expected, tokens + end + + def test_class_tokenize_character_literal + tokens = RDoc::RubyLex.tokenize "?\\", nil + + expected = [ + @TK::TkCHAR.new( 0, 1, 0, "?\\"), + @TK::TkNL .new( 2, 1, 2, "\n"), + ] + + assert_equal expected, tokens + end + + def test_class_tokenize_def_heredoc + tokens = RDoc::RubyLex.tokenize <<-'RUBY', nil +def x + <<E +Line 1 +Line 2 +E +end + RUBY + + expected = [ + @TK::TkDEF .new( 0, 1, 0, 'def'), + @TK::TkSPACE .new( 3, 1, 3, ' '), + @TK::TkIDENTIFIER.new( 4, 1, 4, 'x'), + @TK::TkNL .new( 5, 1, 5, "\n"), + @TK::TkSPACE .new( 6, 2, 0, ' '), + @TK::TkHEREDOC .new( 8, 2, 2, + %Q{<<E\nLine 1\nLine 2\nE}), + @TK::TkNL .new(27, 5, 28, "\n"), + @TK::TkEND .new(28, 6, 0, 'end'), + @TK::TkNL .new(31, 6, 28, "\n"), + ] + + assert_equal expected, tokens + end + + def test_class_tokenize_hash_symbol + tokens = RDoc::RubyLex.tokenize '{ class:"foo" }', nil + + expected = [ + @TK::TkLBRACE .new( 0, 1, 0, '{'), + @TK::TkSPACE .new( 1, 1, 1, ' '), + @TK::TkIDENTIFIER.new( 2, 1, 2, 'class'), + @TK::TkSYMBEG .new( 7, 1, 7, ':'), + @TK::TkSTRING .new( 8, 1, 8, '"foo"'), + @TK::TkSPACE .new(13, 1, 13, ' '), + @TK::TkRBRACE .new(14, 1, 14, '}'), + @TK::TkNL .new(15, 1, 15, "\n"), + ] + + assert_equal expected, tokens + end + + def test_class_tokenize_heredoc_CR_NL + tokens = RDoc::RubyLex.tokenize <<-RUBY, nil +string = <<-STRING\r +Line 1\r +Line 2\r + STRING\r + RUBY + + expected = [ + @TK::TkIDENTIFIER.new( 0, 1, 0, 'string'), + @TK::TkSPACE .new( 6, 1, 6, ' '), + @TK::TkASSIGN .new( 7, 1, 7, '='), + @TK::TkSPACE .new( 8, 1, 8, ' '), + @TK::TkHEREDOC .new( 9, 1, 9, + %Q{<<-STRING\nLine 1\nLine 2\n STRING}), + @TK::TkSPACE .new(44, 4, 45, "\r"), + @TK::TkNL .new(45, 4, 46, "\n"), + ] + + assert_equal expected, tokens + end + + def test_class_tokenize_heredoc_call + tokens = RDoc::RubyLex.tokenize <<-'RUBY', nil +string = <<-STRING.chomp +Line 1 +Line 2 + STRING + RUBY + + expected = [ + @TK::TkIDENTIFIER.new( 0, 1, 0, 'string'), + @TK::TkSPACE .new( 6, 1, 6, ' '), + @TK::TkASSIGN .new( 7, 1, 7, '='), + @TK::TkSPACE .new( 8, 1, 8, ' '), + @TK::TkSTRING .new( 9, 1, 9, %Q{"Line 1\nLine 2\n"}), + @TK::TkDOT .new(41, 4, 42, '.'), + @TK::TkIDENTIFIER.new(42, 4, 43, 'chomp'), + @TK::TkNL .new(47, 4, 48, "\n"), + ] + + assert_equal expected, tokens + end + + def test_class_tokenize_heredoc_indent + tokens = RDoc::RubyLex.tokenize <<-'RUBY', nil +string = <<-STRING +Line 1 +Line 2 + STRING + RUBY + + expected = [ + @TK::TkIDENTIFIER.new( 0, 1, 0, 'string'), + @TK::TkSPACE .new( 6, 1, 6, ' '), + @TK::TkASSIGN .new( 7, 1, 7, '='), + @TK::TkSPACE .new( 8, 1, 8, ' '), + @TK::TkHEREDOC .new( 9, 1, 9, + %Q{<<-STRING\nLine 1\nLine 2\n STRING}), + @TK::TkNL .new(41, 4, 42, "\n"), + ] + + assert_equal expected, tokens + end + + def test_class_tokenize_heredoc_missing_end + e = assert_raises RDoc::RubyLex::Error do + RDoc::RubyLex.tokenize <<-'RUBY', nil +>> string1 = <<-TXT +>" That's swell +>" TXT + RUBY + end + + assert_equal 'Missing terminating TXT for string', e.message + end + + def test_class_tokenize_heredoc_percent_N + tokens = RDoc::RubyLex.tokenize <<-'RUBY', nil +a b <<-U +%N +U + RUBY + + expected = [ + @TK::TkIDENTIFIER.new( 0, 1, 0, 'a'), + @TK::TkSPACE .new( 1, 1, 1, ' '), + @TK::TkIDENTIFIER.new( 2, 1, 2, 'b'), + @TK::TkSPACE .new( 3, 1, 3, ' '), + @TK::TkHEREDOC .new( 4, 1, 4, %Q{<<-U\n%N\nU}), + @TK::TkNL .new(13, 3, 14, "\n"), + ] + + assert_equal expected, tokens + end + + def test_class_tokenize_identifier_high_unicode + tokens = RDoc::RubyLex.tokenize '𝖒', nil + + expected = @TK::TkIDENTIFIER.new(0, 1, 0, '𝖒') + + assert_equal expected, tokens.first + end + + def test_class_tokenize_percent_1 + tokens = RDoc::RubyLex.tokenize 'v%10==10', nil + + expected = [ + @TK::TkIDENTIFIER.new(0, 1, 0, 'v'), + @TK::TkMOD.new( 1, 1, 1, '%'), + @TK::TkINTEGER.new( 2, 1, 2, '10'), + @TK::TkEQ.new( 4, 1, 4, '=='), + @TK::TkINTEGER.new( 6, 1, 6, '10'), + @TK::TkNL.new( 8, 1, 8, "\n"), + ] + + assert_equal expected, tokens + end + + def test_class_tokenize_percent_r + tokens = RDoc::RubyLex.tokenize '%r[hi]', nil + + expected = [ + @TK::TkREGEXP.new( 0, 1, 0, '%r[hi]'), + @TK::TkNL .new( 6, 1, 6, "\n"), + ] + + assert_equal expected, tokens + end + + def test_class_tokenize_percent_w + tokens = RDoc::RubyLex.tokenize '%w[hi]', nil + + expected = [ + @TK::TkDSTRING.new( 0, 1, 0, '%w[hi]'), + @TK::TkNL .new( 6, 1, 6, "\n"), + ] + + assert_equal expected, tokens + end + + def test_class_tokenize_percent_w_quote + tokens = RDoc::RubyLex.tokenize '%w"hi"', nil + + expected = [ + @TK::TkDSTRING.new( 0, 1, 0, '%w"hi"'), + @TK::TkNL .new( 6, 1, 6, "\n"), + ] + + assert_equal expected, tokens + end + + def test_class_tokenize_regexp + tokens = RDoc::RubyLex.tokenize "/hay/", nil + + expected = [ + @TK::TkREGEXP.new( 0, 1, 0, "/hay/"), + @TK::TkNL .new( 5, 1, 5, "\n"), + ] + + assert_equal expected, tokens + end + + def test_class_tokenize_regexp_options + tokens = RDoc::RubyLex.tokenize "/hAY/i", nil + + expected = [ + @TK::TkREGEXP.new( 0, 1, 0, "/hAY/i"), + @TK::TkNL .new( 6, 1, 6, "\n"), + ] + + assert_equal expected, tokens + + tokens = RDoc::RubyLex.tokenize "/hAY/ix", nil + + expected = [ + @TK::TkREGEXP.new( 0, 1, 0, "/hAY/ix"), + @TK::TkNL .new( 7, 1, 7, "\n"), + ] + + assert_equal expected, tokens + end + + def test_class_tokenize_regexp_backref + tokens = RDoc::RubyLex.tokenize "/[csh](..) [csh]\\1 in/", nil + + expected = [ + @TK::TkREGEXP.new( 0, 1, 0, "/[csh](..) [csh]\\1 in/"), + @TK::TkNL .new(22, 1, 22, "\n"), + ] + + assert_equal expected, tokens + end + + def test_class_tokenize_regexp_escape + tokens = RDoc::RubyLex.tokenize "/\\//", nil + + expected = [ + @TK::TkREGEXP.new( 0, 1, 0, "/\\//"), + @TK::TkNL .new( 4, 1, 4, "\n"), + ] + + assert_equal expected, tokens + end + + def test_class_tokenize_string + tokens = RDoc::RubyLex.tokenize "'hi'", nil + + expected = [ + @TK::TkSTRING.new( 0, 1, 0, "'hi'"), + @TK::TkNL .new( 4, 1, 4, "\n"), + ] + + assert_equal expected, tokens + end + + def test_class_tokenize_string_escape + tokens = RDoc::RubyLex.tokenize '"\\n"', nil + assert_equal @TK::TkSTRING.new( 0, 1, 0, "\"\\n\""), tokens.first + + tokens = RDoc::RubyLex.tokenize '"\\r"', nil + assert_equal @TK::TkSTRING.new( 0, 1, 0, "\"\\r\""), tokens.first + + tokens = RDoc::RubyLex.tokenize '"\\f"', nil + assert_equal @TK::TkSTRING.new( 0, 1, 0, "\"\\f\""), tokens.first + + tokens = RDoc::RubyLex.tokenize '"\\\\"', nil + assert_equal @TK::TkSTRING.new( 0, 1, 0, "\"\\\\\""), tokens.first + + tokens = RDoc::RubyLex.tokenize '"\\t"', nil + assert_equal @TK::TkSTRING.new( 0, 1, 0, "\"\\t\""), tokens.first + + tokens = RDoc::RubyLex.tokenize '"\\v"', nil + assert_equal @TK::TkSTRING.new( 0, 1, 0, "\"\\v\""), tokens.first + + tokens = RDoc::RubyLex.tokenize '"\\a"', nil + assert_equal @TK::TkSTRING.new( 0, 1, 0, "\"\\a\""), tokens.first + + tokens = RDoc::RubyLex.tokenize '"\\e"', nil + assert_equal @TK::TkSTRING.new( 0, 1, 0, "\"\\e\""), tokens.first + + tokens = RDoc::RubyLex.tokenize '"\\b"', nil + assert_equal @TK::TkSTRING.new( 0, 1, 0, "\"\\b\""), tokens.first + + tokens = RDoc::RubyLex.tokenize '"\\s"', nil + assert_equal @TK::TkSTRING.new( 0, 1, 0, "\"\\s\""), tokens.first + + tokens = RDoc::RubyLex.tokenize '"\\d"', nil + assert_equal @TK::TkSTRING.new( 0, 1, 0, "\"\\d\""), tokens.first + + end + + def test_class_tokenize_string_escape_control + tokens = RDoc::RubyLex.tokenize '"\\C-a"', nil + assert_equal @TK::TkSTRING.new( 0, 1, 0, "\"\\C-a\""), tokens.first + + tokens = RDoc::RubyLex.tokenize '"\\c\\a"', nil + assert_equal @TK::TkSTRING.new( 0, 1, 0, "\"\\c\\a\""), tokens.first + + tokens = RDoc::RubyLex.tokenize '"\\C-\\M-a"', nil + assert_equal @TK::TkSTRING.new( 0, 1, 0, "\"\\C-\\M-a\""), tokens.first + end + + def test_class_tokenize_string_escape_meta + tokens = RDoc::RubyLex.tokenize '"\\M-a"', nil + assert_equal @TK::TkSTRING.new( 0, 1, 0, "\"\\M-a\""), tokens.first + + tokens = RDoc::RubyLex.tokenize '"\\M-\\C-a"', nil + assert_equal @TK::TkSTRING.new( 0, 1, 0, "\"\\M-\\C-a\""), tokens.first + end + + def test_class_tokenize_string_escape_hexadecimal + tokens = RDoc::RubyLex.tokenize '"\\x0"', nil + assert_equal @TK::TkSTRING.new( 0, 1, 0, "\"\\x0\""), tokens.first + + tokens = RDoc::RubyLex.tokenize '"\\x00"', nil + assert_equal @TK::TkSTRING.new( 0, 1, 0, "\"\\x00\""), tokens.first + + tokens = RDoc::RubyLex.tokenize '"\\x000"', nil + assert_equal @TK::TkSTRING.new( 0, 1, 0, "\"\\x000\""), tokens.first + end + + def test_class_tokenize_string_escape_octal + tokens = RDoc::RubyLex.tokenize '"\\0"', nil + assert_equal @TK::TkSTRING.new( 0, 1, 0, "\"\\0\""), tokens.first + + tokens = RDoc::RubyLex.tokenize '"\\00"', nil + assert_equal @TK::TkSTRING.new( 0, 1, 0, "\"\\00\""), tokens.first + + tokens = RDoc::RubyLex.tokenize '"\\000"', nil + assert_equal @TK::TkSTRING.new( 0, 1, 0, "\"\\000\""), tokens.first + end + + def test_class_tokenize_symbol + tokens = RDoc::RubyLex.tokenize 'scope module: :v1', nil + + expected = [ + @TK::TkIDENTIFIER.new( 0, 1, 0, 'scope'), + @TK::TkSPACE .new( 5, 1, 5, ' '), + @TK::TkIDENTIFIER.new( 6, 1, 6, 'module'), + @TK::TkCOLON .new(12, 1, 12, ':'), + @TK::TkSPACE .new(13, 1, 13, ' '), + @TK::TkSYMBEG .new(14, 1, 14, ':'), + @TK::TkIDENTIFIER.new(15, 1, 15, 'v1'), + @TK::TkNL .new(17, 1, 17, "\n"), + ] + + assert_equal expected, tokens + end + + def test_unary_minus + ruby_lex = RDoc::RubyLex.new("-1", nil) + assert_equal("-1", ruby_lex.token.value) + + ruby_lex = RDoc::RubyLex.new("a[-2]", nil) + 2.times { ruby_lex.token } # skip "a" and "[" + assert_equal("-2", ruby_lex.token.value) + + ruby_lex = RDoc::RubyLex.new("a[0..-12]", nil) + 4.times { ruby_lex.token } # skip "a", "[", "0", and ".." + assert_equal("-12", ruby_lex.token.value) + + ruby_lex = RDoc::RubyLex.new("0+-0.1", nil) + 2.times { ruby_lex.token } # skip "0" and "+" + assert_equal("-0.1", ruby_lex.token.value) + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_ruby_token.rb b/jni/ruby/test/rdoc/test_rdoc_ruby_token.rb new file mode 100644 index 0000000..ed8c827 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_ruby_token.rb @@ -0,0 +1,19 @@ +require 'rdoc/test_case' + +class TestRDocRubyToken < RDoc::TestCase + + def test_Token_text + token = RDoc::RubyToken::Token.new 0, 0, 0, 'text' + + assert_equal 'text', token.text + end + + def test_TkOp_name + token = RDoc::RubyToken::TkOp.new 0, 0, 0, '&' + + assert_equal '&', token.text + assert_equal '&', token.name + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_rubygems_hook.rb b/jni/ruby/test/rdoc/test_rdoc_rubygems_hook.rb new file mode 100644 index 0000000..960afc9 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_rubygems_hook.rb @@ -0,0 +1,251 @@ +require 'rubygems' +require 'rubygems/test_case' +require 'rdoc/rubygems_hook' + +class TestRDocRubygemsHook < Gem::TestCase + + def setup + super + + skip 'requires RubyGems 1.9+' unless + Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.9') + + @a = util_spec 'a', 2 do |s| + s.rdoc_options = %w[--main MyTitle] + s.extra_rdoc_files = %w[README] + end + + write_file File.join(@tempdir, 'lib', 'a.rb') + write_file File.join(@tempdir, 'README') + + install_gem @a + + @hook = RDoc::RubygemsHook.new @a + + begin + RDoc::RubygemsHook.load_rdoc + rescue Gem::DocumentError => e + skip e.message + end + + Gem.configuration[:rdoc] = nil + end + + def test_initialize + refute @hook.generate_rdoc + assert @hook.generate_ri + + rdoc = RDoc::RubygemsHook.new @a, false, false + + refute rdoc.generate_rdoc + refute rdoc.generate_ri + end + + def test_delete_legacy_args + args = %w[ + --inline-source + --one-file + --promiscuous + -p + ] + + @hook.delete_legacy_args args + + assert_empty args + end + + def test_document + options = RDoc::Options.new + options.files = [] + + rdoc = @hook.new_rdoc + rdoc.store = RDoc::Store.new + @hook.instance_variable_set :@rdoc, rdoc + @hook.instance_variable_set :@file_info, [] + + @hook.document 'darkfish', options, @a.doc_dir('rdoc') + + assert @hook.rdoc_installed? + end + + def test_generate + FileUtils.mkdir_p @a.doc_dir + FileUtils.mkdir_p File.join(@a.gem_dir, 'lib') + + @hook.generate + + refute @hook.rdoc_installed? + assert @hook.ri_installed? + + rdoc = @hook.instance_variable_get :@rdoc + + refute rdoc.options.hyperlink_all + assert_equal Pathname(@a.full_gem_path), rdoc.options.root + assert_equal %w[README lib], rdoc.options.files.sort + + assert_equal 'MyTitle', rdoc.store.main + end + + def test_generate_all + @hook.generate_rdoc = true + @hook.generate_ri = true + + FileUtils.mkdir_p @a.doc_dir + FileUtils.mkdir_p File.join(@a.gem_dir, 'lib') + + @hook.generate + + assert @hook.rdoc_installed? + assert @hook.ri_installed? + + rdoc = @hook.instance_variable_get :@rdoc + + refute rdoc.options.hyperlink_all + assert_equal Pathname(@a.full_gem_path), rdoc.options.root + assert_equal %w[README lib], rdoc.options.files.sort + + assert_equal 'MyTitle', rdoc.store.main + end + + def test_generate_configuration_rdoc_array + Gem.configuration[:rdoc] = %w[-A] + + FileUtils.mkdir_p @a.doc_dir + FileUtils.mkdir_p File.join(@a.gem_dir, 'lib') + + @hook.generate + + rdoc = @hook.instance_variable_get :@rdoc + + assert rdoc.options.hyperlink_all + end + + def test_generate_configuration_rdoc_string + Gem.configuration[:rdoc] = '-A' + + FileUtils.mkdir_p @a.doc_dir + FileUtils.mkdir_p File.join(@a.gem_dir, 'lib') + + @hook.generate + + rdoc = @hook.instance_variable_get :@rdoc + + assert rdoc.options.hyperlink_all + end + + def test_generate_default_gem + skip 'RubyGems 2 required' unless @a.respond_to? :default_gem? + @a.loaded_from = + File.join Gem::Specification.default_specifications_dir, 'a.gemspec' + + @hook.generate + + refute @hook.rdoc_installed? + refute @hook.ri_installed? + end + + def test_generate_disabled + @hook.generate_rdoc = false + @hook.generate_ri = false + + @hook.generate + + refute @hook.rdoc_installed? + refute @hook.ri_installed? + end + + def test_generate_force + FileUtils.mkdir_p @a.doc_dir 'ri' + FileUtils.mkdir_p @a.doc_dir 'rdoc' + FileUtils.mkdir_p File.join(@a.gem_dir, 'lib') + + @hook.force = true + + @hook.generate + + refute_path_exists File.join(@a.doc_dir('rdoc'), 'index.html') + assert_path_exists File.join(@a.doc_dir('ri'), 'cache.ri') + end + + def test_generate_no_overwrite + FileUtils.mkdir_p @a.doc_dir 'ri' + FileUtils.mkdir_p @a.doc_dir 'rdoc' + FileUtils.mkdir_p File.join(@a.gem_dir, 'lib') + + @hook.generate + + refute_path_exists File.join(@a.doc_dir('rdoc'), 'index.html') + refute_path_exists File.join(@a.doc_dir('ri'), 'cache.ri') + end + + def test_new_rdoc + assert_kind_of RDoc::RDoc, @hook.new_rdoc + end + + def test_rdoc_installed? + refute @hook.rdoc_installed? + + FileUtils.mkdir_p @a.doc_dir 'rdoc' + + assert @hook.rdoc_installed? + end + + def test_remove + FileUtils.mkdir_p @a.doc_dir 'rdoc' + FileUtils.mkdir_p @a.doc_dir 'ri' + + @hook.remove + + refute @hook.rdoc_installed? + refute @hook.ri_installed? + + assert_path_exists @a.doc_dir + end + + def test_remove_unwritable + skip 'chmod not supported' if Gem.win_platform? + FileUtils.mkdir_p @a.base_dir + FileUtils.chmod 0, @a.base_dir + + e = assert_raises Gem::FilePermissionError do + @hook.remove + end + + assert_equal @a.base_dir, e.directory + ensure + FileUtils.chmod(0755, @a.base_dir) if File.directory?(@a.base_dir) + end + + def test_ri_installed? + refute @hook.ri_installed? + + FileUtils.mkdir_p @a.doc_dir 'ri' + + assert @hook.ri_installed? + end + + def test_setup + @hook.setup + + assert_path_exists @a.doc_dir + end + + def test_setup_unwritable + skip 'chmod not supported' if Gem.win_platform? + FileUtils.mkdir_p @a.doc_dir + FileUtils.chmod 0, @a.doc_dir + + e = assert_raises Gem::FilePermissionError do + @hook.setup + end + + assert_equal @a.doc_dir, e.directory + ensure + if File.exist? @a.doc_dir + FileUtils.chmod 0755, @a.doc_dir + FileUtils.rm_r @a.doc_dir + end + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_servlet.rb b/jni/ruby/test/rdoc/test_rdoc_servlet.rb new file mode 100644 index 0000000..143e2f2 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_servlet.rb @@ -0,0 +1,535 @@ +require 'rdoc/test_case' + +class TestRDocServlet < RDoc::TestCase + + def setup + super + + @orig_gem_path = Gem.path + + @tempdir = File.join Dir.tmpdir, "test_rdoc_servlet_#{$$}" + Gem.use_paths @tempdir + Gem.ensure_gem_subdirectories @tempdir + + @spec = Gem::Specification.new 'spec', '1.0' + @spec.loaded_from = @spec.spec_file + + Gem::Specification.reset + Gem::Specification.all = [@spec] + + @server = {} + def @server.mount(*) end + + @stores = {} + @cache = Hash.new { |hash, store| hash[store] = {} } + + @extra_dirs = [File.join(@tempdir, 'extra1'), File.join(@tempdir, 'extra2')] + + @s = RDoc::Servlet.new @server, @stores, @cache, nil, @extra_dirs + + @req = WEBrick::HTTPRequest.new :Logger => nil + @res = WEBrick::HTTPResponse.new :HTTPVersion => '1.0' + + def @req.path= path + instance_variable_set :@path, path + end + + @req.instance_variable_set :@header, Hash.new { |h, k| h[k] = [] } + + @base = File.join @tempdir, 'base' + @system_dir = File.join @tempdir, 'base', 'system' + @home_dir = File.join @tempdir, 'home' + @gem_doc_dir = File.join @tempdir, 'doc' + + @orig_base = RDoc::RI::Paths::BASE + RDoc::RI::Paths::BASE.replace @base + @orig_ri_path_homedir = RDoc::RI::Paths::HOMEDIR + RDoc::RI::Paths::HOMEDIR.replace @home_dir + + RDoc::RI::Paths.instance_variable_set \ + :@gemdirs, %w[/nonexistent/gems/example-1.0/ri] + end + + def teardown + super + + Gem.use_paths(*@orig_gem_path) + Gem::Specification.reset + + FileUtils.rm_rf @tempdir + + RDoc::RI::Paths::BASE.replace @orig_base + RDoc::RI::Paths::HOMEDIR.replace @orig_ri_path_homedir + RDoc::RI::Paths.instance_variable_set :@gemdirs, nil + end + + def test_asset + temp_dir do + now = Time.now + + open 'rdoc.css', 'w' do |io| io.write 'h1 { color: red }' end + File.utime now, now, 'rdoc.css' + + @s.asset_dirs[:darkfish] = '.' + + @req.path = 'rdoc.css' + + @s.asset :darkfish, @req, @res + + assert_equal 'h1 { color: red }', @res.body + assert_equal 'text/css', @res.content_type + assert_equal now.httpdate, @res['last-modified'] + end + end + + def test_do_GET + touch_system_cache_path + + @req.path = '/ruby/Missing.html' + + @s.do_GET @req, @res + + assert_equal 404, @res.status + end + + def test_do_GET_asset_darkfish + temp_dir do + FileUtils.touch 'rdoc.css' + + @s.asset_dirs[:darkfish] = '.' + + @req.path = '/rdoc.css' + + @s.do_GET @req, @res + + assert_equal 'text/css', @res.content_type + end + end + + def test_do_GET_asset_json_index + temp_dir do + FileUtils.mkdir 'js' + FileUtils.touch 'js/navigation.js' + + @s.asset_dirs[:json_index] = '.' + + @req.path = '/js/navigation.js' + + @s.do_GET @req, @res + + assert_equal 'application/javascript', @res.content_type + end + end + + def test_do_GET_error + touch_system_cache_path + + def @req.path() raise 'no' end + + @s.do_GET @req, @res + + assert_equal 500, @res.status + end + + def test_do_GET_mount_path + @s = RDoc::Servlet.new @server, @stores, @cache, '/mount/path' + + temp_dir do + FileUtils.touch 'rdoc.css' + + @s.asset_dirs[:darkfish] = '.' + + @req.path = '/mount/path/rdoc.css' + + @s.do_GET @req, @res + + assert_equal 'text/css', @res.content_type + end + end + + def do_GET_not_found + touch_system_cache_path + + @req.path = "/#{@spec.full_name}" + + @s.do_GET @req, @res + + assert_equal 404, @res.status + end + + def test_do_GET_not_modified + touch_system_cache_path + @req.header['if-modified-since'] = [(Time.now + 10).httpdate] + @req.path = '/ruby/Missing.html' + + assert_raises WEBrick::HTTPStatus::NotModified do + @s.do_GET @req, @res + end + end + + def test_do_GET_root + touch_system_cache_path + + @req.path = '/' + + @s.do_GET @req, @res + + assert_equal 'text/html', @res.content_type + assert_match %r%<title>Local RDoc Documentation</title>%, @res.body + end + + def test_do_GET_root_search + touch_system_cache_path + + @req.path = '/js/search_index.js' + + @s.do_GET @req, @res + + assert_equal 'application/javascript', @res.content_type + end + + def test_documentation_page_class + store = RDoc::Store.new + + generator = @s.generator_for store + + file = store.add_file 'file.rb' + klass = file.add_class RDoc::NormalClass, 'Klass' + klass.add_class RDoc::NormalClass, 'Sub' + + @s.documentation_page store, generator, 'Klass::Sub.html', @req, @res + + assert_match %r%<title>class Klass::Sub - </title>%, @res.body + assert_match %r%<body id="top" role="document" class="class">%, @res.body + end + + def test_documentation_page_not_found + store = RDoc::Store.new + + generator = @s.generator_for store + + @req.path = '/ruby/Missing.html' + + @s.documentation_page store, generator, 'Missing.html', @req, @res + + assert_equal 404, @res.status + end + + def test_documentation_page_page + store = RDoc::Store.new + + generator = @s.generator_for store + + readme = store.add_file 'README.rdoc' + readme.parser = RDoc::Parser::Simple + + @s.documentation_page store, generator, 'README_rdoc.html', @req, @res + + assert_match %r%<title>README - </title>%, @res.body + assert_match %r%<body [^>]+ class="file">%, @res.body + end + + def test_documentation_source + store, path = @s.documentation_source '/ruby/Object.html' + + assert_equal @system_dir, store.path + + assert_equal 'Object.html', path + end + + def test_documentation_source_cached + cached_store = RDoc::Store.new + + @stores['ruby'] = cached_store + + store, path = @s.documentation_source '/ruby/Object.html' + + assert_same cached_store, store + + assert_equal 'Object.html', path + end + + def test_error + e = RuntimeError.new 'foo' + e.set_backtrace caller + + @s.error e, @req, @res + + assert_equal 'text/html', @res.content_type + assert_equal 500, @res.status + assert_match %r%<title>Error%, @res.body + end + + def test_generator_for + store = RDoc::Store.new + store.main = 'MAIN_PAGE.rdoc' + store.title = 'Title' + + generator = @s.generator_for store + + refute generator.file_output + + assert_equal '..', generator.asset_rel_path + + assert_equal 'MAIN_PAGE.rdoc', @s.options.main_page + assert_equal 'Title', @s.options.title + + assert_kind_of RDoc::RDoc, store.rdoc + assert_same generator, store.rdoc.generator + end + + def test_if_modified_since + skip 'File.utime on directory not supported' if Gem.win_platform? + + temp_dir do + now = Time.now + File.utime now, now, '.' + + @s.if_modified_since @req, @res, '.' + + assert_equal now.to_i, Time.parse(@res['last-modified']).to_i + end + end + + def test_if_modified_since_not_modified + skip 'File.utime on directory not supported' if Gem.win_platform? + + temp_dir do + now = Time.now + File.utime now, now, '.' + + @req.header['if-modified-since'] = [(now + 10).httpdate] + + assert_raises WEBrick::HTTPStatus::NotModified do + @s.if_modified_since @req, @res, '.' + end + + assert_equal now.to_i, Time.parse(@res['last-modified']).to_i + end + end + + def test_installed_docs + touch_system_cache_path + touch_extra_cache_path + + expected = [ + ['My Extra Documentation', 'extra-1/', true, :extra, + @extra_dirs[0]], + ['Extra Documentation', 'extra-2/', false, :extra, + @extra_dirs[1]], + ['Ruby Documentation', 'ruby/', true, :system, + @system_dir], + ['Site Documentation', 'site/', false, :site, + File.join(@base, 'site')], + ['Home Documentation', 'home/', false, :home, + RDoc::RI::Paths::HOMEDIR], + ['spec-1.0', 'spec-1.0/', false, :gem, + File.join(@spec.doc_dir, 'ri')], + ] + + assert_equal expected, @s.installed_docs + end + + def test_not_found + generator = @s.generator_for RDoc::Store.new + + @req.path = '/ruby/Missing.html' + + @s.not_found generator, @req, @res + + assert_equal 404, @res.status + assert_match %r%<title>Not Found</title>%, @res.body + assert_match %r%<kbd>/ruby/Missing\.html</kbd>%, @res.body + end + + def test_not_found_message + generator = @s.generator_for RDoc::Store.new + + @req.path = '/ruby/Missing.html' + + @s.not_found generator, @req, @res, 'woo, this is a message' + + assert_equal 404, @res.status + assert_match %r%<title>Not Found</title>%, @res.body + assert_match %r%woo, this is a message%, @res.body + end + + def test_ri_paths + paths = @s.ri_paths + + expected = [ + [@extra_dirs[0], :extra], + [@extra_dirs[1], :extra], + [@system_dir, :system], + [File.join(@base, 'site'), :site], + [RDoc::RI::Paths::HOMEDIR, :home], + [File.join(@spec.doc_dir, 'ri'), :gem], + ] + + assert_equal expected, paths.to_a + end + + def test_root + @s.root @req, @res + + assert_equal 'text/html', @res.content_type + assert_match %r%<title>Local RDoc Documentation</title>%, @res.body + end + + def test_root_search + touch_system_cache_path + touch_extra_cache_path + + @s.root_search @req, @res + + assert_equal 'application/javascript', @res.content_type + + @res.body =~ /\{.*\}/ + + index = JSON.parse $& + + expected = { + 'index' => { + 'searchIndex' => %w[ + My\ Extra\ Documentation + Ruby\ Documentation + ], + 'longSearchIndex' => %w[ + My\ Extra\ Documentation + Ruby\ Documentation + ], + 'info' => [ + ['My Extra Documentation', '', @extra_dirs[0], '', + 'My Extra Documentation'], + ['Ruby Documentation', '', 'ruby', '', + 'Documentation for the Ruby standard library'], + ], + } + } + + assert_equal expected, index + end + + def test_show_documentation_index + touch_system_cache_path + + @req.path = '/ruby' + + @s.show_documentation @req, @res + + assert_equal 'text/html', @res.content_type + assert_match %r%<title>Standard Library Documentation%, @res.body + end + + def test_show_documentation_table_of_contents + touch_system_cache_path + + @req.path = '/ruby/table_of_contents.html' + + @s.show_documentation @req, @res + + assert_equal 'text/html', @res.content_type + assert_match %r%<title>Table of Contents - Standard Library Documentation%, + @res.body + end + + def test_show_documentation_page + touch_system_cache_path + + @req.path = '/ruby/Missing.html' + + @s.show_documentation @req, @res + + assert_equal 404, @res.status + end + + def test_show_documentation_search_index + touch_system_cache_path + + @req.path = '/ruby/js/search_index.js' + + @s.show_documentation @req, @res + + assert_equal 'application/javascript', @res.content_type + assert_match %r%\Avar search_data =%, @res.body + end + + def test_store_for_gem + ri_dir = File.join @gem_doc_dir, 'spec-1.0', 'ri' + FileUtils.mkdir_p ri_dir + FileUtils.touch File.join ri_dir, 'cache.ri' + + store = @s.store_for 'spec-1.0' + + assert_equal File.join(@gem_doc_dir, 'spec-1.0', 'ri'), store.path + assert_equal :gem, store.type + end + + def test_store_for_home + store = @s.store_for 'home' + + assert_equal @home_dir, store.path + assert_equal :home, store.type + end + + def test_store_for_missing_documentation + FileUtils.mkdir_p(File.join @gem_doc_dir, 'spec-1.0', 'ri') + + e = assert_raises WEBrick::HTTPStatus::NotFound do + @s.store_for 'spec-1.0' + end + + assert_equal 'Could not find documentation for "spec-1.0". Please run `gem rdoc --ri gem_name`', + e.message + end + + def test_store_for_missing_gem + e = assert_raises WEBrick::HTTPStatus::NotFound do + @s.store_for 'missing' + end + + assert_equal 'Could not find gem "missing". Are you sure you installed it?', + e.message + end + + def test_store_for_ruby + store = @s.store_for 'ruby' + + assert_equal @system_dir, store.path + assert_equal :system, store.type + end + + def test_store_for_site + store = @s.store_for 'site' + + assert_equal File.join(@base, 'site'), store.path + assert_equal :site, store.type + end + + def test_store_for_extra + store = @s.store_for 'extra-1' + + assert_equal @extra_dirs.first, store.path + assert_equal :extra, store.type + end + + def touch_system_cache_path + store = RDoc::Store.new @system_dir + store.title = 'Standard Library Documentation' + + FileUtils.mkdir_p File.dirname store.cache_path + + store.save + end + + def touch_extra_cache_path + store = RDoc::Store.new @extra_dirs.first + store.title = 'My Extra Documentation' + + FileUtils.mkdir_p File.dirname store.cache_path + + store.save + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_single_class.rb b/jni/ruby/test/rdoc/test_rdoc_single_class.rb new file mode 100644 index 0000000..e368b3d --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_single_class.rb @@ -0,0 +1,20 @@ +require 'rdoc/test_case' + +class TestRDocSingleClass < RDoc::TestCase + + def setup + super + + @c = RDoc::SingleClass.new 'C' + end + + def test_aref_prefix + assert_equal 'sclass', @c.aref_prefix + end + + def test_definition + assert_equal 'class << C', @c.definition + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_stats.rb b/jni/ruby/test/rdoc/test_rdoc_stats.rb new file mode 100644 index 0000000..cd37c29 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_stats.rb @@ -0,0 +1,722 @@ +require 'rdoc/test_case' + +class TestRDocStats < RDoc::TestCase + + def setup + super + + @s = RDoc::Stats.new @store, 0 + + @tl = @store.add_file 'file.rb' + @tl.parser = RDoc::Parser::Ruby + end + + def test_doc_stats + c = RDoc::CodeObject.new + + assert_equal [1, 1], @s.doc_stats([c]) + end + + def test_doc_stats_documented + c = RDoc::CodeObject.new + c.comment = comment 'x' + + assert_equal [1, 0], @s.doc_stats([c]) + end + + def test_doc_stats_display_eh + c = RDoc::CodeObject.new + c.ignore + + assert_equal [0, 0], @s.doc_stats([c]) + end + + def test_report_attr + c = @tl.add_class RDoc::NormalClass, 'C' + c.record_location @tl + c.add_comment 'C', @tl + + a = RDoc::Attr.new nil, 'a', 'RW', nil + a.record_location @tl + c.add_attribute a + + @store.complete :public + + report = @s.report + + expected = + doc( + para('The following items are not documented:'), + blank_line, + verb( + "class C # is documented\n", + "\n", + " attr_accessor :a # in file file.rb\n", + "\n", + "end\n"), + blank_line) + + assert_equal expected, report + end + + def test_report_attr_documented + c = @tl.add_class RDoc::NormalClass, 'C' + c.record_location @tl + c.add_comment 'C', @tl + + a = RDoc::Attr.new nil, 'a', 'RW', 'a' + a.record_location @tl + c.add_attribute a + + @store.complete :public + + report = @s.report + + assert_equal @s.great_job, report + end + + def test_report_attr_line + c = @tl.add_class RDoc::NormalClass, 'C' + c.record_location @tl + c.add_comment 'C', @tl + + a = RDoc::Attr.new nil, 'a', 'RW', nil + a.record_location @tl + a.line = 3 + c.add_attribute a + + @store.complete :public + + assert_match '# in file file.rb:3', @s.report.accept(to_rdoc) + end + + def test_report_constant + m = @tl.add_module RDoc::NormalModule, 'M' + m.record_location @tl + m.add_comment 'M', @tl + + c = RDoc::Constant.new 'C', nil, nil + c.record_location @tl + m.add_constant c + + @store.complete :public + + report = @s.report + + expected = + doc( + para('The following items are not documented:'), + blank_line, + verb( + "module M # is documented\n", + "\n", + " # in file file.rb\n", + " C = nil\n", + "\n", + "end\n"), + blank_line) + + assert_equal expected, report + end + + def test_report_constant_alias + mod = @tl.add_module RDoc::NormalModule, 'M' + + c = @tl.add_class RDoc::NormalClass, 'C' + mod.add_constant c + + ca = RDoc::Constant.new 'CA', nil, nil + ca.is_alias_for = c + + @tl.add_constant ca + + @store.complete :public + + report = @s.report + + # TODO change this to refute match, aliases should be ignored as they are + # programmer convenience constructs + assert_match 'class Object', report.accept(to_rdoc) + end + + def test_report_constant_documented + m = @tl.add_module RDoc::NormalModule, 'M' + m.record_location @tl + m.add_comment 'M', @tl + + c = RDoc::Constant.new 'C', nil, 'C' + c.record_location @tl + m.add_constant c + + @store.complete :public + + report = @s.report + + assert_equal @s.great_job, report + end + + def test_report_constant_line + m = @tl.add_module RDoc::NormalModule, 'M' + m.record_location @tl + m.add_comment 'M', @tl + + c = RDoc::Constant.new 'C', nil, nil + c.record_location @tl + c.line = 5 + m.add_constant c + + @store.complete :public + + assert_match '# in file file.rb:5', @s.report.accept(to_rdoc) + end + + def test_report_class + c = @tl.add_class RDoc::NormalClass, 'C' + c.record_location @tl + + m = RDoc::AnyMethod.new nil, 'm' + m.record_location @tl + c.add_method m + m.comment = 'm' + + @store.complete :public + + report = @s.report + + expected = + doc( + para('The following items are not documented:'), + blank_line, + para('In files:'), + list(:BULLET, *[ + item(nil, para('file.rb'))]), + blank_line, + verb("class C\n", "end\n"), + blank_line) + + assert_equal expected, report + end + + def test_report_skip_object + c = @tl.add_class RDoc::NormalClass, 'Object' + c.record_location @tl + + m = RDoc::AnyMethod.new nil, 'm' + m.record_location @tl + c.add_method m + m.comment = 'm' + + @store.complete :public + + refute_match %r%^class Object$%, @s.report.accept(to_rdoc) + end + + def test_report_class_documented + c = @tl.add_class RDoc::NormalClass, 'C' + c.record_location @tl + c.add_comment 'C', @tl + + m = RDoc::AnyMethod.new nil, 'm' + m.record_location @tl + c.add_method m + m.comment = 'm' + + @store.complete :public + + report = @s.report + + assert_equal @s.great_job, report + end + + def test_report_class_documented_level_1 + c1 = @tl.add_class RDoc::NormalClass, 'C1' + c1.record_location @tl + c1.add_comment 'C1', @tl + + m1 = RDoc::AnyMethod.new nil, 'm1' + m1.record_location @tl + c1.add_method m1 + m1.comment = 'm1' + + c2 = @tl.add_class RDoc::NormalClass, 'C2' + c2.record_location @tl + + m2 = RDoc::AnyMethod.new nil, 'm2' + m2.record_location @tl + c2.add_method m2 + m2.comment = 'm2' + + @store.complete :public + + @s.coverage_level = 1 + + report = @s.report + + expected = + doc( + para('The following items are not documented:'), + blank_line, + para('In files:'), + list(:BULLET, *[ + item(nil, para('file.rb'))]), + blank_line, + verb("class C2\n", "end\n"), + blank_line) + + assert_equal expected, report + end + + def test_report_class_empty + @tl.add_class RDoc::NormalClass, 'C' + + @store.complete :public + + report = @s.report + + expected = + doc( + para('The following items are not documented:'), + blank_line, + para('class C is referenced but empty.'), + para("It probably came from another project. I'm sorry I'm holding it against you."), + blank_line) + + assert_equal expected, report + end + + def test_report_class_empty_2 + c1 = @tl.add_class RDoc::NormalClass, 'C1' + c1.record_location @tl + + c2 = @tl.add_class RDoc::NormalClass, 'C2' + c2.record_location @tl + c2.add_comment 'C2', @tl + + @store.complete :public + + @s.coverage_level = 1 + report = @s.report + + expected = + doc( + para('The following items are not documented:'), + blank_line, + para('In files:'), + list(:BULLET, *[ + item(nil, para('file.rb'))]), + blank_line, + verb("class C1\n", "end\n"), + blank_line) + + assert_equal expected, report + end + + def test_report_class_method_documented + c = @tl.add_class RDoc::NormalClass, 'C' + c.record_location @tl + + m = RDoc::AnyMethod.new nil, 'm' + m.record_location @tl + c.add_method m + m.comment = 'm' + + @store.complete :public + + report = @s.report + + expected = + doc( + para('The following items are not documented:'), + blank_line, + para('In files:'), + list(:BULLET, *[ + item(nil, para('file.rb'))]), + blank_line, + verb("class C\n", "end\n"), + blank_line) + + assert_equal expected, report + end + + def test_report_class_module_ignore + c = @tl.add_class RDoc::NormalClass, 'C' + c.ignore + + @store.complete :public + + report = @s.report_class_module c + + assert_nil report + end + + def test_report_empty + @store.complete :public + + report = @s.report + + assert_equal @s.great_job, report + end + + def test_report_method + c = @tl.add_class RDoc::NormalClass, 'C' + c.record_location @tl + c.add_comment 'C', @tl + + m1 = RDoc::AnyMethod.new nil, 'm1' + m1.record_location @tl + c.add_method m1 + + m2 = RDoc::AnyMethod.new nil, 'm2' + m2.record_location @tl + c.add_method m2 + m2.comment = 'm2' + + @store.complete :public + + report = @s.report + + expected = + doc( + para('The following items are not documented:'), + blank_line, + verb(*[ + "class C # is documented\n", + "\n", + " # in file file.rb\n", + " def m1; end\n", + "\n", + "end\n"]), + blank_line) + + assert_equal expected, report + end + + def test_report_method_class + c = @tl.add_class RDoc::NormalClass, 'C' + c.record_location @tl + c.add_comment 'C', @tl + + m1 = RDoc::AnyMethod.new nil, 'm1' + m1.record_location @tl + m1.singleton = true + c.add_method m1 + + m2 = RDoc::AnyMethod.new nil, 'm2' + m2.record_location @tl + m2.singleton = true + c.add_method m2 + m2.comment = 'm2' + + @store.complete :public + + report = @s.report + + expected = + doc( + para('The following items are not documented:'), + blank_line, + verb(*[ + "class C # is documented\n", + "\n", + " # in file file.rb\n", + " def self.m1; end\n", + "\n", + "end\n"]), + blank_line) + + assert_equal expected, report + end + + def test_report_method_documented + c = @tl.add_class RDoc::NormalClass, 'C' + c.record_location @tl + c.add_comment 'C', @tl + + m = RDoc::AnyMethod.new nil, 'm' + m.record_location @tl + c.add_method m + m.comment = 'm' + + @store.complete :public + + report = @s.report + + assert_equal @s.great_job, report + end + + def test_report_method_line + c = @tl.add_class RDoc::NormalClass, 'C' + c.record_location @tl + c.add_comment 'C', @tl + + m1 = RDoc::AnyMethod.new nil, 'm1' + m1.record_location @tl + m1.line = 4 + c.add_method m1 + + @store.complete :public + + assert_match '# in file file.rb:4', @s.report.accept(to_rdoc) + end + + def test_report_method_parameters + c = @tl.add_class RDoc::NormalClass, 'C' + c.record_location @tl + c.add_comment 'C', @tl + + m1 = RDoc::AnyMethod.new nil, 'm1' + m1.record_location @tl + m1.params = '(p1, p2)' + m1.comment = 'Stuff with +p1+' + c.add_method m1 + + m2 = RDoc::AnyMethod.new nil, 'm2' + m2.record_location @tl + c.add_method m2 + m2.comment = 'm2' + + @store.complete :public + + @s.coverage_level = 1 + report = @s.report + + expected = + doc( + para('The following items are not documented:'), + blank_line, + verb(*[ + "class C # is documented\n", + "\n", + " # in file file.rb\n", + " # +p2+ is not documented\n", + " def m1(p1, p2); end\n", + "\n", + "end\n"]), + blank_line) + + assert_equal expected, report + end + + def test_report_method_parameters_documented + @tl.parser = RDoc::Parser::Ruby + c = @tl.add_class RDoc::NormalClass, 'C' + c.record_location @tl + c.add_comment 'C', @tl + + m = RDoc::AnyMethod.new nil, 'm' + m.record_location @tl + m.params = '(p1)' + m.comment = 'Stuff with +p1+' + c.add_method m + + @store.complete :public + + @s.coverage_level = 1 + report = @s.report + + assert_equal @s.great_job, report + end + + def test_report_method_parameters_yield + c = @tl.add_class RDoc::NormalClass, 'C' + c.record_location @tl + c.add_comment 'C', @tl + + m = RDoc::AnyMethod.new nil, 'm' + m.record_location @tl + m.call_seq = <<-SEQ +m(a) { |c| ... } +m(a, b) { |c, d| ... } + SEQ + m.comment = 'Stuff with +a+, yields +c+ for you to do stuff with' + c.add_method m + + @store.complete :public + + @s.coverage_level = 1 + report = @s.report + + expected = + doc( + para('The following items are not documented:'), + blank_line, + verb( + "class C # is documented\n", + "\n", + " # in file file.rb\n", + " # +b+, +d+ is not documented\n", + " def m; end\n", + "\n", + "end\n"), + blank_line) + + assert_equal expected, report + end + + def test_summary + c = @tl.add_class RDoc::NormalClass, 'C' + c.record_location @tl + + m = @tl.add_module RDoc::NormalModule, 'M' + m.record_location @tl + + a = RDoc::Attr.new nil, 'a', 'RW', nil + a.record_location @tl + c.add_attribute a + + c_c = RDoc::Constant.new 'C', nil, nil + c_c.record_location @tl + c.add_constant c_c + + m = RDoc::AnyMethod.new nil, 'm' + m.record_location @tl + c.add_method m + + @store.complete :public + + summary = @s.summary.accept to_rdoc + summary.sub!(/ Elapsed:.*/m, '') + + expected = <<-EXPECTED + Files: 0 + + Classes: 1 (1 undocumented) + Modules: 1 (1 undocumented) + Constants: 1 (1 undocumented) + Attributes: 1 (1 undocumented) + Methods: 1 (1 undocumented) + + Total: 5 (5 undocumented) + 0.00% documented + + EXPECTED + + assert_equal summary, expected + end + + def test_summary_level_false + c = @tl.add_class RDoc::NormalClass, 'C' + c.record_location @tl + + @store.complete :public + + @s.coverage_level = false + + summary = @s.summary.accept to_rdoc + summary.sub!(/ Elapsed:.*/m, '') + + expected = <<-EXPECTED + Files: 0 + + Classes: 1 (1 undocumented) + Modules: 0 (0 undocumented) + Constants: 0 (0 undocumented) + Attributes: 0 (0 undocumented) + Methods: 0 (0 undocumented) + + Total: 1 (1 undocumented) + 0.00% documented + + EXPECTED + + assert_equal summary, expected + end + + def test_summary_level_1 + c = @tl.add_class RDoc::NormalClass, 'C' + c.record_location @tl + c.add_comment 'C', @tl + + m = RDoc::AnyMethod.new nil, 'm' + m.record_location @tl + m.params = '(p1, p2)' + m.comment = 'Stuff with +p1+' + c.add_method m + + @store.complete :public + + @s.coverage_level = 1 + @s.report + + summary = @s.summary.accept to_rdoc + summary.sub!(/ Elapsed:.*/m, '') + + expected = <<-EXPECTED + Files: 0 + + Classes: 1 (0 undocumented) + Modules: 0 (0 undocumented) + Constants: 0 (0 undocumented) + Attributes: 0 (0 undocumented) + Methods: 1 (0 undocumented) + Parameters: 2 (1 undocumented) + + Total: 4 (1 undocumented) + 75.00% documented + + EXPECTED + + assert_equal summary, expected + end + + def to_rdoc + RDoc::Markup::ToRdoc.new + end + + def test_undoc_params + method = RDoc::AnyMethod.new [], 'm' + method.params = '(a)' + method.comment = comment 'comment' + + total, undoc = @s.undoc_params method + + assert_equal 1, total + assert_equal %w[a], undoc + end + + def test_undoc_params_block + method = RDoc::AnyMethod.new [], 'm' + method.params = '(&a)' + method.comment = comment '+a+' + + total, undoc = @s.undoc_params method + + assert_equal 1, total + assert_empty undoc + end + + def test_undoc_params_documented + method = RDoc::AnyMethod.new [], 'm' + method.params = '(a)' + method.comment = comment '+a+' + + total, undoc = @s.undoc_params method + + assert_equal 1, total + assert_empty undoc + end + + def test_undoc_params_keywords + method = RDoc::AnyMethod.new [], 'm' + method.params = '(**a)' + method.comment = comment '+a+' + + total, undoc = @s.undoc_params method + + assert_equal 1, total + assert_empty undoc + end + + def test_undoc_params_splat + method = RDoc::AnyMethod.new [], 'm' + method.params = '(*a)' + method.comment = comment '+a+' + + total, undoc = @s.undoc_params method + + assert_equal 1, total + assert_empty undoc + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_store.rb b/jni/ruby/test/rdoc/test_rdoc_store.rb new file mode 100644 index 0000000..bd565e7 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_store.rb @@ -0,0 +1,993 @@ +require File.expand_path '../xref_test_case', __FILE__ + +class TestRDocStore < XrefTestCase + + OBJECT_ANCESTORS = defined?(::BasicObject) ? %w[BasicObject] : [] + + def setup + super + + @tmpdir = File.join Dir.tmpdir, "test_rdoc_ri_store_#{$$}" + @s = RDoc::RI::Store.new @tmpdir + @s.rdoc = @rdoc + + @top_level = @s.add_file 'file.rb' + + @page = @s.add_file 'README.txt' + @page.parser = RDoc::Parser::Simple + @page.comment = RDoc::Comment.new 'This is a page', @page + + @klass = @top_level.add_class RDoc::NormalClass, 'Object' + @klass.add_comment 'original', @top_level + @klass.record_location @top_level + + @cmeth = RDoc::AnyMethod.new nil, 'cmethod' + @cmeth.singleton = true + @cmeth.record_location @top_level + + @meth_comment = RDoc::Comment.new 'method comment' + @meth_comment.location = @top_level + + @meth = RDoc::AnyMethod.new nil, 'method' + @meth.record_location @top_level + @meth.comment = @meth_comment + + @meth_bang = RDoc::AnyMethod.new nil, 'method!' + @meth_bang.record_location @top_level + + @meth_bang_alias = RDoc::Alias.new nil, 'method!', 'method_bang', '' + @meth_bang_alias.record_location @top_level + + @meth_bang.add_alias @meth_bang_alias, @klass + + @attr_comment = RDoc::Comment.new 'attribute comment' + @attr_comment.location = @top_level + + @attr = RDoc::Attr.new nil, 'attr', 'RW', '' + @attr.record_location @top_level + @attr.comment = @attr_comment + + @klass.add_method @cmeth + @klass.add_method @meth + @klass.add_method @meth_bang + @klass.add_attribute @attr + + @nest_klass = @klass.add_class RDoc::NormalClass, 'SubClass' + @nest_meth = RDoc::AnyMethod.new nil, 'method' + @nest_meth.record_location @top_level + + @nest_incl = RDoc::Include.new 'Incl', '' + @nest_incl.record_location @top_level + + @nest_klass.add_method @nest_meth + @nest_klass.add_include @nest_incl + + @mod = @top_level.add_module RDoc::NormalModule, 'Mod' + @mod.record_location @top_level + end + + def teardown + super + + FileUtils.rm_rf @tmpdir + end + + def assert_cache imethods, cmethods, attrs, modules, + ancestors = {}, pages = [], main = nil, title = nil + imethods ||= { 'Object' => %w[method method! method_bang] } + cmethods ||= { 'Object' => %w[cmethod] } + attrs ||= { 'Object' => ['attr_accessor attr'] } + + # this is sort-of a hack + @s.clean_cache_collection ancestors + + expected = { + :ancestors => ancestors, + :attributes => attrs, + :class_methods => cmethods, + :c_class_variables => {}, + :c_singleton_class_variables => {}, + :encoding => nil, + :instance_methods => imethods, + :modules => modules, + :pages => pages, + :main => main, + :title => title, + } + + @s.save_cache + + assert_equal expected, @s.cache + end + + def test_add_c_enclosure + @s.add_c_enclosure 'cC1', @c1 + + expected = { 'cC1' => @c1 } + + assert_equal expected, @s.c_enclosure_classes + end + + def test_add_c_variables + options = RDoc::Options.new + + c_file = @s.add_file 'ext.c' + + some_ext = c_file.add_class RDoc::NormalClass, 'SomeExt' + c_file.add_class RDoc::SingleClass, 'SomeExtSingle' + + c_parser = RDoc::Parser::C.new c_file, 'ext.c', '', options, nil + + c_parser.classes['cSomeExt'] = some_ext + c_parser.singleton_classes['s_cSomeExt'] = 'SomeExtSingle' + + @s.add_c_variables c_parser + + expected = { 'ext.c' => { 'cSomeExt' => 'SomeExt' } } + + assert_equal expected, @s.c_class_variables + + expected = { 'ext.c' => { 's_cSomeExt' => 'SomeExtSingle' } } + + assert_equal expected, @s.c_singleton_class_variables + end + + def test_add_file + top_level = @store.add_file 'file.rb' + + assert_kind_of RDoc::TopLevel, top_level + assert_equal @store, top_level.store + assert_equal 'file.rb', top_level.name + assert_includes @store.all_files, top_level + + assert_same top_level, @store.add_file('file.rb') + refute_same top_level, @store.add_file('other.rb') + end + + def test_add_file_relative + top_level = @store.add_file 'path/file.rb', 'file.rb' + + assert_kind_of RDoc::TopLevel, top_level + assert_equal @store, top_level.store + + assert_equal 'path/file.rb', top_level.absolute_name + assert_equal 'file.rb', top_level.relative_name + + assert_includes @store.all_files, top_level + + assert_same top_level, @store.add_file('file.rb') + refute_same top_level, @store.add_file('other.rb') + end + + def test_all_classes_and_modules + expected = %w[ + C1 C2 C2::C3 C2::C3::H1 C3 C3::H1 C3::H2 C4 C4::C4 C5 C5::C1 + Child + M1 M1::M2 + Parent + ] + + assert_equal expected, + @store.all_classes_and_modules.map { |m| m.full_name }.sort + end + + def test_all_files + assert_equal %w[xref_data.rb], + @store.all_files.map { |m| m.full_name }.sort + end + + def test_all_modules + assert_equal %w[M1 M1::M2], + @store.all_modules.map { |m| m.full_name }.sort + end + + def test_attributes + @s.cache[:attributes]['Object'] = %w[attr] + + expected = { 'Object' => %w[attr] } + + assert_equal expected, @s.attributes + end + + def test_class_file + assert_equal File.join(@tmpdir, 'Object', 'cdesc-Object.ri'), + @s.class_file('Object') + assert_equal File.join(@tmpdir, 'Object', 'SubClass', 'cdesc-SubClass.ri'), + @s.class_file('Object::SubClass') + end + + def test_class_methods + @s.cache[:class_methods]['Object'] = %w[method] + + expected = { 'Object' => %w[method] } + + assert_equal expected, @s.class_methods + end + + def test_class_path + assert_equal File.join(@tmpdir, 'Object'), @s.class_path('Object') + assert_equal File.join(@tmpdir, 'Object', 'SubClass'), + @s.class_path('Object::SubClass') + end + + def test_classes + expected = %w[ + C1 C2 C2::C3 C2::C3::H1 C3 C3::H1 C3::H2 C4 C4::C4 C5 C5::C1 + Child + Parent + ] + + assert_equal expected, @store.all_classes.map { |m| m.full_name }.sort + end + + def test_complete + @c2.add_module_alias @c2_c3, 'A1', @top_level + + @store.complete :public + + a1 = @xref_data.find_class_or_module 'C2::A1' + + assert_equal 'C2::A1', a1.full_name + refute_empty a1.aliases + end + + def test_complete_nodoc + c_nodoc = @top_level.add_class RDoc::NormalClass, 'Nodoc' + c_nodoc.record_location @top_level + c_nodoc.document_self = nil + + @s.complete :nodoc + + assert_includes @s.classes_hash.keys, 'Nodoc' + end + + def test_find_c_enclosure + assert_nil @s.find_c_enclosure 'cC1' + + @s.add_c_enclosure 'cC1', @c1 + + assert_equal @c1, @s.find_c_enclosure('cC1') + end + + def test_find_c_enclosure_from_cache + @s.save_class @klass + @s.classes_hash.clear + + assert_nil @s.find_c_enclosure 'cObject' + + @s.c_enclosure_names['cObject'] = 'Object' + + klass = @s.find_c_enclosure('cObject') + assert_equal @klass, klass + + assert_empty klass.comment_location + assert_equal @top_level, klass.parent + + assert_includes @s.c_enclosure_classes, 'cObject' + end + + def test_find_c_enclosure_from_cache_legacy + @klass.in_files.clear + @s.save_class @klass + @s.classes_hash.clear + + assert_nil @s.find_c_enclosure 'cObject' + + @s.c_enclosure_names['cObject'] = 'Object' + + assert_nil @s.find_c_enclosure('cObject') + end + + def test_find_class_named + assert_equal @c1, @store.find_class_named('C1') + + assert_equal @c2_c3, @store.find_class_named('C2::C3') + end + + def test_find_class_named_from + assert_equal @c5_c1, @store.find_class_named_from('C1', 'C5') + + assert_equal @c1, @store.find_class_named_from('C1', 'C4') + end + + def test_find_class_or_module + assert_equal @m1, @store.find_class_or_module('M1') + assert_equal @c1, @store.find_class_or_module('C1') + + assert_equal @m1, @store.find_class_or_module('::M1') + assert_equal @c1, @store.find_class_or_module('::C1') + end + + def test_find_file_named + assert_equal @xref_data, @store.find_file_named(@file_name) + end + + def test_find_module_named + assert_equal @m1, @store.find_module_named('M1') + assert_equal @m1_m2, @store.find_module_named('M1::M2') + end + + def test_find_text_page + page = @store.add_file 'PAGE.txt' + page.parser = RDoc::Parser::Simple + + assert_nil @store.find_text_page 'no such page' + + assert_equal page, @store.find_text_page('PAGE.txt') + end + + def test_friendly_path + @s.path = @tmpdir + @s.type = nil + assert_equal @s.path, @s.friendly_path + + @s.type = :extra + assert_equal @s.path, @s.friendly_path + + @s.type = :system + assert_equal "ruby core", @s.friendly_path + + @s.type = :site + assert_equal "ruby site", @s.friendly_path + + @s.type = :home + assert_equal "~/.rdoc", @s.friendly_path + + @s.type = :gem + @s.path = "#{@tmpdir}/gem_repository/doc/gem_name-1.0/ri" + assert_equal "gem gem_name-1.0", @s.friendly_path + end + + def test_dry_run + refute @s.dry_run + + @s.dry_run = true + + assert @s.dry_run + end + + def test_instance_methods + @s.cache[:instance_methods]['Object'] = %w[method] + + expected = { 'Object' => %w[method] } + + assert_equal expected, @s.instance_methods + end + + def test_load_all + FileUtils.mkdir_p @tmpdir + + @s.save + + s = RDoc::Store.new @tmpdir + + s.load_all + + assert_equal [@klass, @nest_klass], s.all_classes.sort + assert_equal [@mod], s.all_modules.sort + assert_equal [@page, @top_level], s.all_files.sort + + methods = s.all_classes_and_modules.map do |mod| + mod.method_list + end.flatten.sort + + _meth_bang_alias = RDoc::AnyMethod.new nil, 'method_bang' + _meth_bang_alias.parent = @klass + + assert_equal [@meth, @meth_bang, _meth_bang_alias, @nest_meth, @cmeth], + methods.sort_by { |m| m.full_name } + + method = methods.find { |m| m == @meth } + assert_equal @meth_comment.parse, method.comment + + assert_equal @klass, methods.last.parent + + attributes = s.all_classes_and_modules.map do |mod| + mod.attributes + end.flatten.sort + + assert_equal [@attr], attributes + + assert_equal @attr_comment.parse, attributes.first.comment + end + + def test_load_cache + cache = { + :c_class_variables => + { 'file.c' => { 'cKlass' => 'Klass' } }, + :c_singleton_class_variables => + { 'file.c' => { 'sKlass' => 'KlassSingle' } }, + :encoding => :encoding_value, + :methods => { "Object" => %w[Object#method] }, + :main => @page.full_name, + :modules => %w[Object], + :pages => [], + } + + Dir.mkdir @tmpdir + + open File.join(@tmpdir, 'cache.ri'), 'wb' do |io| + Marshal.dump cache, io + end + + @s.load_cache + + assert_equal cache, @s.cache + + assert_equal :encoding_value, @s.encoding + assert_equal 'README.txt', @s.main + + expected = { 'file.c' => { 'cKlass' => 'Klass' } } + assert_equal expected, @s.cache[:c_class_variables] + + expected = { 'file.c' => { 'sKlass' => 'KlassSingle' } } + assert_equal expected, @s.cache[:c_singleton_class_variables] + + expected = { 'cKlass' => 'Klass' } + assert_equal expected, @s.c_enclosure_names + end + + def test_load_cache_encoding_differs + skip "Encoding not implemented" unless Object.const_defined? :Encoding + + cache = { + :c_class_variables => {}, + :c_singleton_class_variables => {}, + :encoding => Encoding::ISO_8859_1, + :main => nil, + :methods => { "Object" => %w[Object#method] }, + :modules => %w[Object], + :pages => [], + } + + Dir.mkdir @tmpdir + + open File.join(@tmpdir, 'cache.ri'), 'wb' do |io| + Marshal.dump cache, io + end + + @s.encoding = Encoding::UTF_8 + + @s.load_cache + + assert_equal cache, @s.cache + + assert_equal Encoding::UTF_8, @s.encoding + end + + def test_load_cache_no_cache + cache = { + :ancestors => {}, + :attributes => {}, + :class_methods => {}, + :c_class_variables => {}, + :c_singleton_class_variables => {}, + :encoding => nil, + :instance_methods => {}, + :main => nil, + :modules => [], + :pages => [], + :title => nil, + } + + @s.load_cache + + assert_equal cache, @s.cache + end + + def test_load_cache_legacy + cache = { + :ancestors => {}, + :attributes => {}, + :class_methods => {}, + :encoding => :encoding_value, + :instance_methods => { "Object" => %w[Object#method] }, + :modules => %w[Object], + # no :pages + # no :main + # no :c_class_variables + # no :c_singleton_class_variables + } + + Dir.mkdir @tmpdir + + open File.join(@tmpdir, 'cache.ri'), 'wb' do |io| + Marshal.dump cache, io + end + + @s.load_cache + + expected = { + :ancestors => {}, + :attributes => {}, + :class_methods => {}, + :c_class_variables => {}, + :c_singleton_class_variables => {}, + :encoding => :encoding_value, + :instance_methods => { "Object" => %w[Object#method] }, + :main => nil, + :modules => %w[Object], + :pages => [], + } + + assert_equal expected, @s.cache + + assert_equal :encoding_value, @s.encoding + assert_nil @s.main + end + + def test_load_class + @s.save_class @klass + @s.classes_hash.clear + + assert_equal @klass, @s.load_class('Object') + + assert_includes @s.classes_hash, 'Object' + end + + def test_load_method + @s.save_method @klass, @meth_bang + + meth = @s.load_method('Object', '#method!') + assert_equal @meth_bang, meth + assert_equal @klass, meth.parent + assert_equal @s, meth.store + end + + def test_load_method_legacy + @s.save_method @klass, @meth + + file = @s.method_file @klass.full_name, @meth.full_name + + open file, 'wb' do |io| + io.write "\x04\bU:\x14RDoc::AnyMethod[\x0Fi\x00I" + + "\"\vmethod\x06:\x06EF\"\x11Klass#method0:\vpublic" + + "o:\eRDoc::Markup::Document\x06:\v@parts[\x06" + + "o:\x1CRDoc::Markup::Paragraph\x06;\t[\x06I" + + "\"\x16this is a comment\x06;\x06FI" + + "\"\rcall_seq\x06;\x06FI\"\x0Fsome_block\x06;\x06F" + + "[\x06[\aI\"\faliased\x06;\x06Fo;\b\x06;\t[\x06" + + "o;\n\x06;\t[\x06I\"\x12alias comment\x06;\x06FI" + + "\"\nparam\x06;\x06F" + end + + meth = @s.load_method('Object', '#method') + assert_equal 'Klass#method', meth.full_name + assert_equal @klass, meth.parent + assert_equal @s, meth.store + end + + def test_load_page + @s.save_page @page + + assert_equal @page, @s.load_page('README.txt') + end + + def test_main + assert_equal nil, @s.main + + @s.main = 'README.txt' + + assert_equal 'README.txt', @s.main + end + + def test_method_file + assert_equal File.join(@tmpdir, 'Object', 'method-i.ri'), + @s.method_file('Object', 'Object#method') + + assert_equal File.join(@tmpdir, 'Object', 'method%21-i.ri'), + @s.method_file('Object', 'Object#method!') + + assert_equal File.join(@tmpdir, 'Object', 'SubClass', 'method%21-i.ri'), + @s.method_file('Object::SubClass', 'Object::SubClass#method!') + + assert_equal File.join(@tmpdir, 'Object', 'method-c.ri'), + @s.method_file('Object', 'Object::method') + end + + def test_module_names + @s.save_class @klass + + assert_equal %w[Object], @s.module_names + end + + def test_page + page = @store.add_file 'PAGE.txt' + page.parser = RDoc::Parser::Simple + + assert_nil @store.page 'no such page' + + assert_equal page, @store.page('PAGE') + end + + def test_save + FileUtils.mkdir_p @tmpdir + + @s.save + + assert_directory File.join(@tmpdir, 'Object') + + assert_file File.join(@tmpdir, 'Object', 'cdesc-Object.ri') + assert_file File.join(@tmpdir, 'Object', 'method-i.ri') + assert_file File.join(@tmpdir, 'page-README_txt.ri') + + assert_file File.join(@tmpdir, 'cache.ri') + + expected = { + :ancestors => { + 'Object::SubClass' => %w[Incl Object], + }, + :attributes => { 'Object' => ['attr_accessor attr'] }, + :class_methods => { 'Object' => %w[cmethod] }, + :c_class_variables => {}, + :c_singleton_class_variables => {}, + :instance_methods => { + 'Object' => %w[attr method method! method_bang], + 'Object::SubClass' => %w[method], + }, + :main => nil, + :modules => %w[Mod Object Object::SubClass], + :encoding => nil, + :pages => %w[README.txt], + :title => nil, + } + + expected[:ancestors]['Object'] = %w[BasicObject] if defined?(::BasicObject) + + open File.join(@tmpdir, 'cache.ri'), 'rb' do |io| + cache = Marshal.load io.read + + assert_equal expected, cache + end + end + + def test_save_cache + @s.save_class @klass + @s.save_method @klass, @meth + @s.save_method @klass, @cmeth + @s.save_class @nest_klass + @s.save_page @page + @s.encoding = :encoding_value + @s.main = @page.full_name + @s.title = 'title' + + options = RDoc::Options.new + + c_file = @s.add_file 'ext.c' + + some_ext = c_file.add_class RDoc::NormalClass, 'SomeExt' + c_file.add_class RDoc::SingleClass, 'SomeExtSingle' + + c_parser = RDoc::Parser::C.new c_file, 'ext.c', '', options, nil + + c_parser.classes['cSomeExt'] = some_ext + c_parser.singleton_classes['s_cSomeExt'] = 'SomeExtSingle' + + @s.add_c_variables c_parser + + @s.save_cache + + assert_file File.join(@tmpdir, 'cache.ri') + + c_class_variables = { + 'ext.c' => { + 'cSomeExt' => 'SomeExt' + } + } + + c_singleton_class_variables = { + 'ext.c' => { + 's_cSomeExt' => 'SomeExtSingle' + } + } + + expected = { + :ancestors => { + 'Object::SubClass' => %w[Incl Object], + }, + :attributes => { 'Object' => ['attr_accessor attr'] }, + :class_methods => { 'Object' => %w[cmethod] }, + :c_class_variables => c_class_variables, + :c_singleton_class_variables => c_singleton_class_variables, + :instance_methods => { + 'Object' => %w[method method! method_bang], + 'Object::SubClass' => %w[method], + }, + :main => @page.full_name, + :modules => %w[Object Object::SubClass], + :encoding => :encoding_value, + :pages => %w[README.txt], + :title => 'title', + } + + expected[:ancestors]['Object'] = %w[BasicObject] if defined?(::BasicObject) + + open File.join(@tmpdir, 'cache.ri'), 'rb' do |io| + cache = Marshal.load io.read + + assert_equal expected, cache + end + end + + def test_save_cache_dry_run + @s.dry_run = true + + @s.save_class @klass + @s.save_method @klass, @meth + @s.save_method @klass, @cmeth + @s.save_class @nest_klass + + @s.save_cache + + refute_file File.join(@tmpdir, 'cache.ri') + end + + def test_save_cache_duplicate_methods + @s.save_method @klass, @meth + @s.save_method @klass, @meth + + @s.save_cache + + assert_cache({ 'Object' => %w[method] }, {}, {}, []) + end + + def test_save_cache_duplicate_pages + @s.save_page @page + @s.save_page @page + + @s.save_cache + + assert_cache({}, {}, {}, [], {}, %w[README.txt]) + end + + def test_save_class + @s.save_class @klass + + assert_directory File.join(@tmpdir, 'Object') + assert_file File.join(@tmpdir, 'Object', 'cdesc-Object.ri') + + assert_cache nil, nil, nil, %w[Object], 'Object' => OBJECT_ANCESTORS + + assert_equal @klass, @s.load_class('Object') + end + + def test_save_class_basic_object + @klass.instance_variable_set :@superclass, nil + + @s.save_class @klass + + assert_directory File.join(@tmpdir, 'Object') + assert_file File.join(@tmpdir, 'Object', 'cdesc-Object.ri') + + assert_cache(nil, nil, nil, %w[Object]) + + assert_equal @klass, @s.load_class('Object') + end + + def test_save_class_delete + # save original + @s.save_class @klass + @s.save_method @klass, @meth + @s.save_method @klass, @meth_bang + @s.save_method @klass, @cmeth + @s.save_method @klass, @attr + @s.save_cache + + klass = RDoc::NormalClass.new 'Object' + + meth = klass.add_method RDoc::AnyMethod.new(nil, 'replace') + meth.record_location @top_level + + # load original, save newly updated class + @s = RDoc::RI::Store.new @tmpdir + @s.load_cache + @s.save_class klass + @s.save_cache + + # load from disk again + @s = RDoc::RI::Store.new @tmpdir + @s.load_cache + + @s.load_class 'Object' + + assert_cache({ 'Object' => %w[replace] }, {}, + { 'Object' => %w[attr_accessor\ attr] }, %w[Object], + 'Object' => OBJECT_ANCESTORS) + + # assert these files were deleted + refute_file @s.method_file(@klass.full_name, @meth.full_name) + refute_file @s.method_file(@klass.full_name, @meth_bang.full_name) + refute_file @s.method_file(@klass.full_name, @cmeth.full_name) + + # assert these files were not deleted + assert_file @s.method_file(@klass.full_name, @attr.full_name) + end + + def test_save_class_dry_run + @s.dry_run = true + + @s.save_class @klass + + refute_file File.join(@tmpdir, 'Object') + refute_file File.join(@tmpdir, 'Object', 'cdesc-Object.ri') + end + + def test_save_class_loaded + @s.save + + assert_directory File.join(@tmpdir, 'Object') + assert_file File.join(@tmpdir, 'Object', 'cdesc-Object.ri') + + assert_file @s.method_file(@klass.full_name, @attr.full_name) + assert_file @s.method_file(@klass.full_name, @cmeth.full_name) + assert_file @s.method_file(@klass.full_name, @meth.full_name) + assert_file @s.method_file(@klass.full_name, @meth_bang.full_name) + + s = RDoc::Store.new @s.path + s.load_cache + + loaded = s.load_class 'Object' + + assert_equal @klass, loaded + + s.save_class loaded + + s = RDoc::Store.new @s.path + s.load_cache + + reloaded = s.load_class 'Object' + + assert_equal @klass, reloaded + + # assert these files were not deleted. Bug #171 + assert_file s.method_file(@klass.full_name, @attr.full_name) + assert_file s.method_file(@klass.full_name, @cmeth.full_name) + assert_file s.method_file(@klass.full_name, @meth.full_name) + assert_file s.method_file(@klass.full_name, @meth_bang.full_name) + end + + def test_save_class_merge + @s.save_class @klass + + klass = RDoc::NormalClass.new 'Object' + klass.add_comment 'new comment', @top_level + + s = RDoc::RI::Store.new @tmpdir + s.save_class klass + + s = RDoc::RI::Store.new @tmpdir + + inner = @RM::Document.new @RM::Paragraph.new 'new comment' + inner.file = @top_level + + document = @RM::Document.new inner + + assert_equal document, s.load_class('Object').comment_location + end + + # This is a functional test + def test_save_class_merge_constant + store = RDoc::Store.new + tl = store.add_file 'file.rb' + + klass = tl.add_class RDoc::NormalClass, 'C' + klass.add_comment 'comment', tl + + const = klass.add_constant RDoc::Constant.new('CONST', nil, nil) + const.record_location tl + + @s.save_class klass + + # separate parse run, independent store + store = RDoc::Store.new + tl = store.add_file 'file.rb' + klass2 = tl.add_class RDoc::NormalClass, 'C' + klass2.record_location tl + + s = RDoc::RI::Store.new @tmpdir + s.save_class klass2 + + # separate `ri` run, independent store + s = RDoc::RI::Store.new @tmpdir + + result = s.load_class 'C' + + assert_empty result.constants + end + + def test_save_class_methods + @s.save_class @klass + + assert_directory File.join(@tmpdir, 'Object') + assert_file File.join(@tmpdir, 'Object', 'cdesc-Object.ri') + + assert_cache nil, nil, nil, %w[Object], 'Object' => OBJECT_ANCESTORS + + assert_equal @klass, @s.load_class('Object') + end + + def test_save_class_nested + @s.save_class @nest_klass + + assert_directory File.join(@tmpdir, 'Object', 'SubClass') + assert_file File.join(@tmpdir, 'Object', 'SubClass', 'cdesc-SubClass.ri') + + assert_cache({ 'Object::SubClass' => %w[method] }, {}, {}, + %w[Object::SubClass], 'Object::SubClass' => %w[Incl Object]) + end + + def test_save_method + @s.save_method @klass, @meth + + assert_directory File.join(@tmpdir, 'Object') + assert_file File.join(@tmpdir, 'Object', 'method-i.ri') + + assert_cache({ 'Object' => %w[method] }, {}, {}, []) + + assert_equal @meth, @s.load_method('Object', '#method') + end + + def test_save_method_dry_run + @s.dry_run = true + + @s.save_method @klass, @meth + + refute_file File.join(@tmpdir, 'Object') + refute_file File.join(@tmpdir, 'Object', 'method-i.ri') + end + + def test_save_method_nested + @s.save_method @nest_klass, @nest_meth + + assert_directory File.join(@tmpdir, 'Object', 'SubClass') + assert_file File.join(@tmpdir, 'Object', 'SubClass', 'method-i.ri') + + assert_cache({ 'Object::SubClass' => %w[method] }, {}, {}, []) + end + + def test_save_page + @s.save_page @page + + assert_file File.join(@tmpdir, 'page-README_txt.ri') + + assert_cache({}, {}, {}, [], {}, %w[README.txt]) + end + + def test_save_page_file + @s.save_page @top_level + + refute_file File.join(@tmpdir, 'page-file_rb.ri') + end + + def test_source + @s.path = @tmpdir + @s.type = nil + assert_equal @s.path, @s.source + + @s.type = :extra + assert_equal @s.path, @s.source + + @s.type = :system + assert_equal "ruby", @s.source + + @s.type = :site + assert_equal "site", @s.source + + @s.type = :home + assert_equal "home", @s.source + + @s.type = :gem + @s.path = "#{@tmpdir}/gem_repository/doc/gem_name-1.0/ri" + assert_equal "gem_name-1.0", @s.source + end + + def test_title + assert_equal nil, @s.title + + @s.title = 'rdoc' + + assert_equal 'rdoc', @s.title + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_task.rb b/jni/ruby/test/rdoc/test_rdoc_task.rb new file mode 100644 index 0000000..43d4589 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_task.rb @@ -0,0 +1,170 @@ +require 'rdoc/test_case' +require 'rake' + +class TestRDocTask < RDoc::TestCase + + def setup + super + + Rake::Task.clear + + @t = RDoc::Task.new + end + + def test_clobber_task_description + assert_equal 'Remove RDoc HTML files', @t.clobber_task_description + end + + def test_inline_source + _, err = verbose_capture_io do + assert @t.inline_source + end + + assert_equal "RDoc::Task#inline_source is deprecated\n", err + + _, err = verbose_capture_io do + @t.inline_source = false + end + + assert_equal "RDoc::Task#inline_source is deprecated\n", err + + capture_io do + assert @t.inline_source + end + end + + def test_markup_option + rdoc_task = RDoc::Task.new do |rd| + rd.markup = "tomdoc" + end + + assert_equal %w[-o html --markup tomdoc], rdoc_task.option_list + end + + def test_tasks_creation + RDoc::Task.new + assert Rake::Task[:rdoc] + assert Rake::Task[:clobber_rdoc] + assert Rake::Task[:rerdoc] + assert_equal ["html/created.rid"], Rake::Task[:rdoc].prerequisites + end + + def test_tasks_creation_with_custom_name_symbol + rd = RDoc::Task.new(:rdoc_dev) + assert Rake::Task[:rdoc_dev] + assert Rake::Task[:clobber_rdoc_dev] + assert Rake::Task[:rerdoc_dev] + assert_equal :rdoc_dev, rd.name + end + + def test_tasks_option_parser + rdoc_task = RDoc::Task.new do |rd| + rd.title = "Test Tasks Option Parser" + rd.main = "README.md" + rd.rdoc_files.include("README.md") + rd.options << "--all" + end + + assert rdoc_task.title, "Test Tasks Option Parser" + assert rdoc_task.main, "README.md" + assert rdoc_task.rdoc_files.include?("README.md") + assert rdoc_task.options.include?("--all") + + args = %w[--all -o html --main README.md] << "--title" << "Test Tasks Option Parser" << "README.md" + assert_equal args, rdoc_task.option_list + rdoc_task.rdoc_files + end + + def test_generator_option + rdoc_task = RDoc::Task.new do |rd| + rd.generator = "ri" + end + + assert_equal %w[-o html -f ri], rdoc_task.option_list + end + + def test_main_option + rdoc_task = RDoc::Task.new do |rd| + rd.main = "README.md" + end + + assert_equal %w[-o html --main README.md], rdoc_task.option_list + end + + def test_output_dir_option + rdoc_task = RDoc::Task.new do |rd| + rd.rdoc_dir = "zomg" + end + + assert_equal %w[-o zomg], rdoc_task.option_list + end + + def test_rdoc_task_description + assert_equal 'Build RDoc HTML files', @t.rdoc_task_description + end + + def test_rerdoc_task_description + assert_equal 'Rebuild RDoc HTML files', @t.rerdoc_task_description + end + + def test_tasks_creation_with_custom_name_string + rd = RDoc::Task.new("rdoc_dev") + assert Rake::Task[:rdoc_dev] + assert Rake::Task[:clobber_rdoc_dev] + assert Rake::Task[:rerdoc_dev] + assert_equal "rdoc_dev", rd.name + end + + def test_tasks_creation_with_custom_name_hash + options = { + :rdoc => "rdoc", + :clobber_rdoc => "rdoc:clean", + :rerdoc => "rdoc:force" + } + + Rake::Task.clear + + rd = RDoc::Task.new(options) + assert Rake::Task[:"rdoc"] + assert Rake::Task[:"rdoc:clean"] + assert Rake::Task[:"rdoc:force"] + assert_raises(RuntimeError) { Rake::Task[:clobber_rdoc] } + assert_equal options, rd.name + end + + def test_tasks_creation_with_custom_name_hash_will_use_default_if_an_option_isnt_given + RDoc::Task.new(:clobber_rdoc => "rdoc:clean") + assert Rake::Task[:rdoc] + assert Rake::Task[:"rdoc:clean"] + assert Rake::Task[:rerdoc] + end + + def test_tasks_creation_with_custom_name_hash_raises_exception_if_invalid_option_given + assert_raises(ArgumentError) do + RDoc::Task.new(:foo => "bar") + end + + begin + RDoc::Task.new(:foo => "bar") + rescue ArgumentError => e + assert_match(/foo/, e.message) + end + end + + def test_template_option + rdoc_task = RDoc::Task.new do |rd| + rd.template = "foo" + end + + assert_equal %w[-o html -T foo], rdoc_task.option_list + end + + def test_title_option + rdoc_task = RDoc::Task.new do |rd| + rd.title = "Test Title Option" + end + + assert_equal %w[-o html] << "--title" << "Test Title Option", rdoc_task.option_list + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_text.rb b/jni/ruby/test/rdoc/test_rdoc_text.rb new file mode 100644 index 0000000..a69989d --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_text.rb @@ -0,0 +1,557 @@ +# coding: utf-8 + +require 'rdoc/test_case' + +class TestRDocText < RDoc::TestCase + + include RDoc::Text + + def setup + super + + @options = RDoc::Options.new + + @top_level = @store.add_file 'file.rb' + end + + def test_self_encode_fallback + skip "Encoding not implemented" unless Object.const_defined? :Encoding + + assert_equal '…', + RDoc::Text::encode_fallback('…', Encoding::UTF_8, '...') + assert_equal '...', + RDoc::Text::encode_fallback('…', Encoding::US_ASCII, '...') + end + + def test_expand_tabs + assert_equal("hello\n dave", + expand_tabs("hello\n dave"), 'spaces') + + assert_equal("hello\n dave", + expand_tabs("hello\n\tdave"), 'tab') + + assert_equal("hello\n dave", + expand_tabs("hello\n \tdave"), '1 space tab') + + assert_equal("hello\n dave", + expand_tabs("hello\n \tdave"), '2 space tab') + + assert_equal("hello\n dave", + expand_tabs("hello\n \tdave"), '3 space tab') + + assert_equal("hello\n dave", + expand_tabs("hello\n \tdave"), '4 space tab') + + assert_equal("hello\n dave", + expand_tabs("hello\n \tdave"), '5 space tab') + + assert_equal("hello\n dave", + expand_tabs("hello\n \tdave"), '6 space tab') + + assert_equal("hello\n dave", + expand_tabs("hello\n \tdave"), '7 space tab') + + assert_equal("hello\n dave", + expand_tabs("hello\n \tdave"), '8 space tab') + + assert_equal('. .', + expand_tabs(".\t\t."), 'dot tab tab dot') + + assert_equal('a a', + Timeout.timeout(1) {expand_tabs("\ra\ta")}, "carriage return") + end + + def test_expand_tabs_encoding + skip "Encoding not implemented" unless Object.const_defined? :Encoding + + inn = "hello\ns\tdave" + inn.force_encoding Encoding::BINARY + + out = expand_tabs inn + + assert_equal "hello\ns dave", out + assert_equal Encoding::BINARY, out.encoding + end + + def test_flush_left + text = <<-TEXT + + we don't worry too much. + + The comments associated with + TEXT + + expected = <<-EXPECTED + +we don't worry too much. + +The comments associated with + EXPECTED + + assert_equal expected, flush_left(text) + end + + def test_flush_left_encoding + skip "Encoding not implemented" unless Object.const_defined? :Encoding + + text = <<-TEXT + + we don't worry too much. + + The comments associated with + TEXT + + text.force_encoding Encoding::US_ASCII + + expected = <<-EXPECTED + +we don't worry too much. + +The comments associated with + EXPECTED + + result = flush_left text + + assert_equal expected, result + assert_equal Encoding::US_ASCII, result.encoding + end + + def test_markup_string + out = markup('hi').gsub("\n", '') + + assert_equal '<p>hi</p>', out + end + + def test_markup_comment + out = markup(comment('hi')).gsub("\n", '') + + assert_equal '<p>hi</p>', out + end + + def test_normalize_comment_hash + text = <<-TEXT +## +# we don't worry too much. +# +# The comments associated with + TEXT + + expected = <<-EXPECTED.rstrip +we don't worry too much. + +The comments associated with + EXPECTED + + assert_equal expected, normalize_comment(text) + end + + def test_normalize_comment_stars_single_space + text = <<-TEXT +/* + * we don't worry too much. + * + * The comments associated with + */ + TEXT + + expected = <<-EXPECTED.rstrip +we don't worry too much. + +The comments associated with + EXPECTED + + assert_equal expected, normalize_comment(text) + end + + def test_normalize_comment_stars_single_double_space + text = <<-TEXT +/* + * we don't worry too much. + * + * The comments associated with + */ + TEXT + + expected = <<-EXPECTED.rstrip +we don't worry too much. + +The comments associated with + EXPECTED + + assert_equal expected, normalize_comment(text) + end + + def test_parse + assert_kind_of RDoc::Markup::Document, parse('hi') + end + + def test_parse_comment + expected = RDoc::Markup::Document.new + expected.file = @top_level + + c = comment '' + parsed = parse c + + assert_equal expected, parsed + assert_same parsed, parse(c) + end + + def test_parse_document + assert_equal RDoc::Markup::Document.new, parse(RDoc::Markup::Document.new) + end + + def test_parse_empty + assert_equal RDoc::Markup::Document.new, parse('') + end + + def test_parse_empty_newline + assert_equal RDoc::Markup::Document.new, parse("#\n") + end + + def test_parse_format_markdown + expected = + @RM::Document.new( + @RM::Paragraph.new('it _works_')) + + parsed = parse 'it *works*', 'markdown' + + assert_equal expected, parsed + end + + def test_parse_format_rd + expected = + @RM::Document.new( + @RM::Paragraph.new('it <em>works</em>')) + + parsed = parse 'it ((*works*))', 'rd' + + assert_equal expected, parsed + end + + def test_parse_format_tomdoc + code = verb('1 + 1') + code.format = :ruby + + expected = + doc( + para('It does a thing'), + blank_line, + head(3, 'Examples'), + blank_line, + code) + + text = <<-TOMDOC +It does a thing + +Examples + + 1 + 1 + TOMDOC + + parsed = parse text, 'tomdoc' + + assert_equal expected, parsed + end + + def test_parse_newline + assert_equal RDoc::Markup::Document.new, parse("\n") + end + + def test_snippet + text = <<-TEXT +This is one-hundred characters or more of text in a single paragraph. This +paragraph will be cut off some point after the one-hundredth character. + TEXT + + expected = <<-EXPECTED +<p>This is one-hundred characters or more of text in a single paragraph. This +paragraph will be cut off … + EXPECTED + + assert_equal expected, snippet(text) + end + + def test_snippet_comment + c = comment 'This is a comment' + + assert_equal "<p>This is a comment\n", snippet(c) + end + + def test_snippet_short + text = 'This is a comment' + + assert_equal "<p>#{text}\n", snippet(text) + end + + def test_strip_hashes + text = <<-TEXT +## +# we don't worry too much. +# +# The comments associated with + TEXT + + expected = <<-EXPECTED + + we don't worry too much. + + The comments associated with + EXPECTED + + assert_equal expected, strip_hashes(text) + end + + def test_strip_hashes_encoding + skip "Encoding not implemented" unless Object.const_defined? :Encoding + + text = <<-TEXT +## +# we don't worry too much. +# +# The comments associated with + TEXT + + text.force_encoding Encoding::CP852 + + expected = <<-EXPECTED + + we don't worry too much. + + The comments associated with + EXPECTED + + stripped = strip_hashes text + + assert_equal expected, stripped + assert_equal Encoding::CP852, stripped.encoding + end + + def test_strip_newlines + assert_equal ' ', strip_newlines("\n \n") + + assert_equal 'hi', strip_newlines("\n\nhi") + + assert_equal 'hi', strip_newlines( "hi\n\n") + + assert_equal 'hi', strip_newlines("\n\nhi\n\n") + end + + def test_strip_newlines_encoding + skip "Encoding not implemented" unless Object.const_defined? :Encoding + + assert_equal Encoding::UTF_8, ''.encoding, 'Encoding sanity check' + + text = " \n" + text.force_encoding Encoding::US_ASCII + + stripped = strip_newlines text + + assert_equal ' ', stripped + + assert_equal Encoding::US_ASCII, stripped.encoding + end + + def test_strip_stars + text = <<-TEXT +/* + * * we don't worry too much. + * + * The comments associated with + */ + TEXT + + expected = <<-EXPECTED + + * we don't worry too much. + + The comments associated with + EXPECTED + + assert_equal expected, strip_stars(text) + end + + def test_strip_stars_document_method + text = <<-TEXT +/* + * Document-method: Zlib::GzipFile#mtime= + * + * A comment + */ + TEXT + + expected = <<-EXPECTED + + A comment + EXPECTED + + assert_equal expected, strip_stars(text) + end + + def test_strip_stars_encoding + skip "Encoding not implemented" unless Object.const_defined? :Encoding + + text = <<-TEXT +/* + * * we don't worry too much. + * + * The comments associated with + */ + TEXT + + text.force_encoding Encoding::CP852 + + expected = <<-EXPECTED + + * we don't worry too much. + + The comments associated with + EXPECTED + + result = strip_stars text + + assert_equal expected, result + assert_equal Encoding::CP852, result.encoding + end + + def test_strip_stars_encoding2 + skip "Encoding not implemented" unless Object.const_defined? :Encoding + + text = <<-TEXT +/* + * * we don't worry too much. + * + * The comments associated with + */ + TEXT + + text.force_encoding Encoding::BINARY + + expected = <<-EXPECTED + + * we don't worry too much. + + The comments associated with + EXPECTED + + result = strip_stars text + + assert_equal expected, result + assert_equal Encoding::BINARY, result.encoding + end + + def test_strip_stars_no_stars + text = <<-TEXT +* we don't worry too much. + +The comments associated with + + TEXT + + expected = <<-EXPECTED +* we don't worry too much. + +The comments associated with + + EXPECTED + + assert_equal expected, strip_stars(text) + end + + def test_to_html_apostrophe + assert_equal '‘a', to_html("'a") + assert_equal 'a’', to_html("a'") + + assert_equal '‘a’ ‘', to_html("'a' '") + end + + def test_to_html_backslash + assert_equal 'S', to_html('\\S') + end + + def test_to_html_br + assert_equal '<br>', to_html('<br>') + end + + def test_to_html_copyright + assert_equal '©', to_html('(c)') + end + + def test_to_html_dash + assert_equal '-', to_html('-') + assert_equal '–', to_html('--') + assert_equal '—', to_html('---') + assert_equal '—-', to_html('----') + end + + def test_to_html_double_backtick + assert_equal '“a', to_html('``a') + assert_equal '“a“', to_html('``a``') + end + + def test_to_html_double_quote + assert_equal '“a', to_html('"a') + assert_equal '“a”', to_html('"a"') + end + + def test_to_html_double_quote_quot + assert_equal '“a', to_html('"a') + assert_equal '“a”', to_html('"a"') + end + + def test_to_html_double_tick + assert_equal '”a', to_html("''a") + assert_equal '”a”', to_html("''a''") + end + + def test_to_html_ellipsis + assert_equal '..', to_html('..') + assert_equal '…', to_html('...') + assert_equal '.…', to_html('....') + end + + def test_to_html_encoding + skip "Encoding not implemented" unless Object.const_defined? :Encoding + + s = '...(c)'.encode Encoding::Shift_JIS + + html = to_html s + + assert_equal Encoding::Shift_JIS, html.encoding + + expected = '…(c)'.encode Encoding::Shift_JIS + + assert_equal expected, html + end + + def test_to_html_html_tag + assert_equal '<a href="http://example">hi’s</a>', + to_html('<a href="http://example">hi\'s</a>') + end + + def test_to_html_registered_trademark + assert_equal '®', to_html('(r)') + end + + def test_to_html_tt_tag + assert_equal '<tt>hi\'s</tt>', to_html('<tt>hi\'s</tt>') + assert_equal '<tt>hi\\\'s</tt>', to_html('<tt>hi\\\\\'s</tt>') + end + + def test_to_html_tt_tag_mismatch + _, err = verbose_capture_io do + assert_equal '<tt>hi', to_html('<tt>hi') + end + + assert_equal "mismatched <tt> tag\n", err + end + + def formatter + RDoc::Markup::ToHtml.new @options + end + + def options + @options + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_token_stream.rb b/jni/ruby/test/rdoc/test_rdoc_token_stream.rb new file mode 100644 index 0000000..3c1a225 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_token_stream.rb @@ -0,0 +1,42 @@ +require 'rdoc/test_case' + +class TestRDocTokenStream < RDoc::TestCase + + def test_class_to_html + tokens = [ + RDoc::RubyToken::TkCONSTANT. new(0, 0, 0, 'CONSTANT'), + RDoc::RubyToken::TkDEF. new(0, 0, 0, 'KW'), + RDoc::RubyToken::TkIVAR. new(0, 0, 0, 'IVAR'), + RDoc::RubyToken::TkOp. new(0, 0, 0, 'Op'), + RDoc::RubyToken::TkId. new(0, 0, 0, 'Id'), + RDoc::RubyToken::TkNode. new(0, 0, 0, 'Node'), + RDoc::RubyToken::TkCOMMENT. new(0, 0, 0, 'COMMENT'), + RDoc::RubyToken::TkREGEXP. new(0, 0, 0, 'REGEXP'), + RDoc::RubyToken::TkSTRING. new(0, 0, 0, 'STRING'), + RDoc::RubyToken::TkVal. new(0, 0, 0, 'Val'), + RDoc::RubyToken::TkBACKSLASH.new(0, 0, 0, '\\'), + ] + + expected = [ + '<span class="ruby-constant">CONSTANT</span>', + '<span class="ruby-keyword">KW</span>', + '<span class="ruby-ivar">IVAR</span>', + '<span class="ruby-operator">Op</span>', + '<span class="ruby-identifier">Id</span>', + '<span class="ruby-node">Node</span>', + '<span class="ruby-comment">COMMENT</span>', + '<span class="ruby-regexp">REGEXP</span>', + '<span class="ruby-string">STRING</span>', + '<span class="ruby-value">Val</span>', + '\\' + ].join + + assert_equal expected, RDoc::TokenStream.to_html(tokens) + end + + def test_class_to_html_empty + assert_equal '', RDoc::TokenStream.to_html([]) + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_tom_doc.rb b/jni/ruby/test/rdoc/test_rdoc_tom_doc.rb new file mode 100644 index 0000000..63d3a5e --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_tom_doc.rb @@ -0,0 +1,520 @@ +require 'rdoc/test_case' + +class TestRDocTomDoc < RDoc::TestCase + + def setup + super + + @top_level = @store.add_file 'file.rb' + + @TD = RDoc::TomDoc + @td = @TD.new + end + + def test_class_add_post_processor + RDoc::TomDoc.add_post_processor + + pp = RDoc::Markup::PreProcess.new __FILE__, [] + + text = "# Public: Do some stuff\n" + + comment = RDoc::Comment.new text, nil + comment.format = 'tomdoc' + + parent = RDoc::Context.new + + pp.handle comment, parent + + method = parent.add_method RDoc::AnyMethod.new(nil, 'm') + + assert_equal 'Public', method.section.title + assert_equal "# Do some stuff\n", comment.text + end + + def test_class_signature + c = comment <<-COMMENT +Signature + + method_<here>(args) + +here - something + COMMENT + c.format = 'tomdoc' + + signature = @TD.signature c + + assert_equal "method_<here>(args)\n", signature + end + + def test_class_signature_no_space + c = comment <<-COMMENT +Signature + method_<here>(args) + +here - something + COMMENT + c.format = 'tomdoc' + + signature = @TD.signature c + + assert_equal "method_<here>(args)\n", signature + + expected = + doc( + head(3, 'Signature'), + list(:NOTE, + item(%w[here], + para('something')))) + expected.file = @top_level + + assert_equal expected, c.parse + end + + def test_class_signature_none + c = comment '' + c.format = 'tomdoc' + + assert_nil @TD.signature c + end + + def test_class_rdoc + c = comment <<-COMMENT +=== Signature + + method_<here>(args) + +here - something + COMMENT + c.format = 'rdoc' + + signature = @TD.signature c + + assert_nil signature + end + + def test_class_signature_two_space + c = comment <<-COMMENT +Signature + + + method_<here>(args) + +here - something + COMMENT + c.format = 'tomdoc' + + signature = @TD.signature c + + assert_equal "method_<here>(args)\n", signature + + expected = + doc( + head(3, 'Signature'), + list(:NOTE, + item(%w[here], + para('something')))) + expected.file = @top_level + + assert_equal expected, c.parse + end + + def test_parse_paragraph + text = "Public: Do some stuff\n" + + expected = + @RM::Document.new( + @RM::Paragraph.new('Do some stuff')) + + assert_equal expected, @TD.parse(text) + end + + def test_parse_multiline_paragraph + text = "Public: Do some stuff\n" + text << "On a new line\n" + + expected = + doc( + para('Do some stuff', ' ', 'On a new line')) + + assert_equal expected, @TD.parse(text) + end + + def test_parse_arguments + text = <<-TEXT +Create new Arg object. + +name - name of argument +description - arguments description + TEXT + + expected = + doc( + para('Create new Arg object.'), + blank_line, + list(:NOTE, + item(%w[name], + para('name of argument')), + item(%w[description], + para('arguments description')))) + + assert_equal expected, @TD.parse(text) + end + + def test_parse_arguments_array + text = <<-TEXT +Create new Arg object. + +names[] - names of arguments + TEXT + + expected = + doc( + para('Create new Arg object.'), + blank_line, + list(:NOTE, + item(%w[names[]], + para('names of arguments')))) + + assert_equal expected, @TD.parse(text) + end + + def test_parse_arguments_multiline + text = <<-TEXT +Do some stuff + +foo - A comment goes here + and is more than one line + TEXT + + expected = + doc( + para('Do some stuff'), + blank_line, + list(:NOTE, + item(%w[foo], + para('A comment goes here', ' ', 'and is more than one line')))) + + assert_equal expected, @TD.parse(text) + end + + def test_parse_arguments_nested + text = <<-TEXT +Do some stuff + +foo - A comment goes here + :bar - bar documentation + TEXT + + expected = + doc( + para('Do some stuff'), + blank_line, + list(:NOTE, + item(%w[foo], + para('A comment goes here'), + list(:NOTE, + item(%w[:bar], + para('bar documentation')))))) + + assert_equal expected, @TD.parse(text) + end + + def test_parse_examples + text = <<-TEXT +Do some stuff + +Examples + + 1 + 1 + TEXT + + code = verb("1 + 1\n") + code.format = :ruby + + expected = + doc( + para('Do some stuff'), + blank_line, + head(3, 'Examples'), + blank_line, + code) + + document = @TD.parse(text) + assert_equal expected, document + assert document.parts.last.ruby? + end + + def test_parse_examples_signature + text = <<-TEXT +Do some stuff + +Examples + + 1 + 1 + +Signature + + foo(args) + TEXT + + code1 = verb("1 + 1\n") + code1.format = :ruby + + code2 = verb("foo(args)\n") + + expected = + doc( + para('Do some stuff'), + blank_line, + head(3, 'Examples'), + blank_line, + code1, + head(3, 'Signature'), + blank_line, + code2) + + document = @TD.parse text + + assert_equal expected, document + end + + def test_parse_returns + text = <<-TEXT +Do some stuff + +Returns a thing + +Returns another thing + TEXT + + expected = + doc( + para('Do some stuff'), + blank_line, + head(3, 'Returns'), + blank_line, + para('Returns a thing'), + blank_line, + para('Returns another thing')) + + assert_equal expected, @TD.parse(text) + end + + def test_parse_returns_multiline + text = <<-TEXT +Do some stuff + +Returns a thing + that is multiline + TEXT + + expected = + doc( + para('Do some stuff'), + blank_line, + head(3, 'Returns'), + blank_line, + para('Returns a thing', ' ', 'that is multiline')) + + assert_equal expected, @TD.parse(text) + end + + def test_parse_signature + text = <<-TEXT +Do some stuff + +Signature + + some_method(args) + TEXT + + expected = + @RM::Document.new( + @RM::Paragraph.new('Do some stuff'), + @RM::BlankLine.new, + @RM::Heading.new(3, 'Signature'), + @RM::BlankLine.new, + @RM::Verbatim.new("some_method(args)\n")) + + assert_equal expected, @TD.parse(text) + end + + def test_tokenize_paragraph + @td.tokenize "Public: Do some stuff\n" + + expected = [ + [:TEXT, "Do some stuff", 0, 0], + [:NEWLINE, "\n", 13, 0], + ] + + assert_equal expected, @td.tokens + end + + def test_tokenize_multiline_paragraph + text = "Public: Do some stuff\n" + text << "On a new line\n" + + @td.tokenize text + + expected = [ + [:TEXT, "Do some stuff", 0, 0], + [:NEWLINE, "\n", 13, 0], + [:TEXT, "On a new line", 0, 1], + [:NEWLINE, "\n", 13, 1] + ] + + assert_equal expected, @td.tokens + end + + def test_tokenize_arguments + @td.tokenize <<-TEXT +Create new Arg object. + +name - name of argument +description - arguments description + TEXT + + expected = [ + [:TEXT, "Create new Arg object.", 0, 0], + [:NEWLINE, "\n", 22, 0], + [:NEWLINE, "\n", 0, 1], + [:NOTE, "name", 0, 2], + [:TEXT, "name of argument", 14, 2], + [:NEWLINE, "\n", 30, 2], + [:NOTE, "description", 0, 3], + [:TEXT, "arguments description", 14, 3], + [:NEWLINE, "\n", 35, 3], + ] + + assert_equal expected, @td.tokens + end + + def test_tokenize_arguments_array + @td.tokenize <<-TEXT +Create new Arg object. + +names[stuff] - names of arguments + TEXT + + expected = [ + [:TEXT, "Create new Arg object.", 0, 0], + [:NEWLINE, "\n", 22, 0], + [:NEWLINE, "\n", 0, 1], + [:NOTE, "names[stuff]", 0, 2], + [:TEXT, "names of arguments", 15, 2], + [:NEWLINE, "\n", 33, 2], + ] + + assert_equal expected, @td.tokens + end + + def test_tokenize_arguments_multiline + @td.tokenize <<-TEXT +Do some stuff + +foo - A comment goes here + and is more than one line + TEXT + + expected = [ + [:TEXT, "Do some stuff", 0, 0], + [:NEWLINE, "\n", 13, 0], + [:NEWLINE, "\n", 0, 1], + [:NOTE, "foo", 0, 2], + [:TEXT, "A comment goes here", 6, 2], + [:NEWLINE, "\n", 25, 2], + [:TEXT, "and is more than one line", 2, 3], + [:NEWLINE, "\n", 27, 3], + ] + + assert_equal expected, @td.tokens + end + + def test_tokenize_arguments_nested + @td.tokenize <<-TEXT +Do some stuff + +foo - A comment goes here + :bar - bar documentation + TEXT + + expected = [ + [:TEXT, "Do some stuff", 0, 0], + [:NEWLINE, "\n", 13, 0], + [:NEWLINE, "\n", 0, 1], + [:NOTE, "foo", 0, 2], + [:TEXT, "A comment goes here", 6, 2], + [:NEWLINE, "\n", 25, 2], + [:NOTE, ":bar", 6, 3], + [:TEXT, "bar documentation", 13, 3], + [:NEWLINE, "\n", 30, 3], + ] + + assert_equal expected, @td.tokens + end + + def test_tokenize_examples + @td.tokenize <<-TEXT +Do some stuff + +Examples + + 1 + 1 + TEXT + + expected = [ + [:TEXT, "Do some stuff", 0, 0], + [:NEWLINE, "\n", 13, 0], + [:NEWLINE, "\n", 0, 1], + [:HEADER, 3, 0, 2], + [:TEXT, "Examples", 0, 2], + [:NEWLINE, "\n", 8, 2], + [:NEWLINE, "\n", 0, 3], + [:TEXT, "1 + 1", 2, 4], + [:NEWLINE, "\n", 7, 4], + ] + + assert_equal expected, @td.tokens + end + + def test_tokenize_returns + @td.tokenize <<-TEXT +Do some stuff + +Returns a thing + TEXT + + expected = [ + [:TEXT, "Do some stuff", 0, 0], + [:NEWLINE, "\n", 13, 0], + [:NEWLINE, "\n", 0, 1], + [:TEXT, "Returns a thing", 0, 2], + [:NEWLINE, "\n", 15, 2], + ] + + assert_equal expected, @td.tokens + end + + def test_tokenize_returns_multiline + @td.tokenize <<-TEXT +Do some stuff + +Returns a thing + that is multiline + TEXT + + expected = [ + [:TEXT, "Do some stuff", 0, 0], + [:NEWLINE, "\n", 13, 0], + [:NEWLINE, "\n", 0, 1], + [:TEXT, "Returns a thing", 0, 2], + [:NEWLINE, "\n", 15, 2], + [:TEXT, "that is multiline", 2, 3], + [:NEWLINE, "\n", 19, 3], + ] + + assert_equal expected, @td.tokens + end + +end + diff --git a/jni/ruby/test/rdoc/test_rdoc_top_level.rb b/jni/ruby/test/rdoc/test_rdoc_top_level.rb new file mode 100644 index 0000000..f3ee6a4 --- /dev/null +++ b/jni/ruby/test/rdoc/test_rdoc_top_level.rb @@ -0,0 +1,287 @@ +require File.expand_path '../xref_test_case', __FILE__ + +class TestRDocTopLevel < XrefTestCase + + def setup + super + + @top_level = @store.add_file 'path/top_level.rb' + @top_level.parser = RDoc::Parser::Ruby + end + + def test_initialize + t = RDoc::TopLevel.new 'path/file.rb' + + assert_equal 'path/file.rb', t.absolute_name + assert_equal 'path/file.rb', t.relative_name + end + + def test_initialize_relative + t = RDoc::TopLevel.new 'path/file.rb', 'file.rb' + + assert_equal 'path/file.rb', t.absolute_name + assert_equal 'file.rb', t.relative_name + end + + def test_add_alias + a = RDoc::Alias.new nil, 'old', 'new', nil + @top_level.add_alias a + + object = @store.find_class_named 'Object' + expected = { '#old' => [a] } + assert_equal expected, object.unmatched_alias_lists + assert_includes object.in_files, @top_level + end + + def test_add_alias_nodoc + @top_level.document_self = false + + a = RDoc::Alias.new nil, 'old', 'new', nil + @top_level.add_alias a + + object = @store.find_class_named('Object') + assert_empty object.unmatched_alias_lists + assert_includes object.in_files, @top_level + end + + def test_add_constant + const = RDoc::Constant.new 'C', nil, nil + @top_level.add_constant const + + object = @store.find_class_named 'Object' + assert_equal [const], object.constants + assert_includes object.in_files, @top_level + end + + def test_add_constant_nodoc + @top_level.document_self = false + + const = RDoc::Constant.new 'C', nil, nil + @top_level.add_constant const + + object = @store.find_class_named 'Object' + assert_empty object.constants + assert_includes object.in_files, @top_level + end + + def test_add_include + include = RDoc::Include.new 'C', nil + @top_level.add_include include + + object = @store.find_class_named 'Object' + assert_equal [include], object.includes + assert_includes object.in_files, @top_level + end + + def test_add_include_nodoc + @top_level.document_self = false + + include = RDoc::Include.new 'C', nil + @top_level.add_include include + + object = @store.find_class_named('Object') + assert_empty object.includes + assert_includes object.in_files, @top_level + end + + def test_add_method + method = RDoc::AnyMethod.new nil, 'm' + @top_level.add_method method + + object = @store.find_class_named 'Object' + assert_equal [method], object.method_list + assert_includes object.in_files, @top_level + end + + def test_add_method_stopdoc + @top_level.document_self = false + + method = RDoc::AnyMethod.new nil, 'm' + @top_level.add_method method + + object = @store.find_class_named('Object') + assert_empty object.method_list + assert_includes object.in_files, @top_level + end + + def test_base_name + assert_equal 'top_level.rb', @top_level.base_name + end + + def test_display_eh + refute @top_level.display? + + page = @store.add_file 'README.txt' + page.parser = RDoc::Parser::Simple + + assert page.display? + end + + def test_eql_eh + top_level2 = @store.add_file 'path/top_level.rb' + other_level = @store.add_file 'path/other_level.rb' + + assert_operator @top_level, :eql?, top_level2 + + refute_operator other_level, :eql?, @top_level + end + + def test_equals2 + top_level2 = @store.add_file 'path/top_level.rb' + other_level = @store.add_file 'path/other_level.rb' + + assert_equal @top_level, top_level2 + + refute_equal other_level, @top_level + end + + def test_find_class_or_module + assert_equal @c1, @xref_data.find_class_or_module('C1') + assert_equal @c2_c3, @xref_data.find_class_or_module('C2::C3') + assert_equal @c4, @xref_data.find_class_or_module('C4') + assert_equal @m1_m2, @xref_data.find_class_or_module('M1::M2') + end + + def test_full_name + assert_equal 'path/top_level.rb', @top_level.full_name + end + + def test_hash + tl2 = @store.add_file 'path/top_level.rb' + tl3 = @store.add_file 'other/top_level.rb' + + assert_equal @top_level.hash, tl2.hash + refute_equal @top_level.hash, tl3.hash + end + + def test_http_url + assert_equal 'prefix/path/top_level_rb.html', @top_level.http_url('prefix') + end + + def test_last_modified + assert_equal nil, @top_level.last_modified + stat = Object.new + def stat.mtime() 0 end + @top_level.file_stat = stat + assert_equal 0, @top_level.last_modified + end + + def test_marshal_dump + page = @store.add_file 'README.txt' + page.parser = RDoc::Parser::Simple + page.comment = RDoc::Comment.new 'This is a page', page + + loaded = Marshal.load Marshal.dump page + + comment = RDoc::Markup::Document.new( + RDoc::Markup::Paragraph.new('This is a page')) + comment.file = loaded + + assert_equal page, loaded + + assert_equal 'README.txt', loaded.absolute_name + assert_equal 'README.txt', loaded.relative_name + + assert_equal RDoc::Parser::Simple, loaded.parser + + assert_equal comment, loaded.comment + end + + def test_marshal_load_version_0 + loaded = Marshal.load "\x04\bU:\x13RDoc::TopLevel" + + "[\ti\x00I\"\x0FREADME.txt\x06:\x06EF" + + "c\x19RDoc::Parser::Simple" + + "o:\eRDoc::Markup::Document\a:\v@parts" + + "[\x06o:\x1CRDoc::Markup::Paragraph\x06;\b" + + "[\x06I\"\x13This is a page\x06;\x06F:\n@file@\a" + + comment = RDoc::Markup::Document.new( + RDoc::Markup::Paragraph.new('This is a page')) + comment.file = loaded + + assert_equal 'README.txt', loaded.absolute_name + assert_equal 'README.txt', loaded.relative_name + + assert_equal RDoc::Parser::Simple, loaded.parser + + assert_equal comment, loaded.comment + + assert loaded.display? + end + + def test_name + assert_equal 'top_level.rb', @top_level.name + end + + def test_page_name + assert_equal 'top_level', @top_level.page_name + + tl = @store.add_file 'README.ja' + + assert_equal 'README.ja', tl.page_name + + tl = @store.add_file 'Rakefile' + + assert_equal 'Rakefile', tl.page_name + end + + def test_page_name_trim_extension + tl = @store.add_file 'README.ja.rdoc' + + assert_equal 'README.ja', tl.page_name + + tl = @store.add_file 'README.ja.md' + + assert_equal 'README.ja', tl.page_name + + tl = @store.add_file 'README.txt' + + assert_equal 'README', tl.page_name + end + + def test_search_record + assert_nil @xref_data.search_record + end + + def test_search_record_page + page = @store.add_file 'README.txt' + page.parser = RDoc::Parser::Simple + page.comment = 'This is a comment.' + + expected = [ + 'README', + '', + 'README', + '', + 'README_txt.html', + '', + "<p>This is a comment.\n", + ] + + assert_equal expected, page.search_record + end + + def test_text_eh + refute @xref_data.text? + + rd = @store.add_file 'rd_format.rd' + rd.parser = RDoc::Parser::RD + + assert rd.text? + + simple = @store.add_file 'simple.txt' + simple.parser = RDoc::Parser::Simple + + assert simple.text? + end + + def test_text_eh_no_parser + refute @xref_data.text? + + rd = @store.add_file 'rd_format.rd' + + refute rd.text? + end + +end + diff --git a/jni/ruby/test/rdoc/xref_data.rb b/jni/ruby/test/rdoc/xref_data.rb new file mode 100644 index 0000000..4525a29 --- /dev/null +++ b/jni/ruby/test/rdoc/xref_data.rb @@ -0,0 +1,76 @@ +XREF_DATA = <<-XREF_DATA +class C1 + + attr :attr + + # :section: separate + + attr_reader :attr_reader + attr_writer :attr_writer + + # :section: + attr_accessor :attr_accessor + + CONST = :const + + def self.m + end + + def m foo + end + +end + +class C2 + def b + end + + alias a b + + class C3 + def m + end + + class H1 + def m? + end + end + end +end + +class C3 + class H1 + end + + class H2 < H1 + end +end + +class C4 + class C4 + end +end + +class C5 + class C1 + end +end + +module M1 + def m + end +end + +module M1::M2 +end + +class Parent + def m() end + def self.m() end +end + +class Child < Parent +end + +XREF_DATA + diff --git a/jni/ruby/test/rdoc/xref_test_case.rb b/jni/ruby/test/rdoc/xref_test_case.rb new file mode 100644 index 0000000..a56fa71 --- /dev/null +++ b/jni/ruby/test/rdoc/xref_test_case.rb @@ -0,0 +1,67 @@ +ENV['RDOC_TEST'] = 'yes' + +require 'rdoc' +require File.expand_path '../xref_data', __FILE__ + +class XrefTestCase < RDoc::TestCase + + def setup + super + + @options = RDoc::Options.new + @options.quiet = true + + @rdoc.options = @options + + @file_name = 'xref_data.rb' + @xref_data = @store.add_file @file_name + @top_level = @xref_data + + stats = RDoc::Stats.new @store, 0 + + parser = RDoc::Parser::Ruby.new @xref_data, @file_name, XREF_DATA, @options, + stats + @top_levels = [] + @top_levels.push parser.scan + + generator = Object.new + def generator.class_dir() nil end + def generator.file_dir() nil end + @rdoc.options = @options + @rdoc.generator = generator + + @c1 = @xref_data.find_module_named 'C1' + @c1_m = @c1.method_list.last # C1#m + @c1__m = @c1.method_list.first # C1::m + + @c2 = @xref_data.find_module_named 'C2' + @c2_a = @c2.method_list.last + @c2_b = @c2.method_list.first + + @c2_c3 = @xref_data.find_module_named 'C2::C3' + @c2_c3_m = @c2_c3.method_list.first # C2::C3#m + + @c2_c3_h1 = @xref_data.find_module_named 'C2::C3::H1' + @c2_c3_h1_meh = @c2_c3_h1.method_list.first # C2::C3::H1#m? + + @c3 = @xref_data.find_module_named 'C3' + @c4 = @xref_data.find_module_named 'C4' + @c4_c4 = @xref_data.find_module_named 'C4::C4' + @c5_c1 = @xref_data.find_module_named 'C5::C1' + @c3_h1 = @xref_data.find_module_named 'C3::H1' + @c3_h2 = @xref_data.find_module_named 'C3::H2' + + @m1 = @xref_data.find_module_named 'M1' + @m1_m = @m1.method_list.first + + @m1_m2 = @xref_data.find_module_named 'M1::M2' + + @parent = @xref_data.find_module_named 'Parent' + @child = @xref_data.find_module_named 'Child' + + @parent_m = @parent.method_list.first # Parent#m + @parent__m = @parent.method_list.last # Parent::m + end + +end + |