1
0
Fork 0
mirror of https://github.com/thoughtbot/shoulda-matchers.git synced 2022-11-09 12:01:38 -05:00

Add support for Postgres

When running tests, you can now switch between running them against a
SQLite or PostgreSQL database. This is accomplished by modifying the
unit and acceptance tests so that when they generate and load the test
Rails application, database.yml is replaced with content that will
configure the database appropriately.
This commit is contained in:
Elliot Winkler 2015-02-08 14:38:55 -07:00
parent 942a600e07
commit 72f60fae94
30 changed files with 288 additions and 51 deletions

View file

@ -6,6 +6,10 @@ branches:
only: only:
- master - master
env:
- DATABASE_ADAPTER=sqlite3
- DATABASE_ADAPTER=postgresql
rvm: rvm:
- 2.0.0 - 2.0.0
- 2.1.4 - 2.1.4

View file

@ -4,6 +4,7 @@ shared_dependencies = proc do
gem 'rspec-rails', '>= 3.2.0', '< 4' gem 'rspec-rails', '>= 3.2.0', '< 4'
gem 'shoulda-context', '~> 1.2.0' gem 'shoulda-context', '~> 1.2.0'
gem 'sqlite3', platform: :ruby gem 'sqlite3', platform: :ruby
gem 'pg', platform: :ruby
gem 'activerecord-jdbc-adapter', platform: :jruby gem 'activerecord-jdbc-adapter', platform: :jruby
gem 'activerecord-jdbcsqlite3-adapter', platform: :jruby gem 'activerecord-jdbcsqlite3-adapter', platform: :jruby
gem 'jdbc-sqlite3', platform: :jruby gem 'jdbc-sqlite3', platform: :jruby

View file

@ -3,6 +3,7 @@ require 'bundler/gem_tasks'
require 'rspec/core/rake_task' require 'rspec/core/rake_task'
require 'appraisal' require 'appraisal'
require_relative 'tasks/documentation' require_relative 'tasks/documentation'
require_relative 'spec/support/tests/database'
RSpec::Core::RakeTask.new('spec:unit') do |t| RSpec::Core::RakeTask.new('spec:unit') do |t|
t.ruby_opts = '-w -r ./spec/report_warnings' t.ruby_opts = '-w -r ./spec/report_warnings'

View file

@ -15,6 +15,7 @@ gem "watchr"
gem "rspec-rails", ">= 3.2.0", "< 4" gem "rspec-rails", ">= 3.2.0", "< 4"
gem "shoulda-context", "~> 1.2.0" gem "shoulda-context", "~> 1.2.0"
gem "sqlite3", :platform => :ruby gem "sqlite3", :platform => :ruby
gem "pg", :platform => :ruby
gem "activerecord-jdbc-adapter", :platform => :jruby gem "activerecord-jdbc-adapter", :platform => :jruby
gem "activerecord-jdbcsqlite3-adapter", :platform => :jruby gem "activerecord-jdbcsqlite3-adapter", :platform => :jruby
gem "jdbc-sqlite3", :platform => :jruby gem "jdbc-sqlite3", :platform => :jruby

View file

@ -70,6 +70,7 @@ GEM
minitest (>= 2.12, < 5.0) minitest (>= 2.12, < 5.0)
powerbar powerbar
multi_json (1.10.1) multi_json (1.10.1)
pg (0.18.1)
polyglot (0.3.5) polyglot (0.3.5)
posix-spawn (0.3.9) posix-spawn (0.3.9)
powerbar (1.0.11) powerbar (1.0.11)
@ -181,6 +182,7 @@ DEPENDENCIES
jquery-rails jquery-rails
jruby-openssl jruby-openssl
minitest-reporters minitest-reporters
pg
protected_attributes protected_attributes
pry-nav pry-nav
pygments.rb pygments.rb

View file

@ -15,6 +15,7 @@ gem "watchr"
gem "rspec-rails", ">= 3.2.0", "< 4" gem "rspec-rails", ">= 3.2.0", "< 4"
gem "shoulda-context", "~> 1.2.0" gem "shoulda-context", "~> 1.2.0"
gem "sqlite3", :platform => :ruby gem "sqlite3", :platform => :ruby
gem "pg", :platform => :ruby
gem "activerecord-jdbc-adapter", :platform => :jruby gem "activerecord-jdbc-adapter", :platform => :jruby
gem "activerecord-jdbcsqlite3-adapter", :platform => :jruby gem "activerecord-jdbcsqlite3-adapter", :platform => :jruby
gem "jdbc-sqlite3", :platform => :jruby gem "jdbc-sqlite3", :platform => :jruby

