diff --git a/lib/rdoc/cross_reference.rb b/lib/rdoc/cross_reference.rb index 3dcf9b0ea7..a5e4fc879f 100644 --- a/lib/rdoc/cross_reference.rb +++ b/lib/rdoc/cross_reference.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require_relative 'markup/attribute_manager' # for PROTECT_ATTR - ## # RDoc::CrossReference is a reusable way to create cross references for names. @@ -33,7 +31,7 @@ class RDoc::CrossReference # See CLASS_REGEXP_STR METHOD_REGEXP_STR = /( - (?!\d)[\w#{RDoc::Markup::AttributeManager::PROTECT_ATTR}]+[!?=]?| + (?!\d)[\w]+[!?=]?| %|=(?:==?|~)|![=~]|\[\]=?|<(?:<|=>?)?|>[>=]?|[-+!]@?|\*\*?|[\/%\`|&^~] )#{METHOD_ARGS_REGEXP_STR}/.source.delete("\n ").freeze diff --git a/lib/rdoc/generator/template/aliki/_head.rhtml b/lib/rdoc/generator/template/aliki/_head.rhtml index 1733bd0174..c46f0b94e7 100644 --- a/lib/rdoc/generator/template/aliki/_head.rhtml +++ b/lib/rdoc/generator/template/aliki/_head.rhtml @@ -140,6 +140,11 @@ defer > + + "') + assert_includes result, '<script>' + assert_includes result, '</script>' + + result = highlight('echo "a && b"') + assert_includes result, '&&' + end + + private + + def highlight(code) + @context.eval("highlightShell(#{code.to_json})") + end +end diff --git a/test/rdoc/markup/attribute_manager_test.rb b/test/rdoc/markup/attribute_manager_test.rb deleted file mode 100644 index 903966b8e2..0000000000 --- a/test/rdoc/markup/attribute_manager_test.rb +++ /dev/null @@ -1,474 +0,0 @@ -# frozen_string_literal: true -require_relative '../helper' - -class RDocMarkupAttributeManagerTest < 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], []) - - @strike_on = @am.changed_attribute_by_name([], [:STRIKE]) - @strike_off = @am.changed_attribute_by_name([:STRIKE], []) - - @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, '', '' - @formatter.add_tag :EM, '', '' - @formatter.add_tag :TT, '', '' - end - - def crossref(text) - crossref_bitmap = @am.attributes.bitmap_for(:_REGEXP_HANDLING_) | - @am.attributes.bitmap_for(:CROSSREF) - - [ @am.changed_attribute_by_name([], [:CROSSREF, :_REGEXP_HANDLING_]), - RDoc::Markup::RegexpHandling.new(crossref_bitmap, text), - @am.changed_attribute_by_name([:CROSSREF, :_REGEXP_HANDLING_], []) - ] - 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(8, tags.size) - assert(tags.has_key?("test")) - end - - def test_add_regexp_handling - @am.add_regexp_handling "WikiWord", :WIKIWORD - regexp_handlings = @am.regexp_handlings - - assert_equal 1, regexp_handlings.size - assert regexp_handlings.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_raise 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_raise 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")) - - assert_equal([@tt_on, "__id__", @tt_off], @am.flow("+__id__+")) - 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 dog'], @am.flow('cat \dog') - end - - def test_strike_html_escaped - assert_equal ['cat dog'], @am.flow('cat \dog') - assert_equal ['cat dog'], @am.flow('cat \dog') - end - - def test_html_like_strike - assert_equal ["cat ", @strike_on, "dog", @strike_off], - @am.flow("cat dog") - end - - def test_html_like_strike_del - assert_equal ["cat ", @strike_on, "dog", @strike_off], - @am.flow("cat dog") - 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+'.dup - attrs = RDoc::Markup::AttrSpan.new str.length, @am.exclusive_bitmap - - @am.convert_attrs str, attrs, true - @am.convert_attrs str, attrs - - assert_equal "\000foo\000", str - - str = '+:foo:+'.dup - attrs = RDoc::Markup::AttrSpan.new str.length, @am.exclusive_bitmap - - @am.convert_attrs str, attrs, true - @am.convert_attrs str, attrs - - assert_equal "\000:foo:\000", str - - str = '+x-y+'.dup - attrs = RDoc::Markup::AttrSpan.new str.length, @am.exclusive_bitmap - - @am.convert_attrs str, attrs, true - @am.convert_attrs str, attrs - - assert_equal "\000x-y\000", str - end - - def test_convert_attrs_ignores_code - assert_equal 'foo __send__ bar', output('foo __send__ bar') - end - - def test_convert_attrs_ignores_bold_inside_code - assert_equal 'foo *bold* bar', output('foo *bold* bar') - end - - def test_convert_attrs_ignores_em_inside_code - assert_equal 'foo _em_ bar', output('foo _em_ bar') - end - - def test_convert_attrs_ignores_tt_inside_code - assert_equal 'foo +tt+ bar', output('foo +tt+ bar') - end - - def test_convert_attrs_ignores_bold_inside_tt - assert_equal 'foo *bold* bar', output('foo *bold* bar') - end - - def test_convert_attrs_ignores_em_inside_tt - assert_equal 'foo _em_ bar', output('foo _em_ bar') - end - - def test_convert_attrs_ignores_tt_inside_tt - assert_equal 'foo +tt+ bar', output('foo +tt+ bar') - end - - def test_backtick_basic - 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")) - end - - def test_backtick_output - assert_equal 'cat and dog', output('cat `and` dog') - assert_equal 'cat X::Y dog', output('cat `X::Y` dog') - end - - def test_convert_attrs_ignores_backtick_inside_code - assert_equal 'foo `text` bar', output('foo `text` bar') - end - - def test_convert_attrs_ignores_backtick_inside_tt - assert_equal 'foo `text` bar', output('foo `text` bar') - end - - def test_backtick_escaped - assert_equal ['`text`'], @am.flow('\`text`') - end - - def test_convert_attrs_ignores_del_inside_code - assert_equal 'foo strike bar', output('foo strike bar') - end - - def test_convert_attrs_ignores_del_inside_tt - assert_equal 'foo strike bar', output('foo strike bar') - end - - def test_convert_attrs_ignores_s_inside_code - assert_equal 'foo strike bar', output('foo strike bar') - end - - def test_convert_attrs_ignores_tt - assert_equal 'foo __send__ bar', output('foo __send__ 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 IF:key directive', output('the IF:_key_ directive') - end - - def test_escapes - assert_equal 'text', output('text') - assert_equal 'text', output('\\text') - assert_equal '', output('\\') - assert_equal '', output('\\') - assert_equal '\\', output('\\\\') - assert_equal 'text', 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 \\s matches space', - output('and \\s matches space') - assert_equal 'use text for code', - output('use \\text for code') - assert_equal 'use text for code', - output('use \\text\\ for code') - assert_equal 'use text for code', - output('use \\\\text for code') - assert_equal 'use text for code', - output('use \\text for code') - assert_equal 'use +text+ for code', - output('use \\+text+ for code') - assert_equal 'use text for code', - output('use \\+text+ for code') - assert_equal 'illegal not changed', - output('illegal not changed') - assert_equal 'unhandled

