This repository has been archived by the owner on Apr 20, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #35 from valen90/feature/validators
Feature/validators
- Loading branch information
Showing
12 changed files
with
242 additions
and
98 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import Vapor | ||
import Validation | ||
|
||
extension Date: Validatable {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import Vapor | ||
import Validation | ||
|
||
/// Validates that matches a given input | ||
public struct Different<T>: Validator where T: Validatable, T: Equatable { | ||
/// The value expected | ||
public let expectation: T | ||
|
||
/// Initialize a validator with the expected value | ||
public init(_ expectation: T) { | ||
self.expectation = expectation | ||
} | ||
|
||
public func validate(_ input: T) throws { | ||
guard input != expectation else { | ||
throw error("\(input) does not equal expectation \(expectation)") | ||
} | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import Vapor | ||
import Validation | ||
|
||
private let ipv4Pattern = "(([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.){3}([01]?\\d\\d?|2[0-4]\\d|25[0-5])" | ||
|
||
private let ipv6Pattern = | ||
"(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))" | ||
|
||
public enum IPAddress: Validator { | ||
case ipv4 | ||
case ipv6 | ||
case ip | ||
|
||
|
||
public func validate(_ input: String) throws { | ||
switch self { | ||
case .ipv4 where input.range(of: ipv4Pattern, options: .regularExpression) != nil : | ||
break | ||
case .ipv6 where input.range(of: ipv6Pattern, options: .regularExpression) != nil : | ||
break | ||
case .ip where input.range(of: ipv6Pattern, options: .regularExpression) != nil || input.range(of: ipv4Pattern, options: .regularExpression) != nil : | ||
break | ||
default: | ||
throw Abort( | ||
.badRequest, | ||
metadata: nil, | ||
reason: "Not valid IP address" | ||
) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import Vapor | ||
import Validation | ||
|
||
public struct JSONValidator: Validator { | ||
|
||
public func validate(_ input: String) throws { | ||
do { | ||
_ = try JSON(bytes: input.makeBytes()) | ||
} catch { | ||
throw Abort( | ||
.badRequest, | ||
metadata: nil, | ||
reason: "Not valid JSON" | ||
) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import Vapor | ||
import Validation | ||
|
||
public struct Numeric: Validator { | ||
|
||
public func validate(_ input: String) throws { | ||
guard Double(input) != nil else { | ||
throw Abort( | ||
.badRequest, | ||
metadata: nil, | ||
reason: "Not numeric" | ||
) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import Vapor | ||
import Validation | ||
|
||
public struct Required: Validator { | ||
public typealias Input = Node? | ||
|
||
public func validate(_ input: Node?) throws { | ||
guard let input = input else { | ||
throw Abort( | ||
.badRequest, | ||
metadata: nil, | ||
reason: "The value is null." | ||
) | ||
} | ||
|
||
if let string = input.string { | ||
guard !string.isEmpty else { | ||
throw Abort( | ||
.badRequest, | ||
metadata: nil, | ||
reason: "The value is an empty string." | ||
) | ||
} | ||
} | ||
|
||
if let array = input.array { | ||
guard array.count > 0 else { | ||
throw Abort( | ||
.badRequest, | ||
metadata: nil, | ||
reason: "The value is an empty array." | ||
) | ||
} | ||
} | ||
} | ||
} | ||
|
||
extension Optional: Validatable {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import Vapor | ||
import Validation | ||
|
||
private let regex = "^(?:(?:https?|ftp):\\/\\/)(?:\\S+(?::\\S*)?@)?(?:(?!(?:10|127)(?:\\.\\d{1,3}){3})(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,}))\\.?)(?::\\d{2,5})?(?:[/?#]\\S*)?$" | ||
|
||
public struct URL: Validator { | ||
|
||
public func validate(_ input: String) throws { | ||
guard input.range(of: regex, options: .regularExpression) != nil else { | ||
throw Abort( | ||
.badRequest, | ||
metadata: nil, | ||
reason: "Not valid URL" | ||
) | ||
} | ||
|
||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
import XCTest | ||
import Validation | ||
@testable import Sugar | ||
|
||
class ValidatorsTests: XCTestCase { | ||
|
||
static let allTests = [ | ||
("testThatStrongPasswordValidatorWorks", testThatStrongPasswordValidatorWorks), | ||
("testThatURLValidatorWorks", testThatURLValidatorWorks), | ||
("testThatNumericValidatorWorks", testThatNumericValidatorWorks), | ||
("testThatIPv4AddressValidatorWorks", testThatIPv4AddressValidatorWorks), | ||
("testThatIPv6AddressValidatorWorks", testThatIPv6AddressValidatorWorks), | ||
("testThatGenericIPAddressValidatorWorks", testThatGenericIPAddressValidatorWorks), | ||
("testThatRequiredValidatorWorks", testThatRequiredValidatorWorks), | ||
("testThatJSONValidatorWorks", testThatJSONValidatorWorks), | ||
("testThatDifferentValidatorWorks", testThatDifferentValidatorWorks) | ||
] | ||
|
||
func testThatStrongPasswordValidatorWorks() { | ||
XCTAssertThrowsError(try StrongPassword().validate("password")) // Only one category | ||
XCTAssertThrowsError(try StrongPassword().validate("p4ssw0rd")) // Only two categories | ||
XCTAssertThrowsError(try StrongPassword().validate("Aa1!")) // Three categories, but too short | ||
XCTAssertNoThrow(try StrongPassword().validate("p@ssw0rd")) // Three categories, and long enough | ||
|
||
} | ||
|
||
func testThatURLValidatorWorks() { | ||
XCTAssertNoThrow(try URL().validate("ftp://www.website.com")) | ||
XCTAssertNoThrow(try URL().validate("https://www.website.com")) | ||
XCTAssertNoThrow(try URL().validate("http://www.url-with-querystring.com/?url=has-querystring")) | ||
XCTAssertThrowsError(try URL().validate("notvalidurl")) | ||
XCTAssertThrowsError(try URL().validate("http://www.web site.com")) | ||
} | ||
|
||
func testThatNumericValidatorWorks() { | ||
XCTAssertThrowsError(try Numeric().validate("notNumber")) | ||
XCTAssertNoThrow(try Numeric().validate("1337")) | ||
XCTAssertNoThrow(try Numeric().validate("1337.1337")) | ||
} | ||
|
||
func testThatIPv4AddressValidatorWorks() { | ||
XCTAssertNoThrow(try IPAddress.ipv4.validate("0.0.0.0")) | ||
XCTAssertNoThrow(try IPAddress.ipv4.validate("255.255.255.255")) | ||
XCTAssertThrowsError(try IPAddress.ipv4.validate("300.300.300.300")) // Values out of range | ||
XCTAssertThrowsError(try IPAddress.ipv4.validate("255.255.255")) // Missing values | ||
} | ||
|
||
func testThatIPv6AddressValidatorWorks() { | ||
XCTAssertNoThrow(try IPAddress.ipv6.validate("::")) | ||
XCTAssertNoThrow(try IPAddress.ipv6.validate("2001::25de::cade")) | ||
XCTAssertNoThrow(try IPAddress.ipv6.validate("2001:0DB8::1428:57ab")) | ||
XCTAssertNoThrow(try IPAddress.ipv6.validate("2001:0DB8:0000:0000:0000:0000:1428:57ab")) | ||
XCTAssertThrowsError(try IPAddress.ipv6.validate("255.255.255.255")) | ||
XCTAssertThrowsError(try IPAddress.ipv6.validate("xxxx:")) | ||
} | ||
|
||
func testThatGenericIPAddressValidatorWorks() { | ||
XCTAssertNoThrow(try IPAddress.ip.validate("0.0.0.0")) | ||
XCTAssertNoThrow(try IPAddress.ip.validate("255.255.255.255")) | ||
XCTAssertNoThrow(try IPAddress.ip.validate("2001:0DB8::1428:57ab")) | ||
XCTAssertNoThrow(try IPAddress.ip.validate("::")) | ||
} | ||
|
||
func testThatRequiredValidatorWorks() { | ||
XCTAssertThrowsError(try Required().validate("")) | ||
XCTAssertThrowsError(try Required().validate([])) | ||
XCTAssertThrowsError(try Required().validate(nil)) | ||
XCTAssertNoThrow(try Required().validate("notEmpty")) | ||
XCTAssertNoThrow(try Required().validate(["notEmpty"])) | ||
XCTAssertNoThrow(try Required().validate(1)) | ||
} | ||
|
||
func testThatJSONValidatorWorks() { | ||
XCTAssertNoThrow(try JSONValidator().validate( | ||
"{\n" + | ||
"\"boolean\": true,\n" + | ||
"\"object\": {\n" + | ||
"\"a\": \"b\",\n" + | ||
"\"c\": \"d\",\n" + | ||
"\"e\": \"f\"\n" + | ||
"},\n" + | ||
"\"array\": [1 , 2],\n" + | ||
"\"string\": \"Hello World\"\n" + | ||
"}" | ||
)) | ||
XCTAssertThrowsError(try JSONValidator().validate("{notAValidJSON: notValid}")) | ||
} | ||
|
||
func testThatDifferentValidatorWorks() { | ||
let collection = 1 | ||
XCTAssertNoThrow(try collection.tested(by: Different(2))) | ||
XCTAssertThrowsError(try collection.tested(by: Different(1))) | ||
} | ||
|
||
} | ||
|