From 900dffebd6aed544eddae509c983b50744042a79 Mon Sep 17 00:00:00 2001 From: Herwin Date: Fri, 17 Jan 2025 18:23:55 +0100 Subject: [PATCH 01/27] Import be_an_instance_of_spec of mspec This is a verbatim copy from upstream (commit 0aabb3e548eb5ea6cad0125f8f46cee34542b6b7) and should be used to test our spec runner, to prevent issues like the instance_of/kind_of mixup we recently fixed. Of course, this means we need to be able to run it first. Eventually, we should be able to run all the tests, but let's just start with a single one. --- .github/workflows/test.yml | 10 +++ README.md | 1 + test/mspec/Gemfile | 4 ++ test/mspec/Gemfile.lock | 26 +++++++ test/mspec/LICENSE | 22 ++++++ .../spec/matchers/be_an_instance_of_spec.rb | 50 +++++++++++++ test/mspec/spec_helper.rb | 70 +++++++++++++++++++ 7 files changed, 183 insertions(+) create mode 100644 test/mspec/Gemfile create mode 100644 test/mspec/Gemfile.lock create mode 100644 test/mspec/LICENSE create mode 100644 test/mspec/spec/matchers/be_an_instance_of_spec.rb create mode 100644 test/mspec/spec_helper.rb diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8b1f3af75b..7c78d758f8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -111,3 +111,13 @@ jobs: SPEC_TIMEOUT: 480 SOME_TESTS: true run: rake docker_test_asan + mspec: + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + - name: install ruby + run: sudo apt-get install -y ruby ruby-bundler + - name: install rspec + run: cd test/mspec && sudo bundle install + - name: run very limited hacked mspec test + run: cd test/mspec && bundle exec rspec -I. diff --git a/README.md b/README.md index e9353ead47..c4cdefd2c2 100644 --- a/README.md +++ b/README.md @@ -169,6 +169,7 @@ the respective file, in the same directory with a name like `LICENSE`, or both. | `prettyprint.rb` | Yukihiro Matsumoto | BSD | | `shellwords.rb` | Akinori MUSHA | BSD | | `spec/*` | Engine Yard, Inc. | MIT | +| `test/mspec/*` | Engine Yard, Inc. | MIT | | `uri.rb`/`uri/*` | Akira Yamada | BSD | | `version.rb` | Engine Yard, Inc. | MIT | | `zlib` | Jean-loup Gailly and Mark Adler | zlib license | diff --git a/test/mspec/Gemfile b/test/mspec/Gemfile new file mode 100644 index 0000000000..617a995cad --- /dev/null +++ b/test/mspec/Gemfile @@ -0,0 +1,4 @@ +source 'https://rubygems.org' + +gem "rake", "~> 12.3" +gem "rspec", "~> 3.0" diff --git a/test/mspec/Gemfile.lock b/test/mspec/Gemfile.lock new file mode 100644 index 0000000000..cd39906044 --- /dev/null +++ b/test/mspec/Gemfile.lock @@ -0,0 +1,26 @@ +GEM + remote: https://rubygems.org/ + specs: + diff-lcs (1.4.4) + rake (12.3.3) + rspec (3.10.0) + rspec-core (~> 3.10.0) + rspec-expectations (~> 3.10.0) + rspec-mocks (~> 3.10.0) + rspec-core (3.10.1) + rspec-support (~> 3.10.0) + rspec-expectations (3.10.1) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.10.0) + rspec-mocks (3.10.2) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.10.0) + rspec-support (3.10.2) + +PLATFORMS + java + ruby + +DEPENDENCIES + rake (~> 12.3) + rspec (~> 3.0) diff --git a/test/mspec/LICENSE b/test/mspec/LICENSE new file mode 100644 index 0000000000..d581dd1c9f --- /dev/null +++ b/test/mspec/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2008 Engine Yard, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/test/mspec/spec/matchers/be_an_instance_of_spec.rb b/test/mspec/spec/matchers/be_an_instance_of_spec.rb new file mode 100644 index 0000000000..7c74249d24 --- /dev/null +++ b/test/mspec/spec/matchers/be_an_instance_of_spec.rb @@ -0,0 +1,50 @@ +require 'spec_helper' +require 'mspec/expectations/expectations' +require 'mspec/matchers' + +module BeAnInOfSpecs + class A + end + + class B < A + end + + class C < B + end +end + +RSpec.describe BeAnInstanceOfMatcher do + it "matches when actual is an instance_of? expected" do + a = BeAnInOfSpecs::A.new + expect(BeAnInstanceOfMatcher.new(BeAnInOfSpecs::A).matches?(a)).to be_truthy + + b = BeAnInOfSpecs::B.new + expect(BeAnInstanceOfMatcher.new(BeAnInOfSpecs::B).matches?(b)).to be_truthy + end + + it "does not match when actual is not an instance_of? expected" do + a = BeAnInOfSpecs::A.new + expect(BeAnInstanceOfMatcher.new(BeAnInOfSpecs::B).matches?(a)).to be_falsey + + b = BeAnInOfSpecs::B.new + expect(BeAnInstanceOfMatcher.new(BeAnInOfSpecs::A).matches?(b)).to be_falsey + + c = BeAnInOfSpecs::C.new + expect(BeAnInstanceOfMatcher.new(BeAnInOfSpecs::A).matches?(c)).to be_falsey + expect(BeAnInstanceOfMatcher.new(BeAnInOfSpecs::B).matches?(c)).to be_falsey + end + + it "provides a useful failure message" do + matcher = BeAnInstanceOfMatcher.new(Numeric) + matcher.matches?("string") + expect(matcher.failure_message).to eq([ + "Expected \"string\" (String)", "to be an instance of Numeric"]) + end + + it "provides a useful negative failure message" do + matcher = BeAnInstanceOfMatcher.new(Numeric) + matcher.matches?(4.0) + expect(matcher.negative_failure_message).to eq([ + "Expected 4.0 (Float)", "not to be an instance of Numeric"]) + end +end diff --git a/test/mspec/spec_helper.rb b/test/mspec/spec_helper.rb new file mode 100644 index 0000000000..5cabfe5626 --- /dev/null +++ b/test/mspec/spec_helper.rb @@ -0,0 +1,70 @@ +RSpec.configure do |config| + config.disable_monkey_patching! + config.raise_errors_for_deprecations! +end + +require 'mspec' + +# Remove this when MRI has intelligent warnings +$VERBOSE = nil unless $VERBOSE + +class MOSConfig < Hash + def initialize + self[:loadpath] = [] + self[:requires] = [] + self[:flags] = [] + self[:options] = [] + self[:includes] = [] + self[:excludes] = [] + self[:patterns] = [] + self[:xpatterns] = [] + self[:tags] = [] + self[:xtags] = [] + self[:atags] = [] + self[:astrings] = [] + self[:target] = 'ruby' + self[:command] = nil + self[:ltags] = [] + self[:files] = [] + self[:launch] = [] + end +end + +def new_option + config = MOSConfig.new + return MSpecOptions.new("spec", 20, config), config +end + +# Just to have an exception name output not be "Exception" +class MSpecExampleError < Exception +end + +def hide_deprecation_warnings + allow(MSpec).to receive(:deprecate) +end + +def run_mspec(command, args) + cwd = Dir.pwd + command = " #{command}" unless command.start_with?('-') + cmd = "#{cwd}/bin/mspec#{command} -B spec/fixtures/config.mspec #{args}" + out = `#{cmd} 2>&1` + ret = $? + out = out.sub(/\A\$.+\n/, '') # Remove printed command line + out = out.sub(RUBY_DESCRIPTION, "RUBY_DESCRIPTION") + out = out.gsub(/\d+\.\d{6}/, "D.DDDDDD") # Specs total time + out = out.gsub(/\d{2}:\d{2}:\d{2}/, "00:00:00") # Progress bar time + out = out.gsub(cwd, "CWD") + return out, ret +end + +def ensure_mspec_method(method) + file, _line = method.source_location + expect(file).to start_with(File.expand_path('../../lib/mspec', __FILE__ )) +end + +PublicMSpecMatchers = Class.new { + include MSpecMatchers + public :raise_error +}.new + +BACKTRACE_QUOTE = RUBY_VERSION >= "3.4" ? "'" : "`" From b1ee34909222578d47f1f6fff3127cb08fe062fb Mon Sep 17 00:00:00 2001 From: Herwin Date: Fri, 17 Jan 2025 19:02:28 +0100 Subject: [PATCH 02/27] Cobble a passing mspec test together This is very much in the PoC state --- .../spec/matchers/be_an_instance_of_spec.rb | 21 +++++++++++++++++-- test/mspec/spec_helper.rb | 4 ++-- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/test/mspec/spec/matchers/be_an_instance_of_spec.rb b/test/mspec/spec/matchers/be_an_instance_of_spec.rb index 7c74249d24..f3b4280297 100644 --- a/test/mspec/spec/matchers/be_an_instance_of_spec.rb +++ b/test/mspec/spec/matchers/be_an_instance_of_spec.rb @@ -1,6 +1,23 @@ require 'spec_helper' -require 'mspec/expectations/expectations' -require 'mspec/matchers' +#require 'mspec/expectations/expectations' +#require 'mspec/matchers' +class BeAnInstanceOfMatcher + attr_reader :failure_message, :negative_failure_message + + def initialize(klass) + @wrapped = BeInstanceOfExpectation.new(klass) + @klass = klass + end + + def matches?(subject) + @wrapped.match(subject) + true + rescue SpecFailedException => e + @failure_message = ["Expected #{subject.inspect} (#{subject.class})", "to be an instance of #{@klass}"] + @negative_failure_message = ["Expected #{subject.inspect} (#{subject.class})", "not to be an instance of #{@klass}"] + nil + end +end module BeAnInOfSpecs class A diff --git a/test/mspec/spec_helper.rb b/test/mspec/spec_helper.rb index 5cabfe5626..badce06059 100644 --- a/test/mspec/spec_helper.rb +++ b/test/mspec/spec_helper.rb @@ -3,7 +3,7 @@ config.raise_errors_for_deprecations! end -require 'mspec' +require_relative '../spec_helper' # Remove this when MRI has intelligent warnings $VERBOSE = nil unless $VERBOSE @@ -63,7 +63,7 @@ def ensure_mspec_method(method) end PublicMSpecMatchers = Class.new { - include MSpecMatchers + # include MSpecMatchers public :raise_error }.new From dcc478b80ed2401239611e73f87c06d8740752ce Mon Sep 17 00:00:00 2001 From: Herwin Date: Fri, 17 Jan 2025 19:35:43 +0100 Subject: [PATCH 03/27] Split existing BeInstanceOfExpectation into Matcher and Excpectation This Matcher now can be used in the mspec tests, the expectatin is used when running the regular specs. The matcher now fully satisfies the upstream specs, whilst the behaviour of the expectation is unchanged (except for an improved error message). --- .../spec/matchers/be_an_instance_of_spec.rb | 17 ----------- test/support/spec.rb | 29 ++++++++++++++----- 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/test/mspec/spec/matchers/be_an_instance_of_spec.rb b/test/mspec/spec/matchers/be_an_instance_of_spec.rb index f3b4280297..ce85922b1d 100644 --- a/test/mspec/spec/matchers/be_an_instance_of_spec.rb +++ b/test/mspec/spec/matchers/be_an_instance_of_spec.rb @@ -1,23 +1,6 @@ require 'spec_helper' #require 'mspec/expectations/expectations' #require 'mspec/matchers' -class BeAnInstanceOfMatcher - attr_reader :failure_message, :negative_failure_message - - def initialize(klass) - @wrapped = BeInstanceOfExpectation.new(klass) - @klass = klass - end - - def matches?(subject) - @wrapped.match(subject) - true - rescue SpecFailedException => e - @failure_message = ["Expected #{subject.inspect} (#{subject.class})", "to be an instance of #{@klass}"] - @negative_failure_message = ["Expected #{subject.inspect} (#{subject.class})", "not to be an instance of #{@klass}"] - nil - end -end module BeAnInOfSpecs class A diff --git a/test/support/spec.rb b/test/support/spec.rb index e06af271d8..5691506a38 100644 --- a/test/support/spec.rb +++ b/test/support/spec.rb @@ -560,21 +560,36 @@ def inverted_match(subject) end end -class BeInstanceOfExpectation +class BeAnInstanceOfMatcher def initialize(klass) @klass = klass end + def matches?(subject) + @message_prelude = "Expected #{subject.inspect} (#{subject.class})" + subject.instance_of?(@klass) + end + + def failure_message + [@message_prelude, "to be an instance of #{@klass}"] + end + + def negative_failure_message + [@message_prelude, "not to be an instance of #{@klass}"] + end +end + +class BeInstanceOfExpectation + def initialize(klass) + @matcher = BeAnInstanceOfMatcher.new(klass) + end + def match(subject) - if !subject.instance_of?(@klass) - raise SpecFailedException, "#{subject.inspect} (#{subject.class}) should be an instance of #{@klass}" - end + raise SpecFailedException, @matcher.failure_message.join(' ') unless @matcher.matches?(subject) end def inverted_match(subject) - if subject.instance_of?(@klass) - raise SpecFailedException, "#{subject.inspect} (#{subject.class}) should not be an instance of #{@klass}" - end + raise SpecFailedException, @matcher.negative_failure_message.join(' ') if @matcher.matches?(subject) end end From 63a48995898e7491fbdfbd78bf85843da3a6057b Mon Sep 17 00:00:00 2001 From: Herwin Date: Sat, 18 Jan 2025 09:42:32 +0100 Subject: [PATCH 04/27] Add stub files to fix the includes of the upstream mspec specs We can now run the original file, this will help with the remaining specs. --- test/mspec/mspec/expectations/expectations.rb | 1 + test/mspec/mspec/matchers.rb | 1 + test/mspec/spec/matchers/be_an_instance_of_spec.rb | 4 ++-- 3 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 test/mspec/mspec/expectations/expectations.rb create mode 100644 test/mspec/mspec/matchers.rb diff --git a/test/mspec/mspec/expectations/expectations.rb b/test/mspec/mspec/expectations/expectations.rb new file mode 100644 index 0000000000..b695e4ab98 --- /dev/null +++ b/test/mspec/mspec/expectations/expectations.rb @@ -0,0 +1 @@ +# Stub to work around the require statements of the specs diff --git a/test/mspec/mspec/matchers.rb b/test/mspec/mspec/matchers.rb new file mode 100644 index 0000000000..b695e4ab98 --- /dev/null +++ b/test/mspec/mspec/matchers.rb @@ -0,0 +1 @@ +# Stub to work around the require statements of the specs diff --git a/test/mspec/spec/matchers/be_an_instance_of_spec.rb b/test/mspec/spec/matchers/be_an_instance_of_spec.rb index ce85922b1d..7c74249d24 100644 --- a/test/mspec/spec/matchers/be_an_instance_of_spec.rb +++ b/test/mspec/spec/matchers/be_an_instance_of_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -#require 'mspec/expectations/expectations' -#require 'mspec/matchers' +require 'mspec/expectations/expectations' +require 'mspec/matchers' module BeAnInOfSpecs class A From 3e1a89b91dcac5652f577a514446c3301cdd2fba Mon Sep 17 00:00:00 2001 From: Herwin Date: Sat, 18 Jan 2025 09:49:35 +0100 Subject: [PATCH 05/27] Import BeAnInstanceOfMatcher from mspec And update the stub mspec/matchers file to point to our matchers list. --- test/mspec/mspec/matchers.rb | 2 +- test/support/spec.rb | 20 +------- test/support/spec_helpers/matchers.rb | 1 + .../matchers/be_an_instance_of.rb | 51 +++++++++++++++++++ 4 files changed, 54 insertions(+), 20 deletions(-) create mode 100644 test/support/spec_helpers/matchers.rb create mode 100644 test/support/spec_helpers/matchers/be_an_instance_of.rb diff --git a/test/mspec/mspec/matchers.rb b/test/mspec/mspec/matchers.rb index b695e4ab98..86860d9d3e 100644 --- a/test/mspec/mspec/matchers.rb +++ b/test/mspec/mspec/matchers.rb @@ -1 +1 @@ -# Stub to work around the require statements of the specs +require_relative '../../support/spec_helpers/matchers' diff --git a/test/support/spec.rb b/test/support/spec.rb index 5691506a38..58b9e1e12c 100644 --- a/test/support/spec.rb +++ b/test/support/spec.rb @@ -7,6 +7,7 @@ require_relative 'version' require_relative 'spec_helpers/fs' require_relative 'spec_helpers/io' +require_relative 'spec_helpers/matchers' require_relative 'spec_helpers/mock_to_path' require_relative 'spec_helpers/tmp' require_relative 'spec_utils/warnings' @@ -560,25 +561,6 @@ def inverted_match(subject) end end -class BeAnInstanceOfMatcher - def initialize(klass) - @klass = klass - end - - def matches?(subject) - @message_prelude = "Expected #{subject.inspect} (#{subject.class})" - subject.instance_of?(@klass) - end - - def failure_message - [@message_prelude, "to be an instance of #{@klass}"] - end - - def negative_failure_message - [@message_prelude, "not to be an instance of #{@klass}"] - end -end - class BeInstanceOfExpectation def initialize(klass) @matcher = BeAnInstanceOfMatcher.new(klass) diff --git a/test/support/spec_helpers/matchers.rb b/test/support/spec_helpers/matchers.rb new file mode 100644 index 0000000000..c85da4f714 --- /dev/null +++ b/test/support/spec_helpers/matchers.rb @@ -0,0 +1 @@ +require_relative 'matchers/be_an_instance_of' diff --git a/test/support/spec_helpers/matchers/be_an_instance_of.rb b/test/support/spec_helpers/matchers/be_an_instance_of.rb new file mode 100644 index 0000000000..2aaea7daef --- /dev/null +++ b/test/support/spec_helpers/matchers/be_an_instance_of.rb @@ -0,0 +1,51 @@ +=begin +Copyright (c) 2008 Engine Yard, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. +=end + +class BeAnInstanceOfMatcher + def initialize(expected) + @expected = expected + end + + def matches?(actual) + @actual = actual + @actual.instance_of?(@expected) + end + + def failure_message + ["Expected #{@actual.inspect} (#{@actual.class})", + "to be an instance of #{@expected}"] + end + + def negative_failure_message + ["Expected #{@actual.inspect} (#{@actual.class})", + "not to be an instance of #{@expected}"] + end +end + +module MSpecMatchers + private def be_an_instance_of(expected) + BeAnInstanceOfMatcher.new(expected) + end +end From e795ff909427f63a9e3ad8cdf310971d20b2b991 Mon Sep 17 00:00:00 2001 From: Herwin Date: Sat, 18 Jan 2025 10:03:49 +0100 Subject: [PATCH 06/27] Remove BeInstanceOfExpectation Make an Expectation class instead, that can run any matcher. The remaining code is generic enough to be completely disjointed from the actual matcher. The generic class is in a weird code spot, but putting it on the top of the list actually caused git to complete screw up the diff. This way it stays readable, and we should probably just fix the other two the same way. --- test/support/spec.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/support/spec.rb b/test/support/spec.rb index 58b9e1e12c..885845da8d 100644 --- a/test/support/spec.rb +++ b/test/support/spec.rb @@ -561,9 +561,9 @@ def inverted_match(subject) end end -class BeInstanceOfExpectation - def initialize(klass) - @matcher = BeAnInstanceOfMatcher.new(klass) +class Expectation + def initialize(matcher) + @matcher = matcher end def match(subject) @@ -1488,7 +1488,7 @@ def be_kind_of(klass) end def be_an_instance_of(klass) - BeInstanceOfExpectation.new(klass) + Expectation.new(BeAnInstanceOfMatcher.new(klass)) end def be_ancestor_of(klass) From 0189a38327c4455248a1e097ffb641bf52d070ac Mon Sep 17 00:00:00 2001 From: Herwin Date: Sat, 18 Jan 2025 10:11:43 +0100 Subject: [PATCH 07/27] Import BeKindOfMatcher from mspec --- test/mspec/spec/matchers/be_kind_of_spec.rb | 31 ++++++++++++ test/support/spec.rb | 20 +------- test/support/spec_helpers/matchers.rb | 1 + .../spec_helpers/matchers/be_kind_of.rb | 49 +++++++++++++++++++ 4 files changed, 82 insertions(+), 19 deletions(-) create mode 100644 test/mspec/spec/matchers/be_kind_of_spec.rb create mode 100644 test/support/spec_helpers/matchers/be_kind_of.rb diff --git a/test/mspec/spec/matchers/be_kind_of_spec.rb b/test/mspec/spec/matchers/be_kind_of_spec.rb new file mode 100644 index 0000000000..1e19058411 --- /dev/null +++ b/test/mspec/spec/matchers/be_kind_of_spec.rb @@ -0,0 +1,31 @@ +require 'spec_helper' +require 'mspec/expectations/expectations' +require 'mspec/matchers' + +RSpec.describe BeKindOfMatcher do + it "matches when actual is a kind_of? expected" do + expect(BeKindOfMatcher.new(Numeric).matches?(1)).to eq(true) + expect(BeKindOfMatcher.new(Integer).matches?(2)).to eq(true) + expect(BeKindOfMatcher.new(Regexp).matches?(/m/)).to eq(true) + end + + it "does not match when actual is not a kind_of? expected" do + expect(BeKindOfMatcher.new(Integer).matches?(1.5)).to eq(false) + expect(BeKindOfMatcher.new(String).matches?(:a)).to eq(false) + expect(BeKindOfMatcher.new(Hash).matches?([])).to eq(false) + end + + it "provides a useful failure message" do + matcher = BeKindOfMatcher.new(Numeric) + matcher.matches?('string') + expect(matcher.failure_message).to eq([ + "Expected \"string\" (String)", "to be kind of Numeric"]) + end + + it "provides a useful negative failure message" do + matcher = BeKindOfMatcher.new(Numeric) + matcher.matches?(4.0) + expect(matcher.negative_failure_message).to eq([ + "Expected 4.0 (Float)", "not to be kind of Numeric"]) + end +end diff --git a/test/support/spec.rb b/test/support/spec.rb index 885845da8d..85defb4643 100644 --- a/test/support/spec.rb +++ b/test/support/spec.rb @@ -543,24 +543,6 @@ def inverted_match(subject) end end -class BeKindOfExpectation - def initialize(klass) - @klass = klass - end - - def match(subject) - if !(@klass === subject) - raise SpecFailedException, "#{subject.inspect} (#{subject.class}) should be a kind of #{@klass}" - end - end - - def inverted_match(subject) - if @klass === subject - raise SpecFailedException, "#{subject.inspect} (#{subject.class}) should not be a kind of #{@klass}" - end - end -end - class Expectation def initialize(matcher) @matcher = matcher @@ -1484,7 +1466,7 @@ def be_computed_by(method, *args) end def be_kind_of(klass) - BeKindOfExpectation.new(klass) + Expectation.new(BeKindOfMatcher.new(klass)) end def be_an_instance_of(klass) diff --git a/test/support/spec_helpers/matchers.rb b/test/support/spec_helpers/matchers.rb index c85da4f714..4269b6e585 100644 --- a/test/support/spec_helpers/matchers.rb +++ b/test/support/spec_helpers/matchers.rb @@ -1 +1,2 @@ require_relative 'matchers/be_an_instance_of' +require_relative 'matchers/be_kind_of' diff --git a/test/support/spec_helpers/matchers/be_kind_of.rb b/test/support/spec_helpers/matchers/be_kind_of.rb new file mode 100644 index 0000000000..a4b34faedf --- /dev/null +++ b/test/support/spec_helpers/matchers/be_kind_of.rb @@ -0,0 +1,49 @@ +=begin +Copyright (c) 2008 Engine Yard, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. +=end + +class BeKindOfMatcher + def initialize(expected) + @expected = expected + end + + def matches?(actual) + @actual = actual + @actual.is_a?(@expected) + end + + def failure_message + ["Expected #{@actual.inspect} (#{@actual.class})", "to be kind of #{@expected}"] + end + + def negative_failure_message + ["Expected #{@actual.inspect} (#{@actual.class})", "not to be kind of #{@expected}"] + end +end + +module MSpecMatchers + private def be_kind_of(expected) + BeKindOfMatcher.new(expected) + end +end From 73b4f7b5e9450a2ebbd541aed456888e5d94db1c Mon Sep 17 00:00:00 2001 From: Herwin Date: Sat, 18 Jan 2025 10:18:02 +0100 Subject: [PATCH 08/27] Import BeNilMatcher from mspec --- test/mspec/spec/matchers/be_nil_spec.rb | 27 ++++++++++++ test/support/spec.rb | 12 +----- test/support/spec_helpers/matchers.rb | 1 + test/support/spec_helpers/matchers/be_nil.rb | 45 ++++++++++++++++++++ 4 files changed, 74 insertions(+), 11 deletions(-) create mode 100644 test/mspec/spec/matchers/be_nil_spec.rb create mode 100644 test/support/spec_helpers/matchers/be_nil.rb diff --git a/test/mspec/spec/matchers/be_nil_spec.rb b/test/mspec/spec/matchers/be_nil_spec.rb new file mode 100644 index 0000000000..e2768acf83 --- /dev/null +++ b/test/mspec/spec/matchers/be_nil_spec.rb @@ -0,0 +1,27 @@ +require 'spec_helper' +require 'mspec/expectations/expectations' +require 'mspec/matchers' + +RSpec.describe BeNilMatcher do + it "matches when actual is nil" do + expect(BeNilMatcher.new.matches?(nil)).to eq(true) + end + + it "does not match when actual is not nil" do + expect(BeNilMatcher.new.matches?("")).to eq(false) + expect(BeNilMatcher.new.matches?(false)).to eq(false) + expect(BeNilMatcher.new.matches?(0)).to eq(false) + end + + it "provides a useful failure message" do + matcher = BeNilMatcher.new + matcher.matches?("some string") + expect(matcher.failure_message).to eq(["Expected \"some string\"", "to be nil"]) + end + + it "provides a useful negative failure message" do + matcher = BeNilMatcher.new + matcher.matches?(nil) + expect(matcher.negative_failure_message).to eq(["Expected nil", "not to be nil"]) + end +end diff --git a/test/support/spec.rb b/test/support/spec.rb index 85defb4643..247395a55c 100644 --- a/test/support/spec.rb +++ b/test/support/spec.rb @@ -533,16 +533,6 @@ def method_missing(method, *args) undef_method :equal? end -class BeNilExpectation - def match(subject) - raise SpecFailedException, subject.inspect + ' should be nil' if subject != nil - end - - def inverted_match(subject) - raise SpecFailedException, subject.inspect + ' should not be nil' if subject == nil - end -end - class Expectation def initialize(matcher) @matcher = matcher @@ -1422,7 +1412,7 @@ def should_not(*args) end def be_nil - BeNilExpectation.new + Expectation.new(BeNilMatcher.new) end def be_nan diff --git a/test/support/spec_helpers/matchers.rb b/test/support/spec_helpers/matchers.rb index 4269b6e585..bcfe27c81b 100644 --- a/test/support/spec_helpers/matchers.rb +++ b/test/support/spec_helpers/matchers.rb @@ -1,2 +1,3 @@ require_relative 'matchers/be_an_instance_of' require_relative 'matchers/be_kind_of' +require_relative 'matchers/be_nil' diff --git a/test/support/spec_helpers/matchers/be_nil.rb b/test/support/spec_helpers/matchers/be_nil.rb new file mode 100644 index 0000000000..f622de508d --- /dev/null +++ b/test/support/spec_helpers/matchers/be_nil.rb @@ -0,0 +1,45 @@ +=begin +Copyright (c) 2008 Engine Yard, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. +=end + +class BeNilMatcher + def matches?(actual) + @actual = actual + @actual.nil? + end + + def failure_message + ["Expected #{@actual.inspect}", "to be nil"] + end + + def negative_failure_message + ["Expected #{@actual.inspect}", "not to be nil"] + end +end + +module MSpecMatchers + private def be_nil + BeNilMatcher.new + end +end From 90bcf2689b442748b88e0325adc0de878ed07df4 Mon Sep 17 00:00:00 2001 From: Herwin Date: Sat, 18 Jan 2025 10:30:12 +0100 Subject: [PATCH 09/27] Sync spec_helper in mspec tests with upstream file We now have a MSpecMatchers module, and we can just add another stub file to load our spec helper. --- test/mspec/mspec.rb | 1 + test/mspec/spec_helper.rb | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 test/mspec/mspec.rb diff --git a/test/mspec/mspec.rb b/test/mspec/mspec.rb new file mode 100644 index 0000000000..935238dd94 --- /dev/null +++ b/test/mspec/mspec.rb @@ -0,0 +1 @@ +require_relative '../spec_helper' diff --git a/test/mspec/spec_helper.rb b/test/mspec/spec_helper.rb index badce06059..5cabfe5626 100644 --- a/test/mspec/spec_helper.rb +++ b/test/mspec/spec_helper.rb @@ -3,7 +3,7 @@ config.raise_errors_for_deprecations! end -require_relative '../spec_helper' +require 'mspec' # Remove this when MRI has intelligent warnings $VERBOSE = nil unless $VERBOSE @@ -63,7 +63,7 @@ def ensure_mspec_method(method) end PublicMSpecMatchers = Class.new { - # include MSpecMatchers + include MSpecMatchers public :raise_error }.new From 6cce6dae9c6c73e8f1f8dc7a662d79f53a6a45fd Mon Sep 17 00:00:00 2001 From: Herwin Date: Sat, 18 Jan 2025 12:51:56 +0100 Subject: [PATCH 10/27] Import BeAncestorOfMatcher from mspec --- .../spec/matchers/be_ancestor_of_spec.rb | 28 +++++++++++ test/support/spec.rb | 20 +------- test/support/spec_helpers/matchers.rb | 1 + .../spec_helpers/matchers/be_ancestor_of.rb | 49 +++++++++++++++++++ 4 files changed, 79 insertions(+), 19 deletions(-) create mode 100644 test/mspec/spec/matchers/be_ancestor_of_spec.rb create mode 100644 test/support/spec_helpers/matchers/be_ancestor_of.rb diff --git a/test/mspec/spec/matchers/be_ancestor_of_spec.rb b/test/mspec/spec/matchers/be_ancestor_of_spec.rb new file mode 100644 index 0000000000..abc05e0f7a --- /dev/null +++ b/test/mspec/spec/matchers/be_ancestor_of_spec.rb @@ -0,0 +1,28 @@ +require 'spec_helper' +require 'mspec/expectations/expectations' +require 'mspec/matchers' + +class Parent; end +class Child < Parent; end + +RSpec.describe BeAncestorOfMatcher do + it "matches when actual is an ancestor of expected" do + expect(BeAncestorOfMatcher.new(Child).matches?(Parent)).to eq(true) + end + + it "does not match when actual is not an ancestor of expected" do + expect(BeAncestorOfMatcher.new(Parent).matches?(Child)).to eq(false) + end + + it "provides a useful failure message" do + matcher = BeAncestorOfMatcher.new(Parent) + matcher.matches?(Child) + expect(matcher.failure_message).to eq(["Expected Child", "to be an ancestor of Parent"]) + end + + it "provides a useful negative failure message" do + matcher = BeAncestorOfMatcher.new(Child) + matcher.matches?(Parent) + expect(matcher.negative_failure_message).to eq(["Expected Parent", "not to be an ancestor of Child"]) + end +end diff --git a/test/support/spec.rb b/test/support/spec.rb index 247395a55c..2af0765d05 100644 --- a/test/support/spec.rb +++ b/test/support/spec.rb @@ -547,24 +547,6 @@ def inverted_match(subject) end end -class BeAncestorOfExpectation - def initialize(klass) - @klass = klass - end - - def match(subject) - unless @klass.ancestors.include?(subject) - raise SpecFailedException, subject.inspect + ' should be an ancestor of ' + @klass.inspect - end - end - - def inverted_match(subject) - if @klass.ancestors.include?(subject) - raise SpecFailedException, subject.inspect + ' should not to be an ancestor of ' + @klass.inspect - end - end -end - class BlockCallerExpectation def match(subject) raise SpecFailedException, subject.inspect + ' should have blocked, but it did not' unless check(subject) @@ -1464,7 +1446,7 @@ def be_an_instance_of(klass) end def be_ancestor_of(klass) - BeAncestorOfExpectation.new(klass) + Expectation.new(BeAncestorOfMatcher.new(klass)) end def block_caller diff --git a/test/support/spec_helpers/matchers.rb b/test/support/spec_helpers/matchers.rb index bcfe27c81b..af66474820 100644 --- a/test/support/spec_helpers/matchers.rb +++ b/test/support/spec_helpers/matchers.rb @@ -1,3 +1,4 @@ require_relative 'matchers/be_an_instance_of' +require_relative 'matchers/be_ancestor_of' require_relative 'matchers/be_kind_of' require_relative 'matchers/be_nil' diff --git a/test/support/spec_helpers/matchers/be_ancestor_of.rb b/test/support/spec_helpers/matchers/be_ancestor_of.rb new file mode 100644 index 0000000000..7a5cb9743a --- /dev/null +++ b/test/support/spec_helpers/matchers/be_ancestor_of.rb @@ -0,0 +1,49 @@ +=begin +Copyright (c) 2008 Engine Yard, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. +=end + +class BeAncestorOfMatcher + def initialize(expected) + @expected = expected + end + + def matches?(actual) + @actual = actual + @expected.ancestors.include? @actual + end + + def failure_message + ["Expected #{@actual}", "to be an ancestor of #{@expected}"] + end + + def negative_failure_message + ["Expected #{@actual}", "not to be an ancestor of #{@expected}"] + end +end + +module MSpecMatchers + private def be_ancestor_of(expected) + BeAncestorOfMatcher.new(expected) + end +end From f580723d1e831fa782d0eee0ddb1e11ee45910c5 Mon Sep 17 00:00:00 2001 From: Herwin Date: Sat, 18 Jan 2025 12:59:05 +0100 Subject: [PATCH 11/27] Import BlockingMatcher from mspec --- test/mspec/spec/matchers/block_caller_spec.rb | 13 ++++ test/support/spec.rb | 37 +---------- test/support/spec_helpers/matchers.rb | 1 + .../spec_helpers/matchers/block_caller.rb | 62 +++++++++++++++++++ 4 files changed, 77 insertions(+), 36 deletions(-) create mode 100644 test/mspec/spec/matchers/block_caller_spec.rb create mode 100644 test/support/spec_helpers/matchers/block_caller.rb diff --git a/test/mspec/spec/matchers/block_caller_spec.rb b/test/mspec/spec/matchers/block_caller_spec.rb new file mode 100644 index 0000000000..5d7085fa63 --- /dev/null +++ b/test/mspec/spec/matchers/block_caller_spec.rb @@ -0,0 +1,13 @@ +require 'spec_helper' +require 'mspec/expectations/expectations' +require 'mspec/matchers' + +RSpec.describe BlockingMatcher do + it 'matches when a Proc blocks the caller' do + expect(BlockingMatcher.new.matches?(proc { sleep })).to eq(true) + end + + it 'does not match when a Proc does not block the caller' do + expect(BlockingMatcher.new.matches?(proc { 1 })).to eq(false) + end +end diff --git a/test/support/spec.rb b/test/support/spec.rb index 2af0765d05..29fc648570 100644 --- a/test/support/spec.rb +++ b/test/support/spec.rb @@ -547,41 +547,6 @@ def inverted_match(subject) end end -class BlockCallerExpectation - def match(subject) - raise SpecFailedException, subject.inspect + ' should have blocked, but it did not' unless check(subject) - end - - def inverted_match(subject) - raise SpecFailedException, subject.inspect + ' should have not have blocked, but it did' if check(subject) - end - - private - - # I borrowed this from https://github.com/ruby/mspec/blob/master/lib/mspec/matchers/block_caller.rb - # Copyright (c) 2008 Engine Yard, Inc. All rights reserved. - # Licensed Under the MIT license. - def check(subject) - t = Thread.new { subject.call } - - loop do - case t.status - when 'sleep' # blocked - t.kill - t.join - return true - when false # terminated normally, so never blocked - t.join - return false - when nil # terminated exceptionally - t.value - else - Thread.pass - end - end - end -end - class EqlExpectation def initialize(other) @other = other @@ -1450,7 +1415,7 @@ def be_ancestor_of(klass) end def block_caller - BlockCallerExpectation.new + Expectation.new(BlockingMatcher.new) end def eql(other) diff --git a/test/support/spec_helpers/matchers.rb b/test/support/spec_helpers/matchers.rb index af66474820..9ac2b302b4 100644 --- a/test/support/spec_helpers/matchers.rb +++ b/test/support/spec_helpers/matchers.rb @@ -2,3 +2,4 @@ require_relative 'matchers/be_ancestor_of' require_relative 'matchers/be_kind_of' require_relative 'matchers/be_nil' +require_relative 'matchers/block_caller' diff --git a/test/support/spec_helpers/matchers/block_caller.rb b/test/support/spec_helpers/matchers/block_caller.rb new file mode 100644 index 0000000000..3263c7fee7 --- /dev/null +++ b/test/support/spec_helpers/matchers/block_caller.rb @@ -0,0 +1,62 @@ +=begin +Copyright (c) 2008 Engine Yard, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. +=end + +class BlockingMatcher + def matches?(block) + t = Thread.new do + block.call + end + + loop do + case t.status + when "sleep" # blocked + t.kill + t.join + return true + when false # terminated normally, so never blocked + t.join + return false + when nil # terminated exceptionally + t.value + else + Thread.pass + end + end + end + + def failure_message + ['Expected the given Proc', 'to block the caller'] + end + + def negative_failure_message + ['Expected the given Proc', 'to not block the caller'] + end +end + +module MSpecMatchers + private def block_caller + BlockingMatcher.new + end +end From 065322e632c81eddf14f058e87a9f507e15d8a57 Mon Sep 17 00:00:00 2001 From: Herwin Date: Sat, 18 Jan 2025 13:12:31 +0100 Subject: [PATCH 12/27] Import EqlMatcher from mspec Import MSpec.format as well, and alter our MSpec definition to be a module instead of a class. --- test/mspec/spec/matchers/eql_spec.rb | 33 +++++++++++++++ test/support/mspec.rb | 2 +- test/support/spec.rb | 25 ++--------- test/support/spec_helpers/matchers.rb | 1 + test/support/spec_helpers/matchers/eql.rb | 51 +++++++++++++++++++++++ test/support/spec_utils/format.rb | 36 ++++++++++++++++ 6 files changed, 126 insertions(+), 22 deletions(-) create mode 100644 test/mspec/spec/matchers/eql_spec.rb create mode 100644 test/support/spec_helpers/matchers/eql.rb create mode 100644 test/support/spec_utils/format.rb diff --git a/test/mspec/spec/matchers/eql_spec.rb b/test/mspec/spec/matchers/eql_spec.rb new file mode 100644 index 0000000000..66307d2a9d --- /dev/null +++ b/test/mspec/spec/matchers/eql_spec.rb @@ -0,0 +1,33 @@ +require 'spec_helper' +require 'mspec/expectations/expectations' +require 'mspec/matchers' + +RSpec.describe EqlMatcher do + it "matches when actual is eql? to expected" do + expect(EqlMatcher.new(1).matches?(1)).to eq(true) + expect(EqlMatcher.new(1.5).matches?(1.5)).to eq(true) + expect(EqlMatcher.new("red").matches?("red")).to eq(true) + expect(EqlMatcher.new(:blue).matches?(:blue)).to eq(true) + expect(EqlMatcher.new(Object).matches?(Object)).to eq(true) + + o = Object.new + expect(EqlMatcher.new(o).matches?(o)).to eq(true) + end + + it "does not match when actual is not eql? to expected" do + expect(EqlMatcher.new(1).matches?(1.0)).to eq(false) + expect(EqlMatcher.new(Hash).matches?(Object)).to eq(false) + end + + it "provides a useful failure message" do + matcher = EqlMatcher.new("red") + matcher.matches?("red") + expect(matcher.failure_message).to eq(["Expected \"red\"", "to have same value and type as \"red\""]) + end + + it "provides a useful negative failure message" do + matcher = EqlMatcher.new(1) + matcher.matches?(1.0) + expect(matcher.negative_failure_message).to eq(["Expected 1.0", "not to have same value or type as 1"]) + end +end diff --git a/test/support/mspec.rb b/test/support/mspec.rb index 0e5f21b67e..b1495b69c8 100644 --- a/test/support/mspec.rb +++ b/test/support/mspec.rb @@ -1,4 +1,4 @@ -class MSpec +module MSpec def self.features @features || {} end diff --git a/test/support/spec.rb b/test/support/spec.rb index 29fc648570..7c97965744 100644 --- a/test/support/spec.rb +++ b/test/support/spec.rb @@ -10,6 +10,7 @@ require_relative 'spec_helpers/matchers' require_relative 'spec_helpers/mock_to_path' require_relative 'spec_helpers/tmp' +require_relative 'spec_utils/format' require_relative 'spec_utils/warnings' require_relative 'nat_binary' require 'tempfile' @@ -547,24 +548,6 @@ def inverted_match(subject) end end -class EqlExpectation - def initialize(other) - @other = other - end - - def match(subject) - if !subject.eql?(@other) - raise SpecFailedException, subject.inspect + ' should be eql (same type) to ' + @other.inspect - end - end - - def inverted_match(subject) - if subject.eql?(@other) - raise SpecFailedException, subject.inspect + ' should not be eql (same type) to ' + @other.inspect - end - end -end - class BeEmptyExpectation def match(subject) raise SpecFailedException, subject.inspect + ' should be empty but has size ' + subject.length if !subject.empty? @@ -1367,11 +1350,11 @@ def be_nan end def be_negative_zero - EqlExpectation.new(-0.0) + Expectation.new(EqlMatcher.new(-0.0)) end def be_positive_zero - EqlExpectation.new(0.0) + Expectation.new(EqlMatcher.new(0.0)) end def be_positive_infinity @@ -1419,7 +1402,7 @@ def block_caller end def eql(other) - EqlExpectation.new(other) + Expectation.new(EqlMatcher.new(other)) end def be_empty() diff --git a/test/support/spec_helpers/matchers.rb b/test/support/spec_helpers/matchers.rb index 9ac2b302b4..375f4be67d 100644 --- a/test/support/spec_helpers/matchers.rb +++ b/test/support/spec_helpers/matchers.rb @@ -3,3 +3,4 @@ require_relative 'matchers/be_kind_of' require_relative 'matchers/be_nil' require_relative 'matchers/block_caller' +require_relative 'matchers/eql' diff --git a/test/support/spec_helpers/matchers/eql.rb b/test/support/spec_helpers/matchers/eql.rb new file mode 100644 index 0000000000..51447db52f --- /dev/null +++ b/test/support/spec_helpers/matchers/eql.rb @@ -0,0 +1,51 @@ +=begin +Copyright (c) 2008 Engine Yard, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. +=end + +class EqlMatcher + def initialize(expected) + @expected = expected + end + + def matches?(actual) + @actual = actual + @actual.eql?(@expected) + end + + def failure_message + ["Expected #{MSpec.format(@actual)}", + "to have same value and type as #{MSpec.format(@expected)}"] + end + + def negative_failure_message + ["Expected #{MSpec.format(@actual)}", + "not to have same value or type as #{MSpec.format(@expected)}"] + end +end + +module MSpecMatchers + private def eql(expected) + EqlMatcher.new(expected) + end +end diff --git a/test/support/spec_utils/format.rb b/test/support/spec_utils/format.rb new file mode 100644 index 0000000000..d9e40535c1 --- /dev/null +++ b/test/support/spec_utils/format.rb @@ -0,0 +1,36 @@ +=begin +Copyright (c) 2008 Engine Yard, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. +=end + +module MSpec + def self.format(obj) + if String === obj and obj.include?("\n") + "\n#{obj.inspect.gsub('\n', "\n")}" + else + obj.pretty_inspect.chomp + end + rescue => e + "#<#{obj.class}>(#pretty_inspect raised #{e.inspect})" + end +end From 8605374bdb9c4c1b83a49c5ea6a3abebef4da241 Mon Sep 17 00:00:00 2001 From: Herwin Date: Sat, 18 Jan 2025 13:18:43 +0100 Subject: [PATCH 13/27] Import BeEmptyMatcher from mspec --- test/mspec/spec/matchers/be_empty_spec.rb | 26 +++++++++++ test/support/spec.rb | 12 +---- test/support/spec_helpers/matchers.rb | 1 + .../support/spec_helpers/matchers/be_empty.rb | 45 +++++++++++++++++++ 4 files changed, 73 insertions(+), 11 deletions(-) create mode 100644 test/mspec/spec/matchers/be_empty_spec.rb create mode 100644 test/support/spec_helpers/matchers/be_empty.rb diff --git a/test/mspec/spec/matchers/be_empty_spec.rb b/test/mspec/spec/matchers/be_empty_spec.rb new file mode 100644 index 0000000000..30678fe85f --- /dev/null +++ b/test/mspec/spec/matchers/be_empty_spec.rb @@ -0,0 +1,26 @@ +require 'spec_helper' +require 'mspec/expectations/expectations' +require 'mspec/matchers' + +RSpec.describe BeEmptyMatcher do + it "matches when actual is empty" do + expect(BeEmptyMatcher.new.matches?("")).to eq(true) + end + + it "does not match when actual is not empty" do + expect(BeEmptyMatcher.new.matches?([10])).to eq(false) + end + + it "provides a useful failure message" do + matcher = BeEmptyMatcher.new + matcher.matches?("not empty string") + expect(matcher.failure_message).to eq(["Expected \"not empty string\"", "to be empty"]) + end + + it "provides a useful negative failure message" do + matcher = BeEmptyMatcher.new + matcher.matches?("") + expect(matcher.negative_failure_message).to eq(["Expected \"\"", "not to be empty"]) + end +end + diff --git a/test/support/spec.rb b/test/support/spec.rb index 7c97965744..57fcc7a126 100644 --- a/test/support/spec.rb +++ b/test/support/spec.rb @@ -548,16 +548,6 @@ def inverted_match(subject) end end -class BeEmptyExpectation - def match(subject) - raise SpecFailedException, subject.inspect + ' should be empty but has size ' + subject.length if !subject.empty? - end - - def inverted_match(subject) - raise SpecFailedException, subject.inspect + ' should not be empty' if subject.empty? - end -end - class EqualExpectation def initialize(other) @other = other @@ -1406,7 +1396,7 @@ def eql(other) end def be_empty() - BeEmptyExpectation.new + Expectation.new(BeEmptyMatcher.new) end def equal(other) diff --git a/test/support/spec_helpers/matchers.rb b/test/support/spec_helpers/matchers.rb index 375f4be67d..b748b9ca78 100644 --- a/test/support/spec_helpers/matchers.rb +++ b/test/support/spec_helpers/matchers.rb @@ -1,5 +1,6 @@ require_relative 'matchers/be_an_instance_of' require_relative 'matchers/be_ancestor_of' +require_relative 'matchers/be_empty' require_relative 'matchers/be_kind_of' require_relative 'matchers/be_nil' require_relative 'matchers/block_caller' diff --git a/test/support/spec_helpers/matchers/be_empty.rb b/test/support/spec_helpers/matchers/be_empty.rb new file mode 100644 index 0000000000..f7c4b28381 --- /dev/null +++ b/test/support/spec_helpers/matchers/be_empty.rb @@ -0,0 +1,45 @@ +=begin +Copyright (c) 2008 Engine Yard, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. +=end + +class BeEmptyMatcher + def matches?(actual) + @actual = actual + @actual.empty? + end + + def failure_message + ["Expected #{@actual.inspect}", "to be empty"] + end + + def negative_failure_message + ["Expected #{@actual.inspect}", "not to be empty"] + end +end + +module MSpecMatchers + private def be_empty + BeEmptyMatcher.new + end +end From 84ab1253301bde3b5ef2d93b63aafc1b027743a4 Mon Sep 17 00:00:00 2001 From: Herwin Date: Sat, 18 Jan 2025 13:44:06 +0100 Subject: [PATCH 14/27] Remove mspec tests from our repo We ended up with copying both the code and the specs from the mspec repository, so we were effectively running their specs on their code. There's not much point on doing that, so get rid of those specs again. --- .github/workflows/test.yml | 10 --- README.md | 1 - test/mspec/Gemfile | 4 -- test/mspec/Gemfile.lock | 26 ------- test/mspec/LICENSE | 22 ------ test/mspec/mspec.rb | 1 - test/mspec/mspec/expectations/expectations.rb | 1 - test/mspec/mspec/matchers.rb | 1 - .../spec/matchers/be_an_instance_of_spec.rb | 50 ------------- .../spec/matchers/be_ancestor_of_spec.rb | 28 -------- test/mspec/spec/matchers/be_empty_spec.rb | 26 ------- test/mspec/spec/matchers/be_kind_of_spec.rb | 31 -------- test/mspec/spec/matchers/be_nil_spec.rb | 27 ------- test/mspec/spec/matchers/block_caller_spec.rb | 13 ---- test/mspec/spec/matchers/eql_spec.rb | 33 --------- test/mspec/spec_helper.rb | 70 ------------------- 16 files changed, 344 deletions(-) delete mode 100644 test/mspec/Gemfile delete mode 100644 test/mspec/Gemfile.lock delete mode 100644 test/mspec/LICENSE delete mode 100644 test/mspec/mspec.rb delete mode 100644 test/mspec/mspec/expectations/expectations.rb delete mode 100644 test/mspec/mspec/matchers.rb delete mode 100644 test/mspec/spec/matchers/be_an_instance_of_spec.rb delete mode 100644 test/mspec/spec/matchers/be_ancestor_of_spec.rb delete mode 100644 test/mspec/spec/matchers/be_empty_spec.rb delete mode 100644 test/mspec/spec/matchers/be_kind_of_spec.rb delete mode 100644 test/mspec/spec/matchers/be_nil_spec.rb delete mode 100644 test/mspec/spec/matchers/block_caller_spec.rb delete mode 100644 test/mspec/spec/matchers/eql_spec.rb delete mode 100644 test/mspec/spec_helper.rb diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7c78d758f8..8b1f3af75b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -111,13 +111,3 @@ jobs: SPEC_TIMEOUT: 480 SOME_TESTS: true run: rake docker_test_asan - mspec: - runs-on: ubuntu-24.04 - steps: - - uses: actions/checkout@v4 - - name: install ruby - run: sudo apt-get install -y ruby ruby-bundler - - name: install rspec - run: cd test/mspec && sudo bundle install - - name: run very limited hacked mspec test - run: cd test/mspec && bundle exec rspec -I. diff --git a/README.md b/README.md index c4cdefd2c2..e9353ead47 100644 --- a/README.md +++ b/README.md @@ -169,7 +169,6 @@ the respective file, in the same directory with a name like `LICENSE`, or both. | `prettyprint.rb` | Yukihiro Matsumoto | BSD | | `shellwords.rb` | Akinori MUSHA | BSD | | `spec/*` | Engine Yard, Inc. | MIT | -| `test/mspec/*` | Engine Yard, Inc. | MIT | | `uri.rb`/`uri/*` | Akira Yamada | BSD | | `version.rb` | Engine Yard, Inc. | MIT | | `zlib` | Jean-loup Gailly and Mark Adler | zlib license | diff --git a/test/mspec/Gemfile b/test/mspec/Gemfile deleted file mode 100644 index 617a995cad..0000000000 --- a/test/mspec/Gemfile +++ /dev/null @@ -1,4 +0,0 @@ -source 'https://rubygems.org' - -gem "rake", "~> 12.3" -gem "rspec", "~> 3.0" diff --git a/test/mspec/Gemfile.lock b/test/mspec/Gemfile.lock deleted file mode 100644 index cd39906044..0000000000 --- a/test/mspec/Gemfile.lock +++ /dev/null @@ -1,26 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - diff-lcs (1.4.4) - rake (12.3.3) - rspec (3.10.0) - rspec-core (~> 3.10.0) - rspec-expectations (~> 3.10.0) - rspec-mocks (~> 3.10.0) - rspec-core (3.10.1) - rspec-support (~> 3.10.0) - rspec-expectations (3.10.1) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.10.0) - rspec-mocks (3.10.2) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.10.0) - rspec-support (3.10.2) - -PLATFORMS - java - ruby - -DEPENDENCIES - rake (~> 12.3) - rspec (~> 3.0) diff --git a/test/mspec/LICENSE b/test/mspec/LICENSE deleted file mode 100644 index d581dd1c9f..0000000000 --- a/test/mspec/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2008 Engine Yard, Inc. All rights reserved. - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, -copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. diff --git a/test/mspec/mspec.rb b/test/mspec/mspec.rb deleted file mode 100644 index 935238dd94..0000000000 --- a/test/mspec/mspec.rb +++ /dev/null @@ -1 +0,0 @@ -require_relative '../spec_helper' diff --git a/test/mspec/mspec/expectations/expectations.rb b/test/mspec/mspec/expectations/expectations.rb deleted file mode 100644 index b695e4ab98..0000000000 --- a/test/mspec/mspec/expectations/expectations.rb +++ /dev/null @@ -1 +0,0 @@ -# Stub to work around the require statements of the specs diff --git a/test/mspec/mspec/matchers.rb b/test/mspec/mspec/matchers.rb deleted file mode 100644 index 86860d9d3e..0000000000 --- a/test/mspec/mspec/matchers.rb +++ /dev/null @@ -1 +0,0 @@ -require_relative '../../support/spec_helpers/matchers' diff --git a/test/mspec/spec/matchers/be_an_instance_of_spec.rb b/test/mspec/spec/matchers/be_an_instance_of_spec.rb deleted file mode 100644 index 7c74249d24..0000000000 --- a/test/mspec/spec/matchers/be_an_instance_of_spec.rb +++ /dev/null @@ -1,50 +0,0 @@ -require 'spec_helper' -require 'mspec/expectations/expectations' -require 'mspec/matchers' - -module BeAnInOfSpecs - class A - end - - class B < A - end - - class C < B - end -end - -RSpec.describe BeAnInstanceOfMatcher do - it "matches when actual is an instance_of? expected" do - a = BeAnInOfSpecs::A.new - expect(BeAnInstanceOfMatcher.new(BeAnInOfSpecs::A).matches?(a)).to be_truthy - - b = BeAnInOfSpecs::B.new - expect(BeAnInstanceOfMatcher.new(BeAnInOfSpecs::B).matches?(b)).to be_truthy - end - - it "does not match when actual is not an instance_of? expected" do - a = BeAnInOfSpecs::A.new - expect(BeAnInstanceOfMatcher.new(BeAnInOfSpecs::B).matches?(a)).to be_falsey - - b = BeAnInOfSpecs::B.new - expect(BeAnInstanceOfMatcher.new(BeAnInOfSpecs::A).matches?(b)).to be_falsey - - c = BeAnInOfSpecs::C.new - expect(BeAnInstanceOfMatcher.new(BeAnInOfSpecs::A).matches?(c)).to be_falsey - expect(BeAnInstanceOfMatcher.new(BeAnInOfSpecs::B).matches?(c)).to be_falsey - end - - it "provides a useful failure message" do - matcher = BeAnInstanceOfMatcher.new(Numeric) - matcher.matches?("string") - expect(matcher.failure_message).to eq([ - "Expected \"string\" (String)", "to be an instance of Numeric"]) - end - - it "provides a useful negative failure message" do - matcher = BeAnInstanceOfMatcher.new(Numeric) - matcher.matches?(4.0) - expect(matcher.negative_failure_message).to eq([ - "Expected 4.0 (Float)", "not to be an instance of Numeric"]) - end -end diff --git a/test/mspec/spec/matchers/be_ancestor_of_spec.rb b/test/mspec/spec/matchers/be_ancestor_of_spec.rb deleted file mode 100644 index abc05e0f7a..0000000000 --- a/test/mspec/spec/matchers/be_ancestor_of_spec.rb +++ /dev/null @@ -1,28 +0,0 @@ -require 'spec_helper' -require 'mspec/expectations/expectations' -require 'mspec/matchers' - -class Parent; end -class Child < Parent; end - -RSpec.describe BeAncestorOfMatcher do - it "matches when actual is an ancestor of expected" do - expect(BeAncestorOfMatcher.new(Child).matches?(Parent)).to eq(true) - end - - it "does not match when actual is not an ancestor of expected" do - expect(BeAncestorOfMatcher.new(Parent).matches?(Child)).to eq(false) - end - - it "provides a useful failure message" do - matcher = BeAncestorOfMatcher.new(Parent) - matcher.matches?(Child) - expect(matcher.failure_message).to eq(["Expected Child", "to be an ancestor of Parent"]) - end - - it "provides a useful negative failure message" do - matcher = BeAncestorOfMatcher.new(Child) - matcher.matches?(Parent) - expect(matcher.negative_failure_message).to eq(["Expected Parent", "not to be an ancestor of Child"]) - end -end diff --git a/test/mspec/spec/matchers/be_empty_spec.rb b/test/mspec/spec/matchers/be_empty_spec.rb deleted file mode 100644 index 30678fe85f..0000000000 --- a/test/mspec/spec/matchers/be_empty_spec.rb +++ /dev/null @@ -1,26 +0,0 @@ -require 'spec_helper' -require 'mspec/expectations/expectations' -require 'mspec/matchers' - -RSpec.describe BeEmptyMatcher do - it "matches when actual is empty" do - expect(BeEmptyMatcher.new.matches?("")).to eq(true) - end - - it "does not match when actual is not empty" do - expect(BeEmptyMatcher.new.matches?([10])).to eq(false) - end - - it "provides a useful failure message" do - matcher = BeEmptyMatcher.new - matcher.matches?("not empty string") - expect(matcher.failure_message).to eq(["Expected \"not empty string\"", "to be empty"]) - end - - it "provides a useful negative failure message" do - matcher = BeEmptyMatcher.new - matcher.matches?("") - expect(matcher.negative_failure_message).to eq(["Expected \"\"", "not to be empty"]) - end -end - diff --git a/test/mspec/spec/matchers/be_kind_of_spec.rb b/test/mspec/spec/matchers/be_kind_of_spec.rb deleted file mode 100644 index 1e19058411..0000000000 --- a/test/mspec/spec/matchers/be_kind_of_spec.rb +++ /dev/null @@ -1,31 +0,0 @@ -require 'spec_helper' -require 'mspec/expectations/expectations' -require 'mspec/matchers' - -RSpec.describe BeKindOfMatcher do - it "matches when actual is a kind_of? expected" do - expect(BeKindOfMatcher.new(Numeric).matches?(1)).to eq(true) - expect(BeKindOfMatcher.new(Integer).matches?(2)).to eq(true) - expect(BeKindOfMatcher.new(Regexp).matches?(/m/)).to eq(true) - end - - it "does not match when actual is not a kind_of? expected" do - expect(BeKindOfMatcher.new(Integer).matches?(1.5)).to eq(false) - expect(BeKindOfMatcher.new(String).matches?(:a)).to eq(false) - expect(BeKindOfMatcher.new(Hash).matches?([])).to eq(false) - end - - it "provides a useful failure message" do - matcher = BeKindOfMatcher.new(Numeric) - matcher.matches?('string') - expect(matcher.failure_message).to eq([ - "Expected \"string\" (String)", "to be kind of Numeric"]) - end - - it "provides a useful negative failure message" do - matcher = BeKindOfMatcher.new(Numeric) - matcher.matches?(4.0) - expect(matcher.negative_failure_message).to eq([ - "Expected 4.0 (Float)", "not to be kind of Numeric"]) - end -end diff --git a/test/mspec/spec/matchers/be_nil_spec.rb b/test/mspec/spec/matchers/be_nil_spec.rb deleted file mode 100644 index e2768acf83..0000000000 --- a/test/mspec/spec/matchers/be_nil_spec.rb +++ /dev/null @@ -1,27 +0,0 @@ -require 'spec_helper' -require 'mspec/expectations/expectations' -require 'mspec/matchers' - -RSpec.describe BeNilMatcher do - it "matches when actual is nil" do - expect(BeNilMatcher.new.matches?(nil)).to eq(true) - end - - it "does not match when actual is not nil" do - expect(BeNilMatcher.new.matches?("")).to eq(false) - expect(BeNilMatcher.new.matches?(false)).to eq(false) - expect(BeNilMatcher.new.matches?(0)).to eq(false) - end - - it "provides a useful failure message" do - matcher = BeNilMatcher.new - matcher.matches?("some string") - expect(matcher.failure_message).to eq(["Expected \"some string\"", "to be nil"]) - end - - it "provides a useful negative failure message" do - matcher = BeNilMatcher.new - matcher.matches?(nil) - expect(matcher.negative_failure_message).to eq(["Expected nil", "not to be nil"]) - end -end diff --git a/test/mspec/spec/matchers/block_caller_spec.rb b/test/mspec/spec/matchers/block_caller_spec.rb deleted file mode 100644 index 5d7085fa63..0000000000 --- a/test/mspec/spec/matchers/block_caller_spec.rb +++ /dev/null @@ -1,13 +0,0 @@ -require 'spec_helper' -require 'mspec/expectations/expectations' -require 'mspec/matchers' - -RSpec.describe BlockingMatcher do - it 'matches when a Proc blocks the caller' do - expect(BlockingMatcher.new.matches?(proc { sleep })).to eq(true) - end - - it 'does not match when a Proc does not block the caller' do - expect(BlockingMatcher.new.matches?(proc { 1 })).to eq(false) - end -end diff --git a/test/mspec/spec/matchers/eql_spec.rb b/test/mspec/spec/matchers/eql_spec.rb deleted file mode 100644 index 66307d2a9d..0000000000 --- a/test/mspec/spec/matchers/eql_spec.rb +++ /dev/null @@ -1,33 +0,0 @@ -require 'spec_helper' -require 'mspec/expectations/expectations' -require 'mspec/matchers' - -RSpec.describe EqlMatcher do - it "matches when actual is eql? to expected" do - expect(EqlMatcher.new(1).matches?(1)).to eq(true) - expect(EqlMatcher.new(1.5).matches?(1.5)).to eq(true) - expect(EqlMatcher.new("red").matches?("red")).to eq(true) - expect(EqlMatcher.new(:blue).matches?(:blue)).to eq(true) - expect(EqlMatcher.new(Object).matches?(Object)).to eq(true) - - o = Object.new - expect(EqlMatcher.new(o).matches?(o)).to eq(true) - end - - it "does not match when actual is not eql? to expected" do - expect(EqlMatcher.new(1).matches?(1.0)).to eq(false) - expect(EqlMatcher.new(Hash).matches?(Object)).to eq(false) - end - - it "provides a useful failure message" do - matcher = EqlMatcher.new("red") - matcher.matches?("red") - expect(matcher.failure_message).to eq(["Expected \"red\"", "to have same value and type as \"red\""]) - end - - it "provides a useful negative failure message" do - matcher = EqlMatcher.new(1) - matcher.matches?(1.0) - expect(matcher.negative_failure_message).to eq(["Expected 1.0", "not to have same value or type as 1"]) - end -end diff --git a/test/mspec/spec_helper.rb b/test/mspec/spec_helper.rb deleted file mode 100644 index 5cabfe5626..0000000000 --- a/test/mspec/spec_helper.rb +++ /dev/null @@ -1,70 +0,0 @@ -RSpec.configure do |config| - config.disable_monkey_patching! - config.raise_errors_for_deprecations! -end - -require 'mspec' - -# Remove this when MRI has intelligent warnings -$VERBOSE = nil unless $VERBOSE - -class MOSConfig < Hash - def initialize - self[:loadpath] = [] - self[:requires] = [] - self[:flags] = [] - self[:options] = [] - self[:includes] = [] - self[:excludes] = [] - self[:patterns] = [] - self[:xpatterns] = [] - self[:tags] = [] - self[:xtags] = [] - self[:atags] = [] - self[:astrings] = [] - self[:target] = 'ruby' - self[:command] = nil - self[:ltags] = [] - self[:files] = [] - self[:launch] = [] - end -end - -def new_option - config = MOSConfig.new - return MSpecOptions.new("spec", 20, config), config -end - -# Just to have an exception name output not be "Exception" -class MSpecExampleError < Exception -end - -def hide_deprecation_warnings - allow(MSpec).to receive(:deprecate) -end - -def run_mspec(command, args) - cwd = Dir.pwd - command = " #{command}" unless command.start_with?('-') - cmd = "#{cwd}/bin/mspec#{command} -B spec/fixtures/config.mspec #{args}" - out = `#{cmd} 2>&1` - ret = $? - out = out.sub(/\A\$.+\n/, '') # Remove printed command line - out = out.sub(RUBY_DESCRIPTION, "RUBY_DESCRIPTION") - out = out.gsub(/\d+\.\d{6}/, "D.DDDDDD") # Specs total time - out = out.gsub(/\d{2}:\d{2}:\d{2}/, "00:00:00") # Progress bar time - out = out.gsub(cwd, "CWD") - return out, ret -end - -def ensure_mspec_method(method) - file, _line = method.source_location - expect(file).to start_with(File.expand_path('../../lib/mspec', __FILE__ )) -end - -PublicMSpecMatchers = Class.new { - include MSpecMatchers - public :raise_error -}.new - -BACKTRACE_QUOTE = RUBY_VERSION >= "3.4" ? "'" : "`" From 59736dfd2dfac3320659f696e84d49e5df86b732 Mon Sep 17 00:00:00 2001 From: Herwin Date: Sat, 18 Jan 2025 14:51:17 +0100 Subject: [PATCH 15/27] Import BeTrueMatcher from mspec --- test/support/spec.rb | 2 +- test/support/spec_helpers/matchers.rb | 1 + test/support/spec_helpers/matchers/be_true.rb | 45 +++++++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 test/support/spec_helpers/matchers/be_true.rb diff --git a/test/support/spec.rb b/test/support/spec.rb index 57fcc7a126..67c5e87041 100644 --- a/test/support/spec.rb +++ b/test/support/spec.rb @@ -1356,7 +1356,7 @@ def be_negative_infinity end def be_true - EqualExpectation.new(true) + Expectation.new(BeTrueMatcher.new) end def be_false diff --git a/test/support/spec_helpers/matchers.rb b/test/support/spec_helpers/matchers.rb index b748b9ca78..a612a94bb7 100644 --- a/test/support/spec_helpers/matchers.rb +++ b/test/support/spec_helpers/matchers.rb @@ -3,5 +3,6 @@ require_relative 'matchers/be_empty' require_relative 'matchers/be_kind_of' require_relative 'matchers/be_nil' +require_relative 'matchers/be_true' require_relative 'matchers/block_caller' require_relative 'matchers/eql' diff --git a/test/support/spec_helpers/matchers/be_true.rb b/test/support/spec_helpers/matchers/be_true.rb new file mode 100644 index 0000000000..29ec76f905 --- /dev/null +++ b/test/support/spec_helpers/matchers/be_true.rb @@ -0,0 +1,45 @@ +=begin +Copyright (c) 2008 Engine Yard, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. +=end + +class BeTrueMatcher + def matches?(actual) + @actual = actual + @actual == true + end + + def failure_message + ["Expected #{@actual.inspect}", "to be true"] + end + + def negative_failure_message + ["Expected #{@actual.inspect}", "not to be true"] + end +end + +module MSpecMatchers + private def be_true + BeTrueMatcher.new + end +end From bb4ce43393c0da9bc5f7472abd7e73130c9d382c Mon Sep 17 00:00:00 2001 From: Herwin Date: Sat, 18 Jan 2025 14:53:02 +0100 Subject: [PATCH 16/27] Import BeFalseMatcher from mspec --- test/support/spec.rb | 2 +- test/support/spec_helpers/matchers.rb | 1 + .../support/spec_helpers/matchers/be_false.rb | 45 +++++++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 test/support/spec_helpers/matchers/be_false.rb diff --git a/test/support/spec.rb b/test/support/spec.rb index 67c5e87041..48450959f4 100644 --- a/test/support/spec.rb +++ b/test/support/spec.rb @@ -1360,7 +1360,7 @@ def be_true end def be_false - EqualExpectation.new(false) + Expectation.new(BeFalseMatcher.new) end def be_true_or_false diff --git a/test/support/spec_helpers/matchers.rb b/test/support/spec_helpers/matchers.rb index a612a94bb7..2eb7a00e7d 100644 --- a/test/support/spec_helpers/matchers.rb +++ b/test/support/spec_helpers/matchers.rb @@ -1,6 +1,7 @@ require_relative 'matchers/be_an_instance_of' require_relative 'matchers/be_ancestor_of' require_relative 'matchers/be_empty' +require_relative 'matchers/be_false' require_relative 'matchers/be_kind_of' require_relative 'matchers/be_nil' require_relative 'matchers/be_true' diff --git a/test/support/spec_helpers/matchers/be_false.rb b/test/support/spec_helpers/matchers/be_false.rb new file mode 100644 index 0000000000..a4cef73866 --- /dev/null +++ b/test/support/spec_helpers/matchers/be_false.rb @@ -0,0 +1,45 @@ +=begin +Copyright (c) 2008 Engine Yard, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. +=end + +class BeFalseMatcher + def matches?(actual) + @actual = actual + @actual == false + end + + def failure_message + ["Expected #{@actual.inspect}", "to be false"] + end + + def negative_failure_message + ["Expected #{@actual.inspect}", "not to be false"] + end +end + +module MSpecMatchers + private def be_false + BeFalseMatcher.new + end +end From a4fc341b2bf4ff1c803fa46cf663d4b8b76413f0 Mon Sep 17 00:00:00 2001 From: Herwin Date: Sat, 18 Jan 2025 14:54:58 +0100 Subject: [PATCH 17/27] Import EqualMatcher from mspec --- spec/core/kernel/Complex_spec.rb | 2 +- test/support/spec.rb | 16 +------ test/support/spec_helpers/matchers.rb | 1 + test/support/spec_helpers/matchers/equal.rb | 51 +++++++++++++++++++++ 4 files changed, 54 insertions(+), 16 deletions(-) create mode 100644 test/support/spec_helpers/matchers/equal.rb diff --git a/spec/core/kernel/Complex_spec.rb b/spec/core/kernel/Complex_spec.rb index 9d1a5affad..4c855018f6 100644 --- a/spec/core/kernel/Complex_spec.rb +++ b/spec/core/kernel/Complex_spec.rb @@ -191,7 +191,7 @@ n2 = mock_numeric("n2") n3 = mock_numeric("n3") n4 = mock_numeric("n4") - NATFIXME 'when passed Numerics n1 and n2 and at least one responds to #real? with false', exception: ArgumentError, message: 'comparison of MockNumeric with 0 failed' do + NATFIXME 'when passed Numerics n1 and n2 and at least one responds to #real? with false', exception: SpecFailedException, message: 'comparison of MockNumeric with 0 failed' do n1.should_receive(:real?).any_number_of_times.and_return(r1) n2.should_receive(:real?).any_number_of_times.and_return(r2) n2.should_receive(:*).with(Complex(0, 1)).and_return(n3) diff --git a/test/support/spec.rb b/test/support/spec.rb index 48450959f4..0bec86af07 100644 --- a/test/support/spec.rb +++ b/test/support/spec.rb @@ -548,20 +548,6 @@ def inverted_match(subject) end end -class EqualExpectation - def initialize(other) - @other = other - end - - def match(subject) - raise SpecFailedException, subject.inspect + ' should be equal to ' + @other.inspect if !subject.equal?(@other) - end - - def inverted_match(subject) - raise SpecFailedException, subject.inspect + ' should not be equal to ' + @other.inspect if subject.equal?(@other) - end -end - # Largely taken from # https://github.com/ruby/ruby/blob/master/spec/mspec/lib/mspec/matchers/equal_element.rb#L76 class EqualElementExpectation @@ -1400,7 +1386,7 @@ def be_empty() end def equal(other) - EqualExpectation.new(other) + Expectation.new(EqualMatcher.new(other)) end def equal_element(*args) diff --git a/test/support/spec_helpers/matchers.rb b/test/support/spec_helpers/matchers.rb index 2eb7a00e7d..5d7a01ae74 100644 --- a/test/support/spec_helpers/matchers.rb +++ b/test/support/spec_helpers/matchers.rb @@ -7,3 +7,4 @@ require_relative 'matchers/be_true' require_relative 'matchers/block_caller' require_relative 'matchers/eql' +require_relative 'matchers/equal' diff --git a/test/support/spec_helpers/matchers/equal.rb b/test/support/spec_helpers/matchers/equal.rb new file mode 100644 index 0000000000..d71f119000 --- /dev/null +++ b/test/support/spec_helpers/matchers/equal.rb @@ -0,0 +1,51 @@ +=begin +Copyright (c) 2008 Engine Yard, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. +=end + +class EqualMatcher + def initialize(expected) + @expected = expected + end + + def matches?(actual) + @actual = actual + @actual.equal?(@expected) + end + + def failure_message + ["Expected #{MSpec.format(@actual)}", + "to be identical to #{MSpec.format(@expected)}"] + end + + def negative_failure_message + ["Expected #{MSpec.format(@actual)}", + "not to be identical to #{MSpec.format(@expected)}"] + end +end + +module MSpecMatchers + private def equal(expected) + EqualMatcher.new(expected) + end +end From 4ba1dd3c9b7e48800cd536c9aeff12d328eeabd1 Mon Sep 17 00:00:00 2001 From: Herwin Date: Sat, 18 Jan 2025 14:57:22 +0100 Subject: [PATCH 18/27] Import EqualElementMatcher from mspec --- test/support/spec.rb | 83 +------------- test/support/spec_helpers/matchers.rb | 1 + .../spec_helpers/matchers/equal_element.rb | 103 ++++++++++++++++++ 3 files changed, 105 insertions(+), 82 deletions(-) create mode 100644 test/support/spec_helpers/matchers/equal_element.rb diff --git a/test/support/spec.rb b/test/support/spec.rb index 0bec86af07..6b813a6079 100644 --- a/test/support/spec.rb +++ b/test/support/spec.rb @@ -548,87 +548,6 @@ def inverted_match(subject) end end -# Largely taken from -# https://github.com/ruby/ruby/blob/master/spec/mspec/lib/mspec/matchers/equal_element.rb#L76 -class EqualElementExpectation - def initialize(element, attributes = nil, content = nil, options = {}) - @element = element - @attributes = attributes - @content = content - @options = options - end - - def match(subject) - @actual = subject - unless matches? - raise SpecFailedException, - "Expected #{@actual} to be a '#{@element}' element with #{attributes_for_failure_message} and #{content_for_failure_message}" - end - end - - def inverted_match(subject) - @actual = subject - if matches? - raise SpecFailedException "Expected #{@actual} not to be a '#{@element}' element with #{attributes_for_failure_message} and #{content_for_failure_message}" - end - end - - private - - def matches? - actual = @actual - matched = true - - if @options[:not_closed] - matched &&= actual =~ /^#{Regexp.quote('<' + @element)}.*#{Regexp.quote('>' + (@content || ''))}$/ - else - matched &&= actual =~ /^#{Regexp.quote('<' + @element)}/ - matched &&= actual =~ /#{Regexp.quote('')}$/ - matched &&= actual =~ /#{Regexp.quote('>' + @content + ')/).size == 1) - else - matched &&= (actual.scan(%Q{ #{key}="#{value}"}).size == 1) - end - end - end - end - - !!matched - end - - def attributes_for_failure_message - if @attributes - if @attributes.empty? - 'no attributes' - else - @attributes.inject([]) { |memo, n| memo << %Q{#{n[0]}="#{n[1]}"} }.join(' ') - end - else - 'any attributes' - end - end - - def content_for_failure_message - if @content - if @content.empty? - 'no content' - else - "#{@content.inspect} as content" - end - else - 'any content' - end - end -end - class TrueFalseExpectation def match(subject) raise SpecFailedException, subject.inspect + ' should be true or false' unless subject == true || subject == false @@ -1390,7 +1309,7 @@ def equal(other) end def equal_element(*args) - EqualElementExpectation.new(*args) + Expectation.new(EqualElementMatcher.new(*args)) end def output(expected_stdout = nil, expected_stderr = nil) diff --git a/test/support/spec_helpers/matchers.rb b/test/support/spec_helpers/matchers.rb index 5d7a01ae74..1d79d9594a 100644 --- a/test/support/spec_helpers/matchers.rb +++ b/test/support/spec_helpers/matchers.rb @@ -8,3 +8,4 @@ require_relative 'matchers/block_caller' require_relative 'matchers/eql' require_relative 'matchers/equal' +require_relative 'matchers/equal_element' diff --git a/test/support/spec_helpers/matchers/equal_element.rb b/test/support/spec_helpers/matchers/equal_element.rb new file mode 100644 index 0000000000..86a4f33eb5 --- /dev/null +++ b/test/support/spec_helpers/matchers/equal_element.rb @@ -0,0 +1,103 @@ +=begin +Copyright (c) 2008 Engine Yard, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. +=end + +class EqualElementMatcher + def initialize(element, attributes = nil, content = nil, options = {}) + @element = element + @attributes = attributes + @content = content + @options = options + end + + def matches?(actual) + @actual = actual + + matched = true + + if @options[:not_closed] + matched &&= actual =~ /^#{Regexp.quote("<" + @element)}.*#{Regexp.quote(">" + (@content || ''))}$/ + else + matched &&= actual =~ /^#{Regexp.quote("<" + @element)}/ + matched &&= actual =~ /#{Regexp.quote("")}$/ + matched &&= actual =~ /#{Regexp.quote(">" + @content + ")/).size == 1) + else + matched &&= (actual.scan(%Q{ #{key}="#{value}"}).size == 1) + end + end + end + end + + !!matched + end + + def failure_message + ["Expected #{MSpec.format(@actual)}", + "to be a '#{@element}' element with #{attributes_for_failure_message} and #{content_for_failure_message}"] + end + + def negative_failure_message + ["Expected #{MSpec.format(@actual)}", + "not to be a '#{@element}' element with #{attributes_for_failure_message} and #{content_for_failure_message}"] + end + + def attributes_for_failure_message + if @attributes + if @attributes.empty? + "no attributes" + else + @attributes.inject([]) { |memo, n| memo << %Q{#{n[0]}="#{n[1]}"} }.join(" ") + end + else + "any attributes" + end + end + + def content_for_failure_message + if @content + if @content.empty? + "no content" + else + "#{@content.inspect} as content" + end + else + "any content" + end + end +end + +module MSpecMatchers + private def equal_element(*args) + EqualElementMatcher.new(*args) + end +end From 0fbb86d2e034383e6ee66682d78209d25b3c0df7 Mon Sep 17 00:00:00 2001 From: Herwin Date: Sat, 18 Jan 2025 15:00:05 +0100 Subject: [PATCH 19/27] Import BeTrueOrFalseMatcher from mspec --- test/support/spec.rb | 12 +---- test/support/spec_helpers/matchers.rb | 1 + .../spec_helpers/matchers/be_true_or_false.rb | 45 +++++++++++++++++++ 3 files changed, 47 insertions(+), 11 deletions(-) create mode 100644 test/support/spec_helpers/matchers/be_true_or_false.rb diff --git a/test/support/spec.rb b/test/support/spec.rb index 6b813a6079..b82dc690da 100644 --- a/test/support/spec.rb +++ b/test/support/spec.rb @@ -548,16 +548,6 @@ def inverted_match(subject) end end -class TrueFalseExpectation - def match(subject) - raise SpecFailedException, subject.inspect + ' should be true or false' unless subject == true || subject == false - end - - def inverted_match(subject) - raise SpecFailedException, subject.inspect + ' should not be true or false' if subject == true || subject == false - end -end - class BeCloseExpectation def initialize(target, tolerance = TOLERANCE) @target = target @@ -1269,7 +1259,7 @@ def be_false end def be_true_or_false - TrueFalseExpectation.new() + Expectation.new(BeTrueOrFalseMatcher.new) end def be_close(target, tolerance) diff --git a/test/support/spec_helpers/matchers.rb b/test/support/spec_helpers/matchers.rb index 1d79d9594a..ed5c700f7b 100644 --- a/test/support/spec_helpers/matchers.rb +++ b/test/support/spec_helpers/matchers.rb @@ -5,6 +5,7 @@ require_relative 'matchers/be_kind_of' require_relative 'matchers/be_nil' require_relative 'matchers/be_true' +require_relative 'matchers/be_true_or_false' require_relative 'matchers/block_caller' require_relative 'matchers/eql' require_relative 'matchers/equal' diff --git a/test/support/spec_helpers/matchers/be_true_or_false.rb b/test/support/spec_helpers/matchers/be_true_or_false.rb new file mode 100644 index 0000000000..727b15dbd1 --- /dev/null +++ b/test/support/spec_helpers/matchers/be_true_or_false.rb @@ -0,0 +1,45 @@ +=begin +Copyright (c) 2008 Engine Yard, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. +=end + +class BeTrueOrFalseMatcher + def matches?(actual) + @actual = actual + @actual == true || @actual == false + end + + def failure_message + ["Expected #{@actual.inspect}", "to be true or false"] + end + + def negative_failure_message + ["Expected #{@actual.inspect}", "not to be true or false"] + end +end + +module MSpecMatchers + private def be_true_or_false + BeTrueOrFalseMatcher.new + end +end From 3d6c3ecd91e177a9e9ab8e0849dcd190d5d4f7c2 Mon Sep 17 00:00:00 2001 From: Herwin Date: Sat, 18 Jan 2025 15:02:58 +0100 Subject: [PATCH 20/27] Import BeCloseMatcher from mspec --- test/support/spec.rb | 24 +-------- test/support/spec_helpers/matchers.rb | 1 + .../support/spec_helpers/matchers/be_close.rb | 54 +++++++++++++++++++ 3 files changed, 56 insertions(+), 23 deletions(-) create mode 100644 test/support/spec_helpers/matchers/be_close.rb diff --git a/test/support/spec.rb b/test/support/spec.rb index b82dc690da..8932684785 100644 --- a/test/support/spec.rb +++ b/test/support/spec.rb @@ -22,9 +22,6 @@ class NatalieFixMeException < SpecFailedException class UnknownFormatterException < StandardError end -TOLERANCE = 0.00003 -TIME_TOLERANCE = 20.0 - FORMATTERS = %w[default yaml spec] @formatter_name = ARGV[ARGV.index('-f') + 1] if ARGV.include?('-f') @@ -548,25 +545,6 @@ def inverted_match(subject) end end -class BeCloseExpectation - def initialize(target, tolerance = TOLERANCE) - @target = target - @tolerance = tolerance - end - - def match(subject) - if (subject - @target).abs > @tolerance - raise SpecFailedException, "#{subject.inspect} should be within #{@tolerance} of #{@target}" - end - end - - def inverted_match(subject) - if (subject - @target).abs <= @tolerance - raise SpecFailedException, "#{subject.inspect} should not be within #{@tolerance} of #{@target}" - end - end -end - class BeComputedByExpectation def initialize(method, args) @method = method @@ -1263,7 +1241,7 @@ def be_true_or_false end def be_close(target, tolerance) - BeCloseExpectation.new(target, tolerance) + Expectation.new(BeCloseMatcher.new(target, tolerance)) end def be_computed_by(method, *args) diff --git a/test/support/spec_helpers/matchers.rb b/test/support/spec_helpers/matchers.rb index ed5c700f7b..ec20a6caa2 100644 --- a/test/support/spec_helpers/matchers.rb +++ b/test/support/spec_helpers/matchers.rb @@ -1,5 +1,6 @@ require_relative 'matchers/be_an_instance_of' require_relative 'matchers/be_ancestor_of' +require_relative 'matchers/be_close' require_relative 'matchers/be_empty' require_relative 'matchers/be_false' require_relative 'matchers/be_kind_of' diff --git a/test/support/spec_helpers/matchers/be_close.rb b/test/support/spec_helpers/matchers/be_close.rb new file mode 100644 index 0000000000..130b5ff735 --- /dev/null +++ b/test/support/spec_helpers/matchers/be_close.rb @@ -0,0 +1,54 @@ +=begin +Copyright (c) 2008 Engine Yard, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. +=end + +TOLERANCE = 0.00003 unless Object.const_defined?(:TOLERANCE) +# To account for GC, context switches, other processes, load, etc. +TIME_TOLERANCE = 20.0 unless Object.const_defined?(:TIME_TOLERANCE) + +class BeCloseMatcher + def initialize(expected, tolerance) + @expected = expected + @tolerance = tolerance + end + + def matches?(actual) + @actual = actual + (@actual - @expected).abs <= @tolerance + end + + def failure_message + ["Expected #{@actual}", "to be within #{@expected} +/- #{@tolerance}"] + end + + def negative_failure_message + ["Expected #{@actual}", "not to be within #{@expected} +/- #{@tolerance}"] + end +end + +module MSpecMatchers + private def be_close(expected, tolerance) + BeCloseMatcher.new(expected, tolerance) + end +end From 973580bf2ee7c3b36d8cbe2aba801dde9b149fa7 Mon Sep 17 00:00:00 2001 From: Herwin Date: Sat, 18 Jan 2025 15:04:42 +0100 Subject: [PATCH 21/27] Import BeComputedByMatcher from mspec --- test/support/spec.rb | 46 +------------- test/support/spec_helpers/matchers.rb | 1 + .../spec_helpers/matchers/be_computed_by.rb | 62 +++++++++++++++++++ 3 files changed, 64 insertions(+), 45 deletions(-) create mode 100644 test/support/spec_helpers/matchers/be_computed_by.rb diff --git a/test/support/spec.rb b/test/support/spec.rb index 8932684785..07e93c40b9 100644 --- a/test/support/spec.rb +++ b/test/support/spec.rb @@ -545,50 +545,6 @@ def inverted_match(subject) end end -class BeComputedByExpectation - def initialize(method, args) - @method = method - @args = args - end - - def match(subject) - subject.each do |(target, *args, expected)| - actual = target.send(@method, *(@args + args)) - if actual != expected - expected_bits = - if expected.methods.include?(:bytes) - expected.bytes.map { |b| lzpad(b.to_s(2), 8) }.join(' ') - else - expected.inspect - end - - actual_bits = - actual.methods.include?(:bytes) ? actual.bytes.map { |b| lzpad(b.to_s(2), 8) }.join(' ') : actual.inspect - - raise SpecFailedException, "#{target.inspect} should compute to #{expected_bits}, but it was #{actual_bits}" - end - end - end - - def inverted_match(subject) - subject.each do |target, expected| - actual = target.send(@method, *@args) - if actual == expected - expected_bits = expected.bytes.map { |b| lzpad(b.to_s(2), 8) }.join(' ') - raise SpecFailedException, "#{target.inspect} should not compute to #{expected_bits}" - end - end - end - - private - - # TODO: Add % formatting to Natalie :-) - def lzpad(str, length) - str = '0' + str until str.length == length - str - end -end - class BeNanExpectation def match(subject) raise SpecFailedException, "#{subject.inspect} should be NaN" if !subject.nan? @@ -1245,7 +1201,7 @@ def be_close(target, tolerance) end def be_computed_by(method, *args) - BeComputedByExpectation.new(method, args) + Expectation.new(BeComputedByMatcher.new(method, *args)) end def be_kind_of(klass) diff --git a/test/support/spec_helpers/matchers.rb b/test/support/spec_helpers/matchers.rb index ec20a6caa2..fd0b2b10de 100644 --- a/test/support/spec_helpers/matchers.rb +++ b/test/support/spec_helpers/matchers.rb @@ -1,6 +1,7 @@ require_relative 'matchers/be_an_instance_of' require_relative 'matchers/be_ancestor_of' require_relative 'matchers/be_close' +require_relative 'matchers/be_computed_by' require_relative 'matchers/be_empty' require_relative 'matchers/be_false' require_relative 'matchers/be_kind_of' diff --git a/test/support/spec_helpers/matchers/be_computed_by.rb b/test/support/spec_helpers/matchers/be_computed_by.rb new file mode 100644 index 0000000000..9907d03e75 --- /dev/null +++ b/test/support/spec_helpers/matchers/be_computed_by.rb @@ -0,0 +1,62 @@ +=begin +Copyright (c) 2008 Engine Yard, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. +=end + +class BeComputedByMatcher + def initialize(sym, *args) + @method = sym + @args = args + end + + def matches?(array) + array.each do |line| + @receiver = line.shift + @value = line.pop + @arguments = line + @arguments += @args + @actual = @receiver.send(@method, *@arguments) + return false unless @actual == @value + end + + return true + end + + def method_call + method_call = "#{@receiver.inspect}.#{@method}" + unless @arguments.empty? + method_call = "#{method_call} from #{@arguments.map { |x| x.inspect }.join(", ")}" + end + method_call + end + + def failure_message + ["Expected #{@value.inspect}", "to be computed by #{method_call} (computed #{@actual.inspect} instead)"] + end +end + +module MSpecMatchers + private def be_computed_by(sym, *args) + BeComputedByMatcher.new(sym, *args) + end +end From 55ea37c17d223726bacc1a666bea5f1612767782 Mon Sep 17 00:00:00 2001 From: Herwin Date: Sat, 18 Jan 2025 15:06:16 +0100 Subject: [PATCH 22/27] Import BeNanExpectation from mspec --- test/support/spec.rb | 12 +----- test/support/spec_helpers/matchers.rb | 1 + test/support/spec_helpers/matchers/be_nan.rb | 45 ++++++++++++++++++++ 3 files changed, 47 insertions(+), 11 deletions(-) create mode 100644 test/support/spec_helpers/matchers/be_nan.rb diff --git a/test/support/spec.rb b/test/support/spec.rb index 07e93c40b9..35f66c6f80 100644 --- a/test/support/spec.rb +++ b/test/support/spec.rb @@ -545,16 +545,6 @@ def inverted_match(subject) end end -class BeNanExpectation - def match(subject) - raise SpecFailedException, "#{subject.inspect} should be NaN" if !subject.nan? - end - - def inverted_match(subject) - raise SpecFailedException, "#{subject.inspect} should not be NaN" if subject.nan? - end -end - class BeInfinityExpectation def initialize(sign_of_infinity) @sign_of_infinity = sign_of_infinity @@ -1165,7 +1155,7 @@ def be_nil end def be_nan - BeNanExpectation.new + Expectation.new(BeNaNMatcher.new) end def be_negative_zero diff --git a/test/support/spec_helpers/matchers.rb b/test/support/spec_helpers/matchers.rb index fd0b2b10de..d16694c19d 100644 --- a/test/support/spec_helpers/matchers.rb +++ b/test/support/spec_helpers/matchers.rb @@ -5,6 +5,7 @@ require_relative 'matchers/be_empty' require_relative 'matchers/be_false' require_relative 'matchers/be_kind_of' +require_relative 'matchers/be_nan' require_relative 'matchers/be_nil' require_relative 'matchers/be_true' require_relative 'matchers/be_true_or_false' diff --git a/test/support/spec_helpers/matchers/be_nan.rb b/test/support/spec_helpers/matchers/be_nan.rb new file mode 100644 index 0000000000..196a861c05 --- /dev/null +++ b/test/support/spec_helpers/matchers/be_nan.rb @@ -0,0 +1,45 @@ +=begin +Copyright (c) 2008 Engine Yard, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. +=end + +class BeNaNMatcher + def matches?(actual) + @actual = actual + @actual.kind_of?(Float) && @actual.nan? + end + + def failure_message + ["Expected #{@actual}", "to be NaN"] + end + + def negative_failure_message + ["Expected #{@actual}", "not to be NaN"] + end +end + +module MSpecMatchers + private def be_nan + BeNaNMatcher.new + end +end From 4a29807a8b70f6fdabd692b2bc8924028c6d4ae5 Mon Sep 17 00:00:00 2001 From: Herwin Date: Sat, 18 Jan 2025 15:08:21 +0100 Subject: [PATCH 23/27] Import InfinityMatcher from mspec --- test/support/spec.rb | 26 +-------- test/support/spec_helpers/matchers.rb | 1 + .../support/spec_helpers/matchers/infinity.rb | 53 +++++++++++++++++++ 3 files changed, 56 insertions(+), 24 deletions(-) create mode 100644 test/support/spec_helpers/matchers/infinity.rb diff --git a/test/support/spec.rb b/test/support/spec.rb index 35f66c6f80..d2bad0cad0 100644 --- a/test/support/spec.rb +++ b/test/support/spec.rb @@ -545,28 +545,6 @@ def inverted_match(subject) end end -class BeInfinityExpectation - def initialize(sign_of_infinity) - @sign_of_infinity = sign_of_infinity - end - - def match(subject) - unless expected_infinity?(subject) - raise SpecFailedException, "#{subject.inspect} should be #{'-' if negative?}Infinity" - end - end - - private - - def expected_infinity?(subject) - subject.kind_of?(Float) && subject.infinite? == @sign_of_infinity - end - - def negative? - @sign_of_infinity == -1 - end -end - class OutputExpectation def initialize(expected_out, expected_err) @expected_out = expected_out @@ -1167,11 +1145,11 @@ def be_positive_zero end def be_positive_infinity - BeInfinityExpectation.new(1) + Expectation.new(InfinityMatcher.new(1)) end def be_negative_infinity - BeInfinityExpectation.new(-1) + Expectation.new(InfinityMatcher.new(-1)) end def be_true diff --git a/test/support/spec_helpers/matchers.rb b/test/support/spec_helpers/matchers.rb index d16694c19d..563fb04fd1 100644 --- a/test/support/spec_helpers/matchers.rb +++ b/test/support/spec_helpers/matchers.rb @@ -13,3 +13,4 @@ require_relative 'matchers/eql' require_relative 'matchers/equal' require_relative 'matchers/equal_element' +require_relative 'matchers/infinity' diff --git a/test/support/spec_helpers/matchers/infinity.rb b/test/support/spec_helpers/matchers/infinity.rb new file mode 100644 index 0000000000..3dd9b8b6d5 --- /dev/null +++ b/test/support/spec_helpers/matchers/infinity.rb @@ -0,0 +1,53 @@ +=begin +Copyright (c) 2008 Engine Yard, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. +=end + +class InfinityMatcher + def initialize(expected_sign) + @expected_sign = expected_sign + end + + def matches?(actual) + @actual = actual + @actual.kind_of?(Float) && @actual.infinite? == @expected_sign + end + + def failure_message + ["Expected #{@actual}", "to be #{"-" if @expected_sign == -1}Infinity"] + end + + def negative_failure_message + ["Expected #{@actual}", "not to be #{"-" if @expected_sign == -1}Infinity"] + end +end + +module MSpecMatchers + private def be_positive_infinity + InfinityMatcher.new(1) + end + + private def be_negative_infinity + InfinityMatcher.new(-1) + end +end From 29a595b8495de863d4075c55e4af531b7a2a0dc9 Mon Sep 17 00:00:00 2001 From: Herwin Date: Sat, 18 Jan 2025 16:18:37 +0100 Subject: [PATCH 24/27] Draft: A little bit better --- test/support/spec_utils/format.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/support/spec_utils/format.rb b/test/support/spec_utils/format.rb index d9e40535c1..eb1f32b8d8 100644 --- a/test/support/spec_utils/format.rb +++ b/test/support/spec_utils/format.rb @@ -23,6 +23,14 @@ OTHER DEALINGS IN THE SOFTWARE. =end +unless Object.new.respond_to?(:pretty_inspect) + module Kernel + def pretty_inspect + inspect + end + end +end + module MSpec def self.format(obj) if String === obj and obj.include?("\n") From f639bdeb3221a2d208aa7004c92f5a4ed3d840c6 Mon Sep 17 00:00:00 2001 From: Herwin Date: Mon, 21 Apr 2025 17:53:41 +0200 Subject: [PATCH 25/27] Ignore matchers in formatting They're imported from a foreign repository, we should keep the code equal to the upstraem version. --- .streerc | 1 + 1 file changed, 1 insertion(+) diff --git a/.streerc b/.streerc index 8fa44c0915..e3084046cb 100644 --- a/.streerc +++ b/.streerc @@ -25,5 +25,6 @@ --ignore-files=lib/uri* --ignore-files=spec/* --ignore-files=test/support/version.rb* +--ignore-files=test/support/spec_helpers/matchers/* --plugins=plugin/trailing_comma,plugin/single_quotes,plugin/disable_auto_ternary From 7ecbf7a7d7c773f710c1b4f54129c3c64be47a40 Mon Sep 17 00:00:00 2001 From: Herwin Date: Mon, 19 May 2025 20:12:05 +0200 Subject: [PATCH 26/27] Convert OutputExpectation to OutputMatcher Keep our code for now, we're not fully compatible with the mspec version. --- test/support/spec.rb | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/test/support/spec.rb b/test/support/spec.rb index d2bad0cad0..2a4858cc02 100644 --- a/test/support/spec.rb +++ b/test/support/spec.rb @@ -545,29 +545,30 @@ def inverted_match(subject) end end -class OutputExpectation +class OutputMatcher def initialize(expected_out, expected_err) @expected_out = expected_out @expected_err = expected_err end - def match(subject) - actual_out, actual_err = capture_output { subject.call } - if @expected_out && !(@expected_out === actual_out) - raise SpecFailedException, - "expected $stdout to get #{@expected_out.inspect} but it got #{actual_out.inspect} instead" - elsif @expected_err && !(@expected_err === actual_err) - raise SpecFailedException, - "expected $stderr to get #{@expected_err.inspect} but it got #{actual_err.inspect} instead" + def matches?(subject) + @actual_out, @actual_err = capture_output { subject.call } + (@expected_out && (@expected_out === @actual_out)) || (@expected_err && (@expected_err === actual_err)) + end + + def failure_message + if @expected_out && !(@expected_out === @actual_out) + ["expected $stdout to get #{@expected_out.inspect}", "but it got #{actual[$stdout].inspect} instead"] + elsif @expected_err && !(@expected_err === @actual_err) + ["expected $stderr to get #{@expected_err.inspect}", "but it got #{actual[$stderr].inspect} instead"] end end - def inverted_match(subject) - actual_out, actual_err = capture_output { subject.call } - if @expected_out && @expected_out === actual_out - raise SpecFailedException, "expected $stdout not to get #{@expected_out.inspect} but it did" - elsif @expected_err && @expected_err === actual_err - raise SpecFailedException, "expected $stderr not to get #{@expected_err.inspect} but it did" + def negative_failure_message + if @expected_out && @expected_out === @actual_out + ["expected $stdout not to get #{@expected_out.inspect}", "but it did"] + elsif @expected_err && @expected_err === @actual_err + ["expected $stderr not to get #{@expected_err.inspect}", "but it did"] end end @@ -1205,12 +1206,12 @@ def equal_element(*args) end def output(expected_stdout = nil, expected_stderr = nil) - OutputExpectation.new(expected_stdout, expected_stderr) + Expectation.new(OutputMatcher.new(expected_stdout, expected_stderr)) end def output_to_fd(expected, fd = STDOUT) - return OutputExpectation.new(expected, nil) if fd == $stdout - return OutputExpectation.new(nil, expected) if fd == $stderr + return Expectation.new(OutputMatcher.new(expected, nil)) if fd == $stdout + return Expectation.new(OutputMatcher.new(nil, expected)) if fd == $stderr raise NotImplementedError, "Invalid fd #{fd.inspect}" end From fd5fffa81438c7c13b5c2dba0fb6d465dbae92af Mon Sep 17 00:00:00 2001 From: Herwin Date: Mon, 19 May 2025 20:20:09 +0200 Subject: [PATCH 27/27] Convert YAMLExpectation to YAMLMatcher Keep our code for now, we're not fully compatible with the mspec version. --- test/support/spec.rb | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/test/support/spec.rb b/test/support/spec.rb index 2a4858cc02..cced51c8cb 100644 --- a/test/support/spec.rb +++ b/test/support/spec.rb @@ -720,21 +720,22 @@ def run(subject) end end -class YAMLExpectation +class YAMLMatcher def initialize(expected) @expected = expected end - def match(subject) - if prepare_yaml(subject) != @expected - raise SpecFailedException, "#{subject.inspect} should be equal to #{@expected.inspect}" - end + def matches?(subject) + @subject = prepare_yaml(subject) + @subject == @expected end - def inverted_match(subject) - if prepare_yaml(subject) == @expected - raise SpecFailedException, "#{subject.inspect} should not be equal to #{@expected.inspect}" - end + def failure_message + ["#{@subject.inspect}", "should be equal to #{@expected.inspect}"] + end + + def negative_failure_message + ["#{@subject.inspect}", "should not be equal to #{@expected.inspect}"] end private @@ -1224,7 +1225,7 @@ def complain(message = nil, kwargs = {}, verbose: false) end def match_yaml(expected) - YAMLExpectation.new(expected) + Expectation.new(YAMLMatcher.new(expected)) end def should_receive(message)