View file

@ -70,6 +70,7 @@ GEM
minitest (>= 2.12, < 5.0) minitest (>= 2.12, < 5.0)
powerbar powerbar
multi_json (1.10.1) multi_json (1.10.1)
pg (0.18.1)
polyglot (0.3.5) polyglot (0.3.5)
posix-spawn (0.3.9) posix-spawn (0.3.9)
powerbar (1.0.11) powerbar (1.0.11)
@ -181,6 +182,7 @@ DEPENDENCIES
jquery-rails jquery-rails
jruby-openssl jruby-openssl
minitest-reporters minitest-reporters
pg
protected_attributes protected_attributes
pry-nav pry-nav
pygments.rb pygments.rb

View file

@ -15,6 +15,7 @@ gem "watchr"
gem "rspec-rails", ">= 3.2.0", "< 4" gem "rspec-rails", ">= 3.2.0", "< 4"
gem "shoulda-context", "~> 1.2.0" gem "shoulda-context", "~> 1.2.0"
gem "sqlite3", :platform => :ruby gem "sqlite3", :platform => :ruby
gem "pg", :platform => :ruby
gem "activerecord-jdbc-adapter", :platform => :jruby gem "activerecord-jdbc-adapter", :platform => :jruby
gem "activerecord-jdbcsqlite3-adapter", :platform => :jruby gem "activerecord-jdbcsqlite3-adapter", :platform => :jruby
gem "jdbc-sqlite3", :platform => :jruby gem "jdbc-sqlite3", :platform => :jruby

View file

@ -70,6 +70,7 @@ GEM
minitest (>= 5.0) minitest (>= 5.0)
ruby-progressbar ruby-progressbar
multi_json (1.10.1) multi_json (1.10.1)
pg (0.18.1)
posix-spawn (0.3.9) posix-spawn (0.3.9)
protected_attributes (1.0.8) protected_attributes (1.0.8)
activemodel (>= 4.0.1, < 5.0) activemodel (>= 4.0.1, < 5.0)
@ -178,6 +179,7 @@ DEPENDENCIES
jquery-rails jquery-rails
jruby-openssl jruby-openssl
minitest-reporters minitest-reporters
pg
protected_attributes (~> 1.0.6) protected_attributes (~> 1.0.6)
pry-nav pry-nav
pygments.rb pygments.rb

View file

@ -15,6 +15,7 @@ gem "watchr"
gem "rspec-rails", ">= 3.2.0", "< 4" gem "rspec-rails", ">= 3.2.0", "< 4"
gem "shoulda-context", "~> 1.2.0" gem "shoulda-context", "~> 1.2.0"
gem "sqlite3", :platform => :ruby gem "sqlite3", :platform => :ruby
gem "pg", :platform => :ruby
gem "activerecord-jdbc-adapter", :platform => :jruby gem "activerecord-jdbc-adapter", :platform => :jruby
gem "activerecord-jdbcsqlite3-adapter", :platform => :jruby gem "activerecord-jdbcsqlite3-adapter", :platform => :jruby
gem "jdbc-sqlite3", :platform => :jruby gem "jdbc-sqlite3", :platform => :jruby

View file

@ -87,6 +87,7 @@ GEM
multi_json (1.10.1) multi_json (1.10.1)
nokogiri (1.6.6.2) nokogiri (1.6.6.2)
mini_portile (~> 0.6.0) mini_portile (~> 0.6.0)
pg (0.18.1)
posix-spawn (0.3.9) posix-spawn (0.3.9)
protected_attributes (1.0.8) protected_attributes (1.0.8)
activemodel (>= 4.0.1, < 5.0) activemodel (>= 4.0.1, < 5.0)
@ -205,6 +206,7 @@ DEPENDENCIES
jquery-rails jquery-rails
jruby-openssl jruby-openssl
minitest-reporters minitest-reporters
pg
protected_attributes (~> 1.0.6) protected_attributes (~> 1.0.6)
pry-nav pry-nav
pygments.rb pygments.rb

View file

