ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-MCP/t/08_patch.t
Revision: 1.3
Committed: Thu Oct 15 01:38:06 2026 UTC (7 days, 5 hours ago) by root
Content type: application/x-troff
Branch: MAIN
CVS Tags: rel-0_61, rel-0_6, HEAD
Changes since 1.2: +12 -3 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 use common::sense;
2     use Test::More;
3     use AnyEvent ();
4     use AnyEvent::MCP ();
5     use File::Temp qw(tempdir);
6    
7     my $log = "Hmm... Looks like a unified diff to me...\n"
8     . "The text leading up to this was:\n--------------------------\n|--- a/input\n|+++ b/input\n"
9     . "--------------------------\npatching file output (read from input)\n"
10     . "Hunk #1 succeeded at 2 (offset -1 line).\n"
11     . "Hunk #2 succeeded at 8 with fuzz 2 (offset 3 lines).\ndone\n";
12     my $parsed = AnyEvent::MCP::parse_patch_output $log;
13     is_deeply $parsed, {
14     hunks => [
15     { hunk => 1, success => 1, line => 2, fuzz => 0, offset => -1 },
16     { hunk => 2, success => 1, line => 8, fuzz => 2, offset => 3 },
17     ],
18     unparsed => [],
19     }, "parse verbose framing, signed offsets and fuzz";
20    
21     $parsed = AnyEvent::MCP::parse_patch_output (
22     "Hunk #1 FAILED at 4.\nHunk #2 ignored at 7.\nunexpected diagnostic\n"
23     );
24     ok !$parsed->{hunks}[0]{success} && !$parsed->{hunks}[1]{success}, "parse failed and ignored hunks";
25     is_deeply $parsed->{unparsed}, ["unexpected diagnostic"], "retain unknown diagnostics";
26    
27     for my $offset (-2, 0, 2) {
28     my $hunks = AnyEvent::MCP::check_patch_output (
29     0, "Hunk #1 succeeded at 10 (offset $offset lines).\n", [2]
30     );
31     is $hunks->[0]{offset}, $offset, "accept offset inside limit";
32     }
33    
34     for my $case (
35     [256, "Hunk #1 succeeded at 1.\n", [0], qr/wait status 256/],
36     [9, "", [0], qr/wait status 9/],
37     [0, "Hunk #1 succeeded at 1.\nunexpected\n", [0], qr/unrecognized output/],
38     [0, "", [0], qr/expected 1 hunks, got 0/],
39     [0, "", [], qr/expected 0 hunks, got 0/],
40     [0, "Hunk #1 succeeded at 1.\n", [0, 0], qr/expected 2 hunks, got 1/],
41     [0, "Hunk #2 succeeded at 1.\n", [0], qr/unexpected hunk number/],
42     [0, "Hunk #1 succeeded at 1.\nHunk #1 succeeded at 2.\n", [0, 0], qr/unexpected hunk number/],
43     [0, "Hunk #1 FAILED at 1.\n", [0], qr/hunk 1 failed/],
44     [0, "Hunk #1 succeeded at 1 with fuzz 1.\n", [0], qr/used fuzz/],
45     [0, "Hunk #1 succeeded at 1 (offset 3 lines).\n", [2], qr/exceeds 2/],
46     [0, "Hunk #1 succeeded at 1 (offset -3 lines).\n", [2], qr/exceeds 2/],
47     ) {
48     eval { AnyEvent::MCP::check_patch_output @$case[0, 1, 2] };
49     like $@, $case->[3], "reject incomplete or unacceptable application";
50     }
51    
52     my $dir = tempdir CLEANUP => 1;
53     my $input = "$dir/input";
54     my $source = "zero\none\ntwo\nthree\n";
55     open my $fh, ">", $input or die $!;
56     print $fh $source;
57     close $fh or die $!;
58    
59     sub contents {
60     open my $fh, "<", $_[0] or die "$_[0]: $!";
61     binmode $fh;
62     local $/;
63     <$fh>
64     }
65    
66     my $output = "$dir/output";
67     my $diff = "--- a/input\n+++ b/input\n@@ -3 @@\n one\n-two\n+TWO\n three\n";
68 root 1.2 my $bad = "$dir/bad";
69     SKIP: {
70 root 1.3 skip "extended GNU patch tests (PERL_ANYEVENT_MCP_TESTS=1)", 14
71 root 1.2 unless ($ENV{PERL_ANYEVENT_MCP_TESTS} || 0) >= 1;
72     my ($patch) = grep -f && -x _, map "$_/patch", split /:/, $ENV{PATH};
73 root 1.3 skip "GNU patch is unavailable", 14 unless $patch;
74 root 1.2 open my $version, "-|", $patch, "--version" or die "$patch: $!";
75     my $gnu = do { local $/; <$version> } =~ /GNU patch/;
76 root 1.3 skip "GNU patch is unavailable", 14 unless close $version && $gnu;
77 root 1.2
78     my $hunks = AnyEvent::MCP::apply_udiff ($input, $output, $diff)->recv;
79     is contents ($output), "zero\none\nTWO\nthree\n", "real patch output";
80     is contents ($input), $source, "input unchanged";
81     is $hunks->[0]{offset}, -1, "real verbose offset validated";
82    
83     eval { AnyEvent::MCP::apply_udiff ($input, $output, $diff) };
84     like $@, qr/\Q$output\E:/, "existing output refused";
85     is contents ($output), "zero\none\nTWO\nthree\n", "existing output preserved";
86    
87     eval { AnyEvent::MCP::apply_udiff ($input, $bad, "@@ -3 @@\n-one\n+ONE\n")->recv };
88     like $@, qr/offset -1 exceeds 0/, "real excessive relocation rejected";
89     ok !-e $bad, "excessive-offset output removed";
90    
91     eval { AnyEvent::MCP::apply_udiff ($input, $bad, $diff . "@@ -4 @@\n-absent\n+bad\n")->recv };
92     like $@, qr/patch failed/, "real partial application rejected";
93     ok !-e $bad, "partial output removed";
94     is contents ($input), $source, "input unchanged after failures";
95    
96     eval { AnyEvent::MCP::apply_udiff ("$dir/missing", $bad, $diff)->recv };
97     like $@, qr/patch failed/, "missing input rejected";
98     ok !-e $bad, "output removed after command failure";
99 root 1.1
100 root 1.3 open my $binary, ">", "$dir/binary" or die $!;
101     binmode $binary;
102     print {$binary} "a\0\xff\n";
103     close $binary or die $!;
104     AnyEvent::MCP::apply_udiff ("$dir/binary", "$dir/binary-output",
105     "@@ -1 @@\n-a\0\xff\n+b\0\xfe\n")->recv;
106     is contents ("$dir/binary-output"), "b\0\xfe\n", "byte diff preserves NUL and non-UTF-8 bytes";
107     is contents ("$dir/binary"), "a\0\xff\n", "binary patch leaves input unchanged";
108    
109 root 1.2 }
110 root 1.1
111     eval { AnyEvent::MCP::apply_udiff ($input, $bad, "invalid") };
112     like $@, qr/no hunks/, "invalid diff rejected before starting";
113     ok !-e $bad, "invalid diff creates no output";
114    
115     done_testing;