| 12
 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
 
 | require 'cases/helper'
module ActiveRecord
  class AttributeSetTest < ActiveRecord::TestCase
    test "building a new set from raw attributes" do
      builder = AttributeSet::Builder.new(foo: Type::Integer.new, bar: Type::Float.new)
      attributes = builder.build_from_database(foo: '1.1', bar: '2.2')
      assert_equal 1, attributes[:foo].value
      assert_equal 2.2, attributes[:bar].value
      assert_equal :foo, attributes[:foo].name
      assert_equal :bar, attributes[:bar].name
    end
    test "building with custom types" do
      builder = AttributeSet::Builder.new(foo: Type::Float.new)
      attributes = builder.build_from_database({ foo: '3.3', bar: '4.4' }, { bar: Type::Integer.new })
      assert_equal 3.3, attributes[:foo].value
      assert_equal 4, attributes[:bar].value
    end
    test "[] returns a null object" do
      builder = AttributeSet::Builder.new(foo: Type::Float.new)
      attributes = builder.build_from_database(foo: '3.3')
      assert_equal '3.3', attributes[:foo].value_before_type_cast
      assert_equal nil, attributes[:bar].value_before_type_cast
      assert_equal :bar, attributes[:bar].name
    end
    test "duping creates a new hash and dups each attribute" do
      builder = AttributeSet::Builder.new(foo: Type::Integer.new, bar: Type::String.new)
      attributes = builder.build_from_database(foo: 1, bar: 'foo')
      # Ensure the type cast value is cached
      attributes[:foo].value
      attributes[:bar].value
      duped = attributes.dup
      duped.write_from_database(:foo, 2)
      duped[:bar].value << 'bar'
      assert_equal 1, attributes[:foo].value
      assert_equal 2, duped[:foo].value
      assert_equal 'foo', attributes[:bar].value
      assert_equal 'foobar', duped[:bar].value
    end
    test "freezing cloned set does not freeze original" do
      attributes = AttributeSet.new({})
      clone = attributes.clone
      clone.freeze
      assert clone.frozen?
      assert_not attributes.frozen?
    end
    test "to_hash returns a hash of the type cast values" do
      builder = AttributeSet::Builder.new(foo: Type::Integer.new, bar: Type::Float.new)
      attributes = builder.build_from_database(foo: '1.1', bar: '2.2')
      assert_equal({ foo: 1, bar: 2.2 }, attributes.to_hash)
      assert_equal({ foo: 1, bar: 2.2 }, attributes.to_h)
    end
    test "to_hash maintains order" do
      builder = AttributeSet::Builder.new(foo: Type::Integer.new, bar: Type::Float.new)
      attributes = builder.build_from_database(foo: '2.2', bar: '3.3')
      attributes[:bar]
      hash = attributes.to_h
      assert_equal [[:foo, 2], [:bar, 3.3]], hash.to_a
    end
    test "values_before_type_cast" do
      builder = AttributeSet::Builder.new(foo: Type::Integer.new, bar: Type::Integer.new)
      attributes = builder.build_from_database(foo: '1.1', bar: '2.2')
      assert_equal({ foo: '1.1', bar: '2.2' }, attributes.values_before_type_cast)
    end
    test "known columns are built with uninitialized attributes" do
      attributes = attributes_with_uninitialized_key
      assert attributes[:foo].initialized?
      assert_not attributes[:bar].initialized?
    end
    test "uninitialized attributes are not included in the attributes hash" do
      attributes = attributes_with_uninitialized_key
      assert_equal({ foo: 1 }, attributes.to_hash)
    end
    test "uninitialized attributes are not included in keys" do
      attributes = attributes_with_uninitialized_key
      assert_equal [:foo], attributes.keys
    end
    test "uninitialized attributes return false for key?" do
      attributes = attributes_with_uninitialized_key
      assert attributes.key?(:foo)
      assert_not attributes.key?(:bar)
    end
    test "unknown attributes return false for key?" do
      attributes = attributes_with_uninitialized_key
      assert_not attributes.key?(:wibble)
    end
    test "fetch_value returns the value for the given initialized attribute" do
      builder = AttributeSet::Builder.new(foo: Type::Integer.new, bar: Type::Float.new)
      attributes = builder.build_from_database(foo: '1.1', bar: '2.2')
      assert_equal 1, attributes.fetch_value(:foo)
      assert_equal 2.2, attributes.fetch_value(:bar)
    end
    test "fetch_value returns nil for unknown attributes" do
      attributes = attributes_with_uninitialized_key
      assert_nil attributes.fetch_value(:wibble) { "hello" }
    end
    test "fetch_value returns nil for unknown attributes when types has a default" do
      types = Hash.new(Type::Value.new)
      builder = AttributeSet::Builder.new(types)
      attributes = builder.build_from_database
      assert_nil attributes.fetch_value(:wibble) { "hello" }
    end
    test "fetch_value uses the given block for uninitialized attributes" do
      attributes = attributes_with_uninitialized_key
      value = attributes.fetch_value(:bar) { |n| n.to_s + '!' }
      assert_equal 'bar!', value
    end
    test "fetch_value returns nil for uninitialized attributes if no block is given" do
      attributes = attributes_with_uninitialized_key
      assert_nil attributes.fetch_value(:bar)
    end
    test "the primary_key is always initialized" do
      builder = AttributeSet::Builder.new({ foo: Type::Integer.new }, :foo)
      attributes = builder.build_from_database
      assert attributes.key?(:foo)
      assert_equal [:foo], attributes.keys
      assert attributes[:foo].initialized?
    end
    class MyType
      def type_cast_from_user(value)
        return if value.nil?
        value + " from user"
      end
      def type_cast_from_database(value)
        return if value.nil?
        value + " from database"
      end
    end
    test "write_from_database sets the attribute with database typecasting" do
      builder = AttributeSet::Builder.new(foo: MyType.new)
      attributes = builder.build_from_database
      assert_nil attributes.fetch_value(:foo)
      attributes.write_from_database(:foo, "value")
      assert_equal "value from database", attributes.fetch_value(:foo)
    end
    test "write_from_user sets the attribute with user typecasting" do
      builder = AttributeSet::Builder.new(foo: MyType.new)
      attributes = builder.build_from_database
      assert_nil attributes.fetch_value(:foo)
      attributes.write_from_user(:foo, "value")
      assert_equal "value from user", attributes.fetch_value(:foo)
    end
    def attributes_with_uninitialized_key
      builder = AttributeSet::Builder.new(foo: Type::Integer.new, bar: Type::Float.new)
      builder.build_from_database(foo: '1.1')
    end
    test "freezing doesn't prevent the set from materializing" do
      builder = AttributeSet::Builder.new(foo: Type::String.new)
      attributes = builder.build_from_database(foo: "1")
      attributes.freeze
      assert_equal({ foo: "1" }, attributes.to_hash)
    end
    test "comparison for equality is correctly implemented" do
      builder = AttributeSet::Builder.new(foo: Type::Integer.new, bar: Type::Integer.new)
      attributes = builder.build_from_database(foo: "1", bar: "2")
      attributes2 = builder.build_from_database(foo: "1", bar: "2")
      attributes3 = builder.build_from_database(foo: "2", bar: "2")
      assert_equal attributes, attributes2
      assert_not_equal attributes2, attributes3
    end
  end
end
 |