From 3ebb3c3b119045962608a464f3fda1888f081d5f Mon Sep 17 00:00:00 2001 From: Michael Grosser Date: Sun, 18 Jun 2023 11:12:02 -0700 Subject: [PATCH] support before :all and block after :all + around :all --- CHANGELOG.md | 2 ++ README.md | 1 + Rakefile | 5 +++- lib/maxitest/autorun.rb | 1 + lib/maxitest/hook_all.rb | 29 +++++++++++++++++++++ lib/maxitest/let_all.rb | 1 + lib/maxitest/vendor/around.rb | 1 + spec/cases/around.rb | 2 +- spec/cases/hook_all.rb | 47 +++++++++++++++++++++++++++++++++++ spec/maxitest_spec.rb | 37 +++++++++++++++++++++++---- 10 files changed, 119 insertions(+), 7 deletions(-) create mode 100644 lib/maxitest/hook_all.rb create mode 100644 spec/cases/hook_all.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index d13acb7..8b8ac87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,6 @@ # Next +- support `before :all` +- block invalid `after :all` and `around :all` # v5.0.0 - add minitest 5.14 support diff --git a/README.md b/README.md index bfcbd69..2872702 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ Features - **Ctrl+c** stops tests and prints failures - **pastable rerun snippet** for failures (disabled/integrated on rails 5) - multiple before & after blocks + - `before :all` blocks - **around** blocks `around { |t| Dir.chdir(...) { t.call } }` - **red-green** output (disabled/integrated on rails 5) - `mtest` executable to **run by line number** and by folder (disabled/integrated on rails 5) diff --git a/Rakefile b/Rakefile index a02cee4..f4a5b18 100644 --- a/Rakefile +++ b/Rakefile @@ -31,9 +31,12 @@ task :update do # replace ruby with mtest raise unless code.sub!(%{output = "ruby \#{file} -l \#{line}"}, %{output = "mtest \#{file}:\#{line}"}) elsif url.end_with?('/around/spec.rb') - # do not fail with resume for nill class when before was never called + # do not fail with resume for nil class when before was never called # for example when putting <% raise %> into a fixture file raise unless code.sub!(%{fib.resume unless fib == :failed}, %{fib.resume if fib && fib != :failed}) + + # make `after :all` blow up to avoid confusion + raise unless code.sub!(%{fib = nil}, %{raise ArgumentError, "only :each or no argument is supported" if args != [] && args != [:each]\n fib = nil}) elsif url.end_with?('/rg_plugin.rb') # support disabling/enabling colors # https://github.com/blowmage/minitest-rg/pull/15 diff --git a/lib/maxitest/autorun.rb b/lib/maxitest/autorun.rb index d0caeee..0a9fa50 100644 --- a/lib/maxitest/autorun.rb +++ b/lib/maxitest/autorun.rb @@ -4,6 +4,7 @@ require "maxitest/trap" require "maxitest/let_bang" require "maxitest/let_all" +require "maxitest/hook_all" require "maxitest/pending" require "maxitest/xit" require "maxitest/static_class_order" diff --git a/lib/maxitest/hook_all.rb b/lib/maxitest/hook_all.rb new file mode 100644 index 0000000..e7ab5c3 --- /dev/null +++ b/lib/maxitest/hook_all.rb @@ -0,0 +1,29 @@ +module Maxitest + class << self + attr_accessor :hook_all_counter + end +end +Maxitest.hook_all_counter = 0 + +module Maxitest + module HookAll + [:before, :after].each do |hook| + # minitest discards the type argument, so we are not sending it along + define_method(hook) do |type = :each, &block| + case type + when :each then super(&block) + when :all + raise ArgumentError, ":all is not supported in after" if hook == :after + c = (Maxitest.hook_all_counter += 1) + callback = :"maxitest_hook_all_#{c}" + let_all(callback, &block) + super() { send callback } + else + raise ArgumentError, "only :each and :all are supported" + end + end + end + end +end + +Minitest::Spec::DSL.prepend(Maxitest::HookAll) diff --git a/lib/maxitest/let_all.rb b/lib/maxitest/let_all.rb index c1d113f..e7f823c 100644 --- a/lib/maxitest/let_all.rb +++ b/lib/maxitest/let_all.rb @@ -9,6 +9,7 @@ def let_all(name, &block) cache.first end end + def self.included(base) base.extend(self) end diff --git a/lib/maxitest/vendor/around.rb b/lib/maxitest/vendor/around.rb index 18b4db8..bfadf04 100644 --- a/lib/maxitest/vendor/around.rb +++ b/lib/maxitest/vendor/around.rb @@ -57,6 +57,7 @@ def run(*args) # - execute test # - resume fiber to execute last part def around(*args, &block) + raise ArgumentError, "only :each or no argument is supported" if args != [] && args != [:each] fib = nil before do fib = Fiber.new do |context, resume| diff --git a/spec/cases/around.rb b/spec/cases/around.rb index c67ce9f..f96b0b7 100644 --- a/spec/cases/around.rb +++ b/spec/cases/around.rb @@ -4,7 +4,7 @@ let(:calls) { [] } before { calls << 1 } - around { |test| calls << 2; test.call } + around((ENV["HOOK_TYPE"] || "each").to_sym) { |test| calls << 2; test.call } around { |test| calls << 3; test.call } after { calls.must_equal [1,2,3,4] } after { calls << 4 } diff --git a/spec/cases/hook_all.rb b/spec/cases/hook_all.rb new file mode 100644 index 0000000..78797ce --- /dev/null +++ b/spec/cases/hook_all.rb @@ -0,0 +1,47 @@ +require "./spec/cases/helper" + +hook_method = (ENV["HOOK_METHOD"] || "before").to_sym +hook_type = (ENV["HOOK_TYPE"] || "all").to_sym + +# need this globally or classes don't sort +r = Minitest::Runnable.runnables +def r.shuffle + self +end + +# needed or minitest <=5.15 +def r.reject + replace super +end + +describe 2 do + order_dependent! + + send hook_method, hook_type do + puts "ALL" + end + + it "works" do + puts "T1" + end + + describe "subclass" do + order_dependent! + + send hook_method, hook_type do + puts "ALL-SUB" + end + + it "still works" do + puts "TS1" + end + + it "yes it does" do + puts "TS2" + end + end + + it "works after subclass" do + puts "T2" + end +end diff --git a/spec/maxitest_spec.rb b/spec/maxitest_spec.rb index ee6a991..d45580b 100644 --- a/spec/maxitest_spec.rb +++ b/spec/maxitest_spec.rb @@ -19,10 +19,6 @@ run_cmd("ruby spec/cases/plain.rb").should include "\n2 runs, 2 assertions" end - it "supports around" do - run_cmd("ruby spec/cases/around.rb").should include "\n2 runs, 3 assertions" - end - it "supports context" do run_cmd("ruby spec/cases/context.rb").should include "\n2 runs, 2 assertions" end @@ -75,6 +71,38 @@ output_in.should include 'spec/cases/raise.rb:11' end + describe "before/after/around" do + it "works" do + out = run_cmd("ruby spec/cases/hook_all.rb") + out.should include "Running:\n\nALL\nT1\n.T2\n.ALL-SUB\nTS1\n.TS2\n.\n\nFinished" + end + + it "fails when using unsupported type" do + with_env HOOK_TYPE: "foo" do + out = run_cmd("ruby spec/cases/hook_all.rb", fail: true) + out.should include "only :each and :all are supported (ArgumentError)" + end + end + + it "informs user about missing after :all" do + with_env HOOK_METHOD: "after" do + out = run_cmd("ruby spec/cases/hook_all.rb --seed 123", fail: true) + out.should include ":all is not supported in after (ArgumentError)" + end + end + + it "supports around" do + run_cmd("ruby spec/cases/around.rb").should include "\n2 runs, 3 assertions" + end + + it "informs user about missing around :all" do + with_env HOOK_TYPE: "all" do + out = run_cmd("ruby spec/cases/around.rb", fail: true) + out.should include "only :each or no argument is supported (ArgumentError)" + end + end + end + describe "color" do it "is color-less without tty" do run_cmd("ruby spec/cases/plain.rb").should include "\n2 runs, 2 assertions" @@ -315,7 +343,6 @@ def run_cmd(command, options = {}) stdout.strip end - # copied from https://github.com/grosser/parallel/blob/master/spec/parallel_spec.rb#L10-L15 def kill_process_with_name(file, signal='INT') running_processes = `ps -f`.split("\n").map{ |line| line.split(/\s+/) }