@ -14,7 +14,7 @@ describe 'shoulda-matchers integrates with Rails' do
end end
FILE FILE
run_rake_tasks!('db:migrate', 'db:test:prepare') run_rake_tasks! *%w(db:drop db:create db:migrate)
write_file 'app/models/user.rb', <<-FILE write_file 'app/models/user.rb', <<-FILE
class User < ActiveRecord::Base class User < ActiveRecord::Base

View file

@ -5,6 +5,8 @@ Tests::CurrentBundle.instance.assert_appraisal!
#--- #---
require 'rspec/core' require 'rspec/core'
require 'pry'
require 'pry-nav'
Dir[ File.join(File.expand_path('../support/acceptance/**/*.rb', __FILE__)) ].sort.each do |file| Dir[ File.join(File.expand_path('../support/acceptance/**/*.rb', __FILE__)) ].sort.each do |file|
require file require file

View file

@ -1,5 +1,6 @@
require_relative '../../tests/filesystem'
require_relative '../../tests/bundle' require_relative '../../tests/bundle'
require_relative '../../tests/database'
require_relative '../../tests/filesystem'
module AcceptanceTests module AcceptanceTests
module BaseHelpers module BaseHelpers
@ -10,5 +11,9 @@ module AcceptanceTests
def bundle def bundle
@_bundle ||= Tests::Bundle.new @_bundle ||= Tests::Bundle.new
end end
def database
@_database ||= Tests::Database.instance
end
end end
end end

View file

@ -41,11 +41,15 @@ module AcceptanceTests
end end
def run_rake_tasks(*tasks) def run_rake_tasks(*tasks)
run_command_within_bundle('rake', *tasks) options = tasks.last.is_a?(Hash) ? tasks.pop : {}
args = ['rake', *tasks, '--trace'] + [options]
run_command_within_bundle(*args)
end end
def run_rake_tasks!(*tasks) def run_rake_tasks!(*tasks)
run_command_within_bundle!('rake', *tasks) options = tasks.last.is_a?(Hash) ? tasks.pop : {}
args = ['rake', *tasks, '--trace'] + [options]
run_command_within_bundle!(*args)
end end
end end
end end

View file

@ -2,6 +2,8 @@ require_relative 'file_helpers'
require_relative 'gem_helpers' require_relative 'gem_helpers'
require_relative 'minitest_helpers' require_relative 'minitest_helpers'
require 'yaml'
module AcceptanceTests module AcceptanceTests
module StepHelpers module StepHelpers
include FileHelpers include FileHelpers
@ -72,6 +74,11 @@ module AcceptanceTests
bundle.remove_gem 'debugger' bundle.remove_gem 'debugger'
bundle.remove_gem 'byebug' bundle.remove_gem 'byebug'
bundle.remove_gem 'web-console' bundle.remove_gem 'web-console'
bundle.add_gem 'pg'
end
fs.open('config/database.yml', 'w') do |file|
YAML.dump(database.config.to_hash, file)
end end
end end

View file

@ -134,7 +134,7 @@ Output:
end end
def command def command
([command_prefix] + args).flat_map do |word| ([command_prefix] + args).flatten.flat_map do |word|
Shellwords.split(word) Shellwords.split(word)
end end
end end

View file

@ -0,0 +1,28 @@
require_relative 'database_configuration'
module Tests
class Database
NAME = 'shoulda-matchers-test'
ADAPTER_NAME = ENV.fetch('DATABASE_ADAPTER', 'sqlite3').to_sym
include Singleton
attr_reader :config
def initialize
@config = Tests::DatabaseConfiguration.for(NAME, ADAPTER_NAME)
end
def name
config.database
end
def adapter_name
config.adapter
end
def adapter_class
config.adapter_class
end
end
end

View file

@ -0,0 +1,25 @@
module Tests
module DatabaseAdapters
class PostgreSQL
def self.name
:postgresql
end
attr_reader :database
def initialize(database)
@database = database
end
def adapter
self.class.name
end
def require_dependencies
require 'pg'
end
end
DatabaseConfigurationRegistry.instance.register(PostgreSQL)
end
end

View file

@ -0,0 +1,26 @@
module Tests
module DatabaseAdapters
class SQLite3
def self.name
:sqlite3
end
def initialize(_database)
end
def adapter
self.class.name
end
def database
'db/db.sqlite3'
end
def require_dependencies
require 'sqlite3'
end
end
DatabaseConfigurationRegistry.instance.register(SQLite3)
end
end

View file

