aboutsummaryrefslogtreecommitdiffstats
path: root/activemodel/test
diff options
context:
space:
mode:
Diffstat (limited to 'activemodel/test')
-rw-r--r--activemodel/test/cases/attribute_methods_test.rb84
-rw-r--r--activemodel/test/cases/conversion_test.rb2
-rw-r--r--activemodel/test/cases/dirty_test.rb2
-rw-r--r--activemodel/test/cases/errors_test.rb29
-rw-r--r--activemodel/test/cases/helper.rb5
-rw-r--r--activemodel/test/cases/lint_test.rb6
-rw-r--r--activemodel/test/cases/mass_assignment_security/permission_set_test.rb6
-rw-r--r--activemodel/test/cases/mass_assignment_security/sanitizer_test.rb13
-rw-r--r--activemodel/test/cases/mass_assignment_security_test.rb9
-rw-r--r--activemodel/test/cases/model_test.rb26
-rw-r--r--activemodel/test/cases/naming_test.rb101
-rw-r--r--activemodel/test/cases/observing_test.rb69
-rw-r--r--activemodel/test/cases/secure_password_test.rb44
-rw-r--r--activemodel/test/cases/serialization_test.rb111
-rw-r--r--activemodel/test/cases/serializers/json_serialization_test.rb98
-rwxr-xr-x[-rw-r--r--]activemodel/test/cases/serializers/xml_serialization_test.rb61
-rw-r--r--activemodel/test/cases/translation_test.rb25
-rw-r--r--activemodel/test/cases/validations/callbacks_test.rb11
-rw-r--r--activemodel/test/cases/validations/confirmation_validation_test.rb21
-rw-r--r--activemodel/test/cases/validations/exclusion_validation_test.rb22
-rw-r--r--activemodel/test/cases/validations/format_validation_test.rb42
-rw-r--r--activemodel/test/cases/validations/i18n_generate_message_validation_test.rb2
-rw-r--r--activemodel/test/cases/validations/i18n_validation_test.rb43
-rw-r--r--activemodel/test/cases/validations/inclusion_validation_test.rb22
-rw-r--r--activemodel/test/cases/validations/length_validation_test.rb102
-rw-r--r--activemodel/test/cases/validations/numericality_validation_test.rb7
-rw-r--r--activemodel/test/cases/validations/validates_test.rb8
-rw-r--r--activemodel/test/cases/validations_test.rb51
-rw-r--r--activemodel/test/models/administrator.rb3
-rw-r--r--activemodel/test/models/blog_post.rb8
-rw-r--r--activemodel/test/models/oauthed_user.rb11
-rw-r--r--activemodel/test/models/user.rb3
-rw-r--r--activemodel/test/models/visitor.rb7
33 files changed, 747 insertions, 307 deletions
diff --git a/activemodel/test/cases/attribute_methods_test.rb b/activemodel/test/cases/attribute_methods_test.rb
index 67471ed497..baaf842222 100644
--- a/activemodel/test/cases/attribute_methods_test.rb
+++ b/activemodel/test/cases/attribute_methods_test.rb
@@ -10,7 +10,7 @@ class ModelWithAttributes
end
def attributes
- { :foo => 'value of foo' }
+ { :foo => 'value of foo', :baz => 'value of baz' }
end
private
@@ -76,7 +76,28 @@ private
end
end
+class ModelWithRubyKeywordNamedAttributes
+ include ActiveModel::AttributeMethods
+
+ def attributes
+ { :begin => 'value of begin', :end => 'value of end' }
+ end
+
+private
+ def attribute(name)
+ attributes[name.to_sym]
+ end
+end
+
+class ModelWithoutAttributesMethod
+ include ActiveModel::AttributeMethods
+end
+
class AttributeMethodsTest < ActiveModel::TestCase
+ test 'method missing works correctly even if attributes method is not defined' do
+ assert_raises(NoMethodError) { ModelWithoutAttributesMethod.new.foo }
+ end
+
test 'unrelated classes should not share attribute method matchers' do
assert_not_equal ModelWithAttributes.send(:attribute_method_matchers),
ModelWithAttributes2.send(:attribute_method_matchers)
@@ -119,47 +140,54 @@ class AttributeMethodsTest < ActiveModel::TestCase
assert_equal "value of a?b", ModelWithWeirdNamesAttributes.new.send('a?b')
end
- test '#define_attribute_methods generates attribute methods' do
- ModelWithAttributes.define_attribute_methods([:foo])
+ test '#define_attribute_methods works passing multiple arguments' do
+ ModelWithAttributes.define_attribute_methods(:foo, :baz)
- assert_respond_to ModelWithAttributes.new, :foo
assert_equal "value of foo", ModelWithAttributes.new.foo
+ assert_equal "value of baz", ModelWithAttributes.new.baz
end
- test '#define_attribute_methods generates attribute methods with spaces in their names' do
- ModelWithAttributesWithSpaces.define_attribute_methods([:'foo bar'])
+ test '#define_attribute_methods generates attribute methods' do
+ ModelWithAttributes.define_attribute_methods(:foo)
- assert_respond_to ModelWithAttributesWithSpaces.new, :'foo bar'
- assert_equal "value of foo bar", ModelWithAttributesWithSpaces.new.send(:'foo bar')
+ assert_respond_to ModelWithAttributes.new, :foo
+ assert_equal "value of foo", ModelWithAttributes.new.foo
end
- test '#define_attr_method generates attribute method' do
- ModelWithAttributes.define_attr_method(:bar, 'bar')
+ test '#alias_attribute generates attribute_aliases lookup hash' do
+ klass = Class.new(ModelWithAttributes) do
+ define_attribute_methods :foo
+ alias_attribute :bar, :foo
+ end
- assert_respond_to ModelWithAttributes, :bar
- assert_equal "original bar", ModelWithAttributes.original_bar
- assert_equal "bar", ModelWithAttributes.bar
- ModelWithAttributes.define_attr_method(:bar)
- assert !ModelWithAttributes.bar
+ assert_equal({ "bar" => "foo" }, klass.attribute_aliases)
end
- test '#define_attr_method generates attribute method with invalid identifier characters' do
- ModelWithWeirdNamesAttributes.define_attr_method(:'c?d', 'c?d')
+ test '#define_attribute_methods generates attribute methods with spaces in their names' do
+ ModelWithAttributesWithSpaces.define_attribute_methods(:'foo bar')
- assert_respond_to ModelWithWeirdNamesAttributes, :'c?d'
- assert_equal "original c?d", ModelWithWeirdNamesAttributes.send('original_c?d')
- assert_equal "c?d", ModelWithWeirdNamesAttributes.send('c?d')
+ assert_respond_to ModelWithAttributesWithSpaces.new, :'foo bar'
+ assert_equal "value of foo bar", ModelWithAttributesWithSpaces.new.send(:'foo bar')
end
test '#alias_attribute works with attributes with spaces in their names' do
- ModelWithAttributesWithSpaces.define_attribute_methods([:'foo bar'])
+ ModelWithAttributesWithSpaces.define_attribute_methods(:'foo bar')
ModelWithAttributesWithSpaces.alias_attribute(:'foo_bar', :'foo bar')
assert_equal "value of foo bar", ModelWithAttributesWithSpaces.new.foo_bar
end
+ test '#alias_attribute works with attributes named as a ruby keyword' do
+ ModelWithRubyKeywordNamedAttributes.define_attribute_methods([:begin, :end])
+ ModelWithRubyKeywordNamedAttributes.alias_attribute(:from, :begin)
+ ModelWithRubyKeywordNamedAttributes.alias_attribute(:to, :end)
+
+ assert_equal "value of begin", ModelWithRubyKeywordNamedAttributes.new.from
+ assert_equal "value of end", ModelWithRubyKeywordNamedAttributes.new.to
+ end
+
test '#undefine_attribute_methods removes attribute methods' do
- ModelWithAttributes.define_attribute_methods([:foo])
+ ModelWithAttributes.define_attribute_methods(:foo)
ModelWithAttributes.undefine_attribute_methods
assert !ModelWithAttributes.new.respond_to?(:foo)
@@ -180,7 +208,7 @@ class AttributeMethodsTest < ActiveModel::TestCase
assert_deprecated { klass.attribute_method_suffix '' }
assert_deprecated { klass.attribute_method_prefix '' }
- klass.define_attribute_methods([:foo])
+ klass.define_attribute_methods(:foo)
assert_equal 'value of foo', klass.new.foo
end
@@ -198,6 +226,12 @@ class AttributeMethodsTest < ActiveModel::TestCase
assert_raises(NoMethodError) { m.protected_method }
end
+ class ClassWithProtected
+ protected
+ def protected_method
+ end
+ end
+
test 'should not interfere with respond_to? if the attribute has a private/protected method' do
m = ModelWithAttributes2.new
m.attributes = { 'private_method' => '<3', 'protected_method' => 'O_o' }
@@ -205,9 +239,11 @@ class AttributeMethodsTest < ActiveModel::TestCase
assert !m.respond_to?(:private_method)
assert m.respond_to?(:private_method, true)
+ c = ClassWithProtected.new
+
# This is messed up, but it's how Ruby works at the moment. Apparently it will be changed
# in the future.
- assert m.respond_to?(:protected_method)
+ assert_equal c.respond_to?(:protected_method), m.respond_to?(:protected_method)
assert m.respond_to?(:protected_method, true)
end
diff --git a/activemodel/test/cases/conversion_test.rb b/activemodel/test/cases/conversion_test.rb
index 24552bcaf2..d679ad41aa 100644
--- a/activemodel/test/cases/conversion_test.rb
+++ b/activemodel/test/cases/conversion_test.rb
@@ -24,7 +24,7 @@ class ConversionTest < ActiveModel::TestCase
assert_equal "1", Contact.new(:id => 1).to_param
end
- test "to_path default implementation returns a string giving a relative path" do
+ test "to_partial_path default implementation returns a string giving a relative path" do
assert_equal "contacts/contact", Contact.new.to_partial_path
assert_equal "helicopters/helicopter", Helicopter.new.to_partial_path,
"ActiveModel::Conversion#to_partial_path caching should be class-specific"
diff --git a/activemodel/test/cases/dirty_test.rb b/activemodel/test/cases/dirty_test.rb
index 98244a6290..eaaf910bac 100644
--- a/activemodel/test/cases/dirty_test.rb
+++ b/activemodel/test/cases/dirty_test.rb
@@ -3,7 +3,7 @@ require "cases/helper"
class DirtyTest < ActiveModel::TestCase
class DirtyModel
include ActiveModel::Dirty
- define_attribute_methods [:name, :color]
+ define_attribute_methods :name, :color
def initialize
@name = nil
diff --git a/activemodel/test/cases/errors_test.rb b/activemodel/test/cases/errors_test.rb
index 8ddedb160a..3bc0d58351 100644
--- a/activemodel/test/cases/errors_test.rb
+++ b/activemodel/test/cases/errors_test.rb
@@ -27,12 +27,27 @@ class ErrorsTest < ActiveModel::TestCase
end
end
+ def test_delete
+ errors = ActiveModel::Errors.new(self)
+ errors[:foo] = 'omg'
+ errors.delete(:foo)
+ assert_empty errors[:foo]
+ end
+
def test_include?
errors = ActiveModel::Errors.new(self)
errors[:foo] = 'omg'
assert errors.include?(:foo), 'errors should include :foo'
end
+ def test_dup
+ errors = ActiveModel::Errors.new(self)
+ errors[:foo] = 'bar'
+ errors_dup = errors.dup
+ errors_dup[:bar] = 'omg'
+ assert_not_same errors_dup.messages, errors.messages
+ end
+
def test_has_key?
errors = ActiveModel::Errors.new(self)
errors[:foo] = 'omg'
@@ -136,10 +151,10 @@ class ErrorsTest < ActiveModel::TestCase
assert_equal ["name can not be blank", "name can not be nil"], person.errors.to_a
end
- test 'to_hash should return an ordered hash' do
+ test 'to_hash should return a hash' do
person = Person.new
person.errors.add(:name, "can not be blank")
- assert_instance_of ActiveSupport::OrderedHash, person.errors.to_hash
+ assert_instance_of ::Hash, person.errors.to_hash
end
test 'full_messages should return an array of error messages, with the attribute name included' do
@@ -169,6 +184,16 @@ class ErrorsTest < ActiveModel::TestCase
assert_equal ["is invalid"], hash[:email]
end
+ test 'should return a JSON hash representation of the errors with full messages' do
+ person = Person.new
+ person.errors.add(:name, "can not be blank")
+ person.errors.add(:name, "can not be nil")
+ person.errors.add(:email, "is invalid")
+ hash = person.errors.as_json(:full_messages => true)
+ assert_equal ["name can not be blank", "name can not be nil"], hash[:name]
+ assert_equal ["email is invalid"], hash[:email]
+ end
+
test "generate_message should work without i18n_scope" do
person = Person.new
assert !Person.respond_to?(:i18n_scope)
diff --git a/activemodel/test/cases/helper.rb b/activemodel/test/cases/helper.rb
index 2e860272a4..7d6f11b5a5 100644
--- a/activemodel/test/cases/helper.rb
+++ b/activemodel/test/cases/helper.rb
@@ -1,8 +1,5 @@
require File.expand_path('../../../../load_paths', __FILE__)
-lib = File.expand_path("#{File.dirname(__FILE__)}/../../lib")
-$:.unshift(lib) unless $:.include?('lib') || $:.include?(lib)
-
require 'config'
require 'active_model'
require 'active_support/core_ext/string/access'
@@ -10,4 +7,4 @@ require 'active_support/core_ext/string/access'
# Show backtraces for deprecated behavior for quicker cleanup.
ActiveSupport::Deprecation.debug = true
-require 'test/unit'
+require 'minitest/autorun'
diff --git a/activemodel/test/cases/lint_test.rb b/activemodel/test/cases/lint_test.rb
index 68372160cd..8faf93c056 100644
--- a/activemodel/test/cases/lint_test.rb
+++ b/activemodel/test/cases/lint_test.rb
@@ -7,14 +7,10 @@ class LintTest < ActiveModel::TestCase
extend ActiveModel::Naming
include ActiveModel::Conversion
- def valid?() true end
def persisted?() false end
def errors
- obj = Object.new
- def obj.[](key) [] end
- def obj.full_messages() [] end
- obj
+ Hash.new([])
end
end
diff --git a/activemodel/test/cases/mass_assignment_security/permission_set_test.rb b/activemodel/test/cases/mass_assignment_security/permission_set_test.rb
index d005b638e4..8082c49852 100644
--- a/activemodel/test/cases/mass_assignment_security/permission_set_test.rb
+++ b/activemodel/test/cases/mass_assignment_security/permission_set_test.rb
@@ -13,6 +13,12 @@ class PermissionSetTest < ActiveModel::TestCase
assert new_list.include?('admin'), "did not add collection to #{@permission_list.inspect}}"
end
+ test "+ compacts added collection values" do
+ added_collection = [ nil ]
+ new_list = @permission_list + added_collection
+ assert_equal new_list, @permission_list, "did not add collection to #{@permission_list.inspect}}"
+ end
+
test "include? normalizes multi-parameter keys" do
multi_param_key = 'admin(1)'
new_list = @permission_list += [ 'admin' ]
diff --git a/activemodel/test/cases/mass_assignment_security/sanitizer_test.rb b/activemodel/test/cases/mass_assignment_security/sanitizer_test.rb
index 676937b5e1..b141cec059 100644
--- a/activemodel/test/cases/mass_assignment_security/sanitizer_test.rb
+++ b/activemodel/test/cases/mass_assignment_security/sanitizer_test.rb
@@ -1,6 +1,5 @@
require "cases/helper"
-require 'logger'
-require 'active_support/core_ext/object/inclusion'
+require 'active_support/logger'
class SanitizerTest < ActiveModel::TestCase
attr_accessor :logger
@@ -19,7 +18,7 @@ class SanitizerTest < ActiveModel::TestCase
test "sanitize attributes" do
original_attributes = { 'first_name' => 'allowed', 'admin' => 'denied' }
- attributes = @logger_sanitizer.sanitize(original_attributes, @authorizer)
+ attributes = @logger_sanitizer.sanitize(self.class, original_attributes, @authorizer)
assert attributes.key?('first_name'), "Allowed key shouldn't be rejected"
assert !attributes.key?('admin'), "Denied key should be rejected"
@@ -28,15 +27,15 @@ class SanitizerTest < ActiveModel::TestCase
test "debug mass assignment removal with LoggerSanitizer" do
original_attributes = { 'first_name' => 'allowed', 'admin' => 'denied' }
log = StringIO.new
- self.logger = Logger.new(log)
- @logger_sanitizer.sanitize(original_attributes, @authorizer)
+ self.logger = ActiveSupport::Logger.new(log)
+ @logger_sanitizer.sanitize(self.class, original_attributes, @authorizer)
assert_match(/admin/, log.string, "Should log removed attributes: #{log.string}")
end
test "debug mass assignment removal with StrictSanitizer" do
original_attributes = { 'first_name' => 'allowed', 'admin' => 'denied' }
assert_raise ActiveModel::MassAssignmentSecurity::Error do
- @strict_sanitizer.sanitize(original_attributes, @authorizer)
+ @strict_sanitizer.sanitize(self.class, original_attributes, @authorizer)
end
end
@@ -44,7 +43,7 @@ class SanitizerTest < ActiveModel::TestCase
original_attributes = {'id' => 1, 'first_name' => 'allowed'}
assert_nothing_raised do
- @strict_sanitizer.sanitize(original_attributes, @authorizer)
+ @strict_sanitizer.sanitize(self.class, original_attributes, @authorizer)
end
end
diff --git a/activemodel/test/cases/mass_assignment_security_test.rb b/activemodel/test/cases/mass_assignment_security_test.rb
index be07e59a2f..0c6352cd71 100644
--- a/activemodel/test/cases/mass_assignment_security_test.rb
+++ b/activemodel/test/cases/mass_assignment_security_test.rb
@@ -4,7 +4,7 @@ require 'models/mass_assignment_specific'
class CustomSanitizer < ActiveModel::MassAssignmentSecurity::Sanitizer
- def process_removed_attributes(attrs)
+ def process_removed_attributes(klass, attrs)
raise StandardError
end
@@ -19,6 +19,13 @@ class MassAssignmentSecurityTest < ActiveModel::TestCase
assert_equal expected, sanitized
end
+ def test_attribute_protection_when_role_is_nil
+ user = User.new
+ expected = { "name" => "John Smith", "email" => "john@smith.com" }
+ sanitized = user.sanitize_for_mass_assignment(expected.merge("admin" => true), nil)
+ assert_equal expected, sanitized
+ end
+
def test_only_moderator_role_attribute_accessible
user = SpecialUser.new
expected = { "name" => "John Smith", "email" => "john@smith.com" }
diff --git a/activemodel/test/cases/model_test.rb b/activemodel/test/cases/model_test.rb
new file mode 100644
index 0000000000..d93fd96b88
--- /dev/null
+++ b/activemodel/test/cases/model_test.rb
@@ -0,0 +1,26 @@
+require 'cases/helper'
+
+class ModelTest < ActiveModel::TestCase
+ include ActiveModel::Lint::Tests
+
+ class BasicModel
+ include ActiveModel::Model
+ attr_accessor :attr
+ end
+
+ def setup
+ @model = BasicModel.new
+ end
+
+ def test_initialize_with_params
+ object = BasicModel.new(:attr => "value")
+ assert_equal object.attr, "value"
+ end
+
+ def test_initialize_with_nil_or_empty_hash_params_does_not_explode
+ assert_nothing_raised do
+ BasicModel.new()
+ BasicModel.new({})
+ end
+ end
+end
diff --git a/activemodel/test/cases/naming_test.rb b/activemodel/test/cases/naming_test.rb
index 5f943729dd..49d8706ac2 100644
--- a/activemodel/test/cases/naming_test.rb
+++ b/activemodel/test/cases/naming_test.rb
@@ -25,15 +25,13 @@ class NamingTest < ActiveModel::TestCase
assert_equal 'post/track_backs', @model_name.collection
end
- def test_partial_path
- assert_deprecated(/#partial_path.*#to_partial_path/) do
- assert_equal 'post/track_backs/track_back', @model_name.partial_path
- end
- end
-
def test_human
assert_equal 'Track back', @model_name.human
end
+
+ def test_i18n_key
+ assert_equal :"post/track_back", @model_name.i18n_key
+ end
end
class NamingWithNamespacedModelInIsolatedNamespaceTest < ActiveModel::TestCase
@@ -57,12 +55,6 @@ class NamingWithNamespacedModelInIsolatedNamespaceTest < ActiveModel::TestCase
assert_equal 'blog/posts', @model_name.collection
end
- def test_partial_path
- assert_deprecated(/#partial_path.*#to_partial_path/) do
- assert_equal 'blog/posts/post', @model_name.partial_path
- end
- end
-
def test_human
assert_equal 'Post', @model_name.human
end
@@ -75,8 +67,8 @@ class NamingWithNamespacedModelInIsolatedNamespaceTest < ActiveModel::TestCase
assert_equal 'post', @model_name.param_key
end
- def test_recognizing_namespace
- assert_equal 'Post', Blog::Post.model_name.instance_variable_get("@unnamespaced")
+ def test_i18n_key
+ assert_equal :"blog/post", @model_name.i18n_key
end
end
@@ -101,12 +93,6 @@ class NamingWithNamespacedModelInSharedNamespaceTest < ActiveModel::TestCase
assert_equal 'blog/posts', @model_name.collection
end
- def test_partial_path
- assert_deprecated(/#partial_path.*#to_partial_path/) do
- assert_equal 'blog/posts/post', @model_name.partial_path
- end
- end
-
def test_human
assert_equal 'Post', @model_name.human
end
@@ -118,6 +104,10 @@ class NamingWithNamespacedModelInSharedNamespaceTest < ActiveModel::TestCase
def test_param_key
assert_equal 'blog_post', @model_name.param_key
end
+
+ def test_i18n_key
+ assert_equal :"blog/post", @model_name.i18n_key
+ end
end
class NamingWithSuppliedModelNameTest < ActiveModel::TestCase
@@ -141,12 +131,6 @@ class NamingWithSuppliedModelNameTest < ActiveModel::TestCase
assert_equal 'articles', @model_name.collection
end
- def test_partial_path
- assert_deprecated(/#partial_path.*#to_partial_path/) do
- assert_equal 'articles/article', @model_name.partial_path
- end
- end
-
def test_human
assert_equal 'Article', @model_name.human
end
@@ -158,15 +142,58 @@ class NamingWithSuppliedModelNameTest < ActiveModel::TestCase
def test_param_key
assert_equal 'article', @model_name.param_key
end
+
+ def test_i18n_key
+ assert_equal :"article", @model_name.i18n_key
+ end
+end
+
+class NamingUsingRelativeModelNameTest < ActiveModel::TestCase
+ def setup
+ @model_name = Blog::Post.model_name
+ end
+
+ def test_singular
+ assert_equal 'blog_post', @model_name.singular
+ end
+
+ def test_plural
+ assert_equal 'blog_posts', @model_name.plural
+ end
+
+ def test_element
+ assert_equal 'post', @model_name.element
+ end
+
+ def test_collection
+ assert_equal 'blog/posts', @model_name.collection
+ end
+
+ def test_human
+ assert_equal 'Post', @model_name.human
+ end
+
+ def test_route_key
+ assert_equal 'posts', @model_name.route_key
+ end
+
+ def test_param_key
+ assert_equal 'post', @model_name.param_key
+ end
+
+ def test_i18n_key
+ assert_equal :"blog/post", @model_name.i18n_key
+ end
end
-class NamingHelpersTest < Test::Unit::TestCase
+class NamingHelpersTest < ActiveModel::TestCase
def setup
@klass = Contact
@record = @klass.new
@singular = 'contact'
@plural = 'contacts'
@uncountable = Sheep
+ @singular_route_key = 'contact'
@route_key = 'contacts'
@param_key = 'contact'
end
@@ -193,10 +220,12 @@ class NamingHelpersTest < Test::Unit::TestCase
def test_route_key
assert_equal @route_key, route_key(@record)
+ assert_equal @singular_route_key, singular_route_key(@record)
end
def test_route_key_for_class
assert_equal @route_key, route_key(@klass)
+ assert_equal @singular_route_key, singular_route_key(@klass)
end
def test_param_key
@@ -212,8 +241,26 @@ class NamingHelpersTest < Test::Unit::TestCase
assert !uncountable?(@klass), "Expected 'contact' to be countable"
end
+ def test_uncountable_route_key
+ assert_equal "sheep", singular_route_key(@uncountable)
+ assert_equal "sheep_index", route_key(@uncountable)
+ end
+
private
def method_missing(method, *args)
ActiveModel::Naming.send(method, *args)
end
end
+
+class NameWithAnonymousClassTest < ActiveModel::TestCase
+ def test_anonymous_class_without_name_argument
+ assert_raises(ArgumentError) do
+ ActiveModel::Name.new(Class.new)
+ end
+ end
+
+ def test_anonymous_class_with_name_argument
+ model_name = ActiveModel::Name.new(Class.new, nil, "Anonymous")
+ assert_equal "Anonymous", model_name
+ end
+end
diff --git a/activemodel/test/cases/observing_test.rb b/activemodel/test/cases/observing_test.rb
index f6ec24ae57..ade6026602 100644
--- a/activemodel/test/cases/observing_test.rb
+++ b/activemodel/test/cases/observing_test.rb
@@ -14,8 +14,8 @@ class FooObserver < ActiveModel::Observer
attr_accessor :stub
- def on_spec(record)
- stub.event_with(record) if stub
+ def on_spec(record, *args)
+ stub.event_with(record, *args) if stub
end
def around_save(record)
@@ -70,23 +70,38 @@ class ObservingTest < ActiveModel::TestCase
ObservedModel.instantiate_observers
end
+ test "raises an appropriate error when a developer accidentally adds the wrong class (i.e. Widget instead of WidgetObserver)" do
+ assert_raise ArgumentError do
+ ObservedModel.observers = ['string']
+ ObservedModel.instantiate_observers
+ end
+ assert_raise ArgumentError do
+ ObservedModel.observers = [:string]
+ ObservedModel.instantiate_observers
+ end
+ assert_raise ArgumentError do
+ ObservedModel.observers = [String]
+ ObservedModel.instantiate_observers
+ end
+ end
+
test "passes observers to subclasses" do
FooObserver.instance
bar = Class.new(Foo)
- assert_equal Foo.count_observers, bar.count_observers
+ assert_equal Foo.observers_count, bar.observers_count
end
end
class ObserverTest < ActiveModel::TestCase
def setup
ObservedModel.observers = :foo_observer
- FooObserver.instance_eval do
+ FooObserver.singleton_class.instance_eval do
alias_method :original_observed_classes, :observed_classes
end
end
def teardown
- FooObserver.instance_eval do
+ FooObserver.singleton_class.instance_eval do
undef_method :observed_classes
alias_method :observed_classes, :original_observed_classes
end
@@ -98,44 +113,51 @@ class ObserverTest < ActiveModel::TestCase
test "tracks implicit observable models" do
instance = FooObserver.new
- assert instance.send(:observed_classes).include?(Foo), "Foo not in #{instance.send(:observed_classes).inspect}"
- assert !instance.send(:observed_classes).include?(ObservedModel), "ObservedModel in #{instance.send(:observed_classes).inspect}"
+ assert_equal [Foo], instance.observed_classes
end
test "tracks explicit observed model class" do
- old_instance = FooObserver.new
- assert !old_instance.send(:observed_classes).include?(ObservedModel), "ObservedModel in #{old_instance.send(:observed_classes).inspect}"
FooObserver.observe ObservedModel
instance = FooObserver.new
- assert instance.send(:observed_classes).include?(ObservedModel), "ObservedModel not in #{instance.send(:observed_classes).inspect}"
+ assert_equal [ObservedModel], instance.observed_classes
end
test "tracks explicit observed model as string" do
- old_instance = FooObserver.new
- assert !old_instance.send(:observed_classes).include?(ObservedModel), "ObservedModel in #{old_instance.send(:observed_classes).inspect}"
FooObserver.observe 'observed_model'
instance = FooObserver.new
- assert instance.send(:observed_classes).include?(ObservedModel), "ObservedModel not in #{instance.send(:observed_classes).inspect}"
+ assert_equal [ObservedModel], instance.observed_classes
end
test "tracks explicit observed model as symbol" do
- old_instance = FooObserver.new
- assert !old_instance.send(:observed_classes).include?(ObservedModel), "ObservedModel in #{old_instance.send(:observed_classes).inspect}"
FooObserver.observe :observed_model
instance = FooObserver.new
- assert instance.send(:observed_classes).include?(ObservedModel), "ObservedModel not in #{instance.send(:observed_classes).inspect}"
+ assert_equal [ObservedModel], instance.observed_classes
end
test "calls existing observer event" do
foo = Foo.new
FooObserver.instance.stub = stub
FooObserver.instance.stub.expects(:event_with).with(foo)
- Foo.send(:notify_observers, :on_spec, foo)
+ Foo.notify_observers(:on_spec, foo)
+ end
+
+ test "calls existing observer event from the instance" do
+ foo = Foo.new
+ FooObserver.instance.stub = stub
+ FooObserver.instance.stub.expects(:event_with).with(foo)
+ foo.notify_observers(:on_spec)
+ end
+
+ test "passes extra arguments" do
+ foo = Foo.new
+ FooObserver.instance.stub = stub
+ FooObserver.instance.stub.expects(:event_with).with(foo, :bar)
+ Foo.send(:notify_observers, :on_spec, foo, :bar)
end
test "skips nonexistent observer event" do
foo = Foo.new
- Foo.send(:notify_observers, :whatever, foo)
+ Foo.notify_observers(:whatever, foo)
end
test "update passes a block on to the observer" do
@@ -145,4 +167,15 @@ class ObserverTest < ActiveModel::TestCase
end
assert_equal :in_around_save, yielded_value
end
+
+ test "observe redefines observed_classes class method" do
+ class BarObserver < ActiveModel::Observer
+ observe :foo
+ end
+
+ assert_equal [Foo], BarObserver.observed_classes
+
+ BarObserver.observe(ObservedModel)
+ assert_equal [ObservedModel], BarObserver.observed_classes
+ end
end
diff --git a/activemodel/test/cases/secure_password_test.rb b/activemodel/test/cases/secure_password_test.rb
index 4338a3fc53..8650b0e495 100644
--- a/activemodel/test/cases/secure_password_test.rb
+++ b/activemodel/test/cases/secure_password_test.rb
@@ -1,5 +1,6 @@
require 'cases/helper'
require 'models/user'
+require 'models/oauthed_user'
require 'models/visitor'
require 'models/administrator'
@@ -7,28 +8,39 @@ class SecurePasswordTest < ActiveModel::TestCase
setup do
@user = User.new
+ @visitor = Visitor.new
+ @oauthed_user = OauthedUser.new
end
test "blank password" do
- @user.password = ''
- assert !@user.valid?, 'user should be invalid'
+ @user.password = @visitor.password = ''
+ assert !@user.valid?(:create), 'user should be invalid'
+ assert @visitor.valid?(:create), 'visitor should be valid'
end
test "nil password" do
- @user.password = nil
- assert !@user.valid?, 'user should be invalid'
+ @user.password = @visitor.password = nil
+ assert !@user.valid?(:create), 'user should be invalid'
+ assert @visitor.valid?(:create), 'visitor should be valid'
+ end
+
+ test "blank password doesn't override previous password" do
+ @user.password = 'test'
+ @user.password = ''
+ assert_equal @user.password, 'test'
end
test "password must be present" do
- assert !@user.valid?
+ assert !@user.valid?(:create)
assert_equal 1, @user.errors.size
end
- test "password must match confirmation" do
- @user.password = "thiswillberight"
- @user.password_confirmation = "wrong"
+ test "match confirmation" do
+ @user.password = @visitor.password = "thiswillberight"
+ @user.password_confirmation = @visitor.password_confirmation = "wrong"
assert !@user.valid?
+ assert @visitor.valid?
@user.password_confirmation = "thiswillberight"
@@ -53,4 +65,20 @@ class SecurePasswordTest < ActiveModel::TestCase
assert !active_authorizer.include?(:password_digest)
assert active_authorizer.include?(:name)
end
+
+ test "User should not be created with blank digest" do
+ assert_raise RuntimeError do
+ @user.run_callbacks :create
+ end
+ @user.password = "supersecretpassword"
+ assert_nothing_raised do
+ @user.run_callbacks :create
+ end
+ end
+
+ test "Oauthed user can be created with blank digest" do
+ assert_nothing_raised do
+ @oauthed_user.run_callbacks :create
+ end
+ end
end
diff --git a/activemodel/test/cases/serialization_test.rb b/activemodel/test/cases/serialization_test.rb
index b8dad9d51f..d2ba9fd95d 100644
--- a/activemodel/test/cases/serialization_test.rb
+++ b/activemodel/test/cases/serialization_test.rb
@@ -43,38 +43,38 @@ class SerializationTest < ActiveModel::TestCase
end
def test_method_serializable_hash_should_work
- expected = {"name"=>"David", "gender"=>"male", "email"=>"david@example.com"}
- assert_equal expected , @user.serializable_hash
+ expected = {"name"=>"David", "gender"=>"male", "email"=>"david@example.com"}
+ assert_equal expected, @user.serializable_hash
end
def test_method_serializable_hash_should_work_with_only_option
- expected = {"name"=>"David"}
- assert_equal expected , @user.serializable_hash(:only => [:name])
+ expected = {"name"=>"David"}
+ assert_equal expected, @user.serializable_hash(:only => [:name])
end
def test_method_serializable_hash_should_work_with_except_option
- expected = {"gender"=>"male", "email"=>"david@example.com"}
- assert_equal expected , @user.serializable_hash(:except => [:name])
+ expected = {"gender"=>"male", "email"=>"david@example.com"}
+ assert_equal expected, @user.serializable_hash(:except => [:name])
end
def test_method_serializable_hash_should_work_with_methods_option
- expected = {"name"=>"David", "gender"=>"male", :foo=>"i_am_foo", "email"=>"david@example.com"}
- assert_equal expected , @user.serializable_hash(:methods => [:foo])
+ expected = {"name"=>"David", "gender"=>"male", "foo"=>"i_am_foo", "email"=>"david@example.com"}
+ assert_equal expected, @user.serializable_hash(:methods => [:foo])
end
def test_method_serializable_hash_should_work_with_only_and_methods
- expected = {:foo=>"i_am_foo"}
- assert_equal expected , @user.serializable_hash(:only => [], :methods => [:foo])
+ expected = {"foo"=>"i_am_foo"}
+ assert_equal expected, @user.serializable_hash(:only => [], :methods => [:foo])
end
def test_method_serializable_hash_should_work_with_except_and_methods
- expected = {"gender"=>"male", :foo=>"i_am_foo"}
- assert_equal expected , @user.serializable_hash(:except => [:name, :email], :methods => [:foo])
+ expected = {"gender"=>"male", "foo"=>"i_am_foo"}
+ assert_equal expected, @user.serializable_hash(:except => [:name, :email], :methods => [:foo])
end
def test_should_not_call_methods_that_dont_respond
- expected = {"name"=>"David", "gender"=>"male", "email"=>"david@example.com"}
- assert_equal expected , @user.serializable_hash(:methods => [:bar])
+ expected = {"name"=>"David", "gender"=>"male", "email"=>"david@example.com"}
+ assert_equal expected, @user.serializable_hash(:methods => [:bar])
end
def test_should_use_read_attribute_for_serialization
@@ -87,65 +87,82 @@ class SerializationTest < ActiveModel::TestCase
end
def test_include_option_with_singular_association
- expected = {"name"=>"David", "gender"=>"male", "email"=>"david@example.com",
- :address=>{"street"=>"123 Lane", "city"=>"Springfield", "state"=>"CA", "zip"=>11111}}
- assert_equal expected , @user.serializable_hash(:include => :address)
+ expected = {"name"=>"David", "gender"=>"male", "email"=>"david@example.com",
+ "address"=>{"street"=>"123 Lane", "city"=>"Springfield", "state"=>"CA", "zip"=>11111}}
+ assert_equal expected, @user.serializable_hash(:include => :address)
end
def test_include_option_with_plural_association
- expected = {"email"=>"david@example.com", "gender"=>"male", "name"=>"David",
- :friends=>[{"name"=>'Joe', "email"=>'joe@example.com', "gender"=>'male'},
- {"name"=>'Sue', "email"=>'sue@example.com', "gender"=>'female'}]}
- assert_equal expected , @user.serializable_hash(:include => :friends)
+ expected = {"email"=>"david@example.com", "gender"=>"male", "name"=>"David",
+ "friends"=>[{"name"=>'Joe', "email"=>'joe@example.com', "gender"=>'male'},
+ {"name"=>'Sue', "email"=>'sue@example.com', "gender"=>'female'}]}
+ assert_equal expected, @user.serializable_hash(:include => :friends)
end
def test_include_option_with_empty_association
@user.friends = []
- expected = {"email"=>"david@example.com", "gender"=>"male", "name"=>"David", :friends=>[]}
- assert_equal expected , @user.serializable_hash(:include => :friends)
+ expected = {"email"=>"david@example.com", "gender"=>"male", "name"=>"David", "friends"=>[]}
+ assert_equal expected, @user.serializable_hash(:include => :friends)
+ end
+
+ class FriendList
+ def initialize(friends)
+ @friends = friends
+ end
+
+ def to_ary
+ @friends
+ end
+ end
+
+ def test_include_option_with_ary
+ @user.friends = FriendList.new(@user.friends)
+ expected = {"email"=>"david@example.com", "gender"=>"male", "name"=>"David",
+ "friends"=>[{"name"=>'Joe', "email"=>'joe@example.com', "gender"=>'male'},
+ {"name"=>'Sue', "email"=>'sue@example.com', "gender"=>'female'}]}
+ assert_equal expected, @user.serializable_hash(:include => :friends)
end
def test_multiple_includes
- expected = {"email"=>"david@example.com", "gender"=>"male", "name"=>"David",
- :address=>{"street"=>"123 Lane", "city"=>"Springfield", "state"=>"CA", "zip"=>11111},
- :friends=>[{"name"=>'Joe', "email"=>'joe@example.com', "gender"=>'male'},
- {"name"=>'Sue', "email"=>'sue@example.com', "gender"=>'female'}]}
- assert_equal expected , @user.serializable_hash(:include => [:address, :friends])
+ expected = {"email"=>"david@example.com", "gender"=>"male", "name"=>"David",
+ "address"=>{"street"=>"123 Lane", "city"=>"Springfield", "state"=>"CA", "zip"=>11111},
+ "friends"=>[{"name"=>'Joe', "email"=>'joe@example.com', "gender"=>'male'},
+ {"name"=>'Sue', "email"=>'sue@example.com', "gender"=>'female'}]}
+ assert_equal expected, @user.serializable_hash(:include => [:address, :friends])
end
def test_include_with_options
- expected = {"email"=>"david@example.com", "gender"=>"male", "name"=>"David",
- :address=>{"street"=>"123 Lane"}}
- assert_equal expected , @user.serializable_hash(:include => {:address => {:only => "street"}})
+ expected = {"email"=>"david@example.com", "gender"=>"male", "name"=>"David",
+ "address"=>{"street"=>"123 Lane"}}
+ assert_equal expected, @user.serializable_hash(:include => {:address => {:only => "street"}})
end
def test_nested_include
@user.friends.first.friends = [@user]
- expected = {"email"=>"david@example.com", "gender"=>"male", "name"=>"David",
- :friends=>[{"name"=>'Joe', "email"=>'joe@example.com', "gender"=>'male',
- :friends => [{"email"=>"david@example.com", "gender"=>"male", "name"=>"David"}]},
- {"name"=>'Sue', "email"=>'sue@example.com', "gender"=>'female', :friends => []}]}
- assert_equal expected , @user.serializable_hash(:include => {:friends => {:include => :friends}})
+ expected = {"email"=>"david@example.com", "gender"=>"male", "name"=>"David",
+ "friends"=>[{"name"=>'Joe', "email"=>'joe@example.com', "gender"=>'male',
+ "friends"=> [{"email"=>"david@example.com", "gender"=>"male", "name"=>"David"}]},
+ {"name"=>'Sue', "email"=>'sue@example.com', "gender"=>'female', "friends"=> []}]}
+ assert_equal expected, @user.serializable_hash(:include => {:friends => {:include => :friends}})
end
def test_only_include
- expected = {"name"=>"David", :friends => [{"name" => "Joe"}, {"name" => "Sue"}]}
- assert_equal expected , @user.serializable_hash(:only => :name, :include => {:friends => {:only => :name}})
+ expected = {"name"=>"David", "friends" => [{"name" => "Joe"}, {"name" => "Sue"}]}
+ assert_equal expected, @user.serializable_hash(:only => :name, :include => {:friends => {:only => :name}})
end
def test_except_include
expected = {"name"=>"David", "email"=>"david@example.com",
- :friends => [{"name" => 'Joe', "email" => 'joe@example.com'},
- {"name" => "Sue", "email" => 'sue@example.com'}]}
- assert_equal expected , @user.serializable_hash(:except => :gender, :include => {:friends => {:except => :gender}})
+ "friends"=> [{"name" => 'Joe', "email" => 'joe@example.com'},
+ {"name" => "Sue", "email" => 'sue@example.com'}]}
+ assert_equal expected, @user.serializable_hash(:except => :gender, :include => {:friends => {:except => :gender}})
end
def test_multiple_includes_with_options
- expected = {"email"=>"david@example.com", "gender"=>"male", "name"=>"David",
- :address=>{"street"=>"123 Lane"},
- :friends=>[{"name"=>'Joe', "email"=>'joe@example.com', "gender"=>'male'},
- {"name"=>'Sue', "email"=>'sue@example.com', "gender"=>'female'}]}
- assert_equal expected , @user.serializable_hash(:include => [{:address => {:only => "street"}}, :friends])
+ expected = {"email"=>"david@example.com", "gender"=>"male", "name"=>"David",
+ "address"=>{"street"=>"123 Lane"},
+ "friends"=>[{"name"=>'Joe', "email"=>'joe@example.com', "gender"=>'male'},
+ {"name"=>'Sue', "email"=>'sue@example.com', "gender"=>'female'}]}
+ assert_equal expected, @user.serializable_hash(:include => [{:address => {:only => "street"}}, :friends])
end
-
end
diff --git a/activemodel/test/cases/serializers/json_serialization_test.rb b/activemodel/test/cases/serializers/json_serialization_test.rb
index a754d610b9..e2690f1827 100644
--- a/activemodel/test/cases/serializers/json_serialization_test.rb
+++ b/activemodel/test/cases/serializers/json_serialization_test.rb
@@ -14,9 +14,11 @@ class Contact
end
end
+ remove_method :attributes if method_defined?(:attributes)
+
def attributes
instance_values
- end unless method_defined?(:attributes)
+ end
end
class JsonSerializationTest < ActiveModel::TestCase
@@ -29,10 +31,15 @@ class JsonSerializationTest < ActiveModel::TestCase
@contact.preferences = { 'shows' => 'anime' }
end
- test "should include root in json" do
+ def teardown
+ # set to the default value
+ Contact.include_root_in_json = false
+ end
+
+ test "should not include root in json (class method)" do
json = @contact.to_json
- assert_match %r{^\{"contact":\{}, json
+ assert_no_match %r{^\{"contact":\{}, json
assert_match %r{"name":"Konata Izumi"}, json
assert_match %r{"age":16}, json
assert json.include?(%("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))}))
@@ -40,41 +47,31 @@ class JsonSerializationTest < ActiveModel::TestCase
assert_match %r{"preferences":\{"shows":"anime"\}}, json
end
- test "should not include root in json (class method)" do
- begin
- Contact.include_root_in_json = false
- json = @contact.to_json
-
- assert_no_match %r{^\{"contact":\{}, json
- assert_match %r{"name":"Konata Izumi"}, json
- assert_match %r{"age":16}, json
- assert json.include?(%("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))}))
- assert_match %r{"awesome":true}, json
- assert_match %r{"preferences":\{"shows":"anime"\}}, json
- ensure
- Contact.include_root_in_json = true
- end
+ test "should include root in json if include_root_in_json is true" do
+ Contact.include_root_in_json = true
+ json = @contact.to_json
+
+ assert_match %r{^\{"contact":\{}, json
+ assert_match %r{"name":"Konata Izumi"}, json
+ assert_match %r{"age":16}, json
+ assert json.include?(%("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))}))
+ assert_match %r{"awesome":true}, json
+ assert_match %r{"preferences":\{"shows":"anime"\}}, json
end
test "should include root in json (option) even if the default is set to false" do
- begin
- Contact.include_root_in_json = false
- json = @contact.to_json(:root => true)
- assert_match %r{^\{"contact":\{}, json
- ensure
- Contact.include_root_in_json = true
- end
+ json = @contact.to_json(root: true)
+ assert_match %r{^\{"contact":\{}, json
end
test "should not include root in json (option)" do
-
- json = @contact.to_json(:root => false)
+ json = @contact.to_json(root: false)
assert_no_match %r{^\{"contact":\{}, json
end
test "should include custom root in json" do
- json = @contact.to_json(:root => 'json_contact')
+ json = @contact.to_json(root: 'json_contact')
assert_match %r{^\{"json_contact":\{}, json
assert_match %r{"name":"Konata Izumi"}, json
@@ -105,7 +102,7 @@ class JsonSerializationTest < ActiveModel::TestCase
end
test "should allow attribute filtering with except" do
- json = @contact.to_json(:except => [:name, :age])
+ json = @contact.to_json(except: [:name, :age])
assert_no_match %r{"name":"Konata Izumi"}, json
assert_no_match %r{"age":16}, json
@@ -120,35 +117,36 @@ class JsonSerializationTest < ActiveModel::TestCase
def @contact.favorite_quote; "Constraints are liberating"; end
# Single method.
- assert_match %r{"label":"Has cheezburger"}, @contact.to_json(:only => :name, :methods => :label)
+ assert_match %r{"label":"Has cheezburger"}, @contact.to_json(only: :name, methods: :label)
# Both methods.
- methods_json = @contact.to_json(:only => :name, :methods => [:label, :favorite_quote])
+ methods_json = @contact.to_json(only: :name, methods: [:label, :favorite_quote])
assert_match %r{"label":"Has cheezburger"}, methods_json
assert_match %r{"favorite_quote":"Constraints are liberating"}, methods_json
end
- test "should return OrderedHash for errors" do
+ test "should return Hash for errors" do
contact = Contact.new
contact.errors.add :name, "can't be blank"
contact.errors.add :name, "is too short (minimum is 2 characters)"
contact.errors.add :age, "must be 16 or over"
- hash = ActiveSupport::OrderedHash.new
+ hash = {}
hash[:name] = ["can't be blank", "is too short (minimum is 2 characters)"]
hash[:age] = ["must be 16 or over"]
assert_equal hash.to_json, contact.errors.to_json
end
test "serializable_hash should not modify options passed in argument" do
- options = { :except => :name }
+ options = { except: :name }
@contact.serializable_hash(options)
assert_nil options[:only]
assert_equal :name, options[:except]
end
- test "as_json should return a hash" do
+ test "as_json should return a hash if include_root_in_json is true" do
+ Contact.include_root_in_json = true
json = @contact.as_json
assert_kind_of Hash, json
@@ -158,7 +156,7 @@ class JsonSerializationTest < ActiveModel::TestCase
end
end
- test "from_json should set the object's attributes" do
+ test "from_json should work without a root (class attribute)" do
json = @contact.to_json
result = Contact.new.from_json(json)
@@ -170,7 +168,7 @@ class JsonSerializationTest < ActiveModel::TestCase
end
test "from_json should work without a root (method parameter)" do
- json = @contact.to_json(:root => false)
+ json = @contact.to_json
result = Contact.new.from_json(json, false)
assert_equal result.name, @contact.name
@@ -180,24 +178,19 @@ class JsonSerializationTest < ActiveModel::TestCase
assert_equal result.preferences, @contact.preferences
end
- test "from_json should work without a root (class attribute)" do
- begin
- Contact.include_root_in_json = false
- json = @contact.to_json
- result = Contact.new.from_json(json)
-
- assert_equal result.name, @contact.name
- assert_equal result.age, @contact.age
- assert_equal Time.parse(result.created_at), @contact.created_at
- assert_equal result.awesome, @contact.awesome
- assert_equal result.preferences, @contact.preferences
- ensure
- Contact.include_root_in_json = true
- end
+ test "from_json should work with a root (method parameter)" do
+ json = @contact.to_json(root: :true)
+ result = Contact.new.from_json(json, true)
+
+ assert_equal result.name, @contact.name
+ assert_equal result.age, @contact.age
+ assert_equal Time.parse(result.created_at), @contact.created_at
+ assert_equal result.awesome, @contact.awesome
+ assert_equal result.preferences, @contact.preferences
end
test "custom as_json should be honored when generating json" do
- def @contact.as_json(options); { :name => name, :created_at => created_at }; end
+ def @contact.as_json(options); { name: name, created_at: created_at }; end
json = @contact.to_json
assert_match %r{"name":"Konata Izumi"}, json
@@ -207,7 +200,7 @@ class JsonSerializationTest < ActiveModel::TestCase
end
test "custom as_json options should be extendible" do
- def @contact.as_json(options = {}); super(options.merge(:only => [:name])); end
+ def @contact.as_json(options = {}); super(options.merge(only: [:name])); end
json = @contact.to_json
assert_match %r{"name":"Konata Izumi"}, json
@@ -215,5 +208,4 @@ class JsonSerializationTest < ActiveModel::TestCase
assert_no_match %r{"awesome":}, json
assert_no_match %r{"preferences":}, json
end
-
end
diff --git a/activemodel/test/cases/serializers/xml_serialization_test.rb b/activemodel/test/cases/serializers/xml_serialization_test.rb
index fc73d9dcd8..8c5a3c5efd 100644..100755
--- a/activemodel/test/cases/serializers/xml_serialization_test.rb
+++ b/activemodel/test/cases/serializers/xml_serialization_test.rb
@@ -9,6 +9,8 @@ class Contact
attr_accessor :address, :friends
+ remove_method :attributes if method_defined?(:attributes)
+
def attributes
instance_values.except("address", "friends")
end
@@ -26,7 +28,7 @@ class Address
extend ActiveModel::Naming
include ActiveModel::Serializers::Xml
- attr_accessor :street, :city, :state, :zip
+ attr_accessor :street, :city, :state, :zip, :apt_number
def attributes
instance_values
@@ -54,6 +56,7 @@ class XmlSerializationTest < ActiveModel::TestCase
@contact.address.city = "Springfield"
@contact.address.state = "CA"
@contact.address.zip = 11111
+ @contact.address.apt_number = 35
@contact.friends = [Contact.new, Contact.new]
end
@@ -102,7 +105,7 @@ class XmlSerializationTest < ActiveModel::TestCase
assert_match %r{<createdAt}, @xml
end
- test "should use serialiable hash" do
+ test "should use serializable hash" do
@contact = SerializableContact.new
@contact.name = 'aaron stack'
@contact.age = 25
@@ -138,7 +141,7 @@ class XmlSerializationTest < ActiveModel::TestCase
end
test "should serialize datetime" do
- assert_match %r{<created-at type=\"datetime\">2006-08-01T00:00:00Z</created-at>}, @contact.to_xml
+ assert_match %r{<created-at type=\"dateTime\">2006-08-01T00:00:00Z</created-at>}, @contact.to_xml
end
test "should serialize boolean" do
@@ -186,6 +189,23 @@ class XmlSerializationTest < ActiveModel::TestCase
assert_match %r{<friend type="Contact">}, xml
end
+ class FriendList
+ def initialize(friends)
+ @friends = friends
+ end
+
+ def to_ary
+ @friends
+ end
+ end
+
+ test "include option with ary" do
+ @contact.friends = FriendList.new(@contact.friends)
+ xml = @contact.to_xml :include => :friends, :indent => 0
+ assert_match %r{<friends type="array">}, xml
+ assert_match %r{<friend type="Contact">}, xml
+ end
+
test "multiple includes" do
xml = @contact.to_xml :indent => 0, :skip_instruct => true, :include => [ :address, :friends ]
assert xml.include?(@contact.address.to_xml(:indent => 0, :skip_instruct => true))
@@ -203,4 +223,39 @@ class XmlSerializationTest < ActiveModel::TestCase
assert_match %r{<friends>}, xml
assert_match %r{<friend>}, xml
end
+
+ test "propagates skip-types option to included associations and attributes" do
+ xml = @contact.to_xml :skip_types => true, :include => :address, :indent => 0
+ assert_match %r{<address>}, xml
+ assert_match %r{<apt-number>}, xml
+ end
+
+ test "propagates camelize option to included associations and attributes" do
+ xml = @contact.to_xml :camelize => true, :include => :address, :indent => 0
+ assert_match %r{<Address>}, xml
+ assert_match %r{<AptNumber type="integer">}, xml
+ end
+
+ test "propagates dasherize option to included associations and attributes" do
+ xml = @contact.to_xml :dasherize => false, :include => :address, :indent => 0
+ assert_match %r{<apt_number type="integer">}, xml
+ end
+
+ test "don't propagate skip_types if skip_types is defined at the included association level" do
+ xml = @contact.to_xml :skip_types => true, :include => { :address => { :skip_types => false } }, :indent => 0
+ assert_match %r{<address>}, xml
+ assert_match %r{<apt-number type="integer">}, xml
+ end
+
+ test "don't propagate camelize if camelize is defined at the included association level" do
+ xml = @contact.to_xml :camelize => true, :include => { :address => { :camelize => false } }, :indent => 0
+ assert_match %r{<address>}, xml
+ assert_match %r{<apt-number type="integer">}, xml
+ end
+
+ test "don't propagate dasherize if dasherize is defined at the included association level" do
+ xml = @contact.to_xml :dasherize => false, :include => { :address => { :dasherize => true } }, :indent => 0
+ assert_match %r{<address>}, xml
+ assert_match %r{<apt-number type="integer">}, xml
+ end
end
diff --git a/activemodel/test/cases/translation_test.rb b/activemodel/test/cases/translation_test.rb
index 1b1d972d5c..fd833cdd06 100644
--- a/activemodel/test/cases/translation_test.rb
+++ b/activemodel/test/cases/translation_test.rb
@@ -56,6 +56,21 @@ class ActiveModelI18nTests < ActiveModel::TestCase
assert_equal 'person gender attribute', Person::Gender.human_attribute_name('attribute')
end
+ def test_translated_deeply_nested_model_attributes
+ I18n.backend.store_translations 'en', :activemodel => {:attributes => {:"person/contacts/addresses" => {:street => 'Deeply Nested Address Street'}}}
+ assert_equal 'Deeply Nested Address Street', Person.human_attribute_name('contacts.addresses.street')
+ end
+
+ def test_translated_nested_model_attributes
+ I18n.backend.store_translations 'en', :activemodel => {:attributes => {:"person/addresses" => {:street => 'Person Address Street'}}}
+ assert_equal 'Person Address Street', Person.human_attribute_name('addresses.street')
+ end
+
+ def test_translated_nested_model_attributes_with_namespace_fallback
+ I18n.backend.store_translations 'en', :activemodel => {:attributes => {:addresses => {:street => 'Cool Address Street'}}}
+ assert_equal 'Cool Address Street', Person.human_attribute_name('addresses.street')
+ end
+
def test_translated_model_names
I18n.backend.store_translations 'en', :activemodel => {:models => {:person => 'person model'} }
assert_equal 'person model', Person.model_name.human
@@ -72,9 +87,15 @@ class ActiveModelI18nTests < ActiveModel::TestCase
end
def test_human_does_not_modify_options
- options = {:default => 'person model'}
+ options = { :default => 'person model' }
Person.model_name.human(options)
- assert_equal({:default => 'person model'}, options)
+ assert_equal({ :default => 'person model' }, options)
+ end
+
+ def test_human_attribute_name_does_not_modify_options
+ options = { :default => 'Cool gender' }
+ Person.human_attribute_name('gender', options)
+ assert_equal({ :default => 'Cool gender' }, options)
end
end
diff --git a/activemodel/test/cases/validations/callbacks_test.rb b/activemodel/test/cases/validations/callbacks_test.rb
index 1cf09758f9..0015b3c196 100644
--- a/activemodel/test/cases/validations/callbacks_test.rb
+++ b/activemodel/test/cases/validations/callbacks_test.rb
@@ -5,11 +5,10 @@ class Dog
include ActiveModel::Validations
include ActiveModel::Validations::Callbacks
- attr_accessor :name
- attr_writer :history
+ attr_accessor :name, :history
- def history
- @history ||= []
+ def initialize
+ @history = []
end
end
@@ -21,7 +20,7 @@ class DogWithMethodCallbacks < Dog
def set_after_validation_marker; self.history << 'after_validation_marker' ; end
end
-class DogValidtorsAreProc < Dog
+class DogValidatorsAreProc < Dog
before_validation { self.history << 'before_validation_marker' }
after_validation { self.history << 'after_validation_marker' }
end
@@ -50,7 +49,7 @@ class CallbacksWithMethodNamesShouldBeCalled < ActiveModel::TestCase
end
def test_before_validation_and_after_validation_callbacks_should_be_called_with_proc
- d = DogValidtorsAreProc.new
+ d = DogValidatorsAreProc.new
d.valid?
assert_equal ['before_validation_marker', 'after_validation_marker'], d.history
end
diff --git a/activemodel/test/cases/validations/confirmation_validation_test.rb b/activemodel/test/cases/validations/confirmation_validation_test.rb
index d0418170fa..f7556a249f 100644
--- a/activemodel/test/cases/validations/confirmation_validation_test.rb
+++ b/activemodel/test/cases/validations/confirmation_validation_test.rb
@@ -44,7 +44,7 @@ class ConfirmationValidationTest < ActiveModel::TestCase
p.karma_confirmation = "None"
assert p.invalid?
- assert_equal ["doesn't match confirmation"], p.errors[:karma]
+ assert_equal ["doesn't match Karma"], p.errors[:karma_confirmation]
p.karma = "None"
assert p.valid?
@@ -52,4 +52,23 @@ class ConfirmationValidationTest < ActiveModel::TestCase
Person.reset_callbacks(:validate)
end
+ def test_title_confirmation_with_i18n_attribute
+ @old_load_path, @old_backend = I18n.load_path.dup, I18n.backend
+ I18n.load_path.clear
+ I18n.backend = I18n::Backend::Simple.new
+ I18n.backend.store_translations('en', {
+ :errors => {:messages => {:confirmation => "doesn't match %{attribute}"}},
+ :activemodel => {:attributes => {:topic => {:title => 'Test Title'}}}
+ })
+
+ Topic.validates_confirmation_of(:title)
+
+ t = Topic.new("title" => "We should be confirmed","title_confirmation" => "")
+ assert t.invalid?
+ assert_equal ["doesn't match Test Title"], t.errors[:title_confirmation]
+
+ I18n.load_path.replace @old_load_path
+ I18n.backend = @old_backend
+ end
+
end
diff --git a/activemodel/test/cases/validations/exclusion_validation_test.rb b/activemodel/test/cases/validations/exclusion_validation_test.rb
index 72a383f128..baccf72ecb 100644
--- a/activemodel/test/cases/validations/exclusion_validation_test.rb
+++ b/activemodel/test/cases/validations/exclusion_validation_test.rb
@@ -28,6 +28,16 @@ class ExclusionValidationTest < ActiveModel::TestCase
assert_equal ["option monkey is restricted"], t.errors[:title]
end
+ def test_validates_exclusion_of_with_within_option
+ Topic.validates_exclusion_of( :title, :within => %w( abe monkey ) )
+
+ assert Topic.new("title" => "something", "content" => "abc")
+
+ t = Topic.new("title" => "monkey")
+ assert t.invalid?
+ assert t.errors[:title].any?
+ end
+
def test_validates_exclusion_of_for_ruby_class
Person.validates_exclusion_of :karma, :in => %w( abe monkey )
@@ -46,12 +56,12 @@ class ExclusionValidationTest < ActiveModel::TestCase
def test_validates_exclusion_of_with_lambda
Topic.validates_exclusion_of :title, :in => lambda{ |topic| topic.author_name == "sikachu" ? %w( monkey elephant ) : %w( abe wasabi ) }
- p = Topic.new
- p.title = "elephant"
- p.author_name = "sikachu"
- assert p.invalid?
+ t = Topic.new
+ t.title = "elephant"
+ t.author_name = "sikachu"
+ assert t.invalid?
- p.title = "wasabi"
- assert p.valid?
+ t.title = "wasabi"
+ assert t.valid?
end
end
diff --git a/activemodel/test/cases/validations/format_validation_test.rb b/activemodel/test/cases/validations/format_validation_test.rb
index 2ce714fef0..308a3c6cef 100644
--- a/activemodel/test/cases/validations/format_validation_test.rb
+++ b/activemodel/test/cases/validations/format_validation_test.rb
@@ -11,7 +11,7 @@ class PresenceValidationTest < ActiveModel::TestCase
end
def test_validate_format
- Topic.validates_format_of(:title, :content, :with => /^Validation\smacros \w+!$/, :message => "is bad data")
+ Topic.validates_format_of(:title, :content, :with => /\AValidation\smacros \w+!\z/, :message => "is bad data")
t = Topic.new("title" => "i'm incorrect", "content" => "Validation macros rule!")
assert t.invalid?, "Shouldn't be valid"
@@ -27,7 +27,7 @@ class PresenceValidationTest < ActiveModel::TestCase
end
def test_validate_format_with_allow_blank
- Topic.validates_format_of(:title, :with => /^Validation\smacros \w+!$/, :allow_blank => true)
+ Topic.validates_format_of(:title, :with => /\AValidation\smacros \w+!\z/, :allow_blank => true)
assert Topic.new("title" => "Shouldn't be valid").invalid?
assert Topic.new("title" => "").valid?
assert Topic.new("title" => nil).valid?
@@ -36,7 +36,7 @@ class PresenceValidationTest < ActiveModel::TestCase
# testing ticket #3142
def test_validate_format_numeric
- Topic.validates_format_of(:title, :content, :with => /^[1-9][0-9]*$/, :message => "is bad data")
+ Topic.validates_format_of(:title, :content, :with => /\A[1-9][0-9]*\z/, :message => "is bad data")
t = Topic.new("title" => "72x", "content" => "6789")
assert t.invalid?, "Shouldn't be valid"
@@ -63,11 +63,21 @@ class PresenceValidationTest < ActiveModel::TestCase
end
def test_validate_format_with_formatted_message
- Topic.validates_format_of(:title, :with => /^Valid Title$/, :message => "can't be %{value}")
+ Topic.validates_format_of(:title, :with => /\AValid Title\z/, :message => "can't be %{value}")
t = Topic.new(:title => 'Invalid title')
assert t.invalid?
assert_equal ["can't be Invalid title"], t.errors[:title]
end
+
+ def test_validate_format_of_with_multiline_regexp_should_raise_error
+ assert_raise(ArgumentError) { Topic.validates_format_of(:title, :with => /^Valid Title$/) }
+ end
+
+ def test_validate_format_of_with_multiline_regexp_and_option
+ assert_nothing_raised(ArgumentError) do
+ Topic.validates_format_of(:title, :with => /^Valid Title$/, :multiline => true)
+ end
+ end
def test_validate_format_with_not_option
Topic.validates_format_of(:title, :without => /foo/, :message => "should not contain foo")
@@ -101,25 +111,25 @@ class PresenceValidationTest < ActiveModel::TestCase
def test_validates_format_of_with_lambda
Topic.validates_format_of :content, :with => lambda{ |topic| topic.title == "digit" ? /\A\d+\Z/ : /\A\S+\Z/ }
- p = Topic.new
- p.title = "digit"
- p.content = "Pixies"
- assert p.invalid?
+ t = Topic.new
+ t.title = "digit"
+ t.content = "Pixies"
+ assert t.invalid?
- p.content = "1234"
- assert p.valid?
+ t.content = "1234"
+ assert t.valid?
end
def test_validates_format_of_without_lambda
Topic.validates_format_of :content, :without => lambda{ |topic| topic.title == "characters" ? /\A\d+\Z/ : /\A\S+\Z/ }
- p = Topic.new
- p.title = "characters"
- p.content = "1234"
- assert p.invalid?
+ t = Topic.new
+ t.title = "characters"
+ t.content = "1234"
+ assert t.invalid?
- p.content = "Pixies"
- assert p.valid?
+ t.content = "Pixies"
+ assert t.valid?
end
def test_validates_format_of_for_ruby_class
diff --git a/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb b/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb
index 0679e67f84..df0fcd243a 100644
--- a/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb
+++ b/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb
@@ -37,7 +37,7 @@ class I18nGenerateMessageValidationTest < ActiveModel::TestCase
# validates_confirmation_of: generate_message(attr_name, :confirmation, :message => custom_message)
def test_generate_message_confirmation_with_default_message
- assert_equal "doesn't match confirmation", @person.errors.generate_message(:title, :confirmation)
+ assert_equal "doesn't match Title", @person.errors.generate_message(:title, :confirmation)
end
def test_generate_message_confirmation_with_custom_message
diff --git a/activemodel/test/cases/validations/i18n_validation_test.rb b/activemodel/test/cases/validations/i18n_validation_test.rb
index e9f0e430fe..4f8b7327c0 100644
--- a/activemodel/test/cases/validations/i18n_validation_test.rb
+++ b/activemodel/test/cases/validations/i18n_validation_test.rb
@@ -81,7 +81,7 @@ class I18nValidationTest < ActiveModel::TestCase
test "validates_confirmation_of on generated message #{name}" do
Person.validates_confirmation_of :title, validation_options
@person.title_confirmation = 'foo'
- @person.errors.expects(:generate_message).with(:title, :confirmation, generate_message_options)
+ @person.errors.expects(:generate_message).with(:title_confirmation, :confirmation, generate_message_options.merge(:attribute => 'Title'))
@person.valid?
end
end
@@ -141,7 +141,7 @@ class I18nValidationTest < ActiveModel::TestCase
COMMON_CASES.each do |name, validation_options, generate_message_options|
test "validates_format_of on generated message #{name}" do
- Person.validates_format_of :title, validation_options.merge(:with => /^[1-9][0-9]*$/)
+ Person.validates_format_of :title, validation_options.merge(:with => /\A[1-9][0-9]*\z/)
@person.title = '72x'
@person.errors.expects(:generate_message).with(:title, :invalid, generate_message_options.merge(:value => '72x'))
@person.valid?
@@ -159,6 +159,17 @@ class I18nValidationTest < ActiveModel::TestCase
end
end
+ # validates_inclusion_of using :within w/ mocha
+
+ COMMON_CASES.each do |name, validation_options, generate_message_options|
+ test "validates_inclusion_of using :within on generated message #{name}" do
+ Person.validates_inclusion_of :title, validation_options.merge(:within => %w(a b c))
+ @person.title = 'z'
+ @person.errors.expects(:generate_message).with(:title, :inclusion, generate_message_options.merge(:value => 'z'))
+ @person.valid?
+ end
+ end
+
# validates_exclusion_of w/ mocha
COMMON_CASES.each do |name, validation_options, generate_message_options|
@@ -170,6 +181,17 @@ class I18nValidationTest < ActiveModel::TestCase
end
end
+ # validates_exclusion_of using :within w/ mocha
+
+ COMMON_CASES.each do |name, validation_options, generate_message_options|
+ test "validates_exclusion_of using :within generated message #{name}" do
+ Person.validates_exclusion_of :title, validation_options.merge(:within => %w(a b c))
+ @person.title = 'a'
+ @person.errors.expects(:generate_message).with(:title, :exclusion, generate_message_options.merge(:value => 'a'))
+ @person.valid?
+ end
+ end
+
# validates_numericality_of without :only_integer w/ mocha
COMMON_CASES.each do |name, validation_options, generate_message_options|
@@ -217,24 +239,29 @@ class I18nValidationTest < ActiveModel::TestCase
# To make things DRY this macro is defined to define 3 tests for every validation case.
def self.set_expectations_for_validation(validation, error_type, &block_that_sets_validation)
+ if error_type == :confirmation
+ attribute = :title_confirmation
+ else
+ attribute = :title
+ end
# test "validates_confirmation_of finds custom model key translation when blank"
test "#{validation} finds custom model key translation when #{error_type}" do
- I18n.backend.store_translations 'en', :activemodel => {:errors => {:models => {:person => {:attributes => {:title => {error_type => 'custom message'}}}}}}
+ I18n.backend.store_translations 'en', :activemodel => {:errors => {:models => {:person => {:attributes => {attribute => {error_type => 'custom message'}}}}}}
I18n.backend.store_translations 'en', :errors => {:messages => {error_type => 'global message'}}
yield(@person, {})
@person.valid?
- assert_equal ['custom message'], @person.errors[:title]
+ assert_equal ['custom message'], @person.errors[attribute]
end
# test "validates_confirmation_of finds custom model key translation with interpolation when blank"
test "#{validation} finds custom model key translation with interpolation when #{error_type}" do
- I18n.backend.store_translations 'en', :activemodel => {:errors => {:models => {:person => {:attributes => {:title => {error_type => 'custom message with %{extra}'}}}}}}
+ I18n.backend.store_translations 'en', :activemodel => {:errors => {:models => {:person => {:attributes => {attribute => {error_type => 'custom message with %{extra}'}}}}}}
I18n.backend.store_translations 'en', :errors => {:messages => {error_type => 'global message'}}
yield(@person, {:extra => "extra information"})
@person.valid?
- assert_equal ['custom message with extra information'], @person.errors[:title]
+ assert_equal ['custom message with extra information'], @person.errors[attribute]
end
# test "validates_confirmation_of finds global default key translation when blank"
@@ -243,7 +270,7 @@ class I18nValidationTest < ActiveModel::TestCase
yield(@person, {})
@person.valid?
- assert_equal ['global message'], @person.errors[:title]
+ assert_equal ['global message'], @person.errors[attribute]
end
end
@@ -286,7 +313,7 @@ class I18nValidationTest < ActiveModel::TestCase
# validates_format_of w/o mocha
set_expectations_for_validation "validates_format_of", :invalid do |person, options_to_merge|
- Person.validates_format_of :title, options_to_merge.merge(:with => /^[1-9][0-9]*$/)
+ Person.validates_format_of :title, options_to_merge.merge(:with => /\A[1-9][0-9]*\z/)
end
# validates_inclusion_of w/o mocha
diff --git a/activemodel/test/cases/validations/inclusion_validation_test.rb b/activemodel/test/cases/validations/inclusion_validation_test.rb
index 413da92de4..c57fa75faf 100644
--- a/activemodel/test/cases/validations/inclusion_validation_test.rb
+++ b/activemodel/test/cases/validations/inclusion_validation_test.rb
@@ -60,6 +60,16 @@ class InclusionValidationTest < ActiveModel::TestCase
assert_equal ["option uhoh is not in the list"], t.errors[:title]
end
+ def test_validates_inclusion_of_with_within_option
+ Topic.validates_inclusion_of( :title, :within => %w( a b c d e f g ) )
+
+ assert Topic.new("title" => "a", "content" => "abc").valid?
+
+ t = Topic.new("title" => "uhoh", "content" => "abc")
+ assert t.invalid?
+ assert t.errors[:title].any?
+ end
+
def test_validates_inclusion_of_for_ruby_class
Person.validates_inclusion_of :karma, :in => %w( abe monkey )
@@ -78,12 +88,12 @@ class InclusionValidationTest < ActiveModel::TestCase
def test_validates_inclusion_of_with_lambda
Topic.validates_inclusion_of :title, :in => lambda{ |topic| topic.author_name == "sikachu" ? %w( monkey elephant ) : %w( abe wasabi ) }
- p = Topic.new
- p.title = "wasabi"
- p.author_name = "sikachu"
- assert p.invalid?
+ t = Topic.new
+ t.title = "wasabi"
+ t.author_name = "sikachu"
+ assert t.invalid?
- p.title = "elephant"
- assert p.valid?
+ t.title = "elephant"
+ assert t.valid?
end
end
diff --git a/activemodel/test/cases/validations/length_validation_test.rb b/activemodel/test/cases/validations/length_validation_test.rb
index 44048a9c1d..113bfd6337 100644
--- a/activemodel/test/cases/validations/length_validation_test.rb
+++ b/activemodel/test/cases/validations/length_validation_test.rb
@@ -260,74 +260,64 @@ class LengthValidationTest < ActiveModel::TestCase
end
def test_validates_length_of_using_minimum_utf8
- with_kcode('UTF8') do
- Topic.validates_length_of :title, :minimum => 5
+ Topic.validates_length_of :title, :minimum => 5
- t = Topic.new("title" => "一二三四五", "content" => "whatever")
- assert t.valid?
+ t = Topic.new("title" => "一二三四五", "content" => "whatever")
+ assert t.valid?
- t.title = "一二三四"
- assert t.invalid?
- assert t.errors[:title].any?
- assert_equal ["is too short (minimum is 5 characters)"], t.errors["title"]
- end
+ t.title = "一二三四"
+ assert t.invalid?
+ assert t.errors[:title].any?
+ assert_equal ["is too short (minimum is 5 characters)"], t.errors["title"]
end
def test_validates_length_of_using_maximum_utf8
- with_kcode('UTF8') do
- Topic.validates_length_of :title, :maximum => 5
+ Topic.validates_length_of :title, :maximum => 5
- t = Topic.new("title" => "一二三四五", "content" => "whatever")
- assert t.valid?
+ t = Topic.new("title" => "一二三四五", "content" => "whatever")
+ assert t.valid?
- t.title = "一二34五六"
- assert t.invalid?
- assert t.errors[:title].any?
- assert_equal ["is too long (maximum is 5 characters)"], t.errors["title"]
- end
+ t.title = "一二34五六"
+ assert t.invalid?
+ assert t.errors[:title].any?
+ assert_equal ["is too long (maximum is 5 characters)"], t.errors["title"]
end
def test_validates_length_of_using_within_utf8
- with_kcode('UTF8') do
- Topic.validates_length_of(:title, :content, :within => 3..5)
-
- t = Topic.new("title" => "一二", "content" => "12三四五六七")
- assert t.invalid?
- assert_equal ["is too short (minimum is 3 characters)"], t.errors[:title]
- assert_equal ["is too long (maximum is 5 characters)"], t.errors[:content]
- t.title = "一二三"
- t.content = "12三"
- assert t.valid?
- end
+ Topic.validates_length_of(:title, :content, :within => 3..5)
+
+ t = Topic.new("title" => "一二", "content" => "12三四五六七")
+ assert t.invalid?
+ assert_equal ["is too short (minimum is 3 characters)"], t.errors[:title]
+ assert_equal ["is too long (maximum is 5 characters)"], t.errors[:content]
+ t.title = "一二三"
+ t.content = "12三"
+ assert t.valid?
end
def test_optionally_validates_length_of_using_within_utf8
- with_kcode('UTF8') do
- Topic.validates_length_of :title, :within => 3..5, :allow_nil => true
+ Topic.validates_length_of :title, :within => 3..5, :allow_nil => true
- t = Topic.new(:title => "一二三四五")
- assert t.valid?, t.errors.inspect
+ t = Topic.new(:title => "一二三四五")
+ assert t.valid?, t.errors.inspect
- t = Topic.new(:title => "一二三")
- assert t.valid?, t.errors.inspect
+ t = Topic.new(:title => "一二三")
+ assert t.valid?, t.errors.inspect
- t.title = nil
- assert t.valid?, t.errors.inspect
- end
+ t.title = nil
+ assert t.valid?, t.errors.inspect
end
def test_validates_length_of_using_is_utf8
- with_kcode('UTF8') do
- Topic.validates_length_of :title, :is => 5
+ Topic.validates_length_of :title, :is => 5
- t = Topic.new("title" => "一二345", "content" => "whatever")
- assert t.valid?
+ t = Topic.new("title" => "一二345", "content" => "whatever")
+ assert t.valid?
- t.title = "一二345六"
- assert t.invalid?
- assert t.errors[:title].any?
- assert_equal ["is the wrong length (should be 5 characters)"], t.errors["title"]
- end
+ t.title = "一二345六"
+ assert t.invalid?
+ assert t.errors[:title].any?
+ assert_equal ["is the wrong length (should be 5 characters)"], t.errors["title"]
end
def test_validates_length_of_with_block
@@ -367,4 +357,22 @@ class LengthValidationTest < ActiveModel::TestCase
ensure
Person.reset_callbacks(:validate)
end
+
+ def test_validates_length_of_for_infinite_maxima
+ Topic.validates_length_of(:title, :within => 5..Float::INFINITY)
+
+ t = Topic.new("title" => "1234")
+ assert t.invalid?
+ assert t.errors[:title].any?
+
+ t.title = "12345"
+ assert t.valid?
+
+ Topic.validates_length_of(:author_name, :maximum => Float::INFINITY)
+
+ assert t.valid?
+
+ t.author_name = "A very long author name that should still be valid." * 100
+ assert t.valid?
+ end
end
diff --git a/activemodel/test/cases/validations/numericality_validation_test.rb b/activemodel/test/cases/validations/numericality_validation_test.rb
index 08f6169ca5..6742a4bab0 100644
--- a/activemodel/test/cases/validations/numericality_validation_test.rb
+++ b/activemodel/test/cases/validations/numericality_validation_test.rb
@@ -106,6 +106,13 @@ class NumericalityValidationTest < ActiveModel::TestCase
valid!([2])
end
+ def test_validates_numericality_with_other_than
+ Topic.validates_numericality_of :approved, :other_than => 0
+
+ invalid!([0, 0.0])
+ valid!([-1, 42])
+ end
+
def test_validates_numericality_with_proc
Topic.send(:define_method, :min_approved, lambda { 5 })
Topic.validates_numericality_of :approved, :greater_than_or_equal_to => Proc.new {|topic| topic.min_approved }
diff --git a/activemodel/test/cases/validations/validates_test.rb b/activemodel/test/cases/validations/validates_test.rb
index 779f6c8448..90bc018ae1 100644
--- a/activemodel/test/cases/validations/validates_test.rb
+++ b/activemodel/test/cases/validations/validates_test.rb
@@ -16,6 +16,12 @@ class ValidatesTest < ActiveModel::TestCase
PersonWithValidator.reset_callbacks(:validate)
end
+ def test_validates_with_messages_empty
+ Person.validates :title, :presence => {:message => "" }
+ person = Person.new
+ assert !person.valid?, 'person should not be valid.'
+ end
+
def test_validates_with_built_in_validation
Person.validates :title, :numericality => true
person = Person.new
@@ -148,6 +154,6 @@ class ValidatesTest < ActiveModel::TestCase
topic.title = "What's happening"
topic.title_confirmation = "Not this"
assert !topic.valid?
- assert_equal ['Y U NO CONFIRM'], topic.errors[:title]
+ assert_equal ['Y U NO CONFIRM'], topic.errors[:title_confirmation]
end
end
diff --git a/activemodel/test/cases/validations_test.rb b/activemodel/test/cases/validations_test.rb
index 2f4376bd41..a9d32808da 100644
--- a/activemodel/test/cases/validations_test.rb
+++ b/activemodel/test/cases/validations_test.rb
@@ -11,6 +11,8 @@ require 'active_support/xml_mini'
class ValidationsTest < ActiveModel::TestCase
+ class CustomStrictValidationException < StandardError; end
+
def setup
Topic._validators.clear
end
@@ -58,8 +60,7 @@ class ValidationsTest < ActiveModel::TestCase
r = Reply.new
r.valid?
- errors = []
- r.errors.each {|attr, messages| errors << [attr.to_s, messages] }
+ errors = r.errors.collect {|attr, messages| [attr.to_s, messages]}
assert errors.include?(["title", "is Empty"])
assert errors.include?(["content", "is Empty"])
@@ -181,7 +182,7 @@ class ValidationsTest < ActiveModel::TestCase
assert_match %r{<error>Title can't be blank</error>}, xml
assert_match %r{<error>Content can't be blank</error>}, xml
- hash = ActiveSupport::OrderedHash.new
+ hash = {}
hash[:title] = ["can't be blank"]
hash[:content] = ["can't be blank"]
assert_equal t.errors.to_json, hash.to_json
@@ -311,7 +312,7 @@ class ValidationsTest < ActiveModel::TestCase
end
def test_strict_validation_particular_validator
- Topic.validates :title, :presence => {:strict => true}
+ Topic.validates :title, :presence => { :strict => true }
assert_raises ActiveModel::StrictValidationFailed do
Topic.new.valid?
end
@@ -324,10 +325,52 @@ class ValidationsTest < ActiveModel::TestCase
end
end
+ def test_strict_validation_custom_exception
+ Topic.validates_presence_of :title, :strict => CustomStrictValidationException
+ assert_raises CustomStrictValidationException do
+ Topic.new.valid?
+ end
+ end
+
def test_validates_with_bang
Topic.validates! :title, :presence => true
assert_raises ActiveModel::StrictValidationFailed do
Topic.new.valid?
end
end
+
+ def test_validates_with_false_hash_value
+ Topic.validates :title, :presence => false
+ assert Topic.new.valid?
+ end
+
+ def test_strict_validation_error_message
+ Topic.validates :title, :strict => true, :presence => true
+
+ exception = assert_raises(ActiveModel::StrictValidationFailed) do
+ Topic.new.valid?
+ end
+ assert_equal "Title can't be blank", exception.message
+ end
+
+ def test_does_not_modify_options_argument
+ options = { :presence => true }
+ Topic.validates :title, options
+ assert_equal({ :presence => true }, options)
+ end
+
+ def test_dup_validity_is_independent
+ Topic.validates_presence_of :title
+ topic = Topic.new("title" => "Litterature")
+ topic.valid?
+
+ duped = topic.dup
+ duped.title = nil
+ assert duped.invalid?
+
+ topic.title = nil
+ duped.title = 'Mathematics'
+ assert topic.invalid?
+ assert duped.valid?
+ end
end
diff --git a/activemodel/test/models/administrator.rb b/activemodel/test/models/administrator.rb
index a48f8b064f..2d6d34b3e2 100644
--- a/activemodel/test/models/administrator.rb
+++ b/activemodel/test/models/administrator.rb
@@ -1,7 +1,10 @@
class Administrator
+ extend ActiveModel::Callbacks
include ActiveModel::Validations
include ActiveModel::SecurePassword
include ActiveModel::MassAssignmentSecurity
+
+ define_model_callbacks :create
attr_accessor :name, :password_digest
attr_accessible :name
diff --git a/activemodel/test/models/blog_post.rb b/activemodel/test/models/blog_post.rb
index d289177259..46eba857df 100644
--- a/activemodel/test/models/blog_post.rb
+++ b/activemodel/test/models/blog_post.rb
@@ -1,10 +1,6 @@
module Blog
- def self._railtie
- Object.new
- end
-
- def self.table_name_prefix
- "blog_"
+ def self.use_relative_model_naming?
+ true
end
class Post
diff --git a/activemodel/test/models/oauthed_user.rb b/activemodel/test/models/oauthed_user.rb
new file mode 100644
index 0000000000..9750bc19d4
--- /dev/null
+++ b/activemodel/test/models/oauthed_user.rb
@@ -0,0 +1,11 @@
+class OauthedUser
+ extend ActiveModel::Callbacks
+ include ActiveModel::Validations
+ include ActiveModel::SecurePassword
+
+ define_model_callbacks :create
+
+ has_secure_password(validations: false)
+
+ attr_accessor :password_digest, :password_salt
+end
diff --git a/activemodel/test/models/user.rb b/activemodel/test/models/user.rb
index e221bb8091..4b11df12bf 100644
--- a/activemodel/test/models/user.rb
+++ b/activemodel/test/models/user.rb
@@ -1,6 +1,9 @@
class User
+ extend ActiveModel::Callbacks
include ActiveModel::Validations
include ActiveModel::SecurePassword
+
+ define_model_callbacks :create
has_secure_password
diff --git a/activemodel/test/models/visitor.rb b/activemodel/test/models/visitor.rb
index 36c0a16688..d15f448516 100644
--- a/activemodel/test/models/visitor.rb
+++ b/activemodel/test/models/visitor.rb
@@ -1,9 +1,12 @@
class Visitor
+ extend ActiveModel::Callbacks
include ActiveModel::Validations
include ActiveModel::SecurePassword
include ActiveModel::MassAssignmentSecurity
+
+ define_model_callbacks :create
- has_secure_password
+ has_secure_password(validations: false)
- attr_accessor :password_digest
+ attr_accessor :password_digest, :password_confirmation
end