asciidoctor 0.0.9 → 0.1.0

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 (42) hide show
  1. data/README.asciidoc +163 -41
  2. data/Rakefile +3 -1
  3. data/asciidoctor.gemspec +13 -5
  4. data/bin/asciidoctor +6 -3
  5. data/bin/asciidoctor-safe +13 -0
  6. data/lib/asciidoctor.rb +237 -26
  7. data/lib/asciidoctor/abstract_node.rb +27 -17
  8. data/lib/asciidoctor/attribute_list.rb +6 -0
  9. data/lib/asciidoctor/backends/base_template.rb +3 -4
  10. data/lib/asciidoctor/backends/docbook45.rb +114 -55
  11. data/lib/asciidoctor/backends/html5.rb +173 -104
  12. data/lib/asciidoctor/cli/invoker.rb +105 -0
  13. data/lib/asciidoctor/cli/options.rb +146 -0
  14. data/lib/asciidoctor/document.rb +135 -35
  15. data/lib/asciidoctor/lexer.rb +86 -33
  16. data/lib/asciidoctor/list_item.rb +2 -2
  17. data/lib/asciidoctor/reader.rb +6 -7
  18. data/lib/asciidoctor/section.rb +17 -5
  19. data/lib/asciidoctor/substituters.rb +216 -97
  20. data/lib/asciidoctor/table.rb +9 -2
  21. data/lib/asciidoctor/version.rb +1 -1
  22. data/man/asciidoctor.1 +212 -0
  23. data/man/asciidoctor.ad +156 -0
  24. data/test/attributes_test.rb +108 -5
  25. data/test/blocks_test.rb +102 -15
  26. data/test/document_test.rb +214 -3
  27. data/test/fixtures/encoding.asciidoc +4 -0
  28. data/test/fixtures/sample.asciidoc +26 -0
  29. data/test/invoker_test.rb +254 -0
  30. data/test/lexer_test.rb +53 -0
  31. data/test/links_test.rb +30 -0
  32. data/test/lists_test.rb +648 -9
  33. data/test/options_test.rb +68 -0
  34. data/test/paragraphs_test.rb +65 -1
  35. data/test/reader_test.rb +18 -4
  36. data/test/{headers_test.rb → sections_test.rb} +237 -0
  37. data/test/substitutions_test.rb +247 -5
  38. data/test/tables_test.rb +22 -4
  39. data/test/test_helper.rb +47 -3
  40. data/test/text_test.rb +20 -4
  41. metadata +34 -6
  42. data/noof.rb +0 -16
@@ -1 +1,5 @@
1
1
  Gregory Romé has written an AsciiDoc plugin for the Redmine project management application.
