2020-06-08 20:08:47 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
require 'spec_helper'
|
|
|
|
|
2020-06-26 05:08:59 -04:00
|
|
|
RSpec.describe Gitlab::Suggestions::FileSuggestion do
|
2020-06-22 08:08:47 -04:00
|
|
|
def create_suggestion(new_line, to_content, lines_above = 0, lines_below = 0)
|
2020-06-08 20:08:47 -04:00
|
|
|
position = Gitlab::Diff::Position.new(old_path: file_path,
|
|
|
|
new_path: file_path,
|
|
|
|
old_line: nil,
|
|
|
|
new_line: new_line,
|
|
|
|
diff_refs: merge_request.diff_refs)
|
|
|
|
|
|
|
|
diff_note = create(:diff_note_on_merge_request,
|
|
|
|
noteable: merge_request,
|
|
|
|
position: position,
|
|
|
|
project: project)
|
|
|
|
|
|
|
|
create(:suggestion,
|
|
|
|
:content_from_repo,
|
|
|
|
note: diff_note,
|
2020-06-22 08:08:47 -04:00
|
|
|
lines_above: lines_above,
|
|
|
|
lines_below: lines_below,
|
2020-06-08 20:08:47 -04:00
|
|
|
to_content: to_content)
|
|
|
|
end
|
|
|
|
|
|
|
|
let_it_be(:user) { create(:user) }
|
|
|
|
|
|
|
|
let_it_be(:file_path) { 'files/ruby/popen.rb'}
|
|
|
|
|
|
|
|
let_it_be(:project) { create(:project, :repository) }
|
|
|
|
|
|
|
|
let_it_be(:merge_request) do
|
|
|
|
create(:merge_request, source_project: project, target_project: project)
|
|
|
|
end
|
|
|
|
|
|
|
|
let_it_be(:suggestion1) do
|
|
|
|
create_suggestion(9, " *** SUGGESTION 1 ***\n")
|
|
|
|
end
|
|
|
|
|
|
|
|
let_it_be(:suggestion2) do
|
|
|
|
create_suggestion(15, " *** SUGGESTION 2 ***\n")
|
|
|
|
end
|
|
|
|
|
2020-06-22 08:08:47 -04:00
|
|
|
let(:suggestions) { [suggestion1, suggestion2] }
|
2020-06-08 20:08:47 -04:00
|
|
|
|
2020-06-22 08:08:47 -04:00
|
|
|
let(:file_suggestion) { described_class.new(file_path, suggestions) }
|
2020-06-08 20:08:47 -04:00
|
|
|
|
|
|
|
describe '#line_conflict' do
|
|
|
|
def stub_suggestions(line_index_spans)
|
|
|
|
fake_suggestions = line_index_spans.map do |span|
|
|
|
|
double("Suggestion",
|
|
|
|
from_line_index: span[:from_line_index],
|
|
|
|
to_line_index: span[:to_line_index])
|
|
|
|
end
|
|
|
|
|
|
|
|
allow(file_suggestion).to(receive(:suggestions).and_return(fake_suggestions))
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when line ranges do not overlap' do
|
|
|
|
it 'return false' do
|
|
|
|
stub_suggestions(
|
|
|
|
[
|
|
|
|
{
|
|
|
|
from_line_index: 0,
|
|
|
|
to_line_index: 10
|
|
|
|
},
|
|
|
|
{
|
|
|
|
from_line_index: 11,
|
|
|
|
to_line_index: 20
|
|
|
|
}
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|
|
|
|
expect(file_suggestion.line_conflict?).to be(false)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when line ranges are identical' do
|
|
|
|
it 'returns true' do
|
|
|
|
stub_suggestions(
|
|
|
|
[
|
|
|
|
{
|
|
|
|
from_line_index: 0,
|
|
|
|
to_line_index: 10
|
|
|
|
},
|
|
|
|
{
|
|
|
|
from_line_index: 0,
|
|
|
|
to_line_index: 10
|
|
|
|
}
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|
|
|
|
expect(file_suggestion.line_conflict?).to be(true)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when one range starts, and the other ends, on the same line' do
|
|
|
|
it 'returns true' do
|
|
|
|
stub_suggestions(
|
|
|
|
[
|
|
|
|
{
|
|
|
|
from_line_index: 0,
|
|
|
|
to_line_index: 10
|
|
|
|
},
|
|
|
|
{
|
|
|
|
from_line_index: 10,
|
|
|
|
to_line_index: 20
|
|
|
|
}
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|
|
|
|
expect(file_suggestion.line_conflict?).to be(true)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when one line range contains the other' do
|
|
|
|
it 'returns true' do
|
|
|
|
stub_suggestions(
|
|
|
|
[
|
|
|
|
{
|
|
|
|
from_line_index: 0,
|
|
|
|
to_line_index: 10
|
|
|
|
},
|
|
|
|
{
|
|
|
|
from_line_index: 5,
|
|
|
|
to_line_index: 7
|
|
|
|
}
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|
|
|
|
expect(file_suggestion.line_conflict?).to be(true)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when line ranges overlap' do
|
|
|
|
it 'returns true' do
|
|
|
|
stub_suggestions(
|
|
|
|
[
|
|
|
|
{
|
|
|
|
from_line_index: 0,
|
|
|
|
to_line_index: 10
|
|
|
|
},
|
|
|
|
{
|
|
|
|
from_line_index: 8,
|
|
|
|
to_line_index: 15
|
|
|
|
}
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|
|
|
|
expect(file_suggestion.line_conflict?).to be(true)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when no suggestions have been added' do
|
|
|
|
it 'returns false' do
|
|
|
|
expect(file_suggestion.line_conflict?).to be(false)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe '#new_content' do
|
2020-06-22 08:08:47 -04:00
|
|
|
context 'with two suggestions' do
|
|
|
|
let(:suggestions) { [suggestion1, suggestion2] }
|
2020-06-08 20:08:47 -04:00
|
|
|
|
2020-06-22 08:08:47 -04:00
|
|
|
it 'returns a blob with the suggestions applied to it' do
|
|
|
|
expected_content = <<-CONTENT.strip_heredoc
|
|
|
|
require 'fileutils'
|
|
|
|
require 'open3'
|
2020-06-08 20:08:47 -04:00
|
|
|
|
2020-06-22 08:08:47 -04:00
|
|
|
module Popen
|
|
|
|
extend self
|
2020-06-08 20:08:47 -04:00
|
|
|
|
2020-06-22 08:08:47 -04:00
|
|
|
def popen(cmd, path=nil)
|
|
|
|
unless cmd.is_a?(Array)
|
|
|
|
*** SUGGESTION 1 ***
|
|
|
|
end
|
|
|
|
|
|
|
|
path ||= Dir.pwd
|
|
|
|
|
|
|
|
vars = {
|
|
|
|
*** SUGGESTION 2 ***
|
|
|
|
}
|
|
|
|
|
|
|
|
options = {
|
|
|
|
chdir: path
|
|
|
|
}
|
|
|
|
|
|
|
|
unless File.directory?(path)
|
|
|
|
FileUtils.mkdir_p(path)
|
|
|
|
end
|
|
|
|
|
|
|
|
@cmd_output = ""
|
|
|
|
@cmd_status = 0
|
|
|
|
|
|
|
|
Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr|
|
|
|
|
@cmd_output << stdout.read
|
|
|
|
@cmd_output << stderr.read
|
|
|
|
@cmd_status = wait_thr.value.exitstatus
|
|
|
|
end
|
|
|
|
|
|
|
|
return @cmd_output, @cmd_status
|
2020-06-08 20:08:47 -04:00
|
|
|
end
|
2020-06-22 08:08:47 -04:00
|
|
|
end
|
|
|
|
CONTENT
|
2020-06-08 20:08:47 -04:00
|
|
|
|
2020-06-22 08:08:47 -04:00
|
|
|
expect(file_suggestion.new_content).to eq(expected_content)
|
|
|
|
end
|
|
|
|
end
|
2020-06-08 20:08:47 -04:00
|
|
|
|
2020-06-22 08:08:47 -04:00
|
|
|
context 'when no suggestions have been added' do
|
|
|
|
let(:suggestions) { [] }
|
2020-06-08 20:08:47 -04:00
|
|
|
|
2020-06-22 08:08:47 -04:00
|
|
|
it 'returns an empty string' do
|
|
|
|
expect(file_suggestion.new_content).to eq('')
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with multiline suggestions' do
|
|
|
|
let(:suggestions) { [multi_suggestion1, multi_suggestion2, multi_suggestion3] }
|
|
|
|
|
|
|
|
context 'when the previous suggestion increases the line count' do
|
|
|
|
let!(:multi_suggestion1) do
|
|
|
|
create_suggestion(9, " *** SUGGESTION 1 ***\n *** SECOND LINE ***\n *** THIRD LINE ***\n")
|
|
|
|
end
|
2020-06-08 20:08:47 -04:00
|
|
|
|
2020-06-22 08:08:47 -04:00
|
|
|
let!(:multi_suggestion2) do
|
|
|
|
create_suggestion(15, " *** SUGGESTION 2 ***\n *** SECOND LINE ***\n")
|
|
|
|
end
|
|
|
|
|
|
|
|
let!(:multi_suggestion3) do
|
|
|
|
create_suggestion(19, " chdir: *** SUGGESTION 3 ***\n")
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns a blob with the suggestions applied to it' do
|
|
|
|
expected_content = <<-CONTENT.strip_heredoc
|
|
|
|
require 'fileutils'
|
|
|
|
require 'open3'
|
|
|
|
|
|
|
|
module Popen
|
|
|
|
extend self
|
|
|
|
|
|
|
|
def popen(cmd, path=nil)
|
|
|
|
unless cmd.is_a?(Array)
|
|
|
|
*** SUGGESTION 1 ***
|
|
|
|
*** SECOND LINE ***
|
|
|
|
*** THIRD LINE ***
|
|
|
|
end
|
|
|
|
|
|
|
|
path ||= Dir.pwd
|
|
|
|
|
|
|
|
vars = {
|
|
|
|
*** SUGGESTION 2 ***
|
|
|
|
*** SECOND LINE ***
|
|
|
|
}
|
|
|
|
|
|
|
|
options = {
|
|
|
|
chdir: *** SUGGESTION 3 ***
|
|
|
|
}
|
|
|
|
|
|
|
|
unless File.directory?(path)
|
|
|
|
FileUtils.mkdir_p(path)
|
|
|
|
end
|
|
|
|
|
|
|
|
@cmd_output = ""
|
|
|
|
@cmd_status = 0
|
|
|
|
|
|
|
|
Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr|
|
|
|
|
@cmd_output << stdout.read
|
|
|
|
@cmd_output << stderr.read
|
|
|
|
@cmd_status = wait_thr.value.exitstatus
|
|
|
|
end
|
|
|
|
|
|
|
|
return @cmd_output, @cmd_status
|
2020-06-08 20:08:47 -04:00
|
|
|
end
|
2020-06-22 08:08:47 -04:00
|
|
|
end
|
|
|
|
CONTENT
|
|
|
|
|
|
|
|
expect(file_suggestion.new_content).to eq(expected_content)
|
|
|
|
end
|
|
|
|
end
|
2020-06-08 20:08:47 -04:00
|
|
|
|
2020-06-22 08:08:47 -04:00
|
|
|
context 'when the previous suggestion decreases and increases the line count' do
|
|
|
|
let!(:multi_suggestion1) do
|
|
|
|
create_suggestion(9, " *** SUGGESTION 1 ***\n", 1, 1)
|
|
|
|
end
|
|
|
|
|
|
|
|
let!(:multi_suggestion2) do
|
|
|
|
create_suggestion(15, " *** SUGGESTION 2 ***\n *** SECOND LINE ***\n")
|
|
|
|
end
|
|
|
|
|
|
|
|
let!(:multi_suggestion3) do
|
|
|
|
create_suggestion(19, " chdir: *** SUGGESTION 3 ***\n")
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns a blob with the suggestions applied to it' do
|
|
|
|
expected_content = <<-CONTENT.strip_heredoc
|
|
|
|
require 'fileutils'
|
|
|
|
require 'open3'
|
|
|
|
|
|
|
|
module Popen
|
|
|
|
extend self
|
|
|
|
|
|
|
|
def popen(cmd, path=nil)
|
|
|
|
*** SUGGESTION 1 ***
|
2020-06-08 20:08:47 -04:00
|
|
|
|
2020-06-22 08:08:47 -04:00
|
|
|
path ||= Dir.pwd
|
|
|
|
|
|
|
|
vars = {
|
|
|
|
*** SUGGESTION 2 ***
|
|
|
|
*** SECOND LINE ***
|
|
|
|
}
|
|
|
|
|
|
|
|
options = {
|
|
|
|
chdir: *** SUGGESTION 3 ***
|
|
|
|
}
|
|
|
|
|
|
|
|
unless File.directory?(path)
|
|
|
|
FileUtils.mkdir_p(path)
|
|
|
|
end
|
|
|
|
|
|
|
|
@cmd_output = ""
|
|
|
|
@cmd_status = 0
|
|
|
|
|
|
|
|
Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr|
|
|
|
|
@cmd_output << stdout.read
|
|
|
|
@cmd_output << stderr.read
|
|
|
|
@cmd_status = wait_thr.value.exitstatus
|
|
|
|
end
|
|
|
|
|
|
|
|
return @cmd_output, @cmd_status
|
2020-06-08 20:08:47 -04:00
|
|
|
end
|
2020-06-22 08:08:47 -04:00
|
|
|
end
|
|
|
|
CONTENT
|
|
|
|
|
|
|
|
expect(file_suggestion.new_content).to eq(expected_content)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when the previous suggestion replaces with the same number of lines' do
|
|
|
|
let!(:multi_suggestion1) do
|
|
|
|
create_suggestion(9, " *** SUGGESTION 1 ***\n *** SECOND LINE ***\n *** THIRD LINE ***\n", 1, 1)
|
|
|
|
end
|
|
|
|
|
|
|
|
let!(:multi_suggestion2) do
|
|
|
|
create_suggestion(15, " *** SUGGESTION 2 ***\n")
|
|
|
|
end
|
|
|
|
|
|
|
|
let!(:multi_suggestion3) do
|
|
|
|
create_suggestion(19, " chdir: *** SUGGESTION 3 ***\n")
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns a blob with the suggestions applied to it' do
|
|
|
|
expected_content = <<-CONTENT.strip_heredoc
|
|
|
|
require 'fileutils'
|
|
|
|
require 'open3'
|
|
|
|
|
|
|
|
module Popen
|
|
|
|
extend self
|
|
|
|
|
|
|
|
def popen(cmd, path=nil)
|
|
|
|
*** SUGGESTION 1 ***
|
|
|
|
*** SECOND LINE ***
|
|
|
|
*** THIRD LINE ***
|
|
|
|
|
|
|
|
path ||= Dir.pwd
|
|
|
|
|
|
|
|
vars = {
|
|
|
|
*** SUGGESTION 2 ***
|
|
|
|
}
|
|
|
|
|
|
|
|
options = {
|
|
|
|
chdir: *** SUGGESTION 3 ***
|
|
|
|
}
|
|
|
|
|
|
|
|
unless File.directory?(path)
|
|
|
|
FileUtils.mkdir_p(path)
|
|
|
|
end
|
|
|
|
|
|
|
|
@cmd_output = ""
|
|
|
|
@cmd_status = 0
|
|
|
|
|
|
|
|
Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr|
|
|
|
|
@cmd_output << stdout.read
|
|
|
|
@cmd_output << stderr.read
|
|
|
|
@cmd_status = wait_thr.value.exitstatus
|
|
|
|
end
|
2020-06-08 20:08:47 -04:00
|
|
|
|
2020-06-22 08:08:47 -04:00
|
|
|
return @cmd_output, @cmd_status
|
|
|
|
end
|
2020-06-08 20:08:47 -04:00
|
|
|
end
|
2020-06-22 08:08:47 -04:00
|
|
|
CONTENT
|
|
|
|
|
|
|
|
expect(file_suggestion.new_content).to eq(expected_content)
|
2020-06-08 20:08:47 -04:00
|
|
|
end
|
2020-06-22 08:08:47 -04:00
|
|
|
end
|
2020-06-08 20:08:47 -04:00
|
|
|
|
2020-06-22 08:08:47 -04:00
|
|
|
context 'when the previous suggestion replaces multiple lines and the suggestions were applied out of order' do
|
|
|
|
let(:suggestions) { [multi_suggestion1, multi_suggestion3, multi_suggestion2] }
|
2020-06-08 20:08:47 -04:00
|
|
|
|
2020-06-22 08:08:47 -04:00
|
|
|
let!(:multi_suggestion1) do
|
|
|
|
create_suggestion(9, " *** SUGGESTION 1 ***\n *** SECOND LINE ***\n *** THIRD LINE ***\n", 1, 1)
|
|
|
|
end
|
2020-06-08 20:08:47 -04:00
|
|
|
|
2020-06-22 08:08:47 -04:00
|
|
|
let!(:multi_suggestion3) do
|
|
|
|
create_suggestion(19, " *** SUGGESTION 3 ***\n", 1, 1)
|
|
|
|
end
|
2020-06-08 20:08:47 -04:00
|
|
|
|
2020-06-22 08:08:47 -04:00
|
|
|
let!(:multi_suggestion2) do
|
|
|
|
create_suggestion(15, " *** SUGGESTION 2 ***\n", 1, 1)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns a blob with the suggestions applied to it' do
|
|
|
|
expected_content = <<-CONTENT.strip_heredoc
|
|
|
|
require 'fileutils'
|
|
|
|
require 'open3'
|
|
|
|
|
|
|
|
module Popen
|
|
|
|
extend self
|
|
|
|
|
|
|
|
def popen(cmd, path=nil)
|
|
|
|
*** SUGGESTION 1 ***
|
|
|
|
*** SECOND LINE ***
|
|
|
|
*** THIRD LINE ***
|
|
|
|
|
|
|
|
path ||= Dir.pwd
|
|
|
|
|
|
|
|
*** SUGGESTION 2 ***
|
|
|
|
|
|
|
|
*** SUGGESTION 3 ***
|
|
|
|
|
|
|
|
unless File.directory?(path)
|
|
|
|
FileUtils.mkdir_p(path)
|
|
|
|
end
|
|
|
|
|
|
|
|
@cmd_output = ""
|
|
|
|
@cmd_status = 0
|
2020-06-08 20:08:47 -04:00
|
|
|
|
2020-06-22 08:08:47 -04:00
|
|
|
Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr|
|
|
|
|
@cmd_output << stdout.read
|
|
|
|
@cmd_output << stderr.read
|
|
|
|
@cmd_status = wait_thr.value.exitstatus
|
|
|
|
end
|
|
|
|
|
|
|
|
return @cmd_output, @cmd_status
|
|
|
|
end
|
|
|
|
end
|
|
|
|
CONTENT
|
|
|
|
|
|
|
|
expect(file_suggestion.new_content).to eq(expected_content)
|
|
|
|
end
|
|
|
|
end
|
2020-06-08 20:08:47 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|