aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/test/cases/base_test.rb
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/test/cases/base_test.rb')
-rw-r--r--activerecord/test/cases/base_test.rb321
1 files changed, 193 insertions, 128 deletions
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index 12c1cfb30e..698c3d0cb1 100644
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -23,10 +23,18 @@ require 'models/edge'
require 'models/joke'
require 'models/bulb'
require 'models/bird'
+require 'models/teapot'
require 'rexml/document'
require 'active_support/core_ext/exception'
require 'bcrypt'
+class FirstAbstractClass < ActiveRecord::Base
+ self.abstract_class = true
+end
+class SecondAbstractClass < FirstAbstractClass
+ self.abstract_class = true
+end
+class Photo < SecondAbstractClass; end
class Category < ActiveRecord::Base; end
class Categorization < ActiveRecord::Base; end
class Smarts < ActiveRecord::Base; end
@@ -69,6 +77,16 @@ end
class BasicsTest < ActiveRecord::TestCase
fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics, 'warehouse-things', :authors, :categorizations, :categories, :posts
+ def test_generated_methods_modules
+ modules = Computer.ancestors
+ assert modules.include?(Computer::GeneratedFeatureMethods)
+ assert_equal(Computer::GeneratedFeatureMethods, Computer.generated_feature_methods)
+ assert(modules.index(Computer.generated_attribute_methods) > modules.index(Computer.generated_feature_methods),
+ "generated_attribute_methods must be higher in inheritance hierarchy than generated_feature_methods")
+ assert_not_equal Computer.generated_feature_methods, Post.generated_feature_methods
+ assert(modules.index(Computer.generated_attribute_methods) < modules.index(ActiveRecord::Base.ancestors[1]))
+ end
+
def test_column_names_are_escaped
conn = ActiveRecord::Base.connection
classname = conn.class.name[/[^:]*$/]
@@ -169,6 +187,31 @@ class BasicsTest < ActiveRecord::TestCase
end
end
+ def test_previously_changed
+ topic = Topic.find :first
+ topic.title = '<3<3<3'
+ assert_equal({}, topic.previous_changes)
+
+ topic.save!
+ expected = ["The First Topic", "<3<3<3"]
+ assert_equal(expected, topic.previous_changes['title'])
+ end
+
+ def test_previously_changed_dup
+ topic = Topic.find :first
+ topic.title = '<3<3<3'
+ topic.save!
+
+ t2 = topic.dup
+
+ assert_equal(topic.previous_changes, t2.previous_changes)
+
+ topic.title = "lolwut"
+ topic.save!
+
+ assert_not_equal(topic.previous_changes, t2.previous_changes)
+ end
+
def test_preserving_time_objects
assert_kind_of(
Time, Topic.find(1).bonus_time,
@@ -561,10 +604,12 @@ class BasicsTest < ActiveRecord::TestCase
weird = Weird.create('a$b' => 'value')
weird.reload
assert_equal 'value', weird.send('a$b')
+ assert_equal 'value', weird.read_attribute('a$b')
weird.update_column('a$b', 'value2')
weird.reload
assert_equal 'value2', weird.send('a$b')
+ assert_equal 'value2', weird.read_attribute('a$b')
end
def test_multiparameter_attributes_on_date
@@ -644,7 +689,7 @@ class BasicsTest < ActiveRecord::TestCase
}
topic = Topic.find(1)
topic.attributes = attributes
- assert_equal Time.local(2004, 6, 24, 16, 24, 0), topic.written_on
+ assert_equal Time.utc(2004, 6, 24, 16, 24, 0), topic.written_on
end
def test_multiparameter_attributes_on_time_with_no_date
@@ -893,7 +938,7 @@ class BasicsTest < ActiveRecord::TestCase
}
topic = Topic.find(1)
topic.attributes = attributes
- assert_equal Time.local(2000, 1, 1, 5, 42, 0), topic.bonus_time
+ assert_equal Time.utc(2000, 1, 1, 5, 42, 0), topic.bonus_time
end
def test_boolean
@@ -947,10 +992,9 @@ class BasicsTest < ActiveRecord::TestCase
assert_equal "b", duped_topic.title
# test if the attribute values have been duped
- topic.title = {"a" => "b"}
duped_topic = topic.dup
- duped_topic.title["a"] = "c"
- assert_equal "b", topic.title["a"]
+ duped_topic.title.replace "c"
+ assert_equal "a", topic.title
# test if attributes set as part of after_initialize are duped correctly
assert_equal topic.author_email_address, duped_topic.author_email_address
@@ -961,8 +1005,7 @@ class BasicsTest < ActiveRecord::TestCase
assert_not_equal duped_topic.id, topic.id
duped_topic.reload
- # FIXME: I think this is poor behavior, and will fix it with #5686
- assert_equal({'a' => 'c'}.to_yaml, duped_topic.title)
+ assert_equal("c", duped_topic.title)
end
def test_dup_with_aggregate_of_same_name_as_attribute
@@ -1061,7 +1104,10 @@ class BasicsTest < ActiveRecord::TestCase
# TODO: extend defaults tests to other databases!
if current_adapter?(:PostgreSQLAdapter)
def test_default
+ tz = Default.default_timezone
+ Default.default_timezone = :local
default = Default.new
+ Default.default_timezone = tz
# fixed dates / times
assert_equal Date.new(2004, 1, 1), default.fixed_date
@@ -1104,7 +1150,8 @@ class BasicsTest < ActiveRecord::TestCase
# use a geometric function to test for an open path
objs = Geometric.find_by_sql ["select isopen(a_path) from geometrics where id = ?", g.id]
- assert_equal objs[0].isopen, 't'
+
+ assert_equal true, objs[0].isopen
# test alternate formats when defining the geometric types
@@ -1132,7 +1179,8 @@ class BasicsTest < ActiveRecord::TestCase
# use a geometric function to test for an closed path
objs = Geometric.find_by_sql ["select isclosed(a_path) from geometrics where id = ?", g.id]
- assert_equal objs[0].isclosed, 't'
+
+ assert_equal true, objs[0].isclosed
end
end
@@ -1185,19 +1233,6 @@ class BasicsTest < ActiveRecord::TestCase
assert(auto.id > 0)
end
- def quote_column_name(name)
- "<#{name}>"
- end
-
- def test_quote_keys
- ar = AutoId.new
- source = {"foo" => "bar", "baz" => "quux"}
- actual = ar.send(:quote_columns, self, source)
- inverted = actual.invert
- assert_equal("<foo>", inverted["bar"])
- assert_equal("<baz>", inverted["quux"])
- end
-
def test_sql_injection_via_find
assert_raise(ActiveRecord::RecordNotFound, ActiveRecord::StatementInvalid) do
Topic.find("123456 OR id > 0")
@@ -1235,6 +1270,42 @@ class BasicsTest < ActiveRecord::TestCase
assert_equal(myobj, topic.content)
end
+ def test_serialized_attribute_in_base_class
+ Topic.serialize("content", Hash)
+
+ hash = { 'content1' => 'value1', 'content2' => 'value2' }
+ important_topic = ImportantTopic.create("content" => hash)
+ assert_equal(hash, important_topic.content)
+
+ important_topic.reload
+ assert_equal(hash, important_topic.content)
+ end
+
+ # This test was added to fix GH #4004. Obviously the value returned
+ # is not really the value 'before type cast' so we should maybe think
+ # about changing that in the future.
+ def test_serialized_attribute_before_type_cast_returns_unserialized_value
+ klass = Class.new(ActiveRecord::Base)
+ klass.table_name = "topics"
+ klass.serialize :content, Hash
+
+ t = klass.new(:content => { :foo => :bar })
+ assert_equal({ :foo => :bar }, t.content_before_type_cast)
+ t.save!
+ t.reload
+ assert_equal({ :foo => :bar }, t.content_before_type_cast)
+ end
+
+ def test_serialized_attribute_declared_in_subclass
+ hash = { 'important1' => 'value1', 'important2' => 'value2' }
+ important_topic = ImportantTopic.create("important" => hash)
+ assert_equal(hash, important_topic.important)
+
+ important_topic.reload
+ assert_equal(hash, important_topic.important)
+ assert_equal(hash, important_topic.read_attribute(:important))
+ end
+
def test_serialized_time_attribute
myobj = Time.local(2008,1,1,1,0)
topic = Topic.create("content" => myobj).reload
@@ -1247,11 +1318,24 @@ class BasicsTest < ActiveRecord::TestCase
assert_equal(myobj, topic.content)
end
- def test_nil_serialized_attribute_with_class_constraint
+ def test_nil_serialized_attribute_without_class_constraint
topic = Topic.new
assert_nil topic.content
end
+ def test_nil_not_serialized_without_class_constraint
+ assert Topic.new(:content => nil).save
+ assert_equal 1, Topic.where(:content => nil).count
+ end
+
+ def test_nil_not_serialized_with_class_constraint
+ Topic.serialize :content, Hash
+ assert Topic.new(:content => nil).save
+ assert_equal 1, Topic.where(:content => nil).count
+ ensure
+ Topic.serialize(:content)
+ end
+
def test_should_raise_exception_on_serialized_attribute_with_type_mismatch
myobj = MyObject.new('value1', 'value2')
topic = Topic.new(:content => myobj)
@@ -1359,22 +1443,6 @@ class BasicsTest < ActiveRecord::TestCase
assert_equal author_name, Topic.find(topic.id).author_name
end
- if RUBY_VERSION < '1.9'
- def test_quote_chars
- with_kcode('UTF8') do
- str = 'The Narrator'
- topic = Topic.create(:author_name => str)
- assert_equal str, topic.author_name
-
- assert_kind_of ActiveSupport::Multibyte.proxy_class, str.mb_chars
- topic = Topic.find_by_author_name(str.mb_chars)
-
- assert_kind_of Topic, topic
- assert_equal str, topic.author_name, "The right topic should have been found by name even with name passed as Chars"
- end
- end
- end
-
def test_toggle_attribute
assert !topics(:first).approved?
topics(:first).toggle!(:approved)
@@ -1401,86 +1469,48 @@ class BasicsTest < ActiveRecord::TestCase
assert_equal dev, dev.reload
end
- def test_define_attr_method_with_value
- k = Class.new( ActiveRecord::Base )
- k.send(:define_attr_method, :table_name, "foo")
- assert_equal "foo", k.table_name
- end
-
- def test_define_attr_method_with_block
- k = Class.new( ActiveRecord::Base ) do
- class << self
- attr_accessor :foo_key
- end
- end
- k.foo_key = "id"
- k.send(:define_attr_method, :foo_key) { "sys_" + original_foo_key }
- assert_equal "sys_id", k.foo_key
- end
-
- def test_set_table_name_with_value
- k = Class.new( ActiveRecord::Base )
- k.table_name = "foo"
- assert_equal "foo", k.table_name
- k.set_table_name "bar"
- assert_equal "bar", k.table_name
- end
-
def test_switching_between_table_name
assert_difference("GoodJoke.count") do
- Joke.set_table_name "cold_jokes"
+ Joke.table_name = "cold_jokes"
Joke.create
- Joke.set_table_name "funny_jokes"
+ Joke.table_name = "funny_jokes"
Joke.create
end
end
+ def test_set_table_name_symbol_converted_to_string
+ Joke.table_name = :cold_jokes
+ assert_equal 'cold_jokes', Joke.table_name
+ end
+
def test_quoted_table_name_after_set_table_name
klass = Class.new(ActiveRecord::Base)
- klass.set_table_name "foo"
+ klass.table_name = "foo"
assert_equal "foo", klass.table_name
assert_equal klass.connection.quote_table_name("foo"), klass.quoted_table_name
- klass.set_table_name "bar"
+ klass.table_name = "bar"
assert_equal "bar", klass.table_name
assert_equal klass.connection.quote_table_name("bar"), klass.quoted_table_name
end
- def test_set_table_name_with_block
+ def test_set_table_name_with_inheritance
k = Class.new( ActiveRecord::Base )
- k.set_table_name { "ks" }
- assert_equal "ks", k.table_name
+ def k.name; "Foo"; end
+ def k.table_name; super + "ks"; end
+ assert_equal "foosks", k.table_name
end
- def test_set_primary_key_with_value
- k = Class.new( ActiveRecord::Base )
- k.primary_key = "foo"
- assert_equal "foo", k.primary_key
- k.set_primary_key "bar"
- assert_equal "bar", k.primary_key
- end
-
- def test_set_primary_key_with_block
- k = Class.new( ActiveRecord::Base )
- k.primary_key = 'id'
- k.set_primary_key { "sys_" + original_primary_key }
- assert_equal "sys_id", k.primary_key
- end
-
- def test_set_inheritance_column_with_value
- k = Class.new( ActiveRecord::Base )
- k.inheritance_column = "foo"
- assert_equal "foo", k.inheritance_column
- k.set_inheritance_column "bar"
- assert_equal "bar", k.inheritance_column
- end
-
- def test_set_inheritance_column_with_block
- k = Class.new( ActiveRecord::Base )
- k.set_inheritance_column { original_inheritance_column + "_id" }
- assert_equal "type_id", k.inheritance_column
+ def test_sequence_name_with_abstract_class
+ ak = Class.new(ActiveRecord::Base)
+ ak.abstract_class = true
+ k = Class.new(ak)
+ k.table_name = "projects"
+ orig_name = k.sequence_name
+ return skip "sequences not supported by db" unless orig_name
+ assert_equal k.reset_sequence_name, orig_name
end
def test_count_with_join
@@ -1582,7 +1612,7 @@ class BasicsTest < ActiveRecord::TestCase
Developer.find(:all)
end
assert developers.size >= 2
- for i in 1...developers.size
+ (1...developers.size).each do |i|
assert developers[i-1].salary >= developers[i].salary
end
end
@@ -1673,10 +1703,7 @@ class BasicsTest < ActiveRecord::TestCase
end
def test_descends_from_active_record
- # Tries to call Object.abstract_class?
- assert_raise(NoMethodError) do
- ActiveRecord::Base.descends_from_active_record?
- end
+ assert !ActiveRecord::Base.descends_from_active_record?
# Abstract subclass of AR::Base.
assert LoosePerson.descends_from_active_record?
@@ -1699,6 +1726,10 @@ class BasicsTest < ActiveRecord::TestCase
# Concrete subclasses an abstract class which has a type column.
assert !SubStiPost.descends_from_active_record?
+
+ assert Teapot.descends_from_active_record?
+ assert !OtherTeapot.descends_from_active_record?
+ assert CoolTeapot.descends_from_active_record?
end
def test_find_on_abstract_base_class_doesnt_use_type_condition
@@ -1732,7 +1763,7 @@ class BasicsTest < ActiveRecord::TestCase
def test_inspect_instance
topic = topics(:first)
- assert_equal %(#<Topic id: 1, title: "The First Topic", author_name: "David", author_email_address: "david@loudthinking.com", written_on: "#{topic.written_on.to_s(:db)}", bonus_time: "#{topic.bonus_time.to_s(:db)}", last_read: "#{topic.last_read.to_s(:db)}", content: "Have a nice day", approved: false, replies_count: 1, parent_id: nil, parent_title: nil, type: nil, group: nil, created_at: "#{topic.created_at.to_s(:db)}", updated_at: "#{topic.updated_at.to_s(:db)}">), topic.inspect
+ assert_equal %(#<Topic id: 1, title: "The First Topic", author_name: "David", author_email_address: "david@loudthinking.com", written_on: "#{topic.written_on.to_s(:db)}", bonus_time: "#{topic.bonus_time.to_s(:db)}", last_read: "#{topic.last_read.to_s(:db)}", content: "Have a nice day", important: nil, approved: false, replies_count: 1, parent_id: nil, parent_title: nil, type: nil, group: nil, created_at: "#{topic.created_at.to_s(:db)}", updated_at: "#{topic.updated_at.to_s(:db)}">), topic.inspect
end
def test_inspect_new_instance
@@ -1761,10 +1792,18 @@ class BasicsTest < ActiveRecord::TestCase
assert_equal "The First Topic", topics(:first).becomes(Reply).title
end
+ def test_becomes_includes_errors
+ company = Company.new(:name => nil)
+ assert !company.valid?
+ original_errors = company.errors
+ client = company.becomes(Client)
+ assert_equal original_errors, client.errors
+ end
+
def test_silence_sets_log_level_to_error_in_block
original_logger = ActiveRecord::Base.logger
log = StringIO.new
- ActiveRecord::Base.logger = Logger.new(log)
+ ActiveRecord::Base.logger = ActiveSupport::Logger.new(log)
ActiveRecord::Base.logger.level = Logger::DEBUG
ActiveRecord::Base.silence do
ActiveRecord::Base.logger.warn "warn"
@@ -1778,7 +1817,7 @@ class BasicsTest < ActiveRecord::TestCase
def test_silence_sets_log_level_back_to_level_before_yield
original_logger = ActiveRecord::Base.logger
log = StringIO.new
- ActiveRecord::Base.logger = Logger.new(log)
+ ActiveRecord::Base.logger = ActiveSupport::Logger.new(log)
ActiveRecord::Base.logger.level = Logger::WARN
ActiveRecord::Base.silence do
end
@@ -1790,7 +1829,7 @@ class BasicsTest < ActiveRecord::TestCase
def test_benchmark_with_log_level
original_logger = ActiveRecord::Base.logger
log = StringIO.new
- ActiveRecord::Base.logger = Logger.new(log)
+ ActiveRecord::Base.logger = ActiveSupport::Logger.new(log)
ActiveRecord::Base.logger.level = Logger::WARN
ActiveRecord::Base.benchmark("Debug Topic Count", :level => :debug) { Topic.count }
ActiveRecord::Base.benchmark("Warn Topic Count", :level => :warn) { Topic.count }
@@ -1805,10 +1844,8 @@ class BasicsTest < ActiveRecord::TestCase
def test_benchmark_with_use_silence
original_logger = ActiveRecord::Base.logger
log = StringIO.new
- ActiveRecord::Base.logger = Logger.new(log)
- ActiveRecord::Base.benchmark("Logging", :level => :debug, :silence => true) { ActiveRecord::Base.logger.debug "Loud" }
+ ActiveRecord::Base.logger = ActiveSupport::Logger.new(log)
ActiveRecord::Base.benchmark("Logging", :level => :debug, :silence => false) { ActiveRecord::Base.logger.debug "Quiet" }
- assert_no_match(/Loud/, log.string)
assert_match(/Quiet/, log.string)
ensure
ActiveRecord::Base.logger = original_logger
@@ -1840,9 +1877,9 @@ class BasicsTest < ActiveRecord::TestCase
def test_clear_cache!
# preheat cache
- c1 = Post.columns
+ c1 = Post.connection.schema_cache.columns['posts']
ActiveRecord::Base.clear_cache!
- c2 = Post.columns
+ c2 = Post.connection.schema_cache.columns['posts']
assert_not_equal c1, c2
end
@@ -1859,11 +1896,6 @@ class BasicsTest < ActiveRecord::TestCase
end
def test_marshal_round_trip
- if ENV['TRAVIS'] && RUBY_VERSION == "1.8.7"
- return skip("Marshalling tests disabled for Ruby 1.8.7 on Travis CI due to what appears " \
- "to be a Ruby bug.")
- end
-
expected = posts(:welcome)
marshalled = Marshal.dump(expected)
actual = Marshal.load(marshalled)
@@ -1872,11 +1904,6 @@ class BasicsTest < ActiveRecord::TestCase
end
def test_marshal_new_record_round_trip
- if ENV['TRAVIS'] && RUBY_VERSION == "1.8.7"
- return skip("Marshalling tests disabled for Ruby 1.8.7 on Travis CI due to what appears " \
- "to be a Ruby bug.")
- end
-
marshalled = Marshal.dump(Post.new)
post = Marshal.load(marshalled)
@@ -1884,11 +1911,6 @@ class BasicsTest < ActiveRecord::TestCase
end
def test_marshalling_with_associations
- if ENV['TRAVIS'] && RUBY_VERSION == "1.8.7"
- return skip("Marshalling tests disabled for Ruby 1.8.7 on Travis CI due to what appears " \
- "to be a Ruby bug.")
- end
-
post = Post.new
post.comments.build
@@ -1907,7 +1929,7 @@ class BasicsTest < ActiveRecord::TestCase
assert_equal [], NonExistentTable.attribute_names
end
- def test_attribtue_names_on_abstract_class
+ def test_attribute_names_on_abstract_class
assert_equal [], AbstractCompany.attribute_names
end
@@ -1935,4 +1957,47 @@ class BasicsTest < ActiveRecord::TestCase
dev.update_attribute(:updated_at, nil)
assert_match(/\/#{dev.id}$/, dev.cache_key)
end
+
+ def test_uniq_delegates_to_scoped
+ scope = stub
+ Bird.stubs(:scoped).returns(mock(:uniq => scope))
+ assert_equal scope, Bird.uniq
+ end
+
+ def test_active_record_super
+ assert_equal ActiveRecord::Model, ActiveRecord::Base.active_record_super
+ assert_equal ActiveRecord::Base, Topic.active_record_super
+ assert_equal Topic, ImportantTopic.active_record_super
+ assert_equal ActiveRecord::Model, Teapot.active_record_super
+ assert_equal Teapot, OtherTeapot.active_record_super
+ assert_equal ActiveRecord::Model, CoolTeapot.active_record_super
+ end
+
+ def test_table_name_with_2_abstract_subclasses
+ assert_equal "photos", Photo.table_name
+ end
+
+ def test_column_types_typecast
+ topic = Topic.first
+ refute_equal 't.lo', topic.author_name
+
+ attrs = topic.attributes.dup
+ attrs.delete 'id'
+
+ typecast = Class.new {
+ def type_cast value
+ "t.lo"
+ end
+ }
+
+ types = { 'author_name' => typecast.new }
+ topic = Topic.allocate.init_with 'attributes' => attrs,
+ 'column_types' => types
+
+ assert_equal 't.lo', topic.author_name
+ end
+
+ def test_typecasting_aliases
+ assert_equal 10, Topic.select('10 as tenderlove').first.tenderlove
+ end
end