Example #1
0
        public void SufficientBalanceInAccount_CreatesSuccessfulTransaction()
        {
            // Set Expectations
            var expectedStockAfterTransaction  = 18;
            var expectedAmountAfterTransaction = 4.0m;

            // Arrange
            IInventory inventory = new Inventory();

            inventory.LoadInventory();

            // Use a CashCard with wrong Pin
            var cashCard = new CashCard(9191);

            var account = new Account("TEST Account Number");

            account.Deposit(5.0m);

            // Using the CashCard Vending Machine
            var vendingMachine = new VendingMachine(inventory);

            vendingMachine.PurchasedProduct  = inventory.AllInventories.ElementAt(0).Key;
            vendingMachine.PurchasedQuantity = 2;

            // Act
            vendingMachine.AcceptPayment(account);

            // Assert
            var actualStockAfterTransaction  = inventory.AllInventories.ElementAt(0).Value;
            var actualAmountAfterTransaction = account.Balance;

            Assert.AreEqual(expectedStockAfterTransaction, actualStockAfterTransaction);
            Assert.AreEqual(expectedAmountAfterTransaction, actualAmountAfterTransaction);
        }
Example #2
0
        public void CardNumber_Get_Success()
        {
            CashCard card = new CashCard(100, "12345678");


            Assert.AreEqual(card.CardNumber, "12345678");
        }
Example #3
0
        public void Can_withdraw_multiple_amounts_simultaneously()
        {
            var pinValidationService = Substitute.For <IPinValidationService>();

            pinValidationService.IsPinCorrect(Arg.Any <EncryptedPin>(), Arg.Any <string>()).ReturnsForAnyArgs(true)
            .AndDoes(async _ => await Task.Delay(1000));

            var card = new CashCard(TestPin, pinValidationService);

            card.Deposit(100);

            var tf    = new TaskFactory();
            var tasks = new List <Task>();

            for (var i = 1; i <= 4; i++)
            {
                tasks.Add(tf.StartNew(() =>
                {
                    var resp = card.Withdraw(10, TestPin);
                    Assert.That(resp.Status, Is.EqualTo(WithdrawalStatus.Successful));
                }));
            }

            Task.WaitAll(tasks.ToArray());

            // One final one to ensure we end up with the right value
            var response = card.Withdraw(10, TestPin);

            Assert.That(response.Status, Is.EqualTo(WithdrawalStatus.Successful));
            Assert.That(response.ErrorMessage, Is.EqualTo(""));
            Assert.That(card.Balance, Is.EqualTo(50));
        }
Example #4
0
        public void Can_create_new_card()
        {
            var card = new CashCard(TestPin, _pinValidationService);

            Assert.That(card.Balance, Is.EqualTo(0));
            Assert.That(card.Pin.PinsMatch(TestPin));
        }
Example #5
0
        public static void Main()
        {
            var vendingMachine = new Domain.VendingMachine();
            var cashCard       = new CashCard(13.25M);

            Console.WriteLine("Welcome to the vending machine simulator!");
            Console.WriteLine("Dont forget to read the \"ReadMe.txt\"" + Environment.NewLine);

            while (true)
            {
                Console.WriteLine("Press any key to try and buy a soft drink or type \"exit\" to leave.");

                var entry = Console.ReadLine();

                if (string.Equals(entry, "exit", StringComparison.InvariantCultureIgnoreCase))
                {
                    break;
                }

                var result = vendingMachine.BuyCan(cashCard);

                if (result.IsPurchased)
                {
                    Console.WriteLine("You have purchased a soft drink, here it is: " + result.SoftDrink.GetHashCode());
                }
                else
                {
                    Console.WriteLine("Unable to purchase a soft drink, the error message is: " + result.ErrorMessage);
                }
            }
        }
Example #6
0
        public async Task CanWithDrawAndTopupFromMultiplePlacesSameTime()
        {
            var cashCard   = new CashCard(GetMockValidator(), MOCK_CARDNUMBER);
            var prebalance = cashCard.Balance;
            await cashCard.TopupBalance(MOCK_PIN, 2300M);

            Assert.AreEqual(cashCard.Balance, decimal.Add(prebalance, 2300M));

            List <Task> tasksArray = new List <Task>();

            int totalCounter = 100;

            for (int index = 1; index <= totalCounter; index++)
            {
                if (index % 5 == 0)
                {
                    tasksArray.Add(Task.Factory.StartNew(async() => { await cashCard.Withdraw(MOCK_PIN, 500M); }));
                }
                else
                {
                    tasksArray.Add(Task.Factory.StartNew(async() => { await cashCard.TopupBalance(MOCK_PIN, 200M); }));
                }
            }

            var task = Task.Factory.ContinueWhenAll(tasksArray.ToArray(),
                                                    innerTasks =>
            {
                foreach (var innerTask in innerTasks)
                {
                    Assert.That(innerTask.IsFaulted, Is.False);
                }
                Assert.AreEqual(cashCard.Balance, 6000M);
            });
        }
