asciidoctor 0.0.7 → 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/Gemfile +2 -0
  2. data/README.asciidoc +35 -26
  3. data/Rakefile +9 -6
  4. data/asciidoctor.gemspec +27 -8
  5. data/bin/asciidoctor +1 -1
  6. data/lib/asciidoctor.rb +351 -63
  7. data/lib/asciidoctor/abstract_block.rb +218 -0
  8. data/lib/asciidoctor/abstract_node.rb +249 -0
  9. data/lib/asciidoctor/attribute_list.rb +211 -0
  10. data/lib/asciidoctor/backends/base_template.rb +99 -0
  11. data/lib/asciidoctor/backends/docbook45.rb +510 -0
  12. data/lib/asciidoctor/backends/html5.rb +585 -0
  13. data/lib/asciidoctor/block.rb +27 -254
  14. data/lib/asciidoctor/callouts.rb +117 -0
  15. data/lib/asciidoctor/debug.rb +7 -4
  16. data/lib/asciidoctor/document.rb +229 -77
  17. data/lib/asciidoctor/inline.rb +29 -0
  18. data/lib/asciidoctor/lexer.rb +1330 -502
  19. data/lib/asciidoctor/list_item.rb +33 -34
  20. data/lib/asciidoctor/reader.rb +305 -142
  21. data/lib/asciidoctor/renderer.rb +115 -19
  22. data/lib/asciidoctor/section.rb +100 -189
  23. data/lib/asciidoctor/substituters.rb +468 -0
  24. data/lib/asciidoctor/table.rb +499 -0
  25. data/lib/asciidoctor/version.rb +1 -1
  26. data/test/attributes_test.rb +301 -87
  27. data/test/blocks_test.rb +568 -0
  28. data/test/document_test.rb +221 -24
  29. data/test/fixtures/dot.gif +0 -0
  30. data/test/fixtures/encoding.asciidoc +1 -0
  31. data/test/fixtures/include-file.asciidoc +1 -0
  32. data/test/fixtures/tip.gif +0 -0
  33. data/test/headers_test.rb +411 -43
  34. data/test/lexer_test.rb +265 -45
  35. data/test/links_test.rb +144 -3
  36. data/test/lists_test.rb +2252 -74
  37. data/test/paragraphs_test.rb +21 -30
  38. data/test/preamble_test.rb +24 -0
  39. data/test/reader_test.rb +248 -12
  40. data/test/renderer_test.rb +22 -0
  41. data/test/substitutions_test.rb +414 -0
  42. data/test/tables_test.rb +484 -0
  43. data/test/test_helper.rb +70 -6
  44. data/test/text_test.rb +30 -6
  45. metadata +64 -10
  46. data/lib/asciidoctor/render_templates.rb +0 -317
  47. data/lib/asciidoctor/string.rb +0 -12
@@ -1,36 +1,233 @@
1
1
  require 'test_helper'
2
2
 
3
- class DocumentTest < Test::Unit::TestCase
4
- # setup for test
5
- def setup
6
- @doc = example_document(:asciidoc_index)
3
+ context 'Document' do
4
+
5
+ context 'Example document' do
6
+ test 'test_title' do
7
+ doc = example_document(:asciidoc_index)
8
+ assert_equal 'AsciiDoc Home Page', doc.doctitle
9
+ assert_equal 'AsciiDoc Home Page', doc.name
10
+ assert_equal 14, doc.blocks.size
11
+ assert_equal :preamble, doc.blocks[0].context
12
+ assert doc.blocks[1].is_a? ::Asciidoctor::Section
13
+ end
7
14
  end
8
15
 
9
- def test_title
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
16
+ context 'Default settings' do
17
+ test 'safe mode level set to SECURE by default' do
18
+ doc = Asciidoctor::Document.new
19
+ assert_equal Asciidoctor::SafeMode::SECURE, doc.safe
20
+ end
21
+
22
+ test 'safe mode level can be set in the constructor' do
23
+ doc = Asciidoctor::Document.new [], :safe => Asciidoctor::SafeMode::SAFE
24
+ assert_equal Asciidoctor::SafeMode::SAFE, doc.safe
25
+ end
26
+
27
+ test 'safe model level cannot be modified' do
28
+ doc = Asciidoctor::Document.new
29
+ begin
30
+ doc.safe = Asciidoctor::SafeMode::UNSAFE
31
+ flunk 'safe mode property of Asciidoctor::Document should not be writable!'
32
+ rescue
33
+ end
34
+ end
14
35
  end
