public void AddCommands_ShouldThrowExceptionForEmptyArgumentCollection()
        {
            // Arrange
            // Act
            try
            {
                var commands = new List <string>();

                IBitcoinLibrary bitcoinLibrary = new BitcoinLibrary();
                var             walletManager  = new WalletManager(bitcoinLibrary);
                walletManager.AddCommands(commands.ToArray());

                // Should not get here - Force a fail if we do
                walletManager.Should().BeNull();
            }
            catch (CommandArgumentNullOrEmptyException ex)
            {
                ex.Message.Should().Contain("Argument collection is empty.");
            }
            catch (Exception ex)
            {
                // Should not get here
                ex.Should().BeNull();
            }
        }
        public void ProcessCommands_ShouldThrowCustomExceptionWhenCommandNotAvailable()
        {
            // Arrange
            IBitcoinLibrary bitcoinLibrary = new BitcoinLibrary();
            var             walletManager  = new WalletManager(bitcoinLibrary);

            // Act
            try
            {
                walletManager.ProcessCommands();

                // Should not get here - Force a fail if we do
                walletManager.Should().BeNull();
            }
            catch (CommandNotFoundException ex)
            {
                // Assert
                ex.Message.Should().Be("No CommandIdentifier Available.");
            }
            catch (Exception ex)
            {
                // Should not get here
                ex.Should().BeNull();
            }
        }
        public void AddCommands_ShouldAddCommandsToEndOfCommandsCollection()
        {
            // Arrange
            IBitcoinLibrary bitcoinLibrary = new BitcoinLibrary();
            var             walletManager  = new WalletManager(bitcoinLibrary);

            walletManager.AddCommands(Args);
            var newCommand = new List <string>
            {
                "show-balances",
                "wallet-file=test2.json",
                "send", "btc=1.00", "address=mq6fK8fkFyCy9p53m4GG4fiE2XCKvcwgi4", "wallet-file=test2.json",
            };

            var expectedCommands = new List <string>();

            expectedCommands.AddRange(Args);
            expectedCommands.AddRange(newCommand);

            // Act
            walletManager.AddCommands(newCommand.ToArray());
            var actualWalletManagerCommands = walletManager.Commands;

            // Assert
            actualWalletManagerCommands.Should().BeEquivalentTo(expectedCommands);
        }
        public void ProcessGenerateWallet_ShouldSuccessfullyGenerateAWallet()
        {
            // Arrange
            var args = new[]
            {
                "wallet-file=wallet.json",
            };
            var expectedPathToFile = Path.Combine("Wallets", "wallet.json");
            var password           = new SecureString();

            password.AppendChar('p');
            password.AppendChar('a');
            password.AppendChar('s');
            password.AppendChar('s');
            password.AppendChar('w');
            password.AppendChar('o');
            password.AppendChar('r');
            password.AppendChar('d');
            IBitcoinLibrary bitcoinLibrary = new BitcoinLibrary();

            // Act
            var mnemonic = bitcoinLibrary.GenerateWallet(args, password);

            // Assert
            mnemonic.Should().NotBeNull();
            mnemonic.Split(",").Length.Should().Be(12);
            File.Exists(expectedPathToFile).Should().BeTrue();

            // Cleanup
            // Ensure Wallets directory doesn't already exist
            Directory.Delete("Wallets", true);
        }
        public void ProcessNextCommand_ShouldRemoveTheProcessedCommandFromCollectionOnceComplete()
        {
            // Arrange
            string[] commandsAndArgs =
            {
                "generate-wallet", "wallet-file=BitcoinWallet.json",
                "recover-wallet",  "wallet-file=test1.json",
                "show-balances",   "wallet-file=test1.json",
                "send",            "btc=0.0001",                    "address=mq6fK8fkFyCy9p53m4Gf4fiX2XCHvcwgi1","wallet-file=test1.json",
            };

            IBitcoinLibrary bitcoinLibrary = new BitcoinLibrary();
            var             walletManager  = new WalletManager(bitcoinLibrary);

            walletManager.AddCommands(commandsAndArgs);

            var currentCommandCount = walletManager.Commands.Count;

            // Act
            walletManager.ProcessNextCommand();

            // Assert
            walletManager.Commands.Count.Should().NotBe(currentCommandCount);
            walletManager.Commands.Count.Should().Be(currentCommandCount - 2);
        }
        public void AddCommands_ShouldThrowExceptionForArgumentsWithNullValues()
        {
            // Arrange
            // Act
            try
            {
                var commands = new[]
                {
                    "show-balances",
                    null,
                };

                IBitcoinLibrary bitcoinLibrary = new BitcoinLibrary();
                var             walletManager  = new WalletManager(bitcoinLibrary);
                walletManager.AddCommands(commands);

                // Should not get here - Force a fail if we do
                walletManager.Should().BeNull();
            }
            catch (CommandArgumentNullOrEmptyException ex)
            {
                ex.Message.Should().Contain("Received null Argument.");
            }
            catch (Exception ex)
            {
                // Should not get here
                ex.Should().BeNull();
            }
        }
        public void AddCommands_ShouldAddCommandsAsDefined()
        {
            // Arrange
            IBitcoinLibrary bitcoinLibrary = new BitcoinLibrary();
            var             walletManager  = new WalletManager(bitcoinLibrary);

            // Act
            walletManager.AddCommands(Args);

            // Assert
            walletManager.Commands.Should().BeEquivalentTo(Args);
        }
        public void ProcessShowBalances_ShouldReturnBalanceForAGivenWallet()
        {
            // Arrange
            const string walletContents = "{ \"EncryptedSeed\": \"6PYM714zxNRpmx7WRaCLNJyAreYx2BU5GkbCx5jF5QQNKeZExYqrNHzK8L\",\"ChainCode\": \"CarQU+owbi2iML7Fy5vf+6O0Lpc/V//NFkk7WLVkh70=\",\"Network\": \"Main\",\"CreationTime\": \"2019-07-18\"}";

            const string walletDirectoryName = "Wallets";
            const string walletFileName      = "wallet_show_balances_test.json";
            var          walletFilePath      = Path.Combine(walletDirectoryName, walletFileName);

            Directory.CreateDirectory(walletDirectoryName);
            using (File.Create(walletFilePath))
            {
            }

            File.WriteAllText(walletFilePath, walletContents);
            File.Exists(walletFilePath).Should().BeTrue();

            var args = new[]
            {
                $"wallet-file={walletFileName}",
            };

            var password = new SecureString();

            password.AppendChar('p');
            password.AppendChar('a');
            password.AppendChar('s');
            password.AppendChar('s');
            password.AppendChar('w');
            password.AppendChar('o');
            password.AppendChar('r');
            password.AppendChar('d');
            IBitcoinLibrary bitcoinLibrary = new BitcoinLibrary();

            var expectedResult = "Address Key - 12aTk1fcxq2Sa8xpwDyRWVK6pg8RfDzp51:  Confirmed Balance: 0.  Unconfirmed Balance: 0! Address Key - 1An8cCNwNKkZExStUdtuav5XoUPnFTeS32:  Confirmed Balance: 0.  Unconfirmed Balance: 0! Address Key - 17vghiDiZYcpFDgT7FL7wf9NiqFiGyaiWU:  Confirmed Balance: 0.  Unconfirmed Balance: 0! Address Key - 1AZ8mMSmfwyt6RoKU8VvzodbaW7QaTgPL3:  Confirmed Balance: 0.  Unconfirmed Balance: 0! Address Key - 1Prgw1SJF53Qcgmn2YQ4F8suZN9wPZnU7y:  Confirmed Balance: 0.  Unconfirmed Balance: 0! Address Key - 1JU6L1iKYqgEdBdqfGQ4vx1DD2DRq84Hg7:  Confirmed Balance: 0.  Unconfirmed Balance: 0! Address Key - 1HLzcWeRRF8dGitVpwVHw2VRr7jzPr1Fdy:  Confirmed Balance: 0.  Unconfirmed Balance: 0! Address Key - 1BeVydLDbof2jv6upkwm1HdcgDjfUbWo9s:  Confirmed Balance: 0.  Unconfirmed Balance: 0! Address Key - 1AP64gCEBt1MHtXdAFKwcaEpBKaWAm2Yhb:  Confirmed Balance: 0.  Unconfirmed Balance: 0! Address Key - 16DsRYBAVukyC45bWvRki83yTx3djztScq:  Confirmed Balance: 0.  Unconfirmed Balance: 0! Address Key - 16QWEMqjXTaPkxBPtQP8CHvQm7D2q9jc5m:  Confirmed Balance: 0.  Unconfirmed Balance: 0! Address Key - 1EhYAoGP9gbA5tVi7dNqi5vHRCrgzZgnU:  Confirmed Balance: 0.  Unconfirmed Balance: 0! Address Key - 18vwHHkvGGBh2SaeniWKUf9PLo7kRim9XQ:  Confirmed Balance: 0.  Unconfirmed Balance: 0! Address Key - 1BiutrFMyx7H8kLBAJAXLduNEWQTnTJ3Ca:  Confirmed Balance: 0.  Unconfirmed Balance: 0! ";

            try
            {
                // Act
                var result = bitcoinLibrary.ShowBalances(args, password);

                result.Should().Be(expectedResult);
            }
            catch (IncorrectWalletPasswordException ex)
            {
                // Assert
                ex.Message.Should().Contain("Provided password is incorrect.");
            }

            // Clean up
            Directory.Delete(walletDirectoryName, true);
            File.Delete(walletFileName);
        }
        public void ProcessGenerateWallet_ShouldThrowAnExceptionIfWalletAlreadyExists()
        {
            // Arrange
            const string walletDirectory = "Wallets";

            Directory.CreateDirectory(walletDirectory);
            const string walletFileName = "wallet_generate_test.json";

            using (File.Create(Path.Combine(walletDirectory, walletFileName)))
            {
            }

            var args = new[]
            {
                $"wallet-file={walletFileName}",
            };
            var password = new SecureString();

            password.AppendChar('p');
            password.AppendChar('a');
            password.AppendChar('s');
            password.AppendChar('s');
            password.AppendChar('w');
            password.AppendChar('o');
            password.AppendChar('r');
            password.AppendChar('d');

            IBitcoinLibrary bitcoinLibrary = new BitcoinLibrary();

            try
            {
                // Act
                bitcoinLibrary.GenerateWallet(args, password);

                // Should not get here - Force a fail if we do
                bitcoinLibrary.Should().BeNull();
            }
            catch (WalletAlreadyExistsException ex)
            {
                // Assert
                ex.Message.Should().Be("The request to generate a wallet failed because the wallet already exists.");
            }
            catch (Exception ex)
            {
                // Should not get here.
                ex.Should().BeNull();
            }

            // Cleanup
            Directory.Delete("Wallets", true);
            File.Delete(walletFileName); // Default results in locally created wallet file.
        }
        public void ProcessRecoverWallet_ShouldRecoverAWalletWhenGivenValidArguments()
        {
            // Arrange
            const string walletFileName = "wallet_recover_test.json";
            const string mnemonic       = "dash destroy twelve twice labor patch embrace embody chronic inch install term";
            var          args           = new[]
            {
                $"wallet-file={walletFileName}",
                $"mnemonic={mnemonic}",
            };
            var password = new SecureString();

            password.AppendChar('p');
            password.AppendChar('a');
            password.AppendChar('s');
            password.AppendChar('s');
            password.AppendChar('w');
            password.AppendChar('o');
            password.AppendChar('r');
            password.AppendChar('d');

            const string    expectedEncryptedSeed = "6PYM714zxNRpmx7WRaCLNJyAreYx2BU5GkbCx5jF5QQNKeZExYqrNHzK8L";
            const string    expectedChainCode     = "CarQU+owbi2iML7Fy5vf+6O0Lpc/V//NFkk7WLVkh70=";
            IBitcoinLibrary bitcoinLibrary        = new BitcoinLibrary();

            // Act
            var recoveredWalletLocation = string.Empty;

            try
            {
                recoveredWalletLocation = bitcoinLibrary.ProcessRecoverWallet(args, password);
            }
            catch (Exception ex)
            {
                ex.Should().BeNull();
            }

            // Assert
            File.Exists(recoveredWalletLocation).Should().BeTrue();
            var fileContents = File.ReadAllText(recoveredWalletLocation);

            // Check our Encrypted Seed exists
            fileContents.Should().Contain(expectedEncryptedSeed);

            // Check our Chain Code exists
            fileContents.Should().Contain(expectedChainCode);

            // Cleanup
            Directory.Delete("Wallets", true);
            File.Delete(walletFileName);
        }
        public void WalletManager_ShouldEnsureConfigurationLoadOnInstantiation()
        {
            // Arrange
            // Act
            IBitcoinLibrary bitcoinLibrary = new BitcoinLibrary();
            var             walletManager  = new WalletManager(bitcoinLibrary);

            walletManager.AddCommands(Args);

            // Assert
            Configuration.DefaultWalletFileName.Should().NotBeNull();
            Configuration.DefaultNetwork.Should().NotBeNull();
            Configuration.DefaultConnectionType.Should().NotBeNull();
        }
        public void ProcessRecoverWallet_ShouldThrowCustomExceptionIfWalletExists()
        {
            // Arrange
            const string walletDirectoryName = "Wallets";
            const string walletFileName      = "wallet_recover_exists_test.json";

            Directory.CreateDirectory(walletDirectoryName);
            using (File.Create(Path.Combine(walletDirectoryName, walletFileName)))
            {
            }

            const string mnemonic = "dash,destroy,twelve,twice,labor,patch,embrace,embody,chronic,inch,install,term";
            var          args     = new[]
            {
                $"wallet-file={walletFileName}",
                $"mnemonic={mnemonic}",
            };
            var password = new SecureString();

            password.AppendChar('p');
            password.AppendChar('a');
            password.AppendChar('s');
            password.AppendChar('s');
            password.AppendChar('w');
            password.AppendChar('o');
            password.AppendChar('r');
            password.AppendChar('d');
            IBitcoinLibrary bitcoinLibrary = new BitcoinLibrary();

            try
            {
                // Act
                bitcoinLibrary.ProcessRecoverWallet(args, password);

                // Should not get here - force a fail if we do
                bitcoinLibrary.Should().BeNull();
            }
            catch (WalletAlreadyExistsException ex)
            {
                // Assert
                ex.Message.Should().Be("The request to generate a wallet failed because the wallet already exists.");
            }

            // Cleanup
            Directory.Delete(walletDirectoryName, true);
            File.Delete(walletFileName);
        }
        public void ProcessShowBalances_ShouldThrowCustomExceptionForAnIncorrectPassword()
        {
            // Arrange
            const string walletContents = "{ \"EncryptedSeed\": \"6PYM714zxNRpmx7WRaCLNJyAreYx2BU5GkbCx5jF5QQNKeZExYqrNHzK8L\",\"ChainCode\": \"CarQU+owbi2iML7Fy5vf+6O0Lpc/V//NFkk7WLVkh70=\",\"Network\": \"Main\",\"CreationTime\": \"2019-07-18\"}";

            const string walletDirectoryName = "Wallets";
            const string walletFileName      = "wallet_show_balances_test.json";
            var          walletFilePath      = Path.Combine(walletDirectoryName, walletFileName);

            Directory.CreateDirectory(walletDirectoryName);
            using (File.Create(walletFilePath))
            {
            }

            var args = new[]
            {
                $"wallet-file={walletFileName}",
            };

            File.WriteAllText(walletFilePath, walletContents);
            File.Exists(walletFilePath).Should().BeTrue();

            var password = new SecureString(); // Incorrect password.

            password.AppendChar('p');
            IBitcoinLibrary bitcoinLibrary = new BitcoinLibrary();

            try
            {
                // Act
                bitcoinLibrary.ShowBalances(args, password);

                // Should not get here - force a fail if we do
                bitcoinLibrary.Should().BeNull();
            }
            catch (IncorrectWalletPasswordException ex)
            {
                // Assert
                ex.Message.Should().Contain("Provided password is incorrect.");
            }

            // Clean up
            Directory.Delete(walletDirectoryName, true);
            File.Delete(walletFileName);
        }
        public void ProcessGenerateWallet_ShouldThrowAnExceptionIfArgumentIsInvalid()
        {
            // Arrange
            var args = new[]
            {
                "wallet-fi=", // Invalid spelling of 'wallet-file'
            };
            var password = new SecureString();

            password.AppendChar('p');
            password.AppendChar('a');
            password.AppendChar('s');
            password.AppendChar('s');
            password.AppendChar('w');
            password.AppendChar('o');
            password.AppendChar('r');
            password.AppendChar('d');

            IBitcoinLibrary bitcoinLibrary = new BitcoinLibrary();

            try
            {
                // Act
                bitcoinLibrary.GenerateWallet(args, password);

                // Should not get here - Force a fail if we do
                bitcoinLibrary.Should().BeNull();
            }
            catch (GenerateWalletFailedException ex)
            {
                // Assert
                ex.Message.Should().Be("Could not generate wallet 'wallet-file' argument is invalid.");
            }
            catch (Exception ex)
            {
                // Should not get here.
                ex.Should().BeNull();
            }

            // Cleanup
            File.Delete("BitcoinWallet.json");
        }
        public void ProcessNextCommand_ShouldReturnTheMnemonicForProcessingGenerateNewWalletCommand()
        {
            // Arrange
            string[] commandsAndArgs =
            {
                "generate-wallet", "wallet-file=BitcoinWallet.json",
                "recover-wallet",  "wallet-file=test1.json",
                "show-balances",   "wallet-file=test1.json",
                "send",            "btc=0.0001",                    "address=mq6fK8fkFyCy9p53m4Gf4fiX2XCHvcwgi1","wallet-file=test1.json",
            };

            IBitcoinLibrary bitcoinLibrary = new BitcoinLibrary();
            var             walletManager  = new WalletManager(bitcoinLibrary);

            walletManager.AddCommands(commandsAndArgs);

            // Act
            var result = walletManager.ProcessNextCommand();

            // Assert
            result.Should().NotBeNullOrEmpty();
        }
        public void AddCommands_ShouldThrowExceptionForNullArguments()
        {
            // Arrange
            // Act
            try
            {
                IBitcoinLibrary bitcoinLibrary = new BitcoinLibrary();
                var             walletManager  = new WalletManager(bitcoinLibrary);
                walletManager.AddCommands(null);

                // Should not get here - Force a fail if we do
                walletManager.Should().BeNull();
            }
            catch (CommandArgumentNullOrEmptyException ex)
            {
                ex.Message.Should().Contain("Argument contains null or empty values.");
            }
            catch (Exception ex)
            {
                // Should not get here
                ex.Should().BeNull();
            }
        }
        public void ProcessRecoverWallet_ShouldThrowCustomExceptionOnInvalidMnemonic()
        {
            // Arrange
            const string walletFileName = "wallet_recover_invalid_mnemonic_test.json";

            var args = new[]
            {
                $"wallet-file={walletFileName}",
                "mnemonic=InvalidMnemonic",
            };
            var password = new SecureString();

            password.AppendChar('p');
            password.AppendChar('a');
            password.AppendChar('s');
            password.AppendChar('s');
            password.AppendChar('w');
            password.AppendChar('o');
            password.AppendChar('r');
            password.AppendChar('d');

            IBitcoinLibrary bitcoinLibrary = new BitcoinLibrary();

            try
            {
                // Act
                bitcoinLibrary.ProcessRecoverWallet(args, password);

                // Should not get here - force a fail if we do
                bitcoinLibrary.Should().BeNull();
            }
            catch (InvalidMnemonicException ex)
            {
                // Assert
                ex.Message.Should().Be("Mnemonic is invalid.");
            }
        }
        public void ProcessShowBalances_ShouldThrowACustomExceptionWhenAGivenWalletIsMissing()
        {
            // Arrange
            const string walletFileName = "wallet_show_balances_test.json";

            var args = new[]
            {
                $"wallet-file={walletFileName}",
            };

            var password = new SecureString();

            password.AppendChar('p');
            password.AppendChar('a');
            password.AppendChar('s');
            password.AppendChar('s');
            password.AppendChar('w');
            password.AppendChar('o');
            password.AppendChar('r');
            password.AppendChar('d');
            IBitcoinLibrary bitcoinLibrary = new BitcoinLibrary();

            try
            {
                // Act
                bitcoinLibrary.ShowBalances(args, password);

                // Should not get here - force a fail if we do
                bitcoinLibrary.Should().BeNull();
            }
            catch (WalletNotFoundException ex)
            {
                // Assert
                ex.Message.Should().Contain("Wallet not found: ");
            }
        }