stormy-weather/test/models/test-account.rb
2012-02-05 22:01:28 -08:00

384 lines
12 KiB
Ruby

#!/usr/bin/env ruby
#
# Copyright 2012 Sami Samhuri <sami@samhuri.net>
require 'common'
class AccountTest < Stormy::Test::Case
include Stormy::Test::Helpers::Accounts
include Stormy::Test::Helpers::Projects
def setup
setup_accounts
setup_projects
@invalid_addresses = [
'invalid email address',
'invalid@email@address',
'invalid.email.address',
'invalid.email@address'
]
end
def teardown
teardown_projects
teardown_accounts
end
### Class Methods
def test_check_password
assert_equal @existing_account.id, Account.check_password(@existing_account.email, @existing_account_data['password'])
assert_equal @existing_account.id, Account.check_password(@existing_account.email.upcase, @existing_account_data['password'])
assert !Account.check_password(@existing_account.email, 'incorrect password')
assert !Account.check_password('non@existent.email', 'any password')
end
def test_email_taken?
assert Account.email_taken?(@existing_account.email)
assert !Account.email_taken?('freddy@example.com'), "New email is reported as taken"
end
def test_fetch_existing_by_email
account = Account.fetch_by_email(@existing_account.email)
assert account
assert_equal @existing_account.id, account.id
check_account_fields(account, @existing_account_data)
end
def test_fetch_nonexistent_by_email
assert_nil Account.fetch_by_email('this is not a real email')
end
def test_reset_password
data = Account.reset_password(@existing_account.email)
assert_equal @existing_account.first_name, data['name']
assert data['token']
assert !Account.reset_password('non@existent.email')
end
def test_use_password_reset_token
data = Account.reset_password(@existing_account.email)
assert_equal @existing_account.id, Account.use_password_reset_token(@existing_account.email, data['token'])
end
def test_id_from_email
assert_equal @existing_account.id, Account.id_from_email(@existing_account.email)
assert_nil Account.id_from_email('not a real email')
end
def test_verify_email
assert !Account.verify_email(@existing_account.email, 'invalid token')
assert Account.verify_email(@existing_account.email, @existing_account.email_verification_token)
account = Account.fetch(@existing_account.id)
assert account.email_verified
assert !account.email_verification_token
assert !Account.verify_email('non@existent.email', 'insignificant token')
end
def test_email_verified?
assert !Account.email_verified?(@existing_account.email)
Account.verify_email(@existing_account.email, @existing_account.email_verification_token)
assert Account.email_verified?(@existing_account.email)
end
def test_create_email_verification_token
assert @existing_account.email_verification_token
# no new token is generated if one is present
token = @existing_account.email_verification_token
@existing_account.create_email_verification_token
assert_equal @existing_account.email_verification_token, token
# a token is generated if necessary
Account.verify_email(@existing_account.email, @existing_account.email_verification_token) # clears token
account = Account.fetch(@existing_account.id)
assert !account.email_verification_token
account.create_email_verification_token
assert account.email_verification_token
assert account.email_verification_token != token
end
### Instance Methods
def check_account_fields(account, fields)
fields.each do |key, expected|
if key == 'password'
assert account.password == fields['password'], "<#{fields['password'].inspect}> expected but was <#{account.password.inspect}>"
else
actual = account.send(key)
assert_equal expected, actual, "#{key}: <#{expected.inspect}> expected but was <#{actual.inspect}>"
end
end
end
def test_create
assert @existing_account
assert @existing_account.id
assert @existing_account.email_verification_token
# creation time can be 1 - 2 seconds in the past
delta = (Time.now.to_i - @existing_account.created_timestamp).abs
assert delta < 3
check_account_fields(@existing_account, @existing_account_data)
# indexes
assert Account.fetch_by_email(@existing_account.email)
end
def test_create_with_existing_email
assert_raises Account::EmailTakenError do
Account.new(@existing_account_data).create
end
end
def test_create_with_missing_fields
# first name
assert_raises Account::InvalidDataError do
Account.create({ 'last_name' => 'Kruger', 'email' => 'freddy@example.com', 'password' => 'secret password' })
end
assert_raises Account::InvalidDataError do
Account.create({ 'first_name' => ' ', 'last_name' => 'Kruger', 'email' => 'freddy@example.com', 'password' => 'secret password' })
end
# last name
assert_raises Account::InvalidDataError do
Account.create({ 'first_name' => 'Freddy', 'email' => 'freddy@example.com', 'password' => 'secret password' })
end
assert_raises Account::InvalidDataError do
Account.create({ 'first_name' => 'Freddy', 'last_name' => ' ', 'email' => 'freddy@example.com', 'password' => 'secret password' })
end
# email
assert_raises Account::InvalidDataError do
Account.create({ 'first_name' => 'Freddy', 'last_name' => 'Kruger', 'password' => 'secret password' })
end
assert_raises Account::InvalidDataError do
Account.create({ 'first_name' => 'Freddy', 'last_name' => 'Kruger', 'email' => ' ', 'password' => 'secret password' })
end
# password
assert_raises Account::InvalidDataError do
Account.create({ 'first_name' => 'Freddy', 'last_name' => 'Kruger', 'email' => 'freddy@example.com' })
end
assert_raises Account::InvalidDataError do
Account.create({ 'first_name' => 'Freddy', 'last_name' => 'Kruger', 'email' => 'freddy@example.com', 'password' => ' ' })
end
end
def test_create_with_invalid_fields
data = {
'first_name' => 'Sami',
'last_name' => 'Samhuri',
'password' => 'secret password'
}
original_email = data['email']
@invalid_addresses.each do |email|
data['email'] = email
assert_raises Account::InvalidDataError do
Account.create(data)
end
end
data['email'] = original_email
end
def test_delete!
@existing_account.delete!
assert Account.fetch(@existing_account.id).nil?, 'Account was fetched by id after deletion'
assert Account.fetch_by_email(@existing_account.email).nil?, 'Account was fetched by email after deletion'
# indexes
assert !@existing_account.email_taken?, 'Account email is taken after deletion'
assert !Account.exists?(@existing_account.id), 'Account exists after deletion'
# projects are deleted
assert_equal [], @existing_account.project_ids
end
def test_name
assert_equal "#{@existing_account.first_name} #{@existing_account.last_name}", @existing_account.name
end
def test_count_projects
assert_equal 1, @existing_account.count_projects
end
def test_project_ids
assert_equal [@existing_project.id], @existing_account.project_ids
end
def test_projects
assert_equal [@existing_project.id], @existing_account.projects.map { |p| p.id }
end
def test_sorted_projects
# make sure created timestamp is in the future ... this stinks
sleep 1
project = Project.create(@new_project_data.merge(:account_id => @existing_account.id))
assert_equal [@existing_project.id, project.id], @existing_account.sorted_projects.map { |p| p.id }
end
def test_add_project_id
@existing_account.add_project_id('fake-project-id')
assert_equal 2, @existing_account.count_projects
end
def test_remove_project_id
@existing_account.remove_project_id(@existing_project.id)
assert_equal 0, @existing_account.count_projects
end
def test_update
original_data = {
'id' => @existing_account.id,
'email' => @existing_account.email,
'phone' => @existing_account.phone
}
updated_data = {
# updatable
'first_name' => 'Samson',
'last_name' => 'Simpson',
'phone' => '+12509991234',
# not updatable
'id' => 'should be ignored',
'email' => 'should be ignored',
'password' => 'should be ignored'
}
@existing_account.update(updated_data)
# should be updated
assert_equal updated_data['first_name'], @existing_account.first_name
assert_equal updated_data['last_name'], @existing_account.last_name
assert_equal updated_data['phone'], @existing_account.phone
# should not be updated
assert_equal original_data['id'], @existing_account.id
assert_equal original_data['email'], @existing_account.email
assert @existing_account.password != updated_data['password']
assert @existing_account.password == @existing_account_data['password']
end
def test_update_with_invalid_fields
assert_raises Account::InvalidDataError do
@existing_account.update(:first_name => ' ')
end
assert_raises Account::InvalidDataError do
@existing_account.update(:last_name => ' ')
end
# phone number
invalid_numbers = [
'+44 123 456 7890', # too long, wrong country code
'123' # too short, not a real phone number
]
invalid_numbers.each do |number|
assert_raises Account::InvalidDataError do
@existing_account.update(:phone => number)
end
end
end
def test_update_email
# pretend this address is verified
@existing_account.email_verified = true
@existing_account.save
new_email = 'sami-different@example.com'
old_email = @existing_account.email
# updates database immediately
@existing_account.update_email(new_email)
assert_equal new_email, @existing_account.email
assert_equal new_email, Account.fetch(@existing_account.id).email
# new email addresses are not verified
assert !@existing_account.email_verified, "Email address should not be verified"
assert !Account.fetch(@existing_account.id).email_verified
# index is updated
assert Account.email_taken?(new_email)
assert !Account.email_taken?(old_email)
# no change in address is a noop
@existing_account.update_email(new_email)
# invalid addresses are rejected
@invalid_addresses.each do |email|
assert_raises Account::InvalidDataError do
@existing_account.update_email(email)
end
end
end
def test_update_email_changing_only_case
# pretend this address is verified
@existing_account.email_verified = true
@existing_account.save
# change only the case
loud_email = @existing_account.email.upcase
@existing_account.update_email(loud_email)
assert_equal loud_email, @existing_account.email
# a mere change of case does not reset verified flag
assert @existing_account.email_verified
assert Account.fetch(@existing_account.id).email_verified
# is still indexed properly
assert Account.email_taken?(loud_email)
end
def test_update_password
old_password = @existing_account_data['password']
new_password = 'the new password'
@existing_account.update_password(old_password, new_password)
assert @existing_account.password == new_password
assert Account.fetch(@existing_account.id).password == new_password
assert_raises Account::IncorrectPasswordError do
@existing_account.update_password('incorrect', 'irrelevant')
end
assert_raises Account::InvalidDataError do
@existing_account.update_password(new_password, ' ')
end
end
def test_update!
original_data = {
'id' => @existing_account.id,
'email' => @existing_account.email,
'phone' => @existing_account.phone
}
updated_data = {
# updatable
'first_name' => 'Samson',
'last_name' => 'Simpson',
'phone' => '+12509995534',
# not updatable
'id' => 'should be updated',
'email' => 'should be updated',
'password' => 'should be updated'
}
@existing_account.update!(updated_data)
# all should be updated
check_account_fields(@existing_account, updated_data)
# restore fields required for project clean up
@existing_account.update!(original_data)
end
end