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.
- data/README.asciidoc +163 -41
- data/Rakefile +3 -1
- data/asciidoctor.gemspec +13 -5
- data/bin/asciidoctor +6 -3
- data/bin/asciidoctor-safe +13 -0
- data/lib/asciidoctor.rb +237 -26
- data/lib/asciidoctor/abstract_node.rb +27 -17
- data/lib/asciidoctor/attribute_list.rb +6 -0
- data/lib/asciidoctor/backends/base_template.rb +3 -4
- data/lib/asciidoctor/backends/docbook45.rb +114 -55
- data/lib/asciidoctor/backends/html5.rb +173 -104
- data/lib/asciidoctor/cli/invoker.rb +105 -0
- data/lib/asciidoctor/cli/options.rb +146 -0
- data/lib/asciidoctor/document.rb +135 -35
- data/lib/asciidoctor/lexer.rb +86 -33
- data/lib/asciidoctor/list_item.rb +2 -2
- data/lib/asciidoctor/reader.rb +6 -7
- data/lib/asciidoctor/section.rb +17 -5
- data/lib/asciidoctor/substituters.rb +216 -97
- data/lib/asciidoctor/table.rb +9 -2
- data/lib/asciidoctor/version.rb +1 -1
- data/man/asciidoctor.1 +212 -0
- data/man/asciidoctor.ad +156 -0
- data/test/attributes_test.rb +108 -5
- data/test/blocks_test.rb +102 -15
- data/test/document_test.rb +214 -3
- data/test/fixtures/encoding.asciidoc +4 -0
- data/test/fixtures/sample.asciidoc +26 -0
- data/test/invoker_test.rb +254 -0
- data/test/lexer_test.rb +53 -0
- data/test/links_test.rb +30 -0
- data/test/lists_test.rb +648 -9
- data/test/options_test.rb +68 -0
- data/test/paragraphs_test.rb +65 -1
- data/test/reader_test.rb +18 -4
- data/test/{headers_test.rb → sections_test.rb} +237 -0
- data/test/substitutions_test.rb +247 -5
- data/test/tables_test.rb +22 -4
- data/test/test_helper.rb +47 -3
- data/test/text_test.rb +20 -4
- metadata +34 -6
- data/noof.rb +0 -16
@@ -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
|
data/test/lexer_test.rb
CHANGED
@@ -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
|
data/test/links_test.rb
CHANGED
@@ -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])
|
data/test/lists_test.rb
CHANGED
@@ -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::
|
1601
|
+
term1:: def1
|
1141
1602
|
+
|
1142
1603
|
more detail
|
1143
1604
|
+
|
1144
|
-
term2::
|
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
|
-
|
1618
|
+
def1
|
1155
1619
|
+
|
1156
1620
|
more detail
|
1157
1621
|
+
|
1158
|
-
term2::
|
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 '
|
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
|
-
|
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
|