diff --git a/Sources/AppVaporTestTools/routes.swift b/Sources/AppVaporTestTools/routes.swift index 858bd34..68620b5 100644 --- a/Sources/AppVaporTestTools/routes.swift +++ b/Sources/AppVaporTestTools/routes.swift @@ -11,20 +11,4 @@ public func routes(_ router: Router) throws { return "Hello, world!" } - router.get("ping") { (req)->Future in - let ping = "{ \"code\": \"pong\" }" - return try JSONDecoder().decode(MyObject.self, from: HTTPBody(string: ping), maxSize: 500, on: req) - } - - // Example of creating a Service and using it. - router.get("hash", String.parameter) { req -> String in - // Create a BCryptHasher using the Request's Container - let hasher = try req.make(BCryptHasher.self) - - // Fetch the String parameter (as described in the route) - let string = try req.parameter(String.self) - - // Return the hashed string! - return try hasher.make(string) - } } diff --git a/Sources/VaporTestTools/Extensions/Requests/HTTPHeaders+Tools.swift b/Sources/VaporTestTools/Extensions/Requests/HTTPHeaders+Tools.swift index 8fdfda1..be702d3 100644 --- a/Sources/VaporTestTools/Extensions/Requests/HTTPHeaders+Tools.swift +++ b/Sources/VaporTestTools/Extensions/Requests/HTTPHeaders+Tools.swift @@ -5,12 +5,13 @@ // Created by Ondrej Rafaj on 28/02/2018. // -import Foundation -import Vapor +@_exported import Foundation +@_exported import Vapor extension TestableProperty where TestableType == Dictionary { + /// Converts dictionary into HTTPHeaders func asHTTPHeaders() -> HTTPHeaders { var headersObject = HTTPHeaders() for key in element.keys { diff --git a/Sources/VaporTestTools/Extensions/Requests/HTTPRequest+Make.swift b/Sources/VaporTestTools/Extensions/Requests/HTTPRequest+Make.swift index e76ab96..8a86866 100644 --- a/Sources/VaporTestTools/Extensions/Requests/HTTPRequest+Make.swift +++ b/Sources/VaporTestTools/Extensions/Requests/HTTPRequest+Make.swift @@ -5,9 +5,9 @@ // Created by Ondrej Rafaj on 27/02/2018. // -import Foundation -import Vapor -import Routing +@_exported import Foundation +@_exported import Vapor +@_exported import Routing public typealias URI = String @@ -15,6 +15,7 @@ public typealias URI = String extension TestableProperty where TestableType == HTTPRequest { + /// MAke HTTPRequest public static func request(method: HTTPMethod, uri: URI, data: Data? = nil, headers: [String: String]? = nil) -> HTTPRequest { var req = HTTPRequest(method: method, url: URL(string: uri)!) if let headers = headers { @@ -26,51 +27,61 @@ extension TestableProperty where TestableType == HTTPRequest { return req } + /// GET HTTPRequest public static func get(uri: URI, headers: [String: String]? = nil) -> HTTPRequest { let req = request(method: .GET, uri: uri, headers: headers) return req } + /// PUT HTTPRequest public static func put(uri: URI, data: Data? = nil, headers: [String: String]? = nil) -> HTTPRequest { let req = request(method: .PUT, uri: uri, data: data, headers: headers) return req } + /// POST HTTPRequest public static func post(uri: URI, data: Data? = nil, headers: [String: String]? = nil) -> HTTPRequest { let req = request(method: .POST, uri: uri, data: data, headers: headers) return req } + /// PATVH HTTPRequest public static func patch(uri: URI, data: Data? = nil, headers: [String: String]? = nil) -> HTTPRequest { let req = request(method: .PATCH, uri: uri, data: data, headers: headers) return req } + /// DELETE HTTPRequest public static func delete(uri: URI, headers: [String: String]? = nil) -> HTTPRequest { let req = request(method: .DELETE, uri: uri, headers: headers) return req } + /// Return request and response for GET url string & data public static func response(get uri: URI, headers: [String: String]? = nil, with app: Application) -> TestResponse { let req = request(method: .GET, uri: uri, headers: headers) return app.testable.response(to: req) } + /// Return request and response for PUT url string & data public static func response(put uri: URI, data: Data? = nil, headers: [String: String]? = nil, with app: Application) -> TestResponse { let req = request(method: .PUT, uri: uri, data: data, headers: headers) return app.testable.response(to: req) } + /// Return request and response for POST url string & data public static func response(post uri: URI, data: Data? = nil, headers: [String: String]? = nil, with app: Application) -> TestResponse { let req = request(method: .POST, uri: uri, data: data, headers: headers) return app.testable.response(to: req) } + /// Return request and response for PATCH url string & data public static func response(patch uri: URI, data: Data? = nil, headers: [String: String]? = nil, with app: Application) -> TestResponse { let req = request(method: .PATCH, uri: uri, data: data, headers: headers) return app.testable.response(to: req) } + /// Return request and response for DELETE url string & data public static func response(delete uri: URI, headers: [String: String]? = nil, with app: Application) -> TestResponse { let req = request(method: .DELETE, uri: uri, headers: headers) return app.testable.response(to: req) diff --git a/Sources/VaporTestTools/Extensions/Requests/HTTPRequest+Response.swift b/Sources/VaporTestTools/Extensions/Requests/HTTPRequest+Response.swift index 8306692..022b609 100644 --- a/Sources/VaporTestTools/Extensions/Requests/HTTPRequest+Response.swift +++ b/Sources/VaporTestTools/Extensions/Requests/HTTPRequest+Response.swift @@ -5,12 +5,14 @@ // Created by Ondrej Rafaj on 27/02/2018. // -import Foundation -import Vapor -@testable import NIO +@_exported import Foundation +@_exported import Vapor +@_exported @testable import NIO + extension TestableProperty where TestableType == HTTPRequest { + /// Make response func response(using app: Application) -> Response { let responder = try! app.make(Responder.self) let wrappedRequest = Request(http: element, using: app) diff --git a/Sources/VaporTestTools/Extensions/Requests/Request+Make.swift b/Sources/VaporTestTools/Extensions/Requests/Request+Make.swift index 44a979c..e13bafd 100644 --- a/Sources/VaporTestTools/Extensions/Requests/Request+Make.swift +++ b/Sources/VaporTestTools/Extensions/Requests/Request+Make.swift @@ -11,8 +11,10 @@ import Vapor extension TestableProperty where TestableType: Request { + /// HTTPRequest access from request public static var http: TestableProperty.Type { return TestableProperty.self } } + diff --git a/Sources/VaporTestTools/Extensions/Response tools/Response+Checks.swift b/Sources/VaporTestTools/Extensions/Response tools/Response+Checks.swift index 7f12f06..b9e3abe 100644 --- a/Sources/VaporTestTools/Extensions/Response tools/Response+Checks.swift +++ b/Sources/VaporTestTools/Extensions/Response tools/Response+Checks.swift @@ -12,6 +12,7 @@ import Foundation extension TestableProperty where TestableType: Response { + /// Test header value public func has(header name: HTTPHeaderName, value: String? = nil) -> Bool { guard let header = header(name: name) else { return false @@ -26,29 +27,35 @@ extension TestableProperty where TestableType: Response { } } + /// Test header value public func has(header name: String, value: String? = nil) -> Bool { let headerName = HTTPHeaderName(name) return has(header: headerName, value: value) } + /// Test header Content-Type public func has(contentType value: String) -> Bool { let headerName = HTTPHeaderName("Content-Type") return has(header: headerName, value: value) } + /// Test header Content-Length public func has(contentLength value: Int) -> Bool { let headerName = HTTPHeaderName("Content-Length") return has(header: headerName, value: String(value)) } + /// Test response status code public func has(statusCode value: HTTPStatus) -> Bool { return element.http.status.code == value.code } + /// Test response status code and message public func has(statusCode value: HTTPStatus, message: String) -> Bool { return element.http.status.code == value.code && element.http.status.reasonPhrase == message } + /// Test response content public func has(content value: String) -> Bool { return contentString == value } diff --git a/Sources/VaporTestTools/Extensions/Response tools/Response+Debug.swift b/Sources/VaporTestTools/Extensions/Response tools/Response+Debug.swift index 3bd7a0e..800b381 100644 --- a/Sources/VaporTestTools/Extensions/Response tools/Response+Debug.swift +++ b/Sources/VaporTestTools/Extensions/Response tools/Response+Debug.swift @@ -11,6 +11,7 @@ import Foundation extension TestableProperty where TestableType: Response { + /// Prints out useful information out the response public func debug() { print("Debugging response:") print("HTTP [\(element.http.version.major).\(element.http.version.minor)] with status code [\(element.http.status.code)]") @@ -19,10 +20,10 @@ extension TestableProperty where TestableType: Response { print("\t\(header.name.description) = \(header.value)") } print("Content:") - if let size = element.content.body.count { + if let size = element.content.container.http.body.count { print("\tSize: \(String(size))") } - if let mediaType = element.content.mediaType { + if let mediaType = element.content.container.http.mediaType { print("\tMedia type: \(mediaType.description)") } if let stringContent = element.testable.contentString { diff --git a/Sources/VaporTestTools/Extensions/Response tools/Response+Decoding.swift b/Sources/VaporTestTools/Extensions/Response tools/Response+Decoding.swift index 173a216..f7a55a7 100644 --- a/Sources/VaporTestTools/Extensions/Response tools/Response+Decoding.swift +++ b/Sources/VaporTestTools/Extensions/Response tools/Response+Decoding.swift @@ -11,6 +11,7 @@ import Vapor extension TestableProperty where TestableType: Response { + /// Decode returned content public func content(as type: T.Type) -> T? where T: Decodable { let object = try? element.content.decode(type).wait() return object diff --git a/Sources/VaporTestTools/Extensions/Response tools/Response+Getters.swift b/Sources/VaporTestTools/Extensions/Response tools/Response+Getters.swift index fbfac8b..6cf16d0 100644 --- a/Sources/VaporTestTools/Extensions/Response tools/Response+Getters.swift +++ b/Sources/VaporTestTools/Extensions/Response tools/Response+Getters.swift @@ -7,39 +7,45 @@ import Foundation @testable import Vapor +@testable import NIO extension TestableProperty where TestableType: Response { + /// Make a fake request public func fakeRequest() -> Request { let http = HTTPRequest(method: .GET, url: URL(string: "/")!) let req = Request(http: http, using: element) return req } + /// Get header by it's name public func header(name: String) -> String? { let headerName = HTTPHeaderName(name) return header(name: headerName) } + /// Get header by it's HTTPHeaderName representation public func header(name: HTTPHeaderName) -> String? { return element.http.headers[name].first } + /// Size of the content public var contentSize: Int? { - return element.content.body.count + return element.content.container.http.body.data?.count } + /// Get content string. Maximum of 0.5Mb of text will be returned public var contentString: String? { - - guard let data = try? element.content.body.consumeData(max: 500000, on: fakeRequest()).wait() else { + guard let data = try? element.content.container.http.body.consumeData(max: 500000, on: fakeRequest()).wait() else { return nil } return String(data: data, encoding: .utf8) } + /// Get content string with encoding. Maximum of 0.5Mb of text will be returned public func contentString(encoding: String.Encoding) -> String? { - guard let data = try? element.content.body.consumeData(max: 500000, on: fakeRequest()).wait() else { + guard let data = try? element.content.container.http.body.consumeData(max: 500000, on: fakeRequest()).wait() else { return nil } return String(data: data, encoding: encoding) diff --git a/Sources/VaporTestTools/Extensions/Services/Services+Testing.swift b/Sources/VaporTestTools/Extensions/Services/Services+Testing.swift index ad15d64..af3e800 100644 --- a/Sources/VaporTestTools/Extensions/Services/Services+Testing.swift +++ b/Sources/VaporTestTools/Extensions/Services/Services+Testing.swift @@ -11,6 +11,7 @@ import Foundation extension Services { + /// Remove particular service public mutating func remove(type: S.Type) { if let existing = factories.index(where: { $0.serviceType is S.Type diff --git a/Sources/VaporTestTools/Extensions/Testable/Application+Testable.swift b/Sources/VaporTestTools/Extensions/Testable/Application+Testable.swift index 9ba3cd8..8db58f3 100644 --- a/Sources/VaporTestTools/Extensions/Testable/Application+Testable.swift +++ b/Sources/VaporTestTools/Extensions/Testable/Application+Testable.swift @@ -9,7 +9,7 @@ import Foundation import Vapor import Routing - +/// Response tuple containing response as well as the request public typealias TestResponse = (response: Response, request: Request) @@ -18,6 +18,7 @@ extension TestableProperty where TestableType: Application { public typealias AppConfigClosure = ((_ config: inout Config, _ env: inout Vapor.Environment, _ services: inout Services) -> Void) public typealias AppRouterClosure = ((_ router: Router) -> Void) + /// Configure a new test app (in test setup) public static func new(config: Config = Config.default(), env: Environment? = nil, services: Services = Services.default(), _ configClosure: AppConfigClosure? = nil, _ routerClosure: AppRouterClosure) -> Application { var config = config var env = try! env ?? Environment.detect() @@ -32,18 +33,21 @@ extension TestableProperty where TestableType: Application { return app } + /// Respond to HTTPRequest public func response(to request: HTTPRequest) -> TestResponse { let responder = try! element.make(Responder.self) let wrappedRequest = Request(http: request, using: element) return try! (response: responder.respond(to: wrappedRequest).wait(), request: wrappedRequest) } + /// Respond to HTTPRequest (throwing) public func response(throwingTo request: HTTPRequest) throws -> TestResponse { let responder = try element.make(Responder.self) let wrappedRequest = Request(http: request, using: element) return try (response: responder.respond(to: wrappedRequest).wait(), request: wrappedRequest) } + /// Create fake request public func fakeRequest() -> Request { let http = HTTPRequest(method: .GET, url: URL(string: "/")!) let req = Request(http: http, using: element) diff --git a/Sources/VaporTestTools/Extensions/Testable/Decodable+Testable.swift b/Sources/VaporTestTools/Extensions/Testable/Decodable+Testable.swift index e35a885..7afc67a 100644 --- a/Sources/VaporTestTools/Extensions/Testable/Decodable+Testable.swift +++ b/Sources/VaporTestTools/Extensions/Testable/Decodable+Testable.swift @@ -9,7 +9,8 @@ import Foundation extension TestableProperty where TestableType: Decodable { - + + /// Make accessor public static var make: TestableProperty.Type { return TestableProperty.self } @@ -19,6 +20,7 @@ extension TestableProperty where TestableType: Decodable { extension TestableProperty where TestableType: Decodable { + /// Decode data from JSON source public static func fromJSON(fileNamed fileName: String, ofType type: String? = nil, inBundle bundle: Bundle? = nil) -> TestableType { var bundle = bundle if bundle == nil { @@ -31,11 +33,13 @@ extension TestableProperty where TestableType: Decodable { return fromJSON(file: url) } + /// Decode data from JSON source public static func fromJSON(file fileUrl: URL) -> TestableType { let data = try! Data(contentsOf: fileUrl) return fromJSON(data: data) } + /// Decode data from JSON source public static func fromJSON(string: String) -> TestableType { guard let data = string.data(using: .utf8) else { fatalError("Invalid string") @@ -43,6 +47,7 @@ extension TestableProperty where TestableType: Decodable { return fromJSON(data: data) } + /// Decode data from JSON source public static func fromJSON(data: Data) -> TestableType { let decoder = JSONDecoder() let object = try! decoder.decode(TestableType.self, from: data) diff --git a/Sources/VaporTestTools/Extensions/Testable/Encodable+Testable.swift b/Sources/VaporTestTools/Extensions/Testable/Encodable+Testable.swift index af3610f..834763f 100644 --- a/Sources/VaporTestTools/Extensions/Testable/Encodable+Testable.swift +++ b/Sources/VaporTestTools/Extensions/Testable/Encodable+Testable.swift @@ -10,6 +10,7 @@ import Foundation extension TestableProperty where TestableType: Encodable { + /// Convert to Data public func asData() -> Data? { let encoder = JSONEncoder() let jsonData = try? encoder.encode(element) diff --git a/Sources/VaporTestTools/Extensions/Testable/String+Testable.swift b/Sources/VaporTestTools/Extensions/Testable/String+Testable.swift index f3a41d0..58d068c 100644 --- a/Sources/VaporTestTools/Extensions/Testable/String+Testable.swift +++ b/Sources/VaporTestTools/Extensions/Testable/String+Testable.swift @@ -5,11 +5,12 @@ // Created by Ondrej Rafaj on 27/02/2018. // -import Foundation +@_exported import Foundation extension TestableProperty where TestableType == String { + /// Return data in utf8 encoding public func asData() -> Data? { let data = element.data(using: .utf8) return data diff --git a/Sources/VaporTestTools/Properties/TestableProperty.swift b/Sources/VaporTestTools/Properties/TestableProperty.swift index fb18801..723878b 100644 --- a/Sources/VaporTestTools/Properties/TestableProperty.swift +++ b/Sources/VaporTestTools/Properties/TestableProperty.swift @@ -5,11 +5,12 @@ // Created by Ondrej Rafaj on 27/02/2018. // -import Foundation +@_exported import Foundation public struct TestableProperty { + /// Testable element accessor public var element: TestableType init(_ obj: TestableType) { diff --git a/Sources/VaporTestTools/TestTools.swift b/Sources/VaporTestTools/TestTools.swift index 0c18cab..2445603 100644 --- a/Sources/VaporTestTools/TestTools.swift +++ b/Sources/VaporTestTools/TestTools.swift @@ -5,39 +5,47 @@ // Created by Ondrej Rafaj on 27/02/2018. // -import Foundation -import Vapor +@_exported import Foundation +@_exported import Vapor // MARK: Testable +/// Testable protocol public protocol Testable { - + /// Supported testable type associatedtype ObjectType + + /// Main property to access VaporTestTools functionality on supported projects var testable: TestableProperty { get } - static var testable: TestableProperty.Type { get } + /// Main static property to access VaporTestTools functionality on supported projects + static var testable: TestableProperty.Type { get } } extension Testable { + /// Main property to access VaporTestTools functionality on supported projects public var testable: TestableProperty { return TestableProperty(self) } + /// Main static property to access VaporTestTools functionality on supported projects public static var testable: TestableProperty.Type { return TestableProperty.self } } +// MARK: Supported types + extension Request: Testable { } extension HTTPRequest: Testable { } extension Response: Testable { } extension Application: Testable { } - +/// Testable for dictionaries extension Dictionary: Testable where Key == String, Value == String { public typealias ObjectType = [String : String] } diff --git a/Tests/VaporTestToolsTests/AppTests.swift b/Tests/VaporTestToolsTests/AppTests.swift index 6d8610e..563d43a 100644 --- a/Tests/VaporTestToolsTests/AppTests.swift +++ b/Tests/VaporTestToolsTests/AppTests.swift @@ -18,9 +18,7 @@ class GenericControllerTests: XCTestCase { static let allTests = [ ("testHello", testHello), - ("testPing", testPing), - ("testNotFound", testNotFound), - ("testHash", testHash) + ("testNotFound", testNotFound) ] @@ -36,7 +34,8 @@ class GenericControllerTests: XCTestCase { func testHello() { let req = HTTPRequest.testable.get(uri: "/hello") - let res = app.testable.response(to: req) + let r = app.testable.response(to: req) + let res = r.response res.testable.debug() @@ -46,39 +45,17 @@ class GenericControllerTests: XCTestCase { XCTAssertTrue(res.testable.has(content: "Hello, world!"), "Incorrect content") } - func testPing() { - let req = HTTPRequest.testable.get(uri: "/ping") - let res = app.testable.response(to: req) - - res.testable.debug() - - XCTAssertTrue(res.testable.has(statusCode: .ok), "Wrong status code") - XCTAssertTrue(res.testable.has(contentType: "application/json; charset=utf-8"), "Missing content type") - XCTAssertTrue(res.testable.has(contentLength: 15), "Wrong content length") - XCTAssertTrue(res.testable.has(content: "{\"code\":\"pong\"}"), "Incorrect content") - } - func testNotFound() { let req = HTTPRequest.testable.get(uri: "/not-found") - let res = app.testable.response(to: req) + let r = app.testable.response(to: req) + let res = r.response res.testable.debug() - XCTAssertTrue(res.testable.has(statusCode: 404), "Wrong status code") + XCTAssertTrue(res.testable.has(statusCode: .notFound), "Wrong status code") XCTAssertFalse(res.testable.has(header: "Content-Type"), "Should not content type") XCTAssertTrue(res.testable.has(contentLength: 9), "Wrong content length") XCTAssertTrue(res.testable.has(content: "Not found"), "Incorrect content") } - func testHash() { - let req = HTTPRequest.testable.get(uri: "/hash/something") - let res = app.testable.response(to: req) - - res.testable.debug() - - XCTAssertTrue(res.testable.has(statusCode: .ok), "Wrong status code") - XCTAssertTrue(res.testable.has(contentType: "text/plain; charset=utf-8"), "Missing content type") - XCTAssertTrue(res.testable.has(contentLength: 60), "Wrong content length") - } - } diff --git a/scripts/update.sh b/scripts/update.sh index bd70fb8..c254080 100755 --- a/scripts/update.sh +++ b/scripts/update.sh @@ -1,6 +1,5 @@ #!/usr/bin/env bash rm -rf .build -vapor clean --verbose -y -rm Package.resolved -vapor xcode --verbose -y +vapor clean -y --verbose +vapor xcode -n --verbose diff --git a/scripts/upgrade.sh b/scripts/upgrade.sh new file mode 100755 index 0000000..6a98522 --- /dev/null +++ b/scripts/upgrade.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +rm -rf .build +vapor clean -y --verbose +rm Package.resolved +vapor xcode -n --verbose