From df2ed097b730c8ba0b79cac8cc3dbfcb0cf587cb Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Mon, 25 Jul 2016 19:47:09 +0100 Subject: Add backend for merge conflicts reading --- spec/lib/gitlab/conflict/file_spec.rb | 76 ++++++++++++++ spec/lib/gitlab/conflict/parser_spec.rb | 178 ++++++++++++++++++++++++++++++++ 2 files changed, 254 insertions(+) create mode 100644 spec/lib/gitlab/conflict/file_spec.rb create mode 100644 spec/lib/gitlab/conflict/parser_spec.rb (limited to 'spec/lib') diff --git a/spec/lib/gitlab/conflict/file_spec.rb b/spec/lib/gitlab/conflict/file_spec.rb new file mode 100644 index 00000000000..318d0d249d6 --- /dev/null +++ b/spec/lib/gitlab/conflict/file_spec.rb @@ -0,0 +1,76 @@ +require 'spec_helper' + +describe Gitlab::Conflict::File, lib: true do + let(:project) { create(:project) } + let(:repository) { project.repository } + let(:rugged) { repository.rugged } + let(:their_ref) { their_commit.oid } + let(:their_commit) { rugged.branches['conflict-a'].target } + let(:our_ref) { our_commit.oid } + let(:our_commit) { rugged.branches['conflict-b'].target } + let(:index) { rugged.merge_commits(our_commit, their_commit) } + let(:conflict) { index.conflicts.last } + let(:merge_file) { index.merge_file('files/ruby/regex.rb') } + let(:conflict_file) { Gitlab::Conflict::File.new(merge_file, conflict, their_ref, our_ref, repository) } + + describe '#highlighted_lines' do + def html_to_text(html) + CGI.unescapeHTML(ActionView::Base.full_sanitizer.sanitize(html)) + end + + it 'returns lines with rich_text' do + conflict_file.highlighted_lines.each do |line| + expect(line).to have_attributes(rich_text: an_instance_of(String)) + end + end + + it 'returns lines with rich_text matching the text content of the line' do + conflict_file.highlighted_lines.each do |line| + expect(line.text).to eq(html_to_text(line.rich_text)) + end + end + end + + describe '#sections' do + it 'returns match lines when there is a gap between sections' do + section = conflict_file.sections[5] + match_line = section[:lines][0] + + expect(section[:conflict]).to be_falsey + expect(match_line.type).to eq('match') + expect(match_line.text).to eq('@@ -46,53 +46,53 @@') + end + + it 'does not return match lines when there is no gap between sections' do + conflict_file.sections.each_with_index do |section, i| + unless i == 5 + expect(section[:lines][0].type).not_to eq(5) + end + end + end + + it 'sets conflict to false for sections with only unchanged lines' do + conflict_file.sections.reject { |section| section[:conflict] }.each do |section| + without_match = section[:lines].reject { |line| line.type == 'match' } + + expect(without_match).to all(have_attributes(type: nil)) + end + end + + it 'only includes a maximum of CONTEXT_LINES (plus an optional match line) in context sections' do + conflict_file.sections.reject { |section| section[:conflict] }.each do |section| + without_match = section[:lines].reject { |line| line.type == 'match' } + + expect(without_match.length).to be <= Gitlab::Conflict::File::CONTEXT_LINES * 2 + end + end + + it 'sets conflict to true for sections with only changed lines' do + conflict_file.sections.select { |section| section[:conflict] }.each do |section| + section[:lines].each do |line| + expect(line.type).to be_in(['new', 'old']) + end + end + end + end +end diff --git a/spec/lib/gitlab/conflict/parser_spec.rb b/spec/lib/gitlab/conflict/parser_spec.rb new file mode 100644 index 00000000000..335da58e13c --- /dev/null +++ b/spec/lib/gitlab/conflict/parser_spec.rb @@ -0,0 +1,178 @@ +require 'spec_helper' + +describe Gitlab::Conflict::Parser, lib: true do + let(:parser) { Gitlab::Conflict::Parser.new } + + describe '#parse' do + context 'when the file has valid conflicts' do + let(:text) do + <>>>>>> files/ruby/regex.rb + end + + def path_regexp + default_regexp + end + +<<<<<<< files/ruby/regex.rb + def archive_formats_regexp + /(zip|tar|7z|tar\.gz|tgz|gz|tar\.bz2|tbz|tbz2|tb2|bz2)/ +======= + def archive_formats_regex + %r{(zip|tar|7z|tar\.gz|tgz|gz|tar\.bz2|tbz|tbz2|tb2|bz2)} +>>>>>>> files/ruby/regex.rb + end + + def git_reference_regexp + # Valid git ref regexp, see: + # https://www.kernel.org/pub/software/scm/git/docs/git-check-ref-format.html + %r{ + (?! + (?# doesn't begins with) + \/| (?# rule #6) + (?# doesn't contain) + .*(?: + [\/.]\.| (?# rule #1,3) + \/\/| (?# rule #6) + @\{| (?# rule #8) + \\ (?# rule #9) + ) + ) + [^\000-\040\177~^:?*\[]+ (?# rule #4-5) + (?# doesn't end with) + (?>>>>>> files/ruby/regex.rb + end + end +end +CONFLICT + end + + let(:lines) { parser.parse(text, 'files/ruby/regex.rb', 'files/ruby/regex.rb') } + + it 'sets our lines as new lines' do + expect(lines[8..13]).to all(have_attributes(type: 'new')) + expect(lines[26..27]).to all(have_attributes(type: 'new')) + expect(lines[56..57]).to all(have_attributes(type: 'new')) + end + + it 'sets their lines as old lines' do + expect(lines[14..19]).to all(have_attributes(type: 'old')) + expect(lines[28..29]).to all(have_attributes(type: 'old')) + expect(lines[58..59]).to all(have_attributes(type: 'old')) + end + + it 'sets non-conflicted lines as both' do + expect(lines[0..7]).to all(have_attributes(type: nil)) + expect(lines[20..25]).to all(have_attributes(type: nil)) + expect(lines[30..55]).to all(have_attributes(type: nil)) + expect(lines[60..62]).to all(have_attributes(type: nil)) + end + + it 'sets consecutive line numbers for index, old_pos, and new_pos' do + old_line_numbers = lines.select { |line| line.type != 'new' }.map(&:old_pos) + new_line_numbers = lines.select { |line| line.type != 'old' }.map(&:new_pos) + + expect(lines.map(&:index)).to eq(0.upto(62).to_a) + expect(old_line_numbers).to eq(1.upto(53).to_a) + expect(new_line_numbers).to eq(1.upto(53).to_a) + end + end + + context 'when the file contents include conflict delimiters' do + let(:path) { 'README.md' } + + def parse_text(text) + parser.parse(text, path, path) + end + + it 'raises UnexpectedDelimiter when there is a non-start delimiter first' do + expect { parse_text('=======') }. + to raise_error(Gitlab::Conflict::Parser::UnexpectedDelimiter) + + expect { parse_text('>>>>>>> README.md') }. + to raise_error(Gitlab::Conflict::Parser::UnexpectedDelimiter) + + expect { parse_text('>>>>>>> some-other-path.md') }. + not_to raise_error + end + + it 'raises UnexpectedDelimiter when a start delimiter is followed by a non-middle delimiter' do + start_text = "<<<<<<< README.md\n" + end_text = "\n=======\n>>>>>>> README.md" + + expect { parse_text(start_text + '>>>>>>> README.md' + end_text) }. + to raise_error(Gitlab::Conflict::Parser::UnexpectedDelimiter) + + expect { parse_text(start_text + start_text + end_text) }. + to raise_error(Gitlab::Conflict::Parser::UnexpectedDelimiter) + + expect { parse_text(start_text + '>>>>>>> some-other-path.md' + end_text) }. + not_to raise_error + end + + it 'raises UnexpectedDelimiter when a middle delimiter is followed by a non-end delimiter' do + start_text = "<<<<<<< README.md\n=======\n" + end_text = "\n>>>>>>> README.md" + + expect { parse_text(start_text + '=======' + end_text) }. + to raise_error(Gitlab::Conflict::Parser::UnexpectedDelimiter) + + expect { parse_text(start_text + start_text + end_text) }. + to raise_error(Gitlab::Conflict::Parser::UnexpectedDelimiter) + + expect { parse_text(start_text + '>>>>>>> some-other-path.md' + end_text) }. + not_to raise_error + end + + it 'raises MissingEndDelimiter when there is no end delimiter at the end' do + start_text = "<<<<<<< README.md\n=======\n" + + expect { parse_text(start_text) }. + to raise_error(Gitlab::Conflict::Parser::MissingEndDelimiter) + + expect { parse_text(start_text + '>>>>>>> some-other-path.md') }. + to raise_error(Gitlab::Conflict::Parser::MissingEndDelimiter) + end + end + + context 'when lines is blank' do + it { expect(parser.parse('', 'README.md', 'README.md')).to eq([]) } + it { expect(parser.parse(nil, 'README.md', 'README.md')).to eq([]) } + end + end +end -- cgit v1.2.1