Skip to content

Commit 083ac70

Browse files
committed
feat: add NSTextField validation support
1 parent b4b31c1 commit 083ac70

File tree

4 files changed

+123
-0
lines changed

4 files changed

+123
-0
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
//
2+
// Validator
3+
// Copyright © 2023 Space Code. All rights reserved.
4+
//
5+
6+
#if os(macOS)
7+
import AppKit
8+
9+
extension NSTextField: IUIValidatable {
10+
/// The value of the text field to validate.
11+
/// Returns an empty string if `text` is nil.
12+
public var inputValue: String { stringValue }
13+
14+
/// The type of input for validation.
15+
public typealias Input = String
16+
17+
/// Enables or disables automatic validation when the text changes.
18+
///
19+
/// - Parameter isEnabled: If true, validation is triggered on every text change.
20+
/// If false, the target-action is removed.
21+
public func validateOnInputChange(isEnabled: Bool) {
22+
if isEnabled {
23+
NotificationCenter.default.addObserver(
24+
self,
25+
selector: #selector(textFieldDidChange(_:)),
26+
name: NSControl.textDidChangeNotification,
27+
object: self
28+
)
29+
} else {
30+
NotificationCenter.default.removeObserver(
31+
self,
32+
name: NSControl.textDidChangeNotification,
33+
object: self
34+
)
35+
}
36+
}
37+
38+
// MARK: Private
39+
40+
/// Called automatically when the text field changes (if `validateOnInputChange` is enabled).
41+
/// Performs validation using all rules stored in `validationRules`.
42+
///
43+
/// - Parameter notification: The notification containing the text field.
44+
@objc
45+
private func textFieldDidChange(_ notification: Notification) {
46+
guard notification.object as? NSTextField === self else { return }
47+
validate(rules: validationRules)
48+
}
49+
}
50+
#endif
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
//
2+
// Validator
3+
// Copyright © 2023 Space Code. All rights reserved.
4+
//
5+
6+
import ValidatorCore
7+
import ValidatorUI
8+
import XCTest
9+
10+
#if canImport(AppKit)
11+
import AppKit
12+
#endif
13+
14+
#if os(macOS)
15+
final class NSTextFieldTests: XCTestCase {
16+
// MARK: Tests
17+
18+
@MainActor
19+
func test_thatTextFieldValidationReturnsValid_whenInputValueIsValid() {
20+
// given
21+
let textField = NSTextField()
22+
23+
textField.validateOnInputChange(isEnabled: true)
24+
textField.add(rule: LengthValidationRule(max: .max, error: String.error))
25+
26+
// when
27+
textField.stringValue = String(String.text.prefix(.max))
28+
29+
var result: ValidationResult?
30+
31+
textField.validationHandler = { result = $0 }
32+
textField.validate(rules: textField.validationRules)
33+
34+
// when
35+
if case .valid = result {}
36+
else { XCTFail("The result must be equal to the valid value") }
37+
}
38+
39+
@MainActor
40+
func test_thatTextFieldValidationReturnsInvalid_whenInputValueIsInvalid() {
41+
// given
42+
let textField = NSTextField()
43+
44+
textField.validateOnInputChange(isEnabled: true)
45+
textField.add(rule: LengthValidationRule(max: .max, error: String.error))
46+
47+
// when
48+
textField.stringValue = .text
49+
50+
var result: ValidationResult?
51+
52+
textField.validationHandler = { result = $0 }
53+
textField.validate(rules: textField.validationRules)
54+
55+
// when
56+
if case let .invalid(errors) = result {
57+
XCTAssertEqual(errors.count, 1)
58+
XCTAssertEqual(errors.first?.message, .error)
59+
} else { XCTFail("The result must be equal to the invalid value") }
60+
}
61+
}
62+
63+
private extension String {
64+
static let text: String = "lorem ipsum lorem ipsum lorem ipsum"
65+
static let error: String = "error"
66+
}
67+
68+
private extension Int {
69+
static let min = 0
70+
static let max = 10
71+
}
72+
73+
#endif

Tests/ValidatorUITests/UnitTests/UITextFieldTests.swift renamed to Tests/ValidatorUITests/UnitTests/UIKit/UITextFieldTests.swift

File renamed without changes.

Tests/ValidatorUITests/UnitTests/UITextViewTests.swift renamed to Tests/ValidatorUITests/UnitTests/UIKit/UITextViewTests.swift

File renamed without changes.

0 commit comments

Comments
 (0)