# frozen_string_literal: true

require 'care_admonition/extension'
require 'change_admonition/extension'
require 'docbook_compat/extension'
require 'fileutils'
require 'tmpdir'

RSpec.describe DocbookCompat do
  before(:each) do
    Asciidoctor::Extensions.register DocbookCompat
  end

  after(:each) do
    Asciidoctor::Extensions.unregister_all
  end

  include_context 'convert without logs'

  context 'the header and footer' do
    let(:standalone) { true }
    let(:convert_attributes) do
      {
        # Shrink the output slightly so it is easier to read
        'stylesheet!' => false,
        # Set some metadata that will be included in the header
        'dc.type' => 'FooType',
        'dc.subject' => 'BarSubject',
        'dc.identifier' => 'BazIdentifier',
        'docdir' => '/doc/observability-docs/docs/en/observability',
      }
    end
    let(:input) do
      <<~ASCIIDOC
        = Title

        Words.
      ASCIIDOC
    end
    it 'ends in a single newline' do
      expect(converted).to end_with("\n")
      expect(converted).not_to end_with("\n\n")
    end
    it 'has an empty html tag' do
      expect(converted).to include('<html>')
    end
    it "doesn't declare edge compatibility" do
      expect(converted).not_to include('content="IE=edge"')
    end
    it "doesn't declare a viewport" do
      expect(converted).not_to include('name="viewport"')
    end
    it "doesn't declare a generator" do
      expect(converted).not_to include('name="generator"')
    end
    it 'has an elastic meta product_name tag' do
      expect(converted).to include(<<~HTML)
        <meta class="elastic" name="product_name" content="BarSubject"/>
      HTML
    end
    it 'has an elastic meta product_version tag' do
      expect(converted).to include(<<~HTML)
        <meta class="elastic" name="product_version" content="BazIdentifier"/>
      HTML
    end
    it 'has an elastic meta website_area tag' do
      expect(converted).to include(<<~HTML)
        <meta class="elastic" name="website_area" content="documentation"/>
      HTML
    end
    it 'has DC.type' do
      expect(converted).to include(<<~HTML)
        <meta name="DC.type" content="FooType"/>
      HTML
    end
    it 'has DC.subject' do
      expect(converted).to include(<<~HTML)
        <meta name="DC.subject" content="BarSubject"/>
      HTML
    end
    it 'has DC.identifier' do
      expect(converted).to include(<<~HTML)
        <meta name="DC.identifier" content="BazIdentifier"/>
      HTML
    end
    it "doesn't contain a directive to not follow or index the page" do
      expect(converted).not_to include(
        '<meta name="robots" content="noindex,nofollow"/>'
      )
    end
    context 'the title' do
      it 'includes Elastic' do
        expect(converted).to include(<<~HTML)
          <title>Title | Elastic</title>
          <meta class="elastic" name="content" content="Title">
        HTML
      end
    end
    context 'the body' do
      it "doesn't have attributes" do
        expect(converted).to include('<body>')
      end
      it 'is immediately followed by wrappers' do
        expect(converted).to include(<<~HTML)
          <body>
          <div class="book" lang="en">
        HTML
      end
    end
    context 'the header' do
      it "is wrapped in docbook's funny titlepage" do
        expect(converted).to include(<<~HTML)
          <div class="titlepage">
          <div id="breadcrumbs-go-here"></div>
          <div>
          <div><h1 class="title"><a id="id-1"></a>Title</h1></div>
          </div>
        HTML
      end
    end
    context 'when there is an id on the title' do
      let(:input) do
        <<~ASCIIDOC
          [[title-id]]
          = Title

          Words.
        ASCIIDOC
      end
      context 'the header' do
        it "is wrapped in docbook's funny titlepage" do
          expect(converted).to include(<<~HTML)
            <div class="titlepage">
            <div id="breadcrumbs-go-here"></div>
            <div>
            <div><h1 class="title"><a id="title-id"></a>Title</h1></div>
            </div>
          HTML
        end
      end
    end
    context 'when there is a table of contents' do
      let(:convert_attributes) do
        {
          # Shrink the output slightly so it is easier to read
          'stylesheet!' => false,
          # Set some metadata that will be included in the header
          'dc.type' => 'FooType',
          'dc.subject' => 'BarSubject',
          'dc.identifier' => 'BazIdentifier',
          'toc' => '',
          'toclevels' => 1,
        }
      end
      let(:input) do
        <<~ASCIIDOC
          = Title

          == Section 1

          == Section 2
        ASCIIDOC
      end
      context 'the header' do
        it "is wrapped in docbook's funny titlepage" do
          expect(converted).to include(<<~HTML)
            <div class="titlepage">
            <div id="breadcrumbs-go-here"></div>
            <div>
            <div><h1 class="title"><a id="id-1"></a>Title</h1></div>
            </div>
            <!--EXTRA-->
          HTML
        end
      end
      context 'the table of contents' do
        it 'is outside the titlepage' do
          expect(converted).to include(<<~HTML)
            <!--EXTRA-->
            </div>
            <div id="content">
            <!--START_TOC-->
            <div class="toc">
          HTML
        end
        it 'looks like the docbook toc' do
          expect(converted).to include(<<~HTML)
            <!--START_TOC-->
            <div class="toc">
            <ul class="toc">
            <li><span class="chapter"><a href="#_section_1">Section 1</a></span>
            </li>
            <li><span class="chapter"><a href="#_section_2">Section 2</a></span>
            </li>
            </ul>
            </div>
            <!--END_TOC-->
          HTML
        end
      end
      context 'when there is a level 0 section' do
        let(:input) do
          <<~ASCIIDOC
            = Title

            = Part 1

            == Section 1

            == Section 2
          ASCIIDOC
        end
        context 'the table of contents' do
          it 'looks like the docbook toc' do
            expect(converted).to include(<<~HTML)
              <!--START_TOC-->
              <div class="toc">
              <ul class="toc">
              <li><span class="part"><a href="#_part_1">Part 1</a></span>
              <ul>
              <li><span class="chapter"><a href="#_section_1">Section 1</a></span>
              </li>
              <li><span class="chapter"><a href="#_section_2">Section 2</a></span>
              </li>
              </ul>
              </li>
              </ul>
              </div>
              <!--END_TOC-->
            HTML
          end
        end
      end
      context 'when a section has role=exclude' do
        let(:input) do
          <<~ASCIIDOC
            = Title

            == Section 1

            [.exclude]
            == Section 2
          ASCIIDOC
        end
        context 'the table of contents' do
          it "doesn't include the excluded section" do
            expect(converted).to include(<<~HTML)
              <!--START_TOC-->
              <div class="toc">
              <ul class="toc">
              <li><span class="chapter"><a href="#_section_1">Section 1</a></span>
              </li>
              </ul>
              </div>
              <!--END_TOC-->
            HTML
          end
        end
      end
      context 'when a section has reftext' do
        let(:convert_attributes) do
          {
            # Shrink the output slightly so it is easier to read
            'stylesheet!' => false,
            # Set some metadata that will be included in the header
            'dc.type' => 'FooType',
            'dc.subject' => 'BarSubject',
            'dc.identifier' => 'BazIdentifier',
            'toc' => '',
            'toclevels' => 2,
          }
        end
        shared_examples 'reftext' do
          context 'the table of contents' do
            it 'includes the abbreviated title' do
              expect(converted).to include <<~HTML
                <li><span class="chapter"><a href="#s1">S1</a></span>
              HTML
            end
            it 'includes the correct title for a subsection' do
              expect(converted).to include <<~HTML
                <li><span class="section"><a href="#_section_2">Section 2</a></span>
              HTML
            end
          end
          context 'the body' do
            it "doesn't include the titleabbrev tag" do
              expect(converted).not_to include '<titleabbrev>'
            end
            it 'includes the unabbreviated title' do
              expect(converted).to include 'Section 1</h2>'
            end
            it 'includes a link to the abbreviated section' do
              expect(converted).to include <<~HTML.strip
                <a class="xref" href="#s1" title="Section 1"><em>S1</em></a>
              HTML
            end
          end
        end
        context 'using a pass block containing titleabbrev' do
          let(:input) do
            <<~ASCIIDOC
              = Title

              [[s1]]
              == Section 1
              ++++
              <titleabbrev>S1</titleabbrev>
              ++++

              === Section 2

              <<s1>>
            ASCIIDOC
          end
          include_examples 'reftext'
          context 'when the titleabbrev contains an attribute' do
            let(:input) do
              <<~ASCIIDOC
                = Title

                :abbrev: S1
                [[s1]]
                == Section 1
                ++++
                <titleabbrev>{abbrev}</titleabbrev>
                ++++

                === Section 2

                <<s1>>
              ASCIIDOC
            end
            include_examples 'reftext'
          end
        end
        context 'using an attribute' do
          let(:input) do
            <<~ASCIIDOC
              = Title

              [id=s1,reftext=_S1_]
              == Section 1

              === Section 2

              <<s1>>
            ASCIIDOC
          end
          include_examples 'reftext'
        end
      end
    end
    context 'when there is a subtitle' do
      let(:input) do
        <<~ASCIIDOC
          = Title: Subtitle

          Words.
        ASCIIDOC
      end
      context 'the header' do
        it 'includes the title and subtitle' do
          expect(converted).to include(<<~HTML)
            <div class="titlepage">
            <div id="breadcrumbs-go-here"></div>
            <div>
            <div><h1 class="title"><a id="id-1"></a>Title</h1></div>
            <div><h2 class="subtitle">Subtitle</h2></div>
            </div>
            <!--EXTRA-->
            </div>
          HTML
        end
      end
    end
    context 'when there is markup in the title' do
      let(:input) do
        <<~ASCIIDOC
          = `foo`

          Words.
        ASCIIDOC
      end
      context 'the title' do
        it 'only includes the text of the title' do
          expect(converted).to include(<<~HTML)
            <title>foo | Elastic</title>
            <meta class="elastic" name="content" content="foo">
          HTML
        end
      end
      context 'the header' do
        it 'includes the title and subtitle' do
          expect(converted).to include(<<~HTML)
            <div class="titlepage">
            <div id="breadcrumbs-go-here"></div>
            <div>
            <div><h1 class="title"><a id="id-1"></a><code class="literal">foo</code></h1></div>
            </div>
            <!--EXTRA-->
            </div>
          HTML
        end
      end
    end
    context 'contains a navheader' do
      # Emulates the chunker without trying to include it.
      let(:input) do
        <<~ASCIIDOC
          = Title: Subtitle

          [pass]
          --
          <div class="navheader">
          nav nav nav
          </div>
          --

          Words.
        ASCIIDOC
      end
      context 'the navheader' do
        it 'is moved above the "book" wrapper' do
          expect(converted).to include(<<~HTML)
            <div class="navheader">
            nav nav nav
            </div>
            <div class="book" lang="en">
          HTML
        end
      end
    end
    context 'contains a navfooer' do
      # Emulates the chunker without trying to include it.
      let(:input) do
        <<~ASCIIDOC
          = Title: Subtitle

          [pass]
          --
          <div class="navfooter">
          nav nav nav
          </div>
          --

          Words.
        ASCIIDOC
      end
      context 'the navfooter' do
        it 'is moved below the "book" wrapper' do
          expect(converted).to include(<<~HTML)
            <div class="navfooter">
            nav nav nav
            </div>
            </body>
          HTML
        end
      end
    end
    context 'when there is a page-header' do
      let(:convert_attributes) do
        {
          # Shrink the output slightly so it is easier to read
          'stylesheet!' => false,
          'page-header' => '<div class="foo" />',
        }
      end
      let(:input) do
        <<~ASCIIDOC
          = Title

          Words.
        ASCIIDOC
      end
      context 'the header' do
        it 'contains the page-header right after the body tag' do
          expect(converted).not_to include <<~HTML
            <body>
            <div class="foo" />
          HTML
        end
      end
    end
    context 'when the head is disabled' do
      let(:convert_attributes) do
        {
          # Shrink the output slightly so it is easier to read
          'stylesheet!' => false,
          # Set some metadata that will be included in the header
          'dc.type' => 'FooType',
          'dc.subject' => 'BarSubject',
          'dc.identifier' => 'BazIdentifier',
          # Turn off indexing
          'noindex' => true,
        }
      end
      let(:input) do
        <<~ASCIIDOC
          = Title

          Words.
        ASCIIDOC
      end
      context 'the head' do
        it 'contains a directive to not follow or index the page' do
          expect(converted).to include(
            '<meta name="robots" content="noindex,nofollow"/>'
          )
        end
      end
    end
    context 'when there is title-extra' do
      let(:convert_attributes) do
        {
          # Shrink the output slightly so it is easier to read
          'stylesheet!' => false,
          # Set some metadata that will be included in the header
          'dc.type' => 'FooType',
          'dc.subject' => 'BarSubject',
          'dc.identifier' => 'BazIdentifier',
          'toc' => '',
          'toclevels' => 1,
          'title-extra' => ' [fooo]',
        }
      end
      let(:input) do
        <<~ASCIIDOC
          = Title

          == Section 1

          == Section 2
        ASCIIDOC
      end
      context 'the title' do
        it 'includes Elastic' do
          expect(converted).to include(<<~HTML)
            <title>Title [fooo] | Elastic</title>
            <meta class="elastic" name="content" content="Title [fooo]">
          HTML
        end
      end
    end
  end

  context 'sections' do
    shared_examples 'section basics' do |wrapper_class, hlevel, id, title|
      context 'the wrapper' do
        it "has the '#{wrapper_class}' class" do
          expect(converted).to include(<<~HTML.strip)
            <div class="#{wrapper_class}">
          HTML
        end
      end
      context 'the header' do
        let(:xpack_tag) do
          if (input.include? '.xpack') &&
             (!input.include? ':hide-xpack-tags: true')
            '<a class="xpack_tag" href="/subscriptions"></a>'
          else
            ''
          end
        end
        it "is wrapped in docbook's funny titlepage" do
          level = hlevel < 2 ? 2 : hlevel
          expect(converted).to include(<<~HTML)
            <div class="titlepage"><div><div>
            <div class="position-relative"><h#{level} class="title"><a id="#{id}"></a>#{title}#{xpack_tag}</h#{level}></div>
            </div></div></div>
          HTML
        end
      end
    end

    context 'level 1' do
      let(:input) do
        <<~ASCIIDOC
          == Section
        ASCIIDOC
      end
      include_examples 'section basics', 'chapter', 1, '_section', 'Section'
      context 'with the xpack role' do
        let(:input) do
          <<~ASCIIDOC
            [.xpack]
            == S1
          ASCIIDOC
        end
        include_examples 'section basics', 'chapter xpack', 1, '_s1', 'S1'
        context 'with the hide-xpack-tags attribute' do
          let(:input) do
            <<~ASCIIDOC
              :hide-xpack-tags: true

              [.xpack]
              == Some XPack Feature
            ASCIIDOC
          end
          # Because the block is marked with the `xpack` role, the surrounding
          # <div> will still have the "xpack" class. But the clickable icon
          # should be hidden.
          include_examples 'section basics', 'chapter xpack', 1,
                           '_some_xpack_feature', 'Some XPack Feature'
        end
      end
    end

    context 'level 2' do
      let(:input) do
        <<~ASCIIDOC
          === Section 2
        ASCIIDOC
      end
      include_examples 'section basics', 'section', 2, '_section_2', 'Section 2'
      context 'with the xpack role' do
        let(:input) do
          <<~ASCIIDOC
            [.xpack]
            === S2
          ASCIIDOC
        end
        include_examples 'section basics', 'section xpack', 2, '_s2', 'S2'
      end
    end

    context 'level 3' do
      let(:input) do
        <<~ASCIIDOC
          ==== Section 3
        ASCIIDOC
      end
      include_examples 'section basics', 'section', 3, '_section_3', 'Section 3'
      context 'with the xpack role' do
        let(:input) do
          <<~ASCIIDOC
            [.xpack]
            ==== S3
          ASCIIDOC
        end
        include_examples 'section basics', 'section xpack', 3, '_s3', 'S3'
      end
    end

    context 'level 0' do
      let(:input) do
        <<~ASCIIDOC
          = Title

          = Section

          == L1

          === L2
        ASCIIDOC
      end
      include_examples 'section basics', 'part', 1, '_section', 'Section'
      it "bumps the h tag of it's children" do
        expect(converted).to include 'L1</h2>'
      end
      it "doesn't bump the h tag of it's children's children" do
        # Docbook doesn't seem to do this
        expect(converted).to include 'L2</h2>'
      end
      context 'with the xpack role' do
        let(:input) do
          <<~ASCIIDOC
            = Title

            [.xpack]
            = S1

            == Chapter
          ASCIIDOC
        end
        include_examples 'section basics', 'part xpack', 1, '_s1', 'S1'
      end
    end

    context 'a preface' do
      let(:input) do
        <<~ASCIIDOC
          [preface]
          == Preface
          Words.
        ASCIIDOC
      end
      include_examples 'section basics', 'preface', 1, '_preface', 'Preface'
      context 'with the xpack role' do
        let(:input) do
          <<~ASCIIDOC
            [preface.xpack]
            == P
          ASCIIDOC
        end
        include_examples 'section basics', 'preface xpack', 1, '_p', 'P'
      end
    end

    context 'an appendix' do
      let(:input) do
        <<~ASCIIDOC
          [appendix]
          == Foo
          Words.
        ASCIIDOC
      end
      include_examples 'section basics', 'appendix', 1, '_foo',
                       'Appendix A: Foo'
      context 'with the xpack role' do
        let(:input) do
          <<~ASCIIDOC
            [appendix.xpack]
            == Foo
          ASCIIDOC
        end
        include_examples 'section basics', 'appendix xpack', 1, '_foo',
                         'Appendix A: Foo'
      end
      context 'with level 0' do
        let(:input) do
          <<~ASCIIDOC
            = Title

            [appendix]
            = Foo

            == Bar
          ASCIIDOC
        end
        include_examples 'section basics', 'appendix', 1, '_foo',
                         'Appendix A: Foo'
        it "doesn't bump the h tags of sections within it" do
          expect(converted).to include 'Bar</h2>'
        end
      end
    end
  end

  context 'a paragraph' do
    let(:input) do
      <<~ASCIIDOC
        = Title

        == Section
        Words words words.
      ASCIIDOC
    end
    it "isn't wrapped in a paragraph div" do
      expect(converted).not_to include('<div class="paragraph">')
    end
    it 'contains the words' do
      expect(converted).to include('<p>Words words words.</p>')
    end
    context 'has an id' do
      let(:input) do
        <<~ASCIIDOC
          [[foo]]
          Words.
        ASCIIDOC
      end
      it 'contains the id' do
        expect(converted).to include '<p><a id="foo"></a>Words.</p>'
      end
    end
    context 'with a title' do
      let(:input) do
        <<~ASCIIDOC
          .Title
          Words.
        ASCIIDOC
      end
      it 'contains the title' do
        expect(converted).to include '<p><strong>Title</strong>Words.</p>'
      end
    end
    context 'with a role' do
      let(:input) do
        <<~ASCIIDOC
          [.screenshot]
          image:foo[]
        ASCIIDOC
      end
      it 'has the role as a class' do
        expect(converted).to include <<~HTML
          <p class="screenshot"><span class="image"><img src="foo" alt="foo"></span></p>
        HTML
      end
    end
  end

  context 'a link' do
    let(:input) do
      <<~ASCIIDOC
        Words #{link}.
      ASCIIDOC
    end
    let(:url) { 'https://metacpan.org/module/Search::Elasticsearch' }
    let(:link) { url }
    it 'has ulink class' do
      expect(converted).to include('class="ulink"')
    end
    it 'targets the _top' do
      expect(converted).to include('target="_top"')
    end
    it 'references the url' do
      expect(converted).to include(<<~HTML.strip)
        href="#{url}"
      HTML
    end
    it 'contains the link text' do
      expect(converted).to include(">#{url}</a>")
    end
    context 'when the link text and window is overridden' do
      let(:link) { "#{url}[docs,window=_blank]" }
      it 'contains the overridden text' do
        expect(converted).to include('>docs</a>')
      end
      it 'targets the overridden window' do
        expect(converted).to include('target="_blank"')
      end
    end
  end

  context 'a cross reference' do
    let(:input) do
      <<~ASCIIDOC
        Words <<foo>>.

        [[foo]]
        == Foo
      ASCIIDOC
    end
    it 'has xref class' do
      expect(converted).to include(' class="xref"')
    end
    it 'references the target' do
      expect(converted).to include(' href="#foo"')
    end
    it "contains the target's title" do
      expect(converted).to include(' title="Foo"')
    end
    it 'wraps the title in <em>' do
      expect(converted).to include('><em>Foo</em></a>')
    end

    context 'when the link text is overridden' do
      let(:input) do
        <<~ASCIIDOC
          Words <<foo,override text>>.

          [[foo]]
          == Foo
        ASCIIDOC
      end
      it 'contains the overridden text' do
        expect(converted).to include('>override text</a>')
      end
    end
    context 'when the section title has markup' do
      let(:input) do
        <<~ASCIIDOC
          Words <<foo>>.

          [[foo]]
          == `foo`
        ASCIIDOC
      end
      it "contains the target's title without the markup" do
        expect(converted).to include('title="foo"')
      end
    end
    context 'when the section title is empty' do
      let(:input) do
        <<~ASCIIDOC
          Words <<foo>>.

          [[foo]]
          ==
        ASCIIDOC
      end
      it "doesn't contain a title at all" do
        expect(converted).not_to include('title')
      end
    end
    context 'to an inline anchor' do
      let(:input) do
        <<~ASCIIDOC
          [[target]]`target`:: foo

          <<target>>
        ASCIIDOC
      end
      it 'references the url' do
        expect(converted).to include('href="#target"')
      end
      it 'has the right text' do
        expect(converted).to include('><code class="literal">target</code></a>')
      end

      context 'when that inline anchor has empty text' do
        let(:input) do
          <<~ASCIIDOC
            == Section heading

            Words.
            [[target]]
            more words.

            <<target>>
          ASCIIDOC
        end
        it 'references the url' do
          expect(converted).to include('href="#target"')
        end
        it 'has the right text' do
          expect(converted).to include('>Section heading</a>')
        end
      end
    end
    context 'to an appendix' do
      let(:input) do
        <<~ASCIIDOC
          <<target>>

          [[target]]
          [appendix]
          == Foo
        ASCIIDOC
      end
      it 'references the url' do
        expect(converted).to include('href="#target"')
      end
      it 'has the right text' do
        expect(converted).to include('>Appendix A, <em>Foo</em></a>')
      end
    end
  end

  context 'a floating title' do
    let(:input) do
      <<~ASCIIDOC
        [float]
        ==== Foo
      ASCIIDOC
    end
    it 'has the right h level' do
      expect(converted).to include('<h4>')
    end
    it 'has an inline anchor for docbook compatibility' do
      expect(converted).to include('<a id="_foo"></a>')
    end

    context 'with the xpack role' do
      let(:input) do
        <<~ASCIIDOC
          [float.xpack]
          ==== Foo
        ASCIIDOC
      end
      it 'has the xpack class' do
        expect(converted).to include '<h4 class="xpack">'
      end
      it 'has the xpack tag' do
        expect(converted).to include(
          '<a class="xpack_tag" href="/subscriptions"></a></h4>'
        )
      end
    end
    context 'with the xpack bug is declared inline' do
      let(:input) do
        <<~ASCIIDOC
          [float]
          ==== [xpack]#Foo#
        ASCIIDOC
      end
      it 'has the xpack tag' do
        expect(converted).to include <<~HTML
          <span class="xpack">Foo</span><a class="xpack_tag" href="/subscriptions"></a></h4></div>
        HTML
      end
    end
  end

  context 'a listing block' do
    let(:input) do
      <<~ASCIIDOC
        [source,sh]
        ----
        cpanm Search::Elasticsearch
        ----
      ASCIIDOC
    end
    it "is wrapped in docbook's funny wrapper" do
      # It is important that there isn't any extra space around the <pre> tags
      expect(converted).to include(<<~HTML)
        <div class="pre_wrapper lang-sh">
        <div class="console_code_copy" title="Copy to clipboard"></div>
        <pre class="programlisting prettyprint lang-sh">cpanm Search::Elasticsearch</pre>
        </div>
      HTML
    end
    it "isn't followed by an extra blank line" do
      expect(converted).to include(<<~HTML)
        </pre>
        </div>
        </div>
      HTML
    end

    context 'paired with a callout list' do
      let(:input) do
        <<~ASCIIDOC
          [source,sh]
          ----
          cpanm Search::Elasticsearch <1>
          ----
          <1> Foo
        ASCIIDOC
      end
      context 'the listing' do
        it 'includes the callout' do
          expect(converted).to include <<~HTML.strip
            cpanm Search::Elasticsearch <a id="CO1-1"></a><i class="conum" data-value="1"></i>
          HTML
        end
      end
      context 'the callout list' do
        it 'is rendered like a docbook callout list' do
          expect(converted).to include <<~HTML
            <div class="calloutlist">
            <table border="0" summary="Callout list">
            <tr>
            <td align="left" valign="top" width="5%">
            <p><a href="#CO1-1"><i class="conum" data-value="1"></i></a></p>
            </td>
            <td align="left" valign="top">
            <p>Foo</p>
            </td>
            </tr>
            </table>
            </div>
          HTML
        end
      end

      context 'that has a role' do
        let(:input) do
          <<~ASCIIDOC
            [source,sh]
            ----
            cpanm Search::Elasticsearch <1>
            ----
            [.foo]
            <1> Foo
          ASCIIDOC
        end
        context 'the callout list' do
          it 'includes the role' do
            expect(converted).to include '<div class="calloutlist foo">'
          end
        end
      end
      context 'that has duplicates' do
        let(:input) do
          <<~ASCIIDOC
            [source,sh]
            ----
            foo <1>
            bar <1>
            baz <2>
            ----
            <1> Foo
            <2> Baz
          ASCIIDOC
        end
        context 'the duplicated callouts in the listing' do
          it 'have the same data-value' do
            expect(converted).to include <<~HTML
              foo <a id="CO1-1"></a><i class="conum" data-value="1"></i>
              bar <a id="CO1-2"></a><i class="conum" data-value="1"></i>
            HTML
          end
        end
        context 'the unique callout in the listing' do
          it 'has a number that counts up from the previously shown number' do
            expect(converted).to include <<~HTML
              baz <a id="CO1-3"></a><i class="conum" data-value="2"></i></pre>
            HTML
          end
        end
        context 'the duplicated callouts in the callout list' do
          it 'only contains a single number' do
            expect(converted).to include <<~HTML
              <p><a href="#CO1-1"><i class="conum" data-value="1"></i></a><a href="#CO1-2"></a></p>
            HTML
          end
        end
        context 'the unique callout in the callout list' do
          it 'has a number that counts up from the previously shown number' do
            expect(converted).to include <<~HTML
              <p><a href="#CO1-3"><i class="conum" data-value="2"></i></a></p>
            HTML
          end
        end
      end
    end
    context 'with a title' do
      let(:input) do
        <<~ASCIIDOC
          .Title
          [source,sh]
          ----
          cpanm Search::Elasticsearch
          ----
        ASCIIDOC
      end
      it "the title is before in docbook's funny wrapper" do
        expect(converted).to include(<<~HTML)
          <p><strong>Title.</strong></p>
          <div class="pre_wrapper lang-sh">
        HTML
      end

      context 'that ends in a :' do
        let(:input) do
          <<~ASCIIDOC
            .Title:
            [source,sh]
            ----
            cpanm Search::Elasticsearch
            ----
          ASCIIDOC
        end
        it "the title is before in docbook's funny wrapper" do
          expect(converted).to include(<<~HTML)
            <p><strong>Title:</strong></p>
            <div class="pre_wrapper lang-sh">
          HTML
        end
      end
    end
    context 'with an id' do
      let(:input) do
        <<~ASCIIDOC
          [source,sh,id=foo]
          ----
          cpanm Search::Elasticsearch
          ----
        ASCIIDOC
      end
      it "the title is before in docbook's funny wrapper" do
        expect(converted).to include(<<~HTML)
          <a id="foo"></a><div class="pre_wrapper lang-sh">
        HTML
      end
    end
    context 'with an id and a title' do
      let(:input) do
        <<~ASCIIDOC
          .Title
          [source,sh,id=foo]
          ----
          cpanm Search::Elasticsearch
          ----
        ASCIIDOC
      end
      it "the title is before in docbook's funny wrapper" do
        expect(converted).to include(<<~HTML)
          <p><a id="foo"></a><strong>Title.</strong></p>
          <div class="pre_wrapper lang-sh">
        HTML
      end
    end
    context 'with a role' do
      let(:input) do
        <<~ASCIIDOC
          [source,sh,role=foo]
          ----
          cpanm Search::Elasticsearch
          ----
        ASCIIDOC
      end
      it 'the role is included as a class' do
        expect(converted).to include(<<~HTML)
          <div class="pre_wrapper lang-sh foo">
          <div class="console_code_copy" title="Copy to clipboard"></div>
          <pre class="programlisting prettyprint lang-sh foo">cpanm Search::Elasticsearch</pre>
          </div>
        HTML
      end
    end
    context "when the listing doesn't have a language" do
      let(:input) do
        <<~ASCIIDOC
          ----
          cpanm Search::Elasticsearch
          ----
        ASCIIDOC
      end
      it "is wrapped in docbook's funny wrapper" do
        # It is important that there isn't any extra space around the <pre> tags
        expect(converted).to include(<<~HTML)
          <pre class="screen">cpanm Search::Elasticsearch</pre>
        HTML
      end
      it "isn't followed by an extra blank line" do
        expect(converted).to include(<<~HTML)
          </pre>
          </div>
        HTML
      end
      context 'with a title' do
        let(:input) do
          <<~ASCIIDOC
            .Title
            ----
            cpanm Search::Elasticsearch
            ----
          ASCIIDOC
        end
        it "the title is before in docbook's funny wrapper" do
          expect(converted).to include(<<~HTML)
            <p><strong>Title.</strong></p>
            <pre class="screen">cpanm Search::Elasticsearch</pre>
          HTML
        end
      end
    end
  end

  context 'an unordered list' do
    let(:input) do
      <<~ASCIIDOC
        * Thing
        * Other thing
        * Third thing
      ASCIIDOC
    end
    it 'is wrapped an itemizedlist div' do
      expect(converted).to include('<div class="ulist itemizedlist">')
    end
    it 'has the itemizedlist class' do
      expect(converted).to include('<ul class="itemizedlist"')
    end
    context 'the first item' do
      it 'has the listitem class' do
        expect(converted).to include(<<~HTML)
          <li class="listitem">
          Thing
          </li>
        HTML
      end
    end
    context 'the second item' do
      it 'has the listitem class' do
        expect(converted).to include(<<~HTML)
          <li class="listitem">
          Other thing
          </li>
        HTML
      end
    end
    context 'the third item' do
      it 'has the listitem class' do
        expect(converted).to include(<<~HTML)
          <li class="listitem">
          Third thing
          </li>
        HTML
      end
    end

    context 'when there is a title' do
      let(:input) do
        <<~ASCIIDOC
          .Title
          * Thing
        ASCIIDOC
      end
      context 'the title' do
        it 'is wrapped a strong' do
          expect(converted).to include <<~HTML
            <div class="ulist itemizedlist">
            <p class="title"><strong>Title</strong></p>
          HTML
        end
      end
    end
    context 'when it is a TODO list' do
      context "when it isn't done" do
        let(:input) do
          <<~ASCIIDOC
            * [ ] Thing
          ASCIIDOC
        end
        it 'includes to empty check box' do
          expect(converted).to include <<~HTML
            <div class="ulist checklist itemizedlist">
            <ul class="checklist">
            <li class="listitem">
            &#10063; Thing
            </li>
            </ul>
            </div>
          HTML
        end
      end
      context 'when it is done' do
        let(:input) do
          <<~ASCIIDOC
            * [x] Thing
          ASCIIDOC
        end
        it 'includes the check mark' do
          expect(converted).to include <<~HTML
            <div class="ulist checklist itemizedlist">
            <ul class="checklist">
            <li class="listitem">
            &#10003; Thing
            </li>
            </ul>
            </div>
          HTML
        end
      end
      context 'when it is interactive' do
        context "when it isn't done" do
          let(:input) do
            <<~ASCIIDOC
              [%interactive]
              * [ ] Thing
            ASCIIDOC
          end
          it 'includes to empty check box' do
            expect(converted).to include <<~HTML
              <div class="ulist checklist itemizedlist">
              <ul class="checklist">
              <li class="listitem">
              <input type="checkbox" data-item-complete="0"> Thing
              </li>
              </ul>
              </div>
            HTML
          end
        end
        context 'when it is done' do
          let(:input) do
            <<~ASCIIDOC
              [%interactive]
              * [x] Thing
            ASCIIDOC
          end
          it 'includes the check mark' do
            expect(converted).to include <<~HTML
              <div class="ulist checklist itemizedlist">
              <ul class="checklist">
              <li class="listitem">
              <input type="checkbox" data-item-complete="1" checked> Thing
              </li>
              </ul>
              </div>
            HTML
          end
        end
      end
    end
  end

  context 'an ordered list' do
    let(:input) do
      <<~ASCIIDOC
        . Thing
        . Other thing
        . Third thing
      ASCIIDOC
    end
    it 'is wrapped an orderedlist div' do
      expect(converted).to include('<div class="olist orderedlist">')
    end
    it 'has the itemizedlist class' do
      expect(converted).to include('<ol class="orderedlist"')
    end
    context 'the first item' do
      it 'has the listitem class' do
        expect(converted).to include(<<~HTML)
          <li class="listitem">
          Thing
          </li>
        HTML
      end
    end
    context 'the second item' do
      it 'has the listitem class' do
        expect(converted).to include(<<~HTML)
          <li class="listitem">
          Other thing
          </li>
        HTML
      end
    end
    context 'the third item' do
      it 'has the listitem class' do
        expect(converted).to include(<<~HTML)
          <li class="listitem">
          Third thing
          </li>
        HTML
      end
    end

    context 'when there is a title' do
      let(:input) do
        <<~ASCIIDOC
          .Title
          . Thing
        ASCIIDOC
      end
      context 'the title' do
        it 'is wrapped a strong' do
          expect(converted).to include <<~HTML
            <div class="olist orderedlist">
            <p class="title"><strong>Title</strong></p>
          HTML
        end
      end
    end
    context 'when the list if defined with 1.' do
      let(:input) do
        <<~ASCIIDOC
          1. Thing
        ASCIIDOC
      end
      it 'is wrapped an orderedlist div' do
        expect(converted).to include('<div class="olist orderedlist">')
      end
      it 'has the itemizedlist class' do
        expect(converted).to include('<ol class="orderedlist"')
      end
      context 'the item' do
        it 'has the listitem class' do
          expect(converted).to include(<<~HTML)
            <li class="listitem">
            Thing
            </li>
          HTML
        end
      end
    end
    context 'with complex contents' do
      let(:input) do
        <<~ASCIIDOC
          . Foo
          +
          --
          Complex
          --
        ASCIIDOC
      end
      it 'wraps the text in a <p>' do
        expect(converted).to include(<<~HTML)
          <li class="listitem">
          <p>Foo</p>
        HTML
      end
      it 'includes the complex content' do
        expect(converted).to include(<<~HTML)
          <p>Complex</p>
          </li>
        HTML
      end
    end
    context 'second level' do
      let(:input) do
        <<~ASCIIDOC
          . L1
          .. L2
          .. Thing 2
        ASCIIDOC
      end
      it 'the outer list is wrapped an orderedlist div' do
        expect(converted).to include <<~HTML
          <div class="sectionbody">
          <div class="olist orderedlist">
          <ol class="orderedlist">
        HTML
      end
      it 'the inner list is wrapped an orderedlist div' do
        expect(converted).to include <<~HTML
          <p>L1</p>
          <div class="olist orderedlist">
          <ol class="orderedlist">
        HTML
      end
    end
  end

  context 'a description list' do
    context 'basic' do
      let(:input) do
        <<~ASCIIDOC
          Foo:: The foo.
          [[bar]] Bar:: The bar.
        ASCIIDOC
      end
      it 'is wrapped like docbook' do
        expect(converted).to include <<~HTML
          <div class="variablelist">
          <dl class="variablelist">
        HTML
        expect(converted).to include <<~HTML
          </dl>
          </div>
        HTML
      end
      it 'contains the first item' do
        expect(converted).to include <<~HTML
          <dt>
          <span class="term">
          Foo
          </span>
          </dt>
          <dd>
          The foo.
          </dd>
        HTML
      end
      it 'contains the second item' do
        expect(converted).to include <<~HTML
          <dt>
          <span class="term">
          <a id="bar"></a> Bar
          </span>
          </dt>
          <dd>
          The bar.
          </dd>
        HTML
      end
    end

    context 'without a descrition' do
      let(:input) do
        <<~ASCIIDOC
          Foo::
        ASCIIDOC
      end
      it "doesn't have a dd" do
        expect(converted).not_to include '<dd>'
      end
    end
    context 'with complex content' do
      let(:input) do
        <<~ASCIIDOC
          Foo::
          +
          --
          Lots of content.

          In many paragraphs.
          --
        ASCIIDOC
      end
      it 'contains complex content' do
        expect(converted).to include <<~HTML
          <dt>
          <span class="term">
          Foo
          </span>
          </dt>
          <dd>
          <p>Lots of content.</p>
          <p>In many paragraphs.</p>
          </dd>
        HTML
      end
    end
    context 'when the anchor is on the previous line' do
      let(:input) do
        <<~ASCIIDOC
          [[bar]]
          Bar:: The bar.
        ASCIIDOC
      end
      it 'the id preceeds dl' do
        expect(converted).to include <<~HTML
          <div class="variablelist">
          <a id="bar"></a>
          <dl class="variablelist">
        HTML
      end
    end
    context 'horizontally styled' do
      let(:input) do
        <<~ASCIIDOC
          [horizontal]
          Foo:: The foo.
          Bar:: The bar.
        ASCIIDOC
      end
      it 'is rendered like a table' do
        expect(converted).to include <<~HTML
          <div class="informaltable">
          <table border="0" cellpadding="4px">
          <colgroup>
          <col/>
          <col/>
          </colgroup>
          <tbody valign="top">
        HTML
        expect(converted).to include <<~HTML
          </tbody>
          </table>
          </div>
        HTML
      end
      it 'contains a row for the first entry' do
        expect(converted).to include <<~HTML
          <tr>
          <td valign="top">
          <p>
          Foo
          </p>
          </td>
          <td valign="top">
          <p>
          The foo.
          </p>
          </td>
          </tr>
        HTML
      end
      it 'contains a row for the second entry' do
        expect(converted).to include <<~HTML
          <tr>
          <td valign="top">
          <p>
          Bar
          </p>
          </td>
          <td valign="top">
          <p>
          The bar.
          </p>
          </td>
          </tr>
        HTML
      end

      context 'when it has a title' do
        let(:input) do
          <<~ASCIIDOC
            .Title
            [horizontal]
            Foo:: The foo.
            Bar:: The bar.
          ASCIIDOC
        end
        it 'has the title in a strong' do
          expect(converted).to include <<~HTML
            <div class="table">
            <p class="title"><strong>Table 1. Title</strong></p>
            <div class="table-contents">
          HTML
        end
        it 'has the title as the summary' do
          expect(converted).to include <<~HTML
            <div class="table-contents">
            <table border="0" cellpadding="4px" summary="Title">
          HTML
        end

        context 'when the title has markup in it' do
          let(:input) do
            <<~ASCIIDOC
              .`foo`
              [horizontal]
              Foo:: The foo.
              Bar:: The bar.
            ASCIIDOC
          end
          it 'has the title in a strong with the html' do
            expect(converted).to include <<~HTML
              <div class="table">
              <p class="title"><strong>Table 1. <code class="literal">foo</code></strong></p>
              <div class="table-contents">
            HTML
          end
          it 'has the title as the summary without the html' do
            expect(converted).to include <<~HTML
              <div class="table-contents">
              <table border="0" cellpadding="4px" summary="foo">
            HTML
          end
        end
      end
    end
    context 'question and anwer styled' do
      let(:input) do
        <<~ASCIIDOC
          [qanda]
          What is foo?:: You don't want to know.
          Who is Baz?:: Baz is Baz.
        ASCIIDOC
      end
      it 'is rendered like a table' do
        expect(converted).to include <<~HTML
          <div class="qandaset">
          <table border="0">
          <colgroup>
          <col align="left" width="1%"/>
          <col/>
          </colgroup>
          <tbody>
        HTML
        expect(converted).to include <<~HTML
          </tbody>
          </table>
          </div>
        HTML
      end
      it 'contains a row for the first entry' do
        expect(converted).to include <<~HTML
          <tr class="question">
          <td align="left" valign="top">
          <p><strong>1.</strong></p>
          </td>
          <td align="left" valign="top">
          <p>
          What is foo?
          </p>
          </td>
          </tr>
          <tr class="answer">
          <td align="left" valign="top">
          </td>
          <td align="left" valign="top">
          <p>
          You don&#8217;t want to know.
          </p>
          </td>
          </tr>
        HTML
      end
      it 'contains a row for the second entry' do
        expect(converted).to include <<~HTML
          <tr class="question">
          <td align="left" valign="top">
          <p><strong>2.</strong></p>
          </td>
          <td align="left" valign="top">
          <p>
          Who is Baz?
          </p>
          </td>
          </tr>
          <tr class="answer">
          <td align="left" valign="top">
          </td>
          <td align="left" valign="top">
          <p>
          Baz is Baz.
          </p>
          </td>
          </tr>
        HTML
      end
    end
    context 'glossary styled' do
      let(:input) do
        <<~ASCIIDOC
          [glossary]
          Foo:: The foo.
          Bar:: The bar.
        ASCIIDOC
      end
      it 'is wrapped in a dl' do
        expect(converted).to include '<dl>'
        expect(converted).to include '</dl>'
      end
      it 'contains a dt/dd pair for the first entry' do
        expect(converted).to include <<~HTML
          <dt>
          <span class="glossterm">
          Foo
          </span>
          </dt>
          <dd class="glossdef">
          The foo.
          </dd>
        HTML
      end
      it 'contains a dt/dd pair for the second entry' do
        expect(converted).to include <<~HTML
          <dt>
          <span class="glossterm">
          Bar
          </span>
          </dt>
          <dd class="glossdef">
          The bar.
          </dd>
        HTML
      end
    end
    context 'an unimplemented dlist style' do
      include_context 'convert with logs'
      let(:input) do
        <<~ASCIIDOC
          [not_implemented]
          Foo:: The foo.
          Bar:: The bar.
        ASCIIDOC
      end
      it 'logs an warning' do
        expect(logs).to eq <<~LOG.strip
          WARN: <stdin>: line 2: Can't convert unknown description list style [not_implemented].
        LOG
      end
    end
  end

  context 'backticked code' do
    let(:input) do
      <<~ASCIIDOC
        Words `backticked`.
      ASCIIDOC
    end
    it 'is considered a "literal" by default' do
      expect(converted).to include('<code class="literal">backticked</code>')
    end
  end

  context 'stronged text' do
    let(:input) do
      <<~ASCIIDOC
        *strong words*
      ASCIIDOC
    end
    it 'is rendered like docbook' do
      expect(converted).to include(<<~HTML.strip)
        <span class="strong strong"><strong>strong words</strong></span>
      HTML
    end
  end

  context 'admonitions' do
    def expect_block_admonition(body)
      expect(converted).to include <<~HTML
        <div class="#{admon_class} admon">
        <div class="icon"></div>
        <div class="admon_content">
        #{body}
        </div>
        </div>
      HTML
    end
    context 'built in admonitions' do
      shared_examples 'standard admonition' do
        context 'with text' do
          let(:input) do
            <<~ASCIIDOC
              #{key}: words
            ASCIIDOC
          end
          it "renders with Elastic's custom template" do
            expect_block_admonition '<p>words</p>'
          end
        end
        context 'with complex content' do
          let(:input) do
            <<~ASCIIDOC
              [#{key}]
              --
              . words
              --
            ASCIIDOC
          end
          it 'contains the complex content' do
            expect_block_admonition <<~HTML.strip
              <div class="olist orderedlist">
              <ol class="orderedlist">
              <li class="listitem">
              words
              </li>
              </ol>
              </div>
            HTML
          end
        end
        context 'without content' do
          let(:input) do
            <<~ASCIIDOC
              [#{key}]
              --
              --
            ASCIIDOC
          end
          it "doesn't have default text" do
            expect_block_admonition '<p></p>'
          end
        end
        context 'with a title' do
          let(:input) do
            <<~ASCIIDOC
              [#{key}]
              .Title
              --
              words
              --
            ASCIIDOC
          end
          it "renders the title in Elastic's custom template" do
            expect(converted).to include(<<~HTML)
              <div class="#{admon_class} admon">
              <div class="icon"></div>
              <div class="admon_content">
              <p class="admon_title">Title</p>
              <p>words</p>
              </div>
              </div>
            HTML
          end

          context 'and an id' do
            let(:input) do
              <<~ASCIIDOC
                [[id]]
                [#{key}]
                .Title
                --
                words
                --
              ASCIIDOC
            end
            it "renders the title in Elastic's custom template" do
              expect(converted).to include(<<~HTML)
                <div class="#{admon_class} admon">
                <div class="icon"></div>
                <div class="admon_content">
                <p class="admon_title">Title<a id="id"></a></p>
                <p>words</p>
                </div>
                </div>
              HTML
            end
          end
        end
        context 'with an id' do
          let(:input) do
            <<~ASCIIDOC
              [[id]]
              [#{key}]
              --
              words
              --
            ASCIIDOC
          end
          it "renders the id in Elastic's custom template" do
            expect(converted).to include(<<~HTML)
              <div class="#{admon_class} admon">
              <div class="icon"></div>
              <div class="admon_content">
              <a id="id"></a>
              <p>words</p>
              </div>
              </div>
            HTML
          end
        end
      end
      let(:admon_class) { key.downcase }
      context 'note' do
        let(:key) { 'NOTE' }
        include_examples 'standard admonition'
      end
      context 'tip' do
        let(:key) { 'TIP' }
        include_examples 'standard admonition'
      end
      context 'important' do
        let(:key) { 'IMPORTANT' }
        include_examples 'standard admonition'
      end
      context 'caution' do
        let(:key) { 'CAUTION' }
        include_examples 'standard admonition'
      end
      context 'warning' do
        let(:key) { 'WARNING' }
        include_examples 'standard admonition'
      end
    end
  end

  context 'a literal' do
    let(:input) do
      <<~ASCIIDOC
        Words

            Literal words
              indented literal words

        Words
      ASCIIDOC
    end
    it 'renders like docbook' do
      expect(converted).to include(<<~HTML)
        <pre class="literallayout">Literal words
          indented literal words</pre>
      HTML
    end
  end

  context 'a sidebar' do
    let(:input) do
      <<~ASCIIDOC
        ****
        Words
        ****
      ASCIIDOC
    end
    it 'renders like docbook' do
      expect(converted).to include(<<~HTML)
        <div class="sidebar">
        <div class="titlepage"></div>
        <p>Words</p>
        </div>
      HTML
    end
    context 'when there is a title' do
      let(:input) do
        <<~ASCIIDOC
          .Title
          ****
          Words
          ****
        ASCIIDOC
      end
      it 'renders like docbook' do
        expect(converted).to include(<<~HTML)
          <div class="sidebar">
          <div class="titlepage"><div><div>
          <p class="title"><strong>Title</strong></p>
          </div></div></div>
          <p>Words</p>
          </div>
        HTML
      end
    end
    context 'when there is a title' do
      let(:input) do
        <<~ASCIIDOC
          [[id]]
          ****
          Words
          ****
        ASCIIDOC
      end
      it 'renders like docbook' do
        expect(converted).to include(<<~HTML)
          <div class="sidebar">
          <a id="id"></a>
          <div class="titlepage"></div>
          <p>Words</p>
          </div>
        HTML
      end
    end
  end

  context 'an open block' do
    context 'that is empty' do
      let(:input) do
        <<~ASCIIDOC
          --
          Words.
          --
        ASCIIDOC
      end
      it 'just renders its contents' do
        expect(converted).to eq <<~HTML.strip
          <div id="preamble">
          <div class="sectionbody">
          <p>Words.</p>
          </div>
          </div>
        HTML
      end
    end
  end

  context 'tables' do
    context 'basic' do
      let(:input) do
        <<~ASCIIDOC
          |===
          |Col 1 | Col 2

          |Foo   | Bar
          |Baz   | Bort
          |===
        ASCIIDOC
      end
      it 'is wrapped in informaltable' do
        expect(converted).to include <<~HTML
          <div class="informaltable">
          <table border="1" cellpadding="4px">
        HTML
      end
      it 'contains the colgroups' do
        expect(converted).to include <<~HTML
          <colgroup>
          <col class="col_1"/>
          <col class="col_2"/>
          </colgroup>
        HTML
      end
      it 'contains the head' do
        expect(converted).to include <<~HTML
          <thead>
          <tr>
          <th align="left" valign="top">Col 1</th>
          <th align="left" valign="top">Col 2</th>
          </tr>
          </thead>
        HTML
      end
      it 'contains the body' do
        expect(converted).to include <<~HTML
          <tbody>
          <tr>
          <td align="left" valign="top"><p>Foo</p></td>
          <td align="left" valign="top"><p>Bar</p></td>
          </tr>
          <tr>
          <td align="left" valign="top"><p>Baz</p></td>
          <td align="left" valign="top"><p>Bort</p></td>
          </tr>
          </tbody>
        HTML
      end
    end
    context 'with asciidoc content' do
      let(:input) do
        <<~ASCIIDOC
          |===
          |Col 1

          a|
          . Foo
          |===
        ASCIIDOC
      end
      it 'contains the asciidoc content' do
        expect(converted).to include <<~HTML
          <td align="left" valign="top">
          <div class="olist orderedlist">
          <ol class="orderedlist">
          <li class="listitem">
          Foo
          </li>
          </ol>
          </div>
          </td>
        HTML
      end
    end
    context 'with a title' do
      let(:input) do
        <<~ASCIIDOC
          .Title
          |===
          |Col 1 | Col 2
          |===
        ASCIIDOC
      end
      it 'is wrapped in table' do
        expect(converted).to include <<~HTML
          <div class="table">
          <p class="title"><strong>Table 1. Title</strong></p>
          <div class="table-contents">
          <table border="1" cellpadding="4px" summary="Title">
        HTML
      end

      context 'and an id' do
        let(:input) do
          <<~ASCIIDOC
            [[id]]
            .Title
            |===
            |Col 1 | Col 2
            |===
          ASCIIDOC
        end
        it 'is wrapped in table' do
          expect(converted).to include <<~HTML
            <div class="table">
            <a id="id"></a>
            <p class="title"><strong>Table 1. Title</strong></p>
            <div class="table-contents">
            <table border="1" cellpadding="4px" summary="Title">
          HTML
        end
      end
    end
    context 'with an id' do
      let(:input) do
        <<~ASCIIDOC
          [[id]]
          |===
          |Col 1 | Col 2
          |===
        ASCIIDOC
      end
      it 'is wrapped in informaltable' do
        expect(converted).to include <<~HTML
          <div class="informaltable">
          <a id="id"></a>
          <table border="1" cellpadding="4px">
        HTML
      end
    end
    context 'with width' do
      let(:input) do
        <<~ASCIIDOC
          [width=50%]
          |===
          |Col 1 | Col 2
          |===
        ASCIIDOC
      end
      it 'has the width' do
        expect(converted).to include <<~HTML
          <table border="1" cellpadding="4px" width="50%">
        HTML
      end
    end
    context 'with role shorthand' do
      let(:input) do
        <<~ASCIIDOC
          [.role]
          |===
          |Col 1 | Col 2
          |===
        ASCIIDOC
      end
      it 'has the class' do
        expect(converted).to include <<~HTML
          <table border="1" cellpadding="4px" class="role">
        HTML
      end
    end
    context 'with roles shorthand' do
      let(:input) do
        <<~ASCIIDOC
          [.role1.role2]
          |===
          |Col 1 | Col 2
          |===
        ASCIIDOC
      end
      it 'has the classes' do
        expect(converted).to include <<~HTML
          <table border="1" cellpadding="4px" class="role1 role2">
        HTML
      end
    end
    context 'with role attribute' do
      let(:input) do
        <<~ASCIIDOC
          [role=role]
          |===
          |Col 1 | Col 2
          |===
        ASCIIDOC
      end
      it 'has the class' do
        expect(converted).to include <<~HTML
          <table border="1" cellpadding="4px" class="role">
        HTML
      end
    end
    context 'with colspan' do
      let(:input) do
        <<~ASCIIDOC
          |===
          2+|Col
          |===
        ASCIIDOC
      end
      it 'has the colspan' do
        expect(converted).to include <<~HTML.strip
          <td align="left" colspan="2" valign="top">
        HTML
      end
    end
    context 'with rowspan' do
      let(:input) do
        <<~ASCIIDOC
          |===
          .2+|Col
          |===
        ASCIIDOC
      end
      it 'has the rowspan' do
        expect(converted).to include <<~HTML.strip
          <td align="left" rowspan="2" valign="top">
        HTML
      end
    end
    context 'with horizontal alignment' do
      let(:input) do
        <<~ASCIIDOC
          [cols="<,^,>"]
          |===
          |1 |2 |3
          |===
        ASCIIDOC
      end
      it 'aligns the cells' do
        expect(converted).to include <<~HTML
          <td align="left" valign="top"><p>1</p></td>
          <td align="center" valign="top"><p>2</p></td>
          <td align="right" valign="top"><p>3</p></td>
        HTML
      end
    end
    context 'with vertical alignment' do
      let(:input) do
        <<~ASCIIDOC
          [cols=".<,.^,.>"]
          |===
          |1 |2 |3
          |===
        ASCIIDOC
      end
      it 'aligns the cells' do
        expect(converted).to include <<~HTML
          <td align="left" valign="top"><p>1</p></td>
          <td align="left" valign="middle"><p>2</p></td>
          <td align="left" valign="bottom"><p>3</p></td>
        HTML
      end
    end
    context 'with cell formatting' do
      shared_examples 'with formatting' do
        let(:input) do
          <<~ASCIIDOC
            [cols="#{code}"]
            |===
            |Cell
            |===
          ASCIIDOC
        end
        it 'includes the formatting' do
          expect(converted).to include <<~HTML.strip
            <td align="left" valign="top"><p>#{cell}</p></td>
          HTML
        end
      end
      context 'emphasis' do
        let(:code) { 'e' }
        let(:cell) { '<em>Cell</em>' }
        include_examples 'with formatting'
      end
      context 'header' do
        let(:code) { 'h' }
        let(:cell) do
          '<span class="strong strong"><strong>Cell</strong></span>'
        end
        include_examples 'with formatting'
      end
      context 'literal' do
        let(:code) { 'l' }
        let(:cell) { 'Cell' }
        include_examples 'with formatting'
      end
      context 'monospaced' do
        let(:code) { 'm' }
        let(:cell) { '<code class="literal">Cell</code>' }
        include_examples 'with formatting'
      end
      context 'explicit "none"' do
        let(:code) { 'd' } # "d" stands for default, apparently
        let(:cell) { 'Cell' }
        include_examples 'with formatting'
        context 'when the content is a couple of paragraphs' do
          let(:input) do
            <<~ASCIIDOC
              [cols="#{code}"]
              |===
              |Cell

              with

              paragraphs.
              |===
            ASCIIDOC
          end
          it 'includes the formatting' do
            expect(converted).to include <<~HTML.strip
              <td align="left" valign="top"><p>Cell</p>
              <p>with</p>
              <p>paragraphs.</p></td>
            HTML
          end
        end
      end
      context 'strong' do
        let(:code) { 's' }
        let(:cell) do
          '<span class="strong strong"><strong>Cell</strong></span>'
        end
        include_examples 'with formatting'
      end
      context 'verse' do
        let(:code) { 'v' }
        let(:cell) { 'Cell' }
        include_examples 'with formatting'
      end
    end
  end

  context 'a quote' do
    let(:input) do
      <<~ASCIIDOC
        [quote]
        __________________________
        Baz
        __________________________
      ASCIIDOC
    end
    it 'is wrapped in a blockquote' do
      expect(converted).to include <<~HTML
        <blockquote>
        <p>Baz</p>
        </blockquote>
      HTML
    end

    context 'with an attribution' do
      let(:input) do
        <<~ASCIIDOC
          [quote, Brendan Francis Behan]
          __________________________
          Once we accept our limits, we go beyond them.
          __________________________
        ASCIIDOC
      end
      it 'looks like docbook' do
        expect(converted).to include <<~HTML
          <div class="blockquote">
          <table border="0" class="blockquote" summary="Block quote">
          <tr>
          <td valign="top" width="10%"></td>
          <td valign="top" width="80%">
          <p>Once we accept our limits, we go beyond them.</p>
          </td>
          <td valign="top" width="10%"></td>
          </tr>
          <tr>
          <td valign="top" width="10%"></td>
          <td align="right" colspan="2" valign="top">
          -- <span class="attribution">Brendan Francis Behan</span>
          </td>
          </tr>
          </table>
          </div>
        HTML
      end
    end
  end

  context 'example' do
    let(:input) do
      <<~ASCIIDOC
        ====
        Words
        ====
      ASCIIDOC
    end
    it 'is wrapped in an exampleblock' do
      expect(converted).to include <<~HTML
        <div class="exampleblock">
        <div class="content">
        <p>Words</p>
        </div>
        </div>
      HTML
    end

    context 'with a title' do
      let(:input) do
        <<~ASCIIDOC
          .Title
          ====
          Words
          ====
        ASCIIDOC
      end
      it 'is wrapped in an example' do
        expect(converted).to include <<~HTML
          <div class="example">
          <p class="title"><strong>Example 1. Title</strong></p>
          <div class="example-contents">
          <p>Words</p>
          </div>
          </div>
        HTML
      end
    end
    context 'collapsible' do
      let(:input) do
        <<~ASCIIDOC
          [%collapsible]
          .Title
          ====
          Words
          ====
        ASCIIDOC
      end
      it "uses asciidoctor's default" do
        expect(converted).to include <<~HTML
          <details>
          <summary class="title">Title</summary>
          <div class="content">
          <p>Words</p>
          </div>
        HTML
      end
    end
  end
end
