Lychee = require('../')
should = require 'should'

Lychee.connect ['mongodb://127.0.0.1:27017/lychee']

describe 'Lychee', ->
	describe 'Validation', ->
		class CustomEmailValidator
			constructor: (@params) ->
			
			validate: (value, valid, model) ->
				valid /^.+\@.+\..+$/.test(value), 'is not email'
		
		class User extends Lychee.Model
			@driver 'mongodb'
			
			@key '_id', primary: yes
			@key 'posts_number'
			@key 'is_admin'
			@key 'email'
			@key 'password'

			@validate 'email', 'password', presence: yes, allowBlank: no
			@validate 'email', with: /^.+\@.+\..+$/, message: 'is not email'
			@validate 'email', with: CustomEmailValidator
			@validate 'email', with: 'validateEmail'
			@validate 'password', length: '>= 5', confirmation: yes, allowBlank: no
			@validate 'posts_number', value: '>= 0'
			@validate 'is_admin', acceptance: accept: 'yes'
			@validate 'is_admin', if: (valid) ->
				valid @is_admin is 'yes', 'is not valid'
			
			validateEmail: (value, valid) ->
				valid /^.+\@.+\..+$/.test(value), 'is not email' # @email

		User = Lychee.setup User

		it 'should validate user', (done) ->
			user = new User
			user.email = 'test@test.com'
			user.password = 'testtest'
			user.password_confirmation = 'testtest'
			user.posts_number = 1
			user.is_admin = 'yes'
			user.validate (valid) ->
				valid.should.equal true
				user.email = 'not an email'
				user.password = ''
				user.posts_number = -52
				user.is_admin = 'no'
				user.validate (valid) ->
					valid.should.equal false
					done()
		
		it 'should skip all validations', (done) ->
			user = new User
			user.email = 'not email'
			user.save validate: no, ->
				User.all (err, users) ->
					users.length.should.equal 1
					done()
		
		after (done) ->
			User.remove -> done()
	
	describe 'Extensions', ->
		class HasRatingExtension
			class HasRatingExtension.InstanceMethods
				voteUp: ->
					@rating = 0 if not @rating
					@rating++

				voteDown: ->
					@rating = 0 if not @rating
					@rating--

			class HasRatingExtension.ClassMethods
				hasRating: ->
					@key 'rating'

		Lychee.Model.include HasRatingExtension

		class Comment extends Lychee.Model
			@driver 'mongodb'
			
			@key '_id', primary: yes
			@key 'author'
			@key 'body'

			@hasRating()

			@validates 'author', 'body', allowBlank: no, presence: yes

		Comment = Lychee.setup Comment

		it 'should vote up comment', (done) ->
			comment = new Comment
			comment.author = 'Steve'
			comment.body = 'I love Lychee'
			comment.voteUp()
			comment.save ->
				Comment.find (err, comments) ->
					comments.length.should.equal 1
					comments[0].rating.should.equal 1
					done()

		after (done) ->
			Comment.remove -> done()

	describe 'Scopes', ->
		class Post extends Lychee.Model
			@driver 'mongodb'
			
			@key '_id', primary: yes
			@key 'title', default: 'Default title'
			@key 'body', default: 'Default body'

			@scope 'latest', limit: 1, sort: _id: -1

		Post = Lychee.setup Post

		it 'should find latest post', (done) ->
			post = new Post
			post.title = 'First'
			post.body = 'First'
			post.save ->
				post = new Post title: 'Second', body: 'Second'
				post.save ->
					Post.latest (err, posts) ->
						posts[0].title.should.equal 'Second'
						done()

		after (done) ->
			Post.remove -> done()

	describe 'Hooks', ->
		class Post extends Lychee.Model
			@driver 'mongodb'
			
			@key '_id', primary: yes
			@key 'title', default: 'Default title'
			@key 'body', default: 'Default body'

			beforeSave: -> do @hookHandler
			aroundSave: -> do @hookHandler
			afterSave: -> do @hookHandler
			beforeCreate: -> do @hookHandler
			aroundCreate: -> do @hookHandler
			afterCreate: -> do @hookHandler
			beforeUpdate: -> do @hookHandler
			aroundUpdate: -> do @hookHandler
			afterUpdate: -> do @hookHandler
			beforeRemove: -> do @hookHandler
			aroundRemove: -> do @hookHandler
			afterRemove: -> do @hookHandler

		Post = Lychee.setup Post

		it 'should catch all hooks', (done) ->
			post = new Post title: 'Title', body: 'Body'
			hooksCalled = 0
			post.hookHandler = ->
				hooksCalled++
				done() if hooksCalled is 12

			post.save ->
				post.title = 'New title'
				post.save ->
					post.remove ->

		after (done) ->
			Post.remove -> done()

	describe 'Events', ->
		class Post extends Lychee.Model
			@driver 'mongodb'
			
			@key '_id', primary: yes
			@key 'title', default: 'Default title'
			@key 'body', default: 'Default body'

		Post = Lychee.setup Post

		it 'should catch create event', (done) ->
			Post.on 'create', ->
				should.exist @_id
				Post.unbind 'create'
				done()

			post = new Post title: 'Title', body: 'Body'
			post.save ->

		it 'should catch update event', (done) ->
			Post.on 'update', ->
				@title.should.equal 'New title'
				Post.unbind 'update'
				done()

			Post.find title: 'Title', (err, posts) ->
				post = posts[0]
				post.title = 'New title'
				post.save ->

		it 'should catch remove event', (done) ->
			Post.on 'remove', ->
				Post.unbind 'remove'
				done()

			Post.find title: 'New title', (err, posts) ->
				post = posts[0]
				post.remove ->

		it 'should catch removeAll event', (done) ->
			Post.on 'removeAll', ->
				Post.unbind 'removeAll'
				done()

			Post.remove()