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); }
public void CardNumber_Get_Success() { CashCard card = new CashCard(100, "12345678"); Assert.AreEqual(card.CardNumber, "12345678"); }
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)); }
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)); }
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); } } }
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); }); }
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); } }
/// <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); }
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 }
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)); }
public void TopupMoney_SingleTopUp_Success() { CashCard card = new CashCard(100, "12345678"); bool Success = card.Topup(1234, 50); Assert.AreEqual(card.Balance(1234), 150); }
public void WithdrawMoney_NegativeAmount_Success() { CashCard card = new CashCard(100, "12345678"); bool Success = card.Withdraw(1234, -50); Assert.AreEqual(card.Balance(1234), 100); }
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); }
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); }
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); }
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); }
public void WithdrawMoney_FundsNotAvailable_Failure() { CashCard card = new CashCard(100, "12345678"); bool Success = card.Withdraw(1234, 150); Assert.AreEqual(card.Balance(1234), 100); }
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); }
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); }
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); }
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); }
public void NewCashCardBalanceStartFromZero() { int invalidPin = MOCK_PIN + 1; var cashCard = new CashCard(GetMockValidator(), MOCK_CARDNUMBER); var prebalance = cashCard.Balance; Assert.AreEqual(prebalance, 0.00M); }
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); }
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); }
public CashCard HighestCashCard() { CashCard result = new CashCard("TempCamel", -10); foreach (var card in cashCards) { if (card.equity > result.equity) { result = card; } } return result; }
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); } }