enum_test.rb 8.0 KB
Newer Older
1 2 3
require 'cases/helper'
require 'models/book'

4
class EnumTest < ActiveRecord::TestCase
5 6 7
  fixtures :books

  setup do
8
    @book = books(:awdr)
9 10 11 12 13 14
  end

  test "query state by predicate" do
    assert @book.proposed?
    assert_not @book.written?
    assert_not @book.published?
Y
Yury Korolev 已提交
15 16

    assert @book.unread?
17
  end
18

R
Robin Dupret 已提交
19
  test "query state with strings" do
20 21
    assert_equal "proposed", @book.status
    assert_equal "unread", @book.read_status
22 23
  end

24 25
  test "find via scope" do
    assert_equal @book, Book.proposed.first
Y
Yury Korolev 已提交
26
    assert_equal @book, Book.unread.first
27 28
  end

29 30 31 32 33 34 35 36 37 38 39
  test "build from scope" do
    assert Book.proposed.build.proposed?
    refute Book.proposed.build.written?
    assert Book.where(status: Book.statuses[:proposed]).build.proposed?
  end

  test "find via where" do
    assert_equal @book, Book.where(status: "proposed").first
    refute_equal @book, Book.where(status: "written").first
  end

40 41 42 43
  test "update by declaration" do
    @book.written!
    assert @book.written?
  end
44

45 46 47 48
  test "update by setter" do
    @book.update! status: :written
    assert @book.written?
  end
49 50 51 52 53

  test "enum methods are overwritable" do
    assert_equal "do publish work...", @book.published!
    assert @book.published?
  end
54 55 56 57 58 59

  test "direct assignment" do
    @book.status = :written
    assert @book.written?
  end

60 61 62 63 64
  test "assign string value" do
    @book.status = "written"
    assert @book.written?
  end

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
  test "enum changed attributes" do
    old_status = @book.status
    @book.status = :published
    assert_equal old_status, @book.changed_attributes[:status]
  end

  test "enum changes" do
    old_status = @book.status
    @book.status = :published
    assert_equal [old_status, 'published'], @book.changes[:status]
  end

  test "enum attribute was" do
    old_status = @book.status
    @book.status = :published
    assert_equal old_status, @book.attribute_was(:status)
  end

  test "enum attribute changed" do
    @book.status = :published
    assert @book.attribute_changed?(:status)
  end

  test "enum attribute changed to" do
    @book.status = :published
    assert @book.attribute_changed?(:status, to: 'published')
  end

  test "enum attribute changed from" do
    old_status = @book.status
    @book.status = :published
    assert @book.attribute_changed?(:status, from: old_status)
  end

  test "enum attribute changed from old status to new status" do
    old_status = @book.status
    @book.status = :published
    assert @book.attribute_changed?(:status, from: old_status, to: 'published')
  end

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
  test "enum didn't change" do
    old_status = @book.status
    @book.status = old_status
    assert_not @book.attribute_changed?(:status)
  end

  test "persist changes that are dirty" do
    @book.status = :published
    assert @book.attribute_changed?(:status)
    @book.status = :written
    assert @book.attribute_changed?(:status)
  end

  test "reverted changes that are not dirty" do
    old_status = @book.status
    @book.status = :published
    assert @book.attribute_changed?(:status)
    @book.status = old_status
    assert_not @book.attribute_changed?(:status)
  end

  test "reverted changes are not dirty going from nil to value and back" do
    book = Book.create!(nullable_status: nil)

    book.nullable_status = :married
    assert book.attribute_changed?(:nullable_status)

    book.nullable_status = nil
    assert_not book.attribute_changed?(:nullable_status)
  end

136 137 138 139 140 141
  test "assign non existing value raises an error" do
    e = assert_raises(ArgumentError) do
      @book.status = :unknown
    end
    assert_equal "'unknown' is not a valid status", e.message
  end
142

143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
  test "assign nil value" do
    @book.status = nil
    assert @book.status.nil?
  end

  test "assign empty string value" do
    @book.status = ''
    assert @book.status.nil?
  end

  test "assign long empty string value" do
    @book.status = '   '
    assert @book.status.nil?
  end

158
  test "constant to access the mapping" do
159 160 161
    assert_equal 0, Book.statuses[:proposed]
    assert_equal 1, Book.statuses["written"]
    assert_equal 2, Book.statuses[:published]
162
  end
R
Robin Dupret 已提交
163

164 165 166 167
  test "building new objects with enum scopes" do
    assert Book.written.build.written?
    assert Book.read.build.read?
  end
