From 2a590f48efb3808158bd91550cd321b8c07e3ce3 Mon Sep 17 00:00:00 2001 From: Nikita Vasilev Date: Sun, 7 Dec 2025 14:37:40 +0400 Subject: [PATCH] feat: add contains substring validation rule --- README.md | 1 + .../Rules/ContainsValidationRule.swift | 43 +++++++++++ .../ValidatorCore/Validator.docc/Overview.md | 1 + .../Rules/ContainsValidationRuleTests.swift | 73 +++++++++++++++++++ 4 files changed, 118 insertions(+) create mode 100644 Sources/ValidatorCore/Classes/Rules/ContainsValidationRule.swift create mode 100644 Tests/ValidatorCoreTests/UnitTests/Rules/ContainsValidationRuleTests.swift diff --git a/README.md b/README.md index 275eedd..e0c516a 100644 --- a/README.md +++ b/README.md @@ -311,6 +311,7 @@ struct RegistrationView: View { | `NilValidationRule` | Validates that value is nil | `NilValidationRule(error: "Value must be nil")` | `PositiveNumberValidationRule` | Validates that value is positive | `PositiveNumberValidationRule(error: "Value must be positive")` | `NoWhitespaceValidationRule` | Validates that a string does not contain any whitespace characters | `NoWhitespaceValidationRule(error: "Spaces are not allowed")` +| `ContainsValidationRule` | Validates that a string contains a specific substring | `ContainsValidationRule(substring: "@", error: "Must contain @")` ## Custom Validators diff --git a/Sources/ValidatorCore/Classes/Rules/ContainsValidationRule.swift b/Sources/ValidatorCore/Classes/Rules/ContainsValidationRule.swift new file mode 100644 index 0000000..feab257 --- /dev/null +++ b/Sources/ValidatorCore/Classes/Rules/ContainsValidationRule.swift @@ -0,0 +1,43 @@ +// +// Validator +// Copyright © 2025 Space Code. All rights reserved. +// + +/// Validates that a string contains a specific substring. +/// +/// # Example: +/// ```swift +/// let rule = ContainsValidationRule(substring: "@", error: "Must contain @") +/// rule.validate(input: "user@example.com") // true +/// ``` +public struct ContainsValidationRule: IValidationRule { + // MARK: Types + + public typealias Input = String + + // MARK: Properties + + /// The substring that the input must contain. + public let substring: String + + /// The validation error. + public let error: IValidationError + + // MARK: Initialization + + /// Creates a validation rule that checks whether the input contains a required substring. + /// + /// - Parameters: + /// - substring: The string the input must contain. + /// - error: The validation error associated with failed validation. + public init(substring: String, error: IValidationError) { + self.substring = substring + self.error = error + } + + // MARK: IValidationRule + + public func validate(input: String) -> Bool { + input.contains(substring) + } +} diff --git a/Sources/ValidatorCore/Validator.docc/Overview.md b/Sources/ValidatorCore/Validator.docc/Overview.md index 9cb8d66..c935a2b 100644 --- a/Sources/ValidatorCore/Validator.docc/Overview.md +++ b/Sources/ValidatorCore/Validator.docc/Overview.md @@ -34,6 +34,7 @@ ValidatorCore contains all core validation rules, utilities, and mechanisms for - ``NilValidationRule`` - ``PositiveNumberValidationRule`` - ``NoWhitespaceValidationRuleTests`` +- ``ContainsValidationRule`` ### Articles diff --git a/Tests/ValidatorCoreTests/UnitTests/Rules/ContainsValidationRuleTests.swift b/Tests/ValidatorCoreTests/UnitTests/Rules/ContainsValidationRuleTests.swift new file mode 100644 index 0000000..71e4c61 --- /dev/null +++ b/Tests/ValidatorCoreTests/UnitTests/Rules/ContainsValidationRuleTests.swift @@ -0,0 +1,73 @@ +// +// Validator +// Copyright © 2025 Space Code. All rights reserved. +// + +@testable import ValidatorCore +import XCTest + +// MARK: - ContainsValidationRuleTests + +final class ContainsValidationRuleTests: XCTestCase { + // MARK: Properties + + private var sut: ContainsValidationRule! + + // MARK: XCTestCase + + override func setUp() { + super.setUp() + sut = ContainsValidationRule(substring: "@", error: String.error) + } + + override func tearDown() { + sut = nil + super.tearDown() + } + + // MARK: Tests + + func test_thatContainsValidationRuleSetsProperties() { + // then + XCTAssertEqual(sut.substring, "@") + XCTAssertEqual(sut.error.message, .error) + } + + func test_thatRuleReturnsTrue_whenInputContainsSubstring() { + // when + let result = sut.validate(input: "user@example.com") + + // then + XCTAssertTrue(result) + } + + func test_thatRuleReturnsFalse_whenInputDoesNotContainSubstring() { + // when + let result = sut.validate(input: "userexample.com") + + // then + XCTAssertFalse(result) + } + + func test_thatRuleReturnsFalse_whenInputIsEmpty() { + // when + let result = sut.validate(input: "") + + // then + XCTAssertFalse(result) + } + + func test_thatRuleReturnsTrue_whenSubstringAppearsMultipleTimes() { + // when + let result = sut.validate(input: "@user@domain.com") + + // then + XCTAssertTrue(result) + } +} + +// MARK: - Constants + +private extension String { + static let error = "Must contain @" +}