tag

unchanged', - output('unhandled

tag

unchanged') - end - - def test_exclude_tag - assert_equal 'aaa[:symbol]', output('+aaa+[:symbol]') - assert_equal 'aaa[:symbol]', output('+aaa[:symbol]+') - assert_equal 'aaa[:symbol]', output('aaa[:symbol]') - assert_equal 'index', output('index') - end - - def test_exclude_tag_flow - assert_equal [@tt_on, "aaa", @tt_off, "[:symbol]"], - @am.flow("+aaa+[:symbol]") - assert_equal [@tt_on, "aaa[:symbol]", @tt_off], - @am.flow("+aaa[:symbol]+") - assert_equal ["aaa[:symbol]"], - @am.flow("aaa[:symbol]") - end - - def test_html_like_em_bold - assert_equal ["cat ", @em_on, "and ", @em_to_bold, "dog", @bold_off], - @am.flow("cat and dog") - end - - def test_html_like_em_bold_SGML - assert_equal ["cat ", @em_on, "and ", @em_to_bold, "dog", @bold_off], - @am.flow("cat and dog") - end - - def test_html_like_em_bold_nested_1 - assert_equal(["cat ", @bold_em_on, "and", @bold_em_off, " dog"], - @am.flow("cat and 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 and dog") - 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 and dog") - 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 and dog") - end - - def test_html_like_teletype - assert_equal ["cat ", @tt_on, "dog", @tt_off], - @am.flow("cat dog") - 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("cat and dog") - end - - def test_initial_html - html_tags = @am.html_tags - assert html_tags.is_a?(Hash) - assert_equal(7, html_tags.size) - end - - def test_initial_word_pairs - word_pairs = @am.matching_word_pairs - assert word_pairs.is_a?(Hash) - assert_equal(4, word_pairs.size) - end - - def test_mask_protected_sequence - def @am.str() @str end - def @am.str=(str) @str = str end - - @am.str = 'foo'.dup - @am.mask_protected_sequences - - assert_equal "foo", @am.str - - @am.str = 'foo\\'.dup - @am.mask_protected_sequences - - assert_equal "foo<\x04/code>", @am.str, 'escaped close' - - @am.str = 'foo\\\\'.dup - @am.mask_protected_sequences - - assert_equal "foo\\", @am.str, 'escaped backslash' - end - - def test_protect - assert_equal(['cat \\ dog'], - @am.flow('cat \\ dog')) - - assert_equal(["cat dog"], - @am.flow("cat \\dog")) - - assert_equal(["cat ", @em_on, "and", @em_off, " dog"], - @am.flow("cat and \\dog")) - - assert_equal(["*word* or text"], - @am.flow("\\*word* or \\text")) - - assert_equal(["_cat_", @em_on, "dog", @em_off], - @am.flow("\\_cat_dog")) - end - - def test_lost_tag_for_the_second_time - str = "cat dog" - assert_equal(["cat ", @tt_on, "dog", @tt_off], - @am.flow(str)) - assert_equal(["cat ", @tt_on, "dog", @tt_off], - @am.flow(str)) - end - - def test_regexp_handling - @am.add_regexp_handling(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")) - - assert_equal(["(", crossref("#fred"), ")"].flatten, @am.flow("(#fred)")) - end - - def test_tt_html - assert_equal [@tt_on, '"\n"', @tt_off], - @am.flow('"\n"') - end - - def output(str) - @formatter.convert_flow @am.flow str - end - -end diff --git a/test/rdoc/markup/attributes_test.rb b/test/rdoc/markup/attributes_test.rb deleted file mode 100644 index b46b7a0bf9..0000000000 --- a/test/rdoc/markup/attributes_test.rb +++ /dev/null @@ -1,39 +0,0 @@ -# frozen_string_literal: true -require_relative '../helper' - -class RDocMarkupAttributesTest < 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 '_REGEXP_HANDLING_', @as.as_string(1) - assert_equal 'two', @as.as_string(2) - assert_equal '_REGEXP_HANDLING_,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/test/rdoc/markup/formatter_test.rb b/test/rdoc/markup/formatter_test.rb index e17fa7725d..2ff7323622 100644 --- a/test/rdoc/markup/formatter_test.rb +++ b/test/rdoc/markup/formatter_test.rb @@ -7,20 +7,38 @@ class ToTest < RDoc::Markup::Formatter def initialize(markup) super nil, markup - - add_tag :TT, '', '' end def accept_paragraph(paragraph) @res += attributes(paragraph.text) end + def handle_PLAIN_TEXT(text) + @res << text + end + + def handle_REGEXP_HANDLING_TEXT(text) + @res << text + end + + def handle_TT(text) + @res << "#{text}" + end + + def handle_TIDYLINK(label_part, url) + @res << '{' + super + @res << '}[' + url + ']' + end + def attributes(text) - convert_flow @am.flow text.dup + @res = +"" + handle_inline(text) + @res end - def handle_regexp_CAPS(target) - "handled #{target.text}" + def handle_regexp_CAPS(text) + "handled #{text}" end def start_accepting @@ -39,14 +57,7 @@ def setup @markup = @RM.new @markup.add_regexp_handling(/[A-Z]+/, :CAPS) - @attribute_manager = @markup.attribute_manager - @attributes = @attribute_manager.attributes - @to = ToTest.new @markup - - @caps = @attributes.bitmap_for :CAPS - @regexp_handling = @attributes.bitmap_for :_REGEXP_HANDLING_ - @tt = @attributes.bitmap_for :TT end def test_class_gen_relative_url @@ -63,9 +74,7 @@ def gen(from, to) end def regexp_handling_names - @attribute_manager.regexp_handlings.map do |_, mask| - @attributes.as_string mask - end + @to.instance_variable_get(:@markup).regexp_handlings.map(&:last).map(&:to_s) end def test_add_regexp_handling_RDOCLINK @@ -73,43 +82,15 @@ def test_add_regexp_handling_RDOCLINK assert_includes regexp_handling_names, 'RDOCLINK' - def @to.handle_regexp_RDOCLINK(target) - "<#{target.text}>" - end - - document = doc(para('{foo}[rdoc-label:bar].')) - - formatted = document.accept @to - - assert_equal '{foo}[].', formatted - end - - def test_add_regexp_handling_TIDYLINK - @to.add_regexp_handling_TIDYLINK - - assert_includes regexp_handling_names, 'TIDYLINK' - - def @to.handle_regexp_TIDYLINK(target) - "<#{target.text}>" + def @to.handle_regexp_RDOCLINK(text) + "<#{text}>" end - document = doc(para('foo[rdoc-label:bar].')) - - formatted = document.accept @to - - assert_equal '.', formatted - - document = doc(para('{foo}[rdoc-label:bar].')) - - formatted = document.accept @to - - assert_equal '<{foo}[rdoc-label:bar]>.', formatted - - document = doc(para('{abc}: {foo}[rdoc-label:bar].')) + document = doc(para('{foo rdoc-label:bar baz}[url]')) formatted = document.accept @to - assert_equal '{abc}: <{foo}[rdoc-label:bar]>.', formatted + assert_equal '{foo baz}[url]', formatted end def test_parse_url diff --git a/test/rdoc/markup/inline_parser_test.rb b/test/rdoc/markup/inline_parser_test.rb new file mode 100644 index 0000000000..60f03bedd7 --- /dev/null +++ b/test/rdoc/markup/inline_parser_test.rb @@ -0,0 +1,269 @@ +# frozen_string_literal: true + +require_relative '../helper' +require 'rdoc/markup/inline_parser' + +class RDocMarkupInlineParserTest < RDoc::TestCase + def parse(text) + RDoc::Markup::InlineParser.new(text).parse + end + + def em_node(*children) + { type: :EM, children: children } + end + + def bold_node(*children) + { type: :BOLD, children: children } + end + + def bold_word(text) + { type: :BOLD_WORD, children: [text] } + end + + def em_word(text) + { type: :EM_WORD, children: [text] } + end + + def strike_node(*children) + { type: :STRIKE, children: children } + end + + def tt_node(*children) + { type: :TT, children: children } + end + + def tidylink_node(children, url) + { type: :TIDYLINK, children: children, url: url } + end + + def hard_break_node + { type: :HARD_BREAK, children: [] } + end + + def test_escape + # Escaping backslash are removed, other backslashes (suppressed crossref) remains + assert_equal(['\\', bold_node('\\Array'), bold_node('\\#to_s'), bold_node('\\::new')], parse('\\\\\\Array\\#to_s\\::new')) + assert_equal(['_a_ +a+ b \\n \\ABC'], parse('\\_a_ \\+a+ \\b\\ \\n \\ABC')) + assert_equal([bold_node('')], parse('\\')) + assert_equal([em_node('')], parse('\\')) + assert_equal(['a\\'], parse('a\\')) + assert_equal([tidylink_node([''], 'url')], parse('{\\\\}[url]')) + # Unescape \\ and \< in code blocks + assert_equal([tt_node('p(%(\\)+"\\a\\n")')], parse('p(%(\\\\\\\\)+"\\a\\n")')) + end + + def test_bold + assert_equal([bold_node()], parse('')) + assert_equal(['*a b*'], parse('*a b*')) + assert_equal(['x*a* *b*x'], parse('x*a* *b*x')) + assert_equal([bold_word('bold')], parse('*bold*')) + assert_equal([bold_word('bold')], parse('**bold**')) + assert_equal([bold_node('bo ld')], parse('bo ld')) + assert_equal( + ['a ', bold_word('A'), ' b ', bold_word('B'), ' c ', bold_node('C C'), ' d'], + parse('a *A* b **B** c C C d') + ) + assert_equal([bold_node('a', em_node('b'), bold_node('c'), 'd')], parse('abcd')) + end + + def test_em + assert_equal([em_node()], parse('')) + assert_equal(['_a b_'], parse('_a b_')) + assert_equal(['x_a_ _b_x'], parse('x_a_ _b_x')) + assert_equal([em_word('em')], parse('_em_')) + assert_equal([em_word('F1LE')], parse('__F1LE__')) + assert_equal(['_foo_bar_baz'], parse('_foo_bar_baz')) + + # _ inside _em_ + assert_equal([em_word('foo_bar')], parse('_foo_bar_')) + + # non-alphanumeric after _ + assert_equal([em_word('host'), ':', em_word('port')], parse('_host_:_port_')) + + # Special exception + assert_equal(['__send__'], parse('__send__')) + assert_equal(['__FILE__'], parse('__FILE__')) + + assert_equal([em_node('e m')], parse('e m')) + assert_equal([em_node('e m')], parse('e m')) + assert_equal([em_node('a', bold_node('b'), em_node('c'), 'd')], parse('abcd')) + end + + def test_method_like_words + assert_equal([bold_word('::Foo.bar-baz')], parse('*::Foo.bar-baz*')) + assert_equal([bold_word('#foo_bar=')], parse('*#foo_bar=*')) + assert_equal([bold_word('#foo_bar!')], parse('*#foo_bar!*')) + assert_equal([bold_word('#foo_bar?')], parse('*#foo_bar?*')) + + assert_equal([em_word('::Foo.bar-baz')], parse('_::Foo.bar-baz_')) + assert_equal([em_word('#foo_bar=')], parse('_#foo_bar=_')) + assert_equal([em_word('#foo_bar!')], parse('_#foo_bar!_')) + assert_equal([em_word('#foo_bar?')], parse('_#foo_bar?_')) + + assert_equal([em_word('::Foo.bar-baz')], parse('__::Foo.bar-baz__')) + assert_equal([em_word('#foo_bar=')], parse('__#foo_bar=__')) + assert_equal([em_word('#foo_bar!')], parse('__#foo_bar!__')) + assert_equal([em_word('#foo_bar?')], parse('__#foo_bar?__')) + + assert_equal([tt_node('::Foo.bar-baz')], parse('+::Foo.bar-baz+')) + assert_equal([tt_node('#foo_bar=')], parse('+#foo_bar=+')) + assert_equal([tt_node('#foo_bar!')], parse('+#foo_bar!+')) + assert_equal([tt_node('#foo_bar?')], parse('+#foo_bar?+')) + end + + def test_tt + assert_equal([tt_node()], parse('')) + assert_equal(['`a b`'], parse('`a b`')) + assert_equal(['x`a` `b`x'], parse('x`a` `b`x')) + assert_equal([tt_node('code')], parse('`code`')) + assert_equal([tt_node('code')], parse('+code+')) + assert_equal([tt_node('code')], parse('++code++')) + assert_equal([tt_node('code')], parse('``code``')) + assert_equal([tt_node('code(1 + 2)')], parse('code(1 + 2)')) + assert_equal([tt_node('code(1 + 2)')], parse('code(1 + 2)')) + + # Detect closing tag with escaping + assert_equal([tt_node('a
b\\')], parse('a\\b\\\\')) + assert_equal([tt_node('ab\\')], parse('a\\b\\\\')) + + # Close with nearest non-escaped closing tag + assert_equal([tt_node('a
b'), 'c
d
'], parse('a\\b
c
d')) + assert_equal([tt_node('ab'), 'cd'], parse('a\\bcd')) + end + + def test_strike + assert_equal([strike_node()], parse('')) + assert_equal([strike_node('strike ')], parse('strike ')) + assert_equal([strike_node('strike ')], parse('strike ')) + assert_equal([strike_node('a', bold_node('b'), strike_node('c'), 'd')], parse('abcd')) + end + + def test_hard_break + assert_equal([hard_break_node], parse('
')) + assert_equal(['a', hard_break_node, 'b'], parse('a
b')) + assert_equal([hard_break_node, hard_break_node], parse('