Example #7
0
        public Account GetAccount(CashCard cashCard)
        {
            log.Info($"Get account for cash card with id {cashCard.Id}");
            var account = _accountRepository.GetAccount(cashCard);

            return(account ?? throw new NoDataFoundException <Account>());
        }
        public async void MultipleSimultaneousWithdrawTransactions()
        {
            // Arrange
            var cashCard = new CashCard(_testsFixture.MockPinService.Object, 1, 5m);

            // Act
            var withdrawTask1 = Task.Run(() => { return(cashCard.WithdrawCash(1234, 5m)); });
            var withdrawTask2 = Task.Run(() => { return(cashCard.WithdrawCash(1234, 5m)); });
            var withdrawTask3 = Task.Run(() => { return(cashCard.WithdrawCash(1234, 5m)); });

            await Task.WhenAll(withdrawTask1, withdrawTask2, withdrawTask3);

            // Assert
            // Check that we received exactly 2 rejections for insufficient balance from the 3 operations
            var rejectionReasons = new List <RejectionReasonEnum?>()
            {
                withdrawTask1.Result.RejectionReason, withdrawTask2.Result.RejectionReason, withdrawTask3.Result.RejectionReason
            };

            Assert.Single(rejectionReasons.Where(x => x == null));
            Assert.Equal(2, rejectionReasons.Where(x => x == RejectionReasonEnum.InsufficientBalance).Count());

            Assert.Equal(0m, withdrawTask1.Result.RemainingBalance);
            Assert.Equal(0m, withdrawTask2.Result.RemainingBalance);
            Assert.Equal(0m, withdrawTask3.Result.RemainingBalance);
        }
        public void Buy_2_Cans_With_Sufficient_Fund_With_Correct_Pin_And_MultiTHreaded_Should_Return_23_Cans_Vending_Machine()
        {
            // Arrange
            _user = new User(_cashCardA, _cashCardB);

            // Act
            _user.CashCardA.BankAccount.Deposit(5);

            // Person 1
            Thread withdraw1 = new Thread(param =>
            {
                CashCard cashCard = param as CashCard;
                BuyCansWithCorrectPin(1, cashCard);
            });

            // Person 2
            Thread withdraw2 = new Thread(param =>
            {
                CashCard cashCard = param as CashCard;
                BuyCansWithCorrectPin(1, cashCard);
            });

            Console.WriteLine("Balance = {0:c}", _user.CashCardA.BankAccount.Balance);
            withdraw1.Start(_user.CashCardA);
            withdraw2.Start(_user.CashCardB);

            withdraw1.Join();
            withdraw2.Join();
            Console.WriteLine("Balance = {0:c}", _user.CashCardA.BankAccount.Balance);

            // Assert
            Assert.AreEqual(23, _vendingMachine.CansInventory);
        }
        /// <summary>
        /// Withdraw amount from an account.
        /// </summary>
        /// <param name="account">Amount to be withdrawn</param>
        /// <param name="amount">Account to be withdrawn from.</param>
        ///
        public void WithDraw(CashCard cashCard, decimal amount)
        {
            if (amount < 0)
            {
                log.Error($"Negative withdrawal of amount {amount} attempted by cash card id {cashCard.Id}");
                throw new ArgumentException("Amount to withdraw cannot be negative");
            }

            if (amount == 0) //Nothing to withdraw
            {
                return;
            }

            lock (accountLock)
            {
                //Get account for a cash card
                var account = _accountService.GetAccount(cashCard);

                if (account.Balance >= amount)
                {
                    account.Balance = account.Balance - amount;
                }
                else //If balance is less than amount requested for withdrawal then raise InsufficientBalanceException
                {
                    log.Info($"Insufficient balance when withdrawing amount {amount} from cash card with id {cashCard.Id}");
                    throw new InsufficientBalanceException()
                          {
                              Balance = account.Balance, AmountRequested = amount
                          };
                }

                _accountService.UpdateAccount(account);
            }
        }
