Commit 03f9cc03 authored by Nick Thomas's avatar Nick Thomas

Merge branch 'bw-refactor-reference-parser' into 'master'

Refactor banzai reference filter

See merge request gitlab-org/gitlab!59681
parents 27786443 5c31f4f4
......@@ -11,15 +11,13 @@ module EE
module EpicReferenceFilter
extend ActiveSupport::Concern
class_methods do
def references_in(text, pattern = object_class.reference_pattern)
text.gsub(pattern) do |match|
symbol = $~[object_sym]
if object_class.reference_valid?(symbol)
yield match, symbol.to_i, nil, $~[:group], $~
else
match
end
def references_in(text, pattern = object_class.reference_pattern)
text.gsub(pattern) do |match|
symbol = $~[object_sym]
if object_class.reference_valid?(symbol)
yield match, symbol.to_i, nil, $~[:group], $~
else
match
end
end
end
......
......@@ -11,15 +11,13 @@ module EE
module VulnerabilityReferenceFilter
extend ActiveSupport::Concern
class_methods do
def references_in(text, pattern = object_class.reference_pattern)
text.gsub(pattern) do |match|
symbol = $~[object_sym]
if object_class.reference_valid?(symbol)
yield match, symbol.to_i, $~[:project], $~[:namespace], $~
else
match
end
def references_in(text, pattern = object_class.reference_pattern)
text.gsub(pattern) do |match|
symbol = $~[object_sym]
if object_class.reference_valid?(symbol)
yield match, symbol.to_i, $~[:project], $~[:namespace], $~
else
match
end
end
end
......
......@@ -16,22 +16,9 @@ module Banzai
REFERENCE_PLACEHOLDER = "_reference_#{SecureRandom.hex(16)}_"
REFERENCE_PLACEHOLDER_PATTERN = %r{#{REFERENCE_PLACEHOLDER}(\d+)}.freeze
def self.object_class
# Implement in child class
# Example: MergeRequest
end
def self.object_name
@object_name ||= object_class.name.underscore
end
def self.object_sym
@object_sym ||= object_name.to_sym
end
# Public: Find references in text (like `!123` for merge requests)
#
# AnyReferenceFilter.references_in(text) do |match, id, project_ref, matches|
# references_in(text) do |match, id, project_ref, matches|
# object = find_object(project_ref, id)
# "<a href=...>#{object.to_reference}</a>"
# end
......@@ -42,7 +29,7 @@ module Banzai
# of the external project reference, and all of the matchdata.
#
# Returns a String replaced with the return of the block.
def self.references_in(text, pattern = object_class.reference_pattern)
def references_in(text, pattern = object_class.reference_pattern)
text.gsub(pattern) do |match|
if ident = identifier($~)
yield match, ident, $~[:project], $~[:namespace], $~
......@@ -52,17 +39,13 @@ module Banzai
end
end
def self.identifier(match_data)
def identifier(match_data)
symbol = symbol_from_match(match_data)
parse_symbol(symbol, match_data) if object_class.reference_valid?(symbol)
end
def identifier(match_data)
self.class.identifier(match_data)
end
def self.symbol_from_match(match)
def symbol_from_match(match)
key = object_sym
match[key] if match.names.include?(key.to_s)
end
......@@ -72,7 +55,7 @@ module Banzai
#
# This method has the contract that if a string `ref` refers to a
# record `record`, then `parse_symbol(ref) == record_identifier(record)`.
def self.parse_symbol(symbol, match_data)
def parse_symbol(symbol, match_data)
symbol.to_i
end
......@@ -84,21 +67,10 @@ module Banzai
record.id
end
def object_class
self.class.object_class
end
def object_sym
self.class.object_sym
end
def references_in(*args, &block)
self.class.references_in(*args, &block)
end
# Implement in child class
# Example: project.merge_requests.find
def find_object(parent_object, id)
raise NotImplementedError, "#{self.class} must implement method: #{__callee__}"
end
# Override if the link reference pattern produces a different ID (global
......@@ -110,6 +82,7 @@ module Banzai
# Implement in child class
# Example: project_merge_request_url
def url_for_object(object, parent_object)
raise NotImplementedError, "#{self.class} must implement method: #{__callee__}"
end
def find_object_cached(parent_object, id)
......@@ -139,7 +112,7 @@ module Banzai
def call
return doc unless project || group || user
ref_pattern = object_class.reference_pattern
ref_pattern = object_reference_pattern
link_pattern = object_class.link_reference_pattern
# Compile often used regexps only once outside of the loop
......@@ -425,14 +398,6 @@ module Banzai
group_ref
end
def unescape_html_entities(text)
CGI.unescapeHTML(text.to_s)
end
def escape_html_entities(text)
CGI.escapeHTML(text.to_s)
end
def escape_with_placeholders(text, placeholder_data)
escaped = escape_html_entities(text)
......
......@@ -5,12 +5,9 @@ module Banzai
module References
class AlertReferenceFilter < IssuableReferenceFilter
self.reference_type = :alert
self.object_class = AlertManagement::Alert
def self.object_class
AlertManagement::Alert
end
def self.object_sym
def object_sym
:alert
end
......
......@@ -8,12 +8,9 @@ module Banzai
# This filter supports cross-project references.
class CommitRangeReferenceFilter < AbstractReferenceFilter
self.reference_type = :commit_range
self.object_class = CommitRange
def self.object_class
CommitRange
end
def self.references_in(text, pattern = CommitRange.reference_pattern)
def references_in(text, pattern = object_reference_pattern)
text.gsub(pattern) do |match|
yield match, $~[:commit_range], $~[:project], $~[:namespace], $~
end
......
......@@ -8,12 +8,9 @@ module Banzai
# This filter supports cross-project references.
class CommitReferenceFilter < AbstractReferenceFilter
self.reference_type = :commit
self.object_class = Commit
def self.object_class
Commit
end
def self.references_in(text, pattern = Commit.reference_pattern)
def references_in(text, pattern = object_reference_pattern)
text.gsub(pattern) do |match|
yield match, $~[:commit], $~[:project], $~[:namespace], $~
end
......@@ -39,7 +36,7 @@ module Banzai
end
# The default behaviour is `#to_i` - we just pass the hash through.
def self.parse_symbol(sha_hash, _match)
def parse_symbol(sha_hash, _match)
sha_hash
end
......
......@@ -33,6 +33,7 @@ module Banzai
end
self.reference_type = :design
self.object_class = ::DesignManagement::Design
def find_object(project, identifier)
records_per_parent[project][identifier]
......@@ -76,15 +77,11 @@ module Banzai
super.merge(issue: design.issue_id)
end
def self.object_class
::DesignManagement::Design
end
def self.object_sym
def object_sym
:design
end
def self.parse_symbol(raw, match_data)
def parse_symbol(raw, match_data)
filename = match_data[:url_filename]
iid = match_data[:issue].to_i
Identifier.new(filename: CGI.unescape(filename), issue_iid: iid)
......
......@@ -10,10 +10,11 @@ module Banzai
# This filter does not support cross-project references.
class ExternalIssueReferenceFilter < ReferenceFilter
self.reference_type = :external_issue
self.object_class = ExternalIssue
# Public: Find `JIRA-123` issue references in text
#
# ExternalIssueReferenceFilter.references_in(text, pattern) do |match, issue|
# references_in(text, pattern) do |match, issue|
# "<a href=...>##{issue}</a>"
# end
#
......@@ -22,7 +23,7 @@ module Banzai
# Yields the String match and the String issue reference.
#
# Returns a String replaced with the return of the block.
def self.references_in(text, pattern)
def references_in(text, pattern = object_reference_pattern)
text.gsub(pattern) do |match|
yield match, $~[:issue]
end
......@@ -32,27 +33,7 @@ module Banzai
# Early return if the project isn't using an external tracker
return doc if project.nil? || default_issues_tracker?
ref_pattern = issue_reference_pattern
ref_start_pattern = /\A#{ref_pattern}\z/
nodes.each_with_index do |node, index|
if text_node?(node)
replace_text_when_pattern_matches(node, index, ref_pattern) do |content|
issue_link_filter(content)
end
elsif element_node?(node)
yield_valid_link(node) do |link, inner_html|
if link =~ ref_start_pattern
replace_link_node_with_href(node, index, link) do
issue_link_filter(link, link_content: inner_html)
end
end
end
end
end
doc
super
end
private
......@@ -65,8 +46,8 @@ module Banzai
#
# Returns a String with `JIRA-123` references replaced with links. All
# links have `gfm` and `gfm-issue` class names attached for styling.
def issue_link_filter(text, link_content: nil)
self.class.references_in(text, issue_reference_pattern) do |match, id|
def object_link_filter(text, pattern, link_content: nil, link_reference: false)
references_in(text) do |match, id|
url = url_for_issue(id)
klass = reference_class(:issue)
data = data_attribute(project: project.id, external_issue: id)
......@@ -97,14 +78,10 @@ module Banzai
external_issues_cached(:default_issues_tracker?)
end
def issue_reference_pattern
def object_reference_pattern
external_issues_cached(:external_issue_reference_pattern)
end
def project
context[:project]
end
def issue_title
"Issue in #{project.external_issue_tracker.title}"
end
......
......@@ -5,12 +5,9 @@ module Banzai
module References
class FeatureFlagReferenceFilter < IssuableReferenceFilter
self.reference_type = :feature_flag
self.object_class = Operations::FeatureFlag
def self.object_class
Operations::FeatureFlag
end
def self.object_sym
def object_sym
:feature_flag
end
......
......@@ -13,10 +13,7 @@ module Banzai
# to reference issues from other GitLab projects.
class IssueReferenceFilter < IssuableReferenceFilter
self.reference_type = :issue
def self.object_class
Issue
end
self.object_class = Issue
def url_for_object(issue, project)
return issue_path(issue, project) if only_path?
......
......@@ -6,10 +6,7 @@ module Banzai
# The actual filter is implemented in the EE mixin
class IterationReferenceFilter < AbstractReferenceFilter
self.reference_type = :iteration
def self.object_class
Iteration
end
self.object_class = Iteration
end
end
end
......
......@@ -6,10 +6,7 @@ module Banzai
# HTML filter that replaces label references with links.
class LabelReferenceFilter < AbstractReferenceFilter
self.reference_type = :label
def self.object_class
Label
end
self.object_class = Label
def find_object(parent_object, id)
find_labels(parent_object).find(id)
......
......@@ -9,10 +9,7 @@ module Banzai
# This filter supports cross-project references.
class MergeRequestReferenceFilter < IssuableReferenceFilter
self.reference_type = :merge_request
def self.object_class
MergeRequest
end
self.object_class = MergeRequest
def url_for_object(mr, project)
h = Gitlab::Routing.url_helpers
......
......@@ -8,10 +8,7 @@ module Banzai
include Gitlab::Utils::StrongMemoize
self.reference_type = :milestone
def self.object_class
Milestone
end
self.object_class = Milestone
# Links to project milestones contain the IID, but when we're handling
# 'regular' references, we need to use the global ID to disambiguate
......
......@@ -6,10 +6,11 @@ module Banzai
# HTML filter that replaces project references with links.
class ProjectReferenceFilter < ReferenceFilter
self.reference_type = :project
self.object_class = Project
# Public: Find `namespace/project>` project references in text
#
# ProjectReferenceFilter.references_in(text) do |match, project|
# references_in(text) do |match, project|
# "<a href=...>#{project}></a>"
# end
#
......@@ -18,33 +19,16 @@ module Banzai
# Yields the String match, and the String project name.
#
# Returns a String replaced with the return of the block.
def self.references_in(text)
text.gsub(Project.markdown_reference_pattern) do |match|
def references_in(text, pattern = object_reference_pattern)
text.gsub(pattern) do |match|
yield match, "#{$~[:namespace]}/#{$~[:project]}"
end
end
def call
ref_pattern = Project.markdown_reference_pattern
ref_pattern_start = /\A#{ref_pattern}\z/
nodes.each_with_index do |node, index|
if text_node?(node)
replace_text_when_pattern_matches(node, index, ref_pattern) do |content|
project_link_filter(content)
end
elsif element_node?(node)
yield_valid_link(node) do |link, inner_html|
if link =~ ref_pattern_start
replace_link_node_with_href(node, index, link) do
project_link_filter(link, link_content: inner_html)
end
end
end
end
end
private
doc
def object_reference_pattern
@object_reference_pattern ||= Project.markdown_reference_pattern
end
# Replace `namespace/project>` project references in text with links to the referenced
......@@ -55,8 +39,8 @@ module Banzai
#
# Returns a String with `namespace/project>` references replaced with links. All links
# have `gfm` and `gfm-project` class names attached for styling.
def project_link_filter(text, link_content: nil)
self.class.references_in(text) do |match, project_path|
def object_link_filter(text, pattern, link_content: nil, link_reference: false)
references_in(text) do |match, project_path|
cached_call(:banzai_url_for_object, match, path: [Project, project_path.downcase]) do
if project = projects_hash[project_path.downcase]
link_to_project(project, link_content: link_content) || match
......@@ -92,8 +76,6 @@ module Banzai
refs.to_a
end
private
def urls
Gitlab::Routing.url_helpers
end
......
......@@ -16,8 +16,14 @@ module Banzai
include OutputSafety
class << self
# Implement in child class
# Example: self.reference_type = :merge_request
attr_accessor :reference_type
# Implement in child class
# Example: self.object_class = MergeRequest
attr_accessor :object_class
def call(doc, context = nil, result = nil)
new(doc, context, result).call_and_update_nodes
end
......@@ -34,6 +40,65 @@ module Banzai
with_update_nodes { call }
end
def call
ref_pattern_start = /\A#{object_reference_pattern}\z/
nodes.each_with_index do |node, index|
if text_node?(node)
replace_text_when_pattern_matches(node, index, object_reference_pattern) do |content|
object_link_filter(content, object_reference_pattern)
end
elsif element_node?(node)
yield_valid_link(node) do |link, inner_html|
if link =~ ref_pattern_start
replace_link_node_with_href(node, index, link) do
object_link_filter(link, object_reference_pattern, link_content: inner_html)
end
end
end
end
end
doc
end
# Public: Find references in text (like `!123` for merge requests)
#
# references_in(text) do |match, id, project_ref, matches|
# object = find_object(project_ref, id)
# "<a href=...>#{object.to_reference}</a>"
# end
#
# text - String text to search.
#
# Yields the String match, the Integer referenced object ID, an optional String
# of the external project reference, and all of the matchdata.
#
# Returns a String replaced with the return of the block.
def references_in(text, pattern = object_reference_pattern)
raise NotImplementedError, "#{self.class} must implement method: #{__callee__}"
end
# Iterates over all <a> and text() nodes in a document.
#
# Nodes are skipped whenever their ancestor is one of the nodes returned
# by `ignore_ancestor_query`. Link tags are not processed if they have a
# "gfm" class or the "href" attribute is empty.
def each_node
return to_enum(__method__) unless block_given?
doc.xpath(query).each do |node|
yield node
end
end
# Returns an Array containing all HTML nodes.
def nodes
@nodes ||= each_node.to_a
end
private
# Returns a data attribute String to attach to a reference link
#
# attributes - Hash, where the key becomes the data attribute name and the
......@@ -69,6 +134,13 @@ module Banzai
end
end
# Ensure that a :project key exists in context
#
# Note that while the key might exist, its value could be nil!
def validate
needs :project unless skip_project_check?
end
def project
context[:project]
end
......@@ -93,31 +165,6 @@ module Banzai
"#{gfm_klass} has-tooltip"
end
# Ensure that a :project key exists in context
#
# Note that while the key might exist, its value could be nil!
def validate
needs :project unless skip_project_check?
end
# Iterates over all <a> and text() nodes in a document.
#
# Nodes are skipped whenever their ancestor is one of the nodes returned
# by `ignore_ancestor_query`. Link tags are not processed if they have a
# "gfm" class or the "href" attribute is empty.
def each_node
return to_enum(__method__) unless block_given?
doc.xpath(query).each do |node|
yield node
end
end
# Returns an Array containing all HTML nodes.
def nodes
@nodes ||= each_node.to_a
end
# Yields the link's URL and inner HTML whenever the node is a valid <a> tag.
def yield_valid_link(node)
link = unescape_link(node.attr('href').to_s)
......@@ -132,6 +179,14 @@ module Banzai
CGI.unescape(href)
end
def unescape_html_entities(text)
CGI.unescapeHTML(text.to_s)
end
def escape_html_entities(text)
CGI.escapeHTML(text.to_s)
end
def replace_text_when_pattern_matches(node, index, pattern)
return unless node.text =~ pattern
......@@ -161,7 +216,25 @@ module Banzai
node.is_a?(Nokogiri::XML::Element)
end
private
def object_class
self.class.object_class
end
def object_reference_pattern
@object_reference_pattern ||= object_class.reference_pattern
end
def object_name
@object_name ||= object_class.name.underscore
end
def object_sym
@object_sym ||= object_name.to_sym
end
def object_link_filter(text, pattern, link_content: nil, link_reference: false)
raise NotImplementedError, "#{self.class} must implement method: #{__callee__}"
end
def query
@query ||= %Q{descendant-or-self::text()[not(#{ignore_ancestor_query})]
......
......@@ -9,10 +9,7 @@ module Banzai
# This filter supports cross-project references.
class SnippetReferenceFilter < AbstractReferenceFilter
self.reference_type = :snippet
def self.object_class
Snippet
end
self.object_class = Snippet
def find_object(project, id)
return unless project.is_a?(Project)
......
......@@ -8,10 +8,11 @@ module Banzai
# A special `@all` reference is also supported.
class UserReferenceFilter < ReferenceFilter
self.reference_type = :user
self.object_class = User
# Public: Find `@user` user references in text
#
# UserReferenceFilter.references_in(text) do |match, username|
# references_in(text) do |match, username|
# "<a href=...>@#{user}</a>"
# end
#
......@@ -20,8 +21,8 @@ module Banzai
# Yields the String match, and the String user name.
#
# Returns a String replaced with the return of the block.
def self.references_in(text)
text.gsub(User.reference_pattern) do |match|
def references_in(text, pattern = object_reference_pattern)
text.gsub(pattern) do |match|
yield match, $~[:user]
end
end
......@@ -29,28 +30,11 @@ module Banzai
def call
return doc if project.nil? && group.nil? && !skip_project_check?
ref_pattern = User.reference_pattern
ref_pattern_start = /\A#{ref_pattern}\z/
nodes.each_with_index do |node, index|
if text_node?(node)
replace_text_when_pattern_matches(node, index, ref_pattern) do |content|
user_link_filter(content)
end
elsif element_node?(node)
yield_valid_link(node) do |link, inner_html|
if link =~ ref_pattern_start
replace_link_node_with_href(node, index, link) do
user_link_filter(link, link_content: inner_html)
end
end
end
end
end
doc
super
end
private
# Replace `@user` user references in text with links to the referenced
# user's profile page.
#
......@@ -59,8 +43,8 @@ module Banzai
#
# Returns a String with `@user` references replaced with links. All links
# have `gfm` and `gfm-project_member` class names attached for styling.
def user_link_filter(text, link_content: nil)
self.class.references_in(text) do |match, username|
def object_link_filter(text, pattern, link_content: nil, link_reference: false)
references_in(text, pattern) do |match, username|
if username == 'all' && !skip_project_check?
link_to_all(link_content: link_content)
else
......@@ -100,8 +84,6 @@ module Banzai
refs.to_a
end
private
def urls
Gitlab::Routing.url_helpers
end
......
......@@ -6,16 +6,7 @@ module Banzai
# The actual filter is implemented in the EE mixin
class VulnerabilityReferenceFilter < IssuableReferenceFilter
self.reference_type = :vulnerability
def self.object_class
Vulnerability
end
private
def project
context[:project]
end
self.object_class = Vulnerability
end
end
end
......
......@@ -61,13 +61,13 @@ RSpec.describe Banzai::Filter::References::AbstractReferenceFilter do
.to eq([project])
end
context "when no project with that path exists" do
it "returns no value" do
context 'when no project with that path exists' do
it 'returns no value' do
expect(filter.find_for_paths(['nonexistent/project']))
.to eq([])
end
it "adds the ref to the project refs cache" do
it 'adds the ref to the project refs cache' do
project_refs_cache = {}
allow(filter).to receive(:refs_cache).and_return(project_refs_cache)
......@@ -99,4 +99,18 @@ RSpec.describe Banzai::Filter::References::AbstractReferenceFilter do
expect(filter.current_parent_path).to eq(project.full_path)
end
end
context 'abstract methods' do
describe '#find_object' do
it 'raises NotImplementedError' do
expect { filter.find_object(nil, nil) }.to raise_error(NotImplementedError)
end
end
describe '#url_for_object' do
it 'raises NotImplementedError' do
expect { filter.url_for_object(nil, nil) }.to raise_error(NotImplementedError)
end
end
end
end
......@@ -104,7 +104,7 @@ RSpec.describe Banzai::Filter::References::DesignReferenceFilter do
let(:pattern) { described_class.object_class.link_reference_pattern }
let(:parsed) do
m = pattern.match(url)
described_class.identifier(m) if m
described_class.new('', project: nil).identifier(m) if m
end
it 'can parse the reference' do
......@@ -119,9 +119,11 @@ RSpec.describe Banzai::Filter::References::DesignReferenceFilter do
describe 'static properties' do
specify do
expect(described_class).to have_attributes(
object_sym: :design,
reference_type: :design,
object_class: ::DesignManagement::Design
)
expect(described_class.new('', project: nil).object_sym).to eq :design
end
end
......
......@@ -493,19 +493,19 @@ RSpec.describe Banzai::Filter::References::IssueReferenceFilter do
it 'yields valid references' do
expect do |b|
described_class.references_in(issue.to_reference, &b)
described_class.new('', project: nil).references_in(issue.to_reference, &b)
end.to yield_with_args(issue.to_reference, issue.iid, nil, nil, MatchData)
end
it "doesn't yield invalid references" do
expect do |b|
described_class.references_in('#0', &b)
described_class.new('', project: nil).references_in('#0', &b)
end.not_to yield_control
end
it "doesn't yield unsupported references" do
expect do |b|
described_class.references_in(merge_request.to_reference, &b)
described_class.new('', project: nil).references_in(merge_request.to_reference, &b)
end.not_to yield_control
end
end
......
......@@ -85,7 +85,7 @@ RSpec.describe Banzai::Filter::References::ProjectReferenceFilter do
document = Nokogiri::HTML.fragment("<p>#{get_reference(project)}</p>")
filter = described_class.new(document, project: project)
expect(filter.projects_hash).to eq({ project.full_path => project })
expect(filter.send(:projects_hash)).to eq({ project.full_path => project })
end
end
......@@ -94,7 +94,7 @@ RSpec.describe Banzai::Filter::References::ProjectReferenceFilter do
document = Nokogiri::HTML.fragment("<p>#{get_reference(project)}</p>")
filter = described_class.new(document, project: project)
expect(filter.projects).to eq([project.full_path])
expect(filter.send(:projects)).to eq([project.full_path])
end
end
end
......@@ -155,7 +155,7 @@ RSpec.describe Banzai::Filter::References::ReferenceFilter do
let(:nodes) { [node] }
it 'skips node' do
expect { |b| filter.replace_text_when_pattern_matches(filter.nodes[0], 0, ref_pattern, &b) }.not_to yield_control
expect { |b| filter.send(:replace_text_when_pattern_matches, filter.nodes[0], 0, ref_pattern, &b) }.not_to yield_control
end
end
......@@ -183,12 +183,12 @@ RSpec.describe Banzai::Filter::References::ReferenceFilter do
end
end
describe "#call_and_update_nodes" do
describe '#call_and_update_nodes' do
include_context 'new nodes'
let(:document) { Nokogiri::HTML.fragment('<a href="foo">foo</a>') }
let(:filter) { described_class.new(document, project: project) }
it "updates all new nodes", :aggregate_failures do
it 'updates all new nodes', :aggregate_failures do
filter.instance_variable_set('@nodes', nodes)
expect(filter).to receive(:call) { filter.instance_variable_set('@new_nodes', new_nodes) }
......@@ -201,14 +201,14 @@ RSpec.describe Banzai::Filter::References::ReferenceFilter do
end
end
describe ".call" do
describe '.call' do
include_context 'new nodes'
let(:document) { Nokogiri::HTML.fragment('<a href="foo">foo</a>') }
let(:result) { { reference_filter_nodes: nodes } }
it "updates all nodes", :aggregate_failures do
it 'updates all nodes', :aggregate_failures do
expect_next_instance_of(described_class) do |filter|
expect(filter).to receive(:call_and_update_nodes).and_call_original
expect(filter).to receive(:with_update_nodes).and_call_original
......@@ -221,4 +221,21 @@ RSpec.describe Banzai::Filter::References::ReferenceFilter do
expect(result[:reference_filter_nodes]).to eq(expected_nodes)
end
end
context 'abstract methods' do
let(:document) { Nokogiri::HTML.fragment('<a href="foo">foo</a>') }
let(:filter) { described_class.new(document, project: project) }
describe '#references_in' do
it 'raises NotImplementedError' do
expect { filter.references_in('foo', %r{(?<!\w)}) }.to raise_error(NotImplementedError)
end
end
describe '#object_link_filter' do
it 'raises NotImplementedError' do
expect { filter.send(:object_link_filter, 'foo', %r{(?<!\w)}) }.to raise_error(NotImplementedError)
end
end
end
end
......@@ -189,7 +189,7 @@ RSpec.describe Banzai::Filter::References::UserReferenceFilter do
filter = described_class.new(document, project: project)
ns = user.namespace
expect(filter.namespaces).to eq({ ns.path => ns })
expect(filter.send(:namespaces)).to eq({ ns.path => ns })
end
end
......@@ -198,7 +198,7 @@ RSpec.describe Banzai::Filter::References::UserReferenceFilter do
document = Nokogiri::HTML.fragment("<p>#{get_reference(user)}</p>")
filter = described_class.new(document, project: project)
expect(filter.usernames).to eq([user.username])
expect(filter.send(:usernames)).to eq([user.username])
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment