asciidoctor 0.1.2 → 0.1.3

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

Potentially problematic release.


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

Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +10 -0
  3. data/Guardfile +18 -0
  4. data/LICENSE +1 -1
  5. data/README.adoc +65 -21
  6. data/Rakefile +10 -0
  7. data/asciidoctor.gemspec +17 -35
  8. data/compat/asciidoc.conf +130 -13
  9. data/lib/asciidoctor.rb +107 -87
  10. data/lib/asciidoctor/abstract_block.rb +6 -2
  11. data/lib/asciidoctor/abstract_node.rb +21 -13
  12. data/lib/asciidoctor/attribute_list.rb +2 -5
  13. data/{stylesheets/asciidoctor.css → lib/asciidoctor/backends/_stylesheets.rb} +96 -46
  14. data/lib/asciidoctor/backends/base_template.rb +9 -4
  15. data/lib/asciidoctor/backends/docbook45.rb +246 -138
  16. data/lib/asciidoctor/backends/html5.rb +580 -381
  17. data/lib/asciidoctor/block.rb +2 -50
  18. data/lib/asciidoctor/cli/options.rb +9 -8
  19. data/lib/asciidoctor/document.rb +35 -45
  20. data/lib/asciidoctor/helpers.rb +10 -0
  21. data/lib/asciidoctor/lexer.rb +456 -148
  22. data/lib/asciidoctor/list_item.rb +0 -21
  23. data/lib/asciidoctor/path_resolver.rb +18 -12
  24. data/lib/asciidoctor/reader.rb +71 -26
  25. data/lib/asciidoctor/renderer.rb +2 -19
  26. data/lib/asciidoctor/section.rb +0 -1
  27. data/lib/asciidoctor/substituters.rb +150 -36
  28. data/lib/asciidoctor/table.rb +30 -24
  29. data/lib/asciidoctor/version.rb +1 -1
  30. data/man/asciidoctor.1 +22 -16
  31. data/man/asciidoctor.ad +24 -16
  32. data/test/attributes_test.rb +50 -0
  33. data/test/blocks_test.rb +660 -9
  34. data/test/document_test.rb +191 -14
  35. data/test/fixtures/encoding.asciidoc +8 -0
  36. data/test/invoker_test.rb +47 -0
  37. data/test/lexer_test.rb +172 -0
  38. data/test/links_test.rb +28 -0
  39. data/test/lists_test.rb +172 -13
  40. data/test/options_test.rb +29 -2
  41. data/test/paragraphs_test.rb +105 -47
  42. data/test/paths_test.rb +3 -3
  43. data/test/reader_test.rb +46 -0
  44. data/test/sections_test.rb +365 -12
  45. data/test/substitutions_test.rb +127 -11
  46. data/test/tables_test.rb +81 -14
  47. data/test/test_helper.rb +18 -7
  48. data/test/text_test.rb +17 -5
  49. metadata +9 -36
data/test/paths_test.rb CHANGED
@@ -166,9 +166,9 @@ context 'Path Resolver' do
166
166
 
167
167
  test 'resolves windows paths when file separator is backlash' do
168
168
  @resolver.file_separator = '\\'
169
- assert_equal 'C:\\data\\docs', @resolver.system_path('..', "C:\\data\\docs\\assets", 'C:\\data\\docs')
170
- assert_equal 'C:\\data\\docs', @resolver.system_path('..\\..', "C:\\data\\docs\\assets", 'C:\\data\\docs')
171
- assert_equal 'C:\\data\\docs\\css', @resolver.system_path('..\\..\\css', "C:\\data\\docs\\assets", 'C:\\data\\docs')
169
+ assert_equal 'C:/data/docs', @resolver.system_path('..', "C:\\data\\docs\\assets", 'C:\\data\\docs')
170
+ assert_equal 'C:/data/docs', @resolver.system_path('..\\..', "C:\\data\\docs\\assets", 'C:\\data\\docs')
171
+ assert_equal 'C:/data/docs/css', @resolver.system_path('..\\..\\css', "C:\\data\\docs\\assets", 'C:\\data\\docs')
172
172
  end
