asciidoctor 1.5.6.2 → 1.5.7

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of asciidoctor might be problematic. Click here for more details.

Files changed (112) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.adoc +330 -143
  3. data/README-fr.adoc +441 -0
  4. data/README-jp.adoc +418 -0
  5. data/README-zh_CN.adoc +430 -0
  6. data/README.adoc +454 -0
  7. data/Rakefile +57 -0
  8. data/asciidoctor.gemspec +7 -1
  9. data/data/locale/attributes-ar.adoc +22 -0
  10. data/data/locale/attributes-bg.adoc +22 -0
  11. data/data/locale/attributes-ca.adoc +22 -0
  12. data/data/locale/attributes-cs.adoc +22 -0
  13. data/data/locale/attributes-da.adoc +22 -0
  14. data/data/locale/attributes-de.adoc +22 -0
  15. data/data/locale/attributes-en.adoc +23 -0
  16. data/data/locale/attributes-es.adoc +22 -0
  17. data/data/locale/attributes-fa.adoc +22 -0
  18. data/data/locale/attributes-fi.adoc +22 -0
  19. data/data/locale/attributes-fr.adoc +22 -0
  20. data/data/locale/attributes-hu.adoc +22 -0
  21. data/data/locale/attributes-id.adoc +22 -0
  22. data/data/locale/attributes-it.adoc +22 -0
  23. data/data/locale/attributes-ja.adoc +22 -0
  24. data/data/locale/attributes-kr.adoc +22 -0
  25. data/data/locale/attributes-nb.adoc +22 -0
  26. data/data/locale/attributes-nl.adoc +22 -0
  27. data/data/locale/attributes-nn.adoc +22 -0
  28. data/data/locale/attributes-pl.adoc +22 -0
  29. data/data/locale/attributes-pt.adoc +22 -0
  30. data/data/locale/attributes-pt_BR.adoc +22 -0
  31. data/data/locale/attributes-ro.adoc +22 -0
  32. data/data/locale/attributes-ru.adoc +22 -0
  33. data/data/locale/attributes-sr.adoc +22 -0
  34. data/data/locale/attributes-sr_Latn.adoc +22 -0
  35. data/data/locale/attributes-tr.adoc +22 -0
  36. data/data/locale/attributes-uk.adoc +22 -0
  37. data/data/locale/attributes-zh_CN.adoc +22 -0
  38. data/data/locale/attributes-zh_TW.adoc +22 -0
  39. data/data/locale/attributes.adoc +8 -649
  40. data/data/stylesheets/asciidoctor-default.css +77 -72
  41. data/features/xref.feature +366 -7
  42. data/lib/asciidoctor.rb +107 -93
  43. data/lib/asciidoctor/abstract_block.rb +247 -239
  44. data/lib/asciidoctor/abstract_node.rb +56 -58
  45. data/lib/asciidoctor/block.rb +3 -3
  46. data/lib/asciidoctor/callouts.rb +1 -1
  47. data/lib/asciidoctor/cli/invoker.rb +36 -9
  48. data/lib/asciidoctor/cli/options.rb +63 -25
  49. data/lib/asciidoctor/converter.rb +23 -13
  50. data/lib/asciidoctor/converter/base.rb +4 -0
  51. data/lib/asciidoctor/converter/docbook45.rb +16 -9
  52. data/lib/asciidoctor/converter/docbook5.rb +115 -97
  53. data/lib/asciidoctor/converter/factory.rb +29 -31
  54. data/lib/asciidoctor/converter/html5.rb +229 -192
  55. data/lib/asciidoctor/converter/manpage.rb +72 -50
  56. data/lib/asciidoctor/converter/template.rb +12 -12
  57. data/lib/asciidoctor/core_ext.rb +5 -1
  58. data/lib/asciidoctor/core_ext/1.8.7/base64/strict_encode64.rb +6 -0
  59. data/lib/asciidoctor/document.rb +168 -77
  60. data/lib/asciidoctor/extensions.rb +79 -47
  61. data/lib/asciidoctor/helpers.rb +33 -11
  62. data/lib/asciidoctor/inline.rb +3 -2
  63. data/lib/asciidoctor/list.rb +2 -1
  64. data/lib/asciidoctor/logging.rb +122 -0
  65. data/lib/asciidoctor/parser.rb +406 -382
  66. data/lib/asciidoctor/path_resolver.rb +169 -162
  67. data/lib/asciidoctor/reader.rb +166 -121
  68. data/lib/asciidoctor/section.rb +45 -28
  69. data/lib/asciidoctor/stylesheets.rb +13 -5
  70. data/lib/asciidoctor/substitutors.rb +328 -254
  71. data/lib/asciidoctor/table.rb +105 -48
  72. data/lib/asciidoctor/timings.rb +34 -6
  73. data/lib/asciidoctor/version.rb +1 -1
  74. data/man/asciidoctor.1 +41 -23
  75. data/man/asciidoctor.adoc +14 -8
  76. data/test/api_test.rb +1004 -0
  77. data/test/attributes_test.rb +241 -50
  78. data/test/blocks_test.rb +549 -124
  79. data/test/converter_test.rb +170 -78
  80. data/test/document_test.rb +208 -767
  81. data/test/extensions_test.rb +188 -53
  82. data/test/fixtures/custom-backends/slim/html5/block_paragraph.html.slim +1 -1
  83. data/test/fixtures/custom-backends/slim/html5/block_sidebar.html.slim +1 -1
  84. data/test/fixtures/file-with-missing-include.adoc +1 -0
  85. data/test/fixtures/include-file.jsx +8 -0
  86. data/test/fixtures/lists.adoc +96 -0
  87. data/test/fixtures/other-chapters.adoc +11 -0
  88. data/test/fixtures/outer-include.adoc +5 -0
  89. data/test/fixtures/sample.asciidoc +5 -1
  90. data/test/fixtures/subdir/index.adoc +3 -0
  91. data/test/fixtures/subdir/inner-include.adoc +3 -0
  92. data/test/fixtures/subdir/middle-include.adoc +5 -0
  93. data/test/fixtures/tagged-class-enclosed.rb +0 -1
  94. data/test/fixtures/unclosed-tag.adoc +3 -0
  95. data/test/fixtures/unexpected-end-tag.adoc +4 -0
  96. data/test/invoker_test.rb +101 -40
  97. data/test/links_test.rb +266 -72
  98. data/test/lists_test.rb +243 -45
  99. data/test/logger_test.rb +211 -0
  100. data/test/manpage_test.rb +124 -6
  101. data/test/options_test.rb +46 -1
  102. data/test/paragraphs_test.rb +23 -10
  103. data/test/parser_test.rb +30 -1
  104. data/test/paths_test.rb +115 -33
  105. data/test/preamble_test.rb +1 -1
  106. data/test/reader_test.rb +337 -81
  107. data/test/sections_test.rb +656 -72
  108. data/test/substitutions_test.rb +182 -57
  109. data/test/tables_test.rb +324 -57
  110. data/test/test_helper.rb +77 -32
  111. data/test/text_test.rb +7 -7
  112. metadata +67 -3
@@ -194,7 +194,7 @@ Note that multi-entry terms generate separate index entries.
194
194
  EOS
195
195
 
196
196
  output = render_embedded_string input
197
- assert output.include?('*<Hey Jude>*')
197
+ assert_includes output, '*<Hey Jude>*'
198
198
  end
199
199
 
200
200
  test 'normal paragraph should honor specialchars shorthand' do
@@ -204,7 +204,7 @@ Note that multi-entry terms generate separate index entries.
204
204
  EOS
205
205
 
206
206
  output = render_embedded_string input
207
- assert output.include?('*<Hey Jude>*')
207
+ assert_includes output, '*<Hey Jude>*'
208
208
  end