R
Robin Dupret 已提交
168

169 170 171
  test "creating new objects with enum scopes" do
    assert Book.written.create.written?
    assert Book.read.create.read?
R
Robin Dupret 已提交
172
  end
173 174

  test "_before_type_cast returns the enum label (required for form fields)" do
175 176 177 178 179
    if @book.status_came_from_user?
      assert_equal "proposed", @book.status_before_type_cast
    else
      assert_equal "proposed", @book.status
    end
180
  end
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

  test "reserved enum names" do
    klass = Class.new(ActiveRecord::Base) do
      self.table_name = "books"
      enum status: [:proposed, :written, :published]
    end

    conflicts = [
      :column,     # generates class method .columns, which conflicts with an AR method
      :logger,     # generates #logger, which conflicts with an AR method
      :attributes, # generates #attributes=, which conflicts with an AR method
    ]

    conflicts.each_with_index do |name, i|
      assert_raises(ArgumentError, "enum name `#{name}` should not be allowed") do
        klass.class_eval { enum name => ["value_#{i}"] }
      end
    end
  end

  test "reserved enum values" do
    klass = Class.new(ActiveRecord::Base) do
      self.table_name = "books"
      enum status: [:proposed, :written, :published]
    end

    conflicts = [
      :new,      # generates a scope that conflicts with an AR class method
      :valid,    # generates #valid?, which conflicts with an AR method
      :save,     # generates #save!, which conflicts with an AR method
      :proposed, # same value as an existing enum
212 213
      :public, :private, :protected, # some important methods on Module and Class
      :name, :parent, :superclass
214 215 216 217 218 219 220 221 222 223 224
    ]

    conflicts.each_with_index do |value, i|
      assert_raises(ArgumentError, "enum value `#{value}` should not be allowed") do
        klass.class_eval { enum "status_#{i}" => [value] }
      end
    end
  end

  test "overriding enum method should not raise" do
    assert_nothing_raised do
T
Tim Fenney 已提交
225
      Class.new(ActiveRecord::Base) do
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
        self.table_name = "books"

        def published!
          super
          "do publish work..."
        end

        enum status: [:proposed, :written, :published]

        def written!
          super
          "do written work..."
        end
      end
    end
  end
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268

  test "validate uniqueness" do
    klass = Class.new(ActiveRecord::Base) do
      def self.name; 'Book'; end
      enum status: [:proposed, :written]
      validates_uniqueness_of :status
    end
    klass.delete_all
    klass.create!(status: "proposed")
    book = klass.new(status: "written")
    assert book.valid?
    book.status = "proposed"
    assert_not book.valid?
  end

  test "validate inclusion of value in array" do
    klass = Class.new(ActiveRecord::Base) do
      def self.name; 'Book'; end
      enum status: [:proposed, :written]
      validates_inclusion_of :status, in: ["written"]
    end
    klass.delete_all
    invalid_book = klass.new(status: "proposed")
    assert_not invalid_book.valid?
    valid_book = klass.new(status: "written")
    assert valid_book.valid?
  end
E
Evan Whalen 已提交
269 270

  test "enums are distinct per class" do
271 272 273 274 275 276 277 278
    klass1 = Class.new(ActiveRecord::Base) do
      self.table_name = "books"
      enum status: [:proposed, :written]
    end

    klass2 = Class.new(ActiveRecord::Base) do
      self.table_name = "books"
      enum status: [:drafted, :uploaded]
E
Evan Whalen 已提交
279
    end
280 281 282 283 284 285 286 287

    book1 = klass1.proposed.create!
    book1.status = :written
    assert_equal ['proposed', 'written'], book1.status_change

    book2 = klass2.drafted.create!
    book2.status = :uploaded
    assert_equal ['drafted', 'uploaded'], book2.status_change
E
Evan Whalen 已提交
288 289 290
  end

  test "enums are inheritable" do
291 292 293 294
    subklass1 = Class.new(Book)

    subklass2 = Class.new(Book) do
      enum status: [:drafted, :uploaded]
E
Evan Whalen 已提交
295
    end
296 297 298 299 300 301 302 303

    book1 = subklass1.proposed.create!
    book1.status = :written
    assert_equal ['proposed', 'written'], book1.status_change

    book2 = subklass2.drafted.create!
    book2.status = :uploaded
    assert_equal ['drafted', 'uploaded'], book2.status_change
E
Evan Whalen 已提交
304
  end
305
end