public void GetConfirmationType_WithInvalidBlockEventType_ShouldThrow()
 {
     Assert.Throws <ArgumentOutOfRangeException>(
         "eventType",
         () => FakeConfirmationWatcher.GetConfirmationType((BlockEventType)100)
         );
 }
        public Task ExecuteAsync_ConfirmationUpdateAsyncReturnTrue_ShouldRemoveThatWatch(BlockEventType eventType)
        {
            return(AsynchronousTesting.WithCancellationTokenAsync(async cancellationToken =>
            {
                // Arrange.
                var watch1 = new TransactionWatch <object>(null, TestBlock.Regtest0.GetHash(), uint256.One);
                var watch2 = new TransactionWatch <object>(null, TestBlock.Regtest1.GetHash(), uint256.One);
                var watches = new[] { watch1, watch2 };

                var confirmationType = FakeConfirmationWatcher.GetConfirmationType(eventType);

                this.handler.Setup(h => h.GetCurrentWatchesAsync(It.IsAny <CancellationToken>()))
                .Returns(Task.FromResult <IEnumerable <TransactionWatch <object> > >(watches));

                this.handler.Setup(h => h.ConfirmationUpdateAsync(watch1, 2, confirmationType, It.IsAny <CancellationToken>()))
                .Returns(Task.FromResult(false));
                this.handler.Setup(h => h.ConfirmationUpdateAsync(watch2, 1, confirmationType, It.IsAny <CancellationToken>()))
                .Returns(Task.FromResult(true));

                this.blocks.Setup(b => b.GetAsync(TestBlock.Regtest0.GetHash(), It.IsAny <CancellationToken>()))
                .Returns(Task.FromResult((TestBlock.Regtest0, 0)));
                this.blocks.Setup(b => b.GetAsync(TestBlock.Regtest1.GetHash(), It.IsAny <CancellationToken>()))
                .Returns(Task.FromResult((TestBlock.Regtest1, 1)));

                // Act.
                await this.subject.ExecuteAsync(TestBlock.Regtest1, 1, eventType, cancellationToken);

                // Assert.
                this.handler.Verify(
                    h => h.ConfirmationUpdateAsync(
                        watch1,
                        2,
                        confirmationType,
                        CancellationToken.None
                        ),
                    Times.Once()
                    );

                this.handler.Verify(
                    h => h.ConfirmationUpdateAsync(
                        watch2,
                        1,
                        confirmationType,
                        CancellationToken.None
                        ),
                    Times.Once()
                    );

                this.handler.Verify(
                    h => h.RemoveCompletedWatchesAsync(
                        new[] { watch2 },
                        CancellationToken.None
                        ),
                    Times.Once()
                    );
            }));
        }
        public Task ExecuteAsync_GetCurrentWatchesAsyncReturnNonEmptyList_ShouldInvokeConfirmationUpdateAsync(BlockEventType eventType)
        {
            return(AsynchronousTesting.WithCancellationTokenAsync(async cancellationToken =>
            {
                // Arrange.
                var confirmationType = FakeConfirmationWatcher.GetConfirmationType(eventType);
                var block0 = TestBlock.Regtest0;
                var block1 = TestBlock.Regtest1;
                var ctx1 = new object();
                var ctx2 = new object();
                var ctx3 = new object();
                var watch1 = new BalanceWatch <object, int>(ctx1, block0.GetHash(), block0.Transactions[0].GetHash(), TestAddress.Regtest1, 10);
                var watch2 = new BalanceWatch <object, int>(ctx2, block1.GetHash(), block1.Transactions[0].GetHash(), TestAddress.Regtest1, -10);
                var watch3 = new BalanceWatch <object, int>(ctx3, block1.GetHash(), block1.Transactions[0].GetHash(), TestAddress.Regtest2, 5);
                var watches = new[] { watch1, watch2, watch3 };

                this.handler.Setup(h => h.GetBalanceChangesAsync(It.IsAny <Transaction>(), It.IsAny <CancellationToken>()))
                .ReturnsAsync(new Dictionary <BitcoinAddress, BalanceChange <object, int> >());

                this.handler.Setup(h => h.GetCurrentWatchesAsync(It.IsAny <CancellationToken>()))
                .ReturnsAsync(watches);

                this.handler.Setup(h => h.ConfirmationUpdateAsync(It.Is <BalanceConfirmation <object, int> >(c => c.Address == TestAddress.Regtest1), 1, confirmationType, It.IsAny <CancellationToken>()))
                .ReturnsAsync(true);

                this.blocks.Setup(b => b.GetAsync(block0.GetHash(), It.IsAny <CancellationToken>()))
                .ReturnsAsync((block0, 0));

                this.blocks.Setup(b => b.GetAsync(block1.GetHash(), It.IsAny <CancellationToken>()))
                .ReturnsAsync((block1, 1));

                // Act.
                await this.subject.ExecuteAsync(block1, 1, eventType, cancellationToken);

                // Assert.
                this.handler.Verify(
                    h => h.GetCurrentWatchesAsync(cancellationToken),
                    Times.Once()
                    );

                this.handler.Verify(
                    h => h.ConfirmationUpdateAsync(
                        It.Is <BalanceConfirmation <object, int> >(
                            c => c.Address == TestAddress.Regtest1 &&
                            c.Changes.Count() == 2 &&
                            c.Changes.Count(bc => bc.Amount == 10 && bc.Confirmation == 2 && bc.Context == ctx1) == 1 &&
                            c.Changes.Count(bc => bc.Amount == -10 && bc.Confirmation == 1 && bc.Context == ctx2) == 1
                            ),
                        1,
                        confirmationType,
                        CancellationToken.None
                        ),
                    Times.Once()
                    );

                this.handler.Verify(
                    h => h.ConfirmationUpdateAsync(
                        It.Is <BalanceConfirmation <object, int> >(
                            c => c.Address == TestAddress.Regtest2 &&
                            c.Changes.Count() == 1 &&
                            c.Changes.Count(bc => bc.Amount == 5 && bc.Confirmation == 1 && bc.Context == ctx3) == 1
                            ),
                        1,
                        confirmationType,
                        CancellationToken.None
                        ),
                    Times.Once()
                    );

                this.handler.Verify(
                    h => h.RemoveCompletedWatchesAsync(
                        It.Is <IEnumerable <BalanceWatch <object, int> > >(
                            l => l.Count() == 2 && l.Contains(watch1) && l.Contains(watch2)
                            ),
                        CancellationToken.None
                        ),
                    Times.Once()
                    );
            }));
        }
        public void GetConfirmationType_WithValidBlockEventType_ShouldSuccess(BlockEventType eventType, ConfirmationType expected)
        {
            var result = FakeConfirmationWatcher.GetConfirmationType(eventType);

            Assert.Equal(expected, result);
        }