173
173
  end
174
174
  end
data/test/reader_test.rb CHANGED
@@ -243,6 +243,19 @@ include::fixtures/include-file.asciidoc[lines=1, tags=snippetA;snippetB]
243
243
  assert_no_match(/snippetB content/, output)
244
244
  end
245
245
 
246
+ test 'indent of included file can be reset to size of indent attribute' do
247
+ input = <<-EOS
248
+ [source, xml]
249
+ ----
250
+ include::fixtures/basic-docinfo.xml[lines=2..3, indent=0]
251
+ ----
252
+ EOS
253
+
254
+ output = render_string input, :safe => Asciidoctor::SafeMode::SAFE, :header_footer => false, :attributes => {'docdir' => File.dirname(__FILE__)}
255
+ result = xmlnodes_at_xpath('//pre', output, 1).text
256
+ assert_equal "<year>2013</year>\n<holder>Acme, Inc.</holder>", result
257
+ end
258
+
246
259
  test "block is called to handle an include macro" do
247
260
  input = <<-EOS
248
261
  first line
@@ -262,6 +275,39 @@ last line
262
275
  assert_match(/^:includefile: include-file.asciidoc$/, lines.join)
263
276
  end
264
277
 
278
+ test 'attributes are substituted in target of include macro' do
279
+ input = <<-EOS
280
+ :fixturesdir: fixtures
281
+ :ext: asciidoc
282
+
283
+ include::{fixturesdir}/include-file.{ext}[]
284
+ EOS
285
+
286
+ doc = document_from_string input, :safe => Asciidoctor::SafeMode::SAFE, :attributes => {'docdir' => File.dirname(__FILE__)}
287
+ output = doc.render
288
+ assert_match(/included content/, output)
289
+ end
290
+
291
+ test 'line is dropped if target of include macro resolves to empty' do
292
+ input = <<-EOS
293
+ include::{foodir}/include-file.asciidoc[]
294
+ EOS
295
+
296
+ output = render_embedded_string input, :safe => Asciidoctor::SafeMode::SAFE, :attributes => {'docdir' => File.dirname(__FILE__)}
297
+ assert output.strip.empty?
298
+ end
299
+
300
+ test 'line is dropped but not following line if target of include macro resolves to empty' do
301
+ input = <<-EOS
302
+ include::{foodir}/include-file.asciidoc[]
303
+ yo
304
+ EOS
305
+
306
+ output = render_embedded_string input, :safe => Asciidoctor::SafeMode::SAFE, :attributes => {'docdir' => File.dirname(__FILE__)}
307
+ assert_xpath '//p', output, 1
308
+ assert_xpath '//p[text()="yo"]', output, 1
309
+ end
310
+
265
311
  test 'escaped include macro is left unprocessed' do
266
312
  input = <<-EOS
267
313
  \\include::include-file.asciidoc[]
@@ -208,6 +208,50 @@ text
208
208
  end
209
209
  end
210
210
 
211
+ context "level 5" do
212
+ test "with single line syntax" do
213
+ assert_xpath "//h6[@id='_my_title'][text() = 'My Title']", render_string(":fragment:\n====== My Title")
214
+ end
215
+ end
216
+
217
+ context 'Markdown-style headings' do
218
+ test 'single-line document title with leading marker' do
219
+ input = <<-EOS
220
+ # Document Title
221
+ EOS
222
+ output = render_string input
223
+ assert_xpath "//h1[not(@id)][text() = 'Document Title']", output, 1
224
+ end
225
+
226
+ test 'single-line document title with symmetric markers' do
227
+ input = <<-EOS
228
+ # Document Title #
229
+ EOS
230
+ output = render_string input
231
+ assert_xpath "//h1[not(@id)][text() = 'Document Title']", output, 1
232
+ end
233
+
234
+ test 'single-line section title with leading marker' do
235
+ input = <<-EOS
236
+ ## Section One
237
+
238
+ blah blah
239
+ EOS
240
+ output = render_string input
241
+ assert_xpath "//h2[@id='_section_one'][text() = 'Section One']", output, 1
242
+ end
243
+
244
+ test 'single-line section title with symmetric markers' do
245
+ input = <<-EOS
246
+ ## Section One ##
247
+
248
+ blah blah
249
+ EOS
250
+ output = render_string input
251
+ assert_xpath "//h2[@id='_section_one'][text() = 'Section One']", output, 1
252
+ end
253
+ end
254
+
211
255
  context 'Floating Title' do
