FA-75416 / Text diff and three-way merge / Open access
Patch application with offset search: the discovered offset is not carried to later hunks · case 01
After one hunk applies with an offset, later hunks are searched from stale positions and may be rejected.
ROOT CAUSE
The accumulated shift adds only the size change of each hunk and forgets where it was actually found.
VERIFIED REPAIR
Carry both the discovered offset and the size change into the shift.
Unsuccessful approach: Carrying only the discovered offset forgets that earlier hunks grew or shrank the file.
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)
continue
lines[found:found + len(old)] = new
applied.append(found + 1)
delta += 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], 'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': [1]} | {'applied': [5, 13], 'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'L81', 'l9', 'l10', 'l11', 'l12'], 'rejected': []} | Failed |
| 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 / 0ec05959bca9d4d9020ca0a53e08b1993760dcc6eec31fc53e85d05e296b8f13
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)
continue
lines[found:found + len(old)] = new
applied.append(found + 1)
delta += found - expect
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], 'lines': ['pre0', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': [1]} | {'applied': [3, 11], 'lines': ['pre0', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'Z', 'l10', 'l11', 'l12'], 'rejected': []} | Failed |
| 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], 'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': [1, 2]} | {'applied': [1, 5, 11], 'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'm', 'm2', 'l7', 'l8', 'l9', 'T', 'l11', 'l12'], 'rejected': []} | Failed |
| 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 / 864c79b9fd90087bbf95ba909a8af83591304ca0c8666ea2cc030105442bc5ff
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.190711+00:00.
Case digest / d018572c45c4f57117dd503fbb68e84693e5a1258ce38a3b0b1c7a71f0edfa7d