resources/asciidoctor/spec/elastic_compat_preprocessor_spec.rb (434 lines of code) (raw):

# frozen_string_literal: true require 'care_admonition/extension' require 'change_admonition/extension' require 'docbook_compat/extension' require 'elastic_compat_preprocessor/extension' require 'elastic_compat_tree_processor/extension' require 'elastic_include_tagged/extension' require 'lang_override/extension' require 'open_in_widget/extension' require 'shared_examples/does_not_break_line_numbers' RSpec.describe ElasticCompatPreprocessor do before(:each) do Asciidoctor::Extensions.register CareAdmonition Asciidoctor::Extensions.register ChangeAdmonition Asciidoctor::Extensions.register DocbookCompat Asciidoctor::Extensions.register OpenInWidget Asciidoctor::Extensions.register do block_macro LangOverride preprocessor ElasticCompatPreprocessor include_processor ElasticIncludeTagged treeprocessor ElasticCompatTreeProcessor end end after(:each) do Asciidoctor::Extensions.unregister_all end let(:spec_dir) { File.dirname(__FILE__) } include_examples "doesn't break line numbers" context 'admonitions' do shared_examples 'admonition' do include_context 'convert without logs' shared_examples 'invokes the block macro' do it 'invokes the block macro' do expect(converted).to include <<~HTML.strip <div class="#{block_admon_class} admon"> HTML end end context 'when the admonition is alone on a line' do let(:input) { invocation } include_examples 'invokes the block macro' end context 'when the admonition has spaces before it' do let(:input) { " #{invocation}" } include_examples 'invokes the block macro' end context 'when the admonition has spaces after it' do let(:input) { "#{invocation} " } include_examples 'invokes the block macro' end context 'when the admonition has a `]` in it' do let(:invocation_text) { 'link:link.html[Title]' } let(:input) { invocation_with_text } it 'includes the correct body' do expect(converted).to include <<~HTML <p><a href="link.html" class="ulink" target="_top">Title</a></p> HTML end end shared_examples 'invokes the inline macro' do it 'invokes the inline macro' do expect(converted).to include <<~HTML <span class="Admonishment Admonishment--#{inline_admon_class}"> HTML end end context 'when the admonition is surrounded by other text' do let(:input) { "words #{invocation} words" } include_examples 'invokes the inline macro' end context 'when the admonition has text before it' do let(:input) { "words #{invocation}" } include_examples 'invokes the inline macro' end context 'when the admonition has text after it' do let(:input) { "#{invocation} words" } include_examples 'invokes the inline macro' end context 'when the admonition is skipped' do let(:input) do <<~ASCIIDOC words before skip ifeval::["true" == "false"] #{invocation} endif::[] words after skip ASCIIDOC end it 'skips the admonition' do expect(converted).not_to include('Admonishment') end it 'properly converts the rest of the text' do expect(converted).to include('words before skip') expect(converted).to include('words after skip') end end end shared_examples 'change admonition' do include_examples 'admonition' let(:invocation) { "#{name}[some_version]" } let(:invocation_with_text) { "#{name}[some_version, #{invocation_text}]" } end context 'for added' do include_context 'change admonition' let(:name) { 'added' } let(:block_admon_class) { 'note' } let(:inline_admon_class) { 'change' } end context 'for coming' do include_context 'change admonition' let(:name) { 'coming' } let(:block_admon_class) { 'note' } let(:inline_admon_class) { 'change' } end context 'for deprecated' do include_context 'change admonition' let(:name) { 'deprecated' } let(:block_admon_class) { 'warning' } let(:inline_admon_class) { 'change' } end shared_examples 'care admonition' do include_examples 'admonition' let(:invocation) { "#{name}[]" } let(:invocation_with_text) { "#{name}[#{invocation_text}]" } let(:block_admon_class) { 'warning' } end context 'for beta' do include_context 'care admonition' let(:name) { 'beta' } let(:inline_admon_class) { 'beta' } end context 'for dev' do include_context 'care admonition' let(:name) { 'dev' } let(:inline_admon_class) { 'dev' } end context 'for experimental' do include_context 'care admonition' let(:name) { 'experimental' } let(:inline_admon_class) { 'preview' } end end context 'when the document contains include-tagged::' do # include-tagged:: was a macro we built for AsciiDoc for tagged includes # from files. It doesn't have exactly the same form as the include directive # that we use with asciidoctor so the processor morphs it. include_context 'convert without logs' let(:input) do <<~ASCIIDOC [source,java] ---- include-tagged::resources/elastic_include_tagged/Example.java[t1] ---- ASCIIDOC end it 'it includes the tagged portion of the file' do expect(converted).to include <<~JAVA.strip System.err.println("I'm an example"); for (int i = 0; i &lt; 10; i++) { System.err.println(i); <a id="CO1-1"></a><i class="conum" data-value="1"></i> } JAVA end end context 'when the document a block containing only attributes' do include_context 'convert without logs' let(:input) do <<~ASCIIDOC :inheader: foo = Test -- :outheader: bar -- [id="{inheader}-{outheader}"] == Header <<{inheader}-{outheader}>> ASCIIDOC end it 'uses the attributes for the header' do expect(converted).to include <<~HTML <h2 class="title"><a id="foo-bar"></a>Header</h2></div> HTML end it 'uses the attributes outside of the header' do expect(converted).to include <<~HTML.strip <a class="xref" href="#foo-bar" title="Header"><em>Header</em></a> HTML end context 'when it is followed by other complex processing' do let(:input) do <<~ASCIIDOC :inheader: foo = Test -- :outheader: bar -- == Header added[some_version] ASCIIDOC end it 'the processing works as expected' do expect(converted).to include <<~HTML <p>Added in some_version.</p> HTML end end end context 'when a block contains no attributes' do include_context 'convert without logs' let(:input) do <<~ASCIIDOC == Header -- added[some_version] -- ASCIIDOC end it 'the contents of the block are processed normally' do expect(converted).to include <<~HTML <p>Added in some_version.</p> HTML end end context 'when a block contains some attributes and other things' do include_context 'convert without logs' let(:input) do <<~ASCIIDOC -- :attr: test added::[some_version] -- {attr} ASCIIDOC end it "doesn't remove the block" do # The point here is that the attribute setting *doesn't* apply to the # text because we haven't doctored the block. expect(converted).to include('<p>{attr}</p>') end end context "when a source block doesn't have callouts" do include_context 'convert without logs' let(:input) do <<~ASCIIDOC == Example ["source","sh",subs="attributes"] -------------------------------------------- cd elasticsearch-{version}/ <1> -------------------------------------------- <1> This directory is known as `$ES_HOME`. ASCIIDOC end it 'processes callouts anyway' do expect(converted).to include <<~HTML.strip cd elasticsearch-{version}/ <a id="CO1-1"></a><i class="conum" data-value="1"></i> HTML end context 'when the block is skipped' do let(:input) do <<~ASCIIDOC == Example ifeval::["true" == "false"] ["source","sh",subs="attributes"] -------------------------------------------- cd elasticsearch-{version}/ <1> -------------------------------------------- <1> This directory is known as `$ES_HOME`. endif::[] ASCIIDOC end it 'skips the block' do expect(converted).to eq <<~HTML <div class="chapter"> <div class="titlepage"><div><div> <div class="position-relative"><h2 class="title"><a id="_example"></a>Example</h2></div> </div></div></div> </div> HTML end end end context 'when there is a code block with a mismatched start and end' do include_context 'convert with logs' let(:input) do <<~ASCIIDOC ---- foo -------- ASCIIDOC end it 'renders the code block' do expect(converted).to include('<pre class="screen">foo</pre>') end it 'logs a migration warning' do expect(logs).to eq(<<~LOGS.strip) WARN: <stdin>: line 3: MIGRATION: code block end doesn't match start LOGS end context 'when the block is skipped' do let(:input) do <<~ASCIIDOC == Example ifeval::["true" == "false"] ---- foo -------- endif::[] ASCIIDOC end it 'skips the block' do expect(converted).to eq <<~HTML <div class="chapter"> <div class="titlepage"><div><div> <div class="position-relative"><h2 class="title"><a id="_example"></a>Example</h2></div> </div></div></div> </div> HTML end it "doesn't log anything" do expect(logs).to eq('') end end end context 'when a code block contains table-style outputs' do include_context 'convert with logs' let(:table) do <<~TEXT.strip author | name | page_count | release_date ---------------+---------------+---------------+------------------------ Dan Simmons |Hyperion |482 |1989-05-26T00:00:00.000Z Frank Herbert |Dune |604 |1965-06-01T00:00:00.000Z TEXT end let(:input) do <<~ASCIIDOC -------------------------------------------------- #{table} -------------------------------------------------- ASCIIDOC end it 'preservers the table' do expect(converted).to include(%(<pre class="screen">#{table}</pre>)) end end shared_context 'general snippet' do |lang, override| include_context 'convert with logs' let(:convert_attributes) do { 'copy_snippet' => proc { |uri, source| }, 'write_snippet' => proc { |uri, source| }, } end let(:snippet) do snippet = <<~ASCIIDOC [source,js] ---- GET / <1> ---- ASCIIDOC snippet += override if override snippet end let(:lang_declaration) { %(<div class="pre_wrapper lang-#{lang}">) } let(:input) do <<~ASCIIDOC == Example #{snippet} ASCIIDOC end end shared_examples 'linked snippet' do |override, lang, path| shared_examples 'converted with override' do it "has the #{lang} language" do expect(converted).to include(lang_declaration) end it 'have a link to the snippet' do expect(converted).to include(%(data-snippet="#{path}")) end end context 'when there is a space after //' do include_context 'general snippet', lang, "// #{override}" include_examples 'converted with override' end context 'when there is not a space after //' do include_context 'general snippet', lang, "//#{override}" include_examples 'converted with override' end context 'when there is a space after the override command' do include_context 'general snippet', lang, "// #{override} " include_examples 'converted with override' end end shared_examples 'extracted linked snippet' do |override, lang| context "for a snippet with the #{override} lang override" do let(:expected_warnings) do "INFO: <stdin>: line 3: writing snippet snippets/1.#{lang}" end include_examples 'linked snippet', override, lang, "snippets/1.#{lang}" end end include_examples 'extracted linked snippet', 'CONSOLE', 'console' include_examples 'extracted linked snippet', 'AUTOSENSE', 'sense' include_examples 'extracted linked snippet', 'KIBANA', 'kibana' context 'for a snippet with the SENSE override pointing to a specific path' do let(:expected_warnings) do <<~WARNINGS INFO: <stdin>: line 3: copying snippet #{spec_dir}/snippets/snippet.sense WARN: <stdin>: line 3: MIGRATION: reading snippets from a path makes the book harder to read WARNINGS end include_examples( 'linked snippet', 'SENSE: snippet.sense', 'sense', 'snippets/snippet.sense' ) end context 'for a snippet without an override' do include_context 'general snippet', 'js', nil let(:has_any_link) { /<ulink type="snippet"/ } it 'has the js language' do expect(converted).to include(lang_declaration) end it 'not have a link to any snippet' do expect(converted).not_to match(has_any_link) end end context 'when a file is included with leveloffset' do include_context 'convert without logs' let(:input) do <<~ASCIIDOC = Foo include::resources/elastic_compat_preprocessor/target.adoc[leveloffset=+1] ASCIIDOC end it 'has the right offset' do expect(converted).to include <<~HTML <h2 class="title"><a id="_target"></a>Target</h2></div> HTML end end end