diff options
| author | Guillaume Grossetie <g.grossetie@gmail.com> | 2019-06-14 07:53:08 +0000 |
|---|---|---|
| committer | James Lopez <james@gitlab.com> | 2019-06-14 07:53:08 +0000 |
| commit | 3f5d7c7e1c9a8b5ba53996e8a8f2f4881929b2ea (patch) | |
| tree | 6b8c33c73a5391953e9da8c9d7b7f2c72295cf07 /spec/lib | |
| parent | cd300323c8cc6744c46ef3f732c412226615abbf (diff) | |
| download | gitlab-ce-3f5d7c7e1c9a8b5ba53996e8a8f2f4881929b2ea.tar.gz | |
Add basic support for AsciiDoc include directive
See http://asciidoctor.org/docs/user-manual/#include-directive
Diffstat (limited to 'spec/lib')
| -rw-r--r-- | spec/lib/gitlab/asciidoc_spec.rb | 188 |
1 files changed, 180 insertions, 8 deletions
diff --git a/spec/lib/gitlab/asciidoc_spec.rb b/spec/lib/gitlab/asciidoc_spec.rb index e1782cff81a..0f933ac5464 100644 --- a/spec/lib/gitlab/asciidoc_spec.rb +++ b/spec/lib/gitlab/asciidoc_spec.rb @@ -3,20 +3,23 @@ require 'nokogiri' module Gitlab describe Asciidoc do - let(:input) { '<b>ascii</b>' } - let(:context) { {} } - let(:html) { 'H<sub>2</sub>O' } + include FakeBlobHelpers + + before do + allow_any_instance_of(ApplicationSetting).to receive(:current).and_return(::ApplicationSetting.create_from_defaults) + end context "without project" do - before do - allow_any_instance_of(ApplicationSetting).to receive(:current).and_return(::ApplicationSetting.create_from_defaults) - end + let(:input) { '<b>ascii</b>' } + let(:context) { {} } + let(:html) { 'H<sub>2</sub>O' } it "converts the input using Asciidoctor and default options" do expected_asciidoc_opts = { safe: :secure, backend: :gitlab_html5, - attributes: described_class::DEFAULT_ADOC_ATTRS + attributes: described_class::DEFAULT_ADOC_ATTRS, + extensions: be_a(Proc) } expect(Asciidoctor).to receive(:convert) @@ -30,7 +33,8 @@ module Gitlab expected_asciidoc_opts = { safe: :secure, backend: :gitlab_html5, - attributes: described_class::DEFAULT_ADOC_ATTRS + attributes: described_class::DEFAULT_ADOC_ATTRS, + extensions: be_a(Proc) } expect(Asciidoctor).to receive(:convert) @@ -105,6 +109,174 @@ module Gitlab end end + context 'with project' do + let(:context) do + { + commit: commit, + project: project, + ref: ref, + requested_path: requested_path + } + end + let(:commit) { project.commit(ref) } + let(:project) { create(:project, :repository) } + let(:ref) { 'asciidoc' } + let(:requested_path) { '/' } + + context 'include directive' do + subject(:output) { render(input, context) } + + let(:input) { "Include this:\n\ninclude::#{include_path}[]" } + + before do + current_file = requested_path + current_file += 'README.adoc' if requested_path.end_with? '/' + + create_file(current_file, "= AsciiDoc\n") + end + + context 'with path to non-existing file' do + let(:include_path) { 'not-exists.adoc' } + + it 'renders Unresolved directive placeholder' do + is_expected.to include("<strong>[ERROR: include::#{include_path}[] - unresolved directive]</strong>") + end + end + + shared_examples :invalid_include do + let(:include_path) { 'dk.png' } + + before do + allow(project.repository).to receive(:blob_at).and_return(blob) + end + + it 'does not read the blob' do + expect(blob).not_to receive(:data) + end + + it 'renders Unresolved directive placeholder' do + is_expected.to include("<strong>[ERROR: include::#{include_path}[] - unresolved directive]</strong>") + end + end + + context 'with path to a binary file' do + let(:blob) { fake_blob(path: 'dk.png', binary: true) } + include_examples :invalid_include + end + + context 'with path to file in external storage' do + let(:blob) { fake_blob(path: 'dk.png', lfs: true) } + + before do + allow(Gitlab.config.lfs).to receive(:enabled).and_return(true) + project.update_attribute(:lfs_enabled, true) + end + + include_examples :invalid_include + end + + context 'with path to a textual file' do + let(:include_path) { 'sample.adoc' } + + before do + create_file(file_path, "Content from #{include_path}") + end + + shared_examples :valid_include do + [ + ['/doc/sample.adoc', 'doc/sample.adoc', 'absolute path'], + ['sample.adoc', 'doc/api/sample.adoc', 'relative path'], + ['./sample.adoc', 'doc/api/sample.adoc', 'relative path with leading ./'], + ['../sample.adoc', 'doc/sample.adoc', 'relative path to a file up one directory'], + ['../../sample.adoc', 'sample.adoc', 'relative path for a file up multiple directories'] + ].each do |include_path_, file_path_, desc| + + context "the file is specified by #{desc}" do + let(:include_path) { include_path_ } + let(:file_path) { file_path_ } + + it 'includes content of the file' do + is_expected.to include('<p>Include this:</p>') + is_expected.to include("<p>Content from #{include_path}</p>") + end + end + end + end + + context 'when requested path is a file in the repo' do + let(:requested_path) { 'doc/api/README.adoc' } + + include_examples :valid_include + + context 'without a commit (only ref)' do + let(:commit) { nil } + include_examples :valid_include + end + end + + context 'when requested path is a directory in the repo' do + let(:requested_path) { 'doc/api/' } + + include_examples :valid_include + + context 'without a commit (only ref)' do + let(:commit) { nil } + include_examples :valid_include + end + end + end + + context 'recursive includes with relative paths' do + let(:input) do + <<~ADOC + Source: requested file + + include::doc/README.adoc[] + + include::license.adoc[] + ADOC + end + + before do + create_file 'doc/README.adoc', <<~ADOC + Source: doc/README.adoc + + include::../license.adoc[] + + include::api/hello.adoc[] + ADOC + create_file 'license.adoc', <<~ADOC + Source: license.adoc + ADOC + create_file 'doc/api/hello.adoc', <<~ADOC + Source: doc/api/hello.adoc + + include::./common.adoc[] + ADOC + create_file 'doc/api/common.adoc', <<~ADOC + Source: doc/api/common.adoc + ADOC + end + + it 'includes content of the included files recursively' do + expect(output.gsub(/<[^>]+>/, '').gsub(/\n\s*/, "\n").strip).to eq <<~ADOC.strip + Source: requested file + Source: doc/README.adoc + Source: license.adoc + Source: doc/api/hello.adoc + Source: doc/api/common.adoc + Source: license.adoc + ADOC + end + end + + def create_file(path, content) + project.repository.create_file(project.creator, path, content, + message: "Add #{path}", branch_name: 'asciidoc') + end + end + end + def render(*args) described_class.render(*args) end |
