#!/usr/bin/perl

use warnings;
use Test::More;
use Test::BDD::Cucumber::StepFile;
use Log::Log4perl;

my $maxint_locks_sha256 = << "END_MAXINT_LOCKS_SHA256";
02899750161db7f972465da7e7ef011e49e91638529d2f0d3ff475923b7177b8  ./script.h
0da1b23efcdc02ed302211625f07f0a21b2c545ad4f341bebdd14aef29fe08b9  ./bitcoinrpc.h
163cc7ad45bf62df3f22f6c55bb9d5f34fe960284d400c19c7c64788daf6d4f8  ./init.cpp
16b0123375012f07621e163002fccd6b5ed78e1029604af8bd49a4aadba2f131  ./json/json_spirit_writer.cpp
173301ae219764b313d54ec5713395a790c17c7075937d4026b506d39e3dd5f2  ./json/json_spirit_reader.h
1de138674c27465179a18868f20b922c818c7facae8e2641a8eac2bdaf21a0c1  ./script.cpp
1f7ce0f68b5d1771c2309992954e5015a2dd25647867f673c790d8b6b6ea23de  ./json/json_spirit_stream_reader.h
215bbea85b1b8eb39f0963bf881d61bbdf644c2e625651991cd5e41707c64eb1  ./bitcoinrpc.cpp
240a3e0d37d2e86b614063f5347eb02d4f99ca6c254de6b82871ff8d95532a7d  ./obj/.gitignore
240a3e0d37d2e86b614063f5347eb02d4f99ca6c254de6b82871ff8d95532a7d  ./obj/nogui/.gitignore
240a3e0d37d2e86b614063f5347eb02d4f99ca6c254de6b82871ff8d95532a7d  ./obj-test/.gitignore
240a3e0d37d2e86b614063f5347eb02d4f99ca6c254de6b82871ff8d95532a7d  ./obj/test/.gitignore
28d5f9a32fe2492bddab66e411659f48fc385c7162fbff4fd3a92b9d18181d2d  ./json/json_spirit_writer.h
2de7c083aa9ecf175bf4ba5ce2090b8aca9f55ee163641722fed42db939ebfb2  ./uint256.h
2f913fd239d3b012af3e180cbe9e4a8b0e3743f345503c30715dd02681892a86  ./crypter.cpp
315ab67375a24dfdb7a224e06a4d449c1919061cca6ca6535f10e7704024edbf  ./test/DoS_tests.cpp
3500a11f6484442870653e118075cc201df0b7d0f6b871b4120e0055ed2cd3b2  ./json/json_spirit_reader.cpp
3548cba9e4da3abc0cfb74da48e8c35e94e2aaa783f111439473ce9d10542352  ./key.h
3c1e779473f5313f544d13315eff1b43bf46842ac4f257e14a9277f4ba466930  ./json/json_spirit_error_position.h
3ca473a798509553ff04f80b34cae87cf5c855d806b4986a66fda6470408106f  ./keystore.h
3d25a921b937be96becb76d6ed50e784f66528d011352decf5843bfe435633b1  ./noui.h
40a52229536e1ce9b96fb34a56941d4fa85f87461f0fee78021f5eb401537a57  ./checkpoints.cpp
54ffc0e92872f8774bfa5051375e14eb4e68a50a14bf45fcdf145ad6aaf058ab  ./test/util_tests.cpp
5521c46aa5de1b590b18086b06dc1149293927e7a97e851946c7ffcd73802eb8  ./util.h
552296f683c286d9889d46ed0cb9130b9414395421e9ad8fde03a34a51b31a8e  ./test/README
55c879a24937f03f370172cb91048135e4e494199672ba50a8dbdaf01901ddbc  ./net.cpp
565d106852c703aa2846fdf90b79dee4349dbfc0174e123b063647109c613194  ./net.h
5828cb59f818c9d1439cfecf5f964396fd790509792d31234c4b05b4ff98af28  ./json/json_spirit_reader_template.h
5becffa109d7021c78c0a760dfb28c97c3a1a13ccb9b844c4caac45d390aaf3e  ./json/json_spirit_writer_template.h
6a1931bd6e6a765e2026127eb03f2ff24b915028991a2282ff20f0b8cb1d1424  ./json/LICENSE.txt
6c5edfb92f95e7b8237170b1f9c197306060861cb32173bdf28d42ec0448ff57  ./wallet.cpp
79b22c662cec0eb5b2810c2b2b29079018c4c35973e99953a834f028eb69289d  ./headers.h
79dd55f9a783c2425e7f2ce85b73ed5356c0633720d8c56eae1a157f41d6fadf  ./json/json_spirit.h
80f2a51ac724dd21849b0fac1e4886d65cdc2e153f530bb34dc4d2ee29e16d68  ./checkpoints.h
873ea8864ada172514c38c6d98602cd3694d04cfe159f5250b7eb9440262049e  ./json/json_spirit_value.h
8ac8eace8ffe006d16f9afda21de606d60901a6962e86871db2a23f0f6a00352  ./crypter.h
8cd517a6e8bb36e19463864634bb9f2feb7320613b5cf9ae6f217e608f5c7caa  ./strlcpy.h
907eee61824f8206c390a78f1fa1c0a1df322444715f1c45977238c221b55989  ./main.h
915c10007dfce0bfefb540652c43217efee68865d3551a133619ddb9b2515ba8  ./keystore.cpp
9747017069a6048f4e6c0fb431d0a3412f2876e85045a4170e46230df8a78974  ./init.h
98744bebfa9119adb33e1b88ca5515d162765e4af19857b310d61b4743ee5a64  ./util.cpp
989d034e85d2772b78428cddd45ab2f76c386a66f0ef763aae950cb6f54d3d24  ./base58.h
a00d9a30c2f2516c965326a19c66d42cafd05d6e0aef57f85d55cd9ccfffbd84  ./serialize.h
a13585ab0323a9e54139e0f4792053fde0dc37b4b1f761043ce0fef66d09619b  ./test/uint256_tests.cpp
a7f9c1bc0f26cdc0966b9d73a9b473eb5789dc578194705ae22f0ecba4e5f5a2  ./db.cpp
afa054805cfbfe7e0b56fbac2efd2cb58e08bf64815f50dca930b1103b4761e6  ./makefile.unix
b2d3f994ee9ed53e250c0c4b3520e2a8fa83f44c524473520baea736ae4e3cbc  ./test/script_tests.cpp
b37933d24bad2f17b1c82450df4dbf517a20904d245320a271ad82dba1469dd7  ./wallet.h
b7b5975876a75eeca13528c922f7609d4055c32de367942eb8198d5e5f0a8434  ./json/json_spirit_value.cpp
b86ca5963c0e973b1b18d2f96b63764d0d4a2a688423948335ee3382f96fb12c  ./bignum.h
bf0b87228266226e6a51c2653a66c6b4127ebfe9056cec4b1cac8033b5295f63  ./test/test_bitcoin.cpp
bf7d6621f14f528bda7f8027620a3c5dcefe705ab6b72a516b71abcdb7e8272f  ./test/uint160_tests.cpp
c051de356a3fbb42662f30c4a4a1c9e5bc26cf051767723b2aeef9b23402299f  ./json/json_spirit_utils.h
c374f834b5530ee1d7cb6f4e813992dbd7b9ea096c336b96ccba0ce8bccadfc5  ./test/base64_tests.cpp
cbc17932c3e80ece437c8cdb97243ed41a0b195e35ade5c6f2cb3b73b27ca0e5  ./main.cpp
d65bec73d01cad4a2733b058f574ecbfe370cfd927fbd5eafb785850a2109c19  ./test/Checkpoints_tests.cpp
dd08afdba3cd5088c8db3eea33d8d8f45b99d17327c4d381e83a42dea2c3bcca  ./protocol.cpp
dfbc5c95bf817ebb5625bcf060cb9303d96166300ff64e4aa6a819faa331e599  ./test/base58_tests.cpp
e3d7bea43bb30377ae43be9aba3bab44829a2fa6594836a42aaa135e0d7a0e92  ./test/transaction_tests.cpp
e4a281091ad5a11e04fa213333e6e0a4f6359887c1aafaa6d683c8c2c943ed9b  ./db.h
e73117726bf1776da0a3e6d72569e059b1b2998d8a4951cba10ba34d8769bc98  ./protocol.h
ee9d10124a13651b6cade8476da8169c117592720dcaa9151ff9b0ffefafa351  ./test/miner_tests.cpp
END_MAXINT_LOCKS_SHA256