')) + assert_equal([em_node('a', hard_break_node, 'b'), hard_break_node, 'c'], parse('a
b

c')) + end + + def test_simplified_tidylink + # Empty url is not allowed + assert_equal(['label[]'], parse('label[]')) + assert_equal([tidylink_node(['label'], 'url')], parse('label[url]')) + assert_equal([tidylink_node(['label'], 'http://example.com/?q=+1+')], parse('label[http://example.com/?q=+1+]')) + end + + def test_tidylink + # Empty label is allowed, empty url is not allowed + assert_equal([tidylink_node([], 'url')], parse('{}[url]')) + assert_equal(['{label}[]'], parse('{label}[]')) + + assert_equal( + [tidylink_node(['label'], 'http://example.com/')], + parse('{label}[http://example.com/]') + ) + assert_equal( + [tidylink_node(['label'], 'brac[ke]]t\\'), '_esc[]aped'], + parse('{label}[brac\[ke\]\]t\\\\]_esc\[\]aped') + ) + assert_equal( + ['See ', tidylink_node(['this link'], 'http://example.com/'), ' for more info.'], + parse('See {this link}[http://example.com/] for more info.') + ) + assert_equal( + [tidylink_node(['Label with ', bold_word('bold'), ' text'], 'http://example.com/')], + parse('{Label with *bold* text}[http://example.com/]') + ) + assert_equal( + [bold_node('bold', tidylink_node(['link'], 'http://example.com/'))], + parse('bold{link}[http://example.com/]') + ) + assert_equal( + [tidylink_node(['link'], 'http://example.com/?q=+1+')], + parse('{link}[http://example.com/?q=+1+]') + ) + assert_equal( + [tidylink_node([tt_node('}[]{')], 'url')], + parse('{}[]{}[url]') + ) + # Non-tidylink braces and brackets inside tidylink label are allowed + assert_equal( + [tidylink_node(['[a]{b}{c}d'], 'url')], + parse('{[a]{b}{c}d}[url]') + ) + end + + def test_invalid_nested_tidylink + # Simplified tidylink invalidates open tidylinks + assert_equal( + [bold_node('{a ', tidylink_node(['b'], 'url'), '}[', bold_word('c'), ']')], + parse('{a b[url]}[*c*]') + ) + # Normal tidylink invalidates open tidylinks + assert_equal( + [bold_node('{a ', tidylink_node(['b'], 'url'), '}[', bold_word('c'), ']')], + parse('{a {b}[url]}[*c*]') + ) + # Tidylink invalidates all open tidylinks + assert_equal( + [bold_node('{label', em_node('{label{label', tidylink_node(['label'], 'url'), '}[a]}[b]'), '}[c]')], + parse('{label{label{label{label}[url]}[a]}[b]}[c]') + ) + # Valid tidylink inside invalidated tidylink + assert_equal( + [bold_node('{', tidylink_node(['label1'], 'url1'), ' ', tidylink_node(['label2'], 'url2'), '}[', bold_word('b'), ']')], + parse('{{label1}[url1] {label2}[url2]}[*b*]') + ) + # Invalidated tidylink accepts tag break through brackets + assert_equal( + ['{', tidylink_node(['label'], 'url'), '}[', bold_node(']')], + parse('{{label}[url]}[]') + ) + end + + def test_unclosed_error_case + # Treat as normal text + assert_equal(['*unclosed bold'], parse('*unclosed bold')) + assert_equal(['_unclosed em'], parse('_unclosed em')) + assert_equal(['`unclosed tt'], parse('`unclosed tt')) + assert_equal(['unclosed tag'], parse('unclosed tag')) + assert_equal(['unclosed code'], parse('unclosed code')) + assert_equal(['{unclosed tidylink'], parse('{unclosed tidylink')) + assert_equal(['{label}[url'], parse('{label}[url')) + assert_equal(['label[url'], parse('label[url')) + end + + def test_unknown_tag_as_normal_text + # Even if opening and closing tags are present, treat as normal text + assert_equal(['', strike_node('')], parse('')) + end + + def test_invalid_closing_error_case + # No opening tag, then treat it as normal text + assert_equal([bold_node('')], parse('')) + + # (strike closing) shouldn't close (also strike) + assert_equal([bold_node(strike_node(''))], parse('')) + + # Closing tag will close the last opened tag. Tag that has no corresponding open/close pair remains as normal text + assert_equal([em_node(''), ''], parse('')) + + # Tag that has corresponding open/close pair will be parsed normally + assert_equal([em_node('a', bold_node('b'), 'cd')], parse('abcd')) + + # Unclosed code tag content will be parsed as normal rdoc + assert_equal([em_node('', bold_node('b'))], parse('b')) + + # Tidylink closing brace will close the last opened tidylink + assert_equal([tidylink_node(['', bold_node('b')], 'url'), ''], parse('{b}[url]')) + + # Tag closing will invalidate tidylink + assert_equal([em_node('{a', bold_node('b')), 'c}[url]'], parse('{abc}[url]')) + + # Unclosed tidylink url will parsed as normal rdoc + assert_equal(['label[http://example.com/?q=', bold_node(), tt_node('1')], parse('label[http://example.com/?q=+1+')) + assert_equal(['{label}[http://example.com/?q=', bold_node(), tt_node('1')], parse('{label}[http://example.com/?q=+1+')) + + # Closing brace invalidates unclosed tags + assert_equal(['{', bold_node('foo'), '}}[bar]'], parse('{foo}}[bar]')) + end +end diff --git a/test/rdoc/markup/markup_test.rb b/test/rdoc/markup/markup_test.rb index 9945d83ef1..979d0a8c29 100644 --- a/test/rdoc/markup/markup_test.rb +++ b/test/rdoc/markup/markup_test.rb @@ -41,26 +41,6 @@ def test_convert 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 diff --git a/test/rdoc/markup/to_ansi_test.rb b/test/rdoc/markup/to_ansi_test.rb index 19556a0f67..36a4a8bc4a 100644 --- a/test/rdoc/markup/to_ansi_test.rb +++ b/test/rdoc/markup/to_ansi_test.rb @@ -377,4 +377,10 @@ def test_convert_list_note assert_equal expected, @to.convert(note_list) end + def test_ansi_on_off + assert_equal "\e[1mab\e[m", @to.attributes('ab') + assert_equal "\e[1;4ma\e[0;9mb\e[m", @to.attributes('ab') + assert_equal "\e[1;4ma\e[24;9mb\e[m", @to.attributes('ab') + assert_equal "\e[1;4ma\e[22mb\e[m", @to.attributes('ab') + end end diff --git a/test/rdoc/markup/to_html_crossref_test.rb b/test/rdoc/markup/to_html_crossref_test.rb index cf61460297..ce69aa50db 100644 --- a/test/rdoc/markup/to_html_crossref_test.rb +++ b/test/rdoc/markup/to_html_crossref_test.rb @@ -243,10 +243,27 @@ def test_handle_regexp_CROSSREF_show_hash_false def test_handle_regexp_CROSSREF_with_arg_looks_like_TIDYLINK result = @to.convert 'C1.m[:sym]' - assert_equal para("C1.m[:sym]"), result, + assert_equal para("C1.m[:sym]"), result, 'C1.m[:sym]' end + def test_suppress_link_inside_tidylink_label + result = @to.convert '{rdoc-ref:C1.m http://example.com C1}[url]' + assert_equal para('rdoc-ref:C1.m http://example.com C1'), result + end + + def test_crossref_disabled_in_word_pair + result = @to.convert 'C1 *C1* _C1_ C1' + crossref = 'C1' + assert_equal para("#{crossref} C1 C1 #{crossref}"), result + end + + def test_suppressed_crossref + result = @to.convert 'C1 \C1 \CC1' + crossref = 'C1' + assert_equal para("#{crossref} C1 CC1"), result + end + def test_handle_regexp_HYPERLINK_rdoc readme = @store.add_file 'README.txt' readme.parser = RDoc::Parser::Simple @@ -266,31 +283,31 @@ def test_handle_regexp_HYPERLINK_rdoc assert_equal 'README.txt', link end - def test_handle_regexp_TIDYLINK_rdoc + def test_handle_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_regexp_TIDYLINK tidy 'C2::C3' + link = @to.to_html tidy 'C2::C3' assert_equal 'tidy', link - link = @to.handle_regexp_TIDYLINK tidy 'C4' + link = @to.to_html tidy 'C4' assert_equal 'tidy', link - link = @to.handle_regexp_TIDYLINK tidy 'C1#m' + link = @to.to_html tidy 'C1#m' assert_equal 'tidy', link - link = @to.handle_regexp_TIDYLINK tidy 'README.txt' + link = @to.to_html tidy 'README.txt' assert_equal 'tidy', link end def test_handle_regexp_TIDYLINK_label - link = @to.handle_regexp_TIDYLINK tidy 'C1#m@foo' + link = @to.to_html tidy 'C1#m@foo' assert_equal "tidy", link, 'C1#m@foo' @@ -341,19 +358,15 @@ def para(text) end def REGEXP_HANDLING(text) - @to.handle_regexp_CROSSREF regexp_handling text + @to.handle_regexp_CROSSREF text end def hyper(reference) - RDoc::Markup::RegexpHandling.new 0, "rdoc-ref:#{reference}" - end - - def regexp_handling(text) - RDoc::Markup::RegexpHandling.new 0, text + "rdoc-ref:#{reference}" end def tidy(reference) - RDoc::Markup::RegexpHandling.new 0, "{tidy}[rdoc-ref:#{reference}]" + "{tidy}[rdoc-ref:#{reference}]" end end diff --git a/test/rdoc/markup/to_html_snippet_test.rb b/test/rdoc/markup/to_html_snippet_test.rb index a9bc00eef3..ce9118a18c 100644 --- a/test/rdoc/markup/to_html_snippet_test.rb +++ b/test/rdoc/markup/to_html_snippet_test.rb @@ -651,7 +651,7 @@ def test_convert_TIDYLINK_rdoc_label end def test_handle_regexp_HYPERLINK_link - target = RDoc::Markup::RegexpHandling.new 0, 'link:README.txt' + target = 'link:README.txt' link = @to.handle_regexp_HYPERLINK target @@ -675,24 +675,6 @@ def test_list_verbatim_2 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 "

