316
class PatchesTester(unittest.TestCase):
317
def testValidPatchHeader(self):
318
"""Parse a valid patch header"""
319
lines = "--- orig/commands.py\n+++ mod/dommands.py\n".split('\n')
320
(orig, mod) = get_patch_names(lines.__iter__())
321
assert(orig == "orig/commands.py")
322
assert(mod == "mod/dommands.py")
324
def testInvalidPatchHeader(self):
325
"""Parse an invalid patch header"""
326
lines = "-- orig/commands.py\n+++ mod/dommands.py".split('\n')
327
self.assertRaises(MalformedPatchHeader, get_patch_names,
330
def testValidHunkHeader(self):
331
"""Parse a valid hunk header"""
332
header = "@@ -34,11 +50,6 @@\n"
333
hunk = hunk_from_header(header);
334
assert (hunk.orig_pos == 34)
335
assert (hunk.orig_range == 11)
336
assert (hunk.mod_pos == 50)
337
assert (hunk.mod_range == 6)
338
assert (str(hunk) == header)
340
def testValidHunkHeader2(self):
341
"""Parse a tricky, valid hunk header"""
342
header = "@@ -1 +0,0 @@\n"
343
hunk = hunk_from_header(header);
344
assert (hunk.orig_pos == 1)
345
assert (hunk.orig_range == 1)
346
assert (hunk.mod_pos == 0)
347
assert (hunk.mod_range == 0)
348
assert (str(hunk) == header)
350
def makeMalformed(self, header):
351
self.assertRaises(MalformedHunkHeader, hunk_from_header, header)
353
def testInvalidHeader(self):
354
"""Parse an invalid hunk header"""
355
self.makeMalformed(" -34,11 +50,6 \n")
356
self.makeMalformed("@@ +50,6 -34,11 @@\n")
357
self.makeMalformed("@@ -34,11 +50,6 @@")
358
self.makeMalformed("@@ -34.5,11 +50,6 @@\n")
359
self.makeMalformed("@@-34,11 +50,6@@\n")
360
self.makeMalformed("@@ 34,11 50,6 @@\n")
361
self.makeMalformed("@@ -34,11 @@\n")
362
self.makeMalformed("@@ -34,11 +50,6.5 @@\n")
363
self.makeMalformed("@@ -34,11 +50,-6 @@\n")
365
def lineThing(self,text, type):
366
line = parse_line(text)
367
assert(isinstance(line, type))
368
assert(str(line)==text)
370
def makeMalformedLine(self, text):
371
self.assertRaises(MalformedLine, parse_line, text)
373
def testValidLine(self):
374
"""Parse a valid hunk line"""
375
self.lineThing(" hello\n", ContextLine)
376
self.lineThing("+hello\n", InsertLine)
377
self.lineThing("-hello\n", RemoveLine)
379
def testMalformedLine(self):
380
"""Parse invalid valid hunk lines"""
381
self.makeMalformedLine("hello\n")
383
def compare_parsed(self, patchtext):
384
lines = patchtext.splitlines(True)
385
patch = parse_patch(lines.__iter__())
387
i = difference_index(patchtext, pstr)
389
print "%i: \"%s\" != \"%s\"" % (i, patchtext[i], pstr[i])
390
assert (patchtext == str(patch))
393
"""Test parsing a whole patch"""
394
patchtext = """--- orig/commands.py
359
class PatchConflict(Exception):
360
def __init__(self, line_no, orig_line, patch_line):
361
orig = orig_line.rstrip('\n')
362
patch = str(patch_line).rstrip('\n')
363
msg = 'Text contents mismatch at line %d. Original has "%s",'\
364
' but patch says it should be "%s"' % (line_no, orig, patch)
365
Exception.__init__(self, msg)
368
def iter_patched(orig_lines, patch_lines):
369
"""Iterate through a series of lines with a patch applied.
370
This handles a single file, and does exact, not fuzzy patching.
372
if orig_lines is not None:
373
orig_lines = orig_lines.__iter__()
375
patch_lines = iter_lines_handle_nl(patch_lines.__iter__())
376
get_patch_names(patch_lines)
378
for hunk in iter_hunks(patch_lines):
379
while line_no < hunk.orig_pos:
380
orig_line = orig_lines.next()
383
for hunk_line in hunk.lines:
384
seen_patch.append(str(hunk_line))
385
if isinstance(hunk_line, InsertLine):
386
yield hunk_line.contents
387
elif isinstance(hunk_line, (ContextLine, RemoveLine)):
388
orig_line = orig_lines.next()
389
if orig_line != hunk_line.contents:
390
raise PatchConflict(line_no, orig_line, "".join(seen_patch))
391
if isinstance(hunk_line, ContextLine):
394
assert isinstance(hunk_line, RemoveLine)
399
class PatchesTester(unittest.TestCase):
400
def datafile(self, filename):
401
data_path = os.path.join(os.path.dirname(__file__), "testdata",
403
return file(data_path, "rb")
405
def testValidPatchHeader(self):
406
"""Parse a valid patch header"""
407
lines = "--- orig/commands.py\n+++ mod/dommands.py\n".split('\n')
408
(orig, mod) = get_patch_names(lines.__iter__())
409
assert(orig == "orig/commands.py")
410
assert(mod == "mod/dommands.py")
412
def testInvalidPatchHeader(self):
413
"""Parse an invalid patch header"""
414
lines = "-- orig/commands.py\n+++ mod/dommands.py".split('\n')
415
self.assertRaises(MalformedPatchHeader, get_patch_names,
418
def testValidHunkHeader(self):
419
"""Parse a valid hunk header"""
420
header = "@@ -34,11 +50,6 @@\n"
421
hunk = hunk_from_header(header);
422
assert (hunk.orig_pos == 34)
423
assert (hunk.orig_range == 11)
424
assert (hunk.mod_pos == 50)
425
assert (hunk.mod_range == 6)
426
assert (str(hunk) == header)
428
def testValidHunkHeader2(self):
429
"""Parse a tricky, valid hunk header"""
430
header = "@@ -1 +0,0 @@\n"
431
hunk = hunk_from_header(header);
432
assert (hunk.orig_pos == 1)
433
assert (hunk.orig_range == 1)
434
assert (hunk.mod_pos == 0)
435
assert (hunk.mod_range == 0)
436
assert (str(hunk) == header)
438
def makeMalformed(self, header):
439
self.assertRaises(MalformedHunkHeader, hunk_from_header, header)
441
def testInvalidHeader(self):
442
"""Parse an invalid hunk header"""
443
self.makeMalformed(" -34,11 +50,6 \n")
444
self.makeMalformed("@@ +50,6 -34,11 @@\n")
445
self.makeMalformed("@@ -34,11 +50,6 @@")
446
self.makeMalformed("@@ -34.5,11 +50,6 @@\n")
447
self.makeMalformed("@@-34,11 +50,6@@\n")
448
self.makeMalformed("@@ 34,11 50,6 @@\n")
449
self.makeMalformed("@@ -34,11 @@\n")
450
self.makeMalformed("@@ -34,11 +50,6.5 @@\n")
451
self.makeMalformed("@@ -34,11 +50,-6 @@\n")
453
def lineThing(self,text, type):
454
line = parse_line(text)
455
assert(isinstance(line, type))
456
assert(str(line)==text)
458
def makeMalformedLine(self, text):
459
self.assertRaises(MalformedLine, parse_line, text)
461
def testValidLine(self):
462
"""Parse a valid hunk line"""
463
self.lineThing(" hello\n", ContextLine)
464
self.lineThing("+hello\n", InsertLine)
465
self.lineThing("-hello\n", RemoveLine)
467
def testMalformedLine(self):
468
"""Parse invalid valid hunk lines"""
469
self.makeMalformedLine("hello\n")
471
def compare_parsed(self, patchtext):
472
lines = patchtext.splitlines(True)
473
patch = parse_patch(lines.__iter__())
475
i = difference_index(patchtext, pstr)
477
print "%i: \"%s\" != \"%s\"" % (i, patchtext[i], pstr[i])
478
self.assertEqual (patchtext, str(patch))
481
"""Test parsing a whole patch"""
482
patchtext = """--- orig/commands.py
395
483
+++ mod/commands.py
396
484
@@ -1337,7 +1337,8 @@
420
self.compare_parsed(patchtext)
508
self.compare_parsed(patchtext)
423
"""Handle patches missing half the position, range tuple"""
511
"""Handle patches missing half the position, range tuple"""
425
513
"""--- orig/__init__.py
426
514
+++ mod/__init__.py
428
516
__docformat__ = "restructuredtext en"
429
+__doc__ = An alternate Arch commandline interface"""
430
self.compare_parsed(patchtext)
434
def testLineLookup(self):
436
"""Make sure we can accurately look up mod line from orig"""
437
patch = parse_patch(open("testdata/diff"))
438
orig = list(open("testdata/orig"))
439
mod = list(open("testdata/mod"))
441
for i in range(len(orig)):
442
mod_pos = patch.pos_in_mod(i)
444
removals.append(orig[i])
446
assert(mod[mod_pos]==orig[i])
447
rem_iter = removals.__iter__()
448
for hunk in patch.hunks:
449
for line in hunk.lines:
450
if isinstance(line, RemoveLine):
451
next = rem_iter.next()
452
if line.contents != next:
453
sys.stdout.write(" orig:%spatch:%s" % (next,
455
assert(line.contents == next)
456
self.assertRaises(StopIteration, rem_iter.next)
458
def testFirstLineRenumber(self):
459
"""Make sure we handle lines at the beginning of the hunk"""
460
patch = parse_patch(open("testdata/insert_top.patch"))
461
assert (patch.pos_in_mod(0)==1)
517
+__doc__ = An alternate Arch commandline interface
519
self.compare_parsed(patchtext)
523
def testLineLookup(self):
525
"""Make sure we can accurately look up mod line from orig"""
526
patch = parse_patch(self.datafile("diff"))
527
orig = list(self.datafile("orig"))
528
mod = list(self.datafile("mod"))
530
for i in range(len(orig)):
531
mod_pos = patch.pos_in_mod(i)
533
removals.append(orig[i])
535
assert(mod[mod_pos]==orig[i])
536
rem_iter = removals.__iter__()
537
for hunk in patch.hunks:
538
for line in hunk.lines:
539
if isinstance(line, RemoveLine):
540
next = rem_iter.next()
541
if line.contents != next:
542
sys.stdout.write(" orig:%spatch:%s" % (next,
544
assert(line.contents == next)
545
self.assertRaises(StopIteration, rem_iter.next)
547
def testFirstLineRenumber(self):
548
"""Make sure we handle lines at the beginning of the hunk"""
549
patch = parse_patch(self.datafile("insert_top.patch"))
550
assert (patch.pos_in_mod(0)==1)
464
553
patchesTestSuite = unittest.makeSuite(PatchesTester,'test')
465
554
runner = unittest.TextTestRunner(verbosity=0)
466
555
return runner.run(patchesTestSuite)