diff -Nru ruby-shoulda-matchers-2.8.0/Appraisals ruby-shoulda-matchers-4.3.0/Appraisals --- ruby-shoulda-matchers-2.8.0/Appraisals 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/Appraisals 2020-02-18 07:23:52.000000000 +0000 @@ -1,128 +1,136 @@ -ruby_version = Gem::Version.new(RUBY_VERSION + '') +# Note: All of the dependencies here were obtained by running `rails new` with +# various versions of Rails and copying lines from the generated Gemfile. It's +# best to keep the gems here in the same order as they're listed there so you +# can compare them more easily. -spring = proc do +# Needed for Rails 5+ controller tests +controller_test_dependency = proc do + gem 'rails-controller-testing', '>= 1.0.1' +end + +shared_spring_dependencies = proc do gem 'spring' gem 'spring-commands-rspec' end -rails_3 = proc do - gem 'strong_parameters' - gem 'rspec-rails', '2.99.0' - gem 'minitest', '~> 4.0' - gem 'minitest-reporters' +shared_test_dependencies = proc do + gem 'rspec-rails', '~> 3.9' + gem 'shoulda-context', '~> 1.2.0' end -rails_3_1 = proc do - instance_eval(&rails_3) - gem 'rails', '~> 3.1.8' - gem 'bcrypt-ruby', '~> 3.0.0' - gem 'jquery-rails' - gem 'sass-rails', '~> 3.1.5' - gem 'coffee-rails', '~> 3.1.1' - gem 'uglifier', '>= 1.0.3' - gem 'rspec-rails', '2.99.0' - gem 'minitest', '~> 4.0' - gem 'minitest-reporters' +shared_dependencies = proc do + instance_eval(&shared_spring_dependencies) + instance_eval(&shared_test_dependencies) end -rails_3_2 = proc do - instance_eval(&rails_3) - gem 'rails', '~> 3.2.13' - gem 'bcrypt-ruby', '~> 3.0.0' - gem 'jquery-rails' - gem 'sass-rails', '~> 3.2.3' - gem 'coffee-rails', '~> 3.2.1' - gem 'uglifier', '>= 1.0.3' - gem 'minitest', '~> 4.0' - gem 'minitest-reporters' -end +appraise 'rails_4_2' do + instance_eval(&shared_dependencies) -rails_4 = proc do - instance_eval(&spring) + gem 'rails', '4.2.11.1' + gem 'sass-rails', '~> 5.0' gem 'uglifier', '>= 1.3.0' - gem 'coffee-rails', '~> 4.0.0' + gem 'coffee-rails', '~> 4.1.0' gem 'jquery-rails' gem 'turbolinks' - gem 'sdoc' - gem 'activeresource', '4.0.0' - gem 'rspec-rails', '~> 3.0.1' - # Test suite makes heavy use of attr_accessible - gem 'protected_attributes' - gem 'minitest-reporters' -end - -#--- - -if Gem::Requirement.new('< 2').satisfied_by?(ruby_version) - appraise '3.0' do - instance_eval(&rails_3) - gem 'rails', '~> 3.0.17' - end + gem 'jbuilder', '~> 2.0' + gem 'sdoc', '~> 0.4.0', group: :doc + gem 'bcrypt', '~> 3.1.7' - if Gem::Requirement.new('= 1.9.2').satisfied_by?(ruby_version) - appraise '3.1-1.9.2' do - instance_eval(&rails_3_1) - gem 'turn', '0.8.2' - end - else - appraise '3.1' do - instance_eval(&rails_3_1) - gem 'turn', '~> 0.8.3' - end - end -end + # Other dependencies + gem 'activeresource', '4.0.0' + gem 'json', '~> 1.4' + gem 'protected_attributes', '~> 1.0.6' -if Gem::Requirement.new('= 1.9.2').satisfied_by?(ruby_version) - appraise '3.2-1.9.2' do - instance_eval(&rails_3_2) - end -else - appraise '3.2' do - instance_eval(&rails_3_2) - instance_eval(&spring) - end + # Database adapters + gem 'pg', '~> 0.18' + gem 'sqlite3', '~> 1.3.6' end -if Gem::Requirement.new('> 1.9.2').satisfied_by?(ruby_version) - appraise '4.0.0' do - instance_eval(&rails_4) - gem 'rails', '4.0.0' - gem 'jbuilder', '~> 1.2' - gem 'sass-rails', '~> 4.0.0' - gem 'bcrypt-ruby', '~> 3.0.0' - end - - appraise '4.0.1' do - instance_eval(&rails_4) - gem 'rails', '4.0.1' - gem 'jbuilder', '~> 1.2' - gem 'sass-rails', '~> 4.0.0' - gem 'bcrypt-ruby', '~> 3.1.2' - gem 'rspec-rails', '2.99.0' - end +appraise 'rails_5_0' do + instance_eval(&shared_dependencies) + instance_eval(&controller_test_dependency) - appraise '4.1' do - instance_eval(&rails_4) - gem 'rails', '~> 4.1.0' - gem 'jbuilder', '~> 2.0' - gem 'sass-rails', '~> 4.0.3' - gem 'sdoc', '~> 0.4.0' - gem 'bcrypt', '~> 3.1.7' - gem 'protected_attributes', "~> 1.0.6" - gem 'spring' - end - - appraise '4.2' do - instance_eval(&rails_4) - gem 'rails', '~> 4.2.0' - gem 'sass-rails', '~> 5.0' - gem 'coffee-rails', '~> 4.1.0' - gem 'jbuilder', '~> 2.0' - gem 'sdoc', '~> 0.4.0' + gem 'rails', '5.0.7.2' + gem 'puma', '~> 3.0' + gem 'sass-rails', '~> 5.0' + gem 'jquery-rails' + gem 'turbolinks', '~> 5' + gem 'jbuilder', '~> 2.5' + gem 'bcrypt', '~> 3.1.7' + gem 'listen', '~> 3.0.5' + gem 'spring-watcher-listen', '~> 2.0.0' + + # Database adapters + gem 'pg', '~> 0.18' + gem 'sqlite3', '~> 1.3.6' +end + +appraise 'rails_5_1' do + instance_eval(&shared_dependencies) + instance_eval(&controller_test_dependency) + + gem 'rails', '5.1.7' + gem 'puma', '~> 3.7' + gem 'sass-rails', '~> 5.0' + gem 'turbolinks', '~> 5' + gem 'jbuilder', '~> 2.5' + gem 'bcrypt', '~> 3.1.7' + gem 'capybara', '~> 2.13' + gem 'selenium-webdriver' + gem 'listen', '>= 3.0.5', '< 3.2' + gem 'spring-watcher-listen', '~> 2.0.0' + + # Database adapters + gem 'pg', '~> 0.18' + gem 'sqlite3', '~> 1.3.6' +end + +appraise 'rails_5_2' do + instance_eval(&shared_dependencies) + instance_eval(&controller_test_dependency) + + gem 'rails', '5.2.4.1' + gem 'puma', '~> 3.11' + gem 'bootsnap', '>= 1.1.0', require: false + gem 'sass-rails', '~> 5.0' + gem 'turbolinks', '~> 5' + gem 'jbuilder', '~> 2.5' + gem 'bcrypt', '~> 3.1.7' + gem 'capybara', '~> 3.1.1' + gem 'selenium-webdriver' + gem 'chromedriver-helper' + gem 'listen', '>= 3.0.5', '< 3.2' + gem 'spring-watcher-listen', '~> 2.0.0' + + # Database adapters + gem 'pg', '~> 0.18' + gem 'sqlite3', '~> 1.3.6' +end + +if Gem::Requirement.new('>= 2.5.0').satisfied_by?(Gem::Version.new(RUBY_VERSION)) + appraise 'rails_6_0' do + instance_eval(&shared_dependencies) + instance_eval(&controller_test_dependency) + + gem 'rails', '6.0.2.1' + gem 'puma', '~> 4.1' + gem 'bootsnap', '>= 1.4.2', require: false + gem 'sass-rails', '>= 6' + gem 'webpacker', '~> 4.0' + gem 'turbolinks', '~> 5' + gem 'jbuilder', '~> 2.7' gem 'bcrypt', '~> 3.1.7' - gem 'byebug' - gem 'web-console', '~> 2.0' - gem 'spring' - gem 'protected_attributes', "~> 1.0.6" + gem 'capybara', '>= 2.15' + gem 'listen', '>= 3.0.5', '< 3.2' + gem 'spring-watcher-listen', '~> 2.0.0' + gem 'selenium-webdriver' + gem 'webdrivers' + + # Other dependencies + gem 'actiontext', '~> 6.0.2.1' + + # Database adapters + gem 'pg', '>= 0.18', '< 2.0' + gem 'sqlite3', '~> 1.4' end end diff -Nru ruby-shoulda-matchers-2.8.0/bin/setup ruby-shoulda-matchers-4.3.0/bin/setup --- ruby-shoulda-matchers-2.8.0/bin/setup 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/bin/setup 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,201 @@ +#!/usr/bin/env bash + +set -euo pipefail + +RUBY_VERSION=$(script/supported_ruby_versions | xargs -n 1 echo | sort -V | tail -n 1) +required_ruby_version=$(cat .ruby-version) + +cd "$(dirname "$(dirname "$0")")" + +uname=$(uname) + +if [[ $uname == 'Darwin' ]]; then + platform='mac' +else + platform='linux' +fi + +banner() { + echo -e "\033[34m== $@ ==\033[0m" +} + +success() { + echo -e "\033[32m$@\033[0m" +} + +warning() { + echo -e "\033[33m$@\033[0m" +} + +error() { + echo -e "\033[31m$@\033[0m" +} + +echo-wrapped() { + echo "$@" | fmt -w 80 | cat +} + +has-executable() { + type "$1" &>/dev/null +} + +is-running() { + pgrep "$1" >/dev/null +} + +start() { + if has-executable brew; then + brew services start "$1" + else + sudo service "${2:-$1}" start + fi +} + +install() { + local apt_package="" + local rpm_package="" + local brew_package="" + local default_package="" + local package="" + + for arg in "$@"; do + case $arg in + apt=*) + apt_package="${arg#apt=}" + ;; + rpm=*) + rpm_package="${arg#rpm=}" + ;; + brew=*) + brew_package="${arg#brew=}" + ;; + *) + default_package="$arg" + ;; + esac + done + + if has-executable brew; then + package="${brew_package:-$default_package}" + + if [[ -n $package ]]; then + brew install "$package" + fi + elif has-executable apt-get; then + package="${apt_package:-$default_package}" + + if [[ -n $package ]]; then + sudo apt-get install -y "$package" + fi + elif has-executable yum; then + package="${yum_package:-$default_package}" + + if [[ -n $package ]]; then + sudo yum install -y "$package" + fi + else + error "Sorry, I'm not sure how to install $default_package." + exit 1 + fi +} + +check-for-build-tools() { + if [[ $platform == "linux" ]]; then + if ! has-executable apt-get; then + error "You don't seem to have a package manager installed." + echo-wrapped "\ +The setup script assumes you're using Debian or a Debian-derived flavor of +Linux (i.e. something with Apt). If this is not the case, then we would +gladly take a PR fixing this!" + exit 1 + fi + + # TODO: Check if build-essential is installed on Debian? + else + if ! has-executable brew; then + error "You don't seem to have Homebrew installed." + echo-wrapped "\ +Follow the instructions here to do this: + + http://brew.sh + +Then re-run this script." + exit 1 + fi + + # TODO: Check that OS X Command Line Tools are installed? + fi +} + +install-development-libraries() { + install apt=ruby-dev rpm=ruby-devel + install rpm=zlib-devel +} + +install-dependencies() { + if ! has-executable sqlite3; then + banner 'Installing SQLite 3' + install sqlite3 + install apt=libsqlite3-dev rpm=sqlite-devel + fi + + if ! has-executable psql; then + banner 'Installing PostgreSQL' + install postgresql + install apt=libpq-dev rpm=postgresql-devel + fi + + if ! is-running postgres; then + banner 'Starting PostgreSQL' + start postgresql + fi + + if ! has-executable heroku; then + banner 'Installing Heroku' + install brew=heroku/brew/heroku heroku + fi + + if has-executable rbenv; then + if ! (rbenv versions | grep $RUBY_VERSION'\>' &>/dev/null); then + banner "Installing Ruby $RUBY_VERSION with rbenv" + rbenv install --skip-existing "$RUBY_VERSION" + fi + elif has-executable chruby-exec; then + PREFIX='' source /usr/local/share/chruby/chruby.sh + if ! (chruby '' | grep $RUBY_VERSION'\>' &>/dev/null); then + if has-executable install-ruby; then + banner "Installing Ruby $RUBY_VERSION with install-ruby" + install-ruby "$RUBY_VERSION" + else + error "Please install Ruby $RUBY_VERSION" + fi + fi + elif has-executable rvm; then + if ! (rvm list | grep $required_ruby_version'\>' &>/dev/null); then + banner "Installing Ruby $required_ruby_version with rvm" + rvm install $required_ruby_version + rvm use $required_ruby_version + fi + else + error "You don't seem to have a Ruby manager installed." + echo-wrapped "\ +We recommend using rbenv. You can find instructions to install it here: + + https://github.com/rbenv/rbenv#installation + +Make sure to follow the instructions to configure your shell so that rbenv is +automatically loaded. + +When you're done, open up a new terminal tab and re-run this script." + exit 1 + fi + + banner 'Installing Ruby dependencies' + gem install bundler -v '~> 1.0' --conservative + bundle check || bundle install + bundle exec appraisal install +} + +check-for-build-tools +install-development-libraries +install-dependencies diff -Nru ruby-shoulda-matchers-2.8.0/CONTRIBUTING.md ruby-shoulda-matchers-4.3.0/CONTRIBUTING.md --- ruby-shoulda-matchers-2.8.0/CONTRIBUTING.md 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/CONTRIBUTING.md 2020-02-18 07:23:52.000000000 +0000 @@ -1,25 +1,214 @@ -We love contributions from the community! Here's a quick guide to making a pull -request: +# Contributing to Shoulda Matchers -1. Fork the repo. +Although we are always happy to make improvements to Shoulda Matchers, we also +welcome changes and improvements from the community! -2. Run the tests. We only take pull requests with passing tests, and it's great -to know that you have a clean slate: `bundle && bundle exec rake` +Have a fix for a problem you've been running into or an idea for a new feature +you think would be useful? Here's what you need to do: -3. If you're adding functionality or fixing a bug, add a failing test for the -issue first. +1. [Read and understand the Code of Conduct](#code-of-conduct). +1. Fork this repo and clone your fork to somewhere on your machine. +1. [Ensure that you have a working environment](#setting-up-your-environment). +1. Read up on the [architecture of the gem](#architecture), [how to run + tests](#running-tests), and [the code style we use in this + project](#code-style). +1. Cut a new branch and write a failing test for the feature or bugfix you plan + on implementing. +1. [Make sure your branch is well managed as you go + along](#managing-your-branch). +1. [Update the inline documentation if you're making a change to the + API](#documentation). +1. [Refrain from updating the changelog.](#a-word-on-the-changelog) +1. Push to your fork and submit a pull request. +1. [Ensure that the test suite passes on Travis and make any necessary changes + to your branch to bring it to green.](#continuous-integration) -4. Make the test pass. +Although we maintain Shoulda Matchers in our free time, we try to respond to +contributions in a timely manner. Once we look at your pull request, we may give +you feedback. For instance, we may suggest some changes to make to your code to +fit within the project style or discuss alternate ways of addressing the issue +in question. Assuming we're happy with everything, we'll then bring your changes +into master. Now you're a contributor! -5. If you're adding a new feature, ensure that the documentation is up to date -(see the README for instructions on previewing documentation live). +--- -6. Finally, push to your fork and submit a pull request. +## Code of Conduct -At this point you're waiting on us. We try to respond to issues and pull -requests within a few business days. We may suggest some changes to make to your -code to fit with our [code style] or the project style, or discuss alternate -ways of addressing the issue in question. When we're happy with everything, -we'll bring your changes into master. Now you're a contributor! +If this is your first time contributing, please read the [Code of Conduct]. We +want to create a space in which everyone is allowed to contribute, and we +enforce the policies outline in this document. -[code style]: https://github.com/thoughtbot/guides/tree/master/style +[Code of Conduct]: https://thoughtbot.com/open-source-code-of-conduct + +## Setting up your environment + +The setup script will install all dependencies necessary for working on the +project: + +```bash +bin/setup +``` + +## Architecture + +This project follows the typical structure for a gem: code is located in `lib` +and tests are in `spec`. + +### Matchers + +All of the matchers are broken up by the type of example group they apply to: + +* `{lib,spec/unit}/shoulda/matchers/action_controller*` for ActionController + matchers +* `{lib,spec/unit}/shoulda/matchers/active_model*` for ActiveModel matchers +* `{lib,spec/unit}/shoulda/matchers/active_record*` for ActiveRecord matchers +* `{lib,spec/unit}/shoulda/matchers/independent*` for matchers that can be used + in any example group + +There are other files in the project, of course, but these are likely the ones +you'll be most interested in. + +### Tests + +In addition, tests are broken up into two categories: + +* `spec/unit` — low-level tests for individual matchers (you're probably + interested in these) +* `spec/acceptance` — high-level tests to ensure that the gem works in Rails + projects, plain Ruby projects, etc. (these do not need to get updated often) + +A word about the tests, by the way: they're admittedly the most complicated part +of this gem, and there are a few different strategies that we've introduced at +various points in time to set up objects for tests across all specs, some of +which are old and some of which are new. The best approach for writing tests is +probably to copy an existing test in the same file as where you want to add a +new test. + +## Code style + +We follow a derivative of the [unofficial Ruby style guide] created by the +Rubocop developers. You can view our Rubocop configuration [here], but here are +some key differences: + +* Use single quotes for strings. +* When breaking up methods across multiple lines, place the `.` at the end of + the line instead of the beginning. +* Don't use conditional modifiers (i.e. `x if y`); place the beginning and + ending of conditionals on their own lines. +* Use an 80-character line-length except for `describe`, `context`, `it`, and + `specify` lines in tests. +* For arrays, hashes, and method arguments that span multiple lines, place a + trailing comma at the end of the last item. +* Collection methods are spelled `detect`, `inject`, `map`, and `select`. + +[unofficial Ruby style guide]: https://github.com/rubocop-hq/ruby-style-guide +[here]: .rubocop.yml + +## Running tests + +### A word about Appraisals + +Because the gem supports multiple Ruby and Rails versions, we have to be able +to test against them as well. + +Oftentimes it is enough to use whatever Ruby version you have on your computer, +but if you are fixing a bug that targets a specific Ruby version, you'll want to +make sure to switch to that using your Ruby manager of choice before you run any +tests. + +If you are fixing a bug for a specific _Rails_ version, then you'll want to use +a specific "appraisal" when running a test. [Appraisals] are Gemfiles centered +around a Rails version. What this means is that when running tests, you have to +specify which one to use. You do this by using this command: + +```bash +bundle exec appraisal ... +``` + +You can find the available list of appraisals by running: + +```bash +bundle exec appraisal list +``` + +[Appraisals]: https://github.com/thoughtbot/appraisal + +### Unit tests + +Unit tests are the most common kind of tests in the gem. They exercise matcher +code file by file in the context of a real Rails application. This application +is created and loaded every time you start running tests. + +To run a unit test, you might say something like: + +```bash +bundle exec appraisal rails_5_2 rspec spec/unit/shoulda/matchers/active_model/validate_inclusion_of_matcher_spec.rb +``` + +### Acceptance tests + +The acceptance tests exercise matchers in the context of a real Ruby or Rails +application. Unlike unit tests, this application is set up and torn down for +each test. + +To run an acceptance test, you might say something like: + +```bash +bundle exec appraisal rails_5_2 rspec spec/acceptance/rails_integration_spec.rb +``` + +### All tests + +In order to run all of the tests, simply run: + +```bash +bundle exec rake +``` + +## Managing your branch + +* Use well-crafted commit messages, providing context if possible. [Tim Pope's + guide] was a wonderful piece on this topic when it came out and we still find + it to be helpful even today. +* Squash "WIP" commits and remove merge commits by rebasing your branch against + `master`. We try to keep our commit history as clean as possible. + +[Tim Pope's guide]: https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html + +## Documentation + +As you navigate the codebase, you may notice certain classes and methods that +are prefaced with inline documentation. This documentation is written and +generated using [YARD][yard] and is published [online][rubydocs]. + +[rubydocs]: https://matchers.shoulda.io/docs +[yard]: https://github.com/lsegal/yard + +We ensure that the documentation is up to date before we issue a release, but +sometimes we don't catch everything. So if your changes end up extending or +updating the API, it helps us greatly to update the docs at the same time. + +## A word on the changelog + +You may also notice that we have a changelog in the form of [NEWS.md](NEWS.md). +You may be tempted to include changes to this in your branch, but don't worry +about this — we'll take care of it! + +## Continuous integration + +While running `bundle exec rake` is a great way to check your work, this command +will only run your tests against the latest supported Ruby and Rails version. +Ultimately, though, you'll want to ensure that your changes work in all possible +environments. We make use of [Travis][travis] to do this work for us. Travis +will kick in after you push up a branch or open a PR. It takes 20-30 minutes to +run a complete build, which you are free to +[monitor as it progresses][shoulda-matchers-on-travis]. + +[shoulda-matchers-on-travis]: https://travis-ci.org/thoughtbot/shoulda-matchers + +What happens if the build fails in some way? Don't fear! Click on a failed job +and scroll through its output to determine the cause of the failure. You'll want +to make changes to your branch and push them up until the entire build is green. +It may take a bit of time, but overall it is worth it and it helps us immensely! + +[travis]: https://travis-ci.org/ diff -Nru ruby-shoulda-matchers-2.8.0/cucumber.yml ruby-shoulda-matchers-4.3.0/cucumber.yml --- ruby-shoulda-matchers-2.8.0/cucumber.yml 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/cucumber.yml 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -without_spring: --tags ~@spring diff -Nru ruby-shoulda-matchers-2.8.0/custom_plan.rb ruby-shoulda-matchers-4.3.0/custom_plan.rb --- ruby-shoulda-matchers-2.8.0/custom_plan.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/custom_plan.rb 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,104 @@ +require 'zeus' +require 'zeus/plan' +require_relative 'spec/support/tests/current_bundle' + +class CouldNotBootZeusError < StandardError + def self.create(underlying_error:) + new(<<-MESSAGE) +Couldn't boot Zeus. + +Bundler tried to load a gem that has already been loaded (but the +versions are different). + +Note that Appraisal requires Rake, and so you'll want to make sure that +the Gemfile is pointing to the same version of Rake that you have +installed locally. + +The original message is as follows: + +#{underlying_error.message} + MESSAGE + end +end + +class CustomPlan < Zeus::Plan + def boot + ENV['BUNDLE_GEMFILE'] = File.expand_path( + "../gemfiles/#{latest_appraisal}.gemfile", + __FILE__ + ) + + require 'bundler/setup' + + $LOAD_PATH << File.expand_path('../lib', __FILE__) + $LOAD_PATH << File.expand_path('../spec', __FILE__) + + require_relative 'spec/support/unit/load_environment' + rescue Gem::LoadError => error + raise CouldNotBootZeusError.create(underlying_error: error) + end + + def after_fork + end + + def test_environment + require_relative 'spec/unit_spec_helper' + end + + def rspec + ARGV.replace(file_paths_to_run) + RSpec::Core::Runner.invoke + end + + private + + def latest_appraisal + current_bundle.latest_appraisal + end + + def current_bundle + Tests::CurrentBundle.instance + end + + def file_paths_to_run + if given_file_paths.empty? + ['spec/unit'] + else + given_file_paths.map do |given_path| + determine_file_path_to_run(given_path) + end + end + end + + def determine_file_path_to_run(given_rspec_argument) + expanded_file_path, location = + expand_rspec_argument(given_rspec_argument) + + if File.exist?(expanded_file_path) + if location + expanded_file_path + location + else + expanded_file_path + end + else + given_rspec_argument + end + end + + def expand_rspec_argument(rspec_argument) + match = rspec_argument.match(/\A(.+?)(:\d+|\[[\d:]+\])?\Z/) + file_path, location = match.captures + expanded_file_path = File.expand_path( + "../spec/unit/shoulda/matchers/#{file_path}", + __FILE__ + ) + + [expanded_file_path, location] + end + + def given_file_paths + ARGV + end +end + +Zeus.plan = CustomPlan.new diff -Nru ruby-shoulda-matchers-2.8.0/debian/changelog ruby-shoulda-matchers-4.3.0/debian/changelog --- ruby-shoulda-matchers-2.8.0/debian/changelog 2016-07-15 00:44:31.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/debian/changelog 2020-09-04 09:15:32.000000000 +0000 @@ -1,3 +1,44 @@ +ruby-shoulda-matchers (4.3.0-2) unstable; urgency=medium + + [ Debian Janitor ] + * Set upstream metadata fields: Bug-Database, Bug-Submit, Repository, + Repository-Browse. + + [ Pirate Praveen ] + * Add Breaks: ruby-shoulda (<< 4.0~) + * Fix path for removing bin/setup + * Advertize repackaged source in version + * Reupload to unstable + + [ Cédric Boutillier ] + * Update team name + * Add .gitattributes to keep unwanted files out of the source package + + -- Pirate Praveen Fri, 04 Sep 2020 14:45:32 +0530 + +ruby-shoulda-matchers (4.3.0-1) experimental; urgency=medium + + [ Andrew Lee (李健秋) ] + * Added debian/ruby-tests.rake. + * Apply drop-git-in-gemspec.patch. + * debian/watch: fetch tarball from upstream's github instead. + * New upstream version 3.1.2 + * Refresh drop-git-in-gemspec.patch. + + [ Utkarsh Gupta ] + * Add salsa-ci.yml + + [ Pirate Praveen ] + * New upstream version 4.3.0 + * Use salsa.debian.org in Vcs-* fields + * Bump Standards-Version to 4.5.0 (no changes needed) + * Drop compat file, rely on debhelper-compat and bump compat level to 12 + * Refresh patches + * Disable tests (TODO: try fixing the tests) + * Add myself to uploaders + + -- Pirate Praveen Tue, 25 Feb 2020 14:57:45 +0530 + ruby-shoulda-matchers (2.8.0-1) unstable; urgency=low [ Antonio Terceiro] diff -Nru ruby-shoulda-matchers-2.8.0/debian/compat ruby-shoulda-matchers-4.3.0/debian/compat --- ruby-shoulda-matchers-2.8.0/debian/compat 2016-07-15 00:44:31.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/debian/compat 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -9 diff -Nru ruby-shoulda-matchers-2.8.0/debian/control ruby-shoulda-matchers-4.3.0/debian/control --- ruby-shoulda-matchers-2.8.0/debian/control 2016-07-15 00:44:31.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/debian/control 2020-09-04 09:15:32.000000000 +0000 @@ -1,16 +1,16 @@ Source: ruby-shoulda-matchers Section: ruby Priority: optional -Maintainer: Debian Ruby Extras Maintainers -Uploaders: Antonio Terceiro -Build-Depends: debhelper (>= 9~), +Maintainer: Debian Ruby Team +Uploaders: Pirate Praveen +Build-Depends: debhelper-compat (= 12), gem2deb, rake, ruby-activesupport (>= 2:3.0.0), ruby-rspec -Standards-Version: 3.9.8 -Vcs-Git: https://anonscm.debian.org/git/pkg-ruby-extras/ruby-shoulda-matchers.git -Vcs-Browser: https://anonscm.debian.org/cgit/pkg-ruby-extras/ruby-shoulda-matchers.git +Standards-Version: 4.5.0 +Vcs-Git: https://salsa.debian.org/ruby-team/ruby-shoulda-matchers.git +Vcs-Browser: https://salsa.debian.org/ruby-team/ruby-shoulda-matchers Homepage: https://github.com/thoughtbot/shoulda-matchers Testsuite: autopkgtest-pkg-ruby XS-Ruby-Versions: all @@ -22,6 +22,7 @@ ruby-activesupport (>= 2:3.0.0), ${misc:Depends}, ${shlibs:Depends} +Breaks: ruby-shoulda (<< 4.0~) Description: Test helpers for Rails applications, compatible with Test::Unit and RSpec Test::Unit- and RSpec-compatible one-liners that test common Rails functionality. These tests would otherwise be much longer, more complex, and diff -Nru ruby-shoulda-matchers-2.8.0/debian/patches/drop-git-in-gemspec.patch ruby-shoulda-matchers-4.3.0/debian/patches/drop-git-in-gemspec.patch --- ruby-shoulda-matchers-2.8.0/debian/patches/drop-git-in-gemspec.patch 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/debian/patches/drop-git-in-gemspec.patch 2020-09-04 09:15:32.000000000 +0000 @@ -0,0 +1,12 @@ +git is not present in debian build system + +--- a/shoulda-matchers.gemspec ++++ b/shoulda-matchers.gemspec +@@ -31,6 +31,7 @@ + `git ls-files -z -- {docs,lib,README.md,MIT-LICENSE,shoulda-matchers.gemspec}`. + split("\x0") + end ++ s.files = Dir.glob("**/*").select {|v| v !~ /^(debian|test|spec|features)/} + s.require_paths = ['lib'] + + s.required_ruby_version = '>= 2.4.0' diff -Nru ruby-shoulda-matchers-2.8.0/debian/patches/series ruby-shoulda-matchers-4.3.0/debian/patches/series --- ruby-shoulda-matchers-2.8.0/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/debian/patches/series 2020-09-04 09:15:32.000000000 +0000 @@ -0,0 +1 @@ +drop-git-in-gemspec.patch diff -Nru ruby-shoulda-matchers-2.8.0/debian/ruby-tests.rake.disabled ruby-shoulda-matchers-4.3.0/debian/ruby-tests.rake.disabled --- ruby-shoulda-matchers-2.8.0/debian/ruby-tests.rake.disabled 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/debian/ruby-tests.rake.disabled 2020-09-04 09:15:32.000000000 +0000 @@ -0,0 +1,6 @@ +require 'gem2deb/rake/spectask' + +Gem2Deb::Rake::RSpecTask.new do |spec| + spec.pattern = './spec/**/*_spec_helper.rb' +end + diff -Nru ruby-shoulda-matchers-2.8.0/debian/rules ruby-shoulda-matchers-4.3.0/debian/rules --- ruby-shoulda-matchers-2.8.0/debian/rules 2016-07-15 00:44:31.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/debian/rules 2020-09-04 09:15:32.000000000 +0000 @@ -8,3 +8,7 @@ clean: dh clean --buildsystem=ruby --with ruby rm -rf tmp log + +override_dh_auto_install: + dh_auto_install + rm -rf debian/ruby-shoulda-matchers/usr/bin diff -Nru ruby-shoulda-matchers-2.8.0/debian/upstream/metadata ruby-shoulda-matchers-4.3.0/debian/upstream/metadata --- ruby-shoulda-matchers-2.8.0/debian/upstream/metadata 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/debian/upstream/metadata 2020-09-04 09:15:32.000000000 +0000 @@ -0,0 +1,4 @@ +Bug-Database: https://github.com/thoughtbot/shoulda-matchers/issues +Bug-Submit: https://github.com/thoughtbot/shoulda-matchers/issues/new +Repository: https://github.com/thoughtbot/shoulda-matchers.git +Repository-Browse: https://github.com/thoughtbot/shoulda-matchers diff -Nru ruby-shoulda-matchers-2.8.0/debian/watch ruby-shoulda-matchers-4.3.0/debian/watch --- ruby-shoulda-matchers-2.8.0/debian/watch 2016-07-15 00:44:31.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/debian/watch 2020-09-04 09:15:32.000000000 +0000 @@ -1,2 +1,7 @@ version=3 -http://pkg-ruby-extras.alioth.debian.org/cgi-bin/gemwatch/shoulda-matchers .*/shoulda-matchers-(.*).tar.gz +opts=\ +repacksuffix=+dfsg,\ +repack,compression=xz,\ +dversionmangle=s/[\~\+]?dfsg.*//,\ +filenamemangle=s/.+\/v?(\d\S*)\.tar\.gz/shoulda-matchers-$1\.tar\.gz/ \ + https://github.com/thoughtbot/shoulda-matchers/tags .*/v?(\d\S*)\.tar\.gz diff -Nru ruby-shoulda-matchers-2.8.0/docs/errors/NonCaseSwappableValueError.md ruby-shoulda-matchers-4.3.0/docs/errors/NonCaseSwappableValueError.md --- ruby-shoulda-matchers-2.8.0/docs/errors/NonCaseSwappableValueError.md 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/docs/errors/NonCaseSwappableValueError.md 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,111 @@ +# @title NonCaseSwappableValueError + +# NonCaseSwappableValueError + +This error is raised when using `validate_uniqueness_of`. This matcher, of +course, tests that an attribute disallows a non-unique value -- and what +constitutes as "unique" depends on whether the case-sensitivity of that value +matters. If it does matter -- meaning that the uniqueness validation in your +model isn't using `case_sensitive: false` and you haven't qualified the matcher +with `case_insensitive` -- then the matcher will run the following test: + +> Creating first a record with a value of "A": +> +> * A new record with a value of "A" should not be valid (failing the uniqueness +> validation) +> * A new record with a value of "a" should be valid + +The test value we're using is in this case "A", and this is what the matcher +will use if an existing record is not already present in the database. But if +a record already exists, then the matcher will use it as comparison -- it will +read the attribute under test off of the record and use its value. So a better +example might be: + +> Given an existing record with a value: +> +> * A new record with the same value should not be valid (failing the uniqueness +> validation) +> * A new record with the same value, but where the case is swapped (using +> String#swapcase), should be valid + +Now, what happens if an existing record is there, but the value being used is +not one whose case can be swapped, such as `"123"` or `"{-#%}"`? Then the second +assertion cannot be made effectively. + +So this is why you're getting this exception. What can you do about it? As the +error message explains, you have two options: + +1. If you want the uniqueness validation in the model to operate + case-sensitively and you didn't mean to use a non-case-swappable value, + then you need to provide an existing record with a different value, one that + contains alpha characters. Here's an example: + + # Model + class User < ActiveRecord::Base + validates_uniqueness_of :username + end + + # RSpec + RSpec.describe User, type: :model do + context "validations" do + subject do + # Note that "123" == "123".swapcase. This is a problem! + User.new(username: "123") + end + + it do + # So you can either override it like this, or just fix the subject. + user = User.create!(username: "john123") + expect(user).to validate_uniqueness_of(:username) + end + end + end + + # Minitest (Shoulda) + class UserTest < ActiveSupport::TestCase + context "validations" do + subject do + # Note that "123" == "123".swapcase. This is a problem! + User.new(username: "123") + end + + should "validate uniqueness of :username" do + # So you can either override it like this, or just fix the subject. + user = User.create!(username: "john123") + assert_accepts validate_uniqueness_of(:username), record + end + end + end + +2. If you don't want the uniqueness validation to operate case-sensitively, + then you need to add `case_sensitive: false` to the validation and add + `case_insensitive` to the matcher: + + # Model + class User < ActiveRecord::Base + validates_uniqueness_of :username, case_sensitive: false + end + + # RSpec + RSpec.describe User, type: :model do + context "validations" do + subject do + # Note that "123" == "123".swapcase, but it's okay + User.new(username: "123") + end + + it { should validate_uniqueness_of(:username).case_insensitive } + end + end + + # Minitest (Shoulda) + class UserTest < ActiveSupport::TestCase + context "validations" do + subject do + # Note that "123" == "123".swapcase, but it's okay + User.new(username: "123") + end + + should validate_uniqueness_of(:username).case_insensitive + end + end diff -Nru ruby-shoulda-matchers-2.8.0/docs.watchr ruby-shoulda-matchers-4.3.0/docs.watchr --- ruby-shoulda-matchers-2.8.0/docs.watchr 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/docs.watchr 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -watch('README.md') { system('bundle exec yard doc') } -watch('doc_config/yard/.*') { system('bundle exec yard doc') } -watch('lib/.*\.rb') { system('bundle exec yard doc') } - -# vi: ft=ruby diff -Nru ruby-shoulda-matchers-2.8.0/Gemfile ruby-shoulda-matchers-4.3.0/Gemfile --- ruby-shoulda-matchers-2.8.0/Gemfile 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/Gemfile 2020-02-18 07:23:52.000000000 +0000 @@ -1,28 +1,17 @@ source 'https://rubygems.org' -gem 'appraisal', '~> 1.0' -gem 'aruba' -gem 'bourne', '~> 1.3' +gem 'appraisal', '2.2.0' gem 'bundler', '~> 1.1' -gem 'pry-nav' -gem 'rails', '~> 3.0' -gem 'rake', '>= 0.9.2' -gem 'rspec-rails', '>= 2.99.0' +gem 'pry' +gem 'pry-byebug' +gem 'rake', '13.0.1' +gem 'rspec', '~> 3.9' +gem 'rubocop', require: false +gem 'rubocop-rails', require: false +gem 'zeus', require: false # YARD -gem 'yard' -gem 'redcarpet' +gem 'fssm' gem 'pygments.rb' -gem 'watchr' - -# For test Rails application -gem 'shoulda-context', '~> 1.2.0' -gem 'sqlite3', :platform => :ruby - -# Can't wrap in platform :jruby do...end block because appraisal doesn't -# support it -gem 'activerecord-jdbc-adapter', :platform => :jruby -gem 'activerecord-jdbcsqlite3-adapter', :platform => :jruby -gem 'jdbc-sqlite3', :platform => :jruby -gem 'jruby-openssl', :platform => :jruby -gem 'therubyrhino', :platform => :jruby +gem 'redcarpet' +gem 'yard' diff -Nru ruby-shoulda-matchers-2.8.0/Gemfile.lock ruby-shoulda-matchers-4.3.0/Gemfile.lock --- ruby-shoulda-matchers-2.8.0/Gemfile.lock 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/Gemfile.lock 2020-02-18 07:23:52.000000000 +0000 @@ -1,164 +1,80 @@ GEM remote: https://rubygems.org/ specs: - actionmailer (3.2.16) - actionpack (= 3.2.16) - mail (~> 2.5.4) - actionpack (3.2.16) - activemodel (= 3.2.16) - activesupport (= 3.2.16) - builder (~> 3.0.0) - erubis (~> 2.7.0) - journey (~> 1.0.4) - rack (~> 1.4.5) - rack-cache (~> 1.2) - rack-test (~> 0.6.1) - sprockets (~> 2.2.1) - activemodel (3.2.16) - activesupport (= 3.2.16) - builder (~> 3.0.0) - activerecord (3.2.16) - activemodel (= 3.2.16) - activesupport (= 3.2.16) - arel (~> 3.0.2) - tzinfo (~> 0.3.29) - activeresource (3.2.16) - activemodel (= 3.2.16) - activesupport (= 3.2.16) - activesupport (3.2.16) - i18n (~> 0.6, >= 0.6.4) - multi_json (~> 1.0) - appraisal (1.0.2) + appraisal (2.2.0) bundler rake thor (>= 0.14.0) - arel (3.0.3) - aruba (0.6.0) - childprocess (>= 0.3.6) - cucumber (>= 1.1.1) - rspec-expectations (>= 2.7.0) - bourne (1.5.0) - mocha (>= 0.13.2, < 0.15) - builder (3.0.4) - childprocess (0.5.3) - ffi (~> 1.0, >= 1.0.11) - coderay (1.1.0) - cucumber (1.3.16) - builder (>= 2.1.2) - diff-lcs (>= 1.1.3) - gherkin (~> 2.12) - multi_json (>= 1.7.5, < 2.0) - multi_test (>= 0.1.1) - diff-lcs (1.2.5) - erubis (2.7.0) - ffi (1.9.3) - gherkin (2.12.2) - multi_json (~> 1.3) - hike (1.2.3) - i18n (0.6.11) - journey (1.0.4) - json (1.8.1) - mail (2.5.4) - mime-types (~> 1.16) - treetop (~> 1.4.8) - metaclass (0.0.1) - method_source (0.8.2) - mime-types (1.25.1) - mocha (0.14.0) - metaclass (~> 0.0.1) - multi_json (1.10.1) - multi_test (0.1.1) - polyglot (0.3.3) - posix-spawn (0.3.8) - pry (0.10.1) + ast (2.4.0) + byebug (11.0.1) + coderay (1.1.2) + diff-lcs (1.3) + fssm (0.2.10) + jaro_winkler (1.5.4) + method_source (0.9.2) + multi_json (1.14.1) + parallel (1.19.1) + parser (2.6.5.0) + ast (~> 2.4.0) + pry (0.12.2) coderay (~> 1.1.0) - method_source (~> 0.8.1) - slop (~> 3.4) - pry-nav (0.2.4) - pry (>= 0.9.10, < 0.11.0) - pygments.rb (0.3.7) - posix-spawn (~> 0.3.6) - yajl-ruby (~> 1.1.0) - rack (1.4.5) - rack-cache (1.2) - rack (>= 0.4) - rack-ssl (1.3.4) - rack - rack-test (0.6.2) - rack (>= 1.0) - rails (3.2.16) - actionmailer (= 3.2.16) - actionpack (= 3.2.16) - activerecord (= 3.2.16) - activeresource (= 3.2.16) - activesupport (= 3.2.16) - bundler (~> 1.0) - railties (= 3.2.16) - railties (3.2.16) - actionpack (= 3.2.16) - activesupport (= 3.2.16) - rack-ssl (~> 1.3.2) - rake (>= 0.8.7) - rdoc (~> 3.4) - thor (>= 0.14.6, < 2.0) - rake (10.3.2) - rdoc (3.12.2) - json (~> 1.4) - redcarpet (3.0.0) - rspec-core (3.0.3) - rspec-support (~> 3.0.0) - rspec-expectations (3.0.3) + method_source (~> 0.9.0) + pry-byebug (3.7.0) + byebug (~> 11.0) + pry (~> 0.10) + pygments.rb (1.2.1) + multi_json (>= 1.0.0) + rack (2.0.8) + rainbow (3.0.0) + rake (13.0.1) + redcarpet (3.5.0) + rspec (3.9.0) + rspec-core (~> 3.9.0) + rspec-expectations (~> 3.9.0) + rspec-mocks (~> 3.9.0) + 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.0.0) - rspec-mocks (3.0.3) - rspec-support (~> 3.0.0) - rspec-rails (3.0.2) - actionpack (>= 3.0) - activesupport (>= 3.0) - railties (>= 3.0) - rspec-core (~> 3.0.0) - rspec-expectations (~> 3.0.0) - rspec-mocks (~> 3.0.0) - rspec-support (~> 3.0.0) - rspec-support (3.0.3) - shoulda-context (1.2.0) - slop (3.6.0) - sprockets (2.2.2) - hike (~> 1.2) - multi_json (~> 1.0) - rack (~> 1.0) - tilt (~> 1.1, != 1.3.0) - sqlite3 (1.3.8) - thor (0.19.1) - tilt (1.4.1) - treetop (1.4.15) - polyglot - polyglot (>= 0.3.1) - tzinfo (0.3.38) - watchr (0.7) - yajl-ruby (1.1.0) - yard (0.8.7.3) + rspec-support (~> 3.9.0) + rspec-mocks (3.9.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.9.0) + rspec-support (3.9.0) + rubocop (0.71.0) + jaro_winkler (~> 1.5.1) + parallel (~> 1.10) + parser (>= 2.6) + rainbow (>= 2.2.2, < 4.0) + ruby-progressbar (~> 1.7) + unicode-display_width (>= 1.4.0, < 1.7) + rubocop-rails (2.0.1) + rack (>= 1.1) + rubocop (>= 0.70.0) + ruby-progressbar (1.10.1) + thor (0.20.0) + unicode-display_width (1.6.0) + yard (0.9.20) + zeus (0.15.14) + method_source (>= 0.6.7) PLATFORMS ruby DEPENDENCIES - activerecord-jdbc-adapter - activerecord-jdbcsqlite3-adapter - appraisal (~> 1.0) - aruba - bourne (~> 1.3) + appraisal (= 2.2.0) bundler (~> 1.1) - jdbc-sqlite3 - jruby-openssl - pry-nav + fssm + pry + pry-byebug pygments.rb - rails (~> 3.0) - rake (>= 0.9.2) + rake (= 13.0.1) redcarpet - rspec-rails (>= 2.99.0) - shoulda-context (~> 1.2.0) - sqlite3 - therubyrhino - watchr + rspec (~> 3.9) + rubocop + rubocop-rails yard + zeus + +BUNDLED WITH + 1.17.3 diff -Nru ruby-shoulda-matchers-2.8.0/gemfiles/3.0.gemfile ruby-shoulda-matchers-4.3.0/gemfiles/3.0.gemfile --- ruby-shoulda-matchers-2.8.0/gemfiles/3.0.gemfile 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/gemfiles/3.0.gemfile 1970-01-01 00:00:00.000000000 +0000 @@ -1,26 +0,0 @@ -# This file was generated by Appraisal - -source "https://rubygems.org" - -gem "appraisal", "~> 1.0" -gem "aruba" -gem "bourne", "~> 1.3" -gem "bundler", "~> 1.1" -gem "pry-nav" -gem "rails", "~> 3.0.17" -gem "rake", ">= 0.9.2" -gem "rspec-rails", "2.99.0" -gem "yard" -gem "redcarpet" -gem "pygments.rb" -gem "watchr" -gem "shoulda-context", "~> 1.2.0" -gem "sqlite3", :platform => :ruby -gem "activerecord-jdbc-adapter", :platform => :jruby -gem "activerecord-jdbcsqlite3-adapter", :platform => :jruby -gem "jdbc-sqlite3", :platform => :jruby -gem "jruby-openssl", :platform => :jruby -gem "therubyrhino", :platform => :jruby -gem "strong_parameters" -gem "minitest", "~> 4.0" -gem "minitest-reporters" diff -Nru ruby-shoulda-matchers-2.8.0/gemfiles/3.0.gemfile.lock ruby-shoulda-matchers-4.3.0/gemfiles/3.0.gemfile.lock --- ruby-shoulda-matchers-2.8.0/gemfiles/3.0.gemfile.lock 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/gemfiles/3.0.gemfile.lock 1970-01-01 00:00:00.000000000 +0000 @@ -1,173 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - abstract (1.0.0) - actionmailer (3.0.20) - actionpack (= 3.0.20) - mail (~> 2.2.19) - actionpack (3.0.20) - activemodel (= 3.0.20) - activesupport (= 3.0.20) - builder (~> 2.1.2) - erubis (~> 2.6.6) - i18n (~> 0.5.0) - rack (~> 1.2.5) - rack-mount (~> 0.6.14) - rack-test (~> 0.5.7) - tzinfo (~> 0.3.23) - activemodel (3.0.20) - activesupport (= 3.0.20) - builder (~> 2.1.2) - i18n (~> 0.5.0) - activerecord (3.0.20) - activemodel (= 3.0.20) - activesupport (= 3.0.20) - arel (~> 2.0.10) - tzinfo (~> 0.3.23) - activeresource (3.0.20) - activemodel (= 3.0.20) - activesupport (= 3.0.20) - activesupport (3.0.20) - ansi (1.4.3) - appraisal (1.0.0) - bundler - rake - thor (>= 0.14.0) - arel (2.0.10) - aruba (0.6.0) - childprocess (>= 0.3.6) - cucumber (>= 1.1.1) - rspec-expectations (>= 2.7.0) - bourne (1.4.0) - mocha (~> 0.13.2) - builder (2.1.2) - childprocess (0.5.3) - ffi (~> 1.0, >= 1.0.11) - coderay (1.1.0) - cucumber (1.3.16) - builder (>= 2.1.2) - diff-lcs (>= 1.1.3) - gherkin (~> 2.12) - multi_json (>= 1.7.5, < 2.0) - multi_test (>= 0.1.1) - diff-lcs (1.2.5) - erubis (2.6.6) - abstract (>= 1.0.0) - ffi (1.9.3) - gherkin (2.12.2) - multi_json (~> 1.3) - hashie (3.3.1) - i18n (0.5.4) - json (1.8.1) - mail (2.2.19) - activesupport (>= 2.3.6) - i18n (>= 0.4.0) - mime-types (~> 1.16) - treetop (~> 1.4.8) - metaclass (0.0.1) - method_source (0.8.2) - mime-types (1.21) - minitest (4.7.5) - minitest-reporters (0.14.24) - ansi - builder - minitest (>= 2.12, < 5.0) - powerbar - mocha (0.13.3) - metaclass (~> 0.0.1) - multi_json (1.10.1) - multi_test (0.1.1) - polyglot (0.3.3) - posix-spawn (0.3.8) - powerbar (1.0.11) - ansi (~> 1.4.0) - hashie (>= 1.1.0) - pry (0.10.1) - coderay (~> 1.1.0) - method_source (~> 0.8.1) - slop (~> 3.4) - pry-nav (0.2.4) - pry (>= 0.9.10, < 0.11.0) - pygments.rb (0.6.0) - posix-spawn (~> 0.3.6) - yajl-ruby (~> 1.1.0) - rack (1.2.8) - rack-mount (0.6.14) - rack (>= 1.0.0) - rack-test (0.5.7) - rack (>= 1.0) - rails (3.0.20) - actionmailer (= 3.0.20) - actionpack (= 3.0.20) - activerecord (= 3.0.20) - activeresource (= 3.0.20) - activesupport (= 3.0.20) - bundler (~> 1.0) - railties (= 3.0.20) - railties (3.0.20) - actionpack (= 3.0.20) - activesupport (= 3.0.20) - rake (>= 0.8.7) - rdoc (~> 3.4) - thor (~> 0.14.4) - rake (10.3.2) - rdoc (3.12.2) - json (~> 1.4) - redcarpet (3.1.2) - rspec-collection_matchers (1.0.0) - rspec-expectations (>= 2.99.0.beta1) - rspec-core (2.99.1) - rspec-expectations (2.99.2) - diff-lcs (>= 1.1.3, < 2.0) - rspec-mocks (2.99.2) - rspec-rails (2.99.0) - actionpack (>= 3.0) - activemodel (>= 3.0) - activesupport (>= 3.0) - railties (>= 3.0) - rspec-collection_matchers - rspec-core (~> 2.99.0) - rspec-expectations (~> 2.99.0) - rspec-mocks (~> 2.99.0) - shoulda-context (1.2.0) - slop (3.6.0) - sqlite3 (1.3.7) - strong_parameters (0.2.0) - actionpack (~> 3.0) - activemodel (~> 3.0) - railties (~> 3.0) - thor (0.14.6) - treetop (1.4.12) - polyglot - polyglot (>= 0.3.1) - tzinfo (0.3.41) - watchr (0.7) - yajl-ruby (1.1.0) - yard (0.8.7.3) - -PLATFORMS - ruby - -DEPENDENCIES - activerecord-jdbc-adapter - activerecord-jdbcsqlite3-adapter - appraisal (~> 1.0) - aruba - bourne (~> 1.3) - bundler (~> 1.1) - jdbc-sqlite3 - jruby-openssl - minitest (~> 4.0) - minitest-reporters - pry-nav - pygments.rb - rails (~> 3.0.17) - rake (>= 0.9.2) - redcarpet - rspec-rails (= 2.99.0) - shoulda-context (~> 1.2.0) - sqlite3 - strong_parameters - therubyrhino - watchr - yard diff -Nru ruby-shoulda-matchers-2.8.0/gemfiles/3.1_1.9.2.gemfile ruby-shoulda-matchers-4.3.0/gemfiles/3.1_1.9.2.gemfile --- ruby-shoulda-matchers-2.8.0/gemfiles/3.1_1.9.2.gemfile 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/gemfiles/3.1_1.9.2.gemfile 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ -# This file was generated by Appraisal - -source "https://rubygems.org" - -gem "appraisal", "~> 1.0" -gem "aruba" -gem "bourne", "~> 1.3" -gem "bundler", "~> 1.1" -gem "pry-nav" -gem "rails", "~> 3.1.8" -gem "rake", ">= 0.9.2" -gem "rspec-rails", "2.99.0" -gem "yard" -gem "redcarpet" -gem "pygments.rb" -gem "watchr" -gem "shoulda-context", "~> 1.2.0" -gem "sqlite3", :platform => :ruby -gem "activerecord-jdbc-adapter", :platform => :jruby -gem "activerecord-jdbcsqlite3-adapter", :platform => :jruby -gem "jdbc-sqlite3", :platform => :jruby -gem "jruby-openssl", :platform => :jruby -gem "therubyrhino", :platform => :jruby -gem "strong_parameters" -gem "minitest", "~> 4.0" -gem "minitest-reporters" -gem "bcrypt-ruby", "~> 3.0.0" -gem "jquery-rails" -gem "sass-rails", "~> 3.1.5" -gem "coffee-rails", "~> 3.1.1" -gem "uglifier", ">= 1.0.3" -gem "turn", "0.8.2" diff -Nru ruby-shoulda-matchers-2.8.0/gemfiles/3.1_1.9.2.gemfile.lock ruby-shoulda-matchers-4.3.0/gemfiles/3.1_1.9.2.gemfile.lock --- ruby-shoulda-matchers-2.8.0/gemfiles/3.1_1.9.2.gemfile.lock 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/gemfiles/3.1_1.9.2.gemfile.lock 1970-01-01 00:00:00.000000000 +0000 @@ -1,212 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - actionmailer (3.1.11) - actionpack (= 3.1.11) - mail (~> 2.3.3) - actionpack (3.1.11) - activemodel (= 3.1.11) - activesupport (= 3.1.11) - builder (~> 3.0.0) - erubis (~> 2.7.0) - i18n (~> 0.6) - rack (~> 1.3.6) - rack-cache (~> 1.2) - rack-mount (~> 0.8.2) - rack-test (~> 0.6.1) - sprockets (~> 2.0.4) - activemodel (3.1.11) - activesupport (= 3.1.11) - builder (~> 3.0.0) - i18n (~> 0.6) - activerecord (3.1.11) - activemodel (= 3.1.11) - activesupport (= 3.1.11) - arel (~> 2.2.3) - tzinfo (~> 0.3.29) - activeresource (3.1.11) - activemodel (= 3.1.11) - activesupport (= 3.1.11) - activesupport (3.1.11) - multi_json (~> 1.0) - ansi (1.4.3) - appraisal (1.0.0) - bundler - rake - thor (>= 0.14.0) - arel (2.2.3) - aruba (0.6.0) - childprocess (>= 0.3.6) - cucumber (>= 1.1.1) - rspec-expectations (>= 2.7.0) - bcrypt-ruby (3.0.1) - bourne (1.5.0) - mocha (>= 0.13.2, < 0.15) - builder (3.0.4) - childprocess (0.5.3) - ffi (~> 1.0, >= 1.0.11) - coderay (1.1.0) - coffee-rails (3.1.1) - coffee-script (>= 2.2.0) - railties (~> 3.1.0) - coffee-script (2.2.0) - coffee-script-source - execjs - coffee-script-source (1.7.0) - cucumber (1.3.16) - builder (>= 2.1.2) - diff-lcs (>= 1.1.3) - gherkin (~> 2.12) - multi_json (>= 1.7.5, < 2.0) - multi_test (>= 0.1.1) - diff-lcs (1.2.5) - erubis (2.7.0) - execjs (2.0.2) - ffi (1.9.3) - gherkin (2.12.2) - multi_json (~> 1.3) - hashie (3.3.1) - hike (1.2.3) - i18n (0.6.11) - jquery-rails (2.2.1) - railties (>= 3.0, < 5.0) - thor (>= 0.14, < 2.0) - json (1.8.1) - mail (2.3.3) - i18n (>= 0.4.0) - mime-types (~> 1.16) - treetop (~> 1.4.8) - metaclass (0.0.1) - method_source (0.8.2) - mime-types (1.25.1) - minitest (4.7.5) - minitest-reporters (0.14.24) - ansi - builder - minitest (>= 2.12, < 5.0) - powerbar - mocha (0.14.0) - metaclass (~> 0.0.1) - multi_json (1.10.1) - multi_test (0.1.1) - polyglot (0.3.3) - posix-spawn (0.3.8) - powerbar (1.0.11) - ansi (~> 1.4.0) - hashie (>= 1.1.0) - pry (0.10.1) - coderay (~> 1.1.0) - method_source (~> 0.8.1) - slop (~> 3.4) - pry-nav (0.2.4) - pry (>= 0.9.10, < 0.11.0) - pygments.rb (0.6.0) - posix-spawn (~> 0.3.6) - yajl-ruby (~> 1.1.0) - rack (1.3.10) - rack-cache (1.2) - rack (>= 0.4) - rack-mount (0.8.3) - rack (>= 1.0.0) - rack-ssl (1.3.4) - rack - rack-test (0.6.2) - rack (>= 1.0) - rails (3.1.11) - actionmailer (= 3.1.11) - actionpack (= 3.1.11) - activerecord (= 3.1.11) - activeresource (= 3.1.11) - activesupport (= 3.1.11) - bundler (~> 1.0) - railties (= 3.1.11) - railties (3.1.11) - actionpack (= 3.1.11) - activesupport (= 3.1.11) - rack-ssl (~> 1.3.2) - rake (>= 0.8.7) - rdoc (~> 3.4) - thor (~> 0.14.6) - rake (10.3.2) - rdoc (3.12.2) - json (~> 1.4) - redcarpet (3.1.2) - rspec-collection_matchers (1.0.0) - rspec-expectations (>= 2.99.0.beta1) - rspec-core (2.99.1) - rspec-expectations (2.99.2) - diff-lcs (>= 1.1.3, < 2.0) - rspec-mocks (2.99.2) - rspec-rails (2.99.0) - actionpack (>= 3.0) - activemodel (>= 3.0) - activesupport (>= 3.0) - railties (>= 3.0) - rspec-collection_matchers - rspec-core (~> 2.99.0) - rspec-expectations (~> 2.99.0) - rspec-mocks (~> 2.99.0) - sass (3.2.12) - sass-rails (3.1.6) - actionpack (~> 3.1.0) - railties (~> 3.1.0) - sass (>= 3.1.10) - tilt (~> 1.3.2) - shoulda-context (1.2.0) - slop (3.6.0) - sprockets (2.0.4) - hike (~> 1.2) - rack (~> 1.0) - tilt (~> 1.1, != 1.3.0) - sqlite3 (1.3.8) - strong_parameters (0.2.0) - actionpack (~> 3.0) - activemodel (~> 3.0) - railties (~> 3.0) - thor (0.14.6) - tilt (1.3.7) - treetop (1.4.15) - polyglot - polyglot (>= 0.3.1) - turn (0.8.2) - ansi (>= 1.2.2) - tzinfo (0.3.38) - uglifier (2.5.0) - execjs (>= 0.3.0) - json (>= 1.8.0) - watchr (0.7) - yajl-ruby (1.1.0) - yard (0.8.7.3) - -PLATFORMS - ruby - -DEPENDENCIES - activerecord-jdbc-adapter - activerecord-jdbcsqlite3-adapter - appraisal (~> 1.0) - aruba - bcrypt-ruby (~> 3.0.0) - bourne (~> 1.3) - bundler (~> 1.1) - coffee-rails (~> 3.1.1) - jdbc-sqlite3 - jquery-rails - jruby-openssl - minitest (~> 4.0) - minitest-reporters - pry-nav - pygments.rb - rails (~> 3.1.8) - rake (>= 0.9.2) - redcarpet - rspec-rails (= 2.99.0) - sass-rails (~> 3.1.5) - shoulda-context (~> 1.2.0) - sqlite3 - strong_parameters - therubyrhino - turn (= 0.8.2) - uglifier (>= 1.0.3) - watchr - yard diff -Nru ruby-shoulda-matchers-2.8.0/gemfiles/3.1.gemfile ruby-shoulda-matchers-4.3.0/gemfiles/3.1.gemfile --- ruby-shoulda-matchers-2.8.0/gemfiles/3.1.gemfile 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/gemfiles/3.1.gemfile 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ -# This file was generated by Appraisal - -source "https://rubygems.org" - -gem "appraisal", "~> 1.0" -gem "aruba" -gem "bourne", "~> 1.3" -gem "bundler", "~> 1.1" -gem "pry-nav" -gem "rails", "~> 3.1.8" -gem "rake", ">= 0.9.2" -gem "rspec-rails", "2.99.0" -gem "yard" -gem "redcarpet" -gem "pygments.rb" -gem "watchr" -gem "shoulda-context", "~> 1.2.0" -gem "sqlite3", :platform => :ruby -gem "activerecord-jdbc-adapter", :platform => :jruby -gem "activerecord-jdbcsqlite3-adapter", :platform => :jruby -gem "jdbc-sqlite3", :platform => :jruby -gem "jruby-openssl", :platform => :jruby -gem "therubyrhino", :platform => :jruby -gem "strong_parameters" -gem "minitest", "~> 4.0" -gem "minitest-reporters" -gem "bcrypt-ruby", "~> 3.0.0" -gem "jquery-rails" -gem "sass-rails", "~> 3.1.5" -gem "coffee-rails", "~> 3.1.1" -gem "uglifier", ">= 1.0.3" -gem "turn", "~> 0.8.3" diff -Nru ruby-shoulda-matchers-2.8.0/gemfiles/3.1.gemfile.lock ruby-shoulda-matchers-4.3.0/gemfiles/3.1.gemfile.lock --- ruby-shoulda-matchers-2.8.0/gemfiles/3.1.gemfile.lock 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/gemfiles/3.1.gemfile.lock 1970-01-01 00:00:00.000000000 +0000 @@ -1,212 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - actionmailer (3.1.11) - actionpack (= 3.1.11) - mail (~> 2.3.3) - actionpack (3.1.11) - activemodel (= 3.1.11) - activesupport (= 3.1.11) - builder (~> 3.0.0) - erubis (~> 2.7.0) - i18n (~> 0.6) - rack (~> 1.3.6) - rack-cache (~> 1.2) - rack-mount (~> 0.8.2) - rack-test (~> 0.6.1) - sprockets (~> 2.0.4) - activemodel (3.1.11) - activesupport (= 3.1.11) - builder (~> 3.0.0) - i18n (~> 0.6) - activerecord (3.1.11) - activemodel (= 3.1.11) - activesupport (= 3.1.11) - arel (~> 2.2.3) - tzinfo (~> 0.3.29) - activeresource (3.1.11) - activemodel (= 3.1.11) - activesupport (= 3.1.11) - activesupport (3.1.11) - multi_json (~> 1.0) - ansi (1.4.3) - appraisal (1.0.2) - bundler - rake - thor (>= 0.14.0) - arel (2.2.3) - aruba (0.6.0) - childprocess (>= 0.3.6) - cucumber (>= 1.1.1) - rspec-expectations (>= 2.7.0) - bcrypt-ruby (3.0.1) - bourne (1.4.0) - mocha (~> 0.13.2) - builder (3.0.4) - childprocess (0.5.3) - ffi (~> 1.0, >= 1.0.11) - coderay (1.1.0) - coffee-rails (3.1.1) - coffee-script (>= 2.2.0) - railties (~> 3.1.0) - coffee-script (2.2.0) - coffee-script-source - execjs - coffee-script-source (1.7.0) - cucumber (1.3.16) - builder (>= 2.1.2) - diff-lcs (>= 1.1.3) - gherkin (~> 2.12) - multi_json (>= 1.7.5, < 2.0) - multi_test (>= 0.1.1) - diff-lcs (1.2.5) - erubis (2.7.0) - execjs (2.0.2) - ffi (1.9.3) - gherkin (2.12.2) - multi_json (~> 1.3) - hashie (3.3.1) - hike (1.2.3) - i18n (0.6.11) - jquery-rails (2.2.1) - railties (>= 3.0, < 5.0) - thor (>= 0.14, < 2.0) - json (1.8.1) - mail (2.3.3) - i18n (>= 0.4.0) - mime-types (~> 1.16) - treetop (~> 1.4.8) - metaclass (0.0.1) - method_source (0.8.2) - mime-types (1.21) - minitest (4.7.5) - minitest-reporters (0.14.24) - ansi - builder - minitest (>= 2.12, < 5.0) - powerbar - mocha (0.13.3) - metaclass (~> 0.0.1) - multi_json (1.10.1) - multi_test (0.1.1) - polyglot (0.3.3) - posix-spawn (0.3.8) - powerbar (1.0.11) - ansi (~> 1.4.0) - hashie (>= 1.1.0) - pry (0.10.1) - coderay (~> 1.1.0) - method_source (~> 0.8.1) - slop (~> 3.4) - pry-nav (0.2.4) - pry (>= 0.9.10, < 0.11.0) - pygments.rb (0.6.0) - posix-spawn (~> 0.3.6) - yajl-ruby (~> 1.1.0) - rack (1.3.10) - rack-cache (1.2) - rack (>= 0.4) - rack-mount (0.8.3) - rack (>= 1.0.0) - rack-ssl (1.3.4) - rack - rack-test (0.6.2) - rack (>= 1.0) - rails (3.1.11) - actionmailer (= 3.1.11) - actionpack (= 3.1.11) - activerecord (= 3.1.11) - activeresource (= 3.1.11) - activesupport (= 3.1.11) - bundler (~> 1.0) - railties (= 3.1.11) - railties (3.1.11) - actionpack (= 3.1.11) - activesupport (= 3.1.11) - rack-ssl (~> 1.3.2) - rake (>= 0.8.7) - rdoc (~> 3.4) - thor (~> 0.14.6) - rake (10.3.2) - rdoc (3.12.2) - json (~> 1.4) - redcarpet (3.1.2) - rspec-collection_matchers (1.0.0) - rspec-expectations (>= 2.99.0.beta1) - rspec-core (2.99.1) - rspec-expectations (2.99.2) - diff-lcs (>= 1.1.3, < 2.0) - rspec-mocks (2.99.2) - rspec-rails (2.99.0) - actionpack (>= 3.0) - activemodel (>= 3.0) - activesupport (>= 3.0) - railties (>= 3.0) - rspec-collection_matchers - rspec-core (~> 2.99.0) - rspec-expectations (~> 2.99.0) - rspec-mocks (~> 2.99.0) - sass (3.2.7) - sass-rails (3.1.6) - actionpack (~> 3.1.0) - railties (~> 3.1.0) - sass (>= 3.1.10) - tilt (~> 1.3.2) - shoulda-context (1.2.0) - slop (3.6.0) - sprockets (2.0.4) - hike (~> 1.2) - rack (~> 1.0) - tilt (~> 1.1, != 1.3.0) - sqlite3 (1.3.7) - strong_parameters (0.2.0) - actionpack (~> 3.0) - activemodel (~> 3.0) - railties (~> 3.0) - thor (0.14.6) - tilt (1.3.7) - treetop (1.4.12) - polyglot - polyglot (>= 0.3.1) - turn (0.8.3) - ansi - tzinfo (0.3.37) - uglifier (2.2.1) - execjs (>= 0.3.0) - multi_json (~> 1.0, >= 1.0.2) - watchr (0.7) - yajl-ruby (1.1.0) - yard (0.8.7.3) - -PLATFORMS - ruby - -DEPENDENCIES - activerecord-jdbc-adapter - activerecord-jdbcsqlite3-adapter - appraisal (~> 1.0) - aruba - bcrypt-ruby (~> 3.0.0) - bourne (~> 1.3) - bundler (~> 1.1) - coffee-rails (~> 3.1.1) - jdbc-sqlite3 - jquery-rails - jruby-openssl - minitest (~> 4.0) - minitest-reporters - pry-nav - pygments.rb - rails (~> 3.1.8) - rake (>= 0.9.2) - redcarpet - rspec-rails (= 2.99.0) - sass-rails (~> 3.1.5) - shoulda-context (~> 1.2.0) - sqlite3 - strong_parameters - therubyrhino - turn (~> 0.8.3) - uglifier (>= 1.0.3) - watchr - yard diff -Nru ruby-shoulda-matchers-2.8.0/gemfiles/3.2_1.9.2.gemfile ruby-shoulda-matchers-4.3.0/gemfiles/3.2_1.9.2.gemfile --- ruby-shoulda-matchers-2.8.0/gemfiles/3.2_1.9.2.gemfile 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/gemfiles/3.2_1.9.2.gemfile 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -# This file was generated by Appraisal - -source "https://rubygems.org" - -gem "appraisal", "~> 1.0" -gem "aruba" -gem "bourne", "~> 1.3" -gem "bundler", "~> 1.1" -gem "pry-nav" -gem "rails", "~> 3.2.13" -gem "rake", ">= 0.9.2" -gem "rspec-rails", "2.99.0" -gem "yard" -gem "redcarpet" -gem "pygments.rb" -gem "watchr" -gem "shoulda-context", "~> 1.2.0" -gem "sqlite3", :platform => :ruby -gem "activerecord-jdbc-adapter", :platform => :jruby -gem "activerecord-jdbcsqlite3-adapter", :platform => :jruby -gem "jdbc-sqlite3", :platform => :jruby -gem "jruby-openssl", :platform => :jruby -gem "therubyrhino", :platform => :jruby -gem "strong_parameters" -gem "minitest", "~> 4.0" -gem "minitest-reporters" -gem "bcrypt-ruby", "~> 3.0.0" -gem "jquery-rails" -gem "sass-rails", "~> 3.2.3" -gem "coffee-rails", "~> 3.2.1" -gem "uglifier", ">= 1.0.3" diff -Nru ruby-shoulda-matchers-2.8.0/gemfiles/3.2_1.9.2.gemfile.lock ruby-shoulda-matchers-4.3.0/gemfiles/3.2_1.9.2.gemfile.lock --- ruby-shoulda-matchers-2.8.0/gemfiles/3.2_1.9.2.gemfile.lock 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/gemfiles/3.2_1.9.2.gemfile.lock 1970-01-01 00:00:00.000000000 +0000 @@ -1,207 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - actionmailer (3.2.18) - actionpack (= 3.2.18) - mail (~> 2.5.4) - actionpack (3.2.18) - activemodel (= 3.2.18) - activesupport (= 3.2.18) - builder (~> 3.0.0) - erubis (~> 2.7.0) - journey (~> 1.0.4) - rack (~> 1.4.5) - rack-cache (~> 1.2) - rack-test (~> 0.6.1) - sprockets (~> 2.2.1) - activemodel (3.2.18) - activesupport (= 3.2.18) - builder (~> 3.0.0) - activerecord (3.2.18) - activemodel (= 3.2.18) - activesupport (= 3.2.18) - arel (~> 3.0.2) - tzinfo (~> 0.3.29) - activeresource (3.2.18) - activemodel (= 3.2.18) - activesupport (= 3.2.18) - activesupport (3.2.18) - i18n (~> 0.6, >= 0.6.4) - multi_json (~> 1.0) - ansi (1.4.3) - appraisal (1.0.0) - bundler - rake - thor (>= 0.14.0) - arel (3.0.3) - aruba (0.6.0) - childprocess (>= 0.3.6) - cucumber (>= 1.1.1) - rspec-expectations (>= 2.7.0) - bcrypt-ruby (3.0.1) - bourne (1.5.0) - mocha (>= 0.13.2, < 0.15) - builder (3.0.4) - childprocess (0.5.3) - ffi (~> 1.0, >= 1.0.11) - coderay (1.1.0) - coffee-rails (3.2.2) - coffee-script (>= 2.2.0) - railties (~> 3.2.0) - coffee-script (2.2.0) - coffee-script-source - execjs - coffee-script-source (1.7.0) - cucumber (1.3.16) - builder (>= 2.1.2) - diff-lcs (>= 1.1.3) - gherkin (~> 2.12) - multi_json (>= 1.7.5, < 2.0) - multi_test (>= 0.1.1) - diff-lcs (1.2.5) - erubis (2.7.0) - execjs (2.2.0) - ffi (1.9.3) - gherkin (2.12.2) - multi_json (~> 1.3) - hashie (3.3.1) - hike (1.2.3) - i18n (0.6.11) - journey (1.0.4) - jquery-rails (3.1.0) - railties (>= 3.0, < 5.0) - thor (>= 0.14, < 2.0) - json (1.8.1) - mail (2.5.4) - mime-types (~> 1.16) - treetop (~> 1.4.8) - metaclass (0.0.4) - method_source (0.8.2) - mime-types (1.25.1) - minitest (4.7.5) - minitest-reporters (0.14.24) - ansi - builder - minitest (>= 2.12, < 5.0) - powerbar - mocha (0.14.0) - metaclass (~> 0.0.1) - multi_json (1.10.1) - multi_test (0.1.1) - polyglot (0.3.5) - posix-spawn (0.3.8) - powerbar (1.0.11) - ansi (~> 1.4.0) - hashie (>= 1.1.0) - pry (0.10.1) - coderay (~> 1.1.0) - method_source (~> 0.8.1) - slop (~> 3.4) - pry-nav (0.2.4) - pry (>= 0.9.10, < 0.11.0) - pygments.rb (0.6.0) - posix-spawn (~> 0.3.6) - yajl-ruby (~> 1.1.0) - rack (1.4.5) - rack-cache (1.2) - rack (>= 0.4) - rack-ssl (1.3.4) - rack - rack-test (0.6.2) - rack (>= 1.0) - rails (3.2.18) - actionmailer (= 3.2.18) - actionpack (= 3.2.18) - activerecord (= 3.2.18) - activeresource (= 3.2.18) - activesupport (= 3.2.18) - bundler (~> 1.0) - railties (= 3.2.18) - railties (3.2.18) - actionpack (= 3.2.18) - activesupport (= 3.2.18) - rack-ssl (~> 1.3.2) - rake (>= 0.8.7) - rdoc (~> 3.4) - thor (>= 0.14.6, < 2.0) - rake (10.3.2) - rdoc (3.12.2) - json (~> 1.4) - redcarpet (3.1.2) - rspec-collection_matchers (1.0.0) - rspec-expectations (>= 2.99.0.beta1) - rspec-core (2.99.1) - rspec-expectations (2.99.2) - diff-lcs (>= 1.1.3, < 2.0) - rspec-mocks (2.99.2) - rspec-rails (2.99.0) - actionpack (>= 3.0) - activemodel (>= 3.0) - activesupport (>= 3.0) - railties (>= 3.0) - rspec-collection_matchers - rspec-core (~> 2.99.0) - rspec-expectations (~> 2.99.0) - rspec-mocks (~> 2.99.0) - sass (3.3.8) - sass-rails (3.2.6) - railties (~> 3.2.0) - sass (>= 3.1.10) - tilt (~> 1.3) - shoulda-context (1.2.1) - slop (3.6.0) - sprockets (2.2.2) - hike (~> 1.2) - multi_json (~> 1.0) - rack (~> 1.0) - tilt (~> 1.1, != 1.3.0) - sqlite3 (1.3.9) - strong_parameters (0.2.3) - actionpack (~> 3.0) - activemodel (~> 3.0) - activesupport (~> 3.0) - railties (~> 3.0) - thor (0.19.1) - tilt (1.4.1) - treetop (1.4.15) - polyglot - polyglot (>= 0.3.1) - tzinfo (0.3.39) - uglifier (2.5.1) - execjs (>= 0.3.0) - json (>= 1.8.0) - watchr (0.7) - yajl-ruby (1.1.0) - yard (0.8.7.4) - -PLATFORMS - ruby - -DEPENDENCIES - activerecord-jdbc-adapter - activerecord-jdbcsqlite3-adapter - appraisal (~> 1.0) - aruba - bcrypt-ruby (~> 3.0.0) - bourne (~> 1.3) - bundler (~> 1.1) - coffee-rails (~> 3.2.1) - jdbc-sqlite3 - jquery-rails - jruby-openssl - minitest (~> 4.0) - minitest-reporters - pry-nav - pygments.rb - rails (~> 3.2.13) - rake (>= 0.9.2) - redcarpet - rspec-rails (= 2.99.0) - sass-rails (~> 3.2.3) - shoulda-context (~> 1.2.0) - sqlite3 - strong_parameters - therubyrhino - uglifier (>= 1.0.3) - watchr - yard diff -Nru ruby-shoulda-matchers-2.8.0/gemfiles/3.2.gemfile ruby-shoulda-matchers-4.3.0/gemfiles/3.2.gemfile --- ruby-shoulda-matchers-2.8.0/gemfiles/3.2.gemfile 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/gemfiles/3.2.gemfile 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -# This file was generated by Appraisal - -source "https://rubygems.org" - -gem "appraisal", "~> 1.0" -gem "aruba" -gem "bourne", "~> 1.3" -gem "bundler", "~> 1.1" -gem "pry-nav" -gem "rails", "~> 3.2.13" -gem "rake", ">= 0.9.2" -gem "rspec-rails", "2.99.0" -gem "yard" -gem "redcarpet" -gem "pygments.rb" -gem "watchr" -gem "shoulda-context", "~> 1.2.0" -gem "sqlite3", :platform => :ruby -gem "activerecord-jdbc-adapter", :platform => :jruby -gem "activerecord-jdbcsqlite3-adapter", :platform => :jruby -gem "jdbc-sqlite3", :platform => :jruby -gem "jruby-openssl", :platform => :jruby -gem "therubyrhino", :platform => :jruby -gem "strong_parameters" -gem "minitest", "~> 4.0" -gem "minitest-reporters" -gem "bcrypt-ruby", "~> 3.0.0" -gem "jquery-rails" -gem "sass-rails", "~> 3.2.3" -gem "coffee-rails", "~> 3.2.1" -gem "uglifier", ">= 1.0.3" -gem "spring" -gem "spring-commands-rspec" diff -Nru ruby-shoulda-matchers-2.8.0/gemfiles/3.2.gemfile.lock ruby-shoulda-matchers-4.3.0/gemfiles/3.2.gemfile.lock --- ruby-shoulda-matchers-2.8.0/gemfiles/3.2.gemfile.lock 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/gemfiles/3.2.gemfile.lock 1970-01-01 00:00:00.000000000 +0000 @@ -1,212 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - actionmailer (3.2.13) - actionpack (= 3.2.13) - mail (~> 2.5.3) - actionpack (3.2.13) - activemodel (= 3.2.13) - activesupport (= 3.2.13) - builder (~> 3.0.0) - erubis (~> 2.7.0) - journey (~> 1.0.4) - rack (~> 1.4.5) - rack-cache (~> 1.2) - rack-test (~> 0.6.1) - sprockets (~> 2.2.1) - activemodel (3.2.13) - activesupport (= 3.2.13) - builder (~> 3.0.0) - activerecord (3.2.13) - activemodel (= 3.2.13) - activesupport (= 3.2.13) - arel (~> 3.0.2) - tzinfo (~> 0.3.29) - activeresource (3.2.13) - activemodel (= 3.2.13) - activesupport (= 3.2.13) - activesupport (3.2.13) - i18n (= 0.6.1) - multi_json (~> 1.0) - ansi (1.4.3) - appraisal (1.0.2) - bundler - rake - thor (>= 0.14.0) - arel (3.0.2) - aruba (0.6.0) - childprocess (>= 0.3.6) - cucumber (>= 1.1.1) - rspec-expectations (>= 2.7.0) - bcrypt-ruby (3.0.1) - bourne (1.4.0) - mocha (~> 0.13.2) - builder (3.0.4) - childprocess (0.5.3) - ffi (~> 1.0, >= 1.0.11) - coderay (1.1.0) - coffee-rails (3.2.2) - coffee-script (>= 2.2.0) - railties (~> 3.2.0) - coffee-script (2.2.0) - coffee-script-source - execjs - coffee-script-source (1.7.0) - cucumber (1.3.16) - builder (>= 2.1.2) - diff-lcs (>= 1.1.3) - gherkin (~> 2.12) - multi_json (>= 1.7.5, < 2.0) - multi_test (>= 0.1.1) - diff-lcs (1.2.5) - erubis (2.7.0) - execjs (2.0.2) - ffi (1.9.3) - gherkin (2.12.2) - multi_json (~> 1.3) - hashie (3.3.1) - hike (1.2.3) - i18n (0.6.1) - journey (1.0.4) - jquery-rails (2.2.1) - railties (>= 3.0, < 5.0) - thor (>= 0.14, < 2.0) - json (1.8.1) - mail (2.5.3) - i18n (>= 0.4.0) - mime-types (~> 1.16) - treetop (~> 1.4.8) - metaclass (0.0.1) - method_source (0.8.2) - mime-types (1.21) - minitest (4.7.5) - minitest-reporters (0.14.24) - ansi - builder - minitest (>= 2.12, < 5.0) - powerbar - mocha (0.13.3) - metaclass (~> 0.0.1) - multi_json (1.10.1) - multi_test (0.1.1) - polyglot (0.3.3) - posix-spawn (0.3.8) - powerbar (1.0.11) - ansi (~> 1.4.0) - hashie (>= 1.1.0) - pry (0.10.1) - coderay (~> 1.1.0) - method_source (~> 0.8.1) - slop (~> 3.4) - pry-nav (0.2.4) - pry (>= 0.9.10, < 0.11.0) - pygments.rb (0.6.0) - posix-spawn (~> 0.3.6) - yajl-ruby (~> 1.1.0) - rack (1.4.5) - rack-cache (1.2) - rack (>= 0.4) - rack-ssl (1.3.4) - rack - rack-test (0.6.2) - rack (>= 1.0) - rails (3.2.13) - actionmailer (= 3.2.13) - actionpack (= 3.2.13) - activerecord (= 3.2.13) - activeresource (= 3.2.13) - activesupport (= 3.2.13) - bundler (~> 1.0) - railties (= 3.2.13) - railties (3.2.13) - actionpack (= 3.2.13) - activesupport (= 3.2.13) - rack-ssl (~> 1.3.2) - rake (>= 0.8.7) - rdoc (~> 3.4) - thor (>= 0.14.6, < 2.0) - rake (10.3.2) - rdoc (3.12.2) - json (~> 1.4) - redcarpet (3.1.2) - rspec-collection_matchers (1.0.0) - rspec-expectations (>= 2.99.0.beta1) - rspec-core (2.99.1) - rspec-expectations (2.99.2) - diff-lcs (>= 1.1.3, < 2.0) - rspec-mocks (2.99.2) - rspec-rails (2.99.0) - actionpack (>= 3.0) - activemodel (>= 3.0) - activesupport (>= 3.0) - railties (>= 3.0) - rspec-collection_matchers - rspec-core (~> 2.99.0) - rspec-expectations (~> 2.99.0) - rspec-mocks (~> 2.99.0) - sass (3.2.7) - sass-rails (3.2.6) - railties (~> 3.2.0) - sass (>= 3.1.10) - tilt (~> 1.3) - shoulda-context (1.2.0) - slop (3.6.0) - spring (1.1.3) - spring-commands-rspec (1.0.2) - spring (>= 0.9.1) - sprockets (2.2.2) - hike (~> 1.2) - multi_json (~> 1.0) - rack (~> 1.0) - tilt (~> 1.1, != 1.3.0) - sqlite3 (1.3.7) - strong_parameters (0.2.0) - actionpack (~> 3.0) - activemodel (~> 3.0) - railties (~> 3.0) - thor (0.19.1) - tilt (1.4.1) - treetop (1.4.12) - polyglot - polyglot (>= 0.3.1) - tzinfo (0.3.37) - uglifier (2.2.1) - execjs (>= 0.3.0) - multi_json (~> 1.0, >= 1.0.2) - watchr (0.7) - yajl-ruby (1.1.0) - yard (0.8.7.3) - -PLATFORMS - ruby - -DEPENDENCIES - activerecord-jdbc-adapter - activerecord-jdbcsqlite3-adapter - appraisal (~> 1.0) - aruba - bcrypt-ruby (~> 3.0.0) - bourne (~> 1.3) - bundler (~> 1.1) - coffee-rails (~> 3.2.1) - jdbc-sqlite3 - jquery-rails - jruby-openssl - minitest (~> 4.0) - minitest-reporters - pry-nav - pygments.rb - rails (~> 3.2.13) - rake (>= 0.9.2) - redcarpet - rspec-rails (= 2.99.0) - sass-rails (~> 3.2.3) - shoulda-context (~> 1.2.0) - spring - spring-commands-rspec - sqlite3 - strong_parameters - therubyrhino - uglifier (>= 1.0.3) - watchr - yard diff -Nru ruby-shoulda-matchers-2.8.0/gemfiles/4.0.0.gemfile ruby-shoulda-matchers-4.3.0/gemfiles/4.0.0.gemfile --- ruby-shoulda-matchers-2.8.0/gemfiles/4.0.0.gemfile 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/gemfiles/4.0.0.gemfile 1970-01-01 00:00:00.000000000 +0000 @@ -1,36 +0,0 @@ -# This file was generated by Appraisal - -source "https://rubygems.org" - -gem "appraisal", "~> 1.0" -gem "aruba" -gem "bourne", "~> 1.3" -gem "bundler", "~> 1.1" -gem "pry-nav" -gem "rails", "4.0.0" -gem "rake", ">= 0.9.2" -gem "rspec-rails", "~> 3.0.1" -gem "yard" -gem "redcarpet" -gem "pygments.rb" -gem "watchr" -gem "shoulda-context", "~> 1.2.0" -gem "sqlite3", :platform => :ruby -gem "activerecord-jdbc-adapter", :platform => :jruby -gem "activerecord-jdbcsqlite3-adapter", :platform => :jruby -gem "jdbc-sqlite3", :platform => :jruby -gem "jruby-openssl", :platform => :jruby -gem "therubyrhino", :platform => :jruby -gem "spring" -gem "spring-commands-rspec" -gem "uglifier", ">= 1.3.0" -gem "coffee-rails", "~> 4.0.0" -gem "jquery-rails" -gem "turbolinks" -gem "sdoc" -gem "activeresource", "4.0.0" -gem "protected_attributes" -gem "minitest-reporters" -gem "jbuilder", "~> 1.2" -gem "sass-rails", "~> 4.0.0" -gem "bcrypt-ruby", "~> 3.0.0" diff -Nru ruby-shoulda-matchers-2.8.0/gemfiles/4.0.0.gemfile.lock ruby-shoulda-matchers-4.3.0/gemfiles/4.0.0.gemfile.lock --- ruby-shoulda-matchers-2.8.0/gemfiles/4.0.0.gemfile.lock 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/gemfiles/4.0.0.gemfile.lock 1970-01-01 00:00:00.000000000 +0000 @@ -1,223 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - actionmailer (4.0.0) - actionpack (= 4.0.0) - mail (~> 2.5.3) - actionpack (4.0.0) - activesupport (= 4.0.0) - builder (~> 3.1.0) - erubis (~> 2.7.0) - rack (~> 1.5.2) - rack-test (~> 0.6.2) - activemodel (4.0.0) - activesupport (= 4.0.0) - builder (~> 3.1.0) - activerecord (4.0.0) - activemodel (= 4.0.0) - activerecord-deprecated_finders (~> 1.0.2) - activesupport (= 4.0.0) - arel (~> 4.0.0) - activerecord-deprecated_finders (1.0.3) - activeresource (4.0.0) - activemodel (~> 4.0) - activesupport (~> 4.0) - rails-observers (~> 0.1.1) - activesupport (4.0.0) - i18n (~> 0.6, >= 0.6.4) - minitest (~> 4.2) - multi_json (~> 1.3) - thread_safe (~> 0.1) - tzinfo (~> 0.3.37) - ansi (1.4.3) - appraisal (1.0.2) - bundler - rake - thor (>= 0.14.0) - arel (4.0.2) - aruba (0.6.0) - childprocess (>= 0.3.6) - cucumber (>= 1.1.1) - rspec-expectations (>= 2.7.0) - bcrypt-ruby (3.0.1) - bourne (1.5.0) - mocha (>= 0.13.2, < 0.15) - builder (3.1.4) - childprocess (0.5.3) - ffi (~> 1.0, >= 1.0.11) - coderay (1.1.0) - coffee-rails (4.0.1) - coffee-script (>= 2.2.0) - railties (>= 4.0.0, < 5.0) - coffee-script (2.2.0) - coffee-script-source - execjs - coffee-script-source (1.7.0) - cucumber (1.3.16) - builder (>= 2.1.2) - diff-lcs (>= 1.1.3) - gherkin (~> 2.12) - multi_json (>= 1.7.5, < 2.0) - multi_test (>= 0.1.1) - diff-lcs (1.2.5) - erubis (2.7.0) - execjs (2.0.2) - ffi (1.9.3) - gherkin (2.12.2) - multi_json (~> 1.3) - hashie (3.3.1) - hike (1.2.3) - i18n (0.6.11) - jbuilder (1.5.3) - activesupport (>= 3.0.0) - multi_json (>= 1.2.0) - jquery-rails (3.0.4) - railties (>= 3.0, < 5.0) - thor (>= 0.14, < 2.0) - json (1.8.1) - mail (2.5.4) - mime-types (~> 1.16) - treetop (~> 1.4.8) - metaclass (0.0.1) - method_source (0.8.2) - mime-types (1.25.1) - minitest (4.7.5) - minitest-reporters (0.14.24) - ansi - builder - minitest (>= 2.12, < 5.0) - powerbar - mocha (0.14.0) - metaclass (~> 0.0.1) - multi_json (1.10.1) - multi_test (0.1.1) - polyglot (0.3.5) - posix-spawn (0.3.8) - powerbar (1.0.11) - ansi (~> 1.4.0) - hashie (>= 1.1.0) - protected_attributes (1.0.3) - activemodel (>= 4.0.0, < 5.0) - pry (0.10.1) - coderay (~> 1.1.0) - method_source (~> 0.8.1) - slop (~> 3.4) - pry-nav (0.2.4) - pry (>= 0.9.10, < 0.11.0) - pygments.rb (0.6.0) - posix-spawn (~> 0.3.6) - yajl-ruby (~> 1.1.0) - rack (1.5.2) - rack-test (0.6.2) - rack (>= 1.0) - rails (4.0.0) - actionmailer (= 4.0.0) - actionpack (= 4.0.0) - activerecord (= 4.0.0) - activesupport (= 4.0.0) - bundler (>= 1.3.0, < 2.0) - railties (= 4.0.0) - sprockets-rails (~> 2.0.0) - rails-observers (0.1.2) - activemodel (~> 4.0) - railties (4.0.0) - actionpack (= 4.0.0) - activesupport (= 4.0.0) - rake (>= 0.8.7) - thor (>= 0.18.1, < 2.0) - rake (10.3.2) - rdoc (4.1.1) - json (~> 1.4) - redcarpet (3.1.2) - rspec-core (3.0.3) - rspec-support (~> 3.0.0) - rspec-expectations (3.0.3) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.0.0) - rspec-mocks (3.0.3) - rspec-support (~> 3.0.0) - rspec-rails (3.0.2) - actionpack (>= 3.0) - activesupport (>= 3.0) - railties (>= 3.0) - rspec-core (~> 3.0.0) - rspec-expectations (~> 3.0.0) - rspec-mocks (~> 3.0.0) - rspec-support (~> 3.0.0) - rspec-support (3.0.3) - sass (3.2.19) - sass-rails (4.0.3) - railties (>= 4.0.0, < 5.0) - sass (~> 3.2.0) - sprockets (~> 2.8, <= 2.11.0) - sprockets-rails (~> 2.0) - sdoc (0.4.0) - json (~> 1.8) - rdoc (~> 4.0, < 5.0) - shoulda-context (1.2.0) - slop (3.6.0) - spring (1.1.3) - spring-commands-rspec (1.0.2) - spring (>= 0.9.1) - sprockets (2.11.0) - hike (~> 1.2) - multi_json (~> 1.0) - rack (~> 1.0) - tilt (~> 1.1, != 1.3.0) - sprockets-rails (2.0.1) - actionpack (>= 3.0) - activesupport (>= 3.0) - sprockets (~> 2.8) - sqlite3 (1.3.8) - thor (0.19.1) - thread_safe (0.3.4) - tilt (1.4.1) - treetop (1.4.15) - polyglot - polyglot (>= 0.3.1) - turbolinks (2.2.2) - coffee-rails - tzinfo (0.3.41) - uglifier (2.5.0) - execjs (>= 0.3.0) - json (>= 1.8.0) - watchr (0.7) - yajl-ruby (1.1.0) - yard (0.8.7.3) - -PLATFORMS - ruby - -DEPENDENCIES - activerecord-jdbc-adapter - activerecord-jdbcsqlite3-adapter - activeresource (= 4.0.0) - appraisal (~> 1.0) - aruba - bcrypt-ruby (~> 3.0.0) - bourne (~> 1.3) - bundler (~> 1.1) - coffee-rails (~> 4.0.0) - jbuilder (~> 1.2) - jdbc-sqlite3 - jquery-rails - jruby-openssl - minitest-reporters - protected_attributes - pry-nav - pygments.rb - rails (= 4.0.0) - rake (>= 0.9.2) - redcarpet - rspec-rails (~> 3.0.1) - sass-rails (~> 4.0.0) - sdoc - shoulda-context (~> 1.2.0) - spring - spring-commands-rspec - sqlite3 - therubyrhino - turbolinks - uglifier (>= 1.3.0) - watchr - yard diff -Nru ruby-shoulda-matchers-2.8.0/gemfiles/4.0.1.gemfile ruby-shoulda-matchers-4.3.0/gemfiles/4.0.1.gemfile --- ruby-shoulda-matchers-2.8.0/gemfiles/4.0.1.gemfile 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/gemfiles/4.0.1.gemfile 1970-01-01 00:00:00.000000000 +0000 @@ -1,36 +0,0 @@ -# This file was generated by Appraisal - -source "https://rubygems.org" - -gem "appraisal", "~> 1.0" -gem "aruba" -gem "bourne", "~> 1.3" -gem "bundler", "~> 1.1" -gem "pry-nav" -gem "rails", "4.0.1" -gem "rake", ">= 0.9.2" -gem "rspec-rails", "2.99.0" -gem "yard" -gem "redcarpet" -gem "pygments.rb" -gem "watchr" -gem "shoulda-context", "~> 1.2.0" -gem "sqlite3", :platform => :ruby -gem "activerecord-jdbc-adapter", :platform => :jruby -gem "activerecord-jdbcsqlite3-adapter", :platform => :jruby -gem "jdbc-sqlite3", :platform => :jruby -gem "jruby-openssl", :platform => :jruby -gem "therubyrhino", :platform => :jruby -gem "spring" -gem "spring-commands-rspec" -gem "uglifier", ">= 1.3.0" -gem "coffee-rails", "~> 4.0.0" -gem "jquery-rails" -gem "turbolinks" -gem "sdoc" -gem "activeresource", "4.0.0" -gem "protected_attributes" -gem "minitest-reporters" -gem "jbuilder", "~> 1.2" -gem "sass-rails", "~> 4.0.0" -gem "bcrypt-ruby", "~> 3.1.2" diff -Nru ruby-shoulda-matchers-2.8.0/gemfiles/4.0.1.gemfile.lock ruby-shoulda-matchers-4.3.0/gemfiles/4.0.1.gemfile.lock --- ruby-shoulda-matchers-2.8.0/gemfiles/4.0.1.gemfile.lock 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/gemfiles/4.0.1.gemfile.lock 1970-01-01 00:00:00.000000000 +0000 @@ -1,221 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - actionmailer (4.0.1) - actionpack (= 4.0.1) - mail (~> 2.5.4) - actionpack (4.0.1) - activesupport (= 4.0.1) - builder (~> 3.1.0) - erubis (~> 2.7.0) - rack (~> 1.5.2) - rack-test (~> 0.6.2) - activemodel (4.0.1) - activesupport (= 4.0.1) - builder (~> 3.1.0) - activerecord (4.0.1) - activemodel (= 4.0.1) - activerecord-deprecated_finders (~> 1.0.2) - activesupport (= 4.0.1) - arel (~> 4.0.0) - activerecord-deprecated_finders (1.0.3) - activeresource (4.0.0) - activemodel (~> 4.0) - activesupport (~> 4.0) - rails-observers (~> 0.1.1) - activesupport (4.0.1) - i18n (~> 0.6, >= 0.6.4) - minitest (~> 4.2) - multi_json (~> 1.3) - thread_safe (~> 0.1) - tzinfo (~> 0.3.37) - ansi (1.4.3) - appraisal (1.0.2) - bundler - rake - thor (>= 0.14.0) - arel (4.0.1) - aruba (0.6.0) - childprocess (>= 0.3.6) - cucumber (>= 1.1.1) - rspec-expectations (>= 2.7.0) - bcrypt-ruby (3.1.2) - bourne (1.5.0) - mocha (>= 0.13.2, < 0.15) - builder (3.1.4) - childprocess (0.5.3) - ffi (~> 1.0, >= 1.0.11) - coderay (1.1.0) - coffee-rails (4.0.1) - coffee-script (>= 2.2.0) - railties (>= 4.0.0, < 5.0) - coffee-script (2.2.0) - coffee-script-source - execjs - coffee-script-source (1.7.0) - cucumber (1.3.16) - builder (>= 2.1.2) - diff-lcs (>= 1.1.3) - gherkin (~> 2.12) - multi_json (>= 1.7.5, < 2.0) - multi_test (>= 0.1.1) - diff-lcs (1.2.5) - erubis (2.7.0) - execjs (2.0.2) - ffi (1.9.3) - gherkin (2.12.2) - multi_json (~> 1.3) - hashie (3.3.1) - hike (1.2.3) - i18n (0.6.11) - jbuilder (1.5.3) - activesupport (>= 3.0.0) - multi_json (>= 1.2.0) - jquery-rails (3.0.4) - railties (>= 3.0, < 5.0) - thor (>= 0.14, < 2.0) - json (1.8.1) - mail (2.5.4) - mime-types (~> 1.16) - treetop (~> 1.4.8) - metaclass (0.0.1) - method_source (0.8.2) - mime-types (1.25.1) - minitest (4.7.5) - minitest-reporters (0.14.24) - ansi - builder - minitest (>= 2.12, < 5.0) - powerbar - mocha (0.14.0) - metaclass (~> 0.0.1) - multi_json (1.10.1) - multi_test (0.1.1) - polyglot (0.3.3) - posix-spawn (0.3.8) - powerbar (1.0.11) - ansi (~> 1.4.0) - hashie (>= 1.1.0) - protected_attributes (1.0.5) - activemodel (>= 4.0.1, < 5.0) - pry (0.10.1) - coderay (~> 1.1.0) - method_source (~> 0.8.1) - slop (~> 3.4) - pry-nav (0.2.4) - pry (>= 0.9.10, < 0.11.0) - pygments.rb (0.6.0) - posix-spawn (~> 0.3.6) - yajl-ruby (~> 1.1.0) - rack (1.5.2) - rack-test (0.6.2) - rack (>= 1.0) - rails (4.0.1) - actionmailer (= 4.0.1) - actionpack (= 4.0.1) - activerecord (= 4.0.1) - activesupport (= 4.0.1) - bundler (>= 1.3.0, < 2.0) - railties (= 4.0.1) - sprockets-rails (~> 2.0.0) - rails-observers (0.1.2) - activemodel (~> 4.0) - railties (4.0.1) - actionpack (= 4.0.1) - activesupport (= 4.0.1) - rake (>= 0.8.7) - thor (>= 0.18.1, < 2.0) - rake (10.3.2) - rdoc (4.1.1) - json (~> 1.4) - redcarpet (3.1.2) - rspec-collection_matchers (1.0.0) - rspec-expectations (>= 2.99.0.beta1) - rspec-core (2.99.1) - rspec-expectations (2.99.2) - diff-lcs (>= 1.1.3, < 2.0) - rspec-mocks (2.99.2) - rspec-rails (2.99.0) - actionpack (>= 3.0) - activemodel (>= 3.0) - activesupport (>= 3.0) - railties (>= 3.0) - rspec-collection_matchers - rspec-core (~> 2.99.0) - rspec-expectations (~> 2.99.0) - rspec-mocks (~> 2.99.0) - sass (3.2.12) - sass-rails (4.0.1) - railties (>= 4.0.0, < 5.0) - sass (>= 3.1.10) - sprockets-rails (~> 2.0.0) - sdoc (0.4.0) - json (~> 1.8) - rdoc (~> 4.0, < 5.0) - shoulda-context (1.2.0) - slop (3.6.0) - spring (1.1.3) - spring-commands-rspec (1.0.2) - spring (>= 0.9.1) - sprockets (2.10.1) - hike (~> 1.2) - multi_json (~> 1.0) - rack (~> 1.0) - tilt (~> 1.1, != 1.3.0) - sprockets-rails (2.0.1) - actionpack (>= 3.0) - activesupport (>= 3.0) - sprockets (~> 2.8) - sqlite3 (1.3.8) - thor (0.19.1) - thread_safe (0.3.4) - tilt (1.4.1) - treetop (1.4.15) - polyglot - polyglot (>= 0.3.1) - turbolinks (2.2.2) - coffee-rails - tzinfo (0.3.41) - uglifier (2.5.0) - execjs (>= 0.3.0) - json (>= 1.8.0) - watchr (0.7) - yajl-ruby (1.1.0) - yard (0.8.7.3) - -PLATFORMS - ruby - -DEPENDENCIES - activerecord-jdbc-adapter - activerecord-jdbcsqlite3-adapter - activeresource (= 4.0.0) - appraisal (~> 1.0) - aruba - bcrypt-ruby (~> 3.1.2) - bourne (~> 1.3) - bundler (~> 1.1) - coffee-rails (~> 4.0.0) - jbuilder (~> 1.2) - jdbc-sqlite3 - jquery-rails - jruby-openssl - minitest-reporters - protected_attributes - pry-nav - pygments.rb - rails (= 4.0.1) - rake (>= 0.9.2) - redcarpet - rspec-rails (= 2.99.0) - sass-rails (~> 4.0.0) - sdoc - shoulda-context (~> 1.2.0) - spring - spring-commands-rspec - sqlite3 - therubyrhino - turbolinks - uglifier (>= 1.3.0) - watchr - yard diff -Nru ruby-shoulda-matchers-2.8.0/gemfiles/4.1.gemfile ruby-shoulda-matchers-4.3.0/gemfiles/4.1.gemfile --- ruby-shoulda-matchers-2.8.0/gemfiles/4.1.gemfile 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/gemfiles/4.1.gemfile 1970-01-01 00:00:00.000000000 +0000 @@ -1,36 +0,0 @@ -# This file was generated by Appraisal - -source "https://rubygems.org" - -gem "appraisal", "~> 1.0" -gem "aruba" -gem "bourne", "~> 1.3" -gem "bundler", "~> 1.1" -gem "pry-nav" -gem "rails", "~> 4.1.0" -gem "rake", ">= 0.9.2" -gem "rspec-rails", "~> 3.0.1" -gem "yard" -gem "redcarpet" -gem "pygments.rb" -gem "watchr" -gem "shoulda-context", "~> 1.2.0" -gem "sqlite3", :platform => :ruby -gem "activerecord-jdbc-adapter", :platform => :jruby -gem "activerecord-jdbcsqlite3-adapter", :platform => :jruby -gem "jdbc-sqlite3", :platform => :jruby -gem "jruby-openssl", :platform => :jruby -gem "therubyrhino", :platform => :jruby -gem "spring" -gem "spring-commands-rspec" -gem "uglifier", ">= 1.3.0" -gem "coffee-rails", "~> 4.0.0" -gem "jquery-rails" -gem "turbolinks" -gem "sdoc", "~> 0.4.0" -gem "activeresource", "4.0.0" -gem "protected_attributes", "~> 1.0.6" -gem "minitest-reporters" -gem "jbuilder", "~> 2.0" -gem "sass-rails", "~> 4.0.3" -gem "bcrypt", "~> 3.1.7" diff -Nru ruby-shoulda-matchers-2.8.0/gemfiles/4.1.gemfile.lock ruby-shoulda-matchers-4.3.0/gemfiles/4.1.gemfile.lock --- ruby-shoulda-matchers-2.8.0/gemfiles/4.1.gemfile.lock 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/gemfiles/4.1.gemfile.lock 1970-01-01 00:00:00.000000000 +0000 @@ -1,220 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - actionmailer (4.1.7) - actionpack (= 4.1.7) - actionview (= 4.1.7) - mail (~> 2.5, >= 2.5.4) - actionpack (4.1.7) - actionview (= 4.1.7) - activesupport (= 4.1.7) - rack (~> 1.5.2) - rack-test (~> 0.6.2) - actionview (4.1.7) - activesupport (= 4.1.7) - builder (~> 3.1) - erubis (~> 2.7.0) - activemodel (4.1.7) - activesupport (= 4.1.7) - builder (~> 3.1) - activerecord (4.1.7) - activemodel (= 4.1.7) - activesupport (= 4.1.7) - arel (~> 5.0.0) - activeresource (4.0.0) - activemodel (~> 4.0) - activesupport (~> 4.0) - rails-observers (~> 0.1.1) - activesupport (4.1.7) - i18n (~> 0.6, >= 0.6.9) - json (~> 1.7, >= 1.7.7) - minitest (~> 5.1) - thread_safe (~> 0.1) - tzinfo (~> 1.1) - ansi (1.4.3) - appraisal (1.0.2) - bundler - rake - thor (>= 0.14.0) - arel (5.0.1.20140414130214) - aruba (0.6.0) - childprocess (>= 0.3.6) - cucumber (>= 1.1.1) - rspec-expectations (>= 2.7.0) - bcrypt (3.1.7) - bourne (1.5.0) - mocha (>= 0.13.2, < 0.15) - builder (3.2.2) - childprocess (0.5.3) - ffi (~> 1.0, >= 1.0.11) - coderay (1.1.0) - coffee-rails (4.0.1) - coffee-script (>= 2.2.0) - railties (>= 4.0.0, < 5.0) - coffee-script (2.2.0) - coffee-script-source - execjs - coffee-script-source (1.7.0) - cucumber (1.3.16) - builder (>= 2.1.2) - diff-lcs (>= 1.1.3) - gherkin (~> 2.12) - multi_json (>= 1.7.5, < 2.0) - multi_test (>= 0.1.1) - diff-lcs (1.2.5) - erubis (2.7.0) - execjs (2.0.2) - ffi (1.9.3) - gherkin (2.12.2) - multi_json (~> 1.3) - hike (1.2.3) - i18n (0.6.11) - jbuilder (2.0.6) - activesupport (>= 3.0.0, < 5) - multi_json (~> 1.2) - jquery-rails (3.1.0) - railties (>= 3.0, < 5.0) - thor (>= 0.14, < 2.0) - json (1.8.1) - mail (2.6.3) - mime-types (>= 1.16, < 3) - metaclass (0.0.2) - method_source (0.8.2) - mime-types (2.4.3) - minitest (5.4.2) - minitest-reporters (1.0.5) - ansi - builder - minitest (>= 5.0) - ruby-progressbar - mocha (0.14.0) - metaclass (~> 0.0.1) - multi_json (1.10.1) - multi_test (0.1.1) - posix-spawn (0.3.8) - protected_attributes (1.0.7) - activemodel (>= 4.0.1, < 5.0) - pry (0.10.1) - coderay (~> 1.1.0) - method_source (~> 0.8.1) - slop (~> 3.4) - pry-nav (0.2.4) - pry (>= 0.9.10, < 0.11.0) - pygments.rb (0.6.0) - posix-spawn (~> 0.3.6) - yajl-ruby (~> 1.1.0) - rack (1.5.2) - rack-test (0.6.2) - rack (>= 1.0) - rails (4.1.7) - actionmailer (= 4.1.7) - actionpack (= 4.1.7) - actionview (= 4.1.7) - activemodel (= 4.1.7) - activerecord (= 4.1.7) - activesupport (= 4.1.7) - bundler (>= 1.3.0, < 2.0) - railties (= 4.1.7) - sprockets-rails (~> 2.0) - rails-observers (0.1.2) - activemodel (~> 4.0) - railties (4.1.7) - actionpack (= 4.1.7) - activesupport (= 4.1.7) - rake (>= 0.8.7) - thor (>= 0.18.1, < 2.0) - rake (10.3.2) - rdoc (4.1.1) - json (~> 1.4) - redcarpet (3.1.2) - rspec-core (3.0.3) - rspec-support (~> 3.0.0) - rspec-expectations (3.0.3) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.0.0) - rspec-mocks (3.0.3) - rspec-support (~> 3.0.0) - rspec-rails (3.0.2) - actionpack (>= 3.0) - activesupport (>= 3.0) - railties (>= 3.0) - rspec-core (~> 3.0.0) - rspec-expectations (~> 3.0.0) - rspec-mocks (~> 3.0.0) - rspec-support (~> 3.0.0) - rspec-support (3.0.3) - ruby-progressbar (1.5.1) - sass (3.2.19) - sass-rails (4.0.3) - railties (>= 4.0.0, < 5.0) - sass (~> 3.2.0) - sprockets (~> 2.8, <= 2.11.0) - sprockets-rails (~> 2.0) - sdoc (0.4.0) - json (~> 1.8) - rdoc (~> 4.0, < 5.0) - shoulda-context (1.2.0) - slop (3.6.0) - spring (1.1.2) - spring-commands-rspec (1.0.2) - spring (>= 0.9.1) - sprockets (2.11.0) - hike (~> 1.2) - multi_json (~> 1.0) - rack (~> 1.0) - tilt (~> 1.1, != 1.3.0) - sprockets-rails (2.2.0) - actionpack (>= 3.0) - activesupport (>= 3.0) - sprockets (>= 2.8, < 4.0) - sqlite3 (1.3.9) - thor (0.19.1) - thread_safe (0.3.4) - tilt (1.4.1) - turbolinks (2.2.2) - coffee-rails - tzinfo (1.2.2) - thread_safe (~> 0.1) - uglifier (2.5.0) - execjs (>= 0.3.0) - json (>= 1.8.0) - watchr (0.7) - yajl-ruby (1.1.0) - yard (0.8.7.3) - -PLATFORMS - ruby - -DEPENDENCIES - activerecord-jdbc-adapter - activerecord-jdbcsqlite3-adapter - activeresource (= 4.0.0) - appraisal (~> 1.0) - aruba - bcrypt (~> 3.1.7) - bourne (~> 1.3) - bundler (~> 1.1) - coffee-rails (~> 4.0.0) - jbuilder (~> 2.0) - jdbc-sqlite3 - jquery-rails - jruby-openssl - minitest-reporters - protected_attributes (~> 1.0.6) - pry-nav - pygments.rb - rails (~> 4.1.0) - rake (>= 0.9.2) - redcarpet - rspec-rails (~> 3.0.1) - sass-rails (~> 4.0.3) - sdoc (~> 0.4.0) - shoulda-context (~> 1.2.0) - spring - spring-commands-rspec - sqlite3 - therubyrhino - turbolinks - uglifier (>= 1.3.0) - watchr - yard diff -Nru ruby-shoulda-matchers-2.8.0/gemfiles/4.2.gemfile ruby-shoulda-matchers-4.3.0/gemfiles/4.2.gemfile --- ruby-shoulda-matchers-2.8.0/gemfiles/4.2.gemfile 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/gemfiles/4.2.gemfile 1970-01-01 00:00:00.000000000 +0000 @@ -1,38 +0,0 @@ -# This file was generated by Appraisal - -source "https://rubygems.org" - -gem "appraisal", "~> 1.0" -gem "aruba" -gem "bourne", "~> 1.3" -gem "bundler", "~> 1.1" -gem "pry-nav" -gem "rails", "~> 4.2.0" -gem "rake", ">= 0.9.2" -gem "rspec-rails", "~> 3.0.1" -gem "yard" -gem "redcarpet" -gem "pygments.rb" -gem "watchr" -gem "shoulda-context", "~> 1.2.0" -gem "sqlite3", :platform => :ruby -gem "activerecord-jdbc-adapter", :platform => :jruby -gem "activerecord-jdbcsqlite3-adapter", :platform => :jruby -gem "jdbc-sqlite3", :platform => :jruby -gem "jruby-openssl", :platform => :jruby -gem "therubyrhino", :platform => :jruby -gem "spring" -gem "spring-commands-rspec" -gem "uglifier", ">= 1.3.0" -gem "coffee-rails", "~> 4.1.0" -gem "jquery-rails" -gem "turbolinks" -gem "sdoc", "~> 0.4.0" -gem "activeresource", "4.0.0" -gem "protected_attributes", "~> 1.0.6" -gem "minitest-reporters" -gem "sass-rails", "~> 5.0" -gem "jbuilder", "~> 2.0" -gem "bcrypt", "~> 3.1.7" -gem "byebug" -gem "web-console", "~> 2.0" diff -Nru ruby-shoulda-matchers-2.8.0/gemfiles/4.2.gemfile.lock ruby-shoulda-matchers-4.3.0/gemfiles/4.2.gemfile.lock --- ruby-shoulda-matchers-2.8.0/gemfiles/4.2.gemfile.lock 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/gemfiles/4.2.gemfile.lock 1970-01-01 00:00:00.000000000 +0000 @@ -1,263 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - actionmailer (4.2.0) - actionpack (= 4.2.0) - actionview (= 4.2.0) - activejob (= 4.2.0) - mail (~> 2.5, >= 2.5.4) - rails-dom-testing (~> 1.0, >= 1.0.5) - actionpack (4.2.0) - actionview (= 4.2.0) - activesupport (= 4.2.0) - rack (~> 1.6.0) - rack-test (~> 0.6.2) - rails-dom-testing (~> 1.0, >= 1.0.5) - rails-html-sanitizer (~> 1.0, >= 1.0.1) - actionview (4.2.0) - activesupport (= 4.2.0) - builder (~> 3.1) - erubis (~> 2.7.0) - rails-dom-testing (~> 1.0, >= 1.0.5) - rails-html-sanitizer (~> 1.0, >= 1.0.1) - activejob (4.2.0) - activesupport (= 4.2.0) - globalid (>= 0.3.0) - activemodel (4.2.0) - activesupport (= 4.2.0) - builder (~> 3.1) - activerecord (4.2.0) - activemodel (= 4.2.0) - activesupport (= 4.2.0) - arel (~> 6.0) - activeresource (4.0.0) - activemodel (~> 4.0) - activesupport (~> 4.0) - rails-observers (~> 0.1.1) - activesupport (4.2.0) - i18n (~> 0.7) - json (~> 1.7, >= 1.7.7) - minitest (~> 5.1) - thread_safe (~> 0.3, >= 0.3.4) - tzinfo (~> 1.1) - ansi (1.4.3) - appraisal (1.0.2) - bundler - rake - thor (>= 0.14.0) - arel (6.0.0) - aruba (0.6.1) - childprocess (>= 0.3.6) - cucumber (>= 1.1.1) - rspec-expectations (>= 2.7.0) - bcrypt (3.1.9) - binding_of_caller (0.7.2) - debug_inspector (>= 0.0.1) - bourne (1.6.0) - mocha (~> 1.1) - builder (3.2.2) - byebug (3.5.1) - columnize (~> 0.8) - debugger-linecache (~> 1.2) - slop (~> 3.6) - childprocess (0.5.5) - ffi (~> 1.0, >= 1.0.11) - coderay (1.1.0) - coffee-rails (4.1.0) - coffee-script (>= 2.2.0) - railties (>= 4.0.0, < 5.0) - coffee-script (2.3.0) - coffee-script-source - execjs - coffee-script-source (1.8.0) - columnize (0.9.0) - cucumber (1.3.17) - builder (>= 2.1.2) - diff-lcs (>= 1.1.3) - gherkin (~> 2.12) - multi_json (>= 1.7.5, < 2.0) - multi_test (>= 0.1.1) - debug_inspector (0.0.2) - debugger-linecache (1.2.0) - diff-lcs (1.2.5) - erubis (2.7.0) - execjs (2.2.2) - ffi (1.9.6) - gherkin (2.12.2) - multi_json (~> 1.3) - globalid (0.3.0) - activesupport (>= 4.1.0) - hike (1.2.3) - i18n (0.7.0) - jbuilder (2.2.6) - activesupport (>= 3.0.0, < 5) - multi_json (~> 1.2) - jquery-rails (4.0.2) - rails-dom-testing (~> 1.0) - railties (>= 4.2.0) - thor (>= 0.14, < 2.0) - json (1.8.2) - loofah (2.0.1) - nokogiri (>= 1.5.9) - mail (2.6.3) - mime-types (>= 1.16, < 3) - metaclass (0.0.4) - method_source (0.8.2) - mime-types (2.4.3) - mini_portile (0.6.2) - minitest (5.5.1) - minitest-reporters (1.0.8) - ansi - builder - minitest (>= 5.0) - ruby-progressbar - mocha (1.1.0) - metaclass (~> 0.0.1) - multi_json (1.10.1) - multi_test (0.1.1) - nokogiri (1.6.6.1) - mini_portile (~> 0.6.0) - posix-spawn (0.3.9) - protected_attributes (1.0.8) - activemodel (>= 4.0.1, < 5.0) - pry (0.10.1) - coderay (~> 1.1.0) - method_source (~> 0.8.1) - slop (~> 3.4) - pry-nav (0.2.4) - pry (>= 0.9.10, < 0.11.0) - pygments.rb (0.6.0) - posix-spawn (~> 0.3.6) - yajl-ruby (~> 1.1.0) - rack (1.6.0) - rack-test (0.6.3) - rack (>= 1.0) - rails (4.2.0) - actionmailer (= 4.2.0) - actionpack (= 4.2.0) - actionview (= 4.2.0) - activejob (= 4.2.0) - activemodel (= 4.2.0) - activerecord (= 4.2.0) - activesupport (= 4.2.0) - bundler (>= 1.3.0, < 2.0) - railties (= 4.2.0) - sprockets-rails - rails-deprecated_sanitizer (1.0.3) - activesupport (>= 4.2.0.alpha) - rails-dom-testing (1.0.5) - activesupport (>= 4.2.0.beta, < 5.0) - nokogiri (~> 1.6.0) - rails-deprecated_sanitizer (>= 1.0.1) - rails-html-sanitizer (1.0.1) - loofah (~> 2.0) - rails-observers (0.1.2) - activemodel (~> 4.0) - railties (4.2.0) - actionpack (= 4.2.0) - activesupport (= 4.2.0) - rake (>= 0.8.7) - thor (>= 0.18.1, < 2.0) - rake (10.4.2) - rdoc (4.2.0) - json (~> 1.4) - redcarpet (3.2.2) - rspec-core (3.0.4) - rspec-support (~> 3.0.0) - rspec-expectations (3.0.4) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.0.0) - rspec-mocks (3.0.4) - rspec-support (~> 3.0.0) - rspec-rails (3.0.2) - actionpack (>= 3.0) - activesupport (>= 3.0) - railties (>= 3.0) - rspec-core (~> 3.0.0) - rspec-expectations (~> 3.0.0) - rspec-mocks (~> 3.0.0) - rspec-support (~> 3.0.0) - rspec-support (3.0.4) - ruby-progressbar (1.7.1) - sass (3.4.9) - sass-rails (5.0.0) - railties (>= 4.0.0, < 5.0) - sass (~> 3.1) - sprockets (>= 2.8, < 4.0) - sprockets-rails (>= 2.0, < 4.0) - tilt (~> 1.1) - sdoc (0.4.1) - json (~> 1.7, >= 1.7.7) - rdoc (~> 4.0) - shoulda-context (1.2.1) - slop (3.6.0) - spring (1.2.0) - spring-commands-rspec (1.0.4) - spring (>= 0.9.1) - sprockets (2.12.3) - hike (~> 1.2) - multi_json (~> 1.0) - rack (~> 1.0) - tilt (~> 1.1, != 1.3.0) - sprockets-rails (2.2.2) - actionpack (>= 3.0) - activesupport (>= 3.0) - sprockets (>= 2.8, < 4.0) - sqlite3 (1.3.10) - thor (0.19.1) - thread_safe (0.3.4) - tilt (1.4.1) - turbolinks (2.5.3) - coffee-rails - tzinfo (1.2.2) - thread_safe (~> 0.1) - uglifier (2.6.0) - execjs (>= 0.3.0) - json (>= 1.8.0) - watchr (0.7) - web-console (2.0.0) - activemodel (~> 4.0) - binding_of_caller (>= 0.7.2) - railties (~> 4.0) - sprockets-rails (>= 2.0, < 4.0) - yajl-ruby (1.1.0) - yard (0.8.7.6) - -PLATFORMS - ruby - -DEPENDENCIES - activerecord-jdbc-adapter - activerecord-jdbcsqlite3-adapter - activeresource (= 4.0.0) - appraisal (~> 1.0) - aruba - bcrypt (~> 3.1.7) - bourne (~> 1.3) - bundler (~> 1.1) - byebug - coffee-rails (~> 4.1.0) - jbuilder (~> 2.0) - jdbc-sqlite3 - jquery-rails - jruby-openssl - minitest-reporters - protected_attributes (~> 1.0.6) - pry-nav - pygments.rb - rails (~> 4.2.0) - rake (>= 0.9.2) - redcarpet - rspec-rails (~> 3.0.1) - sass-rails (~> 5.0) - sdoc (~> 0.4.0) - shoulda-context (~> 1.2.0) - spring - spring-commands-rspec - sqlite3 - therubyrhino - turbolinks - uglifier (>= 1.3.0) - watchr - web-console (~> 2.0) - yard diff -Nru ruby-shoulda-matchers-2.8.0/gemfiles/rails_4_2.gemfile ruby-shoulda-matchers-4.3.0/gemfiles/rails_4_2.gemfile --- ruby-shoulda-matchers-2.8.0/gemfiles/rails_4_2.gemfile 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/gemfiles/rails_4_2.gemfile 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,35 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "appraisal", "2.2.0" +gem "bundler", "~> 1.1" +gem "pry" +gem "pry-byebug" +gem "rake", "13.0.1" +gem "rspec", "~> 3.9" +gem "rubocop", require: false +gem "rubocop-rails", require: false +gem "zeus", require: false +gem "fssm" +gem "pygments.rb" +gem "redcarpet" +gem "yard" +gem "spring" +gem "spring-commands-rspec" +gem "rspec-rails", "~> 3.9" +gem "shoulda-context", "~> 1.2.0" +gem "rails", "4.2.11.1" +gem "sass-rails", "~> 5.0" +gem "uglifier", ">= 1.3.0" +gem "coffee-rails", "~> 4.1.0" +gem "jquery-rails" +gem "turbolinks" +gem "jbuilder", "~> 2.0" +gem "sdoc", "~> 0.4.0", group: :doc +gem "bcrypt", "~> 3.1.7" +gem "activeresource", "4.0.0" +gem "json", "~> 1.4" +gem "protected_attributes", "~> 1.0.6" +gem "pg", "~> 0.18" +gem "sqlite3", "~> 1.3.6" diff -Nru ruby-shoulda-matchers-2.8.0/gemfiles/rails_4_2.gemfile.lock ruby-shoulda-matchers-4.3.0/gemfiles/rails_4_2.gemfile.lock --- ruby-shoulda-matchers-2.8.0/gemfiles/rails_4_2.gemfile.lock 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/gemfiles/rails_4_2.gemfile.lock 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,250 @@ +GEM + remote: https://rubygems.org/ + specs: + actionmailer (4.2.11.1) + actionpack (= 4.2.11.1) + actionview (= 4.2.11.1) + activejob (= 4.2.11.1) + mail (~> 2.5, >= 2.5.4) + rails-dom-testing (~> 1.0, >= 1.0.5) + actionpack (4.2.11.1) + actionview (= 4.2.11.1) + activesupport (= 4.2.11.1) + rack (~> 1.6) + rack-test (~> 0.6.2) + rails-dom-testing (~> 1.0, >= 1.0.5) + rails-html-sanitizer (~> 1.0, >= 1.0.2) + actionview (4.2.11.1) + activesupport (= 4.2.11.1) + builder (~> 3.1) + erubis (~> 2.7.0) + rails-dom-testing (~> 1.0, >= 1.0.5) + rails-html-sanitizer (~> 1.0, >= 1.0.3) + activejob (4.2.11.1) + activesupport (= 4.2.11.1) + globalid (>= 0.3.0) + activemodel (4.2.11.1) + activesupport (= 4.2.11.1) + builder (~> 3.1) + activerecord (4.2.11.1) + activemodel (= 4.2.11.1) + activesupport (= 4.2.11.1) + arel (~> 6.0) + activeresource (4.0.0) + activemodel (~> 4.0) + activesupport (~> 4.0) + rails-observers (~> 0.1.1) + activesupport (4.2.11.1) + i18n (~> 0.7) + minitest (~> 5.1) + thread_safe (~> 0.3, >= 0.3.4) + tzinfo (~> 1.1) + appraisal (2.2.0) + bundler + rake + thor (>= 0.14.0) + arel (6.0.4) + ast (2.4.0) + bcrypt (3.1.13) + builder (3.2.4) + byebug (11.0.1) + coderay (1.1.2) + coffee-rails (4.1.1) + coffee-script (>= 2.2.0) + railties (>= 4.0.0, < 5.1.x) + coffee-script (2.4.1) + coffee-script-source + execjs + coffee-script-source (1.12.2) + concurrent-ruby (1.1.5) + crass (1.0.5) + diff-lcs (1.3) + erubis (2.7.0) + execjs (2.7.0) + ffi (1.11.3) + fssm (0.2.10) + globalid (0.4.2) + activesupport (>= 4.2.0) + i18n (0.9.5) + concurrent-ruby (~> 1.0) + jaro_winkler (1.5.4) + jbuilder (2.9.1) + activesupport (>= 4.2.0) + jquery-rails (4.3.5) + rails-dom-testing (>= 1, < 3) + railties (>= 4.2.0) + thor (>= 0.14, < 2.0) + json (1.8.6) + loofah (2.4.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + method_source (0.9.2) + mini_mime (1.0.2) + mini_portile2 (2.4.0) + minitest (5.13.0) + multi_json (1.14.1) + nokogiri (1.10.7) + mini_portile2 (~> 2.4.0) + parallel (1.19.1) + parser (2.7.0.0) + ast (~> 2.4.0) + pg (0.21.0) + protected_attributes (1.0.9) + activemodel (>= 4.0.1, < 5.0) + pry (0.12.2) + coderay (~> 1.1.0) + method_source (~> 0.9.0) + pry-byebug (3.7.0) + byebug (~> 11.0) + pry (~> 0.10) + pygments.rb (1.2.1) + multi_json (>= 1.0.0) + rack (1.6.12) + rack-test (0.6.3) + rack (>= 1.0) + rails (4.2.11.1) + actionmailer (= 4.2.11.1) + actionpack (= 4.2.11.1) + actionview (= 4.2.11.1) + activejob (= 4.2.11.1) + activemodel (= 4.2.11.1) + activerecord (= 4.2.11.1) + activesupport (= 4.2.11.1) + bundler (>= 1.3.0, < 2.0) + railties (= 4.2.11.1) + sprockets-rails + rails-deprecated_sanitizer (1.0.3) + activesupport (>= 4.2.0.alpha) + rails-dom-testing (1.0.9) + activesupport (>= 4.2.0, < 5.0) + nokogiri (~> 1.6) + rails-deprecated_sanitizer (>= 1.0.1) + rails-html-sanitizer (1.3.0) + loofah (~> 2.3) + rails-observers (0.1.5) + activemodel (>= 4.0) + railties (4.2.11.1) + actionpack (= 4.2.11.1) + activesupport (= 4.2.11.1) + rake (>= 0.8.7) + thor (>= 0.18.1, < 2.0) + rainbow (3.0.0) + rake (13.0.1) + rb-fsevent (0.10.3) + rb-inotify (0.10.1) + ffi (~> 1.0) + rdoc (4.3.0) + redcarpet (3.5.0) + rspec (3.9.0) + rspec-core (~> 3.9.0) + rspec-expectations (~> 3.9.0) + rspec-mocks (~> 3.9.0) + 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.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.9.0) + rspec-rails (3.9.0) + actionpack (>= 3.0) + activesupport (>= 3.0) + railties (>= 3.0) + rspec-core (~> 3.9.0) + rspec-expectations (~> 3.9.0) + rspec-mocks (~> 3.9.0) + rspec-support (~> 3.9.0) + rspec-support (3.9.0) + rubocop (0.78.0) + jaro_winkler (~> 1.5.1) + parallel (~> 1.10) + 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.1) + rack (>= 1.1) + rubocop (>= 0.72.0) + ruby-progressbar (1.10.1) + sass (3.7.4) + sass-listen (~> 4.0.0) + sass-listen (4.0.0) + rb-fsevent (~> 0.9, >= 0.9.4) + rb-inotify (~> 0.9, >= 0.9.7) + sass-rails (5.0.7) + railties (>= 4.0.0, < 6) + sass (~> 3.1) + sprockets (>= 2.8, < 4.0) + sprockets-rails (>= 2.0, < 4.0) + tilt (>= 1.1, < 3) + sdoc (0.4.2) + json (~> 1.7, >= 1.7.7) + rdoc (~> 4.0) + shoulda-context (1.2.2) + spring (2.1.0) + spring-commands-rspec (1.0.4) + spring (>= 0.9.1) + sprockets (3.7.2) + concurrent-ruby (~> 1.0) + rack (> 1, < 3) + sprockets-rails (3.2.1) + actionpack (>= 4.0) + activesupport (>= 4.0) + sprockets (>= 3.0.0) + sqlite3 (1.3.13) + thor (1.0.1) + thread_safe (0.3.6) + tilt (2.0.10) + turbolinks (5.2.1) + turbolinks-source (~> 5.2) + turbolinks-source (5.2.0) + tzinfo (1.2.6) + thread_safe (~> 0.1) + uglifier (4.2.0) + execjs (>= 0.3.0, < 3) + unicode-display_width (1.6.0) + yard (0.9.20) + zeus (0.15.14) + method_source (>= 0.6.7) + +PLATFORMS + ruby + +DEPENDENCIES + activeresource (= 4.0.0) + appraisal (= 2.2.0) + bcrypt (~> 3.1.7) + bundler (~> 1.1) + coffee-rails (~> 4.1.0) + fssm + jbuilder (~> 2.0) + jquery-rails + json (~> 1.4) + pg (~> 0.18) + protected_attributes (~> 1.0.6) + pry + pry-byebug + pygments.rb + rails (= 4.2.11.1) + rake (= 13.0.1) + redcarpet + rspec (~> 3.9) + rspec-rails (~> 3.9) + rubocop + rubocop-rails + sass-rails (~> 5.0) + sdoc (~> 0.4.0) + shoulda-context (~> 1.2.0) + spring + spring-commands-rspec + sqlite3 (~> 1.3.6) + turbolinks + uglifier (>= 1.3.0) + yard + zeus + +BUNDLED WITH + 1.17.3 diff -Nru ruby-shoulda-matchers-2.8.0/gemfiles/rails_5_0.gemfile ruby-shoulda-matchers-4.3.0/gemfiles/rails_5_0.gemfile --- ruby-shoulda-matchers-2.8.0/gemfiles/rails_5_0.gemfile 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/gemfiles/rails_5_0.gemfile 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,33 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "appraisal", "2.2.0" +gem "bundler", "~> 1.1" +gem "pry" +gem "pry-byebug" +gem "rake", "13.0.1" +gem "rspec", "~> 3.9" +gem "rubocop", require: false +gem "rubocop-rails", require: false +gem "zeus", require: false +gem "fssm" +gem "pygments.rb" +gem "redcarpet" +gem "yard" +gem "spring" +gem "spring-commands-rspec" +gem "rspec-rails", "~> 3.9" +gem "shoulda-context", "~> 1.2.0" +gem "rails-controller-testing", ">= 1.0.1" +gem "rails", "5.0.7.2" +gem "puma", "~> 3.0" +gem "sass-rails", "~> 5.0" +gem "jquery-rails" +gem "turbolinks", "~> 5" +gem "jbuilder", "~> 2.5" +gem "bcrypt", "~> 3.1.7" +gem "listen", "~> 3.0.5" +gem "spring-watcher-listen", "~> 2.0.0" +gem "pg", "~> 0.18" +gem "sqlite3", "~> 1.3.6" diff -Nru ruby-shoulda-matchers-2.8.0/gemfiles/rails_5_0.gemfile.lock ruby-shoulda-matchers-4.3.0/gemfiles/rails_5_0.gemfile.lock --- ruby-shoulda-matchers-2.8.0/gemfiles/rails_5_0.gemfile.lock 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/gemfiles/rails_5_0.gemfile.lock 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,242 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (5.0.7.2) + actionpack (= 5.0.7.2) + nio4r (>= 1.2, < 3.0) + websocket-driver (~> 0.6.1) + actionmailer (5.0.7.2) + actionpack (= 5.0.7.2) + actionview (= 5.0.7.2) + activejob (= 5.0.7.2) + mail (~> 2.5, >= 2.5.4) + rails-dom-testing (~> 2.0) + actionpack (5.0.7.2) + actionview (= 5.0.7.2) + activesupport (= 5.0.7.2) + rack (~> 2.0) + rack-test (~> 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.0.2) + actionview (5.0.7.2) + activesupport (= 5.0.7.2) + builder (~> 3.1) + erubis (~> 2.7.0) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.0.3) + activejob (5.0.7.2) + activesupport (= 5.0.7.2) + globalid (>= 0.3.6) + activemodel (5.0.7.2) + activesupport (= 5.0.7.2) + activerecord (5.0.7.2) + activemodel (= 5.0.7.2) + activesupport (= 5.0.7.2) + arel (~> 7.0) + activesupport (5.0.7.2) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 0.7, < 2) + minitest (~> 5.1) + tzinfo (~> 1.1) + appraisal (2.2.0) + bundler + rake + thor (>= 0.14.0) + arel (7.1.4) + ast (2.4.0) + bcrypt (3.1.13) + builder (3.2.4) + byebug (11.0.1) + coderay (1.1.2) + concurrent-ruby (1.1.5) + crass (1.0.5) + diff-lcs (1.3) + erubis (2.7.0) + ffi (1.11.3) + fssm (0.2.10) + globalid (0.4.2) + activesupport (>= 4.2.0) + i18n (1.7.0) + concurrent-ruby (~> 1.0) + jaro_winkler (1.5.4) + jbuilder (2.9.1) + activesupport (>= 4.2.0) + jquery-rails (4.3.5) + rails-dom-testing (>= 1, < 3) + railties (>= 4.2.0) + thor (>= 0.14, < 2.0) + listen (3.0.8) + rb-fsevent (~> 0.9, >= 0.9.4) + rb-inotify (~> 0.9, >= 0.9.7) + loofah (2.4.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + method_source (0.9.2) + mini_mime (1.0.2) + mini_portile2 (2.4.0) + minitest (5.13.0) + 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.0) + ast (~> 2.4.0) + pg (0.21.0) + pry (0.12.2) + coderay (~> 1.1.0) + method_source (~> 0.9.0) + pry-byebug (3.7.0) + byebug (~> 11.0) + pry (~> 0.10) + puma (3.12.2) + pygments.rb (1.2.1) + multi_json (>= 1.0.0) + rack (2.0.8) + rack-test (0.6.3) + rack (>= 1.0) + rails (5.0.7.2) + actioncable (= 5.0.7.2) + actionmailer (= 5.0.7.2) + actionpack (= 5.0.7.2) + actionview (= 5.0.7.2) + activejob (= 5.0.7.2) + activemodel (= 5.0.7.2) + activerecord (= 5.0.7.2) + activesupport (= 5.0.7.2) + bundler (>= 1.3.0) + railties (= 5.0.7.2) + sprockets-rails (>= 2.0.0) + rails-controller-testing (1.0.4) + actionpack (>= 5.0.1.x) + actionview (>= 5.0.1.x) + activesupport (>= 5.0.1.x) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.3.0) + loofah (~> 2.3) + railties (5.0.7.2) + actionpack (= 5.0.7.2) + activesupport (= 5.0.7.2) + method_source + rake (>= 0.8.7) + thor (>= 0.18.1, < 2.0) + rainbow (3.0.0) + rake (13.0.1) + rb-fsevent (0.10.3) + rb-inotify (0.10.1) + ffi (~> 1.0) + redcarpet (3.5.0) + rspec (3.9.0) + rspec-core (~> 3.9.0) + rspec-expectations (~> 3.9.0) + rspec-mocks (~> 3.9.0) + 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.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.9.0) + rspec-rails (3.9.0) + actionpack (>= 3.0) + activesupport (>= 3.0) + railties (>= 3.0) + rspec-core (~> 3.9.0) + rspec-expectations (~> 3.9.0) + rspec-mocks (~> 3.9.0) + rspec-support (~> 3.9.0) + rspec-support (3.9.0) + rubocop (0.78.0) + jaro_winkler (~> 1.5.1) + parallel (~> 1.10) + 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.1) + rack (>= 1.1) + rubocop (>= 0.72.0) + ruby-progressbar (1.10.1) + sass (3.7.4) + sass-listen (~> 4.0.0) + sass-listen (4.0.0) + rb-fsevent (~> 0.9, >= 0.9.4) + rb-inotify (~> 0.9, >= 0.9.7) + sass-rails (5.0.7) + railties (>= 4.0.0, < 6) + sass (~> 3.1) + sprockets (>= 2.8, < 4.0) + sprockets-rails (>= 2.0, < 4.0) + tilt (>= 1.1, < 3) + shoulda-context (1.2.2) + spring (2.1.0) + spring-commands-rspec (1.0.4) + spring (>= 0.9.1) + spring-watcher-listen (2.0.1) + listen (>= 2.7, < 4.0) + spring (>= 1.2, < 3.0) + sprockets (3.7.2) + concurrent-ruby (~> 1.0) + rack (> 1, < 3) + sprockets-rails (3.2.1) + actionpack (>= 4.0) + activesupport (>= 4.0) + sprockets (>= 3.0.0) + sqlite3 (1.3.13) + thor (1.0.1) + thread_safe (0.3.6) + tilt (2.0.10) + turbolinks (5.2.1) + turbolinks-source (~> 5.2) + turbolinks-source (5.2.0) + tzinfo (1.2.6) + thread_safe (~> 0.1) + unicode-display_width (1.6.0) + websocket-driver (0.6.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.4) + yard (0.9.20) + zeus (0.15.14) + method_source (>= 0.6.7) + +PLATFORMS + ruby + +DEPENDENCIES + appraisal (= 2.2.0) + bcrypt (~> 3.1.7) + bundler (~> 1.1) + fssm + jbuilder (~> 2.5) + jquery-rails + listen (~> 3.0.5) + pg (~> 0.18) + pry + pry-byebug + puma (~> 3.0) + pygments.rb + rails (= 5.0.7.2) + rails-controller-testing (>= 1.0.1) + rake (= 13.0.1) + redcarpet + rspec (~> 3.9) + rspec-rails (~> 3.9) + rubocop + rubocop-rails + sass-rails (~> 5.0) + shoulda-context (~> 1.2.0) + spring + spring-commands-rspec + spring-watcher-listen (~> 2.0.0) + sqlite3 (~> 1.3.6) + turbolinks (~> 5) + yard + zeus + +BUNDLED WITH + 1.17.3 diff -Nru ruby-shoulda-matchers-2.8.0/gemfiles/rails_5_1.gemfile ruby-shoulda-matchers-4.3.0/gemfiles/rails_5_1.gemfile --- ruby-shoulda-matchers-2.8.0/gemfiles/rails_5_1.gemfile 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/gemfiles/rails_5_1.gemfile 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,34 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "appraisal", "2.2.0" +gem "bundler", "~> 1.1" +gem "pry" +gem "pry-byebug" +gem "rake", "13.0.1" +gem "rspec", "~> 3.9" +gem "rubocop", require: false +gem "rubocop-rails", require: false +gem "zeus", require: false +gem "fssm" +gem "pygments.rb" +gem "redcarpet" +gem "yard" +gem "spring" +gem "spring-commands-rspec" +gem "rspec-rails", "~> 3.9" +gem "shoulda-context", "~> 1.2.0" +gem "rails-controller-testing", ">= 1.0.1" +gem "rails", "5.1.7" +gem "puma", "~> 3.7" +gem "sass-rails", "~> 5.0" +gem "turbolinks", "~> 5" +gem "jbuilder", "~> 2.5" +gem "bcrypt", "~> 3.1.7" +gem "capybara", "~> 2.13" +gem "selenium-webdriver" +gem "listen", ">= 3.0.5", "< 3.2" +gem "spring-watcher-listen", "~> 2.0.0" +gem "pg", "~> 0.18" +gem "sqlite3", "~> 1.3.6" diff -Nru ruby-shoulda-matchers-2.8.0/gemfiles/rails_5_1.gemfile.lock ruby-shoulda-matchers-4.3.0/gemfiles/rails_5_1.gemfile.lock --- ruby-shoulda-matchers-2.8.0/gemfiles/rails_5_1.gemfile.lock 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/gemfiles/rails_5_1.gemfile.lock 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,258 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (5.1.7) + actionpack (= 5.1.7) + nio4r (~> 2.0) + websocket-driver (~> 0.6.1) + actionmailer (5.1.7) + actionpack (= 5.1.7) + actionview (= 5.1.7) + activejob (= 5.1.7) + mail (~> 2.5, >= 2.5.4) + rails-dom-testing (~> 2.0) + actionpack (5.1.7) + actionview (= 5.1.7) + activesupport (= 5.1.7) + rack (~> 2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.0.2) + actionview (5.1.7) + activesupport (= 5.1.7) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.0.3) + activejob (5.1.7) + activesupport (= 5.1.7) + globalid (>= 0.3.6) + activemodel (5.1.7) + activesupport (= 5.1.7) + activerecord (5.1.7) + activemodel (= 5.1.7) + activesupport (= 5.1.7) + arel (~> 8.0) + activesupport (5.1.7) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 0.7, < 2) + minitest (~> 5.1) + tzinfo (~> 1.1) + addressable (2.7.0) + public_suffix (>= 2.0.2, < 5.0) + appraisal (2.2.0) + bundler + rake + thor (>= 0.14.0) + arel (8.0.0) + ast (2.4.0) + bcrypt (3.1.13) + builder (3.2.4) + byebug (11.0.1) + capybara (2.18.0) + addressable + mini_mime (>= 0.1.3) + nokogiri (>= 1.3.3) + rack (>= 1.0.0) + rack-test (>= 0.5.4) + xpath (>= 2.0, < 4.0) + childprocess (3.0.0) + coderay (1.1.2) + concurrent-ruby (1.1.5) + crass (1.0.5) + diff-lcs (1.3) + erubi (1.9.0) + ffi (1.11.3) + fssm (0.2.10) + globalid (0.4.2) + activesupport (>= 4.2.0) + i18n (1.7.0) + concurrent-ruby (~> 1.0) + jaro_winkler (1.5.4) + jbuilder (2.9.1) + activesupport (>= 4.2.0) + listen (3.1.5) + rb-fsevent (~> 0.9, >= 0.9.4) + rb-inotify (~> 0.9, >= 0.9.7) + ruby_dep (~> 1.2) + loofah (2.4.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + method_source (0.9.2) + mini_mime (1.0.2) + mini_portile2 (2.4.0) + minitest (5.13.0) + 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.0) + ast (~> 2.4.0) + pg (0.21.0) + pry (0.12.2) + coderay (~> 1.1.0) + method_source (~> 0.9.0) + pry-byebug (3.7.0) + byebug (~> 11.0) + pry (~> 0.10) + public_suffix (4.0.1) + puma (3.12.2) + pygments.rb (1.2.1) + multi_json (>= 1.0.0) + rack (2.0.8) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (5.1.7) + actioncable (= 5.1.7) + actionmailer (= 5.1.7) + actionpack (= 5.1.7) + actionview (= 5.1.7) + activejob (= 5.1.7) + activemodel (= 5.1.7) + activerecord (= 5.1.7) + activesupport (= 5.1.7) + bundler (>= 1.3.0) + railties (= 5.1.7) + sprockets-rails (>= 2.0.0) + rails-controller-testing (1.0.4) + actionpack (>= 5.0.1.x) + actionview (>= 5.0.1.x) + activesupport (>= 5.0.1.x) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.3.0) + loofah (~> 2.3) + railties (5.1.7) + actionpack (= 5.1.7) + activesupport (= 5.1.7) + method_source + rake (>= 0.8.7) + thor (>= 0.18.1, < 2.0) + rainbow (3.0.0) + rake (13.0.1) + rb-fsevent (0.10.3) + rb-inotify (0.10.1) + ffi (~> 1.0) + redcarpet (3.5.0) + rspec (3.9.0) + rspec-core (~> 3.9.0) + rspec-expectations (~> 3.9.0) + rspec-mocks (~> 3.9.0) + 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.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.9.0) + rspec-rails (3.9.0) + actionpack (>= 3.0) + activesupport (>= 3.0) + railties (>= 3.0) + rspec-core (~> 3.9.0) + rspec-expectations (~> 3.9.0) + rspec-mocks (~> 3.9.0) + rspec-support (~> 3.9.0) + rspec-support (3.9.0) + rubocop (0.78.0) + jaro_winkler (~> 1.5.1) + parallel (~> 1.10) + 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.1) + rack (>= 1.1) + rubocop (>= 0.72.0) + ruby-progressbar (1.10.1) + ruby_dep (1.5.0) + rubyzip (2.0.0) + sass (3.7.4) + sass-listen (~> 4.0.0) + sass-listen (4.0.0) + rb-fsevent (~> 0.9, >= 0.9.4) + rb-inotify (~> 0.9, >= 0.9.7) + sass-rails (5.0.7) + railties (>= 4.0.0, < 6) + sass (~> 3.1) + sprockets (>= 2.8, < 4.0) + sprockets-rails (>= 2.0, < 4.0) + tilt (>= 1.1, < 3) + selenium-webdriver (3.142.6) + childprocess (>= 0.5, < 4.0) + rubyzip (>= 1.2.2) + shoulda-context (1.2.2) + spring (2.1.0) + spring-commands-rspec (1.0.4) + spring (>= 0.9.1) + spring-watcher-listen (2.0.1) + listen (>= 2.7, < 4.0) + spring (>= 1.2, < 3.0) + sprockets (3.7.2) + concurrent-ruby (~> 1.0) + rack (> 1, < 3) + sprockets-rails (3.2.1) + actionpack (>= 4.0) + activesupport (>= 4.0) + sprockets (>= 3.0.0) + sqlite3 (1.3.13) + thor (1.0.1) + thread_safe (0.3.6) + tilt (2.0.10) + turbolinks (5.2.1) + turbolinks-source (~> 5.2) + turbolinks-source (5.2.0) + tzinfo (1.2.6) + thread_safe (~> 0.1) + unicode-display_width (1.6.0) + websocket-driver (0.6.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.4) + xpath (3.2.0) + nokogiri (~> 1.8) + yard (0.9.20) + zeus (0.15.14) + method_source (>= 0.6.7) + +PLATFORMS + ruby + +DEPENDENCIES + appraisal (= 2.2.0) + bcrypt (~> 3.1.7) + bundler (~> 1.1) + capybara (~> 2.13) + fssm + jbuilder (~> 2.5) + listen (>= 3.0.5, < 3.2) + pg (~> 0.18) + pry + pry-byebug + puma (~> 3.7) + pygments.rb + rails (= 5.1.7) + rails-controller-testing (>= 1.0.1) + rake (= 13.0.1) + redcarpet + rspec (~> 3.9) + rspec-rails (~> 3.9) + rubocop + rubocop-rails + sass-rails (~> 5.0) + selenium-webdriver + shoulda-context (~> 1.2.0) + spring + spring-commands-rspec + spring-watcher-listen (~> 2.0.0) + sqlite3 (~> 1.3.6) + turbolinks (~> 5) + yard + zeus + +BUNDLED WITH + 1.17.3 diff -Nru ruby-shoulda-matchers-2.8.0/gemfiles/rails_5_2.gemfile ruby-shoulda-matchers-4.3.0/gemfiles/rails_5_2.gemfile --- ruby-shoulda-matchers-2.8.0/gemfiles/rails_5_2.gemfile 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/gemfiles/rails_5_2.gemfile 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,36 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "appraisal", "2.2.0" +gem "bundler", "~> 1.1" +gem "pry" +gem "pry-byebug" +gem "rake", "13.0.1" +gem "rspec", "~> 3.9" +gem "rubocop", require: false +gem "rubocop-rails", require: false +gem "zeus", require: false +gem "fssm" +gem "pygments.rb" +gem "redcarpet" +gem "yard" +gem "spring" +gem "spring-commands-rspec" +gem "rspec-rails", "~> 3.9" +gem "shoulda-context", "~> 1.2.0" +gem "rails-controller-testing", ">= 1.0.1" +gem "rails", "5.2.4.1" +gem "puma", "~> 3.11" +gem "bootsnap", ">= 1.1.0", require: false +gem "sass-rails", "~> 5.0" +gem "turbolinks", "~> 5" +gem "jbuilder", "~> 2.5" +gem "bcrypt", "~> 3.1.7" +gem "capybara", "~> 3.1.1" +gem "selenium-webdriver" +gem "chromedriver-helper" +gem "listen", ">= 3.0.5", "< 3.2" +gem "spring-watcher-listen", "~> 2.0.0" +gem "pg", "~> 0.18" +gem "sqlite3", "~> 1.3.6" diff -Nru ruby-shoulda-matchers-2.8.0/gemfiles/rails_5_2.gemfile.lock ruby-shoulda-matchers-4.3.0/gemfiles/rails_5_2.gemfile.lock --- ruby-shoulda-matchers-2.8.0/gemfiles/rails_5_2.gemfile.lock 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/gemfiles/rails_5_2.gemfile.lock 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,277 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (5.2.4.1) + actionpack (= 5.2.4.1) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailer (5.2.4.1) + actionpack (= 5.2.4.1) + actionview (= 5.2.4.1) + activejob (= 5.2.4.1) + mail (~> 2.5, >= 2.5.4) + rails-dom-testing (~> 2.0) + actionpack (5.2.4.1) + actionview (= 5.2.4.1) + activesupport (= 5.2.4.1) + rack (~> 2.0, >= 2.0.8) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.0.2) + actionview (5.2.4.1) + activesupport (= 5.2.4.1) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.0.3) + activejob (5.2.4.1) + activesupport (= 5.2.4.1) + globalid (>= 0.3.6) + activemodel (5.2.4.1) + activesupport (= 5.2.4.1) + activerecord (5.2.4.1) + activemodel (= 5.2.4.1) + activesupport (= 5.2.4.1) + arel (>= 9.0) + activestorage (5.2.4.1) + actionpack (= 5.2.4.1) + activerecord (= 5.2.4.1) + marcel (~> 0.3.1) + activesupport (5.2.4.1) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 0.7, < 2) + minitest (~> 5.1) + tzinfo (~> 1.1) + addressable (2.7.0) + public_suffix (>= 2.0.2, < 5.0) + appraisal (2.2.0) + bundler + rake + thor (>= 0.14.0) + archive-zip (0.12.0) + io-like (~> 0.3.0) + arel (9.0.0) + ast (2.4.0) + bcrypt (3.1.13) + bootsnap (1.4.5) + msgpack (~> 1.0) + builder (3.2.4) + byebug (11.0.1) + capybara (3.1.1) + addressable + mini_mime (>= 0.1.3) + nokogiri (~> 1.8) + rack (>= 1.6.0) + rack-test (>= 0.6.3) + xpath (~> 3.0) + childprocess (3.0.0) + chromedriver-helper (2.1.1) + archive-zip (~> 0.10) + nokogiri (~> 1.8) + coderay (1.1.2) + concurrent-ruby (1.1.5) + crass (1.0.5) + diff-lcs (1.3) + erubi (1.9.0) + ffi (1.11.3) + fssm (0.2.10) + globalid (0.4.2) + activesupport (>= 4.2.0) + i18n (1.7.0) + concurrent-ruby (~> 1.0) + io-like (0.3.0) + jaro_winkler (1.5.4) + jbuilder (2.9.1) + activesupport (>= 4.2.0) + listen (3.1.5) + rb-fsevent (~> 0.9, >= 0.9.4) + rb-inotify (~> 0.9, >= 0.9.7) + ruby_dep (~> 1.2) + loofah (2.4.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (0.3.3) + mimemagic (~> 0.3.2) + method_source (0.9.2) + mimemagic (0.3.3) + mini_mime (1.0.2) + mini_portile2 (2.4.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.0) + ast (~> 2.4.0) + pg (0.21.0) + pry (0.12.2) + coderay (~> 1.1.0) + method_source (~> 0.9.0) + pry-byebug (3.7.0) + byebug (~> 11.0) + pry (~> 0.10) + public_suffix (4.0.1) + puma (3.12.2) + pygments.rb (1.2.1) + multi_json (>= 1.0.0) + rack (2.0.8) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (5.2.4.1) + actioncable (= 5.2.4.1) + actionmailer (= 5.2.4.1) + actionpack (= 5.2.4.1) + actionview (= 5.2.4.1) + activejob (= 5.2.4.1) + activemodel (= 5.2.4.1) + activerecord (= 5.2.4.1) + activestorage (= 5.2.4.1) + activesupport (= 5.2.4.1) + bundler (>= 1.3.0) + railties (= 5.2.4.1) + sprockets-rails (>= 2.0.0) + rails-controller-testing (1.0.4) + actionpack (>= 5.0.1.x) + actionview (>= 5.0.1.x) + activesupport (>= 5.0.1.x) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.3.0) + loofah (~> 2.3) + railties (5.2.4.1) + actionpack (= 5.2.4.1) + activesupport (= 5.2.4.1) + method_source + rake (>= 0.8.7) + thor (>= 0.19.0, < 2.0) + rainbow (3.0.0) + rake (13.0.1) + rb-fsevent (0.10.3) + rb-inotify (0.10.1) + ffi (~> 1.0) + redcarpet (3.5.0) + rspec (3.9.0) + rspec-core (~> 3.9.0) + rspec-expectations (~> 3.9.0) + rspec-mocks (~> 3.9.0) + 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.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.9.0) + rspec-rails (3.9.0) + actionpack (>= 3.0) + activesupport (>= 3.0) + railties (>= 3.0) + rspec-core (~> 3.9.0) + rspec-expectations (~> 3.9.0) + rspec-mocks (~> 3.9.0) + rspec-support (~> 3.9.0) + rspec-support (3.9.0) + rubocop (0.78.0) + jaro_winkler (~> 1.5.1) + parallel (~> 1.10) + 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.1) + rack (>= 1.1) + rubocop (>= 0.72.0) + ruby-progressbar (1.10.1) + ruby_dep (1.5.0) + rubyzip (2.0.0) + sass (3.7.4) + sass-listen (~> 4.0.0) + sass-listen (4.0.0) + rb-fsevent (~> 0.9, >= 0.9.4) + rb-inotify (~> 0.9, >= 0.9.7) + sass-rails (5.1.0) + railties (>= 5.2.0) + sass (~> 3.1) + sprockets (>= 2.8, < 4.0) + sprockets-rails (>= 2.0, < 4.0) + tilt (>= 1.1, < 3) + selenium-webdriver (3.142.6) + childprocess (>= 0.5, < 4.0) + rubyzip (>= 1.2.2) + shoulda-context (1.2.2) + spring (2.1.0) + spring-commands-rspec (1.0.4) + spring (>= 0.9.1) + spring-watcher-listen (2.0.1) + listen (>= 2.7, < 4.0) + spring (>= 1.2, < 3.0) + sprockets (3.7.2) + concurrent-ruby (~> 1.0) + rack (> 1, < 3) + sprockets-rails (3.2.1) + actionpack (>= 4.0) + activesupport (>= 4.0) + sprockets (>= 3.0.0) + sqlite3 (1.3.13) + thor (1.0.1) + thread_safe (0.3.6) + tilt (2.0.10) + turbolinks (5.2.1) + turbolinks-source (~> 5.2) + turbolinks-source (5.2.0) + tzinfo (1.2.6) + thread_safe (~> 0.1) + unicode-display_width (1.6.0) + websocket-driver (0.7.1) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.4) + xpath (3.2.0) + nokogiri (~> 1.8) + yard (0.9.20) + zeus (0.15.14) + method_source (>= 0.6.7) + +PLATFORMS + ruby + +DEPENDENCIES + appraisal (= 2.2.0) + bcrypt (~> 3.1.7) + bootsnap (>= 1.1.0) + bundler (~> 1.1) + capybara (~> 3.1.1) + chromedriver-helper + fssm + jbuilder (~> 2.5) + listen (>= 3.0.5, < 3.2) + pg (~> 0.18) + pry + pry-byebug + puma (~> 3.11) + pygments.rb + rails (= 5.2.4.1) + rails-controller-testing (>= 1.0.1) + rake (= 13.0.1) + redcarpet + rspec (~> 3.9) + rspec-rails (~> 3.9) + rubocop + rubocop-rails + sass-rails (~> 5.0) + selenium-webdriver + shoulda-context (~> 1.2.0) + spring + spring-commands-rspec + spring-watcher-listen (~> 2.0.0) + sqlite3 (~> 1.3.6) + turbolinks (~> 5) + yard + zeus + +BUNDLED WITH + 1.17.3 diff -Nru ruby-shoulda-matchers-2.8.0/gemfiles/rails_6_0.gemfile ruby-shoulda-matchers-4.3.0/gemfiles/rails_6_0.gemfile --- ruby-shoulda-matchers-2.8.0/gemfiles/rails_6_0.gemfile 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/gemfiles/rails_6_0.gemfile 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,38 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "appraisal", "2.2.0" +gem "bundler", "~> 1.1" +gem "pry" +gem "pry-byebug" +gem "rake", "13.0.1" +gem "rspec", "~> 3.9" +gem "rubocop", require: false +gem "rubocop-rails", require: false +gem "zeus", require: false +gem "fssm" +gem "pygments.rb" +gem "redcarpet" +gem "yard" +gem "spring" +gem "spring-commands-rspec" +gem "rspec-rails", "~> 3.9" +gem "shoulda-context", "~> 1.2.0" +gem "rails-controller-testing", ">= 1.0.1" +gem "rails", "6.0.2.1" +gem "puma", "~> 4.1" +gem "bootsnap", ">= 1.4.2", require: false +gem "sass-rails", ">= 6" +gem "webpacker", "~> 4.0" +gem "turbolinks", "~> 5" +gem "jbuilder", "~> 2.7" +gem "bcrypt", "~> 3.1.7" +gem "capybara", ">= 2.15" +gem "listen", ">= 3.0.5", "< 3.2" +gem "spring-watcher-listen", "~> 2.0.0" +gem "selenium-webdriver" +gem "webdrivers" +gem "actiontext", "~> 6.0.2.1" +gem "pg", ">= 0.18", "< 2.0" +gem "sqlite3", "~> 1.4" diff -Nru ruby-shoulda-matchers-2.8.0/gemfiles/rails_6_0.gemfile.lock ruby-shoulda-matchers-4.3.0/gemfiles/rails_6_0.gemfile.lock --- ruby-shoulda-matchers-2.8.0/gemfiles/rails_6_0.gemfile.lock 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/gemfiles/rails_6_0.gemfile.lock 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,301 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (6.0.2.1) + actionpack (= 6.0.2.1) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (6.0.2.1) + actionpack (= 6.0.2.1) + activejob (= 6.0.2.1) + activerecord (= 6.0.2.1) + activestorage (= 6.0.2.1) + activesupport (= 6.0.2.1) + mail (>= 2.7.1) + actionmailer (6.0.2.1) + actionpack (= 6.0.2.1) + actionview (= 6.0.2.1) + activejob (= 6.0.2.1) + mail (~> 2.5, >= 2.5.4) + rails-dom-testing (~> 2.0) + actionpack (6.0.2.1) + actionview (= 6.0.2.1) + activesupport (= 6.0.2.1) + rack (~> 2.0, >= 2.0.8) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (6.0.2.1) + actionpack (= 6.0.2.1) + activerecord (= 6.0.2.1) + activestorage (= 6.0.2.1) + activesupport (= 6.0.2.1) + nokogiri (>= 1.8.5) + actionview (6.0.2.1) + activesupport (= 6.0.2.1) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (6.0.2.1) + activesupport (= 6.0.2.1) + globalid (>= 0.3.6) + activemodel (6.0.2.1) + activesupport (= 6.0.2.1) + activerecord (6.0.2.1) + activemodel (= 6.0.2.1) + activesupport (= 6.0.2.1) + activestorage (6.0.2.1) + actionpack (= 6.0.2.1) + activejob (= 6.0.2.1) + activerecord (= 6.0.2.1) + marcel (~> 0.3.1) + activesupport (6.0.2.1) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 0.7, < 2) + minitest (~> 5.1) + tzinfo (~> 1.1) + zeitwerk (~> 2.2) + addressable (2.7.0) + public_suffix (>= 2.0.2, < 5.0) + appraisal (2.2.0) + bundler + rake + thor (>= 0.14.0) + ast (2.4.0) + bcrypt (3.1.13) + bootsnap (1.4.5) + msgpack (~> 1.0) + builder (3.2.4) + byebug (11.0.1) + capybara (3.30.0) + addressable + mini_mime (>= 0.1.3) + nokogiri (~> 1.8) + rack (>= 1.6.0) + rack-test (>= 0.6.3) + regexp_parser (~> 1.5) + xpath (~> 3.2) + childprocess (3.0.0) + coderay (1.1.2) + concurrent-ruby (1.1.5) + crass (1.0.5) + diff-lcs (1.3) + erubi (1.9.0) + ffi (1.11.3) + fssm (0.2.10) + globalid (0.4.2) + activesupport (>= 4.2.0) + i18n (1.7.0) + concurrent-ruby (~> 1.0) + jaro_winkler (1.5.4) + jbuilder (2.9.1) + activesupport (>= 4.2.0) + listen (3.1.5) + rb-fsevent (~> 0.9, >= 0.9.4) + rb-inotify (~> 0.9, >= 0.9.7) + ruby_dep (~> 1.2) + loofah (2.4.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (0.3.3) + mimemagic (~> 0.3.2) + method_source (0.9.2) + mimemagic (0.3.3) + mini_mime (1.0.2) + mini_portile2 (2.4.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.0) + ast (~> 2.4.0) + pg (1.2.0) + pry (0.12.2) + coderay (~> 1.1.0) + method_source (~> 0.9.0) + pry-byebug (3.7.0) + byebug (~> 11.0) + pry (~> 0.10) + public_suffix (4.0.1) + puma (4.3.1) + nio4r (~> 2.0) + pygments.rb (1.2.1) + multi_json (>= 1.0.0) + rack (2.0.8) + rack-proxy (0.6.5) + rack + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (6.0.2.1) + actioncable (= 6.0.2.1) + actionmailbox (= 6.0.2.1) + actionmailer (= 6.0.2.1) + actionpack (= 6.0.2.1) + actiontext (= 6.0.2.1) + actionview (= 6.0.2.1) + activejob (= 6.0.2.1) + activemodel (= 6.0.2.1) + activerecord (= 6.0.2.1) + activestorage (= 6.0.2.1) + activesupport (= 6.0.2.1) + bundler (>= 1.3.0) + railties (= 6.0.2.1) + sprockets-rails (>= 2.0.0) + rails-controller-testing (1.0.4) + actionpack (>= 5.0.1.x) + actionview (>= 5.0.1.x) + activesupport (>= 5.0.1.x) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.3.0) + loofah (~> 2.3) + railties (6.0.2.1) + actionpack (= 6.0.2.1) + activesupport (= 6.0.2.1) + method_source + rake (>= 0.8.7) + thor (>= 0.20.3, < 2.0) + rainbow (3.0.0) + rake (13.0.1) + rb-fsevent (0.10.3) + rb-inotify (0.10.1) + ffi (~> 1.0) + redcarpet (3.5.0) + regexp_parser (1.6.0) + rspec (3.9.0) + rspec-core (~> 3.9.0) + rspec-expectations (~> 3.9.0) + rspec-mocks (~> 3.9.0) + 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.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.9.0) + rspec-rails (3.9.0) + actionpack (>= 3.0) + activesupport (>= 3.0) + railties (>= 3.0) + rspec-core (~> 3.9.0) + rspec-expectations (~> 3.9.0) + rspec-mocks (~> 3.9.0) + rspec-support (~> 3.9.0) + rspec-support (3.9.0) + rubocop (0.78.0) + jaro_winkler (~> 1.5.1) + parallel (~> 1.10) + 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.1) + rack (>= 1.1) + rubocop (>= 0.72.0) + ruby-progressbar (1.10.1) + ruby_dep (1.5.0) + rubyzip (2.0.0) + sass-rails (6.0.0) + sassc-rails (~> 2.1, >= 2.1.1) + sassc (2.2.1) + ffi (~> 1.9) + sassc-rails (2.1.2) + railties (>= 4.0.0) + sassc (>= 2.0) + sprockets (> 3.0) + sprockets-rails + tilt + selenium-webdriver (3.142.6) + childprocess (>= 0.5, < 4.0) + rubyzip (>= 1.2.2) + shoulda-context (1.2.2) + spring (2.1.0) + spring-commands-rspec (1.0.4) + spring (>= 0.9.1) + spring-watcher-listen (2.0.1) + listen (>= 2.7, < 4.0) + spring (>= 1.2, < 3.0) + sprockets (4.0.0) + concurrent-ruby (~> 1.0) + rack (> 1, < 3) + sprockets-rails (3.2.1) + actionpack (>= 4.0) + activesupport (>= 4.0) + sprockets (>= 3.0.0) + sqlite3 (1.4.2) + thor (1.0.1) + thread_safe (0.3.6) + tilt (2.0.10) + turbolinks (5.2.1) + turbolinks-source (~> 5.2) + turbolinks-source (5.2.0) + tzinfo (1.2.6) + thread_safe (~> 0.1) + unicode-display_width (1.6.0) + webdrivers (4.1.3) + nokogiri (~> 1.6) + rubyzip (>= 1.3.0) + selenium-webdriver (>= 3.0, < 4.0) + webpacker (4.2.2) + activesupport (>= 4.2) + rack-proxy (>= 0.6.1) + railties (>= 4.2) + websocket-driver (0.7.1) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.4) + xpath (3.2.0) + nokogiri (~> 1.8) + yard (0.9.20) + zeitwerk (2.2.2) + zeus (0.15.14) + method_source (>= 0.6.7) + +PLATFORMS + ruby + +DEPENDENCIES + actiontext (~> 6.0.2.1) + appraisal (= 2.2.0) + bcrypt (~> 3.1.7) + bootsnap (>= 1.4.2) + bundler (~> 1.1) + capybara (>= 2.15) + fssm + jbuilder (~> 2.7) + listen (>= 3.0.5, < 3.2) + pg (>= 0.18, < 2.0) + pry + pry-byebug + puma (~> 4.1) + pygments.rb + rails (= 6.0.2.1) + rails-controller-testing (>= 1.0.1) + rake (= 13.0.1) + redcarpet + rspec (~> 3.9) + rspec-rails (~> 3.9) + rubocop + rubocop-rails + sass-rails (>= 6) + selenium-webdriver + shoulda-context (~> 1.2.0) + spring + spring-commands-rspec + spring-watcher-listen (~> 2.0.0) + sqlite3 (~> 1.4) + turbolinks (~> 5) + webdrivers + webpacker (~> 4.0) + yard + zeus + +BUNDLED WITH + 1.17.3 diff -Nru ruby-shoulda-matchers-2.8.0/.gitignore ruby-shoulda-matchers-4.3.0/.gitignore --- ruby-shoulda-matchers-2.8.0/.gitignore 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/.gitignore 2020-02-18 07:23:52.000000000 +0000 @@ -8,4 +8,5 @@ doc pkg source +spec/examples.txt tmp diff -Nru ruby-shoulda-matchers-2.8.0/.hound_config/ruby.yml ruby-shoulda-matchers-4.3.0/.hound_config/ruby.yml --- ruby-shoulda-matchers-2.8.0/.hound_config/ruby.yml 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/.hound_config/ruby.yml 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -StringLiterals: - EnforcedStyle: single_quotes - -AlignParameters: - EnforcedStyle: with_fixed_indentation diff -Nru ruby-shoulda-matchers-2.8.0/.hound.yml ruby-shoulda-matchers-4.3.0/.hound.yml --- ruby-shoulda-matchers-2.8.0/.hound.yml 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/.hound.yml 2020-02-18 07:23:52.000000000 +0000 @@ -1,3 +1,3 @@ ruby: enabled: true - config_file: .hound_config/ruby.yml + config_file: .rubocop.yml diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/callback_matcher.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/action_controller/callback_matcher.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/callback_matcher.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/action_controller/callback_matcher.rb 2020-02-18 07:23:52.000000000 +0000 @@ -9,21 +9,25 @@ # end # # # RSpec - # describe UsersController do + # RSpec.describe UsersController, type: :controller do # it { should use_before_filter(:authenticate_user!) } # it { should_not use_before_filter(:prevent_ssl) } # end # - # # Test::Unit + # # Minitest (Shoulda) # class UsersControllerTest < ActionController::TestCase # should use_before_filter(:authenticate_user!) # should_not use_before_filter(:prevent_ssl) # end # + # @note This method is only available when using shoulda-matchers under + # Rails 4.x. # @return [CallbackMatcher] # - def use_before_filter(callback) - CallbackMatcher.new(callback, :before, :filter) + if RailsShim.action_pack_lt_5? + def use_before_filter(callback) + CallbackMatcher.new(callback, :before, :filter) + end end # The `use_after_filter` matcher is used to test that an after_filter @@ -34,21 +38,25 @@ # end # # # RSpec - # describe IssuesController do + # RSpec.describe IssuesController, type: :controller do # it { should use_after_filter(:log_activity) } # it { should_not use_after_filter(:destroy_user) } # end # - # # Test::Unit + # # Minitest (Shoulda) # class IssuesControllerTest < ActionController::TestCase # should use_after_filter(:log_activity) # should_not use_after_filter(:destroy_user) # end # + # @note This method is only available when using shoulda-matchers under + # Rails 4.x. # @return [CallbackMatcher] # - def use_after_filter(callback) - CallbackMatcher.new(callback, :after, :filter) + if RailsShim.action_pack_lt_5? + def use_after_filter(callback) + CallbackMatcher.new(callback, :after, :filter) + end end # The `use_before_action` matcher is used to test that a before_action @@ -59,12 +67,12 @@ # end # # # RSpec - # describe UsersController do + # RSpec.describe UsersController, type: :controller do # it { should use_before_action(:authenticate_user!) } # it { should_not use_before_action(:prevent_ssl) } # end # - # # Test::Unit + # # Minitest (Shoulda) # class UsersControllerTest < ActionController::TestCase # should use_before_action(:authenticate_user!) # should_not use_before_action(:prevent_ssl) @@ -84,12 +92,12 @@ # end # # # RSpec - # describe IssuesController do + # RSpec.describe IssuesController, type: :controller do # it { should use_after_action(:log_activity) } # it { should_not use_after_action(:destroy_user) } # end # - # # Test::Unit + # # Minitest (Shoulda) # class IssuesControllerTest < ActionController::TestCase # should use_after_action(:log_activity) # should_not use_after_action(:destroy_user) @@ -109,21 +117,25 @@ # end # # # RSpec - # describe ChangesController do + # RSpec.describe ChangesController, type: :controller do # it { should use_around_filter(:wrap_in_transaction) } # it { should_not use_around_filter(:save_view_context) } # end # - # # Test::Unit + # # Minitest (Shoulda) # class ChangesControllerTest < ActionController::TestCase # should use_around_filter(:wrap_in_transaction) # should_not use_around_filter(:save_view_context) # end # + # @note This method is only available when using shoulda-matchers under + # Rails 4.x. # @return [CallbackMatcher] # - def use_around_filter(callback) - CallbackMatcher.new(callback, :around, :filter) + if RailsShim.action_pack_lt_5? + def use_around_filter(callback) + CallbackMatcher.new(callback, :around, :filter) + end end # The `use_around_action` matcher is used to test that an around_action @@ -134,12 +146,12 @@ # end # # # RSpec - # describe ChangesController do + # RSpec.describe ChangesController, type: :controller do # it { should use_around_action(:wrap_in_transaction) } # it { should_not use_around_action(:save_view_context) } # end # - # # Test::Unit + # # Minitest (Shoulda) # class ChangesControllerTest < ActionController::TestCase # should use_around_action(:wrap_in_transaction) # should_not use_around_action(:save_view_context) @@ -169,12 +181,10 @@ def failure_message "Expected that #{controller_class.name} would have :#{method_name} as a #{kind}_#{callback_type}" end - alias failure_message_for_should failure_message def failure_message_when_negated "Expected that #{controller_class.name} would not have :#{method_name} as a #{kind}_#{callback_type}" end - alias failure_message_for_should_not failure_message_when_negated def description "have :#{method_name} as a #{kind}_#{callback_type}" diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/filter_param_matcher.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/action_controller/filter_param_matcher.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/filter_param_matcher.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/action_controller/filter_param_matcher.rb 2020-02-18 07:23:52.000000000 +0000 @@ -10,11 +10,11 @@ # end # # # RSpec - # describe ApplicationController do + # RSpec.describe ApplicationController, type: :controller do # it { should filter_param(:secret_key) } # end # - # # Test::Unit + # # Minitest (Shoulda) # class ApplicationControllerTest < ActionController::TestCase # should filter_param(:secret_key) # end @@ -38,12 +38,10 @@ def failure_message "Expected #{@key} to be filtered; filtered keys: #{filtered_keys.join(', ')}" end - alias failure_message_for_should failure_message def failure_message_when_negated "Did not expect #{@key} to be filtered" end - alias failure_message_for_should_not failure_message_when_negated def description "filter #{@key}" diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/flash_store.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/action_controller/flash_store.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/flash_store.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/action_controller/flash_store.rb 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,88 @@ +module Shoulda + module Matchers + module ActionController + # @private + class FlashStore + def self.future + new + end + + def self.now + new.use_now! + end + + attr_accessor :controller + + def initialize + @use_now = false + end + + def name + if @use_now + 'flash.now' + else + 'flash' + end + end + + def has_key?(key) + values_to_check.include?(key.to_s) + end + + def has_value?(expected_value) + values_to_check.values.any? do |actual_value| + expected_value === actual_value + end + end + + def empty? + flash.empty? + end + + def use_now! + @use_now = true + self + end + + private + + def flash + @_flash ||= copy_of_flash_from_controller + end + + def copy_of_flash_from_controller + controller.flash.dup.tap do |flash| + copy_flashes(controller.flash, flash) + copy_discard_if_necessary(controller.flash, flash) + end + end + + def copy_flashes(original_flash, new_flash) + flashes = original_flash.instance_variable_get('@flashes').dup + new_flash.instance_variable_set('@flashes', flashes) + end + + def copy_discard_if_necessary(original_flash, new_flash) + discard = original_flash.instance_variable_get('@discard').dup + new_flash.instance_variable_set('@discard', discard) + end + + def set_values + flash.instance_variable_get('@flashes') + end + + def keys_to_discard + flash.instance_variable_get('@discard') + end + + def values_to_check + if @use_now + set_values.slice(*keys_to_discard.to_a) + else + set_values.except(*keys_to_discard.to_a) + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/permit_matcher.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/action_controller/permit_matcher.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/permit_matcher.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/action_controller/permit_matcher.rb 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,445 @@ +require 'delegate' + +begin + require 'strong_parameters' +rescue LoadError +end + +require 'active_support/hash_with_indifferent_access' + +module Shoulda + module Matchers + module ActionController + # The `permit` matcher tests that an action in your controller receives a + # whitelist of parameters using Rails' Strong Parameters feature + # (specifically that `permit` was called with the correct arguments). + # + # Here's an example: + # + # class UsersController < ApplicationController + # def create + # user = User.create(user_params) + # # ... + # end + # + # private + # + # def user_params + # params.require(:user).permit( + # :first_name, + # :last_name, + # :email, + # :password + # ) + # end + # end + # + # # RSpec + # RSpec.describe UsersController, type: :controller do + # it do + # params = { + # user: { + # first_name: 'John', + # last_name: 'Doe', + # email: 'johndoe@example.com', + # password: 'password' + # } + # } + # should permit(:first_name, :last_name, :email, :password). + # for(:create, params: params). + # on(:user) + # end + # end + # + # # Minitest (Shoulda) + # class UsersControllerTest < ActionController::TestCase + # should "(for POST #create) restrict parameters on :user to first_name, last_name, email, and password" do + # params = { + # user: { + # first_name: 'John', + # last_name: 'Doe', + # email: 'johndoe@example.com', + # password: 'password' + # } + # } + # matcher = permit(:first_name, :last_name, :email, :password). + # for(:create, params: params). + # on(:user) + # assert_accepts matcher, subject + # end + # end + # + # If your action requires query parameters in order to work, then you'll + # need to supply them: + # + # class UsersController < ApplicationController + # def update + # user = User.find(params[:id]) + # + # if user.update_attributes(user_params) + # # ... + # else + # # ... + # end + # end + # + # private + # + # def user_params + # params.require(:user).permit( + # :first_name, + # :last_name, + # :email, + # :password + # ) + # end + # end + # + # # RSpec + # RSpec.describe UsersController, type: :controller do + # before do + # create(:user, id: 1) + # end + # + # it do + # params = { + # id: 1, + # user: { + # first_name: 'Jon', + # last_name: 'Doe', + # email: 'jondoe@example.com', + # password: 'password' + # } + # } + # should permit(:first_name, :last_name, :email, :password). + # for(:update, params: params). + # on(:user) + # end + # end + # + # # Minitest (Shoulda) + # class UsersControllerTest < ActionController::TestCase + # setup do + # create(:user, id: 1) + # end + # + # should "(for PATCH #update) restrict parameters on :user to :first_name, :last_name, :email, and :password" do + # params = { + # id: 1, + # user: { + # first_name: 'Jon', + # last_name: 'Doe', + # email: 'jondoe@example.com', + # password: 'password' + # } + # } + # matcher = permit(:first_name, :last_name, :email, :password). + # for(:update, params: params). + # on(:user) + # assert_accepts matcher, subject + # end + # end + # + # Finally, if you have an action that isn't one of the seven resourceful + # actions, then you'll need to provide the HTTP verb that it responds to: + # + # Rails.application.routes.draw do + # resources :users do + # member do + # put :toggle + # end + # end + # end + # + # class UsersController < ApplicationController + # def toggle + # user = User.find(params[:id]) + # + # if user.update_attributes(user_params) + # # ... + # else + # # ... + # end + # end + # + # private + # + # def user_params + # params.require(:user).permit(:activated) + # end + # end + # + # # RSpec + # RSpec.describe UsersController, type: :controller do + # before do + # create(:user, id: 1) + # end + # + # it do + # params = { id: 1, user: { activated: true } } + # should permit(:activated). + # for(:toggle, params: params, verb: :put). + # on(:user) + # end + # end + # + # # Minitest (Shoulda) + # class UsersControllerTest < ActionController::TestCase + # setup do + # create(:user, id: 1) + # end + # + # should "(for PUT #toggle) restrict parameters on :user to :activated" do + # params = { id: 1, user: { activated: true } } + # matcher = permit(:activated). + # for(:toggle, params: params, verb: :put). + # on(:user) + # assert_accepts matcher, subject + # end + # end + # + # @return [PermitMatcher] + # + def permit(*params) + PermitMatcher.new(params).in_context(self) + end + + # @private + class PermitMatcher + attr_writer :stubbed_params + + def initialize(expected_permitted_parameter_names) + @expected_permitted_parameter_names = expected_permitted_parameter_names + @action = nil + @verb = nil + @request_params = {} + @subparameter_name = nil + @parameters_double_registry = CompositeParametersDoubleRegistry.new + end + + def for(action, options = {}) + @action = action + @verb = options.fetch(:verb, default_verb) + @request_params = options.fetch(:params, {}) + self + end + + def add_params(params) + request_params.merge!(params) + self + end + + def on(subparameter_name) + @subparameter_name = subparameter_name + self + end + + def in_context(context) + @context = context + self + end + + def description + "(for #{verb.upcase} ##{action}) " + expectation + end + + def matches?(controller) + @controller = controller + ensure_action_and_verb_present! + + parameters_double_registry.register + + Doublespeak.with_doubles_activated do + Shoulda::Matchers::RailsShim.make_controller_request( + context, + verb, + action, + request_params, + ) + end + + unpermitted_parameter_names.empty? + end + + def failure_message + "Expected #{verb.upcase} ##{action} to #{expectation},\nbut #{reality}." + end + + def failure_message_when_negated + "Expected #{verb.upcase} ##{action} not to #{expectation},\nbut it did." + end + + protected + + attr_reader :controller, :double_collections_by_parameter_name, :action, :verb, + :request_params, :expected_permitted_parameter_names, :context, :subparameter_name, + :parameters_double_registry + + def expectation + message = 'restrict parameters ' + + if subparameter_name + message << "on #{subparameter_name.inspect} " + end + + message << 'to ' + format_parameter_names(expected_permitted_parameter_names) + + message + end + + def reality + if actual_permitted_parameter_names.empty? + 'it did not restrict any parameters' + else + 'the restricted parameters were ' + + format_parameter_names(actual_permitted_parameter_names) + + ' instead' + end + end + + def format_parameter_names(parameter_names) + parameter_names.map(&:inspect).to_sentence + end + + def actual_permitted_parameter_names + @_actual_permitted_parameter_names ||= begin + if subparameter_name + options = { for: subparameter_name } + else + options = {} + end + + parameters_double_registry.permitted_parameter_names(options) + end + end + + def unpermitted_parameter_names + expected_permitted_parameter_names - actual_permitted_parameter_names + end + + def ensure_action_and_verb_present! + if action.blank? + raise ActionNotDefinedError + end + + if verb.blank? + raise VerbNotDefinedError + end + end + + def default_verb + case action + when :create then :post + when :update then RailsShim.verb_for_update + end + end + + def parameter_names_as_sentence + expected_permitted_parameter_names.map(&:inspect).to_sentence + end + + # @private + class CompositeParametersDoubleRegistry + def initialize + @parameters_double_registries = [] + end + + def register + double_collection = Doublespeak.double_collection_for( + ::ActionController::Parameters.singleton_class + ) + double_collection.register_proxy(:new).to_return do |call| + params = call.return_value + parameters_double_registry = ParametersDoubleRegistry.new(params) + parameters_double_registry.register + parameters_double_registries << parameters_double_registry + end + end + + def permitted_parameter_names(options = {}) + parameters_double_registries.flat_map do |double_registry| + double_registry.permitted_parameter_names(options) + end + end + + protected + + attr_reader :parameters_double_registries + end + + # @private + class ParametersDoubleRegistry + TOP_LEVEL = Object.new + + def self.permitted_parameter_names_within(double_collection) + double_collection.calls_to(:permit).map(&:args).flatten + end + + def initialize(params) + @params = params + @double_collections_by_parameter_name = {} + end + + def register + register_double_for_permit_against(params, TOP_LEVEL) + end + + def permitted_parameter_names(args = {}) + subparameter_name = args.fetch(:for, TOP_LEVEL) + + if double_collections_by_parameter_name.key?(subparameter_name) + self.class.permitted_parameter_names_within( + double_collections_by_parameter_name[subparameter_name] + ) + else + [] + end + end + + protected + + attr_reader :params, :double_collections_by_parameter_name + + private + + def register_double_for_permit_against(params, subparameter_name) + klass = params.singleton_class + + double_collection = Doublespeak.double_collection_for(klass) + register_double_for_permit_on(double_collection) + register_double_for_require_on(double_collection) + + double_collections_by_parameter_name[subparameter_name] = + double_collection + end + + def register_double_for_permit_on(double_collection) + double_collection.register_proxy(:permit) + end + + def register_double_for_require_on(double_collection) + double_collection.register_proxy(:require).to_return do |call| + params = call.return_value + subparameter_name = call.args.first + register_double_for_permit_against(params, subparameter_name) + end + end + end + + # @private + class ActionNotDefinedError < StandardError + def message + 'You must specify the controller action using the #for method.' + end + end + + # @private + class VerbNotDefinedError < StandardError + def message + 'You must specify an HTTP verb when using a non-RESTful action. For example: for(:authorize, verb: :post)' + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb 2020-02-18 07:23:52.000000000 +0000 @@ -3,7 +3,7 @@ module ActionController # The `redirect_to` matcher tests that an action redirects to a certain # location. In a test suite using RSpec, it is very similar to - # rspec-rails's `redirect_to` matcher. In a test suite using Test::Unit / + # rspec-rails's `redirect_to` matcher. In a test suite using Minitest + # Shoulda, it provides a more expressive syntax over # `assert_redirected_to`. # @@ -14,7 +14,7 @@ # end # # # RSpec - # describe PostsController do + # RSpec.describe PostsController, type: :controller do # describe 'GET #show' do # before { get :show } # @@ -23,12 +23,12 @@ # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class PostsControllerTest < ActionController::TestCase # context 'GET #show' do # setup { get :show } # - # should redirect_to { posts_path } + # should redirect_to('/posts') { posts_path } # should redirect_to(action: :index) # end # end @@ -43,9 +43,6 @@ class RedirectToMatcher attr_reader :failure_message, :failure_message_when_negated - alias failure_message_for_should failure_message - alias failure_message_for_should_not failure_message_when_negated - def initialize(url_or_description, context, &block) @url_block = nil @url = nil @@ -82,7 +79,7 @@ @context.__send__(:assert_redirected_to, url) @failure_message_when_negated = "Didn't expect to redirect to #{url}" true - rescue Shoulda::Matchers::AssertionError => error + rescue Shoulda::Matchers.assertion_exception_class => error @failure_message = error.message false end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/render_template_matcher.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/action_controller/render_template_matcher.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/render_template_matcher.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/action_controller/render_template_matcher.rb 2020-02-18 07:23:52.000000000 +0000 @@ -3,8 +3,8 @@ module ActionController # The `render_template` matcher tests that an action renders a template # or partial. In RSpec, it is very similar to rspec-rails's - # `render_template` matcher. In Test::Unit, it provides a more expressive - # syntax over `assert_template`. + # `render_template` matcher. In a test suite using Minitest + Shoulda, it + # provides a more expressive syntax over `assert_template`. # # class PostsController < ApplicationController # def show @@ -15,27 +15,25 @@ # <%= render 'sidebar' %> # # # RSpec - # describe PostsController do + # RSpec.describe PostsController, type: :controller do # describe 'GET #show' do # before { get :show } # # it { should render_template('show') } - # it { should render_template(partial: 'sidebar') } + # it { should render_template(partial: '_sidebar') } # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class PostsControllerTest < ActionController::TestCase # context 'GET #show' do # setup { get :show } # # should render_template('show') - # should render_template(partial: 'sidebar') + # should render_template(partial: '_sidebar') # end # end # - # - # # @return [RenderTemplateMatcher] # def render_template(options = {}, message = nil) @@ -46,9 +44,6 @@ class RenderTemplateMatcher attr_reader :failure_message, :failure_message_when_negated - alias failure_message_for_should failure_message - alias failure_message_for_should_not failure_message_when_negated - def initialize(options, message, context) @options = options @message = message @@ -80,7 +75,7 @@ @context.__send__(:assert_template, @options, @message) @failure_message_when_negated = "Didn't expect to render #{@template}" true - rescue Shoulda::Matchers::AssertionError => error + rescue Shoulda::Matchers.assertion_exception_class => error @failure_message = error.message false end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb 2020-02-18 07:23:52.000000000 +0000 @@ -11,7 +11,7 @@ # end # # # RSpec - # describe PostsController do + # RSpec.describe PostsController, type: :controller do # describe 'GET #show' do # before { get :show } # @@ -19,7 +19,7 @@ # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class PostsControllerTest < ActionController::TestCase # context 'GET #show' do # setup { get :show } @@ -38,7 +38,7 @@ # end # # # RSpec - # describe PostsController do + # RSpec.describe PostsController, type: :controller do # describe 'GET #sidebar' do # before { get :sidebar } # @@ -46,7 +46,7 @@ # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class PostsControllerTest < ActionController::TestCase # context 'GET #sidebar' do # setup { get :sidebar } @@ -88,12 +88,10 @@ def failure_message "Expected #{expectation}, but #{result}" end - alias failure_message_for_should failure_message def failure_message_when_negated "Did not expect #{expectation}, but #{result}" end - alias failure_message_for_should_not failure_message_when_negated def description description = 'render with ' @@ -125,7 +123,7 @@ def recorded_layouts if @context - @context.instance_variable_get(Shoulda::Matchers::RailsShim.layouts_ivar) + @context.instance_variable_get('@_layouts') else {} end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/rescue_from_matcher.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/action_controller/rescue_from_matcher.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/rescue_from_matcher.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/action_controller/rescue_from_matcher.rb 2020-02-18 07:23:52.000000000 +0000 @@ -16,14 +16,14 @@ # end # # # RSpec - # describe ApplicationController do + # RSpec.describe ApplicationController, type: :controller do # it do # should rescue_from(ActiveRecord::RecordNotFound). # with(:handle_not_found) # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class ApplicationControllerTest < ActionController::TestCase # should rescue_from(ActiveRecord::RecordNotFound). # with(:handle_not_found) @@ -54,7 +54,7 @@ end def description - description = "rescues from #{exception}" + description = "rescue from #{exception}" description << " with ##{expected_method}" if expected_method description end @@ -62,12 +62,10 @@ def failure_message "Expected #{expectation}" end - alias failure_message_for_should failure_message def failure_message_when_negated "Did not expect #{expectation}" end - alias failure_message_for_should_not failure_message_when_negated protected diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/respond_with_matcher.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/action_controller/respond_with_matcher.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/respond_with_matcher.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/action_controller/respond_with_matcher.rb 2020-02-18 07:23:52.000000000 +0000 @@ -13,7 +13,7 @@ # end # # # RSpec - # describe PostsController do + # RSpec.describe PostsController, type: :controller do # describe 'GET #index' do # before { get :index } # @@ -21,7 +21,7 @@ # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class PostsControllerTest < ActionController::TestCase # context 'GET #index' do # setup { get :index } @@ -39,7 +39,7 @@ # end # # # RSpec - # describe PostsController do + # RSpec.describe PostsController, type: :controller do # describe 'DELETE #destroy' do # before { delete :destroy } # @@ -47,7 +47,7 @@ # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class PostsControllerTest < ActionController::TestCase # context 'DELETE #destroy' do # setup { delete :destroy } @@ -65,7 +65,7 @@ # end # # # RSpec - # describe PostsController do + # RSpec.describe PostsController, type: :controller do # describe 'GET #show' do # before { get :show } # @@ -73,7 +73,7 @@ # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class PostsControllerTest < ActionController::TestCase # context 'GET #show' do # setup { get :show } @@ -102,12 +102,10 @@ def failure_message "Expected #{expectation}" end - alias failure_message_for_should failure_message def failure_message_when_negated "Did not expect #{expectation}" end - alias failure_message_for_should_not failure_message_when_negated def description "respond with #{@status}" @@ -135,11 +133,7 @@ when :missing then 404 when :error then 500..599 when Symbol - if defined?(::Rack::Utils::SYMBOL_TO_STATUS_CODE) - ::Rack::Utils::SYMBOL_TO_STATUS_CODE[potential_symbol] - else - ::ActionController::Base::SYMBOL_TO_STATUS_CODE[potential_symbol] - end + ::Rack::Utils::SYMBOL_TO_STATUS_CODE[potential_symbol] else potential_symbol end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/route_matcher.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/action_controller/route_matcher.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/route_matcher.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/action_controller/route_matcher.rb 2020-02-18 07:23:52.000000000 +0000 @@ -4,15 +4,16 @@ # The `route` matcher tests that a route resolves to a controller, # action, and params; and that the controller, action, and params # generates the same route. For an RSpec suite, this is like using a - # combination of `route_to` and `be_routable`. For a Test::Unit suite, it - # provides a more expressive syntax over `assert_routing`. + # combination of `route_to` and `be_routable`. In a test suite using + # Minitest + Shoulda, it provides a more expressive syntax over + # `assert_routing`. # # You can use this matcher either in a controller test case or in a # routing test case. For instance, given these routes: # # My::Application.routes.draw do - # get '/posts', controller: 'posts', action: 'index' - # get '/posts/:id' => 'posts#show' + # get '/posts', to: 'posts#index' + # get '/posts/:id', to: 'posts#show' # end # # You could choose to write tests for these routes alongside other tests @@ -23,12 +24,12 @@ # end # # # RSpec - # describe PostsController do + # RSpec.describe PostsController, type: :controller do # it { should route(:get, '/posts').to(action: :index) } # it { should route(:get, '/posts/1').to(action: :show, id: 1) } # end # - # # Test::Unit + # # Minitest (Shoulda) # class PostsControllerTest < ActionController::TestCase # should route(:get, '/posts').to(action: 'index') # should route(:get, '/posts/1').to(action: :show, id: 1) @@ -37,7 +38,7 @@ # Or you could place the tests along with other route tests: # # # RSpec - # describe 'Routing' do + # describe 'Routing', type: :routing do # it do # should route(:get, '/posts'). # to(controller: :posts, action: :index) @@ -49,7 +50,7 @@ # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class RoutesTest < ActionController::IntegrationTest # should route(:get, '/posts'). # to(controller: :posts, action: :index) @@ -63,6 +64,42 @@ # this controller. In the latter case we specify this using the # `controller` key passed to the `to` qualifier. # + # #### Specifying a port + # + # If the route you're testing has a constraint on it that limits the route + # to a particular port, you can specify it by passing a `port` option to + # the matcher: + # + # class PortConstraint + # def initialize(port) + # @port = port + # end + # + # def matches?(request) + # request.port == @port + # end + # end + # + # My::Application.routes.draw do + # get '/posts', + # to: 'posts#index', + # constraints: PortConstraint.new(12345) + # end + # + # # RSpec + # describe 'Routing', type: :routing do + # it do + # should route(:get, '/posts', port: 12345). + # to('posts#index') + # end + # end + # + # # Minitest (Shoulda) + # class RoutesTest < ActionController::IntegrationTest + # should route(:get, '/posts', port: 12345). + # to('posts#index') + # end + # # #### Qualifiers # # ##### to @@ -70,7 +107,9 @@ # Use `to` to specify the action (along with the controller, if needed) # that the route resolves to. # - # # Three ways of saying the same thing (using the example above) + # `to` takes either keyword arguments (`controller` and `action`) or a + # string that represents the controller/action pair: + # # route(:get, '/posts').to(action: index) # route(:get, '/posts').to(controller: :posts, action: index) # route(:get, '/posts').to('posts#index') @@ -79,24 +118,26 @@ # # route(:get, '/posts/1').to('posts#show', id: 1) # + # You may also specify special parameters such as `:format`: + # + # route(:get, '/posts').to('posts#index', format: :json) + # # @return [RouteMatcher] # - def route(method, path) - RouteMatcher.new(method, path, self) + def route(method, path, port: nil) + RouteMatcher.new(self, method, path, port: port) end # @private class RouteMatcher - def initialize(method, path, context) - @method = method - @path = path + def initialize(context, method, path, port: nil) @context = context + @method = method + @path = add_port_to_path(normalize_path(path), port) + @params = {} end - attr_reader :failure_message, :failure_message_when_negated - - alias failure_message_for_should failure_message - alias failure_message_for_should_not failure_message_when_negated + attr_reader :failure_message def to(*args) @params = RouteParams.new(args).normalize @@ -109,36 +150,57 @@ end def matches?(controller) - guess_controller!(controller) + guess_controller_if_necessary(controller) + route_recognized? end def description - "route #{@method.to_s.upcase} #{@path} to/from #{@params.inspect}" + "route #{method.to_s.upcase} #{path} to/from #{params.inspect}" + end + + def failure_message_when_negated + "Didn't expect to #{description}" end private - def guess_controller!(controller) - @params[:controller] ||= controller.controller_path + attr_reader :context, :method, :path, :params + + def normalize_path(path) + if path.start_with?('/') + path + else + "/#{path}" + end + end + + def add_port_to_path(path, port) + if port + "http://example.com:#{port}" + path + else + path + end end + def guess_controller_if_necessary(controller) + params[:controller] ||= controller.controller_path + end + def route_recognized? - begin - @context.__send__(:assert_routing, - { method: @method, path: @path }, - @params) - - @failure_message_when_negated = "Didn't expect to #{description}" - true - rescue ::ActionController::RoutingError => error - @failure_message = error.message - false - rescue Shoulda::Matchers::AssertionError => error - @failure_message = error.message - false - end + context.send( + :assert_routing, + { method: method, path: path }, + params, + ) + true + rescue ::ActionController::RoutingError => error + @failure_message = error.message + false + rescue Shoulda::Matchers.assertion_exception_class => error + @failure_message = error.message + false end end end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/route_params.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/action_controller/route_params.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/route_params.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/action_controller/route_params.rb 2020-02-18 07:23:52.000000000 +0000 @@ -3,6 +3,8 @@ module ActionController # @private class RouteParams + PARAMS_TO_SYMBOLIZE = %i{ format } + def initialize(args) @args = args end @@ -26,17 +28,24 @@ def extract_params_from_string controller, action = args[0].split('#') params = (args[1] || {}).merge(controller: controller, action: action) - stringify_values(params) + normalize_values(params) end def stringify_params - stringify_values(args[0]) + normalize_values(args[0]) end - def stringify_values(hash) - hash.inject({}) do |hash_copy, (key, value)| - hash_copy[key] = stringify(value) - hash_copy + def normalize_values(hash) + hash.each_with_object({}) do |(key, value), hash_copy| + hash_copy[key] = symbolize_or_stringify(key, value) + end + end + + def symbolize_or_stringify(key, value) + if PARAMS_TO_SYMBOLIZE.include?(key) + value.to_sym + else + stringify(value) end end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/session_store.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/action_controller/session_store.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/session_store.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/action_controller/session_store.rb 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,34 @@ +module Shoulda + module Matchers + module ActionController + # @private + class SessionStore + attr_accessor :controller + + def name + 'session' + end + + def has_key?(key) + session.key?(key) + end + + def has_value?(expected_value) + session.values.any? do |actual_value| + expected_value === actual_value + end + end + + def empty? + session.empty? + end + + private + + def session + controller.session + end + end + end + end +end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/set_flash_matcher.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/action_controller/set_flash_matcher.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/set_flash_matcher.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/action_controller/set_flash_matcher.rb 2020-02-18 07:23:52.000000000 +0000 @@ -1,3 +1,5 @@ +require 'forwardable' + module Shoulda module Matchers module ActionController @@ -14,7 +16,7 @@ # end # # # RSpec - # describe PostsController do + # RSpec.describe PostsController, type: :controller do # describe 'GET #index' do # before { get :index } # @@ -28,7 +30,7 @@ # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class PostsControllerTest < ActionController::TestCase # context 'GET #index' do # setup { get :index } @@ -56,7 +58,7 @@ # end # # # RSpec - # describe PostsController do + # RSpec.describe PostsController, type: :controller do # describe 'GET #index' do # before { get :index } # @@ -65,7 +67,7 @@ # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class PostsControllerTest < ActionController::TestCase # context 'GET #index' do # setup { get :show } @@ -87,7 +89,7 @@ # end # # # RSpec - # describe PostsController do + # RSpec.describe PostsController, type: :controller do # describe 'GET #index' do # before { get :index } # @@ -98,7 +100,7 @@ # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class PostsControllerTest < ActionController::TestCase # context 'GET #index' do # setup { get :show } @@ -122,184 +124,102 @@ # end # # # RSpec - # describe PostsController do + # RSpec.describe PostsController, type: :controller do # describe 'GET #show' do # before { get :show } # # it { should set_flash.now } - # it { should set_flash[:foo].now } - # it { should set_flash[:foo].to('bar').now } + # it { should set_flash.now[:foo] } + # it { should set_flash.now[:foo].to('bar') } # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class PostsControllerTest < ActionController::TestCase # context 'GET #index' do # setup { get :show } # # should set_flash.now - # should set_flash[:foo].now - # should set_flash[:foo].to('bar').now + # should set_flash.now[:foo] + # should set_flash.now[:foo].to('bar') # end # end # # @return [SetFlashMatcher] # def set_flash - SetFlashMatcher.new - end - - # @deprecated Use {#set_flash} instead. - # @return [SetFlashMatcher] - def set_the_flash - Shoulda::Matchers.warn_about_deprecated_method( - :set_the_flash, - :set_flash - ) - set_flash + SetFlashMatcher.new.in_context(self) end # @private class SetFlashMatcher + extend Forwardable + + def_delegators :underlying_matcher, + :description, + :matches?, + :failure_message, + :failure_message_when_negated + alias_method \ + :failure_message_for_should, + :failure_message + alias_method \ + :failure_message_for_should_not, + :failure_message_when_negated + def initialize - @options = {} - @value = nil + store = FlashStore.future + @underlying_matcher = SetSessionOrFlashMatcher.new(store) end - def to(value) - if !value.is_a?(String) && !value.is_a?(Regexp) - raise "cannot match against #{value.inspect}" + def now + if key || expected_value + raise QualifierOrderError end - @value = value + + store = FlashStore.now + @underlying_matcher = SetSessionOrFlashMatcher.new(store) self end - def now - @options[:now] = true + def in_context(context) + underlying_matcher.in_context(context) self end def [](key) - @options[:key] = key + @key = key + underlying_matcher[key] self end - def matches?(controller) - @controller = controller - sets_the_flash? && string_value_matches? && regexp_value_matches? - end - - def description - description = "set the #{expected_flash_invocation}" - description << " to #{@value.inspect}" unless @value.nil? - description - end - - def failure_message - "Expected #{expectation}" - end - alias failure_message_for_should failure_message - - def failure_message_when_negated - "Did not expect #{expectation}" - end - alias failure_message_for_should_not failure_message_when_negated - - private - - def sets_the_flash? - flash_values.any? - end - - def string_value_matches? - if @value.is_a?(String) - flash_values.any? {|value| value == @value } - else - true - end - end - - def regexp_value_matches? - if @value.is_a?(Regexp) - flash_values.any? {|value| value =~ @value } - else - true - end - end - - def flash_values - if @options.key?(:key) - flash_hash = HashWithIndifferentAccess.new(flash.to_hash) - [flash_hash[@options[:key]]] - else - flash.to_hash.values - end - end - - def flash - @flash ||= copy_of_flash_from_controller - end - - def copy_of_flash_from_controller - @controller.flash.dup.tap do |flash| - copy_flashes(@controller.flash, flash) - copy_discard_if_necessary(@controller.flash, flash) - sweep_flash_if_necessary(flash) - end - end - - def copy_flashes(original_flash, new_flash) - flashes_ivar = Shoulda::Matchers::RailsShim.flashes_ivar - flashes = original_flash.instance_variable_get(flashes_ivar).dup - new_flash.instance_variable_set(flashes_ivar, flashes) - end - - def copy_discard_if_necessary(original_flash, new_flash) - discard_ivar = :@discard - if original_flash.instance_variable_defined?(discard_ivar) - discard = original_flash.instance_variable_get(discard_ivar).dup - new_flash.instance_variable_set(discard_ivar, discard) - end - end - - def sweep_flash_if_necessary(flash) - unless @options[:now] - flash.sweep - end - end - - def expectation - expectation = "the #{expected_flash_invocation} to be set" - expectation << " to #{@value.inspect}" unless @value.nil? - expectation << ", but #{flash_description}" - expectation - end - - def flash_description - if flash.blank? - 'no flash was set' - else - "was #{flash.inspect}" - end + def to(expected_value = nil, &block) + @expected_value = expected_value + underlying_matcher.to(expected_value, &block) + self end - def expected_flash_invocation - "flash#{pretty_now}#{pretty_key}" - end + protected - def pretty_now - if @options[:now] - '.now' - else - '' - end - end + attr_reader :underlying_matcher, :key, :expected_value - def pretty_key - if @options[:key] - "[:#{@options[:key]}]" - else - '' + # @private + class QualifierOrderError < StandardError + def message + <<-MESSAGE.strip +Using `set_flash` with the `now` qualifier and specifying `now` after other +qualifiers is no longer allowed. + +You'll want to use `now` immediately after `set_flash`. For instance: + + # Valid + should set_flash.now[:foo] + should set_flash.now[:foo].to('bar') + + # Invalid + should set_flash[:foo].now + should set_flash[:foo].to('bar').now + MESSAGE end end end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/set_session_matcher.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/action_controller/set_session_matcher.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/set_session_matcher.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/action_controller/set_session_matcher.rb 2020-02-18 07:23:52.000000000 +0000 @@ -1,3 +1,5 @@ +require 'forwardable' + module Shoulda module Matchers module ActionController @@ -14,7 +16,7 @@ # end # # # RSpec - # describe PostsController do + # RSpec.describe PostsController, type: :controller do # describe 'GET #index' do # before { get :index } # @@ -28,7 +30,7 @@ # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class PostsControllerTest < ActionController::TestCase # context 'GET #index' do # setup { get :index } @@ -56,7 +58,7 @@ # end # # # RSpec - # describe PostsController do + # RSpec.describe PostsController, type: :controller do # describe 'GET #index' do # before { get :index } # @@ -65,7 +67,7 @@ # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class PostsControllerTest < ActionController::TestCase # context 'GET #index' do # setup { get :show } @@ -87,7 +89,7 @@ # end # # # RSpec - # describe PostsController do + # RSpec.describe PostsController, type: :controller do # describe 'GET #index' do # before { get :index } # @@ -98,7 +100,7 @@ # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class PostsControllerTest < ActionController::TestCase # context 'GET #index' do # setup { get :show } @@ -112,132 +114,49 @@ # # @return [SetSessionMatcher] # - def set_session(key = nil) - SetSessionMatcher.new(key) + def set_session + SetSessionMatcher.new.in_context(self) end # @private class SetSessionMatcher - def initialize(key) - if key - Shoulda::Matchers.warn < { }) + + @result_of_checking = nil + @result_of_setting = nil + end + + def description + description = ":#{attribute_name} to " + description << Shoulda::Matchers::Util.inspect_value(value_written) + + if attribute_changed_value? + description << " -- which was read back as " + description << Shoulda::Matchers::Util.inspect_value(value_read) + description << " --" + end + + description + end + + def run + check && set + end + + def run! + check && set! + end + + def check + if attribute_exists? + @result_of_checking = successful_check + true + else + @result_of_checking = attribute_does_not_exist_error + false + end + end + + def set! + if attribute_exists? + set + + unless result_of_setting.successful? + raise result_of_setting + end + + @result_of_checking = successful_check + @result_of_setting = successful_setting + + true + else + attribute_does_not_exist! + end + end + + def set + object.public_send("#{attribute_name}=", value_written) + after_set_callback.call + + @result_of_checking = successful_check + + if raise_attribute_changed_value_error? + @result_of_setting = attribute_changed_value_error + false + else + @result_of_setting = successful_setting + true + end + end + + def failure_message + if successful? + raise "We're not supposed to be here!" + elsif result_of_setting + result_of_setting.message + else + result_of_checking.message + end + end + + def successful? + successfully_checked? && successfully_set? + end + + def unsuccessful? + !successful? + end + + def checked? + !result_of_checking.nil? + end + + def successfully_checked? + checked? && result_of_checking.successful? + end + + def unsuccessfully_checked? + !successfully_checked? + end + + def set? + !result_of_setting.nil? + end + + def successfully_set? + set? && result_of_setting.successful? + end + + def value_read + @_value_read ||= object.public_send(attribute_name) + end + + def attribute_changed_value? + value_written != value_read + end + + protected + + attr_reader :args, :matcher_name, :object, :after_set_callback + + private + + def model + object.class + end + + def attribute_exists? + if active_resource_object? + object.known_attributes.include?(attribute_name.to_s) + else + object.respond_to?("#{attribute_name}=") + end + end + + def ignore_interference_by_writer + @ignore_interference_by_writer + end + + def raise_attribute_changed_value_error? + attribute_changed_value? && + !(attribute_is_an_enum? && value_read_is_expected_for_an_enum?) && + !ignore_interference_by_writer.considering?(value_read) + end + + def attribute_is_an_enum? + enum_values.any? + end + + def value_read_is_expected_for_an_enum? + enum_values.key?(value_read) && + enum_values[value_read] == value_written + end + + def enum_values + defined_enums.fetch(attribute_name.to_s, {}) + end + + def defined_enums + if model.respond_to?(:defined_enums) + model.defined_enums + else + {} + end + end + + def successful_check + SuccessfulCheck.new + end + + def successful_setting + SuccessfulSetting.new + end + + def attribute_changed_value! + raise attribute_changed_value_error + end + + def attribute_changed_value_error + AttributeChangedValueError.create( + model: object.class, + attribute_name: attribute_name, + value_written: value_written, + value_read: value_read + ) + end + + def attribute_does_not_exist! + raise attribute_does_not_exist_error + end + + def attribute_does_not_exist_error + AttributeDoesNotExistError.create( + model: object.class, + attribute_name: attribute_name, + value: value_written + ) + end + + def active_resource_object? + object.respond_to?(:known_attributes) + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters_and_validators.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters_and_validators.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters_and_validators.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters_and_validators.rb 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,48 @@ +module Shoulda + module Matchers + module ActiveModel + class AllowValueMatcher + # @private + class AttributeSettersAndValidators + include Enumerable + + def initialize(allow_value_matcher, values) + @tuples = values.map do |attribute_name, value| + AttributeSetterAndValidator.new( + allow_value_matcher, + attribute_name, + value + ) + end + end + + def each(&block) + tuples.each(&block) + end + + def first_passing + tuples.detect(&method(:matches?)) + end + + def first_failing + tuples.detect(&method(:does_not_match?)) + end + + protected + + attr_reader :tuples + + private + + def matches?(tuple) + tuple.attribute_setter.set! && tuple.validator.call + end + + def does_not_match?(tuple) + !matches?(tuple) + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters.rb 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,40 @@ +module Shoulda + module Matchers + module ActiveModel + class AllowValueMatcher + # @private + class AttributeSetters + include Enumerable + + def initialize(allow_value_matcher, values) + @tuples = values.map do |attribute_name, value| + AttributeSetterAndValidator.new( + allow_value_matcher, + attribute_name, + value + ) + end + end + + def each(&block) + tuples.each(&block) + end + + def first_failing + tuples.detect(&method(:does_not_match?)) + end + + protected + + attr_reader :tuples + + private + + def does_not_match?(tuple) + !tuple.attribute_setter.set! + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/allow_value_matcher/successful_check.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/allow_value_matcher/successful_check.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/allow_value_matcher/successful_check.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/allow_value_matcher/successful_check.rb 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,14 @@ +module Shoulda + module Matchers + module ActiveModel + class AllowValueMatcher + # @private + class SuccessfulCheck + def successful? + true + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/allow_value_matcher/successful_setting.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/allow_value_matcher/successful_setting.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/allow_value_matcher/successful_setting.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/allow_value_matcher/successful_setting.rb 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,14 @@ +module Shoulda + module Matchers + module ActiveModel + class AllowValueMatcher + # @private + class SuccessfulSetting + def successful? + true + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/allow_value_matcher.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/allow_value_matcher.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/allow_value_matcher.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/allow_value_matcher.rb 2020-02-18 07:23:52.000000000 +0000 @@ -1,15 +1,11 @@ module Shoulda module Matchers module ActiveModel - # The `allow_value` matcher is used to test that an attribute of a model - # can or cannot be set to a particular value or values. It is most - # commonly used in conjunction with the `validates_format_of` validation. - # - # #### should - # - # In the positive form, `allow_value` asserts that an attribute can be - # set to one or more values, succeeding if none of the values cause the - # record to be invalid: + # The `allow_value` matcher (or its alias, `allow_values`) is used to + # ensure that an attribute is valid or invalid if set to one or more + # values. + # + # Take this model for example: # # class UserProfile # include ActiveModel::Model @@ -18,45 +14,129 @@ # validates_format_of :website_url, with: URI.regexp # end # + # You can use `allow_value` to test one value at a time: + # + # # RSpec + # RSpec.describe UserProfile, type: :model do + # it { should allow_value('http://foo.com').for(:website_url) } + # it { should allow_value('http://bar.com').for(:website_url) } + # end + # + # # Minitest (Shoulda) + # class UserProfileTest < ActiveSupport::TestCase + # should allow_value('http://foo.com').for(:website_url) + # should allow_value('http://bar.com').for(:website_url) + # end + # + # You can also test multiple values in one go, if you like. In the + # positive sense, this makes an assertion that none of the values cause the + # record to be invalid. In the negative sense, this makes an assertion + # that none of the values cause the record to be valid: + # # # RSpec - # describe UserProfile do + # RSpec.describe UserProfile, type: :model do # it do - # should allow_value('http://foo.com', 'http://bar.com/baz'). + # should allow_values('http://foo.com', 'http://bar.com'). + # for(:website_url) + # end + # + # it do + # should_not allow_values('foo', 'buz'). # for(:website_url) # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class UserProfileTest < ActiveSupport::TestCase - # should allow_value('http://foo.com', 'http://bar.com/baz'). + # should allow_values('http://foo.com', 'http://bar.com/baz'). + # for(:website_url) + # + # should_not allow_values('foo', 'buz'). # for(:website_url) # end # - # #### should_not + # #### Caveats # - # In the negative form, `allow_value` asserts that an attribute cannot be - # set to one or more values, succeeding if the *first* value causes the - # record to be invalid. + # When using `allow_value` or any matchers that depend on it, you may + # encounter an AttributeChangedValueError. This exception is raised if the + # matcher, in attempting to set a value on the attribute, detects that + # the value set is different from the value that the attribute returns + # upon reading it back. + # + # This usually happens if the writer method (`foo=`, `bar=`, etc.) for + # that attribute has custom logic to ignore certain incoming values or + # change them in any way. Here are three examples we've seen: + # + # * You're attempting to assert that an attribute should not allow nil, + # yet the attribute's writer method contains a conditional to do nothing + # if the attribute is set to nil: + # + # class Foo + # include ActiveModel::Model + # + # attr_reader :bar + # + # def bar=(value) + # return if value.nil? + # @bar = value + # end + # end # - # **This can be surprising** so in this case if you need to check that - # *all* of the values are invalid, use separate assertions: + # RSpec.describe Foo, type: :model do + # it do + # foo = Foo.new + # foo.bar = "baz" + # # This will raise an AttributeChangedValueError since `foo.bar` is now "123" + # expect(foo).not_to allow_value(nil).for(:bar) + # end + # end # - # class UserProfile - # include ActiveModel::Model - # attr_accessor :website_url + # * You're attempting to assert that a numeric attribute should not allow + # a string that contains non-numeric characters, yet the writer method + # for that attribute strips out non-numeric characters: + # + # class Foo + # include ActiveModel::Model + # + # attr_reader :bar + # + # def bar=(value) + # @bar = value.gsub(/\D+/, '') + # end + # end # - # validates_format_of :website_url, with: URI.regexp - # end + # RSpec.describe Foo, type: :model do + # it do + # foo = Foo.new + # # This will raise an AttributeChangedValueError since `foo.bar` is now "123" + # expect(foo).not_to allow_value("abc123").for(:bar) + # end + # end # - # describe UserProfile do - # # One assertion: 'buz' and 'bar' will not be tested - # it { should_not allow_value('fiz', 'buz', 'bar').for(:website_url) } - # - # # Three assertions, all tested separately - # it { should_not allow_value('fiz').for(:website_url) } - # it { should_not allow_value('buz').for(:website_url) } - # it { should_not allow_value('bar').for(:website_url) } - # end + # * You're passing a value to `allow_value` that the model typecasts into + # another value: + # + # RSpec.describe Foo, type: :model do + # # Assume that `attr` is a string + # # This will raise an AttributeChangedValueError since `attr` typecasts `[]` to `"[]"` + # it { should_not allow_value([]).for(:attr) } + # end + # + # Fortunately, if you understand why this is happening, and wish to get + # around this exception, it is possible to do so. You can use the + # `ignoring_interference_by_writer` qualifier like so: + # + # it do + # should_not allow_value([]). + # for(:attr). + # ignoring_interference_by_writer + # end + # + # Please note, however, that this qualifier won't magically cause your + # test to pass. It may just so happen that the final value that ends up + # being set causes the model to fail validation. In that case, you'll have + # to figure out what to do. You may need to write your own test, or + # perhaps even remove your test altogether. # # #### Qualifiers # @@ -74,7 +154,7 @@ # end # # # RSpec - # describe UserProfile do + # RSpec.describe UserProfile, type: :model do # it do # should allow_value('2013-01-01'). # for(:birthday_as_string). @@ -82,7 +162,7 @@ # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class UserProfileTest < ActiveSupport::TestCase # should allow_value('2013-01-01'). # for(:birthday_as_string). @@ -103,7 +183,7 @@ # end # # # RSpec - # describe UserProfile do + # RSpec.describe UserProfile, type: :model do # it do # should allow_value('open', 'closed'). # for(:state). @@ -111,16 +191,43 @@ # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class UserProfileTest < ActiveSupport::TestCase # should allow_value('open', 'closed'). # for(:state). # with_message('State must be open or closed') # end # + # Use `with_message` with a regexp to perform a partial match: + # + # class UserProfile + # include ActiveModel::Model + # attr_accessor :state + # + # validates_format_of :state, + # with: /^(open|closed)$/, + # message: 'State must be open or closed' + # end + # + # # RSpec + # RSpec.describe UserProfile, type: :model do + # it do + # should allow_value('open', 'closed'). + # for(:state). + # with_message(/open or closed/) + # end + # end + # + # # Minitest (Shoulda) + # class UserProfileTest < ActiveSupport::TestCase + # should allow_value('open', 'closed'). + # for(:state). + # with_message(/open or closed/) + # end + # # Use `with_message` with the `:against` option if the attribute the # validation message is stored under is different from the attribute - # being validated. + # being validated: # # class UserProfile # include ActiveModel::Model @@ -139,7 +246,7 @@ # end # # # RSpec - # describe UserProfile do + # RSpec.describe UserProfile, type: :model do # it do # should allow_value('Broncos', 'Titans'). # for(:sports_team). @@ -149,7 +256,7 @@ # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class UserProfileTest < ActiveSupport::TestCase # should allow_value('Broncos', 'Titans'). # for(:sports_team). @@ -158,6 +265,32 @@ # ) # end # + # ##### ignoring_interference_by_writer + # + # Use `ignoring_interference_by_writer` to bypass an + # AttributeChangedValueError that you have encountered. Please read the + # Caveats section above for more information. + # + # class Address < ActiveRecord::Base + # # Address has a zip_code field which is a string + # end + # + # # RSpec + # RSpec.describe Address, type: :model do + # it do + # should_not allow_value([]). + # for(:zip_code). + # ignoring_interference_by_writer + # end + # end + # + # # Minitest (Shoulda) + # class AddressTest < ActiveSupport::TestCase + # should_not allow_value([]). + # for(:zip_code). + # ignoring_interference_by_writer + # end + # # @return [AllowValueMatcher] # def allow_value(*values) @@ -167,181 +300,320 @@ AllowValueMatcher.new(*values) end end + # @private + alias_method :allow_values, :allow_value # @private class AllowValueMatcher include Helpers + include Qualifiers::IgnoringInterferenceByWriter - attr_accessor :attribute_with_message - attr_accessor :options + attr_reader( + :after_setting_value_callback, + :attribute_to_check_message_against, + :attribute_to_set, + :context, + :instance + ) + + attr_writer( + :attribute_changed_value_message, + :failure_message_preface, + :values_to_preset, + ) def initialize(*values) - self.values_to_match = values - self.options = {} - self.after_setting_value_callback = -> {} - self.validator = Validator.new + super + @values_to_set = values + @options = {} + @after_setting_value_callback = -> {} + @expects_strict = false + @expects_custom_validation_message = false + @context = nil + @values_to_preset = {} + @failure_message_preface = nil + @attribute_changed_value_message = nil end - def for(attribute) - self.attribute_to_set = attribute - self.attribute_to_check_message_against = attribute + def for(attribute_name) + @attribute_to_set = attribute_name + @attribute_to_check_message_against = attribute_name self end def on(context) - validator.context = context + if context.present? + @context = context + end + self end - def with_message(message, options={}) - self.options[:expected_message] = message - self.options[:expected_message_values] = options.fetch(:values, {}) + def with_message(message, given_options = {}) + if message.present? + @expects_custom_validation_message = true + options[:expected_message] = message + options[:expected_message_values] = given_options.fetch(:values, {}) - if options.key?(:against) - self.attribute_to_check_message_against = options[:against] + if given_options.key?(:against) + @attribute_to_check_message_against = given_options[:against] + end end self end - def strict - validator.strict = true + def expected_message + if options.key?(:expected_message) + if Symbol === options[:expected_message] + default_expected_message + else + options[:expected_message] + end + end + end + + def expects_custom_validation_message? + @expects_custom_validation_message + end + + def strict(expects_strict = true) + @expects_strict = expects_strict self end + def expects_strict? + @expects_strict + end + def _after_setting_value(&callback) - self.after_setting_value_callback = callback + @after_setting_value_callback = callback end def matches?(instance) - self.instance = instance - validator.record = instance + @instance = instance + @result = run(:first_failing) + @result.nil? + end - values_to_match.none? do |value| - validator.reset - self.value = value - set_attribute(value) - errors_match? || any_range_error_occurred? - end + def does_not_match?(instance) + @instance = instance + @result = run(:first_passing) + @result.nil? end def failure_message - "Did not expect #{expectation},\ngot#{error_description}" + attribute_setter = result.attribute_setter + + if result.attribute_setter.unsuccessfully_checked? + message = attribute_setter.failure_message + else + validator = result.validator + message = failure_message_preface.call + message << ' valid, but it was invalid instead,' + + if validator.captured_validation_exception? + message << ' raising a validation exception with the message ' + message << validator.validation_exception_message.inspect + message << '.' + else + message << " producing these validation errors:\n\n" + message << validator.all_formatted_validation_error_messages + end + end + + if include_attribute_changed_value_message? + message << "\n\n" + attribute_changed_value_message.call + end + + Shoulda::Matchers.word_wrap(message) end - alias failure_message_for_should failure_message def failure_message_when_negated - "Expected #{expectation},\ngot#{error_description}" - end - alias failure_message_for_should_not failure_message_when_negated + attribute_setter = result.attribute_setter - def description - validator.allow_description(allowed_values) - end + if attribute_setter.unsuccessfully_checked? + message = attribute_setter.failure_message + else + validator = result.validator + message = failure_message_preface.call + ' invalid' - protected + if validator.type_of_message_matched? + if validator.has_messages? + message << ' and to' + + if validator.captured_validation_exception? + message << ' raise a validation exception with message' + else + message << ' produce' + + if expected_message.is_a?(Regexp) + message << ' a' + else + message << ' the' + end + + message << ' validation error' + end + + if expected_message.is_a?(Regexp) + message << ' matching ' + message << Shoulda::Matchers::Util.inspect_value( + expected_message + ) + else + message << " #{expected_message.inspect}" + end + + unless validator.captured_validation_exception? + message << " on :#{attribute_to_check_message_against}" + end + + message << '. The record was indeed invalid, but' + + if validator.captured_validation_exception? + message << ' the exception message was ' + message << validator.validation_exception_message.inspect + message << ' instead.' + else + message << " it produced these validation errors instead:\n\n" + message << validator.all_formatted_validation_error_messages + end + else + message << ', but it was valid instead.' + end + elsif validator.captured_validation_exception? + message << ' and to produce validation errors, but the record' + message << ' raised a validation exception instead.' + else + message << ' and to raise a validation exception, but the record' + message << ' produced validation errors instead.' + end + end - attr_reader :attribute_to_check_message_against - attr_accessor :values_to_match, :instance, :attribute_to_set, :value, - :matched_error, :after_setting_value_callback, :validator + if include_attribute_changed_value_message? + message << "\n\n" + attribute_changed_value_message.call + end - def attribute_to_check_message_against=(attribute) - @attribute_to_check_message_against = attribute - validator.attribute = attribute + Shoulda::Matchers.word_wrap(message) end - def set_attribute(value) - set_attribute_ignoring_range_errors(value) - after_setting_value_callback.call + def description + ValidationMatcher::BuildDescription.call(self, simple_description) end - def set_attribute_ignoring_range_errors(value) - instance.__send__("#{attribute_to_set}=", value) - rescue RangeError => exception - # Have to reset the attribute so that we don't get a RangeError the - # next time we attempt to write the attribute (ActiveRecord seems to - # set the attribute to the "bad" value anyway) - reset_attribute - validator.capture_range_error(exception) + def simple_description + "allow :#{attribute_to_set} to be #{inspected_values_to_set}" end - def reset_attribute - instance.send(:raw_write_attribute, attribute_to_set, nil) + def model + instance.class end - def errors_match? - has_messages? && errors_for_attribute_match? + def last_attribute_setter_used + result.attribute_setter end - def has_messages? - validator.has_messages? + def last_value_set + last_attribute_setter_used.value_written end - def errors_for_attribute_match? - if expected_message - self.matched_error = errors_match_regexp? || errors_match_string? - else - errors_for_attribute.compact.any? - end - end + protected - def errors_for_attribute - validator.formatted_messages - end + attr_reader( + :options, + :result, + :values_to_preset, + :values_to_set, + ) + + private + + def run(strategy) + attribute_setters_for_values_to_preset.first_failing || + attribute_setters_and_validators_for_values_to_set.public_send(strategy) + end + + def failure_message_preface + @failure_message_preface || method(:default_failure_message_preface) + end + + def default_failure_message_preface + ''.tap do |preface| + if descriptions_for_preset_values.any? + preface << 'After setting ' + preface << descriptions_for_preset_values.to_sentence + preface << ', then ' + else + preface << 'After ' + end + + preface << 'setting ' + preface << description_for_resulting_attribute_setter - def errors_match_regexp? - if Regexp === expected_message - errors_for_attribute.detect { |e| e =~ expected_message } + unless preface.end_with?('--') + preface << ',' + end + + preface << " the matcher expected the #{model.name} to be" end end - def errors_match_string? - if errors_for_attribute.include?(expected_message) - expected_message - end + def include_attribute_changed_value_message? + !ignore_interference_by_writer.never? && + result.attribute_setter.attribute_changed_value? end - def any_range_error_occurred? - validator.captured_range_error? + def attribute_changed_value_message + @attribute_changed_value_message || + method(:default_attribute_changed_value_message) end - def expectation - parts = [ - expected_messages_description, - "when #{attribute_to_set} is set to #{value.inspect}" - ] + def default_attribute_changed_value_message + <<-MESSAGE.strip +As indicated in the message above, :#{result.attribute_setter.attribute_name} +seems to be changing certain values as they are set, and this could have +something to do with why this test is failing. If you've overridden the writer +method for this attribute, then you may need to change it to make this test +pass, or do something else entirely. + MESSAGE + end - parts.join(' ').squeeze(' ') + def descriptions_for_preset_values + attribute_setters_for_values_to_preset. + map(&:attribute_setter_description) end - def expected_messages_description - validator.expected_messages_description(expected_message) + def description_for_resulting_attribute_setter + result.attribute_setter_description end - def error_description - validator.messages_description + def attribute_setters_for_values_to_preset + @_attribute_setters_for_values_to_preset ||= + AttributeSetters.new(self, values_to_preset) end - def allowed_values - if values_to_match.length > 1 - "any of [#{values_to_match.map(&:inspect).join(', ')}]" - else - values_to_match.first.inspect - end + def attribute_setters_and_validators_for_values_to_set + @_attribute_setters_and_validators_for_values_to_set ||= + AttributeSettersAndValidators.new( + self, + values_to_set.map { |value| [attribute_to_set, value] } + ) end - def expected_message - if options.key?(:expected_message) - if Symbol === options[:expected_message] - default_expected_message - else - options[:expected_message] - end - end + def inspected_values_to_set + Shoulda::Matchers::Util.inspect_values(values_to_set).to_sentence( + two_words_connector: " or ", + last_word_connector: ", or " + ) end def default_expected_message - validator.expected_message_from(default_attribute_message) + if expects_strict? + "#{human_attribute_name} #{default_attribute_message}" + else + default_attribute_message + end end def default_attribute_message @@ -364,6 +636,12 @@ def model_name instance.class.to_s.underscore end + + def human_attribute_name + instance.class.human_attribute_name( + attribute_to_check_message_against + ) + end end end end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/disallow_value_matcher.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/disallow_value_matcher.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/disallow_value_matcher.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/disallow_value_matcher.rb 2020-02-18 07:23:52.000000000 +0000 @@ -7,43 +7,66 @@ class DisallowValueMatcher extend Forwardable - def_delegators :allow_matcher, :_after_setting_value + def_delegators( + :allow_matcher, + :_after_setting_value, + :attribute_changed_value_message=, + :attribute_to_set, + :description, + :expects_strict?, + :failure_message_preface, + :failure_message_preface=, + :ignore_interference_by_writer, + :last_attribute_setter_used, + :last_value_set, + :model, + :simple_description, + :values_to_preset=, + ) + def initialize(value) @allow_matcher = AllowValueMatcher.new(value) end def matches?(subject) - !@allow_matcher.matches?(subject) + allow_matcher.does_not_match?(subject) + end + + def does_not_match?(subject) + allow_matcher.matches?(subject) end def for(attribute) - @allow_matcher.for(attribute) + allow_matcher.for(attribute) self end def on(context) - @allow_matcher.on(context) + allow_matcher.on(context) self end def with_message(message, options={}) - @allow_matcher.with_message(message, options) + allow_matcher.with_message(message, options) self end - def failure_message - @allow_matcher.failure_message_when_negated + def strict(strict = true) + allow_matcher.strict(strict) + self end - alias failure_message_for_should failure_message - def failure_message_when_negated - @allow_matcher.failure_message + def ignoring_interference_by_writer(value = :always) + allow_matcher.ignoring_interference_by_writer(value) + self end - alias failure_message_for_should_not failure_message_when_negated - def strict - @allow_matcher.strict - self + def failure_message + allow_matcher.failure_message_when_negated + end + + def failure_message_when_negated + allow_matcher.failure_message end protected diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/have_secure_password_matcher.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/have_secure_password_matcher.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/have_secure_password_matcher.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/have_secure_password_matcher.rb 2020-02-18 07:23:52.000000000 +0000 @@ -15,11 +15,11 @@ # end # # # RSpec - # describe User do + # RSpec.describe User, type: :model do # it { should have_secure_password } # end # - # # Test::Unit + # # Minitest (Shoulda) # class UserTest < ActiveSupport::TestCase # should have_secure_password # end @@ -34,8 +34,6 @@ class HaveSecurePasswordMatcher attr_reader :failure_message - alias failure_message_for_should failure_message - CORRECT_PASSWORD = "aBcDe12345" INCORRECT_PASSWORD = "password" diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/helpers.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/helpers.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/helpers.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/helpers.rb 2020-02-18 07:23:52.000000000 +0000 @@ -3,25 +3,17 @@ module ActiveModel # @private module Helpers - def pretty_error_messages(obj) - obj.errors.map do |attribute, message| - full_message = message.dup.inspect - parenthetical_parts = [] - - unless attribute.to_sym == :base - parenthetical_parts << "attribute: #{attribute}" - - if obj.respond_to?(attribute) - parenthetical_parts << "value: #{obj.__send__(attribute).inspect}" - end - end + def pretty_error_messages(object) + format_validation_errors(object.errors) + end - if parenthetical_parts.any? - full_message << " (#{parenthetical_parts.join(', ')})" - end + def format_validation_errors(errors) + list_items = errors.keys.map do |attribute| + messages = errors[attribute] + "* #{attribute}: #{messages}" + end - "* " + full_message - end.join("\n") + list_items.join("\n") end def default_error_message(type, options = {}) diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb 2020-02-18 07:23:52.000000000 +0000 @@ -13,6 +13,7 @@ } def initialize(numericality_matcher, value, operator) + super(nil) unless numericality_matcher.respond_to? :diff_to_compare raise ArgumentError, 'numericality_matcher is invalid' end @@ -20,8 +21,18 @@ @value = value @operator = operator @message = ERROR_MESSAGES[operator] - @comparison_combos = comparison_combos - @strict = false + end + + def simple_description + description = '' + + if expects_strict? + description << ' strictly' + end + + description + + "disallow :#{attribute} from being a number that is not " + + "#{comparison_expectation} #{@value}" end def for(attribute) @@ -29,28 +40,32 @@ self end - def matches?(subject) - @subject = subject - all_bounds_correct? - end - def with_message(message) + @expects_custom_validation_message = true @message = message + self end - def comparison_description - "#{expectation} #{@value}" + def expects_custom_validation_message? + @expects_custom_validation_message + end + + def matches?(subject) + @subject = subject + all_bounds_correct? end def failure_message last_failing_submatcher.failure_message end - alias failure_message_for_should failure_message def failure_message_when_negated last_failing_submatcher.failure_message_when_negated end - alias failure_message_for_should_not failure_message_when_negated + + def comparison_description + "#{comparison_expectation} #{@value}" + end private @@ -71,7 +86,7 @@ def submatchers @_submatchers ||= comparison_combos.map do |diff, submatcher_method_name| - matcher = __send__(submatcher_method_name, @value + diff, nil) + matcher = __send__(submatcher_method_name, diff, nil) matcher.with_message(@message, values: { count: @value }) matcher end @@ -114,11 +129,17 @@ end def diffs_to_compare - diff = @numericality_matcher.diff_to_compare - [-diff, 0, diff] + diff_to_compare = @numericality_matcher.diff_to_compare + values = [-1, 0, 1].map { |sign| @value + (diff_to_compare * sign) } + + if @numericality_matcher.given_numeric_column? + values + else + values.map(&:to_s) + end end - def expectation + def comparison_expectation case @operator when :> then "greater than" when :>= then "greater than or equal to" diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/numericality_matchers/even_number_matcher.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/numericality_matchers/even_number_matcher.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/numericality_matchers/even_number_matcher.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/numericality_matchers/even_number_matcher.rb 2020-02-18 07:23:52.000000000 +0000 @@ -6,20 +6,38 @@ class EvenNumberMatcher < NumericTypeMatcher NON_EVEN_NUMBER_VALUE = 1 - def initialize(attribute, options = {}) - @attribute = attribute - @disallow_value_matcher = DisallowValueMatcher.new(NON_EVEN_NUMBER_VALUE). - for(@attribute). - with_message(:even) + def simple_description + description = '' + + if expects_strict? + description << 'strictly ' + end + + description + + "disallow :#{attribute} from being an odd number" end - def allowed_type - 'even numbers' + def allowed_type_adjective + 'even' end def diff_to_compare 2 end + + protected + + def wrap_disallow_value_matcher(matcher) + matcher.with_message(:even) + end + + def disallowed_value + if @numeric_type_matcher.given_numeric_column? + NON_EVEN_NUMBER_VALUE + else + NON_EVEN_NUMBER_VALUE.to_s + end + end end end end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb 2020-02-18 07:23:52.000000000 +0000 @@ -1,39 +1,67 @@ +require 'forwardable' + module Shoulda module Matchers module ActiveModel module NumericalityMatchers # @private class NumericTypeMatcher - def initialize - raise NotImplementedError + extend Forwardable + + def_delegators( + :disallow_value_matcher, + :expects_custom_validation_message?, + :expects_strict?, + :failure_message, + :failure_message_when_negated, + :ignore_interference_by_writer, + :ignoring_interference_by_writer, + :matches?, + :does_not_match?, + :on, + :strict, + :with_message, + ) + + def initialize(numeric_type_matcher, attribute) + @numeric_type_matcher = numeric_type_matcher + @attribute = attribute end - def matches?(subject) - @disallow_value_matcher.matches?(subject) + def allowed_type_name + 'number' end - def with_message(message) - @disallow_value_matcher.with_message(message) - self + def allowed_type_adjective + '' end - def allowed_type + def diff_to_compare raise NotImplementedError end - def diff_to_compare + protected + + attr_reader :attribute + + def wrap_disallow_value_matcher(matcher) raise NotImplementedError end - def failure_message - @disallow_value_matcher.failure_message + def disallowed_value + raise NotImplementedError end - alias failure_message_for_should failure_message - def failure_message_when_negated - @disallow_value_matcher.failure_message_when_negated + private + + def disallow_value_matcher + @_disallow_value_matcher ||= begin + DisallowValueMatcher.new(disallowed_value).tap do |matcher| + matcher.for(attribute) + wrap_disallow_value_matcher(matcher) + end + end end - alias failure_message_for_should_not failure_message_when_negated end end end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher.rb 2020-02-18 07:23:52.000000000 +0000 @@ -4,22 +4,40 @@ module NumericalityMatchers # @private class OddNumberMatcher < NumericTypeMatcher - NON_ODD_NUMBER_VALUE = 2 + NON_ODD_NUMBER_VALUE = 2 - def initialize(attribute, options = {}) - @attribute = attribute - @disallow_value_matcher = DisallowValueMatcher.new(NON_ODD_NUMBER_VALUE). - for(@attribute). - with_message(:odd) + def simple_description + description = '' + + if expects_strict? + description << 'strictly ' + end + + description + + "disallow :#{attribute} from being an even number" end - def allowed_type - 'odd numbers' + def allowed_type_adjective + 'odd' end def diff_to_compare 2 end + + protected + + def wrap_disallow_value_matcher(matcher) + matcher.with_message(:odd) + end + + def disallowed_value + if @numeric_type_matcher.given_numeric_column? + NON_ODD_NUMBER_VALUE + else + NON_ODD_NUMBER_VALUE.to_s + end + end end end end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher.rb 2020-02-18 07:23:52.000000000 +0000 @@ -5,20 +5,38 @@ # @private class OnlyIntegerMatcher < NumericTypeMatcher NON_INTEGER_VALUE = 0.1 - def initialize(attribute) - @attribute = attribute - @disallow_value_matcher = DisallowValueMatcher.new(NON_INTEGER_VALUE). - for(attribute). - with_message(:not_an_integer) + + def simple_description + description = '' + + if expects_strict? + description << ' strictly' + end + + description + "disallow :#{attribute} from being a decimal number" end - def allowed_type - 'integers' + def allowed_type_name + 'integer' end def diff_to_compare 1 end + + protected + + def wrap_disallow_value_matcher(matcher) + matcher.with_message(:not_an_integer) + end + + def disallowed_value + if @numeric_type_matcher.given_numeric_column? + NON_INTEGER_VALUE + else + NON_INTEGER_VALUE.to_s + end + end end end end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/qualifiers/allow_nil.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/qualifiers/allow_nil.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/qualifiers/allow_nil.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/qualifiers/allow_nil.rb 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,26 @@ +module Shoulda + module Matchers + module ActiveModel + module Qualifiers + # @private + module AllowNil + def initialize(*args) + super + @expects_to_allow_nil = false + end + + def allow_nil + @expects_to_allow_nil = true + self + end + + protected + + def expects_to_allow_nil? + @expects_to_allow_nil + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/qualifiers/ignore_interference_by_writer.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/qualifiers/ignore_interference_by_writer.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/qualifiers/ignore_interference_by_writer.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/qualifiers/ignore_interference_by_writer.rb 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,101 @@ +module Shoulda + module Matchers + module ActiveModel + module Qualifiers + # @private + class IgnoreInterferenceByWriter + attr_reader :setting, :condition + + def initialize(argument = :always) + set(argument) + @changed = false + end + + def set(argument) + if argument.is_a?(self.class) + @setting = argument.setting + @condition = argument.condition + else + case argument + when true, :always + @setting = :always + when false, :never + @setting = :never + else + @setting = :sometimes + + if argument.is_a?(Hash) + @condition = argument.fetch(:when) + else + raise invalid_argument_error(argument) + end + end + end + + @changed = true + + self + rescue KeyError + raise invalid_argument_error(argument) + end + + def default_to(argument) + temporary_ignore_interference_by_writer = + IgnoreInterferenceByWriter.new(argument) + + unless changed? + @setting = temporary_ignore_interference_by_writer.setting + @condition = temporary_ignore_interference_by_writer.condition + end + + self + end + + def considering?(value) + case setting + when :always then true + when :never then false + else condition_matches?(value) + end + end + + def always? + setting == :always + end + + def never? + setting == :never + end + + def changed? + @changed + end + + private + + def invalid_argument_error(invalid_argument) + ArgumentError.new(<<-ERROR) +Unknown argument: #{invalid_argument.inspect}. + +ignoring_interference_by_writer takes one of three arguments: + +* A symbol, either :never or :always. +* A boolean, either true (which means always) or false (which means + never). +* A hash with a single key, :when, and a single value, which is either + the name of a method or a Proc. + ERROR + end + + def condition_matches?(value) + if condition.respond_to?(:call) + condition.call(value) + else + value.public_send(condition) + end + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/qualifiers/ignoring_interference_by_writer.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/qualifiers/ignoring_interference_by_writer.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/qualifiers/ignoring_interference_by_writer.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/qualifiers/ignoring_interference_by_writer.rb 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,21 @@ +module Shoulda + module Matchers + module ActiveModel + module Qualifiers + # @private + module IgnoringInterferenceByWriter + attr_reader :ignore_interference_by_writer + + def initialize(*args) + @ignore_interference_by_writer = IgnoreInterferenceByWriter.new + end + + def ignoring_interference_by_writer(value = :always) + @ignore_interference_by_writer.set(value) + self + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/qualifiers.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/qualifiers.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/qualifiers.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/qualifiers.rb 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,13 @@ +module Shoulda + module Matchers + module ActiveModel + # @private + module Qualifiers + end + end + end +end + +require_relative 'qualifiers/allow_nil' +require_relative 'qualifiers/ignore_interference_by_writer' +require_relative 'qualifiers/ignoring_interference_by_writer' diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/strict_validator.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/strict_validator.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/strict_validator.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/strict_validator.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -module Shoulda - module Matchers - module ActiveModel - # @private - module StrictValidator - def allow_description(allowed_values) - "doesn't raise when #{attribute} is set to #{allowed_values}" - end - - def expected_message_from(attribute_message) - "#{human_attribute_name} #{attribute_message}" - end - - def formatted_messages - [messages.first.message] - end - - def messages_description - if has_messages? - ': ' + messages.first.message.inspect - else - ' no exception' - end - end - - def expected_messages_description(expected_message) - if expected_message - "exception to include #{expected_message.inspect}" - else - 'an exception to have been raised' - end - end - - protected - - def collect_messages - validation_exceptions - end - - private - - def validation_exceptions - record.valid?(context) - [] - rescue ::ActiveModel::StrictValidationFailed => exception - [exception] - end - end - end - end -end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb 2020-02-18 07:23:52.000000000 +0000 @@ -4,49 +4,70 @@ # The `validate_absence_of` matcher tests the usage of the # `validates_absence_of` validation. # - # class Artillery + # class PowerHungryCountry # include ActiveModel::Model - # attr_accessor :arms + # attr_accessor :nuclear_weapons # - # validates_absence_of :arms + # validates_absence_of :nuclear_weapons # end # # # RSpec - # describe Artillery do - # it { should validate_absence_of(:arms) } + # RSpec.describe PowerHungryCountry, type: :model do + # it { should validate_absence_of(:nuclear_weapons) } # end # - # # Test::Unit - # class ArtilleryTest < ActiveSupport::TestCase - # should validate_absence_of(:arms) + # # Minitest (Shoulda) + # class PowerHungryCountryTest < ActiveSupport::TestCase + # should validate_absence_of(:nuclear_weapons) # end # # #### Qualifiers # + # ##### on + # + # Use `on` if your validation applies only under a certain context. + # + # class PowerHungryCountry + # include ActiveModel::Model + # attr_accessor :nuclear_weapons + # + # validates_absence_of :nuclear_weapons, on: :create + # end + # + # # RSpec + # RSpec.describe PowerHungryCountry, type: :model do + # it { should validate_absence_of(:nuclear_weapons).on(:create) } + # end + # + # # Minitest (Shoulda) + # class PowerHungryCountryTest < ActiveSupport::TestCase + # should validate_absence_of(:nuclear_weapons).on(:create) + # end + # # ##### with_message # # Use `with_message` if you are using a custom validation message. # - # class Artillery + # class PowerHungryCountry # include ActiveModel::Model - # attr_accessor :arms + # attr_accessor :nuclear_weapons # - # validates_absence_of :arms, - # message: "We're fresh outta arms here, soldier!" + # validates_absence_of :nuclear_weapons, + # message: "there shall be peace on Earth" # end # # # RSpec - # describe Artillery do + # RSpec.describe PowerHungryCountry, type: :model do # it do - # should validate_absence_of(:arms). - # with_message("We're fresh outta arms here, soldier!") + # should validate_absence_of(:nuclear_weapons). + # with_message("there shall be peace on Earth") # end # end # - # # Test::Unit - # class ArtilleryTest < ActiveSupport::TestCase - # should validate_absence_of(:arms). - # with_message("We're fresh outta arms here, soldier!") + # # Minitest (Shoulda) + # class PowerHungryCountryTest < ActiveSupport::TestCase + # should validate_absence_of(:nuclear_weapons). + # with_message("there shall be peace on Earth") # end # # @return [ValidateAbsenceOfMatcher} @@ -57,19 +78,23 @@ # @private class ValidateAbsenceOfMatcher < ValidationMatcher - def with_message(message) - @expected_message = message - self + def initialize(attribute) + super + @expected_message = :present end def matches?(subject) super(subject) - @expected_message ||= :present disallows_value_of(value, @expected_message) end - def description - "require #{@attribute} to not be set" + def does_not_match?(subject) + super(subject) + allows_value_of(value, @expected_message) + end + + def simple_description + "validate that :#{@attribute} is empty/falsy" end private @@ -82,21 +107,22 @@ else obj end - elsif [Fixnum, Float].include?(attribute_class) - 1 - elsif attribute_class == BigDecimal - BigDecimal.new(1, 0) - elsif !attribute_class || attribute_class == String - 'an arbitrary value' else - attribute_class.new + case column_type + when :integer, :float then 1 + when :decimal then BigDecimal(1, 0) + when :datetime, :time, :timestamp then Time.now + when :date then Date.new + when :binary then '0' + else 'an arbitrary value' + end end end - def attribute_class + def column_type @subject.class.respond_to?(:columns_hash) && - @subject.class.columns_hash[@attribute.to_s].respond_to?(:klass) && - @subject.class.columns_hash[@attribute.to_s].klass + @subject.class.columns_hash[@attribute.to_s].respond_to?(:type) && + @subject.class.columns_hash[@attribute.to_s].type end def collection? diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb 2020-02-18 07:23:52.000000000 +0000 @@ -12,17 +12,41 @@ # end # # # RSpec - # describe Registration do + # RSpec.describe Registration, type: :model do # it { should validate_acceptance_of(:eula) } # end # - # # Test::Unit + # # Minitest (Shoulda) # class RegistrationTest < ActiveSupport::TestCase # should validate_acceptance_of(:eula) # end # # #### Qualifiers # + # ##### on + # + # Use `on` if your validation applies only under a certain context. + # + # class Registration + # include ActiveModel::Model + # attr_accessor :terms_of_service + # + # validates_acceptance_of :terms_of_service, on: :create + # end + # + # # RSpec + # RSpec.describe Registration, type: :model do + # it do + # should validate_acceptance_of(:terms_of_service). + # on(:create) + # end + # end + # + # # Minitest (Shoulda) + # class RegistrationTest < ActiveSupport::TestCase + # should validate_acceptance_of(:terms_of_service).on(:create) + # end + # # ##### with_message # # Use `with_message` if you are using a custom validation message. @@ -36,14 +60,14 @@ # end # # # RSpec - # describe Registration do + # RSpec.describe Registration, type: :model do # it do # should validate_acceptance_of(:terms_of_service). # with_message('You must accept the terms of service') # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class RegistrationTest < ActiveSupport::TestCase # should validate_acceptance_of(:terms_of_service). # with_message('You must accept the terms of service') @@ -57,21 +81,23 @@ # @private class ValidateAcceptanceOfMatcher < ValidationMatcher - def with_message(message) - if message - @expected_message = message - end - self + def initialize(attribute) + super + @expected_message = :accepted end def matches?(subject) super(subject) - @expected_message ||= :accepted disallows_value_of(false, @expected_message) end - def description - "require #{@attribute} to be accepted" + def does_not_match?(subject) + super(subject) + allows_value_of(false, @expected_message) + end + + def simple_description + %(validate that :#{@attribute} has been set to "1") end end end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb 2020-02-18 07:23:52.000000000 +0000 @@ -12,17 +12,38 @@ # end # # # RSpec - # describe User do + # RSpec.describe User, type: :model do # it { should validate_confirmation_of(:email) } # end # - # # Test::Unit + # # Minitest (Shoulda) # class UserTest < ActiveSupport::TestCase # should validate_confirmation_of(:email) # end # # #### Qualifiers # + # ##### on + # + # Use `on` if your validation applies only under a certain context. + # + # class User + # include ActiveModel::Model + # attr_accessor :password + # + # validates_confirmation_of :password, on: :create + # end + # + # # RSpec + # RSpec.describe User, type: :model do + # it { should validate_confirmation_of(:password).on(:create) } + # end + # + # # Minitest (Shoulda) + # class UserTest < ActiveSupport::TestCase + # should validate_confirmation_of(:password).on(:create) + # end + # # ##### with_message # # Use `with_message` if you are using a custom validation message. @@ -36,14 +57,14 @@ # end # # # RSpec - # describe User do + # RSpec.describe User, type: :model do # it do # should validate_confirmation_of(:password). # with_message('Please re-enter your password') # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class UserTest < ActiveSupport::TestCase # should validate_confirmation_of(:password). # with_message('Please re-enter your password') @@ -62,67 +83,78 @@ attr_reader :attribute, :confirmation_attribute def initialize(attribute) - super(attribute) + super + @expected_message = :confirmation @confirmation_attribute = "#{attribute}_confirmation" end - def with_message(message) - @message = message if message - self - end - - def description - "require #{@confirmation_attribute} to match #{@attribute}" + def simple_description + "validate that :#{@confirmation_attribute} matches :#{@attribute}" end def matches?(subject) super(subject) - @message ||= :confirmation disallows_different_value && allows_same_value && allows_missing_confirmation end + def does_not_match?(subject) + super(subject) + + allows_different_value || + disallows_same_value || + disallows_missing_confirmation + end + private + def allows_different_value + allows_value_of('different value') do |matcher| + qualify_matcher(matcher, 'some value') + end + end + def disallows_different_value - set_confirmation('some value') disallows_value_of('different value') do |matcher| - qualify_matcher(matcher) + qualify_matcher(matcher, 'some value') end end def allows_same_value - set_confirmation('same value') allows_value_of('same value') do |matcher| - qualify_matcher(matcher) + qualify_matcher(matcher, 'same value') end end - def allows_missing_confirmation - set_confirmation(nil) - allows_value_of('any value') do |matcher| - qualify_matcher(matcher) + def disallows_same_value + disallows_value_of('same value') do |matcher| + qualify_matcher(matcher, 'same value') end end - def qualify_matcher(matcher) - matcher.with_message(@message, - against: error_attribute, - values: { attribute: attribute } - ) + def allows_missing_confirmation + allows_value_of('any value') do |matcher| + qualify_matcher(matcher, nil) + end end - def set_confirmation(val) - setter = :"#{@confirmation_attribute}=" - if @subject.respond_to?(setter) - @subject.__send__(setter, val) + def disallows_missing_confirmation + disallows_value_of('any value') do |matcher| + qualify_matcher(matcher, nil) end end - def error_attribute - RailsShim.validates_confirmation_of_error_attribute(self) + def qualify_matcher(matcher, confirmation_attribute_value) + matcher.values_to_preset = { + confirmation_attribute => confirmation_attribute_value + } + matcher.with_message( + @expected_message, + against: confirmation_attribute, + values: { attribute: attribute } + ) end end end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb 2020-02-18 07:23:52.000000000 +0000 @@ -16,14 +16,14 @@ # end # # # RSpec - # describe Game do + # RSpec.describe Game, type: :model do # it do # should validate_exclusion_of(:supported_os). # in_array(['Mac', 'Linux']) # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class GameTest < ActiveSupport::TestCase # should validate_exclusion_of(:supported_os). # in_array(['Mac', 'Linux']) @@ -35,18 +35,18 @@ # include ActiveModel::Model # attr_accessor :supported_os # - # validates_exclusion_of :supported_os, in: ['Mac', 'Linux'] + # validates_exclusion_of :supported_os, in: 5..8 # end # # # RSpec - # describe Game do + # RSpec.describe Game, type: :model do # it do # should validate_exclusion_of(:floors_with_enemies). # in_range(5..8) # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class GameTest < ActiveSupport::TestCase # should validate_exclusion_of(:floors_with_enemies). # in_range(5..8) @@ -54,6 +54,35 @@ # # #### Qualifiers # + # ##### on + # + # Use `on` if your validation applies only under a certain context. + # + # class Game + # include ActiveModel::Model + # attr_accessor :weapon + # + # validates_exclusion_of :weapon, + # in: ['pistol', 'paintball gun', 'stick'], + # on: :create + # end + # + # # RSpec + # RSpec.describe Game, type: :model do + # it do + # should validate_exclusion_of(:weapon). + # in_array(['pistol', 'paintball gun', 'stick']). + # on(:create) + # end + # end + # + # # Minitest (Shoulda) + # class GameTest < ActiveSupport::TestCase + # should validate_exclusion_of(:weapon). + # in_array(['pistol', 'paintball gun', 'stick']). + # on(:create) + # end + # # ##### with_message # # Use `with_message` if you are using a custom validation message. @@ -68,7 +97,7 @@ # end # # # RSpec - # describe Game do + # RSpec.describe Game, type: :model do # it do # should validate_exclusion_of(:weapon). # in_array(['pistol', 'paintball gun', 'stick']). @@ -76,7 +105,7 @@ # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class GameTest < ActiveSupport::TestCase # should validate_exclusion_of(:weapon). # in_array(['pistol', 'paintball gun', 'stick']). @@ -89,23 +118,13 @@ ValidateExclusionOfMatcher.new(attr) end - # @deprecated Use {#validate_exclusion_of} instead. - # @return [ValidateExclusionOfMatcher] - def ensure_exclusion_of(attr) - Shoulda::Matchers.warn_about_deprecated_method( - :ensure_exclusion_of, - :validate_exclusion_of - ) - validate_exclusion_of(attr) - end - # @private class ValidateExclusionOfMatcher < ValidationMatcher def initialize(attribute) super(attribute) + @expected_message = :exclusion @array = nil @range = nil - @expected_message = nil end def in_array(array) @@ -120,13 +139,21 @@ self end - def with_message(message) - @expected_message = message if message - self - end + def simple_description + if @range + "validate that :#{@attribute} lies outside the range " + + Shoulda::Matchers::Util.inspect_range(@range) + else + description = "validate that :#{@attribute}" + + if @array.many? + description << " is neither #{inspected_array}" + else + description << " is not #{inspected_array}" + end - def description - "ensure exclusion of #{@attribute} in #{inspect_message}" + description + end end def matches?(subject) @@ -135,39 +162,70 @@ if @range allows_lower_value && disallows_minimum_value && - allows_higher_value && - disallows_maximum_value + disallows_maximum_value && + allows_higher_value elsif @array disallows_all_values_in_array? end end + def does_not_match?(subject) + super(subject) + + if @range + disallows_lower_value || + allows_minimum_value || + allows_maximum_value || + disallows_higher_value + elsif @array + allows_any_values_in_array? + end + end + private + def allows_any_values_in_array? + @array.any? do |value| + allows_value_of(value, @expected_message) + end + end + def disallows_all_values_in_array? @array.all? do |value| - disallows_value_of(value, expected_message) + disallows_value_of(value, @expected_message) end end def allows_lower_value - @minimum == 0 || allows_value_of(@minimum - 1, expected_message) + @minimum == 0 || allows_value_of(@minimum - 1, @expected_message) end - def allows_higher_value - allows_value_of(@maximum + 1, expected_message) + def disallows_lower_value + @minimum != 0 && disallows_value_of(@minimum - 1, @expected_message) + end + + def allows_minimum_value + allows_value_of(@minimum, @expected_message) end def disallows_minimum_value - disallows_value_of(@minimum, expected_message) + disallows_value_of(@minimum, @expected_message) + end + + def allows_maximum_value + allows_value_of(@maximum, @expected_message) end def disallows_maximum_value - disallows_value_of(@maximum, expected_message) + disallows_value_of(@maximum, @expected_message) + end + + def allows_higher_value + allows_value_of(@maximum + 1, @expected_message) end - def expected_message - @expected_message || :exclusion + def disallows_higher_value + disallows_value_of(@maximum + 1, @expected_message) end def inspect_message @@ -177,6 +235,13 @@ @array.inspect end end + + def inspected_array + Shoulda::Matchers::Util.inspect_values(@array).to_sentence( + two_words_connector: " nor ", + last_word_connector: ", nor " + ) + end end end end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb 2020-02-18 07:23:52.000000000 +0000 @@ -1,4 +1,5 @@ require 'bigdecimal' +require 'date' module Shoulda module Matchers @@ -13,21 +14,22 @@ # include ActiveModel::Model # attr_accessor :state # - # validates_inclusion_of :state, in: %w(open resolved unresolved) + # validates_inclusion_of :state, + # in: ['open', 'resolved', 'unresolved'] # end # # # RSpec - # describe Issue do + # RSpec.describe Issue, type: :model do # it do # should validate_inclusion_of(:state). - # in_array(%w(open resolved unresolved)) + # in_array(['open', 'resolved', 'unresolved']) # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class IssueTest < ActiveSupport::TestCase # should validate_inclusion_of(:state). - # in_array(%w(open resolved unresolved)) + # in_array(['open', 'resolved', 'unresolved']) # end # # If your whitelist is a range of values, use `in_range`: @@ -40,11 +42,11 @@ # end # # # RSpec - # describe Issue do + # RSpec.describe Issue, type: :model do # it { should validate_inclusion_of(:state).in_range(1..5) } # end # - # # Test::Unit + # # Minitest (Shoulda) # class IssueTest < ActiveSupport::TestCase # should validate_inclusion_of(:state).in_range(1..5) # end @@ -57,7 +59,10 @@ # one of these three values. That means there isn't any way we can refute # this logic in a test. Hence, this will produce a warning: # - # it { should validate_inclusion_of(:imported).in_array([true, false]) } + # it do + # should validate_inclusion_of(:imported). + # in_array([true, false]) + # end # # The only case where `validate_inclusion_of` *could* be appropriate is # for ensuring that a boolean column accepts nil, but we recommend @@ -67,6 +72,33 @@ # # #### Qualifiers # + # Use `on` if your validation applies only under a certain context. + # + # class Issue + # include ActiveModel::Model + # attr_accessor :severity + # + # validates_inclusion_of :severity, + # in: %w(low medium high), + # on: :create + # end + # + # # RSpec + # RSpec.describe Issue, type: :model do + # it do + # should validate_inclusion_of(:severity). + # in_array(%w(low medium high)). + # on(:create) + # end + # end + # + # # Minitest (Shoulda) + # class IssueTest < ActiveSupport::TestCase + # should validate_inclusion_of(:severity). + # in_array(%w(low medium high)). + # on(:create) + # end + # # ##### with_message # # Use `with_message` if you are using a custom validation message. @@ -81,7 +113,7 @@ # end # # # RSpec - # describe Issue do + # RSpec.describe Issue, type: :model do # it do # should validate_inclusion_of(:severity). # in_array(%w(low medium high)). @@ -89,7 +121,7 @@ # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class IssueTest < ActiveSupport::TestCase # should validate_inclusion_of(:severity). # in_array(%w(low medium high)). @@ -117,7 +149,7 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it do # should validate_inclusion_of(:age). # in_range(0..65). @@ -125,7 +157,7 @@ # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should validate_inclusion_of(:age). # in_range(0..65). @@ -153,7 +185,7 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it do # should validate_inclusion_of(:age). # in_range(0..21). @@ -161,7 +193,7 @@ # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should validate_inclusion_of(:age). # in_range(0..21). @@ -178,23 +210,23 @@ # # validates_presence_of :state # validates_inclusion_of :state, - # in: %w(open resolved unresolved), + # in: ['open', 'resolved', 'unresolved'], # allow_nil: true # end # # # RSpec - # describe Issue do + # RSpec.describe Issue, type: :model do # it do # should validate_inclusion_of(:state). - # in_array(%w(open resolved unresolved)). + # in_array(['open', 'resolved', 'unresolved']). # allow_nil # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class IssueTest < ActiveSupport::TestCase # should validate_inclusion_of(:state). - # in_array(%w(open resolved unresolved)). + # in_array(['open', 'resolved', 'unresolved']). # allow_nil # end # @@ -208,23 +240,23 @@ # # validates_presence_of :state # validates_inclusion_of :state, - # in: %w(open resolved unresolved), + # in: ['open', 'resolved', 'unresolved'], # allow_blank: true # end # # # RSpec - # describe Issue do + # RSpec.describe Issue, type: :model do # it do # should validate_inclusion_of(:state). - # in_array(%w(open resolved unresolved)). + # in_array(['open', 'resolved', 'unresolved']). # allow_blank # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class IssueTest < ActiveSupport::TestCase # should validate_inclusion_of(:state). - # in_array(%w(open resolved unresolved)). + # in_array(['open', 'resolved', 'unresolved']). # allow_blank # end # @@ -234,21 +266,15 @@ ValidateInclusionOfMatcher.new(attr) end - # @deprecated Use {#validate_inclusion_of} instead. - # @return [ValidateInclusionOfMatcher] - def ensure_inclusion_of(attr) - Shoulda::Matchers.warn_about_deprecated_method( - :ensure_inclusion_of, - :validate_inclusion_of - ) - validate_inclusion_of(attr) - end - # @private class ValidateInclusionOfMatcher < ValidationMatcher - ARBITRARY_OUTSIDE_STRING = 'shouldamatchersteststring' - ARBITRARY_OUTSIDE_FIXNUM = 123456789 - ARBITRARY_OUTSIDE_DECIMAL = BigDecimal.new('0.123456789') + BLANK_VALUES = ['', ' ', "\n", "\r", "\t", "\f"] + ARBITRARY_OUTSIDE_STRING = 'shoulda-matchers test string' + ARBITRARY_OUTSIDE_INTEGER = 123456789 + ARBITRARY_OUTSIDE_DECIMAL = BigDecimal('0.123456789') + ARBITRARY_OUTSIDE_DATE = Date.jd(9999999) + ARBITRARY_OUTSIDE_DATETIME = DateTime.jd(9999999) + ARBITRARY_OUTSIDE_TIME = Time.at(9999999999) BOOLEAN_ALLOWS_BOOLEAN_MESSAGE = < 0 && + allows_length_of?( + @options[:minimum] - 1, + translated_short_message + ) + end + def disallows_lower_length? - if @options.key?(:minimum) + !@options.key?(:minimum) || @options[:minimum] == 0 || - disallows_length_of?(@options[:minimum] - 1, @short_message) - else - true - end + disallows_length_of?( + @options[:minimum] - 1, + translated_short_message + ) + end + + def allows_higher_length? + @options.key?(:maximum) && + allows_length_of?( + @options[:maximum] + 1, + translated_long_message + ) end def disallows_higher_length? - if @options.key?(:maximum) - disallows_length_of?(@options[:maximum] + 1, @long_message) - else - true - end + !@options.key?(:maximum) || + disallows_length_of?( + @options[:maximum] + 1, + translated_long_message + ) end def allows_minimum_length? - if @options.key?(:minimum) - allows_length_of?(@options[:minimum], @short_message) - else - true - end + !@options.key?(:minimum) || + allows_length_of?(@options[:minimum], translated_short_message) + end + + def disallows_minimum_length? + @options.key?(:minimum) && + disallows_length_of?(@options[:minimum], translated_short_message) end def allows_maximum_length? - if @options.key?(:maximum) - allows_length_of?(@options[:maximum], @long_message) - else - true - end + !@options.key?(:maximum) || + allows_length_of?(@options[:maximum], translated_long_message) + end + + def disallows_maximum_length? + @options.key?(:maximum) && + disallows_length_of?(@options[:maximum], translated_long_message) + end + + def allow_nil_matches? + !expects_to_allow_nil? || allows_value_of(nil) + end + + def allow_nil_does_not_match? + expects_to_allow_nil? && disallows_value_of(nil) end def allows_length_of?(length, message) @@ -353,6 +437,36 @@ def string_of_length(length) 'x' * length end + + def translated_short_message + @_translated_short_message ||= + if @short_message.is_a?(Symbol) + default_error_message( + @short_message, + model_name: @subject.class.to_s.underscore, + instance: @subject, + attribute: @attribute, + count: @options[:minimum] + ) + else + @short_message + end + end + + def translated_long_message + @_translated_long_message ||= + if @long_message.is_a?(Symbol) + default_error_message( + @long_message, + model_name: @subject.class.to_s.underscore, + instance: @subject, + attribute: @attribute, + count: @options[:maximum] + ) + else + @long_message + end + end end end end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb 2020-02-18 07:23:52.000000000 +0000 @@ -12,17 +12,41 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it { should validate_numericality_of(:gpa) } # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should validate_numericality_of(:gpa) # end # # #### Qualifiers # + # ##### on + # + # Use `on` if your validation applies only under a certain context. + # + # class Person + # include ActiveModel::Model + # attr_accessor :number_of_dependents + # + # validates_numericality_of :number_of_dependents, on: :create + # end + # + # # RSpec + # RSpec.describe Person, type: :model do + # it do + # should validate_numericality_of(:number_of_dependents). + # on(:create) + # end + # end + # + # # Minitest (Shoulda) + # class PersonTest < ActiveSupport::TestCase + # should validate_numericality_of(:number_of_dependents).on(:create) + # end + # # ##### only_integer # # Use `only_integer` to test usage of the `:only_integer` option. This @@ -37,11 +61,11 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it { should validate_numericality_of(:age).only_integer } # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should validate_numericality_of(:age).only_integer # end @@ -61,14 +85,14 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it do # should validate_numericality_of(:number_of_cars). # is_less_than(2) # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should validate_numericality_of(:number_of_cars). # is_less_than(2) @@ -89,14 +113,14 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it do # should validate_numericality_of(:birth_year). # is_less_than_or_equal_to(1987) # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should validate_numericality_of(:birth_year). # is_less_than_or_equal_to(1987) @@ -116,11 +140,11 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it { should validate_numericality_of(:weight).is_equal_to(150) } # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should validate_numericality_of(:weight).is_equal_to(150) # end @@ -140,14 +164,14 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it do # should validate_numericality_of(:height). # is_greater_than_or_equal_to(55) # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should validate_numericality_of(:height). # is_greater_than_or_equal_to(55) @@ -155,7 +179,7 @@ # # ##### is_greater_than # - # Use `is_greater_than` to test usage of tthe `:greater_than` option. + # Use `is_greater_than` to test usage of the `:greater_than` option. # This asserts that the attribute can take a number which is greater than # the given value and cannot take a number less than or equal to it. # @@ -167,14 +191,14 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it do # should validate_numericality_of(:legal_age). # is_greater_than(21) # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should validate_numericality_of(:legal_age). # is_greater_than(21) @@ -193,11 +217,11 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it { should validate_numericality_of(:birth_month).even } # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should validate_numericality_of(:birth_month).even # end @@ -216,11 +240,11 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it { should validate_numericality_of(:birth_day).odd } # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should validate_numericality_of(:birth_day).odd # end @@ -238,14 +262,14 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it do # should validate_numericality_of(:number_of_dependents). # with_message('Number of dependents must be a number') # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should validate_numericality_of(:number_of_dependents). # with_message('Number of dependents must be a number') @@ -255,7 +279,7 @@ # # Use `allow_nil` to assert that the attribute allows nil. # - # class Age + # class Post # include ActiveModel::Model # attr_accessor :age # @@ -263,11 +287,11 @@ # end # # # RSpec - # describe Post do + # RSpec.describe Post, type: :model do # it { should validate_numericality_of(:age).allow_nil } # end # - # # Test::Unit + # # Minitest (Shoulda) # class PostTest < ActiveSupport::TestCase # should validate_numericality_of(:age).allow_nil # end @@ -280,27 +304,46 @@ # @private class ValidateNumericalityOfMatcher - NUMERIC_NAME = 'numbers' + NUMERIC_NAME = 'number' NON_NUMERIC_VALUE = 'abcd' DEFAULT_DIFF_TO_COMPARE = 1 + include Qualifiers::IgnoringInterferenceByWriter + attr_reader :diff_to_compare def initialize(attribute) + super @attribute = attribute @submatchers = [] @diff_to_compare = DEFAULT_DIFF_TO_COMPARE - add_disallow_value_matcher + @expects_custom_validation_message = false + @expects_to_allow_nil = false + @expects_strict = false + @allowed_type_adjective = nil + @allowed_type_name = 'number' + @context = nil + @expected_message = nil + end + + def strict + @expects_strict = true + self + end + + def expects_strict? + @expects_strict end def only_integer prepare_submatcher( - NumericalityMatchers::OnlyIntegerMatcher.new(@attribute) + NumericalityMatchers::OnlyIntegerMatcher.new(self, @attribute) ) self end def allow_nil + @expects_to_allow_nil = true prepare_submatcher( AllowValueMatcher.new(nil) .for(@attribute) @@ -309,16 +352,20 @@ self end + def expects_to_allow_nil? + @expects_to_allow_nil + end + def odd prepare_submatcher( - NumericalityMatchers::OddNumberMatcher.new(@attribute) + NumericalityMatchers::OddNumberMatcher.new(self, @attribute) ) self end def even prepare_submatcher( - NumericalityMatchers::EvenNumberMatcher.new(@attribute) + NumericalityMatchers::EvenNumberMatcher.new(self, @attribute) ) self end @@ -349,33 +396,109 @@ end def with_message(message) - @submatchers.each { |matcher| matcher.with_message(message) } + @expects_custom_validation_message = true + @expected_message = message + self + end + + def expects_custom_validation_message? + @expects_custom_validation_message + end + + def on(context) + @context = context self end def matches?(subject) - @subject = subject - failing_submatchers.empty? + matches_or_does_not_match?(subject) + first_submatcher_that_fails_to_match.nil? + end + + def does_not_match?(subject) + matches_or_does_not_match?(subject) + first_submatcher_that_fails_to_not_match.nil? + end + + def simple_description + description = '' + + description << "validate that :#{@attribute} looks like " + description << Shoulda::Matchers::Util.a_or_an(full_allowed_type) + + if comparison_descriptions.present? + description << ' ' + comparison_descriptions + end + + description end def description - "only allow #{allowed_types} for #{@attribute}#{comparison_descriptions}" + ValidationMatcher::BuildDescription.call(self, simple_description) end def failure_message - last_failing_submatcher.failure_message + overall_failure_message.dup.tap do |message| + message << "\n" + message << failure_message_for_first_submatcher_that_fails_to_match + end end - alias failure_message_for_should failure_message def failure_message_when_negated - last_failing_submatcher.failure_message_when_negated + overall_failure_message_when_negated.dup.tap do |message| + message << "\n" + message << failure_message_for_first_submatcher_that_fails_to_not_match + end + end + + def given_numeric_column? + attribute_is_active_record_column? && + [:integer, :float, :decimal].include?(column_type) end - alias failure_message_for_should_not failure_message_when_negated private + def matches_or_does_not_match?(subject) + @subject = subject + @number_of_submatchers = @submatchers.size + + add_disallow_value_matcher + qualify_submatchers + end + + def overall_failure_message + Shoulda::Matchers.word_wrap( + "Expected #{model.name} to #{description}, but this could not " + + 'be proved.' + ) + end + + def overall_failure_message_when_negated + Shoulda::Matchers.word_wrap( + "Expected #{model.name} not to #{description}, but this could not " + + 'be proved.' + ) + end + + def attribute_is_active_record_column? + columns_hash.key?(@attribute.to_s) + end + + def column_type + columns_hash[@attribute.to_s].type + end + + def columns_hash + if @subject.class.respond_to?(:columns_hash) + @subject.class.columns_hash + else + {} + end + end + def add_disallow_value_matcher - disallow_value_matcher = DisallowValueMatcher.new(NON_NUMERIC_VALUE). + disallow_value_matcher = DisallowValueMatcher. + new(NON_NUMERIC_VALUE). for(@attribute). with_message(:not_a_number) @@ -384,54 +507,120 @@ def prepare_submatcher(submatcher) add_submatcher(submatcher) - if submatcher.respond_to?(:diff_to_compare) - update_diff_to_compare(submatcher) - end + submatcher end def comparison_matcher_for(value, operator) - NumericalityMatchers::ComparisonMatcher - .new(self, value, operator) - .for(@attribute) + NumericalityMatchers::ComparisonMatcher. + new(self, value, operator). + for(@attribute) end def add_submatcher(submatcher) + if submatcher.respond_to?(:allowed_type_name) + @allowed_type_name = submatcher.allowed_type_name + end + + if submatcher.respond_to?(:allowed_type_adjective) + @allowed_type_adjective = submatcher.allowed_type_adjective + end + + if submatcher.respond_to?(:diff_to_compare) + @diff_to_compare = [@diff_to_compare, submatcher.diff_to_compare].max + end + @submatchers << submatcher end - def update_diff_to_compare(matcher) - @diff_to_compare = [@diff_to_compare, matcher.diff_to_compare].max - end + def qualify_submatchers + @submatchers.each do |submatcher| + if @expects_strict + submatcher.strict(@expects_strict) + end + + if @expected_message.present? + submatcher.with_message(@expected_message) + end - def submatchers_and_results - @_submatchers_and_results ||= - @submatchers.map do |matcher| - { matcher: matcher, matched: matcher.matches?(@subject) } + if @context + submatcher.on(@context) end + + submatcher.ignoring_interference_by_writer( + ignore_interference_by_writer + ) + end + end + + def number_of_submatchers_for_failure_message + if has_been_qualified? + @submatchers.size - 1 + else + @submatchers.size + end end - def failing_submatchers - submatchers_and_results. - select { |x| !x[:matched] }. - map { |x| x[:matcher] } + def has_been_qualified? + @submatchers.any? do |submatcher| + Shoulda::Matchers::RailsShim.parent_of(submatcher.class) == + NumericalityMatchers + end end - def last_failing_submatcher - failing_submatchers.last + def first_submatcher_that_fails_to_match + @_failing_submatchers ||= @submatchers.detect do |submatcher| + !submatcher.matches?(@subject) + end end - def allowed_types - allowed_array = submatcher_allowed_types - allowed_array.empty? ? NUMERIC_NAME : allowed_array.join(', ') + def first_submatcher_that_fails_to_not_match + @_failing_submatchers ||= @submatchers.detect do |submatcher| + !submatcher.does_not_match?(@subject) + end end - def submatcher_allowed_types - @submatchers.inject([]){|m, s| m << s.allowed_type if s.respond_to?(:allowed_type); m } + def failure_message_for_first_submatcher_that_fails_to_match + build_submatcher_failure_message_for( + first_submatcher_that_fails_to_match, + :failure_message + ) + end + + def failure_message_for_first_submatcher_that_fails_to_not_match + build_submatcher_failure_message_for( + first_submatcher_that_fails_to_not_match, + :failure_message_when_negated + ) + end + + def build_submatcher_failure_message_for( + submatcher, + failure_message_method + ) + failure_message = submatcher.public_send(failure_message_method) + submatcher_description = submatcher.simple_description. + sub(/\bvalidate that\b/, 'validates'). + sub(/\bdisallow\b/, 'disallows'). + sub(/\ballow\b/, 'allows') + submatcher_message = + if number_of_submatchers_for_failure_message > 1 + "In checking that #{model.name} #{submatcher_description}, " + + failure_message[0].downcase + + failure_message[1..-1] + else + failure_message + end + + Shoulda::Matchers.word_wrap(submatcher_message, indent: 2) + end + + def full_allowed_type + "#{@allowed_type_adjective} #{@allowed_type_name}".strip end def comparison_descriptions description_array = submatcher_comparison_descriptions - description_array.empty? ? '' : ' which are ' + submatcher_comparison_descriptions.join(' and ') + description_array.empty? ? '' : submatcher_comparison_descriptions.join(' and ') end def submatcher_comparison_descriptions @@ -442,6 +631,10 @@ arr end end + + def model + @subject.class + end end end end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb 2020-02-18 07:23:52.000000000 +0000 @@ -12,11 +12,11 @@ # end # # # RSpec - # describe Robot do + # RSpec.describe Robot, type: :model do # it { should validate_presence_of(:arms) } # end # - # # Test::Unit + # # Minitest (Shoulda) # class RobotTest < ActiveSupport::TestCase # should validate_presence_of(:arms) # end @@ -36,7 +36,7 @@ # validates_presence_of :password # end # - # describe User do + # RSpec.describe User, type: :model do # subject { User.new(password: '123456') } # # it { should validate_presence_of(:password) } @@ -57,6 +57,27 @@ # # #### Qualifiers # + # ##### allow_nil + # + # Use `allow_nil` if your model has an optional attribute. + # + # class Robot + # include ActiveModel::Model + # attr_accessor :nickname + # + # validates_presence_of :nickname, allow_nil: true + # end + # + # # RSpec + # RSpec.describe Robot, type: :model do + # it { should validate_presence_of(:nickname).allow_nil } + # end + # + # # Minitest (Shoulda) + # class RobotTest < ActiveSupport::TestCase + # should validate_presence_of(:nickname).allow_nil + # end + # # ##### on # # Use `on` if your validation applies only under a certain context. @@ -69,11 +90,11 @@ # end # # # RSpec - # describe Robot do + # RSpec.describe Robot, type: :model do # it { should validate_presence_of(:arms).on(:create) } # end # - # # Test::Unit + # # Minitest (Shoulda) # class RobotTest < ActiveSupport::TestCase # should validate_presence_of(:arms).on(:create) # end @@ -90,14 +111,14 @@ # end # # # RSpec - # describe Robot do + # RSpec.describe Robot, type: :model do # it do # should validate_presence_of(:legs). # with_message('Robot has no legs') # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class RobotTest < ActiveSupport::TestCase # should validate_presence_of(:legs). # with_message('Robot has no legs') @@ -111,67 +132,244 @@ # @private class ValidatePresenceOfMatcher < ValidationMatcher - def with_message(message) - @expected_message = message if message - self + include Qualifiers::AllowNil + + def initialize(attribute) + super + @expected_message = :blank end def matches?(subject) super(subject) - @expected_message ||= :blank + + possibly_ignore_interference_by_writer + + if secure_password_being_validated? + ignore_interference_by_writer.default_to(when: :blank?) + + disallowed_values.all? do |value| + disallows_and_double_checks_value_of!(value) + end + else + (!expects_to_allow_nil? || allows_value_of(nil)) && + disallowed_values.all? do |value| + disallows_original_or_typecast_value?(value) + end + end + end + + def does_not_match?(subject) + super(subject) + + possibly_ignore_interference_by_writer if secure_password_being_validated? - disallows_and_double_checks_value_of!(blank_value, @expected_message) + ignore_interference_by_writer.default_to(when: :blank?) + + disallowed_values.any? do |value| + allows_and_double_checks_value_of!(value) + end else - disallows_value_of(blank_value, @expected_message) + (expects_to_allow_nil? && disallows_value_of(nil)) || + disallowed_values.any? do |value| + allows_original_or_typecast_value?(value) + end end end - def description - "require #{@attribute} to be set" + def simple_description + "validate that :#{@attribute} cannot be empty/falsy" + end + + def failure_message + message = super + + if should_add_footnote_about_belongs_to? + message << "\n\n" + message << Shoulda::Matchers.word_wrap(<<-MESSAGE.strip, indent: 2) +You're getting this error because #{reason_for_existing_presence_validation}. +*This* presence validation doesn't use "can't be blank", the usual validation +message, but "must exist" instead. + +With that said, did you know that the `belong_to` matcher can test this +validation for you? Instead of using `validate_presence_of`, try +#{suggestions_for_belongs_to} + MESSAGE + end + + message end private def secure_password_being_validated? - defined?(::ActiveModel::SecurePassword) && - @subject.class.ancestors.include?(::ActiveModel::SecurePassword::InstanceMethodsOnActivation) && - @attribute == :password + Shoulda::Matchers::RailsShim.digestible_attributes_in(@subject). + include?(@attribute) end - def disallows_and_double_checks_value_of!(value, message) - error_class = Shoulda::Matchers::ActiveModel::CouldNotSetPasswordError + def possibly_ignore_interference_by_writer + if secure_password_being_validated? + ignore_interference_by_writer.default_to(when: :blank?) + end + end - disallows_value_of(value, message) do |matcher| - matcher._after_setting_value do - actual_value = @subject.__send__(@attribute) + def allows_and_double_checks_value_of!(value) + allows_value_of(value, @expected_message) + rescue ActiveModel::AllowValueMatcher::AttributeChangedValueError + raise ActiveModel::CouldNotSetPasswordError.create(model) + end - if !actual_value.nil? - raise error_class.create(@subject.class) - end + def allows_original_or_typecast_value?(value) + allows_value_of(value, @expected_message) + end + + def disallows_and_double_checks_value_of!(value) + disallows_value_of(value, @expected_message) + rescue ActiveModel::AllowValueMatcher::AttributeChangedValueError + raise ActiveModel::CouldNotSetPasswordError.create(model) + end + + def disallows_original_or_typecast_value?(value) + disallows_value_of(value, @expected_message) + end + + def disallowed_values + if collection_association? + [Array.new] + elsif attachment? + [nil] + else + values = [] + + if attribute_accepts_string_values? + values << '' + end + + if !expects_to_allow_nil? + values << nil end + + values + end + end + + def should_add_footnote_about_belongs_to? + belongs_to_association_being_validated? && + presence_validation_exists_on_attribute? + end + + def reason_for_existing_presence_validation + if belongs_to_association_configured_to_be_required? + "you've instructed your `belongs_to` association to add a " + + 'presence validation to the attribute' + else + # assume ::ActiveRecord::Base.belongs_to_required_by_default == true + 'ActiveRecord is configured to add a presence validation to all ' + + '`belongs_to` associations, and this includes yours' end end - def blank_value - if collection? - [] + def suggestions_for_belongs_to + if belongs_to_association_configured_to_be_required? + <<~MESSAGE + one of the following instead, depending on your use case: + + #{example_of_belongs_to(with: [:optional, false])} + #{example_of_belongs_to(with: [:required, true])} + MESSAGE else - nil + <<~MESSAGE + the following instead: + + #{example_of_belongs_to} + MESSAGE end end - def collection? - if reflection - [:has_many, :has_and_belongs_to_many].include?(reflection.macro) + def example_of_belongs_to(with: nil) + initial_call = "should belong_to(:#{association_name})" + inside = + if with + "#{initial_call}.#{with.first}(#{with.second})" + else + initial_call + end + + if Shoulda::Matchers.integrations.test_frameworks.any?(&:n_unit?) + inside else + "it { #{inside} }" + end + end + + def belongs_to_association_configured_to_be_required? + association_options[:optional] == false || + association_options[:required] == true + end + + def belongs_to_association_being_validated? + association? && association_reflection.macro == :belongs_to + end + + def attribute_accepts_string_values? + if association? false + elsif attribute_serialization_coder.respond_to?(:object_class) + attribute_serialization_coder.object_class == String + else + RailsShim.supports_full_attributes_api?(model) && + attribute_type.try(:type) == :string end end - def reflection - @subject.class.respond_to?(:reflect_on_association) && - @subject.class.reflect_on_association(@attribute) + def association? + association_reflection.present? + end + + def collection_association? + association? && association_reflection.macro.in?( + [:has_many, :has_and_belongs_to_many], + ) + end + + def attachment? + model_has_associations?( + ["#{@attribute}_attachment", "#{@attribute}_attachments"], + ) + end + + def association_name + association_reflection.name + end + + def association_options + association_reflection&.options + end + + def association_reflection + model.try(:reflect_on_association, @attribute) + end + + def model_has_associations?(associations) + associations.any? do |association| + !!model.try(:reflect_on_association, association) + end + end + + def attribute_serialization_coder + RailsShim.attribute_serialization_coder_for(model, @attribute) + end + + def attribute_type + RailsShim.attribute_type_for(model, @attribute) + end + + def presence_validation_exists_on_attribute? + model._validators.include?(@attribute) + end + + def model + @subject.class end end end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/validation_matcher/build_description.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/validation_matcher/build_description.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/validation_matcher/build_description.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/validation_matcher/build_description.rb 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,65 @@ +module Shoulda + module Matchers + module ActiveModel + class ValidationMatcher + # @private + class BuildDescription + def self.call(matcher, main_description) + new(matcher, main_description).call + end + + def initialize(matcher, main_description) + @matcher = matcher + @main_description = main_description + end + + def call + if description_clauses_for_qualifiers.any? + main_description + + clause_for_allow_blank_or_nil + + ', ' + + description_clauses_for_qualifiers.to_sentence + else + main_description + clause_for_allow_blank_or_nil + end + end + + protected + + attr_reader :matcher, :main_description + + private + + def clause_for_allow_blank_or_nil + if matcher.try(:expects_to_allow_blank?) + ' as long as it is not blank' + elsif matcher.try(:expects_to_allow_nil?) + ' as long as it is not nil' + else + '' + end + end + + def description_clauses_for_qualifiers + description_clauses = [] + + if matcher.try(:expects_strict?) + description_clauses << 'raising a validation exception' + + if matcher.try(:expects_custom_validation_message?) + description_clauses.last << ' with a custom message' + end + + description_clauses.last << ' on failure' + elsif matcher.try(:expects_custom_validation_message?) + description_clauses << + 'producing a custom validation error on failure' + end + + description_clauses + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/validation_matcher.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/validation_matcher.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/validation_matcher.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/validation_matcher.rb 2020-02-18 07:23:52.000000000 +0000 @@ -3,15 +3,20 @@ module ActiveModel # @private class ValidationMatcher - attr_reader :failure_message - - alias failure_message_for_should failure_message + include Qualifiers::IgnoringInterferenceByWriter def initialize(attribute) + super @attribute = attribute - @strict = false - @failure_message = nil - @failure_message_when_negated = nil + @expects_strict = false + @subject = nil + @last_submatcher_run = nil + @expected_message = nil + @expects_custom_validation_message = false + end + + def description + ValidationMatcher::BuildDescription.call(self, simple_description) end def on(context) @@ -20,80 +25,141 @@ end def strict - @strict = true + @expects_strict = true self end - def failure_message_when_negated - @failure_message_when_negated || @failure_message + def expects_strict? + @expects_strict + end + + def with_message(expected_message) + if expected_message + @expects_custom_validation_message = true + @expected_message = expected_message + end + + self + end + + def expects_custom_validation_message? + @expects_custom_validation_message end - alias failure_message_for_should_not failure_message_when_negated def matches?(subject) @subject = subject false end - private + def does_not_match?(subject) + @subject = subject + true + end - def allows_value_of(value, message = nil, &block) - allow = allow_value_matcher(value, message) - yield allow if block_given? + def failure_message + overall_failure_message.dup.tap do |message| + if failure_reason.present? + message << "\n" + message << Shoulda::Matchers.word_wrap( + failure_reason, + indent: 2 + ) + end + end + end - if allow.matches?(@subject) - @failure_message_when_negated = allow.failure_message_when_negated - true - else - @failure_message = allow.failure_message - false + def failure_message_when_negated + overall_failure_message_when_negated.dup.tap do |message| + if failure_reason.present? + message << "\n" + message << Shoulda::Matchers.word_wrap( + failure_reason, + indent: 2 + ) + end end end + protected + + attr_reader :attribute, :context, :subject, :last_submatcher_run + + def model + subject.class + end + + def allows_value_of(value, message = nil, &block) + matcher = allow_value_matcher(value, message, &block) + run_allow_or_disallow_matcher(matcher) + end + def disallows_value_of(value, message = nil, &block) - disallow = disallow_value_matcher(value, message) - yield disallow if block_given? + matcher = disallow_value_matcher(value, message, &block) + run_allow_or_disallow_matcher(matcher) + end - if disallow.matches?(@subject) - @failure_message_when_negated = disallow.failure_message_when_negated - true - else - @failure_message = disallow.failure_message - false - end + def allow_value_matcher(value, message = nil, &block) + build_allow_or_disallow_value_matcher( + matcher_class: AllowValueMatcher, + value: value, + message: message, + &block + ) + end + + def disallow_value_matcher(value, message = nil, &block) + build_allow_or_disallow_value_matcher( + matcher_class: DisallowValueMatcher, + value: value, + message: message, + &block + ) end - def allow_value_matcher(value, message) - matcher = AllowValueMatcher.new(value).for(@attribute). - with_message(message) + private + + def overall_failure_message + Shoulda::Matchers.word_wrap( + "Expected #{model.name} to #{description}, but this could not be " + + 'proved.' + ) + end - if defined?(@context) - matcher.on(@context) - end + def overall_failure_message_when_negated + Shoulda::Matchers.word_wrap( + "Expected #{model.name} not to #{description}, but this could " + + 'not be proved.' + ) + end - if strict? - matcher.strict - end + def failure_reason + last_submatcher_run.try(:failure_message) + end - matcher + def failure_reason_when_negated + last_submatcher_run.try(:failure_message_when_negated) end - def disallow_value_matcher(value, message) - matcher = DisallowValueMatcher.new(value).for(@attribute). - with_message(message) + def build_allow_or_disallow_value_matcher(args) + matcher_class = args.fetch(:matcher_class) + value = args.fetch(:value) + message = args[:message] - if defined?(@context) - matcher.on(@context) - end + matcher = matcher_class.new(value). + for(attribute). + with_message(message). + on(context). + strict(expects_strict?). + ignoring_interference_by_writer(ignore_interference_by_writer) - if strict? - matcher.strict - end + yield matcher if block_given? matcher end - def strict? - @strict + def run_allow_or_disallow_matcher(matcher) + @last_submatcher_run = matcher + matcher.matches?(subject) end end end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/validation_message_finder.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/validation_message_finder.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/validation_message_finder.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/validation_message_finder.rb 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,65 @@ +module Shoulda + module Matchers + module ActiveModel + # @private + class ValidationMessageFinder + include Helpers + + def initialize(instance, attribute, context=nil) + @instance = instance + @attribute = attribute + @context = context + end + + def allow_description(allowed_values) + "allow #{@attribute} to be set to #{allowed_values}" + end + + def expected_message_from(attribute_message) + attribute_message + end + + def has_messages? + errors.present? + end + + def source_description + 'errors' + end + + def messages_description + if errors.empty? + ' no errors' + else + " errors:\n#{pretty_error_messages(validated_instance)}" + end + end + + def messages + Array(messages_for_attribute) + end + + private + + def messages_for_attribute + errors[@attribute] + end + + def errors + validated_instance.errors + end + + def validated_instance + @validated_instance ||= validate_instance + end + + def validate_instance + @instance.valid?(*@context) + @instance + end + end + + end + end +end + diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/validator.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/validator.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/validator.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/validator.rb 2020-02-18 07:23:52.000000000 +0000 @@ -5,107 +5,118 @@ class Validator include Helpers - attr_writer :attribute, :context, :record - - def initialize - reset + def initialize(record, attribute, options = {}) + @record = record + @attribute = attribute + @context = options[:context] + @expects_strict = options[:expects_strict] + @expected_message = options[:expected_message] + + @_validation_result = nil + @captured_validation_exception = false + @captured_range_error = false end - def reset - @messages = nil + def call + !messages_match? && !captured_range_error? end - def strict=(strict) - @strict = strict - - if strict - extend StrictValidator - end + def has_messages? + messages.any? end - def capture_range_error(exception) - @captured_range_error = exception - extend ValidatorWithCapturedRangeError + def captured_validation_exception? + @captured_validation_exception end - def allow_description(allowed_values) - "allow #{attribute} to be set to #{allowed_values}" + def type_of_message_matched? + expects_strict? == captured_validation_exception? end - def expected_message_from(attribute_message) - attribute_message + def all_formatted_validation_error_messages + format_validation_errors(all_validation_errors) end - def messages - @messages ||= collect_messages + def validation_exception_message + validation_result[:validation_exception_message] end - def formatted_messages - messages + protected + + attr_reader :attribute, :context, :record + + private + + def expects_strict? + @expects_strict end - def has_messages? - messages.any? + def messages_match? + has_messages? && + type_of_message_matched? && + matched_messages.compact.any? end - def messages_description - if has_messages? - " errors:\n#{pretty_error_messages(record)}" + def messages + if expects_strict? + [validation_exception_message] else - ' no errors' + validation_error_messages end end - def expected_messages_description(expected_message) - if expected_message - "errors to include #{expected_message.inspect}" + def matched_messages + if @expected_message + messages.grep(@expected_message) else - 'errors' + messages end end def captured_range_error? - !!captured_range_error + !!@captured_range_error end - protected - - attr_reader :attribute, :context, :strict, :record, - :captured_range_error - - def collect_messages - validation_errors + def all_validation_errors + validation_result[:all_validation_errors] end - private - - def strict? - !!@strict + def validation_error_messages + validation_result[:validation_error_messages] end - def collect_errors_or_exceptions - collect_messages - rescue RangeError => exception - capture_range_error(exception) - [] + def validation_result + @_validation_result ||= perform_validation end - def validation_errors + def perform_validation if context record.valid?(context) else record.valid? end - if record.errors.respond_to?(:[]) - record.errors[attribute] - else - record.errors.on(attribute) - end - end + all_validation_errors = record.errors.dup - def human_attribute_name - record.class.human_attribute_name(attribute) + validation_error_messages = + if record.errors.respond_to?(:[]) + record.errors[attribute] + else + record.errors.on(attribute) + end + + { + all_validation_errors: all_validation_errors, + validation_error_messages: validation_error_messages, + validation_exception_message: nil + } + rescue ::ActiveModel::StrictValidationFailed => exception + @captured_validation_exception = true + { + all_validation_errors: nil, + validation_error_messages: [], + validation_exception_message: exception.message + } end end end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/validator_with_captured_range_error.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/validator_with_captured_range_error.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/validator_with_captured_range_error.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model/validator_with_captured_range_error.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,12 +0,0 @@ -module Shoulda - module Matchers - module ActiveModel - # @private - module ValidatorWithCapturedRangeError - def messages_description - ' RangeError: ' + captured_range_error.message.inspect - end - end - end - end -end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_model.rb 2020-02-18 07:23:52.000000000 +0000 @@ -1,9 +1,17 @@ require 'shoulda/matchers/active_model/helpers' +require 'shoulda/matchers/active_model/qualifiers' require 'shoulda/matchers/active_model/validation_matcher' +require 'shoulda/matchers/active_model/validation_matcher/build_description' require 'shoulda/matchers/active_model/validator' -require 'shoulda/matchers/active_model/strict_validator' -require 'shoulda/matchers/active_model/validator_with_captured_range_error' require 'shoulda/matchers/active_model/allow_value_matcher' +require 'shoulda/matchers/active_model/allow_value_matcher/attribute_changed_value_error' +require 'shoulda/matchers/active_model/allow_value_matcher/attribute_does_not_exist_error' +require 'shoulda/matchers/active_model/allow_value_matcher/attribute_setter' +require 'shoulda/matchers/active_model/allow_value_matcher/attribute_setter_and_validator' +require 'shoulda/matchers/active_model/allow_value_matcher/attribute_setters' +require 'shoulda/matchers/active_model/allow_value_matcher/attribute_setters_and_validators' +require 'shoulda/matchers/active_model/allow_value_matcher/successful_check' +require 'shoulda/matchers/active_model/allow_value_matcher/successful_setting' require 'shoulda/matchers/active_model/disallow_value_matcher' require 'shoulda/matchers/active_model/validate_length_of_matcher' require 'shoulda/matchers/active_model/validate_inclusion_of_matcher' @@ -24,6 +32,62 @@ module Shoulda module Matchers + # This module provides matchers that are used to test behavior within + # ActiveModel or ActiveRecord classes. + # + # ### Testing conditional validations + # + # If your model defines a validation conditionally -- meaning that the + # validation is declared with an `:if` or `:unless` option -- how do you + # test it? You might expect the validation matchers here to have + # corresponding `if` or `unless` qualifiers, but this isn't what you use. + # Instead, before using the matcher in question, you place the record + # you're testing in a state such that the validation you're also testing + # will be run. A common way to do this is to make a new `context` and + # override the subject to populate the record accordingly. You'll also want + # to make sure to test that the validation is *not* run when the + # conditional fails. + # + # Here's an example to illustrate what we mean: + # + # class User + # include ActiveModel::Model + # + # attr_accessor :role, :admin + # + # validates_presence_of :role, if: :admin + # end + # + # # RSpec + # RSpec.describe User, type: :model do + # context "when an admin" do + # subject { User.new(admin: true) } + # + # it { should validate_presence_of(:role) } + # end + # + # context "when not an admin" do + # subject { User.new(admin: false) } + # + # it { should_not validate_presence_of(:role) } + # end + # end + # + # # Minitest (Shoulda) + # class UserTest < ActiveSupport::TestCase + # context "when an admin" do + # subject { User.new(admin: true) } + # + # should validate_presence_of(:role) + # end + # + # context "when not an admin" do + # subject { User.new(admin: false) } + # + # should_not validate_presence_of(:role) + # end + # end + # module ActiveModel end end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb 2020-02-18 07:23:52.000000000 +0000 @@ -9,11 +9,11 @@ # end # # # RSpec - # describe Car do + # RSpec.describe Car, type: :model do # it { should accept_nested_attributes_for(:doors) } # end # - # # Test::Unit (using Shoulda) + # # Minitest (Shoulda) (using Shoulda) # class CarTest < ActiveSupport::TestCase # should accept_nested_attributes_for(:doors) # end @@ -30,14 +30,14 @@ # end # # # RSpec - # describe Car do + # RSpec.describe Car, type: :model do # it do # should accept_nested_attributes_for(:mirrors). # allow_destroy(true) # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class CarTest < ActiveSupport::TestCase # should accept_nested_attributes_for(:mirrors). # allow_destroy(true) @@ -52,14 +52,14 @@ # end # # # RSpec - # describe Car do + # RSpec.describe Car, type: :model do # it do # should accept_nested_attributes_for(:windows). # limit(3) # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class CarTest < ActiveSupport::TestCase # should accept_nested_attributes_for(:windows). # limit(3) @@ -75,14 +75,14 @@ # end # # # RSpec - # describe Car do + # RSpec.describe Car, type: :model do # it do # should accept_nested_attributes_for(:engine). # update_only(true) # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class CarTest < ActiveSupport::TestCase # should accept_nested_attributes_for(:engine). # update_only(true) @@ -127,12 +127,10 @@ def failure_message "Expected #{expectation} (#{@problem})" end - alias failure_message_for_should failure_message def failure_message_when_negated "Did not expect #{expectation}" end - alias failure_message_for_should_not failure_message_when_negated def description description = "accepts_nested_attributes_for :#{@name}" diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/association_matcher.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_record/association_matcher.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/association_matcher.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_record/association_matcher.rb 2020-02-18 07:23:52.000000000 +0000 @@ -11,11 +11,11 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it { should belong_to(:organization) } # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should belong_to(:organization) # end @@ -28,11 +28,11 @@ # end # # # RSpec - # describe Comment do + # RSpec.describe Comment, type: :model do # it { should belong_to(:commentable) } # end # - # # Test::Unit + # # Minitest (Shoulda) # class CommentTest < ActiveSupport::TestCase # should belong_to(:commentable) # end @@ -49,14 +49,14 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it do # should belong_to(:family). # conditions(everyone_is_perfect: false) # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should belong_to(:family). # conditions(everyone_is_perfect: false) @@ -72,11 +72,11 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it { should belong_to(:previous_company).order('hired_on desc') } # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should belong_to(:previous_company).order('hired_on desc') # end @@ -91,11 +91,11 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it { should belong_to(:ancient_city).class_name('City') } # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should belong_to(:ancient_city).class_name('City') # end @@ -109,14 +109,14 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it do # should belong_to(:great_country). # with_primary_key('country_id') # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should belong_to(:great_country). # with_primary_key('country_id') @@ -131,14 +131,14 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it do # should belong_to(:great_country). # with_foreign_key('country_id') # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should belong_to(:great_country). # with_foreign_key('country_id') @@ -153,11 +153,11 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it { should belong_to(:world).dependent(:destroy) } # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should belong_to(:world).dependent(:destroy) # end @@ -165,7 +165,7 @@ # To assert that *any* `:dependent` option was specified, use `true`: # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it { should belong_to(:world).dependent(true) } # end # @@ -176,7 +176,7 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it { should belong_to(:company).dependent(false) } # end # @@ -190,11 +190,11 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it { should belong_to(:organization).counter_cache(true) } # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should belong_to(:organization).counter_cache(true) # end @@ -208,16 +208,16 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it { should belong_to(:organization).touch(true) } # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should belong_to(:organization).touch(true) # end # - # #### autosave + # ##### autosave # # Use `autosave` to assert that the `:autosave` option was specified. # @@ -226,11 +226,11 @@ # end # # # RSpec - # describe Account do + # RSpec.describe Account, type: :model do # it { should belong_to(:bank).autosave(true) } # end # - # # Test::Unit + # # Minitest (Shoulda) # class AccountTest < ActiveSupport::TestCase # should belong_to(:bank).autosave(true) # end @@ -248,11 +248,78 @@ # it { should belong_to(:organization).inverse_of(:employees) } # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should belong_to(:organization).inverse_of(:employees) # end # + # ##### required + # + # Use `required` to assert that the association is not allowed to be nil. + # (Enabled by default in Rails 5+.) + # + # class Person < ActiveRecord::Base + # belongs_to :organization, required: true + # end + # + # # RSpec + # describe Person + # it { should belong_to(:organization).required } + # end + # + # # Minitest (Shoulda) + # class PersonTest < ActiveSupport::TestCase + # should belong_to(:organization).required + # end + # + # ##### without_validating_presence + # + # Use `without_validating_presence` with `belong_to` to prevent the + # matcher from checking whether the association disallows nil (Rails 5+ + # only). This can be helpful if you have a custom hook that always sets + # the association to a meaningful value: + # + # class Person < ActiveRecord::Base + # belongs_to :organization + # + # before_validation :autoassign_organization + # + # private + # + # def autoassign_organization + # self.organization = Organization.create! + # end + # end + # + # # RSpec + # describe Person + # it { should belong_to(:organization).without_validating_presence } + # end + # + # # Minitest (Shoulda) + # class PersonTest < ActiveSupport::TestCase + # should belong_to(:organization).without_validating_presence + # end + # + # ##### optional + # + # Use `optional` to assert that the association is allowed to be nil. + # (Rails 5+ only.) + # + # class Person < ActiveRecord::Base + # belongs_to :organization, optional: true + # end + # + # # RSpec + # describe Person + # it { should belong_to(:organization).optional } + # end + # + # # Minitest (Shoulda) + # class PersonTest < ActiveSupport::TestCase + # should belong_to(:organization).optional + # end + # # @return [AssociationMatcher] # def belong_to(name) @@ -267,15 +334,32 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it { should have_many(:friends) } # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should have_many(:friends) # end # + # Note that polymorphic associations are automatically detected and do not + # need any qualifiers: + # + # class Person < ActiveRecord::Base + # has_many :pictures, as: :imageable + # end + # + # # RSpec + # RSpec.describe Person, type: :model do + # it { should have_many(:pictures) } + # end + # + # # Minitest (Shoulda) + # class PersonTest < ActiveSupport::TestCase + # should have_many(:pictures) + # end + # # #### Qualifiers # # ##### conditions @@ -288,11 +372,11 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it { should have_many(:coins).conditions(quality: 'mint') } # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should have_many(:coins).conditions(quality: 'mint') # end @@ -307,11 +391,11 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it { should have_many(:shirts).order('color') } # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should have_many(:shirts).order('color') # end @@ -326,11 +410,11 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it { should have_many(:hopes).class_name('Dream') } # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should have_many(:hopes).class_name('Dream') # end @@ -344,11 +428,11 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it { should have_many(:worries).with_primary_key('worrier_id') } # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should have_many(:worries).with_primary_key('worrier_id') # end @@ -362,11 +446,11 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it { should have_many(:worries).with_foreign_key('worrier_id') } # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should have_many(:worries).with_foreign_key('worrier_id') # end @@ -380,11 +464,11 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it { should have_many(:secret_documents).dependent(:destroy) } # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should have_many(:secret_documents).dependent(:destroy) # end @@ -399,11 +483,11 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it { should have_many(:acquaintances).through(:friends) } # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should have_many(:acquaintances).through(:friends) # end @@ -418,7 +502,7 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it do # should have_many(:job_offers). # through(:friends). @@ -426,7 +510,7 @@ # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should have_many(:job_offers). # through(:friends). @@ -442,16 +526,16 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it { should have_many(:ideas).validate(false) } # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should have_many(:ideas).validate(false) # end # - # #### autosave + # ##### autosave # # Use `autosave` to assert that the `:autosave` option was specified. # @@ -460,15 +544,52 @@ # end # # # RSpec - # describe Player do + # RSpec.describe Player, type: :model do # it { should have_many(:games).autosave(true) } # end # - # # Test::Unit + # # Minitest (Shoulda) # class PlayerTest < ActiveSupport::TestCase # should have_many(:games).autosave(true) # end # + # ##### index_errors + # + # Use `index_errors` to assert that the `:index_errors` option was + # specified. + # + # class Player < ActiveRecord::Base + # has_many :games, index_errors: true + # end + # + # # RSpec + # RSpec.describe Player, type: :model do + # it { should have_many(:games).index_errors(true) } + # end + # + # # Minitest (Shoulda) + # class PlayerTest < ActiveSupport::TestCase + # should have_many(:games).index_errors(true) + # end + # + # ##### inverse_of + # + # Use `inverse_of` to assert that the `:inverse_of` option was specified. + # + # class Organization < ActiveRecord::Base + # has_many :employees, inverse_of: :company + # end + # + # # RSpec + # describe Organization + # it { should have_many(:employees).inverse_of(:company) } + # end + # + # # Minitest (Shoulda) + # class OrganizationTest < ActiveSupport::TestCase + # should have_many(:employees).inverse_of(:company) + # end + # # @return [AssociationMatcher] # def have_many(name) @@ -483,11 +604,11 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it { should have_one(:partner) } # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should have_one(:partner) # end @@ -504,11 +625,11 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it { should have_one(:pet).conditions('weight < 80') } # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should have_one(:pet).conditions('weight < 80') # end @@ -523,11 +644,11 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it { should have_one(:focus).order('priority desc') } # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should have_one(:focus).order('priority desc') # end @@ -542,11 +663,11 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it { should have_one(:chance).class_name('Opportunity') } # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should have_one(:chance).class_name('Opportunity') # end @@ -560,11 +681,11 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it { should have_one(:contract).dependent(:nullify) } # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should have_one(:contract).dependent(:nullify) # end @@ -578,11 +699,11 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it { should have_one(:job).with_primary_key('worker_id') } # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should have_one(:job).with_primary_key('worker_id') # end @@ -596,11 +717,11 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it { should have_one(:job).with_foreign_key('worker_id') } # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should have_one(:job).with_foreign_key('worker_id') # end @@ -615,11 +736,11 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it { should have_one(:life).through(:partner) } # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should have_one(:life).through(:partner) # end @@ -634,11 +755,11 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it { should have_one(:car).through(:partner).source(:vehicle) } # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should have_one(:car).through(:partner).source(:vehicle) # end @@ -652,16 +773,16 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it { should have_one(:parking_card).validate(false) } # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should have_one(:parking_card).validate(false) # end # - # #### autosave + # ##### autosave # # Use `autosave` to assert that the `:autosave` option was specified. # @@ -670,15 +791,34 @@ # end # # # RSpec - # describe Account do + # RSpec.describe Account, type: :model do # it { should have_one(:bank).autosave(true) } # end # - # # Test::Unit + # # Minitest (Shoulda) # class AccountTest < ActiveSupport::TestCase # should have_one(:bank).autosave(true) # end # + # ##### required + # + # Use `required` to assert that the association is not allowed to be nil. + # (Rails 5+ only.) + # + # class Person < ActiveRecord::Base + # has_one :brain, required: true + # end + # + # # RSpec + # describe Person + # it { should have_one(:brain).required } + # end + # + # # Minitest (Shoulda) + # class PersonTest < ActiveSupport::TestCase + # should have_one(:brain).required + # end + # # @return [AssociationMatcher] # def have_one(name) @@ -694,11 +834,11 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it { should have_and_belong_to_many(:awards) } # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should have_and_belong_to_many(:awards) # end @@ -715,14 +855,14 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it do # should have_and_belong_to_many(:issues). # conditions(difficulty: 'hard') # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should have_and_belong_to_many(:issues). # conditions(difficulty: 'hard') @@ -738,14 +878,14 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it do # should have_and_belong_to_many(:projects). # order('time_spent') # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should have_and_belong_to_many(:projects). # order('time_spent') @@ -761,19 +901,42 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it do # should have_and_belong_to_many(:places_visited). # class_name('City') # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should have_and_belong_to_many(:places_visited). # class_name('City') # end # + # ##### join_table + # + # Use `join_table` to test usage of the `:join_table` option. This + # asserts that the table you're referring to actually exists. + # + # class Person < ActiveRecord::Base + # has_and_belongs_to_many :issues, join_table: 'people_tickets' + # end + # + # # RSpec + # RSpec.describe Person, type: :model do + # it do + # should have_and_belong_to_many(:issues). + # join_table('people_tickets') + # end + # end + # + # # Minitest (Shoulda) + # class PersonTest < ActiveSupport::TestCase + # should have_and_belong_to_many(:issues). + # join_table('people_tickets') + # end + # # ##### validate # # Use `validate` to test that the `:validate` option was specified. @@ -783,20 +946,20 @@ # end # # # RSpec - # describe Person do + # RSpec.describe Person, type: :model do # it do # should have_and_belong_to_many(:interviews). # validate(false) # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class PersonTest < ActiveSupport::TestCase # should have_and_belong_to_many(:interviews). # validate(false) # end # - # #### autosave + # ##### autosave # # Use `autosave` to assert that the `:autosave` option was specified. # @@ -805,11 +968,11 @@ # end # # # RSpec - # describe Publisher do + # RSpec.describe Publisher, type: :model do # it { should have_and_belong_to_many(:advertisers).autosave(true) } # end # - # # Test::Unit + # # Minitest (Shoulda) # class AccountTest < ActiveSupport::TestCase # should have_and_belong_to_many(:advertisers).autosave(true) # end @@ -823,7 +986,9 @@ # @private class AssociationMatcher delegate :reflection, :model_class, :associated_class, :through?, - :join_table, :polymorphic?, to: :reflector + :polymorphic?, to: :reflector + + attr_reader :name, :options def initialize(macro, name) @macro = macro @@ -831,42 +996,63 @@ @options = {} @submatchers = [] @missing = '' + + if macro == :belongs_to && RailsShim.active_record_gte_5? + required(belongs_to_required_by_default?) + end end def through(through) - through_matcher = AssociationMatchers::ThroughMatcher.new(through, name) - add_submatcher(through_matcher) + add_submatcher( + AssociationMatchers::ThroughMatcher, + through, + name, + ) self end def dependent(dependent) - dependent_matcher = AssociationMatchers::DependentMatcher.new(dependent, name) - add_submatcher(dependent_matcher) + add_submatcher( + AssociationMatchers::DependentMatcher, + dependent, + name, + ) self end def order(order) - order_matcher = AssociationMatchers::OrderMatcher.new(order, name) - add_submatcher(order_matcher) + add_submatcher( + AssociationMatchers::OrderMatcher, + order, + name, + ) self end def counter_cache(counter_cache = true) - counter_cache_matcher = AssociationMatchers::CounterCacheMatcher.new(counter_cache, name) - add_submatcher(counter_cache_matcher) + add_submatcher( + AssociationMatchers::CounterCacheMatcher, + counter_cache, + name, + ) self end def inverse_of(inverse_of) - inverse_of_matcher = - AssociationMatchers::InverseOfMatcher.new(inverse_of, name) - add_submatcher(inverse_of_matcher) + add_submatcher( + AssociationMatchers::InverseOfMatcher, + inverse_of, + name, + ) self end def source(source) - source_matcher = AssociationMatchers::SourceMatcher.new(source, name) - add_submatcher(source_matcher) + add_submatcher( + AssociationMatchers::SourceMatcher, + source, + name, + ) self end @@ -880,6 +1066,11 @@ self end + def index_errors(index_errors) + @options[:index_errors] = index_errors + self + end + def class_name(class_name) @options[:class_name] = class_name self @@ -895,6 +1086,26 @@ self end + def required(required = true) + remove_submatcher(AssociationMatchers::OptionalMatcher) + add_submatcher( + AssociationMatchers::RequiredMatcher, + name, + required, + ) + self + end + + def optional(optional = true) + remove_submatcher(AssociationMatchers::RequiredMatcher) + add_submatcher( + AssociationMatchers::OptionalMatcher, + name, + optional, + ) + self + end + def validate(validate = true) @options[:validate] = validate self @@ -905,6 +1116,16 @@ self end + def join_table(join_table_name) + @options[:join_table_name] = join_table_name + self + end + + def without_validating_presence + remove_submatcher(AssociationMatchers::RequiredMatcher) + self + end + def description description = "#{macro_description} #{name}" description += " class_name => #{options[:class_name]}" if options.key?(:class_name) @@ -914,12 +1135,10 @@ def failure_message "Expected #{expectation} (#{missing_options})" end - alias failure_message_for_should failure_message def failure_message_when_negated "Did not expect #{expectation}" end - alias failure_message_for_should_not failure_message_when_negated def matches?(subject) @subject = subject @@ -931,26 +1150,38 @@ class_name_correct? && join_table_correct? && autosave_correct? && + index_errors_correct? && conditions_correct? && validate_correct? && touch_correct? && submatchers_match? end + def join_table_name + options[:join_table_name] || reflector.join_table_name + end + + def option_verifier + @option_verifier ||= AssociationMatchers::OptionVerifier.new(reflector) + end + protected - attr_reader :submatchers, :missing, :subject, :macro, :name, :options + attr_reader :submatchers, :missing, :subject, :macro def reflector @reflector ||= AssociationMatchers::ModelReflector.new(subject, name) end - def option_verifier - @option_verifier ||= AssociationMatchers::OptionVerifier.new(reflector) + def add_submatcher(matcher_class, *args) + remove_submatcher(matcher_class) + submatchers << matcher_class.new(*args) end - def add_submatcher(matcher) - @submatchers << matcher + def remove_submatcher(matcher_class) + submatchers.delete_if do |submatcher| + submatcher.is_a?(matcher_class) + end end def macro_description @@ -972,12 +1203,12 @@ def missing_options missing_options = [missing, missing_options_for_failing_submatchers] - missing_options.flatten.compact.join(', ') + missing_options.flatten.select(&:present?).join(', ') end def failing_submatchers - @failing_submatchers ||= submatchers.reject do |matcher| - matcher.matches?(subject) + @failing_submatchers ||= submatchers.select do |matcher| + !matcher.matches?(subject) end end @@ -1081,6 +1312,22 @@ end end + def index_errors_correct? + return true unless options.key?(:index_errors) + + if option_verifier.correct_for_boolean?( + :index_errors, + options[:index_errors] + ) + true + else + @missing = + "#{name} should have index_errors set to " + + "#{options[:index_errors]}" + false + end + end + def conditions_correct? if options.key?(:conditions) if option_verifier.correct_for_relation_clause?(:conditions, options[:conditions]) @@ -1115,13 +1362,11 @@ def class_has_foreign_key?(klass) if options.key?(:foreign_key) option_verifier.correct_for_string?(:foreign_key, options[:foreign_key]) + elsif column_names_for(klass).include?(foreign_key) + true else - if klass.column_names.include?(foreign_key) - true - else - @missing = "#{klass} does not have a #{foreign_key} foreign key." - false - end + @missing = "#{klass} does not have a #{foreign_key} foreign key." + false end end @@ -1149,7 +1394,7 @@ end def foreign_key_reflection - if [:has_one, :has_many].include?(macro) && reflection.options.include?(:inverse_of) + if [:has_one, :has_many].include?(macro) && reflection.options.include?(:inverse_of) && reflection.options[:inverse_of] != false associated_class.reflect_on_association(reflection.options[:inverse_of]) else reflection @@ -1159,6 +1404,16 @@ def submatchers_match? failing_submatchers.empty? end + + def column_names_for(klass) + klass.column_names + rescue ::ActiveRecord::StatementInvalid + [] + end + + def belongs_to_required_by_default? + ::ActiveRecord::Base.belongs_to_required_by_default + end end end end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/association_matchers/join_table_matcher.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_record/association_matchers/join_table_matcher.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/association_matchers/join_table_matcher.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_record/association_matchers/join_table_matcher.rb 2020-02-18 07:23:52.000000000 +0000 @@ -8,8 +8,8 @@ alias :missing_option :failure_message - delegate :model_class, :join_table, :associated_class, - to: :association_matcher + delegate :model_class, :join_table_name, :associated_class, :options, + :name, :option_verifier, to: :association_matcher delegate :connection, to: :model_class @@ -19,12 +19,26 @@ end def matches?(subject) - join_table_exists? && + join_table_option_correct? && + join_table_exists? && join_table_has_correct_columns? end + def join_table_option_correct? + if options.key?(:join_table_name) + if option_verifier.correct_for_string?(:join_table, options[:join_table_name]) + true + else + @failure_message = "#{name} should use '#{options[:join_table_name]}' for :join_table option" + false + end + else + true + end + end + def join_table_exists? - if connection.tables.include?(join_table) + if RailsShim.tables_and_views(connection).include?(join_table_name) true else @failure_message = missing_table_message @@ -60,16 +74,16 @@ end def actual_join_table_columns - connection.columns(join_table).map(&:name) + connection.columns(join_table_name).map(&:name) end def missing_table_message - "join table #{join_table} doesn't exist" + "join table #{join_table_name} doesn't exist" end def missing_columns_message missing = missing_columns.join(', ') - "join table #{join_table} missing #{column_label}: #{missing}" + "join table #{join_table_name} missing #{column_label}: #{missing}" end def column_label diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb 2020-02-18 07:23:52.000000000 +0000 @@ -24,24 +24,25 @@ reflection.options[:through] end - def join_table - join_table = + def join_table_name + join_table_name = if has_and_belongs_to_many_name_table_name has_and_belongs_to_many_name_table_name - elsif reflection.respond_to?(:join_table) - reflection.join_table else - reflection.options[:join_table] + reflection.join_table end - join_table.to_s + join_table_name.to_s end def association_relation - if reflection.respond_to?(:scope) - convert_scope_to_relation(reflection.scope) + relation = associated_class.all + + if reflection.scope + # Source: AR::Associations::AssociationScope#eval_scope + relation.instance_exec(subject, &reflection.scope) else - convert_options_to_relation(reflection.options) + relation end end @@ -68,37 +69,7 @@ attr_reader :reflection, :subject - def convert_scope_to_relation(scope) - relation = associated_class.all - - if scope - # Source: AR::Associations::AssociationScope#eval_scope - relation.instance_exec(subject, &scope) - else - relation - end - end - - def convert_options_to_relation(options) - relation = associated_class.scoped - relation = extend_relation_with(relation, :where, options[:conditions]) - relation = extend_relation_with(relation, :includes, options[:include]) - relation = extend_relation_with(relation, :order, options[:order]) - relation = extend_relation_with(relation, :group, options[:group]) - relation = extend_relation_with(relation, :having, options[:having]) - relation = extend_relation_with(relation, :limit, options[:limit]) - relation = extend_relation_with(relation, :offset, options[:offset]) - relation = extend_relation_with(relation, :select, options[:select]) - relation - end - - def extend_relation_with(relation, method_name, value) - if value - relation.__send__(method_name, value) - else - relation - end - end + private def has_and_belongs_to_many_name reflection.options[:through] diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb 2020-02-18 07:23:52.000000000 +0000 @@ -4,7 +4,7 @@ module AssociationMatchers # @private class ModelReflector - delegate :associated_class, :through?, :join_table, + delegate :associated_class, :through?, :join_table_name, :association_relation, :polymorphic?, :foreign_key, :association_foreign_key, to: :reflection diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/association_matchers/optional_matcher.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_record/association_matchers/optional_matcher.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/association_matchers/optional_matcher.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_record/association_matchers/optional_matcher.rb 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,69 @@ +module Shoulda + module Matchers + module ActiveRecord + module AssociationMatchers + # @private + class OptionalMatcher + attr_reader :missing_option + + def initialize(attribute_name, optional) + @attribute_name = attribute_name + @optional = optional + @submatcher = ActiveModel::AllowValueMatcher.new(nil). + for(attribute_name) + @missing_option = '' + end + + def description + "optional: #{optional}" + end + + def matches?(subject) + if submatcher_passes?(subject) + true + else + @missing_option = 'and for the record ' + + missing_option << + if optional + 'not to ' + else + 'to ' + end + + missing_option << ( + 'fail validation if ' + + ":#{attribute_name} is unset; i.e., either the association " + + 'should have been defined with `optional: ' + + "#{optional.inspect}`, or there " + ) + + missing_option << + if optional + 'should not ' + else + 'should ' + end + + missing_option << "be a presence validation on :#{attribute_name}" + + false + end + end + + private + + attr_reader :attribute_name, :optional, :submatcher + + def submatcher_passes?(subject) + if optional + submatcher.matches?(subject) + else + submatcher.does_not_match?(subject) + end + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/association_matchers/option_verifier.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_record/association_matchers/option_verifier.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/association_matchers/option_verifier.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_record/association_matchers/option_verifier.rb 2020-02-18 07:23:52.000000000 +0000 @@ -34,15 +34,16 @@ def correct_for?(*args) expected_value, name, type = args.reverse + if expected_value.nil? true else - expected_value = type_cast( + type_cast_expected_value = type_cast( type, expected_value_for(type, name, expected_value) ) actual_value = type_cast(type, actual_value_for(name)) - expected_value == actual_value + type_cast_expected_value == actual_value end end @@ -65,10 +66,14 @@ def type_cast(type, value) case type - when :string, :relation_clause then value.to_s - when :boolean then !!value - when :hash then Hash(value).stringify_keys - else value + when :string, :relation_clause + value.to_s + when :boolean + !!value + when :hash + Hash(value).stringify_keys + else + value end end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/association_matchers/required_matcher.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_record/association_matchers/required_matcher.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/association_matchers/required_matcher.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_record/association_matchers/required_matcher.rb 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,74 @@ +module Shoulda + module Matchers + module ActiveRecord + module AssociationMatchers + # @private + class RequiredMatcher + attr_reader :missing_option + + def initialize(attribute_name, required) + @attribute_name = attribute_name + @required = required + @submatcher = ActiveModel::DisallowValueMatcher.new(nil). + for(attribute_name). + with_message(validation_message_key) + @missing_option = '' + end + + def description + "required: #{required}" + end + + def matches?(subject) + if submatcher_passes?(subject) + true + else + @missing_option = 'and for the record ' + + missing_option << + if required + 'to ' + else + 'not to ' + end + + missing_option << ( + 'fail validation if ' + + ":#{attribute_name} is unset; i.e., either the association " + + 'should have been defined with `required: ' + + "#{required.inspect}`, or there " + ) + + missing_option << + if required + 'should ' + else + 'should not ' + end + + missing_option << "be a presence validation on :#{attribute_name}" + + false + end + end + + private + + attr_reader :attribute_name, :required, :submatcher + + def submatcher_passes?(subject) + if required + submatcher.matches?(subject) + else + submatcher.does_not_match?(subject) + end + end + + def validation_message_key + RailsShim.validation_message_key_for_association_required_option + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb 2020-02-18 07:23:52.000000000 +0000 @@ -2,46 +2,159 @@ module Matchers module ActiveRecord # The `define_enum_for` matcher is used to test that the `enum` macro has - # been used to decorate an attribute with enum methods. + # been used to decorate an attribute with enum capabilities. # # class Process < ActiveRecord::Base # enum status: [:running, :stopped, :suspended] # end # # # RSpec - # describe Process do + # RSpec.describe Process, type: :model do # it { should define_enum_for(:status) } - # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class ProcessTest < ActiveSupport::TestCase # should define_enum_for(:status) # end # # #### Qualifiers # - # ##### with + # ##### with_values # - # Use `with` to test that the enum has been defined with a certain set of - # known values. + # Use `with_values` to test that the attribute can only receive a certain + # set of possible values. # # class Process < ActiveRecord::Base # enum status: [:running, :stopped, :suspended] # end # # # RSpec - # describe Process do + # RSpec.describe Process, type: :model do + # it do + # should define_enum_for(:status). + # with_values([:running, :stopped, :suspended]) + # end + # end + # + # # Minitest (Shoulda) + # class ProcessTest < ActiveSupport::TestCase + # should define_enum_for(:status). + # with_values([:running, :stopped, :suspended]) + # end + # + # If the values backing your enum attribute are arbitrary instead of a + # series of integers starting from 0, pass a hash to `with_values` instead + # of an array: + # + # class Process < ActiveRecord::Base + # enum status: { + # running: 0, + # stopped: 1, + # suspended: 3, + # other: 99 + # } + # end + # + # # RSpec + # RSpec.describe Process, type: :model do + # it do + # should define_enum_for(:status). + # with_values(running: 0, stopped: 1, suspended: 3, other: 99) + # end + # end + # + # # Minitest (Shoulda) + # class ProcessTest < ActiveSupport::TestCase + # should define_enum_for(:status). + # with_values(running: 0, stopped: 1, suspended: 3, other: 99) + # end + # + # ##### backed_by_column_of_type + # + # Use `backed_by_column_of_type` when the column backing your column type + # is a string instead of an integer: + # + # class LoanApplication < ActiveRecord::Base + # enum status: { + # active: "active", + # pending: "pending", + # rejected: "rejected" + # } + # end + # + # # RSpec + # RSpec.describe LoanApplication, type: :model do + # it do + # should define_enum_for(:status). + # with_values( + # active: "active", + # pending: "pending", + # rejected: "rejected" + # ). + # backed_by_column_of_type(:string) + # end + # end + # + # # Minitest (Shoulda) + # class LoanApplicationTest < ActiveSupport::TestCase + # should define_enum_for(:status). + # with_values( + # active: "active", + # pending: "pending", + # rejected: "rejected" + # ). + # backed_by_column_of_type(:string) + # end + # + ## ##### with_prefix + # + # Use `with_prefix` to test that the enum is defined with a `_prefix` + # option (Rails 5 only). Can take either a boolean or a symbol: + # + # class Issue < ActiveRecord::Base + # enum status: [:open, :closed], _prefix: :old + # end + # + # # RSpec + # RSpec.describe Issue, type: :model do # it do # should define_enum_for(:status). - # with([:running, :stopped, :suspended]) + # with_values([:open, :closed]). + # with_prefix(:old) # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class ProcessTest < ActiveSupport::TestCase # should define_enum_for(:status). - # with([:running, :stopped, :suspended]) + # with_values([:open, :closed]). + # with_prefix(:old) + # end + # + # ##### with_suffix + # + # Use `with_suffix` to test that the enum is defined with a `_suffix` + # option (Rails 5 only). Can take either a boolean or a symbol: + # + # class Issue < ActiveRecord::Base + # enum status: [:open, :closed], _suffix: true + # end + # + # # RSpec + # RSpec.describe Issue, type: :model do + # it do + # should define_enum_for(:status). + # with_values([:open, :closed]). + # with_suffix + # end + # end + # + # # Minitest (Shoulda) + # class ProcessTest < ActiveSupport::TestCase + # should define_enum_for(:status). + # with_values([:open, :closed]). + # with_suffix # end # # @return [DefineEnumForMatcher] @@ -54,82 +167,292 @@ class DefineEnumForMatcher def initialize(attribute_name) @attribute_name = attribute_name - @options = {} + @options = { expected_enum_values: [] } end - def with(expected_enum_values) + def description + description = "#{simple_description} backed by " + description << Shoulda::Matchers::Util.a_or_an(expected_column_type) + + if expected_enum_values.any? + description << ' with values ' + description << Shoulda::Matchers::Util.inspect_value( + expected_enum_values, + ) + end + + if options[:prefix] + description << ", prefix: #{options[:prefix].inspect}" + end + + if options[:suffix] + description << ", suffix: #{options[:suffix].inspect}" + end + + description + end + + def with_values(expected_enum_values) options[:expected_enum_values] = expected_enum_values self end + def with(expected_enum_values) + Shoulda::Matchers.warn_about_deprecated_method( + 'The `with` qualifier on `define_enum_for`', + '`with_values`', + ) + with_values(expected_enum_values) + end + + def with_prefix(expected_prefix = true) + options[:prefix] = expected_prefix + self + end + + def with_suffix(expected_suffix = true) + options[:suffix] = expected_suffix + self + end + + def backed_by_column_of_type(expected_column_type) + options[:expected_column_type] = expected_column_type + self + end + def matches?(subject) - @model = subject - enum_defined? && enum_values_match? + @record = subject + + enum_defined? && + enum_values_match? && + column_type_matches? && + enum_value_methods_exist? end def failure_message - "Expected #{expectation}" + message = + if enum_defined? + "Expected #{model} to #{expectation}. " + else + "Expected #{model} to #{expectation}, but " + end + + message << failure_message_continuation + '.' + + Shoulda::Matchers.word_wrap(message) end - alias :failure_message_for_should :failure_message def failure_message_when_negated - "Did not expect #{expectation}" + message = "Expected #{model} not to #{expectation}, but it did." + Shoulda::Matchers.word_wrap(message) end - alias :failure_message_for_should_not :failure_message_when_negated - def description - desc = "define :#{attribute_name} as an enum" + private + + attr_reader :attribute_name, :options, :record, + :failure_message_continuation + + def expectation + 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 options[:expected_enum_values] - desc << " with #{options[:expected_enum_values]}" + 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 - desc + def simple_description + "define :#{attribute_name} as an enum" end - protected + 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 - attr_reader :model, :attribute_name, :options + def normalized_expected_enum_values + to_hash(expected_enum_values) + end - def expectation - "#{model.class.name} to #{description}" + def expected_enum_value_names + to_array(expected_enum_values) end def expected_enum_values - hashify(options[:expected_enum_values]).with_indifferent_access + options[:expected_enum_values] end - def enum_method - attribute_name.to_s.pluralize + def normalized_actual_enum_values + to_hash(actual_enum_values) end def actual_enum_values - model.class.send(enum_method) + model.send(attribute_name.to_s.pluralize) end def enum_defined? - model.class.respond_to?(enum_method) + if model.defined_enums.include?(attribute_name.to_s) + true + else + @failure_message_continuation = + "no such enum exists on #{model}" + false + end end def enum_values_match? - expected_enum_values.empty? || actual_enum_values == expected_enum_values + passed = + expected_enum_values.empty? || + normalized_actual_enum_values == normalized_expected_enum_values + + if passed + true + else + @failure_message_continuation = + "However, #{attribute_name.inspect} actually maps " + + presented_enum_mapping(normalized_actual_enum_values) + false + end end - def hashify(value) - if value.nil? - return {} + def column_type_matches? + if column.type == expected_column_type.to_sym + true + else + @failure_message_continuation = + "However, #{attribute_name.inspect} is " + + Shoulda::Matchers::Util.a_or_an(column.type) + + ' column' + false end + end - if value.is_a?(Array) - new_value = {} + def expected_column_type + options[:expected_column_type] || :integer + end + + def column + model.columns_hash[attribute_name.to_s] + end + + def model + record.class + end + + def enum_value_methods_exist? + passed = expected_singleton_methods.all? do |method| + model.singleton_methods.include?(method) + end + + if passed + true + else + 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 - value.each_with_index do |v, i| - new_value[v] = i + def expected_singleton_methods + expected_enum_value_names.map do |name| + [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 - new_value + 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)| + hash.merge(item.to_s => index) + end + else + value.stringify_keys + end + end + + def to_array(value) + if value.is_a?(Array) + value.map(&:to_s) else - value + value.keys.map(&:to_s) end end end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/have_db_column_matcher.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_record/have_db_column_matcher.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/have_db_column_matcher.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_record/have_db_column_matcher.rb 2020-02-18 07:23:52.000000000 +0000 @@ -13,11 +13,11 @@ # end # # # RSpec - # describe Phone do + # RSpec.describe Phone, type: :model do # it { should have_db_column(:supported_ios_version) } # end # - # # Test::Unit + # # Minitest (Shoulda) # class PhoneTest < ActiveSupport::TestCase # should have_db_column(:supported_ios_version) # end @@ -37,13 +37,13 @@ # end # # # RSpec - # describe Phone do + # RSpec.describe Phone, type: :model do # it do # should have_db_column(:camera_aperture).of_type(:decimal) # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class PhoneTest < ActiveSupport::TestCase # should have_db_column(:camera_aperture).of_type(:decimal) # end @@ -63,14 +63,14 @@ # end # # # RSpec - # describe Phone do + # RSpec.describe Phone, type: :model do # it do # should have_db_column(:camera_aperture). # with_options(precision: 1, null: false) # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class PhoneTest < ActiveSupport::TestCase # should have_db_column(:camera_aperture). # with_options(precision: 1, null: false) @@ -118,12 +118,10 @@ def failure_message "Expected #{expectation} (#{@missing})" end - alias failure_message_for_should failure_message def failure_message_when_negated "Did not expect #{expectation}" end - alias failure_message_for_should_not failure_message_when_negated def description desc = "have db column named #{@column}" @@ -271,7 +269,7 @@ end def type_cast_default - Shoulda::Matchers::RailsShim.type_cast_default_for(model, self) + model.column_defaults[name] end def primary? diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/have_db_index_matcher.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_record/have_db_index_matcher.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/have_db_index_matcher.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_record/have_db_index_matcher.rb 2020-02-18 07:23:52.000000000 +0000 @@ -2,7 +2,9 @@ module Matchers module ActiveRecord # The `have_db_index` matcher tests that the table that backs your model - # has a index on a specific column. + # has a specific index. + # + # You can specify one column: # # class CreateBlogs < ActiveRecord::Migration # def change @@ -15,52 +17,92 @@ # end # # # RSpec - # describe Blog do + # RSpec.describe Blog, type: :model do # it { should have_db_index(:user_id) } # end # - # # Test::Unit + # # Minitest (Shoulda) # class BlogTest < ActiveSupport::TestCase # should have_db_index(:user_id) # end # - # #### Qualifiers - # - # ##### unique - # - # Use `unique` to assert that the index is unique. + # Or you can specify a group of columns: # # class CreateBlogs < ActiveRecord::Migration # def change # create_table :blogs do |t| + # t.integer :user_id # t.string :name # end # - # add_index :blogs, :name, unique: true + # add_index :blogs, :user_id, :name # end # end # # # RSpec - # describe Blog do - # it { should have_db_index(:name).unique(true) } + # RSpec.describe Blog, type: :model do + # it { should have_db_index([:user_id, :name]) } # end # - # # Test::Unit + # # Minitest (Shoulda) # class BlogTest < ActiveSupport::TestCase - # should have_db_index(:name).unique(true) + # should have_db_index([:user_id, :name]) + # end + # + # Finally, if you're using Rails 5 and PostgreSQL, you can also specify an + # expression: + # + # class CreateLoggedErrors < ActiveRecord::Migration + # def change + # create_table :logged_errors do |t| + # t.string :code + # t.jsonb :content + # end + # + # add_index :logged_errors, 'lower(code)::text' + # end + # end + # + # # RSpec + # RSpec.describe LoggedError, type: :model do + # it { should have_db_index('lower(code)::text') } # end # - # Since it only ever makes since for `unique` to be `true`, you can also - # leave off the argument to save some keystrokes: + # # Minitest (Shoulda) + # class LoggedErrorTest < ActiveSupport::TestCase + # should have_db_index('lower(code)::text') + # end + # + # #### Qualifiers + # + # ##### unique + # + # Use `unique` to assert that the index is either unique or non-unique: + # + # class CreateBlogs < ActiveRecord::Migration + # def change + # create_table :blogs do |t| + # t.string :domain + # t.integer :user_id + # end + # + # add_index :blogs, :domain, unique: true + # add_index :blogs, :user_id + # end + # end # # # RSpec - # describe Blog do + # RSpec.describe Blog, type: :model do # it { should have_db_index(:name).unique } + # it { should have_db_index(:name).unique(true) } # if you want to be explicit + # it { should have_db_index(:user_id).unique(false) } # end # - # # Test::Unit + # # Minitest (Shoulda) # class BlogTest < ActiveSupport::TestCase # should have_db_index(:name).unique + # should have_db_index(:name).unique(true) # if you want to be explicit + # should have_db_index(:user_id).unique(false) # end # # @return [HaveDbIndexMatcher] @@ -72,12 +114,12 @@ # @private class HaveDbIndexMatcher def initialize(columns) - @columns = normalize_columns_to_array(columns) - @options = {} + @expected_columns = normalize_columns_to_array(columns) + @qualifiers = {} end def unique(unique = true) - @options[:unique] = unique + @qualifiers[:unique] = unique self end @@ -87,74 +129,146 @@ end def failure_message - "Expected #{expectation} (#{@missing})" + message = + "Expected #{described_table_name} to #{positive_expectation}" + + message << + if index_exists? + ". The index does exist, but #{reason}." + elsif reason + ", but #{reason}." + else + ', but it does not.' + end + + Shoulda::Matchers.word_wrap(message) end - alias failure_message_for_should failure_message def failure_message_when_negated - "Did not expect #{expectation}" + Shoulda::Matchers.word_wrap( + "Expected #{described_table_name} not to " + + "#{negative_expectation}, but it does.", + ) end - alias failure_message_for_should_not failure_message_when_negated def description - if @options.key?(:unique) - "have a #{index_type} index on columns #{@columns.join(' and ')}" - else - "have an index on columns #{@columns.join(' and ')}" - end - end + description = 'have ' - protected + description << + if qualifiers.include?(:unique) + Shoulda::Matchers::Util.a_or_an(index_type) + ' ' + else + 'an ' + end - def index_exists? - ! matched_index.nil? + description << 'index on ' + + description << inspected_expected_columns end - def correct_unique? - return true unless @options.key?(:unique) + private - is_unique = matched_index.unique + attr_reader :expected_columns, :qualifiers, :subject, :reason - is_unique = !is_unique unless @options[:unique] + def normalize_columns_to_array(columns) + Array.wrap(columns).map(&:to_s) + end - unless is_unique - @missing = "#{table_name} has an index named #{matched_index.name} " << - "of unique #{matched_index.unique}, not #{@options[:unique]}." - end + def index_exists? + !matched_index.nil? + end - is_unique + def correct_unique? + if qualifiers.include?(:unique) + if qualifiers[:unique] && !matched_index.unique + @reason = 'it is not unique' + false + elsif !qualifiers[:unique] && matched_index.unique + @reason = 'it is unique' + false + else + true + end + else + true + end end def matched_index - indexes.detect { |each| each.columns == @columns } + @_matched_index ||= + if expected_columns.one? + actual_indexes.detect do |index| + Array.wrap(index.columns) == expected_columns + end + else + actual_indexes.detect do |index| + index.columns == expected_columns + end + end + end + + def actual_indexes + model.connection.indexes(table_name) + end + + def described_table_name + if model + "the #{table_name} table" + else + 'a table' + end end - def model_class - @subject.class + def table_name + model.table_name end - def table_name - model_class.table_name + def positive_expectation + if index_exists? + expectation = "have an index on #{inspected_expected_columns}" + + if qualifiers.include?(:unique) + expectation << " and for it to be #{index_type}" + end + + expectation + else + description + end end - def indexes - ::ActiveRecord::Base.connection.indexes(table_name) + def negative_expectation + description end - def expectation - "#{model_class.name} to #{description}" + def inspected_expected_columns + if formatted_expected_columns.one? + formatted_expected_columns.first.inspect + else + formatted_expected_columns.inspect + end end def index_type - if @options[:unique] + if qualifiers[:unique] 'unique' else 'non-unique' end end - def normalize_columns_to_array(columns) - Array.wrap(columns).map(&:to_s) + def formatted_expected_columns + expected_columns.map do |column| + if column.match?(/^\w+$/) + column.to_sym + else + column + end + end + end + + def model + subject&.class end end end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb 2020-02-18 07:23:52.000000000 +0000 @@ -9,11 +9,11 @@ # end # # # RSpec - # describe User do + # RSpec.describe User, type: :model do # it { should have_readonly_attribute(:password) } # end # - # # Test::Unit + # # Minitest (Shoulda) # class UserTest < ActiveSupport::TestCase # should have_readonly_attribute(:password) # end @@ -32,9 +32,6 @@ attr_reader :failure_message, :failure_message_when_negated - alias failure_message_for_should failure_message - alias failure_message_for_should_not failure_message_when_negated - def matches?(subject) @subject = subject if readonly_attributes.include?(@attribute) diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/have_rich_text_matcher.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_record/have_rich_text_matcher.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/have_rich_text_matcher.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_record/have_rich_text_matcher.rb 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,79 @@ +module Shoulda + module Matchers + module ActiveRecord + # The `have_rich_text` matcher tests usage of the + # `has_rich_text` macro. + # + # #### Example + # + # class Post < ActiveRecord + # has_rich_text :content + # end + # + # # RSpec + # RSpec.describe Post, type: :model do + # it { is_expected.to have_rich_text(:content) } + # end + # + # # Minitest (Shoulda) + # class PostTest < ActiveSupport::TestCase + # should have_rich_text(:content) + # end + # + # @return [HaveRichText] + # + def have_rich_text(rich_text_attribute) + HaveRichText.new(rich_text_attribute) + end + + # @private + class HaveRichText + def initialize(rich_text_attribute) + @rich_text_attribute = rich_text_attribute + end + + def description + "have configured :#{rich_text_attribute} as a ActionText::RichText association" + end + + def failure_message + "Expected #{subject.class} to #{error_description}" + end + + def failure_message_when_negated + "Did not expect #{subject.class} to have ActionText::RichText :#{rich_text_attribute}" + end + + def matches?(subject) + @subject = subject + @error = run_checks + @error.nil? + end + + private + + attr_reader :error, :rich_text_attribute, :subject + + def run_checks + if !has_attribute? + ":#{rich_text_attribute} does not exist" + elsif !has_expected_action_text? + :default + end + end + + def has_attribute? + @subject.respond_to?(rich_text_attribute.to_s) + end + + def has_expected_action_text? + @subject.send(rich_text_attribute).class.name == 'ActionText::RichText' + end + + def error_description + error == :default ? description : "#{description} but #{error}" + end + end + end + end +end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/have_secure_token_matcher.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_record/have_secure_token_matcher.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/have_secure_token_matcher.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_record/have_secure_token_matcher.rb 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,111 @@ +module Shoulda + module Matchers + module ActiveRecord + # The `have_secure_token` matcher tests usage of the + # `has_secure_token` macro. + # + # #### Example + # + # class User < ActiveRecord + # attr_accessor :token + # attr_accessor :auth_token + # + # has_secure_token + # has_secure_token :auth_token + # end + # + # # RSpec + # RSpec.describe User, type: :model do + # it { should have_secure_token } + # it { should have_secure_token(:auth_token) } + # end + # + # # Minitest (Shoulda) + # class UserTest < ActiveSupport::TestCase + # should have_secure_token + # should have_secure_token(:auth_token) + # end + # + # @return [HaveSecureToken] + # + + # rubocop:disable Style/PredicateName + def have_secure_token(token_attribute = :token) + HaveSecureTokenMatcher.new(token_attribute) + end + # rubocop:enable Style/PredicateName + + # @private + class HaveSecureTokenMatcher + attr_reader :token_attribute + + def initialize(token_attribute) + @token_attribute = token_attribute + end + + def description + "have :#{token_attribute} as a secure token" + end + + def failure_message + return if !@errors + "Expected #{@subject.class} to #{description} but the following " \ + "errors were found: #{@errors.join(', ')}" + end + + def failure_message_when_negated + return if !@errors + "Did not expect #{@subject.class} to have secure token " \ + ":#{token_attribute}" + end + + def matches?(subject) + @subject = subject + @errors = run_checks + @errors.empty? + end + + private + + def run_checks + @errors = [] + if !has_expected_instance_methods? + @errors << 'missing expected class and instance methods' + end + if !has_expected_db_column? + @errors << "missing correct column #{token_attribute}:string" + end + if !has_expected_db_index? + @errors << "missing unique index for #{table_and_column}" + end + @errors + end + + def has_expected_instance_methods? + @subject.respond_to?(token_attribute.to_s) && + @subject.respond_to?("#{token_attribute}=") && + @subject.respond_to?("regenerate_#{token_attribute}") && + @subject.class.respond_to?(:generate_unique_secure_token) + end + + def has_expected_db_column? + matcher = HaveDbColumnMatcher.new(token_attribute).of_type(:string) + matcher.matches?(@subject) + end + + def has_expected_db_index? + matcher = HaveDbIndexMatcher.new(token_attribute).unique(true) + matcher.matches?(@subject) + end + + def table_and_column + "#{table_name}.#{token_attribute}" + end + + def table_name + @subject.class.table_name + end + end + end + end +end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/serialize_matcher.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_record/serialize_matcher.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/serialize_matcher.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_record/serialize_matcher.rb 2020-02-18 07:23:52.000000000 +0000 @@ -8,11 +8,11 @@ # end # # # RSpec - # describe Product do + # RSpec.describe Product, type: :model do # it { should serialize(:customizations) } # end # - # # Test::Unit + # # Minitest (Shoulda) # class ProductTest < ActiveSupport::TestCase # should serialize(:customizations) # end @@ -38,14 +38,14 @@ # end # # # RSpec - # describe Product do + # RSpec.describe Product, type: :model do # it do # should serialize(:specifications). # as(ProductSpecsSerializer) # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class ProductTest < ActiveSupport::TestCase # should serialize(:specifications). # as(ProductSpecsSerializer) @@ -70,14 +70,14 @@ # end # # # RSpec - # describe Product do + # RSpec.describe Product, type: :model do # it do # should serialize(:options). # as_instance_of(ProductOptionsSerializer) # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class ProductTest < ActiveSupport::TestCase # should serialize(:options). # as_instance_of(ProductOptionsSerializer) @@ -114,12 +114,10 @@ def failure_message "Expected #{expectation} (#{@missing})" end - alias failure_message_for_should failure_message def failure_message_when_negated "Did not expect #{expectation}" end - alias failure_message_for_should_not failure_message_when_negated def description description = "serialize :#{@name}" @@ -185,15 +183,11 @@ end def attribute_is_serialized? - serialized_attributes.include?(@name) + !!serialization_coder end def serialization_coder - serialized_attributes[@name] - end - - def serialized_attributes - Shoulda::Matchers::RailsShim.serialized_attributes_for(model) + RailsShim.attribute_serialization_coder_for(model, @name) end def model diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb 2020-02-18 07:23:52.000000000 +0000 @@ -10,15 +10,15 @@ # pre-existing record (thereby failing the uniqueness check). # # class Post < ActiveRecord::Base - # validates_uniqueness_of :permalink + # validates :permalink, uniqueness: true # end # # # RSpec - # describe Post do + # RSpec.describe Post, type: :model do # it { should validate_uniqueness_of(:permalink) } # end # - # # Test::Unit + # # Minitest (Shoulda) # class PostTest < ActiveSupport::TestCase # should validate_uniqueness_of(:permalink) # end @@ -49,62 +49,89 @@ # # You may be tempted to test the model like this: # - # describe Post do + # RSpec.describe Post, type: :model do # it { should validate_uniqueness_of(:title) } # end # - # However, running this test will fail with something like: + # However, running this test will fail with an exception such as: # - # Failures: + # Shoulda::Matchers::ActiveRecord::ValidateUniquenessOfMatcher::ExistingRecordInvalid: + # validate_uniqueness_of works by matching a new record against an + # existing record. If there is no existing record, it will create one + # using the record you provide. # - # 1) Post should require case sensitive unique value for title - # Failure/Error: it { should validate_uniqueness_of(:title) } - # ActiveRecord::StatementInvalid: - # SQLite3::ConstraintException: posts.content may not be NULL: INSERT INTO "posts" ("title") VALUES (?) + # While doing this, the following error was raised: + # + # PG::NotNullViolation: ERROR: null value in column "content" violates not-null constraint + # DETAIL: Failing row contains (1, null, null). + # : INSERT INTO "posts" DEFAULT VALUES RETURNING "id" + # + # The best way to fix this is to provide the matcher with a record where + # any required attributes are filled in with valid values beforehand. + # + # (The exact error message will differ depending on which database you're + # using, but you get the idea.) # # This happens because `validate_uniqueness_of` tries to create a new post # but cannot do so because of the `content` attribute: though unrelated to - # this test, it nevertheless needs to be filled in. The solution is to - # build a custom Post object ahead of time with `content` filled in: + # this test, it nevertheless needs to be filled in. As indicated at the + # end of the error message, the solution is to build a custom Post object + # ahead of time with `content` filled in: # - # describe Post do + # RSpec.describe Post, type: :model do # describe "validations" do - # subject { Post.new(content: 'Here is the content') } + # subject { Post.create(content: "Here is the content") } # it { should validate_uniqueness_of(:title) } # end # end # # Or, if you're using - # [FactoryGirl](http://github.com/thoughtbot/factory_girl) and you have a + # [FactoryBot](https://github.com/thoughtbot/factory_bot) and you have a # `post` factory defined which automatically fills in `content`, you can # say: # - # describe Post do + # RSpec.describe Post, type: :model do # describe "validations" do - # subject { FactoryGirl.build(:post) } + # subject { FactoryBot.create(:post) } # it { should validate_uniqueness_of(:title) } # end # end # # #### Qualifiers # + # Use `on` if your validation applies only under a certain context. + # + # class Post < ActiveRecord::Base + # validates :title, uniqueness: true, on: :create + # end + # + # # RSpec + # RSpec.describe Post, type: :model do + # it { should validate_uniqueness_of(:title).on(:create) } + # end + # + # # Minitest (Shoulda) + # class PostTest < ActiveSupport::TestCase + # should validate_uniqueness_of(:title).on(:create) + # end + # # ##### with_message # # Use `with_message` if you are using a custom validation message. # # class Post < ActiveRecord::Base - # validates_uniqueness_of :title, message: 'Please choose another title' + # validates :title, uniqueness: true, message: 'Please choose another title' # end # # # RSpec - # describe Post do + # RSpec.describe Post, type: :model do # it do # should validate_uniqueness_of(:title). # with_message('Please choose another title') # end # end # - # # Test::Unit + # # Minitest (Shoulda) # class PostTest < ActiveSupport::TestCase # should validate_uniqueness_of(:title). # with_message('Please choose another title') @@ -117,15 +144,15 @@ # unique, but the scoped attributes are not unique either. # # class Post < ActiveRecord::Base - # validates_uniqueness_of :slug, scope: :user_id + # validates :slug, uniqueness: { scope: :journal_id } # end # # # RSpec - # describe Post do + # RSpec.describe Post, type: :model do # it { should validate_uniqueness_of(:slug).scoped_to(:journal_id) } # end # - # # Test::Unit + # # Minitest (Shoulda) # class PostTest < ActiveSupport::TestCase # should validate_uniqueness_of(:slug).scoped_to(:journal_id) # end @@ -138,33 +165,67 @@ # attributes in the pre-existing record. # # class Post < ActiveRecord::Base - # validates_uniqueness_of :key, case_sensitive: false + # validates :key, uniqueness: { case_sensitive: false } # end # # # RSpec - # describe Post do + # RSpec.describe Post, type: :model do # it { should validate_uniqueness_of(:key).case_insensitive } # end # - # # Test::Unit + # # Minitest (Shoulda) # class PostTest < ActiveSupport::TestCase # should validate_uniqueness_of(:key).case_insensitive # end # + # ##### ignoring_case_sensitivity + # + # By default, `validate_uniqueness_of` will check that the + # validation is case sensitive: it asserts that uniquable attributes pass + # validation when their values are in a different case than corresponding + # attributes in the pre-existing record. + # + # Use `ignoring_case_sensitivity` to skip this check. This qualifier is + # particularly handy if your model has somehow changed the behavior of + # attribute you're testing so that it modifies the case of incoming values + # as they are set. For instance, perhaps you've overridden the writer + # method or added a `before_validation` callback to normalize the + # attribute. + # + # class User < ActiveRecord::Base + # validates :email, uniqueness: true + # + # def email=(value) + # super(value.downcase) + # end + # end + # + # # RSpec + # RSpec.describe Post, type: :model do + # it do + # should validate_uniqueness_of(:email).ignoring_case_sensitivity + # end + # end + # + # # Minitest (Shoulda) + # class PostTest < ActiveSupport::TestCase + # should validate_uniqueness_of(:email).ignoring_case_sensitivity + # end + # # ##### allow_nil # # Use `allow_nil` to assert that the attribute allows nil. # # class Post < ActiveRecord::Base - # validates_uniqueness_of :author_id, allow_nil: true + # validates :author_id, uniqueness: true, allow_nil: true # end # # # RSpec - # describe Post do + # RSpec.describe Post, type: :model do # it { should validate_uniqueness_of(:author_id).allow_nil } # end # - # # Test::Unit + # # Minitest (Shoulda) # class PostTest < ActiveSupport::TestCase # should validate_uniqueness_of(:author_id).allow_nil # end @@ -176,15 +237,15 @@ # Use `allow_blank` to assert that the attribute allows a blank value. # # class Post < ActiveRecord::Base - # validates_uniqueness_of :author_id, allow_blank: true + # validates :author_id, uniqueness: true, allow_blank: true # end # # # RSpec - # describe Post do + # RSpec.describe Post, type: :model do # it { should validate_uniqueness_of(:author_id).allow_blank } # end # - # # Test::Unit + # # Minitest (Shoulda) # class PostTest < ActiveSupport::TestCase # should validate_uniqueness_of(:author_id).allow_blank # end @@ -201,21 +262,31 @@ def initialize(attribute) super(attribute) - @options = {} + @expected_message = :taken + @options = { + case_sensitivity_strategy: :sensitive + } + @existing_record_created = false + @failure_reason = nil + @failure_reason_when_negated = nil + @attribute_setters = { + existing_record: AttributeSetters.new, + new_record: AttributeSetters.new + } end def scoped_to(*scopes) - @options[:scopes] = [*scopes].flatten + @options[:scopes] = [*scopes].flatten.map(&:to_sym) self end - def with_message(message) - @expected_message = message + def case_insensitive + @options[:case_sensitivity_strategy] = :insensitive self end - def case_insensitive - @options[:case_insensitive] = true + def ignoring_case_sensitivity + @options[:case_sensitivity_strategy] = :ignore self end @@ -224,137 +295,450 @@ self end + def expects_to_allow_nil? + @options[:allow_nil] == true + end + def allow_blank @options[:allow_blank] = true self end - def description - result = "require " - result << "case sensitive " unless @options[:case_insensitive] - result << "unique value for #{@attribute}" - result << " scoped to #{@options[:scopes].join(', ')}" if @options[:scopes].present? - result - end - - def matches?(subject) - @original_subject = subject - @subject = subject.class.new - @expected_message ||= :taken - - set_scoped_attributes && - validate_everything_except_duplicate_nils_or_blanks? && - validate_after_scope_change? && - allows_nil? && - allows_blank? + def expects_to_allow_blank? + @options[:allow_blank] == true + end + + def simple_description + description = "validate that :#{@attribute} is" + description << description_for_case_sensitive_qualifier + description << ' unique' + + if @options[:scopes].present? + description << " within the scope of #{inspected_expected_scopes}" + end + + description + end + + def matches?(given_record) + @given_record = given_record + @all_records = model.all + + matches_presence_of_attribute? && + matches_presence_of_scopes? && + matches_scopes_configuration? && + matches_uniqueness_without_scopes? && + matches_uniqueness_with_case_sensitivity_strategy? && + matches_uniqueness_with_scopes? && + matches_allow_nil? && + matches_allow_blank? ensure Uniqueness::TestModels.remove_all end + def does_not_match?(given_record) + @given_record = given_record + @all_records = model.all + + does_not_match_presence_of_scopes? || + does_not_match_scopes_configuration? || + does_not_match_uniqueness_without_scopes? || + does_not_match_uniqueness_with_case_sensitivity_strategy? || + does_not_match_uniqueness_with_scopes? || + does_not_match_allow_nil? || + does_not_match_allow_blank? + ensure + Uniqueness::TestModels.remove_all + end + + protected + + def failure_reason + @failure_reason || super + end + + def failure_reason_when_negated + @failure_reason_when_negated || super + end + + def build_allow_or_disallow_value_matcher(args) + super.tap do |matcher| + matcher.failure_message_preface = method(:failure_message_preface) + matcher.attribute_changed_value_message = + method(:attribute_changed_value_message) + end + end + private - def allows_nil? - if @options[:allow_nil] - ensure_nil_record_in_database - allows_value_of(nil, @expected_message) + def case_sensitivity_strategy + @options[:case_sensitivity_strategy] + end + + def new_record + unless defined?(@new_record) + build_new_record + end + + @new_record + end + alias_method :subject, :new_record + + def description_for_case_sensitive_qualifier + case case_sensitivity_strategy + when :sensitive + ' case-sensitively' + when :insensitive + ' case-insensitively' else + '' + end + end + + def validations + model._validators[@attribute].select do |validator| + validator.is_a?(::ActiveRecord::Validations::UniquenessValidator) + end + end + + def matches_scopes_configuration? + if scopes_match? true + else + @failure_reason = 'Expected the validation ' + + if expected_scopes.empty? + @failure_reason << 'not to be scoped to anything, ' + else + @failure_reason << "to be scoped to #{inspected_expected_scopes}, " + end + + if actual_sets_of_scopes.any? + @failure_reason << 'but it was scoped to ' + @failure_reason << "#{inspected_actual_scopes} instead." + else + @failure_reason << 'but it was not scoped to anything.' + end + + false end end - def allows_blank? - if @options[:allow_blank] - ensure_blank_record_in_database - allows_value_of('', @expected_message) + def does_not_match_scopes_configuration? + if scopes_match? + @failure_reason = 'Expected the validation ' + + if expected_scopes.empty? + @failure_reason << 'to be scoped to nothing, ' + @failure_reason << 'but it was scoped to ' + @failure_reason << "#{inspected_actual_scopes} instead." + else + @failure_reason << 'not to be scoped to ' + @failure_reason << inspected_expected_scopes + end + + false else true end end - def existing_record - @existing_record ||= first_instance + def scopes_match? + actual_sets_of_scopes.empty? && expected_scopes.empty? || + actual_sets_of_scopes.any? { |scopes| scopes == expected_scopes } + end + + def inspected_expected_scopes + expected_scopes.map(&:inspect).to_sentence end - def first_instance - @subject.class.first || create_record_in_database + def inspected_actual_scopes + inspected_actual_sets_of_scopes.to_sentence( + words_connector: ' and ', + last_word_connector: ', and' + ) end - def ensure_nil_record_in_database - unless existing_record_is_nil? - create_record_in_database(nil_value: true) + def inspected_actual_sets_of_scopes + inspected_sets_of_scopes = actual_sets_of_scopes.map do |scopes| + scopes.map(&:inspect) end + + if inspected_sets_of_scopes.many? + inspected_sets_of_scopes.map { |x| "(#{x.to_sentence})" } + else + inspected_sets_of_scopes.map(&:to_sentence) + end + end + + def expected_scopes + Array.wrap(@options[:scopes]) end - def ensure_blank_record_in_database - unless existing_record_is_blank? - create_record_in_database(blank_value: true) + def actual_sets_of_scopes + validations.map do |validation| + Array.wrap(validation.options[:scope]).map(&:to_sym) + end.reject(&:empty?) + end + + def matches_allow_nil? + !expects_to_allow_nil? || ( + update_existing_record!(nil) && + allows_value_of(nil, @expected_message) + ) + end + + def does_not_match_allow_nil? + expects_to_allow_nil? && ( + update_existing_record!(nil) && + (@failure_reason = nil || disallows_value_of(nil, @expected_message)) + ) + end + + def matches_allow_blank? + !expects_to_allow_blank? || ( + update_existing_record!('') && + allows_value_of('', @expected_message) + ) + end + + def does_not_match_allow_blank? + expects_to_allow_blank? && ( + update_existing_record!('') && + (@failure_reason = nil || disallows_value_of('', @expected_message)) + ) + end + + def existing_record + unless defined?(@existing_record) + find_or_create_existing_record end + + @existing_record end - def existing_record_is_nil? - @existing_record.present? && existing_value.nil? + def find_or_create_existing_record + @existing_record = find_existing_record + + unless @existing_record + @existing_record = create_existing_record + @existing_record_created = true + end end - def existing_record_is_blank? - @existing_record.present? && existing_value.strip == '' + def find_existing_record + record = model.first + + if record.present? + record + else + nil + end end - def create_record_in_database(options = {}) - @original_subject.tap do |instance| - instance.__send__("#{@attribute}=", value_for_new_record(options)) - ensure_secure_password_set(instance) - instance.save(validate: false) - @created_record = instance + def create_existing_record + @given_record.tap do |existing_record| + existing_record.save(validate: false) end + rescue ::ActiveRecord::StatementInvalid => error + raise ExistingRecordInvalid.create(underlying_exception: error) end - def ensure_secure_password_set(instance) - if has_secure_password? - instance.password = "password" - instance.password_confirmation = "password" + def update_existing_record!(value) + if existing_value_read != value + set_attribute_on_existing_record!(@attribute, value) + # It would be nice if we could ensure that the record was valid, + # but that would break users' existing tests + existing_record.save(validate: false) end + + true end - def value_for_new_record(options = {}) - case - when options[:nil_value] then nil - when options[:blank_value] then '' - else 'a' + def arbitrary_non_blank_value + non_blank_value = dummy_value_for(@attribute) + limit = column_limit_for(@attribute) + + is_string_value = non_blank_value.is_a?(String) + if is_string_value && limit && limit < non_blank_value.length + 'x' * limit + else + non_blank_value end end def has_secure_password? - @subject.class.ancestors.map(&:to_s).include?('ActiveModel::SecurePassword::InstanceMethodsOnActivation') + Shoulda::Matchers::RailsShim.has_secure_password?(subject, @attribute) end - def set_scoped_attributes - if @options[:scopes].present? - @options[:scopes].all? do |scope| - setter = :"#{scope}=" - if @subject.respond_to?(setter) - @subject.__send__(setter, existing_record.__send__(scope)) - true - else - @failure_message = "#{class_name} doesn't seem to have a #{scope} attribute." - false + def build_new_record + @new_record = existing_record.dup + + attribute_names_under_test.each do |attribute_name| + set_attribute_on_new_record!( + attribute_name, + existing_record.public_send(attribute_name) + ) + end + + @new_record + end + + def matches_presence_of_attribute? + if attribute_present_on_model? + true + else + @failure_reason = + ":#{attribute} does not seem to be an attribute on #{model.name}." + false + end + end + + def does_not_match_presence_of_attribute? + if attribute_present_on_model? + @failure_reason = + ":#{attribute} seems to be an attribute on #{model.name}." + false + else + true + end + end + + def attribute_present_on_model? + model.method_defined?("#{attribute}=") || + model.columns_hash.key?(attribute.to_s) + end + + def matches_presence_of_scopes? + if scopes_missing_on_model.none? + true + else + inspected_scopes = scopes_missing_on_model.map(&:inspect) + + reason = '' + + reason << inspected_scopes.to_sentence + + if inspected_scopes.many? + reason << " do not seem to be attributes" + else + reason << " does not seem to be an attribute" + end + + reason << " on #{model.name}." + + @failure_reason = reason + + false + end + end + + def does_not_match_presence_of_scopes? + if scopes_missing_on_model.any? + true + else + inspected_scopes = scopes_present_on_model.map(&:inspect) + + reason = '' + + reason << inspected_scopes.to_sentence + + if inspected_scopes.many? + reason << " seem to be attributes" + else + reason << " seems to be an attribute" + end + + reason << " on #{model.name}." + + @failure_reason = reason + + false + end + end + + def scopes_present_on_model + @_present_scopes ||= expected_scopes.select do |scope| + model.method_defined?("#{scope}=") + end + end + + def scopes_missing_on_model + @_missing_scopes ||= expected_scopes.select do |scope| + !model.method_defined?("#{scope}=") + end + end + + def matches_uniqueness_without_scopes? + if existing_value_read.blank? + update_existing_record!(arbitrary_non_blank_value) + end + + disallows_value_of(existing_value_read, @expected_message) + end + + def does_not_match_uniqueness_without_scopes? + @failure_reason = nil + + if existing_value_read.blank? + update_existing_record!(arbitrary_non_blank_value) + end + + allows_value_of(existing_value_read, @expected_message) + end + + def matches_uniqueness_with_case_sensitivity_strategy? + if should_test_case_sensitivity? + value = existing_value_read + swapcased_value = value.swapcase + + if case_sensitivity_strategy == :sensitive + if value == swapcased_value + raise NonCaseSwappableValueError.create( + model: model, + attribute: @attribute, + value: value + ) end + + allows_value_of(swapcased_value, @expected_message) + else + disallows_value_of(swapcased_value, @expected_message) end else true end end - def validate_everything_except_duplicate_nils_or_blanks? - if (@options[:allow_nil] && existing_value.nil?) || - (@options[:allow_blank] && existing_value.blank?) - create_record_with_value - end + def does_not_match_uniqueness_with_case_sensitivity_strategy? + if should_test_case_sensitivity? + @failure_reason = nil + + value = existing_value_read + swapcased_value = value.swapcase + + if case_sensitivity_strategy == :sensitive + disallows_value_of(swapcased_value, @expected_message) + else + if value == swapcased_value + raise NonCaseSwappableValueError.create( + model: model, + attribute: @attribute, + value: value + ) + end - disallows_value_of(existing_value, @expected_message) + allows_value_of(swapcased_value, @expected_message) + end + else + true + end end - def create_record_with_value - @existing_record = create_record_in_database + def should_test_case_sensitivity? + case_sensitivity_strategy != :ignore && + existing_value_read.respond_to?(:swapcase) && + !existing_value_read.empty? end def model_class?(model_name) @@ -363,78 +747,393 @@ false end - def validate_after_scope_change? - if @options[:scopes].blank? - true - else - all_records = @subject.class.all - @options[:scopes].all? do |scope| - previous_value = all_records.map(&scope).max - - # Assume the scope is a foreign key if the field is nil - previous_value ||= correct_type_for_column(@subject.class.columns_hash[scope.to_s]) - - next_value = next_value_for(scope, previous_value) - - @subject.__send__("#{scope}=", next_value) - - if allows_value_of(existing_value, @expected_message) - @subject.__send__("#{scope}=", previous_value) - - @failure_message_when_negated << - " (with different value of #{scope})" - true - else - @failure_message << " (with different value of #{scope})" - false + def matches_uniqueness_with_scopes? + expected_scopes.none? || + all_scopes_are_booleans? || + expected_scopes.all? do |scope| + setting_next_value_for(scope) do + allows_value_of(existing_value_read, @expected_message) end end - end end - def correct_type_for_column(column) - if column.type == :string - '0' - elsif column.type == :datetime - DateTime.now - elsif column.type == :uuid - SecureRandom.uuid + def does_not_match_uniqueness_with_scopes? + expected_scopes.any? && + !all_scopes_are_booleans? && + expected_scopes.any? do |scope| + setting_next_value_for(scope) do + @failure_reason = nil + disallows_value_of(existing_value_read, @expected_message) + end + end + end + + def setting_next_value_for(scope) + previous_value = @all_records.map(&scope).compact.max + + next_value = + if previous_value.blank? + dummy_value_for(scope) + else + next_value_for(scope, previous_value) + end + + set_attribute_on_new_record!(scope, next_value) + + yield + ensure + set_attribute_on_new_record!(scope, previous_value) + end + + def dummy_value_for(scope) + column = column_for(scope) + + if column.respond_to?(:array) && column.array + [ dummy_scalar_value_for(column) ] else - 0 + dummy_scalar_value_for(column) end end + def dummy_scalar_value_for(column) + Shoulda::Matchers::Util.dummy_value_for(column.type) + end + def next_value_for(scope, previous_value) - if @subject.class.respond_to?(:defined_enums) && @subject.defined_enums[scope.to_s] + if previous_value.is_a?(Array) + [ next_scalar_value_for(scope, previous_value[0]) ] + else + next_scalar_value_for(scope, previous_value) + end + end + + def next_scalar_value_for(scope, previous_value) + column = column_for(scope) + + if column.type == :uuid + SecureRandom.uuid + elsif defined_as_enum?(scope) available_values = available_enum_values_for(scope, previous_value) available_values.keys.last - elsif scope.to_s =~ /_type$/ && model_class?(previous_value) + elsif polymorphic_type_attribute?(scope, previous_value) Uniqueness::TestModels.create(previous_value).to_s elsif previous_value.respond_to?(:next) previous_value.next elsif previous_value.respond_to?(:to_datetime) previous_value.to_datetime.next + elsif boolean_value?(previous_value) + !previous_value else previous_value.to_s.next end end + def all_scopes_are_booleans? + @options[:scopes].all? do |scope| + @all_records.map(&scope).all? { |s| boolean_value?(s) } + end + end + + def boolean_value?(value) + [true, false].include?(value) + end + + def defined_as_enum?(scope) + model.respond_to?(:defined_enums) && + new_record.defined_enums[scope.to_s] + end + + def polymorphic_type_attribute?(scope, previous_value) + scope.to_s =~ /_type$/ && model_class?(previous_value) + end + def available_enum_values_for(scope, previous_value) - @subject.defined_enums[scope.to_s].reject do |key, _| + new_record.defined_enums[scope.to_s].reject do |key, _| key == previous_value end end - def class_name - @subject.class.name + def set_attribute_on!(record_type, record, attribute_name, value) + attribute_setter = build_attribute_setter( + record, + attribute_name, + value + ) + attribute_setter.set! + + @attribute_setters[record_type] << attribute_setter + end + + def set_attribute_on_existing_record!(attribute_name, value) + set_attribute_on!( + :existing_record, + existing_record, + attribute_name, + value + ) + end + + def set_attribute_on_new_record!(attribute_name, value) + set_attribute_on!( + :new_record, + new_record, + attribute_name, + value + ) + end + + def attribute_setter_for_existing_record + @attribute_setters[:existing_record].last + end + + def attribute_setters_for_new_record + @attribute_setters[:new_record] + + [last_attribute_setter_used_on_new_record] + end + + def attribute_names_under_test + [@attribute] + expected_scopes + end + + def build_attribute_setter(record, attribute_name, value) + Shoulda::Matchers::ActiveModel::AllowValueMatcher::AttributeSetter.new( + matcher_name: :validate_uniqueness_of, + object: record, + attribute_name: attribute_name, + value: value, + ignore_interference_by_writer: ignore_interference_by_writer + ) + end + + def existing_value_read + existing_record.public_send(@attribute) + end + + def existing_value_written + if attribute_setter_for_existing_record + attribute_setter_for_existing_record.value_written + else + existing_value_read + end + end + + def column_for(scope) + model.columns_hash[scope.to_s] + end + + def column_limit_for(attribute) + column_for(attribute).try(:limit) + end + + def model + @given_record.class + end + + def failure_message_preface + prefix = '' + + if @existing_record_created + prefix << "After taking the given #{model.name}" + + if attribute_setter_for_existing_record + prefix << ', setting ' + prefix << description_for_attribute_setter( + attribute_setter_for_existing_record + ) + else + prefix << ", whose :#{attribute} is " + prefix << "‹#{existing_value_read.inspect}›" + end + + prefix << ", and saving it as the existing record, then" + else + if attribute_setter_for_existing_record + prefix << "Given an existing #{model.name}," + prefix << ' after setting ' + prefix << description_for_attribute_setter( + attribute_setter_for_existing_record + ) + prefix << ', then' + else + prefix << "Given an existing #{model.name} whose :#{attribute}" + prefix << ' is ' + prefix << Shoulda::Matchers::Util.inspect_value( + existing_value_read + ) + prefix << ', after' + end + end + + prefix << " making a new #{model.name} and setting " + + prefix << descriptions_for_attribute_setters_for_new_record + + prefix << ", the matcher expected the new #{model.name} to be" + + prefix + end + + def attribute_changed_value_message + <<-MESSAGE.strip +As indicated in the message above, +:#{last_attribute_setter_used_on_new_record.attribute_name} seems to be +changing certain values as they are set, and this could have something +to do with why this test is failing. If you or something else has +overridden the writer method for this attribute to normalize values by +changing their case in any way (for instance, ensuring that the +attribute is always downcased), then try adding +`ignoring_case_sensitivity` onto the end of the uniqueness matcher. +Otherwise, you may need to write the test yourself, or do something +different altogether. + MESSAGE + end + + def description_for_attribute_setter(attribute_setter, same_as_existing: nil) + description = "its :#{attribute_setter.attribute_name} to " + + if same_as_existing == false + description << 'a different value, ' + end + + description << Shoulda::Matchers::Util.inspect_value( + attribute_setter.value_written + ) + + if attribute_setter.attribute_changed_value? + description << ' (read back as ' + description << Shoulda::Matchers::Util.inspect_value( + attribute_setter.value_read + ) + description << ')' + end + + if same_as_existing == true + description << ' as well' + end + + description + end + + def descriptions_for_attribute_setters_for_new_record + attribute_setter_descriptions_for_new_record.to_sentence + end + + def attribute_setter_descriptions_for_new_record + attribute_setters_for_new_record.map do |attribute_setter| + same_as_existing = ( + attribute_setter.value_written == + existing_value_written + ) + description_for_attribute_setter( + attribute_setter, + same_as_existing: same_as_existing + ) + end end - def existing_value - value = existing_record.__send__(@attribute) - if @options[:case_insensitive] && value.respond_to?(:swapcase!) - value.swapcase! + def existing_and_new_values_are_same? + last_value_set_on_new_record == existing_value_written + end + + def last_attribute_setter_used_on_new_record + last_submatcher_run.last_attribute_setter_used + end + + def last_value_set_on_new_record + last_submatcher_run.last_value_set + end + + # @private + class AttributeSetters + include Enumerable + + def initialize + @attribute_setters = [] + end + + def <<(given_attribute_setter) + index = find_index_of(given_attribute_setter) + + if index + @attribute_setters[index] = given_attribute_setter + else + @attribute_setters << given_attribute_setter + end + end + + def +(other_attribute_setters) + dup.tap do |attribute_setters| + other_attribute_setters.each do |attribute_setter| + attribute_setters << attribute_setter + end + end + end + + def each(&block) + @attribute_setters.each(&block) + end + + def last + @attribute_setters.last + end + + private + + def find_index_of(given_attribute_setter) + @attribute_setters.find_index do |attribute_setter| + attribute_setter.attribute_name == + given_attribute_setter.attribute_name + end + end + end + + # @private + class NonCaseSwappableValueError < Shoulda::Matchers::Error + attr_accessor :model, :attribute, :value + + def message + Shoulda::Matchers.word_wrap <<-MESSAGE +Your #{model.name} model has a uniqueness validation on :#{attribute} which is +declared to be case-sensitive, but the value the uniqueness matcher used, +#{value.inspect}, doesn't contain any alpha characters, so using it to +test the case-sensitivity part of the validation is ineffective. There are +two possible solutions for this depending on what you're trying to do here: + +a) If you meant for the validation to be case-sensitive, then you need to give + the uniqueness matcher a saved instance of #{model.name} with a value for + :#{attribute} that contains alpha characters. + +b) If you meant for the validation to be case-insensitive, then you need to + add `case_sensitive: false` to the validation and add `case_insensitive` to + the matcher. + +For more information, please see: + +http://matchers.shoulda.io/docs/v#{Shoulda::Matchers::VERSION}/file.NonCaseSwappableValueError.html + MESSAGE + end + end + + # @private + class ExistingRecordInvalid < Shoulda::Matchers::Error + include Shoulda::Matchers::ActiveModel::Helpers + + attr_accessor :underlying_exception + + def message + <<-MESSAGE.strip +validate_uniqueness_of works by matching a new record against an +existing record. If there is no existing record, it will create one +using the record you provide. + +While doing this, the following error was raised: + +#{Shoulda::Matchers::Util.indent(underlying_exception.message, 2)} + +The best way to fix this is to provide the matcher with a record where +any required attributes are filled in with valid values beforehand. + MESSAGE end - value end end end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_record.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/active_record.rb 2020-02-18 07:23:52.000000000 +0000 @@ -6,6 +6,8 @@ require "shoulda/matchers/active_record/association_matchers/order_matcher" require "shoulda/matchers/active_record/association_matchers/through_matcher" require "shoulda/matchers/active_record/association_matchers/dependent_matcher" +require "shoulda/matchers/active_record/association_matchers/required_matcher" +require "shoulda/matchers/active_record/association_matchers/optional_matcher" require "shoulda/matchers/active_record/association_matchers/source_matcher" require "shoulda/matchers/active_record/association_matchers/model_reflector" require "shoulda/matchers/active_record/association_matchers/model_reflection" @@ -13,6 +15,8 @@ require "shoulda/matchers/active_record/have_db_column_matcher" require "shoulda/matchers/active_record/have_db_index_matcher" require "shoulda/matchers/active_record/have_readonly_attribute_matcher" +require "shoulda/matchers/active_record/have_rich_text_matcher" +require "shoulda/matchers/active_record/have_secure_token_matcher" require "shoulda/matchers/active_record/serialize_matcher" require "shoulda/matchers/active_record/accept_nested_attributes_for_matcher" require "shoulda/matchers/active_record/define_enum_for_matcher" @@ -21,6 +25,8 @@ module Shoulda module Matchers + # This module provides matchers that are used to test behavior within + # ActiveRecord classes. module ActiveRecord end end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/assertion_error.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/assertion_error.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/assertion_error.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/assertion_error.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -module Shoulda - module Matchers - if defined?(ActiveSupport::TestCase) - # @private - AssertionError = ActiveSupport::TestCase::Assertion - elsif Gem.ruby_version >= Gem::Version.new('1.8') && Gem.ruby_version < Gem::Version.new('1.9') - require 'test/unit' - # @private - AssertionError = Test::Unit::AssertionFailedError - elsif defined?(Test::Unit::AssertionFailedError) - # Test::Unit has been loaded already, so we use it - # @private - AssertionError = Test::Unit::AssertionFailedError - elsif Gem.ruby_version >= Gem::Version.new("1.9") - begin - require 'minitest' - rescue LoadError - require 'minitest/unit' - ensure - # @private - AssertionError = MiniTest::Assertion - end - else - raise 'No unit test library available' - end - end -end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/configuration.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/configuration.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/configuration.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/configuration.rb 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,31 @@ +module Shoulda + module Matchers + # @private + def self.configure + yield configuration + end + + # @private + def self.integrations + configuration.integrations + end + + # @private + def self.configuration + @_configuration ||= Configuration.new + end + + # @private + class Configuration + attr_reader :integrations + + def initialize + @integrations = nil + end + + def integrate(&block) + @integrations = Integrations::Configuration.apply(&block) + end + end + end +end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/doublespeak/double_collection.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/doublespeak/double_collection.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/doublespeak/double_collection.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/doublespeak/double_collection.rb 2020-02-18 07:23:52.000000000 +0000 @@ -3,7 +3,8 @@ module Doublespeak # @private class DoubleCollection - def initialize(klass) + def initialize(world, klass) + @world = world @klass = klass @doubles_by_method_name = {} end @@ -28,6 +29,12 @@ end end + def calls_by_method_name + doubles_by_method_name.reduce({}) do |hash, (method_name, double)| + hash.merge method_name => double.calls.map(&:args) + end + end + def calls_to(method_name) double = doubles_by_method_name[method_name] @@ -40,14 +47,16 @@ protected - attr_reader :klass, :doubles_by_method_name + attr_reader :world, :klass, :doubles_by_method_name def register_double(method_name, implementation_type) - implementation = - DoubleImplementationRegistry.find(implementation_type) - double = Double.new(klass, method_name, implementation) - doubles_by_method_name[method_name] = double - double + doubles_by_method_name.fetch(method_name) do + implementation = + DoubleImplementationRegistry.find(implementation_type) + double = Double.new(world, klass, method_name, implementation) + doubles_by_method_name[method_name] = double + double + end end end end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/doublespeak/double.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/doublespeak/double.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/doublespeak/double.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/doublespeak/double.rb 2020-02-18 07:23:52.000000000 +0000 @@ -5,12 +5,21 @@ class Double attr_reader :calls - def initialize(klass, method_name, implementation) + def initialize(world, klass, method_name, implementation) + @world = world @klass = klass @method_name = method_name @implementation = implementation @activated = false @calls = [] + + if world.doubles_activated? + activate + end + end + + def activated? + @activated end def to_return(value = nil, &block) @@ -36,36 +45,54 @@ end end - def record_call(args, block) - calls << MethodCall.new(args, block) + def record_call(call) + calls << call end - def call_original_method(object, args, block) - if original_method - original_method.bind(object).call(*args, &block) + def call_original_method(call) + unbound_method = world.original_method_for(klass, call.method_name) + + if unbound_method + unbound_method.bind(call.object).call(*call.args, &call.block) end end protected - attr_reader :klass, :method_name, :implementation, :original_method + attr_reader :world, :klass, :method_name, :implementation, + :original_method def store_original_method - @original_method = klass.instance_method(method_name) + world.store_original_method_for(klass, method_name) end def replace_method_with_double - implementation = @implementation double = self + implementation = @implementation + _method_name = method_name + + if klass.instance_methods(false).include?(method_name) + klass.__send__(:remove_method, method_name) + end klass.__send__(:define_method, method_name) do |*args, &block| - implementation.call(double, self, args, block) + call = MethodCall.new( + double: double, + object: self, + method_name: _method_name, + args: args, + block: block, + caller: caller + ) + implementation.call(call) end end def restore_original_method - original_method = @original_method + original_method = world.original_method_for(klass, method_name) + klass.__send__(:remove_method, method_name) + klass.__send__(:define_method, method_name) do |*args, &block| original_method.bind(self).call(*args, &block) end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/doublespeak/method_call.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/doublespeak/method_call.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/doublespeak/method_call.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/doublespeak/method_call.rb 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,44 @@ +module Shoulda + module Matchers + module Doublespeak + # @private + class MethodCall + attr_accessor :return_value + attr_reader :method_name, :args, :caller, :block, :object, :double + + def initialize(args) + @method_name = args.fetch(:method_name) + @args = args.fetch(:args) + @caller = args.fetch(:caller) + @block = args[:block] + @double = args[:double] + @object = args[:object] + @return_value = nil + end + + def with_return_value(return_value) + dup.tap do |call| + call.return_value = return_value + end + end + + def ==(other) + other.is_a?(self.class) && + method_name == other.method_name && + args == other.args && + block == other.block && + double == other.double && + object == other.object + end + + def to_hash + { method_name: method_name, args: args } + end + + def inspect + "#<#{self.class.name} #{to_hash.inspect}>" + end + end + end + end +end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/doublespeak/object_double.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/doublespeak/object_double.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/doublespeak/object_double.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/doublespeak/object_double.rb 2020-02-18 07:23:52.000000000 +0000 @@ -14,13 +14,23 @@ @calls_by_method_name[method_name] || [] end - def respond_to?(name, include_private = nil) + def respond_to?(_name, _include_private = nil) + true + end + + def respond_to_missing?(_name, _include_all) true end def method_missing(method_name, *args, &block) - calls << MethodCallWithName.new(method_name, args, block) - (calls_by_method_name[method_name] ||= []) << MethodCall.new(args, block) + call = MethodCall.new( + method_name: method_name, + args: args, + block: block, + caller: ::Kernel.caller + ) + calls << call + (calls_by_method_name[method_name] ||= []) << call nil end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/doublespeak/proxy_implementation.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/doublespeak/proxy_implementation.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/doublespeak/proxy_implementation.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/doublespeak/proxy_implementation.rb 2020-02-18 07:23:52.000000000 +0000 @@ -17,9 +17,10 @@ @stub_implementation = stub_implementation end - def call(double, object, args, block) - stub_implementation.call(double, object, args, block) - double.call_original_method(object, args, block) + def call(call) + return_value = call.double.call_original_method(call) + stub_implementation.call(call.with_return_value(return_value)) + return_value end protected diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/doublespeak/structs.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/doublespeak/structs.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/doublespeak/structs.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/doublespeak/structs.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ -module Shoulda - module Matchers - module Doublespeak - # @private - MethodCall = Struct.new(:args, :block) - # @private - MethodCallWithName = Struct.new(:method_name, :args, :block) - end - end -end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/doublespeak/stub_implementation.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/doublespeak/stub_implementation.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/doublespeak/stub_implementation.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/doublespeak/stub_implementation.rb 2020-02-18 07:23:52.000000000 +0000 @@ -21,9 +21,9 @@ end end - def call(double, object, args, block) - double.record_call(args, block) - implementation.call(object, args, block) + def call(call) + call.double.record_call(call) + implementation.call(call) end protected diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/doublespeak/world.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/doublespeak/world.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/doublespeak/world.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/doublespeak/world.rb 2020-02-18 07:23:52.000000000 +0000 @@ -3,17 +3,39 @@ module Doublespeak # @private class World + def initialize + @doubles_activated = false + end + def double_collection_for(klass) - double_collections_by_class[klass] ||= DoubleCollection.new(klass) + double_collections_by_class[klass] ||= + DoubleCollection.new(self, klass) + end + + def store_original_method_for(klass, method_name) + original_methods_for_class(klass)[method_name] ||= + klass.instance_method(method_name) + end + + def original_method_for(klass, method_name) + if original_methods_by_class.key?(klass) + original_methods_by_class[klass][method_name] + end end def with_doubles_activated + @doubles_activated = true activate yield ensure + @doubles_activated = false deactivate end + def doubles_activated? + @doubles_activated + end + private def activate @@ -31,6 +53,14 @@ def double_collections_by_class @_double_collections_by_class ||= {} end + + def original_methods_by_class + @_original_methods_by_class ||= {} + end + + def original_methods_for_class(klass) + original_methods_by_class[klass] ||= {} + end end end end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/doublespeak.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/doublespeak.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/doublespeak.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/doublespeak.rb 2020-02-18 07:23:52.000000000 +0000 @@ -13,6 +13,16 @@ def world @_world ||= World.new end + + def debugging_enabled? + ENV['DEBUG_DOUBLESPEAK'] == '1' + end + + def debug(&block) + if debugging_enabled? + puts block.call + end + end end end end @@ -21,8 +31,8 @@ require 'shoulda/matchers/doublespeak/double' require 'shoulda/matchers/doublespeak/double_collection' require 'shoulda/matchers/doublespeak/double_implementation_registry' +require 'shoulda/matchers/doublespeak/method_call' require 'shoulda/matchers/doublespeak/object_double' require 'shoulda/matchers/doublespeak/proxy_implementation' -require 'shoulda/matchers/doublespeak/structs' require 'shoulda/matchers/doublespeak/stub_implementation' require 'shoulda/matchers/doublespeak/world' diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/error.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/error.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/error.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/error.rb 2020-02-18 07:23:52.000000000 +0000 @@ -20,6 +20,10 @@ def message "" end + + def inspect + %(#<#{self.class}: #{message}>) + end end end end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/independent/delegate_method_matcher.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/independent/delegate_method_matcher.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/independent/delegate_method_matcher.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/independent/delegate_method_matcher.rb 2020-02-18 07:23:52.000000000 +0000 @@ -1,3 +1,6 @@ +require 'shoulda/matchers/doublespeak' +require 'shoulda/matchers/matcher_context' + module Shoulda module Matchers module Independent @@ -26,8 +29,8 @@ # it { should delegate_method(:deliver).to(:post_office) } # end # - # # Test::Unit - # class CourierTest < Test::Unit::TestCase + # # Minitest + # class CourierTest < Minitest::Test # should delegate_method(:deliver).to(:post_office) # end # @@ -77,8 +80,8 @@ # it { should delegate_method(:deliver).to(:post_office).as(:ship) } # end # - # # Test::Unit - # class CourierTest < Test::Unit::TestCase + # # Minitest + # class CourierTest < Minitest::Test # should delegate_method(:deliver).to(:post_office).as(:ship) # end # @@ -100,8 +103,8 @@ # it { should delegate_method(:title).to(:site).with_prefix(:root) } # end # - # # Test::Unit - # class PageTest < Test::Unit::TestCase + # # Minitest + # class PageTest < Minitest::Test # should delegate_method(:name).to(:site).with_prefix # should delegate_method(:name).to(:site).with_prefix(true) # should delegate_method(:title).to(:site).with_prefix(:root) @@ -138,13 +141,33 @@ # end # end # - # # Test::Unit - # class CourierTest < Test::Unit::TestCase + # # Minitest + # class CourierTest < Minitest::Test # should delegate_method(:deliver_package). # to(:post_office). # with_arguments(expedited: true) # end # + # ##### allow_nil + # + # Use `allow_nil` if the delegation accounts for the fact that your + # delegate object could be nil. (This is mostly intended as an analogue to + # the `allow_nil` option that Rails' `delegate` helper takes.) + # + # class Account + # delegate :plan, to: :subscription, allow_nil: true + # end + # + # # RSpec + # describe Account do + # it { should delegate_method(:plan).to(:subscription).allow_nil } + # end + # + # # Minitest + # class PageTest < Minitest::Test + # should delegate_method(:plan).to(:subscription).allow_nil + # end + # # @return [DelegateMethodMatcher] # def delegate_method(delegating_method) @@ -159,10 +182,11 @@ @delegate_method = @delegating_method @delegate_object = Doublespeak::ObjectDouble.new - @delegated_arguments = [] - @delegate_object_reader_method = nil + @context = nil @subject = nil - @subject_double_collection = nil + @delegate_object_reader_method = nil + @delegated_arguments = [] + @expects_to_allow_nil_delegate_object = false end def in_context(context) @@ -177,11 +201,13 @@ subject_has_delegating_method? && subject_has_delegate_object_reader_method? && - subject_delegates_to_delegate_object_correctly? + subject_delegates_to_delegate_object_correctly? && + subject_handles_nil_delegate_object? end def description - string = "delegate #{formatted_delegating_method_name} to " + + string = + "delegate #{formatted_delegating_method_name} to the " + "#{formatted_delegate_object_reader_method_name} object" if delegated_arguments.any? @@ -192,6 +218,12 @@ string << " as #{formatted_delegate_method}" end + if expects_to_allow_nil_delegate_object? + string << ", allowing " + string << formatted_delegate_object_reader_method_name + string << " to return nil" + end + string end @@ -217,6 +249,11 @@ self end + def allow_nil + @expects_to_allow_nil_delegate_object = true + self + end + def build_delegating_method_prefix(prefix) case prefix when true, nil then delegate_object_reader_method @@ -225,17 +262,30 @@ end def failure_message - "Expected #{class_under_test} to #{description}\n" + - "Method calls sent to " + - "#{formatted_delegate_object_reader_method_name(include_module: true)}:" + - formatted_calls_on_delegate_object + message = "Expected #{class_under_test} to #{description}.\n\n" + + if failed_to_allow_nil_delegate_object? + message << formatted_delegating_method_name(include_module: true) + message << ' did delegate to ' + message << formatted_delegate_object_reader_method_name + message << ' when it was non-nil, but it failed to account ' + message << 'for when ' + message << formatted_delegate_object_reader_method_name + message << ' *was* nil.' + else + message << 'Method calls sent to ' + message << formatted_delegate_object_reader_method_name( + include_module: true, + ) + message << ": #{formatted_calls_on_delegate_object}" + end + + Shoulda::Matchers.word_wrap(message) end - alias failure_message_for_should failure_message def failure_message_when_negated - "Expected #{class_under_test} not to #{description}, but it did" + "Expected #{class_under_test} not to #{description}, but it did." end - alias failure_message_for_should_not failure_message_when_negated protected @@ -245,7 +295,6 @@ :delegating_method, :method, :delegate_method, - :subject_double_collection, :delegate_object, :delegate_object_reader_method @@ -269,6 +318,10 @@ end end + def expects_to_allow_nil_delegate_object? + @expects_to_allow_nil_delegate_object + end + def formatted_delegate_method(options = {}) formatted_method_name_for(delegate_method, options) end @@ -328,11 +381,7 @@ end def subject_delegates_to_delegate_object_correctly? - register_subject_double_collection - - Doublespeak.with_doubles_activated do - subject.public_send(delegating_method, *delegated_arguments) - end + call_delegating_method_with_delegate_method_returning(delegate_object) if delegated_arguments.any? delegate_object_received_call_with_delegated_arguments? @@ -341,13 +390,44 @@ end end - def register_subject_double_collection + def subject_handles_nil_delegate_object? + @subject_handled_nil_delegate_object = + if expects_to_allow_nil_delegate_object? + begin + call_delegating_method_with_delegate_method_returning(nil) + true + rescue Module::DelegationError + false + rescue NoMethodError => error + if error.message =~ /undefined method `#{delegate_method}' for nil:NilClass/ + false + else + raise error + end + end + else + true + end + end + + def failed_to_allow_nil_delegate_object? + expects_to_allow_nil_delegate_object? && + !@subject_handled_nil_delegate_object + end + + def call_delegating_method_with_delegate_method_returning(value) + register_subject_double_collection_to(value) + + Doublespeak.with_doubles_activated do + subject.public_send(delegating_method, *delegated_arguments) + end + end + + def register_subject_double_collection_to(returned_value) double_collection = Doublespeak.double_collection_for(subject.singleton_class) double_collection.register_stub(delegate_object_reader_method). - to_return(delegate_object) - - @subject_double_collection = double_collection + to_return(returned_value) end def calls_to_delegate_method @@ -362,7 +442,7 @@ string = "" if calls_on_delegate_object.any? - string << "\n" + string << "\n\n" calls_on_delegate_object.each_with_index do |call, i| name = call.method_name args = call.args.map { |arg| arg.inspect }.join(', ') diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/independent.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/independent.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/independent.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/independent.rb 2020-02-18 07:23:52.000000000 +0000 @@ -4,7 +4,8 @@ module Shoulda module Matchers - # Matchers for non-Rails-dependent code. + # This module provides matchers that are used to test behavior outside of + # Rails-specific classes. module Independent end end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/integrations/configuration_error.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/integrations/configuration_error.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/integrations/configuration_error.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/integrations/configuration_error.rb 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,9 @@ +module Shoulda + module Matchers + module Integrations + # @private + class ConfigurationError < StandardError + end + end + end +end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/integrations/configuration.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/integrations/configuration.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/integrations/configuration.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/integrations/configuration.rb 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,72 @@ +require 'set' + +module Shoulda + module Matchers + module Integrations + # @private + class Configuration + def self.apply(&block) + new(&block).apply + end + + attr_reader :test_frameworks + + def initialize(&block) + @test_frameworks = Set.new + @libraries = Set.new + + test_framework :missing_test_framework + library :missing_library + + block.call(self) + end + + def test_framework(name) + clear_default_test_framework + @test_frameworks << Integrations.find_test_framework!(name) + end + + def library(name) + @libraries << Integrations.find_library!(name) + end + + def apply + if no_test_frameworks_added? && no_libraries_added? + raise ConfigurationError, < { ActiveSupport::TestCase }, - -> { Minitest::Test }, - -> { MiniTest::Unit::TestCase }, - -> { Test::Unit::TestCase } - ] - end - - def self.resolve_constant(future_constant) - future_constant.call - rescue NameError - nil - end - - def self.detected_test_case_constants - possible_test_case_constants. - map { |future_constant| resolve_constant(future_constant) }. - compact - end - - def self.test_case_constants - @_test_case_constants ||= detected_test_case_constants - end - end - end - - # @private - def self.nunit_test_case_constants - Integrations::NUnitTestCaseDetection.test_case_constants - end - end -end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/integrations/rails.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/integrations/rails.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/integrations/rails.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/integrations/rails.rb 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,12 @@ +module Shoulda + module Matchers + module Integrations + # @private + module Rails + def rails? + true + end + end + end + end +end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/integrations/registry.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/integrations/registry.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/integrations/registry.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/integrations/registry.rb 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,28 @@ +module Shoulda + module Matchers + module Integrations + # @private + class Registry + def register(klass, name) + registry[name] = klass + end + + def find!(name) + find_class!(name).new + end + + private + + def registry + @_registry ||= {} + end + + def find_class!(name) + registry.fetch(name) do + raise ArgumentError, "'#{name}' is not registered" + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/integrations/rspec.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/integrations/rspec.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/integrations/rspec.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/integrations/rspec.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,19 +0,0 @@ -# :enddoc: - -if RSpec.respond_to?(:configure) - RSpec.configure do |config| - config.include Shoulda::Matchers::Independent - - if defined?(ActiveRecord) - config.include Shoulda::Matchers::ActiveRecord - end - - if defined?(ActiveModel) - config.include Shoulda::Matchers::ActiveModel - end - - if defined?(ActionController) - config.include Shoulda::Matchers::ActionController - end - end -end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/integrations/test_frameworks/active_support_test_case.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/integrations/test_frameworks/active_support_test_case.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/integrations/test_frameworks/active_support_test_case.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/integrations/test_frameworks/active_support_test_case.rb 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,37 @@ +module Shoulda + module Matchers + module Integrations + module TestFrameworks + # @private + class ActiveSupportTestCase + Integrations.register_test_framework(self, :active_support_test_case) + + def validate! + end + + def include(*modules, **options) + test_case_class.include(*modules) + end + + def n_unit? + true + end + + def present? + true + end + + protected + + attr_reader :configuration + + private + + def test_case_class + ActiveSupport::TestCase + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/integrations/test_frameworks/minitest_4.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/integrations/test_frameworks/minitest_4.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/integrations/test_frameworks/minitest_4.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/integrations/test_frameworks/minitest_4.rb 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,36 @@ +module Shoulda + module Matchers + module Integrations + module TestFrameworks + # @private + class Minitest4 + Integrations.register_test_framework(self, :minitest_4) + + def validate! + end + + def include(*modules, **options) + test_case_class.class_eval do + include(*modules) + extend(*modules) + end + end + + def n_unit? + true + end + + def present? + true + end + + private + + def test_case_class + MiniTest::Unit::TestCase + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/integrations/test_frameworks/minitest_5.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/integrations/test_frameworks/minitest_5.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/integrations/test_frameworks/minitest_5.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/integrations/test_frameworks/minitest_5.rb 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,37 @@ +module Shoulda + module Matchers + module Integrations + module TestFrameworks + # @private + class Minitest5 + Integrations.register_test_framework(self, :minitest_5) + Integrations.register_test_framework(self, :minitest) + + def validate! + end + + def include(*modules, **options) + test_case_class.class_eval do + include(*modules) + extend(*modules) + end + end + + def n_unit? + true + end + + def present? + true + end + + private + + def test_case_class + Minitest::Test + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/integrations/test_frameworks/missing_test_framework.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/integrations/test_frameworks/missing_test_framework.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/integrations/test_frameworks/missing_test_framework.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/integrations/test_frameworks/missing_test_framework.rb 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,40 @@ +module Shoulda + module Matchers + module Integrations + module TestFrameworks + # @private + class MissingTestFramework + Integrations.register_test_framework(self, :missing_test_framework) + + def validate! + raise TestFrameworkNotConfigured, <<-EOT +You need to set a test framework. Please add the following to your +test helper: + +Shoulda::Matchers.configure do |config| + config.integrate do |with| + # Choose one: + with.test_framework :rspec + with.test_framework :minitest # or, :minitest_5 + with.test_framework :minitest_4 + with.test_framework :test_unit + end +end +EOT + end + + def include(*modules, **options) + end + + def n_unit? + false + end + + def present? + false + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/integrations/test_frameworks/rspec.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/integrations/test_frameworks/rspec.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/integrations/test_frameworks/rspec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/integrations/test_frameworks/rspec.rb 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,29 @@ +module Shoulda + module Matchers + module Integrations + module TestFrameworks + # @private + class Rspec + Integrations.register_test_framework(self, :rspec) + + def validate! + end + + def include(*modules, **options) + ::RSpec.configure do |config| + config.include(*modules, **options) + end + end + + def n_unit? + false + end + + def present? + true + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/integrations/test_frameworks/test_unit.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/integrations/test_frameworks/test_unit.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/integrations/test_frameworks/test_unit.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/integrations/test_frameworks/test_unit.rb 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,36 @@ +module Shoulda + module Matchers + module Integrations + module TestFrameworks + # @private + class TestUnit + Integrations.register_test_framework(self, :test_unit) + + def validate! + end + + def include(*modules, **options) + test_case_class.class_eval do + include(*modules) + extend(*modules) + end + end + + def n_unit? + true + end + + def present? + true + end + + private + + def test_case_class + ::Test::Unit::TestCase + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/integrations/test_frameworks.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/integrations/test_frameworks.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/integrations/test_frameworks.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/integrations/test_frameworks.rb 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,16 @@ +require 'shoulda/matchers/integrations/test_frameworks/active_support_test_case' +require 'shoulda/matchers/integrations/test_frameworks/minitest_4' +require 'shoulda/matchers/integrations/test_frameworks/minitest_5' +require 'shoulda/matchers/integrations/test_frameworks/missing_test_framework' +require 'shoulda/matchers/integrations/test_frameworks/rspec' +require 'shoulda/matchers/integrations/test_frameworks/test_unit' + +module Shoulda + module Matchers + module Integrations + # @private + module TestFrameworks + end + end + end +end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/integrations/test_unit.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/integrations/test_unit.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/integrations/test_unit.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/integrations/test_unit.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -# :enddoc: -require 'shoulda/matchers/integrations/nunit_test_case_detection' - -Shoulda::Matchers.nunit_test_case_constants.each do |constant| - constant.class_eval do - include Shoulda::Matchers::Independent - extend Shoulda::Matchers::Independent - end -end - -if defined?(ActionController::TestCase) - ActionController::TestCase.class_eval do - include Shoulda::Matchers::ActionController - extend Shoulda::Matchers::ActionController - - def subject - @controller - end - end -end - -if defined?(ActiveSupport::TestCase) - ActiveSupport::TestCase.class_eval do - if defined?(Shoulda::Matchers::ActiveRecord) - include Shoulda::Matchers::ActiveRecord - extend Shoulda::Matchers::ActiveRecord - end - - if defined?(Shoulda::Matchers::ActiveModel) - include Shoulda::Matchers::ActiveModel - extend Shoulda::Matchers::ActiveModel - end - end -end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/integrations.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/integrations.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/integrations.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/integrations.rb 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,43 @@ +module Shoulda + module Matchers + # @private + module Integrations + class << self + def register_library(klass, name) + library_registry.register(klass, name) + end + + def find_library!(name) + library_registry.find!(name) + end + + def register_test_framework(klass, name) + test_framework_registry.register(klass, name) + end + + def find_test_framework!(name) + test_framework_registry.find!(name) + end + + private + + def library_registry + @_library_registry ||= Registry.new + end + + def test_framework_registry + @_test_framework_registry ||= Registry.new + end + end + end + end +end + +require 'shoulda/matchers/integrations/configuration' +require 'shoulda/matchers/integrations/configuration_error' +require 'shoulda/matchers/integrations/inclusion' +require 'shoulda/matchers/integrations/rails' +require 'shoulda/matchers/integrations/registry' + +require 'shoulda/matchers/integrations/libraries' +require 'shoulda/matchers/integrations/test_frameworks' diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/rails_shim.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/rails_shim.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/rails_shim.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/rails_shim.rb 2020-02-18 07:23:52.000000000 +0000 @@ -1,110 +1,210 @@ module Shoulda module Matchers # @private - class RailsShim - def self.layouts_ivar - if action_pack_major_version >= 4 - '@_layouts' - else - '@layouts' + module RailsShim + class << self + def action_pack_gte_5? + Gem::Requirement.new('>= 5').satisfied_by?(action_pack_version) + end + + def action_pack_lt_5? + Gem::Requirement.new('< 5').satisfied_by?(action_pack_version) + end + + def action_pack_version + Gem::Version.new(::ActionPack::VERSION::STRING) + rescue NameError + Gem::Version.new('0') + end + + def active_record_gte_5? + Gem::Requirement.new('>= 5').satisfied_by?(active_record_version) + end + + def active_record_version + Gem::Version.new(::ActiveRecord::VERSION::STRING) + rescue NameError + Gem::Version.new('0') + end + + def generate_validation_message( + record, + attribute, + type, + model_name, + options + ) + if record && record.errors.respond_to?(:generate_message) + record.errors.generate_message(attribute.to_sym, type, options) + else + simply_generate_validation_message( + attribute, + type, + model_name, + options, + ) + end + rescue RangeError + simply_generate_validation_message( + attribute, + type, + model_name, + options, + ) + end + + def make_controller_request(context, verb, action, request_params) + params = + if action_pack_gte_5? + { params: request_params } + else + request_params + end + + context.__send__(verb, action, params) + end + + def serialized_attributes_for(model) + attribute_types_for(model). + inject({}) do |hash, (attribute_name, attribute_type)| + if attribute_type.is_a?(::ActiveRecord::Type::Serialized) + hash.merge(attribute_name => attribute_type.coder) + else + hash + end + end + rescue NotImplementedError + {} + end + + def attribute_serialization_coder_for(model, attribute_name) + serialized_attributes_for(model)[attribute_name.to_s] + end + + def tables_and_views(connection) + if active_record_gte_5? + connection.data_sources + else + connection.tables + end end - end - def self.flashes_ivar - if action_pack_major_version >= 4 - :@flashes - else - :@used + def verb_for_update + :patch end - end - def self.clean_scope(klass) - if active_record_major_version == 4 - klass.all - else - klass.scoped + def validation_message_key_for_association_required_option + if active_record_gte_5? + :required + else + :blank + end end - end - def self.validates_confirmation_of_error_attribute(matcher) - if active_model_major_version == 4 - matcher.confirmation_attribute - else - matcher.attribute + def parent_of(mod) + if mod.respond_to?(:module_parent) + mod.module_parent + else + mod.parent + end end - end - def self.verb_for_update - if action_pack_gte_4_1? - :patch - else - :put + def has_secure_password?(record, attribute_name) + if secure_password_module + attribute_name == :password && + record.class.ancestors.include?(secure_password_module) + else + record.respond_to?("authenticate_#{attribute_name}") + end end - end - def self.type_cast_default_for(model, column) - if model.respond_to?(:column_defaults) - # Rails 4.2 - model.column_defaults[column.name] - else - column.default + def digestible_attributes_in(record) + record.methods.inject([]) do |array, method_name| + match = method_name.to_s.match( + /\A(\w+)_(?:confirmation|digest)=\Z/, + ) + + if match + array.concat([match[1].to_sym]) + else + array + end + end end - end - def self.serialized_attributes_for(model) - if defined?(::ActiveRecord::Type::Serialized) - # Rails 5+ - model.columns.select do |column| - column.cast_type.is_a?(::ActiveRecord::Type::Serialized) - end.inject({}) do |hash, column| - hash[column.name.to_s] = column.cast_type.coder - hash + def secure_password_module + ::ActiveModel::SecurePassword::InstanceMethodsOnActivation + rescue NameError + nil + end + + def attribute_types_for(model) + if model.respond_to?(:attribute_types) + model.attribute_types + elsif model.respond_to?(:type_for_attribute) + model.columns.inject({}) do |hash, column| + key = column.name.to_s + value = model.type_for_attribute(column.name) + hash.merge(key => value) + end + else + raise NotImplementedError end - else - model.serialized_attributes end - end - def self.generate_validation_message(record, attribute, type, model_name, options) - if record && record.errors.respond_to?(:generate_message) - record.errors.generate_message(attribute.to_sym, type, options) - else - simply_generate_validation_message(attribute, type, model_name, options) + def attribute_type_for(model, attribute_name) + attribute_types_for(model)[attribute_name.to_s] + rescue NotImplementedError + if model.respond_to?(:type_for_attribute) + model.type_for_attribute(attribute_name) + else + FakeAttributeType.new(model, attribute_name) + end end - rescue RangeError - simply_generate_validation_message(attribute, type, model_name, options) - end - - def self.simply_generate_validation_message(attribute, type, model_name, options) - default_translation_keys = [ - :"activerecord.errors.models.#{model_name}.#{type}", - :"activerecord.errors.messages.#{type}", - :"errors.attributes.#{attribute}.#{type}", - :"errors.messages.#{type}" - ] - primary_translation_key = :"activerecord.errors.models.#{model_name}.attributes.#{attribute}.#{type}" - translate_options = { default: default_translation_keys }.merge(options) - I18n.translate(primary_translation_key, translate_options) - end - - def self.active_record_major_version - ::ActiveRecord::VERSION::MAJOR - end - def self.active_model_major_version - ::ActiveModel::VERSION::MAJOR - end + def supports_full_attributes_api?(model) + defined?(::ActiveModel::Attributes) && + model.respond_to?(:attribute_types) + end + + private + + def simply_generate_validation_message( + attribute, + type, + model_name, + options + ) + default_translation_keys = [ + :"activemodel.errors.models.#{model_name}.attributes.#{attribute}.#{type}", + :"activemodel.errors.models.#{model_name}.#{type}", + :"activemodel.errors.messages.#{type}", + :"activerecord.errors.models.#{model_name}.attributes.#{attribute}.#{type}", + :"activerecord.errors.models.#{model_name}.#{type}", + :"activerecord.errors.messages.#{type}", + :"errors.attributes.#{attribute}.#{type}", + :"errors.messages.#{type}", + ] + primary_translation_key = default_translation_keys.shift + translate_options = + { default: default_translation_keys }.merge(options) + I18n.translate(primary_translation_key, translate_options) + end + + class FakeAttributeType + def initialize(model, attribute_name) + @model = model + @attribute_name = attribute_name + end - def self.action_pack_major_version - ::ActionPack::VERSION::MAJOR - end + def coder + nil + end - def self.action_pack_gte_4_1? - Gem::Requirement.new('>= 4.1').satisfied_by?(action_pack_version) - end + private - def self.action_pack_version - Gem::Version.new(::ActionPack::VERSION::STRING) + attr_reader :model, :attribute_name + end end end end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/routing.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/routing.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/routing.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/routing.rb 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,10 @@ +module Shoulda + module Matchers + # @private + module Routing + def route(method, path, port: nil) + ActionController::RouteMatcher.new(self, method, path, port: port) + end + end + end +end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/util/word_wrap.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/util/word_wrap.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/util/word_wrap.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/util/word_wrap.rb 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,211 @@ +module Shoulda + module Matchers + # @private + module WordWrap + TERMINAL_WIDTH = 72 + + def word_wrap(document, options = {}) + Document.new(document, options).wrap + end + end + + extend WordWrap + + # @private + class Document + def initialize(document, indent: 0) + @document = document + @indent = indent + end + + def wrap + wrapped_paragraphs.map { |lines| lines.join("\n") }.join("\n\n") + end + + protected + + attr_reader :document, :indent + + private + + def paragraphs + document.split(/\n{2,}/) + end + + def wrapped_paragraphs + paragraphs.map do |paragraph| + Paragraph.new(paragraph, indent: indent).wrap + end + end + end + + # @private + class Text < ::String + LIST_ITEM_REGEXP = /\A((?:[a-z0-9]+(?:\)|\.)|\*) )/ + + def indented? + self =~ /\A[ ]+/ + end + + def list_item? + self =~ LIST_ITEM_REGEXP + end + + def match_as_list_item + match(LIST_ITEM_REGEXP) + end + end + + # @private + class Paragraph + def initialize(paragraph, indent: 0) + @paragraph = Text.new(paragraph) + @indent = indent + end + + def wrap + if paragraph.indented? + lines + elsif paragraph.list_item? + wrap_list_item + else + wrap_generic_paragraph + end + end + + protected + + attr_reader :paragraph, :indent + + private + + def wrap_list_item + wrap_lines(combine_list_item_lines(lines)) + end + + def lines + paragraph.split("\n").map { |line| Text.new(line) } + end + + def combine_list_item_lines(lines) + lines.reduce([]) do |combined_lines, line| + if line.list_item? + combined_lines << line + else + combined_lines.last << (' ' + line).squeeze(' ') + end + + combined_lines + end + end + + def wrap_lines(lines) + lines.map { |line| Line.new(line, indent: indent).wrap } + end + + def wrap_generic_paragraph + Line.new(combine_paragraph_into_one_line, indent: indent).wrap + end + + def combine_paragraph_into_one_line + paragraph.gsub(/\n/, ' ') + end + end + + # @private + class Line + OFFSETS = { left: -1, right: +1 } + + def initialize(line, indent: 0) + @indent = indent + @original_line = @line_to_wrap = Text.new(line) + @indentation = ' ' * indent + @indentation_read = false + end + + def wrap + if line_to_wrap.indented? + [line_to_wrap] + else + lines = [] + + loop do + @previous_line_to_wrap = line_to_wrap + new_line = (indentation || '') + line_to_wrap + result = wrap_line(new_line) + lines << normalize_whitespace(result[:fitted_line]) + + unless @indentation_read + @indentation = read_indentation + @indentation_read = true + end + + @line_to_wrap = result[:leftover] + + if line_to_wrap.to_s.empty? || previous_line_to_wrap == line_to_wrap + break + end + end + + lines + end + end + + protected + + attr_reader :indent, :original_line, :line_to_wrap, :indentation, + :previous_line_to_wrap + + private + + def read_indentation + initial_indentation = ' ' * indent + match = line_to_wrap.match_as_list_item + + if match + initial_indentation + (' ' * match[1].length) + else + initial_indentation + end + end + + def wrap_line(line, direction: :left) + index = nil + + if line.length > Shoulda::Matchers::WordWrap::TERMINAL_WIDTH + index = determine_where_to_break_line(line, direction: :left) + + if index == -1 + index = determine_where_to_break_line(line, direction: :right) + end + end + + if index.nil? || index == -1 + fitted_line = line + leftover = '' + else + fitted_line = line[0..index].rstrip + leftover = line[index + 1 .. -1] + end + + { fitted_line: fitted_line, leftover: leftover } + end + + def determine_where_to_break_line(line, args) + direction = args.fetch(:direction) + index = Shoulda::Matchers::WordWrap::TERMINAL_WIDTH + offset = OFFSETS.fetch(direction) + + while line[index] !~ /\s/ && (0...line.length).cover?(index) + index += offset + end + + index + end + + def normalize_whitespace(string) + indentation + string.strip.squeeze(' ') + end + end + end +end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/util.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/util.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/util.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/util.rb 2020-02-18 07:23:52.000000000 +0000 @@ -1,3 +1,5 @@ +require 'shoulda/matchers/util/word_wrap' + module Shoulda module Matchers # @private @@ -25,9 +27,74 @@ end def self.indent(string, width) + return if !string indentation = ' ' * width string.split(/[\n\r]/).map { |line| indentation + line }.join("\n") end + + def self.a_or_an(next_word) + if next_word =~ /\A[aeiou]/i && next_word != 'unique' + "an #{next_word}" + else + "a #{next_word}" + end + end + + def self.inspect_value(value) + case value + when Hash + inspect_hash(value) + when Range + inspect_range(value) + else + "‹#{value.inspect}›" + end + end + + def self.inspect_values(values) + values.map { |value| inspect_value(value) } + end + + def self.inspect_range(range) + "#{inspect_value(range.first)} to #{inspect_value(range.last)}" + end + + def self.inspect_hash(hash) + output = '‹{' + + output << hash.map { |key, value| + if key.is_a?(Symbol) + "#{key}: #{value.inspect}" + else + "#{key.inspect} => #{value.inspect}" + end + }.join(', ') + + output << '}›' + end + + def self.dummy_value_for(column_type, array: false) + if array + [dummy_value_for(column_type, array: false)] + else + case column_type + when :integer + 0 + when :date + Date.new(2100, 1, 1) + when :datetime, :timestamp + DateTime.new(2100, 1, 1) + when :time + Time.new(2100, 1, 1) + when :uuid + SecureRandom.uuid + when :boolean + true + else + 'dummy value' + end + end + end end end end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/version.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/version.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/version.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/version.rb 2020-02-18 07:23:52.000000000 +0000 @@ -1,6 +1,6 @@ module Shoulda module Matchers # @private - VERSION = '2.8.0'.freeze + VERSION = '4.3.0'.freeze end end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/warn.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/warn.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/warn.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers/warn.rb 2020-02-18 07:23:52.000000000 +0000 @@ -1,12 +1,13 @@ module Shoulda module Matchers + # @private TERMINAL_MAX_WIDTH = 72 # @private def self.warn(message) header = "Warning from shoulda-matchers:" divider = "*" * TERMINAL_MAX_WIDTH - wrapped_message = word_wrap(message, TERMINAL_MAX_WIDTH) + wrapped_message = word_wrap(message) full_message = [ divider, [header, wrapped_message.strip].join("\n\n"), @@ -23,14 +24,5 @@ release. Please use #{new_method} instead. EOT end - - # Source: - # @private - def self.word_wrap(text, width=80) - text. - gsub(/\n+/, " "). - gsub( /(\S{#{width}})(?=\S)/, '\1 ' ). - gsub( /(.{1,#{width}})(?:\s+|$)/, "\\1\n" ) - end end end diff -Nru ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers.rb ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers.rb --- ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers.rb 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/lib/shoulda/matchers.rb 2020-02-18 07:23:52.000000000 +0000 @@ -1,28 +1,24 @@ -require 'shoulda/matchers/assertion_error' +require 'shoulda/matchers/configuration' require 'shoulda/matchers/doublespeak' require 'shoulda/matchers/error' +require 'shoulda/matchers/independent' +require 'shoulda/matchers/integrations' require 'shoulda/matchers/matcher_context' require 'shoulda/matchers/rails_shim' require 'shoulda/matchers/util' require 'shoulda/matchers/version' require 'shoulda/matchers/warn' -require 'shoulda/matchers/independent' - -if defined?(ActiveModel) - require 'shoulda/matchers/active_model' -end - -if defined?(ActiveRecord) - require 'shoulda/matchers/active_record' +require 'shoulda/matchers/action_controller' +require 'shoulda/matchers/active_model' +require 'shoulda/matchers/active_record' +require 'shoulda/matchers/routing' + +module Shoulda + module Matchers + class << self + # @private + attr_accessor :assertion_exception_class + end + end end - -if defined?(ActionController) - require 'shoulda/matchers/action_controller' -end - -if defined?(RSpec) - require 'shoulda/matchers/integrations/rspec' -end - -require 'shoulda/matchers/integrations/test_unit' diff -Nru ruby-shoulda-matchers-2.8.0/MAINTAINING.md ruby-shoulda-matchers-4.3.0/MAINTAINING.md --- ruby-shoulda-matchers-2.8.0/MAINTAINING.md 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/MAINTAINING.md 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,313 @@ +# Maintaining Shoulda Matchers + +As maintainers of the gem, this is our guide. Most of the steps and guidelines +in the [Contributing](CONTRIBUTING.md) document apply here, including how to set +up your environment, write code to fit the code style, run tests, craft commits +and manage branches. Beyond this, this document provides some details that would +be too low-level for contributors. + +## Table of Contents + +* [Communication](#communication) +* [Managing the community](#managing-the-community) +* [Workflow](#workflow) +* [Architecture](#architecture) +* [Running tests](#running-tests) +* [Updating the changelog](#updating-the-changelog) +* [Documentation](#documentation) +* [Versioning](#versioning) +* [Updating the landing page](#updating-the-landing-page) +* [Addendum: Labels](#addendum-labels) + +## Communication + +We have several ways that we can communicate with each other: + +* In planning major releases, it can be helpful to create a **new issue** + outlining the changes as well as steps needed to launch the release. This + serves both as an announcement to the community as well as an area to keep a + checklist. +* To track progress for the next release, **GitHub milestones** are useful. +* To track progress on the movement of issues, [**labels**](#addendum-labels) + are useful. +* To communicate small-scale changes, **pull requests** are effective, as + mentioned above. +* To communicate large-scale changes or explain topics, **email** is best. + +## Managing the community + +As anyone who has played a sim game before, it's important to make your patrons +happy. We do this by: + +* Answering questions from members of the community +* Closing stale issues and feature requests +* Keeping the community informed by ensuring that the changelog is up to date +* Ensuring that the inline documentation, as well as the docsite, is kept up to + date + +## Workflow + +We generally follow [GitHub Flow]. The `master` branch is the main line, and all +branches are cut from and get merged back into this branch. Generally, the +workflow is as follows: + +[GitHub Flow]: https://help.github.com/articles/github-flow/ + +* Cut a feature or bugfix branch from this branch. +* Upon completing a branch, create a PR and ask another maintainer to approve + it. +* Try to keep the commit history as clean as possible. Before merging, squash + "WIP" or related commits together and rebase as needed. +* Once your PR is approved and you've cleaned up your branch, you're free to + merge it in. + +## Architecture + +Besides the matchers, there are files in `lib` which you may need to reference +or update: + +* `lib/shoulda/matchers/doublespeak*` — a small handrolled mocking library + which is used by the `permit` matcher +* `lib/shoulda/matchers/util*` — extra methods which are used in various places + to detect library versions, wrap/indent text, and more + +## Running tests + +The [Contributing guide](CONTRIBUTING.md) shows how to use Appraisal to run +tests. This works well if you are hopping in, making a few changes, and hopping +right out, but if you plan on working on a feature or bug, there is often a +faster alternative, at least for unit tests: [Zeus]. Zeus works by preloading +the Rails environment so that running unit tests are a lot faster. We also have +it set up to automatically select the latest Appraisal so you don't have to +provide that. + +You'll want to start by running `zeus start` in one shell. Then in another +shell, instead of using `bundle exec rspec` to run tests, you'll use `bundle +exec zeus rspec`. So for instance, you might say: + +```bash +bundle exec zeus rspec spec/unit/shoulda/matchers/active_model/validate_inclusion_of_matcher_spec.rb +``` + +This is long to say, but it helps if you add an alias to your shell: + +```bash +alias zr="bundle exec zeus rspec" +``` + +[Zeus]: https://github.com/burke/zeus + +## Updating the changelog + +After every user-facing change makes it into master, we make a note of it in the +changelog, which for historical reasons is kept in `NEWS.md`. The changelog is +sorted in reverse order by release version, with the topmost version as the next +release (tagged as "(Unreleased)"). + +Within each version, there are five available categories you can divide changes +into. They are all optional but they should appear in this order: + +1. Backward-compatible changes +1. Deprecations +1. Bug fixes +1. Features +1. Improvements + +Within each category section, the changes relevant to that category are listed +in chronological order. + +For each change, provide a human-readable description of the change as well as a +linked reference to the PR where that change emerged (or the commit ID if no +such PR is available). This helps users cross-reference changes if they need to. + +## Documentation + +### Generating documentation + +As mentioned in the [Contributing](CONTRIBUTING.md) document, we use YARD for +documentation. YARD is configured via `.yardopts` to process the Ruby files in +`lib/` as well as `NEWS.md` and the Markdown files in `docs/` and write the +documentation in HTML form to `doc`. This command will do exactly that: + +```bash +bundle exec yard doc +``` + +This works, but if you're actively updating the documentation, it's more helpful +to launch a process that will watch the aforementioned source files for changes +and generate the HTML for you automatically: + +```bash +bundle exec rake docs:autogenerate +``` + +Whichever approach you take, you can view the generated docs locally by running: + +```bash +open doc/index.html +``` + +### Publishing documentation + +The Ruby documentation is hosted on GitHub Pages on a custom domain*: + + + +This URL actually links to a HTML page which merely serves to automatically +redirect the visitor to the docs for the latest published version of the gem. +This version is hardcoded in the HTML page. + +Generally you will update the published docs as a part of a release, but there +may be situations where you'll need to do it manually. + +You can re-publish the docs for the latest version (as governed by +`lib/shoulda/matchers/version.rb`) by running: + +```bash +bundle exec rake docs:publish_latest +``` + +This will update the auto-redirect on the index page to the latest version. For +instance, if the latest version were 4.0.0, this command would publish the docs +at and simultaneously redirect + to this location. + +However, if you want to publish the docs for a version but manually set the +auto-redirected version, you can run this instead: + +```bash +bundle exec rake docs:publish[version, latest_version] +``` + +Here, `version` and `latest_version` are both version strings. For instance, you +might say: + +```bash +bundle exec rake docs:publish[4.0.0, 3.7.2] +``` + +This would publish the docs for 4.0.0 at +, but redirect + to . + +*\* thoughtbot owns , and +they've got `matchers.shoulda.io` set up on the DNS level as an alias for +`thoughtbot.github.io/shoulda-matchers`.* + +## Versioning + +### Naming a new version + +As designated in the README, we follow [SemVer 2.0][semver]. This offers a +meaningful baseline for deciding how to name versions. Generally speaking: + +[semver]: https://semver.org/spec/v2.0.0.html + +* We bump the "major" part of the version if we're introducing + backward-incompatible changes (e.g. changing the API or core behavior, + removing parts of the API, or dropping support for a version of Ruby). +* We bump the "minor" part if we're adding a new feature (e.g. adding a new + matcher or adding a new qualifier to a matcher). +* We bump the "patch" part if we're merely including bugfixes. + +In addition to major, minor, and patch levels, you can also append a +suffix to the version for pre-release versions. We usually use this to issue +release candidates prior to an actual release. A version number in this case +might look like `4.0.0.rc1`. + +### Preparing and releasing a new version + +In order to release any versions at all, you will need to have been added as +an owner of the Ruby gem. If you want to give someone else these permissions, +then run: + +```bash +gem owner shoulda-matchers -a +``` + +Assuming you have permission to publish a new version to RubyGems, then this is +how you release a version: + +1. First, you'll want to [make sure that the changelog is up to + date](#updating-the-changelog). + +2. Next, [generate the documentation locally](#generating-documentation) and do + a quick spot-check (pull up the Classes and Methods menus, click around a + bit) to ensure that nothing looks awry. + +3. Next, you'll want to update the `VERSION` constant in + `lib/shoulda/matchers/version.rb`. This constant is referenced in the gemspec + and is used in the Rake tasks to publish the gem on RubyGems as well as + generate documentation. + +4. Next, make sure that the current version is updated in the [Quick Links + section of the README](README.md#quick-links). + +5. Assuming that everything looks good, place your changes to NEWS, + `version.rb`, and README in their own commit titled "Bump version to + *X.Y.Z*". Push this to GitHub (you can use `[ci skip]`) in the body of the + commit message to skip CI for this commit). **There is no going back after + this point!** + +6. Once GitHub has the version-change commit, you will run: + + ```bash + rake release + ``` + + This will not only push the gem to RubyGems, but also publish the docs to + GitHub Pages. + +## Updating the landing page + +The Shoulda Matchers landing page is located at: + + + +The code for this page is stored on the [`site`][site-branch] branch. There are +instructions there for maintaining and publishing it. + +[site-branch]: https://github.com/thoughtbot/shoulda-matchers/tree/site + +## Addendum: Labels + +Considering that we work on the gem in our spare time, we've found [labels] to +be useful for cataloguing and marking progress. Over time we've added quite a +collection of labels. Here's a quick list: + +[labels]: https://github.com/thoughtbot/shoulda-matchers/labels + +### Labels for issues + +* **Issue: Bug** +* **Issue: Feature Request** +* **Issue: Need to Investigate** — if we don't know whether a bug is legitimate + or not +* **Issue: PR Needed** — perhaps unnecessary, but it does signal to the + community that we'd love a PR + +### Labels for PRs + +* **PR: Bugfix** +* **PR: Feature** +* **PR: Good to Merge** — most of the time not necessary, but can be helpful in + a code freeze before a release to mark PRs that we will include in the next + release +* **PR: In Progress** — used to mark PRs that are still being worked on by the + PR author +* **PR: Needs Documentation** +* **PR: Needs Review** +* **PR: Needs Tests** +* **PR: Needs Updates Before Merge** — along the same lines as the other + "Needs" tags, but more generic + +### Generic labels + +* **Blocked** +* **Documentation** +* **Needs Decision** +* **Needs Revisiting** +* **Question** +* **Rails X** +* **Ruby X.Y** +* **UX** diff -Nru ruby-shoulda-matchers-2.8.0/metadata.yml ruby-shoulda-matchers-4.3.0/metadata.yml --- ruby-shoulda-matchers-2.8.0/metadata.yml 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/metadata.yml 1970-01-01 00:00:00.000000000 +0000 @@ -1,419 +0,0 @@ ---- !ruby/object:Gem::Specification -name: shoulda-matchers -version: !ruby/object:Gem::Version - version: 2.8.0 -platform: ruby -authors: -- Tammer Saleh -- Joe Ferris -- Ryan McGeary -- Dan Croak -- Matt Jankowski -- Stafford Brunk -- Elliot Winkler -autorequire: -bindir: bin -cert_chain: [] -date: 2015-01-30 00:00:00.000000000 Z -dependencies: -- !ruby/object:Gem::Dependency - name: activesupport - requirement: !ruby/object:Gem::Requirement - requirements: - - - ">=" - - !ruby/object:Gem::Version - version: 3.0.0 - type: :runtime - prerelease: false - version_requirements: !ruby/object:Gem::Requirement - requirements: - - - ">=" - - !ruby/object:Gem::Version - version: 3.0.0 -description: Making tests easy on the fingers and eyes -email: support@thoughtbot.com -executables: [] -extensions: [] -extra_rdoc_files: [] -files: -- ".gitignore" -- ".hound.yml" -- ".hound_config/ruby.yml" -- ".travis.yml" -- ".yardopts" -- Appraisals -- CONTRIBUTING.md -- Gemfile -- Gemfile.lock -- MIT-LICENSE -- NEWS.md -- README.md -- Rakefile -- cucumber.yml -- doc_config/gh-pages/index.html.erb -- doc_config/yard/setup.rb -- doc_config/yard/templates/default/fulldoc/html/css/bootstrap.css -- doc_config/yard/templates/default/fulldoc/html/css/full_list.css -- doc_config/yard/templates/default/fulldoc/html/css/global.css -- doc_config/yard/templates/default/fulldoc/html/css/solarized.css -- doc_config/yard/templates/default/fulldoc/html/css/style.css -- doc_config/yard/templates/default/fulldoc/html/full_list.erb -- doc_config/yard/templates/default/fulldoc/html/full_list_class.erb -- doc_config/yard/templates/default/fulldoc/html/full_list_method.erb -- doc_config/yard/templates/default/fulldoc/html/js/app.js -- doc_config/yard/templates/default/fulldoc/html/js/full_list.js -- doc_config/yard/templates/default/fulldoc/html/js/jquery.stickyheaders.js -- doc_config/yard/templates/default/fulldoc/html/js/underscore.min.js -- doc_config/yard/templates/default/fulldoc/html/setup.rb -- doc_config/yard/templates/default/layout/html/breadcrumb.erb -- doc_config/yard/templates/default/layout/html/fonts.erb -- doc_config/yard/templates/default/layout/html/layout.erb -- doc_config/yard/templates/default/layout/html/search.erb -- doc_config/yard/templates/default/layout/html/setup.rb -- doc_config/yard/templates/default/method_details/html/source.erb -- doc_config/yard/templates/default/module/html/box_info.erb -- docs.watchr -- gemfiles/3.0.gemfile -- gemfiles/3.0.gemfile.lock -- gemfiles/3.1.gemfile -- gemfiles/3.1.gemfile.lock -- gemfiles/3.1_1.9.2.gemfile -- gemfiles/3.1_1.9.2.gemfile.lock -- gemfiles/3.2.gemfile -- gemfiles/3.2.gemfile.lock -- gemfiles/3.2_1.9.2.gemfile -- gemfiles/3.2_1.9.2.gemfile.lock -- gemfiles/4.0.0.gemfile -- gemfiles/4.0.0.gemfile.lock -- gemfiles/4.0.1.gemfile -- gemfiles/4.0.1.gemfile.lock -- gemfiles/4.1.gemfile -- gemfiles/4.1.gemfile.lock -- gemfiles/4.2.gemfile -- gemfiles/4.2.gemfile.lock -- lib/shoulda-matchers.rb -- lib/shoulda/matchers.rb -- lib/shoulda/matchers/action_controller.rb -- lib/shoulda/matchers/action_controller/callback_matcher.rb -- lib/shoulda/matchers/action_controller/filter_param_matcher.rb -- lib/shoulda/matchers/action_controller/redirect_to_matcher.rb -- lib/shoulda/matchers/action_controller/render_template_matcher.rb -- lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb -- lib/shoulda/matchers/action_controller/rescue_from_matcher.rb -- lib/shoulda/matchers/action_controller/respond_with_matcher.rb -- lib/shoulda/matchers/action_controller/route_matcher.rb -- lib/shoulda/matchers/action_controller/route_params.rb -- lib/shoulda/matchers/action_controller/set_flash_matcher.rb -- lib/shoulda/matchers/action_controller/set_session_matcher.rb -- lib/shoulda/matchers/action_controller/strong_parameters_matcher.rb -- lib/shoulda/matchers/active_model.rb -- lib/shoulda/matchers/active_model/allow_mass_assignment_of_matcher.rb -- lib/shoulda/matchers/active_model/allow_value_matcher.rb -- lib/shoulda/matchers/active_model/disallow_value_matcher.rb -- lib/shoulda/matchers/active_model/errors.rb -- lib/shoulda/matchers/active_model/have_secure_password_matcher.rb -- lib/shoulda/matchers/active_model/helpers.rb -- lib/shoulda/matchers/active_model/numericality_matchers.rb -- lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb -- lib/shoulda/matchers/active_model/numericality_matchers/even_number_matcher.rb -- lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb -- lib/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher.rb -- lib/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher.rb -- lib/shoulda/matchers/active_model/strict_validator.rb -- lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb -- lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb -- lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb -- lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb -- lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb -- lib/shoulda/matchers/active_model/validate_length_of_matcher.rb -- lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb -- lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb -- lib/shoulda/matchers/active_model/validation_matcher.rb -- lib/shoulda/matchers/active_model/validator.rb -- lib/shoulda/matchers/active_model/validator_with_captured_range_error.rb -- lib/shoulda/matchers/active_record.rb -- lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb -- lib/shoulda/matchers/active_record/association_matcher.rb -- lib/shoulda/matchers/active_record/association_matchers.rb -- lib/shoulda/matchers/active_record/association_matchers/counter_cache_matcher.rb -- lib/shoulda/matchers/active_record/association_matchers/dependent_matcher.rb -- lib/shoulda/matchers/active_record/association_matchers/inverse_of_matcher.rb -- lib/shoulda/matchers/active_record/association_matchers/join_table_matcher.rb -- lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb -- lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb -- lib/shoulda/matchers/active_record/association_matchers/option_verifier.rb -- lib/shoulda/matchers/active_record/association_matchers/order_matcher.rb -- lib/shoulda/matchers/active_record/association_matchers/source_matcher.rb -- lib/shoulda/matchers/active_record/association_matchers/through_matcher.rb -- lib/shoulda/matchers/active_record/define_enum_for_matcher.rb -- lib/shoulda/matchers/active_record/have_db_column_matcher.rb -- lib/shoulda/matchers/active_record/have_db_index_matcher.rb -- lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb -- lib/shoulda/matchers/active_record/serialize_matcher.rb -- lib/shoulda/matchers/active_record/uniqueness.rb -- lib/shoulda/matchers/active_record/uniqueness/model.rb -- lib/shoulda/matchers/active_record/uniqueness/namespace.rb -- lib/shoulda/matchers/active_record/uniqueness/test_model_creator.rb -- lib/shoulda/matchers/active_record/uniqueness/test_models.rb -- lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb -- lib/shoulda/matchers/assertion_error.rb -- lib/shoulda/matchers/doublespeak.rb -- lib/shoulda/matchers/doublespeak/double.rb -- lib/shoulda/matchers/doublespeak/double_collection.rb -- lib/shoulda/matchers/doublespeak/double_implementation_registry.rb -- lib/shoulda/matchers/doublespeak/object_double.rb -- lib/shoulda/matchers/doublespeak/proxy_implementation.rb -- lib/shoulda/matchers/doublespeak/structs.rb -- lib/shoulda/matchers/doublespeak/stub_implementation.rb -- lib/shoulda/matchers/doublespeak/world.rb -- lib/shoulda/matchers/error.rb -- lib/shoulda/matchers/independent.rb -- lib/shoulda/matchers/independent/delegate_method_matcher.rb -- lib/shoulda/matchers/independent/delegate_method_matcher/stubbed_target.rb -- lib/shoulda/matchers/independent/delegate_method_matcher/target_not_defined_error.rb -- lib/shoulda/matchers/integrations/nunit_test_case_detection.rb -- lib/shoulda/matchers/integrations/rspec.rb -- lib/shoulda/matchers/integrations/test_unit.rb -- lib/shoulda/matchers/matcher_context.rb -- lib/shoulda/matchers/rails_shim.rb -- lib/shoulda/matchers/util.rb -- lib/shoulda/matchers/version.rb -- lib/shoulda/matchers/warn.rb -- script/SUPPORTED_VERSIONS -- script/install_gems_in_all_appraisals -- script/run_all_tests -- script/update_gem_in_all_appraisals -- shoulda-matchers.gemspec -- spec/acceptance/active_model_integration_spec.rb -- spec/acceptance/independent_matchers_spec.rb -- spec/acceptance/rails_integration_spec.rb -- spec/acceptance_spec_helper.rb -- spec/report_warnings.rb -- spec/support/acceptance/helpers.rb -- spec/support/acceptance/helpers/active_model_helpers.rb -- spec/support/acceptance/helpers/array_helpers.rb -- spec/support/acceptance/helpers/base_helpers.rb -- spec/support/acceptance/helpers/command_helpers.rb -- spec/support/acceptance/helpers/file_helpers.rb -- spec/support/acceptance/helpers/gem_helpers.rb -- spec/support/acceptance/helpers/minitest_helpers.rb -- spec/support/acceptance/helpers/pluralization_helpers.rb -- spec/support/acceptance/helpers/rails_version_helpers.rb -- spec/support/acceptance/helpers/rspec_helpers.rb -- spec/support/acceptance/helpers/ruby_version_helpers.rb -- spec/support/acceptance/helpers/step_helpers.rb -- spec/support/acceptance/matchers/have_output.rb -- spec/support/acceptance/matchers/indicate_number_of_tests_was_run_matcher.rb -- spec/support/acceptance/matchers/indicate_that_tests_were_run_matcher.rb -- spec/support/tests/bundle.rb -- spec/support/tests/command_runner.rb -- spec/support/tests/filesystem.rb -- spec/support/tests/version.rb -- spec/support/unit/capture.rb -- spec/support/unit/helpers/active_model_helpers.rb -- spec/support/unit/helpers/active_model_versions.rb -- spec/support/unit/helpers/active_record_versions.rb -- spec/support/unit/helpers/active_resource_builder.rb -- spec/support/unit/helpers/allow_value_matcher_helpers.rb -- spec/support/unit/helpers/class_builder.rb -- spec/support/unit/helpers/confirmation_matcher_helpers.rb -- spec/support/unit/helpers/controller_builder.rb -- spec/support/unit/helpers/i18n_faker.rb -- spec/support/unit/helpers/mailer_builder.rb -- spec/support/unit/helpers/model_builder.rb -- spec/support/unit/helpers/rails_versions.rb -- spec/support/unit/i18n.rb -- spec/support/unit/matchers/deprecate.rb -- spec/support/unit/matchers/fail_with_message_including_matcher.rb -- spec/support/unit/matchers/fail_with_message_matcher.rb -- spec/support/unit/matchers/print_warning_including.rb -- spec/support/unit/rails_application.rb -- spec/support/unit/record_builder_with_i18n_validation_message.rb -- spec/support/unit/record_validating_confirmation_builder.rb -- spec/support/unit/record_with_different_error_attribute_builder.rb -- spec/support/unit/shared_examples/numerical_submatcher.rb -- spec/support/unit/shared_examples/numerical_type_submatcher.rb -- spec/unit/shoulda/matchers/action_controller/callback_matcher_spec.rb -- spec/unit/shoulda/matchers/action_controller/filter_param_matcher_spec.rb -- spec/unit/shoulda/matchers/action_controller/redirect_to_matcher_spec.rb -- spec/unit/shoulda/matchers/action_controller/render_template_matcher_spec.rb -- spec/unit/shoulda/matchers/action_controller/render_with_layout_matcher_spec.rb -- spec/unit/shoulda/matchers/action_controller/rescue_from_matcher_spec.rb -- spec/unit/shoulda/matchers/action_controller/respond_with_matcher_spec.rb -- spec/unit/shoulda/matchers/action_controller/route_matcher_spec.rb -- spec/unit/shoulda/matchers/action_controller/route_params_spec.rb -- spec/unit/shoulda/matchers/action_controller/set_flash_matcher_spec.rb -- spec/unit/shoulda/matchers/action_controller/set_session_matcher_spec.rb -- spec/unit/shoulda/matchers/action_controller/strong_parameters_matcher_spec.rb -- spec/unit/shoulda/matchers/active_model/allow_mass_assignment_of_matcher_spec.rb -- spec/unit/shoulda/matchers/active_model/allow_value_matcher_spec.rb -- spec/unit/shoulda/matchers/active_model/disallow_value_matcher_spec.rb -- spec/unit/shoulda/matchers/active_model/have_secure_password_matcher_spec.rb -- spec/unit/shoulda/matchers/active_model/helpers_spec.rb -- spec/unit/shoulda/matchers/active_model/numericality_matchers/comparison_matcher_spec.rb -- spec/unit/shoulda/matchers/active_model/numericality_matchers/even_number_matcher_spec.rb -- spec/unit/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher_spec.rb -- spec/unit/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher_spec.rb -- spec/unit/shoulda/matchers/active_model/validate_absence_of_matcher_spec.rb -- spec/unit/shoulda/matchers/active_model/validate_acceptance_of_matcher_spec.rb -- spec/unit/shoulda/matchers/active_model/validate_confirmation_of_matcher_spec.rb -- spec/unit/shoulda/matchers/active_model/validate_exclusion_of_matcher_spec.rb -- spec/unit/shoulda/matchers/active_model/validate_inclusion_of_matcher_spec.rb -- spec/unit/shoulda/matchers/active_model/validate_length_of_matcher_spec.rb -- spec/unit/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb -- spec/unit/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb -- spec/unit/shoulda/matchers/active_model/validate_uniqueness_of_matcher_spec.rb -- spec/unit/shoulda/matchers/active_record/accept_nested_attributes_for_matcher_spec.rb -- spec/unit/shoulda/matchers/active_record/association_matcher_spec.rb -- spec/unit/shoulda/matchers/active_record/association_matchers/model_reflection_spec.rb -- spec/unit/shoulda/matchers/active_record/define_enum_for_matcher_spec.rb -- spec/unit/shoulda/matchers/active_record/have_db_column_matcher_spec.rb -- spec/unit/shoulda/matchers/active_record/have_db_index_matcher_spec.rb -- spec/unit/shoulda/matchers/active_record/have_readonly_attributes_matcher_spec.rb -- spec/unit/shoulda/matchers/active_record/serialize_matcher_spec.rb -- spec/unit/shoulda/matchers/doublespeak/double_collection_spec.rb -- spec/unit/shoulda/matchers/doublespeak/double_implementation_registry_spec.rb -- spec/unit/shoulda/matchers/doublespeak/double_spec.rb -- spec/unit/shoulda/matchers/doublespeak/object_double_spec.rb -- spec/unit/shoulda/matchers/doublespeak/proxy_implementation_spec.rb -- spec/unit/shoulda/matchers/doublespeak/stub_implementation_spec.rb -- spec/unit/shoulda/matchers/doublespeak/world_spec.rb -- spec/unit/shoulda/matchers/doublespeak_spec.rb -- spec/unit/shoulda/matchers/independent/delegate_method_matcher/stubbed_target_spec.rb -- spec/unit/shoulda/matchers/independent/delegate_method_matcher_spec.rb -- spec/unit_spec_helper.rb -- spec/warnings_spy.rb -- spec/warnings_spy/filesystem.rb -- spec/warnings_spy/partitioner.rb -- spec/warnings_spy/reader.rb -- spec/warnings_spy/reporter.rb -- tasks/documentation.rb -homepage: http://thoughtbot.com/community/ -licenses: -- MIT -metadata: {} -post_install_message: -rdoc_options: [] -require_paths: -- lib -required_ruby_version: !ruby/object:Gem::Requirement - requirements: - - - ">=" - - !ruby/object:Gem::Version - version: 1.9.2 -required_rubygems_version: !ruby/object:Gem::Requirement - requirements: - - - ">=" - - !ruby/object:Gem::Version - version: '0' -requirements: [] -rubyforge_project: -rubygems_version: 2.2.2 -signing_key: -specification_version: 4 -summary: Making tests easy on the fingers and eyes -test_files: -- spec/acceptance/active_model_integration_spec.rb -- spec/acceptance/independent_matchers_spec.rb -- spec/acceptance/rails_integration_spec.rb -- spec/acceptance_spec_helper.rb -- spec/report_warnings.rb -- spec/support/acceptance/helpers.rb -- spec/support/acceptance/helpers/active_model_helpers.rb -- spec/support/acceptance/helpers/array_helpers.rb -- spec/support/acceptance/helpers/base_helpers.rb -- spec/support/acceptance/helpers/command_helpers.rb -- spec/support/acceptance/helpers/file_helpers.rb -- spec/support/acceptance/helpers/gem_helpers.rb -- spec/support/acceptance/helpers/minitest_helpers.rb -- spec/support/acceptance/helpers/pluralization_helpers.rb -- spec/support/acceptance/helpers/rails_version_helpers.rb -- spec/support/acceptance/helpers/rspec_helpers.rb -- spec/support/acceptance/helpers/ruby_version_helpers.rb -- spec/support/acceptance/helpers/step_helpers.rb -- spec/support/acceptance/matchers/have_output.rb -- spec/support/acceptance/matchers/indicate_number_of_tests_was_run_matcher.rb -- spec/support/acceptance/matchers/indicate_that_tests_were_run_matcher.rb -- spec/support/tests/bundle.rb -- spec/support/tests/command_runner.rb -- spec/support/tests/filesystem.rb -- spec/support/tests/version.rb -- spec/support/unit/capture.rb -- spec/support/unit/helpers/active_model_helpers.rb -- spec/support/unit/helpers/active_model_versions.rb -- spec/support/unit/helpers/active_record_versions.rb -- spec/support/unit/helpers/active_resource_builder.rb -- spec/support/unit/helpers/allow_value_matcher_helpers.rb -- spec/support/unit/helpers/class_builder.rb -- spec/support/unit/helpers/confirmation_matcher_helpers.rb -- spec/support/unit/helpers/controller_builder.rb -- spec/support/unit/helpers/i18n_faker.rb -- spec/support/unit/helpers/mailer_builder.rb -- spec/support/unit/helpers/model_builder.rb -- spec/support/unit/helpers/rails_versions.rb -- spec/support/unit/i18n.rb -- spec/support/unit/matchers/deprecate.rb -- spec/support/unit/matchers/fail_with_message_including_matcher.rb -- spec/support/unit/matchers/fail_with_message_matcher.rb -- spec/support/unit/matchers/print_warning_including.rb -- spec/support/unit/rails_application.rb -- spec/support/unit/record_builder_with_i18n_validation_message.rb -- spec/support/unit/record_validating_confirmation_builder.rb -- spec/support/unit/record_with_different_error_attribute_builder.rb -- spec/support/unit/shared_examples/numerical_submatcher.rb -- spec/support/unit/shared_examples/numerical_type_submatcher.rb -- spec/unit/shoulda/matchers/action_controller/callback_matcher_spec.rb -- spec/unit/shoulda/matchers/action_controller/filter_param_matcher_spec.rb -- spec/unit/shoulda/matchers/action_controller/redirect_to_matcher_spec.rb -- spec/unit/shoulda/matchers/action_controller/render_template_matcher_spec.rb -- spec/unit/shoulda/matchers/action_controller/render_with_layout_matcher_spec.rb -- spec/unit/shoulda/matchers/action_controller/rescue_from_matcher_spec.rb -- spec/unit/shoulda/matchers/action_controller/respond_with_matcher_spec.rb -- spec/unit/shoulda/matchers/action_controller/route_matcher_spec.rb -- spec/unit/shoulda/matchers/action_controller/route_params_spec.rb -- spec/unit/shoulda/matchers/action_controller/set_flash_matcher_spec.rb -- spec/unit/shoulda/matchers/action_controller/set_session_matcher_spec.rb -- spec/unit/shoulda/matchers/action_controller/strong_parameters_matcher_spec.rb -- spec/unit/shoulda/matchers/active_model/allow_mass_assignment_of_matcher_spec.rb -- spec/unit/shoulda/matchers/active_model/allow_value_matcher_spec.rb -- spec/unit/shoulda/matchers/active_model/disallow_value_matcher_spec.rb -- spec/unit/shoulda/matchers/active_model/have_secure_password_matcher_spec.rb -- spec/unit/shoulda/matchers/active_model/helpers_spec.rb -- spec/unit/shoulda/matchers/active_model/numericality_matchers/comparison_matcher_spec.rb -- spec/unit/shoulda/matchers/active_model/numericality_matchers/even_number_matcher_spec.rb -- spec/unit/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher_spec.rb -- spec/unit/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher_spec.rb -- spec/unit/shoulda/matchers/active_model/validate_absence_of_matcher_spec.rb -- spec/unit/shoulda/matchers/active_model/validate_acceptance_of_matcher_spec.rb -- spec/unit/shoulda/matchers/active_model/validate_confirmation_of_matcher_spec.rb -- spec/unit/shoulda/matchers/active_model/validate_exclusion_of_matcher_spec.rb -- spec/unit/shoulda/matchers/active_model/validate_inclusion_of_matcher_spec.rb -- spec/unit/shoulda/matchers/active_model/validate_length_of_matcher_spec.rb -- spec/unit/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb -- spec/unit/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb -- spec/unit/shoulda/matchers/active_model/validate_uniqueness_of_matcher_spec.rb -- spec/unit/shoulda/matchers/active_record/accept_nested_attributes_for_matcher_spec.rb -- spec/unit/shoulda/matchers/active_record/association_matcher_spec.rb -- spec/unit/shoulda/matchers/active_record/association_matchers/model_reflection_spec.rb -- spec/unit/shoulda/matchers/active_record/define_enum_for_matcher_spec.rb -- spec/unit/shoulda/matchers/active_record/have_db_column_matcher_spec.rb -- spec/unit/shoulda/matchers/active_record/have_db_index_matcher_spec.rb -- spec/unit/shoulda/matchers/active_record/have_readonly_attributes_matcher_spec.rb -- spec/unit/shoulda/matchers/active_record/serialize_matcher_spec.rb -- spec/unit/shoulda/matchers/doublespeak/double_collection_spec.rb -- spec/unit/shoulda/matchers/doublespeak/double_implementation_registry_spec.rb -- spec/unit/shoulda/matchers/doublespeak/double_spec.rb -- spec/unit/shoulda/matchers/doublespeak/object_double_spec.rb -- spec/unit/shoulda/matchers/doublespeak/proxy_implementation_spec.rb -- spec/unit/shoulda/matchers/doublespeak/stub_implementation_spec.rb -- spec/unit/shoulda/matchers/doublespeak/world_spec.rb -- spec/unit/shoulda/matchers/doublespeak_spec.rb -- spec/unit/shoulda/matchers/independent/delegate_method_matcher/stubbed_target_spec.rb -- spec/unit/shoulda/matchers/independent/delegate_method_matcher_spec.rb -- spec/unit_spec_helper.rb -- spec/warnings_spy.rb -- spec/warnings_spy/filesystem.rb -- spec/warnings_spy/partitioner.rb -- spec/warnings_spy/reader.rb -- spec/warnings_spy/reporter.rb -has_rdoc: diff -Nru ruby-shoulda-matchers-2.8.0/MIT-LICENSE ruby-shoulda-matchers-4.3.0/MIT-LICENSE --- ruby-shoulda-matchers-2.8.0/MIT-LICENSE 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/MIT-LICENSE 2020-02-18 07:23:52.000000000 +0000 @@ -1,4 +1,4 @@ -Copyright (c) 2006-2014, Tammer Saleh, thoughtbot, inc. +Copyright (c) 2006-2020, Tammer Saleh and thoughtbot, inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation diff -Nru ruby-shoulda-matchers-2.8.0/NEWS.md ruby-shoulda-matchers-4.3.0/NEWS.md --- ruby-shoulda-matchers-2.8.0/NEWS.md 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/NEWS.md 2020-02-18 07:23:52.000000000 +0000 @@ -1,3 +1,824 @@ +# 4.3.0 + +### Features + +* Add `have_rich_text` matcher for `ActionText` ([#1263]) + +### Improvements +* Use range on `validate_exclusion_of#in_range` documentation ([#1273]) + +### Bug fixes + +* Fix `missing attribute:: scope 1` intermittent test: ([#1274]) + +[#1263]: https://github.com/thoughtbot/shoulda-matchers/pull/1263 +[#1273]: https://github.com/thoughtbot/shoulda-matchers/pull/1273 +[#1273]: https://github.com/thoughtbot/shoulda-matchers/pull/1274 + +# 4.2.0 + +### Features + +* Add support for `optional: false` in `belongs_to` associations. ([#1237]) +* Add support for associations with `inverse_of: false` and non-standard foreign key ([#1106]) + +### Bug fixes + +* Fix typos in documentation of `allow_values` ([#1241]) +* Fix appraisal command in CONTRIBUTING.md file ([#1253]) + +### Improvements + +* Remove `minitest-reporters` dependency ([#1251]) +* Development dependency updates + +[#1106]: https://github.com/thoughtbot/shoulda-matchers/pull/1106 +[#1237]: https://github.com/thoughtbot/shoulda-matchers/pull/1237 +[#1241]: https://github.com/thoughtbot/shoulda-matchers/pull/1241 +[#1253]: https://github.com/thoughtbot/shoulda-matchers/pull/1253 + +# 4.1.2 + +### Bug fixes + +* Fix another regression with `validate_presence_of` so that it works against an + attribute that has been decorated with `serialize` using a custom serializer + class. ([#1236]) + +[#1236]: https://github.com/thoughtbot/shoulda-matchers/pull/1236 + +# 4.1.1 + +### Bug fixes + +* Patch some backward-incompatible changes to `validate_presence_of` that were + made in the last version. As of 4.1.0 the presence matcher now checks to + ensure that empty string will cause the record to be invalid (in addition to + nil, which it was already checking against). However, this check was being + performed even if the attribute or column the presence matcher is being run + against didn't support being set to an empty string. This releases fixes this. + ([#1222], [#1224], [#1231]) + +[#1222]: https://github.com/thoughtbot/shoulda-matchers/pull/1222 +[#1224]: https://github.com/thoughtbot/shoulda-matchers/pull/1224 +[#1231]: https://github.com/thoughtbot/shoulda-matchers/pull/1231 + +# 4.1.0 + +### Bug fixes + +* Fix `validate_uniqueness_of` so that it works when a scope is defined as a + string instead of a symbol on the model. ([#1176]) +* Fix `have_db_index` so that it can be used against multiple models that are + connected to different databases. ([#1200]) + +[#1176]: https://github.com/thoughtbot/shoulda-matchers/pull/1176 +[#1200]: https://github.com/thoughtbot/shoulda-matchers/pull/1200 + +### Features + +* Add support for Rails 6. No new Rails 6 features are supported, but only + existing features that broke with the upgrade. ([#1193]) +* Add support for expression indexes (Rails 5, Postgres only) to + `have_db_index`. ([#1211]) +* Add `allow_nil` to the `validate_presence_of` matcher. ([834d8d0], [#1100]) + +[#1193]: https://github.com/thoughtbot/shoulda-matchers/pull/1193 +[#1211]: https://github.com/thoughtbot/shoulda-matchers/pull/1211 +[834d8d0]: https://github.com/thoughtbot/shoulda-matchers/commit/834d8d0356573b9f47e63a1b910cfa8f3d815e51 +[#1100]: https://github.com/thoughtbot/shoulda-matchers/pull/1100 + +### Improvements + +* Update `validate_presence_of` so that if it is being used against an + association which is `required: true` or `optional: false`, or it is not + configured as such but ActiveRecord defaults `belong_to` associations to + `optional: false`, and the matcher fails, the developer is reminded in the + failure message that the `belong_to` matcher can be used instead. ([#1214], + [8697b01]) +* Update `define_enum_for` so that it produces a more helpful message on + failure. ([#1216]) + +[#1214]: https://github.com/thoughtbot/shoulda-matchers/pull/1214 +[8697b01]: https://github.com/thoughtbot/shoulda-matchers/commit/8697b015ed88fdbbbcf5d31bf98670f17c3df9e1 +[#1216]: https://github.com/thoughtbot/shoulda-matchers/pull/1216 + +# 4.0.1 + +### Bug fixes + +* Fix gemspec so that `setup` script isn't installed globally when gem is + installed. ([#1180]) + +[#1180]: https://github.com/thoughtbot/shoulda-matchers/pull/1180 + +# 4.0.0 (yanked) + +This release mainly brings the gem up to date with modern versions of Ruby and +Rails and drops support for older, unsupported versions. The compatibility list +is now: + +* **Ruby:** 2.6.0, 2.5.1, 2.4.4, 2.3.7 +* **Rails:** 5.2.2, 5.1.6.1, 5.0.7, 4.2.10 + +### Backward-incompatible changes + +* Drop support for Rails 4.0 and 4.1 as well as Ruby 2.0, 2.1, and 2.2, since + they've been end-of-lifed. The gem now supports Ruby 2.3+ and Rails 4.2+. + +* `use_before_filter`, `use_after_filter`, and `use_around_filter` are no longer + usable when using shoulda-matchers under Rails 5.x, as the corresponding + controller callbacks don't exist there. + + * *PR: [#1054]* + +### Deprecations + +* `define_enum_for`: `with` is deprecated in favor of `with_values`. This is to + prevent confusion with `with_prefix` and `with_suffix`, which are new. + + * *PR: [#1077]* + +### Bug fixes + +* Fix association matchers when used under Rails 5.x so that they make use of + `ActiveRecord::Base.connection.data_sources` instead of + `ActiveRecord::Base.connection.tables`, which was deprecated. + + * *Commit: [61c3654]* + * *PR: [#943]* + * *Original issue: [#933]* + +* Fix the `serialize` matcher so that it works with Rails 5.x. + + * *Commit: [df04f87]* + * *PR: [#965]* + * *Original issue: [#913]* + +* Fix our custom mocking library Doublespeak, which is used by + `delegate_method`, so that it does not produce a warning under Ruby 2.4. + + * *Commit: [8d7dcb8]* + * *PR: [#1038]* + * *Original issue: [#1006]* + +* Fix the `permit` matcher so that it uses the correct method signature to call + the controller action with params in order to prevent a warning under Rails + 5.x. + + * *Commit: [ce9624b]* + * *PRs: [#989], [#964], [#917]* + * *Original issue: [#867]* + +* Fix the `define_enum_for` matcher so that it once more allows string columns + to be used as enum attributes. + + * *Commit: [5650aae]* + * *PR: [#1063]* + * *Original issue: [#912]* + +* Fix `validate_uniqueness_of` when used under Rails 4.2 so that when the + attribute you're testing is a boolean column, it will no longer emit a + warning. + + * *PR: [#1073]* + * *Original issue: [#949]* + +* Fix `validate_inclusion_of` so that if it fails, it will no longer blow up + with the error "undefined method \`attribute_setter' for nil:NilClass". + + * *Original issue: [#904]* + +* Add negative versions of all validation matchers (i.e. implement + `does_not_match?` for them) to prevent them from blowing up with + "undefined method \`attribute_setter' for nil:NilClass". + + * *Original issue: [#904]* + +### Features + +* Add `required` and `optional` qualifiers to `belong_to` and `have_one` + matchers. (When using the `belong_to` matcher under Rails 5+, `required` is + assumed unless overridden.) + + * *Commit: [3af3d9f]* + * *Original PR: [#956]* + * *Original issues: [#870], [#861]* + +* Add `without_validating_presence` qualifier to `belong_to` to get around the + fact that `required` is assumed, above. + + * *Original issues: [#1153], [#1154]* + +* Add `allow_nil` qualifier to `delegate_method`. + + * *Commit: [d49cfca]* + * *Original PR: [#798]* + +* Add `allow_nil` qualifier to `validate_length_of`. + + * *Original PR: [#724]* + +* Add a `port` option to the `route` matcher to allow testing a route that has + a constraint on it such that only a specific port may be used to access that + route. + + * *PRs: [#1074], [#1075]* + * *Original issue: [#954]* + +* Add `with_prefix` and `with_suffix` to `define_enum_for` to allow testing + the `enum` macro with corresponding `prefix` and `suffix` options (Rails 5 + only). + + * *PR: [#1077] + * *Original issue: [#961] + +* Add `index_errors` option to `has_many` (Rails 5 only). + + * *Commit: [795ca68]* + * *PR: [#1089]* + +[a6d09aa]: https://github.com/thoughtbot/shoulda-matchers/commit/a6d09aa5de0d546367e7b3d7177dfde6c66f7f05 +[#943]: https://github.com/thoughtbot/shoulda-matchers/pulls/943 +[#933]: https://github.com/thoughtbot/shoulda-matchers/issues/933 +[df04f87]: https://github.com/thoughtbot/shoulda-matchers/commit/df04f8704abc3754c63c488433dac8c30573da6b +[#965]: https://github.com/thoughtbot/shoulda-matchers/pulls/965 +[#913]: https://github.com/thoughtbot/shoulda-matchers/issues/913 +[8d7dcb8]: https://github.com/thoughtbot/shoulda-matchers/commit/8d7dcb88c3bae8315e4107a39ae17fe19a4b6786 +[#1038]: https://github.com/thoughtbot/shoulda-matchers/pulls/1038 +[#1006]: httpce9624b3c5a08b9134150e228440c771d95782b7s://github.com/thoughtbot/shoulda-matchers/issues/1006 +[ce9624b]: https://github.com/thoughtbot/shoulda-matchers/commit/ce9624b3c5a08b9134150e228440c771d95782b7 +[#989]: https://github.com/thoughtbot/shoulda-matchers/pulls/989 +[#964]: https://github.com/thoughtbot/shoulda-matchers/pulls/964 +[#917]: https://github.com/thoughtbot/shoulda-matchers/pulls/917 +[#867]: https://github.com/thoughtbot/shoulda-matchers/issues/867 +[#1054]: https://github.com/thoughtbot/shoulda-matchers/pulls/1054 +[5650aae]: https://github.com/thoughtbot/shoulda-matchers/commit/5650aae35de85aeabd75bc544324fda33ce1a092 +[#1063]: https://github.com/thoughtbot/shoulda-matchers/pulls/1063 +[#912]: https://github.com/thoughtbot/shoulda-matchers/issues/912 +[#1073]: https://github.com/thoughtbot/shoulda-matchers/pulls/1073 +[#949]: https://github.com/thoughtbot/shoulda-matchers/issues/949 +[d49cfca]: https://github.com/thoughtbot/shoulda-matchers/commit/d49cfcae1b294e12a05e06a5612cb8ebb22a7df1 +[#798]: https://github.com/thoughtbot/shoulda-matchers/pulls/798 +[#724]: https://github.com/thoughtbot/shoulda-matchers/issues/724 +[d49cfca]: https://github.com/thoughtbot/shoulda-matchers/commit/d49cfcae1b294e12a05e06a5612cb8ebb22a7df1 +[3af3d9f]: https://github.com/thoughtbot/shoulda-matchers/commit/3af3d9f7abb768c063759941724ccae48c7b76d6 +[#956]: https://github.com/thoughtbot/shoulda-matchers/pulls/956 +[#870]: https://github.com/thoughtbot/shoulda-matchers/issues/870 +[#861]: https://github.com/thoughtbot/shoulda-matchers/issues/861 +[#1153]: https://github.com/thoughtbot/shoulda-matchers/issues/1153 +[#1154]: https://github.com/thoughtbot/shoulda-matchers/issues/1154 +[#954]: https://github.com/thoughtbot/shoulda-matchers/issues/954 +[#1074]: https://github.com/thoughtbot/shoulda-matchers/pulls/1074 +[#1075]: https://github.com/thoughtbot/shoulda-matchers/pulls/1075 +[#1077]: https://github.com/thoughtbot/shoulda-matchers/pulls/1077 +[#961]: https://github.com/thoughtbot/shoulda-matchers/issues/961 +[795ca68]: https://github.com/thoughtbot/shoulda-matchers/commit/795ca688bff08590dbd2ab6f2b51ea415e0c7473 +[#1089]: https://github.com/thoughtbot/shoulda-matchers/pulls/1089 +[#904]: https://github.com/thoughtbot/shoulda-matchers/issues/904 + +### Improvements + +* Replace usage of Fixnum with Integer to prevent Ruby 2.4 from emitting + deprecation warnings. + + * *Commits: [61c3654], [03a1d21]* + * *PRs: [#1040], [#1031], [#1009]* + * *Original issue: [#1001]* + +[61c3654]: https://github.com/thoughtbot/shoulda-matchers/commit/61c365416a09c5cffd7fcb774a07de4abf8e9afd +[03a1d21]: https://github.com/thoughtbot/shoulda-matchers/commit/03a1d213805a44a0aec99857e01cab8524aa0c05 +[#1040]: https://github.com/thoughtbot/shoulda-matchers/pulls/1040 +[#1031]: https://github.com/thoughtbot/shoulda-matchers/pulls/1031 +[#1009]: https://github.com/thoughtbot/shoulda-matchers/pulls/1009 +[#1001]: https://github.com/thoughtbot/shoulda-matchers/issues/1001 + +# 3.1.3 + +### Improvements + +* Update `BigDecimal.new()` to use `BigDecimal()` and avoid deprecation warnings + in Ruby 2.6. + +# 3.1.2 + +### Deprecations + +* This is the **last version** that supports Rails 4.0 and 4.1 and Ruby 2.0 and + 2.1. + +### Bug fixes + +* When the `permit` matcher was used without `#on`, the controller did not use + `params#require`, the params object was duplicated, and the matcher did not + recognize the `#permit` call inside the controller. This behavior happened + because the matcher overwrote double registries with the same parameter hash + whenever ActionController::Parameters was instantiated. + + * *Commit: [44c019]* + * *Issue: [#899]* + * *Pull request: [#902]* + +[44c019]: https://github.com/thoughtbot/shoulda-matchers/commit/44c0198830921650af3b4a56f5d72aaae2168480 +[#899]: https://github.com/thoughtbot/shoulda-matchers/issues/899 +[#902]: https://github.com/thoughtbot/shoulda-matchers/pulls/902 + +# 3.1.1 + +### Bug fixes + +* Some matchers make use of ActiveSupport's `in?` method, but do not include the + file where this is defined in ActiveSupport. This causes problems with + projects using shoulda-matchers that do not include all of ActiveSupport by + default. To fix this, replace `in?` with Ruby's builtin `include?`. + + * *Pull request: [#879]* + +* `validate_uniqueness_of` works by creating a record if it doesn't exist, and + then testing against a new record with various attributes set that are equal + to (or different than) corresponding attributes in the existing record. In + 3.1.0 a change was made whereby when the uniqueness matcher is given a new + record and creates an existing record out of it, it ensures that the record is + valid before continuing on. This created a problem because if the subject, + before it was saved, was empty and therefore in an invalid state, it could not + effectively be saved. While ideally this should be enforced, doing so would be + a backward-incompatible change, so this behavior has been rolled back. + ([#880], [#884], [#885]) + + * *Commit: [45de869]* + * *Issues: [#880], [#884], [#885]* + +* Fix an issue with `validate_uniqueness_of` + `scoped_to` when used against a + model where the attribute has multiple uniqueness validations and each + validation has a different set of scopes. In this case, a test written for the + first validation (and its scopes) would pass, but tests for the other + validations (and their scopes) would not, as the matcher only considered the + first set of scopes as the *actual* set of scopes. + + * *Commit: [28bd9a1]* + * *Issues: [#830]* + +### Improvements + +* Update `validate_uniqueness_of` so that if an existing record fails to be + created because a column is non-nullable and was not filled in, raise an + ExistingRecordInvalid exception with details on how to fix the test. + + * *Commit: [78ccfc5]* + +[#879]: https://github.com/thoughtbot/shoulda-matchers/issues/879 +[45de869]: https://github.com/thoughtbot/shoulda-matchers/commit/45de8698487d57f559c5bf35818d1c1ee82b0e77 +[#880]: https://github.com/thoughtbot/shoulda-matchers/issues/880 +[#884]: https://github.com/thoughtbot/shoulda-matchers/issues/884 +[#885]: https://github.com/thoughtbot/shoulda-matchers/issues/885 +[78ccfc5]: https://github.com/thoughtbot/shoulda-matchers/commit/78ccfc50b52fa686c109d614df66744b0da65380 +[28bd9a1]: https://github.com/thoughtbot/shoulda-matchers/commit/28bd9a10c71af4d541b692d6204163c394ebd33c +[#830]: https://github.com/thoughtbot/shoulda-matchers/issues/830 + +# 3.1.0 + +### Bug fixes + +* Update `validate_numericality_of` so that submatchers are applied lazily + instead of immediately. Previously, qualifiers were order-dependent, meaning + that if you used `strict` before you used, say, `odd`, then `strict` wouldn't + actually apply to `odd`. Now the order that you specify qualifiers doesn't + matter. + + * *Source: [6c67a5e]* + +* Fix `allow_value` so that it does not raise an AttributeChangedValueError + (formerly CouldNotSetAttributeError) when used against an attribute that is an + enum in an ActiveRecord model. + + * *Source: [9e8603e]* + +* Add a `ignoring_interference_by_writer` qualifier to all matchers, not just + `allow_value`. *This is enabled by default, which means that you should never + get a CouldNotSetAttributeError again.* (You may get some more information if + a test fails, however.) + + * *Source: [1189934], [5532f43]* + * *Fixes: [#786], [#799], [#801], [#804], [#817], [#841], [#849], [#872], + [#873], and [#874]* + +* Fix `validate_numericality_of` so that it does not blow up when used against + a virtual attribute defined in an ActiveRecord model (that is, an attribute + that is not present in the database but is defined using `attr_accessor`). + + * *Source: [#822]* + +* Update `validate_numericality_of` so that it no longer raises an + IneffectiveTestError if used against a numeric column. + + * *Source: [5ed0362]* + * *Fixes: [#832]* + +[6c67a5e]: https://github.com/thoughtbot/shoulda-matchers/commit/6c67a5eb0df265d3a565aa7d1a7e2b645051eb5a +[9e8603e]: https://github.com/thoughtbot/shoulda-matchers/commit/9e8603eb745bfa2a5aea6dfef85adf680d447151 +[1189934]: https://github.com/thoughtbot/shoulda-matchers/commit/118993480604d39c73687d069f7af3726f3e3f3e +[5532f43]: https://github.com/thoughtbot/shoulda-matchers/commit/5532f4359aa332b10de7d46f876eaffd4a95b5b6 +[#786]: https://github.com/thoughtbot/shoulda-matchers/issues/786 +[#799]: https://github.com/thoughtbot/shoulda-matchers/issues/799 +[#801]: https://github.com/thoughtbot/shoulda-matchers/issues/801 +[#804]: https://github.com/thoughtbot/shoulda-matchers/issues/804 +[#817]: https://github.com/thoughtbot/shoulda-matchers/issues/817 +[#841]: https://github.com/thoughtbot/shoulda-matchers/issues/841 +[#849]: https://github.com/thoughtbot/shoulda-matchers/issues/849 +[#872]: https://github.com/thoughtbot/shoulda-matchers/issues/872 +[#873]: https://github.com/thoughtbot/shoulda-matchers/issues/873 +[#874]: https://github.com/thoughtbot/shoulda-matchers/issues/874 +[#822]: https://github.com/thoughtbot/shoulda-matchers/pull/822 +[5ed0362]: https://github.com/thoughtbot/shoulda-matchers/commit/5ed03624197314865ff5463e473e5e84bb91d9ea +[#832]: https://github.com/thoughtbot/shoulda-matchers/issues/832 + +### Features + +* Add a new qualifier, `ignoring_case_sensitivity`, to `validate_uniqueness_of`. + This provides a way to test uniqueness of an attribute whose case is + normalized, either in a custom writer method for that attribute, or in a + custom `before_validation` callback. + + * *Source: [#840]* + * *Fixes: [#836]* + +[#840]: https://github.com/thoughtbot/shoulda-matchers/pull/840 +[#836]: https://github.com/thoughtbot/shoulda-matchers/issues/836 + +### Improvements + +* Improve failure messages and descriptions of all matchers across the board so + that it is easier to understand what the matcher was doing when it failed. + (You'll see a huge difference in the output of the numericality and uniqueness + matchers in particular.) + +* Matchers now raise an error if any attributes that the matcher is attempting + to set do not exist on the model. + + * *Source: [2962112]* + +* Update `validate_numericality_of` so that it doesn't always run all of the + submatchers, but stops on the first one that fails. Since failure messages + now contain information as to what value the matcher set on the attribute when + it failed, this change guarantees that the correct value will be shown. + + * *Source: [8e24a6e]* + +* Continue to detect if attributes change incoming values, but now instead of + immediately seeing a CouldNotSetAttributeError, you will only be informed + about it if the test you've written fails. + + * *Source: [1189934]* + +* Add an additional check to `define_enum_for` to ensure that the column that + underlies the enum attribute you're testing is an integer column. + + * *Source: [68dd70a]* + +* Add a test for `validate_numericality_of` so that it officially supports money + columns. + + * *Source: [a559713]* + * *Refs: [#841]* + +[2962112]: https://github.com/thoughtbot/shoulda-matchers/commit/296211211497e624dde87adae68b385ad4cdae3a +[8e24a6e]: https://github.com/thoughtbot/shoulda-matchers/commit/8e24a6e9b2b147f2c51fb03aa02543f213acab34 +[68dd70a]: https://github.com/thoughtbot/shoulda-matchers/commit/68dd70a23d8997a490683adcd2108a4a5cadf8ba +[a559713]: https://github.com/thoughtbot/shoulda-matchers/commit/a559713f96303414551c0bc1767fb11eb19bcc5d + +# 3.0.1 + +### Bug fixes + +* Fix `validate_inclusion_of` + `in_array` when used against a date or datetime + column/attribute so that it does not raise a CouldNotSetAttributeError. + ([#783], [8fa97b4]) + +* Fix `validate_numericality_of` when used against a numeric column so that it + no longer raises a CouldNotSetAttributeError if the matcher has been qualified + in any way (`only_integer`, `greater_than`, `odd`, etc.). ([#784], [#812]) + +### Improvements + +* `validate_uniqueness_of` now raises a NonCaseSwappableValueError if the value + the matcher is using to test uniqueness cannot be case-swapped -- in other + words, if it doesn't contain any alpha characters. When this is the case, the + matcher cannot work effectively. ([#789], [ada9bd3]) + +[#783]: https://github.com/thoughtbot/shoulda-matchers/pull/783 +[8fa97b4]: https://github.com/thoughtbot/shoulda-matchers/commit/8fa97b4ff33b57ce16dfb96be1ec892502f2aa9e +[#784]: https://github.com/thoughtbot/shoulda-matchers/pull/784 +[#789]: https://github.com/thoughtbot/shoulda-matchers/pull/789 +[ada9bd3]: https://github.com/thoughtbot/shoulda-matchers/commit/ada9bd3a1b9f2bb9fa74d0dfe1f8f7080314298c +[#812]: https://github.com/thoughtbot/shoulda-matchers/pull/812 + +# 3.0.0 + +### Backward-incompatible changes + +* We've dropped support for Rails 3.x, Ruby 1.9.2, and Ruby 1.9.3, and RSpec 2. + All of these have been end-of-lifed. ([a4045a1], [b7fe87a], [32c0e62]) + +* The gem no longer detects the test framework you're using or mixes itself into + that framework automatically. [History][no-auto-integration-1] has + [shown][no-auto-integration-2] that performing any kind of detection is prone + to bugs and more complicated than it should be. + + Here are the updated instructions: + + * You no longer need to say `require: false` in your Gemfile; you can + include the gem as normal. + * You'll need to add the following somewhere in your `rails_helper` (for + RSpec) or `test_helper` (for Minitest / Test::Unit): + + ``` ruby + Shoulda::Matchers.configure do |config| + config.integrate do |with| + # Choose a test framework: + with.test_framework :rspec + with.test_framework :minitest + with.test_framework :minitest_4 + with.test_framework :test_unit + + # Choose one or more libraries: + with.library :active_record + with.library :active_model + with.library :action_controller + # Or, choose the following (which implies all of the above): + with.library :rails + end + end + ``` + + ([1900071]) + +* Previously, under RSpec, all of the matchers were mixed into all of the + example groups. This created a problem because some gems, such as + [active_model_serializers-matchers], provide matchers that share the same + name as some of our own matchers. Now, matchers are only mixed into whichever + example group they belong to: + + * ActiveModel and ActiveRecord matchers are available only in model example + groups. + * ActionController matchers are available only in controller example groups. + * The `route` matcher is available only in routing example groups. + + ([af98a23], [8cf449b]) + +* There are two changes to `allow_value`: + + * The negative form of `allow_value` has been changed so that instead of + asserting that any of the given values is an invalid value (allowing good + values to pass through), assert that *all* values are invalid values + (allowing good values not to pass through). This means that this test which + formerly passed will now fail: + + ``` ruby + expect(record).not_to allow_value('good value', *bad_values) + ``` + + ([19ce8a6]) + + * `allow_value` now raises a CouldNotSetAttributeError if in setting the + attribute, the value of the attribute from reading the attribute back is + different from the one used to set it. + + This would happen if the writer method for that attribute has custom logic + to ignore certain incoming values or change them in any way. Here are three + examples we've seen: + + * You're attempting to assert that an attribute should not allow nil, yet + the attribute's writer method contains a conditional to do nothing if + the attribute is set to nil: + + ``` ruby + class Foo + include ActiveModel::Model + + attr_reader :bar + + def bar=(value) + return if value.nil? + @bar = value + end + end + + describe Foo do + it do + foo = Foo.new + foo.bar = "baz" + # This will raise a CouldNotSetAttributeError since `foo.bar` is now "123" + expect(foo).not_to allow_value(nil).for(:bar) + end + end + ``` + + * You're attempting to assert that an numeric attribute should not allow a + string that contains non-numeric characters, yet the writer method for + that attribute strips out non-numeric characters: + + ``` ruby + class Foo + include ActiveModel::Model + + attr_reader :bar + + def bar=(value) + @bar = value.gsub(/\D+/, '') + end + end + + describe Foo do + it do + foo = Foo.new + # This will raise a CouldNotSetAttributeError since `foo.bar` is now "123" + expect(foo).not_to allow_value("abc123").for(:bar) + end + end + ``` + + * You're passing a value to `allow_value` that the model typecasts into + another value: + + ``` ruby + describe Foo do + # Assume that `attr` is a string + # This will raise a CouldNotSetAttributeError since `attr` typecasts `[]` to `"[]"` + it { should_not allow_value([]).for(:attr) } + end + ``` + + With all of these failing examples, why are we making this change? We want + to guard you (as the developer) from writing a test that you think acts one + way but actually acts a different way, as this could lead to a confusing + false positive or negative. + + If you understand the problem and wish to override this behavior so that + you do not get a CouldNotSetAttributeError, you can add the + `ignoring_interference_by_writer` qualifier like so. Note that this will not + always cause the test to pass. + + ``` ruby + it { should_not allow_value([]).for(:attr).ignoring_interference_by_writer } + ``` + + ([9d9dc4e]) + +* `validate_uniqueness_of` is now properly case-sensitive by default, to match + the default behavior of the validation itself. This is a backward-incompatible + change because this test which incorrectly passed before will now fail: + + ``` ruby + class Product < ActiveRecord::Base + validates_uniqueness_of :name, case_sensitive: false + end + + describe Product do + it { is_expected.to validate_uniqueness_of(:name) } + end + ``` + + ([57a1922]) + +* `ensure_inclusion_of`, `ensure_exclusion_of`, and `ensure_length_of` have been + removed in favor of their `validate_*` counterparts. ([55c8d09]) + +* `set_the_flash` and `set_session` have been changed to more closely align with + each other: + * `set_the_flash` has been removed in favor of `set_flash`. ([801f2c7]) + * `set_session('foo')` is no longer valid syntax, please use + `set_session['foo']` instead. ([535fe05]) + * `set_session['key'].to(nil)` will no longer pass when the key in question + has not been set yet. ([535fe05]) + +* Change `set_flash` so that `set_flash[:foo].now` is no longer valid syntax. + You'll want to use `set_flash.now[:foo]` instead. This was changed in order to + more closely align with how `flash.now` works when used in a controller. + ([#755], [#752]) + +* Change behavior of `validate_uniqueness_of` when the matcher is not + qualified with any scopes, but your validation is. Previously the following + test would pass when it now fails: + + ``` ruby + class Post < ActiveRecord::Base + validate :slug, uniqueness: { scope: :user_id } + end + + describe Post do + it { should validate_uniqueness_of(:slug) } + end + ``` + + ([6ac7b81]) + +[active_model_serializers-matchers]: https://github.com/adambarber/active_model_serializers-matchers +[no-auto-integration-1]: https://github.com/freerange/mocha/commit/049080c673ee3f76e76adc1e1a6122c7869f1648 +[no-auto-integration-2]: https://github.com/rr/rr/issues/29 +[1900071]: https://github.com/thoughtbot/shoulda-matchers/commit/190007155e0676aae84d08d8ed8eed3beebc3a06 +[b7fe87a]: https://github.com/thoughtbot/shoulda-matchers/commit/b7fe87ae915f6b1f99d64e847fea536ad0f78024 +[a4045a1]: https://github.com/thoughtbot/shoulda-matchers/commit/a4045a1f9bc454e618a7c55960942eb030f02fdd +[57a1922]: https://github.com/thoughtbot/shoulda-matchers/commit/57a19228b6a85f12ba7a79a26dae5869c1499c6d +[19ce8a6]: https://github.com/thoughtbot/shoulda-matchers/commit/19c38a642a2ae1316ef12540a0185cd026901e74 +[eaaa2d8]: https://github.com/thoughtbot/shoulda-matchers/commit/eaaa2d83e5cd31a3ca0a1aaa65441ea1a4fffa49 +[55c8d09]: https://github.com/thoughtbot/shoulda-matchers/commit/55c8d09bf2af886540924efa83c3b518d926a770 +[801f2c7]: https://github.com/thoughtbot/shoulda-matchers/commit/801f2c7c1eab3b2053244485c9800f850959cfef +[535fe05]: https://github.com/thoughtbot/shoulda-matchers/commit/535fe05be8686fdafd8b22f2ed5c4192bd565d50 +[6ac7b81]: https://github.com/thoughtbot/shoulda-matchers/commit/6ac7b8158cfba3b518eb3da3c24345e4473b416f +[#755]: https://github.com/thoughtbot/shoulda-matchers/pull/755 +[#752]: https://github.com/thoughtbot/shoulda-matchers/pull/752 +[9d9dc4e]: https://github.com/thoughtbot/shoulda-matchers/commit/9d9dc4e6b9cf2c19df66a1b4ba432ad8d3e5dded +[32c0e62]: https://github.com/thoughtbot/shoulda-matchers/commit/32c0e62596b87e37a301f87bbe21cfcc77750552 +[af98a23]: https://github.com/thoughtbot/shoulda-matchers/commit/af98a23091551fb40aded5a8d4f9e5be926f53a9 +[8cf449b]: https://github.com/thoughtbot/shoulda-matchers/commit/8cf449b4ca37d0d7446d2cabbfa5a1582358256d + +### Bug fixes + +* So far the tests for the gem have been running against only SQLite. Now they + run against PostgreSQL, too. As a result we were able to fix some + Postgres-related bugs, specifically around `validate_uniqueness_of`: + + * When scoped to a UUID column that ends in an "f", the matcher is able to + generate a proper "next" value without erroring. ([#402], [#587], [#662]) + + * Support scopes that are PostgreSQL array columns. Please note that this is + only supported for Rails 4.2 and greater, as versions before this cannot + handle array columns correctly, particularly in conjunction with the + uniqueness validator. ([#554]) + + * Fix so that when scoped to a text column and the scope is set to nil before + running it through the matcher, the matcher does not fail. ([#521], [#607]) + +* Fix `define_enum_for` so that it actually tests that the attribute is present + in the list of defined enums, as you could fool it by merely defining a class + method that was the pluralized version of the attribute name. In the same + vein, passing a pluralized version of the attribute name to `define_enum_for` + would erroneously pass, and now it fails. ([#641]) + +* Fix `permit` so that it does not break the functionality of + ActionController::Parameters#require. ([#648], [#675]) + +* Fix `validate_uniqueness_of` + `scoped_to` so that it does not raise an error + if a record exists where the scoped attribute is nil. ([#677]) + +* Fix `route` matcher so if your route includes a default `format`, you can + specify this as a symbol or string. ([#693]) + +* Fix `validate_uniqueness_of` so that it allows you to test against scoped + attributes that are boolean columns. ([#457], [#694]) + +* Fix failure message for `validate_numericality_of` as it sometimes didn't + provide the reason for failure. ([#699]) + +* Fix `shoulda/matchers/independent` so that it can be required + independently, without having to require all of the gem. ([#746], [e0a0200]) + +### Features + +* Add `on` qualifier to `permit`. This allows you to make an assertion that + a restriction was placed on a slice of the `params` hash and not the entire + `params` hash. Although we don't require you to use this qualifier, we do + recommend it, as it's a more precise check. ([#675]) + +* Add `strict` qualifier to `validate_numericality_of`. ([#620]) + +* Add `on` qualifier to `validate_numericality_of`. ([9748869]; h/t [#356], + [#358]) + +* Add `join_table` qualifier to `have_and_belong_to_many`. ([#556]) + +* `allow_values` is now an alias for `allow_value`. This makes more sense when + checking against multiple values: + + ``` ruby + it { should allow_values('this', 'and', 'that') } + ``` + + ([#692]) + +[9748869]: https://github.com/thoughtbot/shoulda-matchers/commit/97488690910520ed8e1f2e164b1982eff5ef1f19 +[#402]: https://github.com/thoughtbot/shoulda-matchers/pull/402 +[#587]: https://github.com/thoughtbot/shoulda-matchers/pull/587 +[#662]: https://github.com/thoughtbot/shoulda-matchers/pull/662 +[#554]: https://github.com/thoughtbot/shoulda-matchers/pull/554 +[#641]: https://github.com/thoughtbot/shoulda-matchers/pull/641 +[#521]: https://github.com/thoughtbot/shoulda-matchers/pull/521 +[#607]: https://github.com/thoughtbot/shoulda-matchers/pull/607 +[#648]: https://github.com/thoughtbot/shoulda-matchers/pull/648 +[#675]: https://github.com/thoughtbot/shoulda-matchers/pull/675 +[#677]: https://github.com/thoughtbot/shoulda-matchers/pull/677 +[#620]: https://github.com/thoughtbot/shoulda-matchers/pull/620 +[#693]: https://github.com/thoughtbot/shoulda-matchers/pull/693 +[#356]: https://github.com/thoughtbot/shoulda-matchers/pull/356 +[#358]: https://github.com/thoughtbot/shoulda-matchers/pull/358 +[#556]: https://github.com/thoughtbot/shoulda-matchers/pull/556 +[#457]: https://github.com/thoughtbot/shoulda-matchers/pull/457 +[#694]: https://github.com/thoughtbot/shoulda-matchers/pull/694 +[#692]: https://github.com/thoughtbot/shoulda-matchers/pull/692 +[#699]: https://github.com/thoughtbot/shoulda-matchers/pull/699 +[#746]: https://github.com/thoughtbot/shoulda-matchers/pull/746 +[e0a0200]: https://github.com/thoughtbot/shoulda-matchers/commit/e0a0200fe47157c161fb206043540804bdad664e + # 2.8.0 ### Deprecations @@ -49,13 +870,6 @@ notation (e.g. `posts#show`), route parameters such as `id` do not need to be specified as a string but may be specified as a number as well. ([#602]) -* Fix `allow_value`, `validate_numericality_of` and `validate_inclusion_of` so - that they handle RangeErrors emitted from ActiveRecord 4.2. These exceptions - arise whenever we attempt to set an attribute using a value that lies outside - the range of the column (assuming the column is an integer). RangeError is now - treated specially, failing the test instead of bubbling up as an error. - ([#634], [#637], [#642]) - ### Features * Add ability to test `:primary_key` option on associations. ([#597]) @@ -101,9 +915,6 @@ [#622]: https://github.com/thoughtbot/shoulda-matchers/pull/622 [#627]: https://github.com/thoughtbot/shoulda-matchers/pull/627 [#631]: https://github.com/thoughtbot/shoulda-matchers/pull/631 -[#634]: https://github.com/thoughtbot/shoulda-matchers/pull/634 -[#637]: https://github.com/thoughtbot/shoulda-matchers/pull/637 -[#642]: https://github.com/thoughtbot/shoulda-matchers/pull/642 # 2.7.0 diff -Nru ruby-shoulda-matchers-2.8.0/.python-version ruby-shoulda-matchers-4.3.0/.python-version --- ruby-shoulda-matchers-2.8.0/.python-version 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/.python-version 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1 @@ +2.7.15 diff -Nru ruby-shoulda-matchers-2.8.0/Rakefile ruby-shoulda-matchers-4.3.0/Rakefile --- ruby-shoulda-matchers-2.8.0/Rakefile 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/Rakefile 2020-02-18 07:23:52.000000000 +0000 @@ -3,6 +3,8 @@ require 'rspec/core/rake_task' require 'appraisal' require_relative 'tasks/documentation' +require_relative 'spec/support/tests/database' +require_relative 'spec/support/tests/current_bundle' RSpec::Core::RakeTask.new('spec:unit') do |t| t.ruby_opts = '-w -r ./spec/report_warnings' @@ -19,16 +21,24 @@ end task :default do - if ENV['BUNDLE_GEMFILE'] =~ /gemfiles/ - sh 'rake spec:unit' - sh 'rake spec:acceptance' + if Tests::CurrentBundle.instance.appraisal_in_use? + sh 'rake spec:unit --trace' + sh 'rake spec:acceptance --trace' else - Rake::Task['appraise'].invoke + if ENV['CI'] + exec "appraisal install && appraisal rake --trace" + else + appraisal = Tests::CurrentBundle.instance.latest_appraisal + exec "appraisal install && appraisal #{appraisal} rake --trace" + end end end -task :appraise do - exec 'appraisal install && appraisal rake' +namespace :appraisal do + task :list do + appraisals = Tests::CurrentBundle.instance.available_appraisals + puts "Valid appraisals: #{appraisals.join(', ')}" + end end Shoulda::Matchers::DocumentationTasks.create diff -Nru ruby-shoulda-matchers-2.8.0/README.md ruby-shoulda-matchers-4.3.0/README.md --- ruby-shoulda-matchers-2.8.0/README.md 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/README.md 2020-02-18 07:23:52.000000000 +0000 @@ -1,19 +1,308 @@ -# shoulda-matchers [![Gem Version][version-badge]][rubygems] [![Build Status][travis-badge]][travis] ![Downloads][downloads-badge] +# Shoulda Matchers [![Gem Version][version-badge]][rubygems] [![Build Status][travis-badge]][travis] [![Total Downloads][downloads-total]][rubygems] [![Downloads][downloads-badge]][rubygems] [![Hound][hound-badge]][hound] -[Official Documentation][rubydocs] +[version-badge]: https://img.shields.io/gem/v/shoulda-matchers.svg +[rubygems]: https://rubygems.org/gems/shoulda-matchers +[travis-badge]: https://img.shields.io/travis/thoughtbot/shoulda-matchers/master.svg +[travis]: https://travis-ci.org/thoughtbot/shoulda-matchers +[downloads-total]: https://img.shields.io/gem/dt/shoulda-matchers.svg +[downloads-badge]: https://img.shields.io/gem/dtv/shoulda-matchers.svg +[downloads-badge]: https://img.shields.io/gem/dtv/shoulda-matchers.svg +[hound-badge]: https://img.shields.io/badge/Reviewed_by-Hound-8E64B0.svg +[hound]: https://houndci.com -shoulda-matchers provides Test::Unit- and RSpec-compatible one-liners that test -common Rails functionality. These tests would otherwise be much longer, more +[![shoulda-matchers][logo]][website] + +[logo]: https://matchers.shoulda.io/images/shoulda-matchers-logo.png +[website]: https://matchers.shoulda.io/ + +Shoulda Matchers provides RSpec- and Minitest-compatible one-liners to test +common Rails functionality that, if written by hand, would be much longer, more complex, and error-prone. -### ActiveModel Matchers +## Quick links + +📖 **[Read the documentation for the latest version][rubydocs].** +📢 **[See what's changed in a recent version][news].** + +[rubydocs]: http://matchers.shoulda.io/docs +[news]: NEWS.md + +## Table of contents + +* [Getting started](#getting-started) + * [RSpec](#rspec) + * [Minitest](#minitest) +* [Usage](#usage) + * [On the subject of `subject`](#on-the-subject-of-subject) + * [Availability of RSpec matchers in example groups](#availability-of-rspec-matchers-in-example-groups) + * [`should` vs `is_expected.to`](#should-vs-is_expectedto) +* [Matchers](#matchers) + * [ActiveModel matchers](#activemodel-matchers) + * [ActiveRecord matchers](#activerecord-matchers) + * [ActionController matchers](#actioncontroller-matchers) + * [Independent matchers](#independent-matchers) +* [Compatibility](#compatibility) +* [Contributing](#contributing) +* [Versioning](#versioning) +* [License](#license) +* [About thoughtbot](#about-thoughtbot) + +## Getting started + +### RSpec + +Start by including `shoulda-matchers` in your Gemfile: + +```ruby +group :test do + gem 'shoulda-matchers' +end +``` + +Now you need to tell the gem a couple of things: + +* Which test framework you're using +* Which portion of the matchers you want to use + +You can supply this information by providing a configuration block. Where this +goes and what this contains depends on your project. + +#### Rails apps + +Assuming you are testing a Rails app, simply place this at the bottom of +`spec/rails_helper.rb` (or in a support file if you so choose): + +```ruby +Shoulda::Matchers.configure do |config| + config.integrate do |with| + with.test_framework :rspec + with.library :rails + end +end +``` + +Now you're ready to [use matchers in your tests](#usage)! + +#### Non-Rails apps + +If your project isn't a Rails app, but you still make use of ActiveRecord or +ActiveModel, you can still use this gem too! In that case, you'll want to place +the following configuration at the bottom of `spec/spec_helper.rb`: + +```ruby +Shoulda::Matchers.configure do |config| + config.integrate do |with| + with.test_framework :rspec + + # Keep as many of these lines as are necessary: + with.library :active_record + with.library :active_model + end +end +``` + +Now you're ready to [use matchers in your tests](#usage)! + +### Minitest + +Shoulda Matchers was originally a component of [Shoulda][shoulda], a gem that +also provides `should` and `context` syntax via +[`shoulda-context`][shoulda-context]. + +[shoulda]: https://github.com/thoughtbot/shoulda +[shoulda-context]: https://github.com/thoughtbot/shoulda-context + +At the moment, `shoulda` has not been updated to support `shoulda-matchers` 3.x +and 4.x, so you'll want to add the following to your Gemfile: + +```ruby +group :test do + gem 'shoulda', '~> 3.5' + gem 'shoulda-matchers', '~> 2.0' + gem 'rails-controller-testing' +end +``` + +Now you're ready to [use matchers in your tests](#usage)! + +## Usage + +The matchers provided by this gem are divided into different categories +depending on what you're testing within your Rails app: + +* [database models backed by ActiveRecord](#activemodel-matchers) +* [non-database models, form objects, etc. backed by + ActiveModel](#activerecord-matchers) +* [controllers](#actioncontroller-matchers) +* [routes](#routing-matchers) (RSpec only) +* [usage of Rails-specific features like `delegate`](#independent-matchers) + +All matchers are designed to be prepended primarily with the word `should`, +which is a special directive in both RSpec and Shoulda. For instance, a model +test case may look something like: + +``` ruby +# RSpec +RSpec.describe MenuItem, type: :model do + describe 'associations' do + it { should belong_to(:category).class_name('MenuCategory') } + end + + describe 'validations' do + it { should validate_presence_of(:name) } + it { should validate_uniqueness_of(:name).scoped_to(:category_id) } + end +end + +# Minitest (Shoulda) +class MenuItemTest < ActiveSupport::TestCase + context 'associations' do + should belong_to(:category).class_name('MenuCategory') + end + + context 'validations' do + should validate_presence_of(:name) + should validate_uniqueness_of(:name).scoped_to(:category_id) + end +end +``` + +For the full set of matchers you can use, [see below](#matchers). + +### On the subject of `subject` + +For both RSpec and Shoulda, the **subject** is an implicit reference to the +object under test, and all of the matchers make use of it internally when they +are run. This is always set automatically by your test framework in any given +test case; however, in certain cases it can be advantageous to override the +subject. For instance, when testing validations in a model, it is customary to +provide a valid model instead of a fresh one: + +``` ruby +# RSpec +RSpec.describe Post, type: :model do + describe 'validations' do + # Here we're using FactoryBot, but you could use anything + subject { build(:post) } + + it { should validate_presence_of(:title) } + end +end + +# Minitest (Shoulda) +class PostTest < ActiveSupport::TestCase + context 'validations' do + subject { build(:post) } + + should validate_presence_of(:title) + end +end +``` + +When overriding the subject in this manner, then, it's important to provide the +correct object. **When in doubt, provide an instance of the class under test.** +This is particularly necessary for controller tests, where it is easy to +accidentally write something like: + +``` ruby +RSpec.describe PostsController, type: :controller do + describe 'GET #index' do + subject { get :index } + + # This may work... + it { should have_http_status(:success) } + # ...but this will not! + it { should permit(:title, :body).for(:post) } + end +end +``` + +In this case, you would want to use `before` rather than `subject`: + +``` ruby +RSpec.describe PostsController, type: :controller do + describe 'GET #index' do + before { get :index } + + # Notice that we have to assert have_http_status on the response here... + it { expect(response).to have_http_status(:success) } + # ...but we do not have to provide a subject for render_template + it { should render_template('index') } + end +end +``` + +### Availability of RSpec matchers in example groups + +If you're using RSpec, then you're probably familiar with the concept of example +groups: these are different kinds of test cases, and each of them has special +behavior around them. As alluded to [above](#usage), this gem works in a similar +way, and there are matchers that are only available in certain types of example +groups: + +* ActiveRecord and ActiveModel matchers are available only in model example + groups, i.e., those tagged with `type: :model` or in files located under + `spec/models`. +* ActionController matchers are available only in controller example groups, + i.e., those tagged with `type: :controller` or in files located under + `spec/controllers`. +* The `route` matcher is available in routing example groups, i.e., those + tagged with `type: :routing` or in files located under `spec/routing`. +* Independent matchers are available in all example groups. + +As long as you're using Rails, you don't need to worry about this — everything +should "just work". + +**However, if you are using ActiveModel or ActiveRecord outside of Rails**, and +you want to use model matchers in certain example groups, you'll need to +manually include the module that holds those matchers. A good way to do this is +to place the following in your `spec_helper.rb`: + +```ruby +RSpec.configure do |config| + config.include(Shoulda::Matchers::ActiveModel, type: :model) + config.include(Shoulda::Matchers::ActiveRecord, type: :model) +end +``` + +Then you can say: + +```ruby +describe MySpecialModel, type: :model do + # ... +end +``` + +### `should` vs `is_expected.to` + +In this README and throughout the documentation, we're using the `should` form +of RSpec's one-liner syntax over `is_expected.to`. The `should` form works +regardless of how you've configured RSpec — meaning you can still use it even +when using the `expect` syntax. But if you prefer to use `is_expected.to`, you +can do that too: + +```ruby +RSpec.describe Person, type: :model do + it { is_expected.to validate_presence_of(:name) } +end +``` + +## Matchers + +The following is a list of matchers shipped with the gem. If you need details +about any of them, make sure to [consult the documentation][rubydocs]! + +### ActiveModel matchers -* **[allow_mass_assignment_of](lib/shoulda/matchers/active_model/allow_mass_assignment_of_matcher.rb)** - tests usage of Rails 3's `attr_accessible` and `attr_protected` macros. * **[allow_value](lib/shoulda/matchers/active_model/allow_value_matcher.rb)** - tests usage of the `validates_format_of` validation. + tests that an attribute is valid or invalid if set to one or more values. + *(Aliased as #allow_values.)* * **[have_secure_password](lib/shoulda/matchers/active_model/have_secure_password_matcher.rb)** tests usage of `has_secure_password`. +* **[validate_absence_of](lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb)** + tests usage of `validates_absence_of`. +* **[validate_acceptance_of](lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb)** + tests usage of `validates_acceptance_of`. * **[validate_confirmation_of](lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb)** tests usage of `validates_confirmation_of`. * **[validate_exclusion_of](lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb)** @@ -27,7 +316,7 @@ * **[validate_presence_of](lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb)** tests usage of `validates_presence_of`. -### ActiveRecord Matchers +### ActiveRecord matchers * **[accept_nested_attributes_for](lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb)** tests usage of the `accepts_nested_attributes_for` macro. @@ -47,15 +336,19 @@ tests your `has_one` associations. * **[have_readonly_attribute](lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb)** tests usage of the `attr_readonly` macro. +* **[have_rich_text](lib/shoulda/matchers/active_record/have_rich_text_matcher.rb)** + tests your `has_rich_text` associations. * **[serialize](lib/shoulda/matchers/active_record/serialize_matcher.rb)** tests usage of the `serialize` macro. * **[validate_uniqueness_of](lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb)** tests usage of `validates_uniqueness_of`. -### ActionController Matchers +### ActionController matchers * **[filter_param](lib/shoulda/matchers/action_controller/filter_param_matcher.rb)** tests parameter filtering configuration. +* **[permit](lib/shoulda/matchers/action_controller/permit_matcher.rb)** tests + that an action places a restriction on the `params` hash. * **[redirect_to](lib/shoulda/matchers/action_controller/redirect_to_matcher.rb)** tests that an action redirects to a certain location. * **[render_template](lib/shoulda/matchers/action_controller/render_template_matcher.rb)** @@ -72,119 +365,69 @@ makes assertions on the `session` hash. * **[set_flash](lib/shoulda/matchers/action_controller/set_flash_matcher.rb)** makes assertions on the `flash` hash. -* **[use_after_action](lib/shoulda/matchers/action_controller/use_after_action.rb)** - tests that a `after_action` callback is defined in your controller. (Aliased - as *use_after_filter*.) -* **[use_around_action](lib/shoulda/matchers/action_controller/use_around_action.rb)** - tests that a `around_action` callback is defined in your controller. (Aliased - as *use_around_filter*.) -* **[use_before_action](lib/shoulda/matchers/action_controller/use_before_action.rb)** - tests that a `before_action` callback is defined in your controller. (Aliased - as *use_before_filter*.) +* **[use_after_action](lib/shoulda/matchers/action_controller/callback_matcher.rb#L79)** + tests that an `after_action` callback is defined in your controller. +* **[use_around_action](lib/shoulda/matchers/action_controller/callback_matcher.rb#L129)** + tests that an `around_action` callback is defined in your controller. +* **[use_before_action](lib/shoulda/matchers/action_controller/callback_matcher.rb#L54)** + tests that a `before_action` callback is defined in your controller. -### Independent Matchers +### Routing matchers + +* **[route](lib/shoulda/matchers/action_controller/route_matcher.rb)** tests + your routes. + +### Independent matchers * **[delegate_method](lib/shoulda/matchers/independent/delegate_method_matcher.rb)** tests that an object forwards messages to other, internal objects by way of delegation. -## Installation +## Compatibility -### RSpec +Shoulda Matchers is tested and supported against Ruby 2.4+, Rails 5.x, Rails +4.2.x, RSpec 3.x, and Minitest 5.x. -Include the gem in your Gemfile: +For Ruby < 2.4 and Rails < 4.1 compatibility, please use [v3.1.3][v3.1.3]. -``` ruby -group :test do - gem 'shoulda-matchers', require: false -end -``` - -Then require the gem following rspec-rails in your rails_helper (or spec_helper -if you're using RSpec 2.x): - -``` ruby -require 'rspec/rails' -require 'shoulda/matchers' -``` +[v3.1.3]: https://github.com/thoughtbot/shoulda-matchers/releases/tag/v3.1.3 -### Test::Unit - -shoulda-matchers was originally a component of [Shoulda][shoulda], a meta-gem -that also provides `should` and `context` syntax via -[shoulda-context][shoulda-context]. For this reason you'll want to include this -gem in your Gemfile instead: - -```ruby -group :test do - gem 'shoulda' -end -``` - -### Non-Rails apps - -Once it is loaded, shoulda-matchers automatically includes itself into your test -framework. It will mix in the appropriate matchers for ActiveRecord, -ActiveModel, and ActionController depending on the modules that are available at -runtime. For instance, in order to use the ActiveRecord matchers, ActiveRecord -must be present beforehand. - -If your application is written against Rails, everything should "just work", as -shoulda-matchers will most likely be declared after Rails in your Gemfile. If -your application is written against another framework such as Sinatra or -Padrino, you may have a different setup, so you will want to ensure that you are -requiring shoulda-matchers after the components of Rails you are using. For -instance, if you wanted to use and test against ActiveModel, you'd say: - -```ruby -gem 'activemodel' -gem 'shoulda-matchers' -``` +## Contributing -and not: +Shoulda Matchers is open source, and we are grateful for +[everyone][contributors] who's contributed so far. -```ruby -gem 'shoulda-matchers' -gem 'activemodel' -``` - -## Generating documentation +[contributors]: https://github.com/thoughtbot/shoulda-matchers/contributors -YARD is used to generate documentation, which can be viewed [online][rubydocs]. -You can preview changes you make to the documentation locally by running +If you'd like to contribute, please take a look at the +[instructions](CONTRIBUTING.md) for installing dependencies and crafting a good +pull request. - yard doc +## Versioning -from this directory. Then, open `doc/index.html` in your browser. +Shoulda Matchers follows Semantic Versioning 2.0 as defined at +. -If you want to see a live preview as you work without having to run `yard` over -and over again, keep this command running in a separate terminal session: +## License - watchr docs.watchr +Shoulda Matchers is copyright © 2006-2020 +[thoughtbot, inc][thoughtbot-website]. It is free software, +and may be redistributed under the terms specified in the +[MIT-LICENSE](MIT-LICENSE) file. -## Versioning +[thoughtbot-website]: https://thoughtbot.com -shoulda-matchers follows Semantic Versioning 2.0 as defined at -. +## About thoughtbot -## Credits +![thoughtbot][thoughtbot-logo] -shoulda-matchers is maintained and funded by [thoughtbot][community]. Thank you -to all the [contributors][contributors]. +[thoughtbot-logo]: https://presskit.thoughtbot.com/images/thoughtbot-logo-for-readmes.svg -## License +Shoulda Matchers is maintained and funded by thoughtbot, inc. The names and +logos for thoughtbot are trademarks of thoughtbot, inc. -shoulda-matchers is copyright © 2006-2014 thoughtbot, inc. It is free software, -and may be redistributed under the terms specified in the -[MIT-LICENSE](MIT-LICENSE) file. +We are passionate about open source software. See [our other +projects][community]. We are [available for hire][hire]. -[version-badge]: http://img.shields.io/gem/v/shoulda-matchers.svg -[rubygems]: http://rubygems.org/gems/shoulda-matchers -[travis-badge]: http://img.shields.io/travis/thoughtbot/shoulda-matchers/master.svg -[travis]: http://travis-ci.org/thoughtbot/shoulda-matchers -[downloads-badge]: http://img.shields.io/gem/dtv/shoulda-matchers.svg -[rubydocs]: http://matchers.shoulda.io/docs -[community]: http://thoughtbot.com/community -[contributors]: https://github.com/thoughtbot/shoulda-matchers/contributors -[shoulda]: http://github.com/thoughtbot/shoulda -[shoulda-context]: http://github.com/thoughtbot/shoulda-context +[community]: https://thoughtbot.com/community?utm_source=github +[hire]: https://thoughtbot.com?utm_source=github diff -Nru ruby-shoulda-matchers-2.8.0/.rubocop.yml ruby-shoulda-matchers-4.3.0/.rubocop.yml --- ruby-shoulda-matchers-2.8.0/.rubocop.yml 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/.rubocop.yml 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1,220 @@ +require: rubocop-rails +AllCops: + TargetRubyVersion: 2.4 +Layout/AlignArguments: + EnforcedStyle: with_fixed_indentation +Layout/AlignParameters: + EnforcedStyle: with_fixed_indentation +Layout/CommentIndentation: + Enabled: false +Layout/ConditionPosition: + Enabled: false +Layout/DotPosition: + EnforcedStyle: trailing +Layout/EmptyLineBetweenDefs: + AllowAdjacentOneLineDefs: true +Layout/IndentHeredoc: + Enabled: false +Layout/MultilineMethodCallIndentation: + EnforcedStyle: indented +Layout/SpaceInsideBlockBraces: + Enabled: false +Layout/SpaceInLambdaLiteral: + EnforcedStyle: require_space +Lint/AmbiguousOperator: + Enabled: false +Lint/AmbiguousRegexpLiteral: + Enabled: false +Lint/AssignmentInCondition: + Enabled: false +Lint/DeprecatedClassMethods: + Enabled: false +Lint/ElseLayout: + Enabled: false +Lint/FlipFlop: + Enabled: false +Lint/HandleExceptions: + Enabled: false +Lint/LiteralInInterpolation: + Enabled: false +Lint/Loop: + Enabled: false +Lint/ParenthesesAsGroupedExpression: + Enabled: false +Lint/RequireParentheses: + Enabled: false +Lint/SafeNavigationChain: + Enabled: false +Lint/UnderscorePrefixedVariableName: + Enabled: false +Lint/Void: + Enabled: false +Metrics/AbcSize: + Max: 25 +Metrics/BlockLength: + Enabled: false +Metrics/ClassLength: + Enabled: false +Metrics/LineLength: + IgnoredPatterns: + - "^[ ]*#.+$" + - "^[ ]*describe.+$" + - "^[ ]*context.+$" + - "^[ ]*shared_context.+$" + - "^[ ]*shared_examples_for.+$" + - "^[ ]*it.+$" + - "^[ ]*'.+?' => '.+?',?$" + - "^[ ]*\".+?\" => \".+?\",?$" +Metrics/MethodLength: + Max: 30 +Metrics/ParameterLists: + CountKeywordArgs: false +Metrics/PerceivedComplexity: + Max: 10 +Naming/AccessorMethodName: + Enabled: false +Naming/AsciiIdentifiers: + Enabled: false +Naming/BinaryOperatorParameterName: + Enabled: false +Naming/MemoizedInstanceVariableName: + EnforcedStyleForLeadingUnderscores: required +Naming/PredicateName: + Enabled: false +Style/BlockDelimiters: + Enabled: false +Style/ClassVars: + Enabled: false +Style/ColonMethodCall: + Enabled: false +Naming/FileName: + Enabled: false +Rails/Date: + Enabled: false +Rails/Delegate: + Enabled: false +Rails/TimeZone: + Enabled: false +Rails/HttpPositionalArguments: + Enabled: false +Style/Alias: + Enabled: false +Style/ArrayJoin: + Enabled: false +Style/AsciiComments: + Enabled: false +Style/Attr: + Enabled: false +Style/CaseEquality: + Enabled: false +Style/CharacterLiteral: + Enabled: false +Style/ClassAndModuleChildren: + Enabled: false +Style/CollectionMethods: + Enabled: true + PreferredMethods: + find: detect + reduce: inject + collect: map + find_all: select +Style/CommentAnnotation: + Enabled: false +Style/Documentation: + Enabled: false +Style/DoubleNegation: + Enabled: false +Style/EachWithObject: + Enabled: false +Style/EmptyElse: + Enabled: false +Style/EmptyLiteral: + Enabled: false +Style/Encoding: + Enabled: false +Style/EvenOdd: + Enabled: false +Style/FormatString: + Enabled: false +Style/FrozenStringLiteralComment: + Enabled: false +Style/GlobalVars: + Enabled: false +Style/GuardClause: + Enabled: false +Style/IfUnlessModifier: + Enabled: false +Style/IfWithSemicolon: + Enabled: false +Style/InlineComment: + Enabled: false +Style/Lambda: + Enabled: false +Style/LambdaCall: + Enabled: false +Style/LineEndConcatenation: + Enabled: false +Style/MethodCalledOnDoEndBlock: + Enabled: false +Style/ModuleFunction: + Enabled: false +Style/NegatedIf: + Enabled: false +Style/NegatedWhile: + Enabled: false +Style/Next: + Enabled: false +Style/NilComparison: + Enabled: false +Style/Not: + Enabled: false +Style/NumericLiterals: + Enabled: false +Style/NumericPredicate: + Enabled: false +Style/OneLineConditional: + Enabled: false +Style/ParenthesesAroundCondition: + Enabled: false +Style/PercentLiteralDelimiters: + Enabled: false +Style/PerlBackrefs: + Enabled: false +Style/PreferredHashMethods: + Enabled: false +Style/Proc: + Enabled: false +Style/RaiseArgs: + Enabled: false +Style/RegexpLiteral: + Enabled: false +Style/SelfAssignment: + Enabled: false +Style/SignalException: + Enabled: false +Style/SingleLineBlockParams: + Enabled: false +Style/SingleLineMethods: + Enabled: false +Style/SpecialGlobalVars: + Enabled: false +Style/StringLiterals: + EnforcedStyle: single_quotes +Style/SymbolArray: + Enabled: false +Style/TrailingCommaInArguments: + EnforcedStyleForMultiline: consistent_comma +Style/TrailingCommaInArrayLiteral: + EnforcedStyleForMultiline: consistent_comma +Style/TrailingCommaInHashLiteral: + EnforcedStyleForMultiline: consistent_comma +Style/TrivialAccessors: + Enabled: false +Style/WhenThen: + Enabled: false +Style/WhileUntilModifier: + Enabled: false +Style/WordArray: + Enabled: false +Style/VariableInterpolation: + Enabled: false diff -Nru ruby-shoulda-matchers-2.8.0/.ruby-version ruby-shoulda-matchers-4.3.0/.ruby-version --- ruby-shoulda-matchers-2.8.0/.ruby-version 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/.ruby-version 2020-02-18 07:23:52.000000000 +0000 @@ -0,0 +1 @@ +2.6.5 diff -Nru ruby-shoulda-matchers-2.8.0/script/install_gems_in_all_appraisals ruby-shoulda-matchers-4.3.0/script/install_gems_in_all_appraisals --- ruby-shoulda-matchers-2.8.0/script/install_gems_in_all_appraisals 2015-02-25 02:12:36.000000000 +0000 +++ ruby-shoulda-matchers-4.3.0/script/install_gems_in_all_appraisals 2020-02-18 07:23:52.000000000 +0000 @@ -1,6 +1,8 @@ #!/bin/bash -SUPPORTED_VERSIONS=$(