diff options
Diffstat (limited to 'vcx.t')
| -rw-r--r-- | vcx.t | 153 |
1 files changed, 153 insertions, 0 deletions
@@ -0,0 +1,153 @@ +use strict; +use warnings; +use Test::More; +use File::Path qw(remove_tree make_path); +use File::Spec; +use Cwd; +use File::Glob qw(:bsd_glob); + +use constant ROOT => '.vcx'; +use constant HEAD => ROOT . '/head'; +use constant OBJ_DIR => ROOT . '/obj'; +use constant REV_DIR => ROOT . '/rev'; +use constant TMP_DIR => ROOT . '/index'; +use constant TMP_TREE => TMP_DIR . '/tree'; + +# Setup sandbox +my $sandbox = "sandbox"; +remove_tree($sandbox) if -d $sandbox; +make_path($sandbox); + +my $orig_dir = getcwd(); +chdir($sandbox) or die "Cant enter sandbox: $!"; +my $cmd = File::Spec->catfile($orig_dir, "vcx"); + +# Helper functions +sub write_file { + my ($path, $content) = @_; + open my $fh, '>', $path or die $!; + print $fh $content; + close $fh; +} + +sub read_file { + my $path = shift; + open my $fh, '<', $path or return ""; + my $content = <$fh>; + chomp $content if $content; + close $fh; + return $content; +} + +# Tests + +subtest 'Repository Initialization' => sub { + ok(system("perl $cmd init > /dev/null") == 0, "Init exit code 0"); + ok(-d ROOT, "ROOT directory created"); + ok(-e HEAD, "Head file created"); + ok(-d OBJ_DIR, "OBJ_DIR directory created"); + ok(-d REV_DIR, "REV_DIR directory created"); +}; + +subtest 'Adding and Committing Files' => sub { + write_file("test.txt", "Hello, world!"); + + ok(system("perl $cmd add test.txt > /dev/null") == 0, "Add file successful"); + ok(-d TMP_TREE, "Staging tree created"); + + ok(system("perl $cmd commit -m 'Initial commit' > /dev/null") == 0, "Commit successful"); + + my $rev1 = File::Spec->catdir(REV_DIR, "0000001"); + ok(-d $rev1, "Revision 0000001 directory exists"); + + my $msg_file = File::Spec->catfile($rev1, "message"); + is(read_file($msg_file), "Initial commit", "Commit message stored correctly"); +}; + +subtest 'Auto-staging with commit -am' => sub { + # Append content + open my $fh, '>>', "test.txt" or die $!; + print $fh "\nMore content"; + close $fh; + + ok(system("perl $cmd commit -am 'Second commit' > /dev/null") == 0, "Commit -am successful"); + + opendir(my $dh, OBJ_DIR) or die $!; + my @objs = grep { /[a-f0-9]{40}/ } readdir($dh); + closedir($dh); + ok(scalar @objs >= 1, "Content blobs found in object store"); +}; + +subtest 'File Moves and Deletions (Tree Integrity)' => sub { + # Create nested structure + make_path("dirA/dirB"); + write_file("dirA/dirB/shuffle.txt", "Same Content"); + system("perl $cmd add dirA/dirB/shuffle.txt > /dev/null"); + system("perl $cmd commit -m 'Shuffle part 1' > /dev/null"); + + # Move file and delete old dir + make_path("dirC"); + rename("dirA/dirB/shuffle.txt", "dirC/shuffle.txt"); + remove_tree("dirA"); + + ok(system("perl $cmd commit -am 'Shuffle part 2' > /dev/null") == 0, "Commit move successful"); + + my $head = read_file(HEAD); + my ($tree_ptr) = bsd_glob(File::Spec->catfile(REV_DIR, $head, "tree-*")); + my $tree_hash = $tree_ptr =~ s/.*tree-//r; + my $actual_tree_path = File::Spec->catdir(OBJ_DIR, $tree_hash); + + ok(-l File::Spec->catfile($actual_tree_path, "dirC/shuffle.txt"), "New path exists in tree"); + ok(!-d File::Spec->catdir($actual_tree_path, "dirA"), "Deleted path removed from tree"); + + my $link_target = readlink(File::Spec->catfile($actual_tree_path, "dirC/shuffle.txt")); + like($link_target, qr/obj\/[a-f0-9]{40}/, "Tree link points to object store"); +}; + +subtest 'Symlink Handling' => sub { + write_file("target.txt", "Final Destination"); + symlink("target.txt", "link_a"); + symlink("link_a", "link_b"); + + system("perl $cmd add link_b > /dev/null"); + system("perl $cmd commit -m 'Double link' > /dev/null"); + + my $head = read_file(HEAD); + my ($tree_ptr) = bsd_glob(File::Spec->catfile(REV_DIR, $head, "tree-*")); + my $staged_link = File::Spec->catfile(OBJ_DIR, $tree_ptr =~ s/.*tree-//r, "link_b"); + + is(readlink($staged_link), "link_a", "Symlink-to-symlink targets preserved literally"); +}; + +subtest 'Edge Cases: Content Reversion' => sub { + # Clear the staging area to ensure a "Pure" tree + remove_tree(TMP_DIR); + make_path(TMP_TREE); + + make_path("revert_test"); + write_file("revert_test/data.txt", "Version A"); + + # Commit State A + system("perl $cmd add revert_test/data.txt > /dev/null"); + system("perl $cmd commit -m 'State A' > /dev/null"); + my $tree_v1 = (bsd_glob(File::Spec->catfile(REV_DIR, read_file(HEAD), "tree-*")))[0]; + + # Commit State B + write_file("revert_test/data.txt", "Version B"); + system("perl $cmd commit -am 'State B' > /dev/null"); + + # Revert to State A + write_file("revert_test/data.txt", "Version A"); + system("perl $cmd commit -am 'Back to State A' > /dev/null"); + my $tree_v3 = (bsd_glob(File::Spec->catfile(REV_DIR, read_file(HEAD), "tree-*")))[0]; + + # Extract hashes and compare + my $hash1 = $tree_v1 =~ s/.*tree-//r; + my $hash3 = $tree_v3 =~ s/.*tree-//r; + + is($hash1, $hash3, "Tree hashes match after index reset and content restoration"); +}; + +# Cleanup +chdir($orig_dir); +done_testing(); |
