summaryrefslogtreecommitdiff
path: root/spec/lib/banzai
diff options
context:
space:
mode:
Diffstat (limited to 'spec/lib/banzai')
-rw-r--r--spec/lib/banzai/filter/commit_range_reference_filter_spec.rb15
-rw-r--r--spec/lib/banzai/filter/commit_reference_filter_spec.rb15
-rw-r--r--spec/lib/banzai/filter/inline_diff_filter_spec.rb68
-rw-r--r--spec/lib/banzai/filter/issue_reference_filter_spec.rb25
-rw-r--r--spec/lib/banzai/filter/label_reference_filter_spec.rb10
-rw-r--r--spec/lib/banzai/filter/merge_request_reference_filter_spec.rb15
-rw-r--r--spec/lib/banzai/filter/milestone_reference_filter_spec.rb145
-rw-r--r--spec/lib/banzai/filter/redactor_filter_spec.rb38
-rw-r--r--spec/lib/banzai/filter/reference_filter_spec.rb45
-rw-r--r--spec/lib/banzai/filter/reference_gatherer_filter_spec.rb87
-rw-r--r--spec/lib/banzai/filter/sanitization_filter_spec.rb6
-rw-r--r--spec/lib/banzai/filter/snippet_reference_filter_spec.rb15
-rw-r--r--spec/lib/banzai/filter/upload_link_filter_spec.rb18
-rw-r--r--spec/lib/banzai/filter/user_reference_filter_spec.rb50
-rw-r--r--spec/lib/banzai/pipeline/wiki_pipeline_spec.rb108
-rw-r--r--spec/lib/banzai/reference_parser/base_parser_spec.rb237
-rw-r--r--spec/lib/banzai/reference_parser/commit_parser_spec.rb113
-rw-r--r--spec/lib/banzai/reference_parser/commit_range_parser_spec.rb120
-rw-r--r--spec/lib/banzai/reference_parser/external_issue_parser_spec.rb62
-rw-r--r--spec/lib/banzai/reference_parser/issue_parser_spec.rb79
-rw-r--r--spec/lib/banzai/reference_parser/label_parser_spec.rb31
-rw-r--r--spec/lib/banzai/reference_parser/merge_request_parser_spec.rb30
-rw-r--r--spec/lib/banzai/reference_parser/milestone_parser_spec.rb31
-rw-r--r--spec/lib/banzai/reference_parser/snippet_parser_spec.rb31
-rw-r--r--spec/lib/banzai/reference_parser/user_parser_spec.rb189
25 files changed, 1340 insertions, 243 deletions
diff --git a/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb b/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb
index c2a8ad36c30..593bd6d5cac 100644
--- a/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb
@@ -98,11 +98,6 @@ describe Banzai::Filter::CommitRangeReferenceFilter, lib: true do
expect(link).not_to match %r(https?://)
expect(link).to eq urls.namespace_project_compare_url(project.namespace, project, from: commit1.id, to: commit2.id, only_path: true)
end
-
- it 'adds to the results hash' do
- result = reference_pipeline_result("See #{reference}")
- expect(result[:references][:commit_range]).not_to be_empty
- end
end
context 'cross-project reference' do
@@ -135,11 +130,6 @@ describe Banzai::Filter::CommitRangeReferenceFilter, lib: true do
exp = act = "Fixed #{project2.to_reference}@#{commit1.id}...#{commit2.id.reverse}"
expect(reference_filter(act).to_html).to eq exp
end
-
- it 'adds to the results hash' do
- result = reference_pipeline_result("See #{reference}")
- expect(result[:references][:commit_range]).not_to be_empty
- end
end
context 'cross-project URL reference' do
@@ -173,10 +163,5 @@ describe Banzai::Filter::CommitRangeReferenceFilter, lib: true do
exp = act = "Fixed #{project2.to_reference}@#{commit1.id}...#{commit2.id.reverse}"
expect(reference_filter(act).to_html).to eq exp
end
-
- it 'adds to the results hash' do
- result = reference_pipeline_result("See #{reference}")
- expect(result[:references][:commit_range]).not_to be_empty
- end
end
end
diff --git a/spec/lib/banzai/filter/commit_reference_filter_spec.rb b/spec/lib/banzai/filter/commit_reference_filter_spec.rb
index 63a32d9d455..d46d3f1489e 100644
--- a/spec/lib/banzai/filter/commit_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/commit_reference_filter_spec.rb
@@ -93,11 +93,6 @@ describe Banzai::Filter::CommitReferenceFilter, lib: true do
expect(link).not_to match %r(https?://)
expect(link).to eq urls.namespace_project_commit_url(project.namespace, project, reference, only_path: true)
end
-
- it 'adds to the results hash' do
- result = reference_pipeline_result("See #{reference}")
- expect(result[:references][:commit]).not_to be_empty
- end
end
context 'cross-project reference' do
@@ -124,11 +119,6 @@ describe Banzai::Filter::CommitReferenceFilter, lib: true do
exp = act = "Committed #{invalidate_reference(reference)}"
expect(reference_filter(act).to_html).to eq exp
end
-
- it 'adds to the results hash' do
- result = reference_pipeline_result("See #{reference}")
- expect(result[:references][:commit]).not_to be_empty
- end
end
context 'cross-project URL reference' do
@@ -154,10 +144,5 @@ describe Banzai::Filter::CommitReferenceFilter, lib: true do
act = "Committed #{invalidate_reference(reference)}"
expect(reference_filter(act).to_html).to match(/<a.+>#{Regexp.escape(invalidate_reference(reference))}<\/a>/)
end
-
- it 'adds to the results hash' do
- result = reference_pipeline_result("See #{reference}")
- expect(result[:references][:commit]).not_to be_empty
- end
end
end
diff --git a/spec/lib/banzai/filter/inline_diff_filter_spec.rb b/spec/lib/banzai/filter/inline_diff_filter_spec.rb
new file mode 100644
index 00000000000..9e526371294
--- /dev/null
+++ b/spec/lib/banzai/filter/inline_diff_filter_spec.rb
@@ -0,0 +1,68 @@
+require 'spec_helper'
+
+describe Banzai::Filter::InlineDiffFilter, lib: true do
+ include FilterSpecHelper
+
+ it 'adds inline diff span tags for deletions when using square brackets' do
+ doc = "START [-something deleted-] END"
+ expect(filter(doc).to_html).to eq('START <span class="idiff left right deletion">something deleted</span> END')
+ end
+
+ it 'adds inline diff span tags for deletions when using curley braces' do
+ doc = "START {-something deleted-} END"
+ expect(filter(doc).to_html).to eq('START <span class="idiff left right deletion">something deleted</span> END')
+ end
+
+ it 'does not add inline diff span tags when a closing tag is not provided' do
+ doc = "START [- END"
+ expect(filter(doc).to_html).to eq(doc)
+ end
+
+ it 'adds inline span tags for additions when using square brackets' do
+ doc = "START [+something added+] END"
+ expect(filter(doc).to_html).to eq('START <span class="idiff left right addition">something added</span> END')
+ end
+
+ it 'adds inline span tags for additions when using curley braces' do
+ doc = "START {+something added+} END"
+ expect(filter(doc).to_html).to eq('START <span class="idiff left right addition">something added</span> END')
+ end
+
+ it 'does not add inline diff span tags when a closing addition tag is not provided' do
+ doc = "START {+ END"
+ expect(filter(doc).to_html).to eq(doc)
+ end
+
+ it 'does not add inline diff span tags when the tags do not match' do
+ examples = [
+ "{+ additions +]",
+ "[+ additions +}",
+ "{- delletions -]",
+ "[- delletions -}"
+ ]
+
+ examples.each do |doc|
+ expect(filter(doc).to_html).to eq(doc)
+ end
+ end
+
+ it 'prevents user-land html being injected' do
+ doc = "START {+&lt;script&gt;alert('I steal cookies')&lt;/script&gt;+} END"
+ expect(filter(doc).to_html).to eq("START <span class=\"idiff left right addition\">&lt;script&gt;alert('I steal cookies')&lt;/script&gt;</span> END")
+ end
+
+ it 'preserves content inside pre tags' do
+ doc = "<pre>START {+something added+} END</pre>"
+ expect(filter(doc).to_html).to eq(doc)
+ end
+
+ it 'preserves content inside code tags' do
+ doc = "<code>START {+something added+} END</code>"
+ expect(filter(doc).to_html).to eq(doc)
+ end
+
+ it 'preserves content inside tt tags' do
+ doc = "<tt>START {+something added+} END</tt>"
+ expect(filter(doc).to_html).to eq(doc)
+ end
+end
diff --git a/spec/lib/banzai/filter/issue_reference_filter_spec.rb b/spec/lib/banzai/filter/issue_reference_filter_spec.rb
index 266ebef33d6..8e6a264970d 100644
--- a/spec/lib/banzai/filter/issue_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/issue_reference_filter_spec.rb
@@ -91,11 +91,6 @@ describe Banzai::Filter::IssueReferenceFilter, lib: true do
expect(link).to eq helper.url_for_issue(issue.iid, project, only_path: true)
end
- it 'adds to the results hash' do
- result = reference_pipeline_result("Fixed #{reference}")
- expect(result[:references][:issue]).to eq [issue]
- end
-
it 'does not process links containing issue numbers followed by text' do
href = "#{reference}st"
doc = reference_filter("<a href='#{href}'></a>")
@@ -136,11 +131,6 @@ describe Banzai::Filter::IssueReferenceFilter, lib: true do
expect(reference_filter(act).to_html).to eq exp
end
-
- it 'adds to the results hash' do
- result = reference_pipeline_result("Fixed #{reference}")
- expect(result[:references][:issue]).to eq [issue]
- end
end
context 'cross-project URL reference' do
@@ -160,11 +150,6 @@ describe Banzai::Filter::IssueReferenceFilter, lib: true do
doc = reference_filter("Fixed (#{reference}.)")
expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(issue.to_reference(project))} \(comment 123\)<\/a>\.\)/)
end
-
- it 'adds to the results hash' do
- result = reference_pipeline_result("Fixed #{reference}")
- expect(result[:references][:issue]).to eq [issue]
- end
end
context 'cross-project reference in link href' do
@@ -184,11 +169,6 @@ describe Banzai::Filter::IssueReferenceFilter, lib: true do
doc = reference_filter("Fixed (#{reference}.)")
expect(doc.to_html).to match(/\(<a.+>Reference<\/a>\.\)/)
end
-
- it 'adds to the results hash' do
- result = reference_pipeline_result("Fixed #{reference}")
- expect(result[:references][:issue]).to eq [issue]
- end
end
context 'cross-project URL in link href' do
@@ -208,10 +188,5 @@ describe Banzai::Filter::IssueReferenceFilter, lib: true do
doc = reference_filter("Fixed (#{reference}.)")
expect(doc.to_html).to match(/\(<a.+>Reference<\/a>\.\)/)
end
-
- it 'adds to the results hash' do
- result = reference_pipeline_result("Fixed #{reference}")
- expect(result[:references][:issue]).to eq [issue]
- end
end
end
diff --git a/spec/lib/banzai/filter/label_reference_filter_spec.rb b/spec/lib/banzai/filter/label_reference_filter_spec.rb
index b0a38e7c251..f1064a701d8 100644
--- a/spec/lib/banzai/filter/label_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/label_reference_filter_spec.rb
@@ -48,11 +48,6 @@ describe Banzai::Filter::LabelReferenceFilter, lib: true do
expect(link).to eq urls.namespace_project_issues_path(project.namespace, project, label_name: label.name)
end
- it 'adds to the results hash' do
- result = reference_pipeline_result("Label #{reference}")
- expect(result[:references][:label]).to eq [label]
- end
-
describe 'label span element' do
it 'includes default classes' do
doc = reference_filter("Label #{reference}")
@@ -170,11 +165,6 @@ describe Banzai::Filter::LabelReferenceFilter, lib: true do
expect(link).to have_attribute('data-label')
expect(link.attr('data-label')).to eq label.id.to_s
end
-
- it 'adds to the results hash' do
- result = reference_pipeline_result("Label #{reference}")
- expect(result[:references][:label]).to eq [label]
- end
end
describe 'cross project label references' do
diff --git a/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb b/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb
index 352710df307..3185e41fe5c 100644
--- a/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb
@@ -78,11 +78,6 @@ describe Banzai::Filter::MergeRequestReferenceFilter, lib: true do
expect(link).not_to match %r(https?://)
expect(link).to eq urls.namespace_project_merge_request_url(project.namespace, project, merge, only_path: true)
end
-
- it 'adds to the results hash' do
- result = reference_pipeline_result("Merge #{reference}")
- expect(result[:references][:merge_request]).to eq [merge]
- end
end
context 'cross-project reference' do
@@ -109,11 +104,6 @@ describe Banzai::Filter::MergeRequestReferenceFilter, lib: true do
expect(reference_filter(act).to_html).to eq exp
end
-
- it 'adds to the results hash' do
- result = reference_pipeline_result("Merge #{reference}")
- expect(result[:references][:merge_request]).to eq [merge]
- end
end
context 'cross-project URL reference' do
@@ -133,10 +123,5 @@ describe Banzai::Filter::MergeRequestReferenceFilter, lib: true do
doc = reference_filter("Merge (#{reference}.)")
expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(merge.to_reference(project))} \(diffs, comment 123\)<\/a>\.\)/)
end
-
- it 'adds to the results hash' do
- result = reference_pipeline_result("Merge #{reference}")
- expect(result[:references][:merge_request]).to eq [merge]
- end
end
end
diff --git a/spec/lib/banzai/filter/milestone_reference_filter_spec.rb b/spec/lib/banzai/filter/milestone_reference_filter_spec.rb
index ebf3d7489b5..9424f2363e1 100644
--- a/spec/lib/banzai/filter/milestone_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/milestone_reference_filter_spec.rb
@@ -3,8 +3,9 @@ require 'spec_helper'
describe Banzai::Filter::MilestoneReferenceFilter, lib: true do
include FilterSpecHelper
- let(:project) { create(:project, :public) }
- let(:milestone) { create(:milestone, project: project) }
+ let(:project) { create(:project, :public) }
+ let(:milestone) { create(:milestone, project: project) }
+ let(:reference) { milestone.to_reference }
it 'requires project context' do
expect { described_class.call('') }.to raise_error(ArgumentError, /:project/)
@@ -17,11 +18,37 @@ describe Banzai::Filter::MilestoneReferenceFilter, lib: true do
end
end
- context 'internal reference' do
- # Convert the Markdown link to only the URL, since these tests aren't run through the regular Markdown pipeline.
- # Milestone reference behavior in the full Markdown pipeline is tested elsewhere.
- let(:reference) { milestone.to_reference.gsub(/\[([^\]]+)\]\(([^)]+)\)/, '\2') }
+ it 'includes default classes' do
+ doc = reference_filter("Milestone #{reference}")
+ expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-milestone'
+ end
+
+ it 'includes a data-project attribute' do
+ doc = reference_filter("Milestone #{reference}")
+ link = doc.css('a').first
+
+ expect(link).to have_attribute('data-project')
+ expect(link.attr('data-project')).to eq project.id.to_s
+ end
+
+ it 'includes a data-milestone attribute' do
+ doc = reference_filter("See #{reference}")
+ link = doc.css('a').first
+
+ expect(link).to have_attribute('data-milestone')
+ expect(link.attr('data-milestone')).to eq milestone.id.to_s
+ end
+
+ it 'supports an :only_path context' do
+ doc = reference_filter("Milestone #{reference}", only_path: true)
+ link = doc.css('a').first.attr('href')
+ expect(link).not_to match %r(https?://)
+ expect(link).to eq urls.
+ namespace_project_milestone_path(project.namespace, project, milestone)
+ end
+
+ context 'Integer-based references' do
it 'links to a valid reference' do
doc = reference_filter("See #{reference}")
@@ -30,29 +57,82 @@ describe Banzai::Filter::MilestoneReferenceFilter, lib: true do
end
it 'links with adjacent text' do
- doc = reference_filter("milestone (#{reference}.)")
- expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(milestone.title)}<\/a>\.\)/)
+ doc = reference_filter("Milestone (#{reference}.)")
+ expect(doc.to_html).to match(%r(\(<a.+>#{milestone.name}</a>\.\)))
end
- it 'includes a title attribute' do
- doc = reference_filter("milestone #{reference}")
- expect(doc.css('a').first.attr('title')).to eq "Milestone: #{milestone.title}"
+ it 'ignores invalid milestone IIDs' do
+ exp = act = "Milestone #{invalidate_reference(reference)}"
+
+ expect(reference_filter(act).to_html).to eq exp
end
+ end
+
+ context 'String-based single-word references' do
+ let(:milestone) { create(:milestone, name: 'gfm', project: project) }
+ let(:reference) { "#{Milestone.reference_prefix}#{milestone.name}" }
+
+ it 'links to a valid reference' do
+ doc = reference_filter("See #{reference}")
- it 'escapes the title attribute' do
- milestone.update_attribute(:title, %{"></a>whatever<a title="})
+ expect(doc.css('a').first.attr('href')).to eq urls.
+ namespace_project_milestone_url(project.namespace, project, milestone)
+ expect(doc.text).to eq 'See gfm'
+ end
- doc = reference_filter("milestone #{reference}")
- expect(doc.text).to eq "milestone #{milestone.title}"
+ it 'links with adjacent text' do
+ doc = reference_filter("Milestone (#{reference}.)")
+ expect(doc.to_html).to match(%r(\(<a.+>#{milestone.name}</a>\.\)))
end
- it 'includes default classes' do
- doc = reference_filter("milestone #{reference}")
- expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-milestone'
+ it 'ignores invalid milestone names' do
+ exp = act = "Milestone #{Milestone.reference_prefix}#{milestone.name.reverse}"
+
+ expect(reference_filter(act).to_html).to eq exp
+ end
+ end
+
+ context 'String-based multi-word references in quotes' do
+ let(:milestone) { create(:milestone, name: 'gfm references', project: project) }
+ let(:reference) { milestone.to_reference(format: :name) }
+
+ it 'links to a valid reference' do
+ doc = reference_filter("See #{reference}")
+
+ expect(doc.css('a').first.attr('href')).to eq urls.
+ namespace_project_milestone_url(project.namespace, project, milestone)
+ expect(doc.text).to eq 'See gfm references'
+ end
+
+ it 'links with adjacent text' do
+ doc = reference_filter("Milestone (#{reference}.)")
+ expect(doc.to_html).to match(%r(\(<a.+>#{milestone.name}</a>\.\)))
+ end
+
+ it 'ignores invalid milestone names' do
+ exp = act = %(Milestone #{Milestone.reference_prefix}"#{milestone.name.reverse}")
+
+ expect(reference_filter(act).to_html).to eq exp
+ end
+ end
+
+ describe 'referencing a milestone in a link href' do
+ let(:reference) { %Q{<a href="#{milestone.to_reference}">Milestone</a>} }
+
+ it 'links to a valid reference' do
+ doc = reference_filter("See #{reference}")
+
+ expect(doc.css('a').first.attr('href')).to eq urls.
+ namespace_project_milestone_url(project.namespace, project, milestone)
+ end
+
+ it 'links with adjacent text' do
+ doc = reference_filter("Milestone (#{reference}.)")
+ expect(doc.to_html).to match(%r(\(<a.+>Milestone</a>\.\)))
end
it 'includes a data-project attribute' do
- doc = reference_filter("milestone #{reference}")
+ doc = reference_filter("Milestone #{reference}")
link = doc.css('a').first
expect(link).to have_attribute('data-project')
@@ -66,10 +146,31 @@ describe Banzai::Filter::MilestoneReferenceFilter, lib: true do
expect(link).to have_attribute('data-milestone')
expect(link.attr('data-milestone')).to eq milestone.id.to_s
end
+ end
+
+ describe 'cross project milestone references' do
+ let(:another_project) { create(:empty_project, :public) }
+ let(:project_path) { another_project.path_with_namespace }
+ let(:milestone) { create(:milestone, project: another_project) }
+ let(:reference) { milestone.to_reference(project) }
+
+ let!(:result) { reference_filter("See #{reference}") }
+
+ it 'points to referenced project milestone page' do
+ expect(result.css('a').first.attr('href')).to eq urls.
+ namespace_project_milestone_url(another_project.namespace,
+ another_project,
+ milestone)
+ end
- it 'adds to the results hash' do
- result = reference_pipeline_result("milestone #{reference}")
- expect(result[:references][:milestone]).to eq [milestone]
+ it 'contains cross project content' do
+ expect(result.css('a').first.text).to eq "#{milestone.name} in #{project_path}"
+ end
+
+ it 'escapes the name attribute' do
+ allow_any_instance_of(Milestone).to receive(:title).and_return(%{"></a>whatever<a title="})
+ doc = reference_filter("See #{reference}")
+ expect(doc.css('a').first.text).to eq "#{milestone.name} in #{project_path}"
end
end
end
diff --git a/spec/lib/banzai/filter/redactor_filter_spec.rb b/spec/lib/banzai/filter/redactor_filter_spec.rb
index c2c2fd0eb6a..697d10bbf70 100644
--- a/spec/lib/banzai/filter/redactor_filter_spec.rb
+++ b/spec/lib/banzai/filter/redactor_filter_spec.rb
@@ -16,11 +16,23 @@ describe Banzai::Filter::RedactorFilter, lib: true do
end
context 'with data-project' do
+ let(:parser_class) do
+ Class.new(Banzai::ReferenceParser::BaseParser) do
+ self.reference_type = :test
+ end
+ end
+
+ before do
+ allow(Banzai::ReferenceParser).to receive(:[]).
+ with('test').
+ and_return(parser_class)
+ end
+
it 'removes unpermitted Project references' do
user = create(:user)
project = create(:empty_project)
- link = reference_link(project: project.id, reference_filter: 'ReferenceFilter')
+ link = reference_link(project: project.id, reference_type: 'test')
doc = filter(link, current_user: user)
expect(doc.css('a').length).to eq 0
@@ -31,14 +43,14 @@ describe Banzai::Filter::RedactorFilter, lib: true do
project = create(:empty_project)
project.team << [user, :master]
- link = reference_link(project: project.id, reference_filter: 'ReferenceFilter')
+ link = reference_link(project: project.id, reference_type: 'test')
doc = filter(link, current_user: user)
expect(doc.css('a').length).to eq 1
end
it 'handles invalid Project references' do
- link = reference_link(project: 12345, reference_filter: 'ReferenceFilter')
+ link = reference_link(project: 12345, reference_type: 'test')
expect { filter(link) }.not_to raise_error
end
@@ -51,7 +63,7 @@ describe Banzai::Filter::RedactorFilter, lib: true do
project = create(:empty_project, :public)
issue = create(:issue, :confidential, project: project)
- link = reference_link(project: project.id, issue: issue.id, reference_filter: 'IssueReferenceFilter')
+ link = reference_link(project: project.id, issue: issue.id, reference_type: 'issue')
doc = filter(link, current_user: non_member)
expect(doc.css('a').length).to eq 0
@@ -62,7 +74,7 @@ describe Banzai::Filter::RedactorFilter, lib: true do
project = create(:empty_project, :public)
issue = create(:issue, :confidential, project: project, author: author)
- link = reference_link(project: project.id, issue: issue.id, reference_filter: 'IssueReferenceFilter')
+ link = reference_link(project: project.id, issue: issue.id, reference_type: 'issue')
doc = filter(link, current_user: author)
expect(doc.css('a').length).to eq 1
@@ -73,7 +85,7 @@ describe Banzai::Filter::RedactorFilter, lib: true do
project = create(:empty_project, :public)
issue = create(:issue, :confidential, project: project, assignee: assignee)
- link = reference_link(project: project.id, issue: issue.id, reference_filter: 'IssueReferenceFilter')
+ link = reference_link(project: project.id, issue: issue.id, reference_type: 'issue')
doc = filter(link, current_user: assignee)
expect(doc.css('a').length).to eq 1
@@ -85,7 +97,7 @@ describe Banzai::Filter::RedactorFilter, lib: true do
project.team << [member, :developer]
issue = create(:issue, :confidential, project: project)
- link = reference_link(project: project.id, issue: issue.id, reference_filter: 'IssueReferenceFilter')
+ link = reference_link(project: project.id, issue: issue.id, reference_type: 'issue')
doc = filter(link, current_user: member)
expect(doc.css('a').length).to eq 1
@@ -96,7 +108,7 @@ describe Banzai::Filter::RedactorFilter, lib: true do
project = create(:empty_project, :public)
issue = create(:issue, :confidential, project: project)
- link = reference_link(project: project.id, issue: issue.id, reference_filter: 'IssueReferenceFilter')
+ link = reference_link(project: project.id, issue: issue.id, reference_type: 'issue')
doc = filter(link, current_user: admin)
expect(doc.css('a').length).to eq 1
@@ -108,7 +120,7 @@ describe Banzai::Filter::RedactorFilter, lib: true do
project = create(:empty_project, :public)
issue = create(:issue, project: project)
- link = reference_link(project: project.id, issue: issue.id, reference_filter: 'IssueReferenceFilter')
+ link = reference_link(project: project.id, issue: issue.id, reference_type: 'issue')
doc = filter(link, current_user: user)
expect(doc.css('a').length).to eq 1
@@ -121,7 +133,7 @@ describe Banzai::Filter::RedactorFilter, lib: true do
user = create(:user)
group = create(:group, :private)
- link = reference_link(group: group.id, reference_filter: 'UserReferenceFilter')
+ link = reference_link(group: group.id, reference_type: 'user')
doc = filter(link, current_user: user)
expect(doc.css('a').length).to eq 0
@@ -132,14 +144,14 @@ describe Banzai::Filter::RedactorFilter, lib: true do
group = create(:group, :private)
group.add_developer(user)
- link = reference_link(group: group.id, reference_filter: 'UserReferenceFilter')
+ link = reference_link(group: group.id, reference_type: 'user')
doc = filter(link, current_user: user)
expect(doc.css('a').length).to eq 1
end
it 'handles invalid Group references' do
- link = reference_link(group: 12345, reference_filter: 'UserReferenceFilter')
+ link = reference_link(group: 12345, reference_type: 'user')
expect { filter(link) }.not_to raise_error
end
@@ -149,7 +161,7 @@ describe Banzai::Filter::RedactorFilter, lib: true do
it 'allows any User reference' do
user = create(:user)
- link = reference_link(user: user.id, reference_filter: 'UserReferenceFilter')
+ link = reference_link(user: user.id, reference_type: 'user')
doc = filter(link)
expect(doc.css('a').length).to eq 1
diff --git a/spec/lib/banzai/filter/reference_filter_spec.rb b/spec/lib/banzai/filter/reference_filter_spec.rb
new file mode 100644
index 00000000000..55e681f6faf
--- /dev/null
+++ b/spec/lib/banzai/filter/reference_filter_spec.rb
@@ -0,0 +1,45 @@
+require 'spec_helper'
+
+describe Banzai::Filter::ReferenceFilter, lib: true do
+ let(:project) { build(:project) }
+
+ describe '#each_node' do
+ it 'iterates over the nodes in a document' do
+ document = Nokogiri::HTML.fragment('<a href="foo">foo</a>')
+ filter = described_class.new(document, project: project)
+
+ expect { |b| filter.each_node(&b) }.
+ to yield_with_args(an_instance_of(Nokogiri::XML::Element))
+ end
+
+ it 'returns an Enumerator when no block is given' do
+ document = Nokogiri::HTML.fragment('<a href="foo">foo</a>')
+ filter = described_class.new(document, project: project)
+
+ expect(filter.each_node).to be_an_instance_of(Enumerator)
+ end
+
+ it 'skips links with a "gfm" class' do
+ document = Nokogiri::HTML.fragment('<a href="foo" class="gfm">foo</a>')
+ filter = described_class.new(document, project: project)
+
+ expect { |b| filter.each_node(&b) }.not_to yield_control
+ end
+
+ it 'skips text nodes in pre elements' do
+ document = Nokogiri::HTML.fragment('<pre>foo</pre>')
+ filter = described_class.new(document, project: project)
+
+ expect { |b| filter.each_node(&b) }.not_to yield_control
+ end
+ end
+
+ describe '#nodes' do
+ it 'returns an Array of the HTML nodes' do
+ document = Nokogiri::HTML.fragment('<a href="foo">foo</a>')
+ filter = described_class.new(document, project: project)
+
+ expect(filter.nodes).to eq([document.children[0]])
+ end
+ end
+end
diff --git a/spec/lib/banzai/filter/reference_gatherer_filter_spec.rb b/spec/lib/banzai/filter/reference_gatherer_filter_spec.rb
deleted file mode 100644
index c8b1dfdf944..00000000000
--- a/spec/lib/banzai/filter/reference_gatherer_filter_spec.rb
+++ /dev/null
@@ -1,87 +0,0 @@
-require 'spec_helper'
-
-describe Banzai::Filter::ReferenceGathererFilter, lib: true do
- include ActionView::Helpers::UrlHelper
- include FilterSpecHelper
-
- def reference_link(data)
- link_to('text', '', class: 'gfm', data: data)
- end
-
- context "for issue references" do
-
- context 'with data-project' do
- it 'removes unpermitted Project references' do
- user = create(:user)
- project = create(:empty_project)
- issue = create(:issue, project: project)
-
- link = reference_link(project: project.id, issue: issue.id, reference_filter: 'IssueReferenceFilter')
- result = pipeline_result(link, current_user: user)
-
- expect(result[:references][:issue]).to be_empty
- end
-
- it 'allows permitted Project references' do
- user = create(:user)
- project = create(:empty_project)
- issue = create(:issue, project: project)
- project.team << [user, :master]
-
- link = reference_link(project: project.id, issue: issue.id, reference_filter: 'IssueReferenceFilter')
- result = pipeline_result(link, current_user: user)
-
- expect(result[:references][:issue]).to eq([issue])
- end
-
- it 'handles invalid Project references' do
- link = reference_link(project: 12345, issue: 12345, reference_filter: 'IssueReferenceFilter')
-
- expect { pipeline_result(link) }.not_to raise_error
- end
- end
- end
-
- context "for user references" do
-
- context 'with data-group' do
- it 'removes unpermitted Group references' do
- user = create(:user)
- group = create(:group)
-
- link = reference_link(group: group.id, reference_filter: 'UserReferenceFilter')
- result = pipeline_result(link, current_user: user)
-
- expect(result[:references][:user]).to be_empty
- end
-
- it 'allows permitted Group references' do
- user = create(:user)
- group = create(:group)
- group.add_developer(user)
-
- link = reference_link(group: group.id, reference_filter: 'UserReferenceFilter')
- result = pipeline_result(link, current_user: user)
-
- expect(result[:references][:user]).to eq([user])
- end
-
- it 'handles invalid Group references' do
- link = reference_link(group: 12345, reference_filter: 'UserReferenceFilter')
-
- expect { pipeline_result(link) }.not_to raise_error
- end
- end
-
- context 'with data-user' do
- it 'allows any User reference' do
- user = create(:user)
-
- link = reference_link(user: user.id, reference_filter: 'UserReferenceFilter')
- result = pipeline_result(link)
-
- expect(result[:references][:user]).to eq([user])
- end
- end
- end
-end
diff --git a/spec/lib/banzai/filter/sanitization_filter_spec.rb b/spec/lib/banzai/filter/sanitization_filter_spec.rb
index 27ce312b11c..b38e3b17e64 100644
--- a/spec/lib/banzai/filter/sanitization_filter_spec.rb
+++ b/spec/lib/banzai/filter/sanitization_filter_spec.rb
@@ -22,6 +22,12 @@ describe Banzai::Filter::SanitizationFilter, lib: true do
expect(filter(act).to_html).to eq exp
end
+ it 'sanitizes mixed-cased javascript in attributes' do
+ act = %q(<a href="javaScript:alert('foo')">Text</a>)
+ exp = '<a>Text</a>'
+ expect(filter(act).to_html).to eq exp
+ end
+
it 'allows whitelisted HTML tags from the user' do
exp = act = "<dl>\n<dt>Term</dt>\n<dd>Definition</dd>\n</dl>"
expect(filter(act).to_html).to eq exp
diff --git a/spec/lib/banzai/filter/snippet_reference_filter_spec.rb b/spec/lib/banzai/filter/snippet_reference_filter_spec.rb
index 26466fbb180..5068ddd7faa 100644
--- a/spec/lib/banzai/filter/snippet_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/snippet_reference_filter_spec.rb
@@ -77,11 +77,6 @@ describe Banzai::Filter::SnippetReferenceFilter, lib: true do
expect(link).not_to match %r(https?://)
expect(link).to eq urls.namespace_project_snippet_url(project.namespace, project, snippet, only_path: true)
end
-
- it 'adds to the results hash' do
- result = reference_pipeline_result("Snippet #{reference}")
- expect(result[:references][:snippet]).to eq [snippet]
- end
end
context 'cross-project reference' do
@@ -107,11 +102,6 @@ describe Banzai::Filter::SnippetReferenceFilter, lib: true do
expect(reference_filter(act).to_html).to eq exp
end
-
- it 'adds to the results hash' do
- result = reference_pipeline_result("Snippet #{reference}")
- expect(result[:references][:snippet]).to eq [snippet]
- end
end
context 'cross-project URL reference' do
@@ -137,10 +127,5 @@ describe Banzai::Filter::SnippetReferenceFilter, lib: true do
expect(reference_filter(act).to_html).to match(/<a.+>#{Regexp.escape(invalidate_reference(reference))}<\/a>/)
end
-
- it 'adds to the results hash' do
- result = reference_pipeline_result("Snippet #{reference}")
- expect(result[:references][:snippet]).to eq [snippet]
- end
end
end
diff --git a/spec/lib/banzai/filter/upload_link_filter_spec.rb b/spec/lib/banzai/filter/upload_link_filter_spec.rb
index 3b073a90a95..b83be54746c 100644
--- a/spec/lib/banzai/filter/upload_link_filter_spec.rb
+++ b/spec/lib/banzai/filter/upload_link_filter_spec.rb
@@ -8,6 +8,10 @@ describe Banzai::Filter::UploadLinkFilter, lib: true do
project: project
})
+ raw_filter(doc, contexts)
+ end
+
+ def raw_filter(doc, contexts = {})
described_class.call(doc, contexts)
end
@@ -70,4 +74,18 @@ describe Banzai::Filter::UploadLinkFilter, lib: true do
expect(doc.at_css('img')['src']).to match "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/uploads/%ED%95%9C%EA%B8%80.png"
end
end
+
+ context 'when project context does not exist' do
+ let(:upload_link) { link('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg') }
+
+ it 'does not raise error' do
+ expect { raw_filter(upload_link, project: nil) }.not_to raise_error
+ end
+
+ it 'does not rewrite link' do
+ doc = raw_filter(upload_link, project: nil)
+
+ expect(doc.to_html).to eq upload_link
+ end
+ end
end
diff --git a/spec/lib/banzai/filter/user_reference_filter_spec.rb b/spec/lib/banzai/filter/user_reference_filter_spec.rb
index 8bdebae1841..108b36a97cc 100644
--- a/spec/lib/banzai/filter/user_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/user_reference_filter_spec.rb
@@ -31,28 +31,22 @@ describe Banzai::Filter::UserReferenceFilter, lib: true do
end
it 'supports a special @all mention' do
- doc = reference_filter("Hey #{reference}")
+ doc = reference_filter("Hey #{reference}", author: user)
expect(doc.css('a').length).to eq 1
expect(doc.css('a').first.attr('href'))
.to eq urls.namespace_project_url(project.namespace, project)
end
- context "when the author is a member of the project" do
+ it 'includes a data-author attribute when there is an author' do
+ doc = reference_filter(reference, author: user)
- it 'adds to the results hash' do
- result = reference_pipeline_result("Hey #{reference}", author: project.creator)
- expect(result[:references][:user]).to eq [project.creator]
- end
+ expect(doc.css('a').first.attr('data-author')).to eq(user.id.to_s)
end
- context "when the author is not a member of the project" do
-
- let(:other_user) { create(:user) }
+ it 'does not include a data-author attribute when there is no author' do
+ doc = reference_filter(reference)
- it "doesn't add to the results hash" do
- result = reference_pipeline_result("Hey #{reference}", author: other_user)
- expect(result[:references][:user]).to eq []
- end
+ expect(doc.css('a').first.has_attribute?('data-author')).to eq(false)
end
end
@@ -83,11 +77,6 @@ describe Banzai::Filter::UserReferenceFilter, lib: true do
expect(link).to have_attribute('data-user')
expect(link.attr('data-user')).to eq user.namespace.owner_id.to_s
end
-
- it 'adds to the results hash' do
- result = reference_pipeline_result("Hey #{reference}")
- expect(result[:references][:user]).to eq [user]
- end
end
context 'mentioning a group' do
@@ -106,11 +95,6 @@ describe Banzai::Filter::UserReferenceFilter, lib: true do
expect(link).to have_attribute('data-group')
expect(link.attr('data-group')).to eq group.id.to_s
end
-
- it 'adds to the results hash' do
- result = reference_pipeline_result("Hey #{reference}")
- expect(result[:references][:user]).to eq group.users
- end
end
it 'links with adjacent text' do
@@ -151,10 +135,24 @@ describe Banzai::Filter::UserReferenceFilter, lib: true do
expect(link).to have_attribute('data-user')
expect(link.attr('data-user')).to eq user.namespace.owner_id.to_s
end
+ end
+
+ describe '#namespaces' do
+ it 'returns a Hash containing all Namespaces' do
+ document = Nokogiri::HTML.fragment("<p>#{user.to_reference}</p>")
+ filter = described_class.new(document, project: project)
+ ns = user.namespace
+
+ expect(filter.namespaces).to eq({ ns.path => ns })
+ end
+ end
+
+ describe '#usernames' do
+ it 'returns the usernames mentioned in a document' do
+ document = Nokogiri::HTML.fragment("<p>#{user.to_reference}</p>")
+ filter = described_class.new(document, project: project)
- it 'adds to the results hash' do
- result = reference_pipeline_result("Hey #{reference}")
- expect(result[:references][:user]).to eq [user]
+ expect(filter.usernames).to eq([user.username])
end
end
end
diff --git a/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb b/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb
index 7aa1b4a3bf6..72bc6a0b704 100644
--- a/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb
+++ b/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb
@@ -50,4 +50,112 @@ describe Banzai::Pipeline::WikiPipeline do
end
end
end
+
+ describe "Links" do
+ let(:namespace) { create(:namespace, name: "wiki_link_ns") }
+ let(:project) { create(:empty_project, :public, name: "wiki_link_project", namespace: namespace) }
+ let(:project_wiki) { ProjectWiki.new(project, double(:user)) }
+ let(:page) { build(:wiki_page, wiki: project_wiki, page: OpenStruct.new(url_path: 'nested/twice/start-page')) }
+
+ { "when GitLab is hosted at a root URL" => '/',
+ "when GitLab is hosted at a relative URL" => '/nested/relative/gitlab' }.each do |test_name, relative_url_root|
+
+ context test_name do
+ before do
+ allow(Gitlab.config.gitlab).to receive(:relative_url_root).and_return(relative_url_root)
+ end
+
+ describe "linking to pages within the wiki" do
+ context "when creating hierarchical links to the current directory" do
+ it "rewrites non-file links to be at the scope of the current directory" do
+ markdown = "[Page](./page)"
+ output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
+
+ expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/nested/twice/page\"")
+ end
+
+ it "rewrites file links to be at the scope of the current directory" do
+ markdown = "[Link to Page](./page.md)"
+ output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
+
+ expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/nested/twice/page.md\"")
+ end
+ end
+
+ context "when creating hierarchical links to the parent directory" do
+ it "rewrites non-file links to be at the scope of the parent directory" do
+ markdown = "[Link to Page](../page)"
+ output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
+
+ expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/nested/page\"")
+ end
+
+ it "rewrites file links to be at the scope of the parent directory" do
+ markdown = "[Link to Page](../page.md)"
+ output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
+
+ expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/nested/page.md\"")
+ end
+ end
+
+ context "when creating hierarchical links to a sub-directory" do
+ it "rewrites non-file links to be at the scope of the sub-directory" do
+ markdown = "[Link to Page](./subdirectory/page)"
+ output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
+
+ expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/nested/twice/subdirectory/page\"")
+ end
+
+ it "rewrites file links to be at the scope of the sub-directory" do
+ markdown = "[Link to Page](./subdirectory/page.md)"
+ output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
+
+ expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/nested/twice/subdirectory/page.md\"")
+ end
+ end
+
+ describe "when creating non-hierarchical links" do
+ it 'rewrites non-file links to be at the scope of the wiki root' do
+ markdown = "[Link to Page](page)"
+ output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
+
+ expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/page\"")
+ end
+
+ it "rewrites file links to be at the scope of the current directory" do
+ markdown = "[Link to Page](page.md)"
+ output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
+
+ expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/nested/twice/page.md\"")
+ end
+ end
+
+ describe "when creating root links" do
+ it 'rewrites non-file links to be at the scope of the wiki root' do
+ markdown = "[Link to Page](/page)"
+ output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
+
+ expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/page\"")
+ end
+
+ it 'rewrites file links to be at the scope of the wiki root' do
+ markdown = "[Link to Page](/page.md)"
+ output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
+
+ expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/page.md\"")
+ end
+ end
+ end
+
+ describe "linking to pages outside the wiki (absolute)" do
+ it "doesn't rewrite links" do
+ markdown = "[Link to Page](http://example.com/page)"
+ output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
+
+ expect(output).to include('href="http://example.com/page"')
+ end
+ end
+ end
+ end
+ end
end
diff --git a/spec/lib/banzai/reference_parser/base_parser_spec.rb b/spec/lib/banzai/reference_parser/base_parser_spec.rb
new file mode 100644
index 00000000000..543b4786d84
--- /dev/null
+++ b/spec/lib/banzai/reference_parser/base_parser_spec.rb
@@ -0,0 +1,237 @@
+require 'spec_helper'
+
+describe Banzai::ReferenceParser::BaseParser, lib: true do
+ include ReferenceParserHelpers
+
+ let(:user) { create(:user) }
+ let(:project) { create(:empty_project, :public) }
+
+ subject do
+ klass = Class.new(described_class) do
+ self.reference_type = :foo
+ end
+
+ klass.new(project, user)
+ end
+
+ describe '.reference_type=' do
+ it 'sets the reference type' do
+ dummy = Class.new(described_class)
+ dummy.reference_type = :foo
+
+ expect(dummy.reference_type).to eq(:foo)
+ end
+ end
+
+ describe '#nodes_visible_to_user' do
+ let(:link) { empty_html_link }
+
+ context 'when the link has a data-project attribute' do
+ it 'returns the nodes if the attribute value equals the current project ID' do
+ link['data-project'] = project.id.to_s
+
+ expect(Ability.abilities).not_to receive(:allowed?)
+ expect(subject.nodes_visible_to_user(user, [link])).to eq([link])
+ end
+
+ it 'returns the nodes if the user can read the project' do
+ other_project = create(:empty_project, :public)
+
+ link['data-project'] = other_project.id.to_s
+
+ expect(Ability.abilities).to receive(:allowed?).
+ with(user, :read_project, other_project).
+ and_return(true)
+
+ expect(subject.nodes_visible_to_user(user, [link])).to eq([link])
+ end
+
+ it 'returns an empty Array when the attribute value is empty' do
+ link['data-project'] = ''
+
+ expect(subject.nodes_visible_to_user(user, [link])).to eq([])
+ end
+
+ it 'returns an empty Array when the user can not read the project' do
+ other_project = create(:empty_project, :public)
+
+ link['data-project'] = other_project.id.to_s
+
+ expect(Ability.abilities).to receive(:allowed?).
+ with(user, :read_project, other_project).
+ and_return(false)
+
+ expect(subject.nodes_visible_to_user(user, [link])).to eq([])
+ end
+ end
+
+ context 'when the link does not have a data-project attribute' do
+ it 'returns the nodes' do
+ expect(subject.nodes_visible_to_user(user, [link])).to eq([link])
+ end
+ end
+ end
+
+ describe '#nodes_user_can_reference' do
+ it 'returns the nodes' do
+ link = double(:link)
+
+ expect(subject.nodes_user_can_reference(user, [link])).to eq([link])
+ end
+ end
+
+ describe '#referenced_by' do
+ context 'when references_relation is implemented' do
+ it 'returns a collection of objects' do
+ links = Nokogiri::HTML.fragment("<a data-foo='#{user.id}'></a>").
+ children
+
+ expect(subject).to receive(:references_relation).and_return(User)
+ expect(subject.referenced_by(links)).to eq([user])
+ end
+ end
+
+ context 'when references_relation is not implemented' do
+ it 'raises NotImplementedError' do
+ links = Nokogiri::HTML.fragment('<a data-foo="1"></a>').children
+
+ expect { subject.referenced_by(links) }.
+ to raise_error(NotImplementedError)
+ end
+ end
+ end
+
+ describe '#references_relation' do
+ it 'raises NotImplementedError' do
+ expect { subject.references_relation }.to raise_error(NotImplementedError)
+ end
+ end
+
+ describe '#gather_attributes_per_project' do
+ it 'returns a Hash containing attribute values per project' do
+ link = Nokogiri::HTML.fragment('<a data-project="1" data-foo="2"></a>').
+ children[0]
+
+ hash = subject.gather_attributes_per_project([link], 'data-foo')
+
+ expect(hash).to be_an_instance_of(Hash)
+
+ expect(hash[1].to_a).to eq(['2'])
+ end
+ end
+
+ describe '#grouped_objects_for_nodes' do
+ it 'returns a Hash grouping objects per ID' do
+ nodes = [double(:node)]
+
+ expect(subject).to receive(:unique_attribute_values).
+ with(nodes, 'data-user').
+ and_return([user.id])
+
+ hash = subject.grouped_objects_for_nodes(nodes, User, 'data-user')
+
+ expect(hash).to eq({ user.id => user })
+ end
+
+ it 'returns an empty Hash when the list of nodes is empty' do
+ expect(subject.grouped_objects_for_nodes([], User, 'data-user')).to eq({})
+ end
+ end
+
+ describe '#unique_attribute_values' do
+ it 'returns an Array of unique values' do
+ link = double(:link)
+
+ expect(link).to receive(:has_attribute?).
+ with('data-foo').
+ twice.
+ and_return(true)
+
+ expect(link).to receive(:attr).
+ with('data-foo').
+ twice.
+ and_return('1')
+
+ nodes = [link, link]
+
+ expect(subject.unique_attribute_values(nodes, 'data-foo')).to eq(['1'])
+ end
+ end
+
+ describe '#process' do
+ it 'gathers the references for every node matching the reference type' do
+ dummy = Class.new(described_class) do
+ self.reference_type = :test
+ end
+
+ instance = dummy.new(project, user)
+ document = Nokogiri::HTML.fragment('<a class="gfm"></a><a class="gfm" data-reference-type="test"></a>')
+
+ expect(instance).to receive(:gather_references).
+ with([document.children[1]]).
+ and_return([user])
+
+ expect(instance.process([document])).to eq([user])
+ end
+ end
+
+ describe '#gather_references' do
+ let(:link) { double(:link) }
+
+ it 'does not process links a user can not reference' do
+ expect(subject).to receive(:nodes_user_can_reference).
+ with(user, [link]).
+ and_return([])
+
+ expect(subject).to receive(:referenced_by).with([])
+
+ subject.gather_references([link])
+ end
+
+ it 'does not process links a user can not see' do
+ expect(subject).to receive(:nodes_user_can_reference).
+ with(user, [link]).
+ and_return([link])
+
+ expect(subject).to receive(:nodes_visible_to_user).
+ with(user, [link]).
+ and_return([])
+
+ expect(subject).to receive(:referenced_by).with([])
+
+ subject.gather_references([link])
+ end
+
+ it 'returns the references if a user can reference and see a link' do
+ expect(subject).to receive(:nodes_user_can_reference).
+ with(user, [link]).
+ and_return([link])
+
+ expect(subject).to receive(:nodes_visible_to_user).
+ with(user, [link]).
+ and_return([link])
+
+ expect(subject).to receive(:referenced_by).with([link])
+
+ subject.gather_references([link])
+ end
+ end
+
+ describe '#can?' do
+ it 'delegates the permissions check to the Ability class' do
+ user = double(:user)
+
+ expect(Ability.abilities).to receive(:allowed?).
+ with(user, :read_project, project)
+
+ subject.can?(user, :read_project, project)
+ end
+ end
+
+ describe '#find_projects_for_hash_keys' do
+ it 'returns a list of Projects' do
+ expect(subject.find_projects_for_hash_keys(project.id => project)).
+ to eq([project])
+ end
+ end
+end
diff --git a/spec/lib/banzai/reference_parser/commit_parser_spec.rb b/spec/lib/banzai/reference_parser/commit_parser_spec.rb
new file mode 100644
index 00000000000..0b76d29fce0
--- /dev/null
+++ b/spec/lib/banzai/reference_parser/commit_parser_spec.rb
@@ -0,0 +1,113 @@
+require 'spec_helper'
+
+describe Banzai::ReferenceParser::CommitParser, lib: true do
+ include ReferenceParserHelpers
+
+ let(:project) { create(:empty_project, :public) }
+ let(:user) { create(:user) }
+ subject { described_class.new(project, user) }
+ let(:link) { empty_html_link }
+
+ describe '#referenced_by' do
+ context 'when the link has a data-project attribute' do
+ before do
+ link['data-project'] = project.id.to_s
+ end
+
+ context 'when the link has a data-commit attribute' do
+ before do
+ link['data-commit'] = '123'
+ end
+
+ it 'returns an Array of commits' do
+ commit = double(:commit)
+
+ allow_any_instance_of(Project).to receive(:valid_repo?).
+ and_return(true)
+
+ expect(subject).to receive(:find_commits).
+ with(project, ['123']).
+ and_return([commit])
+
+ expect(subject.referenced_by([link])).to eq([commit])
+ end
+
+ it 'returns an empty Array when the commit could not be found' do
+ allow_any_instance_of(Project).to receive(:valid_repo?).
+ and_return(true)
+
+ expect(subject).to receive(:find_commits).
+ with(project, ['123']).
+ and_return([])
+
+ expect(subject.referenced_by([link])).to eq([])
+ end
+
+ it 'skips projects without valid repositories' do
+ allow_any_instance_of(Project).to receive(:valid_repo?).
+ and_return(false)
+
+ expect(subject.referenced_by([link])).to eq([])
+ end
+ end
+
+ context 'when the link does not have a data-commit attribute' do
+ it 'returns an empty Array' do
+ allow_any_instance_of(Project).to receive(:valid_repo?).
+ and_return(true)
+
+ expect(subject.referenced_by([link])).to eq([])
+ end
+ end
+ end
+
+ context 'when the link does not have a data-project attribute' do
+ it 'returns an empty Array' do
+ allow_any_instance_of(Project).to receive(:valid_repo?).
+ and_return(true)
+
+ expect(subject.referenced_by([link])).to eq([])
+ end
+ end
+ end
+
+ describe '#commit_ids_per_project' do
+ before do
+ link['data-project'] = project.id.to_s
+ end
+
+ it 'returns a Hash containing commit IDs per project' do
+ link['data-commit'] = '123'
+
+ hash = subject.commit_ids_per_project([link])
+
+ expect(hash).to be_an_instance_of(Hash)
+
+ expect(hash[project.id].to_a).to eq(['123'])
+ end
+
+ it 'does not add a project when the data-commit attribute is empty' do
+ hash = subject.commit_ids_per_project([link])
+
+ expect(hash).to be_empty
+ end
+ end
+
+ describe '#find_commits' do
+ it 'returns an Array of commit objects' do
+ commit = double(:commit)
+
+ expect(project).to receive(:commit).with('123').and_return(commit)
+ expect(project).to receive(:valid_repo?).and_return(true)
+
+ expect(subject.find_commits(project, %w{123})).to eq([commit])
+ end
+
+ it 'skips commit IDs for which no commit could be found' do
+ expect(project).to receive(:commit).with('123').and_return(nil)
+ expect(project).to receive(:valid_repo?).and_return(true)
+
+ expect(subject.find_commits(project, %w{123})).to eq([])
+ end
+ end
+end
diff --git a/spec/lib/banzai/reference_parser/commit_range_parser_spec.rb b/spec/lib/banzai/reference_parser/commit_range_parser_spec.rb
new file mode 100644
index 00000000000..ba982f38542
--- /dev/null
+++ b/spec/lib/banzai/reference_parser/commit_range_parser_spec.rb
@@ -0,0 +1,120 @@
+require 'spec_helper'
+
+describe Banzai::ReferenceParser::CommitRangeParser, lib: true do
+ include ReferenceParserHelpers
+
+ let(:project) { create(:empty_project, :public) }
+ let(:user) { create(:user) }
+ subject { described_class.new(project, user) }
+ let(:link) { empty_html_link }
+
+ describe '#referenced_by' do
+ context 'when the link has a data-project attribute' do
+ before do
+ link['data-project'] = project.id.to_s
+ end
+
+ context 'when the link as a data-commit-range attribute' do
+ before do
+ link['data-commit-range'] = '123..456'
+ end
+
+ it 'returns an Array of commit ranges' do
+ range = double(:range)
+
+ expect(subject).to receive(:find_object).
+ with(project, '123..456').
+ and_return(range)
+
+ expect(subject.referenced_by([link])).to eq([range])
+ end
+
+ it 'returns an empty Array when the commit range could not be found' do
+ expect(subject).to receive(:find_object).
+ with(project, '123..456').
+ and_return(nil)
+
+ expect(subject.referenced_by([link])).to eq([])
+ end
+ end
+
+ context 'when the link does not have a data-commit-range attribute' do
+ it 'returns an empty Array' do
+ expect(subject.referenced_by([link])).to eq([])
+ end
+ end
+ end
+
+ context 'when the link does not have a data-project attribute' do
+ it 'returns an empty Array' do
+ expect(subject.referenced_by([link])).to eq([])
+ end
+ end
+ end
+
+ describe '#commit_range_ids_per_project' do
+ before do
+ link['data-project'] = project.id.to_s
+ end
+
+ it 'returns a Hash containing range IDs per project' do
+ link['data-commit-range'] = '123..456'
+
+ hash = subject.commit_range_ids_per_project([link])
+
+ expect(hash).to be_an_instance_of(Hash)
+
+ expect(hash[project.id].to_a).to eq(['123..456'])
+ end
+
+ it 'does not add a project when the data-commit-range attribute is empty' do
+ hash = subject.commit_range_ids_per_project([link])
+
+ expect(hash).to be_empty
+ end
+ end
+
+ describe '#find_ranges' do
+ it 'returns an Array of range objects' do
+ range = double(:commit)
+
+ expect(subject).to receive(:find_object).
+ with(project, '123..456').
+ and_return(range)
+
+ expect(subject.find_ranges(project, ['123..456'])).to eq([range])
+ end
+
+ it 'skips ranges that could not be found' do
+ expect(subject).to receive(:find_object).
+ with(project, '123..456').
+ and_return(nil)
+
+ expect(subject.find_ranges(project, ['123..456'])).to eq([])
+ end
+ end
+
+ describe '#find_object' do
+ let(:range) { double(:range) }
+
+ before do
+ expect(CommitRange).to receive(:new).and_return(range)
+ end
+
+ context 'when the range has valid commits' do
+ it 'returns the commit range' do
+ expect(range).to receive(:valid_commits?).and_return(true)
+
+ expect(subject.find_object(project, '123..456')).to eq(range)
+ end
+ end
+
+ context 'when the range does not have any valid commits' do
+ it 'returns nil' do
+ expect(range).to receive(:valid_commits?).and_return(false)
+
+ expect(subject.find_object(project, '123..456')).to be_nil
+ end
+ end
+ end
+end
diff --git a/spec/lib/banzai/reference_parser/external_issue_parser_spec.rb b/spec/lib/banzai/reference_parser/external_issue_parser_spec.rb
new file mode 100644
index 00000000000..a6ef8394fe7
--- /dev/null
+++ b/spec/lib/banzai/reference_parser/external_issue_parser_spec.rb
@@ -0,0 +1,62 @@
+require 'spec_helper'
+
+describe Banzai::ReferenceParser::ExternalIssueParser, lib: true do
+ include ReferenceParserHelpers
+
+ let(:project) { create(:empty_project, :public) }
+ let(:user) { create(:user) }
+ subject { described_class.new(project, user) }
+ let(:link) { empty_html_link }
+
+ describe '#referenced_by' do
+ context 'when the link has a data-project attribute' do
+ before do
+ link['data-project'] = project.id.to_s
+ end
+
+ context 'when the link has a data-external-issue attribute' do
+ it 'returns an Array of ExternalIssue instances' do
+ link['data-external-issue'] = '123'
+
+ refs = subject.referenced_by([link])
+
+ expect(refs).to eq([ExternalIssue.new('123', project)])
+ end
+ end
+
+ context 'when the link does not have a data-external-issue attribute' do
+ it 'returns an empty Array' do
+ expect(subject.referenced_by([link])).to eq([])
+ end
+ end
+ end
+
+ context 'when the link does not have a data-project attribute' do
+ it 'returns an empty Array' do
+ expect(subject.referenced_by([link])).to eq([])
+ end
+ end
+ end
+
+ describe '#issue_ids_per_project' do
+ before do
+ link['data-project'] = project.id.to_s
+ end
+
+ it 'returns a Hash containing range IDs per project' do
+ link['data-external-issue'] = '123'
+
+ hash = subject.issue_ids_per_project([link])
+
+ expect(hash).to be_an_instance_of(Hash)
+
+ expect(hash[project.id].to_a).to eq(['123'])
+ end
+
+ it 'does not add a project when the data-external-issue attribute is empty' do
+ hash = subject.issue_ids_per_project([link])
+
+ expect(hash).to be_empty
+ end
+ end
+end
diff --git a/spec/lib/banzai/reference_parser/issue_parser_spec.rb b/spec/lib/banzai/reference_parser/issue_parser_spec.rb
new file mode 100644
index 00000000000..514c752546d
--- /dev/null
+++ b/spec/lib/banzai/reference_parser/issue_parser_spec.rb
@@ -0,0 +1,79 @@
+require 'spec_helper'
+
+describe Banzai::ReferenceParser::IssueParser, lib: true do
+ include ReferenceParserHelpers
+
+ let(:project) { create(:empty_project, :public) }
+ let(:user) { create(:user) }
+ let(:issue) { create(:issue, project: project) }
+ subject { described_class.new(project, user) }
+ let(:link) { empty_html_link }
+
+ describe '#nodes_visible_to_user' do
+ context 'when the link has a data-issue attribute' do
+ before do
+ link['data-issue'] = issue.id.to_s
+ end
+
+ it 'returns the nodes when the user can read the issue' do
+ expect(Ability.abilities).to receive(:allowed?).
+ with(user, :read_issue, issue).
+ and_return(true)
+
+ expect(subject.nodes_visible_to_user(user, [link])).to eq([link])
+ end
+
+ it 'returns an empty Array when the user can not read the issue' do
+ expect(Ability.abilities).to receive(:allowed?).
+ with(user, :read_issue, issue).
+ and_return(false)
+
+ expect(subject.nodes_visible_to_user(user, [link])).to eq([])
+ end
+ end
+
+ context 'when the link does not have a data-issue attribute' do
+ it 'returns an empty Array' do
+ expect(subject.nodes_visible_to_user(user, [link])).to eq([])
+ end
+ end
+
+ context 'when the project uses an external issue tracker' do
+ it 'returns all nodes' do
+ link = double(:link)
+
+ expect(project).to receive(:external_issue_tracker).and_return(true)
+
+ expect(subject.nodes_visible_to_user(user, [link])).to eq([link])
+ end
+ end
+ end
+
+ describe '#referenced_by' do
+ context 'when the link has a data-issue attribute' do
+ context 'using an existing issue ID' do
+ before do
+ link['data-issue'] = issue.id.to_s
+ end
+
+ it 'returns an Array of issues' do
+ expect(subject.referenced_by([link])).to eq([issue])
+ end
+
+ it 'returns an empty Array when the list of nodes is empty' do
+ expect(subject.referenced_by([link])).to eq([issue])
+ expect(subject.referenced_by([])).to eq([])
+ end
+ end
+ end
+ end
+
+ describe '#issues_for_nodes' do
+ it 'returns a Hash containing the issues for a list of nodes' do
+ link['data-issue'] = issue.id.to_s
+ nodes = [link]
+
+ expect(subject.issues_for_nodes(nodes)).to eq({ issue.id => issue })
+ end
+ end
+end
diff --git a/spec/lib/banzai/reference_parser/label_parser_spec.rb b/spec/lib/banzai/reference_parser/label_parser_spec.rb
new file mode 100644
index 00000000000..77fda47f0e7
--- /dev/null
+++ b/spec/lib/banzai/reference_parser/label_parser_spec.rb
@@ -0,0 +1,31 @@
+require 'spec_helper'
+
+describe Banzai::ReferenceParser::LabelParser, lib: true do
+ include ReferenceParserHelpers
+
+ let(:project) { create(:empty_project, :public) }
+ let(:user) { create(:user) }
+ let(:label) { create(:label, project: project) }
+ subject { described_class.new(project, user) }
+ let(:link) { empty_html_link }
+
+ describe '#referenced_by' do
+ describe 'when the link has a data-label attribute' do
+ context 'using an existing label ID' do
+ it 'returns an Array of labels' do
+ link['data-label'] = label.id.to_s
+
+ expect(subject.referenced_by([link])).to eq([label])
+ end
+ end
+
+ context 'using a non-existing label ID' do
+ it 'returns an empty Array' do
+ link['data-label'] = ''
+
+ expect(subject.referenced_by([link])).to eq([])
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/banzai/reference_parser/merge_request_parser_spec.rb b/spec/lib/banzai/reference_parser/merge_request_parser_spec.rb
new file mode 100644
index 00000000000..cf89ad598ea
--- /dev/null
+++ b/spec/lib/banzai/reference_parser/merge_request_parser_spec.rb
@@ -0,0 +1,30 @@
+require 'spec_helper'
+
+describe Banzai::ReferenceParser::MergeRequestParser, lib: true do
+ include ReferenceParserHelpers
+
+ let(:user) { create(:user) }
+ let(:merge_request) { create(:merge_request) }
+ subject { described_class.new(merge_request.target_project, user) }
+ let(:link) { empty_html_link }
+
+ describe '#referenced_by' do
+ describe 'when the link has a data-merge-request attribute' do
+ context 'using an existing merge request ID' do
+ it 'returns an Array of merge requests' do
+ link['data-merge-request'] = merge_request.id.to_s
+
+ expect(subject.referenced_by([link])).to eq([merge_request])
+ end
+ end
+
+ context 'using a non-existing merge request ID' do
+ it 'returns an empty Array' do
+ link['data-merge-request'] = ''
+
+ expect(subject.referenced_by([link])).to eq([])
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/banzai/reference_parser/milestone_parser_spec.rb b/spec/lib/banzai/reference_parser/milestone_parser_spec.rb
new file mode 100644
index 00000000000..6aa45a22cc4
--- /dev/null
+++ b/spec/lib/banzai/reference_parser/milestone_parser_spec.rb
@@ -0,0 +1,31 @@
+require 'spec_helper'
+
+describe Banzai::ReferenceParser::MilestoneParser, lib: true do
+ include ReferenceParserHelpers
+
+ let(:project) { create(:empty_project, :public) }
+ let(:user) { create(:user) }
+ let(:milestone) { create(:milestone, project: project) }
+ subject { described_class.new(project, user) }
+ let(:link) { empty_html_link }
+
+ describe '#referenced_by' do
+ describe 'when the link has a data-milestone attribute' do
+ context 'using an existing milestone ID' do
+ it 'returns an Array of milestones' do
+ link['data-milestone'] = milestone.id.to_s
+
+ expect(subject.referenced_by([link])).to eq([milestone])
+ end
+ end
+
+ context 'using a non-existing milestone ID' do
+ it 'returns an empty Array' do
+ link['data-milestone'] = ''
+
+ expect(subject.referenced_by([link])).to eq([])
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/banzai/reference_parser/snippet_parser_spec.rb b/spec/lib/banzai/reference_parser/snippet_parser_spec.rb
new file mode 100644
index 00000000000..59127b7c5d1
--- /dev/null
+++ b/spec/lib/banzai/reference_parser/snippet_parser_spec.rb
@@ -0,0 +1,31 @@
+require 'spec_helper'
+
+describe Banzai::ReferenceParser::SnippetParser, lib: true do
+ include ReferenceParserHelpers
+
+ let(:project) { create(:empty_project, :public) }
+ let(:user) { create(:user) }
+ let(:snippet) { create(:snippet, project: project) }
+ subject { described_class.new(project, user) }
+ let(:link) { empty_html_link }
+
+ describe '#referenced_by' do
+ describe 'when the link has a data-snippet attribute' do
+ context 'using an existing snippet ID' do
+ it 'returns an Array of snippets' do
+ link['data-snippet'] = snippet.id.to_s
+
+ expect(subject.referenced_by([link])).to eq([snippet])
+ end
+ end
+
+ context 'using a non-existing snippet ID' do
+ it 'returns an empty Array' do
+ link['data-snippet'] = ''
+
+ expect(subject.referenced_by([link])).to eq([])
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/banzai/reference_parser/user_parser_spec.rb b/spec/lib/banzai/reference_parser/user_parser_spec.rb
new file mode 100644
index 00000000000..9a82891297d
--- /dev/null
+++ b/spec/lib/banzai/reference_parser/user_parser_spec.rb
@@ -0,0 +1,189 @@
+require 'spec_helper'
+
+describe Banzai::ReferenceParser::UserParser, lib: true do
+ include ReferenceParserHelpers
+
+ let(:group) { create(:group) }
+ let(:user) { create(:user) }
+ let(:project) { create(:empty_project, :public, group: group, creator: user) }
+ subject { described_class.new(project, user) }
+ let(:link) { empty_html_link }
+
+ describe '#referenced_by' do
+ context 'when the link has a data-group attribute' do
+ context 'using an existing group ID' do
+ before do
+ link['data-group'] = project.group.id.to_s
+ end
+
+ it 'returns the users of the group' do
+ create(:group_member, group: group, user: user)
+
+ expect(subject.referenced_by([link])).to eq([user])
+ end
+
+ it 'returns an empty Array when the group has no users' do
+ expect(subject.referenced_by([link])).to eq([])
+ end
+ end
+
+ context 'using a non-existing group ID' do
+ it 'returns an empty Array' do
+ link['data-group'] = ''
+
+ expect(subject.referenced_by([link])).to eq([])
+ end
+ end
+ end
+
+ context 'when the link has a data-user attribute' do
+ it 'returns an Array of users' do
+ link['data-user'] = user.id.to_s
+
+ expect(subject.referenced_by([link])).to eq([user])
+ end
+ end
+
+ context 'when the link has a data-project attribute' do
+ context 'using an existing project ID' do
+ let(:contributor) { create(:user) }
+
+ before do
+ project.team << [user, :developer]
+ project.team << [contributor, :developer]
+ end
+
+ it 'returns the members of a project' do
+ link['data-project'] = project.id.to_s
+
+ # This uses an explicit sort to make sure this spec doesn't randomly
+ # fail when objects are returned in a different order.
+ refs = subject.referenced_by([link]).sort_by(&:id)
+
+ expect(refs).to eq([user, contributor])
+ end
+ end
+
+ context 'using a non-existing project ID' do
+ it 'returns an empty Array' do
+ link['data-project'] = ''
+
+ expect(subject.referenced_by([link])).to eq([])
+ end
+ end
+ end
+ end
+
+ describe '#nodes_visible_to_use?' do
+ context 'when the link has a data-group attribute' do
+ context 'using an existing group ID' do
+ before do
+ link['data-group'] = group.id.to_s
+ end
+
+ it 'returns the nodes if the user can read the group' do
+ expect(Ability.abilities).to receive(:allowed?).
+ with(user, :read_group, group).
+ and_return(true)
+
+ expect(subject.nodes_visible_to_user(user, [link])).to eq([link])
+ end
+
+ it 'returns an empty Array if the user can not read the group' do
+ expect(Ability.abilities).to receive(:allowed?).
+ with(user, :read_group, group).
+ and_return(false)
+
+ expect(subject.nodes_visible_to_user(user, [link])).to eq([])
+ end
+ end
+
+ context 'when the link does not have a data-group attribute' do
+ context 'with a data-project attribute' do
+ it 'returns the nodes if the attribute value equals the current project ID' do
+ link['data-project'] = project.id.to_s
+
+ expect(Ability.abilities).not_to receive(:allowed?)
+
+ expect(subject.nodes_visible_to_user(user, [link])).to eq([link])
+ end
+
+ it 'returns the nodes if the user can read the project' do
+ other_project = create(:empty_project, :public)
+
+ link['data-project'] = other_project.id.to_s
+
+ expect(Ability.abilities).to receive(:allowed?).
+ with(user, :read_project, other_project).
+ and_return(true)
+
+ expect(subject.nodes_visible_to_user(user, [link])).to eq([link])
+ end
+
+ it 'returns an empty Array if the user can not read the project' do
+ other_project = create(:empty_project, :public)
+
+ link['data-project'] = other_project.id.to_s
+
+ expect(Ability.abilities).to receive(:allowed?).
+ with(user, :read_project, other_project).
+ and_return(false)
+
+ expect(subject.nodes_visible_to_user(user, [link])).to eq([])
+ end
+ end
+
+ context 'without a data-project attribute' do
+ it 'returns the nodes' do
+ expect(subject.nodes_visible_to_user(user, [link])).to eq([link])
+ end
+ end
+ end
+ end
+ end
+
+ describe '#nodes_user_can_reference' do
+ context 'when the link has a data-author attribute' do
+ it 'returns the nodes when the user is a member of the project' do
+ other_project = create(:project)
+ other_project.team << [user, :developer]
+
+ link['data-project'] = other_project.id.to_s
+ link['data-author'] = user.id.to_s
+
+ expect(subject.nodes_user_can_reference(user, [link])).to eq([link])
+ end
+
+ it 'returns an empty Array when the project could not be found' do
+ link['data-project'] = ''
+ link['data-author'] = user.id.to_s
+
+ expect(subject.nodes_user_can_reference(user, [link])).to eq([])
+ end
+
+ it 'returns an empty Array when the user could not be found' do
+ other_project = create(:project)
+
+ link['data-project'] = other_project.id.to_s
+ link['data-author'] = ''
+
+ expect(subject.nodes_user_can_reference(user, [link])).to eq([])
+ end
+
+ it 'returns an empty Array when the user is not a team member' do
+ other_project = create(:project)
+
+ link['data-project'] = other_project.id.to_s
+ link['data-author'] = user.id.to_s
+
+ expect(subject.nodes_user_can_reference(user, [link])).to eq([])
+ end
+ end
+
+ context 'when the link does not have a data-author attribute' do
+ it 'returns the nodes' do
+ expect(subject.nodes_user_can_reference(user, [link])).to eq([link])
+ end
+ end
+ end
+end