15
36
 
16
- def test_with_no_title
17
- d = Asciidoctor::Document.new(["Snorf"])
18
- assert_nil d.doctitle
37
+ context 'Renderer' do
38
+ test 'built-in HTML5 views are registered by default' do
39
+ doc = document_from_string ''
40
+ assert_equal 'html5', doc.attributes['backend']
41
+ assert doc.attributes.has_key? 'backend-html5'
42
+ assert_equal 'html', doc.attributes['basebackend']
43
+ assert doc.attributes.has_key? 'basebackend-html'
44
+ renderer = doc.renderer
45
+ assert !renderer.nil?
46
+ views = renderer.views
47
+ assert !views.nil?
48
+ assert_equal 26, views.size
49
+ assert views.has_key? 'document'
50
+ assert views['document'].is_a?(Asciidoctor::HTML5::DocumentTemplate)
51
+ assert_equal 'ERB', views['document'].eruby.to_s
52
+ end
53
+
54
+ test 'built-in DocBook45 views are registered when backend is docbook45' do
55
+ doc = document_from_string '', :attributes => {'backend' => 'docbook45'}
56
+ renderer = doc.renderer
57
+ assert_equal 'docbook45', doc.attributes['backend']
58
+ assert doc.attributes.has_key? 'backend-docbook45'
59
+ assert_equal 'docbook', doc.attributes['basebackend']
60
+ assert doc.attributes.has_key? 'basebackend-docbook'
61
+ assert !renderer.nil?
62
+ views = renderer.views
63
+ assert !views.nil?
64
+ assert_equal 26, views.size
65
+ assert views.has_key? 'document'
66
+ assert views['document'].is_a?(Asciidoctor::DocBook45::DocumentTemplate)
67
+ assert_equal 'ERB', views['document'].eruby.to_s
68
+ end
69
+
70
+ test 'can set erubis as eRuby implementation' do
71
+ doc = Asciidoctor::Document.new [], :eruby => 'erubis'
72
+ assert $LOADED_FEATURES.detect {|p| p == 'erubis.rb' || p.end_with?('/erubis.rb') }.nil?
73
+ renderer = doc.renderer
74
+ assert $LOADED_FEATURES.detect {|p| p == 'erubis.rb' || p.end_with?('/erubis.rb') }
75
+ views = renderer.views
76
+ assert !views.nil?
77
+ assert views.has_key? 'document'
78
+ assert_equal 'Erubis::FastEruby', views['document'].eruby.to_s
79
+ assert_equal 'Erubis::FastEruby', views['document'].template.class.to_s
80
+ end
19
81
  end
