1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
|
require 'abstract_unit'
class MemoizableTest < Test::Unit::TestCase
class Person
extend ActiveSupport::Memoizable
attr_reader :name_calls, :age_calls, :is_developer_calls
def initialize
@name_calls = 0
@age_calls = 0
@is_developer_calls = 0
end
def name
@name_calls += 1
"Josh"
end
def name?
true
end
memoize :name?
def update(name)
"Joshua"
end
memoize :update
def age
@age_calls += 1
nil
end
memoize :name, :age
private
def is_developer?
@is_developer_calls += 1
"Yes"
end
memoize :is_developer?
end
class Company
attr_reader :name_calls
def initialize
@name_calls = 0
end
def name
@name_calls += 1
"37signals"
end
end
module Rates
extend ActiveSupport::Memoizable
attr_reader :sales_tax_calls
def sales_tax(price)
@sales_tax_calls ||= 0
@sales_tax_calls += 1
price * 0.1025
end
memoize :sales_tax
end
class Calculator
extend ActiveSupport::Memoizable
include Rates
attr_reader :fib_calls
def initialize
@fib_calls = 0
end
def fib(n)
@fib_calls += 1
if n == 0 || n == 1
n
else
fib(n - 1) + fib(n - 2)
end
end
memoize :fib
def counter
@count ||= 0
@count += 1
end
memoize :counter
end
def setup
@person = Person.new
@calculator = Calculator.new
end
def test_memoization
assert_equal "Josh", @person.name
assert_equal 1, @person.name_calls
3.times { assert_equal "Josh", @person.name }
assert_equal 1, @person.name_calls
end
def test_memoization_with_punctuation
assert_equal true, @person.name?
assert_nothing_raised(NameError) do
@person.memoize_all
@person.unmemoize_all
end
end
def test_memoization_with_nil_value
assert_equal nil, @person.age
assert_equal 1, @person.age_calls
3.times { assert_equal nil, @person.age }
assert_equal 1, @person.age_calls
end
def test_memorized_results_are_immutable
assert_equal "Josh", @person.name
assert_raise(ActiveSupport::FrozenObjectError) { @person.name.gsub!("Josh", "Gosh") }
end
def test_reloadable
counter = @calculator.counter
assert_equal 1, @calculator.counter
assert_equal 2, @calculator.counter(:reload)
assert_equal 2, @calculator.counter
assert_equal 3, @calculator.counter(true)
assert_equal 3, @calculator.counter
end
def test_flush_cache
assert_equal 1, @calculator.counter
assert @calculator.instance_variable_get(:@_memoized_counter).any?
@calculator.flush_cache(:counter)
assert @calculator.instance_variable_get(:@_memoized_counter).empty?
assert_equal 2, @calculator.counter
end
def test_unmemoize_all
assert_equal 1, @calculator.counter
assert @calculator.instance_variable_get(:@_memoized_counter).any?
@calculator.unmemoize_all
assert @calculator.instance_variable_get(:@_memoized_counter).empty?
assert_equal 2, @calculator.counter
end
def test_memoize_all
@calculator.memoize_all
assert @calculator.instance_variable_defined?(:@_memoized_counter)
end
def test_memoization_cache_is_different_for_each_instance
assert_equal 1, @calculator.counter
assert_equal 2, @calculator.counter(:reload)
assert_equal 1, Calculator.new.counter
end
def test_memoized_is_not_affected_by_freeze
@person.freeze
assert_equal "Josh", @person.name
assert_equal "Joshua", @person.update("Joshua")
end
def test_memoization_with_args
assert_equal 55, @calculator.fib(10)
assert_equal 11, @calculator.fib_calls
end
def test_reloadable_with_args
assert_equal 55, @calculator.fib(10)
assert_equal 11, @calculator.fib_calls
assert_equal 55, @calculator.fib(10, :reload)
assert_equal 12, @calculator.fib_calls
assert_equal 55, @calculator.fib(10, true)
assert_equal 13, @calculator.fib_calls
end
def test_object_memoization
[Company.new, Company.new, Company.new].each do |company|
company.extend ActiveSupport::Memoizable
company.memoize :name
assert_equal "37signals", company.name
assert_equal 1, company.name_calls
assert_equal "37signals", company.name
assert_equal 1, company.name_calls
end
end
def test_memoized_module_methods
assert_equal 1.025, @calculator.sales_tax(10)
assert_equal 1, @calculator.sales_tax_calls
assert_equal 1.025, @calculator.sales_tax(10)
assert_equal 1, @calculator.sales_tax_calls
assert_equal 2.5625, @calculator.sales_tax(25)
assert_equal 2, @calculator.sales_tax_calls
end
def test_object_memoized_module_methods
company = Company.new
company.extend(Rates)
assert_equal 1.025, company.sales_tax(10)
assert_equal 1, company.sales_tax_calls
assert_equal 1.025, company.sales_tax(10)
assert_equal 1, company.sales_tax_calls
assert_equal 2.5625, company.sales_tax(25)
assert_equal 2, company.sales_tax_calls
end
def test_double_memoization
assert_raise(RuntimeError) { Person.memoize :name }
person = Person.new
person.extend ActiveSupport::Memoizable
assert_raise(RuntimeError) { person.memoize :name }
company = Company.new
company.extend ActiveSupport::Memoizable
company.memoize :name
assert_raise(RuntimeError) { company.memoize :name }
end
def test_private_method_memoization
person = Person.new
assert_raise(NoMethodError) { person.is_developer? }
assert_equal "Yes", person.send(:is_developer?)
assert_equal 1, person.is_developer_calls
assert_equal "Yes", person.send(:is_developer?)
assert_equal 1, person.is_developer_calls
end
end
|