1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00
rails--rails/activerecord/test/cases/yaml_serialization_test.rb

163 lines
4.5 KiB
Ruby
Raw Normal View History

# frozen_string_literal: true
require "cases/helper"
require "models/topic"
require "models/reply"
require "models/post"
require "models/author"
class YamlSerializationTest < ActiveRecord::TestCase
fixtures :topics, :authors, :author_addresses, :posts
2010-12-02 11:44:31 -05:00
def test_to_yaml_with_time_with_zone_should_not_raise_exception
with_timezone_config aware_attributes: true, zone: "Pacific Time (US & Canada)" do
2016-08-06 13:37:57 -04:00
topic = Topic.new(written_on: DateTime.now)
assert_nothing_raised { topic.to_yaml }
end
end
2010-12-02 11:44:31 -05:00
def test_roundtrip
topic = Topic.first
assert topic
t = YAML.load YAML.dump topic
assert_equal topic, t
end
def test_roundtrip_serialized_column
topic = Topic.new(content: { omg: :lol })
assert_equal({ omg: :lol }, YAML.load(YAML.dump(topic)).content)
end
def test_psych_roundtrip
topic = Topic.first
assert topic
t = Psych.load Psych.dump topic
assert_equal topic, t
end
def test_psych_roundtrip_new_object
topic = Topic.new
assert topic
t = Psych.load Psych.dump topic
assert_equal topic.attributes, t.attributes
end
def test_active_record_relation_serialization
[Topic.all].to_yaml
end
def test_raw_types_are_not_changed_on_round_trip
topic = Topic.new(parent_id: "123")
assert_equal "123", topic.parent_id_before_type_cast
assert_equal "123", YAML.load(YAML.dump(topic)).parent_id_before_type_cast
end
def test_cast_types_are_not_changed_on_round_trip
topic = Topic.new(parent_id: "123")
assert_equal 123, topic.parent_id
assert_equal 123, YAML.load(YAML.dump(topic)).parent_id
end
def test_new_records_remain_new_after_round_trip
topic = Topic.new
assert topic.new_record?, "Sanity check that new records are new"
assert YAML.load(YAML.dump(topic)).new_record?, "Record should be new after deserialization"
topic.save!
assert_not topic.new_record?, "Saved records are not new"
assert_not YAML.load(YAML.dump(topic)).new_record?, "Saved record should not be new after deserialization"
topic = Topic.select("title").last
assert_not topic.new_record?, "Loaded records without ID are not new"
assert_not YAML.load(YAML.dump(topic)).new_record?, "Record should not be new after deserialization"
end
def test_types_of_virtual_columns_are_not_changed_on_round_trip
author = Author.select("authors.*, count(posts.id) as posts_count")
.joins(:posts)
.group("authors.id")
.first
dumped = YAML.load(YAML.dump(author))
assert_equal 5, author.posts_count
assert_equal 5, dumped.posts_count
end
def test_a_yaml_version_is_provided_for_future_backwards_compat
coder = {}
Topic.first.encode_with(coder)
assert coder["active_record_yaml_version"]
end
def test_deserializing_rails_v2_yaml
topic = YAML.load(yaml_fixture("rails_v2"))
assert_not_predicate topic, :new_record?
assert_equal 1, topic.id
assert_equal "The First Topic", topic.title
assert_equal "Have a nice day", topic.content
end
def test_deserializing_rails_v1_mysql_yaml
topic = YAML.load(yaml_fixture("rails_v1_mysql"))
assert_not_predicate topic, :new_record?
assert_equal 1, topic.id
assert_equal "The First Topic", topic.title
assert_equal "Have a nice day", topic.content
end
def test_deserializing_rails_41_yaml
topic = assert_deprecated do
YAML.load(yaml_fixture("rails_4_1"))
end
assert_predicate topic, :new_record?
assert_nil topic.id
assert_equal "The First Topic", topic.title
assert_equal({ omg: :lol }, topic.content)
end
def test_deserializing_rails_4_2_0_yaml
topic = assert_deprecated do
YAML.load(yaml_fixture("rails_4_2_0"))
end
assert_not_predicate topic, :new_record?
assert_equal 1, topic.id
assert_equal "The First Topic", topic.title
assert_equal("Have a nice day", topic.content)
end
Make Active Record emit significantly smaller YAML This reduces the size of a YAML encoded Active Record object by ~80% depending on the number of columns. There were a number of wasteful things that occurred when we encoded the objects before that have resulted in numerous wins - We were emitting the result of `attributes_before_type_cast` as a hack to work around some laziness issues - The name of an attribute was emitted multiple times, since the attribute objects were in a hash keyed by the name. We now store them in an array instead, and reconstruct the hash using the name - The types were included for every attribute. This would use backrefs if multiple objects were encoded, but really we don't need to include it at all unless it differs from the type at the class level. (The only time that will occur is if the field is the result of a custom select clause) - `original_attribute:` was included over and over and over again since the ivar is almost always `nil`. We've added a custom implementation of `encode_with` on the attribute objects to ensure we don't write the key when the field is `nil`. This isn't without a cost though. Since we're no longer including the types, an object can find itself in an invalid state if the type changes on the class after serialization. This is the same as 4.1 and earlier, but I think it's worth noting. I was worried that I'd introduce some new state bugs as a result of doing this, so I've added an additional test that asserts mutation not being lost as the result of YAML round tripping. Fixes #25145
2016-05-31 14:44:38 -04:00
def test_yaml_encoding_keeps_mutations
author = Author.first
author.name = "Sean"
dumped = YAML.load(YAML.dump(author))
assert_equal "Sean", dumped.name
assert_equal author.name_was, dumped.name_was
assert_equal author.changes, dumped.changes
end
def test_yaml_encoding_keeps_false_values
topic = Topic.first
topic.approved = false
dumped = YAML.load(YAML.dump(topic))
assert_equal false, dumped.approved
end
private
def yaml_fixture(file_name)
path = File.expand_path(
"support/yaml_compatibility_fixtures/#{file_name}.yml",
TEST_ROOT
)
File.read(path)
end
end