diff --git a/SwiftValidator/Core/Validator.swift b/SwiftValidator/Core/Validator.swift index afc7895..4d42289 100644 --- a/SwiftValidator/Core/Validator.swift +++ b/SwiftValidator/Core/Validator.swift @@ -61,13 +61,13 @@ public class Validator { have undergone validation attempt. - parameter completion: Bool that is set to true when all fields have experienced validation attempt. - returns: No return value. - */ + */ private func validateAllFields(completion: (finished: Bool) -> Void) { errors = [:] for (textField, rule) in validations { if rule.remoteInfo != nil { - validateRemoteField(textField, completion: { status -> Void in + validateRemoteField(textField, callback: { error -> Void in self.completedValidationsCount = self.completedValidationsCount + 1 if self.completedValidationsCount == self.validations.count { // Sends validation back to validate() @@ -91,16 +91,17 @@ public class Validator { - parameter completion: Closure that holds the status of textField's validation. Is set to true after remote validation has ended, regardless of whether the validation was a success or failure. - returns: No return value. - */ - private func validateRemoteField(textField: UITextField, completion: (status: Bool) -> Void) { + */ + public func validateRemoteField(textField: UITextField, callback: (error: ValidationError?) -> Void) { if let fieldRule = validations[textField] { - // Carry on with validation as regular validation passed + // Carry on with validation only if regular validation passed if self.validateRegularField(fieldRule.textField) { - delegate!.remoteValidationRequest!(textField.text!, urlString: fieldRule.remoteInfo!.urlString, completion: { result -> Void in + delegate!.remoteValidationRequest?(textField.text!, urlString: fieldRule.remoteInfo!.urlString, completion: { result -> Void in if result { if let transform = self.successStyleTransform { transform(validationRule: fieldRule) } + callback(error: nil) } else { // Stop validation because remote validation failed // Validation Failed on remote call @@ -109,15 +110,10 @@ public class Validator { if let transform = self.errorStyleTransform { transform(validationError: error) } + callback(error: error) } - // Validation is over, so let validateAllFields(completion: (status: Bool)) know - completion(status: true) }) - } else { - // Validation is over, so let validateAllFields(completion: (status: Bool)) know - completion(status: true) } - } } @@ -133,15 +129,15 @@ public class Validator { errors[textField] = error if let transform = self.errorStyleTransform { transform(validationError: error) - return false } + return false } else { if let transform = self.successStyleTransform { if fieldRule.remoteInfo == nil { transform(validationRule: fieldRule) } - return true } + return true } } return false diff --git a/SwiftValidator/Rules/ValidationRule.swift b/SwiftValidator/Rules/ValidationRule.swift index b9b5a24..7aaeda5 100644 --- a/SwiftValidator/Rules/ValidationRule.swift +++ b/SwiftValidator/Rules/ValidationRule.swift @@ -30,14 +30,8 @@ public class ValidationRule { - parameter rules: array of Rule objects, which text field will be validated against. - returns: An initialized `ValidationRule` object, or nil if an object could not be created for some reason that would not result in an exception. */ - public init(textField: UITextField, rules:[Rule], errorLabel:UILabel?, remoteURLString: String? = nil){ - self.textField = textField - self.errorLabel = errorLabel - self.rules = rules - //self.remoteURLString = remoteURLString - } - public init(textField: UITextField, rules:[Rule], errorLabel:UILabel?, remoteInfo: (String, String)? = nil){ + public init(textField: UITextField, rules:[Rule], errorLabel:UILabel? = nil, remoteInfo: (String, String)? = nil){ self.textField = textField self.errorLabel = errorLabel self.rules = rules diff --git a/SwiftValidatorTests/SwiftValidatorTests.swift b/SwiftValidatorTests/SwiftValidatorTests.swift index c8a7574..c8519fc 100644 --- a/SwiftValidatorTests/SwiftValidatorTests.swift +++ b/SwiftValidatorTests/SwiftValidatorTests.swift @@ -37,6 +37,7 @@ class SwiftValidatorTests: XCTestCase { let REGISTER_TXT_FIELD = UITextField() let REGISTER_VALIDATOR = Validator() + let REGISTER_VALIDATOR2 = Validator() let REGISTER_RULES = [Rule]() let UNREGISTER_TXT_FIELD = UITextField() @@ -48,6 +49,40 @@ class SwiftValidatorTests: XCTestCase { let ERROR_LABEL = UILabel() + let URL_STRING = "http://localhost:8000/emails/" + let EMAIL_TAKEN_MESSAGE = "Email already taken" + + class FailureRemoteValidationViewController: UIViewController, ValidationDelegate { + func validationSuccessful() { + + } + + func validationFailed(errors: [UITextField : ValidationError]) { + + } + + func remoteValidationRequest(text: String, urlString: String, completion: (result: Bool) -> Void) { + completion(result: false) + } + } + + class SuccessRemoteValidationViewController: UIViewController, ValidationDelegate { + func validationSuccessful() { + + } + + func validationFailed(errors: [UITextField : ValidationError]) { + + } + + func remoteValidationRequest(text: String, urlString: String, completion: (result: Bool) -> Void) { + completion(result: true) + } + } + + let REGISTER_FAILURE_REMOTE_VALIDATION_DELEGATE = FailureRemoteValidationViewController() + let REGISTER_SUCCESS_REMOTE_VALIDATION_DELEGATE = SuccessRemoteValidationViewController() + override func setUp() { super.setUp() // Put setup code here. This method is called before the invocation of each test method in the class. @@ -370,6 +405,43 @@ class SwiftValidatorTests: XCTestCase { } } + /// Used to test validation on a single field that has remote validation + func testValidateSuccessSingleRemoteField() { + REGISTER_TXT_FIELD.text = VALID_EMAIL + REGISTER_VALIDATOR.registerField(REGISTER_TXT_FIELD, errorLabel: ERROR_LABEL, rules: [EmailRule()], remoteInfo: (urlString: URL_STRING, error: EMAIL_TAKEN_MESSAGE)) + REGISTER_VALIDATOR.delegate = REGISTER_SUCCESS_REMOTE_VALIDATION_DELEGATE + REGISTER_VALIDATOR.validateRemoteField(REGISTER_TXT_FIELD) { error -> Void in + XCTAssertNil(error) + } + } + + func testValidateFailureSingleRemoteField() { + REGISTER_TXT_FIELD.text = VALID_EMAIL + REGISTER_VALIDATOR.registerField(REGISTER_TXT_FIELD, errorLabel: ERROR_LABEL, rules: [EmailRule()], remoteInfo: (urlString: URL_STRING, error: EMAIL_TAKEN_MESSAGE)) + REGISTER_VALIDATOR.delegate = REGISTER_FAILURE_REMOTE_VALIDATION_DELEGATE + REGISTER_VALIDATOR.validateRemoteField(REGISTER_TXT_FIELD) { error -> Void in + XCTAssertNotNil(error) + } + } + + /// Used to test remote validation success + func testValidationSuccessOnRemoteSuccess() { + REGISTER_TXT_FIELD.text = VALID_EMAIL + REGISTER_VALIDATOR.registerField(REGISTER_TXT_FIELD, errorLabel: ERROR_LABEL, rules: [EmailRule()], remoteInfo: (urlString: URL_STRING, error: EMAIL_TAKEN_MESSAGE)) + REGISTER_VALIDATOR.delegate = REGISTER_SUCCESS_REMOTE_VALIDATION_DELEGATE + REGISTER_VALIDATOR.validate() + XCTAssert(REGISTER_VALIDATOR.errors.count == 0) + } + + /// Used to test remote validation failure + func testValidationFailOnRemoteFailure() { + REGISTER_TXT_FIELD.text = VALID_EMAIL + REGISTER_VALIDATOR.registerField(REGISTER_TXT_FIELD, errorLabel: ERROR_LABEL, rules: [EmailRule()], remoteInfo: (urlString: URL_STRING, error: EMAIL_TAKEN_MESSAGE)) + REGISTER_VALIDATOR.delegate = REGISTER_FAILURE_REMOTE_VALIDATION_DELEGATE + REGISTER_VALIDATOR.validate() + XCTAssert(REGISTER_VALIDATOR.errors.count == 1, "There is at least one error") + } + // MARK: Validate error field gets it's text set to the error, if supplied func testNoErrorMessageSet() { diff --git a/Validator/ViewController.swift b/Validator/ViewController.swift index 697ec73..e6ea627 100644 --- a/Validator/ViewController.swift +++ b/Validator/ViewController.swift @@ -59,6 +59,10 @@ class ViewController: UIViewController , ValidationDelegate, UITextFieldDelegate @IBAction func submitTapped(sender: AnyObject) { print("Validating...") + validator.validateField(UITextField()) { error -> Void in + + } + validator.validate() } @@ -93,7 +97,7 @@ class ViewController: UIViewController , ValidationDelegate, UITextFieldDelegate } func validationFailed(errors:[UITextField:ValidationError]) { - print("Validation FAILED!") + print("Validation FAILED!", validator.errors.count) } func remoteValidationRequest(text: String, urlString: String, completion: (result: Bool) -> Void) {