20
82
 
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
83
+ context 'Structure' do
84
+ test 'test_with_no_title' do
85
+ doc = document_from_string('Snorf')
86
+ assert_nil doc.doctitle
87
+ assert_nil doc.name
88
+ assert !doc.has_header?
89
+ assert_nil doc.header
90
+ end
91
+
92
+ test 'test_with_explicit_title' do
93
+ input = <<-EOS
94
+ = Title
95
+ :title: Document Title
96
+
97
+ preamble
98
+
99
+ == First Section
100
+ EOS
101
+ doc = document_from_string input
102
+ assert_equal 'Document Title', doc.doctitle
103
+ assert_equal 'Document Title', doc.title
104
+ assert doc.has_header?
105
+ assert_equal 'Title', doc.header.title
106
+ assert_equal 'Title', doc.first_section.title
107
+ end
108
+
109
+ test 'test_empty_document' do
110
+ doc = document_from_string('')
111
+ assert doc.blocks.empty?
112
+ assert_nil doc.doctitle
113
+ assert !doc.has_header?
114
+ assert_nil doc.header
115
+ end
116
+
117
+ test 'test_with_metadata' do
118
+ input = <<-EOS
119
+ = AsciiDoc
120
+ Stuart Rackham <founder@asciidoc.org>
121
+ v8.6.8, 2012-07-12: See changelog.
122
+
123
+ == Version 8.6.8
124
+
125
+ more info...
126
+ EOS
127
+ output = render_string input
128
+ assert_xpath '//*[@id="header"]/span[@id="author"][text() = "Stuart Rackham"]', output, 1
129
+ assert_xpath '//*[@id="header"]/span[@id="email"][contains(text(), "founder@asciidoc.org")]', output, 1
130
+ assert_xpath '//*[@id="header"]/span[@id="revnumber"][text() = "version 8.6.8,"]', output, 1
131
+ assert_xpath '//*[@id="header"]/span[@id="revdate"][text() = "2012-07-12"]', output, 1
132
+ assert_xpath '//*[@id="header"]/span[@id="revremark"][text() = "See changelog."]', output, 1
133
+ end
134
+
135
+ test 'test_with_header_footer' do
136
+ result = render_string("= Title\n\npreamble")
137
+ assert_xpath '/html', result, 1
138
+ assert_xpath '//*[@id="header"]', result, 1
139
+ assert_xpath '//*[@id="footer"]', result, 1
140
+ assert_xpath '//*[@id="preamble"]', result, 1
141
+ end
142
+
143
+ test 'test_with_no_header_footer' do
144
+ result = render_string("= Title\n\npreamble", :header_footer => false)
145
+ assert_xpath '/html', result, 0
146
+ assert_xpath '/*[@id="header"]', result, 0
147
+ assert_xpath '/*[@id="footer"]', result, 0
148
+ assert_xpath '/*[@id="preamble"]', result, 1
149
+ end
27
150
  end
28
151
 
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
152
+ context 'Backends and Doctypes' do
153
+ test 'test_html5_backend_doctype_article' do
154
+ result = render_string("= Title\n\npreamble", :attributes => {'backend' => 'html5'})
155
+ assert_xpath '/html', result, 1
156
+ assert_xpath '/html/body[@class="article"]', result, 1
157
+ assert_xpath '/html//*[@id="header"]/h1[text() = "Title"]', result, 1
158
+ assert_xpath '/html//*[@id="preamble"]//p[text() = "preamble"]', result, 1
159
+ end
160
+
161
+ test 'test_html5_backend_doctype_book' do
162
+ result = render_string("= Title\n\npreamble", :attributes => {'backend' => 'html5', 'doctype' => 'book'})
163
+ assert_xpath '/html', result, 1
164
+ assert_xpath '/html/body[@class="book"]', result, 1
165
+ assert_xpath '/html//*[@id="header"]/h1[text() = "Title"]', result, 1
166
+ assert_xpath '/html//*[@id="preamble"]//p[text() = "preamble"]', result, 1
167
+ end
168
+
169
+ test 'test_docbook45_backend_doctype_article' do
170
+ input = <<-EOS
171
+ = Title
172
+
173
+ preamble
174
+
175
+ == First Section
176
+
177
+ section body
178
+ EOS
179
+ result = render_string(input, :attributes => {'backend' => 'docbook45'})
180
+ assert_xpath '/article', result, 1
181
+ assert_xpath '/article/articleinfo/title[text() = "Title"]', result, 1
182
+ assert_xpath '/article/simpara[text() = "preamble"]', result, 1
183
+ assert_xpath '/article/section', result, 1
184
+ assert_xpath '/article/section[@id = "_first_section"]/title[text() = "First Section"]', result, 1
185
+ assert_xpath '/article/section[@id = "_first_section"]/simpara[text() = "section body"]', result, 1
186
+ end
187
+
188
+ test 'test_docbook45_backend_doctype_article_no_title' do
189
+ result = render_string('text', :attributes => {'backend' => 'docbook45'})
190
+ assert_xpath '/article', result, 1
191
+ assert_xpath '/article/articleinfo/date', result, 1
192
+ assert_xpath '/article/simpara[text() = "text"]', result, 1
193
+ end
194
+
195
+ test 'test_docbook45_backend_doctype_book' do
196
+ input = <<-EOS
197
+ = Title
198
+
199
+ preamble
200
+
201
+ == First Chapter
202
+
203
+ chapter body
204
+ EOS
205
+ result = render_string(input, :attributes => {'backend' => 'docbook45', 'doctype' => 'book'})
206
+ assert_xpath '/book', result, 1
207
+ assert_xpath '/book/bookinfo/title[text() = "Title"]', result, 1
208
+ assert_xpath '/book/preface/simpara[text() = "preamble"]', result, 1
209
+ assert_xpath '/book/chapter', result, 1
210
+ assert_xpath '/book/chapter[@id = "_first_chapter"]/title[text() = "First Chapter"]', result, 1
211
+ assert_xpath '/book/chapter[@id = "_first_chapter"]/simpara[text() = "chapter body"]', result, 1
212
+ end
213
+
214
+ test 'test_docbook45_backend_doctype_book_no_title' do
215
+ result = render_string('text', :attributes => {'backend' => 'docbook45', 'doctype' => 'book'})
216
+ assert_xpath '/book', result, 1
217
+ assert_xpath '/book/bookinfo/date', result, 1
218
+ assert_xpath '/book/simpara[text() = "text"]', result, 1
219
+ end
220
+
221
+ test 'do not override explicit author initials' do
222
+ input = <<-EOS
223
+ = AsciiDoc
224
+ Stuart Rackham <founder@asciidoc.org>
225
+ :Author Initials: SJR
226
+
227
+ more info...
228
+ EOS
229
+ output = render_string input, :attributes => {'backend' => 'docbook45'}
230
+ assert_xpath '/article/articleinfo/authorinitials[text()="SJR"]', output, 1
231
+ end
35
232
  end
