aboutsummaryrefslogtreecommitdiffstats
path: root/activemodel/test/cases/error_test.rb
blob: d74321fee54627c81b8d6dda799815c11155827d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# frozen_string_literal: true

require "cases/helper"
require "active_model/error"

class ErrorTest < ActiveModel::TestCase
  class Person
    extend ActiveModel::Naming
    def initialize
      @errors = ActiveModel::Errors.new(self)
    end

    attr_accessor :name, :age
    attr_reader   :errors

    def read_attribute_for_validation(attr)
      send(attr)
    end

    def self.human_attribute_name(attr, options = {})
      attr
    end

    def self.lookup_ancestors
      [self]
    end
  end

  def test_initialize
    base = Person.new
    error = ActiveModel::Error.new(base, :name, :too_long, foo: :bar)
    assert_equal base, error.base
    assert_equal :name, error.attribute
    assert_equal :too_long, error.type
    assert_equal({ foo: :bar }, error.options)
  end

  test "initialize without type" do
    error = ActiveModel::Error.new(Person.new, :name)
    assert_equal :invalid, error.type
    assert_equal({}, error.options)
  end

  test "initialize without type but with options" do
    options = { message: "bar" }
    error = ActiveModel::Error.new(Person.new, :name, options)
    assert_equal(options, error.options)
  end

  # match?

  test "match? handles mixed condition" do
    subject = ActiveModel::Error.new(Person.new, :mineral, :not_enough, count: 2)
    assert_not subject.match?(:mineral, :too_coarse)
    assert subject.match?(:mineral, :not_enough)
    assert subject.match?(:mineral, :not_enough, count: 2)
    assert_not subject.match?(:mineral, :not_enough, count: 1)
  end

  test "match? handles attribute match" do
    subject = ActiveModel::Error.new(Person.new, :mineral, :not_enough, count: 2)
    assert_not subject.match?(:foo)
    assert subject.match?(:mineral)
  end

  test "match? handles error type match" do
    subject = ActiveModel::Error.new(Person.new, :mineral, :not_enough, count: 2)
    assert_not subject.match?(:mineral, :too_coarse)
    assert subject.match?(:mineral, :not_enough)
  end

  test "match? handles extra options match" do
    subject = ActiveModel::Error.new(Person.new, :mineral, :not_enough, count: 2)
    assert_not subject.match?(:mineral, :not_enough, count: 1)
    assert subject.match?(:mineral, :not_enough, count: 2)
  end

  # message

  test "message with type as a symbol" do
    error = ActiveModel::Error.new(Person.new, :name, :blank)
    assert_equal "can't be blank", error.message
  end

  test "message with custom interpolation" do
    subject = ActiveModel::Error.new(Person.new, :name, :inclusion, message: "custom message %{value}", value: "name")
    assert_equal "custom message name", subject.message
  end

  test "message returns plural interpolation" do
    subject = ActiveModel::Error.new(Person.new, :name, :too_long, count: 10)
    assert_equal "is too long (maximum is 10 characters)", subject.message
  end

  test "message returns singular interpolation" do
    subject = ActiveModel::Error.new(Person.new, :name, :too_long, count: 1)
    assert_equal "is too long (maximum is 1 character)", subject.message
  end

  test "message returns count interpolation" do
    subject = ActiveModel::Error.new(Person.new, :name, :too_long, message: "custom message %{count}", count: 10)
    assert_equal "custom message 10", subject.message
  end

  test "message handles lambda in messages and option values, and i18n interpolation" do
    subject = ActiveModel::Error.new(Person.new, :name, :invalid,
      foo: "foo",
      bar: "bar",
      baz: Proc.new { "baz" },
      message: Proc.new { |model, options|
        "%{attribute} %{foo} #{options[:bar]} %{baz}"
      }
    )
    assert_equal "name foo bar baz", subject.message
  end

  test "generate_message works without i18n_scope" do
    person = Person.new
    error = ActiveModel::Error.new(person, :name, :blank)
    assert_not_respond_to Person, :i18n_scope
    assert_nothing_raised {
      error.message
    }
  end

  test "message with type as custom message" do
    error = ActiveModel::Error.new(Person.new, :name, message: "cannot be blank")
    assert_equal "cannot be blank", error.message
  end

  test "message with options[:message] as custom message" do
    error = ActiveModel::Error.new(Person.new, :name, :blank, message: "cannot be blank")
    assert_equal "cannot be blank", error.message
  end

  test "message renders lazily using current locale" do
    error = nil

    I18n.backend.store_translations(:pl, errors: { messages: { invalid: "jest nieprawidłowe" } })

    I18n.with_locale(:en) { error = ActiveModel::Error.new(Person.new, :name, :invalid) }
    I18n.with_locale(:pl) {
      assert_equal "jest nieprawidłowe", error.message
    }
  end

  test "message uses current locale" do
    I18n.backend.store_translations(:en, errors: { messages: { inadequate: "Inadequate %{attribute} found!" } })
    error = ActiveModel::Error.new(Person.new, :name, :inadequate)
    assert_equal "Inadequate name found!", error.message
  end

  # full_message

  test "full_message returns the given message when attribute is :base" do
    error = ActiveModel::Error.new(Person.new, :base, message: "press the button")
    assert_equal "press the button", error.full_message
  end

  test "full_message returns the given message with the attribute name included" do
    error = ActiveModel::Error.new(Person.new, :name, :blank)
    assert_equal "name can't be blank", error.full_message
  end

  test "full_message uses default format" do
    error = ActiveModel::Error.new(Person.new, :name, message: "can't be blank")

    # Use a locale without errors.format
    I18n.with_locale(:unknown) {
      assert_equal "name can't be blank", error.full_message
    }
  end

  test "equality by base attribute, type and options" do
    person = Person.new

    e1 = ActiveModel::Error.new(person, :name, foo: :bar)
    e2 = ActiveModel::Error.new(person, :name, foo: :bar)
    e2.instance_variable_set(:@_humanized_attribute, "Name")

    assert_equal(e1, e2)
  end

  test "inequality" do
    person = Person.new
    error = ActiveModel::Error.new(person, :name, foo: :bar)

    assert error != ActiveModel::Error.new(person, :name, foo: :baz)
    assert error != ActiveModel::Error.new(person, :name)
    assert error != ActiveModel::Error.new(person, :title, foo: :bar)
    assert error != ActiveModel::Error.new(Person.new, :name, foo: :bar)
  end

  test "comparing against different class would not raise error" do
    person = Person.new
    error = ActiveModel::Error.new(person, :name, foo: :bar)

    assert error != person
  end
end