FA-75426 / Text diff and three-way merge / Open access
Patch application with offset search: a rejected hunk still shifts later hunks · case 01
After one hunk fails, the following hunks are searched at displaced positions.
ROOT CAUSE
The size change of a rejected hunk is added to the shift even though nothing was applied.
VERIFIED REPAIR
Leave the shift untouched when a hunk is rejected.
Unsuccessful approach: Resetting the shift to zero discards the offsets of hunks that did apply.
Case contract
Hunks [old_start, old_lines, new_lines] are applied in order. The expected index is old_start-1 plus the accumulated shift. The search tries distance 0, then 1, 2, ... up to max_offset, at each distance the earlier position before the later one; the first position where old_lines match replaces them with new_lines. After an applied hunk the shift grows by (found-expected) + len(new)-len(old); a hunk that does not match is rejected and changes nothing. Return lines, 1-based applied positions and rejected hunk indices.
Why this case matters
Patch tools tolerate drift by searching near the expected line and carrying the discovered offset to later hunks.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(target, hunks, max_offset):
lines = list(target)
delta = 0
applied, rejected = [], []
for h_i, (old_start, old, new) in enumerate(hunks):
expect = old_start - 1 + delta
found = None
for dist in range(0, max_offset + 1):
for pos in ((expect - dist, expect + dist) if dist else (expect,)):
if 0 <= pos and pos + len(old) <= len(lines) and lines[pos:pos + len(old)] == old:
found = pos
break
if found is not None:
break
if found is None:
rejected.append(h_i)
delta += len(new) - len(old)
continue
lines[found:found + len(old)] = new
applied.append(found + 1)
delta += (found - expect) + len(new) - len(old)
return {'lines': lines, 'applied': applied, 'rejected': rejected}
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = {
1: [('clean apply at the expected line', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X', 'l4']]], 3], {'lines': ['l1', 'l2', 'l3', 'X', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [3], 'rejected': []}), ('offset because lines were added above', [['pre0', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 2], {'lines': ['pre0', 'l1', 'l2', 'l3', 'X', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [4], 'rejected': []}), ('offset beyond the limit is rejected', [['pre0', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 0], {'lines': ['pre0', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [], 'rejected': [0]}), ("second hunk follows the first hunk's offset", [['pre0', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['l2', 'A', 'B']], [8, ['l8', 'l9'], ['Z']]], 1], {'lines': ['pre0', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'Z', 'l10', 'l11', 'l12'], 'applied': [3, 11], 'rejected': []}), ('equal distances prefer the earlier match', [['a', 'k', 'b', 'k', 'c'], [[3, ['k'], ['K']]], 1], {'lines': ['a', 'K', 'b', 'k', 'c'], 'applied': [2], 'rejected': []}), ('rejected hunk does not shift later hunks', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['nope'], ['x', 'y', 'z']], [5, ['l5'], ['F', 'l5']]], 1], {'lines': ['l1', 'l2', 'l3', 'l4', 'F', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [5], 'rejected': [0]}), ('rejected hunk keeps earlier shifts', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['l1', 'a', 'b']], [3, ['nope'], ['x']], [5, ['l5'], ['F']]], 1], {'lines': ['l1', 'a', 'b', 'l2', 'l3', 'l4', 'F', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [1, 7], 'rejected': [1]}), ('carried offset keeps a far hunk in range', [['pre', 'pre', 'pre', 'l1', 'l2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['L2']], [8, ['l8'], ['L81']]], 3], {'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'L81', 'l9', 'l10', 'l11', 'l12'], 'applied': [5, 13], 'rejected': []}), ('two hunks with size changes', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1', 'l2'], ['l1']], [6, ['l6'], ['l6', 'm', 'm2']], [10, ['l10'], ['T']]], 0], {'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'm', 'm2', 'l7', 'l8', 'l9', 'T', 'l11', 'l12'], 'applied': [1, 5, 11], 'rejected': []}), ('only a later occurrence matches', [['q', 'r', 's', 'x', 'y', 'x', 'y'], [[4, ['x', 'z'], ['w']], [1, ['r'], ['R']]], 2], {'lines': ['q', 'R', 's', 'x', 'y', 'x', 'y'], 'applied': [2], 'rejected': [0]}), ('match exactly at the offset limit', [['p', 'p', 'z', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['L1']]], 3], {'lines': ['p', 'p', 'z', 'L1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [4], 'rejected': []})],
2: [('clean apply at the expected line', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X', 'l4']]], 3], {'lines': ['l1', 'l2', 'l3', 'X', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [3], 'rejected': []}), ('offset because lines were added above', [['pre0', 'pre1', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 3], {'lines': ['pre0', 'pre1', 'l1', 'l2', 'l3', 'X', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [5], 'rejected': []}), ('offset beyond the limit is rejected', [['pre0', 'pre1', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 1], {'lines': ['pre0', 'pre1', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [], 'rejected': [0]}), ("second hunk follows the first hunk's offset", [['pre0', 'pre1', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['l2', 'A', 'B']], [8, ['l8', 'l9'], ['Z']]], 2], {'lines': ['pre0', 'pre1', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'Z', 'l10', 'l11', 'l12'], 'applied': [4, 12], 'rejected': []}), ('equal distances prefer the earlier match', [['a', 'k', 'b', 'k', 'c'], [[3, ['k'], ['K']]], 1], {'lines': ['a', 'K', 'b', 'k', 'c'], 'applied': [2], 'rejected': []}), ('rejected hunk does not shift later hunks', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['nope'], ['x', 'y', 'z']], [5, ['l5'], ['F', 'l5']]], 1], {'lines': ['l1', 'l2', 'l3', 'l4', 'F', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [5], 'rejected': [0]}), ('rejected hunk keeps earlier shifts', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['l1', 'a', 'b']], [3, ['nope'], ['x']], [5, ['l5'], ['F']]], 1], {'lines': ['l1', 'a', 'b', 'l2', 'l3', 'l4', 'F', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [1, 7], 'rejected': [1]}), ('carried offset keeps a far hunk in range', [['pre', 'pre', 'pre', 'l1', 'l2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['L2']], [8, ['l8'], ['L82']]], 3], {'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'L82', 'l9', 'l10', 'l11', 'l12'], 'applied': [5, 13], 'rejected': []}), ('two hunks with size changes', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1', 'l2'], ['l1']], [6, ['l6'], ['l6', 'm', 'm2']], [10, ['l10'], ['T']]], 0], {'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'm', 'm2', 'l7', 'l8', 'l9', 'T', 'l11', 'l12'], 'applied': [1, 5, 11], 'rejected': []}), ('only a later occurrence matches', [['q', 'r', 's', 'x', 'y', 'x', 'y'], [[4, ['x', 'z'], ['w']], [1, ['r'], ['R']]], 2], {'lines': ['q', 'R', 's', 'x', 'y', 'x', 'y'], 'applied': [2], 'rejected': [0]}), ('match exactly at the offset limit', [['p', 'p', 'z', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['L1']]], 3], {'lines': ['p', 'p', 'z', 'L1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [4], 'rejected': []})],
3: [('clean apply at the expected line', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X', 'l4']]], 3], {'lines': ['l1', 'l2', 'l3', 'X', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [3], 'rejected': []}), ('offset because lines were added above', [['pre0', 'pre1', 'pre2', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 4], {'lines': ['pre0', 'pre1', 'pre2', 'l1', 'l2', 'l3', 'X', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [6], 'rejected': []}), ('offset beyond the limit is rejected', [['pre0', 'pre1', 'pre2', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 2], {'lines': ['pre0', 'pre1', 'pre2', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [], 'rejected': [0]}), ("second hunk follows the first hunk's offset", [['pre0', 'pre1', 'pre2', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['l2', 'A', 'B']], [8, ['l8', 'l9'], ['Z']]], 3], {'lines': ['pre0', 'pre1', 'pre2', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'Z', 'l10', 'l11', 'l12'], 'applied': [5, 13], 'rejected': []}), ('equal distances prefer the earlier match', [['a', 'k', 'b', 'k', 'c'], [[3, ['k'], ['K']]], 1], {'lines': ['a', 'K', 'b', 'k', 'c'], 'applied': [2], 'rejected': []}), ('rejected hunk does not shift later hunks', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['nope'], ['x', 'y', 'z']], [5, ['l5'], ['F', 'l5']]], 1], {'lines': ['l1', 'l2', 'l3', 'l4', 'F', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [5], 'rejected': [0]}), ('rejected hunk keeps earlier shifts', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['l1', 'a', 'b']], [3, ['nope'], ['x']], [5, ['l5'], ['F']]], 1], {'lines': ['l1', 'a', 'b', 'l2', 'l3', 'l4', 'F', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [1, 7], 'rejected': [1]}), ('carried offset keeps a far hunk in range', [['pre', 'pre', 'pre', 'l1', 'l2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['L2']], [8, ['l8'], ['L83']]], 3], {'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'L83', 'l9', 'l10', 'l11', 'l12'], 'applied': [5, 13], 'rejected': []}), ('two hunks with size changes', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1', 'l2'], ['l1']], [6, ['l6'], ['l6', 'm', 'm2']], [10, ['l10'], ['T']]], 0], {'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'm', 'm2', 'l7', 'l8', 'l9', 'T', 'l11', 'l12'], 'applied': [1, 5, 11], 'rejected': []}), ('only a later occurrence matches', [['q', 'r', 's', 'x', 'y', 'x', 'y'], [[4, ['x', 'z'], ['w']], [1, ['r'], ['R']]], 2], {'lines': ['q', 'R', 's', 'x', 'y', 'x', 'y'], 'applied': [2], 'rejected': [0]}), ('match exactly at the offset limit', [['p', 'p', 'z', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['L1']]], 3], {'lines': ['p', 'p', 'z', 'L1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [4], 'rejected': []})],
4: [('clean apply at the expected line', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X', 'l4']]], 3], {'lines': ['l1', 'l2', 'l3', 'X', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [3], 'rejected': []}), ('offset because lines were added above', [['pre0', 'pre1', 'pre2', 'pre3', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 5], {'lines': ['pre0', 'pre1', 'pre2', 'pre3', 'l1', 'l2', 'l3', 'X', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [7], 'rejected': []}), ('offset beyond the limit is rejected', [['pre0', 'pre1', 'pre2', 'pre3', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 3], {'lines': ['pre0', 'pre1', 'pre2', 'pre3', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [], 'rejected': [0]}), ("second hunk follows the first hunk's offset", [['pre0', 'pre1', 'pre2', 'pre3', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['l2', 'A', 'B']], [8, ['l8', 'l9'], ['Z']]], 4], {'lines': ['pre0', 'pre1', 'pre2', 'pre3', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'Z', 'l10', 'l11', 'l12'], 'applied': [6, 14], 'rejected': []}), ('equal distances prefer the earlier match', [['a', 'k', 'b', 'k', 'c'], [[3, ['k'], ['K']]], 1], {'lines': ['a', 'K', 'b', 'k', 'c'], 'applied': [2], 'rejected': []}), ('rejected hunk does not shift later hunks', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['nope'], ['x', 'y', 'z']], [5, ['l5'], ['F', 'l5']]], 1], {'lines': ['l1', 'l2', 'l3', 'l4', 'F', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [5], 'rejected': [0]}), ('rejected hunk keeps earlier shifts', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['l1', 'a', 'b']], [3, ['nope'], ['x']], [5, ['l5'], ['F']]], 1], {'lines': ['l1', 'a', 'b', 'l2', 'l3', 'l4', 'F', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [1, 7], 'rejected': [1]}), ('carried offset keeps a far hunk in range', [['pre', 'pre', 'pre', 'l1', 'l2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['L2']], [8, ['l8'], ['L84']]], 3], {'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'L84', 'l9', 'l10', 'l11', 'l12'], 'applied': [5, 13], 'rejected': []}), ('two hunks with size changes', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1', 'l2'], ['l1']], [6, ['l6'], ['l6', 'm', 'm2']], [10, ['l10'], ['T']]], 0], {'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'm', 'm2', 'l7', 'l8', 'l9', 'T', 'l11', 'l12'], 'applied': [1, 5, 11], 'rejected': []}), ('only a later occurrence matches', [['q', 'r', 's', 'x', 'y', 'x', 'y'], [[4, ['x', 'z'], ['w']], [1, ['r'], ['R']]], 2], {'lines': ['q', 'R', 's', 'x', 'y', 'x', 'y'], 'applied': [2], 'rejected': [0]}), ('match exactly at the offset limit', [['p', 'p', 'z', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['L1']]], 3], {'lines': ['p', 'p', 'z', 'L1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [4], 'rejected': []})],
5: [('clean apply at the expected line', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X', 'l4']]], 3], {'lines': ['l1', 'l2', 'l3', 'X', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [3], 'rejected': []}), ('offset because lines were added above', [['pre0', 'pre1', 'pre2', 'pre3', 'pre4', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 6], {'lines': ['pre0', 'pre1', 'pre2', 'pre3', 'pre4', 'l1', 'l2', 'l3', 'X', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [8], 'rejected': []}), ('offset beyond the limit is rejected', [['pre0', 'pre1', 'pre2', 'pre3', 'pre4', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 4], {'lines': ['pre0', 'pre1', 'pre2', 'pre3', 'pre4', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [], 'rejected': [0]}), ("second hunk follows the first hunk's offset", [['pre0', 'pre1', 'pre2', 'pre3', 'pre4', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['l2', 'A', 'B']], [8, ['l8', 'l9'], ['Z']]], 5], {'lines': ['pre0', 'pre1', 'pre2', 'pre3', 'pre4', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'Z', 'l10', 'l11', 'l12'], 'applied': [7, 15], 'rejected': []}), ('equal distances prefer the earlier match', [['a', 'k', 'b', 'k', 'c'], [[3, ['k'], ['K']]], 1], {'lines': ['a', 'K', 'b', 'k', 'c'], 'applied': [2], 'rejected': []}), ('rejected hunk does not shift later hunks', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['nope'], ['x', 'y', 'z']], [5, ['l5'], ['F', 'l5']]], 1], {'lines': ['l1', 'l2', 'l3', 'l4', 'F', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [5], 'rejected': [0]}), ('rejected hunk keeps earlier shifts', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['l1', 'a', 'b']], [3, ['nope'], ['x']], [5, ['l5'], ['F']]], 1], {'lines': ['l1', 'a', 'b', 'l2', 'l3', 'l4', 'F', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [1, 7], 'rejected': [1]}), ('carried offset keeps a far hunk in range', [['pre', 'pre', 'pre', 'l1', 'l2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['L2']], [8, ['l8'], ['L85']]], 3], {'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'L85', 'l9', 'l10', 'l11', 'l12'], 'applied': [5, 13], 'rejected': []}), ('two hunks with size changes', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1', 'l2'], ['l1']], [6, ['l6'], ['l6', 'm', 'm2']], [10, ['l10'], ['T']]], 0], {'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'm', 'm2', 'l7', 'l8', 'l9', 'T', 'l11', 'l12'], 'applied': [1, 5, 11], 'rejected': []}), ('only a later occurrence matches', [['q', 'r', 's', 'x', 'y', 'x', 'y'], [[4, ['x', 'z'], ['w']], [1, ['r'], ['R']]], 2], {'lines': ['q', 'R', 's', 'x', 'y', 'x', 'y'], 'applied': [2], 'rejected': [0]}), ('match exactly at the offset limit', [['p', 'p', 'z', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['L1']]], 3], {'lines': ['p', 'p', 'z', 'L1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [4], 'rejected': []})],
}[N]
for label, args, expected in cases:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| clean apply at the expected line | {'applied': [3], 'lines': ['l1', 'l2', 'l3', 'X', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': []} | {'applied': [3], 'lines': ['l1', 'l2', 'l3', 'X', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': []} | Passed |
| offset because lines were added above | {'applied': [4], 'lines': ['pre0', 'l1', 'l2', 'l3', 'X', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': []} | {'applied': [4], 'lines': ['pre0', 'l1', 'l2', 'l3', 'X', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': []} | Passed |
| offset beyond the limit is rejected | {'applied': [], 'lines': ['pre0', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': [0]} | {'applied': [], 'lines': ['pre0', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': [0]} | Passed |
| second hunk follows the first hunk's offset | {'applied': [3, 11], 'lines': ['pre0', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'Z', 'l10', 'l11', 'l12'], 'rejected': []} | {'applied': [3, 11], 'lines': ['pre0', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'Z', 'l10', 'l11', 'l12'], 'rejected': []} | Passed |
| equal distances prefer the earlier match | {'applied': [2], 'lines': ['a', 'K', 'b', 'k', 'c'], 'rejected': []} | {'applied': [2], 'lines': ['a', 'K', 'b', 'k', 'c'], 'rejected': []} | Passed |
| rejected hunk does not shift later hunks | {'applied': [], 'lines': ['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': [0, 1]} | {'applied': [5], 'lines': ['l1', 'l2', 'l3', 'l4', 'F', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': [0]} | Failed |
| rejected hunk keeps earlier shifts | {'applied': [1, 7], 'lines': ['l1', 'a', 'b', 'l2', 'l3', 'l4', 'F', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': [1]} | {'applied': [1, 7], 'lines': ['l1', 'a', 'b', 'l2', 'l3', 'l4', 'F', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': [1]} | Passed |
| carried offset keeps a far hunk in range | {'applied': [5, 13], 'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'L81', 'l9', 'l10', 'l11', 'l12'], 'rejected': []} | {'applied': [5, 13], 'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'L81', 'l9', 'l10', 'l11', 'l12'], 'rejected': []} | Passed |
| two hunks with size changes | {'applied': [1, 5, 11], 'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'm', 'm2', 'l7', 'l8', 'l9', 'T', 'l11', 'l12'], 'rejected': []} | {'applied': [1, 5, 11], 'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'm', 'm2', 'l7', 'l8', 'l9', 'T', 'l11', 'l12'], 'rejected': []} | Passed |
| only a later occurrence matches | {'applied': [2], 'lines': ['q', 'R', 's', 'x', 'y', 'x', 'y'], 'rejected': [0]} | {'applied': [2], 'lines': ['q', 'R', 's', 'x', 'y', 'x', 'y'], 'rejected': [0]} | Passed |
| match exactly at the offset limit | {'applied': [4], 'lines': ['p', 'p', 'z', 'L1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': []} | {'applied': [4], 'lines': ['p', 'p', 'z', 'L1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': []} | Passed |
SHA-256 / 81c303a2c7ec59afe6510a80b6bcb5ee4aa210257b2a04b47dbbce136072508b
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(target, hunks, max_offset):
lines = list(target)
delta = 0
applied, rejected = [], []
for h_i, (old_start, old, new) in enumerate(hunks):
expect = old_start - 1 + delta
found = None
for dist in range(0, max_offset + 1):
for pos in ((expect - dist, expect + dist) if dist else (expect,)):
if 0 <= pos and pos + len(old) <= len(lines) and lines[pos:pos + len(old)] == old:
found = pos
break
if found is not None:
break
if found is None:
rejected.append(h_i)
delta = 0
continue
lines[found:found + len(old)] = new
applied.append(found + 1)
delta += (found - expect) + len(new) - len(old)
return {'lines': lines, 'applied': applied, 'rejected': rejected}
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = {
1: [('clean apply at the expected line', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X', 'l4']]], 3], {'lines': ['l1', 'l2', 'l3', 'X', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [3], 'rejected': []}), ('offset because lines were added above', [['pre0', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 2], {'lines': ['pre0', 'l1', 'l2', 'l3', 'X', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [4], 'rejected': []}), ('offset beyond the limit is rejected', [['pre0', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 0], {'lines': ['pre0', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [], 'rejected': [0]}), ("second hunk follows the first hunk's offset", [['pre0', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['l2', 'A', 'B']], [8, ['l8', 'l9'], ['Z']]], 1], {'lines': ['pre0', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'Z', 'l10', 'l11', 'l12'], 'applied': [3, 11], 'rejected': []}), ('equal distances prefer the earlier match', [['a', 'k', 'b', 'k', 'c'], [[3, ['k'], ['K']]], 1], {'lines': ['a', 'K', 'b', 'k', 'c'], 'applied': [2], 'rejected': []}), ('rejected hunk does not shift later hunks', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['nope'], ['x', 'y', 'z']], [5, ['l5'], ['F', 'l5']]], 1], {'lines': ['l1', 'l2', 'l3', 'l4', 'F', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [5], 'rejected': [0]}), ('rejected hunk keeps earlier shifts', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['l1', 'a', 'b']], [3, ['nope'], ['x']], [5, ['l5'], ['F']]], 1], {'lines': ['l1', 'a', 'b', 'l2', 'l3', 'l4', 'F', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [1, 7], 'rejected': [1]}), ('carried offset keeps a far hunk in range', [['pre', 'pre', 'pre', 'l1', 'l2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['L2']], [8, ['l8'], ['L81']]], 3], {'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'L81', 'l9', 'l10', 'l11', 'l12'], 'applied': [5, 13], 'rejected': []}), ('two hunks with size changes', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1', 'l2'], ['l1']], [6, ['l6'], ['l6', 'm', 'm2']], [10, ['l10'], ['T']]], 0], {'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'm', 'm2', 'l7', 'l8', 'l9', 'T', 'l11', 'l12'], 'applied': [1, 5, 11], 'rejected': []}), ('only a later occurrence matches', [['q', 'r', 's', 'x', 'y', 'x', 'y'], [[4, ['x', 'z'], ['w']], [1, ['r'], ['R']]], 2], {'lines': ['q', 'R', 's', 'x', 'y', 'x', 'y'], 'applied': [2], 'rejected': [0]}), ('match exactly at the offset limit', [['p', 'p', 'z', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['L1']]], 3], {'lines': ['p', 'p', 'z', 'L1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [4], 'rejected': []})],
2: [('clean apply at the expected line', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X', 'l4']]], 3], {'lines': ['l1', 'l2', 'l3', 'X', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [3], 'rejected': []}), ('offset because lines were added above', [['pre0', 'pre1', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 3], {'lines': ['pre0', 'pre1', 'l1', 'l2', 'l3', 'X', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [5], 'rejected': []}), ('offset beyond the limit is rejected', [['pre0', 'pre1', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 1], {'lines': ['pre0', 'pre1', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [], 'rejected': [0]}), ("second hunk follows the first hunk's offset", [['pre0', 'pre1', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['l2', 'A', 'B']], [8, ['l8', 'l9'], ['Z']]], 2], {'lines': ['pre0', 'pre1', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'Z', 'l10', 'l11', 'l12'], 'applied': [4, 12], 'rejected': []}), ('equal distances prefer the earlier match', [['a', 'k', 'b', 'k', 'c'], [[3, ['k'], ['K']]], 1], {'lines': ['a', 'K', 'b', 'k', 'c'], 'applied': [2], 'rejected': []}), ('rejected hunk does not shift later hunks', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['nope'], ['x', 'y', 'z']], [5, ['l5'], ['F', 'l5']]], 1], {'lines': ['l1', 'l2', 'l3', 'l4', 'F', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [5], 'rejected': [0]}), ('rejected hunk keeps earlier shifts', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['l1', 'a', 'b']], [3, ['nope'], ['x']], [5, ['l5'], ['F']]], 1], {'lines': ['l1', 'a', 'b', 'l2', 'l3', 'l4', 'F', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [1, 7], 'rejected': [1]}), ('carried offset keeps a far hunk in range', [['pre', 'pre', 'pre', 'l1', 'l2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['L2']], [8, ['l8'], ['L82']]], 3], {'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'L82', 'l9', 'l10', 'l11', 'l12'], 'applied': [5, 13], 'rejected': []}), ('two hunks with size changes', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1', 'l2'], ['l1']], [6, ['l6'], ['l6', 'm', 'm2']], [10, ['l10'], ['T']]], 0], {'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'm', 'm2', 'l7', 'l8', 'l9', 'T', 'l11', 'l12'], 'applied': [1, 5, 11], 'rejected': []}), ('only a later occurrence matches', [['q', 'r', 's', 'x', 'y', 'x', 'y'], [[4, ['x', 'z'], ['w']], [1, ['r'], ['R']]], 2], {'lines': ['q', 'R', 's', 'x', 'y', 'x', 'y'], 'applied': [2], 'rejected': [0]}), ('match exactly at the offset limit', [['p', 'p', 'z', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['L1']]], 3], {'lines': ['p', 'p', 'z', 'L1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [4], 'rejected': []})],
3: [('clean apply at the expected line', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X', 'l4']]], 3], {'lines': ['l1', 'l2', 'l3', 'X', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [3], 'rejected': []}), ('offset because lines were added above', [['pre0', 'pre1', 'pre2', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 4], {'lines': ['pre0', 'pre1', 'pre2', 'l1', 'l2', 'l3', 'X', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [6], 'rejected': []}), ('offset beyond the limit is rejected', [['pre0', 'pre1', 'pre2', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 2], {'lines': ['pre0', 'pre1', 'pre2', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [], 'rejected': [0]}), ("second hunk follows the first hunk's offset", [['pre0', 'pre1', 'pre2', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['l2', 'A', 'B']], [8, ['l8', 'l9'], ['Z']]], 3], {'lines': ['pre0', 'pre1', 'pre2', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'Z', 'l10', 'l11', 'l12'], 'applied': [5, 13], 'rejected': []}), ('equal distances prefer the earlier match', [['a', 'k', 'b', 'k', 'c'], [[3, ['k'], ['K']]], 1], {'lines': ['a', 'K', 'b', 'k', 'c'], 'applied': [2], 'rejected': []}), ('rejected hunk does not shift later hunks', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['nope'], ['x', 'y', 'z']], [5, ['l5'], ['F', 'l5']]], 1], {'lines': ['l1', 'l2', 'l3', 'l4', 'F', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [5], 'rejected': [0]}), ('rejected hunk keeps earlier shifts', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['l1', 'a', 'b']], [3, ['nope'], ['x']], [5, ['l5'], ['F']]], 1], {'lines': ['l1', 'a', 'b', 'l2', 'l3', 'l4', 'F', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [1, 7], 'rejected': [1]}), ('carried offset keeps a far hunk in range', [['pre', 'pre', 'pre', 'l1', 'l2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['L2']], [8, ['l8'], ['L83']]], 3], {'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'L83', 'l9', 'l10', 'l11', 'l12'], 'applied': [5, 13], 'rejected': []}), ('two hunks with size changes', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1', 'l2'], ['l1']], [6, ['l6'], ['l6', 'm', 'm2']], [10, ['l10'], ['T']]], 0], {'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'm', 'm2', 'l7', 'l8', 'l9', 'T', 'l11', 'l12'], 'applied': [1, 5, 11], 'rejected': []}), ('only a later occurrence matches', [['q', 'r', 's', 'x', 'y', 'x', 'y'], [[4, ['x', 'z'], ['w']], [1, ['r'], ['R']]], 2], {'lines': ['q', 'R', 's', 'x', 'y', 'x', 'y'], 'applied': [2], 'rejected': [0]}), ('match exactly at the offset limit', [['p', 'p', 'z', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['L1']]], 3], {'lines': ['p', 'p', 'z', 'L1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [4], 'rejected': []})],
4: [('clean apply at the expected line', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X', 'l4']]], 3], {'lines': ['l1', 'l2', 'l3', 'X', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [3], 'rejected': []}), ('offset because lines were added above', [['pre0', 'pre1', 'pre2', 'pre3', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 5], {'lines': ['pre0', 'pre1', 'pre2', 'pre3', 'l1', 'l2', 'l3', 'X', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [7], 'rejected': []}), ('offset beyond the limit is rejected', [['pre0', 'pre1', 'pre2', 'pre3', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 3], {'lines': ['pre0', 'pre1', 'pre2', 'pre3', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [], 'rejected': [0]}), ("second hunk follows the first hunk's offset", [['pre0', 'pre1', 'pre2', 'pre3', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['l2', 'A', 'B']], [8, ['l8', 'l9'], ['Z']]], 4], {'lines': ['pre0', 'pre1', 'pre2', 'pre3', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'Z', 'l10', 'l11', 'l12'], 'applied': [6, 14], 'rejected': []}), ('equal distances prefer the earlier match', [['a', 'k', 'b', 'k', 'c'], [[3, ['k'], ['K']]], 1], {'lines': ['a', 'K', 'b', 'k', 'c'], 'applied': [2], 'rejected': []}), ('rejected hunk does not shift later hunks', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['nope'], ['x', 'y', 'z']], [5, ['l5'], ['F', 'l5']]], 1], {'lines': ['l1', 'l2', 'l3', 'l4', 'F', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [5], 'rejected': [0]}), ('rejected hunk keeps earlier shifts', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['l1', 'a', 'b']], [3, ['nope'], ['x']], [5, ['l5'], ['F']]], 1], {'lines': ['l1', 'a', 'b', 'l2', 'l3', 'l4', 'F', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [1, 7], 'rejected': [1]}), ('carried offset keeps a far hunk in range', [['pre', 'pre', 'pre', 'l1', 'l2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['L2']], [8, ['l8'], ['L84']]], 3], {'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'L84', 'l9', 'l10', 'l11', 'l12'], 'applied': [5, 13], 'rejected': []}), ('two hunks with size changes', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1', 'l2'], ['l1']], [6, ['l6'], ['l6', 'm', 'm2']], [10, ['l10'], ['T']]], 0], {'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'm', 'm2', 'l7', 'l8', 'l9', 'T', 'l11', 'l12'], 'applied': [1, 5, 11], 'rejected': []}), ('only a later occurrence matches', [['q', 'r', 's', 'x', 'y', 'x', 'y'], [[4, ['x', 'z'], ['w']], [1, ['r'], ['R']]], 2], {'lines': ['q', 'R', 's', 'x', 'y', 'x', 'y'], 'applied': [2], 'rejected': [0]}), ('match exactly at the offset limit', [['p', 'p', 'z', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['L1']]], 3], {'lines': ['p', 'p', 'z', 'L1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [4], 'rejected': []})],
5: [('clean apply at the expected line', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X', 'l4']]], 3], {'lines': ['l1', 'l2', 'l3', 'X', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [3], 'rejected': []}), ('offset because lines were added above', [['pre0', 'pre1', 'pre2', 'pre3', 'pre4', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 6], {'lines': ['pre0', 'pre1', 'pre2', 'pre3', 'pre4', 'l1', 'l2', 'l3', 'X', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [8], 'rejected': []}), ('offset beyond the limit is rejected', [['pre0', 'pre1', 'pre2', 'pre3', 'pre4', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 4], {'lines': ['pre0', 'pre1', 'pre2', 'pre3', 'pre4', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [], 'rejected': [0]}), ("second hunk follows the first hunk's offset", [['pre0', 'pre1', 'pre2', 'pre3', 'pre4', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['l2', 'A', 'B']], [8, ['l8', 'l9'], ['Z']]], 5], {'lines': ['pre0', 'pre1', 'pre2', 'pre3', 'pre4', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'Z', 'l10', 'l11', 'l12'], 'applied': [7, 15], 'rejected': []}), ('equal distances prefer the earlier match', [['a', 'k', 'b', 'k', 'c'], [[3, ['k'], ['K']]], 1], {'lines': ['a', 'K', 'b', 'k', 'c'], 'applied': [2], 'rejected': []}), ('rejected hunk does not shift later hunks', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['nope'], ['x', 'y', 'z']], [5, ['l5'], ['F', 'l5']]], 1], {'lines': ['l1', 'l2', 'l3', 'l4', 'F', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [5], 'rejected': [0]}), ('rejected hunk keeps earlier shifts', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['l1', 'a', 'b']], [3, ['nope'], ['x']], [5, ['l5'], ['F']]], 1], {'lines': ['l1', 'a', 'b', 'l2', 'l3', 'l4', 'F', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [1, 7], 'rejected': [1]}), ('carried offset keeps a far hunk in range', [['pre', 'pre', 'pre', 'l1', 'l2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['L2']], [8, ['l8'], ['L85']]], 3], {'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'L85', 'l9', 'l10', 'l11', 'l12'], 'applied': [5, 13], 'rejected': []}), ('two hunks with size changes', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1', 'l2'], ['l1']], [6, ['l6'], ['l6', 'm', 'm2']], [10, ['l10'], ['T']]], 0], {'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'm', 'm2', 'l7', 'l8', 'l9', 'T', 'l11', 'l12'], 'applied': [1, 5, 11], 'rejected': []}), ('only a later occurrence matches', [['q', 'r', 's', 'x', 'y', 'x', 'y'], [[4, ['x', 'z'], ['w']], [1, ['r'], ['R']]], 2], {'lines': ['q', 'R', 's', 'x', 'y', 'x', 'y'], 'applied': [2], 'rejected': [0]}), ('match exactly at the offset limit', [['p', 'p', 'z', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['L1']]], 3], {'lines': ['p', 'p', 'z', 'L1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [4], 'rejected': []})],
}[N]
for label, args, expected in cases:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| clean apply at the expected line | {'applied': [3], 'lines': ['l1', 'l2', 'l3', 'X', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': []} | {'applied': [3], 'lines': ['l1', 'l2', 'l3', 'X', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': []} | Passed |
| offset because lines were added above | {'applied': [4], 'lines': ['pre0', 'l1', 'l2', 'l3', 'X', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': []} | {'applied': [4], 'lines': ['pre0', 'l1', 'l2', 'l3', 'X', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': []} | Passed |
| offset beyond the limit is rejected | {'applied': [], 'lines': ['pre0', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': [0]} | {'applied': [], 'lines': ['pre0', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': [0]} | Passed |
| second hunk follows the first hunk's offset | {'applied': [3, 11], 'lines': ['pre0', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'Z', 'l10', 'l11', 'l12'], 'rejected': []} | {'applied': [3, 11], 'lines': ['pre0', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'Z', 'l10', 'l11', 'l12'], 'rejected': []} | Passed |
| equal distances prefer the earlier match | {'applied': [2], 'lines': ['a', 'K', 'b', 'k', 'c'], 'rejected': []} | {'applied': [2], 'lines': ['a', 'K', 'b', 'k', 'c'], 'rejected': []} | Passed |
| rejected hunk does not shift later hunks | {'applied': [5], 'lines': ['l1', 'l2', 'l3', 'l4', 'F', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': [0]} | {'applied': [5], 'lines': ['l1', 'l2', 'l3', 'l4', 'F', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': [0]} | Passed |
| rejected hunk keeps earlier shifts | {'applied': [1], 'lines': ['l1', 'a', 'b', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': [1, 2]} | {'applied': [1, 7], 'lines': ['l1', 'a', 'b', 'l2', 'l3', 'l4', 'F', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': [1]} | Failed |
| carried offset keeps a far hunk in range | {'applied': [5, 13], 'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'L81', 'l9', 'l10', 'l11', 'l12'], 'rejected': []} | {'applied': [5, 13], 'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'L81', 'l9', 'l10', 'l11', 'l12'], 'rejected': []} | Passed |
| two hunks with size changes | {'applied': [1, 5, 11], 'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'm', 'm2', 'l7', 'l8', 'l9', 'T', 'l11', 'l12'], 'rejected': []} | {'applied': [1, 5, 11], 'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'm', 'm2', 'l7', 'l8', 'l9', 'T', 'l11', 'l12'], 'rejected': []} | Passed |
| only a later occurrence matches | {'applied': [2], 'lines': ['q', 'R', 's', 'x', 'y', 'x', 'y'], 'rejected': [0]} | {'applied': [2], 'lines': ['q', 'R', 's', 'x', 'y', 'x', 'y'], 'rejected': [0]} | Passed |
| match exactly at the offset limit | {'applied': [4], 'lines': ['p', 'p', 'z', 'L1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': []} | {'applied': [4], 'lines': ['p', 'p', 'z', 'L1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': []} | Passed |
SHA-256 / 6819e0bc78ade04cc6139914803fcc74692ccb2a2e9b85137585e66d5a88e1fe
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(target, hunks, max_offset):
lines = list(target)
delta = 0
applied, rejected = [], []
for h_i, (old_start, old, new) in enumerate(hunks):
expect = old_start - 1 + delta
found = None
for dist in range(0, max_offset + 1):
for pos in ((expect - dist, expect + dist) if dist else (expect,)):
if 0 <= pos and pos + len(old) <= len(lines) and lines[pos:pos + len(old)] == old:
found = pos
break
if found is not None:
break
if found is None:
rejected.append(h_i)
continue
lines[found:found + len(old)] = new
applied.append(found + 1)
delta += (found - expect) + len(new) - len(old)
return {'lines': lines, 'applied': applied, 'rejected': rejected}
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = {
1: [('clean apply at the expected line', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X', 'l4']]], 3], {'lines': ['l1', 'l2', 'l3', 'X', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [3], 'rejected': []}), ('offset because lines were added above', [['pre0', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 2], {'lines': ['pre0', 'l1', 'l2', 'l3', 'X', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [4], 'rejected': []}), ('offset beyond the limit is rejected', [['pre0', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 0], {'lines': ['pre0', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [], 'rejected': [0]}), ("second hunk follows the first hunk's offset", [['pre0', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['l2', 'A', 'B']], [8, ['l8', 'l9'], ['Z']]], 1], {'lines': ['pre0', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'Z', 'l10', 'l11', 'l12'], 'applied': [3, 11], 'rejected': []}), ('equal distances prefer the earlier match', [['a', 'k', 'b', 'k', 'c'], [[3, ['k'], ['K']]], 1], {'lines': ['a', 'K', 'b', 'k', 'c'], 'applied': [2], 'rejected': []}), ('rejected hunk does not shift later hunks', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['nope'], ['x', 'y', 'z']], [5, ['l5'], ['F', 'l5']]], 1], {'lines': ['l1', 'l2', 'l3', 'l4', 'F', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [5], 'rejected': [0]}), ('rejected hunk keeps earlier shifts', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['l1', 'a', 'b']], [3, ['nope'], ['x']], [5, ['l5'], ['F']]], 1], {'lines': ['l1', 'a', 'b', 'l2', 'l3', 'l4', 'F', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [1, 7], 'rejected': [1]}), ('carried offset keeps a far hunk in range', [['pre', 'pre', 'pre', 'l1', 'l2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['L2']], [8, ['l8'], ['L81']]], 3], {'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'L81', 'l9', 'l10', 'l11', 'l12'], 'applied': [5, 13], 'rejected': []}), ('two hunks with size changes', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1', 'l2'], ['l1']], [6, ['l6'], ['l6', 'm', 'm2']], [10, ['l10'], ['T']]], 0], {'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'm', 'm2', 'l7', 'l8', 'l9', 'T', 'l11', 'l12'], 'applied': [1, 5, 11], 'rejected': []}), ('only a later occurrence matches', [['q', 'r', 's', 'x', 'y', 'x', 'y'], [[4, ['x', 'z'], ['w']], [1, ['r'], ['R']]], 2], {'lines': ['q', 'R', 's', 'x', 'y', 'x', 'y'], 'applied': [2], 'rejected': [0]}), ('match exactly at the offset limit', [['p', 'p', 'z', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['L1']]], 3], {'lines': ['p', 'p', 'z', 'L1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [4], 'rejected': []})],
2: [('clean apply at the expected line', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X', 'l4']]], 3], {'lines': ['l1', 'l2', 'l3', 'X', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [3], 'rejected': []}), ('offset because lines were added above', [['pre0', 'pre1', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 3], {'lines': ['pre0', 'pre1', 'l1', 'l2', 'l3', 'X', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [5], 'rejected': []}), ('offset beyond the limit is rejected', [['pre0', 'pre1', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 1], {'lines': ['pre0', 'pre1', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [], 'rejected': [0]}), ("second hunk follows the first hunk's offset", [['pre0', 'pre1', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['l2', 'A', 'B']], [8, ['l8', 'l9'], ['Z']]], 2], {'lines': ['pre0', 'pre1', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'Z', 'l10', 'l11', 'l12'], 'applied': [4, 12], 'rejected': []}), ('equal distances prefer the earlier match', [['a', 'k', 'b', 'k', 'c'], [[3, ['k'], ['K']]], 1], {'lines': ['a', 'K', 'b', 'k', 'c'], 'applied': [2], 'rejected': []}), ('rejected hunk does not shift later hunks', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['nope'], ['x', 'y', 'z']], [5, ['l5'], ['F', 'l5']]], 1], {'lines': ['l1', 'l2', 'l3', 'l4', 'F', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [5], 'rejected': [0]}), ('rejected hunk keeps earlier shifts', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['l1', 'a', 'b']], [3, ['nope'], ['x']], [5, ['l5'], ['F']]], 1], {'lines': ['l1', 'a', 'b', 'l2', 'l3', 'l4', 'F', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [1, 7], 'rejected': [1]}), ('carried offset keeps a far hunk in range', [['pre', 'pre', 'pre', 'l1', 'l2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['L2']], [8, ['l8'], ['L82']]], 3], {'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'L82', 'l9', 'l10', 'l11', 'l12'], 'applied': [5, 13], 'rejected': []}), ('two hunks with size changes', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1', 'l2'], ['l1']], [6, ['l6'], ['l6', 'm', 'm2']], [10, ['l10'], ['T']]], 0], {'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'm', 'm2', 'l7', 'l8', 'l9', 'T', 'l11', 'l12'], 'applied': [1, 5, 11], 'rejected': []}), ('only a later occurrence matches', [['q', 'r', 's', 'x', 'y', 'x', 'y'], [[4, ['x', 'z'], ['w']], [1, ['r'], ['R']]], 2], {'lines': ['q', 'R', 's', 'x', 'y', 'x', 'y'], 'applied': [2], 'rejected': [0]}), ('match exactly at the offset limit', [['p', 'p', 'z', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['L1']]], 3], {'lines': ['p', 'p', 'z', 'L1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [4], 'rejected': []})],
3: [('clean apply at the expected line', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X', 'l4']]], 3], {'lines': ['l1', 'l2', 'l3', 'X', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [3], 'rejected': []}), ('offset because lines were added above', [['pre0', 'pre1', 'pre2', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 4], {'lines': ['pre0', 'pre1', 'pre2', 'l1', 'l2', 'l3', 'X', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [6], 'rejected': []}), ('offset beyond the limit is rejected', [['pre0', 'pre1', 'pre2', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 2], {'lines': ['pre0', 'pre1', 'pre2', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [], 'rejected': [0]}), ("second hunk follows the first hunk's offset", [['pre0', 'pre1', 'pre2', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['l2', 'A', 'B']], [8, ['l8', 'l9'], ['Z']]], 3], {'lines': ['pre0', 'pre1', 'pre2', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'Z', 'l10', 'l11', 'l12'], 'applied': [5, 13], 'rejected': []}), ('equal distances prefer the earlier match', [['a', 'k', 'b', 'k', 'c'], [[3, ['k'], ['K']]], 1], {'lines': ['a', 'K', 'b', 'k', 'c'], 'applied': [2], 'rejected': []}), ('rejected hunk does not shift later hunks', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['nope'], ['x', 'y', 'z']], [5, ['l5'], ['F', 'l5']]], 1], {'lines': ['l1', 'l2', 'l3', 'l4', 'F', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [5], 'rejected': [0]}), ('rejected hunk keeps earlier shifts', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['l1', 'a', 'b']], [3, ['nope'], ['x']], [5, ['l5'], ['F']]], 1], {'lines': ['l1', 'a', 'b', 'l2', 'l3', 'l4', 'F', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [1, 7], 'rejected': [1]}), ('carried offset keeps a far hunk in range', [['pre', 'pre', 'pre', 'l1', 'l2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['L2']], [8, ['l8'], ['L83']]], 3], {'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'L83', 'l9', 'l10', 'l11', 'l12'], 'applied': [5, 13], 'rejected': []}), ('two hunks with size changes', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1', 'l2'], ['l1']], [6, ['l6'], ['l6', 'm', 'm2']], [10, ['l10'], ['T']]], 0], {'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'm', 'm2', 'l7', 'l8', 'l9', 'T', 'l11', 'l12'], 'applied': [1, 5, 11], 'rejected': []}), ('only a later occurrence matches', [['q', 'r', 's', 'x', 'y', 'x', 'y'], [[4, ['x', 'z'], ['w']], [1, ['r'], ['R']]], 2], {'lines': ['q', 'R', 's', 'x', 'y', 'x', 'y'], 'applied': [2], 'rejected': [0]}), ('match exactly at the offset limit', [['p', 'p', 'z', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['L1']]], 3], {'lines': ['p', 'p', 'z', 'L1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [4], 'rejected': []})],
4: [('clean apply at the expected line', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X', 'l4']]], 3], {'lines': ['l1', 'l2', 'l3', 'X', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [3], 'rejected': []}), ('offset because lines were added above', [['pre0', 'pre1', 'pre2', 'pre3', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 5], {'lines': ['pre0', 'pre1', 'pre2', 'pre3', 'l1', 'l2', 'l3', 'X', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [7], 'rejected': []}), ('offset beyond the limit is rejected', [['pre0', 'pre1', 'pre2', 'pre3', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 3], {'lines': ['pre0', 'pre1', 'pre2', 'pre3', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [], 'rejected': [0]}), ("second hunk follows the first hunk's offset", [['pre0', 'pre1', 'pre2', 'pre3', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['l2', 'A', 'B']], [8, ['l8', 'l9'], ['Z']]], 4], {'lines': ['pre0', 'pre1', 'pre2', 'pre3', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'Z', 'l10', 'l11', 'l12'], 'applied': [6, 14], 'rejected': []}), ('equal distances prefer the earlier match', [['a', 'k', 'b', 'k', 'c'], [[3, ['k'], ['K']]], 1], {'lines': ['a', 'K', 'b', 'k', 'c'], 'applied': [2], 'rejected': []}), ('rejected hunk does not shift later hunks', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['nope'], ['x', 'y', 'z']], [5, ['l5'], ['F', 'l5']]], 1], {'lines': ['l1', 'l2', 'l3', 'l4', 'F', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [5], 'rejected': [0]}), ('rejected hunk keeps earlier shifts', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['l1', 'a', 'b']], [3, ['nope'], ['x']], [5, ['l5'], ['F']]], 1], {'lines': ['l1', 'a', 'b', 'l2', 'l3', 'l4', 'F', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [1, 7], 'rejected': [1]}), ('carried offset keeps a far hunk in range', [['pre', 'pre', 'pre', 'l1', 'l2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['L2']], [8, ['l8'], ['L84']]], 3], {'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'L84', 'l9', 'l10', 'l11', 'l12'], 'applied': [5, 13], 'rejected': []}), ('two hunks with size changes', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1', 'l2'], ['l1']], [6, ['l6'], ['l6', 'm', 'm2']], [10, ['l10'], ['T']]], 0], {'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'm', 'm2', 'l7', 'l8', 'l9', 'T', 'l11', 'l12'], 'applied': [1, 5, 11], 'rejected': []}), ('only a later occurrence matches', [['q', 'r', 's', 'x', 'y', 'x', 'y'], [[4, ['x', 'z'], ['w']], [1, ['r'], ['R']]], 2], {'lines': ['q', 'R', 's', 'x', 'y', 'x', 'y'], 'applied': [2], 'rejected': [0]}), ('match exactly at the offset limit', [['p', 'p', 'z', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['L1']]], 3], {'lines': ['p', 'p', 'z', 'L1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [4], 'rejected': []})],
5: [('clean apply at the expected line', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X', 'l4']]], 3], {'lines': ['l1', 'l2', 'l3', 'X', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [3], 'rejected': []}), ('offset because lines were added above', [['pre0', 'pre1', 'pre2', 'pre3', 'pre4', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 6], {'lines': ['pre0', 'pre1', 'pre2', 'pre3', 'pre4', 'l1', 'l2', 'l3', 'X', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [8], 'rejected': []}), ('offset beyond the limit is rejected', [['pre0', 'pre1', 'pre2', 'pre3', 'pre4', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 4], {'lines': ['pre0', 'pre1', 'pre2', 'pre3', 'pre4', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [], 'rejected': [0]}), ("second hunk follows the first hunk's offset", [['pre0', 'pre1', 'pre2', 'pre3', 'pre4', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['l2', 'A', 'B']], [8, ['l8', 'l9'], ['Z']]], 5], {'lines': ['pre0', 'pre1', 'pre2', 'pre3', 'pre4', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'Z', 'l10', 'l11', 'l12'], 'applied': [7, 15], 'rejected': []}), ('equal distances prefer the earlier match', [['a', 'k', 'b', 'k', 'c'], [[3, ['k'], ['K']]], 1], {'lines': ['a', 'K', 'b', 'k', 'c'], 'applied': [2], 'rejected': []}), ('rejected hunk does not shift later hunks', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['nope'], ['x', 'y', 'z']], [5, ['l5'], ['F', 'l5']]], 1], {'lines': ['l1', 'l2', 'l3', 'l4', 'F', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [5], 'rejected': [0]}), ('rejected hunk keeps earlier shifts', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['l1', 'a', 'b']], [3, ['nope'], ['x']], [5, ['l5'], ['F']]], 1], {'lines': ['l1', 'a', 'b', 'l2', 'l3', 'l4', 'F', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [1, 7], 'rejected': [1]}), ('carried offset keeps a far hunk in range', [['pre', 'pre', 'pre', 'l1', 'l2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['L2']], [8, ['l8'], ['L85']]], 3], {'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'L85', 'l9', 'l10', 'l11', 'l12'], 'applied': [5, 13], 'rejected': []}), ('two hunks with size changes', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1', 'l2'], ['l1']], [6, ['l6'], ['l6', 'm', 'm2']], [10, ['l10'], ['T']]], 0], {'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'm', 'm2', 'l7', 'l8', 'l9', 'T', 'l11', 'l12'], 'applied': [1, 5, 11], 'rejected': []}), ('only a later occurrence matches', [['q', 'r', 's', 'x', 'y', 'x', 'y'], [[4, ['x', 'z'], ['w']], [1, ['r'], ['R']]], 2], {'lines': ['q', 'R', 's', 'x', 'y', 'x', 'y'], 'applied': [2], 'rejected': [0]}), ('match exactly at the offset limit', [['p', 'p', 'z', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['L1']]], 3], {'lines': ['p', 'p', 'z', 'L1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [4], 'rejected': []})],
}[N]
for label, args, expected in cases:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| clean apply at the expected line | {'applied': [3], 'lines': ['l1', 'l2', 'l3', 'X', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': []} | {'applied': [3], 'lines': ['l1', 'l2', 'l3', 'X', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': []} | Passed |
| offset because lines were added above | {'applied': [4], 'lines': ['pre0', 'l1', 'l2', 'l3', 'X', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': []} | {'applied': [4], 'lines': ['pre0', 'l1', 'l2', 'l3', 'X', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': []} | Passed |
| offset beyond the limit is rejected | {'applied': [], 'lines': ['pre0', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': [0]} | {'applied': [], 'lines': ['pre0', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': [0]} | Passed |
| second hunk follows the first hunk's offset | {'applied': [3, 11], 'lines': ['pre0', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'Z', 'l10', 'l11', 'l12'], 'rejected': []} | {'applied': [3, 11], 'lines': ['pre0', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'Z', 'l10', 'l11', 'l12'], 'rejected': []} | Passed |
| equal distances prefer the earlier match | {'applied': [2], 'lines': ['a', 'K', 'b', 'k', 'c'], 'rejected': []} | {'applied': [2], 'lines': ['a', 'K', 'b', 'k', 'c'], 'rejected': []} | Passed |
| rejected hunk does not shift later hunks | {'applied': [5], 'lines': ['l1', 'l2', 'l3', 'l4', 'F', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': [0]} | {'applied': [5], 'lines': ['l1', 'l2', 'l3', 'l4', 'F', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': [0]} | Passed |
| rejected hunk keeps earlier shifts | {'applied': [1, 7], 'lines': ['l1', 'a', 'b', 'l2', 'l3', 'l4', 'F', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': [1]} | {'applied': [1, 7], 'lines': ['l1', 'a', 'b', 'l2', 'l3', 'l4', 'F', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': [1]} | Passed |
| carried offset keeps a far hunk in range | {'applied': [5, 13], 'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'L81', 'l9', 'l10', 'l11', 'l12'], 'rejected': []} | {'applied': [5, 13], 'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'L81', 'l9', 'l10', 'l11', 'l12'], 'rejected': []} | Passed |
| two hunks with size changes | {'applied': [1, 5, 11], 'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'm', 'm2', 'l7', 'l8', 'l9', 'T', 'l11', 'l12'], 'rejected': []} | {'applied': [1, 5, 11], 'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'm', 'm2', 'l7', 'l8', 'l9', 'T', 'l11', 'l12'], 'rejected': []} | Passed |
| only a later occurrence matches | {'applied': [2], 'lines': ['q', 'R', 's', 'x', 'y', 'x', 'y'], 'rejected': [0]} | {'applied': [2], 'lines': ['q', 'R', 's', 'x', 'y', 'x', 'y'], 'rejected': [0]} | Passed |
| match exactly at the offset limit | {'applied': [4], 'lines': ['p', 'p', 'z', 'L1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': []} | {'applied': [4], 'lines': ['p', 'p', 'z', 'L1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': []} | Passed |
SHA-256 / 19a69c28fe03b86f3981723c9ff25c540adb7a3127eb82393dced86942209357
Verification & scope
A deterministic, bounded teaching model of one diff, patch or merge rule with stipulated conventions; it is not a production diff or version-control implementation and makes no claim of conformance to any specific tool. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.
Observations recorded using Python 3.12.14 at 2026-09-29T14:49:06.458891+00:00.
Case digest / 5f57f7339292846effd50e40a22ff88fca878384c7e14e744598404cc6f3a006