asciidoctor 1.5.5 → 1.5.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of asciidoctor might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.adoc +216 -1
- data/CONTRIBUTING.adoc +2 -2
- data/Gemfile +20 -1
- data/LICENSE.adoc +1 -1
- data/README-fr.adoc +4 -3
- data/README-jp.adoc +11 -10
- data/README-zh_CN.adoc +4 -3
- data/README.adoc +17 -202
- data/Rakefile +41 -25
- data/asciidoctor.gemspec +9 -10
- data/data/locale/attributes.adoc +216 -34
- data/data/stylesheets/asciidoctor-default.css +23 -16
- data/features/step_definitions.rb +15 -19
- data/features/xref.feature +584 -20
- data/lib/asciidoctor.rb +292 -278
- data/lib/asciidoctor/abstract_block.rb +155 -94
- data/lib/asciidoctor/abstract_node.rb +108 -94
- data/lib/asciidoctor/attribute_list.rb +30 -22
- data/lib/asciidoctor/block.rb +7 -7
- data/lib/asciidoctor/cli/invoker.rb +47 -34
- data/lib/asciidoctor/cli/options.rb +22 -11
- data/lib/asciidoctor/converter.rb +3 -3
- data/lib/asciidoctor/converter/base.rb +2 -2
- data/lib/asciidoctor/converter/composite.rb +1 -1
- data/lib/asciidoctor/converter/docbook45.rb +2 -2
- data/lib/asciidoctor/converter/docbook5.rb +132 -87
- data/lib/asciidoctor/converter/factory.rb +0 -1
- data/lib/asciidoctor/converter/html5.rb +116 -98
- data/lib/asciidoctor/converter/manpage.rb +51 -52
- data/lib/asciidoctor/converter/template.rb +47 -36
- data/lib/asciidoctor/core_ext.rb +8 -2
- data/lib/asciidoctor/core_ext/1.8.7/hash/key.rb +4 -0
- data/lib/asciidoctor/core_ext/1.8.7/io/binread.rb +6 -0
- data/lib/asciidoctor/core_ext/1.8.7/io/write.rb +5 -0
- data/lib/asciidoctor/core_ext/1.8.7/string/chr.rb +1 -1
- data/lib/asciidoctor/core_ext/1.8.7/string/{limit.rb → limit_bytesize.rb} +7 -6
- data/lib/asciidoctor/core_ext/1.8.7/symbol/empty.rb +6 -0
- data/lib/asciidoctor/core_ext/1.8.7/symbol/length.rb +1 -1
- data/lib/asciidoctor/core_ext/nil_or_empty.rb +5 -5
- data/lib/asciidoctor/core_ext/regexp/is_match.rb +3 -0
- data/lib/asciidoctor/core_ext/string/{limit.rb → limit_bytesize.rb} +2 -2
- data/lib/asciidoctor/document.rb +216 -213
- data/lib/asciidoctor/extensions.rb +318 -185
- data/lib/asciidoctor/helpers.rb +35 -35
- data/lib/asciidoctor/inline.rb +32 -1
- data/lib/asciidoctor/list.rb +22 -6
- data/lib/asciidoctor/parser.rb +1008 -1038
- data/lib/asciidoctor/path_resolver.rb +46 -50
- data/lib/asciidoctor/reader.rb +275 -251
- data/lib/asciidoctor/section.rb +86 -58
- data/lib/asciidoctor/stylesheets.rb +6 -6
- data/lib/asciidoctor/substitutors.rb +567 -649
- data/lib/asciidoctor/table.rb +163 -108
- data/lib/asciidoctor/version.rb +1 -1
- data/man/asciidoctor.1 +18 -16
- data/man/asciidoctor.adoc +15 -13
- data/test/attributes_test.rb +138 -22
- data/test/blocks_test.rb +377 -97
- data/test/converter_test.rb +13 -0
- data/test/document_test.rb +244 -34
- data/test/extensions_test.rb +409 -42
- data/test/fixtures/asciidoc_index.txt +521 -0
- data/test/fixtures/basic-docinfo-footer.html +6 -0
- data/test/fixtures/basic-docinfo-footer.xml +8 -0
- data/test/fixtures/basic-docinfo.html +1 -0
- data/test/fixtures/basic-docinfo.xml +4 -0
- data/test/fixtures/basic.asciidoc +5 -0
- data/test/fixtures/chapter-a.adoc +3 -0
- data/test/fixtures/child-include.adoc +5 -0
- data/test/fixtures/circle.svg +9 -0
- data/test/fixtures/custom-backends/erb/html5/block_paragraph.html.erb +6 -0
- data/test/fixtures/custom-backends/haml/docbook45/block_paragraph.xml.haml +6 -0
- data/test/fixtures/custom-backends/haml/html5-tweaks/block_paragraph.html.haml +1 -0
- data/test/fixtures/custom-backends/haml/html5/block_paragraph.html.haml +3 -0
- data/test/fixtures/custom-backends/haml/html5/block_sidebar.html.haml +5 -0
- data/test/fixtures/custom-backends/slim/docbook45/block_paragraph.xml.slim +6 -0
- data/test/fixtures/custom-backends/slim/html5/block_paragraph.html.slim +3 -0
- data/test/fixtures/custom-backends/slim/html5/block_sidebar.html.slim +5 -0
- data/test/fixtures/custom-docinfodir/basic-docinfo.html +1 -0
- data/test/fixtures/custom-docinfodir/docinfo.html +1 -0
- data/test/fixtures/docinfo-footer.html +1 -0
- data/test/fixtures/docinfo-footer.xml +9 -0
- data/test/fixtures/docinfo.html +1 -0
- data/test/fixtures/docinfo.xml +3 -0
- data/test/fixtures/dot.gif +0 -0
- data/test/fixtures/encoding.asciidoc +13 -0
- data/test/fixtures/grandchild-include.adoc +3 -0
- data/test/fixtures/hello-asciidoctor.pdf +69 -0
- data/test/fixtures/include-file.asciidoc +24 -0
- data/test/fixtures/include-file.ml +3 -0
- data/test/fixtures/include-file.xml +5 -0
- data/test/fixtures/master.adoc +5 -0
- data/test/fixtures/mismatched-end-tag.adoc +7 -0
- data/test/fixtures/parent-include-restricted.adoc +5 -0
- data/test/fixtures/parent-include.adoc +5 -0
- data/test/fixtures/sample.asciidoc +26 -0
- data/test/fixtures/stylesheets/custom.css +3 -0
- data/test/fixtures/subs-docinfo.html +2 -0
- data/test/fixtures/subs.adoc +7 -0
- data/test/fixtures/tagged-class-enclosed.rb +26 -0
- data/test/fixtures/tagged-class.rb +23 -0
- data/test/fixtures/tip.gif +0 -0
- data/test/invoker_test.rb +82 -4
- data/test/links_test.rb +312 -37
- data/test/lists_test.rb +204 -25
- data/test/manpage_test.rb +191 -4
- data/test/options_test.rb +18 -1
- data/test/paragraphs_test.rb +32 -7
- data/test/parser_test.rb +150 -30
- data/test/paths_test.rb +47 -13
- data/test/preamble_test.rb +1 -1
- data/test/reader_test.rb +366 -126
- data/test/sections_test.rb +203 -56
- data/test/substitutions_test.rb +339 -131
- data/test/tables_test.rb +315 -15
- data/test/test_helper.rb +400 -0
- data/test/text_test.rb +5 -5
- metadata +110 -22
    
        data/man/asciidoctor.adoc
    CHANGED
    
    | @@ -2,7 +2,7 @@ | |
| 2 2 | 
             
            Dan Allen; Sarah White; Ryan Waldron
         | 
| 3 3 | 
             
            :doctype: manpage
         | 
| 4 4 | 
             
            :man manual: Asciidoctor Manual
         | 
| 5 | 
            -
            :man source: Asciidoctor 1.5. | 
| 5 | 
            +
            :man source: Asciidoctor 1.5.6
         | 
| 6 6 | 
             
            :page-layout: base
         | 
| 7 7 |  | 
| 8 8 | 
             
            == NAME
         | 
| @@ -26,7 +26,7 @@ If _FILE_ is _-_ then the AsciiDoc source is read from standard input. | |
| 26 26 | 
             
            *-B, --base-dir*=_DIR_::
         | 
| 27 27 | 
             
              Base directory containing the document and resources.
         | 
| 28 28 | 
             
              Defaults to the directory containing the source file, or the working directory if the source is read from a stream.
         | 
| 29 | 
            -
               | 
| 29 | 
            +
              When combined with the safe mode setting, can be used to chroot the execution of the program.
         | 
| 30 30 |  | 
| 31 31 | 
             
            *-S, --safe-mode*=_SAFE_MODE_::
         | 
| 32 32 | 
             
              Set safe mode level: _unsafe_, _safe_, _server_ or _secure_.
         | 
| @@ -35,7 +35,7 @@ If _FILE_ is _-_ then the AsciiDoc source is read from standard input. | |
| 35 35 |  | 
| 36 36 | 
             
            *--safe*::
         | 
| 37 37 | 
             
              Set safe mode level to _safe_.
         | 
| 38 | 
            -
              Enables include  | 
| 38 | 
            +
              Enables include directives, but prevents access to ancestor paths of source file.
         | 
| 39 39 | 
             
              Provided for compatibility with the asciidoc command.
         | 
| 40 40 | 
             
              If not set, the safe mode level defaults to _unsafe_ when Asciidoctor is invoked using this script.
         | 
| 41 41 |  | 
| @@ -43,7 +43,7 @@ If _FILE_ is _-_ then the AsciiDoc source is read from standard input. | |
| 43 43 |  | 
| 44 44 | 
             
            *-a, --attribute*=_ATTRIBUTE_::
         | 
| 45 45 | 
             
              Define, override or delete a document attribute.
         | 
| 46 | 
            -
              Command-line attributes take precedence over attributes defined in the source file.
         | 
| 46 | 
            +
              Command-line attributes take precedence over attributes defined in the source file unless the value ends with _@_.
         | 
| 47 47 | 
             
            +
         | 
| 48 48 | 
             
            _ATTRIBUTE_ is normally formatted as a key-value pair, in the form _NAME=VALUE_.
         | 