2
+
3
+ https://github.com/foo-users/foo
4
+ へと `vicmd` キーマップを足してみている試み、
5
+ アニメーションgifです。
@@ -0,0 +1,26 @@
1
+ Document Title
2
+ ==============
3
+ Doc Writer <thedoc@asciidoctor.org>
4
+ :idprefix: id_
5
+
6
+ Preamble paragraph.
7
+
8
+ NOTE: This is test, only a test.
9
+
10
+ == Section A
11
+
12
+ *Section A* paragraph.
13
+
14
+ === Section A Subsection
15
+
16
+ *Section A* 'subsection' paragraph.
17
+
18
+ == Section B
19
+
20
+ *Section B* paragraph.
21
+
22
+ .Section B list
23
+ * Item 1
24
+ * Item 2
25
+ * Item 3
26
+
@@ -0,0 +1,254 @@
1
+ require 'test_helper'
2
+ require 'asciidoctor/cli/options'
3
+ require 'asciidoctor/cli/invoker'
4
+
5
+ context 'Invoker' do
6
+ test 'should parse source and render as html5 article by default' do
7
+ invoker = nil
8
+ output = nil
9
+ redirect_streams do |stdout, stderr|
10
+ invoker = invoke_cli %w(-o -)
11
+ output = stdout.string
12
+ end
13
+ assert !invoker.nil?
14
+ doc = invoker.document
15
+ assert !doc.nil?
16
+ assert_equal 'Document Title', doc.doctitle
17
+ assert_equal 'Doc Writer', doc.attr('author')
18
+ assert_equal 'html5', doc.attr('backend')
19
+ assert_equal '.html', doc.attr('outfilesuffix')
20
+ assert_equal 'article', doc.attr('doctype')
21
+ assert doc.blocks?
22
+ assert_equal :preamble, doc.blocks.first.context
23
+ assert !output.empty?
24
+ assert_xpath '/html', output, 1
25
+ assert_xpath '/html/head', output, 1
26
+ assert_xpath '/html/body', output, 1
27
+ assert_xpath '/html/head/title[text() = "Document Title"]', output, 1
28
+ assert_xpath '/html/body[@class="article"]/*[@id="header"]/h1[text() = "Document Title"]', output, 1
29
+ end
30
+
31
+ test 'should set implicit doc info attributes' do
32
+ sample_filepath = File.expand_path(File.join(File.dirname(__FILE__), 'fixtures', 'sample.asciidoc'))
33
+ sample_filedir = File.expand_path(File.join(File.dirname(__FILE__), 'fixtures'))
34
+ invoker = invoke_cli_to_buffer %w(-o /dev/null), sample_filepath
35
+ doc = invoker.document
36
+ assert_equal 'sample', doc.attr('docname')
37
+ assert_equal sample_filepath, doc.attr('docfile')
38
+ assert_equal sample_filedir, doc.attr('docdir')
39
+ assert doc.attr?('docdate')
40
+ assert doc.attr?('doctime')
41
+ assert doc.attr?('docdatetime')
42
+ assert invoker.read_output.empty?
43
+ end
44
+
45
+ test 'should accept document from stdin and write to stdout' do
46
+ invoker = invoke_cli_to_buffer(%w(-s), '-') { 'content' }
47
+ doc = invoker.document
48
+ assert !doc.attr?('docname')
49
+ assert !doc.attr?('docfile')
50
+ assert_equal Dir.pwd, doc.attr('docdir')
51
+ assert_equal doc.attr('docdate'), doc.attr('localdate')
52
+ assert_equal doc.attr('doctime'), doc.attr('localtime')
53
+ assert_equal doc.attr('docdatetime'), doc.attr('localdatetime')
54
+ assert !doc.attr?('outfile')
55
+ output = invoker.read_output
56
+ assert !output.empty?
57
+ assert_xpath '/*[@class="paragraph"]/p[text()="content"]', output, 1
58
+ end
59
+
60
+ test 'should allow docdir to be specified when input is a string' do
61
+ expected_docdir = File.expand_path(File.join(File.dirname(__FILE__), 'fixtures'))
62
+ invoker = invoke_cli_to_buffer(%w(-s --base-dir test/fixtures -o /dev/null), '-') { 'content' }
63
+ doc = invoker.document
64
+ assert_equal expected_docdir, doc.attr('docdir')
65
+ assert_equal expected_docdir, doc.base_dir
66
+ end
67
+
68
+ test 'should display version and exit' do
69
+ redirect_streams do |stdout, stderr|
70
+ invoke_cli %w(--version)
71
+ assert_equal "Asciidoctor #{Asciidoctor::VERSION} [http://asciidoctor.org]", stdout.string.chomp
72
+ end
73
+ end
74
+
75
+ test 'should report usage if no input file given' do
76
+ redirect_streams do |stdout, stderr|
77
+ invoke_cli [], nil
78
+ assert_match(/Usage:/, stderr.string)
79
+ end
80
+ end
81
+
82
+ test 'should report error if input file does not exist' do
83
+ redirect_streams do |stdout, stderr|
84
+ invoker = invoke_cli [], 'missing_file.asciidoc'
85
+ assert_match(/input file .* missing/, stderr.string)
86
+ assert_equal 1, invoker.code
87
+ end
88
+ end
89
+
90
+ test 'should fail with too many arguments if extra arguments are included' do
91
+ redirect_streams do |stdout, stderr|
92
+ invoker = invoke_cli %w(-o /dev/null extra arguments sample.asciidoc), nil
93
+ assert_match(/too many arguments/, stderr.string)
94
+ assert_equal 1, invoker.code
95
+ end
96
+ end
97
+
98
+ test 'should output to file name based on input file name' do
99
+ sample_outpath = File.expand_path(File.join(File.dirname(__FILE__), 'fixtures', 'sample.html'))
100
+ begin
101
+ invoker = invoke_cli
102
+ doc = invoker.document
103
+ assert_equal sample_outpath, doc.attr('outfile')
104
+ assert File.exist?(sample_outpath)
105
+ output = File.read(sample_outpath)
106
+ assert !output.empty?
107
+ assert_xpath '/html', output, 1
108
+ assert_xpath '/html/head', output, 1
109
+ assert_xpath '/html/body', output, 1
110
+ assert_xpath '/html/head/title[text() = "Document Title"]', output, 1
111
+ assert_xpath '/html/body/*[@id="header"]/h1[text() = "Document Title"]', output, 1
112
+ ensure
113
+ FileUtils::rm(sample_outpath)
114
+ end
115
+ end
116
+
117
+ test 'should output to file in destination directory if set' do
118
+ destination_path = File.expand_path(File.join(File.dirname(__FILE__), 'test_output'))
119
+ sample_outpath = File.join(destination_path, 'sample.html')
120
+ begin
121
+ FileUtils::mkdir_p(destination_path)
122
+ invoker = invoke_cli %w(-D test/test_output)
123
+ doc = invoker.document
124
+ assert_equal sample_outpath, doc.attr('outfile')
125
+ assert File.exist?(sample_outpath)
126
+ ensure
127
+ FileUtils::rm(sample_outpath)
128
+ FileUtils::rmdir(destination_path)
129
+ end
130
+ end
131
+
132
+ test 'should output to file specified' do
133
+ sample_outpath = File.expand_path(File.join(File.dirname(__FILE__), 'fixtures', 'sample-output.html'))
134
+ begin
135
+ invoker = invoke_cli %W(-o #{sample_outpath})
136
+ doc = invoker.document
137
+ assert_equal sample_outpath, doc.attr('outfile')
138
+ assert File.exist?(sample_outpath)
139
+ ensure
140
+ FileUtils::rm(sample_outpath)
141
+ end
142
+ end
143
+
144
+ test 'should suppress header footer if specified' do
145
+ invoker = invoke_cli_to_buffer %w(-s -o -)
146
+ output = invoker.read_output
147
+ assert_xpath '/html', output, 0
148
+ assert_xpath '/*[@id="preamble"]', output, 1
149
+ end
150
+
151
+ test 'should not compact output by default' do
152
+ invoker = invoke_cli_to_buffer(%w(-s -o -), '-') { 'content' }
153
+ output = invoker.read_output
154
+ assert_match(/\n[[:blank:]]*\n/, output)
155
+ end
156
+
157
+ test 'should compact output if specified' do
158
+ invoker = invoke_cli_to_buffer(%w(-C -s -o -), '-') { 'content' }
159
+ output = invoker.read_output
160
+ assert_no_match(/\n[[:blank:]]*\n/, output)
161
+ end
162
+
163
+ test 'should set backend to html5 if specified' do
164
+ invoker = invoke_cli_to_buffer %w(-b html5 -o -)
165
+ doc = invoker.document
166
+ assert_equal 'html5', doc.attr('backend')
167
+ assert_equal '.html', doc.attr('outfilesuffix')
168
+ output = invoker.read_output
169
+ assert_xpath '/html', output, 1
170
+ end
171
+
172
+ test 'should set backend to docbook45 if specified' do
173
+ invoker = invoke_cli_to_buffer %w(-b docbook45 -o -)
174
+ doc = invoker.document
175
+ assert_equal 'docbook45', doc.attr('backend')
176
+ assert_equal '.xml', doc.attr('outfilesuffix')
177
+ output = invoker.read_output
178
+ assert_xpath '/article', output, 1
179
+ end
180
+
181
+ test 'should set doctype to article if specified' do
182
+ invoker = invoke_cli_to_buffer %w(-d article -o -)
183
+ doc = invoker.document
184
+ assert_equal 'article', doc.attr('doctype')
185
+ output = invoker.read_output
186
+ assert_xpath '/html/body[@class="article"]', output, 1
187
+ end
188
+
189
+ test 'should set doctype to book if specified' do
190
+ invoker = invoke_cli_to_buffer %w(-d book -o -)
191
+ doc = invoker.document
192
+ assert_equal 'book', doc.attr('doctype')
193
+ output = invoker.read_output
194
+ assert_xpath '/html/body[@class="book"]', output, 1
195
+ end
196
+
197
+ test 'should set attribute with value' do
198
+ invoker = invoke_cli_to_buffer %w(--trace -a idprefix=id -s -o -)
199
+ doc = invoker.document
200
+ assert_equal 'id', doc.attr('idprefix')
201
+ output = invoker.read_output
202
+ assert_xpath '//h2[@id="idsection_a"]', output, 1
203
+ end
204
+
205
+ test 'should not set attribute ending in @ if defined in document' do
206
+ invoker = invoke_cli_to_buffer %w(--trace -a idprefix=id@ -s -o -)
207
+ doc = invoker.document
208
+ assert_equal 'id_', doc.attr('idprefix')
209
+ output = invoker.read_output
210
+ assert_xpath '//h2[@id="id_section_a"]', output, 1
211
+ end
212
+
213
+ test 'should set attribute with no value' do
214
+ invoker = invoke_cli_to_buffer %w(-a icons -s -o -)
215
+ doc = invoker.document
216
+ assert_equal '', doc.attr('icons')
217
+ output = invoker.read_output
218
+ assert_xpath '//*[@class="admonitionblock"]//img[@alt="Note"]', output, 1
219
+ end
220
+
221
+ test 'should unset attribute ending in bang' do
222
+ invoker = invoke_cli_to_buffer %w(-a sectids! -s -o -)
223
+ doc = invoker.document
224
+ assert !doc.attr?('sectids')
225
+ output = invoker.read_output
226
+ # leave the count loose in case we add more sections
227
+ assert_xpath '//h2[not(@id)]', output
228
+ end
229
+
230
+ test 'default mode for cli should be unsafe' do
231
+ invoker = invoke_cli_to_buffer %w(-o /dev/null)
232
+ doc = invoker.document
233
+ assert_equal Asciidoctor::SafeMode::UNSAFE, doc.safe
234
+ end
235
+
236
+ test 'should set safe mode if specified' do
237
+ invoker = invoke_cli_to_buffer %w(--safe -o /dev/null)
238
+ doc = invoker.document
239
+ assert_equal Asciidoctor::SafeMode::SAFE, doc.safe
240
+ end
241
+
242
+ test 'should set safe mode to specified level if specified' do
243
+ invoker = invoke_cli_to_buffer %w(-S safe -o /dev/null)
244
+ doc = invoker.document
245
+ assert_equal Asciidoctor::SafeMode::SAFE, doc.safe
246
+ end
247
+
248
+ test 'should set eRuby impl if specified' do
249
+ invoker = invoke_cli_to_buffer %w(--eruby erubis -o /dev/null)
250
+ doc = invoker.document
251
+ assert_equal 'erubis', doc.instance_variable_get('@options')[:eruby]
252
+ end
253
+
254
+ end
@@ -23,6 +23,14 @@ context "Lexer" do
23
23
  assert_equal expected, attributes
24
24
  end
25
25
 
26
+ test "collect empty unnamed attribute double-quoted" do
27
+ attributes = {}
28
+ line = '""'
29
+ expected = {1 => ''}
30
+ Asciidoctor::AttributeList.new(line).parse_into(attributes)
31
+ assert_equal expected, attributes
32
+ end
33
+
26
34
  test "collect unnamed attribute double-quoted containing escaped quote" do
27
35
  attributes = {}
28
36
  line = '"ba\"zaar"'
@@ -39,6 +47,14 @@ context "Lexer" do
39
47
  assert_equal expected, attributes
40
48
  end
41
49
 
50
+ test "collect empty unnamed attribute single-quoted" do
51
+ attributes = {}
52
+ line = '\'\''
53
+ expected = {1 => ''}
54
+ Asciidoctor::AttributeList.new(line).parse_into(attributes)
55
+ assert_equal expected, attributes
56
+ end
57
+
42
58
  test "collect unnamed attribute single-quoted containing escaped quote" do
43
59
  attributes = {}
44
60
  line = '\'ba\\\'zaar\''
@@ -79,6 +95,14 @@ context "Lexer" do
79
95
  assert_equal expected, attributes
80
96
  end
81
97
 
98
+ test 'collect named attribute with double-quoted empty value' do
99
+ attributes = {}
100
+ line = 'height=100,caption="",link="images/octocat.png"'
101
+ expected = {'height' => '100', 'caption' => '', 'link' => 'images/octocat.png'}
102
+ Asciidoctor::AttributeList.new(line).parse_into(attributes)
103
+ assert_equal expected, attributes
104
+ end
105
+
82
106
  test "collect named attribute single-quoted" do
83
107
  attributes = {}
84
108
  line = 'foo=\'bar\''
@@ -87,6 +111,14 @@ context "Lexer" do
87
111
  assert_equal expected, attributes
88
112
  end
89
113
 
114
+ test 'collect named attribute with single-quoted empty value' do
115
+ attributes = {}
116
+ line = "height=100,caption='',link='images/octocat.png'"
117
+ expected = {'height' => '100', 'caption' => '', 'link' => 'images/octocat.png'}
118
+ Asciidoctor::AttributeList.new(line).parse_into(attributes)
119
+ assert_equal expected, attributes
120
+ end
121
+
90
122
  test "collect named attributes unquoted" do
91
123
  attributes = {}
92
124
  line = "first=value, second=two, third=3"
@@ -209,6 +241,27 @@ context "Lexer" do
209
241
  assert_equal 'TB', metadata['authorinitials']
210
242
  end
211
243
 
244
+ test "test_parse_author_with_single_quote" do
245
+ metadata, = parse_header_metadata 'Stephen O\'Grady <founder@redmonk.com>'
246
+ assert_equal 5, metadata.size
247
+ assert_equal 'Stephen O\'Grady', metadata['author']
248
+ assert_equal 'Stephen', metadata['firstname']
249
+ assert_equal 'O\'Grady', metadata['lastname']
250
+ assert_equal 'founder@redmonk.com', metadata['email']
251
+ assert_equal 'SO', metadata['authorinitials']
252
+ end
253
+
254
+ test "parse author with dotted initial" do
255
+ metadata, = parse_header_metadata 'Heiko W. Rupp <hwr@example.de>'
256
+ assert_equal 6, metadata.size
257
+ assert_equal 'Heiko W. Rupp', metadata['author']
258
+ assert_equal 'Heiko', metadata['firstname']
259
+ assert_equal 'W.', metadata['middlename']
260
+ assert_equal 'Rupp', metadata['lastname']
261
+ assert_equal 'hwr@example.de', metadata['email']
262
+ assert_equal 'HWR', metadata['authorinitials']
263
+ end
264
+
212
265
  test "test_parse_author_with_underscore" do
213
266
  metadata, = parse_header_metadata 'Tim_E Fella'
214
267
  assert_equal 4, metadata.size
@@ -50,6 +50,14 @@ context 'Links' do
50
50
  assert_xpath '//a', render_string('\http://asciidoc.org[AsciiDoc] is the key to good docs.'), 0
51
51
  end
52
52
 
53
+ test 'inline qualified url followed by an endline should not include endline in link' do
54
+ assert_xpath '//a[@href="http://github.com/asciidoctor"]', render_string("The source code for Asciidoctor can be found at http://github.com/asciidoctor\nwhich is a GitHub organization."), 1
55
+ end
56
+
57
+ test 'qualified url divided by endline using macro syntax should not create link' do
58
+ assert_xpath '//a', render_string("The source code for Asciidoctor can be found at link:http://github.com/asciidoctor\n[]which is a GitHub organization."), 0
59
+ end
60
+
53
61
  test 'qualified url containing whitespace using macro syntax should not create link' do
54
62
  assert_xpath '//a', render_string('I often need to refer to the chapter on link:http://asciidoc.org?q=attribute references[Attribute References].'), 0
55
63
  end
@@ -58,6 +66,10 @@ context 'Links' do
58
66
  assert_xpath '//a', render_string('I often need to refer to the chapter on link:http://asciidoc.org?q=attribute%20references[Attribute References].'), 1
59
67
  end
60
68
 
69
+ test 'inline quoted qualified url should not consume surrounding angled brackets' do
70
+ assert_xpath '//a[@href="http://github.com/asciidoctor"]', render_string('Asciidoctor GitHub organization: <**http://github.com/asciidoctor**>'), 1
71
+ end
72
+
61
73
  test 'inline ref' do
62
74
  doc = document_from_string 'Here you can read about tigers.[[tigers]]'
63
75
  output = doc.render
@@ -132,6 +144,24 @@ context 'Links' do
132
144
  assert_xpath '//a[@href="#tigers"][text() = "[tigers]"]', doc.render, 1
133
145
  end
134
146
 
147
+ test 'xref shows label from title of target for forward and backward references in html backend' do
148
+ input = <<-EOS
149
+ == Section A
150
+
151
+ <\<_section_b>>
152
+
153
+ == Section B
154
+
155
+ <\<_section_a>>
156
+ EOS
157
+
158
+ output = render_embedded_string input
159
+ assert_xpath '//h2[@id="_section_a"][text()="Section A"]', output, 1
160
+ assert_xpath '//a[@href="#_section_a"][text()="Section A"]', output, 1
161
+ assert_xpath '//h2[@id="_section_b"][text()="Section B"]', output, 1
162
+ assert_xpath '//a[@href="#_section_b"][text()="Section B"]', output, 1
163
+ end
164
+
135
165
  test 'anchor creates reference' do
136
166
  doc = document_from_string "[[tigers]]Tigers roam here."
137
167
  assert_equal({'tigers' => '[tigers]'}, doc.references[:ids])
@@ -33,6 +33,25 @@ List
33
33
  assert_xpath '//ul/li', output, 3
34
34
  end
35
35
 
36
+ test 'dash elements with interspersed line comments should be skipped and not break list' do
37
+ input = <<-EOS
38
+ == List
39
+
40
+ - Foo
41
+ // line comment
42
+ // another line comment
43
+ - Boo
44
+ // line comment
45
+ more text
46
+ // another line comment
47
+ - Blech
48
+ EOS
49
+ output = render_embedded_string input
50
+ assert_xpath '//ul', output, 1
51
+ assert_xpath '//ul/li', output, 3
52
+ assert_xpath %((//ul/li)[2]/p[text()="Boo\nmore text"]), output, 1
53
+ end
54
+
36
55
  test "dash elements separated by a line comment offset by blank lines should not merge lists" do
37
56
  input = <<-EOS
38
57
  List
@@ -101,6 +120,26 @@ List
101
120
  assert_xpath "//ul/li[1]/p[text() = 'Foo\nwrapped content']", output, 1
102
121
  end
103
122
 
123
+ test 'wrapped list item with hanging indent followed by non-indented line' do
124
+ input = <<-EOS
125
+ == Lists
126
+
127
+ - list item 1
128
+ // not line comment
129
+ second wrapped line
130
+ - list item 2
131
+ EOS
132
+ output = render_embedded_string input
133
+ assert_css 'ul', output, 1
134
+ assert_css 'ul li', output, 2
135
+ # NOTE for some reason, we're getting an extra line after the indented line
136
+ lines = xmlnodes_at_xpath('(//ul/li)[1]/p', output, 1).text.gsub(/\n[[:space:]]*\n/, "\n").lines.entries
137
+ assert_equal 3, lines.size
138
+ assert_equal 'list item 1', lines[0].chomp
139
+ assert_equal ' // not line comment', lines[1].chomp
140
+ assert_equal 'second wrapped line', lines[2].chomp
141
+ end
142
+
104
143
  test "a literal paragraph offset by blank lines in list content is appended as a literal block" do
105
144
  input = <<-EOS
106
145
  List
@@ -147,6 +186,24 @@ para
147
186
  assert_xpath '(//ul/li)[1]/*[@class="literalblock"]/following-sibling::*[@class="paragraph"]/p[text()="para"]', output, 1
148
187
  end
149
188
 
189
+ test 'appends line as paragraph if attached by continuation following line comment' do
190
+ input = <<-EOS
191
+ - list item 1
192
+ // line comment
193
+ +
194
+ paragraph in list item 1
195
+
196
+ - list item 2
197
+ EOS
198
+ output = render_embedded_string input
199
+ assert_css 'ul', output, 1
200
+ assert_css 'ul li', output, 2
201
+ assert_xpath '(//ul/li)[1]/p[text()="list item 1"]', output, 1
202
+ assert_xpath '(//ul/li)[1]/p/following-sibling::*[@class="paragraph"]', output, 1
203
+ assert_xpath '(//ul/li)[1]/p/following-sibling::*[@class="paragraph"]/p[text()="paragraph in list item 1"]', output, 1
204
+ assert_xpath '(//ul/li)[2]/p[text()="list item 2"]', output, 1
205
+ end
206
+
150
207
  test "a literal paragraph with a line that appears as a list item that is followed by a continuation should create two blocks" do
151
208
  input = <<-EOS
152
209
  * Foo
@@ -245,6 +302,25 @@ List
245
302
  assert_xpath '//ul/li', output, 3
246
303
  end
247
304
 
305
+ test 'asterisk elements with interspersed line comments should be skipped and not break list' do
306
+ input = <<-EOS
307
+ == List
308
+
309
+ * Foo
310
+ // line comment
311
+ // another line comment
312
+ * Boo
313
+ // line comment
314
+ more text
315
+ // another line comment
316
+ * Blech
317
+ EOS
318
+ output = render_embedded_string input
319
+ assert_xpath '//ul', output, 1
320
+ assert_xpath '//ul/li', output, 3
321
+ assert_xpath %((//ul/li)[2]/p[text()="Boo\nmore text"]), output, 1
322
+ end
323
+
248
324
  test "asterisk elements separated by a line comment offset by blank lines should not merge lists" do
249
325
  input = <<-EOS
250
326
  List
@@ -569,6 +645,27 @@ List
569
645
  assert_xpath '((//ul)[1]/li//ol)[1]/li', output, 1
570
646
  end
571
647
 
648
+ test 'three levels of alternating unordered and ordered elements' do
649
+ input = <<-EOS
650
+ == Lists
651
+
652
+ * bullet 1
653
+ . numbered 1.1
654
+ ** bullet 1.1.1
655
+ * bullet 2
656
+ EOS
657
+
658
+ output = render_embedded_string input
659
+ assert_css '.ulist', output, 2
660
+ assert_css '.olist', output, 1
661
+ assert_css '.ulist > ul > li > p', output, 3
662
+ assert_css '.ulist > ul > li > p + .olist', output, 1
663
+ assert_css '.ulist > ul > li > p + .olist > ol > li > p', output, 1
664
+ assert_css '.ulist > ul > li > p + .olist > ol > li > p + .ulist', output, 1
665
+ assert_css '.ulist > ul > li > p + .olist > ol > li > p + .ulist > ul > li > p', output, 1
666
+ assert_css '.ulist > ul > li + li > p', output, 1
667
+ end
668
+
572
669
  test "lines with alternating markers of unordered and ordered list types separated by blank lines should be nested" do
573
670
  input = <<-EOS
574
671
  List
@@ -711,6 +808,66 @@ Item one, literal block
711
808
  assert_xpath '(//ul/li[1]/p/following-sibling::*)[1][@class = "literalblock"]', output, 1
712
809
  end
713
810
 
811
+ test "adjacent list continuation line attaches following block with block attributes" do
812
+ input = <<-EOS
813
+ Lists
814
+ =====
815
+
816
+ * Item one, paragraph one
817
+ +
818
+ [[beck]]
819
+ .Read the following aloud to yourself
820
+ [source, ruby]
821
+ ----
822
+ 5.times { print "Odelay!" }
823
+ ----
824
+
825
+ * Item two
826
+ EOS
827
+ output = render_string input
828
+ assert_xpath '//ul', output, 1
829
+ assert_xpath '//ul/li', output, 2
830
+ assert_xpath '//ul/li[1]/p', output, 1
831
+ assert_xpath '(//ul/li[1]/p/following-sibling::*)[1][@id="beck"][@class = "listingblock"]', output, 1
832
+ assert_xpath '(//ul/li[1]/p/following-sibling::*)[1][@id="beck"]/div[@class="title"][starts-with(text(),"Read")]', output, 1
833
+ assert_xpath '(//ul/li[1]/p/following-sibling::*)[1][@id="beck"]//code[@class="ruby"][starts-with(text(),"5.times")]', output, 1
834
+ end
835
+
836
+ test 'trailing block attribute line attached by continuation should not create block' do
837
+ input = <<-EOS
838
+ Lists
839
+ =====
840
+
841
+ * Item one, paragraph one
842
+ +
843
+ [source]
844
+
845
+ * Item two
846
+ EOS
847
+ output = render_string input
848
+ assert_xpath '//ul', output, 1
849
+ assert_xpath '//ul/li', output, 2
850
+ assert_xpath '//ul/li[1]/*', output, 1
851
+ assert_xpath '//ul/li//*[@class="listingblock"]', output, 0
852
+ end
853
+
854
+ test 'trailing block title line attached by continuation should not create block' do
855
+ input = <<-EOS
856
+ Lists
857
+ =====
858
+
859
+ * Item one, paragraph one
860
+ +
861
+ .Disappears into the ether
862
+
863
+ * Item two
864
+ EOS
865
+ output = render_string input
866
+ assert_xpath '//ul', output, 1
867
+ assert_xpath '//ul/li', output, 2
868
+ assert_xpath '//ul/li[1]/*', output, 1
869
+ end
870
+
714
871
  test "consecutive blocks in list continuation attach to list item" do
715
872
  input = <<-EOS
716
873
  Lists
@@ -736,6 +893,291 @@ ____
736
893
  assert_xpath '(//ul/li[1]/p/following-sibling::*)[2][@class = "quoteblock"]', output, 1
737
894
  end
738
895
 
896
+ test 'list item with hanging indent followed by block attached by list continuation' do
897
+ input = <<-EOS
898
+ == Lists
899
+
900
+ . list item 1
901
+ continued
902
+ +
903
+ --
904
+ open block in list item 1
905
+ --
906
+
907
+ . list item 2
908
+ EOS
909
+ output = render_embedded_string input
910
+ assert_css 'ol', output, 1
911
+ assert_css 'ol li', output, 2
912
+ assert_xpath %((//ol/li)[1]/p[text()="list item 1\ncontinued"]), output, 1
913
+ assert_xpath '(//ol/li)[1]/p/following-sibling::*[@class="openblock"]', output, 1
914
+ assert_xpath '(//ol/li)[1]/p/following-sibling::*[@class="openblock"]//p[text()="open block in list item 1"]', output, 1
915
+ assert_xpath %((//ol/li)[2]/p[text()="list item 2"]), output, 1
916
+ end
917
+
918
+ test 'list item paragraph in list item and nested list item' do
919
+ input = <<-EOS
920
+ == Lists
921
+
922
+ . list item 1
923
+ +
924
+ list item 1 paragraph
925
+
926
+ * nested list item
927
+ +
928
+ nested list item paragraph
929
+
930
+ . list item 2
931
+ EOS
932
+ output = render_embedded_string input
933
+ assert_css '.olist ol', output, 1
934
+ assert_css '.olist ol > li', output, 2
935
+ assert_css '.ulist ul', output, 1
936
+ assert_css '.ulist ul > li', output, 1
937
+ assert_xpath '(//ol/li)[1]/*', output, 3
938
+ assert_xpath '((//ol/li)[1]/*)[1]/self::p', output, 1
939
+ assert_xpath '((//ol/li)[1]/*)[1]/self::p[text()="list item 1"]', output, 1
940
+ assert_xpath '((//ol/li)[1]/*)[2]/self::div[@class="paragraph"]', output, 1
941
+ assert_xpath '((//ol/li)[1]/*)[3]/self::div[@class="ulist"]', output, 1
942
+ assert_xpath '((//ol/li)[1]/*)[3]/self::div[@class="ulist"]/ul/li', output, 1
943
+ assert_xpath '((//ol/li)[1]/*)[3]/self::div[@class="ulist"]/ul/li/p[text()="nested list item"]', output, 1
944
+ assert_xpath '((//ol/li)[1]/*)[3]/self::div[@class="ulist"]/ul/li/p/following-sibling::div[@class="paragraph"]', output, 1
945
+ end
946
+
947
+ test 'trailing list continuations should attach to list items at respective levels' do
948
+ input = <<-EOS
949
+ == Lists
950
+
951
+ . list item 1
952
+ +
953
+ * nested list item 1
954
+ * nested list item 2
955
+ +
956
+ paragraph for nested list item 2
957
+
958
+ +
959
+ paragraph for list item 1
960
+
961
+ . list item 2
962
+ EOS
963
+ output = render_embedded_string input
964
+ assert_css '.olist ol', output, 1
965
+ assert_css '.olist ol > li', output, 2
966
+ assert_css '.ulist ul', output, 1
967
+ assert_css '.ulist ul > li', output, 2
968
+ assert_css '.olist .ulist', output, 1
969
+ assert_xpath '(//ol/li)[1]/*', output, 3
970
+ assert_xpath '((//ol/li)[1]/*)[1]/self::p', output, 1
971
+ assert_xpath '((//ol/li)[1]/*)[1]/self::p[text()="list item 1"]', output, 1
972
+ assert_xpath '((//ol/li)[1]/*)[2]/self::div[@class="ulist"]', output, 1
973
+ assert_xpath '((//ol/li)[1]/*)[2]/self::div[@class="ulist"]/ul/li', output, 2
974
+ assert_xpath '(((//ol/li)[1]/*)[2]/self::div[@class="ulist"]/ul/li)[2]/*', output, 2
975
+ assert_xpath '(((//ol/li)[1]/*)[2]/self::div[@class="ulist"]/ul/li)[2]/p', output, 1
976
+ assert_xpath '(((//ol/li)[1]/*)[2]/self::div[@class="ulist"]/ul/li)[2]/div[@class="paragraph"]', output, 1
977
+ assert_xpath '((//ol/li)[1]/*)[3]/self::div[@class="paragraph"]', output, 1
978
+ end
979
+
980
+ test 'trailing list continuations should attach to list items of different types at respective levels' do
981
+ input = <<-EOS
982
+ == Lists
983
+
984
+ * bullet 1
985
+ . numbered 1.1
986
+ ** bullet 1.1.1
987
+
988
+ +
989
+ numbered 1.1 paragraph
990
+
991
+ +
992
+ bullet 1 paragraph
993
+
994
+ * bullet 2
995
+ EOS
996
+ output = render_embedded_string input
997
+
998
+ assert_xpath '(//ul)[1]/li', output, 2
999
+
1000
+ assert_xpath '((//ul)[1]/li[1])/*', output, 3
1001
+ assert_xpath '(((//ul)[1]/li[1])/*)[1]/self::p[text()="bullet 1"]', output, 1
1002
+ assert_xpath '(((//ul)[1]/li[1])/*)[2]/ol', output, 1
1003
+ assert_xpath '(((//ul)[1]/li[1])/*)[3]/self::div[@class="paragraph"]/p[text()="bullet 1 paragraph"]', output, 1
1004
+
1005
+ assert_xpath '((//ul)[1]/li)[1]/div/ol/li', output, 1
1006
+ assert_xpath '((//ul)[1]/li)[1]/div/ol/li/*', output, 3
1007
+ assert_xpath '(((//ul)[1]/li)[1]/div/ol/li/*)[1]/self::p[text()="numbered 1.1"]', output, 1
1008
+ assert_xpath '(((//ul)[1]/li)[1]/div/ol/li/*)[2]/self::div[@class="ulist"]', output, 1
1009
+ assert_xpath '(((//ul)[1]/li)[1]/div/ol/li/*)[3]/self::div[@class="paragraph"]/p[text()="numbered 1.1 paragraph"]', output, 1
1010
+
1011
+ assert_xpath '((//ul)[1]/li)[1]/div/ol/li/div[@class="ulist"]/ul/li', output, 1
1012
+ assert_xpath '((//ul)[1]/li)[1]/div/ol/li/div[@class="ulist"]/ul/li/*', output, 1
1013
+ assert_xpath '((//ul)[1]/li)[1]/div/ol/li/div[@class="ulist"]/ul/li/p[text()="bullet 1.1.1"]', output, 1
1014
+ end
1015
+
1016
+ test 'repeated list continuations should attach to list items at respective levels' do
1017
+ input = <<-EOS
1018
+ == Lists
1019
+
1020
+ . list item 1
1021
+
1022
+ * nested list item 1
1023
+ +
1024
+ --
1025
+ open block for nested list item 1
1026
+ --
1027
+ +
1028
+ * nested list item 2
1029
+ +
1030
+ paragraph for nested list item 2
1031
+
1032
+ +
1033
+ paragraph for list item 1
1034
+
1035
+ . list item 2
1036
+ EOS
1037
+ output = render_embedded_string input
1038
+ assert_css '.olist ol', output, 1
1039
+ assert_css '.olist ol > li', output, 2
1040
+ assert_css '.ulist ul', output, 1
1041
+ assert_css '.ulist ul > li', output, 2
1042
+ assert_css '.olist .ulist', output, 1
1043
+ assert_xpath '(//ol/li)[1]/*', output, 3
1044
+ assert_xpath '((//ol/li)[1]/*)[1]/self::p', output, 1
1045
+ assert_xpath '((//ol/li)[1]/*)[1]/self::p[text()="list item 1"]', output, 1
1046
+ assert_xpath '((//ol/li)[1]/*)[2]/self::div[@class="ulist"]', output, 1
1047
+ assert_xpath '((//ol/li)[1]/*)[2]/self::div[@class="ulist"]/ul/li', output, 2
1048
+ assert_xpath '(((//ol/li)[1]/*)[2]/self::div[@class="ulist"]/ul/li)[1]/*', output, 2
1049
+ assert_xpath '(((//ol/li)[1]/*)[2]/self::div[@class="ulist"]/ul/li)[1]/p', output, 1
1050
+ assert_xpath '(((//ol/li)[1]/*)[2]/self::div[@class="ulist"]/ul/li)[1]/div[@class="openblock"]', output, 1
1051
+ assert_xpath '(((//ol/li)[1]/*)[2]/self::div[@class="ulist"]/ul/li)[2]/*', output, 2
1052
+ assert_xpath '(((//ol/li)[1]/*)[2]/self::div[@class="ulist"]/ul/li)[2]/p', output, 1
1053
+ assert_xpath '(((//ol/li)[1]/*)[2]/self::div[@class="ulist"]/ul/li)[2]/div[@class="paragraph"]', output, 1
1054
+ assert_xpath '((//ol/li)[1]/*)[3]/self::div[@class="paragraph"]', output, 1
1055
+ end
1056
+
1057
+ test 'repeated list continuations attached directly to list item should attach to list items at respective levels' do
1058
+ input = <<-EOS
1059
+ == Lists
1060
+
1061
+ . list item 1
1062
+ +
1063
+ * nested list item 1
1064
+ +
1065
+ --
1066
+ open block for nested list item 1
1067
+ --
1068
+ +
1069
+ * nested list item 2
1070
+ +
1071
+ paragraph for nested list item 2
1072
+
1073
+ +
1074
+ paragraph for list item 1
1075
+
1076
+ . list item 2
1077
+ EOS
1078
+ output = render_embedded_string input
1079
+ assert_css '.olist ol', output, 1
1080
+ assert_css '.olist ol > li', output, 2
1081
+ assert_css '.ulist ul', output, 1
1082
+ assert_css '.ulist ul > li', output, 2
1083
+ assert_css '.olist .ulist', output, 1
1084
+ assert_xpath '(//ol/li)[1]/*', output, 3
1085
+ assert_xpath '((//ol/li)[1]/*)[1]/self::p', output, 1
1086
+ assert_xpath '((//ol/li)[1]/*)[1]/self::p[text()="list item 1"]', output, 1
1087
+ assert_xpath '((//ol/li)[1]/*)[2]/self::div[@class="ulist"]', output, 1
1088
+ assert_xpath '((//ol/li)[1]/*)[2]/self::div[@class="ulist"]/ul/li', output, 2
1089
+ assert_xpath '(((//ol/li)[1]/*)[2]/self::div[@class="ulist"]/ul/li)[1]/*', output, 2
1090
+ assert_xpath '(((//ol/li)[1]/*)[2]/self::div[@class="ulist"]/ul/li)[1]/p', output, 1
1091
+ assert_xpath '(((//ol/li)[1]/*)[2]/self::div[@class="ulist"]/ul/li)[1]/div[@class="openblock"]', output, 1
1092
+ assert_xpath '(((//ol/li)[1]/*)[2]/self::div[@class="ulist"]/ul/li)[2]/*', output, 2
1093
+ assert_xpath '(((//ol/li)[1]/*)[2]/self::div[@class="ulist"]/ul/li)[2]/p', output, 1
1094
+ assert_xpath '(((//ol/li)[1]/*)[2]/self::div[@class="ulist"]/ul/li)[2]/div[@class="paragraph"]', output, 1
1095
+ assert_xpath '((//ol/li)[1]/*)[3]/self::div[@class="paragraph"]', output, 1
1096
+ end
1097
+
1098
+ test 'repeated list continuations should attach to list items at respective levels ignoring blank lines' do
1099
+ input = <<-EOS
1100
+ == Lists
1101
+
1102
+ . list item 1
1103
+ +
1104
+ * nested list item 1
1105
+ +
1106
+ --
1107
+ open block for nested list item 1
1108
+ --
1109
+ +
1110
+ * nested list item 2
1111
+ +
1112
+ paragraph for nested list item 2
1113
+
1114
+
1115
+ +
1116
+ paragraph for list item 1
1117
+
1118
+ . list item 2
1119
+ EOS
1120
+ output = render_embedded_string input
1121
+ assert_css '.olist ol', output, 1
1122
+ assert_css '.olist ol > li', output, 2
1123
+ assert_css '.ulist ul', output, 1
1124
+ assert_css '.ulist ul > li', output, 2
1125
+ assert_css '.olist .ulist', output, 1
1126
+ assert_xpath '(//ol/li)[1]/*', output, 3
1127
+ assert_xpath '((//ol/li)[1]/*)[1]/self::p', output, 1
1128
+ assert_xpath '((//ol/li)[1]/*)[1]/self::p[text()="list item 1"]', output, 1
1129
+ assert_xpath '((//ol/li)[1]/*)[2]/self::div[@class="ulist"]', output, 1
1130
+ assert_xpath '((//ol/li)[1]/*)[2]/self::div[@class="ulist"]/ul/li', output, 2
1131
+ assert_xpath '(((//ol/li)[1]/*)[2]/self::div[@class="ulist"]/ul/li)[1]/*', output, 2
1132
+ assert_xpath '(((//ol/li)[1]/*)[2]/self::div[@class="ulist"]/ul/li)[1]/p', output, 1
1133
+ assert_xpath '(((//ol/li)[1]/*)[2]/self::div[@class="ulist"]/ul/li)[1]/div[@class="openblock"]', output, 1
1134
+ assert_xpath '(((//ol/li)[1]/*)[2]/self::div[@class="ulist"]/ul/li)[2]/*', output, 2
1135
+ assert_xpath '(((//ol/li)[1]/*)[2]/self::div[@class="ulist"]/ul/li)[2]/p', output, 1
1136
+ assert_xpath '(((//ol/li)[1]/*)[2]/self::div[@class="ulist"]/ul/li)[2]/div[@class="paragraph"]', output, 1
1137
+ assert_xpath '((//ol/li)[1]/*)[3]/self::div[@class="paragraph"]', output, 1
1138
+ end
1139
+
1140
+ test 'trailing list continuations should ignore preceding blank lines' do
1141
+ input = <<-EOS
1142
+ == Lists
1143
+
1144
+ * bullet 1
1145
+ ** bullet 1.1
1146
+ *** bullet 1.1.1
1147
+ +
1148
+ --
1149
+ open block
1150
+ --
1151
+
1152
+
1153
+ +
1154
+ bullet 1.1 paragraph
1155
+
1156
+
1157
+ +
1158
+ bullet 1 paragraph
1159
+
1160
+ * bullet 2
1161
+ EOS
1162
+ output = render_embedded_string input
1163
+
1164
+ assert_xpath '((//ul)[1]/li[1])/*', output, 3
1165
+ assert_xpath '(((//ul)[1]/li[1])/*)[1]/self::p[text()="bullet 1"]', output, 1
1166
+ assert_xpath '(((//ul)[1]/li[1])/*)[2]/self::div[@class="ulist"]', output, 1
1167
+ assert_xpath '(((//ul)[1]/li[1])/*)[3]/self::div[@class="paragraph"]/p[text()="bullet 1 paragraph"]', output, 1
1168
+
1169
+ assert_xpath '((//ul)[1]/li)[1]/div[@class="ulist"]/ul/li', output, 1
1170
+ assert_xpath '((//ul)[1]/li)[1]/div[@class="ulist"]/ul/li/*', output, 3
1171
+ assert_xpath '(((//ul)[1]/li)[1]/div[@class="ulist"]/ul/li/*)[1]/self::p[text()="bullet 1.1"]', output, 1
1172
+ assert_xpath '(((//ul)[1]/li)[1]/div[@class="ulist"]/ul/li/*)[2]/self::div[@class="ulist"]', output, 1
1173
+ assert_xpath '(((//ul)[1]/li)[1]/div[@class="ulist"]/ul/li/*)[3]/self::div[@class="paragraph"]/p[text()="bullet 1.1 paragraph"]', output, 1
1174
+
1175
+ assert_xpath '((//ul)[1]/li)[1]/div[@class="ulist"]/ul/li/div[@class="ulist"]/ul/li', output, 1
1176
+ assert_xpath '((//ul)[1]/li)[1]/div[@class="ulist"]/ul/li/div[@class="ulist"]/ul/li/*', output, 2
1177
+ assert_xpath '(((//ul)[1]/li)[1]/div[@class="ulist"]/ul/li/div[@class="ulist"]/ul/li/*)[1]/self::p', output, 1
1178
+ assert_xpath '(((//ul)[1]/li)[1]/div[@class="ulist"]/ul/li/div[@class="ulist"]/ul/li/*)[2]/self::div[@class="openblock"]', output, 1
1179
+ end
1180
+
739
1181
  # NOTE this is not consistent w/ AsciiDoc output, but this is some screwy input anyway
740
1182
  =begin
741
1183
  test "consecutive list continuation lines are folded" do
@@ -799,6 +1241,25 @@ List
799
1241
  assert_xpath '//ol/li', output, 3
800
1242
  end
801
1243
 
1244
+ test 'dot elements with interspersed line comments should be skipped and not break list' do
1245
+ input = <<-EOS
1246
+ == List
1247
+
1248
+ . Foo
1249
+ // line comment
1250
+ // another line comment
1251
+ . Boo
1252
+ // line comment
1253
+ more text
1254
+ // another line comment
1255
+ . Blech
1256
+ EOS
1257
+ output = render_embedded_string input
1258
+ assert_xpath '//ol', output, 1
1259
+ assert_xpath '//ol/li', output, 3
1260
+ assert_xpath %((//ol/li)[2]/p[text()="Boo\nmore text"]), output, 1
1261
+ end
1262
+
802
1263
  test "dot elements separated by line comment offset by blank lines should not merge lists" do
803
1264
  input = <<-EOS
804
1265
  List
@@ -1135,30 +1596,36 @@ anotherterm:: def
1135
1596
  assert_xpath '(//dl/dd)[1]//*[@class="openblock"]//p', output, 2
1136
1597
  end
1137
1598
 
1138
- test "paragraph attached by a list continuation in a labeled list" do
1599
+ test "paragraph attached by a list continuation on either side in a labeled list" do
1139
1600
  input = <<-EOS
1140
- term1:: def
1601
+ term1:: def1
1141
1602
  +
1142
1603
  more detail
1143
1604
  +
1144
- term2:: def
1605
+ term2:: def2
1145
1606
  EOS
1146
1607
  output = render_string input
1608
+ assert_xpath '(//dl/dt)[1][normalize-space(text())="term1"]', output, 1
1609
+ assert_xpath '(//dl/dt)[2][normalize-space(text())="term2"]', output, 1
1147
1610
  assert_xpath '(//dl/dd)[1]//p', output, 2
1611
+ assert_xpath '((//dl/dd)[1]//p)[1][text()="def1"]', output, 1
1148
1612
  assert_xpath '(//dl/dd)[1]/p/following-sibling::*[@class="paragraph"]/p[text() = "more detail"]', output, 1
1149
1613
  end
1150
1614
 
1151
- test "paragraph attached by a list continuation to a multi-line element in a labeled list" do
1615
+ test "paragraph attached by a list continuation on either side to a multi-line element in a labeled list" do
1152
1616
  input = <<-EOS
1153
1617
  term1::
1154
- def
1618
+ def1
1155
1619
  +
1156
1620
  more detail
1157
1621
  +
1158
- term2:: def
1622
+ term2:: def2
1159
1623
  EOS
1160
1624
  output = render_string input
1625
+ assert_xpath '(//dl/dt)[1][normalize-space(text())="term1"]', output, 1
1626
+ assert_xpath '(//dl/dt)[2][normalize-space(text())="term2"]', output, 1
1161
1627
  assert_xpath '(//dl/dd)[1]//p', output, 2
1628
+ assert_xpath '((//dl/dd)[1]//p)[1][text()="def1"]', output, 1
1162
1629
  assert_xpath '(//dl/dd)[1]/p/following-sibling::*[@class="paragraph"]/p[text() = "more detail"]', output, 1
1163
1630
  end
1164
1631
 
@@ -1469,11 +1936,87 @@ detail1
1469
1936
  assert_xpath '//dl//dl/dt/following-sibling::dd/p[text() = "detail1"]', output, 1
1470
1937
  end
1471
1938
  end
1939
+
1940
+ context 'Special lists' do
1941
+ test 'should render glossary list with proper semantics' do
1942
+ input = <<-EOS
1943
+ [glossary]
1944
+ term 1:: def 1
1945
+ term 2:: def 2
1946
+ EOS
1947
+ output = render_embedded_string input
1948
+ assert_css '.dlist.glossary', output, 1
1949
+ assert_css '.dlist dt:not([class])', output, 2
1950
+ end
1951
+
1952
+ test 'should render horizontal list with proper markup' do
1953
+ input = <<-EOS
1954
+ [horizontal]
1955
+ first term:: definition
1956
+ +
1957
+ more detail
1958
+
1959
+ second term:: definition
1960
+ EOS
1961
+ output = render_embedded_string input
1962
+ assert_css '.hdlist', output, 1
1963
+ assert_css '.hdlist table', output, 1
1964
+ assert_css '.hdlist table colgroup col', output, 2
1965
+ assert_css '.hdlist table tr', output, 2
1966
+ assert_xpath '/*[@class="hdlist"]/table/tr[1]/td', output, 2
1967
+ assert_xpath '/*[@class="hdlist"]/table/tr[1]/td[@class="hdlist1"]', output, 1
1968
+ assert_xpath '/*[@class="hdlist"]/table/tr[1]/td[@class="hdlist2"]', output, 1
1969
+ assert_xpath '/*[@class="hdlist"]/table/tr[1]/td[@class="hdlist2"]/p', output, 1
1970
+ assert_xpath '/*[@class="hdlist"]/table/tr[1]/td[@class="hdlist2"]/p/following-sibling::*[@class="paragraph"]', output, 1
1971
+ assert_xpath '((//tr)[1]/td)[1][normalize-space(text())="first term"]', output, 1
1972
+ assert_xpath '((//tr)[1]/td)[2]/p[normalize-space(text())="definition"]', output, 1
1973
+
1974
+ assert_xpath '/*[@class="hdlist"]/table/tr[2]/td', output, 2
1975
+ assert_xpath '((//tr)[2]/td)[1][normalize-space(text())="second term"]', output, 1
1976
+ assert_xpath '((//tr)[2]/td)[2]/p[normalize-space(text())="definition"]', output, 1
1977
+ end
1978
+
1979
+ test 'should render qanda list with proper semantics' do
1980
+ input = <<-EOS
1981
+ [qanda]
1982
+ Question one::
1983
+ Answer one.
1984
+ Question two::
1985
+ Answer two.
1986
+ EOS
1987
+ output = render_embedded_string input
1988
+ assert_css '.qlist.qanda', output, 1
1989
+ assert_css '.qlist ol', output, 1
1990
+ assert_css '.qlist ol li', output, 2
1991
+ assert_css '.qlist ol li:nth-child(1) p em', output, 1
1992
+ assert_css '.qlist ol li:nth-child(1) p', output, 2
1993
+ end
1994
+
1995
+ test 'should render bibliography list with proper semantics' do
1996
+ input = <<-EOS
1997
+ [bibliography]
1998
+ - [[[taoup]]] Eric Steven Raymond. 'The Art of Unix
1999
+ Programming'. Addison-Wesley. ISBN 0-13-142901-9.
2000
+ - [[[walsh-muellner]]] Norman Walsh & Leonard Muellner.
2001
+ 'DocBook - The Definitive Guide'. O'Reilly & Associates. 1999.
2002
+ ISBN 1-56592-580-7.
2003
+ EOS
2004
+ output = render_embedded_string input
2005
+ assert_css '.ulist.bibliography', output, 1
2006
+ assert_css '.ulist.bibliography ul', output, 1
2007
+ assert_css '.ulist.bibliography ul li', output, 2
2008
+ assert_css '.ulist.bibliography ul li p', output, 2
2009
+ assert_css '.ulist.bibliography ul li:nth-child(1) p a#taoup', output, 1
2010
+ assert_xpath '//a/*', output, 0
2011
+ text = xmlnodes_at_xpath '(//a)[1]/following-sibling::text()', output, 1
2012
+ assert text.text.start_with?('[taoup] ')
2013
+ end
2014
+ end
1472
2015
  end
1473
2016
 
1474
2017
  context 'Labeled lists redux' do
1475
2018
 
1476
- context 'Item without text inline' do
2019
+ context 'Label without text on same line' do
1477
2020
 
1478
2021
  test 'folds text from subsequent line' do
1479
2022
  input = <<-EOS
@@ -1520,6 +2063,24 @@ term2:: def2
1520
2063
  assert_xpath '//*[@class="dlist"]//dd', output, 2
1521
2064
  assert_xpath '(//*[@class="dlist"]//dd)[1]/p[text()="def1"]', output, 1
1522
2065
  end
2066
+
2067
+ test 'paragraph offset by blank lines does not break list if label does not have inline text' do
2068
+ input = <<-EOS
2069
+ == Lists
2070
+
2071
+ term1::
2072
+
2073
+ def1
2074
+
2075
+ term2:: def2
2076
+ EOS
2077
+
2078
+ output = render_embedded_string input
2079
+ assert_css 'dl', output, 1
2080
+ assert_css 'dl > dt', output, 2
2081
+ assert_css 'dl > dd', output, 2
2082
+ assert_xpath '(//dl/dd)[1]/p[text()="def1"]', output, 1
2083
+ end
1523
2084
 
1524
2085
  test 'folds text from first line after comment line' do
1525
2086
  input = <<-EOS
@@ -1858,6 +2419,62 @@ term2:: def2
1858
2419
  assert_xpath '(//*[@class="dlist"]//dd)[1]//ul/li', output, 3
1859
2420
  assert_xpath '(//*[@class="dlist"]//dd)[2]/p[text()="def2"]', output, 1
1860
2421
  end
2422
+
2423
+ test 'appends indented list to first term that is adjacent to second term' do
2424
+ input = <<-EOS
2425
+ == Lists
2426
+
2427
+ label 1::
2428
+ definition 1
2429
+
2430
+ * one
2431
+ * two
2432
+ * three
2433
+ label 2::
2434
+ definition 2
2435
+
2436
+ paragraph
2437
+ EOS
2438
+ output = render_embedded_string input
2439
+ assert_css '.dlist > dl', output, 1
2440
+ assert_css '.dlist dt', output, 2
2441
+ assert_xpath '(//*[@class="dlist"]//dt)[1][normalize-space(text())="label 1"]', output, 1
2442
+ assert_xpath '(//*[@class="dlist"]//dt)[2][normalize-space(text())="label 2"]', output, 1
2443
+ assert_css '.dlist dd', output, 2
2444
+ assert_xpath '(//*[@class="dlist"]//dd)[1]/p[text()="definition 1"]', output, 1
2445
+ assert_xpath '(//*[@class="dlist"]//dd)[2]/p[text()="definition 2"]', output, 1
2446
+ assert_xpath '(//*[@class="dlist"]//dd)[1]/p/following-sibling::*[@class="ulist"]', output, 1
2447
+ assert_xpath '(//*[@class="dlist"]//dd)[1]/p/following-sibling::*[@class="ulist"]//li', output, 3
2448
+ assert_css '.dlist + .paragraph', output, 1
2449
+ end
2450
+
2451
+ test 'appends indented list to first term that is attached by a continuation and adjacent to second term' do
2452
+ input = <<-EOS
2453
+ == Lists
2454
+
2455
+ label 1::
2456
+ definition 1
2457
+ +
2458
+ * one
2459
+ * two
2460
+ * three
2461
+ label 2::
2462
+ definition 2
2463
+
2464
+ paragraph
2465
+ EOS
2466
+ output = render_embedded_string input
2467
+ assert_css '.dlist > dl', output, 1
2468
+ assert_css '.dlist dt', output, 2
2469
+ assert_xpath '(//*[@class="dlist"]//dt)[1][normalize-space(text())="label 1"]', output, 1
2470
+ assert_xpath '(//*[@class="dlist"]//dt)[2][normalize-space(text())="label 2"]', output, 1
2471
+ assert_css '.dlist dd', output, 2
2472
+ assert_xpath '(//*[@class="dlist"]//dd)[1]/p[text()="definition 1"]', output, 1
2473
+ assert_xpath '(//*[@class="dlist"]//dd)[2]/p[text()="definition 2"]', output, 1
2474
+ assert_xpath '(//*[@class="dlist"]//dd)[1]/p/following-sibling::*[@class="ulist"]', output, 1
2475
+ assert_xpath '(//*[@class="dlist"]//dd)[1]/p/following-sibling::*[@class="ulist"]//li', output, 3
2476
+ assert_css '.dlist + .paragraph', output, 1
2477
+ end
1861
2478
 
1862
2479
  test 'appends list and paragraph block when line following list attached by continuation' do
1863
2480
  input = <<-EOS
@@ -2060,8 +2677,7 @@ continued
2060
2677
  output = render_embedded_string input
2061
2678
  assert_xpath '//*[@class="dlist"]/dl', output, 1
2062
2679
  assert_xpath '//*[@class="dlist"]//dd', output, 1
2063
- # NOTE the extra endline is added as a result of whitespace in the ERB template
2064
- assert_xpath %(//*[@class="dlist"]//dd/p[text()="def1\ncontinued\n\ncontinued"]), output, 1
2680
+ assert_xpath %(//*[@class="dlist"]//dd/p[text()="def1\ncontinued\ncontinued"]), output, 1
2065
2681
  end
2066
2682
 
2067
2683
  test 'folds text from inline definition and line following comment line' do
@@ -2581,4 +3197,27 @@ Violets are blue <2>
2581
3197
  assert_xpath '(//literallayout/following-sibling::*[1][self::calloutlist]/callout)[1][@arearefs = "CO1-1"]', output, 1
2582
3198
  assert_xpath '(//literallayout/following-sibling::*[1][self::calloutlist]/callout)[2][@arearefs = "CO1-2"]', output, 1
2583
3199
  end
3200
+
3201
+ test 'callout list with icons enabled' do
3202
+ input = <<-EOS
3203
+ [source]
3204
+ ----
3205
+ require 'asciidoctor' # <1>
3206
+ doc = Asciidoctor::Document.new('Hello, World!') # <2>
3207
+ puts doc.render # <3>
3208
+ ----
3209
+ <1> Describe the first line
3210
+ <2> Describe the second line
3211
+ <3> Describe the third line
3212
+ EOS
3213
+ output = render_embedded_string input, :attributes => {'icons' => ''}
3214
+ assert_css '.listingblock code > img', output, 3
3215
+ (1..3).each do |i|
3216
+ assert_xpath %((/div[@class="listingblock"]//code/img)[#{i}][@src="images/icons/callouts/#{i}.png"][@alt="#{i}"]), output, 1
3217
+ end
3218
+ assert_css '.colist table td img', output, 3
3219
+ (1..3).each do |i|
3220
+ assert_xpath %((/div[@class="colist arabic"]//td/img)[#{i}][@src="images/icons/callouts/#{i}.png"][@alt="#{i}"]), output, 1
3221
+ end
3222
+ end
2584
3223
  end