36
233
  end
Binary file
@@ -0,0 +1 @@
1
+ Gregory Romé has written an AsciiDoc plugin for the Redmine project management application.
@@ -0,0 +1 @@
1
+ included content
Binary file
@@ -1,47 +1,119 @@
1
+ # encoding: UTF-8
1
2
  require 'test_helper'
2
3
 
3
- context "Headers" do
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
4
+ context 'Sections' do
5
+ context 'Ids' do
6
+ test 'synthetic id is generated by default' do
7
+ sec = block_from_string('== Section One')
8
+ assert_equal '_section_one', sec.id
9
+ end
10
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
11
+ test 'synthetic id replaces non-word characters with underscores' do
12
+ sec = block_from_string("== We're back!")
13
+ assert_equal '_we_re_back', sec.id
14
+ end
17
15
 
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
16
+ test 'synthetic id removes repeating underscores' do
17
+ sec = block_from_string('== Section $ One')
18
+ assert_equal '_section_one', sec.id
19
+ end
24
20
 
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
21
+ test 'synthetic id prefix can be customized' do
22
+ sec = block_from_string(":idprefix: id_\n\n== Section One")
23
+ assert_equal 'id_section_one', sec.id
24
+ end
31
25
 
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
26
+ test 'synthetic id prefix can be set to blank' do
27
+ sec = block_from_string(":idprefix:\n\n== Section One")
28
+ assert_equal 'section_one', sec.id
29
+ end
30
+
31
+ test 'synthetic ids can be disabled' do
32
+ sec = block_from_string(":sectids!:\n\n== Section One\n")
33
+ assert sec.id.nil?
34
+ end
35
+
36
+ test 'explicit id in anchor above section title overrides synthetic id' do
37
+ sec = block_from_string("[[one]]\n== Section One")
38
+ assert_equal 'one', sec.id
39
+ end
40
+
41
+ test 'explicit id can be defined using an inline anchor' do
42
+ sec = block_from_string("== Section One [[one]] ==")
43
+ assert_equal 'one', sec.id
44
+ assert_equal 'Section One', sec.title
45
+ end
38
46
 
