From 6a2e7551b269a4f982379f95ac7596f17eace117 Mon Sep 17 00:00:00 2001 From: Elliot Winkler Date: Fri, 20 Mar 2020 12:18:40 -0600 Subject: [PATCH] Tweak have_implicit_order_column + tests * Make the error messaging a little more natural * Align tests to the current style (specifically using `match_against`) --- gemfiles/rails_6_0.gemfile.lock | 50 +++--- .../have_implicit_order_column.rb | 61 ++++--- lib/shoulda/matchers/util.rb | 2 +- .../have_implicit_order_column_spec.rb | 170 +++++++++--------- 4 files changed, 148 insertions(+), 135 deletions(-) diff --git a/gemfiles/rails_6_0.gemfile.lock b/gemfiles/rails_6_0.gemfile.lock index 085bc740..73a641da 100644 --- a/gemfiles/rails_6_0.gemfile.lock +++ b/gemfiles/rails_6_0.gemfile.lock @@ -67,8 +67,8 @@ GEM bootsnap (1.4.5) msgpack (~> 1.0) builder (3.2.4) - byebug (11.1.1) - capybara (3.31.0) + byebug (11.0.1) + capybara (3.30.0) addressable mini_mime (>= 0.1.3) nokogiri (~> 1.8) @@ -79,14 +79,14 @@ GEM childprocess (3.0.0) coderay (1.1.2) concurrent-ruby (1.1.5) - crass (1.0.6) + crass (1.0.5) diff-lcs (1.3) erubi (1.9.0) - ffi (1.12.1) + ffi (1.11.3) fssm (0.2.10) globalid (0.4.2) activesupport (>= 4.2.0) - i18n (1.8.2) + i18n (1.7.0) concurrent-ruby (~> 1.0) jaro_winkler (1.5.4) jbuilder (2.9.1) @@ -103,31 +103,31 @@ GEM marcel (0.3.3) mimemagic (~> 0.3.2) method_source (0.9.2) - mimemagic (0.3.4) + mimemagic (0.3.3) mini_mime (1.0.2) mini_portile2 (2.4.0) - minitest (5.14.0) + minitest (5.13.0) msgpack (1.3.1) multi_json (1.14.1) nio4r (2.5.2) nokogiri (1.10.7) mini_portile2 (~> 2.4.0) parallel (1.19.1) - parser (2.7.0.2) + parser (2.7.0.0) ast (~> 2.4.0) - pg (1.2.2) + pg (1.2.0) pry (0.12.2) coderay (~> 1.1.0) method_source (~> 0.9.0) - pry-byebug (3.8.0) + pry-byebug (3.7.0) byebug (~> 11.0) pry (~> 0.10) - public_suffix (4.0.3) + public_suffix (4.0.1) puma (4.3.1) nio4r (~> 2.0) pygments.rb (1.2.1) multi_json (>= 1.0.0) - rack (2.1.2) + rack (2.0.8) rack-proxy (0.6.5) rack rack-test (1.1.0) @@ -173,12 +173,12 @@ GEM rspec-core (~> 3.9.0) rspec-expectations (~> 3.9.0) rspec-mocks (~> 3.9.0) - rspec-core (3.9.1) - rspec-support (~> 3.9.1) + rspec-core (3.9.0) + rspec-support (~> 3.9.0) rspec-expectations (3.9.0) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.9.0) - rspec-mocks (3.9.1) + rspec-mocks (3.9.0) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.9.0) rspec-rails (3.9.0) @@ -189,20 +189,20 @@ GEM rspec-expectations (~> 3.9.0) rspec-mocks (~> 3.9.0) rspec-support (~> 3.9.0) - rspec-support (3.9.2) - rubocop (0.79.0) + rspec-support (3.9.0) + rubocop (0.78.0) jaro_winkler (~> 1.5.1) parallel (~> 1.10) - parser (>= 2.7.0.1) + parser (>= 2.6) rainbow (>= 2.2.2, < 4.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 1.4.0, < 1.7) - rubocop-rails (2.4.2) + rubocop-rails (2.4.1) rack (>= 1.1) rubocop (>= 0.72.0) ruby-progressbar (1.10.1) ruby_dep (1.5.0) - rubyzip (2.1.0) + rubyzip (2.0.0) sass-rails (6.0.0) sassc-rails (~> 2.1, >= 2.1.1) sassc (2.2.1) @@ -213,7 +213,7 @@ GEM sprockets (> 3.0) sprockets-rails tilt - selenium-webdriver (3.142.7) + selenium-webdriver (3.142.6) childprocess (>= 0.5, < 4.0) rubyzip (>= 1.2.2) shoulda-context (1.2.2) @@ -239,8 +239,8 @@ GEM turbolinks-source (5.2.0) tzinfo (1.2.6) thread_safe (~> 0.1) - unicode-display_width (1.6.1) - webdrivers (4.2.0) + unicode-display_width (1.6.0) + webdrivers (4.1.3) nokogiri (~> 1.6) rubyzip (>= 1.3.0) selenium-webdriver (>= 3.0, < 4.0) @@ -253,7 +253,7 @@ GEM websocket-extensions (0.1.4) xpath (3.2.0) nokogiri (~> 1.8) - yard (0.9.24) + yard (0.9.20) zeitwerk (2.2.2) zeus (0.15.14) method_source (>= 0.6.7) @@ -298,4 +298,4 @@ DEPENDENCIES zeus BUNDLED WITH - 1.17.2 + 1.17.3 diff --git a/lib/shoulda/matchers/active_record/have_implicit_order_column.rb b/lib/shoulda/matchers/active_record/have_implicit_order_column.rb index 228f8d3e..a90602dc 100644 --- a/lib/shoulda/matchers/active_record/have_implicit_order_column.rb +++ b/lib/shoulda/matchers/active_record/have_implicit_order_column.rb @@ -1,8 +1,9 @@ module Shoulda module Matchers module ActiveRecord - # The `have_implicit_order_column` matcher tests that the model has `implicit_order_column` - # assigned to one of the table columns. (Rails 6+ only) + # The `have_implicit_order_column` matcher tests that the model has + # `implicit_order_column` assigned to one of the table columns. + # (Rails 6+ only.) # # class Product < ApplicationRecord # self.implicit_order_column = :created_at @@ -38,52 +39,70 @@ module Shoulda end def failure_message - "Expected #{expectation} (#{@details})" + message = + if details + "Expected #{expectation} (#{details})." + else + "Expected #{expectation}." + end + + Shoulda::Matchers.word_wrap(message) end def failure_message_when_negated - "Did not expect #{expectation}" + Shoulda::Matchers.word_wrap( + "Did not expect #{expectation}, but it did.", + ) end def description - "have implicit_order_column assigned to #{@column}" + "have an implicit_order_column of :#{column}" end private - def column_exists? - matcher = HaveDbColumnMatcher.new(@column) + attr_reader :column, :subject, :details - if matcher.matches?(@subject) + def column_exists? + matcher = HaveDbColumnMatcher.new(column) + + if matcher.matches?(subject) true else - @details = "#{model_class} does not have a db column named #{@column}" + @details = + "#{model.table_name} does not have #{a_or_an(":#{column}")} " + + 'column' false end end def implicit_order_column_matches? - model_implicit_order_column = model_class.implicit_order_column + model_implicit_order_column = model.implicit_order_column - if model_implicit_order_column.to_s == @column.to_s + if model_implicit_order_column.to_s == column.to_s true else - @details = if model_implicit_order_column.nil? - "#{model_class} implicit_order_column is not set" - else - "#{model_class} implicit_order_column is " + - "set to #{model_implicit_order_column}" - end + @details = + if model_implicit_order_column + 'its implicit_order_column is ' + + ":#{model_implicit_order_column}" + else + 'it does not have an implicit_order_column' + end false end end - def model_class - @subject.class + def expectation + "#{model.name} to have an implicit_order_column of :#{column}" end - def expectation - "#{model_class.name} to have implicit_order_column set to #{@column}" + def model + subject.class + end + + def a_or_an(word) + Shoulda::Matchers::Util.a_or_an(word) end end end diff --git a/lib/shoulda/matchers/util.rb b/lib/shoulda/matchers/util.rb index 37737a9d..c8826203 100644 --- a/lib/shoulda/matchers/util.rb +++ b/lib/shoulda/matchers/util.rb @@ -33,7 +33,7 @@ module Shoulda end def self.a_or_an(next_word) - if next_word =~ /\A[aeiou]/i && next_word != 'unique' + if next_word =~ /\A:?[aeiou]/i && next_word != 'unique' "an #{next_word}" else "a #{next_word}" diff --git a/spec/unit/shoulda/matchers/active_record/have_implicit_order_column_spec.rb b/spec/unit/shoulda/matchers/active_record/have_implicit_order_column_spec.rb index d00f74fa..8768b8c1 100644 --- a/spec/unit/shoulda/matchers/active_record/have_implicit_order_column_spec.rb +++ b/spec/unit/shoulda/matchers/active_record/have_implicit_order_column_spec.rb @@ -2,169 +2,163 @@ require 'unit_spec_helper' describe Shoulda::Matchers::ActiveRecord::HaveImplicitOrderColumnMatcher, type: :model do if active_record_supports_implicit_order_column? - context 'when implicit_order_column is defined for the column' do - context 'when column name is a symbol' do + context 'when the model sets implicit_order_column to the given column' do + context 'when the given column name is a symbol' do it 'accepts' do record = record_with_implicit_order_column_on( - 'created_at', + :created_at, + model_name: 'Employee', columns: { created_at: :timestamp }, ) - expect(record).to have_implicit_order_column(:created_at) + expect { have_implicit_order_column(:created_at) }. + to match_against(record). + or_fail_with(<<~MESSAGE, wrap: true) + Did not expect Employee to have an implicit_order_column of + :created_at, but it did. + MESSAGE end end - context 'when column name is a string' do + context 'when the given column name is a string' do it 'accepts' do record = record_with_implicit_order_column_on( - 'created_at', + :created_at, columns: { created_at: :timestamp }, ) - expect(record).to have_implicit_order_column('created_at') + expect { have_implicit_order_column('created_at') }. + to match_against(record). + or_fail_with(<<~MESSAGE, wrap: true) + Did not expect Employee to have an implicit_order_column of + :created_at, but it did. + MESSAGE end end end - context 'when implicit_order_column is defined for another column' do - context 'when column name is a symbol' do + context 'when the model sets implicit_order_column to another column' do + context 'when the given column name is a symbol' do it 'rejects with an appropriate failure message' do record = record_with_implicit_order_column_on( - 'created_at', + :created_at, columns: { created_at: :timestamp, email: :string }, ) - assertion = lambda { - expect(record).to have_implicit_order_column(:email) - } - - message = format_message(<<-MESSAGE, one_line: true) - Expected Employee to have implicit_order_column set to email - (Employee implicit_order_column is set to created_at) - MESSAGE - - expect(&assertion).to fail_with_message(message) + expect { have_implicit_order_column(:email) }. + not_to match_against(record). + and_fail_with(<<~MESSAGE, wrap: true) + Expected Employee to have an implicit_order_column of :email + (its implicit_order_column is :created_at). + MESSAGE end end - context 'when column name is a string' do + context 'when the given column name is a string' do it 'rejects with an appropriate failure message' do record = record_with_implicit_order_column_on( - 'created_at', + :created_at, columns: { created_at: :timestamp, email: :string }, ) - assertion = lambda { - expect(record).to have_implicit_order_column('email') - } - - message = format_message(<<-MESSAGE, one_line: true) - Expected Employee to have implicit_order_column set to email - (Employee implicit_order_column is set to created_at) - MESSAGE - - expect(&assertion).to fail_with_message(message) + expect { have_implicit_order_column('email') }. + not_to match_against(record). + and_fail_with(<<~MESSAGE, wrap: true) + Expected Employee to have an implicit_order_column of :email + (its implicit_order_column is :created_at). + MESSAGE end end end - context 'when implicit_order_column is NOT defined on model' do - context 'when column name is a symbol' do + context 'when the model does NOT set implicit_order_column' do + context 'when the given column name is a symbol' do it 'rejects with an appropriate failure message' do record = record_without_implicit_order_column( columns: { created_at: :timestamp }, ) - assertion = lambda { - expect(record).to have_implicit_order_column(:created_at) - } - - message = format_message(<<-MESSAGE, one_line: true) - Expected Employee to have implicit_order_column set to created_at - (Employee implicit_order_column is not set) - MESSAGE - - expect(&assertion).to fail_with_message(message) + expect { have_implicit_order_column(:created_at) }. + not_to match_against(record). + and_fail_with(<<~MESSAGE, wrap: true) + Expected Employee to have an implicit_order_column of :created_at + (it does not have an implicit_order_column). + MESSAGE end end - context 'when column name is a string' do + context 'when the given column name is a string' do it 'rejects with an appropriate failure message' do record = record_without_implicit_order_column( columns: { created_at: :timestamp }, ) - assertion = lambda { - expect(record).to have_implicit_order_column('created_at') - } - - message = format_message(<<-MESSAGE, one_line: true) - Expected Employee to have implicit_order_column set to created_at - (Employee implicit_order_column is not set) - MESSAGE - - expect(&assertion).to fail_with_message(message) + expect { have_implicit_order_column('created_at') }. + not_to match_against(record). + and_fail_with(<<~MESSAGE, wrap: true) + Expected Employee to have an implicit_order_column of :created_at + (it does not have an implicit_order_column). + MESSAGE end end end - context 'when given column does NOT exist' do - context 'when column name is a symbol' do + context 'when the given column does not exist on the table' do + context 'when the given column name is a symbol' do it 'rejects with an appropriate failure message' do record = record_without_implicit_order_column( columns: { created_at: :timestamp }, ) - assertion = lambda { - expect(record).to have_implicit_order_column(:whatever) - } - - message = format_message(<<-MESSAGE, one_line: true) - Expected Employee to have implicit_order_column set to whatever - (Employee does not have a db column named whatever) - MESSAGE - - expect(&assertion).to fail_with_message(message) + expect { have_implicit_order_column(:individual) }. + not_to match_against(record). + and_fail_with(<<~MESSAGE, wrap: true) + Expected Employee to have an implicit_order_column of :individual + (employees does not have an :individual column). + MESSAGE end end - context 'when column name is a string' do + context 'when the given column name is a string' do it 'rejects with an appropriate failure message' do record = record_without_implicit_order_column( columns: { created_at: :timestamp }, ) - assertion = lambda { - expect(record).to have_implicit_order_column('whatever') - } - - message = format_message(<<-MESSAGE, one_line: true) - Expected Employee to have implicit_order_column set to whatever - (Employee does not have a db column named whatever) - MESSAGE - - expect(&assertion).to fail_with_message(message) + expect { have_implicit_order_column('individual') }. + not_to match_against(record). + and_fail_with(<<~MESSAGE, wrap: true) + Expected Employee to have an implicit_order_column of :individual + (employees does not have an :individual column). + MESSAGE end end end - describe 'description' do - it 'returns correct description' do + describe '#description' do + it 'returns the correct description' do matcher = have_implicit_order_column(:created_at) - expect(matcher.description).to \ - eq('have implicit_order_column assigned to created_at') + expect(matcher.description).to eq( + 'have an implicit_order_column of :created_at', + ) end end - def record_with_implicit_order_column_on(column_name, columns:) - define_model(:employee, columns) do |model| - model.implicit_order_column = column_name - end.new + def record_with_implicit_order_column_on( + column_name, + columns:, + model_name: 'Employee' + ) + model = define_model(model_name, columns) do |m| + m.implicit_order_column = column_name + end + + model.new end - def record_without_implicit_order_column(columns:) - define_model(:employee, columns).new + def record_without_implicit_order_column(columns:, model_name: 'Employee') + define_model(model_name, columns).new end end end