diff --git a/FormTextField/Sources/FormTextField/InputValidator/EuropeanPhoneNumberInputValidator.swift b/FormTextField/Sources/FormTextField/InputValidator/EuropeanPhoneNumberInputValidator.swift index 2d0efa3..c25fc37 100644 --- a/FormTextField/Sources/FormTextField/InputValidator/EuropeanPhoneNumberInputValidator.swift +++ b/FormTextField/Sources/FormTextField/InputValidator/EuropeanPhoneNumberInputValidator.swift @@ -21,8 +21,6 @@ public struct EuropeanPhoneNumberInputValidator: InputValidatable { } if valid { - guard let replacementString = replacementString, let range = range else { return false } - let composedString = self.composedString(replacementString, fullString: fullString, inRange: range) valid = validatePartialEuropeanPhoneNumber(composedString) } diff --git a/FormTextField/Sources/FormTextField/InputValidator/MixedPhoneNumberInputValidator.swift b/FormTextField/Sources/FormTextField/InputValidator/MixedPhoneNumberInputValidator.swift index a14ee69..1d3b643 100644 --- a/FormTextField/Sources/FormTextField/InputValidator/MixedPhoneNumberInputValidator.swift +++ b/FormTextField/Sources/FormTextField/InputValidator/MixedPhoneNumberInputValidator.swift @@ -10,9 +10,15 @@ public struct MixedPhoneNumberInputValidator: InputValidatable { self.validation = validation } - public func validateReplacementString(_ replacementString: String?, fullString: String?, inRange range: NSRange?) -> Bool { - guard let replacementString = replacementString, let range = range else { return false } + public func validateString(_ string: String) -> Bool { + if string.hasPrefix("+") { + return europeanValidator.validateString(string) + } else { + return norwegianValidator.validateString(string) + } + } + public func validateReplacementString(_ replacementString: String?, fullString: String?, inRange range: NSRange?) -> Bool { let composedString = self.composedString(replacementString, fullString: fullString, inRange: range) if composedString.hasPrefix("+") { diff --git a/FormTextField/Sources/FormTextField/InputValidator/NorwegianPhoneNumberInputValidator.swift b/FormTextField/Sources/FormTextField/InputValidator/NorwegianPhoneNumberInputValidator.swift index d02cdeb..4ebd242 100644 --- a/FormTextField/Sources/FormTextField/InputValidator/NorwegianPhoneNumberInputValidator.swift +++ b/FormTextField/Sources/FormTextField/InputValidator/NorwegianPhoneNumberInputValidator.swift @@ -18,8 +18,6 @@ public struct NorwegianPhoneNumberInputValidator: InputValidatable { } if valid { - guard let replacementString = replacementString, let range = range else { return false } - let composedString = self.composedString(replacementString, fullString: fullString, inRange: range) valid = validatePartialNorwegianPhoneNumber(composedString) } @@ -29,34 +27,8 @@ public struct NorwegianPhoneNumberInputValidator: InputValidatable { private func validatePartialNorwegianPhoneNumber(_ phoneNumber: String) -> Bool { guard !phoneNumber.isEmpty else { return true } - - if phoneNumber.count == 8 { - return validateNorwegianPhoneNumber(phoneNumber) - } - - if phoneNumber.hasPrefix("4") { - if phoneNumber.count == 1 { - return true // Just "4" is valid as partial input - } else if phoneNumber.hasPrefix("48") { - return true // Longer sequences must start with "48" - } else { - return false // Any other "4x" is invalid - } - } - - let validStartDigits: Set = ["2", "3", "9"] - if let firstDigit = phoneNumber.first { - return validStartDigits.contains(firstDigit) - } - - return false - } - private func validateNorwegianPhoneNumber(_ phoneNumber: String) -> Bool { - let phoneNumberPattern = "^[2349]\\d{7}$|^48\\d{6}$" - let regex = try! NSRegularExpression(pattern: phoneNumberPattern) - let range = NSRange(location: 0, length: phoneNumber.utf16.count) - return regex.firstMatch(in: phoneNumber, options: [], range: range) != nil + return phoneNumber.hasPrefix("4") || phoneNumber.hasPrefix("9") } private func composedString(_ replacementString: String?, fullString: String?, inRange range: NSRange?) -> String { diff --git a/FormTextField/Tests/FormTextFieldTests/InputValidatorTests/MixedPhoneNumberInputValidatorTests.swift b/FormTextField/Tests/FormTextFieldTests/InputValidatorTests/MixedPhoneNumberInputValidatorTests.swift index 9b64606..8679c51 100644 --- a/FormTextField/Tests/FormTextFieldTests/InputValidatorTests/MixedPhoneNumberInputValidatorTests.swift +++ b/FormTextField/Tests/FormTextFieldTests/InputValidatorTests/MixedPhoneNumberInputValidatorTests.swift @@ -6,13 +6,21 @@ class MixedPhoneNumberInputValidatorTests: XCTestCase { func testNorwegianPhoneNumbers() { let validator = MixedPhoneNumberInputValidator() + XCTAssertTrue(validator.validateString("91234567")) + XCTAssertTrue(validator.validateString("48123456")) + XCTAssertTrue(validator.validateString("98765432")) + + XCTAssertFalse(validator.validateString("11234567")) + XCTAssertFalse(validator.validateString("28123456")) + XCTAssertFalse(validator.validateString("9876543")) + // Test valid numbers - XCTAssertTrue(validator.validateReplacementString("23456789", fullString: "", inRange: NSRange(location: 0, length: 0))) XCTAssertTrue(validator.validateReplacementString("91234567", fullString: "", inRange: NSRange(location: 0, length: 0))) XCTAssertTrue(validator.validateReplacementString("48123456", fullString: "", inRange: NSRange(location: 0, length: 0))) XCTAssertTrue(validator.validateReplacementString("98765432", fullString: "", inRange: NSRange(location: 0, length: 0))) // Valid number starting with 9 // Test invalid numbers + XCTAssertFalse(validator.validateReplacementString("23456789", fullString: "", inRange: NSRange(location: 0, length: 0))) XCTAssertFalse(validator.validateReplacementString("12345678", fullString: "", inRange: NSRange(location: 0, length: 0))) XCTAssertFalse(validator.validateReplacementString("56789012", fullString: "", inRange: NSRange(location: 0, length: 0))) XCTAssertFalse(validator.validateReplacementString("00000000", fullString: "", inRange: NSRange(location: 0, length: 0))) @@ -23,27 +31,27 @@ class MixedPhoneNumberInputValidatorTests: XCTestCase { // Test partial valid sequences XCTAssertTrue(validator.validateReplacementString("4", fullString: "", inRange: NSRange(location: 0, length: 0))) // Starts with 4 - XCTAssertTrue(validator.validateReplacementString("2", fullString: "", inRange: NSRange(location: 0, length: 0))) // Starts with 2 XCTAssertTrue(validator.validateReplacementString("9", fullString: "", inRange: NSRange(location: 0, length: 0))) // Starts with 9 // Test partial valid sequences (2 characters) XCTAssertTrue(validator.validateReplacementString("8", fullString: "4", inRange: NSRange(location: 1, length: 0))) // Starts with 4, then 8 XCTAssertTrue(validator.validateReplacementString("1", fullString: "9", inRange: NSRange(location: 1, length: 0))) // Starts with 9, then 1 - XCTAssertTrue(validator.validateReplacementString("3", fullString: "2", inRange: NSRange(location: 1, length: 0))) // Starts with 2, then 3 XCTAssertTrue(validator.validateReplacementString("8", fullString: "49", inRange: NSRange(location: 1, length: 0))) // "49" becomes "489", which is valid + XCTAssertTrue(validator.validateReplacementString("9", fullString: "49", inRange: NSRange(location: 2, length: 0))) // "49" becomes "499" + XCTAssertTrue(validator.validateReplacementString("8", fullString: "49", inRange: NSRange(location: 2, length: 0))) // "49" becomes "498" // Test partial invalid sequences (1 character) XCTAssertFalse(validator.validateReplacementString("1", fullString: "", inRange: NSRange(location: 0, length: 0))) // Invalid start XCTAssertFalse(validator.validateReplacementString("5", fullString: "", inRange: NSRange(location: 0, length: 0))) // Invalid start XCTAssertFalse(validator.validateReplacementString("0", fullString: "", inRange: NSRange(location: 0, length: 0))) // Invalid start + XCTAssertFalse(validator.validateReplacementString("2", fullString: "", inRange: NSRange(location: 0, length: 0))) // Starts with 2 // Test partial invalid sequences (2 characters) - XCTAssertFalse(validator.validateReplacementString("9", fullString: "49", inRange: NSRange(location: 2, length: 0))) // "49" becomes "499", which is invalid - XCTAssertFalse(validator.validateReplacementString("8", fullString: "49", inRange: NSRange(location: 2, length: 0))) // "49" becomes "498", which is invalid + XCTAssertFalse(validator.validateReplacementString("3", fullString: "2", inRange: NSRange(location: 1, length: 0))) // Starts with 2, then 3 // Test valid sequences extended (3 characters) XCTAssertTrue(validator.validateReplacementString("1", fullString: "481", inRange: NSRange(location: 3, length: 0))) // "481" is a valid sequence - XCTAssertTrue(validator.validateReplacementString("5", fullString: "235", inRange: NSRange(location: 3, length: 0))) // "235" is a valid sequence + XCTAssertFalse(validator.validateReplacementString("5", fullString: "235", inRange: NSRange(location: 3, length: 0))) // "235" is an invalid sequence // Test other invalid patterns XCTAssertFalse(validator.validateReplacementString("12345678", fullString: "", inRange: NSRange(location: 0, length: 0))) // Invalid start @@ -52,6 +60,15 @@ class MixedPhoneNumberInputValidatorTests: XCTestCase { func testEuropeanPhoneNumbers() { let validator = MixedPhoneNumberInputValidator() + XCTAssertTrue(validator.validateString("+447911123456")) + XCTAssertTrue(validator.validateString("+33612345678")) + XCTAssertTrue(validator.validateString("+491711234567")) + + XCTAssertFalse(validator.validateString("+336123456789012345")) + XCTAssertFalse(validator.validateString("+0044711123456")) + XCTAssertFalse(validator.validateString("+4479111234567890123456")) + XCTAssertFalse(validator.validateString("+4479")) + // Test valid European numbers XCTAssertTrue(validator.validateReplacementString("+447911123456", fullString: "", inRange: NSRange(location: 0, length: 0))) // UK XCTAssertTrue(validator.validateReplacementString("+33612345678", fullString: "", inRange: NSRange(location: 0, length: 0))) // France diff --git a/FormTextField/Tests/FormTextFieldTests/InputValidatorTests/NorwegianPhoneNumberInputValidatorTests.swift b/FormTextField/Tests/FormTextFieldTests/InputValidatorTests/NorwegianPhoneNumberInputValidatorTests.swift deleted file mode 100644 index e61d3c7..0000000 --- a/FormTextField/Tests/FormTextFieldTests/InputValidatorTests/NorwegianPhoneNumberInputValidatorTests.swift +++ /dev/null @@ -1,52 +0,0 @@ -import XCTest -import FormTextField -import Foundation - -class NorwegianPhoneNumberInputValidatorTests: XCTestCase { - func testNorwegianPhoneNumberValidator() { - let validator = NorwegianPhoneNumberInputValidator() - - // Test valid numbers - XCTAssertTrue(validator.validateReplacementString("23456789", fullString: "", inRange: NSRange(location: 0, length: 0))) - XCTAssertTrue(validator.validateReplacementString("91234567", fullString: "", inRange: NSRange(location: 0, length: 0))) - XCTAssertTrue(validator.validateReplacementString("48123456", fullString: "", inRange: NSRange(location: 0, length: 0))) - XCTAssertTrue(validator.validateReplacementString("98765432", fullString: "", inRange: NSRange(location: 0, length: 0))) // Valid number starting with 9 - - // Test invalid numbers - XCTAssertFalse(validator.validateReplacementString("12345678", fullString: "", inRange: NSRange(location: 0, length: 0))) - XCTAssertFalse(validator.validateReplacementString("56789012", fullString: "", inRange: NSRange(location: 0, length: 0))) - XCTAssertFalse(validator.validateReplacementString("00000000", fullString: "", inRange: NSRange(location: 0, length: 0))) - - // Test length - XCTAssertFalse(validator.validateReplacementString("1234567", fullString: "", inRange: NSRange(location: 0, length: 0))) // Too short - XCTAssertFalse(validator.validateReplacementString("123456789", fullString: "", inRange: NSRange(location: 0, length: 0))) // Too long - - // Test partial valid sequences - XCTAssertTrue(validator.validateReplacementString("", fullString: "2", inRange: NSRange(location: 0, length: 1))) // Was 2 to become empty - XCTAssertTrue(validator.validateReplacementString("4", fullString: "", inRange: NSRange(location: 0, length: 0))) // Starts with 4 - XCTAssertTrue(validator.validateReplacementString("2", fullString: "", inRange: NSRange(location: 0, length: 0))) // Starts with 2 - XCTAssertTrue(validator.validateReplacementString("9", fullString: "", inRange: NSRange(location: 0, length: 0))) // Starts with 9 - - // Test partial valid sequences (2 characters) - XCTAssertTrue(validator.validateReplacementString("8", fullString: "4", inRange: NSRange(location: 1, length: 0))) // Starts with 4, then 8 - XCTAssertTrue(validator.validateReplacementString("1", fullString: "9", inRange: NSRange(location: 1, length: 0))) // Starts with 9, then 1 - XCTAssertTrue(validator.validateReplacementString("3", fullString: "2", inRange: NSRange(location: 1, length: 0))) // Starts with 2, then 3 - XCTAssertTrue(validator.validateReplacementString("8", fullString: "49", inRange: NSRange(location: 1, length: 0))) // "49" becomes "489", which is valid - - // Test partial invalid sequences (1 character) - XCTAssertFalse(validator.validateReplacementString("1", fullString: "", inRange: NSRange(location: 0, length: 0))) // Invalid start - XCTAssertFalse(validator.validateReplacementString("5", fullString: "", inRange: NSRange(location: 0, length: 0))) // Invalid start - XCTAssertFalse(validator.validateReplacementString("0", fullString: "", inRange: NSRange(location: 0, length: 0))) // Invalid start - - // Test partial invalid sequences (2 characters) - XCTAssertFalse(validator.validateReplacementString("9", fullString: "49", inRange: NSRange(location: 2, length: 0))) // "49" becomes "499", which is invalid - XCTAssertFalse(validator.validateReplacementString("8", fullString: "49", inRange: NSRange(location: 2, length: 0))) // "49" becomes "498", which is invalid - - // Test valid sequences extended (3 characters) - XCTAssertTrue(validator.validateReplacementString("1", fullString: "481", inRange: NSRange(location: 3, length: 0))) // "481" is a valid sequence - XCTAssertTrue(validator.validateReplacementString("5", fullString: "235", inRange: NSRange(location: 3, length: 0))) // "235" is a valid sequence - - // Test other invalid patterns - XCTAssertFalse(validator.validateReplacementString("12345678", fullString: "", inRange: NSRange(location: 0, length: 0))) // Invalid start - } -} diff --git a/Vanilla/Vanilla/ViewController.swift b/Vanilla/Vanilla/ViewController.swift index 38f6577..30f8e15 100644 --- a/Vanilla/Vanilla/ViewController.swift +++ b/Vanilla/Vanilla/ViewController.swift @@ -32,11 +32,9 @@ class ViewController: UIViewController { ]) } - var reverse = false - @objc func textFieldDidUpdate() { let phoneNumber = textField.text ?? "" - textField.backgroundColor = self.inputValidator.validateString(phoneNumber) ? .secondaryLabel : .secondarySystemFill + textField.backgroundColor = self.inputValidator.validateString(phoneNumber) ? .systemMint : .secondarySystemBackground } } @@ -47,8 +45,6 @@ extension ViewController: UITextFieldDelegate { return true } - self.reverse = string.isEmpty - return self.inputValidator.validateReplacementString(string, fullString: textField.text, inRange: range) } }