210 lines
6.1 KiB
Swift
210 lines
6.1 KiB
Swift
//
|
|
// Copyright 2022 Signal Messenger, LLC
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
//
|
|
|
|
import XCTest
|
|
@testable import Signal
|
|
|
|
final class DonationPaymentDetailsViewControllerTest: XCTestCase {
|
|
// MARK: - Formatting tests
|
|
|
|
func testFormatCardNumber() {
|
|
// We test this by "round-tripping".
|
|
let testCases: [String] = [
|
|
"",
|
|
// American Express
|
|
"37",
|
|
"3782 ",
|
|
"3782 822463 ",
|
|
"3782 822463 10005",
|
|
"3782 822463 100051234",
|
|
// UnionPay
|
|
"6200 ",
|
|
"6200 0",
|
|
"6200 0000 00",
|
|
"6200 0000 0000 000",
|
|
"6200 0000 0000 0000",
|
|
"6200 0000 0000 0000000",
|
|
// Other types
|
|
"42",
|
|
"4242 4242 ",
|
|
"4242 4242 4242 4242",
|
|
"4242 4242 4242 4242424"
|
|
]
|
|
|
|
for testCase in testCases {
|
|
let reformatted = DonationPaymentDetailsViewController.formatCardNumber(
|
|
unformatted: testCase.asciiDigitsOnly
|
|
)
|
|
XCTAssertEqual(reformatted, testCase)
|
|
}
|
|
}
|
|
|
|
func testFormatExpirationDate() {
|
|
// We test this by "round-tripping".
|
|
let testCases: [String] = [
|
|
"",
|
|
"0",
|
|
"1",
|
|
"2/",
|
|
"9/",
|
|
"01/",
|
|
"02/",
|
|
"10/",
|
|
"11/",
|
|
"12/",
|
|
"1/3",
|
|
"1/9",
|
|
"2/3",
|
|
"2/00",
|
|
"2/34",
|
|
"01/00",
|
|
"01/23",
|
|
"02/00",
|
|
"02/34",
|
|
"10/98",
|
|
"12/34",
|
|
// These cases aren't that important because they're invalid.
|
|
// If these tests fail, that's probably fine.
|
|
// We mostly want to ensure they don't crash.
|
|
"1/345",
|
|
"0/0",
|
|
"0/000"
|
|
]
|
|
|
|
for testCase in testCases {
|
|
let reformatted = DonationPaymentDetailsViewController.formatExpirationDate(
|
|
unformatted: testCase.asciiDigitsOnly
|
|
)
|
|
XCTAssertEqual(reformatted, testCase)
|
|
}
|
|
}
|
|
|
|
// MARK: - Form state tests
|
|
|
|
// Field validity is largely tested elsewhere
|
|
// (for example, the specifics of CVV validation).
|
|
|
|
private static func nextYearTwoDigits() -> String {
|
|
let calendar = Calendar(identifier: .iso8601)
|
|
let currentYear = calendar.component(.year, from: Date())
|
|
let nextYear = currentYear + 1
|
|
return String(String(nextYear).suffix(2))
|
|
}
|
|
|
|
private static func validRawExpiration() -> String {
|
|
" 09 / \(nextYearTwoDigits()) "
|
|
}
|
|
|
|
private func assertFullyValid(
|
|
_ formState: DonationPaymentDetailsViewController.FormState,
|
|
_ message: String = "Form state not fully valid"
|
|
) {
|
|
switch formState {
|
|
case .fullyValid:
|
|
break
|
|
case .invalid, .potentiallyValid:
|
|
XCTFail(message)
|
|
}
|
|
}
|
|
|
|
private func fs(
|
|
cardNumber: String = "4242424242424242",
|
|
isCardNumberFieldFocused: Bool = false,
|
|
expirationDate: String = DonationPaymentDetailsViewControllerTest.validRawExpiration(),
|
|
cvv: String = "123"
|
|
) -> DonationPaymentDetailsViewController.FormState {
|
|
DonationPaymentDetailsViewController.formState(
|
|
cardNumber: cardNumber,
|
|
isCardNumberFieldFocused: isCardNumberFieldFocused,
|
|
expirationDate: expirationDate,
|
|
cvv: cvv
|
|
)
|
|
}
|
|
|
|
func testFormStateFullForm() {
|
|
XCTAssertEqual(fs(cardNumber: "x", cvv: "x"), .invalid(invalidFields: [.cardNumber, .cvv]))
|
|
XCTAssertEqual(fs(cvv: ""), .potentiallyValid)
|
|
XCTAssertEqual(fs(), .fullyValid(.card(.init(
|
|
cardNumber: "4242424242424242",
|
|
expirationMonth: 9,
|
|
expirationTwoDigitYear: UInt8(Self.nextYearTwoDigits())!,
|
|
cvv: "123"
|
|
))))
|
|
}
|
|
|
|
func testFormStateCardNumber() {
|
|
XCTAssertEqual(fs(cardNumber: "x"), .invalid(invalidFields: [.cardNumber]))
|
|
XCTAssertEqual(fs(cardNumber: ""), .potentiallyValid)
|
|
XCTAssertEqual(fs(cardNumber: "123"), .potentiallyValid)
|
|
assertFullyValid(fs(cardNumber: " 4111 1111 1111 1111 "))
|
|
}
|
|
|
|
func testFormStateExpirationDate() {
|
|
let year = Self.nextYearTwoDigits()
|
|
|
|
let invalids: [String] = [
|
|
"x",
|
|
"13\(year)",
|
|
"09\(year)0",
|
|
"009\(year)",
|
|
"13 / \(year)",
|
|
"09 / \(year)0",
|
|
"009 / \(year)",
|
|
"09 / \(year)x",
|
|
"09 / \(year) /",
|
|
"00 / \(year)"
|
|
]
|
|
for expirationDate in invalids {
|
|
XCTAssertEqual(
|
|
fs(expirationDate: expirationDate),
|
|
.invalid(invalidFields: [.expirationDate]),
|
|
expirationDate
|
|
)
|
|
}
|
|
|
|
let potentiallyValids: [String] = [
|
|
"",
|
|
"0",
|
|
"1",
|
|
"09",
|
|
"13",
|
|
"09 /",
|
|
"1 / 3",
|
|
"0 / \(year)"
|
|
]
|
|
for expirationDate in potentiallyValids {
|
|
XCTAssertEqual(
|
|
fs(expirationDate: expirationDate),
|
|
.potentiallyValid,
|
|
expirationDate
|
|
)
|
|
}
|
|
|
|
let fullyValids: [String] = [
|
|
"1\(year)",
|
|
"9\(year)",
|
|
"09\(year)",
|
|
" 12 \(year) ",
|
|
"1 / \(year)",
|
|
"9 / \(year)",
|
|
"09 / \(year)",
|
|
" 12 / \(year) "
|
|
]
|
|
for expirationDate in fullyValids {
|
|
assertFullyValid(fs(expirationDate: expirationDate), expirationDate)
|
|
}
|
|
}
|
|
|
|
func testFormStateCvv() {
|
|
XCTAssertEqual(fs(cvv: "x"), .invalid(invalidFields: [.cvv]))
|
|
XCTAssertEqual(fs(cvv: ""), .potentiallyValid)
|
|
XCTAssertEqual(fs(cvv: "12"), .potentiallyValid)
|
|
assertFullyValid(fs(cvv: " 123 "))
|
|
|
|
let amexCard = "378282246310005"
|
|
XCTAssertEqual(fs(cardNumber: amexCard, cvv: "123"), .potentiallyValid)
|
|
assertFullyValid(fs(cardNumber: amexCard, cvv: " 1234 "))
|
|
}
|
|
}
|