asciidoctor 0.0.5 → 0.0.6
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 +156 -0
- data/asciidoctor.gemspec +5 -4
- data/lib/asciidoctor.rb +46 -34
- data/lib/asciidoctor/block.rb +59 -42
- data/lib/asciidoctor/document.rb +56 -20
- data/lib/asciidoctor/lexer.rb +204 -107
- data/lib/asciidoctor/list_item.rb +47 -14
- data/lib/asciidoctor/reader.rb +29 -14
- data/lib/asciidoctor/render_templates.rb +162 -64
- data/lib/asciidoctor/renderer.rb +3 -3
- data/lib/asciidoctor/section.rb +32 -6
- data/lib/asciidoctor/version.rb +1 -1
- data/test/attributes_test.rb +44 -4
- data/test/document_test.rb +21 -2
- data/test/headers_test.rb +72 -13
- data/test/lexer_test.rb +54 -0
- data/test/lists_test.rb +406 -0
- data/test/paragraphs_test.rb +103 -3
- data/test/preamble_test.rb +88 -0
- data/test/test_helper.rb +6 -5
- data/test/text_test.rb +2 -1
- metadata +7 -5
- data/README.md +0 -154
- data/test/list_elements_test.rb +0 -55
data/lib/asciidoctor/renderer.rb
CHANGED
@@ -62,8 +62,8 @@ class Asciidoctor::Renderer
|
|
62
62
|
if stack_obj.context == :dlist
|
63
63
|
dt_list = stack_obj.buffer.map{|dt,dd| dt.content.strip}.join(', ')
|
64
64
|
"BLOCK :dlist (#{dt_list})"
|
65
|
-
else
|
66
|
-
|
65
|
+
#else
|
66
|
+
# "BLOCK #{stack_obj.context.inspect}"
|
67
67
|
end
|
68
68
|
else stack_obj.class
|
69
69
|
end
|
@@ -71,7 +71,7 @@ class Asciidoctor::Renderer
|
|
71
71
|
prefix << ' '
|
72
72
|
end
|
73
73
|
STDERR.puts '-' * 80
|
74
|
-
STDERR.puts ret.inspect
|
74
|
+
#STDERR.puts ret.inspect
|
75
75
|
STDERR.puts '=' * 80
|
76
76
|
STDERR.puts
|
77
77
|
end
|
data/lib/asciidoctor/section.rb
CHANGED
@@ -24,14 +24,15 @@ class Asciidoctor::Section
|
|
24
24
|
# Public: Set the String section name.
|
25
25
|
attr_writer :name
|
26
26
|
|
27
|
-
# Public: Get/Set the String section title.
|
28
|
-
attr_accessor :title
|
29
|
-
|
30
27
|
# Public: Get/Set the String section caption.
|
31
28
|
attr_accessor :caption
|
32
29
|
|
33
30
|
# Public: Get/Set the String section anchor name.
|
34
31
|
attr_accessor :anchor
|
32
|
+
alias :id :anchor
|
33
|
+
|
34
|
+
# Public: Get the Hash of attributes for this block
|
35
|
+
attr_accessor :attributes
|
35
36
|
|
36
37
|
# Public: Get the Array of section blocks.
|
37
38
|
attr_reader :blocks
|
@@ -41,6 +42,7 @@ class Asciidoctor::Section
|
|
41
42
|
# parent - The parent Asciidoc Object.
|
42
43
|
def initialize(parent)
|
43
44
|
@parent = parent
|
45
|
+
@attributes = {}
|
44
46
|
@blocks = []
|
45
47
|
end
|
46
48
|
|
@@ -59,16 +61,22 @@ class Asciidoctor::Section
|
|
59
61
|
gsub( /`([^`]+)`/, '<tt>\1</tt>' )
|
60
62
|
end
|
61
63
|
|
62
|
-
# Public: Get the String section id
|
64
|
+
# Public: Get the String section id prefixed with value of idprefix attribute, otherwise an underscore
|
65
|
+
#
|
66
|
+
# Section ID synthesis can be disabled by undefining the sectids attribute.
|
63
67
|
#
|
64
68
|
# Examples
|
65
69
|
#
|
66
|
-
# section = Section.new
|
70
|
+
# section = Section.new(parent)
|
67
71
|
# section.name = "Foo"
|
68
72
|
# section.section_id
|
69
73
|
# => "_foo"
|
70
74
|
def section_id
|
71
|
-
|
75
|
+
if self.document.attributes.has_key? 'sectids'
|
76
|
+
self.document.attributes.fetch('idprefix', '_') + "#{name && name.downcase.gsub(/\W+/,'_').gsub(/_+$/, '')}".tr_s('_', '_')
|
77
|
+
else
|
78
|
+
nil
|
79
|
+
end
|
72
80
|
end
|
73
81
|
|
74
82
|
# Public: Get the Asciidoctor::Document instance to which this Block belongs
|
@@ -76,6 +84,19 @@ class Asciidoctor::Section
|
|
76
84
|
@parent.is_a?(Asciidoctor::Document) ? @parent : @parent.document
|
77
85
|
end
|
78
86
|
|
87
|
+
def attr(name, default = nil)
|
88
|
+
default.nil? ? @attributes.fetch(name.to_s, self.document.attr(name)) :
|
89
|
+
@attributes.fetch(name.to_s, self.document.attr(name, default))
|
90
|
+
end
|
91
|
+
|
92
|
+
def attr?(name)
|
93
|
+
@attributes.has_key?(name.to_s) || self.document.attr?(name)
|
94
|
+
end
|
95
|
+
|
96
|
+
def update_attributes(attributes)
|
97
|
+
@attributes.update(attributes)
|
98
|
+
end
|
99
|
+
|
79
100
|
# Public: Get the Asciidoctor::Renderer instance being used for the ancestor
|
80
101
|
# Asciidoctor::Document instance.
|
81
102
|
def renderer
|
@@ -109,6 +130,11 @@ class Asciidoctor::Section
|
|
109
130
|
end.join
|
110
131
|
end
|
111
132
|
|
133
|
+
# Public: The title of this section, an alias of the section name
|
134
|
+
def title
|
135
|
+
@name
|
136
|
+
end
|
137
|
+
|
112
138
|
# Public: Get the Integer number of blocks in the section.
|
113
139
|
#
|
114
140
|
# Examples
|
data/lib/asciidoctor/version.rb
CHANGED
data/test/attributes_test.rb
CHANGED
@@ -3,17 +3,27 @@ require 'test_helper'
|
|
3
3
|
context "Attributes" do
|
4
4
|
test "creates an attribute" do
|
5
5
|
doc = document_from_string(":frog: Tanglefoot")
|
6
|
-
assert_equal doc.
|
6
|
+
assert_equal doc.attributes['frog'], 'Tanglefoot'
|
7
|
+
end
|
8
|
+
|
9
|
+
test "creates an attribute by fusing a multi-line value" do
|
10
|
+
str = <<-EOS
|
11
|
+
:description: This is the first +
|
12
|
+
Ruby implementation of +
|
13
|
+
AsciiDoc.
|
14
|
+
EOS
|
15
|
+
doc = document_from_string(str)
|
16
|
+
assert_equal doc.attributes['description'], 'This is the first Ruby implementation of AsciiDoc.'
|
7
17
|
end
|
8
18
|
|
9
19
|
test "deletes an attribute" do
|
10
20
|
doc = document_from_string(":frog: Tanglefoot\n:frog!:")
|
11
|
-
assert_equal nil, doc.
|
21
|
+
assert_equal nil, doc.attributes['frog']
|
12
22
|
end
|
13
23
|
|
14
24
|
test "doesn't choke when deleting a non-existing attribute" do
|
15
25
|
doc = document_from_string(":frog!:")
|
16
|
-
assert_equal nil, doc.
|
26
|
+
assert_equal nil, doc.attributes['frog']
|
17
27
|
end
|
18
28
|
|
19
29
|
test "render properly with simple names" do
|
@@ -66,7 +76,8 @@ context "Attributes" do
|
|
66
76
|
test "doesn't disturb attribute-looking things escaped with literals" do
|
67
77
|
html = render_string(":foo: bar\nThis is a +++{foo}+++ day.")
|
68
78
|
result = Nokogiri::HTML(html)
|
69
|
-
assert_equal 'This is a {foo} day.', result.css('p').first.content.strip
|
79
|
+
#assert_equal 'This is a {foo} day.', result.css('p').first.content.strip
|
80
|
+
pending "Don't yet have inline passthrough working"
|
70
81
|
end
|
71
82
|
|
72
83
|
test "doesn't substitute attributes inside code blocks" do
|
@@ -77,6 +88,35 @@ context "Attributes" do
|
|
77
88
|
pending "whut?"
|
78
89
|
end
|
79
90
|
|
91
|
+
context "Block attributes" do
|
92
|
+
test "Position attributes assigned to block" do
|
93
|
+
input = <<-EOS
|
94
|
+
[quote, Name, Source]
|
95
|
+
____
|
96
|
+
A famous quote.
|
97
|
+
____
|
98
|
+
EOS
|
99
|
+
doc = document_from_string(input)
|
100
|
+
qb = doc.elements.first
|
101
|
+
assert_equal 'quote', qb.attributes['style']
|
102
|
+
assert_equal 'quote', qb.attr(:style)
|
103
|
+
assert_equal 'Name', qb.attributes['attribution']
|
104
|
+
assert_equal 'Source', qb.attributes['citetitle']
|
105
|
+
end
|
106
|
+
|
107
|
+
test "Block attributes are additive" do
|
108
|
+
input = <<-EOS
|
109
|
+
[id='foo']
|
110
|
+
[role='lead']
|
111
|
+
A paragraph.
|
112
|
+
EOS
|
113
|
+
doc = document_from_string(input)
|
114
|
+
para = doc.elements.first
|
115
|
+
assert_equal 'foo', para.id
|
116
|
+
assert_equal 'lead', para.attributes['role']
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
80
120
|
context "intrinsics" do
|
81
121
|
|
82
122
|
test "substitute intrinsics" do
|
data/test/document_test.rb
CHANGED
@@ -7,11 +7,30 @@ class DocumentTest < Test::Unit::TestCase
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def test_title
|
10
|
-
assert_equal "AsciiDoc Home Page", @doc.
|
10
|
+
assert_equal "AsciiDoc Home Page", @doc.doctitle
|
11
|
+
assert_equal 14, @doc.elements.size
|
12
|
+
assert_equal :preamble, @doc.elements[0].context
|
13
|
+
assert @doc.elements[1].is_a? ::Asciidoctor::Section
|
11
14
|
end
|
12
15
|
|
13
16
|
def test_with_no_title
|
14
17
|
d = Asciidoctor::Document.new(["Snorf"])
|
15
|
-
assert_nil d.
|
18
|
+
assert_nil d.doctitle
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_with_header_footer
|
22
|
+
result = render_string("= Title\n\npreamble")
|
23
|
+
assert_xpath '/html', result, 1
|
24
|
+
assert_xpath '//*[@id="header"]', result, 1
|
25
|
+
assert_xpath '//*[@id="footer"]', result, 1
|
26
|
+
assert_xpath '//*[@id="preamble"]', result, 1
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_with_no_header_footer
|
30
|
+
result = render_string("= Title\n\npreamble", :header_footer => false)
|
31
|
+
assert_xpath '/html', result, 0
|
32
|
+
assert_xpath '/*[@id="header"]', result, 0
|
33
|
+
assert_xpath '/*[@id="footer"]', result, 0
|
34
|
+
assert_xpath '/*[@id="preamble"]', result, 1
|
16
35
|
end
|
17
36
|
end
|
data/test/headers_test.rb
CHANGED
@@ -1,55 +1,114 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
3
|
context "Headers" do
|
4
|
-
test "
|
5
|
-
|
4
|
+
test "document title with multiline syntax" do
|
5
|
+
title = "My Title"
|
6
|
+
chars = "=" * title.length
|
7
|
+
assert_xpath "//h1[not(@id)][text() = 'My Title']", render_string(title + "\n" + chars)
|
8
|
+
assert_xpath "//h1[not(@id)][text() = 'My Title']", render_string(title + "\n" + chars + "\n")
|
9
|
+
end
|
10
|
+
|
11
|
+
test "document title with multiline syntax, give a char" do
|
12
|
+
title = "My Title"
|
13
|
+
chars = "=" * (title.length + 1)
|
14
|
+
assert_xpath "//h1[not(@id)][text() = 'My Title']", render_string(title + "\n" + chars)
|
15
|
+
assert_xpath "//h1[not(@id)][text() = 'My Title']", render_string(title + "\n" + chars + "\n")
|
16
|
+
end
|
17
|
+
|
18
|
+
test "document title with multiline syntax, take a char" do
|
19
|
+
title = "My Title"
|
20
|
+
chars = "=" * (title.length - 1)
|
21
|
+
assert_xpath "//h1[not(@id)][text() = 'My Title']", render_string(title + "\n" + chars)
|
22
|
+
assert_xpath "//h1[not(@id)][text() = 'My Title']", render_string(title + "\n" + chars + "\n")
|
23
|
+
end
|
24
|
+
|
25
|
+
test "not enough chars for a multiline document title" do
|
26
|
+
title = "My Title"
|
27
|
+
chars = "=" * (title.length - 2)
|
28
|
+
assert_xpath '//h1', render_string(title + "\n" + chars), 0
|
29
|
+
assert_xpath '//h1', render_string(title + "\n" + chars + "\n"), 0
|
30
|
+
end
|
31
|
+
|
32
|
+
test "too many chars for a multiline document title" do
|
33
|
+
title = "My Title"
|
34
|
+
chars = "=" * (title.length + 2)
|
35
|
+
assert_xpath '//h1', render_string(title + "\n" + chars), 0
|
36
|
+
assert_xpath '//h1', render_string(title + "\n" + chars + "\n"), 0
|
37
|
+
end
|
38
|
+
|
39
|
+
test "document title with single-line syntax" do
|
40
|
+
assert_xpath "//h1[not(@id)][text() = 'My Title']", render_string("= My Title")
|
41
|
+
end
|
42
|
+
|
43
|
+
test "document title with symmetric syntax" do
|
44
|
+
assert_xpath "//h1[not(@id)][text() = 'My Title']", render_string("= My Title =")
|
6
45
|
end
|
7
46
|
|
8
47
|
context "level 1" do
|
9
48
|
test "with multiline syntax" do
|
10
|
-
assert_xpath "//h2[@id='_my_section']", render_string("My Section\n-----------")
|
49
|
+
assert_xpath "//h2[@id='_my_section'][text() = 'My Section']", render_string("My Section\n-----------")
|
11
50
|
end
|
12
51
|
|
13
|
-
test "with single
|
14
|
-
assert_xpath "//h2[@id='_my_title']", render_string("== My Title")
|
52
|
+
test "with single-line syntax" do
|
53
|
+
assert_xpath "//h2[@id='_my_title'][text() = 'My Title']", render_string("== My Title")
|
54
|
+
end
|
55
|
+
|
56
|
+
test "with single-line symmetric syntax" do
|
57
|
+
assert_xpath "//h2[@id='_my_title'][text() = 'My Title']", render_string("== My Title ==")
|
58
|
+
end
|
59
|
+
|
60
|
+
test "with single-line non-matching symmetric syntax" do
|
61
|
+
assert_xpath "//h2[@id='_my_title'][text() = 'My Title ===']", render_string("== My Title ===")
|
15
62
|
end
|
16
63
|
|
17
64
|
test "with non-word character" do
|
18
|
-
assert_xpath "//h2[@id='_where_s_the_love']", render_string("== Where's the love?")
|
65
|
+
assert_xpath "//h2[@id='_where_s_the_love'][text() = \"Where's the love?\"]", render_string("== Where's the love?")
|
19
66
|
end
|
20
67
|
|
21
68
|
test "with sequential non-word characters" do
|
22
|
-
assert_xpath "//h2[@id='
|
69
|
+
assert_xpath "//h2[@id='_what_the_is_this'][text() = 'What the \#@$ is this?']", render_string('== What the #@$ is this?')
|
70
|
+
end
|
71
|
+
|
72
|
+
test "with trailing whitespace" do
|
73
|
+
assert_xpath "//h2[@id='_my_title'][text() = 'My Title']", render_string("== My Title ")
|
74
|
+
end
|
75
|
+
|
76
|
+
test "with custom blank idprefix" do
|
77
|
+
assert_xpath "//h2[@id='my_title'][text() = 'My Title']", render_string(":idprefix:\n\n== My Title ")
|
78
|
+
end
|
79
|
+
|
80
|
+
test "with custom non-blank idprefix" do
|
81
|
+
assert_xpath "//h2[@id='ref_my_title'][text() = 'My Title']", render_string(":idprefix: ref_\n\n== My Title ")
|
23
82
|
end
|
24
83
|
end
|
25
84
|
|
26
85
|
context "level 2" do
|
27
86
|
test "with multiline syntax" do
|
28
|
-
assert_xpath "//h3", render_string("My Section\n~~~~~~~~~~~")
|
87
|
+
assert_xpath "//h3[@id='_my_section'][text() = 'My Section']", render_string("My Section\n~~~~~~~~~~~")
|
29
88
|
end
|
30
89
|
|
31
90
|
test "with single line syntax" do
|
32
|
-
assert_xpath "//h3", render_string("=== My Title")
|
91
|
+
assert_xpath "//h3[@id='_my_title'][text() = 'My Title']", render_string("=== My Title")
|
33
92
|
end
|
34
93
|
end
|
35
94
|
|
36
95
|
context "level 3" do
|
37
96
|
test "with multiline syntax" do
|
38
|
-
assert_xpath "//h4", render_string("My Section\n^^^^^^^^^^")
|
97
|
+
assert_xpath "//h4[@id='_my_section'][text() = 'My Section']", render_string("My Section\n^^^^^^^^^^")
|
39
98
|
end
|
40
99
|
|
41
100
|
test "with single line syntax" do
|
42
|
-
assert_xpath "//h4", render_string("==== My Title")
|
101
|
+
assert_xpath "//h4[@id='_my_title'][text() = 'My Title']", render_string("==== My Title")
|
43
102
|
end
|
44
103
|
end
|
45
104
|
|
46
105
|
context "level 4" do
|
47
106
|
test "with multiline syntax" do
|
48
|
-
assert_xpath "//h5", render_string("My Section\n++++++++++")
|
107
|
+
assert_xpath "//h5[@id='_my_section'][text() = 'My Section']", render_string("My Section\n++++++++++")
|
49
108
|
end
|
50
109
|
|
51
110
|
test "with single line syntax" do
|
52
|
-
assert_xpath "//h5", render_string("===== My Title")
|
111
|
+
assert_xpath "//h5[@id='_my_title'][text() = 'My Title']", render_string("===== My Title")
|
53
112
|
end
|
54
113
|
end
|
55
114
|
end
|
data/test/lexer_test.rb
CHANGED
@@ -9,4 +9,58 @@ class LexerTest < Test::Unit::TestCase
|
|
9
9
|
assert Asciidoctor::Lexer.is_section_heading?("AsciiDoc Home Page", "==================")
|
10
10
|
assert Asciidoctor::Lexer.is_section_heading?("=== AsciiDoc Home Page")
|
11
11
|
end
|
12
|
+
|
13
|
+
def test_collect_unnamed_attributes
|
14
|
+
attributes = {}
|
15
|
+
line = "first, second one, third"
|
16
|
+
Asciidoctor::Lexer.collect_attributes(line, attributes)
|
17
|
+
assert_equal 3, attributes.length
|
18
|
+
assert_equal 'first', attributes[0]
|
19
|
+
assert_equal 'second one', attributes[1]
|
20
|
+
assert_equal 'third', attributes[2]
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_collect_named_attributes
|
24
|
+
attributes = {}
|
25
|
+
line = "first='value', second=\"value two\", third=three"
|
26
|
+
Asciidoctor::Lexer.collect_attributes(line, attributes)
|
27
|
+
assert_equal 3, attributes.length
|
28
|
+
assert_equal 'value', attributes['first']
|
29
|
+
assert_equal 'value two', attributes['second']
|
30
|
+
assert_equal 'three', attributes['third']
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_collect_mixed_named_and_unnamed_attributes
|
34
|
+
attributes = {}
|
35
|
+
line = "first, second=\"value two\", third=three"
|
36
|
+
Asciidoctor::Lexer.collect_attributes(line, attributes)
|
37
|
+
assert_equal 3, attributes.length
|
38
|
+
assert_equal 'first', attributes[0]
|
39
|
+
assert_equal 'value two', attributes['second']
|
40
|
+
assert_equal 'three', attributes['third']
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_collect_and_rekey_unnamed_attributes
|
44
|
+
attributes = {}
|
45
|
+
line = "first, second one, third, fourth"
|
46
|
+
Asciidoctor::Lexer.collect_attributes(line, attributes, ['a', 'b', 'c'])
|
47
|
+
assert_equal 7, attributes.length
|
48
|
+
assert_equal 'first', attributes['a']
|
49
|
+
assert_equal 'second one', attributes['b']
|
50
|
+
assert_equal 'third', attributes['c']
|
51
|
+
assert_equal 'first', attributes[0]
|
52
|
+
assert_equal 'second one', attributes[1]
|
53
|
+
assert_equal 'third', attributes[2]
|
54
|
+
assert_equal 'fourth', attributes[3]
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_rekey_positional_attributes
|
58
|
+
attributes = {0 => 'source', 1 => 'java'}
|
59
|
+
Asciidoctor::Lexer.rekey_positional_attributes(attributes, ['style', 'language', 'linenums'])
|
60
|
+
assert_equal 4, attributes.length
|
61
|
+
assert_equal 'source', attributes[0]
|
62
|
+
assert_equal 'java', attributes[1]
|
63
|
+
assert_equal 'source', attributes['style']
|
64
|
+
assert_equal 'java', attributes['language']
|
65
|
+
end
|
12
66
|
end
|
data/test/lists_test.rb
ADDED
@@ -0,0 +1,406 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
context "Bulleted lists (:ulist)" do
|
4
|
+
context "Simple lists" do
|
5
|
+
test "dash elements with no blank lines" do
|
6
|
+
output = render_string("Blah\n====\n- Foo\n- Boo\n- Blech")
|
7
|
+
assert_xpath '//ul', output, 1
|
8
|
+
assert_xpath '//ul/li', output, 3
|
9
|
+
end
|
10
|
+
|
11
|
+
test "dash elements with blank lines" do
|
12
|
+
output = render_string("Blah\n====\n- Foo\n\n- Boo\n\n- Blech")
|
13
|
+
assert_xpath '//ul', output, 1
|
14
|
+
assert_xpath '//ul/li', output, 3
|
15
|
+
end
|
16
|
+
|
17
|
+
test "asterisk elements with no blank lines" do
|
18
|
+
output = render_string("Blah\n====\n* Foo\n* Boo\n* Blech")
|
19
|
+
assert_xpath '//ul', output, 1
|
20
|
+
assert_xpath '//ul/li', output, 3
|
21
|
+
end
|
22
|
+
|
23
|
+
test "asterisk elements with blank lines should merge lists" do
|
24
|
+
output = render_string("Blah\n====\n* Foo\n\n* Boo\n\n* Blech")
|
25
|
+
assert_xpath '//ul', output, 1
|
26
|
+
assert_xpath '//ul/li', output, 3
|
27
|
+
end
|
28
|
+
|
29
|
+
test "asterisk elements with blank lines separated by line comment should not merge lists" do
|
30
|
+
output = render_string("Blah\n====\n* Foo\n* Boo\n\n//\n\n* Blech")
|
31
|
+
assert_xpath '//ul', output, 2
|
32
|
+
assert_xpath '(//ul)[1]/li', output, 2
|
33
|
+
assert_xpath '(//ul)[2]/li', output, 1
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context "Lists with inline markup" do
|
38
|
+
test "Quoted text" do
|
39
|
+
output = render_string("Blah\n====\n- I am *strong*.\n- I am 'stressed'.\n- I am `inflexible`.")
|
40
|
+
assert_xpath '//ul', output, 1
|
41
|
+
assert_xpath '//ul/li', output, 3
|
42
|
+
assert_xpath '(//ul/li)[1]//strong', output, 1
|
43
|
+
assert_xpath '(//ul/li)[2]//em', output, 1
|
44
|
+
assert_xpath '(//ul/li)[3]//tt', output, 1
|
45
|
+
end
|
46
|
+
|
47
|
+
test "Attribute substitutions" do
|
48
|
+
output = render_string("Blah\n====\n:foo: bar\n\n- side a {brvbar} side b\n- Take me to a {foo}.")
|
49
|
+
assert_xpath '//ul', output, 1
|
50
|
+
assert_xpath '//ul/li', output, 2
|
51
|
+
assert_xpath '(//ul/li)[1]//p[text() = "side a | side b"]', output, 1
|
52
|
+
assert_xpath '(//ul/li)[2]//p[text() = "Take me to a bar."]', output, 1
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context "Nested lists" do
|
57
|
+
test "nested mixed elements (asterisk and dash)" do
|
58
|
+
output = render_string("Blah\n====\n- Foo\n* Boo\n- Blech")
|
59
|
+
assert_xpath '//ul', output, 1
|
60
|
+
assert_xpath '//ul/li', output, 3
|
61
|
+
end
|
62
|
+
|
63
|
+
test "nested elements (2) with asterisks" do
|
64
|
+
output = render_string("* Foo\n** Boo\n* Blech")
|
65
|
+
assert_xpath '//ul', output, 2
|
66
|
+
assert_xpath '(//ul)[1]/li', output, 2
|
67
|
+
assert_xpath '(//ul)[1]/li//ul/li', output, 1
|
68
|
+
end
|
69
|
+
|
70
|
+
test "nested elements (3) with asterisks" do
|
71
|
+
output = render_string("Blah\n====\n* Foo\n** Boo\n*** Snoo\n* Blech")
|
72
|
+
assert_xpath '//ul', output, 3
|
73
|
+
assert_xpath '(//ul)[1]/li', output, 2
|
74
|
+
assert_xpath '((//ul)[1]/li//ul)[1]/li', output, 1
|
75
|
+
assert_xpath '(((//ul)[1]/li//ul)[1]/li//ul)[1]/li', output, 1
|
76
|
+
end
|
77
|
+
|
78
|
+
test "nested elements (4) with asterisks" do
|
79
|
+
output = render_string("Blah\n====\n* Foo\n** Boo\n*** Snoo\n**** Froo\n* Blech")
|
80
|
+
assert_xpath '//ul', output, 4
|
81
|
+
assert_xpath '(//ul)[1]/li', output, 2
|
82
|
+
assert_xpath '((//ul)[1]/li//ul)[1]/li', output, 1
|
83
|
+
assert_xpath '(((//ul)[1]/li//ul)[1]/li//ul)[1]/li', output, 1
|
84
|
+
assert_xpath '((((//ul)[1]/li//ul)[1]/li//ul)[1]/li//ul)[1]/li', output, 1
|
85
|
+
end
|
86
|
+
|
87
|
+
test "nested elements (5) with asterisks" do
|
88
|
+
output = render_string("Blah\n====\n* Foo\n** Boo\n*** Snoo\n**** Froo\n***** Groo\n* Blech")
|
89
|
+
assert_xpath '//ul', output, 5
|
90
|
+
assert_xpath '(//ul)[1]/li', output, 2
|
91
|
+
assert_xpath '((//ul)[1]/li//ul)[1]/li', output, 1
|
92
|
+
assert_xpath '(((//ul)[1]/li//ul)[1]/li//ul)[1]/li', output, 1
|
93
|
+
assert_xpath '((((//ul)[1]/li//ul)[1]/li//ul)[1]/li//ul)[1]/li', output, 1
|
94
|
+
assert_xpath '(((((//ul)[1]/li//ul)[1]/li//ul)[1]/li//ul)[1]/li//ul)[1]/li', output, 1
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
context "List continuations" do
|
99
|
+
test "Adjacent list continuation line attaches following paragraph" do
|
100
|
+
input = <<-EOS
|
101
|
+
Lists
|
102
|
+
=====
|
103
|
+
|
104
|
+
* Item one, paragraph one
|
105
|
+
+
|
106
|
+
Item one, paragraph two
|
107
|
+
+
|
108
|
+
* Item two
|
109
|
+
EOS
|
110
|
+
output = render_string(input)
|
111
|
+
assert_xpath '//ul', output, 1
|
112
|
+
assert_xpath '//ul/li', output, 2
|
113
|
+
assert_xpath '//ul/li[1]/p', output, 1
|
114
|
+
assert_xpath '//ul/li[1]//p', output, 2
|
115
|
+
assert_xpath '//ul/li[1]//p[text() = "Item one, paragraph one"]', output, 1
|
116
|
+
assert_xpath '//ul/li[1]//p[text() = "Item one, paragraph two"]', output, 1
|
117
|
+
end
|
118
|
+
|
119
|
+
test "Adjacent list continuation line attaches following block" do
|
120
|
+
input = <<-EOS
|
121
|
+
Lists
|
122
|
+
=====
|
123
|
+
|
124
|
+
* Item one, paragraph one
|
125
|
+
+
|
126
|
+
....
|
127
|
+
Item one, literal block
|
128
|
+
....
|
129
|
+
+
|
130
|
+
* Item two
|
131
|
+
EOS
|
132
|
+
output = render_string(input)
|
133
|
+
assert_xpath '//ul', output, 1
|
134
|
+
assert_xpath '//ul/li', output, 2
|
135
|
+
assert_xpath '//ul/li[1]/p', output, 1
|
136
|
+
assert_xpath '(//ul/li[1]/p/following-sibling::*)[1][@class = "literalblock"]', output, 1
|
137
|
+
end
|
138
|
+
|
139
|
+
test "Consecutive blocks in list continuation attach to list item" do
|
140
|
+
input = <<-EOS
|
141
|
+
Lists
|
142
|
+
=====
|
143
|
+
|
144
|
+
* Item one, paragraph one
|
145
|
+
+
|
146
|
+
....
|
147
|
+
Item one, literal block
|
148
|
+
....
|
149
|
+
+
|
150
|
+
____
|
151
|
+
Item one, quote block
|
152
|
+
____
|
153
|
+
+
|
154
|
+
* Item two
|
155
|
+
EOS
|
156
|
+
output = render_string(input)
|
157
|
+
assert_xpath '//ul', output, 1
|
158
|
+
assert_xpath '//ul/li', output, 2
|
159
|
+
assert_xpath '//ul/li[1]/p', output, 1
|
160
|
+
assert_xpath '(//ul/li[1]/p/following-sibling::*)[1][@class = "literalblock"]', output, 1
|
161
|
+
assert_xpath '(//ul/li[1]/p/following-sibling::*)[2][@class = "quoteblock"]', output, 1
|
162
|
+
end
|
163
|
+
|
164
|
+
# NOTE this differs from AsciiDoc behavior, but is more logical
|
165
|
+
test "Consecutive list continuation lines are folded" do
|
166
|
+
input = <<-EOS
|
167
|
+
Lists
|
168
|
+
=====
|
169
|
+
|
170
|
+
* Item one, paragraph one
|
171
|
+
+
|
172
|
+
+
|
173
|
+
Item one, paragraph two
|
174
|
+
+
|
175
|
+
+
|
176
|
+
* Item two
|
177
|
+
+
|
178
|
+
+
|
179
|
+
EOS
|
180
|
+
output = render_string(input)
|
181
|
+
assert_xpath '//ul', output, 1
|
182
|
+
assert_xpath '//ul/li', output, 2
|
183
|
+
assert_xpath '//ul/li[1]/p', output, 1
|
184
|
+
assert_xpath '//ul/li[1]//p', output, 2
|
185
|
+
assert_xpath '//ul/li[1]//p[text() = "Item one, paragraph one"]', output, 1
|
186
|
+
assert_xpath '//ul/li[1]//p[text() = "Item one, paragraph two"]', output, 1
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
context "Ordered lists (:olist)" do
|
192
|
+
context "Simple lists" do
|
193
|
+
test "dot elements with no blank lines" do
|
194
|
+
output = render_string("Blah\n====\n\n. Foo\n. Boo\n. Blech")
|
195
|
+
assert_xpath '//ol', output, 1
|
196
|
+
assert_xpath '//ol/li', output, 3
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
context "Labeled lists (:dlist)" do
|
202
|
+
context "Simple lists" do
|
203
|
+
test "single-line adjacent elements" do
|
204
|
+
output = render_string("term1:: def1\nterm2:: def2")
|
205
|
+
assert_xpath '//dl', output, 1
|
206
|
+
assert_xpath '//dl/dt', output, 2
|
207
|
+
assert_xpath '//dl/dt/following-sibling::dd', output, 2
|
208
|
+
assert_xpath '(//dl/dt)[1][normalize-space(text()) = "term1"]', output, 1
|
209
|
+
assert_xpath '(//dl/dt)[1]/following-sibling::dd/p[text() = "def1"]', output, 1
|
210
|
+
assert_xpath '(//dl/dt)[2][normalize-space(text()) = "term2"]', output, 1
|
211
|
+
assert_xpath '(//dl/dt)[2]/following-sibling::dd/p[text() = "def2"]', output, 1
|
212
|
+
end
|
213
|
+
|
214
|
+
test "single-line indented adjacent elements" do
|
215
|
+
output = render_string("term1:: def1\n term2:: def2")
|
216
|
+
assert_xpath '//dl', output, 1
|
217
|
+
assert_xpath '//dl/dt', output, 2
|
218
|
+
assert_xpath '//dl/dt/following-sibling::dd', output, 2
|
219
|
+
assert_xpath '(//dl/dt)[1][normalize-space(text()) = "term1"]', output, 1
|
220
|
+
assert_xpath '(//dl/dt)[1]/following-sibling::dd/p[text() = "def1"]', output, 1
|
221
|
+
assert_xpath '(//dl/dt)[2][normalize-space(text()) = "term2"]', output, 1
|
222
|
+
assert_xpath '(//dl/dt)[2]/following-sibling::dd/p[text() = "def2"]', output, 1
|
223
|
+
end
|
224
|
+
|
225
|
+
test "single-line elements separated by blank line" do
|
226
|
+
output = render_string("term1:: def1\n\nterm2:: def2")
|
227
|
+
assert_xpath '//dl', output, 1
|
228
|
+
assert_xpath '//dl/dt', output, 2
|
229
|
+
assert_xpath '//dl/dt/following-sibling::dd', output, 2
|
230
|
+
end
|
231
|
+
|
232
|
+
test "multi-line elements with paragraph content" do
|
233
|
+
output = render_string("term1::\ndef1\nterm2::\ndef2")
|
234
|
+
assert_xpath '//dl', output, 1
|
235
|
+
assert_xpath '//dl/dt', output, 2
|
236
|
+
assert_xpath '//dl/dt/following-sibling::dd', output, 2
|
237
|
+
assert_xpath '(//dl/dt)[1][normalize-space(text()) = "term1"]', output, 1
|
238
|
+
assert_xpath '(//dl/dt)[1]/following-sibling::dd/p[text() = "def1"]', output, 1
|
239
|
+
assert_xpath '(//dl/dt)[2][normalize-space(text()) = "term2"]', output, 1
|
240
|
+
assert_xpath '(//dl/dt)[2]/following-sibling::dd/p[text() = "def2"]', output, 1
|
241
|
+
end
|
242
|
+
|
243
|
+
test "multi-line elements with indented paragraph content" do
|
244
|
+
output = render_string("term1::\n def1\nterm2::\n def2")
|
245
|
+
assert_xpath '//dl', output, 1
|
246
|
+
assert_xpath '//dl/dt', output, 2
|
247
|
+
assert_xpath '//dl/dt/following-sibling::dd', output, 2
|
248
|
+
assert_xpath '(//dl/dt)[1][normalize-space(text()) = "term1"]', output, 1
|
249
|
+
assert_xpath '(//dl/dt)[1]/following-sibling::dd/p[text() = "def1"]', output, 1
|
250
|
+
assert_xpath '(//dl/dt)[2][normalize-space(text()) = "term2"]', output, 1
|
251
|
+
assert_xpath '(//dl/dt)[2]/following-sibling::dd/p[text() = "def2"]', output, 1
|
252
|
+
end
|
253
|
+
|
254
|
+
test "multi-line elements with blank line before paragraph content" do
|
255
|
+
output = render_string("term1::\n\ndef1\nterm2::\n\ndef2")
|
256
|
+
assert_xpath '//dl', output, 1
|
257
|
+
assert_xpath '//dl/dt', output, 2
|
258
|
+
assert_xpath '//dl/dt/following-sibling::dd', output, 2
|
259
|
+
assert_xpath '(//dl/dt)[1][normalize-space(text()) = "term1"]', output, 1
|
260
|
+
assert_xpath '(//dl/dt)[1]/following-sibling::dd/p[text() = "def1"]', output, 1
|
261
|
+
assert_xpath '(//dl/dt)[2][normalize-space(text()) = "term2"]', output, 1
|
262
|
+
assert_xpath '(//dl/dt)[2]/following-sibling::dd/p[text() = "def2"]', output, 1
|
263
|
+
end
|
264
|
+
|
265
|
+
test "multi-line elements with paragraph and literal content" do
|
266
|
+
output = render_string("term1::\n def1\n\n literal\nterm2::\n def2")
|
267
|
+
assert_xpath '//dl', output, 1
|
268
|
+
assert_xpath '//dl/dt', output, 2
|
269
|
+
assert_xpath '//dl/dt/following-sibling::dd', output, 2
|
270
|
+
assert_xpath '//dl/dt/following-sibling::dd//pre', output, 1
|
271
|
+
assert_xpath '(//dl/dt)[1][normalize-space(text()) = "term1"]', output, 1
|
272
|
+
assert_xpath '(//dl/dt)[1]/following-sibling::dd/p[text() = "def1"]', output, 1
|
273
|
+
assert_xpath '(//dl/dt)[2][normalize-space(text()) = "term2"]', output, 1
|
274
|
+
assert_xpath '(//dl/dt)[2]/following-sibling::dd/p[text() = "def2"]', output, 1
|
275
|
+
end
|
276
|
+
|
277
|
+
test "mixed single and multi-line adjacent elements" do
|
278
|
+
output = render_string("term1:: def1\nterm2::\ndef2")
|
279
|
+
assert_xpath '//dl', output, 1
|
280
|
+
assert_xpath '//dl/dt', output, 2
|
281
|
+
assert_xpath '//dl/dt/following-sibling::dd', output, 2
|
282
|
+
assert_xpath '(//dl/dt)[1][normalize-space(text()) = "term1"]', output, 1
|
283
|
+
assert_xpath '(//dl/dt)[1]/following-sibling::dd/p[text() = "def1"]', output, 1
|
284
|
+
assert_xpath '(//dl/dt)[2][normalize-space(text()) = "term2"]', output, 1
|
285
|
+
assert_xpath '(//dl/dt)[2]/following-sibling::dd/p[text() = "def2"]', output, 1
|
286
|
+
end
|
287
|
+
|
288
|
+
test "element with anchor" do
|
289
|
+
output = render_string("[[term1]]term1:: def1\n[[term2]]term2:: def2")
|
290
|
+
assert_xpath '//dl', output, 1
|
291
|
+
assert_xpath '//dl/dt', output, 2
|
292
|
+
assert_xpath '(//dl/dt)[1]/a[@id = "term1"]', output, 1
|
293
|
+
assert_xpath '(//dl/dt)[2]/a[@id = "term2"]', output, 1
|
294
|
+
end
|
295
|
+
|
296
|
+
test "missing space before term does not produce labeled list" do
|
297
|
+
output = render_string("term1::def1\nterm2::def2")
|
298
|
+
assert_xpath '//dl', output, 0
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
context "Nested lists" do
|
303
|
+
test "single-line adjacent nested elements" do
|
304
|
+
output = render_string("term1:: def1\nlabel1::: detail1\nterm2:: def2")
|
305
|
+
assert_xpath '//dl', output, 2
|
306
|
+
assert_xpath '//dl//dl', output, 1
|
307
|
+
assert_xpath '(//dl)[1]/dt[1][normalize-space(text()) = "term1"]', output, 1
|
308
|
+
assert_xpath '(//dl)[1]/dt[1]/following-sibling::dd/p[text() = "def1"]', output, 1
|
309
|
+
assert_xpath '//dl//dl/dt[normalize-space(text()) = "label1"]', output, 1
|
310
|
+
assert_xpath '//dl//dl/dt/following-sibling::dd/p[text() = "detail1"]', output, 1
|
311
|
+
assert_xpath '(//dl)[1]/dt[2][normalize-space(text()) = "term2"]', output, 1
|
312
|
+
assert_xpath '(//dl)[1]/dt[2]/following-sibling::dd/p[text() = "def2"]', output, 1
|
313
|
+
end
|
314
|
+
|
315
|
+
test "single-line adjacent maximum nested elements" do
|
316
|
+
output = render_string("term1:: def1\nlabel1::: detail1\nname1:::: value1\nitem1;; price1\nterm2:: def2")
|
317
|
+
assert_xpath '//dl', output, 4
|
318
|
+
assert_xpath '//dl//dl//dl//dl', output, 1
|
319
|
+
end
|
320
|
+
|
321
|
+
test "single-line nested elements seperated by blank line at top level" do
|
322
|
+
output = render_string("term1:: def1\n\nlabel1::: detail1\n\nterm2:: def2")
|
323
|
+
assert_xpath '//dl', output, 2
|
324
|
+
assert_xpath '//dl//dl', output, 1
|
325
|
+
assert_xpath '(//dl)[1]/dt[1][normalize-space(text()) = "term1"]', output, 1
|
326
|
+
assert_xpath '(//dl)[1]/dt[1]/following-sibling::dd/p[text() = "def1"]', output, 1
|
327
|
+
assert_xpath '//dl//dl/dt[normalize-space(text()) = "label1"]', output, 1
|
328
|
+
assert_xpath '//dl//dl/dt/following-sibling::dd/p[text() = "detail1"]', output, 1
|
329
|
+
assert_xpath '(//dl)[1]/dt[2][normalize-space(text()) = "term2"]', output, 1
|
330
|
+
assert_xpath '(//dl)[1]/dt[2]/following-sibling::dd/p[text() = "def2"]', output, 1
|
331
|
+
end
|
332
|
+
|
333
|
+
# FIXME test pending, haven't fixed lexer to allow blank line at nested level
|
334
|
+
#test "single-line nested elements seperated by blank line at nested level" do
|
335
|
+
# output = render_string("term1:: def1\nlabel1::: detail1\n\nlabel2::: detail2\nterm2:: def2")
|
336
|
+
# assert_xpath '//dl', output, 2
|
337
|
+
# assert_xpath '//dl//dl', output, 1
|
338
|
+
# assert_xpath '(//dl)[1]/dt[1][normalize-space(text()) = "term1"]', output, 1
|
339
|
+
# assert_xpath '(//dl)[1]/dt[1]/following-sibling::dd/p[text() = "def1"]', output, 1
|
340
|
+
# assert_xpath '//dl//dl/dt[normalize-space(text()) = "label1"]', output, 1
|
341
|
+
# assert_xpath '//dl//dl/dt/following-sibling::dd/p[text() = "detail1"]', output, 1
|
342
|
+
# assert_xpath '(//dl)[1]/dt[2][normalize-space(text()) = "term2"]', output, 1
|
343
|
+
# assert_xpath '(//dl)[1]/dt[2]/following-sibling::dd/p[text() = "def2"]', output, 1
|
344
|
+
#end
|
345
|
+
|
346
|
+
test "single-line adjacent nested elements with alternate delimiters" do
|
347
|
+
output = render_string("term1:: def1\nlabel1;; detail1\nterm2:: def2")
|
348
|
+
assert_xpath '//dl', output, 2
|
349
|
+
assert_xpath '//dl//dl', output, 1
|
350
|
+
assert_xpath '(//dl)[1]/dt[1][normalize-space(text()) = "term1"]', output, 1
|
351
|
+
assert_xpath '(//dl)[1]/dt[1]/following-sibling::dd/p[text() = "def1"]', output, 1
|
352
|
+
assert_xpath '//dl//dl/dt[normalize-space(text()) = "label1"]', output, 1
|
353
|
+
assert_xpath '//dl//dl/dt/following-sibling::dd/p[text() = "detail1"]', output, 1
|
354
|
+
assert_xpath '(//dl)[1]/dt[2][normalize-space(text()) = "term2"]', output, 1
|
355
|
+
assert_xpath '(//dl)[1]/dt[2]/following-sibling::dd/p[text() = "def2"]', output, 1
|
356
|
+
end
|
357
|
+
|
358
|
+
test "multi-line adjacent nested elements" do
|
359
|
+
output = render_string("term1::\ndef1\nlabel1:::\ndetail1\nterm2::\ndef2")
|
360
|
+
assert_xpath '//dl', output, 2
|
361
|
+
assert_xpath '//dl//dl', output, 1
|
362
|
+
assert_xpath '(//dl)[1]/dt[1][normalize-space(text()) = "term1"]', output, 1
|
363
|
+
assert_xpath '(//dl)[1]/dt[1]/following-sibling::dd/p[text() = "def1"]', output, 1
|
364
|
+
assert_xpath '//dl//dl/dt[normalize-space(text()) = "label1"]', output, 1
|
365
|
+
assert_xpath '//dl//dl/dt/following-sibling::dd/p[text() = "detail1"]', output, 1
|
366
|
+
assert_xpath '(//dl)[1]/dt[2][normalize-space(text()) = "term2"]', output, 1
|
367
|
+
assert_xpath '(//dl)[1]/dt[2]/following-sibling::dd/p[text() = "def2"]', output, 1
|
368
|
+
end
|
369
|
+
|
370
|
+
# FIXME test pending, haven't fixed lexer to allow blank line at nested level
|
371
|
+
#test "multi-line nested elements seperated by blank line at nested level" do
|
372
|
+
# output = render_string("term1::\ndef1\nlabel1:::\n\ndetail1\nlabel2:::\ndetail2\n\nterm2:: def2")
|
373
|
+
# assert_xpath '//dl', output, 2
|
374
|
+
# assert_xpath '//dl//dl', output, 1
|
375
|
+
# assert_xpath '(//dl)[1]/dt[1][normalize-space(text()) = "term1"]', output, 1
|
376
|
+
# assert_xpath '(//dl)[1]/dt[1]/following-sibling::dd/p[text() = "def1"]', output, 1
|
377
|
+
# assert_xpath '(//dl//dl/dt)[1][normalize-space(text()) = "label1"]', output, 1
|
378
|
+
# assert_xpath '(//dl//dl/dt)[1]/following-sibling::dd/p[text() = "detail1"]', output, 1
|
379
|
+
# assert_xpath '(//dl//dl/dt)[2][normalize-space(text()) = "label2"]', output, 1
|
380
|
+
# assert_xpath '(//dl//dl/dt)[2]/following-sibling::dd/p[text() = "detail2"]', output, 1
|
381
|
+
#end
|
382
|
+
|
383
|
+
test "mixed single and multi-line elements with indented nested elements" do
|
384
|
+
output = render_string("term1:: def1\n label1:::\n detail1\nterm2:: def2")
|
385
|
+
assert_xpath '//dl', output, 2
|
386
|
+
assert_xpath '//dl//dl', output, 1
|
387
|
+
assert_xpath '(//dl)[1]/dt[1][normalize-space(text()) = "term1"]', output, 1
|
388
|
+
assert_xpath '(//dl)[1]/dt[1]/following-sibling::dd/p[text() = "def1"]', output, 1
|
389
|
+
assert_xpath '//dl//dl/dt[normalize-space(text()) = "label1"]', output, 1
|
390
|
+
assert_xpath '//dl//dl/dt/following-sibling::dd/p[text() = "detail1"]', output, 1
|
391
|
+
assert_xpath '(//dl)[1]/dt[2][normalize-space(text()) = "term2"]', output, 1
|
392
|
+
assert_xpath '(//dl)[1]/dt[2]/following-sibling::dd/p[text() = "def2"]', output, 1
|
393
|
+
end
|
394
|
+
|
395
|
+
test "multi-line elements with first paragraph folded to text with adjacent nested element" do
|
396
|
+
output = render_string("term1:: def1\ncontinued\nlabel1:::\ndetail1")
|
397
|
+
assert_xpath '//dl', output, 2
|
398
|
+
assert_xpath '//dl//dl', output, 1
|
399
|
+
assert_xpath '(//dl)[1]/dt[1][normalize-space(text()) = "term1"]', output, 1
|
400
|
+
assert_xpath '(//dl)[1]/dt[1]/following-sibling::dd/p[starts-with(text(), "def1")]', output, 1
|
401
|
+
assert_xpath '(//dl)[1]/dt[1]/following-sibling::dd/p[contains(text(), "continued")]', output, 1
|
402
|
+
assert_xpath '//dl//dl/dt[normalize-space(text()) = "label1"]', output, 1
|
403
|
+
assert_xpath '//dl//dl/dt/following-sibling::dd/p[text() = "detail1"]', output, 1
|
404
|
+
end
|
405
|
+
end
|
406
|
+
end
|