├── .github ├── FUNDING.yml ├── no-response.yml └── workflows │ └── ci.yml ├── .gitignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── Gemfile ├── LICENSE.txt ├── README.md ├── Rakefile ├── lib └── minitest │ ├── matchers_vaccine.rb │ └── matchers_vaccine │ └── version.rb ├── minitest-matchers_vaccine.gemspec └── test └── matchers_test.rb /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [rmm5t] 4 | # patreon: # Replace with a single Patreon username 5 | # open_collective: # Replace with a single Open Collective username 6 | # ko_fi: # Replace with a single Ko-fi username 7 | # tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | # community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | custom: "https://www.paypal.me/rmm5t/5" 10 | -------------------------------------------------------------------------------- /.github/no-response.yml: -------------------------------------------------------------------------------- 1 | # Configuration for probot-no-response - https://github.com/probot/no-response 2 | 3 | # Number of days of inactivity before an Issue is closed for lack of response 4 | daysUntilClose: 7 5 | # Label requiring a response 6 | responseRequiredLabel: more-information-needed 7 | # Comment to post when closing an Issue for lack of response. Set to `false` to disable 8 | closeComment: > 9 | This issue has been automatically closed because there has been no response 10 | to our request for more information from the original author. With only the 11 | information that is currently in the issue, we don't have enough information 12 | to take action. Please reach out if you have or find the answers we need so 13 | that we can investigate further. 14 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches: [master] 5 | pull_request: 6 | branches: [master] 7 | 8 | jobs: 9 | test: 10 | runs-on: ubuntu-latest 11 | strategy: 12 | matrix: 13 | ruby: ["2.4", "2.5", "2.6", "2.7", "3.0", "3.1", "3.2", "3.3", "3.4"] 14 | 15 | steps: 16 | # https://github.com/marketplace/actions/checkout 17 | - uses: actions/checkout@v4 18 | # https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby 19 | - name: Set up Ruby 20 | uses: ruby/setup-ruby@v1 21 | with: 22 | ruby-version: ${{ matrix.ruby }} 23 | bundler-cache: true # runs `bundle install` and caches gems automatically 24 | - name: Run tests 25 | run: bundle exec rake 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | .bundle 4 | .config 5 | .yardoc 6 | Gemfile.lock 7 | gemfiles/*.lock 8 | InstalledFiles 9 | _yardoc 10 | coverage 11 | doc/ 12 | lib/bundler/man 13 | pkg 14 | rdoc 15 | spec/reports 16 | test/tmp 17 | test/version_tmp 18 | tmp 19 | *.bundle 20 | *.so 21 | *.o 22 | *.a 23 | mkmf.log 24 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com//), and this project adheres to [Semantic Versioning](https://semver.org/). 6 | 7 | ## [Unreleased] - TBD 8 | 9 | ## [1.0.7] - 2024-12-10 10 | 11 | - `funding_uri` added to gemspec 12 | 13 | ## [1.0.6] - 2022-05-12 14 | 15 | - Fix rubygems release 16 | 17 | ## [1.0.5] - 2022-05-12 18 | 19 | - Add GitHub CI workflow 20 | - Add Ruby 3 support 21 | 22 | ## [1.0.4] - 2016-05-31 23 | 24 | - Prevent warnings for `@subject` instance variable not initialized 25 | 26 | ## [1.0.3] - 2016-05-31 27 | 28 | - Improved Ruby 2.2 support (#1 thanks to @spovich). 29 | 30 | ## [1.0.2] - 2016-05-31 31 | 32 | - Renamed MiniTest to Minitest 33 | 34 | ## [1.0.1] - 2016-05-31 35 | 36 | - Bug fixes 37 | 38 | ## [1.0.0] - 2016-05-31 39 | 40 | - Initial release 41 | 42 | [Unreleased]: https://github.com/rmm5t/minitest-matchers_vaccine/compare/v1.0.6..HEAD 43 | [1.0.6]: https://github.com/rmm5t/minitest-matchers_vaccine/compare/v1.0.5..v1.0.6 44 | [1.0.5]: https://github.com/rmm5t/minitest-matchers_vaccine/compare/v1.0.4..v1.0.5 45 | [1.0.4]: https://github.com/rmm5t/minitest-matchers_vaccine/compare/v1.0.3..v1.0.4 46 | [1.0.3]: https://github.com/rmm5t/minitest-matchers_vaccine/compare/v1.0.2..v1.0.3 47 | [1.0.2]: https://github.com/rmm5t/minitest-matchers_vaccine/compare/v1.0.1..v1.0.2 48 | [1.0.1]: https://github.com/rmm5t/minitest-matchers_vaccine/compare/v1.0.0..v1.0.1 49 | [1.0.0]: https://github.com/rmm5t/minitest-matchers_vaccine/compare/6fdef88..v1.0.0 50 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Want to Contribute? 2 | 3 | Awesome. We love help, but before getting started, please read: 4 | 5 | **[Don't "Push" Your Pull Requests](http://www.igvita.com/2011/12/19/dont-push-your-pull-requests/)** 6 | 7 | ## Ready for a Pull-Request? 8 | 9 | 1. Fork the repo. 10 | 11 | 2. Run the tests. We only take pull requests with passing tests, and it's great 12 | to know that you have a clean slate: `bundle && bundle exec rake` 13 | 14 | 3. Add a test for your change. Only refactoring and documentation changes 15 | require no new tests. If you are adding functionality or fixing a bug, we need 16 | a test! 17 | 18 | 4. Make the test pass. 19 | 20 | 5. Push to your fork and submit a pull request. 21 | 22 | At this point you're waiting on us. We like to at least comment on, if not 23 | accept, pull requests within three business days (and, typically, one business 24 | day). We may suggest some changes or improvements or alternatives. 25 | 26 | Some things that will increase the chance that your pull request is accepted, 27 | taken straight from the Ruby on Rails guide: 28 | 29 | ## Conventions 30 | 31 | * Use Rails idioms and helpers. 32 | * Include tests that fail without your code, and pass with your code. 33 | * Update the documentation, the surrounding one, examples elsewhere, guides, 34 | whatever is affected by your contribution 35 | 36 | Syntax: 37 | 38 | * Two spaces, no tabs. 39 | * No trailing whitespace. Blank lines should not have any space. 40 | * Prefer `&&`/`||` over `and`/`or`. 41 | * `MyClass.my_method(my_arg)` not `my_method( my_arg )` or `my_method my_arg`. 42 | * `a = b` not `a=b`. 43 | * Follow the conventions you see used in the source already. 44 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in minitest-matchers_vaccine.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014-2018 Ryan McGeary 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Minitest::MatchersVaccine 2 | 3 | [![Gem Version](http://img.shields.io/gem/v/minitest-matchers_vaccine.svg)](https://rubygems.org/gems/minitest-matchers_vaccine) 4 | [![Build Status](https://github.com/rmm5t/minitest-matchers_vaccine/workflows/CI/badge.svg)](https://github.com/rmm5t/minitest-matchers_vaccine/actions?query=workflow%3ACI) 5 | [![Maintainability](https://api.codeclimate.com/v1/badges/ca7aadb1a0a1c1c6782e/maintainability)](https://codeclimate.com/github/rmm5t/minitest-matchers_vaccine) 6 | 7 | Adds matcher support to minitest without all the other RSpec-style expectation 8 | _infections_. 9 | 10 | Using matchers with RSpec-style expectations requires that we _infect_ the 11 | objects that we are testing with new methods. Matcher implementations are 12 | typically overkill, but there are a lot of good testing libraries that still 13 | insist on standardizing on matchers. These matchers still have some value, and 14 | this gem tries to extract that value with straight-forward assertions that 15 | adhere to the matcher spec. 16 | 17 | **Why not use 18 | [minitest-matchers](https://github.com/wojtekmach/minitest-matchers)?** This 19 | gem is actually heavily inspired by and based upon the assertions in 20 | minitest-matchers; however, everything else that minitest-matchers brings to 21 | the table is unnecessary unless you're bent on a true RSpec-style syntax. 22 | 23 | ## Installation 24 | 25 | Add this line to your application's Gemfile: 26 | 27 | gem "minitest-matchers_vaccine" 28 | 29 | And then execute: 30 | 31 | $ bundle 32 | 33 | Or install it yourself as: 34 | 35 | $ gem install minitest-matchers_vaccine 36 | 37 | ## Usage 38 | 39 | Includes both `assert_must` and `assert_wont` assertions, but also includes 40 | `must` and `wont` facilitator assertions that automatically default to using 41 | the current `subject` method (aka "let variable") or `@subject` instance 42 | variable. 43 | 44 | **NOTE:** This gem does not allow matchers to be used with an expectation 45 | syntax. Let's avoid infecting the objects we're testing. 46 | 47 | ### Minitest::Test 48 | 49 | ```ruby 50 | class UserTest < Minitest::Test 51 | def setup 52 | @subject = User.new 53 | end 54 | 55 | def test_fields_and_associations 56 | must have_db_column :name 57 | must belong_to :account 58 | assert_must have_many(:widgets), @subject 59 | end 60 | 61 | def test_validations 62 | must have_valid(:email).when("a@a.com", "foo@bar.com", "dave@abc.io") 63 | wont have_valid(:email).when(nil, "foo", "foo@bar", "@bar.com") 64 | end 65 | 66 | # Works with matchers in other libs 67 | def test_stripping 68 | assert_must strip_attribute(:name), User.new 69 | end 70 | end 71 | ``` 72 | 73 | ### Minitest::Spec 74 | 75 | ```ruby 76 | describe User do 77 | subject { User.new } 78 | 79 | # Works with shoulda-matchers 80 | it "has fields and associations" do 81 | must have_db_column :name 82 | must belong_to :account 83 | must have_many :widgets 84 | end 85 | 86 | # Works with valid_attribute 87 | it "validates" do 88 | must have_valid(:email).when("a@a.com", "foo@bar.com", "dave@abc.io") 89 | wont have_valid(:email).when(nil, "foo", "foo@bar", "@bar.com") 90 | end 91 | 92 | # Works with matchers in other libs 93 | it "strips attributes" do 94 | must strip_attribute :name 95 | end 96 | end 97 | ``` 98 | 99 | ## Contributing 100 | 101 | 1. Fork it ( https://github.com/rmm5t/minitest-matchers_vaccine/fork ) 102 | 2. Create your feature branch (`git checkout -b my-new-feature`) 103 | 3. Commit your changes (`git commit -am 'Add some feature'`) 104 | 4. Push to the branch (`git push origin my-new-feature`) 105 | 5. Create a new Pull Request 106 | 107 | ## Credits 108 | 109 | The idea was originally inspired by the matcher assertions implementation in 110 | [minitest-matchers](https://github.com/wojtekmach/minitest-matchers). 111 | 112 | ## License 113 | 114 | [MIT License](https://rmm5t.mit-license.org/) 115 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "rake/testtask" 2 | require "bundler/gem_tasks" 3 | 4 | desc "Default: run unit tests." 5 | task default: :test 6 | 7 | Rake::TestTask.new(:test) do |t| 8 | t.libs << "lib" << "test" 9 | t.pattern = "test/**/*_test.rb" 10 | end 11 | -------------------------------------------------------------------------------- /lib/minitest/matchers_vaccine.rb: -------------------------------------------------------------------------------- 1 | require "minitest" 2 | require "minitest/matchers_vaccine/version" 3 | 4 | # Borrowed and modified from minitest-matchers, but we don't need all the 5 | # other RSpec-style expectation "infections." 6 | module Minitest 7 | module Assertions 8 | ## 9 | # Passes if matcher.matches?(subject) returns true 10 | # 11 | # Example: 12 | # 13 | # def test_validations 14 | # assert_must be_valid, @user 15 | # end 16 | def assert_must(matcher, subject, msg = nil) 17 | msg = message(msg) do 18 | if matcher.respond_to? :failure_message 19 | matcher.failure_message # RSpec 3.x, 1.1 20 | else 21 | matcher.failure_message_for_should # RSpec 2.x, 1.2 22 | end 23 | end 24 | 25 | assert matcher.matches?(subject), msg 26 | end 27 | 28 | ## 29 | # Facilitator to assert_must for use with minitest-spec. If no subject 30 | # given, defaults to matching against the current `subject` or the 31 | # instance variable `@subject`. 32 | # 33 | # Example: 34 | # 35 | # subject { Order.new } 36 | # 37 | # it "should have associations" do 38 | # must belong_to :account 39 | # must have_many :line_items 40 | # end 41 | def must(matcher, subject = ((defined?(@subject) && @subject) || subject()), msg = nil) 42 | assert_must matcher, subject, msg 43 | end 44 | 45 | ## 46 | # Passes if matcher.matches?(subject) returns false 47 | # 48 | # Example: 49 | # 50 | # def test_validations 51 | # assert_wont be_valid, @user 52 | # end 53 | def assert_wont(matcher, subject, msg = nil) 54 | msg = message(msg) do 55 | if matcher.respond_to? :failure_message_when_negated # RSpec 3.x 56 | matcher.failure_message_when_negated # RSpec 3.x 57 | elsif matcher.respond_to? :failure_message_for_should_not 58 | matcher.failure_message_for_should_not # RSpec 2.x, 1.2 59 | else 60 | matcher.negative_failure_message # RSpec 1.1 61 | end 62 | end 63 | 64 | if matcher.respond_to? :does_not_match? 65 | assert matcher.does_not_match?(subject), msg 66 | else 67 | refute matcher.matches?(subject), msg 68 | end 69 | end 70 | 71 | ## 72 | # Facilitator to assert_wont for use with minitest-spec. If no subject 73 | # given, defaults to matching against the current `subject` or the 74 | # instance variable `@subject`. 75 | # 76 | # Example: 77 | # 78 | # subject { User.new } 79 | # 80 | # it "should validate" do 81 | # wont have_valid(:email).when("foo", "foo@bar", "@bar.com") 82 | # end 83 | def wont(matcher, subject = ((defined?(@subject) && @subject) || subject()), msg = nil) 84 | assert_wont matcher, subject, msg 85 | end 86 | end 87 | end 88 | -------------------------------------------------------------------------------- /lib/minitest/matchers_vaccine/version.rb: -------------------------------------------------------------------------------- 1 | module Minitest 2 | module MatchersVaccine 3 | VERSION = "1.0.7" 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /minitest-matchers_vaccine.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'minitest/matchers_vaccine/version' 5 | 6 | Gem::Specification.new do |spec| 7 | username = "rmm5t" 8 | spec.name = "minitest-matchers_vaccine" 9 | spec.version = Minitest::MatchersVaccine::VERSION 10 | spec.authors = ["Ryan McGeary"] 11 | spec.email = ["ryan@mcgeary.org"] 12 | spec.summary = %q{Adds support for RSpec-style matchers to minitest.} 13 | spec.description = %q{Adds matcher support to minitest without all the other RSpec-style expectation "infections."} 14 | spec.homepage = "https://github.com/#{username}/#{spec.name}" 15 | spec.license = "MIT" 16 | 17 | spec.files = Dir["{lib,test}/**/*", "README*", "LICENSE*"] 18 | spec.test_files = Dir["{test}/**/*"] 19 | spec.require_paths = ["lib"] 20 | 21 | spec.metadata = { 22 | "bug_tracker_uri" => "#{spec.homepage}/issues", 23 | "changelog_uri" => "#{spec.homepage}/blob/master/CHANGELOG.md", 24 | "source_code_uri" => spec.homepage, 25 | "funding_uri" => "https://github.com/sponsors/#{username}", 26 | } 27 | 28 | spec.required_ruby_version = ">= 1.9" 29 | 30 | spec.add_dependency "minitest", "~> 5.0" 31 | spec.add_development_dependency "rake" 32 | end 33 | -------------------------------------------------------------------------------- /test/matchers_test.rb: -------------------------------------------------------------------------------- 1 | require "minitest/autorun" 2 | require "minitest/matchers_vaccine" 3 | 4 | module InstanceOf 5 | def be_instance_of klass 6 | Matcher.new klass 7 | end 8 | 9 | class Matcher 10 | def initialize klass 11 | @klass = klass 12 | end 13 | 14 | def description 15 | "be instance of #{@klass}" 16 | end 17 | 18 | def matches? subject 19 | @subject = subject 20 | @subject.instance_of? @klass 21 | end 22 | 23 | def failure_message 24 | "expected to " + description 25 | end 26 | 27 | def failure_message_when_negated 28 | "expected not to " + description 29 | end 30 | end 31 | end 32 | 33 | describe "#assert_must" do 34 | include InstanceOf 35 | 36 | it "should be capable of passing" do 37 | assert_must(be_instance_of(Array), [:hello]) 38 | assert_must(be_instance_of(String), "hello") 39 | end 40 | 41 | it "should be capable of failing" do 42 | assert_raises(Minitest::Assertion) { assert_must(be_instance_of(String), [:hello]) } 43 | assert_raises(Minitest::Assertion) { assert_must(be_instance_of(Array), "hello") } 44 | end 45 | end 46 | 47 | describe "#assert_wont" do 48 | include InstanceOf 49 | 50 | it "should be capable of passing" do 51 | assert_wont(be_instance_of(String), [:hello]) 52 | assert_wont(be_instance_of(Array), "hello") 53 | end 54 | 55 | it "should be capable of failing" do 56 | assert_raises(Minitest::Assertion) { assert_wont(be_instance_of(Array), [:hello]) } 57 | assert_raises(Minitest::Assertion) { assert_wont(be_instance_of(String), "hello") } 58 | end 59 | end 60 | 61 | describe "#must" do 62 | include InstanceOf 63 | 64 | describe "given a subject" do 65 | subject { [:hello] } 66 | 67 | it "should be capable of passing" do 68 | assert must(be_instance_of(Array)) 69 | end 70 | 71 | it "should be capable of failing" do 72 | assert_raises(Minitest::Assertion) { must be_instance_of String } 73 | end 74 | end 75 | 76 | describe "given a @subject" do 77 | before do 78 | @subject = "hello" 79 | end 80 | 81 | it "should be capable of passing" do 82 | assert must(be_instance_of(String)) 83 | end 84 | 85 | it "should be capable of failing" do 86 | assert_raises(Minitest::Assertion) { must be_instance_of Array } 87 | end 88 | end 89 | 90 | describe "without a subject" do 91 | it "should error" do 92 | assert_raises(NoMethodError) { must be_instance_of Array } 93 | end 94 | end 95 | end 96 | 97 | describe "#wont" do 98 | include InstanceOf 99 | 100 | describe "given a subject" do 101 | subject { [:hello] } 102 | 103 | it "should be capable of passing" do 104 | wont(be_instance_of(String)) 105 | end 106 | 107 | it "should be capable of failing" do 108 | assert_raises(Minitest::Assertion) { wont be_instance_of Array } 109 | end 110 | end 111 | 112 | describe "given a @subject" do 113 | before do 114 | @subject = "hello" 115 | end 116 | 117 | it "should be capable of passing" do 118 | wont(be_instance_of(Array)) 119 | end 120 | 121 | it "should be capable of failing" do 122 | assert_raises(Minitest::Assertion) { wont be_instance_of String } 123 | end 124 | end 125 | 126 | describe "without a subject" do 127 | it "should error" do 128 | assert_raises(NoMethodError) { wont be_instance_of Array } 129 | end 130 | end 131 | end 132 | --------------------------------------------------------------------------------