Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

root/branches/2-1-caching/activerecord/test/attribute_methods_test.rb

Revision 7752, 5.2 kB (checked in by nzkoz, 1 year ago)

Only cache attributes which need it for performance reasons. Closes #9767 [skaes]

  • Property svn:executable set to *
Line 
1 require 'abstract_unit'
2 require 'fixtures/topic'
3
4 class AttributeMethodsTest < Test::Unit::TestCase
5   fixtures :topics
6   def setup
7     @old_suffixes = ActiveRecord::Base.send(:attribute_method_suffixes).dup
8     @target = Class.new(ActiveRecord::Base)
9     @target.table_name = 'topics'
10   end
11
12   def teardown
13     ActiveRecord::Base.send(:attribute_method_suffixes).clear
14     ActiveRecord::Base.attribute_method_suffix *@old_suffixes
15   end
16
17
18   def test_match_attribute_method_query_returns_match_data
19     assert_not_nil md = @target.match_attribute_method?('title=')
20     assert_equal 'title', md.pre_match
21     assert_equal ['='], md.captures
22
23     %w(_hello_world ist! _maybe?).each do |suffix|
24       @target.class_eval "def attribute#{suffix}(*args) args end"
25       @target.attribute_method_suffix suffix
26
27       assert_not_nil md = @target.match_attribute_method?("title#{suffix}")
28       assert_equal 'title', md.pre_match
29       assert_equal [suffix], md.captures
30     end
31   end
32
33   def test_declared_attribute_method_affects_respond_to_and_method_missing
34     topic = @target.new(:title => 'Budget')
35     assert topic.respond_to?('title')
36     assert_equal 'Budget', topic.title
37     assert !topic.respond_to?('title_hello_world')
38     assert_raise(NoMethodError) { topic.title_hello_world }
39
40     %w(_hello_world _it! _candidate= able?).each do |suffix|
41       @target.class_eval "def attribute#{suffix}(*args) args end"
42       @target.attribute_method_suffix suffix
43
44       meth = "title#{suffix}"
45       assert topic.respond_to?(meth)
46       assert_equal ['title'], topic.send(meth)
47       assert_equal ['title', 'a'], topic.send(meth, 'a')
48       assert_equal ['title', 1, 2, 3], topic.send(meth, 1, 2, 3)
49     end
50   end
51  
52   def test_should_unserialize_attributes_for_frozen_records
53     myobj = {:value1 => :value2}
54     topic = Topic.create("content" => myobj)
55     topic.freeze
56     assert_equal myobj, topic.content
57   end
58  
59   def test_kernel_methods_not_implemented_in_activerecord
60     %w(test name display y).each do |method|
61       assert_equal false, ActiveRecord::Base.instance_method_already_implemented?(method), "##{method} is defined"
62     end
63   end
64  
65   def test_primary_key_implemented
66     assert_equal true, Class.new(ActiveRecord::Base).instance_method_already_implemented?('id')
67   end
68  
69   def test_defined_kernel_methods_implemented_in_model
70     %w(test name display y).each do |method|
71       klass = Class.new ActiveRecord::Base
72       klass.class_eval "def #{method}() 'defined #{method}' end"
73       assert_equal true, klass.instance_method_already_implemented?(method), "##{method} is not defined"
74     end
75   end
76  
77   def test_defined_kernel_methods_implemented_in_model_abstract_subclass
78     %w(test name display y).each do |method|
79       abstract = Class.new ActiveRecord::Base
80       abstract.class_eval "def #{method}() 'defined #{method}' end"
81       abstract.abstract_class = true
82       klass = Class.new abstract
83       assert_equal true, klass.instance_method_already_implemented?(method), "##{method} is not defined"
84     end
85   end
86  
87   def test_raises_dangerous_attribute_error_when_defining_activerecord_method_in_model
88     %w(save create_or_update).each do |method|
89       klass = Class.new ActiveRecord::Base
90       klass.class_eval "def #{method}() 'defined #{method}' end"
91       assert_raises ActiveRecord::DangerousAttributeError do
92         klass.instance_method_already_implemented?(method)
93       end
94     end
95   end
96
97   def test_only_time_related_columns_are_meant_to_be_cached_by_default
98     expected = %w(datetime timestamp time date).sort
99     assert_equal expected, ActiveRecord::Base.attribute_types_cached_by_default.map(&:to_s).sort
100 end
101
102   def test_declaring_attributes_as_cached_adds_them_to_the_attributes_cached_by_default
103     default_attributes = Topic.cached_attributes
104     Topic.cache_attributes :replies_count
105     expected = default_attributes + ["replies_count"]
106     assert_equal expected.sort, Topic.cached_attributes.sort
107     Topic.instance_variable_set "@cached_attributes", nil
108   end
109
110   def test_time_related_columns_are_actually_cached
111     column_types = %w(datetime timestamp time date).map(&:to_sym)
112     column_names = Topic.columns.select{|c| column_types.include?(c.type) }.map(&:name)
113
114     assert_equal column_names.sort, Topic.cached_attributes.sort
115     assert_equal time_related_columns_on_topic.sort, Topic.cached_attributes.sort
116   end
117
118   def test_accessing_cached_attributes_caches_the_converted_values_and_nothing_else
119     t = topics(:first)
120     cache = t.instance_variable_get "@attributes_cache"
121
122     assert_not_nil cache
123     assert cache.empty?
124
125     all_columns = Topic.columns.map(&:name)
126     cached_columns = time_related_columns_on_topic
127     uncached_columns =  all_columns - cached_columns
128
129     all_columns.each do |attr_name|
130       attribute_gets_cached = Topic.cache_attribute?(attr_name)
131       val = t.send attr_name unless attr_name == "type"
132       if attribute_gets_cached
133         assert cached_columns.include?(attr_name)
134         assert_equal val, cache[attr_name]
135       else
136         assert uncached_columns.include?(attr_name)
137         assert !cache.include?(attr_name)
138       end
139     end
140   end
141
142   private
143   def time_related_columns_on_topic
144     Topic.columns.select{|c| [:time, :date, :datetime, :timestamp].include?(c.type)}.map(&:name)
145   end
146 end
Note: See TracBrowser for help on using the browser.