Skip to content

Commit

Permalink
Expose the wrapper as projected value (#2)
Browse files Browse the repository at this point in the history
Also introduce a binding property for SwiftUI
  • Loading branch information
reddavis authored Mar 2, 2022
1 parent 50532a5 commit a31e251
Show file tree
Hide file tree
Showing 8 changed files with 55 additions and 91 deletions.
4 changes: 2 additions & 2 deletions ExampleApp/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ struct ContentView: View
var body: some View {
VStack(spacing: 60) {
VStack {
TextField("Name", text: self.$name)
TextField("Name", text: self.$name.binding)
.textFieldStyle(.roundedBorder)
.padding()

VStack {
ForEach(self._name.errors.localizedDescriptions, id: \.self) { message in
ForEach(self.$name.errors.localizedDescriptions, id: \.self) { message in
Text(message)
.foregroundColor(.red)
.font(.footnote)
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,12 @@ struct ContentView: View {
var body: some View {
VStack(spacing: 60) {
VStack {
TextField("Name", text: self.$name)
TextField("Name", text: self.$name.binding)
.textFieldStyle(.roundedBorder)
.padding()

VStack {
ForEach(self._name.errors.localizedDescriptions, id: \.self) { message in
ForEach(self.$name.errors.localizedDescriptions, id: \.self) { message in
Text(message)
.foregroundColor(.red)
.font(.footnote)
Expand Down
9 changes: 8 additions & 1 deletion Validate/Source/Validate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,14 @@ public struct Validate<Value>: DynamicProperty {
}
}

public var projectedValue: Binding<Value> {
public var projectedValue: Validate<Value> {
self
}

/// Create a binding for the wrapped value.
///
/// This is useful for working with SwiftUI components.
public var binding: Binding<Value> {
Binding(
get: { self.wrappedValue },
set: { self.wrappedValue = $0 }
Expand Down
75 changes: 25 additions & 50 deletions ValidateTests/CountValidationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@ import XCTest
@testable import Validate


class CountValidationTests: XCTestCase
{
class CountValidationTests: XCTestCase {
// MARK: Greater than

func testCountGreaterThanValidation()
{
func testCountGreaterThanValidation() {
@Validate(.count(greaterThan: 3)) var value: String = ""
XCTAssertFalse(_value.isValid)

Expand All @@ -18,8 +16,7 @@ class CountValidationTests: XCTestCase
XCTAssert(_value.isValid)
}

func testCountGreaterThanForOptionalValidation()
{
func testCountGreaterThanForOptionalValidation() {
@Validate(.count(greaterThan: 3)) var value: String? = nil
XCTAssertFalse(_value.isValid)

Expand All @@ -30,24 +27,21 @@ class CountValidationTests: XCTestCase
XCTAssert(_value.isValid)
}

func testGreaterThanErrorMessage() throws
{
func testGreaterThanErrorMessage() throws {
@Validate(.count(greaterThan: 3)) var value: String = ""

let error = try XCTUnwrap(_value.errors.first as? ValidationError)
XCTAssertEqual(error.errorDescription, "Should be greater than 3")
}

func testGreaterThanErrorMessageForOptional() throws
{
func testGreaterThanErrorMessageForOptional() throws {
@Validate(.count(greaterThan: 3)) var value: String? = nil

let error = try XCTUnwrap(_value.errors.first as? ValidationError)
XCTAssertEqual(error.errorDescription, "Should be greater than 3")
}

func testGreaterThanCustomErrorMessage() throws
{
func testGreaterThanCustomErrorMessage() throws {
let message = "a message"
@Validate(
.count(
Expand All @@ -61,8 +55,7 @@ class CountValidationTests: XCTestCase
XCTAssertEqual(error.errorDescription, message)
}

func testGreaterThanCustomErrorMessageForOptional() throws
{
func testGreaterThanCustomErrorMessageForOptional() throws {
let message = "a message"
@Validate(
.count(
Expand All @@ -78,8 +71,7 @@ class CountValidationTests: XCTestCase

// MARK: Less than

func testCountLessThanValidation()
{
func testCountLessThanValidation() {
@Validate(.count(lessThan: 3)) var value: String = "12345"
XCTAssertFalse(_value.isValid)

Expand All @@ -90,8 +82,7 @@ class CountValidationTests: XCTestCase
XCTAssert(_value.isValid)
}

func testCountLessThanForOptionalValidation()
{
func testCountLessThanForOptionalValidation() {
@Validate(.count(lessThan: 3)) var value: String? = nil
XCTAssertFalse(_value.isValid)

Expand All @@ -102,24 +93,21 @@ class CountValidationTests: XCTestCase
XCTAssert(_value.isValid)
}

func testLessThanErrorMessage() throws
{
func testLessThanErrorMessage() throws {
@Validate(.count(lessThan: 3)) var value: String = "1234"

let error = try XCTUnwrap(_value.errors.first as? ValidationError)
XCTAssertEqual(error.errorDescription, "Should be less than 3")
}

func testLessThanErrorMessageForOptional() throws
{
func testLessThanErrorMessageForOptional() throws {
@Validate(.count(lessThan: 3)) var value: String? = nil

let error = try XCTUnwrap(_value.errors.first as? ValidationError)
XCTAssertEqual(error.errorDescription, "Should be less than 3")
}

func testLessThanCustomErrorMessage() throws
{
func testLessThanCustomErrorMessage() throws {
let message = "a message"
@Validate(
.count(
Expand All @@ -133,8 +121,7 @@ class CountValidationTests: XCTestCase
XCTAssertEqual(error.errorDescription, message)
}

func testLessThanCustomErrorMessageForOptional() throws
{
func testLessThanCustomErrorMessageForOptional() throws {
let message = "a message"
@Validate(
.count(
Expand All @@ -150,8 +137,7 @@ class CountValidationTests: XCTestCase

// MARK: Equal

func testCountEqualToValidation()
{
func testCountEqualToValidation() {
@Validate(.count(equalTo: 3)) var value: String = ""
XCTAssertFalse(_value.isValid)

Expand All @@ -165,8 +151,7 @@ class CountValidationTests: XCTestCase
XCTAssert(_value.isValid)
}

func testCountEqualToForOptionalValidation()
{
func testCountEqualToForOptionalValidation() {
@Validate(.count(equalTo: 3)) var value: String? = nil
XCTAssertFalse(_value.isValid)

Expand All @@ -180,25 +165,22 @@ class CountValidationTests: XCTestCase
XCTAssert(_value.isValid)
}

func testEqualToErrorMessage() throws
{
func testEqualToErrorMessage() throws {
@Validate(.count(equalTo: 3)) var value: String = ""
XCTAssertFalse(_value.isValid)

let error = try XCTUnwrap(_value.errors.first as? ValidationError)
XCTAssertEqual(error.errorDescription, "Should be equal to 3")
}

func testEqualToErrorMessageForOptional() throws
{
func testEqualToErrorMessageForOptional() throws {
@Validate(.count(equalTo: 3)) var value: String? = nil

let error = try XCTUnwrap(_value.errors.first as? ValidationError)
XCTAssertEqual(error.errorDescription, "Should be equal to 3")
}

func testEqualToCustomErrorMessage() throws
{
func testEqualToCustomErrorMessage() throws {
let message = "a message"
@Validate(
.count(
Expand All @@ -212,8 +194,7 @@ class CountValidationTests: XCTestCase
XCTAssertEqual(error.errorDescription, message)
}

func testEqualToCustomErrorMessageForOptional() throws
{
func testEqualToCustomErrorMessageForOptional() throws {
let message = "a message"
@Validate(
.count(
Expand All @@ -229,8 +210,7 @@ class CountValidationTests: XCTestCase

// MARK: Range

func testCountRangeValidation()
{
func testCountRangeValidation() {
@Validate(.count(in: 2...4)) var value: String = ""
XCTAssertFalse(_value.isValid)

Expand All @@ -244,8 +224,7 @@ class CountValidationTests: XCTestCase
XCTAssert(_value.isValid)
}

func testCountRangeForOptionalValidation()
{
func testCountRangeForOptionalValidation() {
@Validate(.count(in: 2...4)) var value: String? = nil
XCTAssertFalse(_value.isValid)

Expand All @@ -259,24 +238,21 @@ class CountValidationTests: XCTestCase
XCTAssert(_value.isValid)
}

func testRangeErrorMessage() throws
{
func testRangeErrorMessage() throws {
@Validate(.count(in: 2...4)) var value: String = ""

let error = try XCTUnwrap(_value.errors.first as? ValidationError)
XCTAssertEqual(error.errorDescription, "Should be between 2 and 4")
}

func testRangeErrorMessageForOptional() throws
{
func testRangeErrorMessageForOptional() throws {
@Validate(.count(in: 2...4)) var value: String? = nil

let error = try XCTUnwrap(_value.errors.first as? ValidationError)
XCTAssertEqual(error.errorDescription, "Should be between 2 and 4")
}

func testRangeCustomErrorMessage() throws
{
func testRangeCustomErrorMessage() throws {
let message = "a message"
@Validate(
.count(
Expand All @@ -290,8 +266,7 @@ class CountValidationTests: XCTestCase
XCTAssertEqual(error.errorDescription, message)
}

func testRangeCustomErrorMessageForOptional() throws
{
func testRangeCustomErrorMessageForOptional() throws {
let message = "a message"
@Validate(
.count(
Expand Down
18 changes: 6 additions & 12 deletions ValidateTests/FormatValidationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,16 @@ import XCTest
@testable import Validate


class FormatValidationTests: XCTestCase
{
func testFormatValidation()
{
class FormatValidationTests: XCTestCase {
func testFormatValidation() {
@Validate(.format("\\d{3}")) var value: String = ""
XCTAssertFalse(_value.isValid)

value = "123"
XCTAssert(_value.isValid)
}

func testFormatValidationForOptionalString()
{
func testFormatValidationForOptionalString() {
@Validate(.format("\\d{3}")) var value: String? = nil
XCTAssertFalse(_value.isValid)

Expand All @@ -27,17 +24,15 @@ class FormatValidationTests: XCTestCase

// MARK: Errors

func testFormatErrorMessage() throws
{
func testFormatErrorMessage() throws {
@Validate(.format("\\d{3}")) var value: String = ""
XCTAssertEqual(_value.errors.count, 1)

let error = try XCTUnwrap(_value.errors.first as? ValidationError)
XCTAssertEqual(error.errorDescription, "Is incorrectly formatted")
}

func testCustomErrorMessage() throws
{
func testCustomErrorMessage() throws {
let message = "this is a message"
@Validate(
.format(
Expand All @@ -51,8 +46,7 @@ class FormatValidationTests: XCTestCase
XCTAssertEqual(error.errorDescription, message)
}

func testCustomErrorMessageForOptionalString() throws
{
func testCustomErrorMessageForOptionalString() throws {
let message = "this is a message"
@Validate(
.format(
Expand Down
21 changes: 7 additions & 14 deletions ValidateTests/PresenceValidationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,16 @@ import XCTest
@testable import Validate


class PresenceValidationTests: XCTestCase
{
func testPresenceValidation() throws
{
class PresenceValidationTests: XCTestCase {
func testPresenceValidation() throws {
@Validate(.presence()) var value: Int? = nil
XCTAssertFalse(_value.isValid)

value = 1
XCTAssert(_value.isValid)
}

func testPresenceValidationForOptionalString()
{
func testPresenceValidationForOptionalString() {
@Validate(.presence(allowEmpty: true)) var blankAllowed: String? = nil
XCTAssertFalse(_blankAllowed.isValid)
blankAllowed = ""
Expand All @@ -28,8 +25,7 @@ class PresenceValidationTests: XCTestCase
XCTAssert(_blankNotAllowed.isValid)
}

func testPresenceValidationForString()
{
func testPresenceValidationForString() {
@Validate(.presence()) var value: String = ""
XCTAssertFalse(_value.isValid)
value = "a"
Expand All @@ -38,17 +34,15 @@ class PresenceValidationTests: XCTestCase

// MARK: Errors

func testPresenceErrorMessage() throws
{
func testPresenceErrorMessage() throws {
@Validate(.presence()) var value: Int? = nil
XCTAssertEqual(_value.errors.count, 1)

let error = try XCTUnwrap(_value.errors.first as? ValidationError)
XCTAssertEqual(error.errorDescription, "Can't be blank")
}

func testCustomErrorMessage() throws
{
func testCustomErrorMessage() throws {
let message = "this is a message"
@Validate(
.presence(
Expand All @@ -75,8 +69,7 @@ class PresenceValidationTests: XCTestCase
XCTAssertEqual(error.errorDescription, message)
}

func testCustomErrorMessageForOptionalString() throws
{
func testCustomErrorMessageForOptionalString() throws {
let message = "this is a message"
@Validate(
.presence(
Expand Down
Loading

0 comments on commit a31e251

Please sign in to comment.