"Fossies" - the Fresh Open Source Software Archive

Member "asciidoctor-2.0.10/test/links_test.rb" (1 Jun 2019, 40258 Bytes) of package /linux/www/asciidoctor-2.0.10.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Ruby source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the last Fossies "Diffs" side-by-side code changes report for "links_test.rb": 2.0.7_vs_2.0.8.

    1 # frozen_string_literal: true
    2 require_relative 'test_helper'
    3 
    4 context 'Links' do
    5 
    6   test 'qualified url inline with text' do
    7     assert_xpath "//a[@href='http://asciidoc.org'][@class='bare'][text() = 'http://asciidoc.org']", convert_string("The AsciiDoc project is located at http://asciidoc.org.")
    8   end
    9 
   10   test 'qualified url with role inline with text' do
   11     assert_xpath "//a[@href='http://asciidoc.org'][@class='bare project'][text() = 'http://asciidoc.org']", convert_string("The AsciiDoc project is located at http://asciidoc.org[role=project].")
   12   end
   13 
   14   test 'qualified http url inline with hide-uri-scheme set' do
   15     assert_xpath "//a[@href='http://asciidoc.org'][@class='bare'][text() = 'asciidoc.org']", convert_string("The AsciiDoc project is located at http://asciidoc.org.", attributes: { 'hide-uri-scheme' => '' })
   16   end
   17 
   18   test 'qualified file url inline with label' do
   19     assert_xpath "//a[@href='file:///home/user/bookmarks.html'][text() = 'My Bookmarks']", convert_string_to_embedded('file:///home/user/bookmarks.html[My Bookmarks]')
   20   end
   21 
   22   test 'qualified file url inline with hide-uri-scheme set' do
   23     assert_xpath "//a[@href='file:///etc/app.conf'][text() = '/etc/app.conf']", convert_string('Edit the configuration file link:file:///etc/app.conf[]', attributes: { 'hide-uri-scheme' => '' })
   24   end
   25 
   26   test 'should not hide bare URI scheme in implicit text of link macro when hide-uri-scheme is set' do
   27     {
   28       'link:https://[]' => 'https://',
   29       'link:ssh://[]' => 'ssh://',
   30     }.each do |input, expected|
   31       assert_xpath %(/a[text() = "#{expected}"]), (convert_inline_string input, attributes: { 'hide-uri-scheme' => '' })
   32     end
   33   end
   34 
   35   test 'qualified url with label' do
   36     assert_xpath "//a[@href='http://asciidoc.org'][text() = 'AsciiDoc']", convert_string("We're parsing http://asciidoc.org[AsciiDoc] markup")
   37   end
   38 
   39   test 'qualified url with label containing escaped right square bracket' do
   40     assert_xpath "//a[@href='http://asciidoc.org'][text() = '[Ascii]Doc']", convert_string("We're parsing http://asciidoc.org[[Ascii\\]Doc] markup")
   41   end
   42 
   43   test 'qualified url with backslash label' do
   44     assert_xpath "//a[@href='https://google.com'][text() = 'Google for \\']", convert_string("I advise you to https://google.com[Google for +\\+]")
   45   end
   46 
   47   test 'qualified url with label using link macro' do
   48     assert_xpath "//a[@href='http://asciidoc.org'][text() = 'AsciiDoc']", convert_string("We're parsing link:http://asciidoc.org[AsciiDoc] markup")
   49   end
   50 
   51   test 'qualified url with role using link macro' do
   52     assert_xpath "//a[@href='http://asciidoc.org'][@class='bare project'][text() = 'http://asciidoc.org']", convert_string("We're parsing link:http://asciidoc.org[role=project] markup")
   53   end
   54 
   55   test 'qualified url using macro syntax with multi-line label inline with text' do
   56     assert_xpath %{//a[@href='http://asciidoc.org'][text() = 'AsciiDoc\nmarkup']}, convert_string("We're parsing link:http://asciidoc.org[AsciiDoc\nmarkup]")
   57   end
   58 
   59   test 'qualified url with label containing square brackets using link macro' do
   60     str = 'http://example.com[[bracket1\]]'
   61     doc = document_from_string str, standalone: false, doctype: 'inline'
   62     assert_match '<a href="http://example.com">[bracket1]</a>', doc.convert, 1
   63     doc = document_from_string str, standalone: false, backend: 'docbook', doctype: 'inline'
   64     assert_match '<link xl:href="http://example.com">[bracket1]</link>', doc.convert, 1
   65   end
   66 
   67   test 'link macro with empty target' do
   68     input = 'Link to link:[this page].'
   69     output = convert_string_to_embedded input
   70     assert_xpath '//a', output, 1
   71     assert_xpath '//a[@href=""]', output, 1
   72   end
   73 
   74   test 'should not recognize link macro with double colons' do
   75     input = 'The link::http://example.org[example domain] is reserved for tests and documentation.'
   76     output = convert_string_to_embedded input
   77     assert_includes output, 'link::http://example.org[example domain]'
   78   end
   79 
   80   test 'qualified url surrounded by angled brackets' do
   81     assert_xpath '//a[@href="http://asciidoc.org"][text()="http://asciidoc.org"]', convert_string('<http://asciidoc.org> is the project page for AsciiDoc.'), 1
   82   end
   83 
   84   test 'qualified url surrounded by round brackets' do
   85     assert_xpath '//a[@href="http://asciidoc.org"][text()="http://asciidoc.org"]', convert_string('(http://asciidoc.org) is the project page for AsciiDoc.'), 1
   86   end
   87 
   88   test 'qualified url with trailing round bracket' do
   89     result = convert_string_to_embedded 'Asciidoctor is a Ruby-based AsciiDoc processor (see https://asciidoctor.org)'
   90     assert_xpath '//a[@href="https://asciidoctor.org"][text()="https://asciidoctor.org"]', result, 1
   91     assert_xpath '//a[@href="https://asciidoctor.org"][text()="https://asciidoctor.org"]/following-sibling::text()[starts-with(.,")")]', result, 1
   92   end
   93 
   94   test 'qualified url with trailing semi-colon' do
   95     result = convert_string_to_embedded 'https://asciidoctor.org; where text gets parsed'
   96     assert_xpath '//a[@href="https://asciidoctor.org"][text()="https://asciidoctor.org"]', result, 1
   97     assert_xpath '//a[@href="https://asciidoctor.org"][text()="https://asciidoctor.org"]/following-sibling::text()[starts-with(.,";")]', result, 1
   98   end
   99 
  100   test 'qualified url with trailing colon' do
  101     result = convert_string_to_embedded 'https://asciidoctor.org: where text gets parsed'
  102     assert_xpath '//a[@href="https://asciidoctor.org"][text()="https://asciidoctor.org"]', result, 1
  103     assert_xpath '//a[@href="https://asciidoctor.org"][text()="https://asciidoctor.org"]/following-sibling::text()[starts-with(.,":")]', result, 1
  104   end
  105 
  106   test 'qualified url in round brackets with trailing colon' do
  107     result = convert_string_to_embedded '(https://asciidoctor.org): where text gets parsed'
  108     assert_xpath '//a[@href="https://asciidoctor.org"][text()="https://asciidoctor.org"]', result, 1
  109     assert_xpath '//a[@href="https://asciidoctor.org"][text()="https://asciidoctor.org"]/following-sibling::text()[starts-with(.,"):")]', result, 1
  110   end
  111 
  112   test 'qualified url with trailing round bracket followed by colon' do
  113     result = convert_string_to_embedded '(from https://asciidoctor.org): where text gets parsed'
  114     assert_xpath '//a[@href="https://asciidoctor.org"][text()="https://asciidoctor.org"]', result, 1
  115     assert_xpath '//a[@href="https://asciidoctor.org"][text()="https://asciidoctor.org"]/following-sibling::text()[starts-with(., "):")]', result, 1
  116   end
  117 
  118   test 'qualified url in round brackets with trailing semi-colon' do
  119     result = convert_string_to_embedded '(https://asciidoctor.org); where text gets parsed'
  120     assert_xpath '//a[@href="https://asciidoctor.org"][text()="https://asciidoctor.org"]', result, 1
  121     assert_xpath '//a[@href="https://asciidoctor.org"][text()="https://asciidoctor.org"]/following-sibling::text()[starts-with(., ");")]', result, 1
  122   end
  123 
  124   test 'qualified url with trailing round bracket followed by semi-colon' do
  125     result = convert_string_to_embedded '(from https://asciidoctor.org); where text gets parsed'
  126     assert_xpath '//a[@href="https://asciidoctor.org"][text()="https://asciidoctor.org"]', result, 1
  127     assert_xpath '//a[@href="https://asciidoctor.org"][text()="https://asciidoctor.org"]/following-sibling::text()[starts-with(., ");")]', result, 1
  128   end
  129 
  130   test 'URI scheme with trailing characters should not be converted to a link' do
  131     input_sources = %w(
  132       (https://)
  133       http://;
  134       file://:
  135       <ftp://>
  136     )
  137     expected_outputs = %w(
  138       (https://)
  139       http://;
  140       file://:
  141       &lt;ftp://&gt;
  142     )
  143     input_sources.each_with_index do |input_source, i|
  144       expected_output = expected_outputs[i]
  145       actual = block_from_string input_source
  146       assert_equal expected_output, actual.content
  147     end
  148   end
  149 
  150   test 'qualified url containing round brackets' do
  151     assert_xpath '//a[@href="http://jruby.org/apidocs/org/jruby/Ruby.html#addModule(org.jruby.RubyModule)"][text()="addModule() adds a Ruby module"]', convert_string('http://jruby.org/apidocs/org/jruby/Ruby.html#addModule(org.jruby.RubyModule)[addModule() adds a Ruby module]'), 1
  152   end
  153 
  154   test 'qualified url adjacent to text in square brackets' do
  155     assert_xpath '//a[@href="http://asciidoc.org"][text()="AsciiDoc"]', convert_string(']http://asciidoc.org[AsciiDoc] project page.'), 1
  156   end
  157 
  158   test 'qualified url adjacent to text in round brackets' do
  159     assert_xpath '//a[@href="http://asciidoc.org"][text()="AsciiDoc"]', convert_string(')http://asciidoc.org[AsciiDoc] project page.'), 1
  160   end
  161 
  162   test 'qualified url following no-break space' do
  163     assert_xpath '//a[@href="http://asciidoc.org"][text()="AsciiDoc"]', convert_string(%(#{[0xa0].pack 'U1'}http://asciidoc.org[AsciiDoc] project page.)), 1
  164   end
  165 
  166   test 'qualified url following smart apostrophe' do
  167     output = convert_string_to_embedded("l&#8217;http://www.irit.fr[IRIT]")
  168     assert_match(/l&#8217;<a href=/, output)
  169   end
  170 
  171   test 'qualified url using invalid link macro should not create link' do
  172     assert_xpath '//a', convert_string('link:http://asciidoc.org is the project page for AsciiDoc.'), 0
  173   end
  174 
  175   test 'escaped inline qualified url should not create link' do
  176     assert_xpath '//a', convert_string('\http://asciidoc.org is the project page for AsciiDoc.'), 0
  177   end
  178 
  179   test 'url in link macro with at (@) sign should not create mailto link' do
  180     assert_xpath '//a[@href="http://xircles.codehaus.org/lists/dev@geb.codehaus.org"][text()="subscribe"]', convert_string('http://xircles.codehaus.org/lists/dev@geb.codehaus.org[subscribe]')
  181   end
  182 
  183   test 'implicit url with at (@) sign should not create mailto link' do
  184     assert_xpath '//a[@href="http://xircles.codehaus.org/lists/dev@geb.codehaus.org"][text()="http://xircles.codehaus.org/lists/dev@geb.codehaus.org"]', convert_string('http://xircles.codehaus.org/lists/dev@geb.codehaus.org')
  185   end
  186 
  187   test 'escaped inline qualified url using macro syntax should not create link' do
  188     assert_xpath '//a', convert_string('\http://asciidoc.org[AsciiDoc] is the key to good docs.'), 0
  189   end
  190 
  191   test 'inline qualified url followed by a newline should not include newline in link' do
  192     assert_xpath '//a[@href="https://github.com/asciidoctor"]', convert_string("The source code for Asciidoctor can be found at https://github.com/asciidoctor\nwhich is a GitHub organization."), 1
  193   end
  194 
  195   test 'qualified url divided by newline using macro syntax should not create link' do
  196     assert_xpath '//a', convert_string("The source code for Asciidoctor can be found at link:https://github.com/asciidoctor\n[]which is a GitHub organization."), 0
  197   end
  198 
  199   test 'qualified url containing whitespace using macro syntax should not create link' do
  200     assert_xpath '//a', convert_string('I often need to refer to the chapter on link:http://asciidoc.org?q=attribute references[Attribute References].'), 0
  201   end
  202 
  203   test 'qualified url containing an encoded space using macro syntax should create a link' do
  204     assert_xpath '//a', convert_string('I often need to refer to the chapter on link:http://asciidoc.org?q=attribute%20references[Attribute References].'), 1
  205   end
  206 
  207   test 'inline quoted qualified url should not consume surrounding angled brackets' do
  208     assert_xpath '//a[@href="https://github.com/asciidoctor"]', convert_string('Asciidoctor GitHub organization: <**https://github.com/asciidoctor**>'), 1
  209   end
  210 
  211   test 'link with quoted text should not be separated into attributes when text contains an equal sign' do
  212     assert_xpath '//a[@href="http://search.example.com"][text()="Google, Yahoo, Bing = Search Engines"]', convert_string_to_embedded('http://search.example.com["Google, Yahoo, Bing = Search Engines"]'), 1
  213   end
  214 
  215   test 'link with quoted text but no equal sign should carry quotes over to output' do
  216     assert_xpath %(//a[@href="http://search.example.com"][text()='"Google, Yahoo, Bing"']), convert_string_to_embedded('http://search.example.com["Google, Yahoo, Bing"]'), 1
  217   end
  218 
  219   test 'link with comma in text but no equal sign should not be separated into attributes' do
  220     assert_xpath '//a[@href="http://search.example.com"][text()="Google, Yahoo, Bing"]', convert_string_to_embedded('http://search.example.com[Google, Yahoo, Bing]'), 1
  221   end
  222 
  223   test 'role and window attributes on link are processed' do
  224     assert_xpath '//a[@href="http://google.com"][@class="external"][@target="_blank"]', convert_string_to_embedded('http://google.com[Google, role=external, window="_blank"]'), 1
  225   end
  226 
  227   test 'link macro with attributes but no text should use URL as text' do
  228     url = 'https://fonts.googleapis.com/css?family=Roboto:400,400italic,'
  229     assert_xpath %(//a[@href="#{url}"][text()="#{url}"]), convert_string_to_embedded(%(link:#{url}[family=Roboto,weight=400])), 1
  230   end
  231 
  232   test 'link macro with attributes but blank text should use URL as text' do
  233     url = 'https://fonts.googleapis.com/css?family=Roboto:400,400italic,'
  234     assert_xpath %(//a[@href="#{url}"][text()="#{url}"]), convert_string_to_embedded(%(link:#{url}[,family=Roboto,weight=400])), 1
  235   end
  236 
  237   test 'link macro with comma but no explicit attributes in text should not parse text' do
  238     url = 'https://fonts.googleapis.com/css?family=Roboto:400,400italic,'
  239     assert_xpath %(//a[@href="#{url}"][text()="Roboto,400"]), convert_string_to_embedded(%(link:#{url}[Roboto,400])), 1
  240   end
  241 
  242   test 'link text that ends in ^ should set link window to _blank' do
  243     assert_xpath '//a[@href="http://google.com"][@target="_blank"]', convert_string_to_embedded('http://google.com[Google^]'), 1
  244   end
  245 
  246   test 'rel=noopener should be added to a link that targets the _blank window' do
  247     assert_xpath '//a[@href="http://google.com"][@target="_blank"][@rel="noopener"]', convert_string_to_embedded('http://google.com[Google^]'), 1
  248   end
  249 
  250   test 'rel=noopener should be added to a link that targets a named window when the noopener option is set' do
  251     assert_xpath '//a[@href="http://google.com"][@target="name"][@rel="noopener"]', convert_string_to_embedded('http://google.com[Google,window=name,opts=noopener]'), 1
  252   end
  253 
  254   test 'rel=noopener should not be added to a link if it does not target a window' do
  255     result = convert_string_to_embedded 'http://google.com[Google,opts=noopener]'
  256     assert_xpath '//a[@href="http://google.com"]', result, 1
  257     assert_xpath '//a[@href="http://google.com"][@rel="noopener"]', result, 0
  258   end
  259 
  260   test 'rel=nofollow should be added to a link when the nofollow option is set' do
  261     assert_xpath '//a[@href="http://google.com"][@target="name"][@rel="nofollow noopener"]', convert_string_to_embedded('http://google.com[Google,window=name,opts="nofollow,noopener"]'), 1
  262   end
  263 
  264   test 'id attribute on link is processed' do
  265     assert_xpath '//a[@href="http://google.com"][@id="link-1"]', convert_string_to_embedded('http://google.com[Google, id="link-1"]'), 1
  266   end
  267 
  268   test 'title attribute on link is processed' do
  269     assert_xpath '//a[@href="http://google.com"][@title="title-1"]', convert_string_to_embedded('http://google.com[Google, title="title-1"]'), 1
  270   end
  271 
  272   test 'inline irc link' do
  273     assert_xpath '//a[@href="irc://irc.freenode.net"][text()="irc://irc.freenode.net"]', convert_string_to_embedded('irc://irc.freenode.net'), 1
  274   end
  275 
  276   test 'inline irc link with text' do
  277     assert_xpath '//a[@href="irc://irc.freenode.net"][text()="Freenode IRC"]', convert_string_to_embedded('irc://irc.freenode.net[Freenode IRC]'), 1
  278   end
  279 
  280   test 'inline ref' do
  281     variations = %w([[tigers]] anchor:tigers[])
  282     variations.each do |anchor|
  283       doc = document_from_string %(Here you can read about tigers.#{anchor})
  284       output = doc.convert
  285       assert_kind_of Asciidoctor::Inline, doc.catalog[:refs]['tigers']
  286       assert_nil doc.catalog[:refs]['tigers'].text
  287       assert_xpath '//a[@id="tigers"]', output, 1
  288       assert_xpath '//a[@id="tigers"]/child::text()', output, 0
  289     end
  290   end
  291 
  292   test 'escaped inline ref' do
  293     variations = %w([[tigers]] anchor:tigers[])
  294     variations.each do |anchor|
  295       doc = document_from_string %(Here you can read about tigers.\\#{anchor})
  296       output = doc.convert
  297       refute doc.catalog[:refs].key?('tigers')
  298       assert_xpath '//a[@id="tigers"]', output, 0
  299     end
  300   end
  301 
  302   test 'inline ref can start with colon' do
  303     input = '[[:idname]] text'
  304     output = convert_string_to_embedded input
  305     assert_xpath '//a[@id=":idname"]', output, 1
  306   end
  307 
  308   test 'inline ref cannot start with digit' do
  309     input = '[[1-install]] text'
  310     output = convert_string_to_embedded input
  311     assert_includes output, '[[1-install]]'
  312     assert_xpath '//a[@id = "1-install"]', output, 0
  313   end
  314 
  315   test 'inline ref with reftext' do
  316     %w([[tigers,Tigers]] anchor:tigers[Tigers]).each do |anchor|
  317       doc = document_from_string %(Here you can read about tigers.#{anchor})
  318       output = doc.convert
  319       assert_kind_of Asciidoctor::Inline, doc.catalog[:refs]['tigers']
  320       assert_equal 'Tigers', doc.catalog[:refs]['tigers'].text
  321       assert_xpath '//a[@id="tigers"]', output, 1
  322       assert_xpath '//a[@id="tigers"]/child::text()', output, 0
  323     end
  324   end
  325 
  326   test 'should encode double quotes in reftext of anchor macro in DocBook output' do
  327     input = 'anchor:uncola[the "un"-cola]'
  328     result = convert_inline_string input, backend: :docbook
  329     assert_equal '<anchor xml:id="uncola" xreflabel="the &quot;un&quot;-cola"/>', result
  330   end
  331 
  332   test 'should substitute attribute references in reftext when registering inline ref' do
  333     %w([[tigers,{label-tigers}]] anchor:tigers[{label-tigers}]).each do |anchor|
  334       doc = document_from_string %(Here you can read about tigers.#{anchor}), attributes: { 'label-tigers' => 'Tigers' }
  335       doc.convert
  336       assert_kind_of Asciidoctor::Inline, doc.catalog[:refs]['tigers']
  337       assert_equal 'Tigers', doc.catalog[:refs]['tigers'].text
  338     end
  339   end
  340 
  341   test 'inline ref with reftext converted to DocBook' do
  342     %w([[tigers,<Tigers>]] anchor:tigers[<Tigers>]).each do |anchor|
  343       doc = document_from_string %(Here you can read about tigers.#{anchor}), backend: :docbook
  344       output = doc.convert standalone: false
  345       assert_kind_of Asciidoctor::Inline, doc.catalog[:refs]['tigers']
  346       assert_equal '<Tigers>', doc.catalog[:refs]['tigers'].text
  347       assert_includes output, '<anchor xml:id="tigers" xreflabel="&lt;Tigers&gt;"/>'
  348     end
  349   end
  350 
  351   test 'does not match bibliography anchor in prose when scanning for inline anchor' do
  352     doc = document_from_string 'Use [[[label]]] to assign a label to a bibliography entry.'
  353     refute doc.catalog[:refs].key? 'label'
  354   end
  355 
  356   test 'repeating inline anchor macro with empty reftext' do
  357     input = 'anchor:one[] anchor:two[] anchor:three[]'
  358     result = convert_inline_string input
  359     assert_equal '<a id="one"></a> <a id="two"></a> <a id="three"></a>', result
  360   end
  361 
  362   test 'mixed inline anchor macro and anchor shorthand with empty reftext' do
  363     input = 'anchor:one[][[two]]anchor:three[][[four]]anchor:five[]'
  364     result = convert_inline_string input
  365     assert_equal '<a id="one"></a><a id="two"></a><a id="three"></a><a id="four"></a><a id="five"></a>', result
  366   end
  367 
  368   test 'assigns xreflabel value for anchor macro without reftext in DocBook output' do
  369     ['anchor:foo[]bar', '[[foo]]bar'].each do |input|
  370       result = convert_inline_string input, backend: :docbook
  371       assert_equal '<anchor xml:id="foo" xreflabel="[foo]"/>bar', result
  372     end
  373   end
  374 
  375   test 'unescapes square bracket in reftext of anchor macro' do
  376     input = <<~'EOS'
  377     see <<foo>>
  378 
  379     anchor:foo[b[a\]r]tex'
  380     EOS
  381     result = convert_string_to_embedded input
  382     assert_includes result, 'see <a href="#foo">b[a]r</a>'
  383   end
  384 
  385   test 'unescapes square bracket in reftext of anchor macro in DocBook output' do
  386     input = 'anchor:foo[b[a\]r]'
  387     result = convert_inline_string input, backend: :docbook
  388     assert_equal '<anchor xml:id="foo" xreflabel="b[a]r"/>', result
  389   end
  390 
  391   test 'xref using angled bracket syntax' do
  392     doc = document_from_string '<<tigers>>'
  393     doc.register :refs, ['tigers', (Asciidoctor::Inline.new doc, :anchor, '[tigers]', type: :ref, target: 'tigers'), '[tigers]']
  394     assert_xpath '//a[@href="#tigers"][text() = "[tigers]"]', doc.convert, 1
  395   end
  396 
  397   test 'xref using angled bracket syntax with explicit hash' do
  398     doc = document_from_string '<<#tigers>>'
  399     doc.register :refs, ['tigers', (Asciidoctor::Inline.new doc, :anchor, 'Tigers', type: :ref, target: 'tigers'), 'Tigers']
  400     assert_xpath '//a[@href="#tigers"][text() = "Tigers"]', doc.convert, 1
  401   end
  402 
  403   test 'xref using angled bracket syntax with label' do
  404     input = <<~'EOS'
  405     <<tigers,About Tigers>>
  406 
  407     [#tigers]
  408     == Tigers
  409     EOS
  410     assert_xpath '//a[@href="#tigers"][text() = "About Tigers"]', convert_string(input), 1
  411   end
  412 
  413   test 'xref using angled bracket syntax with quoted label' do
  414     input = <<~'EOS'
  415     <<tigers,"About Tigers">>
  416 
  417     [#tigers]
  418     == Tigers
  419     EOS
  420     assert_xpath %q(//a[@href="#tigers"][text() = '"About Tigers"']), convert_string(input), 1
  421   end
  422 
  423   test 'should not interpret path sans extension in xref with angled bracket syntax in compat mode' do
  424     using_memory_logger do |logger|
  425       doc = document_from_string '<<tigers#>>', standalone: false, attributes: { 'compat-mode' => '' }
  426       assert_xpath '//a[@href="#tigers#"][text() = "[tigers#]"]', doc.convert, 1
  427     end
  428   end
  429 
  430   test 'xref using angled bracket syntax with path sans extension' do
  431     doc = document_from_string '<<tigers#>>', standalone: false
  432     assert_xpath '//a[@href="tigers.html"][text() = "tigers.html"]', doc.convert, 1
  433   end
  434 
  435   test 'inter-document xref shorthand syntax should assume AsciiDoc extension if AsciiDoc extension not present' do
  436     {
  437       'using-.net-web-services#' => 'Using .NET web services',
  438       'asciidoctor.1#' => 'Asciidoctor Manual',
  439       'path/to/document#' => 'Document Title',
  440     }.each do |target, text|
  441       result = convert_string_to_embedded %(<<#{target},#{text}>>)
  442       assert_xpath %(//a[@href="#{target.chop}.html"][text()="#{text}"]), result, 1
  443     end
  444   end
  445 
  446   test 'xref macro with explicit inter-document target should assume implicit AsciiDoc file extension if no file extension is present' do
  447     {
  448       'using-.net-web-services#' => 'Using .NET web services',
  449       'asciidoctor.1#' => 'Asciidoctor Manual',
  450     }.each do |target, text|
  451       result = convert_string_to_embedded %(xref:#{target}[#{text}])
  452       assert_xpath %(//a[@href="#{target.chop}"][text()="#{text}"]), result, 1
  453     end
  454     {
  455       'document#' => 'Document Title',
  456       'path/to/document#' => 'Document Title',
  457       'include.d/document#' => 'Document Title',
  458     }.each do |target, text|
  459       result = convert_string_to_embedded %(xref:#{target}[#{text}])
  460       assert_xpath %(//a[@href="#{target.chop}.html"][text()="#{text}"]), result, 1
  461     end
  462   end
  463 
  464   test 'xref macro with implicit inter-document target should preserve path with file extension' do
  465     {
  466       'refcard.pdf' => 'Refcard',
  467       'asciidoctor.1' => 'Asciidoctor Manual',
  468     }.each do |path, text|
  469       result = convert_string_to_embedded %(xref:#{path}[#{text}])
  470       assert_xpath %(//a[@href="#{path}"][text()="#{text}"]), result, 1
  471     end
  472     {
  473       'sections.d/first' => 'First Section',
  474     }.each do |path, text|
  475       result = convert_string_to_embedded %(xref:#{path}[#{text}])
  476       assert_xpath %(//a[@href="##{path}"][text()="#{text}"]), result, 1
  477     end
  478   end
  479 
  480   test 'inter-document xref should only remove the file extension part if the path contains a period elsewhere' do
  481     result = convert_string_to_embedded '<<using-.net-web-services.adoc#,Using .NET web services>>'
  482     assert_xpath '//a[@href="using-.net-web-services.html"][text() = "Using .NET web services"]', result, 1
  483   end
  484 
  485   test 'xref macro target containing dot should be interpreted as a path unless prefixed by #' do
  486     result = convert_string_to_embedded 'xref:using-.net-web-services[Using .NET web services]'
  487     assert_xpath '//a[@href="using-.net-web-services"][text() = "Using .NET web services"]', result, 1
  488     result = convert_string_to_embedded 'xref:#using-.net-web-services[Using .NET web services]'
  489     assert_xpath '//a[@href="#using-.net-web-services"][text() = "Using .NET web services"]', result, 1
  490   end
  491 
  492   test 'xref using angled bracket syntax with path sans extension using docbook backend' do
  493     doc = document_from_string '<<tigers#>>', standalone: false, backend: 'docbook'
  494     assert_match '<link xl:href="tigers.xml">tigers.xml</link>', doc.convert, 1
  495   end
  496 
  497   test 'xref using angled bracket syntax with ancestor path sans extension' do
  498     doc = document_from_string '<<../tigers#,tigers>>', standalone: false
  499     assert_xpath '//a[@href="../tigers.html"][text() = "tigers"]', doc.convert, 1
  500   end
  501 
  502   test 'xref using angled bracket syntax with absolute path sans extension' do
  503     doc = document_from_string '<</path/to/tigers#,tigers>>', standalone: false
  504     assert_xpath '//a[@href="/path/to/tigers.html"][text() = "tigers"]', doc.convert, 1
  505   end
  506 
  507   test 'xref using angled bracket syntax with path and extension' do
  508     using_memory_logger do |logger|
  509       doc = document_from_string '<<tigers.adoc>>', standalone: false
  510       assert_xpath '//a[@href="#tigers.adoc"][text() = "[tigers.adoc]"]', doc.convert, 1
  511     end
  512   end
  513 
  514   test 'xref using angled bracket syntax with path and extension with hash' do
  515     doc = document_from_string '<<tigers.adoc#>>', standalone: false
  516     assert_xpath '//a[@href="tigers.html"][text() = "tigers.html"]', doc.convert, 1
  517   end
  518 
  519   test 'xref using angled bracket syntax with path and extension with fragment' do
  520     doc = document_from_string '<<tigers.adoc#id>>', standalone: false
  521     assert_xpath '//a[@href="tigers.html#id"][text() = "tigers.html"]', doc.convert, 1
  522   end
  523 
  524   test 'xref using macro syntax with path and extension in compat mode' do
  525     using_memory_logger do |logger|
  526       doc = document_from_string 'xref:tigers.adoc[]', standalone: false, attributes: { 'compat-mode' => '' }
  527       assert_xpath '//a[@href="#tigers.adoc"][text() = "[tigers.adoc]"]', doc.convert, 1
  528     end
  529   end
  530 
  531   test 'xref using macro syntax with path and extension' do
  532     doc = document_from_string 'xref:tigers.adoc[]', standalone: false
  533     assert_xpath '//a[@href="tigers.html"][text() = "tigers.html"]', doc.convert, 1
  534   end
  535 
  536   test 'xref using angled bracket syntax with path and fragment' do
  537     doc = document_from_string '<<tigers#about>>', standalone: false
  538     assert_xpath '//a[@href="tigers.html#about"][text() = "tigers.html"]', doc.convert, 1
  539   end
  540 
  541   test 'xref using angled bracket syntax with path, fragment and text' do
  542     doc = document_from_string '<<tigers#about,About Tigers>>', standalone: false
  543     assert_xpath '//a[@href="tigers.html#about"][text() = "About Tigers"]', doc.convert, 1
  544   end
  545 
  546   test 'xref using angled bracket syntax with path and custom relfilesuffix and outfilesuffix' do
  547     attributes = { 'relfileprefix' => '../', 'outfilesuffix' => '/' }
  548     doc = document_from_string '<<tigers#about,About Tigers>>', standalone: false, attributes: attributes
  549     assert_xpath '//a[@href="../tigers/#about"][text() = "About Tigers"]', doc.convert, 1
  550   end
  551 
  552   test 'xref using angled bracket syntax with path and custom relfilesuffix' do
  553     attributes = { 'relfilesuffix' => '/' }
  554     doc = document_from_string '<<tigers#about,About Tigers>>', standalone: false, attributes: attributes
  555     assert_xpath '//a[@href="tigers/#about"][text() = "About Tigers"]', doc.convert, 1
  556   end
  557 
  558   test 'xref using angled bracket syntax with path which has been included in this document' do
  559     using_memory_logger do |logger|
  560       in_verbose_mode do
  561         doc = document_from_string '<<tigers#about,About Tigers>>', standalone: false
  562         doc.catalog[:includes]['tigers'] = true
  563         output = doc.convert
  564         assert_xpath '//a[@href="#about"][text() = "About Tigers"]', output, 1
  565         assert_message logger, :INFO, 'possible invalid reference: about'
  566       end
  567     end
  568   end
  569 
  570   test 'xref using angled bracket syntax with nested path which has been included in this document' do
  571     using_memory_logger do |logger|
  572       in_verbose_mode do
  573         doc = document_from_string '<<part1/tigers#about,About Tigers>>', standalone: false
  574         doc.catalog[:includes]['part1/tigers'] = true
  575         output = doc.convert
  576         assert_xpath '//a[@href="#about"][text() = "About Tigers"]', output, 1
  577         assert_message logger, :INFO, 'possible invalid reference: about'
  578       end
  579     end
  580   end
  581 
  582   test 'xref using angled bracket syntax inline with text' do
  583     input = <<~'EOS'
  584     Want to learn <<tigers,about tigers>>?
  585 
  586     [#tigers]
  587     == Tigers
  588     EOS
  589     assert_xpath '//a[@href="#tigers"][text() = "about tigers"]', convert_string(input), 1
  590   end
  591 
  592   test 'xref using angled bracket syntax with multi-line label inline with text' do
  593     input = <<~'EOS'
  594     Want to learn <<tigers,about
  595     tigers>>?
  596 
  597     [#tigers]
  598     == Tigers
  599     EOS
  600     assert_xpath %{//a[@href="#tigers"][normalize-space(text()) = "about tigers"]}, convert_string(input), 1
  601   end
  602 
  603   test 'xref with escaped text' do
  604     # when \x0 was used as boundary character for passthrough, it was getting stripped
  605     # now using unicode marks as boundary characters, which resolves issue
  606     input = <<~'EOS'
  607     See the <<tigers, `+[tigers]+`>> section for details about tigers.
  608 
  609     [#tigers]
  610     == Tigers
  611     EOS
  612     output = convert_string_to_embedded input
  613     assert_xpath %(//a[@href="#tigers"]/code[text()="[tigers]"]), output, 1
  614   end
  615 
  616   test 'xref with target that begins with attribute reference in title' do
  617     ['<<{lessonsdir}/lesson-1#,Lesson 1>>', 'xref:{lessonsdir}/lesson-1.adoc[Lesson 1]'].each do |xref|
  618       input = <<~EOS
  619       :lessonsdir: lessons
  620 
  621       [#lesson-1-listing]
  622       == #{xref}
  623 
  624       A summary of the first lesson.
  625       EOS
  626 
  627       output = convert_string_to_embedded input
  628       assert_xpath '//h2/a[@href="lessons/lesson-1.html"]', output, 1
  629     end
  630   end
  631 
  632   test 'xref using macro syntax' do
  633     doc = document_from_string 'xref:tigers[]'
  634     doc.register :refs, ['tigers', (Asciidoctor::Inline.new doc, :anchor, '[tigers]', type: :ref, target: 'tigers'), '[tigers]']
  635     assert_xpath '//a[@href="#tigers"][text() = "[tigers]"]', doc.convert, 1
  636   end
  637 
  638   test 'multiple xref macros with implicit text in single line' do
  639     input = <<~'EOS'
  640     This document has two sections, xref:sect-a[] and xref:sect-b[].
  641 
  642     [#sect-a]
  643     == Section A
  644 
  645     [#sect-b]
  646     == Section B
  647     EOS
  648     result = convert_string_to_embedded input
  649     assert_xpath '//a[@href="#sect-a"][text() = "Section A"]', result, 1
  650     assert_xpath '//a[@href="#sect-b"][text() = "Section B"]', result, 1
  651   end
  652 
  653   test 'xref using macro syntax with explicit hash' do
  654     doc = document_from_string 'xref:#tigers[]'
  655     doc.register :refs, ['tigers', (Asciidoctor::Inline.new doc, :anchor, 'Tigers', type: :ref, target: 'tigers'), 'Tigers']
  656     assert_xpath '//a[@href="#tigers"][text() = "Tigers"]', doc.convert, 1
  657   end
  658 
  659   test 'xref using macro syntax with label' do
  660     input = <<~'EOS'
  661     xref:tigers[About Tigers]
  662 
  663     [#tigers]
  664     == Tigers
  665     EOS
  666     assert_xpath '//a[@href="#tigers"][text() = "About Tigers"]', convert_string(input), 1
  667   end
  668 
  669   test 'xref using macro syntax inline with text' do
  670     input = <<~'EOS'
  671     Want to learn xref:tigers[about tigers]?
  672 
  673     [#tigers]
  674     == Tigers
  675     EOS
  676 
  677     assert_xpath '//a[@href="#tigers"][text() = "about tigers"]', convert_string(input), 1
  678   end
  679 
  680   test 'xref using macro syntax with multi-line label inline with text' do
  681     input = <<~'EOS'
  682     Want to learn xref:tigers[about
  683     tigers]?
  684 
  685     [#tigers]
  686     == Tigers
  687     EOS
  688     assert_xpath %{//a[@href="#tigers"][normalize-space(text()) = "about tigers"]}, convert_string(input), 1
  689   end
  690 
  691   test 'xref using macro syntax with text that ends with an escaped closing bracket' do
  692     input = <<~'EOS'
  693     xref:tigers[[tigers\]]
  694 
  695     [#tigers]
  696     == Tigers
  697     EOS
  698     assert_xpath '//a[@href="#tigers"][text() = "[tigers]"]', convert_string_to_embedded(input), 1
  699   end
  700 
  701   test 'xref using macro syntax with text that contains an escaped closing bracket' do
  702     input = <<~'EOS'
  703     xref:tigers[[tigers\] are cats]
  704 
  705     [#tigers]
  706     == Tigers
  707     EOS
  708     assert_xpath '//a[@href="#tigers"][text() = "[tigers] are cats"]', convert_string_to_embedded(input), 1
  709   end
  710 
  711   test 'unescapes square bracket in reftext used by xref' do
  712     input = <<~'EOS'
  713     anchor:foo[b[a\]r]about
  714 
  715     see <<foo>>
  716     EOS
  717     result = convert_string_to_embedded input
  718     assert_xpath '//a[@href="#foo"]', result, 1
  719     assert_xpath '//a[@href="#foo"][text()="b[a]r"]', result, 1
  720   end
  721 
  722   test 'xref using invalid macro syntax does not create link' do
  723     doc = document_from_string 'xref:tigers'
  724     doc.register :refs, ['tigers', (Asciidoctor::Inline.new doc, :anchor, 'Tigers', type: :ref, target: 'tigers'), 'Tigers']
  725     assert_xpath '//a', doc.convert, 0
  726   end
  727 
  728   test 'should warn and create link if verbose flag is set and reference is not found' do
  729     input = <<~'EOS'
  730     [#foobar]
  731     == Foobar
  732 
  733     == Section B
  734 
  735     See <<foobaz>>.
  736     EOS
  737     using_memory_logger do |logger|
  738       in_verbose_mode do
  739         output = convert_string_to_embedded input
  740         assert_xpath '//a[@href="#foobaz"][text() = "[foobaz]"]', output, 1
  741         assert_message logger, :INFO, 'possible invalid reference: foobaz'
  742       end
  743     end
  744   end
  745 
  746   test 'should warn and create link if verbose flag is set and reference using # notation is not found' do
  747     input = <<~'EOS'
  748     [#foobar]
  749     == Foobar
  750 
  751     == Section B
  752 
  753     See <<#foobaz>>.
  754     EOS
  755     using_memory_logger do |logger|
  756       in_verbose_mode do
  757         output = convert_string_to_embedded input
  758         assert_xpath '//a[@href="#foobaz"][text() = "[foobaz]"]', output, 1
  759         assert_message logger, :INFO, 'possible invalid reference: foobaz'
  760       end
  761     end
  762   end
  763 
  764   test 'should produce an internal anchor from an inter-document xref to file included into current file' do
  765     input = <<~'EOS'
  766     = Book Title
  767     :doctype: book
  768 
  769     [#ch1]
  770     == Chapter 1
  771 
  772     So it begins.
  773 
  774     Read <<other-chapters.adoc#ch2>> to find out what happens next!
  775 
  776     include::other-chapters.adoc[]
  777     EOS
  778 
  779     doc = document_from_string input, safe: :safe, base_dir: fixturedir
  780     assert doc.catalog[:includes].key?('other-chapters')
  781     assert doc.catalog[:includes]['other-chapters']
  782     output = doc.convert
  783     assert_xpath '//a[@href="#ch2"][text()="Chapter 2"]', output, 1
  784   end
  785 
  786   test 'should produce an internal anchor from an inter-document xref to file included entirely into current file using tags' do
  787     input = <<~'EOS'
  788     = Book Title
  789     :doctype: book
  790 
  791     [#ch1]
  792     == Chapter 1
  793 
  794     So it begins.
  795 
  796     Read <<other-chapters.adoc#ch2>> to find out what happens next!
  797 
  798     include::other-chapters.adoc[tags=**]
  799     EOS
  800 
  801     output = convert_string_to_embedded input, safe: :safe, base_dir: fixturedir
  802     assert_xpath '//a[@href="#ch2"][text()="Chapter 2"]', output, 1
  803   end
  804 
  805   test 'should not produce an internal anchor for inter-document xref to file partially included into current file' do
  806     input = <<~'EOS'
  807     = Book Title
  808     :doctype: book
  809 
  810     [#ch1]
  811     == Chapter 1
  812 
  813     So it begins.
  814 
  815     Read <<other-chapters.adoc#ch2,the next chapter>> to find out what happens next!
  816 
  817     include::other-chapters.adoc[tags=ch2]
  818     EOS
  819 
  820     doc = document_from_string input, safe: :safe, base_dir: fixturedir
  821     assert doc.catalog[:includes].key?('other-chapters')
  822     refute doc.catalog[:includes]['other-chapters']
  823     output = doc.convert
  824     assert_xpath '//a[@href="other-chapters.html#ch2"][text()="the next chapter"]', output, 1
  825   end
  826 
  827   test 'should warn and create link if debug mode is enabled, inter-document xref points to current doc, and reference not found' do
  828     input = <<~'EOS'
  829     [#foobar]
  830     == Foobar
  831 
  832     == Section B
  833 
  834     See <<test.adoc#foobaz>>.
  835     EOS
  836     using_memory_logger do |logger|
  837       in_verbose_mode do
  838         output = convert_string_to_embedded input, attributes: { 'docname' => 'test' }
  839         assert_xpath '//a[@href="#foobaz"][text() = "[foobaz]"]', output, 1
  840         assert_message logger, :INFO, 'possible invalid reference: foobaz'
  841       end
  842     end
  843   end
  844 
  845   test 'should produce an internal anchor for inter-document xref to file outside of base directory' do
  846     input = <<~'EOS'
  847     = Document Title
  848 
  849     See <<../section-a.adoc#section-a>>.
  850 
  851     include::../section-a.adoc[]
  852     EOS
  853 
  854     doc = document_from_string input, safe: :unsafe, base_dir: (File.join fixturedir, 'subdir')
  855     assert_includes doc.catalog[:includes], '../section-a'
  856     output = doc.convert standalone: false
  857     assert_xpath '//a[@href="#section-a"][text()="Section A"]', output, 1
  858   end
  859 
  860   test 'xref uses title of target as label for forward and backward references in html output' do
  861     input = <<~'EOS'
  862     == Section A
  863 
  864     <<_section_b>>
  865 
  866     == Section B
  867 
  868     <<_section_a>>
  869     EOS
  870 
  871     output = convert_string_to_embedded input
  872     assert_xpath '//h2[@id="_section_a"][text()="Section A"]', output, 1
  873     assert_xpath '//a[@href="#_section_a"][text()="Section A"]', output, 1
  874     assert_xpath '//h2[@id="_section_b"][text()="Section B"]', output, 1
  875     assert_xpath '//a[@href="#_section_b"][text()="Section B"]', output, 1
  876   end
  877 
  878   test 'should not fail to resolve broken xref in title of block with ID' do
  879     input = <<~'EOS'
  880     [#p1]
  881     .<<DNE>>
  882     paragraph text
  883     EOS
  884 
  885     output = convert_string_to_embedded input
  886     assert_xpath '//*[@class="title"]/a[@href="#DNE"][text()="[DNE]"]', output, 1
  887   end
  888 
  889   test 'should resolve forward xref in title of block with ID' do
  890     input = <<~'EOS'
  891     [#p1]
  892     .<<conclusion>>
  893     paragraph text
  894 
  895     [#conclusion]
  896     == Conclusion
  897     EOS
  898 
  899     output = convert_string_to_embedded input
  900     assert_xpath '//*[@class="title"]/a[@href="#conclusion"][text()="Conclusion"]', output, 1
  901   end
  902 
  903   test 'should not fail to resolve broken xref in section title' do
  904     input = <<~'EOS'
  905     [#s1]
  906     == <<DNE>>
  907 
  908     == <<s1>>
  909     EOS
  910 
  911     # NOTE this output is nonsensical, but we still need to verify the scenario
  912     output = convert_string_to_embedded input
  913     assert_xpath '//a[@href="#DNE"][text()="[DNE]"]', output, 2
  914   end
  915 
  916   test 'should not resolve forward xref evaluated during parsing' do
  917     input = <<~'EOS'
  918     [#s1]
  919     == <<forward>>
  920 
  921     == <<s1>>
  922 
  923     [#forward]
  924     == Forward
  925     EOS
  926 
  927     output = convert_string_to_embedded input
  928     assert_xpath '//a[@href="#forward"][text()="Forward"]', output, 0
  929   end
  930 
  931   test 'should not resolve forward natural xref evaluated during parsing' do
  932     input = <<~'EOS'
  933     :idprefix:
  934 
  935     [#s1]
  936     == <<Forward>>
  937 
  938     == <<s1>>
  939 
  940     == Forward
  941     EOS
  942 
  943     output = convert_string_to_embedded input
  944     assert_xpath '//a[@href="#forward"][text()="Forward"]', output, 0
  945   end
  946 
  947   test 'should resolve first matching natural xref' do
  948     input = <<~'EOS'
  949     see <<Section Title>>
  950 
  951     [#s1]
  952     == Section Title
  953 
  954     [#s2]
  955     == Section Title
  956     EOS
  957 
  958     output = convert_string_to_embedded input
  959     assert_xpath '//a[@href="#s1"]', output, 1
  960     assert_xpath '//a[@href="#s1"][text()="Section Title"]', output, 1
  961   end
  962 
  963   test 'anchor creates reference' do
  964     doc = document_from_string '[[tigers]]Tigers roam here.'
  965     ref = doc.catalog[:refs]['tigers']
  966     refute_nil ref
  967     assert_nil ref.reftext
  968   end
  969 
  970   test 'anchor with label creates reference' do
  971     doc = document_from_string '[[tigers,Tigers]]Tigers roam here.'
  972     ref = doc.catalog[:refs]['tigers']
  973     refute_nil ref
  974     assert_equal 'Tigers', ref.reftext
  975   end
  976 
  977   test 'anchor with quoted label creates reference with quoted label text' do
  978     doc = document_from_string %([[tigers,"Tigers roam here"]]Tigers roam here.)
  979     ref = doc.catalog[:refs]['tigers']
  980     refute_nil ref
  981     assert_equal '"Tigers roam here"', ref.reftext
  982   end
  983 
  984   test 'anchor with label containing a comma creates reference' do
  985     doc = document_from_string %([[tigers,Tigers, scary tigers, roam here]]Tigers roam here.)
  986     ref = doc.catalog[:refs]['tigers']
  987     refute_nil ref
  988     assert_equal 'Tigers, scary tigers, roam here', ref.reftext
  989   end
  990 end