39
- test "document title with single-line syntax" do
40
- assert_xpath "//h1[not(@id)][text() = 'My Title']", render_string("= My Title")
47
+ test 'title substitutions are applied before generating id' do
48
+ sec = block_from_string("== Section{sp}One\n")
49
+ assert_equal '_section_one', sec.id
50
+ end
51
+
52
+ test 'synthetic ids are unique' do
53
+ input = <<-EOS
54
+ == Some section
55
+
56
+ text
57
+
58
+ == Some section
59
+
60
+ text
61
+ EOS
62
+ doc = document_from_string input
63
+ assert_equal '_some_section', doc.blocks[0].id
64
+ assert_equal '_some_section_2', doc.blocks[1].id
65
+ end
41
66
  end
42
67
 
43
- test "document title with symmetric syntax" do
44
- assert_xpath "//h1[not(@id)][text() = 'My Title']", render_string("= My Title =")
68
+ context "document title (level 0)" do
69
+ test "document title with multiline syntax" do
70
+ title = "My Title"
71
+ chars = "=" * title.length
72
+ assert_xpath "//h1[not(@id)][text() = 'My Title']", render_string(title + "\n" + chars)
73
+ assert_xpath "//h1[not(@id)][text() = 'My Title']", render_string(title + "\n" + chars + "\n")
74
+ end
75
+
76
+ test "document title with multiline syntax, give a char" do
77
+ title = "My Title"
78
+ chars = "=" * (title.length + 1)
79
+ assert_xpath "//h1[not(@id)][text() = 'My Title']", render_string(title + "\n" + chars)
80
+ assert_xpath "//h1[not(@id)][text() = 'My Title']", render_string(title + "\n" + chars + "\n")
81
+ end
82
+
83
+ test "document title with multiline syntax, take a char" do
84
+ title = "My Title"
85
+ chars = "=" * (title.length - 1)
86
+ assert_xpath "//h1[not(@id)][text() = 'My Title']", render_string(title + "\n" + chars)
87
+ assert_xpath "//h1[not(@id)][text() = 'My Title']", render_string(title + "\n" + chars + "\n")
88
+ end
89
+
90
+ test "not enough chars for a multiline document title" do
91
+ title = "My Title"
92
+ chars = "=" * (title.length - 2)
93
+ assert_xpath '//h1', render_string(title + "\n" + chars), 0
94
+ assert_xpath '//h1', render_string(title + "\n" + chars + "\n"), 0
95
+ end
96
+
97
+ test "too many chars for a multiline document title" do
98
+ title = "My Title"
99
+ chars = "=" * (title.length + 2)
100
+ assert_xpath '//h1', render_string(title + "\n" + chars), 0
101
+ assert_xpath '//h1', render_string(title + "\n" + chars + "\n"), 0
102
+ end
103
+
104
+ test "document title with multiline syntax cannot begin with a dot" do
105
+ title = ".My Title"
106
+ chars = "=" * title.length
107
+ assert_xpath '//h1', render_string(title + "\n" + chars), 0
108
+ end
109
+
110
+ test "document title with single-line syntax" do
111
+ assert_xpath "//h1[not(@id)][text() = 'My Title']", render_string("= My Title")
112
+ end
113
+
114
+ test "document title with symmetric syntax" do
115
+ assert_xpath "//h1[not(@id)][text() = 'My Title']", render_string("= My Title =")
116
+ end
45
117
  end
46
118
 
47
119
  context "level 1" do
@@ -49,6 +121,12 @@ context "Headers" do
49
121
  assert_xpath "//h2[@id='_my_section'][text() = 'My Section']", render_string("My Section\n-----------")
50
122
  end
51
123
 
124
+ test "heading title with multiline syntax cannot begin with a dot" do
125
+ title = ".My Title"
126
+ chars = "-" * title.length
127
+ assert_xpath '//h2', render_string(title + "\n" + chars), 0
128
+ end
129
+
52
130
  test "with single-line syntax" do
53
131
  assert_xpath "//h2[@id='_my_title'][text() = 'My Title']", render_string("== My Title")
54
132
  end
@@ -62,7 +140,7 @@ context "Headers" do
62
140
  end
63
141
 
64
142
  test "with non-word character" do
65
- assert_xpath "//h2[@id='_where_s_the_love'][text() = \"Where's the love?\"]", render_string("== Where's the love?")
143
+ assert_xpath "//h2[@id='_where_s_the_love'][text() = \"Where#{[8217].pack('U*')}s the love?\"]", render_string("== Where's the love?")
66
144
  end
