Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions tests/samples/quilt.diff
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
Description: Add fts64 support
Adds a new fts64 header and its implementation, and wires the new
module into the io Makefile.
Author: Some One <someone@example.com>
Forwarded: https://example.com/thread
Last-Update: 2026-07-31

--- /dev/null
+++ b/include/fts64.h
@@ -0,0 +1,3 @@
+#ifndef _FTS64_H
+#define _FTS64_H
+#endif
--- /dev/null
+++ b/io/fts64.c
@@ -0,0 +1,2 @@
+#include <fts64.h>
+/* implementation */
--- a/io/Makefile
+++ b/io/Makefile
@@ -1,3 +1,4 @@
routines := \
fts \
+ fts64 \
open
45 changes: 45 additions & 0 deletions tests/test_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,51 @@ def test_parse_diff_with_empty_filenames(self):
# the parsed patch should round-trip back to the original input
self.assertEqual(str(res), ''.join(diff))

def test_parse_multiple_added_files(self):
# regression test for issue #143: quilt-style patches that add several
# files in a row all share the "/dev/null" source, which must not make
# consecutive files be merged into one.
diff = (
'--- /dev/null\n'
'+++ b/1.txt\n'
'@@ -0,0 +1 @@\n'
'+a\n'
'--- /dev/null\n'
'+++ b/2.txt\n'
'@@ -0,0 +1 @@\n'
'+b\n'
)

res = PatchSet(diff)

self.assertEqual(len(res), 2)
self.assertEqual([f.path for f in res], ['1.txt', '2.txt'])
self.assertTrue(all(f.is_added_file for f in res))
self.assertFalse(any(f.is_rename for f in res))
self.assertEqual(res.added, 2)
self.assertEqual(res[0].target_file, 'b/1.txt')
self.assertEqual(res[1].target_file, 'b/2.txt')

def test_parse_quilt_diff(self):
# issue #143: a realistic quilt patch (DEP-3 header preamble, two added
# files sharing the /dev/null source, then a modified file).
filename = os.path.join(self.samples_dir, 'samples/quilt.diff')
with open(filename) as f:
res = PatchSet(f)

self.assertEqual(len(res), 3)
self.assertEqual(
[f.path for f in res],
['include/fts64.h', 'io/fts64.c', 'io/Makefile'])
self.assertEqual(
[f.path for f in res.added_files], ['include/fts64.h', 'io/fts64.c'])
self.assertEqual([f.path for f in res.modified_files], ['io/Makefile'])
self.assertFalse(any(f.is_rename for f in res))
self.assertEqual((res.added, res.removed), (6, 0))
# the DEP-3 header preamble is kept as the first file's patch info
self.assertTrue(
str(res[0].patch_info).startswith('Description: Add fts64 support'))

def test_parse_filename_with_spaces(self):
filename = os.path.join(self.samples_dir, 'samples/git_filenames_with_spaces.diff')
with open(filename) as f:
Expand Down
9 changes: 5 additions & 4 deletions unidiff/patch.py
Original file line number Diff line number Diff line change
Expand Up @@ -530,10 +530,11 @@ def _parse(self, diff: Iterable, encoding: Optional[str],
if is_source_filename:
source_file = is_source_filename.group('filename')
source_timestamp = is_source_filename.group('timestamp')
# reset current file, unless we are processing a rename
# (in that case, source files should match)
if current_file is not None and not (
current_file.source_file == source_file):
# a "---" line starts a new file, unless we are still inside a
# git header block (patch_info is only set while a "diff --git"
# header is being processed, in which case this line just
# restates the source of the file already being built)
if current_file is not None and patch_info is None:
current_file = None
elif current_file is not None:
current_file.source_timestamp = source_timestamp
Expand Down
Loading