Permalink
Fetching contributors…
Cannot retrieve contributors at this time
2701 lines (1999 sloc) 68.3 KB
# encoding: UTF-8
unless defined? ASCIIDOCTOR_PROJECT_DIR
$: << File.dirname(__FILE__); $:.uniq!
require 'test_helper'
end
context 'Sections' do
context 'Ids' do
test 'synthetic id is generated by default' do
sec = block_from_string('== Section One')
assert_equal '_section_one', sec.id
end
test 'synthetic id replaces non-word characters with underscores' do
sec = block_from_string("== We're back!")
assert_equal '_we_re_back', sec.id
end
test 'synthetic id removes repeating underscores' do
sec = block_from_string('== Section $ One')
assert_equal '_section_one', sec.id
end
test 'synthetic id removes entities' do
sec = block_from_string('== Ben & Jerry &amp; Company &#34;Ice Cream Brothers&#34; &#10046;')
assert_equal '_ben_jerry_company_ice_cream_brothers', sec.id
end
test 'synthetic id prefix can be customized' do
sec = block_from_string(":idprefix: id_\n\n== Section One")
assert_equal 'id_section_one', sec.id
end
test 'synthetic id prefix can be set to blank' do
sec = block_from_string(":idprefix:\n\n== Section One")
assert_equal 'section_one', sec.id
end
test 'synthetic id prefix is stripped from beginning of id if set to blank' do
sec = block_from_string(":idprefix:\n\n== & More")
assert_equal 'more', sec.id
end
test 'synthetic id separator can be customized' do
sec = block_from_string(":idseparator: -\n\n== Section One")
assert_equal '_section-one', sec.id
end
test 'synthetic id separator can be set to blank' do
sec = block_from_string(":idseparator:\n\n== Section One")
assert_equal '_sectionone', sec.id
end
test 'synthetic id separator can be set to blank when idprefix is blank' do
sec = block_from_string(":idprefix:\n:idseparator:\n\n== Section One")
assert_equal 'sectionone', sec.id
end
test 'synthetic id separator is removed from beginning of id when idprefix is blank' do
sec = block_from_string(":idprefix:\n:idseparator: _\n\n== +Section One")
assert_equal 'section_one', sec.id
end
test 'synthetic ids can be disabled' do
sec = block_from_string(":sectids!:\n\n== Section One\n")
assert sec.id.nil?
end
test 'explicit id in anchor above section title overrides synthetic id' do
sec = block_from_string("[[one]]\n== Section One")
assert_equal 'one', sec.id
end
test 'explicit id can be defined using an embedded anchor' do
sec = block_from_string("== Section One [[one]] ==")
assert_equal 'one', sec.id
assert_equal 'Section One', sec.title
end
test 'explicit id can be defined using an embedded anchor with reftext' do
sec = block_from_string("== Section One [[one,Section Uno]] ==")
assert_equal 'one', sec.id
assert_equal 'Section One', sec.title
assert_equal 'Section Uno', (sec.attr 'reftext')
end
test 'id and reftext in embedded anchor cannot be quoted' do
sec = block_from_string(%(== Section One [["one","Section Uno"]] ==))
refute_equal 'one', sec.id
assert_equal 'Section One [["one","Section Uno"]]', sec.title
assert_nil(sec.attr 'reftext')
end
test 'reftext in embedded anchor may contain comma' do
sec = block_from_string(%(== Section One [[one, Section,Uno]] ==))
assert_equal 'one', sec.id
assert_equal 'Section One', sec.title
assert_equal 'Section,Uno', (sec.attr 'reftext')
end
test 'should unescape but not process inline anchor' do
sec = block_from_string(%(== Section One \\[[one]] ==))
refute_equal 'one', sec.id
assert_equal 'Section One [[one]]', sec.title
end
test 'title substitutions are applied before generating id' do
sec = block_from_string("== Section{sp}One\n")
assert_equal '_section_one', sec.id
end
test 'synthetic ids are unique' do
input = <<-EOS
== Some section
text
== Some section
text
EOS
doc = document_from_string input
assert_equal '_some_section', doc.blocks[0].id
assert_equal '_some_section_2', doc.blocks[1].id
end
# NOTE test cannot be run in parallel with other tests
test 'can set start index of synthetic ids' do
old_unique_id_start_index = Asciidoctor::Compliance.unique_id_start_index
begin
input = <<-EOS
== Some section
text
== Some section
text
EOS
Asciidoctor::Compliance.unique_id_start_index = 1
doc = document_from_string input
assert_equal '_some_section', doc.blocks[0].id
assert_equal '_some_section_1', doc.blocks[1].id
ensure
Asciidoctor::Compliance.unique_id_start_index = old_unique_id_start_index
end
end
test 'should use specified id and reftext when registering section reference' do
input = <<-EOS
[[install,Install Procedure]]
== Install
content
EOS
doc = document_from_string input
reftext = doc.references[:ids]['install']
refute_nil reftext
assert_equal 'Install Procedure', reftext
end
test 'should use specified reftext when registering section reference' do
input = <<-EOS
[reftext="Install Procedure"]
== Install
content
EOS
doc = document_from_string input
reftext = doc.references[:ids]['_install']
refute_nil reftext
assert_equal 'Install Procedure', reftext
end
test 'should not overwrite existing id entry in references table' do
input = <<-EOS
[#install]
== First Install
content
[#install]
== Second Install
content
EOS
doc = document_from_string input
reftext = doc.references[:ids]['install']
refute_nil reftext
assert_equal 'First Install', reftext
end
test 'should not overwrite existing id entry with generated reftext in references table' do
input = <<-EOS
[#install]
== First Install
content
[#install]
content
EOS
doc = document_from_string input
reftext = doc.references[:ids]['install']
refute_nil reftext
assert_equal 'First Install', reftext
end
end
context "document title (level 0)" do
test "document title with multiline syntax" do
title = "My Title"
chars = "=" * title.length
assert_xpath "//h1[not(@id)][text() = 'My Title']", render_string(title + "\n" + chars)
assert_xpath "//h1[not(@id)][text() = 'My Title']", render_string(title + "\n" + chars + "\n")
end
test "document title with multiline syntax, give a char" do
title = "My Title"
chars = "=" * (title.length + 1)
assert_xpath "//h1[not(@id)][text() = 'My Title']", render_string(title + "\n" + chars)
assert_xpath "//h1[not(@id)][text() = 'My Title']", render_string(title + "\n" + chars + "\n")
end
test "document title with multiline syntax, take a char" do
title = "My Title"
chars = "=" * (title.length - 1)
assert_xpath "//h1[not(@id)][text() = 'My Title']", render_string(title + "\n" + chars)
assert_xpath "//h1[not(@id)][text() = 'My Title']", render_string(title + "\n" + chars + "\n")
end
test 'document title with multiline syntax and unicode characters' do
input = <<-EOS
AsciiDoc Writer’s Guide
=======================
Author Name
preamble
EOS
result = render_string input
assert_xpath '//h1', result, 1
assert_xpath '//h1[text()="AsciiDoc Writer’s Guide"]', result, 1
end
test "not enough chars for a multiline document title" do
title = "My Title"
chars = "=" * (title.length - 2)
assert_xpath '//h1', render_string(title + "\n" + chars), 0
assert_xpath '//h1', render_string(title + "\n" + chars + "\n"), 0
end
test "too many chars for a multiline document title" do
title = "My Title"
chars = "=" * (title.length + 2)
assert_xpath '//h1', render_string(title + "\n" + chars), 0
assert_xpath '//h1', render_string(title + "\n" + chars + "\n"), 0
end
test "document title with multiline syntax cannot begin with a dot" do
title = ".My Title"
chars = "=" * title.length
assert_xpath '//h1', render_string(title + "\n" + chars), 0
end
test "document title with single-line syntax" do
assert_xpath "//h1[not(@id)][text() = 'My Title']", render_string("= My Title")
end
test "document title with symmetric syntax" do
assert_xpath "//h1[not(@id)][text() = 'My Title']", render_string("= My Title =")
end
test 'should assign id on document title to body' do
input = <<-EOS
[[idname]]
= Document Title
content
EOS
output = render_string input
assert_css 'body#idname', output, 1
end
test 'should assign id defined using shorthand syntax on document title to body' do
input = <<-EOS
[#idname]
= Document Title
content
EOS
output = render_string input
assert_css 'body#idname', output, 1
end
test 'should use inline id instead of id defined in block attributes' do
input = <<-EOS
[#idname-block]
= Document Title [[idname-inline]]
content
EOS
output = render_string input
assert_css 'body#idname-inline', output, 1
end
test 'block id above document title sets id on document' do
input = <<-EOS
[[reference]]
= Reference Manual
:css-signature: refguide
preamble
EOS
doc = document_from_string input
assert_equal 'reference', doc.id
assert_equal 'refguide', doc.attr('css-signature')
output = doc.render
assert_css 'body#reference', output, 1
end
test 'should discard style, role and options shorthand attributes defined on document title' do
input = <<-EOS
[style#idname.rolename%optionname]
= Document Title
content
EOS
doc = document_from_string input
assert doc.blocks[0].attributes.empty?
output = doc.convert
assert_css 'body#idname', output, 1
assert_css '.rolename', output, 0
end
end
context "level 1" do
test "with multiline syntax" do
assert_xpath "//h2[@id='_my_section'][text() = 'My Section']", render_string("My Section\n-----------")
end
test "heading title with multiline syntax cannot begin with a dot" do
title = ".My Title"
chars = "-" * title.length
assert_xpath '//h2', render_string(title + "\n" + chars), 0
end
test "with single-line syntax" do
assert_xpath "//h2[@id='_my_title'][text() = 'My Title']", render_string("== My Title")
end
test "with single-line symmetric syntax" do
assert_xpath "//h2[@id='_my_title'][text() = 'My Title']", render_string("== My Title ==")
end
test "with single-line non-matching symmetric syntax" do
assert_xpath "//h2[@id='_my_title'][text() = 'My Title ===']", render_string("== My Title ===")
end
test "with XML entity" do
assert_xpath "//h2[@id='_where_s_the_love'][text() = \"Where#{[8217].pack('U*')}s the love?\"]", render_string("== Where's the love?")
end
test "with non-word character" do
assert_xpath "//h2[@id='_where_s_the_love'][text() = \"Where’s the love?\"]", render_string("== Where’s the love?")
end
test "with sequential non-word characters" do
assert_xpath "//h2[@id='_what_the_is_this'][text() = 'What the \#@$ is this?']", render_string('== What the #@$ is this?')
end
test "with trailing whitespace" do
assert_xpath "//h2[@id='_my_title'][text() = 'My Title']", render_string("== My Title ")
end
test "with custom blank idprefix" do
assert_xpath "//h2[@id='my_title'][text() = 'My Title']", render_string(":idprefix:\n\n== My Title ")
end
test "with custom non-blank idprefix" do
assert_xpath "//h2[@id='ref_my_title'][text() = 'My Title']", render_string(":idprefix: ref_\n\n== My Title ")
end
test 'with multibyte characters' do
input = <<-EOS
== Asciidoctor in 中文
EOS
output = render_string input
if ::RUBY_MIN_VERSION_1_9
assert_xpath '//h2[@id="_asciidoctor_in_中文"][text()="Asciidoctor in 中文"]', output
else
assert_xpath '//h2[@id="_asciidoctor_in"][text()="Asciidoctor in 中文"]', output
end
end
test 'with only multibyte characters' do
input = <<-EOS
== 视图
EOS
output = render_embedded_string input
assert_xpath '//h2[@id="_视图"][text()="视图"]', output
end if ::RUBY_MIN_VERSION_1_9
test 'multiline syntax with only multibyte characters' do
input = <<-EOS
视图
--
content
连接器
---
content
EOS
output = render_embedded_string input
assert_xpath '//h2[@id="_视图"][text()="视图"]', output
assert_xpath '//h2[@id="_连接器"][text()="连接器"]', output
end if ::RUBY_MIN_VERSION_1_9
end
context "level 2" do
test "with multiline syntax" do
assert_xpath "//h3[@id='_my_section'][text() = 'My Section']", render_string(":fragment:\nMy Section\n~~~~~~~~~~~")
end
test "with single line syntax" do
assert_xpath "//h3[@id='_my_title'][text() = 'My Title']", render_string(":fragment:\n=== My Title")
end
end
context "level 3" do
test "with multiline syntax" do
assert_xpath "//h4[@id='_my_section'][text() = 'My Section']", render_string(":fragment:\nMy Section\n^^^^^^^^^^")
end
test "with single line syntax" do
assert_xpath "//h4[@id='_my_title'][text() = 'My Title']", render_string(":fragment:\n==== My Title")
end
end
context "level 4" do
test "with multiline syntax" do
assert_xpath "//h5[@id='_my_section'][text() = 'My Section']", render_string(":fragment:\nMy Section\n++++++++++")
end
test "with single line syntax" do
assert_xpath "//h5[@id='_my_title'][text() = 'My Title']", render_string(":fragment:\n===== My Title")
end
end
context "level 5" do
test "with single line syntax" do
assert_xpath "//h6[@id='_my_title'][text() = 'My Title']", render_string(":fragment:\n====== My Title")
end
end
context 'Markdown-style headings' do
test 'single-line document title with leading marker' do
input = <<-EOS
# Document Title
EOS
output = render_string input
assert_xpath "//h1[not(@id)][text() = 'Document Title']", output, 1
end
test 'single-line document title with symmetric markers' do
input = <<-EOS
# Document Title #
EOS
output = render_string input
assert_xpath "//h1[not(@id)][text() = 'Document Title']", output, 1
end
test 'single-line section title with leading marker' do
input = <<-EOS
## Section One
blah blah
EOS
output = render_string input
assert_xpath "//h2[@id='_section_one'][text() = 'Section One']", output, 1
end
test 'single-line section title with symmetric markers' do
input = <<-EOS
## Section One ##
blah blah
EOS
output = render_string input
assert_xpath "//h2[@id='_section_one'][text() = 'Section One']", output, 1
end
end
context 'Floating Title' do
test 'should create floating title if style is float' do
input = <<-EOS
[float]
= Independent Heading!
not in section
EOS
output = render_embedded_string input
assert_xpath '/h1[@id="_independent_heading"]', output, 1
assert_xpath '/h1[@class="float"]', output, 1
assert_xpath %(/h1[@class="float"][text()="Independent Heading!"]), output, 1
assert_xpath '/h1/following-sibling::*[@class="paragraph"]', output, 1
assert_xpath '/h1/following-sibling::*[@class="paragraph"]/p', output, 1
assert_xpath '/h1/following-sibling::*[@class="paragraph"]/p[text()="not in section"]', output, 1
end
test 'should create floating title if style is discrete' do
input = <<-EOS
[discrete]
=== Independent Heading!
not in section
EOS
output = render_embedded_string input
assert_xpath '/h3', output, 1
assert_xpath '/h3[@id="_independent_heading"]', output, 1
assert_xpath '/h3[@class="discrete"]', output, 1
assert_xpath %(/h3[@class="discrete"][text()="Independent Heading!"]), output, 1
assert_xpath '/h3/following-sibling::*[@class="paragraph"]', output, 1
assert_xpath '/h3/following-sibling::*[@class="paragraph"]/p', output, 1
assert_xpath '/h3/following-sibling::*[@class="paragraph"]/p[text()="not in section"]', output, 1
end
test 'should create floating title if style is float with shorthand role and id' do
input = <<-EOS
[float.independent#first]
= Independent Heading!
not in section
EOS
output = render_embedded_string input
assert_xpath '/h1[@id="first"]', output, 1
assert_xpath '/h1[@class="float independent"]', output, 1
assert_xpath %(/h1[@class="float independent"][text()="Independent Heading!"]), output, 1
assert_xpath '/h1/following-sibling::*[@class="paragraph"]', output, 1
assert_xpath '/h1/following-sibling::*[@class="paragraph"]/p', output, 1
assert_xpath '/h1/following-sibling::*[@class="paragraph"]/p[text()="not in section"]', output, 1
end
test 'should create floating title if style is discrete with shorthand role and id' do
input = <<-EOS
[discrete.independent#first]
= Independent Heading!
not in section
EOS
output = render_embedded_string input
assert_xpath '/h1[@id="first"]', output, 1
assert_xpath '/h1[@class="discrete independent"]', output, 1
assert_xpath %(/h1[@class="discrete independent"][text()="Independent Heading!"]), output, 1
assert_xpath '/h1/following-sibling::*[@class="paragraph"]', output, 1
assert_xpath '/h1/following-sibling::*[@class="paragraph"]/p', output, 1
assert_xpath '/h1/following-sibling::*[@class="paragraph"]/p[text()="not in section"]', output, 1
end
test 'floating title should be a block with context floating_title' do
input = <<-EOS
[float]
=== Independent Heading!
not in section
EOS
doc = document_from_string input
floatingtitle = doc.blocks.first
assert floatingtitle.is_a?(Asciidoctor::Block)
assert floatingtitle.context != :section
assert_equal :floating_title, floatingtitle.context
assert_equal '_independent_heading', floatingtitle.id
assert doc.references[:ids].has_key?('_independent_heading')
end
test 'can assign explicit id to floating title' do
input = <<-EOS
[[unchained]]
[float]
=== Independent Heading!
not in section
EOS
doc = document_from_string input
floating_title = doc.blocks.first
assert_equal 'unchained', floating_title.id
assert doc.references[:ids].has_key?('unchained')
end
test 'should not include floating title in toc' do
input = <<-EOS
:toc:
== Section One
[float]
=== Miss Independent
== Section Two
EOS
output = render_string input
assert_xpath '//*[@id="toc"]', output, 1
assert_xpath %(//*[@id="toc"]//a[contains(text(), "Section ")]), output, 2
assert_xpath %(//*[@id="toc"]//a[text()="Miss Independent"]), output, 0
end
test 'should not set id on floating title if sectids attribute is unset' do
input = <<-EOS
[float]
=== Independent Heading!
not in section
EOS
output = render_embedded_string input, :attributes => {'sectids' => nil}
assert_xpath '/h3', output, 1
assert_xpath '/h3[@id="_independent_heading"]', output, 0
assert_xpath '/h3[@class="float"]', output, 1
end
test 'should use explicit id for floating title if specified' do
input = <<-EOS
[[free]]
[float]
== Independent Heading!
not in section
EOS
output = render_embedded_string input
assert_xpath '/h2', output, 1
assert_xpath '/h2[@id="free"]', output, 1
assert_xpath '/h2[@class="float"]', output, 1
end
test 'should add role to class attribute on floating title' do
input = <<-EOS
[float, role="isolated"]
== Independent Heading!
not in section
EOS
output = render_embedded_string input
assert_xpath '/h2', output, 1
assert_xpath '/h2[@id="_independent_heading"]', output, 1
assert_xpath '/h2[@class="float isolated"]', output, 1
end
test 'should use specified id and reftext when registering discrete section reference' do
input = <<-EOS
[[install,Install Procedure]]
[discrete]
== Install
content
EOS
doc = document_from_string input
reftext = doc.references[:ids]['install']
refute_nil reftext
assert_equal 'Install Procedure', reftext
end
test 'should use specified reftext when registering discrete section reference' do
input = <<-EOS
[reftext="Install Procedure"]
[discrete]
== Install
content
EOS
doc = document_from_string input
reftext = doc.references[:ids]['_install']
refute_nil reftext
assert_equal 'Install Procedure', reftext
end
end
context 'Level offset' do
test 'should print error if standalone document is included without level offset' do
input = <<-EOS
= Master Document
Doc Writer
text in master
// begin simulated include::[]
= Standalone Document
:author: Junior Writer
text in standalone
// end simulated include::[]
EOS
output = warnings = nil
redirect_streams do |out, err|
output = render_string input
warnings = err.string
end
assert !warnings.empty?
assert_match(/only book doctypes can contain level 0 sections/, warnings)
end
test 'should add level offset to section level' do
input = <<-EOS
= Master Document
Doc Writer
Master document written by {author}.
:leveloffset: 1
// begin simulated include::[]
= Standalone Document
:author: Junior Writer
Standalone document written by {author}.
== Section in Standalone
Standalone section text.
// end simulated include::[]
:leveloffset!:
== Section in Master
Master section text.
EOS
output = warnings = nil
redirect_streams do |out, err|
output = render_string input
warnings = err.string
end
assert warnings.empty?
assert_match(/Master document written by Doc Writer/, output)
assert_match(/Standalone document written by Junior Writer/, output)
assert_xpath '//*[@class="sect1"]/h2[text() = "Standalone Document"]', output, 1
assert_xpath '//*[@class="sect2"]/h3[text() = "Section in Standalone"]', output, 1
assert_xpath '//*[@class="sect1"]/h2[text() = "Section in Master"]', output, 1
end
test 'level offset should be added to floating title' do
input = <<-EOS
= Master Document
Doc Writer
:leveloffset: 1
[float]
= Floating Title
EOS
output = render_string input
assert_xpath '//h2[@class="float"][text() = "Floating Title"]', output, 1
end
test 'should be able to reset level offset' do
input = <<-EOS
= Master Document
Doc Writer
Master preamble.
:leveloffset: 1
= Standalone Document
Standalone preamble.
:leveloffset!:
== Level 1 Section
EOS
output = render_string input
assert_xpath '//*[@class = "sect1"]/h2[text() = "Standalone Document"]', output, 1
assert_xpath '//*[@class = "sect1"]/h2[text() = "Level 1 Section"]', output, 1
end
test 'should add relative offset value to current leveloffset' do
input = <<-EOS
= Master Document
Doc Writer
Master preamble.
:leveloffset: 1
= Chapter 1
content
:leveloffset: +1
= Standalone Section
content
EOS
output = render_string input
assert_xpath '//*[@class = "sect1"]/h2[text() = "Chapter 1"]', output, 1
assert_xpath '//*[@class = "sect2"]/h3[text() = "Standalone Section"]', output, 1
end
end
context 'Section Numbering' do
test 'should create section number with one entry for level 1' do
sect1 = Asciidoctor::Section.new
assert_equal '1.', sect1.sectnum
end
test 'should create section number with two entries for level 2' do
sect1 = Asciidoctor::Section.new
sect1_1 = Asciidoctor::Section.new(sect1)
sect1 << sect1_1
assert_equal '1.1.', sect1_1.sectnum
end
test 'should create section number with three entries for level 3' do
sect1 = Asciidoctor::Section.new
sect1_1 = Asciidoctor::Section.new(sect1)
sect1 << sect1_1
sect1_1_1 = Asciidoctor::Section.new(sect1_1)
sect1_1 << sect1_1_1
assert_equal '1.1.1.', sect1_1_1.sectnum
end
test 'should create section number for second section in level' do
sect1 = Asciidoctor::Section.new
sect1_1 = Asciidoctor::Section.new(sect1)
sect1 << sect1_1
sect1_2 = Asciidoctor::Section.new(sect1)
sect1 << sect1_2
assert_equal '1.2.', sect1_2.sectnum
end
test 'sectnum should use specified delimiter and append string' do
sect1 = Asciidoctor::Section.new
sect1_1 = Asciidoctor::Section.new(sect1)
sect1 << sect1_1
sect1_1_1 = Asciidoctor::Section.new(sect1_1)
sect1_1 << sect1_1_1
assert_equal '1,1,1,', sect1_1_1.sectnum(',')
assert_equal '1:1:1', sect1_1_1.sectnum(':', false)
end
test 'should render section numbers when sectnums attribute is set' do
input = <<-EOS
= Title
:sectnums:
== Section_1
text
=== Section_1_1
text
==== Section_1_1_1
text
== Section_2
text
=== Section_2_1
text
=== Section_2_2
text
EOS
output = render_string input
assert_xpath '//h2[@id="_section_1"][starts-with(text(), "1. ")]', output, 1
assert_xpath '//h3[@id="_section_1_1"][starts-with(text(), "1.1. ")]', output, 1
assert_xpath '//h4[@id="_section_1_1_1"][starts-with(text(), "1.1.1. ")]', output, 1
assert_xpath '//h2[@id="_section_2"][starts-with(text(), "2. ")]', output, 1
assert_xpath '//h3[@id="_section_2_1"][starts-with(text(), "2.1. ")]', output, 1
assert_xpath '//h3[@id="_section_2_2"][starts-with(text(), "2.2. ")]', output, 1
end
test 'should render section numbers when numbered attribute is set' do
input = <<-EOS
= Title
:numbered:
== Section_1
text
=== Section_1_1
text
==== Section_1_1_1
text
== Section_2
text
=== Section_2_1
text
=== Section_2_2
text
EOS
output = render_string input
assert_xpath '//h2[@id="_section_1"][starts-with(text(), "1. ")]', output, 1
assert_xpath '//h3[@id="_section_1_1"][starts-with(text(), "1.1. ")]', output, 1
assert_xpath '//h4[@id="_section_1_1_1"][starts-with(text(), "1.1.1. ")]', output, 1
assert_xpath '//h2[@id="_section_2"][starts-with(text(), "2. ")]', output, 1
assert_xpath '//h3[@id="_section_2_1"][starts-with(text(), "2.1. ")]', output, 1
assert_xpath '//h3[@id="_section_2_2"][starts-with(text(), "2.2. ")]', output, 1
end
test 'blocks should have level' do
input = <<-EOS
= Title
preamble
== Section 1
paragraph
=== Section 1.1
paragraph
EOS
doc = document_from_string input
assert_equal 0, doc.blocks[0].level
assert_equal 1, doc.blocks[1].level
assert_equal 1, doc.blocks[1].blocks[0].level
assert_equal 2, doc.blocks[1].blocks[1].level
assert_equal 2, doc.blocks[1].blocks[1].blocks[0].level
end
test 'section numbers should not increment when numbered attribute is turned off within document' do
input = <<-EOS
= Document Title
:numbered:
:numbered!:
== Colophon Section
== Another Colophon Section
== Final Colophon Section
:numbered:
== Section One
=== Section One Subsection
== Section Two
== Section Three
EOS
output = render_string input
assert_xpath '//h1[text()="Document Title"]', output, 1
assert_xpath '//h2[@id="_colophon_section"][text()="Colophon Section"]', output, 1
assert_xpath '//h2[@id="_another_colophon_section"][text()="Another Colophon Section"]', output, 1
assert_xpath '//h2[@id="_final_colophon_section"][text()="Final Colophon Section"]', output, 1
assert_xpath '//h2[@id="_section_one"][text()="1. Section One"]', output, 1
assert_xpath '//h3[@id="_section_one_subsection"][text()="1.1. Section One Subsection"]', output, 1
assert_xpath '//h2[@id="_section_two"][text()="2. Section Two"]', output, 1
assert_xpath '//h2[@id="_section_three"][text()="3. Section Three"]', output, 1
end
test 'section numbers can be toggled even if numbered attribute is enable via the API' do
input = <<-EOS
= Document Title
:numbered!:
== Colophon Section
== Another Colophon Section
== Final Colophon Section
:numbered:
== Section One
=== Section One Subsection
== Section Two
== Section Three
EOS
output = render_string input, :attributes => {'numbered' => ''}
assert_xpath '//h1[text()="Document Title"]', output, 1
assert_xpath '//h2[@id="_colophon_section"][text()="Colophon Section"]', output, 1
assert_xpath '//h2[@id="_another_colophon_section"][text()="Another Colophon Section"]', output, 1
assert_xpath '//h2[@id="_final_colophon_section"][text()="Final Colophon Section"]', output, 1
assert_xpath '//h2[@id="_section_one"][text()="1. Section One"]', output, 1
assert_xpath '//h3[@id="_section_one_subsection"][text()="1.1. Section One Subsection"]', output, 1
assert_xpath '//h2[@id="_section_two"][text()="2. Section Two"]', output, 1
assert_xpath '//h2[@id="_section_three"][text()="3. Section Three"]', output, 1
end
test 'section numbers cannot be toggled even if numbered attribute is disabled via the API' do
input = <<-EOS
= Document Title
:numbered!:
== Colophon Section
== Another Colophon Section
== Final Colophon Section
:numbered:
== Section One
=== Section One Subsection
== Section Two
== Section Three
EOS
output = render_string input, :attributes => {'numbered!' => ''}
assert_xpath '//h1[text()="Document Title"]', output, 1
assert_xpath '//h2[@id="_colophon_section"][text()="Colophon Section"]', output, 1
assert_xpath '//h2[@id="_another_colophon_section"][text()="Another Colophon Section"]', output, 1
assert_xpath '//h2[@id="_final_colophon_section"][text()="Final Colophon Section"]', output, 1
assert_xpath '//h2[@id="_section_one"][text()="Section One"]', output, 1
assert_xpath '//h3[@id="_section_one_subsection"][text()="Section One Subsection"]', output, 1
assert_xpath '//h2[@id="_section_two"][text()="Section Two"]', output, 1
assert_xpath '//h2[@id="_section_three"][text()="Section Three"]', output, 1
end
# NOTE AsciiDoc fails this test because it does not properly check for a None value when looking up the numbered attribute
test 'section numbers should not increment until numbered attribute is turned back on' do
input = <<-EOS
= Document Title
:numbered!:
== Colophon Section
== Another Colophon Section
== Final Colophon Section
:numbered:
== Section One
=== Section One Subsection
== Section Two
== Section Three
EOS
output = render_string input
assert_xpath '//h1[text()="Document Title"]', output, 1
assert_xpath '//h2[@id="_colophon_section"][text()="Colophon Section"]', output, 1
assert_xpath '//h2[@id="_another_colophon_section"][text()="Another Colophon Section"]', output, 1
assert_xpath '//h2[@id="_final_colophon_section"][text()="Final Colophon Section"]', output, 1
assert_xpath '//h2[@id="_section_one"][text()="1. Section One"]', output, 1
assert_xpath '//h3[@id="_section_one_subsection"][text()="1.1. Section One Subsection"]', output, 1
assert_xpath '//h2[@id="_section_two"][text()="2. Section Two"]', output, 1
assert_xpath '//h2[@id="_section_three"][text()="3. Section Three"]', output, 1
end
test 'table with asciidoc content should not disable numbering of subsequent sections' do
input = <<-EOS
= Document Title
:numbered:
preamble
== Section One
|===
a|content
|===
== Section Two
content
EOS
output = render_string input
assert_xpath '//h2[@id="_section_one"]', output, 1
assert_xpath '//h2[@id="_section_one"][text()="1. Section One"]', output, 1
assert_xpath '//h2[@id="_section_two"]', output, 1
assert_xpath '//h2[@id="_section_two"][text()="2. Section Two"]', output, 1
end
test 'should not number parts when doctype is book' do
input = <<-EOS
= Document Title
:doctype: book
:numbered:
= Part 1
== Chapter 1
content
= Part 2
== Chapter 2
content
EOS
output = render_string input
assert_xpath '(//h1)[1][text()="Document Title"]', output, 1
assert_xpath '(//h1)[2][text()="Part 1"]', output, 1
assert_xpath '(//h1)[3][text()="Part 2"]', output, 1
assert_xpath '(//h2)[1][text()="1. Chapter 1"]', output, 1
assert_xpath '(//h2)[2][text()="2. Chapter 2"]', output, 1
end
test 'should number chapters sequentially even when divided into parts' do
input = <<-EOS
= Document Title
:doctype: book
:numbered:
== Chapter 1
content
= Part 1
== Chapter 2
content
= Part 2
== Chapter 3
content
== Chapter 4
content
EOS
result = render_string input
(1..4).each do |num|
assert_xpath %(//h2[@id="_chapter_#{num}"]), result, 1
assert_xpath %(//h2[@id="_chapter_#{num}"][text()="#{num}. Chapter #{num}"]), result, 1
end
end
end
context 'Links and anchors' do
test 'should include anchor if sectanchors document attribute is set' do
input = <<-EOS
== Installation
Installation section.
=== Linux
Linux installation instructions.
EOS
output = render_embedded_string input, :attributes => {'sectanchors' => ''}
assert_xpath '/*[@class="sect1"]/h2[@id="_installation"]/a', output, 1
assert_xpath '/*[@class="sect1"]/h2[@id="_installation"]/a[@class="anchor"][@href="#_installation"]', output, 1
assert_xpath '/*[@class="sect1"]/h2[@id="_installation"]/a/following-sibling::text()="Installation"', output, true
assert_xpath '//*[@class="sect2"]/h3[@id="_linux"]/a', output, 1
assert_xpath '//*[@class="sect2"]/h3[@id="_linux"]/a[@class="anchor"][@href="#_linux"]', output, 1
assert_xpath '//*[@class="sect2"]/h3[@id="_linux"]/a/following-sibling::text()="Linux"', output, true
end
test 'should link section if sectlinks document attribute is set' do
input = <<-EOS
== Installation
Installation section.
=== Linux
Linux installation instructions.
EOS
output = render_embedded_string input, :attributes => {'sectlinks' => ''}
assert_xpath '/*[@class="sect1"]/h2[@id="_installation"]/a', output, 1
assert_xpath '/*[@class="sect1"]/h2[@id="_installation"]/a[@class="link"][@href="#_installation"]', output, 1
assert_xpath '/*[@class="sect1"]/h2[@id="_installation"]/a[text()="Installation"]', output, 1
assert_xpath '//*[@class="sect2"]/h3[@id="_linux"]/a', output, 1
assert_xpath '//*[@class="sect2"]/h3[@id="_linux"]/a[@class="link"][@href="#_linux"]', output, 1
assert_xpath '//*[@class="sect2"]/h3[@id="_linux"]/a[text()="Linux"]', output, 1
end
end
context 'Special sections' do
test 'should assign sectname and caption to appendix section' do
input = <<-EOS
[appendix]
== Attribute Options
Details
EOS
output = block_from_string input
assert_equal 'appendix', output.sectname
assert_equal 'Appendix A: ', output.caption
end
test 'should render appendix title prefixed with caption' do
input = <<-EOS
[appendix]
== Attribute Options
Details
EOS
output = render_embedded_string input
assert_xpath '//h2[text()="Appendix A: Attribute Options"]', output, 1
end
test 'should prefix appendix title by label and letter only when numbered is enabled' do
input = <<-EOS
:numbered:
[appendix]
== Attribute Options
Details
EOS
output = render_embedded_string input
assert_xpath '//h2[text()="Appendix A: Attribute Options"]', output, 1
end
test 'should use custom appendix caption if specified' do
input = <<-EOS
:appendix-caption: App
[appendix]
== Attribute Options
Details
EOS
output = render_embedded_string input
assert_xpath '//h2[text()="App A: Attribute Options"]', output, 1
end
test 'should only assign letter to appendix when numbered is enabled and appendix caption is empty' do
input = <<-EOS
:numbered:
:appendix-caption:
[appendix]
== Attribute Options
Details
EOS
output = render_embedded_string input
assert_xpath '//h2[text()="A. Attribute Options"]', output, 1
end
test 'should increment appendix number for each appendix section' do
input = <<-EOS
[appendix]
== Attribute Options
Details
[appendix]
== Migration
Details
EOS
output = render_embedded_string input
assert_xpath '(//h2)[1][text()="Appendix A: Attribute Options"]', output, 1
assert_xpath '(//h2)[2][text()="Appendix B: Migration"]', output, 1
end
test 'should continue numbering after appendix' do
input = <<-EOS
:numbered:
== First Section
content
[appendix]
== Attribute Options
content
== Migration
content
EOS
output = render_embedded_string input
assert_xpath '(//h2)[1][text()="1. First Section"]', output, 1
assert_xpath '(//h2)[2][text()="Appendix A: Attribute Options"]', output, 1
assert_xpath '(//h2)[3][text()="2. Migration"]', output, 1
end
test 'should number appendix subsections using appendix letter' do
input = <<-EOS
:numbered:
[appendix]
== Attribute Options
Details
=== Optional Attributes
Details
EOS
output = render_embedded_string input
assert_xpath '(//h2)[1][text()="Appendix A: Attribute Options"]', output, 1
assert_xpath '(//h3)[1][text()="A.1. Optional Attributes"]', output, 1
end
test 'should not number level 4 section by default' do
input = <<-EOS
:numbered:
== Level_1
=== Level_2
==== Level_3
===== Level_4
text
EOS
output = render_embedded_string input
assert_xpath '//h5', output, 1
assert_xpath '//h5[text()="Level_4"]', output, 1
end
test 'should only number levels up to value defined by sectnumlevels attribute' do
input = <<-EOS
:numbered:
:sectnumlevels: 2
== Level_1
=== Level_2
==== Level_3
===== Level_4
text
EOS
output = render_embedded_string input
assert_xpath '//h2', output, 1
assert_xpath '//h2[text()="1. Level_1"]', output, 1
assert_xpath '//h3', output, 1
assert_xpath '//h3[text()="1.1. Level_2"]', output, 1
assert_xpath '//h4', output, 1
assert_xpath '//h4[text()="Level_3"]', output, 1
assert_xpath '//h5', output, 1
assert_xpath '//h5[text()="Level_4"]', output, 1
end
test 'should not number sections or subsections in regions where numbered is off' do
input = <<-EOS
:numbered:
== Section One
:numbered!:
[appendix]
== Attribute Options
Details
[appendix]
== Migration
Details
=== Gotchas
Details
[glossary]
== Glossary
Terms
EOS
output = render_embedded_string input
assert_xpath '(//h2)[1][text()="1. Section One"]', output, 1
assert_xpath '(//h2)[2][text()="Appendix A: Attribute Options"]', output, 1
assert_xpath '(//h2)[3][text()="Appendix B: Migration"]', output, 1
assert_xpath '(//h3)[1][text()="Gotchas"]', output, 1
assert_xpath '(//h2)[4][text()="Glossary"]', output, 1
end
test 'should not number sections or subsections in toc in regions where numbered is off' do
input = <<-EOS
:numbered:
:toc:
== Section One
:numbered!:
[appendix]
== Attribute Options
Details
[appendix]
== Migration
Details
=== Gotchas
Details
[glossary]
== Glossary
Terms
EOS
output = render_string input
assert_xpath '//*[@id="toc"]/ul//li/a[text()="1. Section One"]', output, 1
assert_xpath '//*[@id="toc"]/ul//li/a[text()="Appendix A: Attribute Options"]', output, 1
assert_xpath '//*[@id="toc"]/ul//li/a[text()="Appendix B: Migration"]', output, 1
assert_xpath '//*[@id="toc"]/ul//li/a[text()="Gotchas"]', output, 1
assert_xpath '//*[@id="toc"]/ul//li/a[text()="Glossary"]', output, 1
end
test 'should only number sections in toc up to value defined by sectnumlevels attribute' do
input = <<-EOS
:numbered:
:toc:
:sectnumlevels: 2
:toclevels: 3
== Level 1
=== Level 2
==== Level 3
EOS
output = render_string input
assert_xpath '//*[@id="toc"]//a[@href="#_level_1"][text()="1. Level 1"]', output, 1
assert_xpath '//*[@id="toc"]//a[@href="#_level_2"][text()="1.1. Level 2"]', output, 1
assert_xpath '//*[@id="toc"]//a[@href="#_level_3"][text()="Level 3"]', output, 1
end
# reenable once we have :specialnumbered!: implemented
=begin
test 'should not number special sections or subsections' do
input = <<-EOS
:numbered:
:specialnumbered!:
== Section One
[appendix]
== Attribute Options
Details
[appendix]
== Migration
Details
=== Gotchas
Details
[glossary]
== Glossary
Terms
EOS
output = render_embedded_string input
assert_xpath '(//h2)[1][text()="1. Section One"]', output, 1
assert_xpath '(//h2)[2][text()="Appendix A: Attribute Options"]', output, 1
assert_xpath '(//h2)[3][text()="Appendix B: Migration"]', output, 1
assert_xpath '(//h3)[1][text()="Gotchas"]', output, 1
assert_xpath '(//h2)[4][text()="Glossary"]', output, 1
end
test 'should not number special sections or subsections in toc' do
input = <<-EOS
:numbered:
:specialnumbered!:
:toc:
== Section One
[appendix]
== Attribute Options
Details
[appendix]
== Migration
Details
=== Gotchas
Details
[glossary]
== Glossary
Terms
EOS
output = render_string input
assert_xpath '//*[@id="toc"]/ul//li/a[text()="1. Section One"]', output, 1
assert_xpath '//*[@id="toc"]/ul//li/a[text()="Appendix A: Attribute Options"]', output, 1
assert_xpath '//*[@id="toc"]/ul//li/a[text()="Appendix B: Migration"]', output, 1
assert_xpath '//*[@id="toc"]/ul//li/a[text()="Gotchas"]', output, 1
assert_xpath '//*[@id="toc"]/ul//li/a[text()="Glossary"]', output, 1
end
=end
test 'level 0 special sections in multipart book should be rendered as level 1' do
input = <<-EOS
= Multipart Book
Doc Writer
:doctype: book
[preface]
= Preface
Preface text
[appendix]
= Appendix
Appendix text
EOS
output = render_string input
assert_xpath '//h2[@id = "_preface"]', output, 1
assert_xpath '//h2[@id = "_appendix"]', output, 1
end
test 'should output docbook elements that coorespond to special sections in book doctype' do
input = <<-EOS
= Multipart Book
:doctype: book
:idprefix:
[abstract]
= Abstract Title
Normal chapter (no abstract in book)
[dedication]
= Dedication Title
Dedication content
[preface]
= Preface Title
Preface content
=== Preface sub-section
Preface subsection content
= Part 1
[partintro]
.Part intro title
Part intro content
== Chapter 1
blah blah
== Chapter 2
blah blah
= Part 2
[partintro]
blah blah
== Chapter 3
blah blah
== Chapter 4
blah blah
[appendix]
= Appendix Title
Appendix content
=== Appendix sub-section
Appendix sub-section content
[bibliography]
= Bibliography Title
Bibliography content
[glossary]
= Glossary Title
Glossary content
[colophon]
= Colophon Title
Colophon content
[index]
= Index Title
EOS
output = render_embedded_string input, :backend => 'docbook45'
assert_xpath '/chapter[@id="abstract_title"]', output, 1
assert_xpath '/chapter[@id="abstract_title"]/title[text()="Abstract Title"]', output, 1
assert_xpath '/chapter/following-sibling::dedication[@id="dedication_title"]', output, 1
assert_xpath '/chapter/following-sibling::dedication[@id="dedication_title"]/title[text()="Dedication Title"]', output, 1
assert_xpath '/dedication/following-sibling::preface[@id="preface_title"]', output, 1
assert_xpath '/dedication/following-sibling::preface[@id="preface_title"]/title[text()="Preface Title"]', output, 1
assert_xpath '/preface/section[@id="preface_sub_section"]', output, 1
assert_xpath '/preface/section[@id="preface_sub_section"]/title[text()="Preface sub-section"]', output, 1
assert_xpath '/preface/following-sibling::part[@id="part_1"]', output, 1
assert_xpath '/preface/following-sibling::part[@id="part_1"]/title[text()="Part 1"]', output, 1
assert_xpath '/part[@id="part_1"]/partintro', output, 1
assert_xpath '/part[@id="part_1"]/partintro/title[text()="Part intro title"]', output, 1
assert_xpath '/part[@id="part_1"]/partintro/following-sibling::chapter[@id="chapter_1"]', output, 1
assert_xpath '/part[@id="part_1"]/partintro/following-sibling::chapter[@id="chapter_1"]/title[text()="Chapter 1"]', output, 1
assert_xpath '(/part)[2]/following-sibling::appendix[@id="appendix_title"]', output, 1
assert_xpath '(/part)[2]/following-sibling::appendix[@id="appendix_title"]/title[text()="Appendix Title"]', output, 1
assert_xpath '/appendix/section[@id="appendix_sub_section"]', output, 1
assert_xpath '/appendix/section[@id="appendix_sub_section"]/title[text()="Appendix sub-section"]', output, 1
assert_xpath '/appendix/following-sibling::bibliography[@id="bibliography_title"]', output, 1
assert_xpath '/appendix/following-sibling::bibliography[@id="bibliography_title"]/title[text()="Bibliography Title"]', output, 1
assert_xpath '/bibliography/following-sibling::glossary[@id="glossary_title"]', output, 1
assert_xpath '/bibliography/following-sibling::glossary[@id="glossary_title"]/title[text()="Glossary Title"]', output, 1
assert_xpath '/glossary/following-sibling::colophon[@id="colophon_title"]', output, 1
assert_xpath '/glossary/following-sibling::colophon[@id="colophon_title"]/title[text()="Colophon Title"]', output, 1
assert_xpath '/colophon/following-sibling::index[@id="index_title"]', output, 1
assert_xpath '/colophon/following-sibling::index[@id="index_title"]/title[text()="Index Title"]', output, 1
end
test 'abstract section maps to abstract element in docbook for article doctype' do
input = <<-EOS
= Article
:idprefix:
[abstract]
== Abstract Title
Abstract content
EOS
output = render_embedded_string input, :backend => 'docbook45'
assert_xpath '/abstract[@id="abstract_title"]', output, 1
assert_xpath '/abstract[@id="abstract_title"]/title[text()="Abstract Title"]', output, 1
end
test 'should allow a special section to be nested at arbitrary depth in DocBook output' do
input = <<-EOS
= Document Title
:doctype: book
== Glossaries
[glossary]
=== Glossary A
Glossaries are optional.
Glossaries entries are an example of a style of AsciiDoc labeled lists.
[glossary]
A glossary term::
The corresponding definition.
A second glossary term::
The corresponding definition.
EOS
output = render_string input, :backend => :docbook
assert_xpath '//glossary', output, 1
assert_xpath '//chapter/glossary', output, 1
assert_xpath '//glossary/title[text()="Glossary A"]', output, 1
assert_xpath '//glossary/glossentry', output, 2
end
end
context "heading patterns in blocks" do
test "should not interpret a listing block as a heading" do
input = <<-EOS
Section
-------
----
code
----
fin.
EOS
output = render_string input
assert_xpath "//h2", output, 1
end
test "should not interpret an open block as a heading" do
input = <<-EOS
Section
-------
--
ha
--
fin.
EOS
output = render_string input
assert_xpath "//h2", output, 1
end
test "should not interpret an attribute list as a heading" do
input = <<-EOS
Section
=======
preamble
[TIP]
====
This should be a tip, not a heading.
====
EOS
output = render_string input
assert_xpath "//*[@class='admonitionblock tip']//p[text() = 'This should be a tip, not a heading.']", output, 1
end
test "should not match a heading in a labeled list" do
input = <<-EOS
Section
-------
term1::
+
----
list = [1, 2, 3];
----
term2::
== not a heading
term3:: def
//
fin.
EOS
output = render_string input
assert_xpath "//h2", output, 1
assert_xpath "//dl", output, 1
end
test "should not match a heading in a bulleted list" do
input = <<-EOS
Section
-------
* first
+
----
list = [1, 2, 3];
----
+
* second
== not a heading
* third
fin.
EOS
output = render_string input
assert_xpath "//h2", output, 1
assert_xpath "//ul", output, 1
end
test "should not match a heading in a block" do
input = <<-EOS
====
== not a heading
====
EOS
output = render_string input
assert_xpath "//h2", output, 0
assert_xpath "//*[@class='exampleblock']//p[text() = '== not a heading']", output, 1
end
end
context 'Table of Contents' do
test 'should render unnumbered table of contents in header if toc attribute is set' do
input = <<-EOS
= Article
:toc:
== Section One
It was a dark and stormy night...
== Section Two
They couldn't believe their eyes when...
=== Interlude
While they were waiting...
== Section Three
That's all she wrote!
EOS
output = render_string input
assert_xpath '//*[@id="header"]//*[@id="toc"][@class="toc"]', output, 1
assert_xpath '//*[@id="header"]//*[@id="toc"]/*[@id="toctitle"][text()="Table of Contents"]', output, 1
assert_xpath '//*[@id="header"]//*[@id="toc"]/ul', output, 1
assert_xpath '//*[@id="header"]//*[@id="toc"]/ul[@class="sectlevel1"]', output, 1
assert_xpath '//*[@id="header"]//*[@id="toc"]//ul', output, 2
assert_xpath '//*[@id="header"]//*[@id="toc"]//li', output, 4
assert_xpath '//*[@id="header"]//*[@id="toc"]/ul/li[1]/a[@href="#_section_one"][text()="Section One"]', output, 1
assert_xpath '//*[@id="header"]//*[@id="toc"]/ul/li/ul', output, 1
assert_xpath '//*[@id="header"]//*[@id="toc"]/ul/li/ul[@class="sectlevel2"]', output, 1
assert_xpath '//*[@id="header"]//*[@id="toc"]/ul/li/ul/li', output, 1
assert_xpath '//*[@id="header"]//*[@id="toc"]/ul/li/ul/li/a[@href="#_interlude"][text()="Interlude"]', output, 1
assert_xpath '((//*[@id="header"]//*[@id="toc"]/ul)[1]/li)[3]/a[@href="#_section_three"][text()="Section Three"]', output, 1
end
test 'should render numbered table of contents in header if toc and numbered attributes are set' do
input = <<-EOS
= Article
:toc:
:numbered:
== Section One
It was a dark and stormy night...
== Section Two
They couldn't believe their eyes when...
=== Interlude
While they were waiting...
== Section Three
That's all she wrote!
EOS
output = render_string input
assert_xpath '//*[@id="header"]//*[@id="toc"][@class="toc"]', output, 1
assert_xpath '//*[@id="header"]//*[@id="toc"]/*[@id="toctitle"][text()="Table of Contents"]', output, 1
assert_xpath '//*[@id="header"]//*[@id="toc"]/ul', output, 1
assert_xpath '//*[@id="header"]//*[@id="toc"]//ul', output, 2
assert_xpath '//*[@id="header"]//*[@id="toc"]//li', output, 4
assert_xpath '//*[@id="header"]//*[@id="toc"]/ul/li[1]/a[@href="#_section_one"][text()="1. Section One"]', output, 1
assert_xpath '//*[@id="header"]//*[@id="toc"]/ul/li/ul/li', output, 1
assert_xpath '//*[@id="header"]//*[@id="toc"]/ul/li/ul/li/a[@href="#_interlude"][text()="2.1. Interlude"]', output, 1
assert_xpath '((//*[@id="header"]//*[@id="toc"]/ul)[1]/li)[3]/a[@href="#_section_three"][text()="3. Section Three"]', output, 1
end
test 'should render a table of contents that honors numbered setting at position of section in document' do
input = <<-EOS
= Article
:toc:
:numbered:
== Section One
It was a dark and stormy night...
== Section Two
They couldn't believe their eyes when...
=== Interlude
While they were waiting...
:numbered!:
== Section Three
That's all she wrote!
EOS
output = render_string input
assert_xpath '//*[@id="header"]//*[@id="toc"][@class="toc"]', output, 1
assert_xpath '//*[@id="header"]//*[@id="toc"]/*[@id="toctitle"][text()="Table of Contents"]', output, 1
assert_xpath '//*[@id="header"]//*[@id="toc"]/ul', output, 1
assert_xpath '//*[@id="header"]//*[@id="toc"]//ul', output, 2
assert_xpath '//*[@id="header"]//*[@id="toc"]//li', output, 4
assert_xpath '//*[@id="header"]//*[@id="toc"]/ul/li[1]/a[@href="#_section_one"][text()="1. Section One"]', output, 1
assert_xpath '((//*[@id="header"]//*[@id="toc"]/ul)[1]/li)[3]/a[@href="#_section_three"][text()="Section Three"]', output, 1
end
test 'should not number parts in table of contents for book doctype when numbered attribute is set' do
input = <<-EOS
= Book
:doctype: book
:toc:
:numbered:
= Part 1
== First Section of Part 1
blah
== Second Section of Part 1
blah
= Part 2
== First Section of Part 2
blah
EOS
output = render_string input
assert_xpath '//*[@id="toc"]', output, 1
assert_xpath '//*[@id="toc"]/ul', output, 1
assert_xpath '//*[@id="toc"]/ul[@class="sectlevel0"]', output, 1
assert_xpath '//*[@id="toc"]/ul[@class="sectlevel0"]/li', output, 2
assert_xpath '(//*[@id="toc"]/ul[@class="sectlevel0"]/li)[1]/a[text()="Part 1"]', output, 1
assert_xpath '(//*[@id="toc"]/ul[@class="sectlevel0"]/li)[2]/a[text()="Part 2"]', output, 1
assert_xpath '(//*[@id="toc"]/ul[@class="sectlevel0"]/li)[1]/ul', output, 1
assert_xpath '(//*[@id="toc"]/ul[@class="sectlevel0"]/li)[1]/ul[@class="sectlevel1"]', output, 1
assert_xpath '(//*[@id="toc"]/ul[@class="sectlevel0"]/li)[1]/ul/li', output, 2
assert_xpath '((//*[@id="toc"]/ul[@class="sectlevel0"]/li)[1]/ul/li)[1]/a[text()="1. First Section of Part 1"]', output, 1
end
test 'should render table of contents in header if toc2 attribute is set' do
input = <<-EOS
= Article
:toc2:
:numbered:
== Section One
It was a dark and stormy night...
== Section Two
They couldn't believe their eyes when...
EOS
output = render_string input
assert_xpath '//body[@class="article toc2 toc-left"]', output, 1
assert_xpath '//*[@id="header"]//*[@id="toc"][@class="toc2"]', output, 1
assert_xpath '//*[@id="header"]//*[@id="toc"]/ul/li[1]/a[@href="#_section_one"][text()="1. Section One"]', output, 1
end
test 'should set toc position if toc attribute is set to position' do
input = <<-EOS
= Article
:toc: >
:numbered:
== Section One
It was a dark and stormy night...
== Section Two
They couldn't believe their eyes when...
EOS
output = render_string input
assert_xpath '//body[@class="article toc2 toc-right"]', output, 1
assert_xpath '//*[@id="header"]//*[@id="toc"][@class="toc2"]', output, 1
assert_xpath '//*[@id="header"]//*[@id="toc"]/ul/li[1]/a[@href="#_section_one"][text()="1. Section One"]', output, 1
end
test 'should set toc position if toc and toc-position attributes are set' do
input = <<-EOS
= Article
:toc:
:toc-position: right
:numbered:
== Section One
It was a dark and stormy night...
== Section Two
They couldn't believe their eyes when...
EOS
output = render_string input
assert_xpath '//body[@class="article toc2 toc-right"]', output, 1
assert_xpath '//*[@id="header"]//*[@id="toc"][@class="toc2"]', output, 1
assert_xpath '//*[@id="header"]//*[@id="toc"]/ul/li[1]/a[@href="#_section_one"][text()="1. Section One"]', output, 1
end
test 'should set toc position if toc2 and toc-position attribute are set' do
input = <<-EOS
= Article
:toc2:
:toc-position: right
:numbered:
== Section One
It was a dark and stormy night...
== Section Two
They couldn't believe their eyes when...
EOS
output = render_string input
assert_xpath '//body[@class="article toc2 toc-right"]', output, 1
assert_xpath '//*[@id="header"]//*[@id="toc"][@class="toc2"]', output, 1
assert_xpath '//*[@id="header"]//*[@id="toc"]/ul/li[1]/a[@href="#_section_one"][text()="1. Section One"]', output, 1
end
test 'should set toc position if toc attribute is set to direction' do
input = <<-EOS
= Article
:toc: right
:numbered:
== Section One
It was a dark and stormy night...
== Section Two
They couldn't believe their eyes when...
EOS
output = render_string input
assert_xpath '//body[@class="article toc2 toc-right"]', output, 1
assert_xpath '//*[@id="header"]//*[@id="toc"][@class="toc2"]', output, 1
assert_xpath '//*[@id="header"]//*[@id="toc"]/ul/li[1]/a[@href="#_section_one"][text()="1. Section One"]', output, 1
end
test 'should set toc placement to preamble if toc attribute is set to preamble' do
input = <<-EOS
= Article
:toc: preamble
Yada yada
== Section One
It was a dark and stormy night...
== Section Two
They couldn't believe their eyes when...
EOS
output = render_string input
assert_css '#preamble #toc', output, 1
assert_css '#preamble .sectionbody + #toc', output, 1
end
test 'should use document attributes toc-class, toc-title and toclevels to create toc' do
input = <<-EOS
= Article
:toc:
:toc-title: Contents
:toc-class: toc2
:toclevels: 1
== Section 1
=== Section 1.1
==== Section 1.1.1
==== Section 1.1.2
=== Section 1.2
== Section 2
Fin.
EOS
output = render_string input
assert_css '#header #toc', output, 1
assert_css '#header #toc.toc2', output, 1
assert_css '#header #toc li', output, 2
assert_css '#header #toc #toctitle', output, 1
assert_xpath '//*[@id="header"]//*[@id="toc"]/*[@id="toctitle"][text()="Contents"]', output, 1
end
test 'should not render table of contents if toc-placement attribute is unset' do
input = <<-EOS
= Article
:toc:
:toc-placement!:
== Section One
It was a dark and stormy night...
== Section Two
They couldn't believe their eyes when...
EOS
output = render_string input
assert_xpath '//*[@id="toc"]', output, 0
end
test 'should render table of contents at location of toc macro' do
input = <<-EOS
= Article
:toc:
:toc-placement: macro
Once upon a time...
toc::[]
== Section One
It was a dark and stormy night...
== Section Two
They couldn't believe their eyes when...
EOS
output = render_string input
assert_css '#preamble #toc', output, 1
assert_css '#preamble .paragraph + #toc', output, 1
end
test 'should render table of contents at location of toc macro in embedded document' do
input = <<-EOS
= Article
:toc:
:toc-placement: macro
Once upon a time...
toc::[]
== Section One
It was a dark and stormy night...
== Section Two
They couldn't believe their eyes when...
EOS
output = render_string input, :header_footer => false
assert_css '#preamble:root #toc', output, 1
assert_css '#preamble:root .paragraph + #toc', output, 1
end
test 'should render table of contents at default location in embedded document if toc attribute is set' do
input = <<-EOS
= Article
:showtitle:
:toc:
Once upon a time...
== Section One
It was a dark and stormy night...
== Section Two
They couldn't believe their eyes when...
EOS
output = render_string input, :header_footer => false
assert_css 'h1:root', output, 1
assert_css 'h1:root + #toc:root', output, 1
assert_css 'h1:root + #toc:root + #preamble:root', output, 1
end
test 'should not activate toc macro if toc-placement is not set' do
input = <<-EOS
= Article
:toc:
Once upon a time...
toc::[]
== Section One
It was a dark and stormy night...
== Section Two
They couldn't believe their eyes when...
EOS
output = render_string input
assert_css '#toc', output, 1
assert_css '#toctitle', output, 1
assert_css '.toc', output, 1
assert_css '#content .toc', output, 0
end
test 'should only output toc at toc macro if toc is macro' do
input = <<-EOS
= Article
:toc: macro
Once upon a time...
toc::[]
== Section One
It was a dark and stormy night...
== Section Two
They couldn't believe their eyes when...
EOS
output = render_string input
assert_css '#toc', output, 1
assert_css '#toctitle', output, 1
assert_css '.toc', output, 1
assert_css '#content .toc', output, 1
end
test 'should use global attributes for toc-title, toc-class and toclevels for toc macro' do
input = <<-EOS
= Article
:toc:
:toc-placement: macro
:toc-title: Contents
:toc-class: contents
:toclevels: 1
Preamble.
toc::[]
== Section 1
=== Section 1.1
==== Section 1.1.1
==== Section 1.1.2
=== Section 1.2
== Section 2
Fin.
EOS
output = render_string input
assert_css '#toc', output, 1
assert_css '#toctitle', output, 1
assert_css '#preamble #toc', output, 1
assert_css '#preamble #toc.contents', output, 1
assert_xpath '//*[@id="toc"]/*[@class="title"][text() = "Contents"]', output, 1
assert_css '#toc li', output, 2
assert_xpath '(//*[@id="toc"]//li)[1]/a[text() = "Section 1"]', output, 1
assert_xpath '(//*[@id="toc"]//li)[2]/a[text() = "Section 2"]', output, 1
end
test 'should honor id, title, role and level attributes on toc macro' do
input = <<-EOS
= Article
:toc:
:toc-placement: macro
:toc-title: Ignored
:toc-class: ignored
:toclevels: 5
:tocdepth: 1
Preamble.
[[contents]]
[role="contents"]
.Contents
toc::[levels={tocdepth}]
== Section 1
=== Section 1.1
==== Section 1.1.1
==== Section 1.1.2
=== Section 1.2
== Section 2
Fin.
EOS
output = render_string input
assert_css '#toc', output, 0
assert_css '#toctitle', output, 0
assert_css '#preamble #contents', output, 1
assert_css '#preamble #contents.contents', output, 1
assert_xpath '//*[@id="contents"]/*[@class="title"][text() = "Contents"]', output, 1
assert_css '#contents li', output, 2
assert_xpath '(//*[@id="contents"]//li)[1]/a[text() = "Section 1"]', output, 1
assert_xpath '(//*[@id="contents"]//li)[2]/a[text() = "Section 2"]', output, 1
end
test 'child toc levels should not have additional bullet at parent level in html' do
input = <<-EOS
= Article
:toc:
== Section One
It was a dark and stormy night...
== Section Two
They couldn't believe their eyes when...
=== Interlude
While they were waiting...
== Section Three
That's all she wrote!
EOS
output = render_string input
assert_xpath '//*[@id="header"]//*[@id="toc"][@class="toc"]', output, 1
assert_xpath '//*[@id="header"]//*[@id="toc"]/*[@id="toctitle"][text()="Table of Contents"]', output, 1
assert_xpath '//*[@id="header"]//*[@id="toc"]/ul', output, 1
assert_xpath '//*[@id="header"]//*[@id="toc"]//ul', output, 2
assert_xpath '//*[@id="header"]//*[@id="toc"]//li', output, 4
assert_xpath '//*[@id="header"]//*[@id="toc"]/ul/li[2]/a[@href="#_section_two"][text()="Section Two"]', output, 1
assert_xpath '//*[@id="header"]//*[@id="toc"]/ul/li/ul/li', output, 1
assert_xpath '//*[@id="header"]//*[@id="toc"]/ul/li[2]/ul/li', output, 1
assert_xpath '//*[@id="header"]//*[@id="toc"]/ul/li/ul/li/a[@href="#_interlude"][text()="Interlude"]', output, 1
assert_xpath '((//*[@id="header"]//*[@id="toc"]/ul)[1]/li)[3]/a[@href="#_section_three"][text()="Section Three"]', output, 1
end
test 'should not display a table of contents if document has no sections' do
input_src = <<-EOS
= Document Title
:toc:
toc::[]
This document has no sections.
It only has content.
EOS
['', 'left', 'preamble', 'macro'].each do |placement|
input = input_src.gsub(':toc:', "\\& #{placement}")
output = render_string input
assert_css '#toctitle', output, 0
end
end
end
context 'article doctype' do
test 'should create sections only in docbook backend' do
input = <<-EOS
= Article
Doc Writer
== Section 1
The adventure.
=== Subsection One
It was a dark and stormy night...
=== Subsection Two
They couldn't believe their eyes when...
== Section 2
The return.
=== Subsection Three
While they were returning...
=== Subsection Four
That's all she wrote!
EOS
output = render_string input, :backend => 'docbook'
assert_xpath '//part', output, 0
assert_xpath '//chapter', output, 0
assert_xpath '/article/section', output, 2
assert_xpath '/article/section[1]/title[text() = "Section 1"]', output, 1
assert_xpath '/article/section[2]/title[text() = "Section 2"]', output, 1
assert_xpath '/article/section/section', output, 4
assert_xpath '/article/section[1]/section[1]/title[text() = "Subsection One"]', output, 1
assert_xpath '/article/section[2]/section[1]/title[text() = "Subsection Three"]', output, 1
end
end
context 'book doctype' do
test 'document title with level 0 headings' do
input = <<-EOS
= Book
Doc Writer
:doctype: book
= Chapter One
[partintro]
It was a dark and stormy night...
== Scene One
Someone's gonna get axed.
= Chapter Two
[partintro]
They couldn't believe their eyes when...
== Interlude
While they were waiting...
= Chapter Three
== Scene One
That's all she wrote!
EOS
output = render_string(input)
assert_css 'body.book', output, 1
assert_css 'h1', output, 4
assert_css '#header h1', output, 1
assert_css '#content h1', output, 3
assert_css '#content h1.sect0', output, 3
assert_css 'h2', output, 3
assert_css '#content h2', output, 3
assert_xpath '//h1[@id="_chapter_one"][text() = "Chapter One"]', output, 1
assert_xpath '//h1[@id="_chapter_two"][text() = "Chapter Two"]', output, 1
assert_xpath '//h1[@id="_chapter_three"][text() = "Chapter Three"]', output, 1
end
test 'should add partintro style to child paragraph of part' do
input = <<-EOS
= Book
:doctype: book
= Part 1
part intro
== Chapter 1
EOS
doc = document_from_string input
partintro = doc.blocks.first.blocks.first
assert_equal :open, partintro.context
assert_equal 'partintro', partintro.style
end
test 'should add partintro style to child open block of part' do
input = <<-EOS
= Book
:doctype: book
= Part 1
--
part intro
--
== Chapter 1
EOS
doc = document_from_string input
partintro = doc.blocks.first.blocks.first
assert_equal :open, partintro.context
assert_equal 'partintro', partintro.style
end
test 'should wrap child paragraphs of part in partintro open block' do
input = <<-EOS
= Book
:doctype: book
= Part 1
part intro
more part intro
== Chapter 1
EOS
doc = document_from_string input
partintro = doc.blocks.first.blocks.first
assert_equal :open, partintro.context
assert_equal 'partintro', partintro.style
assert_equal 2, partintro.blocks.size
assert_equal :paragraph, partintro.blocks[0].context
assert_equal :paragraph, partintro.blocks[1].context
end
test 'should warn if part has no sections' do
input = <<-EOS
= Book
:doctype: book
= Part 1
[partintro]
intro
EOS
doc = warnings = nil
redirect_streams do |out, err|
doc = document_from_string input
warnings = err.string
end
refute_nil warnings
assert !warnings.empty?
assert_match(/ERROR:.*section/, warnings)
end
test 'should create parts and chapters in docbook backend' do
input = <<-EOS
= Book
Doc Writer
:doctype: book
= Part 1
[partintro]
The adventure.
== Chapter One
It was a dark and stormy night...
== Chapter Two
They couldn't believe their eyes when...
= Part 2
[partintro]
The return.
== Chapter Three
While they were returning...
== Chapter Four
That's all she wrote!
EOS
output = render_string input, :backend => 'docbook'
assert_xpath '//chapter/chapter', output, 0
assert_xpath '/book/part', output, 2
assert_xpath '/book/part[1]/title[text() = "Part 1"]', output, 1
assert_xpath '/book/part[2]/title[text() = "Part 2"]', output, 1
assert_xpath '/book/part/chapter', output, 4
assert_xpath '/book/part[1]/chapter[1]/title[text() = "Chapter One"]', output, 1
assert_xpath '/book/part[2]/chapter[1]/title[text() = "Chapter Three"]', output, 1
end
test 'subsections in preface and appendix should start at level 2' do
input = <<-EOS
= Multipart Book
Doc Writer
:doctype: book
[preface]
= Preface
Preface content
=== Preface subsection
Preface subsection content
= Part 1
.Part intro title
[partintro]
Part intro content
== Chapter 1
content
[appendix]
= Appendix
Appendix content
=== Appendix subsection
Appendix subsection content
EOS
output = warnings = nil
redirect_streams do |out, err|
output = render_string input, :backend => 'docbook'
warnings = err.string
end
assert warnings.empty?
assert_xpath '/book/preface', output, 1
assert_xpath '/book/preface/section', output, 1
assert_xpath '/book/part', output, 1
assert_xpath '/book/part/partintro', output, 1
assert_xpath '/book/part/partintro/title', output, 1
assert_xpath '/book/part/partintro/simpara', output, 1
assert_xpath '/book/appendix', output, 1
assert_xpath '/book/appendix/section', output, 1
end
end
end