# frozen_string_literal: true

require 'fileutils'
require 'net/http'

require_relative 'spec_helper'

RSpec.describe 'building a single book' do
  HEADER = <<~ASCIIDOC
    = Title

    [[chapter]]
    == Chapter
  ASCIIDOC

  let(:emdash)           { '&#8212;' }
  let(:ellipsis)         { '&#8230;' }
  let(:zero_width_space) { '&#8203;' }

  context 'for a minimal book' do
    shared_context 'expected' do |file_name|
      convert_single_before_context do |src|
        src.write file_name, <<~ASCIIDOC
          #{HEADER}
          This is a minimal viable asciidoc file for use with build_docs. The
          actual contents of this paragraph aren't important but having a
          paragraph here is required.
        ASCIIDOC
      end

      page_context 'index.html' do
        it 'has the right title' do
          expect(title).to eq('Title')
        end
        it 'has a link to the css' do
          expect(head).to include(<<~HTML)
            <link rel="stylesheet" type="text/css" href="/guide/static/styles-v1.css" />
          HTML
        end
        it 'has a link to the js' do
          expect(contents).to include(<<~HTML)
            <script type="text/javascript" src="/guide/static/docs-v1.js"></script>
          HTML
        end
        it 'has the right language' do
          expect(language).to eq('en')
        end
        it 'has an empty initial js state' do
          expect(contents).to initial_js_state(be_empty)
        end
      end
      page_context 'toc.html' do
        it "doesn't have the initial js state" do
          # because we didn't apply the template
          expect(contents).to initial_js_state(be_nil)
        end
      end
      page_context 'raw/toc.html'
      page_context 'raw/index.html' do
        it "doesn't have the xml prolog" do
          expect(contents).not_to include('?xml')
        end
        it 'has the html5 doctype' do
          expect(contents).to include("<!DOCTYPE html>\n")
        end
        it "doesn't have any xmlns declarations" do
          expect(contents).not_to include('xmlns=')
        end
        it "doesn't have a meta generator" do
          expect(contents).not_to include('<meta name="generator"')
        end
        it "doesn't have a meta description" do
          expect(contents).not_to include('<meta name="description"')
        end
        it "doesn't have any xml:lang tags" do
          expect(contents).not_to include('xml:lang=')
        end
        it 'has a trailing newline' do
          expect(contents).to end_with("\n")
        end
        it 'has the right title in head' do
          expect(head_title).to match(/Title\s+\|\s+Elastic/m)
        end
        it 'has the right title' do
          expect(title).to eq('Title')
        end
        it "doesn't have the initial js state" do
          # because we don't apply the template which is how that gets in there
          expect(contents).to initial_js_state(be_nil)
        end
      end
      page_context 'chapter.html' do
        it 'has the right title in head' do
          expect(head_title).to match(/Chapter\s+\|\s+Title\s+\|\s+Elastic/m)
        end
        it 'has the right title' do
          expect(title).to eq('Chapter')
        end
      end
      page_context 'raw/chapter.html' do
        it 'has the right title in head' do
          expect(head_title).to match(/Chapter\s+\|\s+Title\s+\|\s+Elastic/m)
        end
        it 'has the right title' do
          expect(title).to eq('Chapter')
        end
      end
    end

    context 'when the file ends in .asciidoc' do
      include_context 'expected', 'minimal.asciidoc'
    end

    context 'when the file ends in .adoc' do
      include_context 'expected', 'minimal.adoc'
    end
  end

  context "when there isn't an elastic remote" do
    convert_single_before_context do |src|
      src.add_elastic_remote = false
      src.write 'index.asciidoc', <<~ASCIIDOC
        #{HEADER}
        This is a minimal viable asciidoc file for use with build_docs. The
        actual contents of this paragraph aren't important but having a
        paragraph here is required.
      ASCIIDOC
    end
    let(:repo) { src.repo 'src' }
    context 'the logs' do
      it 'say they are using the first remote intead' do
        expect(outputs[0]).to include(<<~LOG)
          Couldn't find an Elastic remote for #{repo.root}. Generating edit links targeting the first remote instead.
        LOG
      end
    end
    page_context 'chapter.html' do
      it 'has an "unknown" edit url' do
        expect(body).to include(<<~HTML.strip)
          <a class="edit_me" rel="nofollow" title="Edit this page on GitHub" href="unknown/edit/master/index.asciidoc">edit</a>
        HTML
      end
    end
  end

  context 'when one file includes another' do
    convert_single_before_context do |src|
      src.write 'included.asciidoc', 'I am tiny.'
      src.write 'index.asciidoc', <<~ASCIIDOC
        #{HEADER}
        I include "included" between here

        include::included.asciidoc[]

        and here.
      ASCIIDOC
    end

    page_context 'chapter.html' do
      it 'contains the index text' do
        expect(body).to include('I include "included"')
      end
      it 'contains the included text' do
        expect(body).to include('I am tiny.')
      end
    end
  end

  context 'for "interesting" inputs' do
    context 'for a book that contains an em dash' do
      convert_single_before_context do |src|
        src.write 'index.asciidoc', <<~ASCIIDOC
          #{HEADER}
          I have an em dash between some--words.
        ASCIIDOC
      end
      page_context 'chapter.html' do
        it 'the emdash is followed by a zero width space' do
          expect(body).to include("some#{emdash}#{zero_width_space}words")
        end
      end
    end
    context 'for a book that contains an ellipsis' do
      convert_single_before_context do |src|
        src.write 'index.asciidoc', <<~ASCIIDOC
          #{HEADER}
          I have an ellipsis between some...words.
        ASCIIDOC
      end
      page_context 'chapter.html' do
        it 'the ellipsis is followed by a zero width space' do
          expect(body).to include("some#{ellipsis}#{zero_width_space}words")
        end
      end
    end
    context 'for a book that contains an empty table cell' do
      convert_single_before_context do |src|
        src.write 'index.asciidoc', <<~ASCIIDOC
          #{HEADER}
          |===
          | Title | Other Title
          |       | Empty cell before this one
          |===
        ASCIIDOC
      end
      let(:empty_cell) do
        <<~HTML.strip
          <td align="left" valign="top"><p></p></td>
        HTML
      end
      let(:non_empty_cell) do
        <<~HTML.strip
          <td align="left" valign="top"><p>Empty cell before this one</p></td>
        HTML
      end
      page_context 'chapter.html' do
        it "the empty cell doesn't contain any other tags" do
          # We match on the empty cell followed by the non-empty cell so we
          # can be sure we're matching the right part of the table.
          expect(body).to include <<~HTML
            <tr>
            #{empty_cell}
            #{non_empty_cell}
            </tr>
          HTML
        end
      end
    end
    context 'for a book that has a reference to a floating title' do
      convert_single_before_context do |src|
        src.write 'index.asciidoc', <<~ASCIIDOC
          #{HEADER}
          <<floater>>

          [float]
          [[floater]]
          == Floater
        ASCIIDOC
      end
      page_context 'chapter.html' do
        it "there isn't an edit me link in the link to the section" do
          expect(body).to include(<<~HTML.strip)
            <a class="xref" href="chapter.html#floater" title="Floater">Floater</a>
          HTML
        end
      end
    end
  end

  shared_context 'care admonition' do
    page_context 'chapter.html' do
      it 'includes the warning admonition' do
        expect(body).to include(
          '<div class="warning admon">'
        )
      end
    end
  end
  context 'when the book contains beta[]' do
    include_context 'care admonition'
    convert_single_before_context do |src|
      src.write 'index.asciidoc', <<~ASCIIDOC
        #{HEADER}
        beta[]

        Words
      ASCIIDOC
    end
    page_context 'chapter.html' do
      it 'includes the beta text' do
        expect(body).to include(
          'The design and code is less mature than official GA features'
        )
      end
    end
  end
  context 'when the book contains experimental[]' do
    include_context 'care admonition'
    convert_single_before_context do |src|
      src.write 'index.asciidoc', <<~ASCIIDOC
        #{HEADER}
        experimental[]

        Words
      ASCIIDOC
    end
    page_context 'chapter.html' do
      it 'includes the experimental text' do
        expect(body).to include(
          'This functionality is in technical preview and may be changed or '\
          'removed in a future release. Elastic will work to fix '\
          'any issues, but features in technical preview are not subject to '\
          'the support SLA of official GA features.'
        )
      end
    end
  end
  context 'when there is a link to elastic.co' do
    convert_single_before_context do |src|
      src.write 'index.asciidoc', <<~ASCIIDOC
        = Title

        [[chapter]]
        == Chapter
        https://www.elastic.co/cloud/[link]
      ASCIIDOC
    end
    page_context 'chapter.html' do
      it 'contains an absolute link to www.elatic.co' do
        expect(body).to include(<<~HTML.strip)
          <a href="https://www.elastic.co/cloud/" class="ulink" target="_top">link</a>
        HTML
      end
    end
  end

  context 'for README.asciidoc' do
    convert_single_before_context do |src|
      root = File.expand_path('../../', __dir__)
      images = ['cat.jpg', 'chunking-toc.png', 'example.svg', 'screenshot.png']
      images.each do |img|
        src.cp "#{root}/resources/readme/#{img}", "resources/readme/#{img}"
      end
      src.copy_shared_conf
      txt = File.open("#{root}/README.asciidoc", 'r:UTF-8', &:read)
      src.write 'index.asciidoc', txt
    end
    page_context 'index.html' do
      it 'has the right title' do
        expect(title).to eq('Docs HOWTO')
      end
    end
    page_context '_conditions_of_use.html' do
      it 'has the right title' do
        expect(title).to eq('Conditions of use')
      end
    end
    page_context 'setup.html' do
      it 'has the right title' do
        expect(title).to eq('Getting started')
      end
    end
    page_context 'build.html' do
      it 'has the right title' do
        expect(title).to eq('Building documentation')
      end
    end
    page_context 'asciidoc-guide.html' do
      it 'has the right title' do
        expect(title).to eq('Asciidoc Guide')
      end
    end
    page_context 'images.html' do
      it 'has the right title' do
        expect(title).to eq('Images')
      end
      it 'has the cat image with a title' do
        expect(body).to include <<~HTML
          <div id="cat" class="imageblock">
          <div class="content">
          <img src="resources/readme/cat.jpg" alt="Alt text">
          </div>
          <div class="title">Figure 1. A scaredy cat</div>
          </div>
        HTML
      end
      it 'has the cat image with specified width and without a title' do
        expect(body).to include <<~HTML
          <div id="cat" class="imageblock">
          <div class="content">
          <img src="resources/readme/cat.jpg" alt="Alt text">
          </div>
        HTML
      end
      it 'has the screenshot' do
        expect(body).to include <<~HTML
          <div class="imageblock screenshot">
          <div class="content">
          <img src="resources/readme/screenshot.png" alt="A screenshot example">
          </div>
          </div>
        HTML
      end
    end
    page_context 'chunking.html' do
      it 'has the right title' do
        expect(title).to eq('Controlling chunking')
      end
      it 'has the chunking image' do
        expect(body).to include <<~HTML
          <div class="imageblock">
          <div class="content">
          <img src="resources/readme/chunking-toc.png" alt="TOC screenshot">
          </div>
          </div>
        HTML
      end
    end
    # NOTE: There are lots more pages but it probably isn't worth asserting
    # on them too.
    file_context 'snippets/1.console' do
      let(:expected) do
        <<~CONSOLE
          GET /_search
          {
              "query": "foo bar"
          }
        CONSOLE
      end
      it 'has the right content' do
        expect(contents).to eq(expected)
      end
    end
    file_context 'resources/readme/cat.jpg'
    file_context 'resources/readme/chunking-toc.png'
    file_context 'resources/readme/screenshot.png'
  end

  context 'for a book with console alternatives' do
    def self.index
      <<~ASCIIDOC
        = Title

        [[chapter]]
        == Chapter
        #{ConsoleExamples::README_LIKE}
      ASCIIDOC
    end
    convert_before do |src, dest|
      repo = src.repo 'src'
      from = repo.write 'index.asciidoc', index
      repo.commit 'commit outstanding'
      # Points java to a directory without any examples so we can report that.
      convert = dest.prepare_convert_single(from, '.')
                    .alternatives(
                      'console', 'js', "#{__dir__}/../readme_examples/js"
                    )
                    .alternatives(
                      'console', 'csharp',
                      "#{__dir__}/../readme_examples/csharp"
                    )
                    .alternatives('console', 'java', "#{__dir__}/helper")
      convert.convert
    end
    include_examples 'README-like console alternatives', 'raw', '.'
  end

  context 'for a book with an -extra-title-page.html file' do
    INDEX_BODY = <<~ASCIIDOC
      = Title

      [[section]]
      == Section
    ASCIIDOC
    context 'single page' do
      def self.setup(index_name)
        convert_before do |src, dest|
          repo = src.repo 'src'
          from = repo.write index_name, INDEX_BODY
          repo.write 'index-extra-title-page.html', '<p>extra!</p>'
          repo.commit 'commit outstanding'
          dest.prepare_convert_single(from, '.').single.convert
        end
      end
      shared_examples 'has the extra' do
        file_context 'raw/index.html' do
          it 'contains the extra title page' do
            expect(contents).to include("<div>\n<p>extra!</p>\n</div>")
          end
        end
      end
      context 'when the index is .adoc' do
        setup 'index.adoc'
        include_examples 'has the extra'
      end
      context 'when the index is .asciidoc' do
        setup 'index.asciidoc'
        include_examples 'has the extra'
      end
      context 'when the index is .x.asciidoc' do
        setup 'index.x.asciidoc'
        include_examples 'has the extra'
      end
    end
    context 'multipage' do
      convert_before do |src, dest|
        repo = src.repo 'src'
        from = repo.write 'index.adoc', INDEX_BODY
        repo.write 'index-extra-title-page.html', '<p>extra!</p>'
        repo.commit 'commit outstanding'
        dest.prepare_convert_single(from, '.').convert
      end
      file_context 'raw/index.html' do
        it 'contains the extra title page' do
          expect(contents).to include("<div>\n<p>extra!</p>\n</div>")
        end
        it 'still contains the TOC' do
          expect(contents).to include('START_TOC')
          expect(contents).to include('<div class="toc">')
        end
      end
      file_context 'raw/section.html' do
        it "doesn't contain the extra title page" do
          expect(contents).not_to include("<div>\n<p>extra!</p>\n</div>")
        end
      end
    end
  end
  context 'for a book with a -custom-title-page.html file' do
    INDEX_BODY = <<~ASCIIDOC
      = Title

      [[section]]
      == Section
    ASCIIDOC
    context 'built as a single page' do
      convert_before do |src, dest|
        repo = src.repo 'src'
        from = repo.write 'index.asciidoc', INDEX_BODY
        repo.write 'index-custom-title-page.html', '<h1>My Custom Header</h1>'
        repo.commit 'commit outstanding'
        dest.prepare_convert_single(from, '.')
            .single.convert(expect_failure: true)
      end
      it 'prints an error message about being incompatible' do
        expect(outputs[0]).to include(<<~LOG.strip)
          Using a custom title page is incompatible with --single
        LOG
      end
    end
    context 'multipage' do
      convert_before do |src, dest|
        repo = src.repo 'src'
        from = repo.write 'index.adoc', INDEX_BODY
        repo.write 'index-custom-title-page.html', '<h1>My Custom Header</h1>'
        repo.commit 'commit outstanding'
        dest.prepare_convert_single(from, '.').convert
      end
      file_context 'raw/index.html' do
        it 'contains the custom header' do
          expect(contents).to include('<h1>My Custom Header</h1>')
        end
        it 'does not contain the table of contents' do
          expect(contents).not_to include('START_TOC')
          expect(contents).not_to include('<div class="toc">')
        end
      end
      file_context 'raw/section.html' do
        it 'does not contain the custom header' do
          expect(contents).not_to include('My Custom Header')
        end
      end
    end
    context 'and a -extra-title-page.html file' do
      convert_before do |src, dest|
        repo = src.repo 'src'
        from = repo.write 'index.adoc', INDEX_BODY
        repo.write 'index-custom-title-page.html', '<h1>My Custom Header</h1>'
        repo.write 'index-extra-title-page.html', '<h1>My Extra Header</h1>'
        repo.commit 'commit outstanding'
        dest.prepare_convert_single(from, '.').convert(expect_failure: true)
      end
      it 'prints an error about both files existing' do
        expect(outputs[0]).to include(<<~LOG.strip)
          Cannot have both custom and extra title pages for the same source file
        LOG
      end
    end
  end
  context 'for a book with page-header.html' do
    context 'single page' do
      convert_before do |src, dest|
        repo = src.repo 'src'
        from = repo.write 'index.adoc', <<~ASCIIDOC
          = Title

          [[section]]
          == Section

          Words.
        ASCIIDOC
        repo.write 'page_header.html', '<p>header</p>'
        repo.commit 'commit outstanding'
        dest.prepare_convert_single(from, '.').single.convert
      end
      file_context 'raw/index.html' do
        it 'should contain the header' do
          expect(contents).to include '<p>header</p>'
        end
      end
    end
    context 'multipage' do
      convert_before do |src, dest|
        repo = src.repo 'src'
        from = repo.write 'index.adoc', <<~ASCIIDOC
          = Title

          [[section]]
          == Section

          Words.
        ASCIIDOC
        repo.write 'page_header.html', '<p>header</p>'
        repo.commit 'commit outstanding'
        dest.prepare_convert_single(from, '.').convert
      end
      file_context 'raw/index.html' do
        it 'should contain the header' do
          expect(contents).to include '<p>header</p>'
        end
      end
      file_context 'raw/section.html' do
        it 'should contain the header' do
          expect(contents).to include '<p>header</p>'
        end
      end
    end
    context 'with chinese text' do
      # We've failed in the past on Chinese text with encoding issues.
      convert_before do |src, dest|
        repo = src.repo 'src'
        from = repo.write 'index.adoc', <<~ASCIIDOC
          = Title

          [[section]]
          == Section

          Words.
        ASCIIDOC
        repo.write 'page_header.html', '<p>请注意</p>'
        repo.commit 'commit outstanding'
        dest.prepare_convert_single(from, '.').convert
      end
      file_context 'raw/index.html' do
        it 'should contain the header' do
          expect(contents).to include '<p>请注意</p>'
        end
      end
      file_context 'raw/section.html' do
        it 'should contain the header' do
          expect(contents).to include '<p>请注意</p>'
        end
      end
    end
  end

  context 'for a book that uses {source_branch}' do
    INDEX = <<~ASCIIDOC
      = Title

      [[chapter]]
      == Chapter
      The branch is {source_branch}.
    ASCIIDOC
    def self.convert_with_source_branch_before_context(branch)
      convert_single_before_context do |src|
        unless branch == 'master'
          src.write 'dummy', 'needed so git is ok with switching branches'
          src.commit 'dummy'
          src.switch_to_new_branch branch
        end
        src.write 'index.asciidoc', INDEX
      end
    end
    shared_examples 'contains branch' do |branch|
      page_context 'chapter.html' do
        it 'contains the branch name' do
          expect(body).to include("The branch is #{branch}.")
        end
      end
    end
    context 'when the branch is master' do
      convert_with_source_branch_before_context 'master'
      include_examples 'contains branch', 'master'
    end
    context 'when the branch is 7.x' do
      convert_with_source_branch_before_context '7.x'
      include_examples 'contains branch', '7.x'
    end
    context 'when the branch is 1.5' do
      convert_with_source_branch_before_context '1.5'
      include_examples 'contains branch', '1.5'
    end
    context 'when the branch is 18.5' do
      convert_with_source_branch_before_context '18.5'
      include_examples 'contains branch', '18.5'
    end
    context 'when the branch is some_crazy_thing' do
      convert_with_source_branch_before_context 'some_crazy_thing'
      include_examples 'contains branch', 'master'
    end
    context 'when the branch is some_crazy_thing_7.x' do
      convert_with_source_branch_before_context 'some_crazy_thing_7.x'
      include_examples 'contains branch', '7.x'
    end
    context 'when the branch is some_crazy_thing_7_x' do
      convert_with_source_branch_before_context 'some_crazy_thing_7_x'
      include_examples 'contains branch', '7_x'
    end
  end

  context 'when run with --open' do
    include_context 'source and dest'
    before(:context) do
      repo = @src.repo_with_index 'repo', 'Words'
      @opened_docs =
        @dest.prepare_convert_single("#{repo.root}/index.asciidoc", '.').open
    end
    after(:context) do
      @opened_docs.exit
    end

    let(:root) { 'http://localhost:8000/guide' }
    let(:static) { "#{root}/static" }
    let(:index) { Net::HTTP.get_response(URI("#{root}/index.html")) }
    let(:air_gapped_index) do
      uri = URI("#{root}/index.html")
      req = Net::HTTP::Get.new(uri)
      req['Host'] = 'gapped.localhost'
      Net::HTTP.start(uri.hostname, uri.port, read_timeout: 20) do |http|
        http.request(req)
      end
    end
    let(:toc) { Net::HTTP.get_response(URI("#{root}/toc.html")) }
    let(:js) do
      Net::HTTP.get_response(URI("#{static}/docs-v1.js"))
    end
    let(:jquery) do
      Net::HTTP.get_response(URI("#{static}/jquery.js"))
    end
    let(:css) do
      Net::HTTP.get_response(URI("#{static}/styles-v1.css"))
    end

    include_examples 'the root'
    include_examples 'the favicon'

    context 'the index' do
      context 'when not air gapped' do
        it 'contains the gtag js' do
          expect(index).to serve(include(<<~HTML.strip))
            https://www.googletagmanager.com/gtag/js
          HTML
        end
        it 'serves the chapter header' do
          expect(index).to serve(doc_body(include(<<~HTML.strip)))
            <a href="chapter.html">Chapter
          HTML
        end
      end
      context 'when air gapped' do
        it "doesn't contain the gtag js" do
          expect(air_gapped_index).not_to serve(include(<<~HTML.strip))
            https://www.googletagmanager.com/gtag/js
          HTML
        end
        it 'serves the chapter header' do
          expect(air_gapped_index).to serve(doc_body(include(<<~HTML.strip)))
            <a href="chapter.html">Chapter
          HTML
        end
      end
    end
    context 'the table of contents' do
      it "isn't templated" do
        expect(toc).to serve(start_with('<div class="toc">'))
      end
    end

    context 'the js' do
      it 'is unminified' do
        expect(js).to serve(include(<<~JS))
          // Test comment used to detect unminifed JS in tests
        JS
      end
      it 'include hot module replacement for the css' do
        expect(js).to serve(include(<<~JS))
          // Setup hot module replacement for css if we're in dev mode.
        JS
      end
      it 'includes a source map' do
        expect(js).to serve(include('sourceMappingURL='))
      end
    end
    context 'jquery' do
      it 'is unminified' do
        # This comment is a little brittle to detect but I don't expect us to
        # rely on jquery forever.
        expect(jquery).to serve(include(<<~JS))
          Includes Sizzle.js
        JS
      end
      it "doesn't include a source map" do
        expect(jquery).not_to serve(include('sourceMappingURL='))
      end
    end
    context 'the css' do
      it 'is unminified' do
        expect(css).to serve(include(<<~CSS))
          /* test comment used to detect unminified source */
        CSS
      end
      it 'includes a source map' do
        expect(css).to serve(include('sourceMappingURL='))
      end
    end
  end

  ##
  # When you point `build_docs` to a worktree it doesn't properly share the
  # worktree's parent into the docker container. This test simulates *that*.
  context 'when building a book in a worktree without its parent' do
    convert_before do |src, dest|
      repo = src.repo_with_index 'src', <<~ASCIIDOC
        I am in a worktree.
      ASCIIDOC
      worktree = src.path 'worktree'
      repo.create_worktree worktree, 'HEAD'
      FileUtils.rm_rf repo.root
      dest.prepare_convert_single("#{worktree}/index.asciidoc", '.')
          .convert
    end
    page_context 'chapter.html' do
      it 'complains about not being able to find the repo toplevel' do
        expect(outputs[0]).to include("Couldn't find repo toplevel for /tmp/")
      end
      it 'has the worktree text' do
        expect(body).to include('I am in a worktree.')
      end
    end
  end

  context 'when a book contains migration warnings' do
    shared_context 'convert with migration warnings' do |suppress|
      convert_before do |src, dest|
        repo = src.repo_with_index 'src', <<~ASCIIDOC
          --------
          CODE HERE
          ----
        ASCIIDOC
        c = dest.prepare_convert_single("#{repo.root}/index.asciidoc", '.')
        c.suppress_migration_warnings if suppress
        c.convert(expect_failure: !suppress)
      end
    end
    context 'and they are not suppressed' do
      include_context 'convert with migration warnings', false
      it 'fails with an appropriate error status' do
        expect(statuses[0]).to eq(255)
      end
      it 'complains about the MIGRATION warning' do
        expect(outputs[0]).to include(<<~LOG)
          asciidoctor: WARNING: index.asciidoc: line 7: MIGRATION: code block end doesn't match start
        LOG
      end
    end
    context 'and they are suppressed' do
      include_context 'convert with migration warnings', true
      it "doesn't complain about the MIGRATION warning" do
        expect(outputs[0]).not_to include(<<~LOG)
          asciidoctor: WARNING: index.asciidoc: line 7: MIGRATION: code block end doesn't match start
        LOG
      end
      page_context 'chapter.html' do
        it 'contains the snippet' do
          expect(body).to include('CODE HERE')
        end
      end
    end
  end

  context 'when an included file is missing' do
    convert_before do |src, dest|
      repo = src.repo_with_index 'src', <<~ASCIIDOC
        include::missing.asciidoc[]
      ASCIIDOC
      dest.prepare_convert_single("#{repo.root}/index.asciidoc", '.')
          .convert(expect_failure: true)
    end
    it 'fails with an appropriate error status' do
      expect(statuses[0]).to eq(255)
    end
    it 'logs the missing file' do
      expect(outputs[0]).to include(<<~LOG.strip)
        ERROR: index.asciidoc: line 5: include file not found: #{@src.repo('src').root}/missing.asciidoc
      LOG
    end
  end
  context 'when a referenced id is missing' do
    convert_before do |src, dest|
      repo = src.repo_with_index 'src', <<~ASCIIDOC
        <<missing-ref>>
      ASCIIDOC
      dest.prepare_convert_single("#{repo.root}/index.asciidoc", '.')
          .convert(expect_failure: true)
    end
    it 'fails with an appropriate error status' do
      expect(statuses[0]).to eq(255)
    end
    it 'logs the file that contains the missing include' do
      expect(outputs[0]).to include(<<~LOG.strip)
        asciidoctor: WARNING: invalid reference: missing-ref
      LOG
    end
  end
end
