diff options
Diffstat (limited to 'activerecord/test/cases/serialized_attribute_test.rb')
-rw-r--r-- | activerecord/test/cases/serialized_attribute_test.rb | 179 |
1 files changed, 104 insertions, 75 deletions
diff --git a/activerecord/test/cases/serialized_attribute_test.rb b/activerecord/test/cases/serialized_attribute_test.rb index 6962da298e..66f345d805 100644 --- a/activerecord/test/cases/serialized_attribute_test.rb +++ b/activerecord/test/cases/serialized_attribute_test.rb @@ -1,25 +1,31 @@ -require "cases/helper" +require 'cases/helper' require 'models/topic' +require 'models/reply' +require 'models/person' +require 'models/traffic_light' +require 'models/post' require 'bcrypt' class SerializedAttributeTest < ActiveRecord::TestCase - fixtures :topics + fixtures :topics, :posts MyObject = Struct.new :attribute1, :attribute2 - def teardown - super + teardown do Topic.serialize("content") end - def test_list_of_serialized_attributes - assert_equal %w(content), Topic.serialized_attributes.keys + def test_serialize_does_not_eagerly_load_columns + Topic.reset_column_information + assert_no_queries do + Topic.serialize(:content) + end end - def test_serialized_attributes_are_class_level_settings - topic = Topic.new - assert_raise(NoMethodError) { topic.serialized_attributes = [] } - assert_deprecated { topic.serialized_attributes } + def test_list_of_serialized_attributes + assert_deprecated do + assert_equal %w(content), Topic.serialized_attributes.keys + end end def test_serialized_attribute @@ -33,12 +39,6 @@ class SerializedAttributeTest < ActiveRecord::TestCase assert_equal(myobj, topic.content) end - def test_serialized_attribute_init_with - topic = Topic.allocate - topic.init_with('attributes' => { 'content' => '--- foo' }) - assert_equal 'foo', topic.content - end - def test_serialized_attribute_in_base_class Topic.serialize("content", Hash) @@ -50,34 +50,56 @@ class SerializedAttributeTest < ActiveRecord::TestCase 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 + def test_serialized_attributes_from_database_on_subclass Topic.serialize :content, Hash - t = Topic.new(content: { foo: :bar }) - assert_equal({ foo: :bar }, t.content_before_type_cast) + t = Reply.new(content: { foo: :bar }) + assert_equal({ foo: :bar }, t.content) t.save! - t.reload - assert_equal({ foo: :bar }, t.content_before_type_cast) + t = Reply.last + assert_equal({ foo: :bar }, t.content) end - def test_serialized_attributes_before_type_cast_returns_unserialized_value - Topic.serialize :content, Hash + def test_serialized_attribute_calling_dup_method + Topic.serialize :content, JSON - t = Topic.new(content: { foo: :bar }) - assert_equal({ foo: :bar }, t.attributes_before_type_cast["content"]) + orig = Topic.new(content: { foo: :bar }) + clone = orig.dup + assert_equal(orig.content, clone.content) + end + + def test_serialized_json_attribute_returns_unserialized_value + Topic.serialize :content, JSON + my_post = posts(:welcome) + + t = Topic.new(content: my_post) t.save! t.reload - assert_equal({ foo: :bar }, t.attributes_before_type_cast["content"]) + + assert_instance_of(Hash, t.content) + assert_equal(my_post.id, t.content["id"]) + assert_equal(my_post.title, t.content["title"]) end - def test_serialized_attribute_calling_dup_method + def test_json_read_legacy_null Topic.serialize :content, JSON - t = Topic.new(:content => { :foo => :bar }).dup - assert_equal({ :foo => :bar }, t.content_before_type_cast) + # Force a row to have a JSON "null" instead of a database NULL (this is how + # null values are saved on 4.1 and before) + id = Topic.connection.insert "INSERT INTO topics (content) VALUES('null')" + t = Topic.find(id) + + assert_nil t.content + end + + def test_json_read_db_null + Topic.serialize :content, JSON + + # Force a row to have a database NULL instead of a JSON "null" + id = Topic.connection.insert "INSERT INTO topics (content) VALUES(NULL)" + t = Topic.find(id) + + assert_nil t.content end def test_serialized_attribute_declared_in_subclass @@ -118,10 +140,11 @@ class SerializedAttributeTest < ActiveRecord::TestCase assert_equal 1, Topic.where(:content => nil).count end - def test_serialized_attribute_should_raise_exception_on_save_with_wrong_type + def test_serialized_attribute_should_raise_exception_on_assignment_with_wrong_type Topic.serialize(:content, Hash) - topic = Topic.new(:content => "string") - assert_raise(ActiveRecord::SerializationTypeMismatch) { topic.save } + assert_raise(ActiveRecord::SerializationTypeMismatch) do + Topic.new(content: 'string') + end end def test_should_raise_exception_on_serialized_attribute_with_type_mismatch @@ -172,57 +195,63 @@ class SerializedAttributeTest < ActiveRecord::TestCase end def test_serialize_with_coder - coder = Class.new { - # Identity - def load(thing) - thing + some_class = Struct.new(:foo) do + def self.dump(value) + value.foo end - # base 64 - def dump(thing) - [thing].pack('m') + def self.load(value) + new(value) end - }.new + end - Topic.serialize(:content, coder) - s = 'hello world' - topic = Topic.new(:content => s) - assert topic.save - topic = topic.reload - assert_equal [s].pack('m'), topic.content + Topic.serialize(:content, some_class) + topic = Topic.new(:content => some_class.new('my value')) + topic.save! + topic.reload + assert_kind_of some_class, topic.content + assert_equal topic.content, some_class.new('my value') end - def test_serialize_with_bcrypt_coder - crypt_coder = Class.new { - def load(thing) - return unless thing - BCrypt::Password.new thing - end + def test_serialize_attribute_via_select_method_when_time_zone_available + with_timezone_config aware_attributes: true do + Topic.serialize(:content, MyObject) - def dump(thing) - BCrypt::Password.create(thing).to_s - end - }.new + myobj = MyObject.new('value1', 'value2') + topic = Topic.create(content: myobj) - Topic.serialize(:content, crypt_coder) - password = 'password' - topic = Topic.new(:content => password) - assert topic.save - topic = topic.reload - assert_kind_of BCrypt::Password, topic.content - assert_equal(true, topic.content == password, 'password should equal') + assert_equal(myobj, Topic.select(:content).find(topic.id).content) + assert_raise(ActiveModel::MissingAttributeError) { Topic.select(:id).find(topic.id).content } + end end - def test_serialize_attribute_via_select_method_when_time_zone_available - ActiveRecord::Base.time_zone_aware_attributes = true - Topic.serialize(:content, MyObject) + def test_serialize_attribute_can_be_serialized_in_an_integer_column + insures = ['life'] + person = SerializedPerson.new(first_name: 'David', insures: insures) + assert person.save + person = person.reload + assert_equal(insures, person.insures) + end - myobj = MyObject.new('value1', 'value2') - topic = Topic.create(content: myobj) + def test_regression_serialized_default_on_text_column_with_null_false + light = TrafficLight.new + assert_equal [], light.state + assert_equal [], light.long_state + end + + def test_serialized_column_should_unserialize_after_update_column + t = Topic.create(content: "first") + assert_equal("first", t.content) + + t.update_column(:content, Topic.type_for_attribute('content').type_cast_for_database("second")) + assert_equal("second", t.content) + end + + def test_serialized_column_should_unserialize_after_update_attribute + t = Topic.create(content: "first") + assert_equal("first", t.content) - assert_equal(myobj, Topic.select(:content).find(topic.id).content) - assert_raise(ActiveModel::MissingAttributeError) { Topic.select(:id).find(topic.id).content } - ensure - ActiveRecord::Base.time_zone_aware_attributes = false + t.update_attribute(:content, "second") + assert_equal("second", t.content) end end |