Class: NoBrainer::Matchers::Associations::HaveAssociationMatcher

Inherits:
Object
  • Object
show all
Defined in:
lib/matchers/associations.rb

Overview

The ‘belong_to` matcher is used to ensure that a `belongs_to` association exists on your model.

class Person
  include NoBrainer::Document

  belongs_to :organization
end

# RSpec
RSpec.describe Person, type: :model do
  it { is_expected.to belong_to(:organization) }
end

#### Qualifiers

##### class_name

Use ‘class_name` to test usage of the `:class_name` option. This asserts that the model you’re referring to actually exists.

class Person
  include NoBrainer::Document

  belongs_to :ancient_city, class_name: 'City'
end

# RSpec
RSpec.describe Person, type: :model do
  it { is_expected.to belong_to(:ancient_city).class_name('City') }
end

##### with_primary_key

Use ‘with_primary_key` to test usage of the `:primary_key` option.

class Person
  include NoBrainer::Document

  belongs_to :great_country, primary_key: 'country_id'
end

# RSpec
RSpec.describe Person, type: :model do
  it do
    is_expected.to belong_to(:great_country)
      .with_primary_key('country_id')
  end
end

##### with_foreign_key

Use ‘with_foreign_key` to test usage of the `:foreign_key` option.

class Person
  include NoBrainer::Document

  belongs_to :great_country, foreign_key: 'country_id'
end

# RSpec
RSpec.describe Person, type: :model do
  it do
    is_expected.to belong_to(:great_country)
      .with_foreign_key('country_id')
  end
end

##### with_dependent

Use ‘with_dependent` to assert that the `:dependent` option was specified.

class Person
  include NoBrainer::Document

  belongs_to :world, dependent: :destroy
end

# RSpec
RSpec.describe Person, type: :model do
  it { is_expected.to belong_to(:world).with_dependent(:destroy) }
end

##### required

Use ‘required` to assert that the association is not allowed to be nil.

class Person
  include NoBrainer::Document

  belongs_to :organization, required: true
end

# RSpec
describe Person
  it { is_expected.to belong_to(:organization).with_required(true) }
end

Instance Method Summary collapse

Constructor Details

#initialize(name, association_type) ⇒ HaveAssociationMatcher

Returns a new instance of HaveAssociationMatcher.



112
113
114
115
116
117
118
# File 'lib/matchers/associations.rb', line 112

def initialize(name, association_type)
  @association = {}
  @association[:name] = name.to_sym
  @association[:type] = association_type
  @expectation_message = "#{type_description} #{@association[:name].inspect}"
  @expectation_message += " of type #{@association[:class].inspect}" unless @association[:class].nil?
end

Instance Method Details

#class_name(klass) ⇒ Object



120
121
122
123
124
# File 'lib/matchers/associations.rb', line 120

def class_name(klass)
  @association[:class] = klass
  @expectation_message += " with class_name #{@association[:class].inspect}"
  self
end

#descriptionObject



242
243
244
# File 'lib/matchers/associations.rb', line 242

def description
  @expectation_message
end

#failure_message_for_shouldObject Also known as: failure_message



231
232
233
# File 'lib/matchers/associations.rb', line 231

def failure_message_for_should
  "Expected #{@actual.inspect} to #{@expectation_message}, got #{@negative_result_message}"
end

#failure_message_for_should_notObject Also known as: failure_message_when_negated



235
236
237
# File 'lib/matchers/associations.rb', line 235

def failure_message_for_should_not
  "Expected #{@actual.inspect} to not #{@expectation_message}, got #{@positive_result_message}"
end

#matches?(actual) ⇒ Boolean

Returns:

  • (Boolean)


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
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'lib/matchers/associations.rb', line 157

