public async Task StartPaymentAsync_WithValidCommmand_MapsData()
        {
            var command    = CreateValidAddPaymentCommand();
            var repository = new InMemoryPaymentsRepository(NullLogger <InMemoryPaymentsRepository> .Instance);
            var merchantId = 456;

            var id = await repository.StartPaymentAsync(merchantId, command);

            var result = await repository.GetPaymentDetailsByPaymentIdAsync(id);

            Assert.NotNull(result);
            Assert.Equal(command.Amount, result.Amount);
            Assert.Equal(command.Currency, result.Currency);
            Assert.Equal(CreditCardNumberFormatter.Mask(command.CreditCard.CardNumber), result.MaskedCreditCardNumber);
            Assert.Equal(merchantId, result.MerchantId);
            Assert.Equal(id, result.PaymentId);
            Assert.Equal(PaymentStatus.Started, result.Status);
            Assert.True(result.RequestedDate > DateTime.MinValue);
            Assert.True(!result.ResponseReceivedDate.HasValue);
            Assert.Null(result.BankPaymentId);
        }
        public Task <int> StartPaymentAsync(int merchantId, AddPaymentCommand command)
        {
            // threadsafe id increment because the repository is singleton scope
            var paymentId = Interlocked.Increment(ref _currentId);

            var payment = new PaymentDetails()
            {
                PaymentId = paymentId,
                Amount    = command.Amount,
                Currency  = command.Currency,
                MaskedCreditCardNumber = CreditCardNumberFormatter.Mask(command.CreditCard.CardNumber),
                MerchantId             = merchantId,
                RequestedDate          = DateTime.UtcNow,
                Status = PaymentStatus.Started
            };

            _payments.Add(paymentId, payment);

            _logger.LogDebug("Started payment successfully for merchant {MerchantId}. PaymentId: {PaymentId}", merchantId, paymentId);

            return(Task.FromResult(paymentId));
        }
        public void Mask_WithValidValue_ReturnsMasked(string cardNumber, string expected)
        {
            var result = CreditCardNumberFormatter.Mask(cardNumber);

            Assert.Equal(expected, result);
        }
        public void ToDigitsOnly_WithNonDigits_ReturnsNormalized(string cardNumber, string expected)
        {
            var result = CreditCardNumberFormatter.ToDigitsOnly(cardNumber);

            Assert.Equal(expected, result);
        }
        public void ToDigitsOnly_WhenValid_ReturnsUnchanged(string cardNumber)
        {
            var result = CreditCardNumberFormatter.ToDigitsOnly(cardNumber);

            Assert.Equal(cardNumber, result);
        }