#!/bin/env ruby require File.dirname(__FILE__) + '/../test_helper' class UserTest < Test::Unit::TestCase fixtures 'users', 'topics', 'posts', 'topic_subscriptions', 'topic_reads' def test_login user = User.find_by_login('u', 'u') assert_equal 'u', user.name assert_equal User, user.class user = User.find_by_login('u', 'u') assert_equal 'u', user.name assert_equal User, user.class # wrong password assert_nil User.find_by_login('u', 'wrong password') # invalid user assert_nil User.find_by_login('unknown user', 'password doesnt matter') end def test_create db.execute 'DELETE FROM users' User.create(prototype_params(User)) user = User.find_all[0] assert user assert_equal prototype_params(User)['firstname'].capitalize, user.firstname assert_equal prototype_params(User)['surname'].capitalize, user.surname prototype_params(User).each_pair { |k, v| next if ['firstname', 'surname'].include? k assert_equal v, user[k], "Value of #{k} not as expected" unless k == 'id' } end def test_create_simple_validations assert_nothing_raised {User.create(prototype_params(User))} # empty name assert_validation_fails(User, prototype_params(User, 'name' => '')) # empty email assert_validation_fails(User, prototype_params(User, 'email' => '')) # empty firstname assert_validation_fails(User, prototype_params(User, 'firstname' => '')) # empty surname assert_validation_fails(User, prototype_params(User, 'surname' => '')) # invalid email (unit-tested elsewhere) assert_validation_fails(User, prototype_params(User, 'email' => 'bad@email')) end def test_create_bad_firstname # bad firstname doesn't match /^.{2,20}$/ # too short db.execute('DELETE FROM users') assert_validation_fails(User, prototype_params(User, {'firstname' => 'a'}), 'firstname') assert_nothing_raised { User.create(prototype_params(User, {'firstname' => 'Aa'})) } # too long db.execute('DELETE FROM users') assert_validation_fails(User, prototype_params(User, 'firstname' => '123456789012345678901'), 'firstname') assert_nothing_raised { User.create(prototype_params(User, {'firstname' => '12345678901234567890'})) } end def test_create_bad_surname # bad surname doesn't match /^.{2,20}$/ # too short db.execute('DELETE FROM users') assert_validation_fails(User, prototype_params(User, {'surname' => 'a'}), 'surname') assert_nothing_raised { User.create(prototype_params(User, {'surname' => 'Aa'})) } # too long db.execute('DELETE FROM users') assert_validation_fails(User, prototype_params(User, 'surname' => '123456789012345678901'), 'surname') assert_nothing_raised { User.create(prototype_params(User, {'surname' => '12345678901234567890'})) } end def test_create_bad_name # bad name doesn't match /^[a-z0-9\-]{3,15}$/i # too short db.execute('DELETE FROM users') assert_validation_fails(User, prototype_params(User, {'name' => 'aa'}), 'name') assert_nothing_raised { User.create(prototype_params(User, {'name' => 'aAa'})) } # too long db.execute('DELETE FROM users') assert_validation_fails(User, prototype_params(User, {'name' => '1234567890123456'}), 'name') assert_nothing_raised { User.create(prototype_params(User, {'name' => '123456789012345'})) } # bad character db.execute('DELETE FROM users') assert_validation_fails(User, prototype_params(User, {'name' => 'aaa#'}), 'name') assert_nothing_raised { User.create(prototype_params(User, {'name' => 'aZa-'})) } end def test_create_duplicate_name User.create(prototype_params(User)) assert_validation_fails(User, prototype_params(User, {'email' => 'some@other.email'}), 'name') end def test_create_duplicate_email User.create(prototype_params(User)) assert_validation_fails(User, prototype_params(User, {'name' => 'some other name'}), 'email') end def test_update_read_time user = User.find(1) topic = Topic.find(2) db.execute('DELETE FROM topic_reads') result = time {user.update_read_time(topic)} topic_reads = user.find_all_in_topic_reads assert_equal 1, topic_reads.size topic_read = topic_reads[0] assert_equal topic_read, result assert_equal_sysdate result.updated_at assert_equal 2, result.topic_id end def test_can_delete? # post is own, has no children assert User.find(2).can_delete?(Post.find(21)) # post has no children but is somebody else's assert !(User.find(3).can_delete?(Post.find(21))) # own post, but it has children assert !(User.find(2).can_delete?(Post.find(101))) end def can_edit? # post is own assert User.find(2).can_edit?(Post.find(2)) # post is somebody else's assert !(User.find(2).can_edit?(Post.find(3))) # anonymous post Post.update 2, {'user_id' => nil} assert !(User.find(2).can__edit?(Post.find(2))) end def test_topic_read_times # one topic read assert_equal({1 => Time.mktime(2004, 10, 01, 0, 0, 0, 0)}, User.find(1).topic_read_times) # one topic reads expected_reads = { 1 => Time.mktime(2004, 10, 03, 0, 0, 0, 0), 3 => Time.mktime(2004, 10, 03, 1, 0, 0, 0), } assert_equal(expected_reads, User.find(3).topic_read_times) # no topic reads assert_equal({}, User.find(2).topic_read_times) end def test_update_duplicate_validations # update should bypass the already existing nick check admin = User.find(1) sergej = User.find(2) assert_raise(RForum::ValidationError) { User.update(2, 'name' => admin.name) } assert_nothing_raised { User.update(2, 'name' => sergej.name) } # update should smartly check for the already existing email - email of another user should not # be duplicated assert_raise(RForum::ValidationError) { User.update(2, 'email' => admin.email) } assert_nothing_raised { User.update(2, 'email' => sergej.email) } end def test_update_nick_cannot_change assert_raise(RForum::ValidationError) { User.update(2, 'name' => 'anothernick') } end def test_create_unencrypted_password_handling new_user = User.create(prototype_params(User)) password = new_user.instance_eval("@unencrypted_password") assert_match /\w{8}/, password assert_equal password, new_user.tell_and_forget_unencrypted_password assert_nil new_user.instance_eval("@unencrypted_password") end def test_generate_security_token user = User.find(1) assert_nil user.security_token time { user.generate_security_token } @start_time += RForum::CONFIG[:security_token_life_hours] * 60 * 60 @finish_time += RForum::CONFIG[:security_token_life_hours] * 60 * 60 user_from_db = User.find(1) assert user_from_db.token_expiry.to_i.between?(@start_time.to_i, @finish_time.to_i) assert_match /\w{32}/, user_from_db.security_token end def test_generate_security_token_twice # If user clicks several times on user = User.find(1) token1 = user.generate_security_token token2 = user.generate_security_token assert_equal token1, token2 # but if a new security token is requested several hours later (more than half the token # lifetime in fact), it should be generated anew, and the old one should be discarded. token1 = user.generate_security_token user.token_expiry = Time.at( Time.now.to_i + RForum::CONFIG[:security_token_life_hours] * 60 * 60 / 2) token2 = user.generate_security_token assert token1 != token2 end def test_find_by_token user = User.find(1) token = user.generate_security_token result = User.find_by_token(1, token) assert_equal user, result end def test_find_by_token_error_handling user = User.find(1) token = user.generate_security_token assert_raise(ArgumentError) { result = User.find_by_token(1, nil) } assert_raise(ArgumentError) { result = User.find_by_token(nil, token) } assert_nil User.find_by_token(1, "some_other_token") assert_nil User.find_by_token(non_existent_user = 97531, token) end def test_find_by_token_expired_token user = User.find(1) token = user.generate_security_token user.update_attribute('token_expiry', Time.at(Time.new.to_i - 1)) assert_nil User.find_by_token(1, token) end # TODO test when token is expired def test_additional_information # TODO: test if type checking works user = User.find(1) user.additional_information = { 'Website' => 'http://andreas-s.net' } user.save reloaded_user = User.find(1) assert_equal user.additional_information, reloaded_user.additional_information end end