Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix SonarCloud "Cognitive Complexity" warning in CreditCardPaymentController #296

Merged
merged 3 commits into from
Jun 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions OmiseSDK/Sources/3DS/NetceteraThreeDSController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ func apiKey(config: NetceteraConfig) throws -> String {
key: decryptionKey
)

// swiftlint:disable:next non_optional_string_data_conversion
if let apiKey = String(data: encrypted, encoding: .utf8) {
return apiKey
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -736,104 +736,28 @@ extension CreditCardPaymentController {
updateSupplementaryUI()
}

// swiftlint:disable:next function_body_length
func configureAccessibility() {
formLabels.forEach {
$0.adjustsFontForContentSizeCategory = true
}
formFields.forEach {
$0.adjustsFontForContentSizeCategory = true
}

let fields = formFields

formLabels.forEach { $0.adjustsFontForContentSizeCategory = true }
formFields.forEach { $0.adjustsFontForContentSizeCategory = true }
submitButton.titleLabel?.adjustsFontForContentSizeCategory = true

// swiftlint:disable:next function_body_length
func accessiblityElementAfter(
_ element: NSObjectProtocol?,
matchingPredicate predicate: (OmiseTextField) -> Bool,
direction: UIAccessibilityCustomRotor.Direction
) -> NSObjectProtocol? {
guard let element = element else {
switch direction {
case .previous:
return fields.reversed().first(where: predicate)?.accessibilityElements?.last as? NSObjectProtocol
?? fields.reversed().first(where: predicate)
case .next:
fallthrough
@unknown default:
return fields.first(where: predicate)?.accessibilityElements?.first as? NSObjectProtocol
?? fields.first(where: predicate)
}
}

let fieldOfElement = fields.first { field in
guard let accessibilityElements = field.accessibilityElements as? [NSObjectProtocol] else {
return element === field
}

return accessibilityElements.contains { $0 === element }
} ?? cardNumberTextField! // swiftlint:disable:this force_unwrapping

func filedAfter(
_ field: OmiseTextField,
matchingPredicate predicate: (OmiseTextField) -> Bool,
direction: UIAccessibilityCustomRotor.Direction
) -> OmiseTextField? {
guard let indexOfField = fields.firstIndex(of: field) else { return nil }
switch direction {
case .previous:
return fields[fields.startIndex..<indexOfField].reversed().first(where: predicate)
case .next: fallthrough
@unknown default:
return fields[fields.index(after: indexOfField)...].first(where: predicate)
}
}

let nextField = filedAfter(fieldOfElement, matchingPredicate: predicate, direction: direction)

guard let currentAccessibilityElements = (fieldOfElement.accessibilityElements as? [NSObjectProtocol]),
let indexOfAccessibilityElement = currentAccessibilityElements.firstIndex(where: { $0 === element }) else {
switch direction {
case .previous:
return nextField?.accessibilityElements?.last as? NSObjectProtocol ?? nextField
case .next:
fallthrough
@unknown default:
return nextField?.accessibilityElements?.first as? NSObjectProtocol ?? nextField
}
}

switch direction {
case .previous:
if predicate(fieldOfElement) && indexOfAccessibilityElement > currentAccessibilityElements.startIndex {
return currentAccessibilityElements[currentAccessibilityElements.index(before: indexOfAccessibilityElement)]
} else {
return nextField?.accessibilityElements?.last as? NSObjectProtocol ?? nextField
}
case .next:
fallthrough
@unknown default:
if predicate(fieldOfElement) && indexOfAccessibilityElement < currentAccessibilityElements.endIndex - 1 {
return currentAccessibilityElements[currentAccessibilityElements.index(after: indexOfAccessibilityElement)]
} else {
return nextField?.accessibilityElements?.first as? NSObjectProtocol ?? nextField
}
}
}

/* write unit tests for the code below */
accessibilityCustomRotors = [
UIAccessibilityCustomRotor(name: "Fields") { (predicate) -> UIAccessibilityCustomRotorItemResult? in
return accessiblityElementAfter(predicate.currentItem.targetElement,
matchingPredicate: { _ in true },
direction: predicate.searchDirection)
UIAccessibilityCustomRotor(name: "Fields") { [weak self] (predicate) -> UIAccessibilityCustomRotorItemResult? in
let fields = self?.formFields ?? []
return self?.accessibilityElementAfter(predicate.currentItem.targetElement,
fields: fields,
matchingPredicate: { _ in true },
direction: predicate.searchDirection)
.map { UIAccessibilityCustomRotorItemResult(targetElement: $0, targetRange: nil) }
},
UIAccessibilityCustomRotor(name: "Invalid Data Fields") { (predicate) -> UIAccessibilityCustomRotorItemResult? in
return accessiblityElementAfter(predicate.currentItem.targetElement,
matchingPredicate: { !$0.isValid },
direction: predicate.searchDirection)

UIAccessibilityCustomRotor(name: "Invalid Data Fields") { [weak self] (predicate) -> UIAccessibilityCustomRotorItemResult? in
let fields = self?.formFields ?? []
return self?.accessibilityElementAfter(predicate.currentItem.targetElement,
fields: fields,
matchingPredicate: { !$0.isValid },
direction: predicate.searchDirection)
.map { UIAccessibilityCustomRotorItemResult(targetElement: $0, targetRange: nil) }
}
]
Expand Down Expand Up @@ -1025,3 +949,101 @@ extension CreditCardPaymentController {
view.endEditing(true)
}
}

extension CreditCardPaymentController {
// Move out to the same level as configureAccessibility
func accessibilityElementAfter(
_ element: NSObjectProtocol?,
fields: [OmiseTextField],
matchingPredicate predicate: (OmiseTextField) -> Bool,
direction: UIAccessibilityCustomRotor.Direction
) -> NSObjectProtocol? {
guard let element = element else {
return handleNoElement(direction, fields: fields, matchingPredicate: predicate)
}
return findAccessibilityElement(element, fields: fields, matchingPredicate: predicate, direction: direction)
}

// This could be the new helper function handling cases when no element is provided
func handleNoElement(
_ direction: UIAccessibilityCustomRotor.Direction,
fields: [OmiseTextField],
matchingPredicate predicate: (OmiseTextField) -> Bool
) -> NSObjectProtocol? {

switch direction {
case .previous:
return fields.reversed().first(where: predicate)?.accessibilityElements?.last as? NSObjectProtocol
?? fields.reversed().first(where: predicate)
case .next:
fallthrough
@unknown default:
return fields.first(where: predicate)?.accessibilityElements?.first as? NSObjectProtocol
?? fields.first(where: predicate)
}
}

// This could be another helper function finding an accessibility element
func findAccessibilityElement(
_ element: NSObjectProtocol,
fields: [OmiseTextField],
matchingPredicate predicate: (OmiseTextField) -> Bool,
direction: UIAccessibilityCustomRotor.Direction
) -> NSObjectProtocol? {
let fieldOfElement = fields.first { field in
guard let accessibilityElements = field.accessibilityElements as? [NSObjectProtocol] else {
return element === field
}

return accessibilityElements.contains { $0 === element }
} ?? cardNumberTextField! // swiftlint:disable:this force_unwrapping

let nextField = filedAfter(fieldOfElement, fields: fields, matchingPredicate: predicate, direction: direction)

guard let currentAccessibilityElements = (fieldOfElement.accessibilityElements as? [NSObjectProtocol]),
let indexOfAccessibilityElement = currentAccessibilityElements.firstIndex(where: { $0 === element }) else {
switch direction {
case .previous:
return nextField?.accessibilityElements?.last as? NSObjectProtocol ?? nextField
case .next:
fallthrough
@unknown default:
return nextField?.accessibilityElements?.first as? NSObjectProtocol ?? nextField
}
}

switch direction {
case .previous:
if predicate(fieldOfElement) && indexOfAccessibilityElement > currentAccessibilityElements.startIndex {
return currentAccessibilityElements[currentAccessibilityElements.index(before: indexOfAccessibilityElement)]
} else {
return nextField?.accessibilityElements?.last as? NSObjectProtocol ?? nextField
}
case .next:
fallthrough
@unknown default:
if predicate(fieldOfElement) && indexOfAccessibilityElement < currentAccessibilityElements.endIndex - 1 {
return currentAccessibilityElements[currentAccessibilityElements.index(after: indexOfAccessibilityElement)]
} else {
return nextField?.accessibilityElements?.first as? NSObjectProtocol ?? nextField
}
}
}

func filedAfter(
_ field: OmiseTextField,
fields: [OmiseTextField],
matchingPredicate predicate: (OmiseTextField) -> Bool,
direction: UIAccessibilityCustomRotor.Direction
) -> OmiseTextField? {
guard let indexOfField = fields.firstIndex(of: field) else { return nil }
switch direction {
case .previous:
return fields[fields.startIndex..<indexOfField].reversed().first(where: predicate)
case .next: fallthrough
@unknown default:
return fields[fields.index(after: indexOfField)...].first(where: predicate)
}
}

}
5 changes: 3 additions & 2 deletions OmiseSDKTests/3DS/SHA512Tests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ class SHA512Tests: XCTestCase {

func testSHA512EmptyString() {
let emptyString = ""

// expected SHA-512 hash of empty string
let expectedHash = Data(
// swiftlint:disable:next multiline_literal_brackets
[ // expected SHA-512 hash of empty string
[
0xcf, 0x83, 0xe1, 0x35, 0x7e, 0xef, 0xb8, 0xbd,
0xf1, 0x54, 0x28, 0x50, 0xd6, 0x6d, 0x80, 0x07,
0xd6, 0x20, 0xe4, 0x05, 0x0b, 0x57, 0x15, 0xdc,
Expand Down
2 changes: 2 additions & 0 deletions OmiseSDKTests/ClientTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class ClientTests: XCTestCase {
defer { expectation.fulfill() }

func validateURLRequest() {
// swiftlint:disable:next non_optional_string_data_conversion
if let data = urlRequest.httpBody, let jsonString = String(data: data, encoding: .utf8) {
do {
let decodedCardPayload: CreateTokenPayload = try parse(jsonString: jsonString)
Expand Down Expand Up @@ -88,6 +89,7 @@ class ClientTests: XCTestCase {
defer { expectation.fulfill() }

func validateURLRequest() {
// swiftlint:disable:next non_optional_string_data_conversion
if let data = urlRequest.httpBody, let jsonString = String(data: data, encoding: .utf8) {
do {
let decodedCardPayload: CreateSourcePayload = try parse(jsonString: jsonString)
Expand Down
1 change: 1 addition & 0 deletions OmiseSDKTests/Helpers/SampleData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ func encodeToJson<T: Encodable>(_ object: T) throws -> String {
encoder.outputFormatting = [.sortedKeys]

let data = try encoder.encode(object)
// swiftlint:disable:next non_optional_string_data_conversion
guard let result = String(data: data, encoding: .utf8) else {
throw DataToStringCastError()
}
Expand Down
1 change: 1 addition & 0 deletions OmiseSDKTests/Helpers/String+JSON.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ extension String {
encoder.outputFormatting = [.sortedKeys]

let data = try encoder.encode(encodable)
// swiftlint:disable:next non_optional_string_data_conversion
guard let string = String(data: data, encoding: .utf8) else {
throw StringFromDateError()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class SourceTests: XCTestCase {
/// Test Source.Payload's Codable protocol
func validatePayloadCodable(_ payload: Payment) throws {
let encodedPayload = try JSONEncoder().encode(payload)
// swiftlint:disable:next non_optional_string_data_conversion
let encodedPayloadJson = String(data: encodedPayload, encoding: .utf8) ?? ""
if payload.sourceType == .duitNowOBW {
print(encodedPayloadJson)
Expand Down
8 changes: 8 additions & 0 deletions dev.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@
75D13E1D2B86FF8C0073A831 /* CreditCardPaymentDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75D13E1C2B86FF8C0073A831 /* CreditCardPaymentDelegate.swift */; };
75D13E202B8703F80073A831 /* CreditCardPaymentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75D13E1E2B8703F70073A831 /* CreditCardPaymentController.swift */; };
75D13E212B8703F80073A831 /* CreditCardPaymentController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 75D13E1F2B8703F80073A831 /* CreditCardPaymentController.xib */; };
75D2C3EE2C19A80C006072D9 /* ThreeDS_SDK in Frameworks */ = {isa = PBXBuildFile; productRef = 75D2C3ED2C19A80C006072D9 /* ThreeDS_SDK */; };
75D4E7062C05F50500ECCE72 /* OmiseErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75D4E7052C05F50500ECCE72 /* OmiseErrorTests.swift */; };
75DAD8902A0BB8D80098AF96 /* LocalConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75DAD88F2A0BB8D80098AF96 /* LocalConfig.swift */; };
75E0EB712B7A904100E3198A /* SourceFlowTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75E0EB702B7A904100E3198A /* SourceFlowTests.swift */; };
Expand Down Expand Up @@ -511,6 +512,7 @@
buildActionMask = 2147483647;
files = (
75D13E0F2B8678530073A831 /* OmiseSwiftUIKit in Frameworks */,
75D2C3EE2C19A80C006072D9 /* ThreeDS_SDK in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -1294,6 +1296,7 @@
name = ExampleApp;
packageProductDependencies = (
75D13E0E2B8678530073A831 /* OmiseSwiftUIKit */,
75D2C3ED2C19A80C006072D9 /* ThreeDS_SDK */,
);
productName = ExampleApp;
productReference = 22D4809D1D0EB29C00544CE1 /* ExampleApp.app */;
Expand Down Expand Up @@ -2229,6 +2232,11 @@
isa = XCSwiftPackageProductDependency;
productName = OmiseSwiftUIKit;
};
75D2C3ED2C19A80C006072D9 /* ThreeDS_SDK */ = {
isa = XCSwiftPackageProductDependency;
package = 758A4E822BE38AC3005E7B5A /* XCRemoteSwiftPackageReference "SPM" */;
productName = ThreeDS_SDK;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 2259310F1CE3210700841B86 /* Project object */;
Expand Down
Loading