209
209
 
210
210
  test 'should add a hardbreak at end of each line when hardbreaks option is set' do
@@ -218,7 +218,7 @@ lips
218
218
  output = render_embedded_string input
219
219
  assert_css 'br', output, 2
220
220
  assert_xpath '//p', output, 1
221
- assert output.include?("<p>read<br>\nmy<br>\nlips</p>")
221
+ assert_includes output, "<p>read<br>\nmy<br>\nlips</p>"
222
222
  end
223
223
  end
224
224
 
@@ -371,7 +371,7 @@ _GET /groups/link:#group-id[\{group-id\}]_
371
371
  EOS
372
372
 
373
373
  output = render_embedded_string input
374
- assert output.include?('<pre class="content"><em>GET /groups/<a href="#group-id">{group-id}</a></em></pre>')
374
+ assert_includes output, '<pre class="content"><em>GET /groups/<a href="#group-id">{group-id}</a></em></pre>'
375
375
  end
376
376
 
377
377
  test 'quote paragraph should honor explicit subs list' do
@@ -382,7 +382,7 @@ _GET /groups/link:#group-id[\{group-id\}]_
382
382
  EOS
383
383
 
384
384
  output = render_embedded_string input
385
- assert output.include?('*Hey Jude*')
385
+ assert_includes output, '*Hey Jude*'
386
386
  end
387
387
  end
388
388
 
@@ -465,6 +465,9 @@ As you can see here.
465
465
 
466
466
  [quote]
467
467
  Wise words from a wise person.
468
+
469
+ [open]
470
+ Make it what you want.
468
471
  EOS
469
472
 
470
473
  output = render_string input, :backend => 'docbook'
@@ -473,6 +476,18 @@ Wise words from a wise person.
473
476
  assert_css 'sidebar > simpara', output, 1
474
477
  assert_css 'informalexample > simpara', output, 1
475
478
  assert_css 'blockquote > simpara', output, 1
479
+ assert_css 'chapter > simpara', output, 1
480
+ end
481
+
482
+ test 'should convert open paragraph to open block' do
483
+ input = <<-EOS
484
+ [open]
485
+ Make it what you want.
486
+ EOS
487
+
488
+ output = render_embedded_string input
489
+ assert_css '.openblock', output, 1
490
+ assert_css '.openblock p', output, 0
476
491
  end
477
492
 
478
493
  test 'should wrap text in simpara for styled paragraphs with title when rendered to DocBook' do
@@ -536,13 +551,11 @@ Wise words from a wise person.
536
551
 
537
552
  test 'should output nil and warn if first block is not a paragraph' do
538
553
  input = '* bullet'
539
- output = nil
540
- warnings = redirect_streams do |_, err|
554
+ using_memory_logger do |logger|
541
555
  output = render_string input, :doctype => 'inline'
542
- err.string
556
+ assert_nil output
557
+ assert_message logger, :WARN, '~no inline candidate'
543
558
  end
544
- assert_nil output
545
- assert_includes warnings, 'no inline candidate'
546
559
  end
547
560
  end
548
561
  end
@@ -351,7 +351,7 @@ context "Parser" do
351
351
  attributes = {1 => '%header', 'options' => 'footer', 'footer-option' => ''}
352
352
  style = Asciidoctor::Parser.parse_style_attribute(attributes)
353
353
  assert_nil style
354
- assert_equal 'header,footer', attributes['options']
354
+ assert_equal 'footer,header', attributes['options']
355
355
  assert_equal '', attributes['header-option']
356
356
  assert_equal '', attributes['footer-option']
357
357
  end
@@ -526,6 +526,13 @@ context "Parser" do
526
526
  assert_equal 'John Smith', metadata['author_2']
527
527
  end
528
528
 
529
+ test 'skips blank author entries in implicit author line' do
530
+ metadata, _ = parse_header_metadata 'Doc Writer; ; John Smith <john.smith@asciidoc.org>;'
531
+ assert_equal 2, metadata['authorcount']
532
+ assert_equal 'Doc Writer', metadata['author_1']
533
+ assert_equal 'John Smith', metadata['author_2']
534
+ end
535
+
529
536
  test 'parse name with more than 3 parts in author attribute' do
530
537
  doc = empty_document
531
538
  parse_header_metadata ':author: Leroy Harold Scherer, Jr.', doc
@@ -535,6 +542,14 @@ context "Parser" do
535
542
  assert_equal 'Scherer, Jr.', doc.attributes['lastname']
536
543
  end
537
544
 
545
+ test 'sets authorcount to 0 if document has no authors' do
546
+ input = ''
547
+ doc = empty_document
548
+ metadata, _ = parse_header_metadata input, doc
549
+ assert_equal 0, doc.attributes['authorcount']
550
+ assert_equal 0, metadata['authorcount']
551
+ end
552
+
538
553
  test 'does not drop name joiner when using multiple authors' do
539
554
  input = <<-EOS
540
555
  Kismet Chameleon; Lazarus het_Draeke
@@ -712,6 +727,20 @@ v0.0.7, 2013-12-18
712
727
  assert_equal '2013-12-18', metadata['revdate']
713
728
  end
714
729
 
730
+ test 'break header at line with three forward slashes' do
731
+ input = <<-EOS
732
+ Joe Cool
733
+ v1.0
734
+ ///
735
+ stuff
736
+ EOS
737
+ metadata, _ = parse_header_metadata input
738
+ assert_equal 7, metadata.size
739
+ assert_equal 1, metadata['authorcount']
740
+ assert_equal 'Joe Cool', metadata['author']
741
+ assert_equal '1.0', metadata['revnumber']
742
+ end
743
+
715
744
  test 'attribute entry overrides generated author initials' do
716
745
  doc = empty_document
717
746
  metadata, _ = parse_header_metadata %(Stuart Rackham <founder@asciidoc.org>\n:Author Initials: SJR), doc
@@ -89,6 +89,7 @@ context 'Path Resolver' do
89
89
  end
90
90
 
91
91
  test 'posixifies windows paths' do
92
+ @resolver.file_separator = '\\'
92
93
  assert_equal '/images', @resolver.web_path('\\images')
93
94
  assert_equal '../images', @resolver.web_path('..\\images')
94
95
  assert_equal '/images', @resolver.web_path('\\..\\images')
@@ -103,29 +104,47 @@ context 'Path Resolver' do
103
104
 
104
105
  context 'System Paths' do
105
106
  JAIL = '/home/doctor/docs'
107
+ default_logger = Asciidoctor::LoggerManager.logger
106
108
 
107
109
  def setup
108
110
  @resolver = Asciidoctor::PathResolver.new
111
+ @logger = (Asciidoctor::LoggerManager.logger = Asciidoctor::MemoryLogger.new)
109
112
  end
110
113
 
