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/enum_test.rb
George Claghorn 908cfef6e2 Resolve enums in test fixtures
Currently, values for columns backing Active Record enums must be
specified as integers in test fixtures:

    awdr:
      title: "Agile Web Development with Rails"
      status: 2

    rfr:
      title: "Ruby for Rails"
      status: <%= Book.statuses[:proposed] %>

This is potentially confusing, since enum values are typically
specified as symbols or strings in application code. To resolve the
confusion, this change permits the use of symbols or strings to specify
enum values:

    awdr:
      status: :published

It is compatible with fixtures that specify enum values as integers.
2015-05-27 21:48:58 -04:00

358 lines
10 KiB
Ruby

require 'cases/helper'
require 'models/book'
class EnumTest < ActiveRecord::TestCase
fixtures :books
setup do
@book = books(:awdr)
end
test "query state by predicate" do
assert @book.published?
assert_not @book.written?
assert_not @book.proposed?
assert @book.read?
end
test "query state with strings" do
assert_equal "published", @book.status
assert_equal "read", @book.read_status
end
test "find via scope" do
assert_equal @book, Book.published.first
assert_equal @book, Book.read.first
end
test "find via where with values" do
published, written = Book.statuses[:published], Book.statuses[:written]
assert_equal @book, Book.where(status: published).first
refute_equal @book, Book.where(status: written).first
assert_equal @book, Book.where(status: [published]).first
refute_equal @book, Book.where(status: [written]).first
refute_equal @book, Book.where("status <> ?", published).first
assert_equal @book, Book.where("status <> ?", written).first
end
test "find via where with symbols" do
assert_equal @book, Book.where(status: :published).first
refute_equal @book, Book.where(status: :written).first
assert_equal @book, Book.where(status: [:published]).first
refute_equal @book, Book.where(status: [:written]).first
refute_equal @book, Book.where.not(status: :published).first
assert_equal @book, Book.where.not(status: :written).first
end
test "find via where with strings" do
assert_equal @book, Book.where(status: "published").first
refute_equal @book, Book.where(status: "written").first
assert_equal @book, Book.where(status: ["published"]).first
refute_equal @book, Book.where(status: ["written"]).first
refute_equal @book, Book.where.not(status: "published").first
assert_equal @book, Book.where.not(status: "written").first
end
test "build from scope" do
assert Book.written.build.written?
refute Book.written.build.proposed?
end
test "build from where" do
assert Book.where(status: Book.statuses[:written]).build.written?
refute Book.where(status: Book.statuses[:written]).build.proposed?
assert Book.where(status: :written).build.written?
refute Book.where(status: :written).build.proposed?
assert Book.where(status: "written").build.written?
refute Book.where(status: "written").build.proposed?
end
test "update by declaration" do
@book.written!
assert @book.written?
end
test "update by setter" do
@book.update! status: :written
assert @book.written?
end
test "enum methods are overwritable" do
assert_equal "do publish work...", @book.published!
assert @book.published?
end
test "direct assignment" do
@book.status = :written
assert @book.written?
end
test "assign string value" do
@book.status = "written"
assert @book.written?
end
test "enum changed attributes" do
old_status = @book.status
@book.status = :proposed
assert_equal old_status, @book.changed_attributes[:status]
end
test "enum changes" do
old_status = @book.status
@book.status = :proposed
assert_equal [old_status, 'proposed'], @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 = :proposed
assert @book.attribute_changed?(:status)
end
test "enum attribute changed to" do
@book.status = :proposed
assert @book.attribute_changed?(:status, to: 'proposed')
end
test "enum attribute changed from" do
old_status = @book.status
@book.status = :proposed
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 = :proposed
assert @book.attribute_changed?(:status, from: old_status, to: 'proposed')
end
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 = :proposed
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 = :proposed
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
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
test "NULL values from database should be casted to nil" do
Book.where(id: @book.id).update_all("status = NULL")
assert_nil @book.reload.status
end
test "assign nil value" do
@book.status = nil
assert_nil @book.status
end
test "assign empty string value" do
@book.status = ''
assert_nil @book.status
end
test "assign long empty string value" do
@book.status = ' '
assert_nil @book.status
end
test "constant to access the mapping" do
assert_equal 0, Book.statuses[:proposed]
assert_equal 1, Book.statuses["written"]
assert_equal 2, Book.statuses[:published]
end
test "building new objects with enum scopes" do
assert Book.written.build.written?
assert Book.read.build.read?
end
test "creating new objects with enum scopes" do
assert Book.written.create.written?
assert Book.read.create.read?
end
test "_before_type_cast returns the enum label (required for form fields)" do
if @book.status_came_from_user?
assert_equal "published", @book.status_before_type_cast
else
assert_equal "published", @book.status
end
end
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|
e = assert_raises(ArgumentError) do
klass.class_eval { enum name => ["value_#{i}"] }
end
assert_match(/You tried to define an enum named \"#{name}\" on the model/, e.message)
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
:public, :private, :protected, # some important methods on Module and Class
:name, :parent, :superclass
]
conflicts.each_with_index do |value, i|
e = assert_raises(ArgumentError, "enum value `#{value}` should not be allowed") do
klass.class_eval { enum "status_#{i}" => [value] }
end
assert_match(/You tried to define an enum named .* on the model/, e.message)
end
end
test "overriding enum method should not raise" do
assert_nothing_raised do
Class.new(ActiveRecord::Base) do
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
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
test "enums are distinct per class" do
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]
end
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
end
test "enums are inheritable" do
subklass1 = Class.new(Book)
subklass2 = Class.new(Book) do
enum status: [:drafted, :uploaded]
end
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
end
test "declare multiple enums at a time" do
klass = Class.new(ActiveRecord::Base) do
self.table_name = "books"
enum status: [:proposed, :written, :published],
nullable_status: [:single, :married]
end
book1 = klass.proposed.create!
assert book1.proposed?
book2 = klass.single.create!
assert book2.single?
end
end