--\n", util_format("--") assert_equal 2, @to.characters diff --git a/test/rdoc/markup/to_html_test.rb b/test/rdoc/markup/to_html_test.rb index 3d2b010c4b..459bcb140e 100644 --- a/test/rdoc/markup/to_html_test.rb +++ b/test/rdoc/markup/to_html_test.rb @@ -907,7 +907,7 @@ def test_gen_url_rb_file end def test_handle_regexp_HYPERLINK_link - target = RDoc::Markup::RegexpHandling.new 0, 'link:README.txt' + target = 'link:README.txt' link = @to.handle_regexp_HYPERLINK target @@ -915,7 +915,7 @@ def test_handle_regexp_HYPERLINK_link end def test_handle_regexp_HYPERLINK_irc - target = RDoc::Markup::RegexpHandling.new 0, 'irc://irc.freenode.net/#ruby-lang' + target = 'irc://irc.freenode.net/#ruby-lang' link = @to.handle_regexp_HYPERLINK target @@ -998,7 +998,7 @@ def test_parseable_eh end def test_to_html - assert_equal "\n

--

\n", util_format("--") + assert_equal "\n

--\\\\

\n", util_format("--\\\\\\\\") end def util_format(text) @@ -1040,6 +1040,11 @@ def test_accept_table assert_include(res[%r<]*>C1>], 'C1') end + def test_suppressed_crossref_and_backslashes + result = @to.convert('\\1 \\n \\Ruby \\::new \\foo_bar \\') + assert_equal "\n

