From 5ffc3b9a77cf1b9e8b3f3a275f451ccf76f700a8 Mon Sep 17 00:00:00 2001 From: Ben Spoor Date: Mon, 9 Feb 2026 21:41:39 +0100 Subject: [PATCH 1/4] Add additional scenarios for patch fuzzing --- features/patch-fuzzy-matching.feature | 77 +++++++++++++++++++++++++++ features/steps/generic_steps.py | 5 +- features/steps/git_steps.py | 8 +++ 3 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 features/patch-fuzzy-matching.feature diff --git a/features/patch-fuzzy-matching.feature b/features/patch-fuzzy-matching.feature new file mode 100644 index 00000000..7c90152d --- /dev/null +++ b/features/patch-fuzzy-matching.feature @@ -0,0 +1,77 @@ +Feature: Patch application tolerates small upstream changes + + If an upstream git repository changes slightly after a patch was created, + the patch should still apply successfully using fuzzy matching, as long as + the changes are compatible. + + Background: + Given a git repository "SomeProject.git" + And the patch file 'SomeProject.patch' in MyProject + """ + diff --git a/README.md b/README.md + index 1e65bd6..faa3b21 100644 + --- a/README.md + +++ b/README.md + @@ -1 +1,2 @@ + Generated file for SomeProject.git + +An important sentence for the README! + """ + And a fetched and committed MyProject with the manifest + """ + manifest: + version: 0.0 + projects: + - name: SomeProject + url: some-remote-server/SomeProject.git + patch: SomeProject.patch + """ + + Scenario: Patch applies when upstream adds extra lines + Given "README.md" in git-repository "SomeProject.git" is changed to: + """ + Generated file for SomeProject.git + Additional upstream line. + """ + When I run "dfetch update" + Then the patched 'MyProject/SomeProject/README.md' is + """ + Generated file for SomeProject.git + An important sentence for the README! + Additional upstream line. + """ + + Scenario: Patch applies when context lines have changed + Given "README.md" in git-repository "SomeProject.git" is changed to: + """ + Generated file for SomeProject + This repository is used for testing. + """ + And the patch file 'SomeProject.patch' in SomeProject + """ + diff --git a/README.md b/README.md + index 1e65bd6..faa3b21 100644 + --- a/README.md + +++ b/README.md + @@ -1 +1,2 @@ + Generated file for SomeProject.git + +An important sentence for the README! + """ + When I run "dfetch update" + Then the output shows + """ + Dfetch (0.11.0) + SomeProject: + > Fetched master - f47d80c35e14dfa4f9c9c30c9865cbf0f8d50933 + > Applying patch "SomeProject.patch" + file 1/1: b'README.md' + hunk no.1 doesn't match source file at line 1 + expected: b'Generated file for SomeProject.git' + actual : b'Generated file for SomeProject' + successfully patched 1/1: b'README.md' + """ + And the patched 'MyProject/SomeProject/README.md' is + """ + Generated file for SomeProject + An important sentence for the README! + This repository is used for testing. + """ diff --git a/features/steps/generic_steps.py b/features/steps/generic_steps.py index 8e00b9e2..ca64a655 100644 --- a/features/steps/generic_steps.py +++ b/features/steps/generic_steps.py @@ -246,9 +246,10 @@ def step_impl(_, old_path: str, new_path: str, directory: str): @given("the patch file '{name}'") +@given("the patch file '{name}' in {directory}") @given("the patch file '{name}' with '{encoding}' encoding") -def step_impl(context, name, encoding="UTF-8"): - generate_file(os.path.join(os.getcwd(), name), context.text, encoding) +def step_impl(context, name, encoding="UTF-8", directory="."): + generate_file(os.path.join(directory, name), context.text, encoding) @given('"{path}" in {directory} is created') diff --git a/features/steps/git_steps.py b/features/steps/git_steps.py index b1d923fc..73d61318 100644 --- a/features/steps/git_steps.py +++ b/features/steps/git_steps.py @@ -135,6 +135,14 @@ def step_impl(context, directory, path): commit_all("A change") +@given('"{path}" in git-repository "{name}" is changed to:') +def step_impl(context, path, name): + remote_path = os.path.join(context.remotes_dir, name) + with in_directory(remote_path): + generate_file(path, context.text) + commit_all("A change") + + @given("all files in {directory} are committed") @when("all files in {directory} are committed") def step_impl(_, directory): From b7d5681e96e8c2e30f5a941f072b685dae7f9271 Mon Sep 17 00:00:00 2001 From: Ben Spoor Date: Mon, 9 Feb 2026 21:42:13 +0100 Subject: [PATCH 2/4] Add more scenarios to docs --- dfetch/manifest/project.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dfetch/manifest/project.py b/dfetch/manifest/project.py index 567cfe15..fdef549b 100644 --- a/dfetch/manifest/project.py +++ b/dfetch/manifest/project.py @@ -259,6 +259,8 @@ For more details see the `git-diff `_ documentation. .. scenario-include:: ../features/diff-in-git.feature + .. scenario-include:: ../features/patch-after-fetch-git.feature + .. scenario-include:: ../features/patch-fuzzy-matching.feature .. tab:: SVN @@ -269,6 +271,8 @@ For more details see the `svn-diff `_ documentation. .. scenario-include:: ../features/diff-in-svn.feature + .. scenario-include:: ../features/patch-after-fetch-svn.feature + .. scenario-include:: ../features/patch-fuzzy-matching.feature """ From ddd1b15c7f057b1997b6afe7f5a9aa5c4fb066c7 Mon Sep 17 00:00:00 2001 From: Ben Spoor Date: Mon, 9 Feb 2026 22:06:52 +0100 Subject: [PATCH 3/4] Mark scenario as git specific and remove it from svn docs --- dfetch/manifest/project.py | 3 +-- ...fuzzy-matching.feature => patch-fuzzy-matching-git.feature} | 0 2 files changed, 1 insertion(+), 2 deletions(-) rename features/{patch-fuzzy-matching.feature => patch-fuzzy-matching-git.feature} (100%) diff --git a/dfetch/manifest/project.py b/dfetch/manifest/project.py index fdef549b..2c47da58 100644 --- a/dfetch/manifest/project.py +++ b/dfetch/manifest/project.py @@ -260,7 +260,7 @@ .. scenario-include:: ../features/diff-in-git.feature .. scenario-include:: ../features/patch-after-fetch-git.feature - .. scenario-include:: ../features/patch-fuzzy-matching.feature + .. scenario-include:: ../features/patch-fuzzy-matching-git.feature .. tab:: SVN @@ -272,7 +272,6 @@ .. scenario-include:: ../features/diff-in-svn.feature .. scenario-include:: ../features/patch-after-fetch-svn.feature - .. scenario-include:: ../features/patch-fuzzy-matching.feature """ diff --git a/features/patch-fuzzy-matching.feature b/features/patch-fuzzy-matching-git.feature similarity index 100% rename from features/patch-fuzzy-matching.feature rename to features/patch-fuzzy-matching-git.feature From ef67f6daaa10c364b8d33b7b32bb136de6e2c849 Mon Sep 17 00:00:00 2001 From: Ben Spoor Date: Mon, 9 Feb 2026 22:11:49 +0100 Subject: [PATCH 4/4] Improve scenarios --- features/patch-fuzzy-matching-git.feature | 2 +- features/steps/generic_steps.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/features/patch-fuzzy-matching-git.feature b/features/patch-fuzzy-matching-git.feature index 7c90152d..38487693 100644 --- a/features/patch-fuzzy-matching-git.feature +++ b/features/patch-fuzzy-matching-git.feature @@ -46,7 +46,7 @@ Feature: Patch application tolerates small upstream changes Generated file for SomeProject This repository is used for testing. """ - And the patch file 'SomeProject.patch' in SomeProject + And the patch file 'SomeProject.patch' in MyProject """ diff --git a/README.md b/README.md index 1e65bd6..faa3b21 100644 diff --git a/features/steps/generic_steps.py b/features/steps/generic_steps.py index ca64a655..8d35a44f 100644 --- a/features/steps/generic_steps.py +++ b/features/steps/generic_steps.py @@ -198,6 +198,7 @@ def check_output(context, line_count=None): """ expected_text = multisub( patterns=[ + (dfetch_title, "Dfetch (x.x.x)"), (git_hash, r"\1[commit-hash]\2"), (timestamp, "[timestamp]"), (ansi_escape, ""), @@ -208,6 +209,7 @@ def check_output(context, line_count=None): actual_text = multisub( patterns=[ + (dfetch_title, "Dfetch (x.x.x)"), (git_hash, r"\1[commit-hash]\2"), (timestamp, "[timestamp]"), (ansi_escape, ""),