67
145
 
68
146
  test "with sequential non-word characters" do
@@ -80,35 +158,325 @@ context "Headers" do
80
158
  test "with custom non-blank idprefix" do
81
159
  assert_xpath "//h2[@id='ref_my_title'][text() = 'My Title']", render_string(":idprefix: ref_\n\n== My Title ")
82
160
  end
161
+
162
+ test 'with multibyte characters' do
163
+ input = <<-EOS
164
+ == Asciidoctor in 中文
165
+ EOS
166
+ output = render_string input
167
+ assert_xpath '//h2[@id="_asciidoctor_in"][text()="Asciidoctor in 中文"]', output
168
+ end
83
169
  end
84
170
 
85
171
  context "level 2" do
86
172
  test "with multiline syntax" do
87
- assert_xpath "//h3[@id='_my_section'][text() = 'My Section']", render_string("My Section\n~~~~~~~~~~~")
173
+ assert_xpath "//h3[@id='_my_section'][text() = 'My Section']", render_string(":fragment:\nMy Section\n~~~~~~~~~~~")
88
174
  end
89
175
 
90
176
  test "with single line syntax" do
91
- assert_xpath "//h3[@id='_my_title'][text() = 'My Title']", render_string("=== My Title")
177
+ assert_xpath "//h3[@id='_my_title'][text() = 'My Title']", render_string(":fragment:\n=== My Title")
92
178
  end
93
179
  end
94
180
 
95
181
  context "level 3" do
96
182
  test "with multiline syntax" do
97
- assert_xpath "//h4[@id='_my_section'][text() = 'My Section']", render_string("My Section\n^^^^^^^^^^")
183
+ assert_xpath "//h4[@id='_my_section'][text() = 'My Section']", render_string(":fragment:\nMy Section\n^^^^^^^^^^")
98
184
  end
99
185
 
100
186
  test "with single line syntax" do
101
- assert_xpath "//h4[@id='_my_title'][text() = 'My Title']", render_string("==== My Title")
187
+ assert_xpath "//h4[@id='_my_title'][text() = 'My Title']", render_string(":fragment:\n==== My Title")
102
188
  end
103
189
  end
104
190
 
105
191
  context "level 4" do
106
192
  test "with multiline syntax" do
107
- assert_xpath "//h5[@id='_my_section'][text() = 'My Section']", render_string("My Section\n++++++++++")
193
+ assert_xpath "//h5[@id='_my_section'][text() = 'My Section']", render_string(":fragment:\nMy Section\n++++++++++")
108
194
  end
109
195
 
110
196
  test "with single line syntax" do
111
- assert_xpath "//h5[@id='_my_title'][text() = 'My Title']", render_string("===== My Title")
197
+ assert_xpath "//h5[@id='_my_title'][text() = 'My Title']", render_string(":fragment:\n===== My Title")
112
198
  end
