stripe-ios/Stripe/StripeiOSTests/STPCardValidatorTest.swift

472 lines
13 KiB
Swift

//
// STPCardValidatorTest.swift
// StripeiOS Tests
//
// Created by Jack Flintermann on 7/24/15.
// Copyright (c) 2015 Stripe, Inc. All rights reserved.
//
import UIKit
import XCTest
@testable@_spi(STP) import Stripe
@testable@_spi(STP) import StripeCore
@testable@_spi(STP) import StripePayments
@testable@_spi(STP) import StripePaymentSheet
@testable@_spi(STP) import StripePaymentsUI
class STPCardValidatorTest: XCTestCase {
static let cardData: [(STPCardBrand, String, STPCardValidationState)] = {
return [
(
.visa,
"4242424242424242",
.valid
),
(
.visa,
"4242424242422",
.incomplete
),
(
.visa,
"4012888888881881",
.valid
),
(
.visa,
"4000056655665556",
.valid
),
(
.mastercard,
"5555555555554444",
.valid
),
(
.mastercard,
"5200828282828210",
.valid
),
(
.mastercard,
"5105105105105100",
.valid
),
(
.mastercard,
"2223000010089800",
.valid
),
(
.amex,
"378282246310005",
.valid
),
(
.amex,
"371449635398431",
.valid
),
(
.discover,
"6011111111111117",
.valid
),
(
.discover,
"6011000990139424",
.valid
),
(
.dinersClub,
"36227206271667",
.valid
),
(
.dinersClub,
"3056930009020004",
.valid
),
(
.JCB,
"3530111333300000",
.valid
),
(
.JCB,
"3566002020360505",
.valid
),
(
.unknown,
"1234567812345678",
.invalid
),
]
}()
func testNumberSanitization() {
let tests = [
["4242424242424242", "4242424242424242"],
["XXXXXX", ""],
["424242424242424X", "424242424242424"],
["X4242", "4242"],
["4242 4242 4242 4242", "4242424242424242"],
]
for test in tests {
XCTAssertEqual(STPCardValidator.sanitizedNumericString(for: test[0]), test[1])
}
}
func testNumberValidation() {
var tests: [(STPCardValidationState, String)] = []
for card in STPCardValidatorTest.cardData {
tests.append((card.2, card.1))
}
tests.append((.valid, "4242 4242 4242 4242"))
tests.append((.valid, "4136000000008"))
let badCardNumbers = [
"0000000000000000",
"9999999999999995",
"1",
"1234123412341234",
"xxx",
"9999999999999999999999",
"42424242424242424242",
"4242-4242-4242-4242",
]
for card in badCardNumbers {
tests.append((.invalid, card))
}
let possibleCardNumbers = ["4242", "5", "3", "", " ", "6011", "4012888888881"]
for card in possibleCardNumbers {
tests.append((.incomplete, card))
}
for test in tests {
let card = test.1
let validationState = STPCardValidator.validationState(
forNumber: card,
validatingCardBrand: true
)
let expected = test.0
if !(validationState == expected) {
XCTFail("Expected \(expected), got \(validationState) for number \(card)")
}
}
XCTAssertEqual(
.incomplete,
STPCardValidator.validationState(forNumber: "1", validatingCardBrand: false)
)
XCTAssertEqual(
.incomplete,
STPCardValidator.validationState(
forNumber: "0000000000000000",
validatingCardBrand: false
)
)
XCTAssertEqual(
.incomplete,
STPCardValidator.validationState(
forNumber: "9999999999999995",
validatingCardBrand: false
)
)
XCTAssertEqual(
.valid,
STPCardValidator.validationState(
forNumber: "0000000000000000000",
validatingCardBrand: false
)
)
XCTAssertEqual(
.valid,
STPCardValidator.validationState(
forNumber: "9999999999999999998",
validatingCardBrand: false
)
)
XCTAssertEqual(
.incomplete,
STPCardValidator.validationState(forNumber: "4242424242424", validatingCardBrand: true)
)
XCTAssertEqual(
.incomplete,
STPCardValidator.validationState(forNumber: nil, validatingCardBrand: true)
)
}
func testBrand() {
for test in STPCardValidatorTest.cardData {
XCTAssertEqual(STPCardValidator.brand(forNumber: test.1), test.0)
}
}
func testLengthsForCardBrand() {
let tests: [(STPCardBrand, Set<Int>)] = [
(.visa, Set([13, 16])),
(.mastercard, Set([16])),
(.amex, Set([15])),
(.discover, Set([16])),
(.dinersClub, Set([14, 16])),
(.JCB, Set([16])),
(.unionPay, Set([16, 19])),
(.unknown, Set([19])),
]
for test in tests {
let lengths = STPCardValidator.lengths(for: test.0) as NSSet
let expected = test.1 as NSSet
if !lengths.isEqual(expected) {
XCTFail("Invalid lengths for brand \(test.0): expected \(expected), got \(lengths)")
}
}
}
func testFragmentLength() {
let tests: [(STPCardBrand, Int)] = [
(.visa, 4),
(.mastercard, 4),
(.amex, 5),
(.discover, 4),
(.dinersClub, 4),
(.JCB, 4),
(.unionPay, 4),
(.unknown, 4),
]
for test in tests {
XCTAssertEqual(STPCardValidator.fragmentLength(for: test.0), test.1)
}
}
func testMonthValidation() {
let tests: [(String, STPCardValidationState)] = [
("", .incomplete),
("0", .incomplete),
("1", .incomplete),
("2", .valid),
("9", .valid),
("10", .valid),
("12", .valid),
("13", .invalid),
("11a", .invalid),
("x", .invalid),
("100", .invalid),
("00", .invalid),
("13", .invalid),
]
for test in tests {
XCTAssertEqual(STPCardValidator.validationState(forExpirationMonth: test.0), test.1)
}
}
func testYearValidation() {
let tests: [(String, String, STPCardValidationState)] = [
("12", "15", .valid),
("8", "15", .valid),
("9", "15", .valid),
("11", "16", .valid),
("11", "99", .valid),
("01", "99", .valid),
("1", "99", .valid),
("00", "99", .invalid),
("12", "14", .invalid),
("7", "15", .invalid),
("12", "00", .invalid),
("13", "16", .invalid),
("12", "2", .incomplete),
("12", "1", .incomplete),
("12", "0", .incomplete),
]
for test in tests {
let state = STPCardValidator.validationState(
forExpirationYear: test.1,
inMonth: test.0,
inCurrentYear: 15,
currentMonth: 8
)
XCTAssertEqual(state, test.2)
}
}
func testCVCLength() {
let tests: [(STPCardBrand, UInt)] = [
(.visa, 3),
(.mastercard, 3),
(.amex, 4),
(.discover, 3),
(.dinersClub, 3),
(.JCB, 3),
(.unionPay, 3),
(.unknown, 4),
]
for test in tests {
let maxCVCLength = STPCardValidator.maxCVCLength(for: test.0)
XCTAssertEqual(maxCVCLength, test.1)
}
}
func testCVCValidation() {
let tests: [(String, STPCardBrand, STPCardValidationState)] = [
("x", .visa, .invalid),
("", .visa, .incomplete),
("1", .visa, .incomplete),
("12", .visa, .incomplete),
("1x3", .visa, .invalid),
("123", .visa, .valid),
("123", .amex, .valid),
("123", .unknown, .valid),
("1234", .visa, .invalid),
("1234", .amex, .valid),
("12345", .amex, .invalid),
]
for test in tests {
let state = STPCardValidator.validationState(forCVC: test.0, cardBrand: test.1)
XCTAssertEqual(state, test.2)
}
}
func testCardValidation() {
// swiftlint:disable:next large_tuple
let tests: [(String, UInt, UInt, String, STPCardValidationState)] = [
(
"4242424242424242",
12,
15,
"123",
.valid
),
(
"4242424242424242",
12,
15,
"x",
.invalid
),
(
"4242424242424242",
12,
15,
"1",
.incomplete
),
(
"4242424242424242",
12,
14,
"123",
.invalid
),
(
"4242424242424242",
21,
15,
"123",
.invalid
),
(
"42424242",
12,
15,
"123",
.incomplete
),
(
"378282246310005",
12,
15,
"1234",
.valid
),
(
"378282246310005",
12,
15,
"123",
.valid
),
(
"378282246310005",
12,
15,
"12345",
.invalid
),
(
"1234567812345678",
12,
15,
"12345",
.invalid
),
]
for test in tests {
let card = STPCardParams()
card.number = test.0
card.expMonth = test.1
card.expYear = test.2
card.cvc = test.3
let state = STPCardValidator.validationState(
forCard: card,
inCurrentYear: 15,
currentMonth: 8
)
if state != test.4 {
XCTFail(
"Wrong validation state for \(String(describing: card.number)). Expected \(test.4), got \(state))"
)
}
}
}
func testCBCFetch() {
STPAPIClient.shared.publishableKey = STPTestingDefaultPublishableKey
let mcExp = expectation(description: "Mastercard/CBC")
let visaExp = expectation(description: "Visa/CBC")
let justVisaExp = expectation(description: "Visa Only")
let paramsExp = expectation(description: "Params")
let emptyParamsExp = expectation(description: "Empty Params")
STPCardValidator.possibleBrands(forNumber: "513130") { result in
let brands = try! result.get()
XCTAssertEqual(brands, [.cartesBancaires, .mastercard])
mcExp.fulfill()
}
STPCardValidator.possibleBrands(forNumber: "455673") { result in
let brands = try! result.get()
XCTAssertEqual(brands, [.cartesBancaires, .visa])
visaExp.fulfill()
}
STPCardValidator.possibleBrands(forNumber: "424242") { result in
let brands = try! result.get()
XCTAssertEqual(brands, [.visa])
justVisaExp.fulfill()
}
let params = STPPaymentMethodCardParams()
params.number = "5131301234"
STPCardValidator.possibleBrands(forCard: params) { result in
let brands = try! result.get()
XCTAssertEqual(brands, [.cartesBancaires, .mastercard])
paramsExp.fulfill()
}
let paramsEmpty = STPPaymentMethodCardParams()
STPCardValidator.possibleBrands(forCard: paramsEmpty) { result in
let brands = try! result.get()
XCTAssertEqual(brands, Set(STPCardBrand.allCases))
emptyParamsExp.fulfill()
}
wait(for: [mcExp, visaExp, justVisaExp, paramsExp, emptyParamsExp], timeout: STPTestingNetworkRequestTimeout)
}
}