111
- test 'prevents access to paths outside of jail' do
112
- result, warnings = redirect_streams do |_, err|
113
- [(@resolver.system_path '../../../../../css', %(#{JAIL}/assets/stylesheets), JAIL), err.string]
114
+ teardown do
115
+ Asciidoctor::LoggerManager.logger = default_logger
116
+ end
117
+
118
+ test 'raises security error if jail is not an absolute path' do
119
+ begin
120
+ @resolver.system_path('images/tiger.png', '/etc', 'foo')
121
+ flunk 'Expecting SecurityError to be raised'
122
+ rescue SecurityError
114
123
  end
124
+ end
125
+
126
+ #test 'raises security error if jail is not a canoncial path' do
127
+ # begin
128
+ # @resolver.system_path('images/tiger.png', '/etc', %(#{JAIL}/../foo))
129
+ # flunk 'Expecting SecurityError to be raised'
130
+ # rescue SecurityError
131
+ # end
132
+ #end
133
+
134
+ test 'prevents access to paths outside of jail' do
135
+ result = @resolver.system_path '../../../../../css', %(#{JAIL}/assets/stylesheets), JAIL
115
136
  assert_equal %(#{JAIL}/css), result
116
- assert_includes warnings, 'path has illegal reference to ancestor of jail'
137
+ assert_message @logger, :WARN, 'path has illegal reference to ancestor of jail; recovering automatically'
117
138
 
118
- result, warnings = redirect_streams do |_, err|
119
- [(@resolver.system_path '/../../../../../css', %(#{JAIL}/assets/stylesheets), JAIL), err.string]
120
- end
139
+ @logger.clear
140
+ result = @resolver.system_path '/../../../../../css', %(#{JAIL}/assets/stylesheets), JAIL
121
141
  assert_equal %(#{JAIL}/css), result
122
- assert_includes warnings, 'path has illegal reference to ancestor of jail'
142
+ assert_message @logger, :WARN, 'path is outside of jail; recovering automatically'
123
143
 
124
- result, warnings = redirect_streams do |_, err|
125
- [(@resolver.system_path '../../../css', '../../..', JAIL), err.string]
126
- end
144
+ @logger.clear
145
+ result = @resolver.system_path '../../../css', '../../..', JAIL
127
146
  assert_equal %(#{JAIL}/css), result
128
- assert_includes warnings, 'path has illegal reference to ancestor of jail'
147
+ assert_message @logger, :WARN, 'path has illegal reference to ancestor of jail; recovering automatically'
129
148
  end
130
149
 
131
150
  test 'throws exception for illegal path access if recover is false' do
@@ -141,15 +160,39 @@ context 'Path Resolver' do
141
160
  assert_equal "#{JAIL}/assets/stylesheets", @resolver.system_path(nil, "#{JAIL}/assets/stylesheets", JAIL)
142
161
  end
143
162
 
163
+ test 'expands parent references in start path if target is empty' do
164
+ assert_equal "#{JAIL}/stylesheets", @resolver.system_path('', "#{JAIL}/assets/../stylesheets", JAIL)
165
+ end
166
+
167
+ test 'expands parent references in start path if target is not empty' do
168
+ assert_equal "#{JAIL}/stylesheets/site.css", @resolver.system_path('site.css', "#{JAIL}/assets/../stylesheets", JAIL)
169
+ end
170
+
144
171
  test 'resolves start path if target is dot' do
145
172
  assert_equal "#{JAIL}/assets/stylesheets", @resolver.system_path('.', "#{JAIL}/assets/stylesheets", JAIL)
146
173
  assert_equal "#{JAIL}/assets/stylesheets", @resolver.system_path('./', "#{JAIL}/assets/stylesheets", JAIL)
147
174
  end
148
175
 
149
- test 'treats absolute target as relative when jail is specified' do
150
- assert_equal "#{JAIL}/assets/stylesheets", @resolver.system_path('/', "#{JAIL}/assets/stylesheets", JAIL)
151
- assert_equal "#{JAIL}/assets/stylesheets/foo", @resolver.system_path('/foo', "#{JAIL}/assets/stylesheets", JAIL)
152
- assert_equal "#{JAIL}/assets/foo", @resolver.system_path('/../foo', "#{JAIL}/assets/stylesheets", JAIL)
176
+ test 'treats absolute target outside of jail as relative when jail is specified' do
177
+ result = @resolver.system_path '/', "#{JAIL}/assets/stylesheets", JAIL
178
+ assert_equal JAIL, result
179
+ assert_message @logger, :WARN, 'path is outside of jail; recovering automatically'
180
+
181
+ @logger.clear
182
+ result = @resolver.system_path '/foo', "#{JAIL}/assets/stylesheets", JAIL
183
+ assert_equal "#{JAIL}/foo", result
184
+ assert_message @logger, :WARN, 'path is outside of jail; recovering automatically'
185
+
186
+ @logger.clear
187
+ result = @resolver.system_path '/../foo', "#{JAIL}/assets/stylesheets", JAIL
188
+ assert_equal "#{JAIL}/foo", result
189
+ assert_message @logger, :WARN, 'path is outside of jail; recovering automatically'
190
+
191
+ @logger.clear
192
+ @resolver.file_separator = '\\'
193
+ result = @resolver.system_path 'baz.adoc', 'C:/foo', 'C:/bar'
194
+ assert_equal 'C:/bar/baz.adoc', result
195
+ assert_message @logger, :WARN, 'path is outside of jail; recovering automatically'
153
196
  end
154
197
 
155
198
  test 'allows use of absolute target or start if resolved path is sub-path of jail' do
@@ -158,6 +201,9 @@ context 'Path Resolver' do
158
201
  assert_equal "#{JAIL}/my/path", @resolver.system_path('', "#{JAIL}/my/path", JAIL)
159
202
  assert_equal "#{JAIL}/my/path", @resolver.system_path(nil, "#{JAIL}/my/path", JAIL)
160
203
  assert_equal "#{JAIL}/my/path", @resolver.system_path('path', "#{JAIL}/my", JAIL)
204
+ assert_equal '/foo/bar/baz.adoc', @resolver.system_path('/foo/bar/baz.adoc', nil, '/')
205
+ assert_equal '/foo/bar/baz.adoc', @resolver.system_path('baz.adoc', '/foo/bar', '/')
206
+ assert_equal '/foo/bar/baz.adoc', @resolver.system_path('baz.adoc', 'foo/bar', '/')
161
207
  end
162
208
 
163
209
  test 'uses jail path if start path is empty' do
@@ -165,20 +211,59 @@ context 'Path Resolver' do
165
211
  assert_equal "#{JAIL}/images/tiger.png", @resolver.system_path('images/tiger.png', nil, JAIL)
166
212
  end
167
213
 
168
- test 'raises security error if start is not contained within jail' do
214
+ test 'warns if start is not contained within jail' do
215
+ result = @resolver.system_path 'images/tiger.png', '/etc', JAIL
216
+ assert_equal %(#{JAIL}/images/tiger.png), result
217
+ assert_message @logger, :WARN, 'path is outside of jail; recovering automatically'
218
+
219
+ @logger.clear
220
+ result = @resolver.system_path '.', '/etc', JAIL
221
+ assert_equal JAIL, result
222
+ assert_message @logger, :WARN, 'path is outside of jail; recovering automatically'
223
+
224
+ @logger.clear
225
+ @resolver.file_separator = '\\'
226
+ result = @resolver.system_path '.', 'C:/foo', 'C:/bar'
227
+ assert_equal 'C:/bar', result
228
+ assert_message @logger, :WARN, 'path is outside of jail; recovering automatically'
229
+ end
230
+
231
+ test 'allows start path to be parent of jail if resolved target is inside jail' do
232
+ assert_equal "#{JAIL}/foo/path", @resolver.system_path('foo/path', JAIL, "#{JAIL}/foo")
233
+ @resolver.file_separator = '\\'
234
+ assert_equal "C:/dev/project/README.adoc", @resolver.system_path('project/README.adoc', 'C:/dev', 'C:/dev/project')
235
+ end
236
+
237
+ test 'relocates target to jail if resolved value fails outside of jail' do
238
+ result = @resolver.system_path 'bar/baz.adoc', JAIL, "#{JAIL}/foo"
239
+ assert_equal %(#{JAIL}/foo/bar/baz.adoc), result
240
+ assert_message @logger, :WARN, 'path is outside of jail; recovering automatically'
241
+
242
+ @logger.clear
243
+ @resolver.file_separator = '\\'
244
+ result = @resolver.system_path 'bar/baz.adoc', 'D:/', 'C:/foo'
245
+ assert_equal 'C:/foo/bar/baz.adoc', result
246
+ assert_message @logger, :WARN, '~outside of jail root'
247
+ end
248
+
249
+ test 'raises security error if start is not contained within jail and recover is disabled' do
169
250
  begin
170
- @resolver.system_path('images/tiger.png', '/etc', JAIL)
251
+ @resolver.system_path('images/tiger.png', '/etc', JAIL, :recover => false)
171
252
  flunk 'Expecting SecurityError to be raised'
172
253
  rescue SecurityError
173
254
  end
174
255
 
175
256
  begin
176
- @resolver.system_path('.', '/etc', JAIL)
257
+ @resolver.system_path('.', '/etc', JAIL, :recover => false)
177
258
  flunk 'Expecting SecurityError to be raised'
178
259
  rescue SecurityError
179
260
  end
180
261
  end
181
262
 
263
+ test 'expands parent references in absolute path if jail is not specified' do
264
+ assert_equal '/etc/stylesheet.css', @resolver.system_path('/usr/share/../../etc/stylesheet.css')
265
+ end
266
+
182
267
  test 'resolves absolute directory if jail is not specified' do
183
268
  assert_equal '/usr/share/stylesheet.css', @resolver.system_path('/usr/share/stylesheet.css', '/home/dallen/docs/assets/stylesheets')
184
269
  end
@@ -208,19 +293,19 @@ context 'Path Resolver' do
208
293
  assert_equal "#{pwd}/.images/tiger.png", @resolver.system_path('.images/tiger.png', nil)
209
294
  end
210
295
 
211
- test 'resolves and normalizes start with target is empty' do
296
+ test 'resolves and normalizes start when target is empty' do
212
297
  pwd = File.expand_path Dir.pwd
213
298
  assert_equal '/home/doctor/docs', (@resolver.system_path '', '/home/doctor/docs')
299
+ assert_equal '/home/doctor/docs', (@resolver.system_path '', '/home/doctor/./docs')
214
300
  assert_equal '/home/doctor/docs', (@resolver.system_path nil, '/home/doctor/docs')
301
+ assert_equal '/home/doctor/docs', (@resolver.system_path nil, '/home/doctor/./docs')
215
302
  assert_equal %(#{pwd}/assets/images), (@resolver.system_path nil, 'assets/images')
216
- result, warnings = redirect_streams do |_, err|
217
- [(@resolver.system_path '', '../assets/images', JAIL), err.string]
218
- end
219
- assert_equal %(#{JAIL}/assets/images), result
220
- assert_includes warnings, 'path has illegal reference to ancestor of jail'
303
+ @resolver.system_path '', '../assets/images', JAIL
304
+ assert_message @logger, :WARN, 'path has illegal reference to ancestor of jail; recovering automatically'
221
305
  end
222
306
 
223
307
  test 'posixifies windows paths' do
308
+ @resolver.file_separator = '\\'
224
309
  assert_equal "#{JAIL}/assets/css", @resolver.system_path('..\\css', 'assets\\stylesheets', JAIL)
225
310
  end
226
311
 
@@ -229,17 +314,14 @@ context 'Path Resolver' do
229
314
 
230
315
  assert_equal 'C:/data/docs', (@resolver.system_path '..', 'C:\\data\\docs\\assets', 'C:\\data\\docs')
231
316
 
232
- result, warnings = redirect_streams do |_, err|
233
- [(@resolver.system_path '..\\..', 'C:\\data\\docs\\assets', 'C:\\data\\docs'), err.string]
234
- end
317
+ result = @resolver.system_path '..\\..', 'C:\\data\\docs\\assets', 'C:\\data\\docs'
235
318
  assert_equal 'C:/data/docs', result
236
- assert_includes warnings, 'path has illegal reference to ancestor of jail'
319
+ assert_message @logger, :WARN, 'path has illegal reference to ancestor of jail; recovering automatically'
237
320
 
238
- result, warnings = redirect_streams do |_, err|
239
- [(@resolver.system_path '..\\..\\css', 'C:\\data\\docs\\assets', 'C:\\data\\docs'), err.string]
240
- end
321
+ @logger.clear
322
+ result = @resolver.system_path '..\\..\\css', 'C:\\data\\docs\\assets', 'C:\\data\\docs'
241
323
  assert_equal 'C:/data/docs/css', result
242
- assert_includes warnings, 'path has illegal reference to ancestor of jail'
324
+ assert_message @logger, :WARN, 'path has illegal reference to ancestor of jail; recovering automatically'
243
325
  end
244
326
 
245
327
  test 'should calculate relative path' do
@@ -145,7 +145,7 @@ The axe came swinging.
145
145
 
146
146
  d = document_from_string(input)
147
147
  assert_equal 'book', d.doctype
148
- output = d.render
148
+ output = d.convert
149
149
  assert_xpath '//h1', output, 3
150
150
  assert_xpath %{//*[@id="preamble"]//p[text() = "Back then#{decode_char 8230}#{decode_char 8203}"]}, output, 1
151
151
  end
@@ -5,7 +5,7 @@ unless defined? ASCIIDOCTOR_PROJECT_DIR
5
5
  end
6
6
 
7
7
  class ReaderTest < Minitest::Test
8
- DIRNAME = File.expand_path(File.dirname(__FILE__))
8
+ DIRNAME = File.expand_path File.dirname __FILE__
9
9
 
10
10
  SAMPLE_DATA = <<-EOS.chomp.split(::Asciidoctor::LF)
11
11
  first line
@@ -156,6 +156,12 @@ third line
156
156
  assert_equal 1, reader.lineno
157
157
  end
158
158
 
159
+ test 'peek_lines should peek all lines if no arguments are given' do
160
+ reader = Asciidoctor::Reader.new SAMPLE_DATA
161
+ assert_equal SAMPLE_DATA, reader.peek_lines
162
+ assert_equal 1, reader.lineno
163
+ end
164
+
159
165
  test 'peek_lines should not invert order of lines' do
160
166
  reader = Asciidoctor::Reader.new SAMPLE_DATA
161
167
  assert_equal SAMPLE_DATA, reader.lines
@@ -251,13 +257,13 @@ third line
251
257
  reader = Asciidoctor::Reader.new SAMPLE_DATA, 'sample.adoc'
252
258
  reader.read_line
253
259
  assert_equal 'sample.adoc: line 2', reader.line_info
254
- assert_equal 'sample.adoc: line 2', reader.next_line_info
260
+ assert_equal 'sample.adoc: line 2', reader.cursor.to_s
255
261
  end
256
262
 
257
- test 'prev_line_info should return file name and line number of previous line read' do
263
+ test 'cursor_at_prev_line should return file name and line number of previous line read' do
258
264
  reader = Asciidoctor::Reader.new SAMPLE_DATA, 'sample.adoc'
259
265
  reader.read_line
260
- assert_equal 'sample.adoc: line 1', reader.prev_line_info
266
+ assert_equal 'sample.adoc: line 1', reader.cursor_at_prev_line.to_s
261
267
  end
262
268
  end
263
269
 
@@ -361,6 +367,50 @@ This is a paragraph outside the block.
361
367
  assert_equal lines[1, 4], result
362
368
  assert_equal '--', reader.peek_line
363
369
  end
370
+
371
+ test 'read lines until terminator' do
372
+ lines = <<-EOS.each_line.to_a
373
+ ****
374
+ captured
375
+
376
+ also captured
377
+ ****
378
+
379
+ not captured
380
+ EOS
381
+
382
+ expected = ['captured', '', 'also captured']
383
+
384
+ doc = empty_safe_document :base_dir => DIRNAME
385
+ reader = Asciidoctor::PreprocessorReader.new doc, lines, nil, :normalize => true
386
+ terminator = reader.read_line
387
+ result = reader.read_lines_until :terminator => terminator, :skip_processing => true
388
+ assert_equal expected, result
389
+ refute reader.unterminated
390
+ end
391
+
392
+ test 'should flag reader as unterminated if reader reaches end of source without finding terminator' do
393
+ lines = <<-EOS.each_line.to_a
394
+ ****
395
+ captured
396
+
397
+ also captured
398
+
399
+ captured yet again
400
+ EOS
401
+
402
+ expected = lines[1..-1].map {|l| l.chomp }
403
+
404
+ using_memory_logger do |logger|
405
+ doc = empty_safe_document :base_dir => DIRNAME
406
+ reader = Asciidoctor::PreprocessorReader.new doc, lines, nil, :normalize => true
407
+ terminator = reader.peek_line
408
+ result = reader.read_lines_until :terminator => terminator, :skip_first_line => true, :skip_processing => true
409
+ assert_equal expected, result
410
+ assert reader.unterminated
411
+ assert_message logger, :WARN, '<stdin>: line 1: unterminated **** block', Hash
412
+ end
413
+ end
364
414
  end
365
415
  end
366
416
 
@@ -368,7 +418,7 @@ This is a paragraph outside the block.
368
418
  context 'Type hierarchy' do
369
419
  test 'PreprocessorReader should extend from Reader' do
370
420
  reader = empty_document.reader
371
- assert reader.is_a?(Asciidoctor::Reader)
421
+ assert_kind_of Asciidoctor::PreprocessorReader, reader
372
422
  end
373
423
 
374
424
  test 'PreprocessorReader should invoke or emulate Reader initializer' do
@@ -489,6 +539,36 @@ preamble
489
539
  assert_nil reader.file
490
540
  assert_equal '<stdin>', reader.path
491
541
  end
542
+
543
+ test 'PreprocessorReader#push_include method should set path from file automatically if not specified' do
544
+ lines = %w(a b c)
545
+ doc = Asciidoctor::Document.new lines
546
+ reader = doc.reader
547
+ append_lines = %w(one two three)
548
+ reader.push_include append_lines, '/tmp/lines.adoc'
549
+ assert_equal '/tmp/lines.adoc', reader.file
550
+ assert_equal 'lines.adoc', reader.path
551
+ end
552
+
553
+ test 'PreprocessorReader#push_include method should accept file as a URI and compute dir and path' do
554
+ file_uri = ::URI.parse 'http://example.com/docs/file.adoc'
555
+ dir_uri = ::URI.parse 'http://example.com/docs'
556
+ reader = empty_document.reader
557
+ reader.push_include %w(one two three), file_uri
558
+ assert_same file_uri, reader.file
559
+ assert_equal dir_uri, reader.dir
560
+ assert_equal 'file.adoc', reader.path
561
+ end
562
+
563
+ test 'PreprocessorReader#push_include method should accept file as a top-level URI and compute dir and path' do
564
+ file_uri = ::URI.parse 'http://example.com/index.adoc'
565
+ dir_uri = ::URI.parse 'http://example.com'
566
+ reader = empty_document.reader
567
+ reader.push_include %w(one two three), file_uri
568
+ assert_same file_uri, reader.file
569
+ assert_equal dir_uri, reader.dir
570
+ assert_equal 'index.adoc', reader.path
571
+ end
492
572
  end
493
573
 
494
574
  context 'Include Directive' do
@@ -507,8 +587,20 @@ include::fixtures/include-file.asciidoc[]
507
587
  EOS
508
588
 
509
589
  doc = document_from_string input, :safe => :safe, :header_footer => false, :base_dir => DIRNAME
510
- output = doc.render
590
+ output = doc.convert
511
591
  assert_match(/included content/, output)
592
+ assert doc.catalog[:includes]['fixtures/include-file']
593
+ end
594
+
595
+ test 'should not track include in catalog for non-AsciiDoc include files' do
596
+ input = <<-EOS
597
+ ----
598
+ include::fixtures/circle.svg[]
599
+ ----
600
+ EOS
601
+
602
+ doc = document_from_string input, :safe => :safe, :header_footer => false, :base_dir => DIRNAME
603
+ assert doc.catalog[:includes].empty?
512
604
  end
513
605
 
514
606
  test 'include directive should resolve file with spaces in name' do
@@ -521,7 +613,7 @@ include::fixtures/include file.asciidoc[]
521
613
  begin
522
614
  FileUtils.cp include_file, include_file_with_sp
523
615
  doc = document_from_string input, :safe => :safe, :header_footer => false, :base_dir => DIRNAME
524
- output = doc.render
616
+ output = doc.convert
525
617
  assert_match(/included content/, output)
526
618
  ensure
527
619
  FileUtils.rm include_file_with_sp
@@ -538,7 +630,7 @@ include::fixtures/include{sp}file.asciidoc[]
538
630
  begin
539
631
  FileUtils.cp include_file, include_file_with_sp
540
632
  doc = document_from_string input, :safe => :safe, :header_footer => false, :base_dir => DIRNAME
541
- output = doc.render
633
+ output = doc.convert
542
634
  assert_match(/included content/, output)
543
635
  ensure
544
636
  FileUtils.rm include_file_with_sp
@@ -565,7 +657,7 @@ include::fixtures/parent-include.adoc[]
565
657
 
566
658
  assert_equal 'first line of parent', reader.read_line
567
659
 
568
- assert_equal 'fixtures/parent-include.adoc: line 1', reader.prev_line_info
660
+ assert_equal 'fixtures/parent-include.adoc: line 1', reader.cursor_at_prev_line.to_s
569
661
  assert_equal parent_include_docfile, reader.file
570
662
  assert_equal fixtures_dir, reader.dir
571
663
  assert_equal 'fixtures/parent-include.adoc', reader.path
@@ -574,7 +666,7 @@ include::fixtures/parent-include.adoc[]
574
666
 
575
667
  assert_equal 'first line of child', reader.read_line
576
668
 
577
- assert_equal 'fixtures/child-include.adoc: line 1', reader.prev_line_info
669
+ assert_equal 'fixtures/child-include.adoc: line 1', reader.cursor_at_prev_line.to_s
578
670
  assert_equal child_include_docfile, reader.file
579
671
  assert_equal fixtures_dir, reader.dir
580
672
  assert_equal 'fixtures/child-include.adoc', reader.path
@@ -583,7 +675,7 @@ include::fixtures/parent-include.adoc[]
583
675
 
584
676
  assert_equal 'first line of grandchild', reader.read_line
585
677
 
586
- assert_equal 'fixtures/grandchild-include.adoc: line 1', reader.prev_line_info
678
+ assert_equal 'fixtures/grandchild-include.adoc: line 1', reader.cursor_at_prev_line.to_s
587
679
  assert_equal grandchild_include_docfile, reader.file
588
680
  assert_equal fixtures_dir, reader.dir
589
681
  assert_equal 'fixtures/grandchild-include.adoc', reader.path
@@ -600,12 +692,31 @@ include::fixtures/parent-include.adoc[]
600
692
 
601
693
  assert_equal 'last line of parent', reader.read_line
602
694
 
603
- assert_equal 'fixtures/parent-include.adoc: line 5', reader.prev_line_info
695
+ assert_equal 'fixtures/parent-include.adoc: line 5', reader.cursor_at_prev_line.to_s
604
696
  assert_equal parent_include_docfile, reader.file
605
697
  assert_equal fixtures_dir, reader.dir
606
698
  assert_equal 'fixtures/parent-include.adoc', reader.path
607
699
  end
608
700
 
701
+ test 'missing file referenced by include directive is skipped when optional option is set' do
702
+ input = <<-EOS
703
+ include::fixtures/no-such-file.adoc[opts=optional]
704
+
705
+ trailing content
706
+ EOS
707
+
708
+ begin
709
+ using_memory_logger do |logger|
710
+ doc = document_from_string input, :safe => :safe, :base_dir => DIRNAME
711
+ assert_equal 1, doc.blocks.size
712
+ assert_equal ['trailing content'], doc.blocks[0].lines
713
+ assert logger.empty?
714
+ end
715
+ rescue
716
+ flunk 'include directive should not raise exception on missing file'
717
+ end
718
+ end
719
+
609
720
  test 'missing file referenced by include directive is replaced by warning' do
610
721
  input = <<-EOS
611
722
  include::fixtures/no-such-file.adoc[]
@@ -614,13 +725,13 @@ trailing content
614
725
  EOS
615
726
 
616
727
  begin
617
- doc, warnings = redirect_streams do |_, err|
618
- [(document_from_string input, :safe => :safe, :base_dir => DIRNAME), err.string]
728
+ using_memory_logger do |logger|
729
+ doc = document_from_string input, :safe => :safe, :base_dir => DIRNAME
730
+ assert_equal 2, doc.blocks.size
731
+ assert_equal ['Unresolved directive in <stdin> - include::fixtures/no-such-file.adoc[]'], doc.blocks[0].lines
732
+ assert_equal ['trailing content'], doc.blocks[1].lines
733
+ assert_message logger, :ERROR, '~<stdin>: line 1: include file not found', Hash
619
734
  end
620
- assert_equal 2, doc.blocks.size
621
- assert_equal ['Unresolved directive in <stdin> - include::fixtures/no-such-file.adoc[]'], doc.blocks[0].lines
622
- assert_equal ['trailing content'], doc.blocks[1].lines
623
- assert_includes warnings, 'include file not found'
624
735
  rescue
625
736
  flunk 'include directive should not raise exception on missing file'
626
737
  end
@@ -636,13 +747,13 @@ trailing content
636
747
  EOS
637
748
 
638
749
  begin
639
- doc, warnings = redirect_streams do |_, err|
640
- [(document_from_string input, :safe => :safe, :base_dir => DIRNAME), err.string]
750
+ using_memory_logger do |logger|
751
+ doc = document_from_string input, :safe => :safe, :base_dir => DIRNAME
752
+ assert_equal 2, doc.blocks.size
753
+ assert_equal ['Unresolved directive in <stdin> - include::fixtures/chapter-a.adoc[]'], doc.blocks[0].lines
754
+ assert_equal ['trailing content'], doc.blocks[1].lines
755
+ assert_message logger, :ERROR, '~<stdin>: line 1: include file not readable', Hash
641
756
  end
642
- assert_equal 2, doc.blocks.size
643
- assert_equal ['Unresolved directive in <stdin> - include::fixtures/chapter-a.adoc[]'], doc.blocks[0].lines
644
- assert_equal ['trailing content'], doc.blocks[1].lines
645
- assert_includes warnings, 'include file not readable'
646
757
  rescue
647
758
  flunk 'include directive should not raise exception on missing file'
648
759
  ensure
@@ -664,7 +775,6 @@ include::#{include_path}[]
664
775
  end
665
776
 
666
777
  test 'include directive can retrieve data from uri' do
667
- #url = 'http://echo.jsontest.com/name/asciidoctor'
668
778
  url = %(http://#{resolve_localhost}:9876/name/asciidoctor)
669
779
  input = <<-EOS
670
780
  ....
@@ -680,6 +790,92 @@ include::#{url}[]
680
790
  assert_match(expect, output)
681
791
  end
682
792
 
793
+ test 'nested include directives are resolved relative to current file' do
794
+ input = <<-EOS
795
+ ....
796
+ include::fixtures/outer-include.adoc[]
797
+ ....
798
+ EOS
799
+
800
+ output = render_embedded_string input, :safe => :safe, :base_dir => DIRNAME
801
+ expected = 'first line of outer
802
+
803
+ first line of middle
804
+
805
+ first line of inner
806
+
807
+ last line of inner
808
+
809
+ last line of middle
810
+
811
+ last line of outer'
812
+ assert_includes output, expected
813
+ end
814
+
815
+ test 'nested remote include directive is resolved relative to uri of current file' do
816
+ url = %(http://#{resolve_localhost}:9876/fixtures/outer-include.adoc)
817
+ input = <<-EOS
818
+ ....
819
+ include::#{url}[]
820
+ ....
821
+ EOS
822
+ output = using_test_webserver do
823
+ render_embedded_string input, :safe => :safe, :attributes => {'allow-uri-read' => ''}
824
+ end
825
+
826
+ expected = 'first line of outer
827
+
828
+ first line of middle
829
+
830
+ first line of inner
831
+
832
+ last line of inner
833
+
834
+ last line of middle
835
+
836
+ last line of outer'
837
+ assert_includes output, expected
838
+ end
839
+
840
+ test 'nested remote include directive that cannot be resolved does not crash processor' do
841
+ include_url = %(http://#{resolve_localhost}:9876/fixtures/file-with-missing-include.adoc)
842
+ nested_include_url = 'no-such-file.adoc'
843
+ input = <<-EOS
844
+ ....
845
+ include::#{include_url}[]
846
+ ....
847
+ EOS
848
+ begin
849
+ using_memory_logger do |logger|
850
+ result = using_test_webserver do
851
+ render_embedded_string input, :safe => :safe, :attributes => {'allow-uri-read' => ''}
852
+ end
853
+ assert_includes result, %(Unresolved directive in #{include_url} - include::#{nested_include_url}[])
854
+ assert_message logger, :ERROR, %(#{include_url}: line 1: include uri not readable: http://#{resolve_localhost}:9876/fixtures/#{nested_include_url}), Hash
855
+ end
856
+ rescue
857
+ flunk 'include directive should not raise exception on missing file'
858
+ end
859
+ end
860
+
861
+ test 'tag filtering is supported for remote includes' do
862
+ url = %(http://#{resolve_localhost}:9876/fixtures/tagged-class.rb)
863
+ input = <<-EOS
864
+ [source,ruby]
865
+ ----
866
+ include::#{url}[tag=init,indent=0]
867
+ ----
868
+ EOS
869
+ output = using_test_webserver do
870
+ render_embedded_string input, :safe => :safe, :attributes => {'allow-uri-read' => ''}
871
+ end
872
+
873
+ expected = '<code class="language-ruby" data-lang="ruby">def initialize breed
874
+ @breed = breed
875
+ end</code>'
876
+ assert_includes output, expected
877
+ end
878
+
683
879
  test 'inaccessible uri referenced by include directive does not crash processor' do
684
880
  url = %(http://#{resolve_localhost}:9876/no_such_file)
685
881
  input = <<-EOS
@@ -689,22 +885,20 @@ include::#{url}[]
689
885
  EOS
690
886
 
691
887
  begin
692
- output = warnings = nil
693
- redirect_streams do |_, err|
888
+ using_memory_logger do |logger|
694
889
  output = using_test_webserver do
695
890
  render_embedded_string input, :safe => :safe, :attributes => {'allow-uri-read' => ''}
696
891
  end
697
- warnings = err.string
892
+ refute_nil output
893
+ assert_match(/Unresolved directive/, output)
894
+ assert_message logger, :ERROR, %(<stdin>: line 2: include uri not readable: #{url}), Hash
698
895
  end
699
- refute_nil output
700
- assert_match(/Unresolved directive/, output)
701
- assert_includes warnings, 'include uri not readable'
702
896
  rescue
703
897
  flunk 'include directive should not raise exception on inaccessible uri'
704
898
  end
705
899
  end
706
900
 
707
- test 'include directive supports line selection' do
901
+ test 'include directive supports selecting lines by line number' do
708
902
  input = <<-EOS
709
903
  include::fixtures/include-file.asciidoc[lines=1;3..4;6..-1]
710
904
  EOS
@@ -721,7 +915,7 @@ include::fixtures/include-file.asciidoc[lines=1;3..4;6..-1]
721
915
  assert_match(/last line of included content/, output)
722
916
  end
723
917
 
724
- test 'include directive supports line selection using quoted attribute value' do
918
+ test 'include directive supports line ranges specified in quoted attribute value' do
725
919
  input = <<-EOS
726
920
  include::fixtures/include-file.asciidoc[lines="1, 3..4 , 6 .. -1"]
727
921
  EOS
@@ -750,7 +944,7 @@ include::fixtures/include-file.asciidoc[lines=]
750
944
  assert_includes output, 'last line of included content'
751
945
  end
752
946
 
753
- test 'include directive supports tagged selection' do
947
+ test 'include directive supports selecting lines by tag' do
754
948
  input = <<-EOS
755
949
  include::fixtures/include-file.asciidoc[tag=snippetA]
756
950
  EOS
@@ -762,7 +956,7 @@ include::fixtures/include-file.asciidoc[tag=snippetA]
762
956
  refute_match(/included content/, output)
763
957
  end
764
958
 
765
- test 'include directive supports multiple tagged selection' do
959
+ test 'include directive supports selecting lines by tags' do
766
960
  input = <<-EOS
767
961
  include::fixtures/include-file.asciidoc[tags=snippetA;snippetB]
768
962
  EOS
@@ -774,15 +968,16 @@ include::fixtures/include-file.asciidoc[tags=snippetA;snippetB]
774
968
  refute_match(/included content/, output)
775
969
  end
776
970
 
777
- test 'include directive supports tagged selection in language that uses circumfix comments' do
971
+ test 'include directive supports selecting lines by tag in language that uses circumfix comments' do
778
972
  {
779
973
  'include-file.xml' => '<snippet>content</snippet>',
780
- 'include-file.ml' => 'let s = SS.empty;;'
974
+ 'include-file.ml' => 'let s = SS.empty;;',
975
+ 'include-file.jsx' => '<p>Welcome to the club.</p>'
781
976
  }.each do |filename, expect|
782
977
  input = <<-EOS
783
- [source,xml,indent=0]
978
+ [source,xml]
784
979
  ----
785
- include::fixtures/#{filename}[tag=snippet]
980
+ include::fixtures/#{filename}[tag=snippet,indent=0]
786
981
  ----
787
982
  EOS
788
983
 
@@ -791,7 +986,24 @@ include::fixtures/#{filename}[tag=snippet]
791
986
  end
792
987
  end
793
988
 
794
- test 'include directive does not select lines with tag directives inside tagged selection' do
989
+ test 'include directive supports selecting tagged lines in file that has CRLF endlines' do
990
+ begin
991
+ tmp_include = Tempfile.new %w(include- .adoc)
992
+ tmp_include_dir, tmp_include_path = File.split tmp_include.path
993
+ tmp_include.write %(do not include\r\ntag::include-me[]\r\nincluded line\r\nend::include-me[]\r\ndo not include\r\n)
994
+ tmp_include.close
995
+ input = <<-EOS
996
+ include::#{tmp_include_path}[tag=include-me]
997
+ EOS
998
+ output = render_embedded_string input, :safe => :safe, :base_dir => tmp_include_dir
999
+ assert_includes output, 'included line'
1000
+ refute_includes output, 'do not include'
1001
+ ensure
1002
+ tmp_include.close!
1003
+ end
1004
+ end
1005
+
1006
+ test 'include directive does not select lines with tag directives within selected tag region' do
795
1007
  input = <<-EOS
796
1008
  ++++
797
1009
  include::fixtures/include-file.asciidoc[tags=snippet]
@@ -938,20 +1150,44 @@ end)
938
1150
  assert_includes output, expected
939
1151
  end
940
1152
 
941
- test 'should warn if tag is not found in include file' do
1153
+ test 'should warn if specified tag is not found in include file' do
942
1154
  input = <<-EOS
943
- include::fixtures/include-file.asciidoc[tag=snippetZ]
1155
+ include::fixtures/include-file.asciidoc[tag=no-such-tag]
944
1156
  EOS
945
1157
 
946
- old_stderr = $stderr
947
- $stderr = StringIO.new
948
- begin
1158
+ using_memory_logger do |logger|
949
1159
  render_embedded_string input, :safe => :safe, :base_dir => DIRNAME
950
- warning = $stderr.tap(&:rewind).read
951
- refute_nil warning
952
- assert_match(/WARNING.*snippetZ/, warning)
953
- ensure
954
- $stderr = old_stderr
1160
+ assert_message logger, :WARN, %(~<stdin>: line 1: tag 'no-such-tag' not found in include file), Hash
1161
+ end
1162
+ end
1163
+
1164
+ test 'should warn if specified tags are not found in include file' do
1165
+ input = <<-EOS
1166
+ ++++
1167
+ include::fixtures/include-file.asciidoc[tags=no-such-tag-b;no-such-tag-a]
1168
+ ++++
1169
+ EOS
1170
+
1171
+ using_memory_logger do |logger|
1172
+ render_embedded_string input, :safe => :safe, :base_dir => DIRNAME
1173
+ # NOTE Ruby 1.8 swaps the order of the list for some silly reason
1174
+ expected_tags = ::RUBY_MIN_VERSION_1_9 ? 'no-such-tag-b, no-such-tag-a' : 'no-such-tag-a, no-such-tag-b'
1175
+ assert_message logger, :WARN, %(~<stdin>: line 2: tags '#{expected_tags}' not found in include file), Hash
1176
+ end
1177
+ end
1178
+
1179
+ test 'should warn if specified tag in include file is not closed' do
1180
+ input = <<-EOS
1181
+ ++++
1182
+ include::fixtures/unclosed-tag.adoc[tag=a]
1183
+ ++++
1184
+ EOS
1185
+
1186
+ using_memory_logger do |logger|
1187
+ result = render_embedded_string input, :safe => :safe, :base_dir => DIRNAME
1188
+ assert_equal 'a', result
1189
+ assert_message logger, :WARN, %(~<stdin>: line 2: detected unclosed tag 'a' starting at line 2 of include file), Hash
1190
+ refute_nil logger.messages[0][:message][:include_location]
955
1191
  end
956
1192
  end
957
1193
 
@@ -962,12 +1198,29 @@ include::fixtures/mismatched-end-tag.adoc[tags=a;b]
962
1198
  ++++
963
1199
  EOS
964
1200
 
965
- result, warnings = redirect_streams do |out, err|
966
- [(render_embedded_string input, :safe => :safe, :base_dir => DIRNAME), err.string]
1201
+ inc_path = File.join DIRNAME, 'fixtures/mismatched-end-tag.adoc'
1202
+ using_memory_logger do |logger|
1203
+ result = render_embedded_string input, :safe => :safe, :base_dir => DIRNAME
1204
+ assert_equal %(a\nb), result
1205
+ assert_message logger, :WARN, %(<stdin>: line 2: mismatched end tag (expected 'b' but found 'a') at line 5 of include file: #{inc_path}), Hash
1206
+ refute_nil logger.messages[0][:message][:include_location]
1207
+ end
1208
+ end
1209
+
1210
+ test 'should warn if unexpected end tag is found in included file' do
1211
+ input = <<-EOS
1212
+ ++++
1213
+ include::fixtures/unexpected-end-tag.adoc[tags=a]
1214
+ ++++
1215
+ EOS
1216
+
1217
+ inc_path = File.join DIRNAME, 'fixtures/unexpected-end-tag.adoc'
1218
+ using_memory_logger do |logger|
1219
+ result = render_embedded_string input, :safe => :safe, :base_dir => DIRNAME
1220
+ assert_equal 'a', result
1221
+ assert_message logger, :WARN, %(<stdin>: line 2: unexpected end tag 'a' at line 4 of include file: #{inc_path}), Hash
1222
+ refute_nil logger.messages[0][:message][:include_location]
967
1223
  end
968
- assert_equal %(a\nb), result
969
- refute_nil warnings
970
- assert_match(/WARNING: .*end tag/, warnings)
971
1224
  end
972
1225
 
973
1226
  test 'include directive ignores tags attribute when empty' do
@@ -1065,7 +1318,7 @@ include::{fixturesdir}/include-file.{ext}[]
1065
1318
  EOS
1066
1319
 
1067
1320
  doc = document_from_string input, :safe => :safe, :base_dir => DIRNAME
1068
- output = doc.render
1321
+ output = doc.convert
1069
1322
  assert_match(/included content/, output)
1070
1323
  end
1071
1324
 
@@ -1074,13 +1327,13 @@ include::{fixturesdir}/include-file.{ext}[]
1074
1327
  include::{foodir}/include-file.asciidoc[]
1075
1328
  EOS
1076
1329
 
1077
- line, warnings = redirect_streams do |_, err|
1330
+ using_memory_logger do |logger|
1078
1331
  doc = empty_safe_document :base_dir => DIRNAME
1079
1332
  reader = Asciidoctor::PreprocessorReader.new doc, input, nil, :normalize => true
1080
- [reader.read_line, err.string]
1333
+ line = reader.read_line
1334
+ assert_equal 'Unresolved directive in <stdin> - include::{foodir}/include-file.asciidoc[]', line
1335
+ assert_message logger, :WARN, 'dropping line containing reference to missing attribute: foodir'
1081
1336
  end
1082
- assert_equal 'Unresolved directive in <stdin> - include::{foodir}/include-file.asciidoc[]', line
1083
- assert_includes warnings, 'dropping line containing reference to missing attribute'
1084
1337
  end
1085
1338
 
1086
1339
  test 'line is dropped if target of include directive resolves to empty and attribute-missing attribute is not skip' do
@@ -1088,13 +1341,13 @@ include::{foodir}/include-file.asciidoc[]
1088
1341
  include::{foodir}/include-file.asciidoc[]
1089
1342
  EOS
1090
1343
 
1091
- line, warnings = redirect_streams do |_, err|
1344
+ using_memory_logger do |logger|
1092
1345
  doc = empty_safe_document :base_dir => DIRNAME, :attributes => {'attribute-missing' => 'drop'}
1093
1346
  reader = Asciidoctor::PreprocessorReader.new doc, input, nil, :normalize => true
1094
- [reader.read_line, err.string]
1347
+ line = reader.read_line
1348
+ assert_nil line
1349
+ assert_message logger, :WARN, 'dropping line containing reference to missing attribute: foodir'
1095
1350
  end
1096
- assert_nil line
1097
- assert_includes warnings, 'dropping line containing reference to missing attribute'
1098
1351
  end
1099
1352
 
1100
1353
  test 'line following dropped include is not dropped' do
@@ -1103,13 +1356,13 @@ include::{foodir}/include-file.asciidoc[]
1103
1356
  yo
1104
1357
  EOS
1105
1358
 
1106
- line, warnings = redirect_streams do |_, err|
1359
+ using_memory_logger do |logger|
1107
1360
  doc = empty_safe_document :base_dir => DIRNAME, :attributes => {'attribute-missing' => 'drop'}
1108
1361
  reader = Asciidoctor::PreprocessorReader.new doc, input, nil, :normalize => true
1109
- [reader.read_line, err.string]
1362
+ line = reader.read_line
1363
+ assert_equal 'yo', line
1364
+ assert_message logger, :WARN, 'dropping line containing reference to missing attribute: foodir'
1110
1365
  end
1111
- assert_equal 'yo', line
1112
- assert_includes warnings, 'dropping line containing reference to missing attribute'
1113
1366
  end
1114
1367
 
1115
1368
  test 'escaped include directive is left unprocessed' do
@@ -1163,14 +1416,14 @@ include::include-file.asciidoc[]
1163
1416
  include::fixtures/parent-include.adoc[depth=1]
1164
1417
  EOS
1165
1418
 
1166
- lines, warnings = redirect_streams do |_, err|
1419
+ using_memory_logger do |logger|
1167
1420
  pseudo_docfile = File.join DIRNAME, 'include-master.adoc'
1168
1421
  doc = empty_safe_document :base_dir => DIRNAME
1169
1422
  reader = Asciidoctor::PreprocessorReader.new doc, input, Asciidoctor::Reader::Cursor.new(pseudo_docfile), :normalize => true
1170
- [reader.readlines, err.string]
1423
+ lines = reader.readlines
1424
+ assert_includes lines, 'include::child-include.adoc[]'
1425
+ assert_message logger, :ERROR, 'fixtures/parent-include.adoc: line 3: maximum include depth of 1 exceeded', Hash
1171
1426
  end
1172
- assert lines.include?('include::child-include.adoc[]')
1173
- assert_match(/maximum include depth .* exceeded/, warnings)
1174
1427
  end
1175
1428
 
1176
1429
  test 'include directive should be disabled if max include depth set in nested context has been exceeded' do
@@ -1178,15 +1431,15 @@ include::fixtures/parent-include.adoc[depth=1]
1178
1431
  include::fixtures/parent-include-restricted.adoc[depth=3]
1179
1432
  EOS
1180
1433
 
1181
- lines, warnings = redirect_streams do |_, err|
1434
+ using_memory_logger do |logger|
1182
1435
  pseudo_docfile = File.join DIRNAME, 'include-master.adoc'
1183
1436
  doc = empty_safe_document :base_dir => DIRNAME
1184
1437
  reader = Asciidoctor::PreprocessorReader.new doc, input, Asciidoctor::Reader::Cursor.new(pseudo_docfile), :normalize => true
1185
- [reader.readlines, err.string]
1438
+ lines = reader.readlines
1439
+ assert_includes lines, 'first line of child'
1440
+ assert_includes lines, 'include::grandchild-include.adoc[]'
1441
+ assert_message logger, :ERROR, 'fixtures/child-include.adoc: line 3: maximum include depth of 1 exceeded', Hash
1186
1442
  end
1187
- assert lines.include?('first line of child')
1188
- assert lines.include?('include::grandchild-include.adoc[]')
1189
- assert_match(/maximum include depth .* exceeded/, warnings)
1190
1443
  end
1191
1444
 
1192
1445
  test 'read_lines_until should not process lines if process option is false' do
@@ -1210,10 +1463,13 @@ include::fixtures/no-such-file.adoc[]
1210
1463
  ////
1211
1464
  EOS
1212
1465
 
1213
- doc = empty_safe_document :base_dir => DIRNAME
1214
- reader = Asciidoctor::PreprocessorReader.new doc, lines, nil, :normalize => true
1215
- result = reader.skip_comment_lines
1216
- assert_equal lines.map {|l| l.chomp}, result
1466
+ using_memory_logger do |logger|
1467
+ doc = empty_safe_document :base_dir => DIRNAME
1468
+ reader = Asciidoctor::PreprocessorReader.new doc, lines, nil, :normalize => true
1469
+ reader.skip_comment_lines
1470
+ assert reader.empty?
1471
+ assert logger.empty?
1472
+ end
1217
1473
  end
1218
1474
  end
1219
1475