<commit_before>@testable import Vapor
@testable import Auth
@testable import HTTP
@testable import Fluent
import XCTest

class AuthTests: XCTestCase {
    static let allTests = [
        ("testUserLoginAndOut", testUserLoginAndOut),
    ]
    
    var database:Database!
    var droplet:Droplet!
    
    
    override func setUp() {
        
        //setup droplet
        database = Database(MemoryDriver())
        droplet = Droplet()
        
        droplet.database = database
        
        let authMiddleware = AuthMiddleware(user: User.self)
        droplet.middleware.append(authMiddleware)
        
        //creates dummy user
        User.database = database

        do {
            var user = User(name:"John")
            try user.save()
            
        } catch {
            XCTFail("Could not create User")
        }
        
    }
    
    func testUserLoginAndOut() throws {
        let request = Request(method: .get, path: "login")
        
        droplet.get("login") { req in
            
            try req.auth.login(Identifier(id:1)) // id of first item inserted
            return try req.auth.user().converted(to: JSON.self)
        }
        
        let res = try droplet.respond(to: request)
        
        XCTAssertEqual(res.status, .ok)
        XCTAssertEqual(res.data["name"]?.string, "John")
        XCTAssertNotNil(res.cookies["vapor-auth"])
        
        try testUserLogout(with: res) //try to logout with content of response (w/ cookies etc.)
        
    }
    
    func testUserLogout(with response:Response) throws {
        let request = Request(method: .get, path: "logout")
        request.cookies = response.cookies
        
        droplet.get("logout") { req in
            
            guard let user = try req.auth.user() as? User, user.id == 1 else {
                throw User.Error.userNotLoggedIn
            }
            
            try req.auth.logout()
            
            return JSON(["message": "User logged out"])
        }
        
        let res = try droplet.respond(to: request)
        XCTAssertEqual(res.status, .ok)
        XCTAssertNil(res.cookies["vapor-auth"])
        XCTAssertEqual(res.data["message"]?.string, "User logged out")
    }

}

/**
    Utilities/User.swift conforms to Auth.User
    in order to log it in & out.
 */

extension User: Auth.User {
    
    enum Error:Swift.Error {
        case invalidCredentialType
        case userNotFound
        case userNotLoggedIn
        case notAllowed
    }
    
    public static func register(credentials: Credentials) throws -> Auth.User {
        //required but not used
        return User(name: "Dummy user")
    }
    
    public static func authenticate(credentials: Credentials) throws -> Auth.User {
        
        guard let id = credentials as? Identifier else {
            throw Error.invalidCredentialType
        }
        
        let user = try User.find(id.id)
        
        guard let u = user else {
            throw Error.userNotFound
        }
        
        return u
        
    }

}

<commit_msg>ProtectMiddleware tests + more modular Auth tests<commit_after>@testable import Vapor
@testable import Auth
@testable import HTTP
@testable import Fluent
import XCTest

class AuthTests: XCTestCase {
    static let allTests = [
        ("testUserLogin", testUserLogin),
        ("testProtectedRoute", testProtectedRoute),
        ("testUserLogout", testUserLogout)
    ]
    
    var database:Database!
    var droplet:Droplet!
    
    
    override func setUp() {
        
        //setup droplet
        database = Database(MemoryDriver())
        droplet = Droplet()
        
        droplet.database = database
        
        let authMiddleware = AuthMiddleware(user: User.self)
        droplet.middleware.append(authMiddleware)
        
    }
    
    /**
        Logs in a basic user with provided credentials.
        Can be used in any tests requiring auth.
        Will provide a response with an auth cookie only
        with an Identifier with an id of 1.
    */
    
    func login(credentials:Identifier) throws -> Response {
        
        //First : creates a dummy user with an Id of 1 if not exists
        User.database = self.database
        var user = try User.find(1)
        if user == nil {
            user = User(name: "John")
            try user!.save()
        }
        
        //Second : Bind the login request to a registered "login" route
        let login = Request(method: .get, path: "login")
        droplet.get("login") { req in
            
            try req.auth.login(credentials) // id of first item inserted
            return try req.auth.user().converted(to: JSON.self)
        }
        
        //Third : If successful, returns a response containing the user logged in as JSON and vapor-auth cookie
        
        return try droplet.respond(to: login)
    }
    
    func testUserLogin() throws {
        
        let authenticated = try login(credentials:Identifier(id:1))
        XCTAssertEqual(authenticated.status, .ok)
        XCTAssertEqual(authenticated.data["name"]?.string, "John")
        XCTAssertNotNil(authenticated.cookies["vapor-auth"])
        
        let notAuthenticated = try login(credentials:Identifier(id:2)) // user with id of 2 does not exist in the database
        XCTAssertNotEqual(notAuthenticated.status, .ok)
        XCTAssertNil(notAuthenticated.cookies["vapor-auth"])
        
    }
    
    func testProtectedRoute() throws {
        
        let protectMiddleware = ProtectMiddleware(error: Abort.custom(status: .methodNotAllowed, message: ""))
        
        droplet.group(protectMiddleware) { secure in
            secure.get("secure") { req in
                return try req.auth.user().converted(to: JSON.self)
            }
        }
        
        let secure = Request(method: .get, path:"secure")

        var protected = try droplet.respond(to: secure)
        XCTAssertEqual(protected.status, .methodNotAllowed) // thrown from ProtectMiddleware
        
        let authenticated = try login(credentials:Identifier(id:1))
        secure.cookies = authenticated.cookies //set appropriate login cookie
        
        protected = try droplet.respond(to: secure)
        XCTAssertEqual(protected.status, .ok)
        XCTAssertEqual(protected.data["name"]?.string, "John")

    }
    
    func testUserLogout() throws {
        
        droplet.get("logout") { req in
            
            let user = try req.auth.user() as? User
            XCTAssertNotNil(user)
            XCTAssertEqual(user?.id, 1)
            try req.auth.logout()
            
            return JSON(["message": "User logged out"])
        }
        
        let request = Request(method: .get, path: "logout")
        
        let authenticated = try login(credentials: Identifier(id:1))
        request.cookies = authenticated.cookies //set appropriate login cookie
        
        let res = try droplet.respond(to: request)
        XCTAssertEqual(res.status, .ok)
        XCTAssertNil(res.cookies["vapor-auth"])
        XCTAssertEqual(res.data["message"]?.string, "User logged out")
    }

}

/**
    Utilities/User.swift conforms to Auth.User
    in order to log it in & out.
 */

extension User: Auth.User {
    
    public static func register(credentials: Credentials) throws -> Auth.User {
        //required but not used
        return User(name: "Dummy user")
    }
    
    public static func authenticate(credentials: Credentials) throws -> Auth.User {
        
        let id = credentials as? Identifier
        XCTAssertNotNil(id)
        
        guard let user = try User.find(id!.id) else {
            throw Abort.custom(status: .methodNotAllowed, message: "")
        }
        
        return user
    }

}


{'fraction_non_alphanumeric': 0.0928709055876686, 'fraction_numerical': 0.0014129736673089274, 'mean_word_length': 1.8901262063845583, 'pattern_counts': {'":': 2, '<': 3, '<?xml version=': 0, '>': 8, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1985189', 'n_tokens_mistral': 2176, 'n_tokens_neox': 2144, 'n_words': 570}