my $verifyall_sha256 = << "END_VERIFYALL_SHA256";
02899750161db7f972465da7e7ef011e49e91638529d2f0d3ff475923b7177b8  ./script.h
0da1b23efcdc02ed302211625f07f0a21b2c545ad4f341bebdd14aef29fe08b9  ./bitcoinrpc.h
16b0123375012f07621e163002fccd6b5ed78e1029604af8bd49a4aadba2f131  ./json/json_spirit_writer.cpp
173301ae219764b313d54ec5713395a790c17c7075937d4026b506d39e3dd5f2  ./json/json_spirit_reader.h
1de138674c27465179a18868f20b922c818c7facae8e2641a8eac2bdaf21a0c1  ./script.cpp
1f7ce0f68b5d1771c2309992954e5015a2dd25647867f673c790d8b6b6ea23de  ./json/json_spirit_stream_reader.h
240a3e0d37d2e86b614063f5347eb02d4f99ca6c254de6b82871ff8d95532a7d  ./obj/.gitignore
240a3e0d37d2e86b614063f5347eb02d4f99ca6c254de6b82871ff8d95532a7d  ./obj/nogui/.gitignore
240a3e0d37d2e86b614063f5347eb02d4f99ca6c254de6b82871ff8d95532a7d  ./obj-test/.gitignore
240a3e0d37d2e86b614063f5347eb02d4f99ca6c254de6b82871ff8d95532a7d  ./obj/test/.gitignore
28d5f9a32fe2492bddab66e411659f48fc385c7162fbff4fd3a92b9d18181d2d  ./json/json_spirit_writer.h
2900a4fcb36a6f44fa73bcf031c4f1890aa1b04978a95aeb99cdab9b2f9f6569  ./util.h
2de7c083aa9ecf175bf4ba5ce2090b8aca9f55ee163641722fed42db939ebfb2  ./uint256.h
2f913fd239d3b012af3e180cbe9e4a8b0e3743f345503c30715dd02681892a86  ./crypter.cpp
315ab67375a24dfdb7a224e06a4d449c1919061cca6ca6535f10e7704024edbf  ./test/DoS_tests.cpp
3500a11f6484442870653e118075cc201df0b7d0f6b871b4120e0055ed2cd3b2  ./json/json_spirit_reader.cpp
3548cba9e4da3abc0cfb74da48e8c35e94e2aaa783f111439473ce9d10542352  ./key.h
3c1e779473f5313f544d13315eff1b43bf46842ac4f257e14a9277f4ba466930  ./json/json_spirit_error_position.h
3c76848173ecbdc1d84498ffa0a2727f6116475b258bab2a4713ddebb9a402c9  ./checkpoints.cpp
3ca473a798509553ff04f80b34cae87cf5c855d806b4986a66fda6470408106f  ./keystore.h
3d25a921b937be96becb76d6ed50e784f66528d011352decf5843bfe435633b1  ./noui.h
51c21692ea64a72a9a8f4b0625cae850bb78b15eae4aa38c5dbf809f43ce4106  ./util.cpp
539f240ed0493f57f388de312346bf1a446bf58af75d4aee0001ce8666e33582  ./base58.h
54ffc0e92872f8774bfa5051375e14eb4e68a50a14bf45fcdf145ad6aaf058ab  ./test/util_tests.cpp
552296f683c286d9889d46ed0cb9130b9414395421e9ad8fde03a34a51b31a8e  ./test/README
55c879a24937f03f370172cb91048135e4e494199672ba50a8dbdaf01901ddbc  ./net.cpp
565d106852c703aa2846fdf90b79dee4349dbfc0174e123b063647109c613194  ./net.h
5828cb59f818c9d1439cfecf5f964396fd790509792d31234c4b05b4ff98af28  ./json/json_spirit_reader_template.h
5becffa109d7021c78c0a760dfb28c97c3a1a13ccb9b844c4caac45d390aaf3e  ./json/json_spirit_writer_template.h
686fac4db5112931b07454947908a003a5fef12338dece0506dd614ed05cfd26  ./init.cpp
6a1931bd6e6a765e2026127eb03f2ff24b915028991a2282ff20f0b8cb1d1424  ./json/LICENSE.txt
6c5edfb92f95e7b8237170b1f9c197306060861cb32173bdf28d42ec0448ff57  ./wallet.cpp
79b22c662cec0eb5b2810c2b2b29079018c4c35973e99953a834f028eb69289d  ./headers.h
79dd55f9a783c2425e7f2ce85b73ed5356c0633720d8c56eae1a157f41d6fadf  ./json/json_spirit.h
80f2a51ac724dd21849b0fac1e4886d65cdc2e153f530bb34dc4d2ee29e16d68  ./checkpoints.h
873ea8864ada172514c38c6d98602cd3694d04cfe159f5250b7eb9440262049e  ./json/json_spirit_value.h
8ac8eace8ffe006d16f9afda21de606d60901a6962e86871db2a23f0f6a00352  ./crypter.h
8cd517a6e8bb36e19463864634bb9f2feb7320613b5cf9ae6f217e608f5c7caa  ./strlcpy.h
907eee61824f8206c390a78f1fa1c0a1df322444715f1c45977238c221b55989  ./main.h
915c10007dfce0bfefb540652c43217efee68865d3551a133619ddb9b2515ba8  ./keystore.cpp
9747017069a6048f4e6c0fb431d0a3412f2876e85045a4170e46230df8a78974  ./init.h
a00d9a30c2f2516c965326a19c66d42cafd05d6e0aef57f85d55cd9ccfffbd84  ./serialize.h
a13585ab0323a9e54139e0f4792053fde0dc37b4b1f761043ce0fef66d09619b  ./test/uint256_tests.cpp
a7f9c1bc0f26cdc0966b9d73a9b473eb5789dc578194705ae22f0ecba4e5f5a2  ./db.cpp
afa054805cfbfe7e0b56fbac2efd2cb58e08bf64815f50dca930b1103b4761e6  ./makefile.unix
b231c48c8a9858798c42c771b870849ab5bd49bbc0d65b5fe3e5f399409e6e4e  ./main.cpp
b2d3f994ee9ed53e250c0c4b3520e2a8fa83f44c524473520baea736ae4e3cbc  ./test/script_tests.cpp
b37933d24bad2f17b1c82450df4dbf517a20904d245320a271ad82dba1469dd7  ./wallet.h
b7b5975876a75eeca13528c922f7609d4055c32de367942eb8198d5e5f0a8434  ./json/json_spirit_value.cpp
b86ca5963c0e973b1b18d2f96b63764d0d4a2a688423948335ee3382f96fb12c  ./bignum.h
bf0b87228266226e6a51c2653a66c6b4127ebfe9056cec4b1cac8033b5295f63  ./test/test_bitcoin.cpp
bf7d6621f14f528bda7f8027620a3c5dcefe705ab6b72a516b71abcdb7e8272f  ./test/uint160_tests.cpp
c051de356a3fbb42662f30c4a4a1c9e5bc26cf051767723b2aeef9b23402299f  ./json/json_spirit_utils.h
c26f5201956e77d8cf92dc0cae7e8a906b028f5650e1ca8edaebd75d9591c0b7  ./bitcoinrpc.cpp
c374f834b5530ee1d7cb6f4e813992dbd7b9ea096c336b96ccba0ce8bccadfc5  ./test/base64_tests.cpp
d15bcc15a32171e8fefc4d75f04747c67addfaf5898929b646b1c253134ea463  ./protocol.h
d65bec73d01cad4a2733b058f574ecbfe370cfd927fbd5eafb785850a2109c19  ./test/Checkpoints_tests.cpp
dd08afdba3cd5088c8db3eea33d8d8f45b99d17327c4d381e83a42dea2c3bcca  ./protocol.cpp
dfbc5c95bf817ebb5625bcf060cb9303d96166300ff64e4aa6a819faa331e599  ./test/base58_tests.cpp
e3d7bea43bb30377ae43be9aba3bab44829a2fa6594836a42aaa135e0d7a0e92  ./test/transaction_tests.cpp
e4a281091ad5a11e04fa213333e6e0a4f6359887c1aafaa6d683c8c2c943ed9b  ./db.h
ee9d10124a13651b6cade8476da8169c117592720dcaa9151ff9b0ffefafa351  ./test/miner_tests.cpp
ff864a4385d090d143f883cd75e594486542caed8113165152151412c45684bc  ./.gitignore
END_VERIFYALL_SHA256