Example #11
0
        /// <summary>
        /// Gets Account balance for given cash card linked to an account.
        /// </summary>
        /// <param name="cashCard"></param>
        /// <returns></returns>
        /// <exception cref="CSTechTest.Repository.Exceptions.NoDataFoundException"></exception>
        public decimal GetBalance(CashCard cashCard)
        {
            log.Info($"Getting account balance from cash card with id {cashCard.Id}");
            var account = _accountService.GetAccount(cashCard);

            return(account.Balance);
        }
Example #12
0
        public void InsufficientBalanceInAccount_ThrowsException()
        {
            // Arrange
            IInventory inventory = new Inventory();

            inventory.LoadInventory();

            // Use a CashCard with wrong Pin
            var cashCard = new CashCard(9191);

            var account = new Account("TEST Account Number");

            account.Deposit(0.5m);

            // Using the CashCard Vending Machine
            var vendingMachine = new VendingMachine(inventory);

            vendingMachine.PurchasedProduct = new Product {
                ProductId = 1, Cost = 0.5m
            };
            vendingMachine.PurchasedQuantity = 2;

            // Act
            vendingMachine.AcceptPayment(account);

            // Assert
            // Throws an exception
        }
Example #13
0
        public void Cannot_withdraw_more_than_balance_with_multiple_simultaneous_requests()
        {
            var pinValidationService = Substitute.For <IPinValidationService>();

            pinValidationService.IsPinCorrect(Arg.Any <EncryptedPin>(), Arg.Any <string>()).ReturnsForAnyArgs(true)
            .AndDoes(async _ => await Task.Delay(1500));

            var card = new CashCard(TestPin, pinValidationService);

            card.Deposit(25);

            var tf        = new TaskFactory();
            var tasks     = new List <Task>();
            var responses = new List <WithdrawalStatus>();

            for (var i = 1; i <= 4; i++)
            {
                tasks.Add(tf.StartNew(() =>
                {
                    var resp = card.Withdraw(10, TestPin);
                    responses.Add(resp.Status);
                }));
            }

            Task.WaitAll(tasks.ToArray());
            Assert.That(responses.Count(r => r == WithdrawalStatus.Successful), Is.EqualTo(2));
            Assert.That(responses.Count(r => r == WithdrawalStatus.InsufficientFunds), Is.EqualTo(2));

            Assert.That(card.Balance, Is.EqualTo(5));
        }
Example #14
0
        public void TopupMoney_SingleTopUp_Success()
        {
            CashCard card = new CashCard(100, "12345678");

            bool Success = card.Topup(1234, 50);

            Assert.AreEqual(card.Balance(1234), 150);
        }
Example #15
0
        public void WithdrawMoney_NegativeAmount_Success()
        {
            CashCard card = new CashCard(100, "12345678");

            bool Success = card.Withdraw(1234, -50);

            Assert.AreEqual(card.Balance(1234), 100);
        }
Example #16
0
        public void WithDrawal_Failed_On_Invalid_Pin()
        {
            var      initBalance = 100;
            IAccount account     = new CashAccount("1234123412341234", initBalance);
            ICard    card        = new CashCard(account, 1234);

            var retVal = card.WithDraw(9999, 5);
        }
 public async Task CanTopupArbitraryAmount()
 {
     var cashCard = new CashCard(GetMockValidator(),MOCK_CARDNUMBER);
     var prebalance = cashCard.Balance;
     var result = await cashCard.TopupBalance(MOCK_PIN, 200M);
     Assert.That(result, Is.True);
     Assert.AreEqual(decimal.Add(prebalance, 200M), cashCard.Balance);
 }
Example #18
0
        public void WithDraw_Failed_On_Insufficient_Fund()
        {
            IAccount account = new CashAccount("1234123412341234", 100);
            ICard    card    = new CashCard(account, 1234);
            var      retVal  = card.WithDraw(1234, 200);

            Assert.IsFalse(retVal == 0);
        }
Example #19
0
        public void WithDraw_Successful_On_Sufficient_Fund()
        {
            IAccount account = new CashAccount("1234123412341234", 100);
            ICard    card    = new CashCard(account, 1234);
            var      retVal  = card.WithDraw(1234, 5);

            Assert.IsTrue(retVal == 0);
        }
Example #20
0
        public void CardDeductMethodIsThreadSafe()
        {
            var          card   = new CashCard(100000);
            Action <int> deduct = x => { card.Deduct(10); };

            Parallel.For(0, 10000, deduct);
            Assert.AreEqual(0, card.Balance);
        }
Example #21
0
        public void WithdrawMoney_FundsNotAvailable_Failure()
        {
            CashCard card = new CashCard(100, "12345678");

            bool Success = card.Withdraw(1234, 150);

            Assert.AreEqual(card.Balance(1234), 100);
        }
