From 47f47d0d7a9444e990ade859acf91dc2eaa993c7 Mon Sep 17 00:00:00 2001 From: Elliot Winkler Date: Sun, 9 Jun 2019 01:57:09 -0600 Subject: [PATCH] Improve failure message for enum matcher When the enum matcher fails, the message it generates is not as clear as it could be, particularly around showing the expected enum values versus the actual ones. This commit expands the failure message to be more helpful (and ensures that the description of the matcher is kept compact). --- .../active_record/define_enum_for_matcher.rb | 189 +++++---- .../define_enum_for_matcher_spec.rb | 366 +++++++++++++----- 2 files changed, 390 insertions(+), 165 deletions(-) diff --git a/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb b/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb index 09e1da20..a194f5da 100644 --- a/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb +++ b/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb @@ -144,33 +144,24 @@ module Shoulda end def description - description = "define :#{attribute_name} as an enum, backed by " + description = "#{simple_description} backed by " description << Shoulda::Matchers::Util.a_or_an(expected_column_type) - if options[:expected_prefix] - description << ', using a prefix of ' - description << "#{options[:expected_prefix].inspect}" - end - - if options[:expected_suffix] - if options[:expected_prefix] - description << ' and' - else - description << ', using' - end - - description << ' a suffix of ' - - description << "#{options[:expected_suffix].inspect}" - end - - if presented_expected_enum_values.any? - description << ', with possible values ' + if expected_enum_values.any? + description << ' with values ' description << Shoulda::Matchers::Util.inspect_value( - presented_expected_enum_values, + expected_enum_values, ) end + if options[:prefix] + description << ", prefix: #{options[:prefix].inspect}" + end + + if options[:suffix] + description << ", suffix: #{options[:suffix].inspect}" + end + description end @@ -187,13 +178,13 @@ module Shoulda with_values(expected_enum_values) end - def with_prefix(expected_prefix = attribute_name) - options[:expected_prefix] = expected_prefix + def with_prefix(expected_prefix = true) + options[:prefix] = expected_prefix self end - def with_suffix(expected_suffix = attribute_name) - options[:expected_suffix] = expected_suffix + def with_suffix(expected_suffix = true) + options[:suffix] = expected_suffix self end @@ -212,13 +203,14 @@ module Shoulda end def failure_message - message = "Expected #{model} to #{expectation}" + message = + if enum_defined? + "Expected #{model} to #{expectation}. " + else + "Expected #{model} to #{expectation}, but " + end - if failure_reason - message << ". However, #{failure_reason}" - end - - message << '.' + message << failure_message_continuation + '.' Shoulda::Matchers.word_wrap(message) end @@ -230,18 +222,63 @@ module Shoulda private - attr_reader :attribute_name, :options, :record, :failure_reason + attr_reader :attribute_name, :options, :record, + :failure_message_continuation def expectation - description + if enum_defined? + expectation = "#{simple_description} backed by " + expectation << Shoulda::Matchers::Util.a_or_an(expected_column_type) + + if expected_enum_values.any? + expectation << ', mapping ' + expectation << presented_enum_mapping( + normalized_expected_enum_values, + ) + end + + if expected_prefix + expectation << + if expected_suffix + ', ' + else + ' and ' + end + + expectation << 'prefixing accessor methods with ' + expectation << "#{expected_prefix}_".inspect + end + + if expected_suffix + expectation << + if expected_prefix + ', and ' + else + ' and ' + end + + expectation << 'suffixing accessor methods with ' + expectation << "_#{expected_suffix}".inspect + end + + expectation + else + simple_description + end end - def presented_expected_enum_values - if expected_enum_values.is_a?(Hash) - expected_enum_values.symbolize_keys - else - expected_enum_values - end + def simple_description + "define :#{attribute_name} as an enum" + end + + def presented_enum_mapping(enum_values) + enum_values. + map { |output_to_input| + output_to_input. + map(&Shoulda::Matchers::Util.method(:inspect_value)). + join(' to ') + }. + to_sentence end def normalized_expected_enum_values @@ -256,14 +293,6 @@ module Shoulda options[:expected_enum_values] end - def presented_actual_enum_values - if expected_enum_values.is_a?(Array) - to_array(actual_enum_values) - else - to_hash(actual_enum_values).symbolize_keys - end - end - def normalized_actual_enum_values to_hash(actual_enum_values) end @@ -276,7 +305,8 @@ module Shoulda if model.defined_enums.include?(attribute_name.to_s) true else - @failure_reason = "no such enum exists in #{model}" + @failure_message_continuation = + "no such enum exists on #{model}" false end end @@ -289,11 +319,9 @@ module Shoulda if passed true else - @failure_reason = - "the actual enum values for #{attribute_name.inspect} are " + - Shoulda::Matchers::Util.inspect_value( - presented_actual_enum_values, - ) + @failure_message_continuation = + "However, #{attribute_name.inspect} actually maps " + + presented_enum_mapping(normalized_actual_enum_values) false end end @@ -302,8 +330,8 @@ module Shoulda if column.type == expected_column_type.to_sym true else - @failure_reason = - "#{attribute_name.inspect} is " + + @failure_message_continuation = + "However, #{attribute_name.inspect} is " + Shoulda::Matchers::Util.a_or_an(column.type) + ' column' false @@ -330,30 +358,59 @@ module Shoulda if passed true else - @failure_reason = - if options[:expected_prefix] - if options[:expected_suffix] - 'it was defined with either a different prefix, a ' + - 'different suffix, or neither one at all' - else - 'it was defined with either a different prefix or none at all' - end - elsif options[:expected_suffix] - 'it was defined with either a different suffix or none at all' + message = "#{attribute_name.inspect} does map to these " + message << 'values, but the enum is ' + + if expected_prefix + if expected_suffix + message << 'configured with either a different prefix or ' + message << 'suffix, or no prefix or suffix at all' + else + message << 'configured with either a different prefix or no ' + message << 'prefix at all' end + elsif expected_suffix + message << 'configured with either a different suffix or no ' + message << 'suffix at all' + end + + message << " (we can't tell which)" + + @failure_message_continuation = message + false end end def expected_singleton_methods expected_enum_value_names.map do |name| - [options[:expected_prefix], name, options[:expected_suffix]]. + [expected_prefix, name, expected_suffix]. select(&:present?). join('_'). to_sym end end + def expected_prefix + if options.include?(:prefix) + if options[:prefix] == true + attribute_name#.to_sym + else + options[:prefix]#.to_sym + end + end + end + + def expected_suffix + if options.include?(:suffix) + if options[:suffix] == true + attribute_name#.to_sym + else + options[:suffix]#.to_sym + end + end + end + def to_hash(value) if value.is_a?(Array) value.each_with_index.inject({}) do |hash, (item, index)| diff --git a/spec/unit/shoulda/matchers/active_record/define_enum_for_matcher_spec.rb b/spec/unit/shoulda/matchers/active_record/define_enum_for_matcher_spec.rb index ef9ce151..8b3517f6 100644 --- a/spec/unit/shoulda/matchers/active_record/define_enum_for_matcher_spec.rb +++ b/spec/unit/shoulda/matchers/active_record/define_enum_for_matcher_spec.rb @@ -9,8 +9,8 @@ describe Shoulda::Matchers::ActiveRecord::DefineEnumForMatcher, type: :model do column_type: :integer, ) message = format_message(<<-MESSAGE) - Expected Example to define :attrs as an enum, backed by an integer. - However, no such enum exists in Example. + Expected Example to define :attrs as an enum, but no such enum exists on + Example. MESSAGE assertion = lambda do @@ -28,8 +28,8 @@ describe Shoulda::Matchers::ActiveRecord::DefineEnumForMatcher, type: :model do end message = format_message(<<-MESSAGE) - Expected Example to define :attr as an enum, backed by an integer. - However, no such enum exists in Example. + Expected Example to define :attr as an enum, but no such enum exists on + Example. MESSAGE assertion = lambda do @@ -48,8 +48,8 @@ describe Shoulda::Matchers::ActiveRecord::DefineEnumForMatcher, type: :model do attribute_name: :attr, ) message = format_message(<<-MESSAGE) - Expected Example to define :attr as an enum, backed by an integer. - However, no such enum exists in Example. + Expected Example to define :attr as an enum, but no such enum exists + on Example. MESSAGE assertion = lambda do @@ -68,7 +68,7 @@ describe Shoulda::Matchers::ActiveRecord::DefineEnumForMatcher, type: :model do column_type: :string, ) message = format_message(<<-MESSAGE) - Expected Example to define :attr as an enum, backed by an integer. + Expected Example to define :attr as an enum backed by an integer. However, :attr is a string column. MESSAGE @@ -81,30 +81,23 @@ describe Shoulda::Matchers::ActiveRecord::DefineEnumForMatcher, type: :model do end context 'if the attribute is defined as an enum' do - it 'accepts' do + it 'matches' do record = build_record_with_array_values(attribute_name: :attr) - expect(record).to define_enum_for(:attr) + expect { define_enum_for(:attr) }. + to match_against(record). + or_fail_with(<<-MESSAGE, wrap: true) + Expected Example not to define :attr as an enum backed by an + integer, but it did. + MESSAGE end - context 'and the matcher is negated' do - it 'rejects with an appropriate failure message' do - record = build_record_with_array_values( - model_name: 'Example', - attribute_name: :attr, - column_type: :integer, - ) - message = format_message(<<-MESSAGE) - Expected Example not to define :attr as an enum, backed by an integer, - but it did. - MESSAGE + it 'has the right description' do + matcher = define_enum_for(:attr) - assertion = lambda do - expect(record).not_to define_enum_for(:attr) - end - - expect(&assertion).to fail_with_message(message) - end + expect(matcher.description).to eq(<<~MESSAGE.strip) + define :attr as an enum backed by an integer + MESSAGE end end end @@ -118,9 +111,8 @@ describe Shoulda::Matchers::ActiveRecord::DefineEnumForMatcher, type: :model do attribute_name: :attr, ) message = format_message(<<-MESSAGE) - Expected Example to define :attr as an enum, backed by an integer, - with possible values ‹["open", "close"]›. However, no such enum - exists in Example. + Expected Example to define :attr as an enum, but no such enum + exists on Example. MESSAGE assertion = lambda do @@ -142,9 +134,10 @@ describe Shoulda::Matchers::ActiveRecord::DefineEnumForMatcher, type: :model do values: ['published', 'unpublished', 'draft'], ) message = format_message(<<-MESSAGE) - Expected Example to define :attr as an enum, backed by an integer, - with possible values ‹["open", "close"]›. However, the actual - enum values for :attr are ‹["published", "unpublished", "draft"]›. + Expected Example to define :attr as an enum backed by an integer, + mapping ‹"open"› to ‹0› and ‹"close"› to ‹1›. However, :attr + actually maps ‹"published"› to ‹0›, ‹"unpublished"› to ‹1›, and + ‹"draft"› to ‹2›. MESSAGE assertion = lambda do @@ -158,14 +151,33 @@ describe Shoulda::Matchers::ActiveRecord::DefineEnumForMatcher, type: :model do end context 'and the enum values match' do - it 'accepts' do + it 'matches' do record = build_record_with_array_values( attribute_name: :attr, values: ['published', 'unpublished', 'draft'], ) - expect(record).to define_enum_for(:attr). + matcher = lambda do + define_enum_for(:attr). + with_values(['published', 'unpublished', 'draft']) + end + + expect(&matcher). + to match_against(record). + or_fail_with(<<-MESSAGE, wrap: true) + Expected Example not to define :attr as an enum backed by an + integer, mapping ‹"published"› to ‹0›, ‹"unpublished"› to ‹1›, + and ‹"draft"› to ‹2›, but it did. + MESSAGE + end + + it 'has the right description' do + matcher = define_enum_for(:attr). with_values(['published', 'unpublished', 'draft']) + + expect(matcher.description).to eq(<<~MESSAGE.strip) + define :attr as an enum backed by an integer with values ‹["published", "unpublished", "draft"]› + MESSAGE end end end @@ -179,9 +191,8 @@ describe Shoulda::Matchers::ActiveRecord::DefineEnumForMatcher, type: :model do attribute_name: :attr, ) message = format_message(<<-MESSAGE) - Expected Example to define :attr as an enum, backed by an integer, - with possible values ‹{active: 5, archived: 10}›. However, no such - enum exists in Example. + Expected Example to define :attr as an enum, but no such enum exists + on Example. MESSAGE assertion = lambda do @@ -203,9 +214,9 @@ describe Shoulda::Matchers::ActiveRecord::DefineEnumForMatcher, type: :model do values: { active: 0, archived: 1 }, ) message = format_message(<<-MESSAGE) - Expected Example to define :attr as an enum, backed by an integer, - with possible values ‹{active: 5, archived: 10}›. However, the - actual enum values for :attr are ‹{active: 0, archived: 1}›. + Expected Example to define :attr as an enum backed by an integer, + mapping ‹"active"› to ‹5› and ‹"archived"› to ‹10›. However, :attr + actually maps ‹"active"› to ‹0› and ‹"archived"› to ‹1›. MESSAGE assertion = lambda do @@ -220,28 +231,64 @@ describe Shoulda::Matchers::ActiveRecord::DefineEnumForMatcher, type: :model do context 'and the enum values match' do context 'when expected enum values are a hash' do - it 'accepts' do + it 'matches' do record = build_record_with_hash_values( attribute_name: :attr, values: { active: 0, archived: 1 }, ) - expect(record). - to define_enum_for(:attr). + matcher = lambda do + define_enum_for(:attr). + with_values(active: 0, archived: 1) + end + + expect(&matcher). + to match_against(record). + or_fail_with(<<-MESSAGE, wrap: true) + Expected Example not to define :attr as an enum backed by an + integer, mapping ‹"active"› to ‹0› and ‹"archived"› to ‹1›, + but it did. + MESSAGE + end + + it 'has the right description' do + matcher = define_enum_for(:attr). with_values(active: 0, archived: 1) + + expect(matcher.description).to eq(<<~MESSAGE.strip) + define :attr as an enum backed by an integer with values ‹{active: 0, archived: 1}› + MESSAGE end end context 'when expected enum values are an array' do - it 'accepts' do + it 'matches' do record = build_record_with_hash_values( attribute_name: :attr, values: { active: 0, archived: 1 }, ) - expect(record). - to define_enum_for(:attr). + matcher = lambda do + define_enum_for(:attr). + with_values(['active', 'archived']) + end + + expect(&matcher). + to match_against(record). + or_fail_with(<<-MESSAGE, wrap: true) + Expected Example not to define :attr as an enum backed by an + integer, mapping ‹"active"› to ‹0› and ‹"archived"› to ‹1›, + but it did. + MESSAGE + end + + it 'has the right description' do + matcher = define_enum_for(:attr). with_values(['active', 'archived']) + + expect(matcher.description).to eq(<<~MESSAGE.strip) + define :attr as an enum backed by an integer with values ‹["active", "archived"]› + MESSAGE end end end @@ -276,7 +323,7 @@ describe Shoulda::Matchers::ActiveRecord::DefineEnumForMatcher, type: :model do column_type: :integer, ) message = format_message(<<-MESSAGE) - Expected Example to define :attr as an enum, backed by a string. + Expected Example to define :attr as an enum backed by a string. However, :attr is an integer column. MESSAGE @@ -291,15 +338,30 @@ describe Shoulda::Matchers::ActiveRecord::DefineEnumForMatcher, type: :model do end context 'if the column storing the attribute is of the same type' do - it 'accepts' do + it 'matches' do record = build_record_with_array_values( attribute_name: :attr, column_type: :string, ) - expect(record). - to define_enum_for(:attr). - backed_by_column_of_type(:string) + matcher = lambda do + define_enum_for(:attr).backed_by_column_of_type(:string) + end + + expect(&matcher). + to match_against(record). + or_fail_with(<<-MESSAGE, wrap: true) + Expected Example not to define :attr as an enum backed by a string, + but it did. + MESSAGE + end + + it 'has the right description' do + matcher = define_enum_for(:attr).backed_by_column_of_type(:string) + + expect(matcher.description).to eq(<<~MESSAGE.strip) + define :attr as an enum backed by a string + MESSAGE end end end @@ -324,10 +386,11 @@ describe Shoulda::Matchers::ActiveRecord::DefineEnumForMatcher, type: :model do end message = format_message(<<-MESSAGE) - Expected Example to define :attr as an enum, backed by an integer, - using a prefix of :foo, with possible values ‹[:active, - :archived]›. However, it was defined with either a different - prefix or none at all. + Expected Example to define :attr as an enum backed by an integer, + mapping ‹"active"› to ‹0› and ‹"archived"› to ‹1› and prefixing + accessor methods with "foo_". :attr does map to these values, but + the enum is configured with either a different prefix or no prefix + at all (we can't tell which). MESSAGE expect(&assertion).to fail_with_message(message) @@ -352,10 +415,11 @@ describe Shoulda::Matchers::ActiveRecord::DefineEnumForMatcher, type: :model do end message = format_message(<<-MESSAGE) - Expected Example to define :attr as an enum, backed by an integer, - using a prefix of :bar, with possible values ‹[:active, - :archived]›. However, it was defined with either a different - prefix or none at all. + Expected Example to define :attr as an enum backed by an integer, + mapping ‹"active"› to ‹0› and ‹"archived"› to ‹1› and prefixing + accessor methods with "bar_". :attr does map to these values, but + the enum is configured with either a different prefix or no prefix + at all (we can't tell which). MESSAGE expect(&assertion).to fail_with_message(message) @@ -363,7 +427,7 @@ describe Shoulda::Matchers::ActiveRecord::DefineEnumForMatcher, type: :model do end context 'if the attribute was defined with the same prefix' do - it 'accepts' do + it 'matches' do record = build_record_with_array_values( model_name: 'Example', attribute_name: :attr, @@ -371,10 +435,29 @@ describe Shoulda::Matchers::ActiveRecord::DefineEnumForMatcher, type: :model do prefix: :foo, ) - expect(record). - to define_enum_for(:attr). + matcher = lambda do + define_enum_for(:attr). + with_values([:active, :archived]). + with_prefix(:foo) + end + + expect(&matcher). + to match_against(record). + or_fail_with(<<-MESSAGE, wrap: true) + Expected Example not to define :attr as an enum backed by an + integer, mapping ‹"active"› to ‹0› and ‹"archived"› to ‹1› and + prefixing accessor methods with "foo_", but it did. + MESSAGE + end + + it 'has the right description' do + matcher = define_enum_for(:attr). with_values([:active, :archived]). with_prefix(:foo) + + expect(matcher.description).to eq(<<~MESSAGE.strip) + define :attr as an enum backed by an integer with values ‹[:active, :archived]›, prefix: :foo + MESSAGE end end end @@ -397,10 +480,11 @@ describe Shoulda::Matchers::ActiveRecord::DefineEnumForMatcher, type: :model do end message = format_message(<<-MESSAGE) - Expected Example to define :attr as an enum, backed by an integer, - using a prefix of :attr, with possible values ‹[:active, - :archived]›. However, it was defined with either a different - prefix or none at all. + Expected Example to define :attr as an enum backed by an integer, + mapping ‹"active"› to ‹0› and ‹"archived"› to ‹1› and prefixing + accessor methods with "attr_". :attr does map to these values, but + the enum is configured with either a different prefix or no prefix + at all (we can't tell which). MESSAGE expect(&assertion).to fail_with_message(message) @@ -408,7 +492,7 @@ describe Shoulda::Matchers::ActiveRecord::DefineEnumForMatcher, type: :model do end context 'if the attribute was defined with a prefix' do - it 'accepts' do + it 'matches' do record = build_record_with_array_values( model_name: 'Example', attribute_name: :attr, @@ -416,10 +500,29 @@ describe Shoulda::Matchers::ActiveRecord::DefineEnumForMatcher, type: :model do prefix: true, ) - expect(record). - to define_enum_for(:attr). + matcher = lambda do + define_enum_for(:attr). + with_values([:active, :archived]). + with_prefix + end + + expect(&matcher). + to match_against(record). + or_fail_with(<<-MESSAGE, wrap: true) + Expected Example not to define :attr as an enum backed by an + integer, mapping ‹"active"› to ‹0› and ‹"archived"› to ‹1› and + prefixing accessor methods with "attr_", but it did. + MESSAGE + end + + it 'has the right description' do + matcher = define_enum_for(:attr). with_values([:active, :archived]). with_prefix + + expect(matcher.description).to eq(<<~MESSAGE.strip) + define :attr as an enum backed by an integer with values ‹[:active, :archived]›, prefix: true + MESSAGE end end end @@ -444,10 +547,11 @@ describe Shoulda::Matchers::ActiveRecord::DefineEnumForMatcher, type: :model do end message = format_message(<<-MESSAGE) - Expected Example to define :attr as an enum, backed by an integer, - using a suffix of :foo, with possible values ‹[:active, - :archived]›. However, it was defined with either a different - suffix or none at all. + Expected Example to define :attr as an enum backed by an integer, + mapping ‹"active"› to ‹0› and ‹"archived"› to ‹1› and suffixing + accessor methods with "_foo". :attr does map to these values, but + the enum is configured with either a different suffix or no suffix + at all (we can't tell which). MESSAGE expect(&assertion).to fail_with_message(message) @@ -472,10 +576,11 @@ describe Shoulda::Matchers::ActiveRecord::DefineEnumForMatcher, type: :model do end message = format_message(<<-MESSAGE) - Expected Example to define :attr as an enum, backed by an integer, - using a suffix of :bar, with possible values ‹[:active, - :archived]›. However, it was defined with either a different - suffix or none at all. + Expected Example to define :attr as an enum backed by an integer, + mapping ‹"active"› to ‹0› and ‹"archived"› to ‹1› and suffixing + accessor methods with "_bar". :attr does map to these values, but + the enum is configured with either a different suffix or no suffix + at all (we can't tell which). MESSAGE expect(&assertion).to fail_with_message(message) @@ -483,7 +588,7 @@ describe Shoulda::Matchers::ActiveRecord::DefineEnumForMatcher, type: :model do end context 'if the attribute was defined with the same suffix' do - it 'accepts' do + it 'matches' do record = build_record_with_array_values( model_name: 'Example', attribute_name: :attr, @@ -491,10 +596,29 @@ describe Shoulda::Matchers::ActiveRecord::DefineEnumForMatcher, type: :model do suffix: :foo, ) - expect(record). - to define_enum_for(:attr). + matcher = lambda do + define_enum_for(:attr). + with_values([:active, :archived]). + with_suffix(:foo) + end + + expect(&matcher). + to match_against(record). + or_fail_with(<<-MESSAGE, wrap: true) + Expected Example not to define :attr as an enum backed by an + integer, mapping ‹"active"› to ‹0› and ‹"archived"› to ‹1› and + suffixing accessor methods with "_foo", but it did. + MESSAGE + end + + it 'has the right description' do + matcher = define_enum_for(:attr). with_values([:active, :archived]). with_suffix(:foo) + + expect(matcher.description).to eq(<<~MESSAGE.strip) + define :attr as an enum backed by an integer with values ‹[:active, :archived]›, suffix: :foo + MESSAGE end end end @@ -517,10 +641,11 @@ describe Shoulda::Matchers::ActiveRecord::DefineEnumForMatcher, type: :model do end message = format_message(<<-MESSAGE) - Expected Example to define :attr as an enum, backed by an integer, - using a suffix of :attr, with possible values ‹[:active, - :archived]›. However, it was defined with either a different - suffix or none at all. + Expected Example to define :attr as an enum backed by an integer, + mapping ‹"active"› to ‹0› and ‹"archived"› to ‹1› and suffixing + accessor methods with "_attr". :attr does map to these values, but + the enum is configured with either a different suffix or no suffix + at all (we can't tell which). MESSAGE expect(&assertion).to fail_with_message(message) @@ -528,7 +653,7 @@ describe Shoulda::Matchers::ActiveRecord::DefineEnumForMatcher, type: :model do end context 'if the attribute was defined with a suffix' do - it 'accepts' do + it 'matches' do record = build_record_with_array_values( model_name: 'Example', attribute_name: :attr, @@ -536,10 +661,29 @@ describe Shoulda::Matchers::ActiveRecord::DefineEnumForMatcher, type: :model do suffix: true, ) - expect(record). - to define_enum_for(:attr). + matcher = lambda do + define_enum_for(:attr). + with_values([:active, :archived]). + with_suffix + end + + expect(&matcher). + to match_against(record). + or_fail_with(<<-MESSAGE, wrap: true) + Expected Example not to define :attr as an enum backed by an + integer, mapping ‹"active"› to ‹0› and ‹"archived"› to ‹1› and + suffixing accessor methods with "_attr", but it did. + MESSAGE + end + + it 'has the right description' do + matcher = define_enum_for(:attr). with_values([:active, :archived]). with_suffix + + expect(matcher.description).to eq(<<~MESSAGE.strip) + define :attr as an enum backed by an integer with values ‹[:active, :archived]›, suffix: true + MESSAGE end end end @@ -566,10 +710,12 @@ describe Shoulda::Matchers::ActiveRecord::DefineEnumForMatcher, type: :model do end message = format_message(<<-MESSAGE) - Expected Example to define :attr as an enum, backed by an integer, - using a prefix of :whatever and a suffix of :bar, with possible - values ‹[:active, :archived]›. However, it was defined with either - a different prefix, a different suffix, or neither one at all. + Expected Example to define :attr as an enum backed by an integer, + mapping ‹"active"› to ‹0› and ‹"archived"› to ‹1›, prefixing + accessor methods with "whatever_", and suffixing accessor methods + with "_bar". :attr does map to these values, but the enum is + configured with either a different prefix or suffix, or no prefix or + suffix at all (we can't tell which). MESSAGE expect(&assertion).to fail_with_message(message) @@ -595,11 +741,12 @@ describe Shoulda::Matchers::ActiveRecord::DefineEnumForMatcher, type: :model do end message = format_message(<<-MESSAGE) - Expected Example to define :attr as an enum, backed by an integer, - using a prefix of :foo and a suffix of :whatever, with possible - values ‹[:active, :archived]›. However, it was defined with - either a different prefix, a different suffix, or neither one at - all. + Expected Example to define :attr as an enum backed by an integer, + mapping ‹"active"› to ‹0› and ‹"archived"› to ‹1›, prefixing + accessor methods with "foo_", and suffixing accessor methods with + "_whatever". :attr does map to these values, but the enum is + configured with either a different prefix or suffix, or no prefix + or suffix at all (we can't tell which). MESSAGE expect(&assertion).to fail_with_message(message) @@ -607,7 +754,7 @@ describe Shoulda::Matchers::ActiveRecord::DefineEnumForMatcher, type: :model do end context 'if the attribute was defined with the same prefix and suffix' do - it 'accepts' do + it 'matches' do record = build_record_with_array_values( model_name: 'Example', attribute_name: :attr, @@ -616,11 +763,32 @@ describe Shoulda::Matchers::ActiveRecord::DefineEnumForMatcher, type: :model do suffix: :bar, ) - expect(record). - to define_enum_for(:attr). + matcher = lambda do + define_enum_for(:attr). + with_values([:active, :archived]). + with_prefix(:foo). + with_suffix(:bar) + end + + expect(&matcher). + to match_against(record). + or_fail_with(<<-MESSAGE, wrap: true) + Expected Example not to define :attr as an enum backed by an + integer, mapping ‹"active"› to ‹0› and ‹"archived"› to ‹1›, + prefixing accessor methods with "foo_", and suffixing accessor + methods with "_bar", but it did. + MESSAGE + end + + it 'has the right description' do + matcher = define_enum_for(:attr). with_values([:active, :archived]). with_prefix(:foo). with_suffix(:bar) + + expect(matcher.description).to eq(<<~MESSAGE.strip) + define :attr as an enum backed by an integer with values ‹[:active, :archived]›, prefix: :foo, suffix: :bar + MESSAGE end end end