def matches?(actual)
  @actual = actual.is_a?(Class) ? actual : actual.class
   = @actual.[@association[:name]]

  if .nil?
    @negative_result_message = "no association named #{@association[:name]}"
    return false
  else
    @positive_result_message = "association named #{@association[:name]}"
  end

  relation = .class.name.gsub(/::Metadata$/, '').constantize
  if relation != @association[:type]
    @negative_result_message = "#{@actual.inspect} #{type_description(relation, false)} #{@association[:name].inspect}"
    return false
  else
    @positive_result_message = "#{@actual.inspect} #{type_description(relation, false)} #{@association[:name].inspect}"
  end

  if !@association[:class].nil? && (@association[:class] != .options[:class_name])
    @negative_result_message = "#{@positive_result_message} with class_name #{.options[:class_name].inspect}"
    return false
  else
    @positive_result_message = "#{@positive_result_message}#{" with class_name #{.options[:class_name].inspect}" if @association[:class]}"
  end

  if @association[:dependent]
    if @association[:dependent].to_sym != (.options[:dependent] && .options[:dependent].to_sym)
      @negative_result_message = "#{@positive_result_message} which specified dependent as #{.options[:dependent]}"
      return false
    else
      @positive_result_message = "#{@positive_result_message} which specified dependent as #{.options[:dependent]}"
    end
  end

  if @association[:primary_key]
    if .options[:primary_key] != @association[:primary_key]
      @negative_result_message = "#{@positive_result_message} with primary key #{.options[:primary_key].inspect}"
      return false
    else
      @positive_result_message = "#{@positive_result_message} with primary key #{.options[:primary_key].inspect}"
    end
  end

  if @association[:foreign_key]
    if .foreign_key != @association[:foreign_key]
      @negative_result_message = "#{@positive_result_message} with foreign key #{.foreign_key.inspect}"
      return false
    else
      @positive_result_message = "#{@positive_result_message} with foreign key #{.foreign_key.inspect}"
    end
  end

  if @association[:through]
    if .options[:through] != @association[:through]
      @negative_result_message = "#{@positive_result_message} through #{.options[:through].inspect}"
      return false
    else
      @positive_result_message = "#{@positive_result_message} through #{.options[:through].inspect}"
    end
  end

  if @association[:required]
    if .options[:required] != @association[:required]
      @negative_result_message = "#{@positive_result_message} with required #{.options[:required].inspect}"
      return false
    else
      @positive_result_message = "#{@positive_result_message} with required #{.options[:required].inspect}"
    end
  end

  true
end

#through(association_key) ⇒ Object



126
127
128
129
130
131
# File 'lib/matchers/associations.rb', line 126

def through(association_key)
  @association[:through] = association_key
  @association[:type] = @association[:type] == HAS_ONE ? HAS_ONE_THROUGH : HAS_MANY_THROUGH
  @expectation_message += " through #{association_key.inspect}"
  self
end

#type_description(type = nil, passive = true) ⇒ Object



246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
# File 'lib/matchers/associations.rb', line 246

def type_description(type = nil, passive = true)
  type ||= @association[:type]
  case type.name
  when HAS_ONE.name
    (passive ? 'have one' : 'having one')
  when HAS_ONE_THROUGH.name
    (passive ? 'have one through' : 'having one')
  when HAS_MANY.name
    (passive ? 'have many' : 'having many')
  when HAS_MANY_THROUGH.name
    (passive ? 'have many through' : 'having many')
  when BELONGS_TO.name
    (passive ? 'belong to' : 'belonging to')
  else
    raise format("Unknown association type #{type}")
  end
end

#with_dependent(method_name) ⇒ Object



133
134
135
136
137
# File 'lib/matchers/associations.rb', line 133

def with_dependent(method_name)
  @association[:dependent] = method_name
  @expectation_message += " which specifies dependent as #{@association[:dependent]}"
  self
end

#with_foreign_key(foreign_key) ⇒ Object



145
146
147
148
149
# File 'lib/matchers/associations.rb', line 145

def with_foreign_key(foreign_key)
  @association[:foreign_key] = foreign_key.to_sym
  @expectation_message += " using foreign key #{@association[:foreign_key].inspect}"
  self
end

#with_primary_key(primary_key) ⇒ Object



139
140
141
142
143
# File 'lib/matchers/associations.rb', line 139

def with_primary_key(primary_key)
  @association[:primary_key] = primary_key.to_sym
  @expectation_message += " using primary key #{@association[:primary_key].inspect}"
  self
end

#with_required(required) ⇒ Object



151
152
153
154
155
# File 'lib/matchers/associations.rb', line 151

def with_required(required)
  @association[:required] = required
  @expectation_message += " with required #{@association[:required].inspect}"
  self
end