| 49 49 | 
             
            Alternate acceptable forms are _NAME_ (where the _VALUE_ defaults to an empty string), _NAME!_ (unassigns the _NAME_ attribute) and _NAME=VALUE@_ (where _VALUE_ does not override value of _NAME_ attribute if it's already defined in the source document).
         | 
| @@ -54,14 +54,14 @@ This option may be specified more than once. | |
| 54 54 | 
             
            *-b, --backend*=_BACKEND_::
         | 
| 55 55 | 
             
              Backend output file format: _html5_, _docbook5_, _docbook45_ and _manpage_ are supported out of the box.
         | 
| 56 56 | 
             
              You can also use the backend alias names _html_ (aliased to _html5_) or _docbook_ (aliased to _docbook5_).
         | 
| 57 | 
            +
              Other values can be passed, but if Asciidoctor cannot resolve the backend to a converter, it will fail.
         | 
| 57 58 | 
             
              Defaults to _html5_.
         | 
| 58 | 
            -
              Other options can be passed, but if Asciidoctor cannot find the backend, it will fail during conversion.
         | 
| 59 59 |  | 
| 60 60 | 
             
            *-d, --doctype*=_DOCTYPE_::
         | 
| 61 61 | 
             
              Document type: _article_, _book_, _manpage_ or _inline_.
         | 
| 62 62 | 
             
              Sets the root element when using the _docbook_ backend and the style class on the HTML body element when using the _html_ backend.
         | 
| 63 63 | 
             
              The _book_ document type allows multiple level-0 section titles in a single document.
         | 
| 64 | 
            -
              The _manpage_ document type enables parsing of metadata necessary to produce a  | 
| 64 | 
            +
              The _manpage_ document type enables parsing of metadata necessary to produce a man page.
         | 
| 65 65 | 
             
              The _inline_ document type allows the content of a single paragraph to be formatted and returned without wrapping it in a containing element.
         | 
| 66 66 | 
             
              Defaults to _article_.
         | 
| 67 67 |  | 
| @@ -98,9 +98,9 @@ This option may be specified more than once. | |
| 98 98 | 
             
            *-o, --out-file*=_OUT_FILE_::
         | 
| 99 99 | 
             
              Write output to file _OUT_FILE_.
         | 
| 100 100 | 
             
              Defaults to the base name of the input file suffixed with _backend_ extension.
         | 
| 101 | 
            -
               | 
| 102 | 
            -
              If  | 
| 103 | 
            -
              If  | 
| 101 | 
            +
              The file is resolved relative to the working directory.
         | 
| 102 | 
            +
              If the input is read from standard input or a named pipe (fifo), then the output file defaults to stdout.
         | 
| 103 | 
            +
              If _OUT_FILE_ is _-_, then the output file is written to standard output.
         | 
| 104 104 |  | 
| 105 105 | 
             
            *-r, --require*=_LIBRARY_::
         | 
| 106 106 | 
             
              Require the specified library before executing the processor, using the standard Ruby require.
         | 
| @@ -136,8 +136,10 @@ Matching templates found in subsequent directories override ones previously disc | |
| 136 136 |  | 
| 137 137 | 
             
            === Program Information
         | 
| 138 138 |  | 
| 139 | 
            -
            *-h, --help | 
| 140 | 
            -
               | 
| 139 | 
            +
            *-h, --help* [_TOPIC_]::
         | 
| 140 | 
            +
              Print the help message.
         | 
| 141 | 
            +
              Show the command usage if _TOPIC_ is not specified (or not recognized).
         | 
| 142 | 
            +
              Dump the Asciidoctor man page (in troff/groff format) if _TOPIC_ is _manpage_.
         | 
| 141 143 |  | 
| 142 144 | 
             
            *-V, --version*::
         | 
| 143 145 | 
             
              Print program version number.
         | 
| @@ -146,7 +148,7 @@ Matching templates found in subsequent directories override ones previously disc | |
| 146 148 |  | 
| 147 149 | 
             
            == ENVIRONMENT
         | 
| 148 150 |  | 
| 149 | 
            -
            *Asciidoctor* honors the SOURCE_DATE_EPOCH environment variable.
         | 
| 151 | 
            +
            *Asciidoctor* honors the *SOURCE_DATE_EPOCH* environment variable.
         | 
| 150 152 | 
             
            If this variable is assigned an integer value, that value is used as the epoch of all input documents and as the local date and time.
         | 
| 151 153 | 
             
            See https://reproducible-builds.org/specs/source-date-epoch/ for more information about this environment variable.
         | 
| 152 154 |  | 
| @@ -180,5 +182,5 @@ Refer to the *Asciidoctor* issue tracker at https://github.com/asciidoctor/ascii | |
| 180 182 |  | 
| 181 183 | 
             
            == COPYING
         | 
| 182 184 |  | 
| 183 | 
            -
            Copyright \(C) 2012- | 
| 185 | 
            +
            Copyright \(C) 2012-2017 Dan Allen, Ryan Waldron and the Asciidoctor Project.
         | 
| 184 186 | 
             
            Free use of this software is granted under the terms of the MIT License.
         | 
    
        data/test/attributes_test.rb
    CHANGED
    
    | @@ -46,6 +46,16 @@ linus.torvalds@example.com | |
| 46 46 | 
             
                  assert_equal %(Linus Torvalds +\nLinux Hacker +\nlinus.torvalds@example.com), doc.attributes['signature']
         | 
| 47 47 | 
             
                end
         | 
| 48 48 |  | 
| 49 | 
            +
                test 'should allow pass macro to surround a multi-line value that contains line breaks' do
         | 
| 50 | 
            +
                  str = <<-EOS
         | 
| 51 | 
            +
            :signature: pass:a[{author} + \\
         | 
| 52 | 
            +
            {title} + \\
         | 
| 53 | 
            +
            {email}]
         | 
| 54 | 
            +
                  EOS
         | 
| 55 | 
            +
                  doc = document_from_string str, :attributes => { 'author' => 'Linus Torvalds', 'title' => 'Linux Hacker', 'email' => 'linus.torvalds@example.com' }
         | 
| 56 | 
            +
                  assert_equal %(Linus Torvalds +\nLinux Hacker +\nlinus.torvalds@example.com), (doc.attr 'signature')
         | 
| 57 | 
            +
                end
         | 
| 58 | 
            +
             | 
| 49 59 | 
             
                test 'should delete an attribute that ends with !' do
         | 
| 50 60 | 
             
                  doc = document_from_string(":frog: Tanglefoot\n:frog!:")
         | 
| 51 61 | 
             
                  assert_equal nil, doc.attributes['frog']
         | 
| @@ -86,14 +96,25 @@ linus.torvalds@example.com | |
| 86 96 | 
             
                  assert_equal 'Asciidoctor 1.0', doc.attributes['release']
         | 
| 87 97 | 
             
                end
         | 
| 88 98 |  | 
| 89 | 
            -
                test  | 
| 90 | 
            -
                   | 
| 99 | 
            +
                test 'assigns attribute to empty string if substitution fails to resolve attribute' do
         | 
| 100 | 
            +
                  input = ':release: Asciidoctor {version}'
         | 
| 101 | 
            +
                  doc, warnings = redirect_streams do |_, err|
         | 
| 102 | 
            +
                    [(document_from_string input, :attributes => { 'attribute-missing' => 'drop-line' }), err.string]
         | 
| 103 | 
            +
                  end
         | 
| 91 104 | 
             
                  assert_equal '', doc.attributes['release']
         | 
| 105 | 
            +
                  assert_includes warnings, 'dropping line containing reference to missing attribute'
         | 
| 92 106 | 
             
                end
         | 
| 93 107 |  | 
| 94 | 
            -
                test  | 
| 95 | 
            -
                   | 
| 108 | 
            +
                test 'assigns multi-line attribute to empty string if substitution fails to resolve attribute' do
         | 
| 109 | 
            +
                  input = <<-EOS
         | 
| 110 | 
            +
            :release: Asciidoctor +
         | 
| 111 | 
            +
                      {version}
         | 
| 112 | 
            +
                  EOS
         | 
| 113 | 
            +
                  doc, warnings = redirect_streams do |_, err|
         | 
| 114 | 
            +
                    [(document_from_string input, :attributes => { 'attribute-missing' => 'drop-line' }), err.string]
         | 
| 115 | 
            +
                  end
         | 
| 96 116 | 
             
                  assert_equal '', doc.attributes['release']
         | 
| 117 | 
            +
                  assert_includes warnings, 'dropping line containing reference to missing attribute'
         | 
| 97 118 | 
             
                end
         | 
| 98 119 |  | 
| 99 120 | 
             
                test 'resolves attributes inside attribute value within header' do
         | 
| @@ -213,6 +234,13 @@ EOS | |
| 213 234 | 
             
                  assert_equal '<>&', doc.attributes['xml-busters']
         | 
| 214 235 | 
             
                end
         | 
| 215 236 |  | 
| 237 | 
            +
                test 'should not recognize pass macro with invalid substitution list in attribute value' do
         | 
| 238 | 
            +
                  [',', '42', 'a,'].each do |subs|
         | 
| 239 | 
            +
                    doc = document_from_string %(:pass-fail: pass:#{subs}[whale])
         | 
| 240 | 
            +
                    assert_equal %(pass:#{subs}[whale]), doc.attributes['pass-fail']
         | 
| 241 | 
            +
                  end
         | 
| 242 | 
            +
                end
         | 
| 243 | 
            +
             | 
| 216 244 | 
             
                test "attribute is treated as defined until it's not" do
         | 
| 217 245 | 
             
                  input = <<-EOS
         | 
| 218 246 | 
             
            :holygrail:
         | 
| @@ -350,6 +378,19 @@ content | |
| 350 378 | 
             
                  assert doc.attributes.has_key? 'basebackend-html'
         | 
| 351 379 | 
             
                end
         | 
| 352 380 |  | 
| 381 | 
            +
                test 'set_attr should set value to empty string if no value is specified' do
         | 
| 382 | 
            +
                  node = Asciidoctor::Block.new nil, :paragraph, :attributes => {}
         | 
| 383 | 
            +
                  node.set_attr 'foo'
         | 
| 384 | 
            +
                  assert_equal '', (node.attr 'foo')
         | 
| 385 | 
            +
                end
         | 
| 386 | 
            +
             | 
| 387 | 
            +
                test 'remove_attr should remove attribute and return previous value' do
         | 
| 388 | 
            +
                  doc = empty_document
         | 
| 389 | 
            +
                  node = Asciidoctor::Block.new doc, :paragraph, :attributes => { 'foo' => 'bar' }
         | 
| 390 | 
            +
                  assert_equal 'bar', (node.remove_attr 'foo')
         | 
| 391 | 
            +
                  assert_nil node.attr('foo')
         | 
| 392 | 
            +
                end
         | 
| 393 | 
            +
             | 
| 353 394 | 
             
                test 'set_attr should not overwrite existing key if overwrite is false' do
         | 
| 354 395 | 
             
                  node = Asciidoctor::Block.new nil, :paragraph, :attributes => { 'foo' => 'bar' }
         | 
| 355 396 | 
             
                  assert_equal 'bar', (node.attr 'foo')
         | 
| @@ -377,6 +418,31 @@ content | |
| 377 418 | 
             
                  assert_xpath '//a[@href="https://google.com"]', output, 1
         | 
| 378 419 | 
             
                end
         | 
| 379 420 |  | 
| 421 | 
            +
                test 'set_attribute should set attribute if key is not locked' do
         | 
| 422 | 
            +
                  doc = empty_document
         | 
| 423 | 
            +
                  assert !(doc.attr? 'foo')
         | 
| 424 | 
            +
                  res = doc.set_attribute 'foo', 'baz'
         | 
| 425 | 
            +
                  assert res
         | 
| 426 | 
            +
                  assert_equal 'baz', (doc.attr 'foo')
         | 
| 427 | 
            +
                end
         | 
| 428 | 
            +
             | 
| 429 | 
            +
                test 'set_attribute should not set key if key is locked' do
         | 
| 430 | 
            +
                  doc = empty_document :attributes => { 'foo' => 'bar' }
         | 
| 431 | 
            +
                  assert_equal 'bar', (doc.attr 'foo')
         | 
| 432 | 
            +
                  res = doc.set_attribute 'foo', 'baz'
         | 
| 433 | 
            +
                  assert !res
         | 
| 434 | 
            +
                  assert_equal 'bar', (doc.attr 'foo')
         | 
| 435 | 
            +
                end
         | 
| 436 | 
            +
             | 
| 437 | 
            +
                test 'set_attribute should update backend attributes' do
         | 
| 438 | 
            +
                  doc = empty_document :attributes => { 'backend' => 'html5@' }
         | 
| 439 | 
            +
                  assert_equal '', (doc.attr 'backend-html5')
         | 
| 440 | 
            +
                  res = doc.set_attribute 'backend', 'docbook5'
         | 
| 441 | 
            +
                  assert res
         | 
| 442 | 
            +
                  assert !(doc.attr? 'backend-html5')
         | 
| 443 | 
            +
                  assert_equal '', (doc.attr 'backend-docbook5')
         | 
| 444 | 
            +
                end
         | 
| 445 | 
            +
             | 
| 380 446 | 
             
                test 'verify toc attribute matrix' do
         | 
| 381 447 | 
             
                  expected_data = <<-EOS
         | 
| 382 448 | 
             
            #attributes                               |toc|toc-position|toc-placement|toc-class
         | 
| @@ -399,7 +465,7 @@ toc toc-placement!                        |   |content     |macro        |nil | |
| 399 465 |  | 
| 400 466 | 
             
                  expected.each do |expect|
         | 
| 401 467 | 
             
                    raw_attrs, toc, toc_position, toc_placement, toc_class = expect
         | 
| 402 | 
            -
                    attrs = Hash[* | 
| 468 | 
            +
                    attrs = Hash[*raw_attrs.split.map {|e| e.include?('=') ? e.split('=', 2) : [e, ''] }.flatten]
         | 
| 403 469 | 
             
                    doc = document_from_string '', :attributes => attrs
         | 
| 404 470 | 
             
                    toc ? (assert doc.attr?('toc', toc)) : (assert !doc.attr?('toc'))
         | 
| 405 471 | 
             
                    toc_position ? (assert doc.attr?('toc-position', toc_position)) : (assert !doc.attr?('toc-position'))
         | 
| @@ -448,7 +514,7 @@ Yo, {myfrog}! | |
| 448 514 | 
             
                  assert_xpath '(//p)[1][text()="Yo, Tanglefoot!"]', output, 1
         | 
| 449 515 | 
             
                end
         | 
| 450 516 |  | 
| 451 | 
            -
                test  | 
| 517 | 
            +
                test 'ignores lines with bad attributes if attribute-missing is drop-line' do
         | 
| 452 518 | 
             
                  input = <<-EOS
         | 
| 453 519 | 
             
            :attribute-missing: drop-line
         | 
| 454 520 |  | 
| @@ -456,9 +522,10 @@ This is | |
| 456 522 | 
             
            blah blah {foobarbaz}
         | 
| 457 523 | 
             
            all there is.
         | 
| 458 524 | 
             
                  EOS
         | 
| 459 | 
            -
                   | 
| 460 | 
            -
                   | 
| 461 | 
            -
                   | 
| 525 | 
            +
                  output, warnings = redirect_streams {|_, err| [(render_embedded_string input), err.string] }
         | 
| 526 | 
            +
                  para = xmlnodes_at_css 'p', output, 1
         | 
| 527 | 
            +
                  refute_includes 'blah blah', para.content
         | 
| 528 | 
            +
                  assert_includes warnings, 'dropping line containing reference to missing attribute'
         | 
| 462 529 | 
             
                end
         | 
| 463 530 |  | 
| 464 531 | 
             
                test "attribute value gets interpretted when rendering" do
         | 
| @@ -476,9 +543,10 @@ Line 1: This line should appear in the output. | |
| 476 543 | 
             
            Line 2: Oh no, a {bogus-attribute}! This line should not appear in the output.
         | 
| 477 544 | 
             
                  EOS
         | 
| 478 545 |  | 
| 479 | 
            -
                  output = render_embedded_string input
         | 
| 546 | 
            +
                  output, warnings = redirect_streams {|_, err| [(render_embedded_string input), err.string] }
         | 
| 480 547 | 
             
                  assert_match(/Line 1/, output)
         | 
| 481 548 | 
             
                  refute_match(/Line 2/, output)
         | 
| 549 | 
            +
                  assert_includes warnings, 'dropping line containing reference to missing attribute'
         | 
| 482 550 | 
             
                end
         | 
| 483 551 |  | 
| 484 552 | 
             
                test 'should not drop line with reference to missing attribute by default' do
         | 
| @@ -512,7 +580,7 @@ Line 2: {set:a!}This line should not appear in the output. | |
| 512 580 | 
             
            :a:
         | 
| 513 581 |  | 
| 514 582 | 
             
            Line 1: This line should appear in the output.
         | 
| 515 | 
            -
            Line 2: {set:a!}This line should  | 
| 583 | 
            +
            Line 2: {set:a!}This line should appear in the output.
         | 
| 516 584 | 
             
                  EOS
         | 
| 517 585 |  | 
| 518 586 | 
             
                  output = render_embedded_string input
         | 
| @@ -748,7 +816,7 @@ of the attribute named foo in your document. | |
| 748 816 | 
             
            {set:foo!}
         | 
| 749 817 | 
             
            {foo}yes
         | 
| 750 818 | 
             
                  EOS
         | 
| 751 | 
            -
                  output = render_embedded_string input
         | 
| 819 | 
            +
                  output = redirect_streams { render_embedded_string input }
         | 
| 752 820 | 
             
                  assert_xpath '//p', output, 1
         | 
| 753 821 | 
             
                  assert_xpath '//p/child::text()', output, 0
         | 
| 754 822 | 
             
                end
         | 
| @@ -878,6 +946,34 @@ after: {counter:mycounter} | |
| 878 946 | 
             
                  assert_xpath '//p[text()="before: 1 2 3"]', output, 1
         | 
| 879 947 | 
             
                  assert_xpath '//p[text()="after: 1"]', output, 1
         | 
| 880 948 | 
             
                end
         | 
| 949 | 
            +
             | 
| 950 | 
            +
                test 'nested document should use counter from parent document' do
         | 
| 951 | 
            +
                  input = <<-EOS
         | 
| 952 | 
            +
            .Title for Foo
         | 
| 953 | 
            +
            image::foo.jpg[]
         | 
| 954 | 
            +
             | 
| 955 | 
            +
            [cols="2*a"]
         | 
| 956 | 
            +
            |===
         | 
| 957 | 
            +
            |
         | 
| 958 | 
            +
            .Title for Bar
         | 
| 959 | 
            +
            image::bar.jpg[]
         | 
| 960 | 
            +
             | 
| 961 | 
            +
            |
         | 
| 962 | 
            +
            .Title for Baz
         | 
| 963 | 
            +
            image::baz.jpg[]
         | 
| 964 | 
            +
            |===
         | 
| 965 | 
            +
             | 
| 966 | 
            +
            .Title for Qux
         | 
| 967 | 
            +
            image::qux.jpg[]
         | 
| 968 | 
            +
                  EOS
         | 
| 969 | 
            +
             | 
| 970 | 
            +
                  output = render_embedded_string input
         | 
| 971 | 
            +
                  assert_xpath '//div[@class="title"]', output, 4
         | 
| 972 | 
            +
                  assert_xpath '//div[@class="title"][text() = "Figure 1. Title for Foo"]', output, 1
         | 
| 973 | 
            +
                  assert_xpath '//div[@class="title"][text() = "Figure 2. Title for Bar"]', output, 1
         | 
| 974 | 
            +
                  assert_xpath '//div[@class="title"][text() = "Figure 3. Title for Baz"]', output, 1
         | 
| 975 | 
            +
                  assert_xpath '//div[@class="title"][text() = "Figure 4. Title for Qux"]', output, 1
         | 
| 976 | 
            +
                end
         | 
| 881 977 | 
             
              end
         | 
| 882 978 |  | 
| 883 979 | 
             
              context 'Block attributes' do
         | 
| @@ -952,7 +1048,7 @@ content | |
| 952 1048 | 
             
                  assert_xpath '//*[@class="title"]/strong[text()="title"]', output, 1
         | 
| 953 1049 | 
             
                end
         | 
| 954 1050 |  | 
| 955 | 
            -
                test 'attribute list may begin with space' do
         | 
| 1051 | 
            +
                test 'attribute list may not begin with space' do
         | 
| 956 1052 | 
             
                  input = <<-EOS
         | 
| 957 1053 | 
             
            [ quote]
         | 
| 958 1054 | 
             
            ____
         | 
| @@ -961,8 +1057,8 @@ ____ | |
| 961 1057 | 
             
                  EOS
         | 
| 962 1058 |  | 
| 963 1059 | 
             
                  doc = document_from_string input
         | 
| 964 | 
            -
                   | 
| 965 | 
            -
                  assert_equal 'quote',  | 
| 1060 | 
            +
                  b1 = doc.blocks.first
         | 
| 1061 | 
            +
                  assert_equal ['[ quote]'], b1.lines
         | 
| 966 1062 | 
             
                end
         | 
| 967 1063 |  | 
| 968 1064 | 
             
                test 'attribute list may begin with comma' do
         | 
| @@ -1125,7 +1221,8 @@ A normal paragraph | |
| 1125 1221 | 
             
                    EOS
         | 
| 1126 1222 | 
             
                  doc = document_from_string(input)
         | 
| 1127 1223 | 
             
                  para = doc.blocks.first
         | 
| 1128 | 
            -
                  para.add_role 'role1'
         | 
| 1224 | 
            +
                  res = para.add_role 'role1'
         | 
| 1225 | 
            +
                  assert res
         | 
| 1129 1226 | 
             
                  assert_equal 'role1', para.attributes['role']
         | 
| 1130 1227 | 
             
                  assert para.has_role? 'role1'
         | 
| 1131 1228 | 
             
                end
         | 
| @@ -1137,7 +1234,8 @@ A normal paragraph | |
| 1137 1234 | 
             
                    EOS
         | 
| 1138 1235 | 
             
                  doc = document_from_string(input)
         | 
| 1139 1236 | 
             
                  para = doc.blocks.first
         | 
| 1140 | 
            -
                  para.add_role 'role2'
         | 
| 1237 | 
            +
                  res = para.add_role 'role2'
         | 
| 1238 | 
            +
                  assert res
         | 
| 1141 1239 | 
             
                  assert_equal 'role1 role2', para.attributes['role']
         | 
| 1142 1240 | 
             
                  assert para.has_role? 'role1'
         | 
| 1143 1241 | 
             
                  assert para.has_role? 'role2'
         | 
| @@ -1150,7 +1248,8 @@ A normal paragraph | |
| 1150 1248 | 
             
                    EOS
         | 
| 1151 1249 | 
             
                  doc = document_from_string(input)
         | 
| 1152 1250 | 
             
                  para = doc.blocks.first
         | 
| 1153 | 
            -
                  para.add_role 'role1'
         | 
| 1251 | 
            +
                  res = para.add_role 'role1'
         | 
| 1252 | 
            +
                  refute res
         | 
| 1154 1253 | 
             
                  assert_equal 'role1', para.attributes['role']
         | 
| 1155 1254 | 
             
                  assert para.has_role? 'role1'
         | 
| 1156 1255 | 
             
                end
         | 
| @@ -1162,12 +1261,27 @@ A normal paragraph | |
| 1162 1261 | 
             
                    EOS
         | 
| 1163 1262 | 
             
                  doc = document_from_string(input)
         | 
| 1164 1263 | 
             
                  para = doc.blocks.first
         | 
| 1165 | 
            -
                  para.remove_role 'role1'
         | 
| 1264 | 
            +
                  res = para.remove_role 'role1'
         | 
| 1265 | 
            +
                  assert res
         | 
| 1166 1266 | 
             
                  assert_equal 'role2', para.attributes['role']
         | 
| 1167 1267 | 
             
                  assert para.has_role? 'role2'
         | 
| 1168 1268 | 
             
                  assert !para.has_role?('role1')
         | 
| 1169 1269 | 
             
                end
         | 
| 1170 1270 |  | 
| 1271 | 
            +
                test 'roles are removed when last role is removed using remove_role' do
         | 
| 1272 | 
            +
                    input = <<-EOS
         | 
| 1273 | 
            +
            [.role1]
         | 
| 1274 | 
            +
            A normal paragraph
         | 
| 1275 | 
            +
                    EOS
         | 
| 1276 | 
            +
                  doc = document_from_string(input)
         | 
| 1277 | 
            +
                  para = doc.blocks.first
         | 
| 1278 | 
            +
                  res = para.remove_role 'role1'
         | 
| 1279 | 
            +
                  assert res
         | 
| 1280 | 
            +
                  refute para.role?
         | 
| 1281 | 
            +
                  assert_equal nil, para.attributes['role']
         | 
| 1282 | 
            +
                  refute para.has_role? 'role1'
         | 
| 1283 | 
            +
                end
         | 
| 1284 | 
            +
             | 
| 1171 1285 | 
             
                test 'roles are not changed when a non-existent role is removed using remove_role' do
         | 
| 1172 1286 | 
             
                    input = <<-EOS
         | 
| 1173 1287 | 
             
            [.role1]
         | 
| @@ -1175,7 +1289,8 @@ A normal paragraph | |
| 1175 1289 | 
             
                    EOS
         | 
| 1176 1290 | 
             
                  doc = document_from_string(input)
         | 
| 1177 1291 | 
             
                  para = doc.blocks.first
         | 
| 1178 | 
            -
                  para.remove_role 'role2'
         | 
| 1292 | 
            +
                  res = para.remove_role 'role2'
         | 
| 1293 | 
            +
                  refute res
         | 
| 1179 1294 | 
             
                  assert_equal 'role1', para.attributes['role']
         | 
| 1180 1295 | 
             
                  assert para.has_role? 'role1'
         | 
| 1181 1296 | 
             
                  assert !para.has_role?('role2')
         | 
| @@ -1187,7 +1302,8 @@ A normal paragraph | |
| 1187 1302 | 
             
                    EOS
         | 
| 1188 1303 | 
             
                  doc = document_from_string(input)
         | 
| 1189 1304 | 
             
                  para = doc.blocks.first
         | 
| 1190 | 
            -
                  para.remove_role 'role1'
         | 
| 1305 | 
            +
                  res = para.remove_role 'role1'
         | 
| 1306 | 
            +
                  refute res
         | 
| 1191 1307 | 
             
                  assert_equal nil, para.attributes['role']
         | 
| 1192 1308 | 
             
                  assert !para.has_role?('role1')
         | 
| 1193 1309 | 
             
                end
         | 
| @@ -1265,7 +1381,7 @@ paragraph | |
| 1265 1381 | 
             
                  assert_equal 'coolio', subsec.id
         | 
| 1266 1382 | 
             
                end
         | 
| 1267 1383 |  | 
| 1268 | 
            -
                test "trailing block attributes  | 
| 1384 | 
            +
                test "trailing block attributes transfer to the following section" do
         | 
| 1269 1385 | 
             
                  input = <<-EOS
         | 
| 1270 1386 | 
             
            [[one]]
         | 
| 1271 1387 |  | 
    
        data/test/blocks_test.rb
    CHANGED
    
    | @@ -5,22 +5,39 @@ unless defined? ASCIIDOCTOR_PROJECT_DIR | |
| 5 5 | 
             
            end
         | 
| 6 6 |  | 
| 7 7 | 
             
            context "Blocks" do
         | 
| 8 | 
            -
              context ' | 
| 9 | 
            -
                test  | 
| 10 | 
            -
                   | 
| 11 | 
            -
             | 
| 12 | 
            -
             | 
| 8 | 
            +
              context 'Layout Breaks' do
         | 
| 9 | 
            +
                test 'horizontal rule' do
         | 
| 10 | 
            +
                  %w(''' '''' '''''').each do |line|
         | 
| 11 | 
            +
                    output = render_embedded_string line
         | 
| 12 | 
            +
                    assert_includes output, '<hr>'
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                test '< 3 chars does not make horizontal rule' do
         | 
| 17 | 
            +
                  %w(' '').each do |line|
         | 
| 18 | 
            +
                    output = render_embedded_string line
         | 
| 19 | 
            +
                    refute_includes output, '<hr>'
         | 
| 20 | 
            +
                    assert_includes output, %(<p>#{line}</p>)
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                test 'mixed chars does not make horizontal rule' do
         | 
| 25 | 
            +
                  [%q(''<), %q('''<), %q(' ' ')].each do |line|
         | 
| 26 | 
            +
                    output = render_embedded_string line
         | 
| 27 | 
            +
                    refute_includes output, '<hr>'
         | 
| 28 | 
            +
                    assert_includes output, %(<p>#{line.sub '<', '<'}</p>)
         | 
| 29 | 
            +
                  end
         | 
| 13 30 | 
             
                end
         | 
| 14 31 |  | 
| 15 | 
            -
                test  | 
| 16 | 
            -
                  output =  | 
| 17 | 
            -
                  assert_xpath ' | 
| 18 | 
            -
                  assert_xpath ' | 
| 19 | 
            -
                  assert_xpath ' | 
| 32 | 
            +
                test 'horizontal rule between blocks' do
         | 
| 33 | 
            +
                  output = render_embedded_string %(Block above\n\n'''\n\nBlock below)
         | 
| 34 | 
            +
                  assert_xpath '/hr', output, 1
         | 
| 35 | 
            +
                  assert_xpath '/hr/preceding-sibling::*', output, 1
         | 
| 36 | 
            +
                  assert_xpath '/hr/following-sibling::*', output, 1
         | 
| 20 37 | 
             
                end
         | 
| 21 38 |  | 
| 22 | 
            -
                test  | 
| 23 | 
            -
                  output = render_embedded_string( | 
| 39 | 
            +
                test 'page break' do
         | 
| 40 | 
            +
                  output = render_embedded_string %(page 1\n\n<<<\n\npage 2)
         | 
| 24 41 | 
             
                  assert_xpath '/*[translate(@style, ";", "")="page-break-after: always"]', output, 1
         | 
| 25 42 | 
             
                  assert_xpath '/*[translate(@style, ";", "")="page-break-after: always"]/preceding-sibling::div/p[text()="page 1"]', output, 1
         | 
| 26 43 | 
             
                  assert_xpath '/*[translate(@style, ";", "")="page-break-after: always"]/following-sibling::div/p[text()="page 2"]', output, 1
         | 
| @@ -254,7 +271,7 @@ ____ | |
| 254 271 | 
             
                  assert_xpath '//*[@class = "quoteblock"]/*[@class = "attribution"]/cite[text() = "Famous Book (1999)"]', output, 1
         | 
| 255 272 | 
             
                  attribution = xmlnodes_at_xpath '//*[@class = "quoteblock"]/*[@class = "attribution"]', output, 1
         | 
| 256 273 | 
             
                  author = attribution.children.first
         | 
| 257 | 
            -
                  assert_equal "#{ | 
| 274 | 
            +
                  assert_equal "#{decode_char 8212} Famous Person", author.text.strip
         | 
| 258 275 | 
             
                end
         | 
| 259 276 |  | 
| 260 277 | 
             
                test 'quote block with attribute and id and role shorthand' do
         | 
| @@ -374,7 +391,7 @@ Some more inspiring words. | |
| 374 391 | 
             
                  assert_xpath '//*[@class = "quoteblock"]/*[@class = "attribution"]/cite[text() = "Famous Source, Volume 1 (1999)"]', output, 1
         | 
| 375 392 | 
             
                  attribution = xmlnodes_at_xpath '//*[@class = "quoteblock"]/*[@class = "attribution"]', output, 1
         | 
| 376 393 | 
             
                  author = attribution.children.first
         | 
| 377 | 
            -
                  assert_equal "#{ | 
| 394 | 
            +
                  assert_equal "#{decode_char 8212} Famous Person", author.text.strip
         | 
| 378 395 | 
             
                end
         | 
| 379 396 |  | 
| 380 397 | 
             
                test 'quoted paragraph-style quote block with attribution' do
         | 
| @@ -393,7 +410,7 @@ Some more inspiring words." | |
| 393 410 | 
             
                  assert_xpath '//*[@class = "quoteblock"]/*[@class = "attribution"]/cite[text() = "Famous Source, Volume 1 (1999)"]', output, 1
         | 
| 394 411 | 
             
                  attribution = xmlnodes_at_xpath '//*[@class = "quoteblock"]/*[@class = "attribution"]', output, 1
         | 
| 395 412 | 
             
                  author = attribution.children.first
         | 
| 396 | 
            -
                  assert_equal "#{ | 
| 413 | 
            +
                  assert_equal "#{decode_char 8212} Famous Person", author.text.strip
         | 
| 397 414 | 
             
                end
         | 
| 398 415 |  | 
| 399 416 | 
             
                test 'single-line verse block without attribution' do
         | 
| @@ -428,7 +445,7 @@ ____ | |
| 428 445 | 
             
                  assert_xpath '//*[@class = "verseblock"]/*[@class = "attribution"]/cite[text() = "Famous Poem"]', output, 1
         | 
| 429 446 | 
             
                  attribution = xmlnodes_at_xpath '//*[@class = "verseblock"]/*[@class = "attribution"]', output, 1
         | 
| 430 447 | 
             
                  author = attribution.children.first
         | 
| 431 | 
            -
                  assert_equal "#{ | 
| 448 | 
            +
                  assert_equal "#{decode_char 8212} Famous Poet", author.text.strip
         | 
| 432 449 | 
             
                end
         | 
| 433 450 |  | 
| 434 451 | 
             
                test 'multi-stanza verse block' do
         | 
| @@ -475,7 +492,7 @@ ____ | |
| 475 492 | 
             
                  EOS
         | 
| 476 493 |  | 
| 477 494 | 
             
                  verse = block_from_string input
         | 
| 478 | 
            -
                  assert_equal Asciidoctor::Substitutors:: | 
| 495 | 
            +
                  assert_equal Asciidoctor::Substitutors::NORMAL_SUBS, verse.subs
         | 
| 479 496 | 
             
                end
         | 
| 480 497 |  | 
| 481 498 | 
             
                test 'should not recognize callouts in a verse' do
         | 
| @@ -487,8 +504,9 @@ ____ | |
| 487 504 | 
             
            <1> Not pointing to a callout
         | 
| 488 505 | 
             
                  EOS
         | 
| 489 506 |  | 
| 490 | 
            -
                  output = render_embedded_string input
         | 
| 507 | 
            +
                  output, warnings = redirect_streams {|_, err| [(render_embedded_string input), err.string] }
         | 
| 491 508 | 
             
                  assert_xpath '//pre[text()="La la la <1>"]', output, 1
         | 
| 509 | 
            +
                  assert_includes warnings, 'line 5: no callouts refer to list item 1'
         | 
| 492 510 | 
             
                end
         | 
| 493 511 |  | 
| 494 512 | 
             
                test 'should perform normal subs on a verse block' do
         | 
| @@ -536,6 +554,8 @@ You futz with XML. | |
| 536 554 | 
             
                  EOS
         | 
| 537 555 |  | 
| 538 556 | 
             
                  doc = document_from_string input
         | 
| 557 | 
            +
                  assert_equal 1, doc.blocks[0].number
         | 
| 558 | 
            +
                  assert_equal 2, doc.blocks[1].number
         | 
| 539 559 | 
             
                  output = doc.render
         | 
| 540 560 | 
             
                  assert_xpath '(//*[@class="exampleblock"])[1]/*[@class="title"][text()="Example 1. Writing Docs with AsciiDoc"]', output, 1
         | 
| 541 561 | 
             
                  assert_xpath '(//*[@class="exampleblock"])[2]/*[@class="title"][text()="Example 2. Writing Docs with DocBook"]', output, 1
         | 
| @@ -562,6 +582,8 @@ You futz with XML. | |
| 562 582 | 
             
                  EOS
         | 
| 563 583 |  | 
| 564 584 | 
             
                  doc = document_from_string input
         | 
| 585 | 
            +
                  assert_equal 'A', doc.blocks[0].number
         | 
| 586 | 
            +
                  assert_equal 'B', doc.blocks[1].number
         | 
| 565 587 | 
             
                  output = doc.render
         | 
| 566 588 | 
             
                  assert_xpath '(//*[@class="exampleblock"])[1]/*[@class="title"][text()="Example A. Writing Docs with AsciiDoc"]', output, 1
         | 
| 567 589 | 
             
                  assert_xpath '(//*[@class="exampleblock"])[2]/*[@class="title"][text()="Example B. Writing Docs with DocBook"]', output, 1
         | 
| @@ -580,25 +602,12 @@ You just write. | |
| 580 602 | 
             
                  EOS
         | 
| 581 603 |  | 
| 582 604 | 
             
                  doc = document_from_string input
         | 
| 605 | 
            +
                  assert_nil doc.blocks[0].number
         | 
| 583 606 | 
             
                  output = doc.render
         | 
| 584 607 | 
             
                  assert_xpath '(//*[@class="exampleblock"])[1]/*[@class="title"][text()="Look! Writing Docs with AsciiDoc"]', output, 1
         | 
| 585 608 | 
             
                  assert !doc.attributes.has_key?('example-number')
         | 
| 586 609 | 
             
                end
         | 
| 587 610 |  | 
| 588 | 
            -
                test 'explicit caption is set on block even if block has no title' do
         | 
| 589 | 
            -
                  input = <<-EOS
         | 
| 590 | 
            -
            [caption="Look!"]
         | 
| 591 | 
            -
            ====
         | 
| 592 | 
            -
            Just write.
         | 
| 593 | 
            -
            ====
         | 
| 594 | 
            -
                  EOS
         | 
| 595 | 
            -
             | 
| 596 | 
            -
                  doc = document_from_string input
         | 
| 597 | 
            -
                  assert_equal 'Look!', doc.blocks.first.caption
         | 
| 598 | 
            -
                  output = doc.render
         | 
| 599 | 
            -
                  refute_match(/Look/, output)
         | 
| 600 | 
            -
                end
         | 
| 601 | 
            -
             | 
| 602 611 | 
             
                test 'automatic caption can be turned off and on and modified' do
         | 
| 603 612 | 
             
                  input = <<-EOS
         | 
| 604 613 | 
             
            .first example
         | 
| @@ -802,7 +811,7 @@ source line 2\r | |
| 802 811 | 
             
            ----
         | 
| 803 812 | 
             
                def names
         | 
| 804 813 |  | 
| 805 | 
            -
                  @names.split | 
| 814 | 
            +
                  @names.split
         | 
| 806 815 |  | 
| 807 816 | 
             
                end
         | 
| 808 817 | 
             
            ----
         | 
| @@ -811,7 +820,7 @@ source line 2\r | |
| 811 820 | 
             
                  expected = <<-EOS
         | 
| 812 821 | 
             
            def names
         | 
| 813 822 |  | 
| 814 | 
            -
              @names.split | 
| 823 | 
            +
              @names.split
         | 
| 815 824 |  | 
| 816 825 | 
             
            end
         | 
| 817 826 | 
             
                  EOS
         | 
| @@ -829,7 +838,7 @@ end | |
| 829 838 | 
             
            ----
         | 
| 830 839 | 
             
                def names
         | 
| 831 840 |  | 
| 832 | 
            -
                  @names.split | 
| 841 | 
            +
                  @names.split
         | 
| 833 842 |  | 
| 834 843 | 
             
                end
         | 
| 835 844 | 
             
            ----
         | 
| @@ -838,7 +847,7 @@ end | |
| 838 847 | 
             
                  expected = <<-EOS
         | 
| 839 848 | 
             
                def names
         | 
| 840 849 |  | 
| 841 | 
            -
                  @names.split | 
| 850 | 
            +
                  @names.split
         | 
| 842 851 |  | 
| 843 852 | 
             
                end
         | 
| 844 853 | 
             
                  EOS
         | 
| @@ -856,7 +865,7 @@ end | |
| 856 865 | 
             
            ----
         | 
| 857 866 | 
             
                def names
         | 
| 858 867 |  | 
| 859 | 
            -
                  @names.split | 
| 868 | 
            +
                  @names.split
         | 
| 860 869 |  | 
| 861 870 | 
             
                end
         | 
| 862 871 | 
             
            ----
         | 
| @@ -865,7 +874,7 @@ end | |
| 865 874 | 
             
                  expected = <<-EOS
         | 
| 866 875 | 
             
             def names
         | 
| 867 876 |  | 
| 868 | 
            -
               @names.split | 
| 877 | 
            +
               @names.split
         | 
| 869 878 |  | 
| 870 879 | 
             
             end
         | 
| 871 880 | 
             
                  EOS
         | 
| @@ -885,7 +894,7 @@ end | |
| 885 894 | 
             
            ----
         | 
| 886 895 | 
             
                def names
         | 
| 887 896 |  | 
| 888 | 
            -
                  @names.split | 
| 897 | 
            +
                  @names.split
         | 
| 889 898 |  | 
| 890 899 | 
             
                end
         | 
| 891 900 | 
             
            ----
         | 
| @@ -894,7 +903,7 @@ end | |
| 894 903 | 
             
                  expected = <<-EOS
         | 
| 895 904 | 
             
             def names
         | 
| 896 905 |  | 
| 897 | 
            -
               @names.split | 
| 906 | 
            +
               @names.split
         | 
| 898 907 |  | 
| 899 908 | 
             
             end
         | 
| 900 909 | 
             
                  EOS
         | 
| @@ -914,7 +923,7 @@ end | |
| 914 923 | 
             
            ----
         | 
| 915 924 | 
             
            	def names
         | 
| 916 925 |  | 
| 917 | 
            -
            		@names.split | 
| 926 | 
            +
            		@names.split
         | 
| 918 927 |  | 
| 919 928 | 
             
            	end
         | 
| 920 929 | 
             
            ----
         | 
| @@ -923,7 +932,7 @@ end | |
| 923 932 | 
             
                  expected = <<-EOS
         | 
| 924 933 | 
             
            def names
         | 
| 925 934 |  | 
| 926 | 
            -
                @names.split | 
| 935 | 
            +
                @names.split
         | 
| 927 936 |  | 
| 928 937 | 
             
            end
         | 
| 929 938 | 
             
                  EOS
         | 
| @@ -1212,7 +1221,7 @@ line below | |
| 1212 1221 |  | 
| 1213 1222 | 
             
                  output = render_embedded_string input
         | 
| 1214 1223 | 
             
                  assert_css '.stemblock', output, 1
         | 
| 1215 | 
            -
                  nodes = xmlnodes_at_xpath '//*[@class="content"]/child::text()', output | 
| 1224 | 
            +
                  nodes = xmlnodes_at_xpath '//*[@class="content"]/child::text()', output
         | 
| 1216 1225 | 
             
                  assert_equal '\[\sqrt{3x-1}+(1+x)^2 < y\]', nodes.first.to_s.strip
         | 
| 1217 1226 | 
             
                end
         | 
| 1218 1227 |  | 
| @@ -1226,7 +1235,7 @@ line below | |
| 1226 1235 |  | 
| 1227 1236 | 
             
                  output = render_embedded_string input
         | 
| 1228 1237 | 
             
                  assert_css '.stemblock', output, 1
         | 
| 1229 | 
            -
                  nodes = xmlnodes_at_xpath '//*[@class="content"]/child::text()', output | 
| 1238 | 
            +
                  nodes = xmlnodes_at_xpath '//*[@class="content"]/child::text()', output
         | 
| 1230 1239 | 
             
                  assert_equal '\[\sqrt{3x-1}+(1+x)^2 < y\]', nodes.first.to_s.strip
         | 
| 1231 1240 | 
             
                end
         | 
| 1232 1241 |  | 
| @@ -1259,7 +1268,7 @@ sqrt(3x-1)+(1+x)^2 < y | |
| 1259 1268 |  | 
| 1260 1269 | 
             
                  output = render_embedded_string input
         | 
| 1261 1270 | 
             
                  assert_css '.stemblock', output, 1
         | 
| 1262 | 
            -
                  nodes = xmlnodes_at_xpath '//*[@class="content"]/child::text()', output | 
| 1271 | 
            +
                  nodes = xmlnodes_at_xpath '//*[@class="content"]/child::text()', output
         | 
| 1263 1272 | 
             
                  assert_equal '\$sqrt(3x-1)+(1+x)^2 < y\$', nodes.first.to_s.strip
         | 
| 1264 1273 | 
             
                end
         | 
| 1265 1274 |  | 
| @@ -1273,7 +1282,7 @@ sqrt(3x-1)+(1+x)^2 < y | |
| 1273 1282 |  | 
| 1274 1283 | 
             
                  output = render_embedded_string input
         | 
| 1275 1284 | 
             
                  assert_css '.stemblock', output, 1
         | 
| 1276 | 
            -
                  nodes = xmlnodes_at_xpath '//*[@class="content"]/child::text()', output | 
| 1285 | 
            +
                  nodes = xmlnodes_at_xpath '//*[@class="content"]/child::text()', output
         | 
| 1277 1286 | 
             
                  assert_equal '\$sqrt(3x-1)+(1+x)^2 < y\$', nodes.first.to_s.strip
         | 
| 1278 1287 | 
             
                end
         | 
| 1279 1288 |  | 
| @@ -1342,7 +1351,7 @@ sqrt(3x-1)+(1+x)^2 < y | |
| 1342 1351 | 
             
                  ].each do |attributes|
         | 
| 1343 1352 | 
             
                    output = render_embedded_string input, :attributes => attributes
         | 
| 1344 1353 | 
             
                    assert_css '.stemblock', output, 1
         | 
| 1345 | 
            -
                    nodes = xmlnodes_at_xpath '//*[@class="content"]/child::text()', output | 
| 1354 | 
            +
                    nodes = xmlnodes_at_xpath '//*[@class="content"]/child::text()', output
         | 
| 1346 1355 | 
             
                    assert_equal '\$sqrt(3x-1)+(1+x)^2 < y\$', nodes.first.to_s.strip
         | 
| 1347 1356 | 
             
                  end
         | 
| 1348 1357 | 
             
                end
         | 
| @@ -1357,7 +1366,7 @@ sqrt(3x-1)+(1+x)^2 < y | |
| 1357 1366 |  | 
| 1358 1367 | 
             
                  output = render_embedded_string input, :attributes => {'stem' => 'latexmath'}
         | 
| 1359 1368 | 
             
                  assert_css '.stemblock', output, 1
         | 
| 1360 | 
            -
                  nodes = xmlnodes_at_xpath '//*[@class="content"]/child::text()', output | 
| 1369 | 
            +
                  nodes = xmlnodes_at_xpath '//*[@class="content"]/child::text()', output
         | 
| 1361 1370 | 
             
                  assert_equal '\[\sqrt{3x-1}+(1+x)^2 < y\]', nodes.first.to_s.strip
         | 
| 1362 1371 | 
             
                end
         | 
| 1363 1372 | 
             
              end
         | 
| @@ -1399,6 +1408,7 @@ section paragraph | |
| 1399 1408 |  | 
| 1400 1409 | 
             
                test 'block title above document title gets carried over to first block in first section if no preamble' do
         | 
| 1401 1410 | 
             
                  input = <<-EOS
         | 
| 1411 | 
            +
            :doctype: book
         | 
| 1402 1412 | 
             
            .Block title
         | 
| 1403 1413 | 
             
            = Document Title
         | 
| 1404 1414 |  | 
| @@ -1406,7 +1416,10 @@ section paragraph | |
| 1406 1416 |  | 
| 1407 1417 | 
             
            paragraph
         | 
| 1408 1418 | 
             
                  EOS
         | 
| 1409 | 
            -
                   | 
| 1419 | 
            +
                  doc = document_from_string input
         | 
| 1420 | 
            +
                  # NOTE block title demotes document title to level-0 section
         | 
| 1421 | 
            +
                  refute doc.header?
         | 
| 1422 | 
            +
                  output = doc.convert
         | 
| 1410 1423 | 
             
                  assert_xpath '//*[@class="sect1"]//*[@class="paragraph"]/*[@class="title"][text() = "Block title"]', output, 1
         | 
| 1411 1424 | 
             
                end
         | 
| 1412 1425 |  | 
| @@ -1548,18 +1561,39 @@ image::circle.svg[Tiger,100] | |
| 1548 1561 | 
             
            image::no-such-image.svg[Alt Text]
         | 
| 1549 1562 | 
             
                  EOS
         | 
| 1550 1563 |  | 
| 1551 | 
            -
                  output = render_embedded_string input, :safe => Asciidoctor::SafeMode::SERVER
         | 
| 1564 | 
            +
                  output, warnings = redirect_streams {|_, err| [(render_embedded_string input, :safe => Asciidoctor::SafeMode::SERVER), err.string] }
         | 
| 1552 1565 | 
             
                  assert_xpath '//span[@class="alt"][text()="Alt Text"]', output, 1
         | 
| 1566 | 
            +
                  assert_includes warnings, 'SVG does not exist or cannot be read'
         | 
| 1553 1567 | 
             
                end
         | 
| 1554 1568 |  | 
| 1555 | 
            -
                test 'can render block image with alt text defined in macro containing  | 
| 1569 | 
            +
                test 'can render block image with alt text defined in macro containing square bracket' do
         | 
| 1556 1570 | 
             
                  input = <<-EOS
         | 
| 1557 | 
            -
            image::images/tiger.png[A [Bengal | 
| 1571 | 
            +
            image::images/tiger.png[A [Bengal] Tiger]
         | 
| 1558 1572 | 
             
                  EOS
         | 
| 1559 1573 |  | 
| 1560 1574 | 
             
                  output = render_string input
         | 
| 1561 1575 | 
             
                  img = xmlnodes_at_xpath '//img', output, 1
         | 
| 1562 | 
            -
                  assert_equal 'A [Bengal] Tiger', img.attr('alt') | 
| 1576 | 
            +
                  assert_equal 'A [Bengal] Tiger', img.attr('alt')
         | 
| 1577 | 
            +
                end
         | 
| 1578 | 
            +
             | 
| 1579 | 
            +
                test 'can render block image with target containing spaces' do
         | 
| 1580 | 
            +
                  input = <<-EOS
         | 
| 1581 | 
            +
            image::images/big tiger.png[A Big Tiger]
         | 
| 1582 | 
            +
                  EOS
         | 
| 1583 | 
            +
             | 
| 1584 | 
            +
                  output = render_string input
         | 
| 1585 | 
            +
                  img = xmlnodes_at_xpath '//img', output, 1
         | 
| 1586 | 
            +
                  assert_equal 'images/big%20tiger.png', img.attr('src')
         | 
| 1587 | 
            +
                  assert_equal 'A Big Tiger', img.attr('alt')
         | 
| 1588 | 
            +
                end
         | 
| 1589 | 
            +
             | 
| 1590 | 
            +
                test 'should not recognize block image if target has leading or trailing spaces' do
         | 
| 1591 | 
            +
                  [' tiger.png', 'tiger.png '].each do |target|
         | 
| 1592 | 
            +
                    input = %(image::#{target}[Tiger])
         | 
| 1593 | 
            +
             | 
| 1594 | 
            +
                    output = render_embedded_string input
         | 
| 1595 | 
            +
                    assert_xpath '//img', output, 0
         | 
| 1596 | 
            +
                  end
         | 
| 1563 1597 | 
             
                end
         | 
| 1564 1598 |  | 
| 1565 1599 | 
             
                test 'can render block image with alt text defined in block attribute above macro' do
         | 
| @@ -1582,31 +1616,52 @@ image::images/tiger.png[Tiger] | |
| 1582 1616 | 
             
                  assert_xpath '/*[@class="imageblock"]//img[@src="images/tiger.png"][@alt="Tiger"]', output, 1
         | 
| 1583 1617 | 
             
                end
         | 
| 1584 1618 |  | 
| 1585 | 
            -
                test 'alt text  | 
| 1619 | 
            +
                test 'should substitute attribute references in alt text defined in image block macro' do
         | 
| 1586 1620 | 
             
                  input = <<-EOS
         | 
| 1587 | 
            -
             | 
| 1588 | 
            -
                  EOS
         | 
| 1621 | 
            +
            :alt-text: Tiger
         | 
| 1589 1622 |  | 
| 1623 | 
            +
            image::images/tiger.png[{alt-text}]
         | 
| 1624 | 
            +
                  EOS
         | 
| 1590 1625 | 
             
                  output = render_embedded_string input
         | 
| 1591 | 
            -
                   | 
| 1626 | 
            +
                  assert_xpath '/*[@class="imageblock"]//img[@src="images/tiger.png"][@alt="Tiger"]', output, 1
         | 
| 1592 1627 | 
             
                end
         | 
| 1593 1628 |  | 
| 1594 | 
            -
                test ' | 
| 1629 | 
            +
                test 'style attribute is dropped from image macro' do
         | 
| 1595 1630 | 
             
                  input = <<-EOS
         | 
| 1596 | 
            -
             | 
| 1631 | 
            +
            [style=value]
         | 
| 1632 | 
            +
            image::images/tiger.png[Tiger]
         | 
| 1597 1633 | 
             
                  EOS
         | 
| 1598 1634 |  | 
| 1599 | 
            -
                   | 
| 1600 | 
            -
                   | 
| 1635 | 
            +
                  doc = document_from_string input
         | 
| 1636 | 
            +
                  img = doc.blocks[0]
         | 
| 1637 | 
            +
                  refute(img.attributes.key? 'style')
         | 
| 1638 | 
            +
                  assert_nil img.style
         | 
| 1639 | 
            +
                end
         | 
| 1640 | 
            +
             | 
| 1641 | 
            +
                test 'should apply specialcharacters and replacement substitutions to alt text' do
         | 
| 1642 | 
            +
                  input = 'A tiger\'s "roar" is < a bear\'s "growl"'
         | 
| 1643 | 
            +
                  expected = 'A tiger’s "roar" is < a bear’s "growl"'
         | 
| 1644 | 
            +
                  result = render_embedded_string %(image::images/tiger-roar.png[#{input}])
         | 
| 1645 | 
            +
                  assert_includes result, %(alt="#{expected}")
         | 
| 1601 1646 | 
             
                end
         | 
| 1602 1647 |  | 
| 1603 | 
            -
                test  | 
| 1648 | 
            +
                test 'should not encode double quotes in alt text when converting to DocBook' do
         | 
| 1649 | 
            +
                  input = 'Select "File > Open"'
         | 
| 1650 | 
            +
                  expected = 'Select "File > Open"'
         | 
| 1651 | 
            +
                  result = render_embedded_string %(image::images/open.png[#{input}]), :backend => :docbook
         | 
| 1652 | 
            +
                  assert_includes result, %(<phrase>#{expected}</phrase>)
         | 
| 1653 | 
            +
                end
         | 
| 1654 | 
            +
             | 
| 1655 | 
            +
                test 'should auto-generate alt text for block image if alt text is not specified' do
         | 
| 1604 1656 | 
             
                  input = <<-EOS
         | 
| 1605 | 
            -
            image::images/ | 
| 1657 | 
            +
            image::images/lions-and-tigers.png[]
         | 
| 1606 1658 | 
             
                  EOS
         | 
| 1607 1659 |  | 
| 1608 | 
            -
                   | 
| 1609 | 
            -
                   | 
| 1660 | 
            +
                  image = block_from_string input
         | 
| 1661 | 
            +
                  assert_equal 'lions and tigers', (image.attr 'alt')
         | 
| 1662 | 
            +
                  assert_equal 'lions and tigers', (image.attr 'default-alt')
         | 
| 1663 | 
            +
                  output = image.convert
         | 
| 1664 | 
            +
                  assert_xpath '/*[@class="imageblock"]//img[@src="images/lions-and-tigers.png"][@alt="lions and tigers"]', output, 1
         | 
| 1610 1665 | 
             
                end
         | 
| 1611 1666 |  | 
| 1612 1667 | 
             
                test "can render block image with alt text and height and width" do
         | 
| @@ -1627,13 +1682,32 @@ image::images/tiger.png[Tiger, link='http://en.wikipedia.org/wiki/Tiger'] | |
| 1627 1682 | 
             
                  assert_xpath '/*[@class="imageblock"]//a[@class="image"][@href="http://en.wikipedia.org/wiki/Tiger"]/img[@src="images/tiger.png"][@alt="Tiger"]', output, 1
         | 
| 1628 1683 | 
             
                end
         | 
| 1629 1684 |  | 
| 1630 | 
            -
                test  | 
| 1685 | 
            +
                test 'adds rel=noopener attribute to block image with link that targets _blank window' do
         | 
| 1686 | 
            +
                  input = <<-EOS
         | 
| 1687 | 
            +
            image::images/tiger.png[Tiger,link=http://en.wikipedia.org/wiki/Tiger,window=_blank]
         | 
| 1688 | 
            +
                  EOS
         | 
| 1689 | 
            +
             | 
| 1690 | 
            +
                  output = render_embedded_string input
         | 
| 1691 | 
            +
                  assert_xpath '/*[@class="imageblock"]//a[@class="image"][@href="http://en.wikipedia.org/wiki/Tiger"][@target="_blank"][@rel="noopener"]/img[@src="images/tiger.png"][@alt="Tiger"]', output, 1
         | 
| 1692 | 
            +
                end
         | 
| 1693 | 
            +
             | 
| 1694 | 
            +
                test 'adds rel=noopener attribute to block image with link that targets name window when the noopener option is set' do
         | 
| 1695 | 
            +
                  input = <<-EOS
         | 
| 1696 | 
            +
            image::images/tiger.png[Tiger,link=http://en.wikipedia.org/wiki/Tiger,window=name,opts=noopener]
         | 
| 1697 | 
            +
                  EOS
         | 
| 1698 | 
            +
             | 
| 1699 | 
            +
                  output = render_embedded_string input
         | 
| 1700 | 
            +
                  assert_xpath '/*[@class="imageblock"]//a[@class="image"][@href="http://en.wikipedia.org/wiki/Tiger"][@target="name"][@rel="noopener"]/img[@src="images/tiger.png"][@alt="Tiger"]', output, 1
         | 
| 1701 | 
            +
                end
         | 
| 1702 | 
            +
             | 
| 1703 | 
            +
                test 'can render block image with caption' do
         | 
| 1631 1704 | 
             
                  input = <<-EOS
         | 
| 1632 1705 | 
             
            .The AsciiDoc Tiger
         | 
| 1633 1706 | 
             
            image::images/tiger.png[Tiger]
         | 
| 1634 1707 | 
             
                  EOS
         | 
| 1635 1708 |  | 
| 1636 1709 | 
             
                  doc = document_from_string input
         | 
| 1710 | 
            +
                  assert_equal 1, doc.blocks[0].number
         | 
| 1637 1711 | 
             
                  output = doc.render
         | 
| 1638 1712 | 
             
                  assert_xpath '//*[@class="imageblock"]//img[@src="images/tiger.png"][@alt="Tiger"]', output, 1
         | 
| 1639 1713 | 
             
                  assert_xpath '//*[@class="imageblock"]/*[@class="title"][text() = "Figure 1. The AsciiDoc Tiger"]', output, 1
         | 
| @@ -1648,6 +1722,7 @@ image::images/tiger.png[Tiger] | |
| 1648 1722 | 
             
                  EOS
         | 
| 1649 1723 |  | 
| 1650 1724 | 
             
                  doc = document_from_string input
         | 
| 1725 | 
            +
                  assert_nil doc.blocks[0].number
         | 
| 1651 1726 | 
             
                  output = doc.render
         | 
| 1652 1727 | 
             
                  assert_xpath '//*[@class="imageblock"]//img[@src="images/tiger.png"][@alt="Tiger"]', output, 1
         | 
| 1653 1728 | 
             
                  assert_xpath '//*[@class="imageblock"]/*[@class="title"][text() = "Voila! The AsciiDoc Tiger"]', output, 1
         | 
| @@ -1656,7 +1731,7 @@ image::images/tiger.png[Tiger] | |
| 1656 1731 |  | 
| 1657 1732 | 
             
                test 'can align image in DocBook backend' do
         | 
| 1658 1733 | 
             
                  input = <<-EOS
         | 
| 1659 | 
            -
            image::images/sunset.jpg[Sunset, | 
| 1734 | 
            +
            image::images/sunset.jpg[Sunset,align=right]
         | 
| 1660 1735 | 
             
                  EOS
         | 
| 1661 1736 |  | 
| 1662 1737 | 
             
                  output = render_embedded_string input, :backend => :docbook
         | 
| @@ -1664,36 +1739,54 @@ image::images/sunset.jpg[Sunset, align="right"] | |
| 1664 1739 | 
             
                  assert_xpath '//imagedata[@align="right"]', output, 1
         | 
| 1665 1740 | 
             
                end
         | 
| 1666 1741 |  | 
| 1742 | 
            +
                test 'should set content width and depth in DocBook backend if no scaling' do
         | 
| 1743 | 
            +
                  input = <<-EOS
         | 
| 1744 | 
            +
            image::images/sunset.jpg[Sunset,500,332]
         | 
| 1745 | 
            +
                  EOS
         | 
| 1746 | 
            +
             | 
| 1747 | 
            +
                  output = render_embedded_string input, :backend => :docbook
         | 
| 1748 | 
            +
                  assert_xpath '//imagedata', output, 1
         | 
| 1749 | 
            +
                  assert_xpath '//imagedata[@contentwidth="500"]', output, 1
         | 
| 1750 | 
            +
                  assert_xpath '//imagedata[@contentdepth="332"]', output, 1
         | 
| 1751 | 
            +
                  assert_xpath '//imagedata[@width]', output, 0
         | 
| 1752 | 
            +
                  assert_xpath '//imagedata[@depth]', output, 0
         | 
| 1753 | 
            +
                end
         | 
| 1754 | 
            +
             | 
| 1667 1755 | 
             
                test 'can scale image in DocBook backend' do
         | 
| 1668 1756 | 
             
                  input = <<-EOS
         | 
| 1669 | 
            -
            image::images/sunset.jpg[Sunset, | 
| 1757 | 
            +
            image::images/sunset.jpg[Sunset,500,332,scale=200]
         | 
| 1670 1758 | 
             
                  EOS
         | 
| 1671 1759 |  | 
| 1672 1760 | 
             
                  output = render_embedded_string input, :backend => :docbook
         | 
| 1673 1761 | 
             
                  assert_xpath '//imagedata', output, 1
         | 
| 1674 1762 | 
             
                  assert_xpath '//imagedata[@scale="200"]', output, 1
         | 
| 1763 | 
            +
                  assert_xpath '//imagedata[@width]', output, 0
         | 
| 1764 | 
            +
                  assert_xpath '//imagedata[@depth]', output, 0
         | 
| 1765 | 
            +
                  assert_xpath '//imagedata[@contentwidth]', output, 0
         | 
| 1766 | 
            +
                  assert_xpath '//imagedata[@contentdepth]', output, 0
         | 
| 1675 1767 | 
             
                end
         | 
| 1676 1768 |  | 
| 1677 | 
            -
                test ' | 
| 1769 | 
            +
                test 'scale image width in DocBook backend' do
         | 
| 1678 1770 | 
             
                  input = <<-EOS
         | 
| 1679 | 
            -
            image::images/sunset.jpg[Sunset, | 
| 1771 | 
            +
            image::images/sunset.jpg[Sunset,500,332,scaledwidth=25%]
         | 
| 1680 1772 | 
             
                  EOS
         | 
| 1681 1773 |  | 
| 1682 1774 | 
             
                  output = render_embedded_string input, :backend => :docbook
         | 
| 1683 1775 | 
             
                  assert_xpath '//imagedata', output, 1
         | 
| 1684 1776 | 
             
                  assert_xpath '//imagedata[@width="25%"]', output, 1
         | 
| 1685 | 
            -
                  assert_xpath '//imagedata[@ | 
| 1777 | 
            +
                  assert_xpath '//imagedata[@depth]', output, 0
         | 
| 1778 | 
            +
                  assert_xpath '//imagedata[@contentwidth]', output, 0
         | 
| 1779 | 
            +
                  assert_xpath '//imagedata[@contentdepth]', output, 0
         | 
| 1686 1780 | 
             
                end
         | 
| 1687 1781 |  | 
| 1688 1782 | 
             
                test 'adds % to scaled width if no units given in DocBook backend ' do
         | 
| 1689 1783 | 
             
                  input = <<-EOS
         | 
| 1690 | 
            -
            image::images/sunset.jpg[Sunset, | 
| 1784 | 
            +
            image::images/sunset.jpg[Sunset,scaledwidth=25]
         | 
| 1691 1785 | 
             
                  EOS
         | 
| 1692 1786 |  | 
| 1693 1787 | 
             
                  output = render_embedded_string input, :backend => :docbook
         | 
| 1694 1788 | 
             
                  assert_xpath '//imagedata', output, 1
         | 
| 1695 1789 | 
             
                  assert_xpath '//imagedata[@width="25%"]', output, 1
         | 
| 1696 | 
            -
                  assert_xpath '//imagedata[@scalefit="1"]', output, 1
         | 
| 1697 1790 | 
             
                end
         | 
| 1698 1791 |  | 
| 1699 1792 | 
             
                test 'keeps line unprocessed if image target is missing attribute reference and attribute-missing is skip' do
         | 
| @@ -1703,8 +1796,9 @@ image::images/sunset.jpg[Sunset, scaledwidth="25"] | |
| 1703 1796 | 
             
            image::{bogus}[]
         | 
| 1704 1797 | 
             
                  EOS
         | 
| 1705 1798 |  | 
| 1706 | 
            -
                  output = render_embedded_string input
         | 
| 1799 | 
            +
                  output, warnings = redirect_streams {|_, err| [(render_embedded_string input), err.string] }
         | 
| 1707 1800 | 
             
                  assert output.include?('image::{bogus}[]')
         | 
| 1801 | 
            +
                  assert_includes warnings, 'dropping line containing reference to missing attribute'
         | 
| 1708 1802 | 
             
                end
         | 
| 1709 1803 |  | 
| 1710 1804 | 
             
                test 'drops line if image target is missing attribute reference and attribute-missing is drop' do
         | 
| @@ -1714,8 +1808,9 @@ image::{bogus}[] | |
| 1714 1808 | 
             
            image::{bogus}[]
         | 
| 1715 1809 | 
             
                  EOS
         | 
| 1716 1810 |  | 
| 1717 | 
            -
                  output = render_embedded_string input
         | 
| 1811 | 
            +
                  output, warnings = redirect_streams {|_, err| [(render_embedded_string input), err.string] }
         | 
| 1718 1812 | 
             
                  assert output.strip.empty?
         | 
| 1813 | 
            +
                  assert_includes warnings, 'dropping line containing reference to missing attribute'
         | 
| 1719 1814 | 
             
                end
         | 
| 1720 1815 |  | 
| 1721 1816 | 
             
                test 'drops line if image target is missing attribute reference and attribute-missing is drop-line' do
         | 
| @@ -1725,8 +1820,9 @@ image::{bogus}[] | |
| 1725 1820 | 
             
            image::{bogus}[]
         | 
| 1726 1821 | 
             
                  EOS
         | 
| 1727 1822 |  | 
| 1728 | 
            -
                  output = render_embedded_string input
         | 
| 1823 | 
            +
                  output, warnings = redirect_streams {|_, err| [(render_embedded_string input), err.string] }
         | 
| 1729 1824 | 
             
                  assert output.strip.empty?
         | 
| 1825 | 
            +
                  assert_includes warnings, 'dropping line containing reference to missing attribute'
         | 
| 1730 1826 | 
             
                end
         | 
| 1731 1827 |  | 
| 1732 1828 | 
             
                test 'dropped image does not break processing of following section and attribute-missing is drop-line' do
         | 
| @@ -1738,10 +1834,11 @@ image::{bogus}[] | |
| 1738 1834 | 
             
            == Section Title
         | 
| 1739 1835 | 
             
                  EOS
         | 
| 1740 1836 |  | 
| 1741 | 
            -
                  output = render_embedded_string input
         | 
| 1837 | 
            +
                  output, warnings = redirect_streams {|_, err| [(render_embedded_string input), err.string] }
         | 
| 1742 1838 | 
             
                  assert_css 'img', output, 0
         | 
| 1743 1839 | 
             
                  assert_css 'h2', output, 1
         | 
| 1744 1840 | 
             
                  assert !output.include?('== Section Title')
         | 
| 1841 | 
            +
                  assert_includes warnings, 'dropping line containing reference to missing attribute'
         | 
| 1745 1842 | 
             
                end
         | 
| 1746 1843 |  | 
| 1747 1844 | 
             
                test 'should pass through image that references uri' do
         | 
| @@ -1755,6 +1852,15 @@ image::http://asciidoc.org/images/tiger.png[Tiger] | |
| 1755 1852 | 
             
                  assert_xpath '/*[@class="imageblock"]//img[@src="http://asciidoc.org/images/tiger.png"][@alt="Tiger"]', output, 1
         | 
| 1756 1853 | 
             
                end
         | 
| 1757 1854 |  | 
| 1855 | 
            +
                test 'should encode spaces in image target if value is a URI' do
         | 
| 1856 | 
            +
                  input = <<-EOS
         | 
| 1857 | 
            +
            image::http://example.org/svg?digraph=digraph G { a -> b; }[diagram]
         | 
| 1858 | 
            +
                  EOS
         | 
| 1859 | 
            +
             | 
| 1860 | 
            +
                  output = render_embedded_string input
         | 
| 1861 | 
            +
                  assert_xpath %(/*[@class="imageblock"]//img[@src="http://example.org/svg?digraph=digraph%20G%20{%20a%20-#{decode_char 62}%20b;%20}"]), output, 1
         | 
| 1862 | 
            +
                end
         | 
| 1863 | 
            +
             | 
| 1758 1864 | 
             
                test 'can resolve image relative to imagesdir' do
         | 
| 1759 1865 | 
             
                  input = <<-EOS
         | 
| 1760 1866 | 
             
            :imagesdir: images
         | 
| @@ -1780,6 +1886,21 @@ image::dot.gif[Dot] | |
| 1780 1886 | 
             
                  assert_xpath '//img[@src="data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs="][@alt="Dot"]', output, 1
         | 
| 1781 1887 | 
             
                end
         | 
| 1782 1888 |  | 
| 1889 | 
            +
                test 'embeds empty base64-encoded data uri for unreadable image when data-uri attribute is set' do
         | 
| 1890 | 
            +
                  input = <<-EOS
         | 
| 1891 | 
            +
            :data-uri:
         | 
| 1892 | 
            +
            :imagesdir: fixtures
         | 
| 1893 | 
            +
             | 
| 1894 | 
            +
            image::unreadable.gif[Dot]
         | 
| 1895 | 
            +
                  EOS
         | 
| 1896 | 
            +
             | 
| 1897 | 
            +
                  doc = document_from_string input, :safe => Asciidoctor::SafeMode::SAFE, :attributes => {'docdir' => File.dirname(__FILE__)}
         | 
| 1898 | 
            +
                  assert_equal 'fixtures', doc.attributes['imagesdir']
         | 
| 1899 | 
            +
                  output, warnings = redirect_streams {|_, err| [doc.render, err.string] }
         | 
| 1900 | 
            +
                  assert_xpath '//img[@src="data:image/gif;base64,"]', output, 1
         | 
| 1901 | 
            +
                  assert_includes warnings, 'image to embed not found or not readable'
         | 
| 1902 | 
            +
                end
         | 
| 1903 | 
            +
             | 
| 1783 1904 | 
             
                test 'embeds base64-encoded data uri for remote image when data-uri attribute is set' do
         | 
| 1784 1905 | 
             
                  input = <<-EOS
         | 
| 1785 1906 | 
             
            :data-uri:
         | 
| @@ -1817,11 +1938,16 @@ image::dot.gif[Dot] | |
| 1817 1938 | 
             
            image::#{image_uri}[Missing image]
         | 
| 1818 1939 | 
             
                  EOS
         | 
| 1819 1940 |  | 
| 1820 | 
            -
                  output =  | 
| 1821 | 
            -
             | 
| 1941 | 
            +
                  output = warnings = nil
         | 
| 1942 | 
            +
                  redirect_streams do |_, err|
         | 
| 1943 | 
            +
                    output = using_test_webserver do
         | 
| 1944 | 
            +
                      render_embedded_string input, :safe => :safe, :attributes => {'allow-uri-read' => ''}
         | 
| 1945 | 
            +
                    end
         | 
| 1946 | 
            +
                    warnings = err.string
         | 
| 1822 1947 | 
             
                  end
         | 
| 1823 1948 |  | 
| 1824 1949 | 
             
                  assert_xpath %(/*[@class="imageblock"]//img[@src="#{image_uri}"][@alt="Missing image"]), output, 1
         | 
| 1950 | 
            +
                  assert_includes warnings, 'could not retrieve image data from URI'
         | 
| 1825 1951 | 
             
                end
         | 
| 1826 1952 |  | 
| 1827 1953 | 
             
                test 'uses remote image uri when data-uri attribute is set and allow-uri-read is not set' do
         | 
| @@ -1859,7 +1985,6 @@ image::data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=[Do | |
| 1859 1985 | 
             
                  assert_xpath '//img[@src="data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs="][@alt="Dot"]', output, 1
         | 
| 1860 1986 | 
             
                end
         | 
| 1861 1987 |  | 
| 1862 | 
            -
                # this test will cause a warning to be printed to the console (until we have a message facility)
         | 
| 1863 1988 | 
             
                test 'cleans reference to ancestor directories in imagesdir before reading image if safe mode level is at least SAFE' do
         | 
| 1864 1989 | 
             
                  input = <<-EOS
         | 
| 1865 1990 | 
             
            :data-uri:
         | 
| @@ -1870,10 +1995,11 @@ image::dot.gif[Dot] | |
| 1870 1995 |  | 
| 1871 1996 | 
             
                  doc = document_from_string input, :safe => Asciidoctor::SafeMode::SAFE, :attributes => {'docdir' => File.dirname(__FILE__)}
         | 
| 1872 1997 | 
             
                  assert_equal '../..//fixtures/./../../fixtures', doc.attributes['imagesdir']
         | 
| 1873 | 
            -
                  output = doc.render
         | 
| 1998 | 
            +
                  output, warnings = redirect_streams {|_, err| [doc.render, err.string] }
         | 
| 1874 1999 | 
             
                  # image target resolves to fixtures/dot.gif relative to docdir (which is explicitly set to the directory of this file)
         | 
| 1875 2000 | 
             
                  # the reference cannot fall outside of the document directory in safe mode
         | 
| 1876 2001 | 
             
                  assert_xpath '//img[@src="data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs="][@alt="Dot"]', output, 1
         | 
| 2002 | 
            +
                  assert_includes warnings, 'image has illegal reference to ancestor of jail'
         | 
| 1877 2003 | 
             
                end
         | 
| 1878 2004 |  | 
| 1879 2005 | 
             
                test 'cleans reference to ancestor directories in target before reading image if safe mode level is at least SAFE' do
         | 
| @@ -1886,10 +2012,11 @@ image::../..//fixtures/./../../fixtures/dot.gif[Dot] | |
| 1886 2012 |  | 
| 1887 2013 | 
             
                  doc = document_from_string input, :safe => Asciidoctor::SafeMode::SAFE, :attributes => {'docdir' => File.dirname(__FILE__)}
         | 
| 1888 2014 | 
             
                  assert_equal './', doc.attributes['imagesdir']
         | 
| 1889 | 
            -
                  output = doc.render
         | 
| 2015 | 
            +
                  output, warnings = redirect_streams {|_, err| [doc.render, err.string] }
         | 
| 1890 2016 | 
             
                  # image target resolves to fixtures/dot.gif relative to docdir (which is explicitly set to the directory of this file)
         | 
| 1891 2017 | 
             
                  # the reference cannot fall outside of the document directory in safe mode
         | 
| 1892 2018 | 
             
                  assert_xpath '//img[@src="data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs="][@alt="Dot"]', output, 1
         | 
| 2019 | 
            +
                  assert_includes warnings, 'image has illegal reference to ancestor of jail'
         | 
| 1893 2020 | 
             
                end
         | 
| 1894 2021 | 
             
              end
         | 
| 1895 2022 |  | 
| @@ -1919,7 +2046,7 @@ video::cats-vs-dogs.avi[cats-and-dogs.png, 200, 300] | |
| 1919 2046 |  | 
| 1920 2047 | 
             
                test 'video macro should honor all options' do
         | 
| 1921 2048 | 
             
                  input = <<-EOS
         | 
| 1922 | 
            -
            video::cats-vs-dogs.avi[options="autoplay,nocontrols,loop"]
         | 
| 2049 | 
            +
            video::cats-vs-dogs.avi[options="autoplay,nocontrols,loop",preload="metadata"]
         | 
| 1923 2050 | 
             
                  EOS
         | 
| 1924 2051 |  | 
| 1925 2052 | 
             
                  output = render_embedded_string input
         | 
| @@ -1927,6 +2054,7 @@ video::cats-vs-dogs.avi[options="autoplay,nocontrols,loop"] | |
| 1927 2054 | 
             
                  assert_css 'video[autoplay]', output, 1
         | 
| 1928 2055 | 
             
                  assert_css 'video:not([controls])', output, 1
         | 
| 1929 2056 | 
             
                  assert_css 'video[loop]', output, 1
         | 
| 2057 | 
            +
                  assert_css 'video[preload=metadata]', output, 1
         | 
| 1930 2058 | 
             
                end
         | 
| 1931 2059 |  | 
| 1932 2060 | 
             
                test 'video macro should add time range anchor with start time if start attribute is set' do
         | 
| @@ -2067,6 +2195,17 @@ audio::podcast.mp3[options="autoplay,nocontrols,loop"] | |
| 2067 2195 | 
             
                  assert_css 'audio:not([controls])', output, 1
         | 
| 2068 2196 | 
             
                  assert_css 'audio[loop]', output, 1
         | 
| 2069 2197 | 
             
                end
         | 
| 2198 | 
            +
             | 
| 2199 | 
            +
                test 'audio macro should support start and end time' do
         | 
| 2200 | 
            +
                  input = <<-EOS
         | 
| 2201 | 
            +
            audio::podcast.mp3[start=1,end=2]
         | 
| 2202 | 
            +
                  EOS
         | 
| 2203 | 
            +
             | 
| 2204 | 
            +
                  output = render_embedded_string input
         | 
| 2205 | 
            +
                  assert_css 'audio', output, 1
         | 
| 2206 | 
            +
                  assert_css 'audio[controls]', output, 1
         | 
| 2207 | 
            +
                  assert_css 'audio[src="podcast.mp3#t=1,2"]', output, 1
         | 
| 2208 | 
            +
                end
         | 
| 2070 2209 | 
             
              end
         | 
| 2071 2210 |  | 
| 2072 2211 | 
             
              context 'Admonition icons' do
         | 
| @@ -2149,8 +2288,11 @@ You can use icons for admonitions by setting the 'icons' attribute. | |
| 2149 2288 | 
             
            You can use icons for admonitions by setting the 'icons' attribute.
         | 
| 2150 2289 | 
             
                  EOS
         | 
| 2151 2290 |  | 
| 2152 | 
            -
                  output =  | 
| 2291 | 
            +
                  output, warnings = redirect_streams do |_, err|
         | 
| 2292 | 
            +
                    [(render_string input, :safe => Asciidoctor::SafeMode::SAFE, :attributes => {'docdir' => File.dirname(__FILE__)}), err.string]
         | 
| 2293 | 
            +
                  end
         | 
| 2153 2294 | 
             
                  assert_xpath '//*[@class="admonitionblock tip"]//*[@class="icon"]/img[@src="data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs="][@alt="Tip"]', output, 1
         | 
| 2295 | 
            +
                  assert_includes warnings, 'image has illegal reference to ancestor of jail'
         | 
| 2154 2296 | 
             
                end
         | 
| 2155 2297 |  | 
| 2156 2298 | 
             
                test 'should import Font Awesome and use font-based icons when value of icons attribute is font' do
         | 
| @@ -2194,7 +2336,7 @@ puts "AsciiDoc, FTW!" | |
| 2194 2336 |  | 
| 2195 2337 | 
             
                  output = render_string input, :safe => Asciidoctor::SafeMode::SAFE
         | 
| 2196 2338 | 
             
                  assert_css 'html > head > link[rel="stylesheet"][href="http://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.6.3/css/font-awesome.min.css"]', output, 1
         | 
| 2197 | 
            -
                  assert_css 'html > body > script[src="http://cdnjs.cloudflare.com/ajax/libs/highlight.js/ | 
| 2339 | 
            +
                  assert_css 'html > body > script[src="http://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"]', output, 1
         | 
| 2198 2340 | 
             
                end
         | 
| 2199 2341 |  | 
| 2200 2342 | 
             
                test 'should use no uri scheme for assets when asset-uri-scheme is blank' do
         | 
| @@ -2211,7 +2353,7 @@ puts "AsciiDoc, FTW!" | |
| 2211 2353 |  | 
| 2212 2354 | 
             
                  output = render_string input, :safe => Asciidoctor::SafeMode::SAFE
         | 
| 2213 2355 | 
             
                  assert_css 'html > head > link[rel="stylesheet"][href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.6.3/css/font-awesome.min.css"]', output, 1
         | 
| 2214 | 
            -
                  assert_css 'html > body > script[src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/ | 
| 2356 | 
            +
                  assert_css 'html > body > script[src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"]', output, 1
         | 
| 2215 2357 | 
             
                end
         | 
| 2216 2358 | 
             
              end
         | 
| 2217 2359 |  | 
| @@ -2227,8 +2369,8 @@ image::asciidoctor.png[Asciidoctor] | |
| 2227 2369 | 
             
                  assert doc.safe >= Asciidoctor::SafeMode::SAFE
         | 
| 2228 2370 |  | 
| 2229 2371 | 
             
                  assert_equal File.join(basedir, 'images'), block.normalize_asset_path('images')
         | 
| 2230 | 
            -
                  assert_equal File.join(basedir, 'etc/images'), block.normalize_asset_path("#{disk_root}etc/images")
         | 
| 2231 | 
            -
                  assert_equal File.join(basedir, 'images'), block.normalize_asset_path('../../images')
         | 
| 2372 | 
            +
                  assert_equal File.join(basedir, 'etc/images'), redirect_streams { block.normalize_asset_path("#{disk_root}etc/images") }
         | 
| 2373 | 
            +
                  assert_equal File.join(basedir, 'images'), redirect_streams { block.normalize_asset_path('../../images') }
         | 
| 2232 2374 | 
             
                end
         | 
| 2233 2375 |  | 
| 2234 2376 | 
             
                test 'does not restrict access to ancestor directories when safe mode is disabled' do
         | 
| @@ -2327,6 +2469,46 @@ html = CodeRay.scan("puts 'Hello, world!'", :ruby).div(:line_numbers => :table) | |
| 2327 2469 | 
             
                  assert_match(/\.CodeRay *\{/, output)
         | 
| 2328 2470 | 
             
                end
         | 
| 2329 2471 |  | 
| 2472 | 
            +
                test 'should number lines if third positional attribute is set' do
         | 
| 2473 | 
            +
                  input = <<-EOS
         | 
| 2474 | 
            +
            :source-highlighter: coderay
         | 
| 2475 | 
            +
             | 
| 2476 | 
            +
            [source,ruby,linenums]
         | 
| 2477 | 
            +
            ----
         | 
| 2478 | 
            +
            puts 'Hello, World!'
         | 
| 2479 | 
            +
            ----
         | 
| 2480 | 
            +
                  EOS
         | 
| 2481 | 
            +
                  output = render_embedded_string input, :safe => Asciidoctor::SafeMode::SAFE
         | 
| 2482 | 
            +
                  assert_xpath '//td[@class="line-numbers"]', output, 1
         | 
| 2483 | 
            +
                end
         | 
| 2484 | 
            +
             | 
| 2485 | 
            +
                test 'should number lines if linenums option is set on source block' do
         | 
| 2486 | 
            +
                  input = <<-EOS
         | 
| 2487 | 
            +
            :source-highlighter: coderay
         | 
| 2488 | 
            +
             | 
| 2489 | 
            +
            [source%linenums,ruby]
         | 
| 2490 | 
            +
            ----
         | 
| 2491 | 
            +
            puts 'Hello, World!'
         | 
| 2492 | 
            +
            ----
         | 
| 2493 | 
            +
                  EOS
         | 
| 2494 | 
            +
                  output = render_embedded_string input, :safe => Asciidoctor::SafeMode::SAFE
         | 
| 2495 | 
            +
                  assert_xpath '//td[@class="line-numbers"]', output, 1
         | 
| 2496 | 
            +
                end
         | 
| 2497 | 
            +
             | 
| 2498 | 
            +
                test 'should number lines of source block if source-linenums-option document attribute is set' do
         | 
| 2499 | 
            +
                  input = <<-EOS
         | 
| 2500 | 
            +
            :source-highlighter: coderay
         | 
| 2501 | 
            +
            :source-linenums-option:
         | 
| 2502 | 
            +
             | 
| 2503 | 
            +
            [source,ruby]
         | 
| 2504 | 
            +
            ----
         | 
| 2505 | 
            +
            puts 'Hello, World!'
         | 
| 2506 | 
            +
            ----
         | 
| 2507 | 
            +
                  EOS
         | 
| 2508 | 
            +
                  output = render_embedded_string input, :safe => Asciidoctor::SafeMode::SAFE
         | 
| 2509 | 
            +
                  assert_xpath '//td[@class="line-numbers"]', output, 1
         | 
| 2510 | 
            +
                end
         | 
| 2511 | 
            +
             | 
| 2330 2512 | 
             
                test 'should read source language from source-language document attribute if not specified on source block' do
         | 
| 2331 2513 | 
             
                  input = <<-EOS
         | 
| 2332 2514 | 
             
            :source-highlighter: coderay
         | 
| @@ -2414,6 +2596,43 @@ exit 0 # <5><6> | |
| 2414 2596 | 
             
                  assert_match(/exit.* <b class="conum">\(5\)<\/b> <b class="conum">\(6\)<\/b><\/pre>/, output)
         | 
| 2415 2597 | 
             
                end
         | 
| 2416 2598 |  | 
| 2599 | 
            +
                test 'should preserve space before callout on final line' do
         | 
| 2600 | 
            +
                  inputs = []
         | 
| 2601 | 
            +
             | 
| 2602 | 
            +
                  inputs << <<-EOS
         | 
| 2603 | 
            +
            [source,yaml]
         | 
| 2604 | 
            +
            ----
         | 
| 2605 | 
            +
            a: 'a'
         | 
| 2606 | 
            +
            key: 'value' #<1>
         | 
| 2607 | 
            +
            ----
         | 
| 2608 | 
            +
            <1> key-value pair
         | 
| 2609 | 
            +
                  EOS
         | 
| 2610 | 
            +
             | 
| 2611 | 
            +
                  inputs << <<-EOS
         | 
| 2612 | 
            +
            [source,ruby]
         | 
| 2613 | 
            +
            ----
         | 
| 2614 | 
            +
            puts 'hi'
         | 
| 2615 | 
            +
            puts 'value' #<1>
         | 
| 2616 | 
            +
            ----
         | 
| 2617 | 
            +
            <1> print to stdout
         | 
| 2618 | 
            +
                  EOS
         | 
| 2619 | 
            +
             | 
| 2620 | 
            +
                  inputs << <<-EOS
         | 
| 2621 | 
            +
            [source,python]
         | 
| 2622 | 
            +
            ----
         | 
| 2623 | 
            +
            print 'hi'
         | 
| 2624 | 
            +
            print 'value' #<1>
         | 
| 2625 | 
            +
            ----
         | 
| 2626 | 
            +
            <1> print to stdout
         | 
| 2627 | 
            +
                  EOS
         | 
| 2628 | 
            +
             | 
| 2629 | 
            +
                  inputs.each do |input|
         | 
| 2630 | 
            +
                    output = render_embedded_string input, :safe => Asciidoctor::SafeMode::SAFE, :attributes => { 'source-highlighter' => 'coderay' }
         | 
| 2631 | 
            +
                    output = output.gsub(/<\/?span.*?>/, '')
         | 
| 2632 | 
            +
                    assert_includes output, '\'value\' <b class="conum">(1)</b>'
         | 
| 2633 | 
            +
                  end
         | 
| 2634 | 
            +
                end
         | 
| 2635 | 
            +
             | 
| 2417 2636 | 
             
                test 'should preserve passthrough placeholders when highlighting source using coderay' do
         | 
| 2418 2637 | 
             
                  input = <<-EOS
         | 
| 2419 2638 | 
             
            :source-highlighter: coderay
         | 
| @@ -2741,8 +2960,9 @@ content | |
| 2741 2960 | 
             
            part intro paragraph
         | 
| 2742 2961 | 
             
                  EOS
         | 
| 2743 2962 |  | 
| 2744 | 
            -
                  output = render_string input
         | 
| 2963 | 
            +
                  output, warnings = redirect_streams {|_, err| [(render_string input), err.string] }
         | 
| 2745 2964 | 
             
                  assert_css '.partintro', output, 0
         | 
| 2965 | 
            +
                  assert_includes warnings, 'partintro block can only be used when doctype is book and it\'s a child of a book part'
         | 
| 2746 2966 | 
             
                end
         | 
| 2747 2967 |  | 
| 2748 2968 | 
             
                test 'should not allow partintro unless doctype is book' do
         | 
| @@ -2751,8 +2971,9 @@ part intro paragraph | |
| 2751 2971 | 
             
            part intro paragraph
         | 
| 2752 2972 | 
             
                  EOS
         | 
| 2753 2973 |  | 
| 2754 | 
            -
                  output = render_string input
         | 
| 2974 | 
            +
                  output, warnings = redirect_streams {|_, err| [(render_string input), err.string] }
         | 
| 2755 2975 | 
             
                  assert_css '.partintro', output, 0
         | 
| 2976 | 
            +
                  assert_includes warnings, 'partintro block can only be used when doctype is book and it\'s a child of a book part'
         | 
| 2756 2977 | 
             
                end
         | 
| 2757 2978 |  | 
| 2758 2979 | 
             
                test 'should accept partintro on open block without title rendered to DocBook' do
         | 
| @@ -2814,8 +3035,9 @@ content | |
| 2814 3035 | 
             
            part intro paragraph
         | 
| 2815 3036 | 
             
                  EOS
         | 
| 2816 3037 |  | 
| 2817 | 
            -
                  output = render_string input, :backend => 'docbook'
         | 
| 3038 | 
            +
                  output, warnings = redirect_streams {|_, err| [(render_string input, :backend => 'docbook'), err.string] }
         | 
| 2818 3039 | 
             
                  assert_css 'partintro', output, 0
         | 
| 3040 | 
            +
                  assert_includes warnings, 'partintro block can only be used when doctype is book and it\'s a child of a part section'
         | 
| 2819 3041 | 
             
                end
         | 
| 2820 3042 |  | 
| 2821 3043 | 
             
                test 'should not allow partintro unless doctype is book rendered to DocBook' do
         | 
| @@ -2824,12 +3046,26 @@ part intro paragraph | |
| 2824 3046 | 
             
            part intro paragraph
         | 
| 2825 3047 | 
             
                  EOS
         | 
| 2826 3048 |  | 
| 2827 | 
            -
                  output = render_string input, :backend => 'docbook'
         | 
| 3049 | 
            +
                  output, warnings = redirect_streams {|_, err| [(render_string input, :backend => 'docbook'), err.string] }
         | 
| 2828 3050 | 
             
                  assert_css 'partintro', output, 0
         | 
| 3051 | 
            +
                  assert_includes warnings, 'partintro block can only be used when doctype is book and it\'s a child of a part section'
         | 
| 2829 3052 | 
             
                end
         | 
| 2830 3053 | 
             
              end
         | 
| 2831 3054 |  | 
| 2832 3055 | 
             
              context 'Substitutions' do
         | 
| 3056 | 
            +
                test 'processor should not crash if subs are empty' do
         | 
| 3057 | 
            +
                  input = <<-EOS
         | 
| 3058 | 
            +
            [subs=","]
         | 
| 3059 | 
            +
            ....
         | 
| 3060 | 
            +
            content
         | 
| 3061 | 
            +
            ....
         | 
| 3062 | 
            +
                  EOS
         | 
| 3063 | 
            +
             | 
| 3064 | 
            +
                  doc = document_from_string input
         | 
| 3065 | 
            +
                  block = doc.blocks.first
         | 
| 3066 | 
            +
                  assert_equal [], block.subs
         | 
| 3067 | 
            +
                end
         | 
| 3068 | 
            +
             | 
| 2833 3069 | 
             
                test 'should be able to append subs to default block substitution list' do
         | 
| 2834 3070 | 
             
                  input = <<-EOS
         | 
| 2835 3071 | 
             
            :application: Asciidoctor
         | 
| @@ -2915,7 +3151,32 @@ content | |
| 2915 3151 | 
             
                  block = doc.blocks.first
         | 
| 2916 3152 | 
             
                  assert_nil block.id
         | 
| 2917 3153 | 
             
                  assert_nil(block.attr 'reftext')
         | 
| 2918 | 
            -
                  assert !doc. | 
| 3154 | 
            +
                  assert !doc.catalog[:ids].has_key?('illegal$id')
         | 
| 3155 | 
            +
                end
         | 
| 3156 | 
            +
             | 
| 3157 | 
            +
                test 'should not recognize block anchor that starts with digit' do
         | 
| 3158 | 
            +
                  input = <<-EOS
         | 
| 3159 | 
            +
            [[3-blind-mice]]
         | 
| 3160 | 
            +
            --
         | 
| 3161 | 
            +
            see how they run
         | 
| 3162 | 
            +
            --
         | 
| 3163 | 
            +
                  EOS
         | 
| 3164 | 
            +
             | 
| 3165 | 
            +
                  output = render_embedded_string input
         | 
| 3166 | 
            +
                  assert_includes output, '[[3-blind-mice]]'
         | 
| 3167 | 
            +
                  assert_xpath '/*[@id = ":3-blind-mice"]', output, 0
         | 
| 3168 | 
            +
                end
         | 
| 3169 | 
            +
             | 
| 3170 | 
            +
                test 'should recognize block anchor that starts with colon' do
         | 
| 3171 | 
            +
                  input = <<-EOS
         | 
| 3172 | 
            +
            [[:idname]]
         | 
| 3173 | 
            +
            --
         | 
| 3174 | 
            +
            content
         | 
| 3175 | 
            +
            --
         | 
| 3176 | 
            +
                  EOS
         | 
| 3177 | 
            +
             | 
| 3178 | 
            +
                  output = render_embedded_string input
         | 
| 3179 | 
            +
                  assert_xpath '/*[@id = ":idname"]', output, 1
         | 
| 2919 3180 | 
             
                end
         | 
| 2920 3181 |  | 
| 2921 3182 | 
             
                test 'should use specified id and reftext when registering block reference' do
         | 
| @@ -2928,7 +3189,7 @@ $ apt-get install asciidoctor | |
| 2928 3189 | 
             
                  EOS
         | 
| 2929 3190 |  | 
| 2930 3191 | 
             
                  doc = document_from_string input
         | 
| 2931 | 
            -
                  reftext = doc. | 
| 3192 | 
            +
                  reftext = doc.catalog[:ids]['debian']
         | 
| 2932 3193 | 
             
                  refute_nil reftext
         | 
| 2933 3194 | 
             
                  assert_equal 'Debian Install', reftext
         | 
| 2934 3195 | 
             
                end
         | 
| @@ -2943,7 +3204,7 @@ $ apt-get install asciidoctor | |
| 2943 3204 | 
             
                  EOS
         | 
| 2944 3205 |  | 
| 2945 3206 | 
             
                  doc = document_from_string input
         | 
| 2946 | 
            -
                  reftext = doc. | 
| 3207 | 
            +
                  reftext = doc.catalog[:ids]['debian']
         | 
| 2947 3208 | 
             
                  refute_nil reftext
         | 
| 2948 3209 | 
             
                  assert_equal '[Debian] Install', reftext
         | 
| 2949 3210 | 
             
                end
         | 
| @@ -2958,11 +3219,30 @@ $ apt-get install asciidoctor | |
| 2958 3219 | 
             
                  EOS
         | 
| 2959 3220 |  | 
| 2960 3221 | 
             
                  doc = document_from_string input
         | 
| 2961 | 
            -
                  reftext = doc. | 
| 3222 | 
            +
                  reftext = doc.catalog[:ids]['debian']
         | 
| 2962 3223 | 
             
                  refute_nil reftext
         | 
| 2963 3224 | 
             
                  assert_equal 'Debian, Ubuntu', reftext
         | 
| 2964 3225 | 
             
                end
         | 
| 2965 3226 |  | 
| 3227 | 
            +
                test 'should substitute attribute references in reftext when registering block reference' do
         | 
| 3228 | 
            +
                  input = <<-EOS
         | 
| 3229 | 
            +
            :label-tiger: Tiger
         | 
| 3230 | 
            +
             | 
| 3231 | 
            +
            [[tiger-evolution,Evolution of the {label-tiger}]]
         | 
| 3232 | 
            +
            ****
         | 
| 3233 | 
            +
            Information about the evolution of the tiger.
         | 
| 3234 | 
            +
            ****
         | 
| 3235 | 
            +
                  EOS
         | 
| 3236 | 
            +
             | 
| 3237 | 
            +
                  doc = document_from_string input
         | 
| 3238 | 
            +
                  reftext = doc.catalog[:ids]['tiger-evolution']
         | 
| 3239 | 
            +
                  refute_nil reftext
         | 
| 3240 | 
            +
                  assert_equal 'Evolution of the Tiger', reftext
         | 
| 3241 | 
            +
                  ref = doc.catalog[:refs]['tiger-evolution']
         | 
| 3242 | 
            +
                  refute_nil ref
         | 
| 3243 | 
            +
                  assert_equal 'Evolution of the Tiger', ref.attributes['reftext']
         | 
| 3244 | 
            +
                end
         | 
| 3245 | 
            +
             | 
| 2966 3246 | 
             
                test 'should use specified reftext when registering block reference' do
         | 
| 2967 3247 | 
             
                  input = <<-EOS
         | 
| 2968 3248 | 
             
            [[debian]]
         | 
| @@ -2974,7 +3254,7 @@ $ apt-get install asciidoctor | |
| 2974 3254 | 
             
                  EOS
         | 
| 2975 3255 |  | 
| 2976 3256 | 
             
                  doc = document_from_string input
         | 
| 2977 | 
            -
                  reftext = doc. | 
| 3257 | 
            +
                  reftext = doc.catalog[:ids]['debian']
         | 
| 2978 3258 | 
             
                  refute_nil reftext
         | 
| 2979 3259 | 
             
                  assert_equal 'Debian Install', reftext
         | 
| 2980 3260 | 
             
                end
         |