// // ValidationHelpersTests.swift // honeyDueTests // // Unit tests for ValidationHelpers, FormValidator, and related types. // import Testing @testable import honeyDue // MARK: - ValidationResult Tests struct ValidationResultTests { @Test func validResultIsValid() { let result = ValidationResult.valid #expect(result.isValid) #expect(result.errorMessage == nil) } @Test func invalidResultIsNotValid() { let result = ValidationResult.invalid("Error") #expect(!result.isValid) #expect(result.errorMessage == "Error") } } // MARK: - Email Validation Tests struct EmailValidationTests { @Test func validEmailPasses() { let result = ValidationHelpers.validateEmail("user@example.com") #expect(result.isValid) } @Test func emptyEmailFails() { let result = ValidationHelpers.validateEmail("") #expect(!result.isValid) #expect(result.errorMessage == "Email is required") } @Test func whitespaceOnlyEmailFails() { let result = ValidationHelpers.validateEmail(" ") #expect(!result.isValid) #expect(result.errorMessage == "Email is required") } @Test func emailWithoutAtSignFails() { let result = ValidationHelpers.validateEmail("userexample.com") #expect(!result.isValid) #expect(result.errorMessage == "Please enter a valid email address") } @Test func emailWithoutDomainFails() { let result = ValidationHelpers.validateEmail("user@") #expect(!result.isValid) } @Test func emailWithSubdomainPasses() { let result = ValidationHelpers.validateEmail("user@mail.example.com") #expect(result.isValid) } @Test func emailWithPlusAddressingPasses() { let result = ValidationHelpers.validateEmail("user+tag@example.com") #expect(result.isValid) } @Test func emailWithDotsInLocalPartPasses() { let result = ValidationHelpers.validateEmail("first.last@example.com") #expect(result.isValid) } } // MARK: - Password Validation Tests struct PasswordValidationTests { @Test func validPasswordPasses() { let result = ValidationHelpers.validatePassword("StrongPass1") #expect(result.isValid) } @Test func emptyPasswordFails() { let result = ValidationHelpers.validatePassword("") #expect(!result.isValid) #expect(result.errorMessage == "Password is required") } @Test func shortPasswordFails() { let result = ValidationHelpers.validatePassword("short") #expect(!result.isValid) #expect(result.errorMessage == "Password must be at least 8 characters") } @Test func exactMinLengthPasswordPasses() { let result = ValidationHelpers.validatePassword("12345678") #expect(result.isValid) } @Test func customMinLengthEnforced() { let result = ValidationHelpers.validatePassword("1234", minLength: 6) #expect(!result.isValid) #expect(result.errorMessage == "Password must be at least 6 characters") } @Test func customMinLengthPassesWhenMet() { let result = ValidationHelpers.validatePassword("123456", minLength: 6) #expect(result.isValid) } } // MARK: - Password Confirmation Tests struct PasswordConfirmationTests { @Test func matchingPasswordsPasses() { let result = ValidationHelpers.validatePasswordConfirmation("password123", confirmation: "password123") #expect(result.isValid) } @Test func mismatchedPasswordsFails() { let result = ValidationHelpers.validatePasswordConfirmation("password123", confirmation: "password456") #expect(!result.isValid) #expect(result.errorMessage == "Passwords do not match") } @Test func emptyConfirmationFails() { let result = ValidationHelpers.validatePasswordConfirmation("password123", confirmation: "") #expect(!result.isValid) } @Test func caseSensitiveMismatchFails() { let result = ValidationHelpers.validatePasswordConfirmation("Password", confirmation: "password") #expect(!result.isValid) } } // MARK: - Name Validation Tests struct NameValidationTests { @Test func validNamePasses() { let result = ValidationHelpers.validateName("John") #expect(result.isValid) } @Test func emptyNameFails() { let result = ValidationHelpers.validateName("") #expect(!result.isValid) #expect(result.errorMessage == "Name is required") } @Test func singleCharNameFails() { let result = ValidationHelpers.validateName("J") #expect(!result.isValid) #expect(result.errorMessage == "Name must be at least 2 characters") } @Test func twoCharNamePasses() { let result = ValidationHelpers.validateName("Jo") #expect(result.isValid) } @Test func customFieldNameInError() { let result = ValidationHelpers.validateName("", fieldName: "Username") #expect(result.errorMessage == "Username is required") } @Test func whitespaceOnlyNameFails() { let result = ValidationHelpers.validateName(" ") #expect(!result.isValid) } } // MARK: - Phone Validation Tests struct PhoneValidationTests { @Test func validUSPhonePasses() { let result = ValidationHelpers.validatePhone("(555) 123-4567") #expect(result.isValid) } @Test func emptyPhoneFails() { let result = ValidationHelpers.validatePhone("") #expect(!result.isValid) #expect(result.errorMessage == "Phone number is required") } @Test func shortPhoneFails() { let result = ValidationHelpers.validatePhone("12345") #expect(!result.isValid) #expect(result.errorMessage == "Please enter a valid phone number") } @Test func phoneWithCountryCodePasses() { let result = ValidationHelpers.validatePhone("+1 555-123-4567") #expect(result.isValid) } @Test func digitsOnlyPhonePasses() { let result = ValidationHelpers.validatePhone("5551234567") #expect(result.isValid) } } // MARK: - Required Field Validation Tests struct RequiredFieldValidationTests { @Test func nonEmptyPasses() { let result = ValidationHelpers.validateRequired("value", fieldName: "Field") #expect(result.isValid) } @Test func emptyFails() { let result = ValidationHelpers.validateRequired("", fieldName: "Title") #expect(!result.isValid) #expect(result.errorMessage == "Title is required") } @Test func whitespaceOnlyFails() { let result = ValidationHelpers.validateRequired(" ", fieldName: "Description") #expect(!result.isValid) } } // MARK: - Number Validation Tests struct NumberValidationTests { @Test func validNumberPasses() { let result = ValidationHelpers.validateNumber("42.5", fieldName: "Cost") #expect(result.isValid) } @Test func emptyNumberFails() { let result = ValidationHelpers.validateNumber("", fieldName: "Cost") #expect(!result.isValid) #expect(result.errorMessage == "Cost is required") } @Test func nonNumericFails() { let result = ValidationHelpers.validateNumber("abc", fieldName: "Cost") #expect(!result.isValid) #expect(result.errorMessage == "Cost must be a valid number") } @Test func belowMinFails() { let result = ValidationHelpers.validateNumber("5", fieldName: "Cost", min: 10) #expect(!result.isValid) #expect(result.errorMessage == "Cost must be at least 10.0") } @Test func aboveMaxFails() { let result = ValidationHelpers.validateNumber("100", fieldName: "Cost", max: 50) #expect(!result.isValid) #expect(result.errorMessage == "Cost must be at most 50.0") } @Test func withinRangePasses() { let result = ValidationHelpers.validateNumber("25", fieldName: "Cost", min: 10, max: 50) #expect(result.isValid) } @Test func negativeNumberValidated() { let result = ValidationHelpers.validateNumber("-5", fieldName: "Value", min: 0) #expect(!result.isValid) } } // MARK: - Integer Validation Tests struct IntegerValidationTests { @Test func validIntegerPasses() { let result = ValidationHelpers.validateInteger("42", fieldName: "Bedrooms") #expect(result.isValid) } @Test func decimalFails() { let result = ValidationHelpers.validateInteger("3.5", fieldName: "Bedrooms") #expect(!result.isValid) #expect(result.errorMessage == "Bedrooms must be a whole number") } @Test func belowMinFails() { let result = ValidationHelpers.validateInteger("0", fieldName: "Bedrooms", min: 1) #expect(!result.isValid) } @Test func aboveMaxFails() { let result = ValidationHelpers.validateInteger("100", fieldName: "Bedrooms", max: 50) #expect(!result.isValid) } } // MARK: - Length Validation Tests struct LengthValidationTests { @Test func withinLengthPasses() { let result = ValidationHelpers.validateLength("hello", fieldName: "Title", min: 2, max: 100) #expect(result.isValid) } @Test func tooShortFails() { let result = ValidationHelpers.validateLength("a", fieldName: "Title", min: 3) #expect(!result.isValid) #expect(result.errorMessage == "Title must be at least 3 characters") } @Test func tooLongFails() { let result = ValidationHelpers.validateLength("abcdef", fieldName: "Code", max: 5) #expect(!result.isValid) #expect(result.errorMessage == "Code must be at most 5 characters") } @Test func emptyWithNoMinPasses() { let result = ValidationHelpers.validateLength("", fieldName: "Notes") #expect(result.isValid) } } // MARK: - URL Validation Tests struct URLValidationTests { @Test func validURLPasses() { let result = ValidationHelpers.validateURL("https://example.com") #expect(result.isValid) } @Test func emptyURLFails() { let result = ValidationHelpers.validateURL("") #expect(!result.isValid) #expect(result.errorMessage == "URL is required") } @Test func httpURLPasses() { let result = ValidationHelpers.validateURL("http://example.com/path") #expect(result.isValid) } } // MARK: - Custom Validation Tests struct CustomValidationTests { @Test func passingCustomValidatorPasses() { let result = ValidationHelpers.validateCustom( "abc123", fieldName: "Code", validator: { $0.count == 6 }, errorMessage: "Code must be exactly 6 characters" ) #expect(result.isValid) } @Test func failingCustomValidatorFails() { let result = ValidationHelpers.validateCustom( "abc", fieldName: "Code", validator: { $0.count == 6 }, errorMessage: "Code must be exactly 6 characters" ) #expect(!result.isValid) #expect(result.errorMessage == "Code must be exactly 6 characters") } @Test func emptyValueInCustomValidatorFails() { let result = ValidationHelpers.validateCustom( "", fieldName: "Code", validator: { _ in true }, errorMessage: "Unused" ) #expect(!result.isValid) #expect(result.errorMessage == "Code is required") } } // MARK: - FormValidator Tests struct FormValidatorTests { @Test func allValidFieldsPass() { let validator = FormValidator() validator.add(fieldName: "email") { ValidationHelpers.validateEmail("user@example.com") } validator.add(fieldName: "name") { ValidationHelpers.validateName("John") } let result = validator.validate() #expect(result.isValid) #expect(result.errors.isEmpty) } @Test func singleInvalidFieldFails() { let validator = FormValidator() validator.add(fieldName: "email") { ValidationHelpers.validateEmail("") } validator.add(fieldName: "name") { ValidationHelpers.validateName("John") } let result = validator.validate() #expect(!result.isValid) #expect(result.errors.count == 1) #expect(result.errors["email"] != nil) } @Test func multipleInvalidFieldsFail() { let validator = FormValidator() validator.add(fieldName: "email") { ValidationHelpers.validateEmail("") } validator.add(fieldName: "password") { ValidationHelpers.validatePassword("") } let result = validator.validate() #expect(!result.isValid) #expect(result.errors.count == 2) } @Test func clearRemovesValidations() { let validator = FormValidator() validator.add(fieldName: "email") { ValidationHelpers.validateEmail("") } validator.clear() let result = validator.validate() #expect(result.isValid) } } // MARK: - FormValidationResult Tests struct FormValidationResultTests { @Test func validResultHasNoErrors() { let result = FormValidationResult.valid #expect(result.isValid) #expect(result.errors.isEmpty) } @Test func invalidResultHasErrors() { let result = FormValidationResult.invalid(["email": "Email is required"]) #expect(!result.isValid) #expect(result.errors["email"] == "Email is required") } }