Given qr/Load the (\S+) Mod/, sub {
  use_ok($1);
};

Then qr/Init the Command Mod/, sub {
  S->{'Command'} = Command->new;
};

Then qr/I set the work directory as "(.*)"/, sub {
  my $cmd = S->{'Command'};
  $cmd->setWorkDir($1);
};

Then qr/I set the path to V as "(.*)"/, sub {
  my $cmd = S->{'Command'};
  $cmd->setBinPath($1);  
};

Then qr/I set the home directory/, sub { 
  my $cmd = S->{'Command'};
  my $home = `echo \$HOME`; chomp($home); 
  $cmd->setHomeDir($home);
};

sub getWorkDir { 
  my $cmd = S->{'Command'};
  return $cmd->getWorkDir;
};

sub getBinPath {
  my $cmd     = S->{'Command'};
  my $workDir = getWorkDir();
  return $cmd->getBinPath;
};

sub getHomeDir { 
  my $cmd = S->{'Command'};
  return $cmd->getHomeDir;
};

Then qr/validate V output without any flags on first run/, sub {
  my $cmd     = S->{'Command'};
  my $binPath = getBinPath();
  my @got     = `$binPath/v.pl`;

  like($got[0], qr/Unknown or missing option!/, "Validate V without flags, first run test");
};