@ -0,0 +1,26 @@
require_relative 'database_configuration_registry'
require 'delegate'
module Tests
class DatabaseConfiguration < SimpleDelegator
ENVIRONMENTS = %w(development test production)
def self.for(database_name, adapter_name)
config_class = DatabaseConfigurationRegistry.instance.get(adapter_name)
config = config_class.new(database_name)
new(config)
end
def to_hash
ENVIRONMENTS.each_with_object({}) do |env, config_as_hash|
config_as_hash[env] = inner_config_as_hash
end
end
private
def inner_config_as_hash
{ 'adapter' => adapter.to_s, 'database' => database.to_s }
end
end
end

View file

@ -0,0 +1,28 @@
require 'singleton'
module Tests
class DatabaseConfigurationRegistry
include Singleton
def initialize
@registry = {}
end
def register(config_class)
registry[config_class.name] = config_class
end
def get(name)
registry.fetch(name) do
raise KeyError, "No such adapter registered: #{name}"
end
end
protected
attr_reader :registry
end
end
require_relative 'database_adapters/postgresql'
require_relative 'database_adapters/sqlite3'

View file

@ -0,0 +1,26 @@
module UnitTests
module ColumnTypeHelpers
def self.configure_example_group(example_group)
example_group.include(self)
end
def column_type_class_namespace
if database_adapter == :postgresql
ActiveRecord::ConnectionAdapters::PostgreSQL
else
ActiveRecord::Type
end
end
def column_type_class_for(type)
namespace =
if type == :integer && database_adapter == :postgresql
column_type_class_namespace::OID
else
column_type_class_namespace
end
namespace.const_get(type.to_s.camelize)
end
end
end

View file

@ -0,0 +1,16 @@
module UnitTests
module DatabaseHelpers
def self.configure_example_group(example_group)
example_group.include(self)
example_group.extend(self)
end
def database_adapter
Tests::Database.instance.adapter_name
end
def database_supports_uuid_columns?
database_adapter == :postgresql
end
end
end

View file

@ -66,17 +66,21 @@ module UnitTests
create_table(table_name, &table_block) create_table(table_name, &table_block)
end end
define_model_class(class_name).tap do |model| model = define_model_class(class_name).tap do |m|
if block if block
if block.arity == 0 if block.arity == 0
model.class_eval(&block) m.class_eval(&block)
else else
block.call(model) block.call(m)
end end
end end
model.table_name = table_name m.table_name = table_name
end end
defined_models << model
model
end end
private private
@ -89,6 +93,10 @@ module UnitTests
elsif ActiveRecord::Base.connection_pool.respond_to?(:clear_cache!) elsif ActiveRecord::Base.connection_pool.respond_to?(:clear_cache!)
ActiveRecord::Base.connection_pool.clear_cache! ActiveRecord::Base.connection_pool.clear_cache!
end end
defined_models.each do |model|
model.reset_column_information
end
end end
def drop_created_tables def drop_created_tables
@ -102,5 +110,9 @@ module UnitTests
def created_tables def created_tables
@_created_tables ||= [] @_created_tables ||= []
end end
def defined_models
@_defined_models ||= []
end
end end
end end

View file

@ -1,17 +1,22 @@
require_relative '../tests/command_runner'
require_relative '../tests/filesystem'
require_relative '../tests/bundle' require_relative '../tests/bundle'
require_relative '../tests/command_runner'
require_relative '../tests/database'
require_relative '../tests/filesystem'
require 'yaml'
module UnitTests module UnitTests
class RailsApplication class RailsApplication
def initialize def initialize
@fs = Tests::Filesystem.new @fs = Tests::Filesystem.new
@bundle = Tests::Bundle.new @bundle = Tests::Bundle.new
@database = Tests::Database.instance
end end
def create def create
fs.clean fs.clean
generate generate
fs.within_project do fs.within_project do
install_gems install_gems
remove_unwanted_gems remove_unwanted_gems
@ -54,7 +59,7 @@ module UnitTests
protected protected
attr_reader :fs, :shell, :bundle attr_reader :fs, :shell, :bundle, :database
private private
@ -69,6 +74,7 @@ module UnitTests
def generate def generate
rails_new rails_new
fix_available_locales_warning fix_available_locales_warning
write_database_configuration
end end
def rails_new def rails_new
@ -87,13 +93,18 @@ end
end end
end end
def write_database_configuration
YAML.dump(database.config.to_hash, fs.open('config/database.yml', 'w'))
end
def load_environment def load_environment
require environment_file_path require environment_file_path
end end
def run_migrations def run_migrations
ActiveRecord::Migration.verbose = false fs.within_project do
ActiveRecord::Migrator.migrate(migrations_directory) run_command! 'bundle exec rake db:drop db:create db:migrate'
end
end end
def install_gems def install_gems

