# frozen_string_literal: true require 'spec_helper' RSpec.describe Gitlab::Diff::Highlight do include RepoHelpers let_it_be(:project) { create(:project, :repository) } let(:commit) { project.commit(sample_commit.id) } let(:diff) { commit.raw_diffs.first } let(:diff_file) { Gitlab::Diff::File.new(diff, diff_refs: commit.diff_refs, repository: project.repository) } shared_examples 'without inline diffs' do let(:code) { '

Test

' } before do allow(Gitlab::Diff::InlineDiff).to receive(:for_lines).and_return([]) allow_any_instance_of(Gitlab::Diff::Line).to receive(:text).and_return(code) end it 'returns html escaped diff text' do expect(subject[1].rich_text).to eq html_escape(code) expect(subject[1].rich_text).to be_html_safe end end describe '#highlight' do context "with a diff file" do let(:subject) { described_class.new(diff_file, repository: project.repository).highlight } it 'returns Gitlab::Diff::Line elements' do expect(subject.first).to be_an_instance_of(Gitlab::Diff::Line) end it 'does not modify "match" lines' do expect(subject[0].text).to eq('@@ -6,12 +6,18 @@ module Popen') expect(subject[22].text).to eq('@@ -19,6 +25,7 @@ module Popen') end it 'highlights and marks unchanged lines' do code = %Q{ def popen(cmd, path=nil)\n} expect(subject[2].rich_text).to eq(code) end it 'highlights and marks removed lines' do code = %Q{- raise "System commands must be given as an array of strings"\n} expect(subject[4].rich_text).to eq(code) end it 'highlights and marks added lines' do code = %Q{+ raise RuntimeError, "System commands must be given as an array of strings"\n} expect(subject[5].rich_text).to eq(code) end context 'when no diff_refs' do before do allow(diff_file).to receive(:diff_refs).and_return(nil) end context 'when no inline diffs' do it_behaves_like 'without inline diffs' end end end context "with diff lines" do let(:subject) { described_class.new(diff_file.diff_lines, repository: project.repository).highlight } it 'returns Gitlab::Diff::Line elements' do expect(subject.first).to be_an_instance_of(Gitlab::Diff::Line) end it 'does not modify "match" lines' do expect(subject[0].text).to eq('@@ -6,12 +6,18 @@ module Popen') expect(subject[22].text).to eq('@@ -19,6 +25,7 @@ module Popen') end it 'marks unchanged lines' do code = %q{ def popen(cmd, path=nil)} expect(subject[2].text).to eq(code) expect(subject[2].text).not_to be_html_safe end it 'marks removed lines' do code = %q{- raise "System commands must be given as an array of strings"} expect(subject[4].text).to eq(code) expect(subject[4].text).not_to be_html_safe end it 'marks added lines' do code = %q{+ raise RuntimeError, "System commands must be given as an array of strings"} expect(subject[5].rich_text).to eq(code) expect(subject[5].rich_text).to be_html_safe end context 'when the inline diff marker has an invalid range' do before do allow_any_instance_of(Gitlab::Diff::InlineDiffMarker).to receive(:mark).and_raise(RangeError) end it 'keeps the original rich line' do allow(Gitlab::ErrorTracking).to receive(:track_and_raise_for_dev_exception) code = %q{+ raise RuntimeError, "System commands must be given as an array of strings"} expect(subject[5].text).to eq(code) expect(subject[5].text).not_to be_html_safe end it 'reports to Sentry if configured' do expect(Gitlab::ErrorTracking).to receive(:track_and_raise_for_dev_exception).and_call_original expect { subject }.to raise_exception(RangeError) end end context 'when `use_marker_ranges` feature flag is disabled' do it 'returns the same result' do with_feature_flag = described_class.new(diff_file, repository: project.repository).highlight stub_feature_flags(use_marker_ranges: false) without_feature_flag = described_class.new(diff_file, repository: project.repository).highlight expect(with_feature_flag.map(&:rich_text)).to eq(without_feature_flag.map(&:rich_text)) end end context 'when no inline diffs' do it_behaves_like 'without inline diffs' end end context 'when blob is too large' do let(:subject) { described_class.new(diff_file, repository: project.repository).highlight } before do allow(Gitlab::Highlight).to receive(:too_large?).and_return(true) end it 'blobs are highlighted as plain text without loading all data' do expect(diff_file.blob).not_to receive(:load_all_data!) expect(subject[2].rich_text).to eq(%Q{ def popen(cmd, path=nil)\n}) expect(subject[2].rich_text).to be_html_safe end end end end