113
- end
199
+ end
200
+
201
+ context 'Section Numbering' do
202
+ test 'should create section number with one entry for level 1' do
203
+ sect1 = Asciidoctor::Section.new(nil)
204
+ sect1.level = 1
205
+ assert_equal '1.', sect1.sectnum
206
+ end
207
+
208
+ test 'should create section number with two entries for level 2' do
209
+ sect1 = Asciidoctor::Section.new(nil)
210
+ sect1.level = 1
211
+ sect1_1 = Asciidoctor::Section.new(sect1)
212
+ sect1 << sect1_1
213
+ assert_equal '1.1.', sect1_1.sectnum
214
+ end
215
+
216
+ test 'should create section number with three entries for level 3' do
217
+ sect1 = Asciidoctor::Section.new(nil)
218
+ sect1.level = 1
219
+ sect1_1 = Asciidoctor::Section.new(sect1)
220
+ sect1 << sect1_1
221
+ sect1_1_1 = Asciidoctor::Section.new(sect1_1)
222
+ sect1_1 << sect1_1_1
223
+ assert_equal '1.1.1.', sect1_1_1.sectnum
224
+ end
225
+
226
+ test 'should create section number for second section in level' do
227
+ sect1 = Asciidoctor::Section.new(nil)
228
+ sect1.level = 1
229
+ sect1_1 = Asciidoctor::Section.new(sect1)
230
+ sect1 << sect1_1
231
+ sect1_2 = Asciidoctor::Section.new(sect1)
232
+ sect1 << sect1_2
233
+ assert_equal '1.2.', sect1_2.sectnum
234
+ end
235
+
236
+ test 'sectnum should use specified delimiter and append string' do
237
+ sect1 = Asciidoctor::Section.new(nil)
238
+ sect1.level = 1
239
+ sect1_1 = Asciidoctor::Section.new(sect1)
240
+ sect1 << sect1_1
241
+ sect1_1_1 = Asciidoctor::Section.new(sect1_1)
242
+ sect1_1 << sect1_1_1
243
+ assert_equal '1,1,1,', sect1_1_1.sectnum(',')
244
+ assert_equal '1:1:1', sect1_1_1.sectnum(':', false)
245
+ end
246
+
247
+ test 'should render section numbers when numbered attribute is set' do
248
+ input = <<-EOS
249
+ = Title
250
+ :numbered:
251
+
252
+ == Section_1
253
+
254
+ text
255
+
256
+ === Section_1_1
257
+
258
+ text
259
+
260
+ ==== Section_1_1_1
261
+
262
+ text
263
+
264
+ == Section_2
265
+
266
+ text
267
+
268
+ === Section_2_1
269
+
270
+ text
271
+
272
+ === Section_2_2
273
+
274
+ text
275
+ EOS
276
+
277
+ output = render_string input
278
+ assert_xpath '//h2[@id="_section_1"][starts-with(text(), "1. ")]', output, 1
279
+ assert_xpath '//h3[@id="_section_1_1"][starts-with(text(), "1.1. ")]', output, 1
280
+ assert_xpath '//h4[@id="_section_1_1_1"][starts-with(text(), "1.1.1. ")]', output, 1
281
+ assert_xpath '//h2[@id="_section_2"][starts-with(text(), "2. ")]', output, 1
282
+ assert_xpath '//h3[@id="_section_2_1"][starts-with(text(), "2.1. ")]', output, 1
283
+ assert_xpath '//h3[@id="_section_2_2"][starts-with(text(), "2.2. ")]', output, 1
284
+ end
285
+
286
+ test 'blocks should have level' do
287
+ input = <<-EOS
288
+ = Title
289
+
290
+ preamble
291
+
292
+ == Section 1
293
+
294
+ paragraph
295
+
296
+ === Section 1.1
297
+
298
+ paragraph
299
+ EOS
300
+ doc = document_from_string input
301
+ assert_equal 0, doc.blocks[0].level
302
+ assert_equal 1, doc.blocks[1].level
303
+ assert_equal 1, doc.blocks[1].blocks[0].level
304
+ assert_equal 2, doc.blocks[1].blocks[1].level
305
+ assert_equal 2, doc.blocks[1].blocks[1].blocks[0].level
306
+ end
307
+ end
308
+
309
+ context "heading patterns in blocks" do
310
+ test "should not interpret a listing block as a heading" do
311
+ input = <<-EOS
312
+ Section
313
+ -------
314
+
315
+ ----
316
+ code
317
+ ----
318
+
319
+ fin.
320
+ EOS
321
+ output = render_string input
322
+ assert_xpath "//h2", output, 1
323
+ end
324
+
325
+ test "should not interpret an open block as a heading" do
326
+ input = <<-EOS
327
+ Section
328
+ -------
329
+
330
+ --
331
+ ha
332
+ --
333
+
334
+ fin.
335
+ EOS
336
+ output = render_string input
337
+ assert_xpath "//h2", output, 1
338
+ end
339
+
340
+ test "should not interpret an attribute list as a heading" do
341
+ input = <<-EOS
342
+ Section
343
+ =======
344
+
345
+ preamble
346
+
347
+ [TIP]
348
+ ====
349
+ This should be a tip, not a heading.
350
+ ====
351
+ EOS
352
+ output = render_string input
353
+ assert_xpath "//*[@class='admonitionblock']//p[text() = 'This should be a tip, not a heading.']", output, 1
354
+ end
355
+
356
+ test "should not match a heading in a labeled list" do
357
+ input = <<-EOS
358
+ Section
359
+ -------
360
+
361
+ term1::
362
+ +
363
+ ----
364
+ list = [1, 2, 3];
365
+ ----
366
+ term2::
367
+ == not a heading
368
+ term3:: def
369
+
370
+ //
371
+
372
+ fin.
373
+ EOS
374
+ output = render_string input
375
+ assert_xpath "//h2", output, 1
376
+ assert_xpath "//dl", output, 1
377
+ end
378
+
379
+ test "should not match a heading in a bulleted list" do
380
+ input = <<-EOS
381
+ Section
382
+ -------
383
+
384
+ * first
385
+ +
386
+ ----
387
+ list = [1, 2, 3];
388
+ ----
389
+ +
390
+ * second
391
+ == not a heading
392
+ * third
393
+
394
+ fin.
395
+ EOS
396
+ output = render_string input
397
+ assert_xpath "//h2", output, 1
398
+ assert_xpath "//ul", output, 1
399
+ end
400
+
401
+ test "should not match a heading in a block" do
402
+ input = <<-EOS
403
+ ====
404
+
405
+ == not a heading
406
+
407
+ ====
408
+ EOS
409
+ output = render_string input
410
+ assert_xpath "//h2", output, 0
411
+ assert_xpath "//*[@class='exampleblock']//p[text() = '== not a heading']", output, 1
412
+ end
413
+ end
414
+
415
+ context 'Table of Contents' do
416
+ test 'should render table of contents if toc attribute is set' do
417
+ input = <<-EOS
418
+ Article
419
+ =======
420
+ :toc:
421
+
422
+ == Section One
423
+
424
+ It was a dark and stormy night...
425
+
426
+ == Section Two
427
+
428
+ They couldn't believe their eyes when...
429
+
430
+ === Interlude
431
+
432
+ While they were waiting...
433
+
434
+ == Section Three
435
+
436
+ That's all she wrote!
437
+ EOS
438
+ output = render_string input
439
+ assert_xpath '//*[@id="toc"]', output, 1
440
+ assert_xpath '//*[@id="toc"]/*[@id="toctitle"][text()="Table of Contents"]', output, 1
441
+ assert_xpath '//*[@id="toc"]/ol', output, 1
442
+ assert_xpath '//*[@id="toc"]//ol', output, 2
443
+ assert_xpath '//*[@id="toc"]/ol/li', output, 4
444
+ assert_xpath '//*[@id="toc"]/ol/li[1]/a[@href="#_section_one"][text()="1. Section One"]', output, 1
445
+ assert_xpath '//*[@id="toc"]/ol/li/ol/li', output, 1
446
+ assert_xpath '//*[@id="toc"]/ol/li/ol/li/a[@href="#_interlude"][text()="2.1. Interlude"]', output, 1
447
+ end
448
+ end
449
+
450
+ context "book doctype" do
451
+ test "document title with level 0 headings" do
452
+ input = <<-EOS
453
+ Book
454
+ ====
455
+ :doctype: book
456
+
457
+ = Chapter One
458
+
459
+ It was a dark and stormy night...
460
+
461
+ = Chapter Two
462
+
463
+ They couldn't believe their eyes when...
464
+
465
+ == Interlude
466
+
467
+ While they were waiting...
468
+
469
+ = Chapter Three
470
+
471
+ That's all she wrote!
472
+ EOS
473
+
474
+ output = render_string(input)
475
+ assert_xpath '//h1', output, 4
476
+ assert_xpath '//h2', output, 1
477
+ assert_xpath '//h1[@id="_chapter_one"][text() = "Chapter One"]', output, 1
478
+ assert_xpath '//h1[@id="_chapter_two"][text() = "Chapter Two"]', output, 1
479
+ assert_xpath '//h1[@id="_chapter_three"][text() = "Chapter Three"]', output, 1
480
+ end
481
+ end
114
482
  end