Then qr/validate option "(.*)" without an argument/, sub { 
  my $cmd     = S->{'Command'};
  my $binPath = getBinPath();
  my $option  = $1;
  my @got     = `$binPath/v.pl $option`;

  like($got[0], qr/Option \"$option\" requires arguments!/, "Option without arguments test."); 
};

Then qr/validate option "(.*)" with "(.*)" argument/, sub { 
  my $cmd     = S->{'Command'};
  my $binPath = getBinPath();
  my $option  = $1;
  my $argNum  = $2;
  my @got     = ();
  if($argNum eq "1") { 
    @got = `$binPath/v.pl $option blah`;
    like($got[0], qr/$option requires two arguments/, "Argument count test.");
  } 
  if($argNum eq "2") {
    @got = `$binPath/v.pl $option blah blah`;
    like($got[0], qr/$option requires three arguments/, "Argument count test.");
  } 
};

Then qr/validate mirrors "(.*)" and sigs from "(.*)"/, sub {
  my $cmd     = S->{'Command'};
  my $binPath = getBinPath();
  my $mirrors = $1;
  my $sigs    = $2;
  my @got     = `$binPath/v.pl m mirror`;
 
  like($got[0], qr/$sigs/, "Mirrors sig test.");
  like($got[1], qr/$mirrors/, "Mirrors url test.");
};

Then qr/validate init "(.*)" short flag output/, sub { 
  my $cmd     = S->{'Command'};
  my $binPath = getBinPath();
  my @got     = `$binPath/v.pl $1`;  

  my $got0 = shift @got;
  my $got1 = shift @got;
  like($got0, qr/Full vpatch sync complete to \"$binPath\/patches\"/, "V init patches sync test.");
  like($got1, qr/Seal sync complete to \"$binPath\/\.seals\"/, "V init seals sync test.");
  foreach(@got) { 
    if($_ =~ /Usage: v\.pl/) { 
      ok(1, "Long help detection."); 
    }
  }
};

Then qr/validate init "(.*)" long flag output/, sub { 
  my $cmd     = S->{'Command'};
  my $binPath = getBinPath();
  my @got     = `$binPath/v.pl $1`;  

  like($got[0], qr/patches dir exists! Skipping initial Vpatch sync/, "V init second patches sync rejected test.");
  like($got[1], qr/$binPath\/\.seals dir exists! Skipping initial Seal sync/, "V init second seals sync rejected test.");
};

Then qr/validate init "(.*)" without option argument/, sub { 
  my $cmd     = S->{'Command'};
  my $binPath = getBinPath();
  my $option  = $1;
  my @got     = `$binPath/v.pl $option 2>&1`;

  like($got[0], qr/Option \"$option\" requires arguments!/, "V init no option argument test.");
};

Then qr/validate init "(.*)" with URL "(.*)" with patchdir "(.*)" and sealdir "(.*)"/, sub { 
  my $cmd     = S->{'Command'};
  my $binPath = getBinPath();
  my $option  = $1;
  my $URL     = $2;
  my $pdir    = $3;
  my $sdir    = $4;  
  my @got     = `$binPath/v.pl $option $URL $pdir $sdir`;
 
  if(-d $pdir) { ok(1); } else { ok(0); }
  if(-e "$pdir/genesis.vpatch") { ok(1); } else { ok(0); }
  if(-d $sdir) { ok(1); } else { ok(0); }
  if(-e "$sdir/genesis.vpatch.mod6.sig") { ok(1); } else { ok(0); }
};

Then qr/validate help "(.*)" flag output/, sub { 
  my $cmd      = S->{'Command'};
  my $binPath  = getBinPath();
  my @got      = `$binPath/v.pl $1`;
  
  foreach(@got) { 
    if($_ =~ /Usage: v\.pl/) { ok(1, "Long Help Message Test"); } 
    if($_ =~ /Prints this full help message/) { ok(1, "Long Help Message Test"); }
  }
};

Then qr/validate short help message/, sub { 
  my $cmd      = S->{'Command'};
  my $binPath  = getBinPath();
  my @got      = `$binPath/v.pl asdfasdf`;
  
  like($got[0], qr/Unknown option/, "Short help message test."); 
  like($got[$#got-2], qr/.*\(h | \? | help\).*/, "Short help message test.");
};

Then qr/validate version message/, sub { 
  my $cmd      = S->{'Command'};
  my $binPath  = getBinPath();
  my @got      = `$binPath/v.pl v`;
  
  foreach(@got) { 
    ok(1) if $_ =~ /Version: 99996 K/;
  }
};

Then qr/validate wot "(.*)" flag output/, sub { 
  my $cmd     = S->{'Command'};
  my $binPath = getBinPath();
  my @got     = `$binPath/v.pl $1`;
  my @wot = (
    "asciilifeform:17215D118B7239507FAFED98B98228A001ABFFC7:Stanislav Datskovskiy <stas\@loper-os.org>",
    "ben_vulpes:4F7907942CA8B89B01E25A762AFA1A9FD2D031DA:Ben Vulpes <benkay\@gmail.com>",
    "mircea_popescu:6160E1CAC8A3C52966FD76998A736F0E2FB7B452:Mircea Popescu (Acest articol are apriori avantajul aliteralitatii alaturi.) <office\@polimedia.us>",
    "mod6:027A8D7C0FB8A16643720F40721705A8B71EADAF:mod6 (mod6) <modsix\@gmail.com>",
    "punkman:F28E0095843B91CB22E7D65533588BE08B232B13:punkman",
    "trinque:FC66C0C5D98C42A1D4A98B6B42F9985AFAB953C4:Michael Trinque <mike\@trinque.org>"
  );
  foreach my $o (@got) { 
    foreach my $w (@wot) {  
      if($o eq $w) { 
        ok($o eq $w, "WoT flag test.");
	delete $wot[$w];
      }
    }
  }
};

Then qr/validate wot "(.*)" flag output/, sub { 
  my $cmd     = S->{'Command'};
  my $binPath = getBinPath();
  my @got     = `$binPath/v.pl $1`;
  my @wot = (
    "asciilifeform-B98228A001ABFFC7:17215D118B7239507FAFED98B98228A001ABFFC7:Stanislav Datskovskiy <stas\@loper-os.org>",
    "ben_vulpes-2AFA1A9FD2D031DA:4F7907942CA8B89B01E25A762AFA1A9FD2D031DA:Ben Vulpes <benkay\@gmail.com>",
    "mircea_popescu-8A736F0E2FB7B452:6160E1CAC8A3C52966FD76998A736F0E2FB7B452:Mircea Popescu (Acest articol are apriori avantajul aliteralitatii alaturi.) <office\@polimedia.us>",
    "mod6-721705A8B71EADAF:027A8D7C0FB8A16643720F40721705A8B71EADAF:mod6 (mod6) <modsix\@gmail.com>",
    "punkman-33588BE08B232B13:F28E0095843B91CB22E7D65533588BE08B232B13:punkman",
    "trinque-42F9985AFAB953C4:FC66C0C5D98C42A1D4A98B6B42F9985AFAB953C4:Michael Trinque <mike\@trinque.org>"
  );
  foreach my $o (@got) { 
    foreach my $w (@wot) {  
      if($o eq $w) { 
        ok($o eq $w, "WoT flag test with finger");
	delete $wot[$w];
      }
    }
  }
};

Then qr/validate roots "(.*)" flag output with signatories "(.*)"/, sub { 
  my $cmd     = S->{'Command'};
  my $binPath = getBinPath();
  my @got     = `$binPath/v.pl $1`;
  my $sigs    = $2;
  like($got[0], qr/Root: genesis\.vpatch \($sigs\)/, "Roots flag test.");
};

Then qr/validate leafs "(.*)" flag output with signatories "(.*)"/, sub { 
  my $cmd     = S->{'Command'};
  my $binPath = getBinPath();
  my @got     = `$binPath/v.pl $1`;
  my $sigs    = $2;
  like($got[0], qr/Leaf: .*\.vpatch \($sigs\)/, "Leafs flag test.");
};

Then qr/validate antecedents "(.*)" flag output/, sub { 
  my $cmd     = S->{'Command'};
  my $binPath = getBinPath();
  my @got     = `$binPath/v.pl $1`;
  like($got[0], qr/Antecedent: .*\.vpatch \(.*\) \[.*\]/, "Antecedent flag test.");
};

Then qr/validate antecedents "(.*)" without option argument/, sub { 
  my $cmd     = S->{'Command'};
  my $binPath = getBinPath();
  my $option  = $1;
  my @got     = `$binPath/v.pl $1 2>&1`;  

  like($got[0], qr/Option \"$option\" requires arguments!/, "V antecedents no option argument test.");
};

Given qr/vpatch to process/, sub {
  my $cmd = S->{'Command'};
  $cmd->setVpatchToProcess(@_);
};

Given qr/expected antecedents/, sub { 
  my $cmd = S->{'Command'};
  $cmd->setExpectedAntecedents(@_);
};

Given qr/expected descendants/, sub {
  my $cmd = S->{'Command'};
  $cmd->setExpectedDescendants(@_);
};

Given qr/expected signatures/, sub { 
  my $cmd = S->{'Command'};
  $cmd->setExpectedSignatures(@_);
};

Given qr/expected source files/, sub { 
  my $cmd = S->{'Command'};
  $cmd->setExpectedSourceFiles(@_);
};

Then qr/validate output antecedents/, sub { 
  my $cmd      = S->{'Command'};
  my $binPath  = getBinPath();

  my @vpdata   = @{$cmd->getVpatchToProcess->{_data}};
  my @antedata = @{$cmd->getExpectedAntecedents->{_data}};
  my @sigdata  = @{$cmd->getExpectedSignatures->{_data}};
  my @srcfiles = @{$cmd->getExpectedSourceFiles->{_data}};
  
  if(@vpdata == @antedata && 
     @antedata == @sigdata && 
     @sigdata == @srcfiles) {
    for($i = 0; $i < @vpdata; $i++) {
      my @ante = split /!/, $antedata[$i]->{antecedents};
      my @sigs = split /!/, $sigdata[$i]->{signatures};
      my @sf   = split /!/, $srcfiles[$i]->{source_files};

      my @out = `$binPath/v.pl a $vpdata[$i]->{vpatch}`;
      $cmd->logger->info("Test antecedent: $vpdata[$i]->{vpatch}");

      for($j = 0; $j < @out; $j++) { 
        like($out[$j], qr/Antecedent: $ante[$j] \($sigs[$j]\) \[ $sf[$j] \]/, "$vpdata[$i]->{vpatch} antecedents validation test.");
      }
    }
  } else { $cmd->logger->info("ERROR: TABLE DATA INPUT SIZES DO NOT MATCH! Fail."); ok(0); }
};

Then qr/validate descendants "(.*)" flag output/, sub { 
  my $cmd     = S->{'Command'};
  my $binPath = getBinPath();
  my @got     = `$binPath/v.pl $1`;
  like($got[0], qr/Descendant: .*\.vpatch \(.*\) \[.*\]/, "Descendants flag test.");
};

Then qr/validate descendants "(.*)" without option argument/, sub { 
  my $cmd     = S->{'Command'};
  my $binPath = getBinPath();
  my $option  = $1;
  my @got     = `$binPath/v.pl $option 2>&1`;  

  like($got[0], qr/Option \"$option\" requires arguments!/, "V descendants no option argument test.");
};

Then qr/validate output descendants/, sub { 
  my $cmd      = S->{'Command'};
  my $binPath  = getBinPath();

  my @vpdata   = @{$cmd->getVpatchToProcess->{_data}};
  my @descdata = @{$cmd->getExpectedDescendants->{_data}};
  my @sigdata  = @{$cmd->getExpectedSignatures->{_data}};
  my @srcfiles = @{$cmd->getExpectedSourceFiles->{_data}};
  
  if(@vpdata == @descdata && 
     @descdata == @sigdata && 
     @sigdata == @srcfiles) {
    for($i = 0; $i < @vpdata; $i++) {
      my @desc = split /!/, $descdata[$i]->{descendants};
      my @sigs = split /!/, $sigdata[$i]->{signatures};
      my @sf   = split /!/, $srcfiles[$i]->{source_files};

      my @out = `$binPath/v.pl d $vpdata[$i]->{vpatch}`;
      $cmd->logger->info("Test descendant: $vpdata[$i]->{vpatch}");

      for($j = 0; $j < @out; $j++) { 
        like($out[$j], qr/Descendant: $desc[$j] \($sigs[$j]\) \[ $sf[$j] \]/, "$vpdata[$i]->{vpatch} descendants validation test.");
      }
    }
  } else { $cmd->logger->info("ERROR: TABLE DATA INPUT SIZES DO NOT MATCH! Fail."); ok(0); }
};

Then qr/validate flow "(.*)" flag output/, sub { 
  my $cmd     = S->{'Command'};
  my $binPath = getBinPath();
  my @got     = `$binPath/v.pl $1`;
   
  like($got[0], qr/genesis.vpatch \(asciilifeform, mircea_popescu, mod6, trinque\)/, "Start of flow validation test."); 
  like($got[$#got], qr/asciilifeform_malleus_mikehearnificarum\.vpatch/, "End of flow validation test."); 
};

Then qr/validate graphviz "(.*)" flag output/, sub { 
  my $cmd     = S->{'Command'};
  my $binPath = getBinPath();
  my @got     = `$binPath/v.pl $1`;

  like($got[0], qr/digraph VPATCH_GRAPH/, "Graphviz flag validation test.");
};

Then qr/validate graphviz "(.*)" flag with output file/, sub { 
  my $cmd     = S->{'Command'};
  my $binPath = getBinPath();
  my $flag    = $1;
  my @got     = `$binPath/v.pl $flag`;

  like($got[0], qr/Printed Graphviz dot file to/, "Graphviz flag with output file validation test.");
  my @args    = split / /, $flag;
  my @head    = `head -1 $args[1]`; 
  like($head[0], qr/digraph VPATCH_GRAPH/, "Graphviz flag with output file validation test.");
};

Then qr/validate graphviz "(.*)" flag with output html file/, sub { 
  my $cmd     = S->{'Command'};
  my $binPath = getBinPath();
  my $flag    = $1;
  my @got     = `$binPath/v.pl $flag`;

  like($got[0], qr/Printed Graphviz dot file to/, "Graphviz flag with output file validation test.");
  my @args    = split / /, $flag;
  my @head    = `head -1 $args[1]`; 
  like($head[0], qr/digraph VPATCH_GRAPH/, "Graphviz flag with output file validation test.");

  @head       = `head -6 $args[2] | tail -1`;
  like($head[0], qr/<!-- Title: VPATCH_GRAPH Pages: 1 -->/, "Graphviz flag with html output file validation test."); 
};

Then qr/validate sync wot "(.*)" flag output/, sub { 
  my $cmd     = S->{'Command'};
  my $binPath = getBinPath();
  my $flag    = $1;
  my @args    = split / /, $flag;
  my @got     = `$binPath/v.pl $flag`;
 
  if(-d $args[1]) { 
    like($got[0], qr/WoT sync complete/, "WoT Sync flag validation test."); 
    ok(1, "WoT Sync directory was created.");
  }
};

Then qr/validate sync wot "(.*)" without option argument/, sub { 
  my $cmd     = S->{'Command'};
  my $binPath = getBinPath();
  my $option  = $1;
  my @got     = `$binPath/v.pl $option 2>&1`;  

  like($got[0], qr/Option \"$option\" requires arguments!/, "V sync-wot no option argument test.");
};

Then qr/validate sync vpatch "(.*)" flag output/, sub {
  my $cmd     = S->{'Command'};
  my $binPath = getBinPath();
  my $flag    = $1;
  my @args    = split / /, $flag;
  my @got     = `$binPath/v.pl $flag`;

  if(-d $args[2]) { 
    shift @args; shift @args; my $outdir = shift @args; #remove the first three args, leaving the vpatch file names
    if(@got == @args) { 
      for($i = 0; $i < @got; $i++) {  
        like($got[$i], qr/$args[$i] sync complete/, "Vpatch sync flag validation."); 
        if(-e "$outdir/$args[$i]") { ok(1, "Vpatch file was sync'd and created."); }
        else { ok(0, "Vpatch file not created!"); }
      } 
    } else { print "GOT AND ARGS SIZES DO NOT MATCH!\n"; ok(0); }
    ok(1, "Vpatch Sync directory was created.");
  }
};

Then qr/validate sync vpatch "(.*)" without option argument/, sub { 
  my $cmd     = S->{'Command'};
  my $binPath = getBinPath();
  my $option  = $1;
  my @got     = `$binPath/v.pl $option 2>&1`;  

  like($got[0], qr/Option \"$option\" requires arguments!/, "V sync-vpatches no option argument test.");
};

Then qr/validate sync vpatch fails silently "(.*)" with nonexistant vpatch/, sub {
  my $cmd     = S->{'Command'};
  my $binPath = getBinPath();
  my $flag    = $1;
  my @args    = split / /, $flag;
  my @got     = `$binPath/v.pl $flag`;
 
  shift @args; shift @args; # remove the first two args, leaving the output dir
  if(!-e "$args[0]/$args[1]") { 
    ok(1, "Vpatch sync of non-existant file validation test.");
  } else { 
    ok(0, "File was created! Fail.");
  }
};

Then qr/validate sync all flag for "(.*)" vpatches with options "(.*)"/, sub { 
  my $cmd     = S->{'Command'};
  my $binPath = getBinPath();
  my $vpcount = $1;
  my $flag    = $2;
  my @args    = split / /, $flag;
  my @got     = `$binPath/v.pl $flag`;
  
  shift @args; shift @args; # remove first two args, leaving the output dir
  if(-d $args[0]) { 
    my $actual = `ls $args[0] | sort | wc -l`;
    ok($vpcount == $actual, "Sync of all vpatches validation test.");
  } 
};

Then qr/validate sync all vpatches "(.*)" without option argument/, sub { 
  my $cmd     = S->{'Command'};
  my $binPath = getBinPath();
  my $option  = $1;
  my @got     = `$binPath/v.pl $option 2>&1`;  

  like($got[0], qr/Option \"$option\" requires arguments!/, "V sync-all-vpatches no option argument test.");
};

Then qr/validate sync seals flag for "(.*)" seals with options "(.*)"/, sub { 
  my $cmd      = S->{'Command'};
  my $binPath  = getBinPath();
  my $sigcount = $1;
  my $flag     = $2;
  my @args     = split / /, $flag;
  my @got      = `$binPath/v.pl $flag`;
 
  shift @args; shift @args; # remove first two args, leaving the output dir
  if(-d $args[0]) { 
    my $actual = `ls $args[0] | sort | wc -l`; 
    ok($sigcount == $actual, "Sync of all seals validation test.");
  }
};

Then qr/validate sync seals "(.*)" without option argument/, sub { 
  my $cmd     = S->{'Command'};
  my $binPath = getBinPath();
  my $option  = $1;
  my @got     = `$binPath/v.pl $option 2>&1`;  

  like($got[0], qr/Option \"$option\" requires arguments!/, "V sync-seals no option argument test.");
};

Then qr/validate sync everything flag for "(.*)" vpatches "(.*)" seals with options "(.*)"/, sub {
  my $cmd        = S->{'Command'};
  my $binPath    = getBinPath();
  my $vpcount    = $1;
  my $sealscount = $2;
  my $flag       = $3;
  my @args       = split / /, $flag;
  my @got        = `$binPath/v.pl $flag`;

  shift @args; shift @args; # remove first two args, leaving the output dir
  if(-d $args[0]) {
    my $actual_vp = `ls $args[0] | sort | wc -l`;
    ok($vpcount == $actual_vp, "Sync of everything [vpatches] validation test.");
  }

  if(-d $args[1]) {
    my $actual_seals = `ls $args[1] | sort | wc -l`;
    ok($sealscount == $actual_seals, "Sync of everything [seals] validation test.");
  }
};

Then qr/validate sync everything "(.*)" without option argument/, sub { 
  my $cmd     = S->{'Command'};
  my $binPath = getBinPath();
  my $option  = $1;
  my @got     = `$binPath/v.pl $1 2>&1`;

  like($got[0], qr/Option \"$option\" requires arguments!/, "V sync-everything no option argument test.");
};

When qr/delete public key "(.*)" from "(.*)"/, sub {
  my $cmd     = S->{'Command'};
  my $pubkey = $1;
  my $wotdir = $2;

  $res = `rm $wotdir/$pubkey`;   
  if($res) { 
    ok(0, "Delete public key. Point at new wot dir test."); 
    print "Error: $res\n";
  } else {
    ok(1, "Delete public key. Point at new wot dir test.");
  }
};

Then qr/point at wot dir "(.*)" with flag "(.*)" and validate that "(.*)" is no longer in wot "(.*)"/, sub {
  my $cmd     = S->{'Command'};
  my $binPath = getBinPath();
  my $wotdir  = $1;
  my $wdflag  = $2;
  my $wotuid  = $3;
  my $wotflag = $4;
  my @got     = `$binPath/v.pl $wotflag $wdflag $wotdir`;

  my @wot = ();
  if($wotflag =~ /finger/) {
    @wot = (
      "asciilifeform-B98228A001ABFFC7:17215D118B7239507FAFED98B98228A001ABFFC7:Stanislav Datskovskiy <stas\@loper-os.org>",
      "ben_vulpes-2AFA1A9FD2D031DA:4F7907942CA8B89B01E25A762AFA1A9FD2D031DA:Ben Vulpes <benkay\@gmail.com>",
      "mircea_popescu-8A736F0E2FB7B452:6160E1CAC8A3C52966FD76998A736F0E2FB7B452:Mircea Popescu (Acest articol are apriori avantajul aliteralitatii alaturi.) <office\@polimedia.us>",
      "punkman-33588BE08B232B13:F28E0095843B91CB22E7D65533588BE08B232B13:punkman",
      "trinque-42F9985AFAB953C4:FC66C0C5D98C42A1D4A98B6B42F9985AFAB953C4:Michael Trinque <mike\@trinque.org>"
    );
  } else {
    @wot = (
      "asciilifeform:17215D118B7239507FAFED98B98228A001ABFFC7:Stanislav Datskovskiy <stas\@loper-os.org>",
      "ben_vulpes:4F7907942CA8B89B01E25A762AFA1A9FD2D031DA:Ben Vulpes <benkay\@gmail.com>",
      "mircea_popescu:6160E1CAC8A3C52966FD76998A736F0E2FB7B452:Mircea Popescu (Acest articol are apriori avantajul aliteralitatii alaturi.) <office\@polimedia.us>",
      "punkman:F28E0095843B91CB22E7D65533588BE08B232B13:punkman",
      "trinque:FC66C0C5D98C42A1D4A98B6B42F9985AFAB953C4:Michael Trinque <mike\@trinque.org>"
    );
  }

  foreach my $o (@got) { 
    foreach my $w (@wot) {  
      if($o eq $w) { 
        like($o, qr/$w/, "WoT dir flag test.");
	delete $wot[$w];
      }
    }
  }

  my @flow = `$binPath/v.pl f $wdflag $wotdir\n`;
  like($flow[0], qr/genesis.vpatch \(asciilifeform, mircea_popescu, trinque\)/, "Start of wotdir w/flow validation test."); 
  like($flow[$#flow], qr/asciilifeform_malleus_mikehearnificarum\.vpatch \(asciilifeform\)/, "End of wotdir w/flow validation test."); 
};

When qr/add a test patch to the new patchdir "(.*)"/, sub {
  my $cmd      = S->{'Command'};
  my $binPath  = getBinPath();
  my $patchdir = $1;
  my $vpatch   = << "END_RELEASE_VPATCH";
diff -uNr a/bitcoin/src/db.cpp b/bitcoin/src/db.cpp
--- a/bitcoin/src/db.cpp 565faf3ef371f5e2178ae30c45b08b93415eeb92263486e68f2ac2e8f4c7900056e628804bf5c0707a90be946e0aeaebfcd0a391aab40de2e5d56e6bcbdccb1e
+++ b/bitcoin/src/db.cpp df9d907531884755a254eb8c7614d9424f79ce56f9503df86ffd455375a302e12f1a31340f725f9d10eb1771c68e351026dd47c33cbd1c9da519462dea70a8af
@@ -3,6 +3,8 @@
 // Distributed under the MIT/X11 software license, see the accompanying
 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
 
+// v99999 | v0.5.4 RELEASE
+
 #include "headers.h"
 #include "db.h"
 #include "net.h"
diff -uNr a/bitcoin/src/key.h b/bitcoin/src/key.h
--- a/bitcoin/src/key.h afe71ade56fae65b970ff3dfb3f14edacee0af497ae57e2d2502c9a4b4f49f3336f9d3794b72a87d185b92fc01f1a5077e1ccd63a61ac4fa9c4464c6224fd1e4
+++ b/bitcoin/src/key.h 5c2a4e6737cbe6fe1d0fa89e19bc8a79557cb3ccc6fafa0520f93c1f0eae3dd60119e79cddb5ccbda3c89396dbc9fef1025a97d6db54089b381ad6665a2b6cef
@@ -2,6 +2,9 @@
 // Copyright (c) 2009-2012 The Bitcoin developers
 // Distributed under the MIT/X11 software license, see the accompanying
 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
+
+// v99999 | v0.5.4 RELEASE
+
 #ifndef BITCOIN_KEY_H
 #define BITCOIN_KEY_H
 
diff -uNr a/bitcoin/src/main.cpp b/bitcoin/src/main.cpp
--- a/bitcoin/src/main.cpp 02ccc72e42939509fc180861db7ffec50563a84869f35671fcf720090f9782674edcc89c4174175691566fac7277f1ebe0f50253d1e4a995eb960f5b43cce2a3
+++ b/bitcoin/src/main.cpp cfb33fe0943251327f18759470923a9f89bebaf7f524897e06daee222893ec6a9244e1837c80f3fa06b15cac2df228e8badf258665a6b1a3439d77a3824c1b49
@@ -2,6 +2,9 @@
 // Copyright (c) 2009-2012 The Bitcoin developers
 // Distributed under the MIT/X11 software license, see the accompanying
 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
+
+// v99999 | v0.5.4 RELEASE
+
 #include "headers.h"
 #include "checkpoints.h"
 #include "db.h"
END_RELEASE_VPATCH

  my $vpatch_name = "test_release.vpatch";
  my $path = "$patchdir/$vpatch_name";
  open(my $fh, ">", $path); print $fh "$vpatch\n";
  close($fh);
};

Then qr/point v at patch dir "(.*)" with flag "(.*)" and validate/, sub {
  my $cmd      = S->{'Command'};
  my $binPath  = getBinPath();
  my $patchdir = $1;
  my $pdflag   = $2;
  my @flow     = `$binPath/v.pl f $pdflag $patchdir`; 
  like($flow[$#flow], qr/test_release\.vpatch \(WILD\)/, "Patchdir pd/patchdir test."); 
};

When qr/point v at seals dir "(.*)" and delete all seals from "(.*)"/, sub {
  my $cmd     = S->{'Command'};
  my $binPath = getBinPath();
  my $sealdir = $1;
  my $wotuid  = $2;
  $res = `rm -f $sealdir/*.$wotuid.sig`; 
  if($res) { 
    ok(0, "Delete seals from alternate seals dir for wotuid: $wotuid");
  }
};

Then qr/point v at seals dir "(.*)" with flag "(.*)" and validate no vpatches with seals by "(.*)"/, sub {
  my $cmd     = S->{'Command'};
  my $binPath = getBinPath();
  my $sealdir = $1;
  my $sdflag  = $2;
  my $wotuid  = $3;
  my @flow    = `$binPath/v.pl f $sdflag $sealdir`;
  foreach(@flow) {  
    unlike($_, qr/.*\($wotuid\).*/, "Seal dir test");
  } 
};

Then qr/validate press "(.*)" to dir "(.*)" with head "(.*)"/, sub {
  my $cmd     = S->{'Command'};
  my $binPath = getBinPath();
  my $option  = $1;
  my $outdir  = $2;
  my $head    = $3;
  my @sha256  = ();
 
  # DEBUG 
  #my @res = `$binPath/v.pl $option --verbose $outdir $head 2>&1`;
  #if(@res) { foreach(@res) { print "$_"; } }

  my @res = `$binPath/v.pl $option $outdir $head`;
  if(!@res) { ok(1); }
  if(!-d $outdir) { ok(0); }
 
  if($head =~ /"asciilifeform_maxint_locks_corrected\.vpatch/) {
    chdir("$outdir/bitcoin/src");
    @sha256 = `find $outdir/bitcoin/src -type f -print0 | xargs -0 sha256sum | sort`;
    chdir(getBinPath());
    open ORIG, ">$outdir/maxint_locks.vpatch.sha256.orig" or die "$!";
    print ORIG $verifyall_sha256;
    close ORIG;
    open NEW, ">$outdir/maxint_locks.vpatch.sha256" or die "$!";
    foreach(@sha256) { print NEW $_; }
    close NEW;
    @diff = `diff -u $outdir/maxint_locks.vpatch.sha256.orig $outdir/maxint_locks.vpatch.sha256`;
    if(!@diff) { ok(1); } else { ok(0); }
  }

  if($head =~ /"asciilifeform_add_verifyall_option\.vpatch/) {
    chdir("$outdir/bitcoin/src");
    @sha256 = `find $outdir/bitcoin/src -type f -print0 | xargs -0 sha256sum | sort`;
    chdir(getBinPath());
    open ORIG, ">$outdir/verifyall.vpatch.sha256.orig" or die "$!";
    print ORIG $verifyall_sha256;
    close ORIG;
    open NEW, ">$outdir/verifyall.vpatch.sha256" or die "$!";
    foreach(@sha256) { print NEW $_; }
    close NEW;
    @diff = `diff -u $outdir/verifyall.vpatch.sha256.orig $outdir/verifyall.vpatch.sha256`;
    if(!@diff) { ok(1); } else { ok(0); }
  }
};

When qr/user creates new wot directory "(.*)" with one entry "(.*)"/, sub {
  my $cmd    = S->{'Command'};
  my $wotDir = $1;
  my $pubkey = $2; 

  `mkdir -p $wotDir`;
  `cp -p .wot/$pubkey $wotDir`;
};

When qr/user creates new seals directory "(.*)" with one entry from a nonexisting WoT member "(.*)"/, sub {
  my $cmd      = S->{'Command'};
  my $sealsDir = $1; 
  my $seal     = $2;

  `mkdir -p $sealsDir`;
  `cp -p .seals/$seal $sealsDir`;
};

Then qr/I validate that V will fail when encountering a seal in "(.*)" from an entity not in the current WoT "(.*)"/, sub { 
  my $cmd     = S->{'Command'};
  my $binPath = getBinPath();
  my $sealDir = $1;
  my $wotDir  = $2;
  
  my @got = `$binPath/v.pl f wd $wotDir sd $sealDir`;
  foreach(@got) { 
    ok(1) if $_ =~ /Check that this user is in your WoT, and that this key/;
  } 

  my @got2 = `$binPath/v.pl f wd $wotDir sd $sealDir`;
  foreach(@got2) { 
    ok(1) if $_ =~ /Check that this user is in your WoT, and that this key/;
  } 
};

Then qr/I remove "(.*)"/, sub { 
  my $cmd     = S->{'Command'};
  my $binPath = getBinPath();
  my $arg     = $1;
  if($arg     =~ /~\/(.*)/) { $arg = getHomeDir() . "/$1"; }
  my @res     = `rm -rf $arg`;
  if(@res) { ok(0, "Clean up $arg"); }
};
