public async Task AddTransfer_WithInvalidArguments_ShouldFail()
 {
     var addTransactionCommandFaker = new Common.Fakers.AddTransactionCommandFaker();
     await Assert.ThrowsAsync <ArgumentException>(async() =>
                                                  await transactionRepository.Add(
                                                      addTransactionCommandFaker
                                                      .RuleFor(ta => ta.CreditsChange, 0m)
                                                      .Generate()));
 }
        public async Task AddTransfer_ToUnknownAccount_ShouldFail()
        {
            var addTransactionCommandFaker = new Common.Fakers.AddTransactionCommandFaker()
                                             .RuleFor(ta => ta.UserId, UserId)
                                             .RuleFor(ta => ta.AccountId, Account.ExternalId);

            var addTransactionCommand = addTransactionCommandFaker.Generate();

            await Assert.ThrowsAsync <AccountNotFoundException>(async() =>
                                                                await transactionRepository.Add(addTransactionCommand));
        }
        public async Task AddTransfer_BetweenSameAccounts_ShouldFail()
        {
            var addTransactionCommandFaker = new Common.Fakers.AddTransactionCommandFaker()
                                             .RuleFor(ta => ta.UserId, UserId)
                                             .RuleFor(ta => ta.AccountId, Account.ExternalId)
                                             .RuleFor(ta => ta.OtherAccountId, Account.ExternalId);

            var addTransactionCommand = addTransactionCommandFaker.Generate();

            await Assert.ThrowsAsync <TransactionBetweenSameAccountsException>(async() =>
                                                                               await transactionRepository.Add(addTransactionCommand));
        }
        public async Task AddTransfer_TakingCreditsFromOtherAccount_ShouldFail()
        {
            var addTransactionCommandFaker = new Common.Fakers.AddTransactionCommandFaker()
                                             .RuleFor(ta => ta.UserId, UserId)
                                             .RuleFor(ta => ta.AccountId, Account.ExternalId)
                                             .RuleFor(ta => ta.OtherAccountId, OtherAccount.ExternalId)
                                             .RuleFor(ta => ta.CreditsChange, f => f.Random.Money(+1m, +50m));

            var addTransactionCommand = addTransactionCommandFaker.Generate();

            await Assert.ThrowsAsync <DebetFromOtherAccountNotAllowedException>(async() =>
                                                                                await transactionRepository.Add(addTransactionCommand));
        }
        public async Task Add_ShouldSucceed()
        {
            var addTransactionCommandFaker = new Common.Fakers.AddTransactionCommandFaker();
            var addTransactionCommand      = addTransactionCommandFaker.Generate();

            var mockTransactionRepository = new Mock <ITransactionRepository>();

            TransactionCommandHandler transactionCommandHandler = new TransactionCommandHandler(mockTransactionRepository.Object);
            await transactionCommandHandler.HandleAsync(addTransactionCommand);

            mockTransactionRepository.Verify(tr => tr.Add(It.Is <AddTransactionCommand>(ta => ta.IsDeepEqual(addTransactionCommand))));
            mockTransactionRepository.VerifyNoOtherCalls();
        }
        public async Task AddTransfer_BelowMinimumCredits_ShouldFail()
        {
            var addTransactionCommandFaker = new Common.Fakers.AddTransactionCommandFaker()
                                             .RuleFor(ta => ta.UserId, UserId)
                                             .RuleFor(ta => ta.AccountId, Account.ExternalId)
                                             .RuleFor(ta => ta.OtherAccountId, OtherAccount.ExternalId)
                                             .RuleFor(ta => ta.CreditsChange, f =>
                                                      f.Random.Money(-Account.Credits + Account.MinimumCredits - 0.01m, -Account.Credits + Account.MinimumCredits - 50m));

            var addTransactionCommand = addTransactionCommandFaker.Generate();

            await Assert.ThrowsAsync <AccountCreditsInsufficientException>(async() =>
                                                                           await transactionRepository.Add(addTransactionCommand));
        }
        public async Task AddTransfer_WithSameTransactionId_ShouldFail()
        {
            var addTransactionCommandFaker = new Common.Fakers.AddTransactionCommandFaker()
                                             .RuleFor(ta => ta.UserId, UserId)
                                             .RuleFor(ta => ta.AccountId, Account.ExternalId)
                                             .RuleFor(ta => ta.OtherAccountId, OtherAccount.ExternalId);

            var transaction1 = addTransactionCommandFaker.Generate();
            var transaction2 = addTransactionCommandFaker
                               .RuleFor(ta => ta.TransactionId, transaction1.TransactionId)
                               .Generate();

            await transactionRepository.Add(transaction1);

            await Assert.ThrowsAsync <DatabaseException>(async() =>
                                                         await transactionRepository.Add(transaction2));
        }
        public async Task AddTransfer_ShouldSucceed()
        {
            var addTransactionCommandFaker = new Common.Fakers.AddTransactionCommandFaker()
                                             .RuleFor(ta => ta.UserId, UserId)
                                             .RuleFor(ta => ta.AccountId, Account.ExternalId)
                                             .RuleFor(ta => ta.OtherAccountId, OtherAccount.ExternalId);

            var addTransactionCommand = addTransactionCommandFaker.Generate();
            await transactionRepository.Add(addTransactionCommand);

            var account2 = await dbContext.Accounts.FindAsync(Account.Id);

            Assert.Equal(addTransactionCommand.DateTimeUtc, account2.LastChangeUtc);
            Assert.Equal(Account.Credits + addTransactionCommand.CreditsChange, account2.Credits);

            var transaction = await dbContext.Transactions
                              .Where(t => t.AccountId == account2.Id)
                              .OrderByDescending(t => t.Id)
                              .FirstAsync();

            Assert.Equal(addTransactionCommand.CreditsChange, transaction.CreditsChange);
            Assert.Equal(Account.Credits + addTransactionCommand.CreditsChange, transaction.CreditsNew);
            Assert.Equal(addTransactionCommand.TransactionId, transaction.ExternalId);
            Assert.Equal(addTransactionCommand.Description, transaction.Description);
            Assert.Equal(addTransactionCommand.DateTimeUtc, transaction.DateTimeUtc);

            var otherAccount2 = await dbContext.Accounts.FindAsync(OtherAccount.Id);

            Assert.Equal(addTransactionCommand.DateTimeUtc, otherAccount2.LastChangeUtc);
            Assert.Equal(OtherAccount.Credits - addTransactionCommand.CreditsChange, otherAccount2.Credits);

            var otherTransaction = await dbContext.Transactions
                                   .Where(t => t.AccountId == otherAccount2.Id)
                                   .OrderByDescending(t => t.Id)
                                   .FirstAsync();

            Assert.Equal(-addTransactionCommand.CreditsChange, otherTransaction.CreditsChange);
            Assert.Equal(OtherAccount.Credits - addTransactionCommand.CreditsChange, otherTransaction.CreditsNew);
            Assert.Equal(addTransactionCommand.TransactionId, otherTransaction.ExternalId);
            Assert.Equal(addTransactionCommand.Description, otherTransaction.Description);
            Assert.Equal(addTransactionCommand.DateTimeUtc, otherTransaction.DateTimeUtc);

            Assert.Equal(transaction.Id, otherTransaction.PrimaryTransactionId);
        }