users = require './fixtures/users'
User     = require '../models/User'
require 'should'

describe 'User', ->

  before (done) ->
    users.clear done
  
  describe 'schema', ->

    user = null
    guest = null

    beforeEach (done) ->
      users.clear ->
        user = new User
        guest = users.build 'guest'
        done()

    it 'should require an email', (done) ->
      user.save (err) ->
        err.errors.email.should.be.a 'object'
        done()
  
    it 'should require email to be valid', (done) ->
      user.email = 'not-valid'
      user.save (err) ->
        err.errors.email.type.should.eql 'email is invalid'
        done()
  
    it 'should require email to be unique', (done) ->
      user1 = new User email: 'maverick@woof.com'
      user2 = new User email: 'maverick@woof.com'
      user1.save ->
        user2.save (err) ->
          err.should.be.a 'object'
          done()
  
    it 'should require hash', (done) ->
      user.save (err) ->
        err.errors.hash.should.be.a 'object'
        done()
  
    it 'should require salt', (done) ->
      user.save (err) ->
        err.errors.salt.should.be.a 'object'
        done()
  
    it 'should require a first name', (done) ->
      user.save (err) ->
        err.errors['name.first'].should.be.a 'object'
        done()
  
    it 'should require a last name', (done) ->
      user.save (err) ->
        err.errors['name.last'].should.be.a 'object'
        done()
  
    it 'should get the full name', (done) ->
      user.name.first = 'John'
      user.name.last = 'Coltrane'
      user.name.full.should.equal 'John Coltrane'
      done()
  
    it 'should set salt and hash from a password', (done) ->
      user.password = 'secret'
      user.save (err) ->
        user.salt.should.be.a 'string'
        user.hash.should.be.a 'string'
        done()
  
    it 'should not store the password', (done) ->
      guest.save (err) ->
        User.findOne {_id: guest._id}, (err, u) ->
          u.should.not.have.property 'password'
          done()
  
    it 'should require a non-empty password' , (done) ->
      user = new User
        email: 'jc@example.com'
        password: ''
        name:
          first: 'John'
          last: 'Coltrane'
      
      user.save (err) ->
        err.errors.password.should.be.a 'object'
        done()

    it 'should have a list of roles', (done) ->
      user = new User
      user.roles.should.be.an.instanceof Array
      done()

    it 'should know when it was created', (done) ->
      guest.save (err) ->
        guest.created.should.exist
        done()

    it 'should know when it was last updated', (done) ->
      guest.save (err) ->
        cb = () =>
          guest.first = 'Johnny'
          guest.save (err) -> 
            guest.updated.should.not.eql guest.created
            done()
        setTimeout cb, 1000

  describe 'authentication', ->
    
    user = users.build 'guest'
  
    it 'should verify a correct password', (done) ->
      user.verifyPassword 'secret', (err, veracity) ->
        veracity.should.equal true
        done()
  
    it 'should not verify an incorrect password', (done) ->
      user.verifyPassword 'wrong', (err, veracity) ->
        veracity.should.equal false
        done()
  
    it 'should authenticate valid credentials', (done) ->
      user.save (err) ->
        User.authenticate user.email, 'secret', (err, u) ->
          u.email.should.eql user.email
          done()
      
    it 'should not authenticate an invalid password', (done) ->
      user.save (err) ->
        User.authenticate user.email, 'wrong', (err, u, info) ->
          u.should.equal false
          info.should.eql {message: 'Invalid password!'}
          done()
      
    it 'should not authenticate an unknown user', (done) ->
      User.authenticate 'unknown@example.com', 'secret', (err, u, info) ->
        u.should.equal false
        info.should.eql {message: 'Unknown user!'}
        done()
  
    it 'should pass a database error'
  
    it 'should pass a password verification error'
  
  describe 'authorization', ->

    it 'should check for a role', (done) ->
      user = new User roles: ['editor']
      user.is('editor').should.be.true
      user.is('admin').should.be.false
      done()