View file

@ -237,19 +237,22 @@ describe Shoulda::Matchers::ActiveModel::AllowValueMatcher, type: :model do
context 'when the value is outside of the range of the column' do context 'when the value is outside of the range of the column' do
context 'not qualified with strict' do context 'not qualified with strict' do
it 'rejects, failing with the correct message' do it 'rejects, failing with the correct message' do
attribute_options = { type: :integer, options: { limit: 2 } } type = :integer
attribute_options = { type: type, options: { limit: 2 } }
record = define_model(:example, attr: attribute_options).new record = define_model(:example, attr: attribute_options).new
assertion = -> { expect(record).to allow_value(100000).for(:attr) } assertion = -> { expect(record).to allow_value(100000).for(:attr) }
column_type_class = column_type_class_for(type)
message = <<-MESSAGE.strip_heredoc.strip message = <<-MESSAGE.strip_heredoc.strip
Did not expect errors when attr is set to 100000, Did not expect errors when attr is set to 100000,
got RangeError: "100000 is out of range for ActiveRecord::Type::Integer with limit 2" got RangeError: "100000 is out of range for #{column_type_class} with limit 2"
MESSAGE MESSAGE
expect(&assertion).to fail_with_message(message) expect(&assertion).to fail_with_message(message)
end end
context 'qualified with a message' do context 'qualified with a message' do
it 'ignores any specified message, failing with the correct message' do it 'ignores any specified message, failing with the correct message' do
attribute_options = { type: :integer, options: { limit: 2 } } type = :integer
attribute_options = { type: type, options: { limit: 2 } }
record = define_model(:example, attr: attribute_options).new record = define_model(:example, attr: attribute_options).new
assertion = -> do assertion = -> do
expect(record). expect(record).
@ -257,9 +260,10 @@ describe Shoulda::Matchers::ActiveModel::AllowValueMatcher, type: :model do
for(:attr). for(:attr).
with_message('some message') with_message('some message')
end end
column_type_class = column_type_class_for(type)
message = <<-MESSAGE.strip_heredoc.strip message = <<-MESSAGE.strip_heredoc.strip
Did not expect errors to include "some message" when attr is set to 100000, Did not expect errors to include "some message" when attr is set to 100000,
got RangeError: "100000 is out of range for ActiveRecord::Type::Integer with limit 2" got RangeError: "100000 is out of range for #{column_type_class} with limit 2"
MESSAGE MESSAGE
expect(&assertion).to fail_with_message(message) expect(&assertion).to fail_with_message(message)
end end
@ -269,7 +273,8 @@ describe Shoulda::Matchers::ActiveModel::AllowValueMatcher, type: :model do
if active_model_supports_strict? if active_model_supports_strict?
context 'qualified with strict' do context 'qualified with strict' do
it 'rejects, failing with the correct message' do it 'rejects, failing with the correct message' do
attribute_options = { type: :integer, options: { limit: 2 } } type = :integer
attribute_options = { type: type, options: { limit: 2 } }
record = define_model(:example, attr: attribute_options).new record = define_model(:example, attr: attribute_options).new
assertion = -> do assertion = -> do
expect(record). expect(record).
@ -277,16 +282,18 @@ describe Shoulda::Matchers::ActiveModel::AllowValueMatcher, type: :model do
for(:attr). for(:attr).
strict strict
end end
column_type_class = column_type_class_for(type)
message = <<-MESSAGE.strip_heredoc.strip message = <<-MESSAGE.strip_heredoc.strip
Did not expect an exception to have been raised when attr is set to 100000, Did not expect an exception to have been raised when attr is set to 100000,
got RangeError: "100000 is out of range for ActiveRecord::Type::Integer with limit 2" got RangeError: "100000 is out of range for #{column_type_class} with limit 2"
MESSAGE MESSAGE
expect(&assertion).to fail_with_message(message) expect(&assertion).to fail_with_message(message)
end end
context 'qualified with a message' do context 'qualified with a message' do
it 'ignores any specified message' do it 'ignores any specified message' do
attribute_options = { type: :integer, options: { limit: 2 } } type = :integer
attribute_options = { type: type, options: { limit: 2 } }
record = define_model(:example, attr: attribute_options).new record = define_model(:example, attr: attribute_options).new
assertion = -> do assertion = -> do
expect(record). expect(record).
@ -295,9 +302,10 @@ describe Shoulda::Matchers::ActiveModel::AllowValueMatcher, type: :model do
with_message('some message'). with_message('some message').
strict strict
end end
column_type_class = column_type_class_for(type)
message = <<-MESSAGE.strip_heredoc.strip message = <<-MESSAGE.strip_heredoc.strip
Did not expect exception to include "some message" when attr is set to 100000, Did not expect exception to include "some message" when attr is set to 100000,
got RangeError: "100000 is out of range for ActiveRecord::Type::Integer with limit 2" got RangeError: "100000 is out of range for #{column_type_class} with limit 2"
MESSAGE MESSAGE
expect(&assertion).to fail_with_message(message) expect(&assertion).to fail_with_message(message)
end end
@ -306,4 +314,5 @@ describe Shoulda::Matchers::ActiveModel::AllowValueMatcher, type: :model do
end end
end end
end end
end end

