aboutsummaryrefslogtreecommitdiffstats
path: root/activemodel/test/cases/validations/with_validation_test.rb
blob: 92df4dd6cdb1524af8d062a7493f6d6131afd794 (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
# encoding: utf-8
require 'cases/helper'
require 'cases/tests_database'

require 'models/topic'

class ValidatesWithTest < ActiveRecord::TestCase
  include ActiveModel::TestsDatabase

  def teardown
    Topic.reset_callbacks(:validate)
    Topic._validators.clear
  end

  ERROR_MESSAGE = "Validation error from validator"
  OTHER_ERROR_MESSAGE = "Validation error from other validator"

  class ValidatorThatAddsErrors < ActiveModel::Validator
    def validate(record)
      record.errors[:base] << ERROR_MESSAGE
    end
  end

  class OtherValidatorThatAddsErrors < ActiveModel::Validator
    def validate(record)
      record.errors[:base] << OTHER_ERROR_MESSAGE
    end
  end

  class ValidatorThatDoesNotAddErrors < ActiveModel::Validator
    def validate(record)
    end
  end

  class ValidatorThatValidatesOptions < ActiveModel::Validator
    def validate(record)
      if options[:field] == :first_name
        record.errors[:base] << ERROR_MESSAGE
      end
    end
  end

  class ValidatorPerEachAttribute < ActiveModel::EachValidator
    def validate_each(record, attribute, value)
      record.errors[attribute] << "Value is #{value}"
    end
  end

  class ValidatorCheckValidity < ActiveModel::EachValidator
    def check_validity!
      raise "boom!"
    end
  end

  test "vaidation with class that adds errors" do
    Topic.validates_with(ValidatorThatAddsErrors)
    topic = Topic.new
    assert !topic.valid?, "A class that adds errors causes the record to be invalid"
    assert topic.errors[:base].include?(ERROR_MESSAGE)
  end

  test "with a class that returns valid" do
    Topic.validates_with(ValidatorThatDoesNotAddErrors)
    topic = Topic.new
    assert topic.valid?, "A class that does not add errors does not cause the record to be invalid"
  end

  test "with a class that adds errors on update and a new record" do
    Topic.validates_with(ValidatorThatAddsErrors, :on => :update)
    topic = Topic.new
    assert topic.valid?, "Validation doesn't run on create if 'on' is set to update"
  end

  test "with a class that adds errors on create and a new record" do
    Topic.validates_with(ValidatorThatAddsErrors, :on => :create)
    topic = Topic.new
    assert !topic.valid?, "Validation does run on create if 'on' is set to create"
    assert topic.errors[:base].include?(ERROR_MESSAGE)
  end

  test "with multiple classes" do
    Topic.validates_with(ValidatorThatAddsErrors, OtherValidatorThatAddsErrors)
    topic = Topic.new
    assert !topic.valid?
    assert topic.errors[:base].include?(ERROR_MESSAGE)
    assert topic.errors[:base].include?(OTHER_ERROR_MESSAGE)
  end

  test "with if statements that return false" do
    Topic.validates_with(ValidatorThatAddsErrors, :if => "1 == 2")
    topic = Topic.new
    assert topic.valid?
  end

  test "with if statements that return true" do
    Topic.validates_with(ValidatorThatAddsErrors, :if => "1 == 1")
    topic = Topic.new
    assert !topic.valid?
    assert topic.errors[:base].include?(ERROR_MESSAGE)
  end

  test "with unless statements that return true" do
    Topic.validates_with(ValidatorThatAddsErrors, :unless => "1 == 1")
    topic = Topic.new
    assert topic.valid?
  end

  test "with unless statements that returns false" do
    Topic.validates_with(ValidatorThatAddsErrors, :unless => "1 == 2")
    topic = Topic.new
    assert !topic.valid?
    assert topic.errors[:base].include?(ERROR_MESSAGE)
  end

  test "passes all configuration options to the validator class" do
    topic = Topic.new
    validator = mock()
    validator.expects(:new).with(:foo => :bar, :if => "1 == 1").returns(validator)
    validator.expects(:validate).with(topic)

    Topic.validates_with(validator, :if => "1 == 1", :foo => :bar)
    assert topic.valid?
  end
 
  test "calls setup method of validator passing in self when validator has setup method" do
    topic = Topic.new
    validator = stub_everything
    validator.stubs(:new).returns(validator)
    validator.stubs(:validate)
    validator.stubs(:respond_to?).with(:setup).returns(true)
    validator.expects(:setup).with(Topic).once
    Topic.validates_with(validator)
    assert topic.valid?
  end
  
  test "doesn't call setup method of validator when validator has no setup method" do
    topic = Topic.new
    validator = stub_everything
    validator.stubs(:new).returns(validator)
    validator.stubs(:validate)
    validator.stubs(:respond_to?).with(:setup).returns(false)
    validator.expects(:setup).with(Topic).never
    Topic.validates_with(validator)
    assert topic.valid?
  end

  test "validates_with with options" do
    Topic.validates_with(ValidatorThatValidatesOptions, :field => :first_name)
    topic = Topic.new
    assert !topic.valid?
    assert topic.errors[:base].include?(ERROR_MESSAGE)
  end

  test "validates_with each validator" do
    Topic.validates_with(ValidatorPerEachAttribute, :attributes => [:title, :content])
    topic = Topic.new :title => "Title", :content => "Content"
    assert !topic.valid?
    assert_equal ["Value is Title"], topic.errors[:title]
    assert_equal ["Value is Content"], topic.errors[:content]
  end

  test "each validator checks validity" do
    assert_raise RuntimeError do
      Topic.validates_with(ValidatorCheckValidity, :attributes => [:title])
    end
  end

  test "each validator expects attributes to be given" do
    assert_raise RuntimeError do
      Topic.validates_with(ValidatorPerEachAttribute)
    end
  end

  test "each validator skip nil values if :allow_nil is set to true" do
    Topic.validates_with(ValidatorPerEachAttribute, :attributes => [:title, :content], :allow_nil => true)
    topic = Topic.new :content => ""
    assert !topic.valid?
    assert topic.errors[:title].empty?
    assert_equal ["Value is "], topic.errors[:content]
  end

  test "each validator skip blank values if :allow_blank is set to true" do
    Topic.validates_with(ValidatorPerEachAttribute, :attributes => [:title, :content], :allow_blank => true)
    topic = Topic.new :content => ""
    assert topic.valid?
    assert topic.errors[:title].empty?
    assert topic.errors[:content].empty?
  end
end