\\1 \\n Ruby ::new foo_bar \\

\n", result + end + def test_gen_url_markdown_anchor assert_equal 'link', @to.gen_url('#hello-world', 'link') end @@ -1049,6 +1054,29 @@ def test_convert_tidy_link_markdown_anchor assert_equal "\n

link

\n", result end + def test_convert_hyperlink_disabled_inside_tidylink + result = @to.convert '{See http://example.com}[README.txt] http://example.com' + assert_equal "\n

See http://example.com example.com

\n", result + end + + def test_convert_rdoc_image_inside_tidylink + result = @to.convert '{See rdoc-image:image.png:text}[url] rdoc-image:image.jpg:text' + assert_equal "\n

See \"text\" \"text\"

\n", result + + # When `label =~ regexp_handling == 0`, label is handled specially in RDoc::Markup::ToHTML#apply_tidylink_label_special_regexp_handling + result = @to.convert '{rdoc-image:image.png:text}[url] rdoc-image:image.jpg:text' + assert_equal "\n

\"text\" \"text\"

\n", result + end + + def test_convert_rdoc_label_disabled_inside_tidylink + result = @to.convert '{See rdoc-label:label}[url] rdoc-label:label' + assert_equal "\n

See rdoc-label:label label

\n", result + + # When `label =~ regexp_handling == 0`, label is handled specially in RDoc::Markup::ToHTML#apply_tidylink_label_special_regexp_handling + result = @to.convert '{rdoc-label:label}[url] rdoc-label:label' + assert_equal "\n

