diff options
Diffstat (limited to 'vcx_patch.t')
| -rw-r--r-- | vcx_patch.t | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/vcx_patch.t b/vcx_patch.t new file mode 100644 index 0000000..d2b813f --- /dev/null +++ b/vcx_patch.t @@ -0,0 +1,104 @@ +#!/usr/bin/perl +use strict; +use warnings; +use Test::More; +use File::Temp qw(tempfile); +use File::Spec; + +# Overrides exit and silences the 'Usage' print during the 'do' call. +BEGIN { + *CORE::GLOBAL::exit = sub { }; +} + +{ + local @ARGV = (); + open my $oldout, ">&STDOUT"; + open STDOUT, ">", File::Spec->devnull(); + eval { do './vcx' }; + open STDOUT, ">&", $oldout; +} + +subtest 'Binary Patching: Shrink & Truncate' => sub { + my ($fh_old, $old_path) = tempfile(); + my ($fh_new, $new_path) = tempfile(); + + # 8KB of 'A' shrinking to 6 bytes + print $fh_old "A" x 8192; close $fh_old; + print $fh_new "SHRINK"; close $fh_new; + + my $patch = main::make_bin_patch($new_path, $old_path); + ok(defined($patch), "Patch generated for shrinking file"); + + main::apply_bin_patch($old_path, $patch); + + is(-s $old_path, 6, "File size correctly truncated to 6 bytes"); + + open my $check, '<:raw', $old_path; + my $content = <$check>; + is($content, "SHRINK", "Content matches perfectly (no stale trailing data)"); + close $check; +}; + +subtest 'Binary Patching: Growth & Extension' => sub { + my ($fh_old, $old_path) = tempfile(); + my ($fh_new, $new_path) = tempfile(); + + print $fh_old "Tiny"; + close $fh_old; + + # Create a 5KB string to cross a block boundary (4096) + my $big_data = "EXTENDED" . ("." x 5000); + print $fh_new $big_data; + close $fh_new; + + my $patch = main::make_bin_patch($new_path, $old_path); + main::apply_bin_patch($old_path, $patch); + + is(-s $old_path, 5008, "File size correctly extended"); + + open my $check, '<:raw', $old_path; + my $result = do { local $/; <$check> }; + is($result, $big_data, "Extended content matches perfectly"); + close $check; +}; + +subtest 'Binary Patching: Sparse Block Edits' => sub { + my ($fh_old, $old_path) = tempfile(); + my ($fh_new, $new_path) = tempfile(); + + # Create three 4KB blocks + my $data = ("X" x 4096) . ("Y" x 4096) . ("Z" x 4096); + print $fh_old $data; close $fh_old; + + # Modify only the middle block ('Y' block) + substr($data, 5000, 10) = "MODIFIED!!"; + print $fh_new $data; close $fh_new; + + my $patch = main::make_bin_patch($new_path, $old_path); + + # Header (8) + Block Header (12) + Block (4096) = ~4116 bytes + ok(length($patch) < 4200, "Patch is efficient (only captured the changed block)"); + + main::apply_bin_patch($old_path, $patch); + + open my $check, '<:raw', $old_path; + my $final = do { local $/; <$check> }; + is(substr($final, 5000, 10), "MODIFIED!!", "Middle block update applied"); + is(substr($final, 0, 10), "XXXXXXXXXX", "First block preserved"); + is(substr($final, -10), "ZZZZZZZZZZ", "Last block preserved"); + close $check; +}; + +subtest 'Binary Patching: No Change Identity' => sub { + my ($fh_old, $old_path) = tempfile(); + my ($fh_new, $new_path) = tempfile(); + + my $data = "Same data" x 50; + print $fh_old $data; close $fh_old; + print $fh_new $data; close $fh_new; + + my $patch = main::make_bin_patch($new_path, $old_path); + is($patch, undef, "No patch generated for identical files"); +}; + +done_testing(); |