View file

@ -83,19 +83,22 @@ describe Shoulda::Matchers::ActiveModel::DisallowValueMatcher, type: :model do
context 'when the value is outside of the range of the column' do context 'when the value is outside of the range of the column' do
context 'not qualified with strict' do context 'not qualified with strict' do
it 'accepts, failing with the correct message' do it 'accepts, failing with the correct message' do
attribute_options = { type: :integer, options: { limit: 2 } } type = :integer
attribute_options = { type: type, options: { limit: 2 } }
record = define_model(:example, attr: attribute_options).new record = define_model(:example, attr: attribute_options).new
assertion = -> { expect(record).not_to disallow_value(100000).for(:attr) } assertion = -> { expect(record).not_to disallow_value(100000).for(:attr) }
column_type_class = column_type_class_for(type)
message = <<-MESSAGE.strip_heredoc.strip message = <<-MESSAGE.strip_heredoc.strip
Did not expect errors when attr is set to 100000, Did not expect errors when attr is set to 100000,
got RangeError: "100000 is out of range for ActiveRecord::Type::Integer with limit 2" got RangeError: "100000 is out of range for #{column_type_class} with limit 2"
MESSAGE MESSAGE
expect(&assertion).to fail_with_message(message) expect(&assertion).to fail_with_message(message)
end end
context 'qualified with a message' do context 'qualified with a message' do
it 'ignores any specified message, failing with the correct message' do it 'ignores any specified message, failing with the correct message' do
attribute_options = { type: :integer, options: { limit: 2 } } type = :integer
attribute_options = { type: type, options: { limit: 2 } }
record = define_model(:example, attr: attribute_options).new record = define_model(:example, attr: attribute_options).new
assertion = -> do assertion = -> do
expect(record). expect(record).
@ -103,9 +106,10 @@ describe Shoulda::Matchers::ActiveModel::DisallowValueMatcher, type: :model do
for(:attr). for(:attr).
with_message('some message') with_message('some message')
end end
column_type_class = column_type_class_for(type)
message = <<-MESSAGE.strip_heredoc.strip message = <<-MESSAGE.strip_heredoc.strip
Did not expect errors to include "some message" when attr is set to 100000, Did not expect errors to include "some message" when attr is set to 100000,
got RangeError: "100000 is out of range for ActiveRecord::Type::Integer with limit 2" got RangeError: "100000 is out of range for #{column_type_class} with limit 2"
MESSAGE MESSAGE
expect(&assertion).to fail_with_message(message) expect(&assertion).to fail_with_message(message)
end end
@ -115,7 +119,8 @@ describe Shoulda::Matchers::ActiveModel::DisallowValueMatcher, type: :model do
if active_model_supports_strict? if active_model_supports_strict?
context 'qualified with strict' do context 'qualified with strict' do
it 'accepts, failing with the correct message' do it 'accepts, failing with the correct message' do
attribute_options = { type: :integer, options: { limit: 2 } } type = :integer
attribute_options = { type: type, options: { limit: 2 } }
record = define_model(:example, attr: attribute_options).new record = define_model(:example, attr: attribute_options).new
assertion = -> do assertion = -> do
expect(record). expect(record).
@ -123,16 +128,18 @@ describe Shoulda::Matchers::ActiveModel::DisallowValueMatcher, type: :model do
for(:attr). for(:attr).
strict strict
end end
column_type_class = column_type_class_for(type)
message = <<-MESSAGE.strip_heredoc.strip message = <<-MESSAGE.strip_heredoc.strip
Did not expect an exception to have been raised when attr is set to 100000, Did not expect an exception to have been raised when attr is set to 100000,
got RangeError: "100000 is out of range for ActiveRecord::Type::Integer with limit 2" got RangeError: "100000 is out of range for #{column_type_class} with limit 2"
MESSAGE MESSAGE
expect(&assertion).to fail_with_message(message) expect(&assertion).to fail_with_message(message)
end end
context 'qualified with a message' do context 'qualified with a message' do
it 'ignores any specified message' do it 'ignores any specified message' do
attribute_options = { type: :integer, options: { limit: 2 } } type = :integer
attribute_options = { type: type, options: { limit: 2 } }
record = define_model(:example, attr: attribute_options).new record = define_model(:example, attr: attribute_options).new
assertion = -> do assertion = -> do
expect(record). expect(record).
@ -141,9 +148,10 @@ describe Shoulda::Matchers::ActiveModel::DisallowValueMatcher, type: :model do
with_message('some message'). with_message('some message').
strict strict
end end
column_type_class = column_type_class_for(type)
message = <<-MESSAGE.strip_heredoc.strip message = <<-MESSAGE.strip_heredoc.strip
Did not expect exception to include "some message" when attr is set to 100000, Did not expect exception to include "some message" when attr is set to 100000,
got RangeError: "100000 is out of range for ActiveRecord::Type::Integer with limit 2" got RangeError: "100000 is out of range for #{column_type_class} with limit 2"
MESSAGE MESSAGE
expect(&assertion).to fail_with_message(message) expect(&assertion).to fail_with_message(message)
end end

