10 | @import PAYJP;
11 |
12 | @interface PAYJPSDKTests : XCTestCase
13 | @end
14 |
15 | @implementation PAYJPSDKTests
16 |
17 | - (void)setUp {
18 | [super setUp];
19 |
20 | PAYJPSDK.publicKey = nil;
21 | PAYJPSDK.locale = nil;
22 | }
23 |
24 | - (void)testValuesSet {
25 | NSString *mockPublicKey = @"publicKey";
26 | NSLocale *mockLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"ja"];
27 |
28 | PAYJPSDK.publicKey = mockPublicKey;
29 | PAYJPSDK.locale = mockLocale;
30 |
31 | XCTAssertEqual(PAYJPSDK.publicKey, mockPublicKey);
32 | XCTAssertEqual(PAYJPSDK.locale.localeIdentifier, mockLocale.localeIdentifier);
33 | }
34 |
35 | @end
36 |
--------------------------------------------------------------------------------
/Tests/Core/PAYJPSDKTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PAYJPSDKTests.swift
3 | // PAYJPTests
4 | //
5 | // Created by Li-Hsuan Chen on 2019/07/24.
6 | // Copyright © 2019 PAY, Inc. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import PAYJP
11 |
12 | class PAYJPSDKTests: XCTestCase {
13 | override func setUp() {
14 | super.setUp()
15 |
16 | PAYJPSDK.publicKey = nil
17 | PAYJPSDK.locale = nil
18 | }
19 |
20 | func testValueSet() {
21 | let mockPublicKey = "publicKey"
22 | let mockLocale = Locale(identifier: "ja")
23 |
24 | PAYJPSDK.publicKey = mockPublicKey
25 | PAYJPSDK.locale = mockLocale
26 |
27 | XCTAssertEqual(PAYJPSDK.publicKey, mockPublicKey)
28 | XCTAssertEqual(PAYJPSDK.locale, mockLocale)
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Tests/Fixtures/cardBrands.json:
--------------------------------------------------------------------------------
1 | {
2 | "card_types_supported": [
3 | "Visa",
4 | "MasterCard",
5 | "JCB",
6 | "American Express",
7 | "Diners Club",
8 | "Discover"
9 | ],
10 | "livemode": false
11 | }
12 |
--------------------------------------------------------------------------------
/Tests/Fixtures/error.json:
--------------------------------------------------------------------------------
1 | {
2 | "error": {
3 | "status": 402,
4 | "message": "Invalid card number",
5 | "param": "card[number]",
6 | "code": "invalid_number",
7 | "type": "card_error"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Tests/Fixtures/invalid_apple_pay_token.json:
--------------------------------------------------------------------------------
1 | {
2 | "error": {
3 | "code": "invalid_apple_pay_token",
4 | "message": "Invalid Apple Pay token.",
5 | "param": "card",
6 | "status": 400,
7 | "type": "client_error"
8 | }
9 | }
--------------------------------------------------------------------------------
/Tests/Fixtures/token.json:
--------------------------------------------------------------------------------
1 | {
2 | "card": {
3 | "address_city": null,
4 | "address_line1": null,
5 | "address_line2": null,
6 | "address_state": null,
7 | "address_zip": null,
8 | "address_zip_check": "unchecked",
9 | "brand": "Visa",
10 | "country": null,
11 | "created": 1475462082,
12 | "customer": null,
13 | "cvc_check": "unchecked",
14 | "exp_month": 12,
15 | "exp_year": 2018,
16 | "fingerprint": "35c45684bce0412a22a515f432d40be8",
17 | "id": "car_202e275bfde8d17eb2e0444ff767",
18 | "last4": "0300",
19 | "livemode": true,
20 | "metadata": {
21 | "foo": "bar"
22 | },
23 | "name": "TARO YAMADA",
24 | "object": "card",
25 | "three_d_secure_status": "verified",
26 | "email": "test@example.com",
27 | "phone": "+819012345678"
28 | },
29 | "created": 1475462082,
30 | "id": "tok_bba03649fecef2d367be6fc28367",
31 | "livemode": true,
32 | "object": "token",
33 | "used": false
34 | }
--------------------------------------------------------------------------------
/Tests/Formatters/CvcFormatterTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CvcFormatterTests.swift
3 | // PAYJPTests
4 | //
5 | // Created by Tadashi Wakayanagi on 2019/07/19.
6 | // Copyright © 2019 PAY, Inc. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import PAYJP
11 |
12 | class CvcFormatterTests: XCTestCase {
13 |
14 | let formatter = CvcFormatter()
15 |
16 | private func testFortmat(cases: [(String?, CardBrand, String?)]) {
17 | for (cvc, brand, formatted) in cases {
18 | let output = formatter.string(from: cvc, brand: brand)
19 | XCTAssertEqual(output, formatted)
20 | }
21 | }
22 |
23 | func testCvcFormat() {
24 | let cases: [(String?, CardBrand, String?)] = [
25 | (nil, .unknown, nil),
26 | (nil, .visa, nil),
27 | (nil, .americanExpress, nil),
28 | ("", .unknown, nil),
29 | ("", .mastercard, nil),
30 | ("", .americanExpress, nil),
31 | ("1", .unknown, "1"),
32 | ("1", .jcb, "1"),
33 | ("1", .americanExpress, "1"),
34 | ("12", .unknown, "12"),
35 | ("12", .dinersClub, "12"),
36 | ("12", .americanExpress, "12"),
37 | ("123", .unknown, "123"),
38 | ("123", .discover, "123"),
39 | ("123", .americanExpress, "123"),
40 | ("1234", .unknown, "1234"),
41 | ("1234", .visa, "123"),
42 | ("1234", .americanExpress, "1234"),
43 | ("12345", .unknown, "1234"),
44 | ("12345", .mastercard, "123"),
45 | ("12345", .americanExpress, "1234"),
46 | ("aaa", .unknown, nil),
47 | ("aaa", .jcb, nil),
48 | ("aaa", .americanExpress, nil)
49 | ]
50 | testFortmat(cases: cases)
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Tests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 2.2.1
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Tests/Networking/Core/ClientInfoTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ClientInfoTests.swift
3 | // PAYJPTests
4 | //
5 | // Created by Tatsuya Kitagawa on 2020/02/06.
6 | // Copyright © 2020 PAY, Inc. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import OHHTTPStubs
11 | @testable import PAYJP
12 |
13 | class ClientInfoTests: XCTestCase {
14 |
15 | func testCreate() {
16 | let clientInfo = ClientInfo.makeInfo()
17 | XCTAssertEqual(clientInfo.bindingsName, "jp.pay.ios")
18 | XCTAssertEqual(clientInfo.platform, "ios")
19 | XCTAssertEqual(clientInfo.bindingsPlugin, nil)
20 | XCTAssertEqual(clientInfo.publisher, "payjp")
21 | }
22 |
23 | func testCreate_plugin() {
24 | let clientInfo = ClientInfo.makeInfo(plugin: "jp.pay.kitagawa/1.0.0", publisher: "kitagawa")
25 | XCTAssertEqual(clientInfo.bindingsName, "jp.pay.ios")
26 | XCTAssertEqual(clientInfo.platform, "ios")
27 | XCTAssertEqual(clientInfo.bindingsPlugin, "jp.pay.kitagawa/1.0.0")
28 | XCTAssertEqual(clientInfo.publisher, "kitagawa")
29 | }
30 |
31 | func testBindingVersion() {
32 | let clientInfo = ClientInfo(
33 | bindingsName: "jp.pay.ios",
34 | bindingsVersion: "1.0.0",
35 | bindingsPlugin: nil,
36 | unameString: "iPhone X",
37 | platform: "ios",
38 | publisher: "payjp")
39 | XCTAssertEqual(clientInfo.bindingInfo, "jp.pay.ios/1.0.0")
40 | }
41 |
42 | func testBindingVersion_withPlugin() {
43 | let clientInfo = ClientInfo(
44 | bindingsName: "jp.pay.ios",
45 | bindingsVersion: "1.0.0",
46 | bindingsPlugin: "jp.pay.kitagawa/1.0.0",
47 | unameString: "iPhone X",
48 | platform: "ios",
49 | publisher: "payjp")
50 | XCTAssertEqual(clientInfo.bindingInfo, "jp.pay.ios/1.0.0@jp.pay.kitagawa/1.0.0")
51 | }
52 |
53 | func testUserAgent() {
54 | let clientInfo = ClientInfo(
55 | bindingsName: "jp.pay.ios",
56 | bindingsVersion: "1.0.0",
57 | bindingsPlugin: nil,
58 | unameString: "iPhone X",
59 | platform: "ios",
60 | publisher: "payjp")
61 | XCTAssertEqual(clientInfo.userAgent, "jp.pay.ios/1.0.0; iPhone X")
62 | }
63 |
64 | func testJson() {
65 | let clientInfo = ClientInfo(
66 | bindingsName: "jp.pay.ios",
67 | bindingsVersion: "1.1.0",
68 | bindingsPlugin: "jp.pay.kitagawa/1.0.0",
69 | unameString: "iPhoneX",
70 | platform: "ios",
71 | publisher: "payjp")
72 | XCTAssertNotNil(clientInfo.json)
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/Tests/Networking/Models/GetAcceptedBrandsResponseTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GetAcceptedBrandsResponseTests.swift
3 | // PAYJPTests
4 | //
5 | // Created by Li-Hsuan Chen on 2019/07/31.
6 | // Copyright © 2019 PAY, Inc. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import PAYJP
11 |
12 | class GetAcceptedBrandsResponseTests: XCTestCase {
13 | func testDecoding() {
14 | let jsonData = """
15 | {"card_types_supported": ["Visa"], "livemode": true}
16 | """.data(using: .utf8)!
17 |
18 | let response = try? JSONDecoder.shared.decode(GetAcceptedBrandsResponse.self, from: jsonData)
19 |
20 | XCTAssertEqual(response?.acceptedBrands.count, 1)
21 | XCTAssertEqual(response?.acceptedBrands.first, .visa)
22 | XCTAssertEqual(response?.liveMode, true)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Tests/Networking/Models/PAYErrorResponseTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PAYErrorResponseTests.swift
3 | // PAYJP
4 | //
5 | // Created by Li-Hsuan Chen on 2018/05/21.
6 | // Copyright © 2018年 PAY, Inc. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | import XCTest
12 | @testable import PAYJP
13 |
14 | class PAYErrorResponseTests: XCTestCase {
15 | var errorResponse: PAYErrorResponse!
16 |
17 | override func setUp() {
18 | let json = TestFixture.JSON(by: "error.json")
19 | let decoder = JSONDecoder.shared
20 | // swiftlint:disable force_try
21 | errorResponse = try! decoder.decode(PAYErrorResult.self, from: json).error
22 | // swiftlint:enable force_try
23 | }
24 |
25 | func testErrorProperties() {
26 | XCTAssertEqual(errorResponse.status, 402)
27 | XCTAssertEqual(errorResponse.message, "Invalid card number")
28 | XCTAssertEqual(errorResponse.param, "card[number]")
29 | XCTAssertEqual(errorResponse.code, "invalid_number")
30 | XCTAssertEqual(errorResponse.type, "card_error")
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Tests/Networking/Models/ThreeDSecureStatusTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ThreeDSecureStatusTests.swift
3 | // PAYJPTests
4 | //
5 | // Created by Tadashi Wakayanagi on 2020/04/02.
6 | // Copyright © 2020 PAY, Inc. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import PAYJP
11 |
12 | class ThreeDSecureStatusTests: XCTestCase {
13 |
14 | func testFind_verified() {
15 | let rawValue = PAYThreeDSecureStatus.verified.rawValue
16 | let status = ThreeDSecureStatus.find(rawValue: rawValue)
17 | XCTAssertEqual(status, PAYThreeDSecureStatus.verified)
18 | }
19 |
20 | func testFind_attempted() {
21 | let rawValue = PAYThreeDSecureStatus.attempted.rawValue
22 | let status = ThreeDSecureStatus.find(rawValue: rawValue)
23 | XCTAssertEqual(status, PAYThreeDSecureStatus.attempted)
24 | }
25 |
26 | func testFind_unverified() {
27 | let rawValue = PAYThreeDSecureStatus.unverified.rawValue
28 | let status = ThreeDSecureStatus.find(rawValue: rawValue)
29 | XCTAssertEqual(status, PAYThreeDSecureStatus.unverified)
30 | }
31 |
32 | func testFind_failed() {
33 | let rawValue = PAYThreeDSecureStatus.failed.rawValue
34 | let status = ThreeDSecureStatus.find(rawValue: rawValue)
35 | XCTAssertEqual(status, PAYThreeDSecureStatus.failed)
36 | }
37 |
38 | func testFind_aborted() {
39 | let rawValue = PAYThreeDSecureStatus.aborted.rawValue
40 | let status = ThreeDSecureStatus.find(rawValue: rawValue)
41 | XCTAssertEqual(status, PAYThreeDSecureStatus.aborted)
42 | }
43 |
44 | func testFind_error() {
45 | let rawValue = PAYThreeDSecureStatus.error.rawValue
46 | let status = ThreeDSecureStatus.find(rawValue: rawValue)
47 | XCTAssertEqual(status, PAYThreeDSecureStatus.error)
48 | }
49 |
50 | func testFind_unknown() {
51 | let rawValue = "unknown"
52 | let status = ThreeDSecureStatus.find(rawValue: rawValue)
53 | XCTAssertNil(status)
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/Tests/Networking/Models/TokenTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TokenTests.swift
3 | // PAYJP
4 | //
5 | // Created by k@binc.jp on 10/3/16.
6 | // Copyright © 2016 PAY, Inc. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import XCTest
11 | @testable import PAYJP
12 |
13 | class TokenTests: XCTestCase {
14 | var token: Token!
15 | var json: Data!
16 |
17 | override func setUp() {
18 | json = TestFixture.JSON(by: "token.json")
19 | let decoder = JSONDecoder.shared
20 | // swiftlint:disable force_try
21 | token = try! Token.decodeJson(with: json, using: decoder)
22 | // swiftlint:enable force_try
23 | }
24 |
25 | func testTokenProperties() {
26 | XCTAssertEqual(token.identifer, "tok_bba03649fecef2d367be6fc28367")
27 | XCTAssertEqual(token.livemode, true)
28 | XCTAssertEqual(token.used, false)
29 | }
30 |
31 | func testCreatedDate() {
32 | XCTAssertEqual(token.createdAt, Date(timeIntervalSince1970: 1475462082))
33 | }
34 |
35 | func testRawObject() {
36 | let rawValue = token.rawValue
37 | XCTAssertEqual(rawValue?.count, 6)
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Tests/Networking/NSErrorConverterTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NSErrorConverter.swift
3 | // PAYJPTests
4 | //
5 | // Created by Tadashi Wakayanagi on 2019/10/07.
6 | // Copyright © 2019 PAY, Inc. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import PAYJP
11 |
12 | class NSErrorConverterTests: XCTestCase {
13 |
14 | let converter = NSErrorConverter()
15 |
16 | func testConvertAPIError() {
17 | let error = APIError.invalidResponse(nil)
18 | let nsError = converter.convert(from: error)
19 | XCTAssertEqual(nsError?.domain, PAYErrorDomain)
20 | XCTAssertEqual(nsError?.code, PAYErrorInvalidResponse)
21 | let description = nsError?.userInfo[NSLocalizedDescriptionKey] as? String
22 | XCTAssertEqual(description, "The response is not a HTTPURLResponse instance.")
23 | }
24 |
25 | func testConvertOtherError() {
26 | let error = NSError(domain: "other", code: 100, userInfo: nil)
27 | let nsError = converter.convert(from: error)
28 | XCTAssertEqual(nsError?.domain, PAYErrorDomain)
29 | XCTAssertEqual(nsError?.code, PAYErrorSystemError)
30 | XCTAssertNotNil(nsError?.userInfo)
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Tests/Networking/Requests/CreateTokenForApplePayRequestTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CreateTokenForApplePayRequestTests.swift
3 | // PAYJPTests
4 | //
5 | // Created by Li-Hsuan Chen on 2019/07/25.
6 | // Copyright © 2019 PAY, Inc. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import PAYJP
11 |
12 | class CreateTokenForApplePayRequestTests: XCTestCase {
13 | func testInitialization() {
14 | let request = CreateTokenForApplePayRequest(paymentToken: "token")
15 |
16 | XCTAssertEqual(request.httpMethod, "POST")
17 | XCTAssertEqual(request.path, "tokens")
18 | XCTAssertEqual(request.bodyParameters?["card"], "token")
19 | XCTAssertNil(request.queryParameters)
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Tests/Networking/Requests/GetAcceptedBrandsTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GetAcceptedBrandsTests.swift
3 | // PAYJPTests
4 | //
5 | // Created by Li-Hsuan Chen on 2019/07/25.
6 | // Copyright © 2019 PAY, Inc. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import PAYJP
11 |
12 | class GetAcceptedBrandsTests: XCTestCase {
13 | func testInitializationWithTenantId() {
14 | let request = GetAcceptedBrands(tenantId: "mock_id")
15 |
16 | XCTAssertEqual(request.httpMethod, "GET")
17 | XCTAssertEqual(request.path, "accounts/brands")
18 | XCTAssertEqual(request.queryParameters?["tenant"] as? String, "mock_id")
19 | }
20 |
21 | func testInitializationWithoutTenantId() {
22 | let request = GetAcceptedBrands(tenantId: nil)
23 |
24 | XCTAssertEqual(request.httpMethod, "GET")
25 | XCTAssertEqual(request.path, "accounts/brands")
26 | XCTAssertNil(request.queryParameters?["tenant"])
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Tests/Networking/Requests/GetTokenRequestTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GetTokenRequestTests.swift
3 | // PAYJPTests
4 | //
5 | // Created by Li-Hsuan Chen on 2019/07/25.
6 | // Copyright © 2019 PAY, Inc. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import PAYJP
11 |
12 | class GetTokenRequestTests: XCTestCase {
13 | func testInitialization() {
14 | let request = GetTokenRequest(tokenId: "mock_id")
15 |
16 | XCTAssertEqual(request.httpMethod, "GET")
17 | XCTAssertEqual(request.path, "tokens/mock_id")
18 |
19 | XCTAssertNil(request.bodyParameters)
20 | XCTAssertNil(request.queryParameters)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Tests/PAYJPTests-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | //
2 | // Use this file to import your target's public headers that you would like to expose to Swift.
3 | //
4 |
5 |
--------------------------------------------------------------------------------
/Tests/PAYJPTests.xctestplan:
--------------------------------------------------------------------------------
1 | {
2 | "configurations" : [
3 | {
4 | "id" : "34338B67-6AB8-4364-B59C-164A6AEBF39F",
5 | "name" : "Test Scheme Action",
6 | "options" : {
7 |
8 | }
9 | }
10 | ],
11 | "defaultOptions" : {
12 | "language" : "en"
13 | },
14 | "testTargets" : [
15 | {
16 | "parallelizable" : true,
17 | "target" : {
18 | "containerPath" : "container:PAYJP.xcodeproj",
19 | "identifier" : "615AFF641C8C74A1003FB86F",
20 | "name" : "PAYJPTests"
21 | }
22 | }
23 | ],
24 | "version" : 1
25 | }
26 |
--------------------------------------------------------------------------------
/Tests/String+PAYJPTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // String+PAYJPTests.swift
3 | // PAYJPTests
4 | //
5 | // Created by Tadashi Wakayanagi on 2019/07/31.
6 | // Copyright © 2019 PAY, Inc. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import PAYJP
11 |
12 | // swiftlint:disable type_name
13 | class String_PAYJPTests: XCTestCase {
14 |
15 | private func testNumberfy(cases: [(String, String)]) {
16 | for (input, expected) in cases {
17 | let filtered = input.numberfy()
18 | XCTAssertEqual(filtered, expected)
19 | }
20 | }
21 |
22 | func testStringToDigitString() {
23 | let cases = [
24 | ("", ""),
25 | ("12", "12"),
26 | ("1234 567", "1234567"),
27 | ("1234 5678 90", "1234567890"),
28 | ("1 @ 234 # 5", "12345")
29 | ]
30 | testNumberfy(cases: cases)
31 | }
32 |
33 | func testLocalizeString() {
34 | XCTAssertEqual("Please enter a card number.", "payjp_card_form_error_no_number".localized)
35 | }
36 |
37 | func testIsDigistOnly() {
38 | XCTAssertTrue("1".isDigitsOnly)
39 | XCTAssertTrue("1234".isDigitsOnly)
40 | XCTAssertFalse("a1".isDigitsOnly)
41 | XCTAssertFalse("abc".isDigitsOnly)
42 | }
43 |
44 | func testCapture() {
45 | let pattern = "^(https?)://([^/]+)/?"
46 | let target = "https://pay.jp/"
47 |
48 | let result = target.capture(pattern: pattern, group: 2)
49 | XCTAssertEqual(result, "pay.jp")
50 | }
51 |
52 | func testCapture_nil() {
53 | let pattern = "^(https?)://([^/]+)/?"
54 | let target = "pay.jp"
55 |
56 | let result = target.capture(pattern: pattern, group: 1)
57 | XCTAssertNil(result)
58 | }
59 |
60 | func testCaptureMulti() {
61 | let pattern = "^(https?)://([^/]+)/?"
62 | let target = "https://pay.jp/"
63 |
64 | let result = target.capture(pattern: pattern, group: [1, 2])
65 | XCTAssertEqual(result[0], "https")
66 | XCTAssertEqual(result[1], "pay.jp")
67 | }
68 |
69 | func testCaptureMulti_empty() {
70 | let pattern = "^(https?)://([^/]+)/?"
71 | let target = "pay.jp"
72 |
73 | let result = target.capture(pattern: pattern, group: [1, 2])
74 | XCTAssertTrue(result.isEmpty)
75 | }
76 | }
77 | // swiftlint:enable type_name
78 |
--------------------------------------------------------------------------------
/Tests/StringProtocol+PAYJPTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StringProtocol+PAYJPTests.swift
3 | // PAYJPTests
4 | //
5 | // Created by Tadashi Wakayanagi on 2019/09/02.
6 | // Copyright © 2019 PAY, Inc. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import PAYJP
11 |
12 | // swiftlint:disable type_name
13 | class StringProtocol_PAYJPTests: XCTestCase {
14 |
15 | func testInsertSpaceWithCount() {
16 | var target = "1234567812345678"
17 | target.insert(separator: " ", every: 4)
18 | XCTAssertEqual(target, "1234 5678 1234 5678")
19 | }
20 |
21 | func testInsertSpaceWithPositions() {
22 | var target = "1234567812345678"
23 | target.insert(separator: " ", positions: [2, 4, 8, 14])
24 | XCTAssertEqual(target, "12 34 5678 123456 78")
25 | }
26 |
27 | func testInsertSlashWithCount() {
28 | var target = "1234"
29 | target.insert(separator: "/", every: 2)
30 | XCTAssertEqual(target, "12/34")
31 | }
32 | }
33 | // swiftlint:enable type_name
34 |
--------------------------------------------------------------------------------
/Tests/StubPaymentToken.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StubPaymentToken.swift
3 | // PAYJP
4 | //
5 | // Created by Li-Hsuan Chen on 2019/07/31.
6 | // Copyright © 2019 PAY, Inc. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import PassKit
11 |
12 | class StubPaymentToken: PKPaymentToken {
13 | // swiftlint:disable force_try
14 | override var paymentData: Data {
15 | let data = TestFixture.JSON(by: "paymentData.json")
16 | let json = try! JSONSerialization.jsonObject(with: data, options: .allowFragments)
17 | return try! JSONSerialization.data(withJSONObject: json, options: .prettyPrinted)
18 | }
19 | // swiftlint:enable force_try
20 | }
21 |
--------------------------------------------------------------------------------
/Tests/TestFixture.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TestHelper.swift
3 | // PAYJP
4 | //
5 | // Created by k@binc.jp on 2017/01/05.
6 | // Copyright © 2017 PAY, Inc. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | struct TestFixture {
12 | private static let bundle = Bundle(identifier: "jp.pay.ios.PAYJPTests")!
13 |
14 | static func JSON(by name: String) -> Data {
15 | let url = self.bundle.url(forResource: name, withExtension: nil, subdirectory: "Fixtures", localization: nil)
16 | // swiftlint:disable force_try
17 | let data = try! Data(contentsOf: url!)
18 | // swiftlint:enable force_try
19 | return data
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Tests/ThreeDSecure/Mock.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Mock.swift
3 | // PAYJP
4 | //
5 | // Created by Tadashi Wakayanagi on 2020/04/06.
6 | // Copyright © 2020 PAY, Inc. All rights reserved.
7 | //
8 |
9 | import SafariServices
10 |
11 | class MockViewController: UIViewController {
12 | var tdsStatus: ThreeDSecureProcessStatus?
13 | var presentedVC: UIViewController?
14 |
15 | override func present(_ viewControllerToPresent: UIViewController,
16 | animated flag: Bool,
17 | completion: (() -> Void)? = nil) {
18 | presentedVC = viewControllerToPresent
19 | }
20 | }
21 |
22 | extension MockViewController: ThreeDSecureProcessHandlerDelegate {
23 | func threeDSecureProcessHandlerDidFinish(_ handler: ThreeDSecureProcessHandler,
24 | status: ThreeDSecureProcessStatus) {
25 | tdsStatus = status
26 | }
27 | }
28 |
29 | class MockSafariViewController: SFSafariViewController {
30 | var dismissCalled: Bool = false
31 |
32 | override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
33 | dismissCalled = true
34 | completion?()
35 | }
36 | }
37 |
38 | class MockThreeDSecureWebDriverDelegate: NSObject, ThreeDSecureWebDriverDelegate {
39 | var webBrowseDidFinishCalled: Bool = false
40 |
41 | func webBrowseDidFinish(_ driver: ThreeDSecureWebDriver) {
42 | webBrowseDidFinishCalled = true
43 | }
44 | }
45 |
46 | class MockWebDriver: ThreeDSecureWebDriver {
47 | var openWebBrowserUrl: URL?
48 | var isSafariVC: Bool = false
49 |
50 | init(isSafariVC: Bool = false) {
51 | self.isSafariVC = isSafariVC
52 | }
53 |
54 | func openWebBrowser(host: UIViewController, url: URL, delegate: ThreeDSecureWebDriverDelegate) {
55 | openWebBrowserUrl = url
56 | }
57 |
58 | func closeWebBrowser(host: UIViewController?, completion: (() -> Void)?) -> Bool {
59 | if isSafariVC {
60 | completion?()
61 | return true
62 | }
63 | return false
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/Tests/ThreeDSecure/ThreeDSecureSFSafariViewControllerDriverTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ThreeDSecureSFSafariViewControllerDriverTests.swift
3 | // PAYJPTests
4 | //
5 | // Created by Tadashi Wakayanagi on 2020/04/06.
6 | // Copyright © 2020 PAY, Inc. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import SafariServices
11 | @testable import PAYJP
12 |
13 | class ThreeDSecureSFSafariViewControllerDriverTests: XCTestCase {
14 |
15 | func testOpenWebBrowser() {
16 | let driver = ThreeDSecureSFSafariViewControllerDriver()
17 | let mockVC = MockViewController()
18 | let mockDelegate = MockThreeDSecureWebDriverDelegate()
19 | let url = URL(string: "https://test")!
20 |
21 | driver.openWebBrowser(host: mockVC, url: url, delegate: mockDelegate)
22 |
23 | XCTAssertTrue(mockVC.presentedVC is SFSafariViewController)
24 | }
25 |
26 | func testCloseWebBrowser() {
27 | let driver = ThreeDSecureSFSafariViewControllerDriver()
28 | let mockVC = MockSafariViewController(url: URL(string: "https://test")!)
29 |
30 | let result = driver.closeWebBrowser(host: mockVC, completion: nil)
31 |
32 | XCTAssertTrue(result)
33 | XCTAssertTrue(mockVC.dismissCalled)
34 | }
35 |
36 | func testCloseWebBrowser_notSafariVC() {
37 | let driver = ThreeDSecureSFSafariViewControllerDriver()
38 | let mockVC = MockViewController()
39 |
40 | let result = driver.closeWebBrowser(host: mockVC, completion: nil)
41 |
42 | XCTAssertFalse(result)
43 | }
44 |
45 | func testWebBrowswDidFinishDelegate() {
46 | let driver = ThreeDSecureSFSafariViewControllerDriver()
47 | let mockVC = MockViewController()
48 | let mockDelegate = MockThreeDSecureWebDriverDelegate()
49 | let url = URL(string: "https://test")!
50 |
51 | driver.openWebBrowser(host: mockVC, url: url, delegate: mockDelegate)
52 | // SafariVCを閉じた場合を想定
53 | driver.safariViewControllerDidFinish(MockSafariViewController(url: url))
54 |
55 | XCTAssertTrue(mockDelegate.webBrowseDidFinishCalled)
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/Tests/ThreeDSecure/ThreeDSecureURLConfigurationTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import PAYJP
3 |
4 | class ThreeDSecureURLConfigurationTests: XCTestCase {
5 | override func setUp() {
6 | super.setUp()
7 |
8 | PAYJPSDK.publicKey = "public_key"
9 | }
10 |
11 | func testMakeThreeDSecureEntryURL() {
12 | let redirectURL = URL(string: "test://")!
13 | let redirectURLKey = "test"
14 | let configuration = ThreeDSecureURLConfiguration(redirectURL: redirectURL, redirectURLKey: redirectURLKey)
15 | let resourceId = "ch_123"
16 | let expectedUrlString = "\(PAYJPApiEndpoint)tds/\(resourceId)/start?publickey=\(PAYJPSDK.publicKey!)&back=\(redirectURLKey)"
17 | let threeDSecureEntryURL = configuration.makeThreeDSecureEntryURL(resourceId: resourceId)
18 |
19 | XCTAssertEqual(threeDSecureEntryURL.absoluteString, expectedUrlString)
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Tests/ThreeDSecure/ThreeDSecureWebViewControllerDriverTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import PAYJP
3 |
4 | final class ThreeDSecureWebViewControllerDriverTests: XCTestCase {
5 | class DummyHostViewController: UIViewController {
6 | var presentedVC: UIViewController?
7 | override func present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)? = nil) {
8 | presentedVC = viewControllerToPresent
9 | completion?()
10 | }
11 | }
12 |
13 | class DummyDelegate: ThreeDSecureWebDriverDelegate {
14 | var didFinishCalled = false
15 | func webBrowseDidFinish(_ driver: ThreeDSecureWebDriver) {
16 | didFinishCalled = true
17 | }
18 | }
19 |
20 | func testOpenWebBrowser_presentsWebViewController() {
21 | let driver = ThreeDSecureWebViewControllerDriver()
22 | let host = DummyHostViewController()
23 | let delegate = DummyDelegate()
24 | let url = URL(string: "https://example.com")!
25 |
26 | driver.openWebBrowser(host: host, url: url, delegate: delegate)
27 | XCTAssertTrue(host.presentedVC is ThreeDSecureWebViewController)
28 | }
29 |
30 | func testCloseWebBrowser_dismissesWebViewController() {
31 | let driver = ThreeDSecureWebViewControllerDriver()
32 | let host = DummyHostViewController()
33 | let delegate = DummyDelegate()
34 | let url = URL(string: "https://example.com")!
35 | driver.openWebBrowser(host: host, url: url, delegate: delegate)
36 | let result = driver.closeWebBrowser(host: nil, completion: nil)
37 | XCTAssertTrue(result)
38 | }
39 |
40 | func testWebViewControllerDidFinish_callsDelegate() {
41 | let driver = ThreeDSecureWebViewControllerDriver()
42 | let host = DummyHostViewController()
43 | let delegate = DummyDelegate()
44 | let url = URL(string: "https://example.com")!
45 | driver.openWebBrowser(host: host, url: url, delegate: delegate)
46 | if let webVC = host.presentedVC as? ThreeDSecureWebViewController {
47 | (driver as? ThreeDSecureWebViewControllerDriver)?.webViewControllerDidFinish(webVC, completed: false)
48 | XCTAssertTrue(delegate.didFinishCalled)
49 | } else {
50 | XCTFail("WebViewController was not presented")
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Tests/ThreeDSecure/ThreeDSecureWebViewControllerTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | import WebKit
3 | @testable import PAYJP
4 |
5 | final class ThreeDSecureWebViewControllerTests: XCTestCase {
6 | func testUserAgentIsSetCorrectly() {
7 | let version = Bundle.payjpBundle.infoDictionary?["CFBundleShortVersionString"] as? String ?? ""
8 | let url = URL(string: "https://example.com")!
9 | let vc = ThreeDSecureWebViewController(url: url)
10 | let exp = expectation(description: "Retrieve UserAgent")
11 |
12 | _ = vc.view
13 |
14 | let webViewMirror = Mirror(reflecting: vc)
15 | guard let webView = webViewMirror.children.first(where: { $0.label == "webView" })?.value as? WKWebView else {
16 | XCTFail("Failed to retrieve webView")
17 | return
18 | }
19 | webView.evaluateJavaScript("navigator.userAgent") { result, error in
20 | guard let userAgent = result as? String else {
21 | XCTFail("Failed to retrieve UserAgent: \(error?.localizedDescription ?? "")")
22 | exp.fulfill()
23 | return
24 | }
25 | XCTAssertTrue(userAgent.contains("PAY.JP iOS WKWebView/\(version)"), "Expected value is not included in UserAgent: \(userAgent)")
26 | exp.fulfill()
27 | }
28 | wait(for: [exp], timeout: 5.0)
29 | }
30 |
31 | func testErrorIsDisplayedInWebView() {
32 | let url = URL(string: "http://invalid.invalid-domain-for-test-404.localhost/")!
33 | let vc = ThreeDSecureWebViewController(url: url)
34 | let exp = expectation(description: "Display error HTML")
35 |
36 | _ = vc.view
37 |
38 | let webViewMirror = Mirror(reflecting: vc)
39 | guard let webView = webViewMirror.children.first(where: { $0.label == "webView" })?.value as? WKWebView else {
40 | XCTFail("Failed to retrieve webView")
41 | return
42 | }
43 |
44 | DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
45 | webView.evaluateJavaScript("document.body.innerHTML") { result, error in
46 | guard let html = result as? String else {
47 | XCTFail("Failed to retrieve HTML: \(error?.localizedDescription ?? "")")
48 | exp.fulfill()
49 | return
50 | }
51 | XCTAssertTrue(html.contains("A server with the specified hostname could not be found."), "Error content is not included in the HTML: \(html)")
52 | exp.fulfill()
53 | }
54 | }
55 | wait(for: [exp], timeout: 10.0)
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/Tests/Validators/CardHolderValidatorTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CardHolderValidatorTests.swift
3 | // PAYJP
4 | //
5 | // Created by Tatsuya Kitagawa on 2024/10/02.
6 | // Copyright © 2024 PAY, Inc. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import PAYJP
11 |
12 | class CardHolderValidatorTests: XCTestCase {
13 | func testCardHolderValidation() {
14 | let validator = CardHolderValidator()
15 | XCTAssertEqual(validator.validate(cardHolder: "JANE DOE"), .valid)
16 | XCTAssertEqual(validator.validate(cardHolder: "abcABC012 -."), .valid)
17 | XCTAssertEqual(validator.validate(cardHolder: "山田たろう"), .invalidCardHolderCharacter)
18 | // 全角スペースは不可
19 | XCTAssertEqual(validator.validate(cardHolder: "JANE DOE"), .invalidCardHolderCharacter)
20 | // 全角数字は不可
21 | XCTAssertEqual(validator.validate(cardHolder: "123"), .invalidCardHolderCharacter)
22 | // 46文字以上は不可
23 | XCTAssertEqual(validator.validate(cardHolder: "1234567890123456789012345678901234567890123456"), .invalidCardHolderLength)
24 | // 45文字はOK
25 | XCTAssertEqual(validator.validate(cardHolder: "123456789012345678901234567890123456789012345"), .valid)
26 | // 1文字は不可
27 | XCTAssertEqual(validator.validate(cardHolder: "1"), .invalidCardHolderLength)
28 | // 2文字はOK
29 | XCTAssertEqual(validator.validate(cardHolder: "12"), .valid)
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Tests/Validators/CardNumberValidatorTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CardNumberValidatorTests.swift
3 | // PAYJPTests
4 | //
5 | // Created by Tadashi Wakayanagi on 2019/07/19.
6 | // Copyright © 2019 PAY, Inc. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import PAYJP
11 |
12 | class CardNumberValidatorTests: XCTestCase {
13 |
14 | let validator = CardNumberValidator()
15 |
16 | private func testIsValid(cases: [(String, CardBrand, Bool)]) {
17 | for (number, brand, expected) in cases {
18 | let valid = validator.isValid(cardNumber: number, brand: brand)
19 | XCTAssertEqual(valid, expected)
20 | }
21 | }
22 |
23 | func testCardNumberValidation() {
24 | let cases: [(String, CardBrand, Bool)] = [
25 | // 13桁
26 | ("1234567890123", .unknown, false),
27 | // luhn NG
28 | ("12345678901234", .unknown, false),
29 | // luhn OK
30 | ("12345678901237", .unknown, false),
31 | ("4242424242424242", .unknown, true),
32 | ("12345678901234569", .unknown, false),
33 | ("12345678901237ab", .unknown, false),
34 | ("ab12345678901237", .unknown, false),
35 | // Visa
36 | ("4200250796648831", .visa, true),
37 | ("4929613427952262", .visa, true),
38 | ("4929610527143692", .visa, false),
39 | // Master
40 | ("5269278488737492", .mastercard, true),
41 | ("5106733522040110", .mastercard, true),
42 | ("5589306849102132", .mastercard, false),
43 | // JCB
44 | ("3533401879982122", .jcb, true),
45 | ("3535909680226735", .jcb, true),
46 | ("3534067821171002", .jcb, false),
47 | // Amex
48 | ("346191816620108", .americanExpress, true),
49 | ("341179142096577", .americanExpress, true),
50 | ("372086951160373", .americanExpress, false),
51 | // Discover
52 | ("6011341651562441", .discover, true),
53 | ("6011290763638088", .discover, true),
54 | ("6011621030885715", .discover, false),
55 | // Diners
56 | ("36868003801279", .dinersClub, true),
57 | ("36785415704877", .dinersClub, true),
58 | ("36267608413862", .dinersClub, false)
59 | ]
60 | testIsValid(cases: cases)
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/Tests/Validators/CvcValidatorTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CvcValidatorTests.swift
3 | // PAYJPTests
4 | //
5 | // Created by Tadashi Wakayanagi on 2019/07/19.
6 | // Copyright © 2019 PAY, Inc. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import PAYJP
11 |
12 | class CvcValidatorTests: XCTestCase {
13 |
14 | let validator = CvcValidator()
15 |
16 | func testIsValid(cases: [(String, CardBrand, (Bool, Bool))]) {
17 | for (cvc, brand, expected) in cases {
18 | let result = validator.isValid(cvc: cvc, brand: brand)
19 | XCTAssertEqual(result.validated, expected.0)
20 | XCTAssertEqual(result.isInstant, expected.1)
21 | }
22 | }
23 |
24 | func testCvcValidation() {
25 | let cases: [(String, CardBrand, (Bool, Bool))] = [
26 | ("", .unknown, (false, false)),
27 | ("", .visa, (false, false)),
28 | ("", .americanExpress, (false, false)),
29 | ("1", .unknown, (false, false)),
30 | ("1", .mastercard, (false, false)),
31 | ("1", .americanExpress, (false, false)),
32 | ("12", .unknown, (false, false)),
33 | ("12", .jcb, (false, false)),
34 | ("12", .americanExpress, (false, false)),
35 | ("123", .unknown, (false, false)),
36 | ("123", .dinersClub, (true, false)),
37 | ("123", .americanExpress, (false, false)),
38 | ("1234", .unknown, (true, false)),
39 | ("1234", .discover, (false, true)),
40 | ("1234", .americanExpress, (true, false)),
41 | ("12345", .unknown, (false, true)),
42 | ("12345", .visa, (false, true)),
43 | ("12345", .americanExpress, (false, true)),
44 | ("a123", .unknown, (false, false)),
45 | ("a123", .mastercard, (false, false)),
46 | ("a123", .americanExpress, (false, false)),
47 | ("123a", .unknown, (false, false)),
48 | ("123a", .jcb, (false, false)),
49 | ("123a", .americanExpress, (false, false))
50 | ]
51 | testIsValid(cases: cases)
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Tests/Validators/ExpirationValidatorTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ExpirationValidatorTests.swift
3 | // PAYJPTests
4 | //
5 | // Created by Li-Hsuan Chen on 2019/07/19.
6 | // Copyright © 2019 PAY, Inc. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import PAYJP
11 |
12 | class ExpirationValidatorTests: XCTestCase {
13 | func testCurrentDate() {
14 | let date = Date(timeIntervalSinceNow: 0)
15 | let (month, year) = extractMonthYear(date: date)
16 |
17 | let validator = ExpirationValidator()
18 | let isValid = validator.isValid(month: month, year: year)
19 |
20 | XCTAssertTrue(isValid)
21 | }
22 |
23 | func testPastDate() {
24 | let date = Date(timeIntervalSinceNow: -60 * 60 * 24 * 30 * 2) // 今から二ヶ月くらい前
25 | let (month, year) = extractMonthYear(date: date)
26 |
27 | let validator = ExpirationValidator()
28 | let isValid = validator.isValid(month: month, year: year)
29 |
30 | XCTAssertFalse(isValid)
31 | }
32 |
33 | func testFutureDate() {
34 | let date = Date(timeIntervalSinceNow: 60 * 60 * 24 * 30 * 2) // 今から二ヶ月くらい後
35 | let (month, year) = extractMonthYear(date: date)
36 |
37 | let validator = ExpirationValidator()
38 | let isValid = validator.isValid(month: month, year: year)
39 |
40 | XCTAssertTrue(isValid)
41 | }
42 |
43 | private func extractMonthYear(date: Date) -> (month: String, year: String) {
44 | let calendar = Calendar(identifier: .gregorian)
45 | let year = calendar.component(.year, from: date) % 100
46 | let month = calendar.component(.month, from: date)
47 | return ("\(month)", "\(year)")
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Tests/Validators/PublicKeyValidatorTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PublicKeyValidatorTests.swift
3 | // PAYJPTests
4 | //
5 | // Created by Tadashi Wakayanagi on 2019/11/27.
6 | // Copyright © 2019 PAY, Inc. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import PAYJP
11 |
12 | class PublicKeyValidatorTests: XCTestCase {
13 |
14 | func testPublicKeyValidationSuccess() {
15 | let cases: [String] = [
16 | ("pk_test_123456789"),
17 | ("pk_live_123456789")
18 | ]
19 |
20 | for publicKey in cases {
21 | var results: [Bool] = []
22 | let assert: (Bool, String, StaticString, UInt) -> Void = { condition, _, _, _ in
23 | results.append(condition)
24 | }
25 | let validator = PublicKeyValidator(assert: assert)
26 | validator.validate(publicKey: publicKey)
27 | // assertの成功をチェックするため、conditionにfalseが含まれていないことをテストする
28 | XCTAssertFalse(results.contains(false))
29 | }
30 | }
31 |
32 | func testPublicKeyValidationFailed() {
33 | let cases: [(String, String)] = [
34 | ("", "❌You need to set publickey for PAY.JP. You can find in https://pay.jp/d/settings ."),
35 | (" ", "❌You need to set publickey for PAY.JP. You can find in https://pay.jp/d/settings ."),
36 | ("sk_test_123456789", "❌You are using secretkey (`sk_xxxx`) instead of PAY.JP publickey." +
37 | "You can find **public** key like `pk_xxxxxx` in https://pay.jp/d/settings ."),
38 | ("sk_live_123456789", "❌You are using secretkey (`sk_xxxx`) instead of PAY.JP publickey." +
39 | "You can find **public** key like `pk_xxxxxx` in https://pay.jp/d/settings .")
40 | ]
41 |
42 | for (publicKey, expectedMessage) in cases {
43 | var results: [(Bool, String)] = []
44 | let assert: (Bool, String, StaticString, UInt) -> Void = { condition, message, _, _ in
45 | results.append((condition, message))
46 | }
47 | let validator = PublicKeyValidator(assert: assert)
48 | validator.validate(publicKey: publicKey)
49 | // assertの失敗をチェックするため、conditionにfalseが含まれていることをテストする
50 | XCTAssertTrue(results.contains(where: { (condition, message) -> Bool in
51 | return !condition && message == expectedMessage
52 | }))
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/docs/docsets/PAYJP.docset/Contents/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleIdentifier
6 | com.jazzy.payjp
7 | CFBundleName
8 | PAYJP
9 | DocSetPlatformFamily
10 | payjp
11 | isDashDocset
12 |
13 | dashIndexFilePath
14 | index.html
15 | isJavaScriptEnabled
16 |
17 | DashDocSetFamily
18 | dashtoc
19 |
20 |
21 |
--------------------------------------------------------------------------------
/docs/docsets/PAYJP.docset/Contents/Resources/Documents/img/carat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/payjp/payjp-ios/d4e228ba0bfc6dd82b216342a57c03059043ace7/docs/docsets/PAYJP.docset/Contents/Resources/Documents/img/carat.png
--------------------------------------------------------------------------------
/docs/docsets/PAYJP.docset/Contents/Resources/Documents/img/dash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/payjp/payjp-ios/d4e228ba0bfc6dd82b216342a57c03059043ace7/docs/docsets/PAYJP.docset/Contents/Resources/Documents/img/dash.png
--------------------------------------------------------------------------------
/docs/docsets/PAYJP.docset/Contents/Resources/Documents/img/gh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/payjp/payjp-ios/d4e228ba0bfc6dd82b216342a57c03059043ace7/docs/docsets/PAYJP.docset/Contents/Resources/Documents/img/gh.png
--------------------------------------------------------------------------------
/docs/docsets/PAYJP.docset/Contents/Resources/Documents/img/spinner.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/payjp/payjp-ios/d4e228ba0bfc6dd82b216342a57c03059043ace7/docs/docsets/PAYJP.docset/Contents/Resources/Documents/img/spinner.gif
--------------------------------------------------------------------------------
/docs/docsets/PAYJP.docset/Contents/Resources/Documents/js/jazzy.js:
--------------------------------------------------------------------------------
1 | // Jazzy - https://github.com/realm/jazzy
2 | // Copyright Realm Inc.
3 | // SPDX-License-Identifier: MIT
4 |
5 | window.jazzy = {'docset': false}
6 | if (typeof window.dash != 'undefined') {
7 | document.documentElement.className += ' dash'
8 | window.jazzy.docset = true
9 | }
10 | if (navigator.userAgent.match(/xcode/i)) {
11 | document.documentElement.className += ' xcode'
12 | window.jazzy.docset = true
13 | }
14 |
15 | function toggleItem($link, $content) {
16 | var animationDuration = 300;
17 | $link.toggleClass('token-open');
18 | $content.slideToggle(animationDuration);
19 | }
20 |
21 | function itemLinkToContent($link) {
22 | return $link.parent().parent().next();
23 | }
24 |
25 | // On doc load + hash-change, open any targetted item
26 | function openCurrentItemIfClosed() {
27 | if (window.jazzy.docset) {
28 | return;
29 | }
30 | var $link = $(`a[name="${location.hash.substring(1)}"]`).nextAll('.token');
31 | $content = itemLinkToContent($link);
32 | if ($content.is(':hidden')) {
33 | toggleItem($link, $content);
34 | }
35 | }
36 |
37 | $(openCurrentItemIfClosed);
38 | $(window).on('hashchange', openCurrentItemIfClosed);
39 |
40 | // On item link ('token') click, toggle its discussion
41 | $('.token').on('click', function(event) {
42 | if (window.jazzy.docset) {
43 | return;
44 | }
45 | var $link = $(this);
46 | toggleItem($link, itemLinkToContent($link));
47 |
48 | // Keeps the document from jumping to the hash.
49 | var href = $link.attr('href');
50 | if (history.pushState) {
51 | history.pushState({}, '', href);
52 | } else {
53 | location.hash = href;
54 | }
55 | event.preventDefault();
56 | });
57 |
58 | // Clicks on links to the current, closed, item need to open the item
59 | $("a:not('.token')").on('click', function() {
60 | if (location == this.href) {
61 | openCurrentItemIfClosed();
62 | }
63 | });
64 |
65 | // KaTeX rendering
66 | if ("katex" in window) {
67 | $($('.math').each( (_, element) => {
68 | katex.render(element.textContent, element, {
69 | displayMode: $(element).hasClass('m-block'),
70 | throwOnError: false,
71 | trust: true
72 | });
73 | }))
74 | }
75 |
--------------------------------------------------------------------------------
/docs/docsets/PAYJP.docset/Contents/Resources/Documents/js/jazzy.search.js:
--------------------------------------------------------------------------------
1 | // Jazzy - https://github.com/realm/jazzy
2 | // Copyright Realm Inc.
3 | // SPDX-License-Identifier: MIT
4 |
5 | $(function(){
6 | var $typeahead = $('[data-typeahead]');
7 | var $form = $typeahead.parents('form');
8 | var searchURL = $form.attr('action');
9 |
10 | function displayTemplate(result) {
11 | return result.name;
12 | }
13 |
14 | function suggestionTemplate(result) {
15 | var t = '';
16 | t += '' + result.name + '';
17 | if (result.parent_name) {
18 | t += '' + result.parent_name + '';
19 | }
20 | t += '
';
21 | return t;
22 | }
23 |
24 | $typeahead.one('focus', function() {
25 | $form.addClass('loading');
26 |
27 | $.getJSON(searchURL).then(function(searchData) {
28 | const searchIndex = lunr(function() {
29 | this.ref('url');
30 | this.field('name');
31 | this.field('abstract');
32 | for (const [url, doc] of Object.entries(searchData)) {
33 | this.add({url: url, name: doc.name, abstract: doc.abstract});
34 | }
35 | });
36 |
37 | $typeahead.typeahead(
38 | {
39 | highlight: true,
40 | minLength: 3,
41 | autoselect: true
42 | },
43 | {
44 | limit: 10,
45 | display: displayTemplate,
46 | templates: { suggestion: suggestionTemplate },
47 | source: function(query, sync) {
48 | const lcSearch = query.toLowerCase();
49 | const results = searchIndex.query(function(q) {
50 | q.term(lcSearch, { boost: 100 });
51 | q.term(lcSearch, {
52 | boost: 10,
53 | wildcard: lunr.Query.wildcard.TRAILING
54 | });
55 | }).map(function(result) {
56 | var doc = searchData[result.ref];
57 | doc.url = result.ref;
58 | return doc;
59 | });
60 | sync(results);
61 | }
62 | }
63 | );
64 | $form.removeClass('loading');
65 | $typeahead.trigger('focus');
66 | });
67 | });
68 |
69 | var baseURL = searchURL.slice(0, -"search.json".length);
70 |
71 | $typeahead.on('typeahead:select', function(e, result) {
72 | window.location = baseURL + result.url;
73 | });
74 | });
75 |
--------------------------------------------------------------------------------
/docs/docsets/PAYJP.docset/Contents/Resources/docSet.dsidx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/payjp/payjp-ios/d4e228ba0bfc6dd82b216342a57c03059043ace7/docs/docsets/PAYJP.docset/Contents/Resources/docSet.dsidx
--------------------------------------------------------------------------------
/docs/img/carat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/payjp/payjp-ios/d4e228ba0bfc6dd82b216342a57c03059043ace7/docs/img/carat.png
--------------------------------------------------------------------------------
/docs/img/dash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/payjp/payjp-ios/d4e228ba0bfc6dd82b216342a57c03059043ace7/docs/img/dash.png
--------------------------------------------------------------------------------
/docs/img/gh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/payjp/payjp-ios/d4e228ba0bfc6dd82b216342a57c03059043ace7/docs/img/gh.png
--------------------------------------------------------------------------------
/docs/img/spinner.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/payjp/payjp-ios/d4e228ba0bfc6dd82b216342a57c03059043ace7/docs/img/spinner.gif
--------------------------------------------------------------------------------
/docs/js/jazzy.js:
--------------------------------------------------------------------------------
1 | // Jazzy - https://github.com/realm/jazzy
2 | // Copyright Realm Inc.
3 | // SPDX-License-Identifier: MIT
4 |
5 | window.jazzy = {'docset': false}
6 | if (typeof window.dash != 'undefined') {
7 | document.documentElement.className += ' dash'
8 | window.jazzy.docset = true
9 | }
10 | if (navigator.userAgent.match(/xcode/i)) {
11 | document.documentElement.className += ' xcode'
12 | window.jazzy.docset = true
13 | }
14 |
15 | function toggleItem($link, $content) {
16 | var animationDuration = 300;
17 | $link.toggleClass('token-open');
18 | $content.slideToggle(animationDuration);
19 | }
20 |
21 | function itemLinkToContent($link) {
22 | return $link.parent().parent().next();
23 | }
24 |
25 | // On doc load + hash-change, open any targetted item
26 | function openCurrentItemIfClosed() {
27 | if (window.jazzy.docset) {
28 | return;
29 | }
30 | var $link = $(`a[name="${location.hash.substring(1)}"]`).nextAll('.token');
31 | $content = itemLinkToContent($link);
32 | if ($content.is(':hidden')) {
33 | toggleItem($link, $content);
34 | }
35 | }
36 |
37 | $(openCurrentItemIfClosed);
38 | $(window).on('hashchange', openCurrentItemIfClosed);
39 |
40 | // On item link ('token') click, toggle its discussion
41 | $('.token').on('click', function(event) {
42 | if (window.jazzy.docset) {
43 | return;
44 | }
45 | var $link = $(this);
46 | toggleItem($link, itemLinkToContent($link));
47 |
48 | // Keeps the document from jumping to the hash.
49 | var href = $link.attr('href');
50 | if (history.pushState) {
51 | history.pushState({}, '', href);
52 | } else {
53 | location.hash = href;
54 | }
55 | event.preventDefault();
56 | });
57 |
58 | // Clicks on links to the current, closed, item need to open the item
59 | $("a:not('.token')").on('click', function() {
60 | if (location == this.href) {
61 | openCurrentItemIfClosed();
62 | }
63 | });
64 |
65 | // KaTeX rendering
66 | if ("katex" in window) {
67 | $($('.math').each( (_, element) => {
68 | katex.render(element.textContent, element, {
69 | displayMode: $(element).hasClass('m-block'),
70 | throwOnError: false,
71 | trust: true
72 | });
73 | }))
74 | }
75 |
--------------------------------------------------------------------------------
/docs/js/jazzy.search.js:
--------------------------------------------------------------------------------
1 | // Jazzy - https://github.com/realm/jazzy
2 | // Copyright Realm Inc.
3 | // SPDX-License-Identifier: MIT
4 |
5 | $(function(){
6 | var $typeahead = $('[data-typeahead]');
7 | var $form = $typeahead.parents('form');
8 | var searchURL = $form.attr('action');
9 |
10 | function displayTemplate(result) {
11 | return result.name;
12 | }
13 |
14 | function suggestionTemplate(result) {
15 | var t = '';
16 | t += '' + result.name + '';
17 | if (result.parent_name) {
18 | t += '' + result.parent_name + '';
19 | }
20 | t += '
';
21 | return t;
22 | }
23 |
24 | $typeahead.one('focus', function() {
25 | $form.addClass('loading');
26 |
27 | $.getJSON(searchURL).then(function(searchData) {
28 | const searchIndex = lunr(function() {
29 | this.ref('url');
30 | this.field('name');
31 | this.field('abstract');
32 | for (const [url, doc] of Object.entries(searchData)) {
33 | this.add({url: url, name: doc.name, abstract: doc.abstract});
34 | }
35 | });
36 |
37 | $typeahead.typeahead(
38 | {
39 | highlight: true,
40 | minLength: 3,
41 | autoselect: true
42 | },
43 | {
44 | limit: 10,
45 | display: displayTemplate,
46 | templates: { suggestion: suggestionTemplate },
47 | source: function(query, sync) {
48 | const lcSearch = query.toLowerCase();
49 | const results = searchIndex.query(function(q) {
50 | q.term(lcSearch, { boost: 100 });
51 | q.term(lcSearch, {
52 | boost: 10,
53 | wildcard: lunr.Query.wildcard.TRAILING
54 | });
55 | }).map(function(result) {
56 | var doc = searchData[result.ref];
57 | doc.url = result.ref;
58 | return doc;
59 | });
60 | sync(results);
61 | }
62 | }
63 | );
64 | $form.removeClass('loading');
65 | $typeahead.trigger('focus');
66 | });
67 | });
68 |
69 | var baseURL = searchURL.slice(0, -"search.json".length);
70 |
71 | $typeahead.on('typeahead:select', function(e, result) {
72 | window.location = baseURL + result.url;
73 | });
74 | });
75 |
--------------------------------------------------------------------------------
/example-objc/.gitignore:
--------------------------------------------------------------------------------
1 | Pods/
2 | Podfile.lock
3 |
--------------------------------------------------------------------------------
/example-objc/Podfile:
--------------------------------------------------------------------------------
1 | platform :ios, '12.0'
2 | use_frameworks!
3 |
4 | target 'example-objc' do
5 | # pod 'PAYJP'
6 | pod 'PAYJP', :path => '../'
7 | # NOTE: if you need to scan card, add CardIO dependency like below
8 | # pod 'CardIO'
9 | end
10 |
--------------------------------------------------------------------------------
/example-objc/example-objc.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example-objc/example-objc.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/example-objc/example-objc.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example-objc/example-objc/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // example-objc
4 | //
5 | // Created by Tatsuya Kitagawa on 2017/12/08.
6 | // Copyright © 2017年 PAY, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface AppDelegate : UIResponder
12 |
13 | @property(strong, nonatomic) UIWindow *window;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/example-objc/example-objc/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/example-objc/example-objc/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/example-objc/example-objc/CardFormViewExampleViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // CardFormViewExampleViewController.h
3 | // example-objc
4 | //
5 | // Created by Li-Hsuan Chen on 2019/07/23.
6 | // Copyright © 2019 PAY, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 | @import PAYJP;
11 |
12 | NS_ASSUME_NONNULL_BEGIN
13 |
14 | @interface CardFormViewExampleViewController : UITableViewController
18 |
19 | @end
20 |
21 | NS_ASSUME_NONNULL_END
22 |
--------------------------------------------------------------------------------
/example-objc/example-objc/CardFormViewScrollViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // CardFormViewScrollViewConstroller.h
3 | // example-objc
4 | //
5 | // Created by Tadashi Wakayanagi on 2019/08/28.
6 | // Copyright © 2019 PAY, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 | @import PAYJP;
11 |
12 | NS_ASSUME_NONNULL_BEGIN
13 |
14 | @interface CardFormViewScrollViewController
15 | : UIViewController
20 |
21 | @end
22 |
23 | NS_ASSUME_NONNULL_END
24 |
--------------------------------------------------------------------------------
/example-objc/example-objc/ColorTheme.h:
--------------------------------------------------------------------------------
1 | //
2 | // ColorStyle.h
3 | // example-objc
4 | //
5 | // Created by Tadashi Wakayanagi on 2019/09/25.
6 | // Copyright © 2019 PAY, Inc. All rights reserved.
7 | //
8 |
9 | #ifndef ColorStyle_h
10 | #define ColorStyle_h
11 |
12 | typedef NS_ENUM(NSInteger, ColorTheme) { Normal, Red, Blue, Dark };
13 | #define GetColorThemeText(type) ColorThemeTextList[type]
14 | #define GetColorTheme(typeText) (ColorTheme)[ColorThemeTextList indexOfObject:typeText]
15 | #define ColorThemeTextList @[ @"Normal", @"Red", @"Blue", @"Dark" ]
16 | #define RGB(r, g, b) [UIColor colorWithRed:(r) / 255.0 green:(g) / 255.0 blue:(b) / 255.0 alpha:1]
17 |
18 | #endif
19 |
--------------------------------------------------------------------------------
/example-objc/example-objc/ExampleHostViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ExampleHostViewController.h
3 | // example-objc
4 | //
5 | // Created by Tadashi Wakayanagi on 2019/11/18.
6 | // Copyright © 2019 PAY, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 | @import PAYJP;
11 |
12 | @interface ExampleHostViewController : UITableViewController
13 |
14 | @end
15 |
--------------------------------------------------------------------------------
/example-objc/example-objc/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleURLTypes
20 |
21 |
22 | CFBundleURLName
23 | $(PRODUCT_BUNDLE_IDENTIFIER)
24 | CFBundleURLSchemes
25 |
26 | exampleobjc
27 |
28 |
29 |
30 | CFBundleVersion
31 | 1
32 | LSRequiresIPhoneOS
33 |
34 | NSCameraUsageDescription
35 | We will use camera for card scanning.
36 | UILaunchStoryboardName
37 | LaunchScreen
38 | UIMainStoryboardFile
39 | Main
40 | UIRequiredDeviceCapabilities
41 |
42 | armv7
43 |
44 | UISupportedInterfaceOrientations
45 |
46 | UIInterfaceOrientationPortrait
47 | UIInterfaceOrientationLandscapeLeft
48 | UIInterfaceOrientationLandscapeRight
49 |
50 | UISupportedInterfaceOrientations~ipad
51 |
52 | UIInterfaceOrientationPortrait
53 | UIInterfaceOrientationPortraitUpsideDown
54 | UIInterfaceOrientationLandscapeLeft
55 | UIInterfaceOrientationLandscapeRight
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/example-objc/example-objc/SampleService.h:
--------------------------------------------------------------------------------
1 | //
2 | // SampleService.h
3 | // example-objc
4 | //
5 | // Created by Tadashi Wakayanagi on 2019/11/25.
6 | // Copyright © 2019 PAY, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 | @import PAYJP;
11 |
12 | @interface SampleService : NSObject
13 |
14 | + (SampleService *)sharedService;
15 | - (void)saveCardWithToken:(NSString *)token completion:(void (^)(NSError *error))completion;
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/example-objc/example-objc/ThreeDSecureExampleViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ThreeDSecureExampleViewController.h
3 | // example-objc
4 | //
5 |
6 | #import
7 | @import PAYJP;
8 |
9 | NS_ASSUME_NONNULL_BEGIN
10 |
11 | @interface ThreeDSecureExampleViewController
12 | : UIViewController
13 |
14 | @end
15 |
16 | NS_ASSUME_NONNULL_END
--------------------------------------------------------------------------------
/example-objc/example-objc/ThreeDSecureExampleViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ThreeDSecureExampleViewController.m
3 | // example-objc
4 | //
5 |
6 | #import "ThreeDSecureExampleViewController.h"
7 | #import "UIViewController+Alert.h"
8 |
9 | @interface ThreeDSecureExampleViewController ()
10 |
11 | @property(weak, nonatomic) IBOutlet UIButton *startButton;
12 | @property(weak, nonatomic) IBOutlet UITextField *textField;
13 | @property(weak, nonatomic) IBOutlet UILabel *resultLabel;
14 | @property(strong, nonatomic) NSString *pendingResourceId;
15 |
16 | @end
17 |
18 | @implementation ThreeDSecureExampleViewController
19 |
20 | - (void)viewDidLoad {
21 | [super viewDidLoad];
22 | }
23 |
24 | - (IBAction)startThreeDSecure:(id)sender {
25 | if (self.textField.text.length == 0) {
26 | self.resultLabel.text = @"";
27 | self.resultLabel.hidden = YES;
28 | return;
29 | }
30 |
31 | self.pendingResourceId = self.textField.text;
32 | [[PAYJPThreeDSecureProcessHandler sharedHandler]
33 | startThreeDSecureProcessWithViewController:self
34 | delegate:self
35 | resourceId:self.textField.text];
36 | }
37 |
38 | #pragma mark - PAYJPThreeDSecureProcessHandlerDelegate
39 |
40 | - (void)threeDSecureProcessHandlerDidFinish:(PAYJPThreeDSecureProcessHandler *)handler
41 | status:(enum ThreeDSecureProcessStatus)status {
42 | switch (status) {
43 | case ThreeDSecureProcessStatusCompleted:
44 | self.resultLabel.text =
45 | @"3Dセキュア認証が終了しました。\nこの結果をサーバーサイドに伝え、完了処理や結果のハンド"
46 | @"リングを行なってください。\n後続処理の実装方法に関してはドキュメントをご参照ください。";
47 | self.resultLabel.textColor = UIColor.blackColor;
48 | self.resultLabel.hidden = NO;
49 | break;
50 | case ThreeDSecureProcessStatusCanceled:
51 | self.resultLabel.text = @"3Dセキュア認証がキャンセルされました。";
52 | self.resultLabel.textColor = UIColor.redColor;
53 | self.resultLabel.hidden = NO;
54 | break;
55 | default:
56 | break;
57 | }
58 | }
59 |
60 | @end
61 |
--------------------------------------------------------------------------------
/example-objc/example-objc/UIViewController+Alert.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIViewController+Alert.h
3 | // example-objc
4 | //
5 | // Created by Tadashi Wakayanagi on 2019/11/20.
6 | // Copyright © 2019 PAY, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 | @import PAYJP;
11 |
12 | @interface UIViewController (Alert)
13 |
14 | - (void)showToken:(PAYToken *)token;
15 | - (void)showError:(NSError *)error;
16 | - (NSString *)displayToken:(PAYToken *)token;
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/example-objc/example-objc/UIViewController+Alert.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIViewController+Alert.m
3 | // example-objc
4 | //
5 | // Created by Tadashi Wakayanagi on 2019/11/20.
6 | // Copyright © 2019 PAY, Inc. All rights reserved.
7 | //
8 |
9 | #import "UIViewController+Alert.h"
10 |
11 | @implementation UIViewController (Alert)
12 |
13 | - (void)showToken:(PAYToken *)token {
14 | UIAlertController *alert =
15 | [UIAlertController alertControllerWithTitle:@"success"
16 | message:[self displayToken:token]
17 | preferredStyle:UIAlertControllerStyleAlert];
18 | [alert addAction:[UIAlertAction actionWithTitle:@"OK"
19 | style:UIAlertActionStyleCancel
20 | handler:nil]];
21 | [self presentViewController:alert animated:true completion:nil];
22 | }
23 |
24 | - (void)showError:(NSError *)error {
25 | UIAlertController *alert =
26 | [UIAlertController alertControllerWithTitle:@"error"
27 | message:error.localizedDescription
28 | preferredStyle:UIAlertControllerStyleAlert];
29 | [alert addAction:[UIAlertAction actionWithTitle:@"OK"
30 | style:UIAlertActionStyleCancel
31 | handler:nil]];
32 | [self presentViewController:alert animated:true completion:nil];
33 | }
34 |
35 | - (NSString *)displayToken:(PAYToken *)token {
36 | return [NSString stringWithFormat:@"id=%@,\ncard.id=%@,\ncard.last4=%@,\ncard.exp=%hhu/"
37 | @"%hu,\ncard.name=%@,\ncard.email=%@,\ncard.phone=%@",
38 | token.identifer, token.card.identifer, token.card.last4Number,
39 | token.card.expirationMonth, token.card.expirationYear,
40 | token.card.name, token.card.email, token.card.phone];
41 | }
42 |
43 | @end
44 |
--------------------------------------------------------------------------------
/example-objc/example-objc/ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // example-objc
4 | //
5 | // Created by Tatsuya Kitagawa on 2017/12/08.
6 | // Copyright © 2017年 PAY, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ViewController : UITableViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/example-objc/example-objc/en.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 | /*
2 | Localizable.strings
3 | example-objc
4 |
5 | Created by Tadashi Wakayanagi on 2019/08/27.
6 | Copyright © 2019 PAY, Inc. All rights reserved.
7 | */
8 |
9 | "example_card_information_section" = "Card Information";
10 | "example_token_id_section" = "Token ID";
11 |
--------------------------------------------------------------------------------
/example-objc/example-objc/ja.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 | /*
2 | Localizable.strings
3 | example-objc
4 |
5 | Created by Tadashi Wakayanagi on 2019/08/27.
6 | Copyright © 2019 PAY, Inc. All rights reserved.
7 | */
8 |
9 | "example_card_information_section" = "Card Information";
10 | "example_token_id_section" = "Token ID";
11 |
--------------------------------------------------------------------------------
/example-objc/example-objc/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // example-objc
4 | //
5 | // Created by Tatsuya Kitagawa on 2017/12/08.
6 | // Copyright © 2017年 Tatsuya Kitagawa. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "AppDelegate.h"
11 |
12 | int main(int argc, char* argv[]) {
13 | @autoreleasepool {
14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/example-swift/.gitignore:
--------------------------------------------------------------------------------
1 | Carthage/
2 | Cartfile.resolved
--------------------------------------------------------------------------------
/example-swift/Cartfile:
--------------------------------------------------------------------------------
1 | # github "payjp/payjp-ios"
2 | git "../" "HEAD"
3 |
4 |
--------------------------------------------------------------------------------
/example-swift/example-swift-ui/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // example-swift-ui
4 | //
5 | // Created by Tatsuya Kitagawa on 2020/07/21.
6 | //
7 |
8 | import UIKit
9 | import PAYJP
10 |
11 | let PAYJPPublicKey = "pk_test_0383a1b8f91e8a6e3ea0e2a9"
12 | let App3DSRedirectURL = "exampleswift://tds/complete"
13 | let App3DSRedirectURLKey = "swift-app"
14 |
15 | @UIApplicationMain
16 | class AppDelegate: UIResponder, UIApplicationDelegate {
17 |
18 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
19 | // Override point for customization after application launch.
20 | PAYJPSDK.publicKey = PAYJPPublicKey
21 | PAYJPSDK.locale = Locale.current
22 | PAYJPSDK.threeDSecureURLConfiguration =
23 | ThreeDSecureURLConfiguration(redirectURL: URL(string: App3DSRedirectURL)!,
24 | redirectURLKey: App3DSRedirectURLKey)
25 | return true
26 | }
27 |
28 | func application(_ app: UIApplication,
29 | open url: URL,
30 | options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
31 | return ThreeDSecureProcessHandler.shared.completeThreeDSecureProcess(url: url)
32 | }
33 |
34 | // MARK: UISceneSession Lifecycle
35 |
36 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
37 | // Called when a new scene session is being created.
38 | // Use this method to select a configuration to create the new scene with.
39 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
40 | }
41 |
42 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) {
43 | // Called when the user discards a scene session.
44 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
45 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/example-swift/example-swift-ui/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/example-swift/example-swift-ui/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/example-swift/example-swift-ui/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/example-swift/example-swift-ui/CardFormViewControllerExampleView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CardFormViewControllerExampleView.swift
3 | // example-swift
4 | //
5 |
6 | import SwiftUI
7 | import PAYJP
8 |
9 | struct CardFormViewControllerExampleView: View {
10 | @ObservedObject private var cardFormDelegate = CardFormDelegate()
11 | var body: some View {
12 | Button("Add Credit Card") {
13 | self.cardFormDelegate.isPresented.toggle()
14 | }
15 | .sheet(isPresented: self.$cardFormDelegate.isPresented) {
16 | CardFormViewControllerWrapper(delegate: self.cardFormDelegate)
17 | }
18 | }
19 | }
20 |
21 | // MARK: - CardFormViewControllerDelegate
22 |
23 | class CardFormDelegate: ObservableObject, CardFormViewControllerDelegate {
24 | @Published var isPresented: Bool = false
25 |
26 | func cardFormViewController(_: CardFormViewController, didCompleteWith result: CardFormResult) {
27 | switch result {
28 | case .cancel:
29 | print("CardFormResult.cancel")
30 | case .success:
31 | print("CardFormResult.success")
32 | DispatchQueue.main.async { [weak self] in
33 | self?.isPresented.toggle()
34 | }
35 | }
36 | }
37 |
38 | func cardFormViewController(_: CardFormViewController,
39 | didProduced token: Token,
40 | completionHandler: @escaping (Error?) -> Void) {
41 | print("token = \(String(describing: token.rawValue))")
42 | // TODO: send token to server
43 | completionHandler(nil)
44 | }
45 | }
46 |
47 | // MARK: - CardFormViewControllerWrapper
48 |
49 | struct CardFormViewControllerWrapper: UIViewControllerRepresentable {
50 | weak var delegate: CardFormViewControllerDelegate!
51 |
52 | func makeUIViewController(context: Context) -> UINavigationController {
53 | let cardFormVc = CardFormViewController.createCardFormViewController(delegate: delegate,
54 | viewType: .displayStyled)
55 | let naviVc = UINavigationController(rootViewController: cardFormVc)
56 | naviVc.presentationController?.delegate = cardFormVc
57 | return naviVc
58 | }
59 |
60 | func updateUIViewController(_ uiViewController: UINavigationController, context: Context) {
61 | }
62 |
63 | typealias UIViewControllerType = UINavigationController
64 | }
65 |
--------------------------------------------------------------------------------
/example-swift/example-swift-ui/ContentView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContentView.swift
3 | // example-swift-ui
4 | //
5 | // Created by Tatsuya Kitagawa on 2020/07/21.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct ContentView: View {
11 | var body: some View {
12 | NavigationView {
13 | List {
14 | Section(header: Text("カードフォーム")) {
15 | NavigationLink(destination: CardFormViewControllerExampleView()) {
16 | Text("Card Form ViewController")
17 | }
18 | }
19 | Section(header: Text("支払い時の3Dセキュア、または顧客カードの3Dセキュア")) {
20 | NavigationLink(destination: ThreeDSecureProcessHandlerExampleView()) {
21 | Text("ThreeD Secure Process Handler")
22 | }
23 | }
24 | }
25 | .navigationBarTitle("Example")
26 | }
27 | }
28 | }
29 |
30 |
31 | // MARK: - Preview
32 |
33 | struct ContentView_Previews: PreviewProvider {
34 | static var previews: some View {
35 | ContentView()
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/example-swift/example-swift-ui/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSceneManifest
24 |
25 | UIApplicationSupportsMultipleScenes
26 |
27 | UISceneConfigurations
28 |
29 | UIWindowSceneSessionRoleApplication
30 |
31 |
32 | UISceneConfigurationName
33 | Default Configuration
34 | UISceneDelegateClassName
35 | $(PRODUCT_MODULE_NAME).SceneDelegate
36 |
37 |
38 |
39 |
40 | UILaunchStoryboardName
41 | LaunchScreen
42 | UIRequiredDeviceCapabilities
43 |
44 | armv7
45 |
46 | UISupportedInterfaceOrientations
47 |
48 | UIInterfaceOrientationPortrait
49 | UIInterfaceOrientationLandscapeLeft
50 | UIInterfaceOrientationLandscapeRight
51 |
52 | UISupportedInterfaceOrientations~ipad
53 |
54 | UIInterfaceOrientationPortrait
55 | UIInterfaceOrientationPortraitUpsideDown
56 | UIInterfaceOrientationLandscapeLeft
57 | UIInterfaceOrientationLandscapeRight
58 |
59 | CFBundleURLTypes
60 |
61 |
62 | CFBundleURLName
63 | $(PRODUCT_BUNDLE_IDENTIFIER)
64 | CFBundleURLSchemes
65 |
66 | exampleswift
67 |
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/example-swift/example-swift-ui/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/example-swift/example-swift.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example-swift/example-swift.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example-swift/example-swift/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // example-swift
4 | //
5 | // Created by Tatsuya Kitagawa on 2017/12/08.
6 | // Copyright © 2017年 PAY, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import PAYJP
11 |
12 | let PAYJPPublicKey = "pk_test_0383a1b8f91e8a6e3ea0e2a9"
13 | let App3DSRedirectURL = "exampleswift://tds/complete"
14 | let App3DSRedirectURLKey = "swift-app"
15 |
16 | @UIApplicationMain
17 | class AppDelegate: UIResponder, UIApplicationDelegate {
18 |
19 | var window: UIWindow?
20 |
21 | func application(
22 | _ application: UIApplication,
23 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
24 | ) -> Bool {
25 |
26 | PAYJPSDK.publicKey = PAYJPPublicKey
27 | PAYJPSDK.locale = Locale.current
28 | PAYJPSDK.threeDSecureURLConfiguration =
29 | ThreeDSecureURLConfiguration(redirectURL: URL(string: App3DSRedirectURL)!,
30 | redirectURLKey: App3DSRedirectURLKey)
31 |
32 | return true
33 | }
34 |
35 | func application(_ app: UIApplication,
36 | open url: URL,
37 | options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
38 |
39 | return ThreeDSecureProcessHandler.shared.completeThreeDSecureProcess(url: url)
40 | }
41 |
42 | func applicationWillResignActive(_ application: UIApplication) {
43 | }
44 |
45 | func applicationDidEnterBackground(_ application: UIApplication) {
46 | }
47 |
48 | func applicationWillEnterForeground(_ application: UIApplication) {
49 | }
50 |
51 | func applicationDidBecomeActive(_ application: UIApplication) {
52 | }
53 |
54 | func applicationWillTerminate(_ application: UIApplication) {
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/example-swift/example-swift/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/example-swift/example-swift/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/example-swift/example-swift/ColorTheme.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ColorTheme.swift
3 | // example-swift
4 | //
5 | // Created by Tadashi Wakayanagi on 2019/10/15.
6 | //
7 |
8 | import UIKit
9 |
10 | enum ColorTheme: String {
11 | case Normal
12 | case Red
13 | case Blue
14 | case Dark
15 | }
16 |
17 | extension UIColor {
18 |
19 | convenience init(_ red: Int, _ green: Int, _ blue: Int, _ alpha: Int = 255) {
20 | let rgba = [red, green, blue, alpha].map { i -> CGFloat in
21 | switch i {
22 | case let i where i < 0:
23 | return 0
24 | case let i where i > 255:
25 | return 1
26 | default:
27 | return CGFloat(i) / 255
28 | }
29 | }
30 | self.init(red: rgba[0], green: rgba[1], blue: rgba[2], alpha: rgba[3])
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/example-swift/example-swift/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | CFBundleURLTypes
28 |
29 |
30 | CFBundleURLName
31 | $(PRODUCT_BUNDLE_IDENTIFIER)
32 | CFBundleURLSchemes
33 |
34 | exampleswift
35 |
36 |
37 |
38 | UIRequiredDeviceCapabilities
39 |
40 | armv7
41 |
42 | UISupportedInterfaceOrientations
43 |
44 | UIInterfaceOrientationPortrait
45 | UIInterfaceOrientationLandscapeLeft
46 | UIInterfaceOrientationLandscapeRight
47 |
48 | UISupportedInterfaceOrientations~ipad
49 |
50 | UIInterfaceOrientationPortrait
51 | UIInterfaceOrientationPortraitUpsideDown
52 | UIInterfaceOrientationLandscapeLeft
53 | UIInterfaceOrientationLandscapeRight
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/example-swift/example-swift/SampleService.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SampleService.swift
3 | // example-swift
4 | //
5 | // Created by Tadashi Wakayanagi on 2019/11/26.
6 | //
7 |
8 | import Foundation
9 |
10 | // TODO: REPLACE WITH YOUR ENDPOINT URL
11 | private let BACKEND_URL = ""
12 | private let API_PATH = "/save_card"
13 |
14 | enum SampleError: LocalizedError {
15 | case unexpected
16 |
17 | var errorDescription: String? {
18 | switch self {
19 | case .unexpected:
20 | return "予期しない問題が発生しました"
21 | }
22 | }
23 | }
24 |
25 | struct SampleService {
26 |
27 | static let shared = SampleService()
28 |
29 | func saveCard(withToken token: String, completion: @escaping (Error?) -> Void) {
30 | if BACKEND_URL.isEmpty {
31 | completion(nil)
32 | return
33 | }
34 |
35 | do {
36 | let dict = ["card": token]
37 | let data = try JSONSerialization.data(withJSONObject: dict, options: .prettyPrinted)
38 | let urlString = BACKEND_URL + API_PATH
39 | let request = NSMutableURLRequest(url: URL(string: urlString)!)
40 | request.cachePolicy = .reloadIgnoringLocalCacheData
41 | request.setValue("Application/json", forHTTPHeaderField: "Content-Type")
42 | request.httpMethod = "POST"
43 | request.httpBody = data
44 |
45 | let configuration = URLSessionConfiguration.ephemeral
46 | let session = URLSession(configuration: configuration)
47 | let dataTask = session.dataTask(with: request as URLRequest) { (_, response, error) in
48 | if let httpResponse = response as? HTTPURLResponse {
49 | print("Status code: \(httpResponse.statusCode)")
50 |
51 | if httpResponse.statusCode == 201 {
52 | print("SampleService Success.")
53 | completion(nil)
54 | } else {
55 | if let error = error {
56 | print("SampleService Error => \(error)")
57 | completion(error)
58 | } else {
59 | print("SampleService Error other.")
60 | completion(SampleError.unexpected)
61 | }
62 | }
63 | }
64 | }
65 | dataTask.resume()
66 | } catch {
67 | print("Error: \(error)")
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/example-swift/example-swift/ThreeDSecureExampleViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ThreeDSecureExampleViewController.swift
3 | // example-swift
4 | //
5 |
6 | import UIKit
7 | import PAYJP
8 |
9 | class ThreeDSecureExampleViewController: UIViewController {
10 | @IBOutlet private var startButton: UIButton!
11 |
12 | @IBOutlet private var textField: UITextField!
13 |
14 | @IBOutlet private var resultLabel: UILabel!
15 |
16 | private var pendingResourceId: String?
17 |
18 | override func viewDidLoad() {
19 | super.viewDidLoad()
20 | }
21 |
22 | @IBAction private func startThreeDSecure(_ sender: Any) {
23 | guard let resourceId = textField.text, !resourceId.isEmpty else {
24 | self.resultLabel.text = ""
25 | self.resultLabel.isHidden = true
26 | return
27 | }
28 |
29 | pendingResourceId = resourceId
30 | ThreeDSecureProcessHandler.shared.startThreeDSecureProcess(viewController: self, delegate: self, resourceId: resourceId)
31 | }
32 | }
33 |
34 | // MARK: - ThreeDSecureProcessHandlerDelegate
35 |
36 | extension ThreeDSecureExampleViewController: ThreeDSecureProcessHandlerDelegate {
37 | func threeDSecureProcessHandlerDidFinish(_ handler: ThreeDSecureProcessHandler, status: ThreeDSecureProcessStatus) {
38 | switch status {
39 | case .completed:
40 | DispatchQueue.main.async {
41 | self.resultLabel.text = "3Dセキュア認証が終了しました。\nこの結果をサーバーサイドに伝え、完了処理や結果のハンドリングを行なってください。\n後続処理の実装方法に関してはドキュメントをご参照ください。"
42 | self.resultLabel.textColor = .black
43 | self.resultLabel.isHidden = false
44 | }
45 | case .canceled:
46 | DispatchQueue.main.async {
47 | self.resultLabel.text = "3Dセキュア認証がキャンセルされました。"
48 | self.resultLabel.textColor = .red
49 | self.resultLabel.isHidden = false
50 | }
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/example-swift/example-swift/en.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 | /*
2 | Localizable.strings
3 | example-swift
4 |
5 | Created by Tadashi Wakayanagi on 2019/09/12.
6 |
7 | */
8 |
9 | "example_card_information_section" = "Card Information";
10 | "example_token_id_section" = "Token ID";
11 |
--------------------------------------------------------------------------------
/example-swift/example-swift/ja.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 | /*
2 | Localizable.strings
3 | example-swift
4 |
5 | Created by Tadashi Wakayanagi on 2019/09/12.
6 |
7 | */
8 |
9 | "example_card_information_section" = "Card Information";
10 | "example_token_id_section" = "Token ID";
11 |
--------------------------------------------------------------------------------
/example-swift/run-swiftlint.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -ex
2 | if which swiftlint >/dev/null; then
3 | swiftlint lint path example-swift/*.swift --config ../.swiftlint.yml
4 | else
5 | echo "warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint"
6 | fi
7 |
8 |
--------------------------------------------------------------------------------
/fastlane/Pluginfile:
--------------------------------------------------------------------------------
1 | # Autogenerated by fastlane
2 | #
3 | # Ensure this file is checked in to source control!
4 |
5 | gem 'fastlane-plugin-firebase_app_distribution'
6 |
--------------------------------------------------------------------------------
/podspec.rb:
--------------------------------------------------------------------------------
1 | module PAYJPSDK
2 | VERSION = '2.2.1'
3 | HOMEPAGE_URL = 'https://github.com/payjp/payjp-ios'
4 | LICENSE = { :type => 'MIT' }
5 | AUTHOR = { 'PAY.JP (https://pay.jp)' => 'support@pay.jp' }
6 | SOURCE = { :git => 'https://github.com/payjp/payjp-ios.git', :tag => VERSION }
7 | MODULE_NAME = 'PAYJP'
8 | SWIFT_VERSIONS = ['5.0', '5.1', '5.2', '5.3', '5.4', '5.5']
9 | IOS_DEPLOYMENT_TARGET = '12.0'
10 | SOURCE_FILES = ['Sources/**/*.{h,m,swift}']
11 | RESOURCE_BUNDLES = { 'PAYJP' => ['Sources/Resources/**/*'] }
12 | RESOURCES = [ 'Sources/Resources/Assets.xcassets' ]
13 | PUBLIC_HEADER_FILES = 'Sources/**/*.h'
14 | FRAMEWORKS = 'PassKit'
15 | POD_TARGET_XCCONFIG = { 'OTHER_SWIFT_FLAGS' => '-DPAYJPSDKCocoaPods' }
16 | end
17 |
--------------------------------------------------------------------------------
/scripts/bash.source:
--------------------------------------------------------------------------------
1 | if [[ -z "$REPOSITORY_ROOT" ]]; then
2 | export REPOSITORY_ROOT="$(git rev-parse --show-toplevel)"
3 | fi
4 |
5 | export ENTERPRISE_P12_FILE=$REPOSITORY_ROOT/BASE_Enterprise.p12
6 | export PROFILE_EXAMPLE_OBJC_APP_FILE=$REPOSITORY_ROOT/payjpiosexampleobjc.mobileprovision
7 |
--------------------------------------------------------------------------------
/scripts/carthage.sh:
--------------------------------------------------------------------------------
1 | # carthage.sh
2 | # Usage example: ./carthage.sh build --platform iOS
3 |
4 | set -euo pipefail
5 |
6 | xcconfig=$(mktemp /tmp/static.xcconfig.XXXXXX)
7 | trap 'rm -f "$xcconfig"' INT TERM HUP EXIT
8 |
9 | echo "IPHONEOS_DEPLOYMENT_TARGET = 12.0" >> $xcconfig
10 |
11 | export XCODE_XCCONFIG_FILE="$xcconfig"
12 | carthage "$@"
--------------------------------------------------------------------------------
/scripts/restore_signing_credential.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -ex
2 | echo -n $ENTERPRISE_P12_ENC | base64 --decode > $ENTERPRISE_P12_FILE
3 | echo -n $PROFILE_EXAMPLE_OBJC_APP_ENC | base64 --decode > $PROFILE_EXAMPLE_OBJC_APP_FILE
4 |
--------------------------------------------------------------------------------
/scripts/run-clang-format.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -ex
2 | ROOT="$(git rev-parse --show-toplevel)"
3 | find $ROOT/Sources/ -iname *.h -o -iname *.m | xargs clang-format -i -style=Google
4 | find $ROOT/example-objc/example-objc/ -iname *.h -o -iname *.m | xargs clang-format -i -style=Google
--------------------------------------------------------------------------------
/scripts/run-swift-format.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -ex
2 | ROOT="$(git rev-parse --show-toplevel)"
3 | swiftlint --fix --format $ROOT --config $ROOT/.swiftlint.yml
4 | swiftlint --fix --format $ROOT/example-swift/**/*.swift --config $ROOT/.swiftlint.yml
5 |
--------------------------------------------------------------------------------