Example #22
0
        public void CardTopUpIsThreadSafe()
        {
            var          card   = new CashCard(0);
            Action <int> deduct = x => { card.TopUp(10); };

            Parallel.For(0, 10000, deduct);
            Assert.AreEqual(100000, card.Balance);
        }
        public Account GetAccount(CashCard cashCard)
        {
            var account =
                MemoryCache.Default.SingleOrDefault(x => (x.Value is Account) &&
                                                    (x.Value as Account).CashCards.Exists(y => y.Id.Equals(cashCard.Id, StringComparison.InvariantCultureIgnoreCase))).Value as Account;

            return(account);
        }
Example #24
0
        public void CardTopUpNonThreadSafe()
        {
            var          card   = CashCard.CreateNonThreadSafeMock(0);
            Action <int> deduct = x => { card.TopUp(10); };

            Parallel.For(0, 10000, deduct);
            Assert.AreNotEqual(100000, card.Balance);
        }
Example #25
0
        public void TopupMoney_InvalidPin_Success()
        {
            CashCard card = new CashCard(100, "12345678");


            bool Success = card.Topup(1111, 50);

            Assert.AreEqual(card.Balance(1234), 100);
        }
 public async Task TopupFailOnFailedPinVerification()
 {
     int invalidPin = MOCK_PIN + 900; 
     var cashCard = new CashCard(GetMockValidator(), MOCK_CARDNUMBER);
     var prebalance = cashCard.Balance;
     var result = await cashCard.TopupBalance(invalidPin, 200M);
     Assert.That(result, Is.False);
     Assert.AreEqual(prebalance, cashCard.Balance);
 }
Example #27
0
        public async Task WithdrawFailOnNegativeDecimalAmount()
        {
            var cashCard   = new CashCard(GetMockValidator(), MOCK_CARDNUMBER);
            var prebalance = cashCard.Balance;
            var result     = await cashCard.Withdraw(MOCK_PIN, -1M);

            Assert.That(result, Is.False);
            Assert.AreEqual(0M, cashCard.Balance);
        }
Example #28
0
        public void NewCashCardBalanceStartFromZero()
        {
            int invalidPin = MOCK_PIN + 1;
            var cashCard   = new CashCard(GetMockValidator(), MOCK_CARDNUMBER);

            var prebalance = cashCard.Balance;

            Assert.AreEqual(prebalance, 0.00M);
        }
Example #29
0
        public async Task TopUpFailOnMaxDecimalAmount()
        {
            var cashCard   = new CashCard(GetMockValidator(), MOCK_CARDNUMBER);
            var prebalance = cashCard.Balance;
            var result     = await cashCard.TopupBalance(MOCK_PIN, decimal.MaxValue);

            Assert.That(result, Is.False);
            Assert.AreEqual(prebalance, cashCard.Balance);
        }
Example #30
0
        public void WithDrawal_Successful_On_Valid_Pin()
        {
            var      initBalance = 100;
            IAccount account     = new CashAccount("1234123412341234", initBalance);
            ICard    card        = new CashCard(account, 1234);
            var      retVal      = card.WithDraw(1234, 5);

            Assert.IsTrue(retVal == 0);
        }
Example #31
0
    public CashCard HighestCashCard()
    {
        CashCard result = new CashCard("TempCamel", -10);

        foreach (var card in cashCards)
        {
            if (card.equity > result.equity)
            {
                result = card;
            }
        }

        return result;
    }
Example #32
0
    public void FindEquityCashCard(List<CashCard> cashCards)
    {
        for (int i = 0; i < cashCards.Count; i++)
        {
            float equity = 0;

            equity += cashCards[i].winForFirst * rankCounts.GetRankCount(cashCards[i].camel).GetPercent(RankPosition.First);
            equity += cashCards[i].winForSecond * rankCounts.GetRankCount(cashCards[i].camel).GetPercent(RankPosition.Second);
            equity += cashCards[i].lostForOthers * rankCounts.GetRankCount(cashCards[i].camel).GetPercent(RankPosition.Third);
            equity += cashCards[i].lostForOthers * rankCounts.GetRankCount(cashCards[i].camel).GetPercent(RankPosition.Fourth);
            equity += cashCards[i].lostForOthers * rankCounts.GetRankCount(cashCards[i].camel).GetPercent(RankPosition.Fifth);

            cashCards[i] = new CashCard(cashCards[i].camel, cashCards[i].winForFirst, equity);
        }
    }