View file

@ -16,15 +16,6 @@ describe Shoulda::Matchers::ActiveRecord::ValidateUniquenessOfMatcher, type: :mo
) )
expect(record).to validate_uniqueness.scoped_to(:scope1, :scope2) expect(record).to validate_uniqueness.scoped_to(:scope1, :scope2)
end end
it 'still accepts if the value of the scope is nil' do
record = build_record_validating_uniqueness(
scopes: [
build_attribute(name: :scope, value: nil)
]
)
expect(record).to validate_uniqueness.scoped_to(:scope)
end
end end
context 'when the subject is an existing record' do context 'when the subject is an existing record' do
@ -38,15 +29,6 @@ describe Shoulda::Matchers::ActiveRecord::ValidateUniquenessOfMatcher, type: :mo
expect(record).to validate_uniqueness.scoped_to(:scope1, :scope2) expect(record).to validate_uniqueness.scoped_to(:scope1, :scope2)
end end
it 'still accepts if the value of the scope is nil' do
record = create_record_validating_uniqueness(
scopes: [
build_attribute(name: :scope, value: nil)
]
)
expect(record).to validate_uniqueness.scoped_to(:scope)
end
end end
end end
@ -330,9 +312,11 @@ describe Shoulda::Matchers::ActiveRecord::ValidateUniquenessOfMatcher, type: :mo
value_type: :time value_type: :time
end end
context 'when one of the scoped attributes is a UUID column' do if database_supports_uuid_columns?
include_context 'it supports scoped attributes of a certain type', context 'when one of the scoped attributes is a UUID column' do
column_type: :uuid include_context 'it supports scoped attributes of a certain type',
column_type: :uuid
end
end end
end end

View file

@ -51,6 +51,8 @@ RSpec.configure do |config|
UnitTests::RailsVersions.configure_example_group(config) UnitTests::RailsVersions.configure_example_group(config)
UnitTests::ActiveRecordVersions.configure_example_group(config) UnitTests::ActiveRecordVersions.configure_example_group(config)
UnitTests::ActiveModelVersions.configure_example_group(config) UnitTests::ActiveModelVersions.configure_example_group(config)
UnitTests::DatabaseHelpers.configure_example_group(config)
UnitTests::ColumnTypeHelpers.configure_example_group(config)
config.include UnitTests::Matchers config.include UnitTests::Matchers
end end