Skip to content

Commit da69d17

Browse files
committed
Better newline handling when performing regexp diffs/ignores
1 parent b00015b commit da69d17

File tree

2 files changed

+134
-1
lines changed

2 files changed

+134
-1
lines changed

lib/octocatalog-diff/catalog-diff/differ.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,10 +294,13 @@ def regexp_operator_match?(operator, regex, old_val, new_val)
294294
# Use diffy to get only the lines that have changed in a text object.
295295
# As we iterate through the diff, jump out if we have our answer: either
296296
# true if '=~>' finds ANY match, or false if '=&>' fails to find a match.
297-
Diffy::Diff.new(old_val, new_val, context: 0).each do |line|
297+
diffy_result = Diffy::Diff.new(old_val, new_val, context: 0)
298+
newline_alerts = diffy_result.count { |line| line.strip == '\\ No newline at end of file' }
299+
diffy_result.each do |line|
298300
if regex.match(line.strip)
299301
return true if operator == '=~>'
300302
elsif operator == '=&>'
303+
next if line.strip == '\\ No newline at end of file' && newline_alerts == 2
301304
return false
302305
end
303306
end

spec/octocatalog-diff/tests/catalog-diff/differ_spec.rb

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1391,4 +1391,134 @@
13911391
expect(result[0]).to eq(['!', "Class\fOpenssl::Package\fparameters\fcommon-array", [1, 2, 3], [1, 5, 25], fileref, fileref])
13921392
end
13931393
end
1394+
1395+
describe '#regexp_operator_match?' do
1396+
let(:subject) { described_class.allocate }
1397+
1398+
context 'for a multi-line diff' do
1399+
context 'for operator =~>' do
1400+
let(:operator) { '=~>' }
1401+
let(:regex) { Regexp.new('\\A.(kittens|cats)\\z') }
1402+
1403+
it 'should return true when at least one line matches' do
1404+
old_val = "kittens\nkittens\ncats\n"
1405+
new_val = "puppies\ndogs\n"
1406+
expect(subject.send(:regexp_operator_match?, operator, regex, old_val, new_val)).to eq(true)
1407+
end
1408+
1409+
it 'should return false when neither line matches' do
1410+
old_val = "puppies\ndogs\ndonkeys\n"
1411+
new_val = "puppies\ndogs\n"
1412+
expect(subject.send(:regexp_operator_match?, operator, regex, old_val, new_val)).to eq(false)
1413+
end
1414+
end
1415+
1416+
context 'for operator =&>' do
1417+
let(:operator) { '=&>' }
1418+
let(:regex) { Regexp.new('\\A(-|\\+)(kittens )*(kittens|cats)\\z') }
1419+
1420+
it 'should return true when all lines match' do
1421+
old_val = "kittens\nkittens\ncats\n"
1422+
new_val = "kittens\nkittens\n"
1423+
expect(subject.send(:regexp_operator_match?, operator, regex, old_val, new_val)).to eq(true)
1424+
end
1425+
1426+
it 'should return false when the regex does not match line' do
1427+
old_val = "kittens\nkittens\ncats\n"
1428+
new_val = "kittens\nkittens\ndogs\n"
1429+
expect(subject.send(:regexp_operator_match?, operator, regex, old_val, new_val)).to eq(false)
1430+
end
1431+
1432+
it 'should return true if both old and new do not end in a newline' do
1433+
old_val = "kittens\nkittens\ncats"
1434+
new_val = "kittens\nkittens\nkittens"
1435+
expect(subject.send(:regexp_operator_match?, operator, regex, old_val, new_val)).to eq(true)
1436+
end
1437+
1438+
it 'should return false if one ends in a newline and the other does not' do
1439+
old_val = "kittens\nkittens\ncats\n"
1440+
new_val = "kittens\nkittens\nkittens"
1441+
expect(subject.send(:regexp_operator_match?, operator, regex, old_val, new_val)).to eq(false)
1442+
end
1443+
end
1444+
end
1445+
1446+
context 'for a single-line diff' do
1447+
context 'for operator =~>' do
1448+
let(:operator) { '=~>' }
1449+
let(:regex) { Regexp.new('\\A(-|\\+)(kittens )+(kittens|cats)\\z') }
1450+
1451+
it 'should return true when at least one line matches' do
1452+
old_val = 'kittens kittens kittens'
1453+
new_val = 'kittens cats'
1454+
expect(subject.send(:regexp_operator_match?, operator, regex, old_val, new_val)).to eq(true)
1455+
end
1456+
1457+
it 'should return false when neither line matches' do
1458+
old_val = 'kittens dogs cats kittens kittens'
1459+
new_val = 'kittens cats dogs'
1460+
expect(subject.send(:regexp_operator_match?, operator, regex, old_val, new_val)).to eq(false)
1461+
end
1462+
end
1463+
1464+
context 'for operator =&>' do
1465+
let(:operator) { '=&>' }
1466+
let(:regex) { Regexp.new('\\A(-|\\+)(kittens )+(kittens|cats)\\z') }
1467+
1468+
it 'should return true when both lines match' do
1469+
old_val = 'kittens kittens kittens'
1470+
new_val = 'kittens cats'
1471+
expect(subject.send(:regexp_operator_match?, operator, regex, old_val, new_val)).to eq(true)
1472+
end
1473+
1474+
it 'should return false when the regex does not match line' do
1475+
old_val = 'kittens kittens dogs kittens'
1476+
new_val = 'kittens cats'
1477+
expect(subject.send(:regexp_operator_match?, operator, regex, old_val, new_val)).to eq(false)
1478+
end
1479+
end
1480+
end
1481+
1482+
context 'for a multi-line versus a single-line diff' do
1483+
context 'for operator =~>' do
1484+
let(:operator) { '=~>' }
1485+
let(:regex) { Regexp.new('\\A.(kittens|cats)\\z') }
1486+
1487+
it 'should return true when at least one line matches' do
1488+
old_val = "kittens\nkittens\ncats\n"
1489+
new_val = 'puppies'
1490+
expect(subject.send(:regexp_operator_match?, operator, regex, old_val, new_val)).to eq(true)
1491+
end
1492+
1493+
it 'should return false when neither line matches' do
1494+
old_val = "puppies\ndogs\ndonkeys\n"
1495+
new_val = 'puppies'
1496+
expect(subject.send(:regexp_operator_match?, operator, regex, old_val, new_val)).to eq(false)
1497+
end
1498+
end
1499+
1500+
context 'for operator =&>' do
1501+
let(:operator) { '=&>' }
1502+
let(:regex) { Regexp.new('\\A(-|\\+)(kittens )*(kittens|cats)\\z') }
1503+
1504+
it 'should return true when all lines match and both old and new do not end in newline' do
1505+
old_val = "kittens\nkittens\ncats"
1506+
new_val = 'kittens'
1507+
expect(subject.send(:regexp_operator_match?, operator, regex, old_val, new_val)).to eq(true)
1508+
end
1509+
1510+
it 'should return false when all lines match but ending in newlines differs' do
1511+
old_val = "kittens\nkittens\ncats\n"
1512+
new_val = 'kittens'
1513+
expect(subject.send(:regexp_operator_match?, operator, regex, old_val, new_val)).to eq(false)
1514+
end
1515+
1516+
it 'should return false when the regex does not match line' do
1517+
old_val = "kittens\nkittens\ncats"
1518+
new_val = 'dogs'
1519+
expect(subject.send(:regexp_operator_match?, operator, regex, old_val, new_val)).to eq(false)
1520+
end
1521+
end
1522+
end
1523+
end
13941524
end

0 commit comments

Comments
 (0)