rdoc-label:label label

\n", result + end + def assert_escaped(unexpected, code) result = @to.convert(code) assert_not_include result, unexpected diff --git a/test/rdoc/markup/to_rdoc_test.rb b/test/rdoc/markup/to_rdoc_test.rb index 1ee6e0b26a..ea7326ec6f 100644 --- a/test/rdoc/markup/to_rdoc_test.rb +++ b/test/rdoc/markup/to_rdoc_test.rb @@ -2,6 +2,35 @@ require_relative '../helper' class RDocMarkupToRDocTest < RDoc::Markup::TextFormatterTestCase + class ToBoldEmTT < RDoc::Markup::ToRdoc + def handle_BOLD(nodes) + emit_inline('') + super + emit_inline('') + end + + def handle_EM(nodes) + emit_inline('') + super + emit_inline('') + end + + def handle_BOLD_WORD(word) + emit_inline('') + super + emit_inline('') + end + + def handle_EM_WORD(word) + emit_inline('') + super + emit_inline('') + end + + def handle_TT(text) + emit_inline("#{text}") + end + end add_visitor_tests add_text_tests @@ -9,7 +38,7 @@ class RDocMarkupToRDocTest < RDoc::Markup::TextFormatterTestCase def setup super - @to = RDoc::Markup::ToRdoc.new + @to = ToBoldEmTT.new end def accept_blank_line diff --git a/test/rdoc/rdoc_text_test.rb b/test/rdoc/rdoc_text_test.rb index b691afa0ca..03c4167ac5 100644 --- a/test/rdoc/rdoc_text_test.rb +++ b/test/rdoc/rdoc_text_test.rb @@ -493,7 +493,8 @@ def test_to_html_apostrophe_entity end def test_to_html_backslash - assert_equal 'S', to_html('\\S') + # Don't handle unescaped crossref. It should be handled in RDoc::Markup::ToHtml, not in RDoc::Text + assert_equal '\\S', to_html('\\S') end def test_to_html_br @@ -562,8 +563,9 @@ def test_to_html_registered_trademark end def test_to_html_tt_tag + # tt tag content is already escaped assert_equal 'hi\'s', to_html('hi\'s') - assert_equal 'hi\\\'s', to_html('hi\\\\\'s') + assert_equal 'hi\\\\\'s', to_html('hi\\\\\'s') end def test_to_html_tt_tag_mismatch