212
256
  test 'should create floating title if style is float' do
213
257
  input = <<-EOS
@@ -290,7 +334,7 @@ not in section
290
334
 
291
335
  output = render_string input
292
336
  assert_xpath '//*[@id="toc"]', output, 1
293
- assert_xpath %(//*[@id="toc"]//a[contains(text(), " Section ")]), output, 2
337
+ assert_xpath %(//*[@id="toc"]//a[contains(text(), "Section ")]), output, 2
294
338
  assert_xpath %(//*[@id="toc"]//a[text()="Miss Independent"]), output, 0
295
339
  end
296
340
 
@@ -355,15 +399,14 @@ text in standalone
355
399
  // end simulated include::[]
356
400
  EOS
357
401
 
358
- output = nil
359
- errors = nil
402
+ output, errors = nil
360
403
  redirect_streams do |stdout, stderr|
361
404
  output = render_string input
362
405
  errors = stdout.string
363
406
  end
364
407
 
365
408
  assert !errors.empty?
366
- assert_match(/section title out of sequence/, errors)
409
+ assert_match(/only book doctypes can contain level 0 sections/, errors)
367
410
  end
368
411
 
369
412
  test 'should add level offset to section level' do
@@ -555,6 +598,48 @@ paragraph
555
598
  end
556
599
  end
557
600
 
601
+ context 'Links and anchors' do
602
+ test 'should include anchor if sectanchors document attribute is set' do
603
+ input = <<-EOS
604
+ == Installation
605
+
606
+ Installation section.
607
+
608
+ === Linux
609
+
610
+ Linux installation instructions.
611
+ EOS
612
+
613
+ output = render_embedded_string input, :attributes => {'sectanchors' => ''}
614
+ assert_xpath '/*[@class="sect1"]/h2[@id="_installation"]/a', output, 1
615
+ assert_xpath '/*[@class="sect1"]/h2[@id="_installation"]/a[@class="anchor"][@href="#_installation"]', output, 1
616
+ assert_xpath '/*[@class="sect1"]/h2[@id="_installation"]/a/following-sibling::text()="Installation"', output, true
617
+ assert_xpath '//*[@class="sect2"]/h3[@id="_linux"]/a', output, 1
618
+ assert_xpath '//*[@class="sect2"]/h3[@id="_linux"]/a[@class="anchor"][@href="#_linux"]', output, 1
619
+ assert_xpath '//*[@class="sect2"]/h3[@id="_linux"]/a/following-sibling::text()="Linux"', output, true
620
+ end
621
+
622
+ test 'should link section if sectlinks document attribute is set' do
623
+ input = <<-EOS
624
+ == Installation
625
+
626
+ Installation section.
627
+
628
+ === Linux
629
+
630
+ Linux installation instructions.
631
+ EOS
632
+
633
+ output = render_embedded_string input, :attributes => {'sectlinks' => ''}
634
+ assert_xpath '/*[@class="sect1"]/h2[@id="_installation"]/a', output, 1
635
+ assert_xpath '/*[@class="sect1"]/h2[@id="_installation"]/a[@class="link"][@href="#_installation"]', output, 1
636
+ assert_xpath '/*[@class="sect1"]/h2[@id="_installation"]/a[text()="Installation"]', output, 1
637
+ assert_xpath '//*[@class="sect2"]/h3[@id="_linux"]/a', output, 1
638
+ assert_xpath '//*[@class="sect2"]/h3[@id="_linux"]/a[@class="link"][@href="#_linux"]', output, 1
639
+ assert_xpath '//*[@class="sect2"]/h3[@id="_linux"]/a[text()="Linux"]', output, 1
640
+ end
641
+ end
642
+
558
643
  context 'Special sections' do
559
644
  test 'should assign sectname and caption to appendix section' do
560
645
  input = <<-EOS
@@ -566,7 +651,7 @@ Details
566
651
 
567
652
  output = block_from_string input
568
653
  assert_equal 'appendix', output.sectname
569
- assert_equal 'Appendix A: ', output.attr('caption')
654
+ assert_equal 'Appendix A: ', output.caption
570
655
  end
571
656
 
572
657
  test 'should render appendix title prefixed with caption' do
@@ -708,6 +793,130 @@ Appendix text
708
793
  assert_xpath '//h2[@id = "_preface"]', output, 1
709
794
  assert_xpath '//h2[@id = "_appendix"]', output, 1
710
795
  end
796
+
797
+ test 'should output docbook elements that coorespond to special sections in book doctype' do
798
+ input = <<-EOS
799
+ = Multipart Book
800
+ :doctype: book
801
+ :idprefix:
802
+
803
+ [abstract]
804
+ = Abstract Title
805
+
806
+ Normal chapter (no abstract in book)
807
+
808
+ [dedication]
809
+ = Dedication Title
810
+
811
+ Dedication content
812
+
813
+ [preface]
814
+ = Preface Title
815
+
816
+ Preface content
817
+
818
+ === Preface sub-section
819
+
820
+ Preface subsection content
821
+
822
+ = Part 1
823
+
824
+ [partintro]
825
+ .Part intro title
826
+ Part intro content
827
+
828
+ == Chapter 1
829
+
830
+ blah blah
831
+
832
+ == Chapter 2
833
+
834
+ blah blah
835
+
836
+ = Part 2
837
+
838
+ blah blah
839
+
840
+ == Chapter 3
841
+
842
+ blah blah
843
+
844
+ == Chapter 4
845
+
846
+ blah blah
847
+
848
+ [appendix]
849
+ = Appendix Title
850
+
851
+ Appendix content
852
+
853
+ === Appendix sub-section
854
+
855
+ Appendix sub-section content
856
+
857
+ [bibliography]
858
+ = Bibliography Title
859
+
860
+ Bibliography content
861
+
862
+ [glossary]
863
+ = Glossary Title
864
+
865
+ Glossary content
866
+
867
+ [colophon]
868
+ = Colophon Title
869
+
870
+ Colophon content
871
+
872
+ [index]
873
+ = Index Title
874
+ EOS
875
+
876
+ output = render_embedded_string input, :backend => 'docbook'
877
+ assert_xpath '/chapter[@id="abstract_title"]', output, 1
878
+ assert_xpath '/chapter[@id="abstract_title"]/title[text()="Abstract Title"]', output, 1
879
+ assert_xpath '/chapter/following-sibling::dedication[@id="dedication_title"]', output, 1
880
+ assert_xpath '/chapter/following-sibling::dedication[@id="dedication_title"]/title[text()="Dedication Title"]', output, 1
881
+ assert_xpath '/dedication/following-sibling::preface[@id="preface_title"]', output, 1
882
+ assert_xpath '/dedication/following-sibling::preface[@id="preface_title"]/title[text()="Preface Title"]', output, 1
883
+ assert_xpath '/preface/section[@id="preface_sub_section"]', output, 1
884
+ assert_xpath '/preface/section[@id="preface_sub_section"]/title[text()="Preface sub-section"]', output, 1
885
+ assert_xpath '/preface/following-sibling::part[@id="part_1"]', output, 1
886
+ assert_xpath '/preface/following-sibling::part[@id="part_1"]/title[text()="Part 1"]', output, 1
887
+ assert_xpath '/part[@id="part_1"]/partintro', output, 1
888
+ assert_xpath '/part[@id="part_1"]/partintro/title[text()="Part intro title"]', output, 1
889
+ assert_xpath '/part[@id="part_1"]/partintro/following-sibling::chapter[@id="chapter_1"]', output, 1
890
+ assert_xpath '/part[@id="part_1"]/partintro/following-sibling::chapter[@id="chapter_1"]/title[text()="Chapter 1"]', output, 1
891
+ assert_xpath '(/part)[2]/following-sibling::appendix[@id="appendix_title"]', output, 1
892
+ assert_xpath '(/part)[2]/following-sibling::appendix[@id="appendix_title"]/title[text()="Appendix Title"]', output, 1
893
+ assert_xpath '/appendix/section[@id="appendix_sub_section"]', output, 1
894
+ assert_xpath '/appendix/section[@id="appendix_sub_section"]/title[text()="Appendix sub-section"]', output, 1
895
+ assert_xpath '/appendix/following-sibling::bibliography[@id="bibliography_title"]', output, 1
896
+ assert_xpath '/appendix/following-sibling::bibliography[@id="bibliography_title"]/title[text()="Bibliography Title"]', output, 1
897
+ assert_xpath '/bibliography/following-sibling::glossary[@id="glossary_title"]', output, 1
898
+ assert_xpath '/bibliography/following-sibling::glossary[@id="glossary_title"]/title[text()="Glossary Title"]', output, 1
899
+ assert_xpath '/glossary/following-sibling::colophon[@id="colophon_title"]', output, 1
900
+ assert_xpath '/glossary/following-sibling::colophon[@id="colophon_title"]/title[text()="Colophon Title"]', output, 1
901
+ assert_xpath '/colophon/following-sibling::index[@id="index_title"]', output, 1
902
+ assert_xpath '/colophon/following-sibling::index[@id="index_title"]/title[text()="Index Title"]', output, 1
903
+ end
904
+
905
+ test 'abstract section maps to abstract element in docbook for article doctype' do
906
+ input = <<-EOS
907
+ = Article
908
+ :idprefix:
909
+
910
+ [abstract]
911
+ == Abstract Title
912
+
913
+ Abstract content
914
+ EOS
915
+
916
+ output = render_embedded_string input, :backend => 'docbook'
917
+ assert_xpath '/abstract[@id="abstract_title"]', output, 1
918
+ assert_xpath '/abstract[@id="abstract_title"]/title[text()="Abstract Title"]', output, 1
919
+ end
711
920
  end
712
921
 
713
922
  context "heading patterns in blocks" do
@@ -817,7 +1026,7 @@ fin.
817
1026
  end
818
1027
 
819
1028
  context 'Table of Contents' do
820
- test 'should render table of contents in header if toc attribute is set' do
1029
+ test 'should render unnumbered table of contents in header if toc attribute is set' do
821
1030
  input = <<-EOS
822
1031
  = Article
823
1032
  :toc:
@@ -842,17 +1051,133 @@ That's all she wrote!
842
1051
  assert_xpath '//*[@id="header"]//*[@id="toc"][@class="toc"]', output, 1
843
1052
  assert_xpath '//*[@id="header"]//*[@id="toc"]/*[@id="toctitle"][text()="Table of Contents"]', output, 1
844
1053
  assert_xpath '//*[@id="header"]//*[@id="toc"]/ol', output, 1
1054
+ assert_xpath '//*[@id="header"]//*[@id="toc"]/ol[@type="none"][@class="sectlevel1"]', output, 1
845
1055
  assert_xpath '//*[@id="header"]//*[@id="toc"]//ol', output, 2
1056
+ assert_xpath '//*[@id="header"]//*[@id="toc"]//ol[@type="none"]', output, 2
1057
+ assert_xpath '//*[@id="header"]//*[@id="toc"]/ol/li', output, 4
1058
+ assert_xpath '//*[@id="header"]//*[@id="toc"]/ol/li[1]/a[@href="#_section_one"][text()="Section One"]', output, 1
1059
+ assert_xpath '//*[@id="header"]//*[@id="toc"]/ol/li/ol', output, 1
1060
+ assert_xpath '//*[@id="header"]//*[@id="toc"]/ol/li/ol[@type="none"]', output, 1
1061
+ assert_xpath '//*[@id="header"]//*[@id="toc"]/ol/li/ol[@class="sectlevel2"]', output, 1
1062
+ assert_xpath '//*[@id="header"]//*[@id="toc"]/ol/li/ol/li', output, 1
1063
+ assert_xpath '//*[@id="header"]//*[@id="toc"]/ol/li/ol/li/a[@href="#_interlude"][text()="Interlude"]', output, 1
1064
+ assert_xpath '((//*[@id="header"]//*[@id="toc"]/ol)[1]/li)[4]/a[@href="#_section_three"][text()="Section Three"]', output, 1
1065
+ end
1066
+
1067
+ test 'should render numbered table of contents in header if toc and numbered attributes are set' do
1068
+ input = <<-EOS
1069
+ = Article
1070
+ :toc:
1071
+ :numbered:
1072
+
1073
+ == Section One
1074
+
1075
+ It was a dark and stormy night...
1076
+
1077
+ == Section Two
1078
+
1079
+ They couldn't believe their eyes when...
1080
+
1081
+ === Interlude
1082
+
1083
+ While they were waiting...
1084
+
1085
+ == Section Three
1086
+
1087
+ That's all she wrote!
1088
+ EOS
1089
+ output = render_string input
1090
+ assert_xpath '//*[@id="header"]//*[@id="toc"][@class="toc"]', output, 1
1091
+ assert_xpath '//*[@id="header"]//*[@id="toc"]/*[@id="toctitle"][text()="Table of Contents"]', output, 1
1092
+ assert_xpath '//*[@id="header"]//*[@id="toc"]/ol', output, 1
1093
+ assert_xpath '//*[@id="header"]//*[@id="toc"]/ol[@type="none"]', output, 1
1094
+ assert_xpath '//*[@id="header"]//*[@id="toc"]//ol', output, 2
1095
+ assert_xpath '//*[@id="header"]//*[@id="toc"]//ol[@type="none"]', output, 2
846
1096
  assert_xpath '//*[@id="header"]//*[@id="toc"]/ol/li', output, 4
847
1097
  assert_xpath '//*[@id="header"]//*[@id="toc"]/ol/li[1]/a[@href="#_section_one"][text()="1. Section One"]', output, 1
848
1098
  assert_xpath '//*[@id="header"]//*[@id="toc"]/ol/li/ol/li', output, 1
849
1099
  assert_xpath '//*[@id="header"]//*[@id="toc"]/ol/li/ol/li/a[@href="#_interlude"][text()="2.1. Interlude"]', output, 1
1100
+ assert_xpath '((//*[@id="header"]//*[@id="toc"]/ol)[1]/li)[4]/a[@href="#_section_three"][text()="3. Section Three"]', output, 1
1101
+ end
1102
+
1103
+ test 'should render a table of contents that honors numbered setting at position of section in document' do
1104
+ input = <<-EOS
1105
+ = Article
1106
+ :toc:
1107
+ :numbered:
1108
+
1109
+ == Section One
1110
+
1111
+ It was a dark and stormy night...
1112
+
1113
+ == Section Two
1114
+
1115
+ They couldn't believe their eyes when...
1116
+
1117
+ === Interlude
1118
+
1119
+ While they were waiting...
1120
+
1121
+ :numbered!:
1122
+
1123
+ == Section Three
1124
+
1125
+ That's all she wrote!
1126
+ EOS
1127
+ output = render_string input
1128
+ assert_xpath '//*[@id="header"]//*[@id="toc"][@class="toc"]', output, 1
1129
+ assert_xpath '//*[@id="header"]//*[@id="toc"]/*[@id="toctitle"][text()="Table of Contents"]', output, 1
1130
+ assert_xpath '//*[@id="header"]//*[@id="toc"]/ol', output, 1
1131
+ assert_xpath '//*[@id="header"]//*[@id="toc"]/ol[@type="none"]', output, 1
1132
+ assert_xpath '//*[@id="header"]//*[@id="toc"]//ol', output, 2
1133
+ assert_xpath '//*[@id="header"]//*[@id="toc"]//ol[@type="none"]', output, 2
1134
+ assert_xpath '//*[@id="header"]//*[@id="toc"]/ol/li', output, 4
1135
+ assert_xpath '//*[@id="header"]//*[@id="toc"]/ol/li[1]/a[@href="#_section_one"][text()="1. Section One"]', output, 1
1136
+ assert_xpath '((//*[@id="header"]//*[@id="toc"]/ol)[1]/li)[4]/a[@href="#_section_three"][text()="Section Three"]', output, 1
1137
+ end
1138
+
1139
+ test 'should not number parts in table of contents for book doctype when numbered attribute is set' do
1140
+ input = <<-EOS
1141
+ = Book
1142
+ :doctype: book
1143
+ :toc:
1144
+ :numbered:
1145
+
1146
+ = Part 1
1147
+
1148
+ == First Section of Part 1
1149
+
1150
+ blah
1151
+
1152
+ == Second Section of Part 1
1153
+
1154
+ blah
1155
+
1156
+ = Part 2
1157
+
1158
+ == First Section of Part 2
1159
+
1160
+ blah
1161
+ EOS
1162
+
1163
+ output = render_string input
1164
+ assert_xpath '//*[@id="toc"]', output, 1
1165
+ assert_xpath '//*[@id="toc"]/ol', output, 1
1166
+ assert_xpath '//*[@id="toc"]/ol[@type="none"][@class="sectlevel0"]', output, 1
1167
+ assert_xpath '//*[@id="toc"]/ol[@type="none"][@class="sectlevel0"]/li', output, 4
1168
+ assert_xpath '(//*[@id="toc"]/ol[@type="none"][@class="sectlevel0"]/li)[1]/a[text()="Part 1"]', output, 1
1169
+ assert_xpath '(//*[@id="toc"]/ol[@type="none"][@class="sectlevel0"]/li)[3]/a[text()="Part 2"]', output, 1
1170
+ assert_xpath '(//*[@id="toc"]/ol[@type="none"][@class="sectlevel0"]/li)[2]/ol', output, 1
1171
+ assert_xpath '(//*[@id="toc"]/ol[@type="none"][@class="sectlevel0"]/li)[2]/ol[@type="none"][@class="sectlevel1"]', output, 1
1172
+ assert_xpath '(//*[@id="toc"]/ol[@type="none"][@class="sectlevel0"]/li)[2]/ol/li', output, 2
1173
+ assert_xpath '((//*[@id="toc"]/ol[@type="none"][@class="sectlevel0"]/li)[2]/ol/li)[1]/a[text()="1. First Section of Part 1"]', output, 1
850
1174
  end
851
1175
 
852
1176
  test 'should render table of contents in header if toc2 attribute is set' do
853
1177
  input = <<-EOS
854
1178
  = Article
855
1179
  :toc2:
1180
+ :numbered:
856
1181
 
857
1182
  == Section One
858
1183
 
@@ -864,6 +1189,7 @@ They couldn't believe their eyes when...
864
1189
  EOS
865
1190
 
866
1191
  output = render_string input
1192
+ assert_xpath '//body[@class="article toc2"]', output, 1
867
1193
  assert_xpath '//*[@id="header"]//*[@id="toc"][@class="toc2"]', output, 1
868
1194
  assert_xpath '//*[@id="header"]//*[@id="toc"]/ol/li[1]/a[@href="#_section_one"][text()="1. Section One"]', output, 1
869
1195
  end
@@ -898,9 +1224,31 @@ Fin.
898
1224
  assert_xpath '//*[@id="header"]//*[@id="toc"]/*[@id="toctitle"][text()="Contents"]', output, 1
899
1225
  end
900
1226
 
1227
+ test 'should render table of contents in preamble if toc-placement attribute value is preamble' do
1228
+ input = <<-EOS
1229
+ = Article
1230
+ :toc:
1231
+ :toc-placement: preamble
1232
+
1233
+ Once upon a time...
1234
+
1235
+ == Section One
1236
+
1237
+ It was a dark and stormy night...
1238
+
1239
+ == Section Two
1240
+
1241
+ They couldn't believe their eyes when...
1242
+ EOS
1243
+
1244
+ output = render_string input
1245
+ assert_xpath '//*[@id="preamble"]/*[@id="toc"]', output, 1
1246
+ end
1247
+
901
1248
  test 'should not render table of contents if toc-placement attribute is unset' do
902
1249
  input = <<-EOS
903
1250
  = Article
1251
+ :toc:
904
1252
  :toc-placement!:
905
1253
 
906
1254
  == Section One
@@ -1025,8 +1373,8 @@ Fin.
1025
1373
  assert_css '#preamble #toc.contents', output, 1
1026
1374
  assert_xpath '//*[@id="toc"]/*[@class="title"][text() = "Contents"]', output, 1
1027
1375
  assert_css '#toc li', output, 2
1028
- assert_xpath '(//*[@id="toc"]//li)[1]/a[text() = "1. Section 1"]', output, 1
1029
- assert_xpath '(//*[@id="toc"]//li)[2]/a[text() = "2. Section 2"]', output, 1
1376
+ assert_xpath '(//*[@id="toc"]//li)[1]/a[text() = "Section 1"]', output, 1
1377
+ assert_xpath '(//*[@id="toc"]//li)[2]/a[text() = "Section 2"]', output, 1
1030
1378
  end
1031
1379
 
1032
1380
  test 'should honor id, title, role and level attributes on toc macro' do
@@ -1068,8 +1416,8 @@ Fin.
1068
1416
  assert_css '#preamble #contents.contents', output, 1
1069
1417
  assert_xpath '//*[@id="contents"]/*[@class="title"][text() = "Contents"]', output, 1
1070
1418
  assert_css '#contents li', output, 2
1071
- assert_xpath '(//*[@id="contents"]//li)[1]/a[text() = "1. Section 1"]', output, 1
1072
- assert_xpath '(//*[@id="contents"]//li)[2]/a[text() = "2. Section 2"]', output, 1
1419
+ assert_xpath '(//*[@id="contents"]//li)[1]/a[text() = "Section 1"]', output, 1
1420
+ assert_xpath '(//*[@id="contents"]//li)[2]/a[text() = "Section 2"]', output, 1
1073
1421
  end
1074
1422
  end
1075
1423
 
@@ -1141,8 +1489,13 @@ That's all she wrote!
1141
1489
  EOS
1142
1490
 
1143
1491
  output = render_string(input)
1144
- assert_xpath '//h1', output, 4
1145
- assert_xpath '//h2', output, 1
1492
+ assert_css 'body.book', output, 1
1493
+ assert_css 'h1', output, 4
1494
+ assert_css '#header h1', output, 1
1495
+ assert_css '#content h1', output, 3
1496
+ assert_css '#content h1.sect0', output, 3
1497
+ assert_css 'h2', output, 1
1498
+ assert_css '#content h2', output, 1
1146
1499
  assert_xpath '//h1[@id="_chapter_one"][text() = "Chapter One"]', output, 1
1147
1500
  assert_xpath '//h1[@id="_chapter_two"][text() = "Chapter Two"]', output, 1
1148
1501
  assert_xpath '//h1[@id="_chapter_three"][text() = "Chapter Three"]', output, 1