[DRE-commits] [ruby-guard] 10/13: support test
Daisuke Higuchi
dai at moszumanska.debian.org
Tue Nov 28 08:10:09 UTC 2017
This is an automated email from the git hooks/post-receive script.
dai pushed a commit to branch master
in repository ruby-guard.
commit 566f7cdeff57c2e2d23e7cce085e08ba59bc197c
Author: HIGUCHI Daisuke (VDR dai) <dai at debian.org>
Date: Tue Nov 28 16:57:54 2017 +0900
support test
---
debian/control | 1 +
debian/patches/add_specs.patch | 7722 ++++++++++++++++++++++++++++++++
debian/patches/disable_simplecov.patch | 19 +
debian/patches/pending_examples.patch | 27 +
debian/patches/series | 4 +
debian/ruby-tests.rake | 7 +
debian/rules | 3 +
7 files changed, 7783 insertions(+)
diff --git a/debian/control b/debian/control
index b31ee6b..a2d9220 100644
--- a/debian/control
+++ b/debian/control
@@ -5,6 +5,7 @@ Maintainer: Debian Ruby Extras Maintainers <pkg-ruby-extras-maintainers at lists.al
Uploaders: HIGUCHI Daisuke (VDR dai) <dai at debian.org>
Build-Depends: debhelper (>= 10~),
gem2deb,
+ ruby-rspec-core,
pry (>= 0.9.12),
ruby-formatador (>= 0.2.4),
ruby-listen (<< 4.0),
diff --git a/debian/patches/add_specs.patch b/debian/patches/add_specs.patch
new file mode 100644
index 0000000..c2d03c3
--- /dev/null
+++ b/debian/patches/add_specs.patch
@@ -0,0 +1,7722 @@
+Description: add specs
+Author: HIGUCHI Daisuke (VDR dai) <dai at debian.org>
+Origin: upstream
+Forwarded: not-needed
+Last-Update: 2017-11-28
+
+Index: ruby-guard/spec/.gitignore
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/.gitignore
+@@ -0,0 +1 @@
++/fake-home/
+Index: ruby-guard/spec/lib/guard/bin_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/bin_spec.rb
+@@ -0,0 +1,137 @@
++path = File.expand_path("../../../../bin/guard", __FILE__)
++load path
++
++RSpec.describe GuardReloader do
++ let(:config) { instance_double(described_class::Config) }
++
++ subject { described_class.new(config) }
++
++ let(:guard_core_path) { "/home/me/.rvm/gems/ruby-2.2.2/bin/_guard-core" }
++
++ before do
++ allow(described_class::Config).to receive(:new).and_return(config)
++
++ allow(config).to receive(:current_bundler_gemfile).
++ and_return(bundle_gemfile_env)
++
++ allow(config).to receive(:using_bundler?).and_return(bundle_gemfile_env)
++ allow(config).to receive(:guard_core_path).and_return(guard_core_path)
++
++ allow(config).to receive(:program_arguments).and_return(%w(foo bar baz))
++ allow(config).to receive(:using_rubygems?).and_return(rubygems_deps_env)
++ allow(config).to receive(:program_path).and_return(program_path)
++ end
++
++ let(:program_path) { Pathname("/home/me/.rvm/gems/ruby-2.2.2/bin/guard") }
++ let(:rubygems_deps_env) { nil } # or any gemfile path
++
++ context "when running with bundler" do
++ let(:bundle_gemfile_env) { "./Gemfile" }
++
++ it "sets up bundler" do
++ expect(config).to receive(:setup_bundler)
++ subject.setup
++ end
++ end
++
++ context "when not running with bundler" do
++ let(:bundle_gemfile_env) { nil }
++
++ context "when running with rubygems_gemdeps" do
++ let(:rubygems_deps_env) { "-" } # or any gemfile path
++
++ it "sets up rubygems" do
++ expect(config).to receive(:setup_rubygems_for_deps)
++ subject.setup
++ end
++ end
++
++ context "when not running with rubygems_gemdeps" do
++ let(:rubygems_deps_env) { nil }
++
++ context "when running as binstub" do
++ let(:program_path) { Pathname("/my/project/bin/guard") }
++
++ context "when the relative Gemfile exists" do
++ before do
++ allow(config).to receive(:exist?).
++ with(Pathname("/my/project/Gemfile")).and_return(true)
++
++ allow(config).to receive(:setup_bundler)
++ allow(config).to receive(:setup_bundler_env)
++ end
++
++ it "sets up bundler" do
++ expect(config).to receive(:setup_bundler)
++ subject.setup
++ end
++
++ it "sets the Gemfile" do
++ expect(config).to receive(:setup_bundler_env).
++ with("/my/project/Gemfile")
++ subject.setup
++ end
++ end
++
++ context "when the relative Gemfile does not exist" do
++ before do
++ allow(config).to receive(:exist?).
++ with(Pathname("/my/project/Gemfile")).and_return(false)
++
++ allow(config).to receive(:exist?).with(Pathname("Gemfile")).
++ and_return(false)
++ end
++
++ it "does not setup bundler" do
++ subject.setup
++ end
++
++ it "does not setup rubygems" do
++ subject.setup
++ end
++
++ it "shows no warning" do
++ expect(STDERR).to_not receive(:puts)
++ subject.setup
++ end
++ end
++ end
++
++ context "when not run as binstub" do
++ let(:program_path) do
++ Pathname("/home/me/.rvm/gems/ruby-2.2.2/bin/guard")
++ end
++
++ before do
++ allow(config).to receive(:exist?).with(
++ Pathname("/home/me/.rvm/gems/ruby-2.2.2/Gemfile")
++ ).and_return(false)
++ end
++
++ context "when Gemfile exists" do
++ before do
++ allow(config).to receive(:exist?).with(Pathname("Gemfile")).
++ and_return(true)
++ end
++
++ it "shows a warning" do
++ expect(STDERR).to receive(:puts).with(/Warning: you have a Gemfile/)
++ subject.setup
++ end
++ end
++
++ context "when no Gemfile exists" do
++ before do
++ allow(config).to receive(:exist?).with(Pathname("Gemfile")).
++ and_return(false)
++ end
++
++ it "shows no warning" do
++ expect(STDERR).to_not receive(:puts)
++ subject.setup
++ end
++ end
++ end
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/cli/environments/bundler_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/cli/environments/bundler_spec.rb
+@@ -0,0 +1,60 @@
++require "guard/cli/environments/bundler"
++
++# TODO: instead of shared examples, use have_received if possible
++RSpec.shared_examples "avoids Bundler warning" do
++ it "does not show the Bundler warning" do
++ expect(Guard::UI).to_not have_received(:info).with(/Guard here!/)
++ end
++end
++
++RSpec.shared_examples "shows Bundler warning" do
++ it "shows the Bundler warning" do
++ expect(Guard::UI).to have_received(:info).with(/Guard here!/)
++ end
++end
++
++RSpec.describe Guard::Cli::Environments::Bundler do
++ describe "#verify" do
++ let(:gemdeps) { nil }
++ let(:gemfile) { nil }
++
++ before do
++ allow(ENV).to receive(:[]).with("BUNDLE_GEMFILE").and_return(gemfile)
++ allow(ENV).to receive(:[]).with("RUBYGEMS_GEMDEPS").and_return(gemdeps)
++
++ allow(File).to receive(:exist?).with("Gemfile").
++ and_return(gemfile_present)
++
++ subject.verify
++ end
++
++ context "without an existing Gemfile" do
++ let(:gemfile_present) { false }
++ include_examples "avoids Bundler warning"
++ end
++
++ context "with an existing Gemfile" do
++ let(:gemfile_present) { true }
++
++ context "with Bundler" do
++ let(:gemdeps) { nil }
++ let(:gemfile) { "Gemfile" }
++ include_examples "avoids Bundler warning"
++ end
++
++ context "without Bundler" do
++ let(:gemfile) { nil }
++
++ context "with Rubygems Gemfile autodetection or custom Gemfile" do
++ let(:gemdeps) { "-" }
++ include_examples "avoids Bundler warning"
++ end
++
++ context "without Rubygems Gemfile handling" do
++ let(:gemdeps) { nil }
++ include_examples "shows Bundler warning"
++ end
++ end
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/cli/environments/evaluate_only_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/cli/environments/evaluate_only_spec.rb
+@@ -0,0 +1,73 @@
++require "guard/cli/environments/evaluate_only"
++
++RSpec.describe Guard::Cli::Environments::EvaluateOnly do
++ subject { described_class.new(options) }
++ let(:options) { double("options") }
++
++ describe "#evaluate" do
++ let(:evaluator) { instance_double("Guard::Guardfile::Evaluator") }
++ let(:state) { instance_double("Guard::Internals::State") }
++ let(:session) { instance_double("Guard::Internals::Session") }
++
++ before do
++ allow(Guard::Guardfile::Evaluator).to receive(:new).and_return(evaluator)
++ allow(evaluator).to receive(:evaluate)
++ allow(Guard).to receive(:init)
++ allow(Guard).to receive(:state).and_return(state)
++ allow(state).to receive(:session).and_return(session)
++ allow(session).to receive(:evaluator_options)
++ end
++
++ it "calls Guard.init" do
++ expect(Guard).to receive(:init)
++ subject.evaluate
++ end
++
++ it "initializes Guard with options" do
++ expect(Guard).to receive(:init).with(options)
++ subject.evaluate
++ end
++
++ it "evaluates the guardfile" do
++ expect(evaluator).to receive(:evaluate)
++ subject.evaluate
++ end
++
++ it "passes options to evaluator" do
++ evaluator_options = double("evaluator_options")
++ allow(session).to receive(:evaluator_options).
++ and_return(evaluator_options)
++
++ expect(Guard::Guardfile::Evaluator).to receive(:new).
++ with(evaluator_options).and_return(evaluator)
++
++ subject.evaluate
++ end
++
++ [
++ Guard::Dsl::Error,
++ Guard::Guardfile::Evaluator::NoPluginsError,
++ Guard::Guardfile::Evaluator::NoGuardfileError,
++ Guard::Guardfile::Evaluator::NoCustomGuardfile
++ ].each do |error_class|
++ context "when a #{error_class} error occurs" do
++ before do
++ allow(Guard).to receive(:init).
++ and_raise(error_class, "#{error_class} error!")
++ end
++
++ it "aborts" do
++ expect { subject.evaluate }.to raise_error(SystemExit)
++ end
++
++ it "shows error message" do
++ expect(Guard::UI).to receive(:error).with(/#{error_class} error!/)
++ begin
++ subject.evaluate
++ rescue SystemExit
++ end
++ end
++ end
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/cli/environments/valid_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/cli/environments/valid_spec.rb
+@@ -0,0 +1,253 @@
++require "guard/cli/environments/valid"
++require "guard/cli/environments/bundler"
++
++RSpec.describe Guard::Cli::Environments::Valid do
++ subject { described_class.new(options) }
++ let(:options) { double("options") }
++
++ before do
++ # TODO: start should be an instance method of something
++ allow(Guard).to receive(:start)
++ end
++
++ describe "#start_guard" do
++ let(:bundler) { instance_double("Guard::Cli::Environments::Bundler") }
++
++ before do
++ allow(Guard::Cli::Environments::Bundler).to receive(:new).
++ and_return(bundler)
++
++ allow(bundler).to receive(:verify)
++ end
++
++ context "with a valid bundler setup" do
++ before do
++ allow(bundler).to receive(:verify)
++
++ allow(options).to receive(:[]).with(:no_bundler_warning).
++ and_return(false)
++ end
++
++ it "starts guard" do
++ expect(Guard).to receive(:start)
++ subject.start_guard
++ end
++
++ it "start guard with options" do
++ expect(Guard).to receive(:start).with(options)
++ subject.start_guard
++ end
++
++ it "returns exit code" do
++ exitcode = double("exitcode")
++ expect(Guard).to receive(:start).and_return(exitcode)
++ expect(subject.start_guard).to be(exitcode)
++ end
++
++ [
++ Guard::Dsl::Error,
++ Guard::Guardfile::Evaluator::NoPluginsError,
++ Guard::Guardfile::Evaluator::NoGuardfileError,
++ Guard::Guardfile::Evaluator::NoCustomGuardfile
++ ].each do |error_class|
++ context "when a #{error_class} error occurs" do
++ before do
++ allow(Guard).to receive(:start).
++ and_raise(error_class, "#{error_class} error!")
++ end
++
++ it "aborts" do
++ expect { subject.start_guard }.to raise_error(SystemExit)
++ end
++
++ it "shows error message" do
++ expect(Guard::UI).to receive(:error).with(/#{error_class} error!/)
++ begin
++ subject.start_guard
++ rescue SystemExit
++ end
++ end
++ end
++ end
++ end
++
++ context "without no_bundler_warning option" do
++ subject { described_class.new(no_bundler_warning: false) }
++
++ it "verifies bundler presence" do
++ expect(bundler).to receive(:verify)
++ subject.start_guard
++ end
++
++ context "without a valid bundler setup" do
++ before do
++ allow(bundler).to receive(:verify).and_raise(SystemExit)
++ end
++
++ it "does not start guard" do
++ expect(Guard).to_not receive(:start)
++
++ begin
++ subject.start_guard
++ rescue SystemExit
++ end
++ end
++ end
++ end
++
++ context "with no_bundler_warning option" do
++ subject { described_class.new(no_bundler_warning: true) }
++
++ it "does not verify bundler presence" do
++ expect(bundler).to_not receive(:verify)
++ subject.start_guard
++ end
++
++ it "starts guard" do
++ expect(Guard).to receive(:start)
++ subject.start_guard
++ end
++ end
++
++ describe "return value" do
++ let(:exitcode) { double("Fixnum") }
++ subject { described_class.new(no_bundler_warning: true) }
++
++ before do
++ allow(Guard).to receive(:start).and_return(exitcode)
++ end
++
++ it "matches return value of Guard.start" do
++ expect(subject.start_guard).to be(exitcode)
++ end
++ end
++ end
++
++ describe "#initialize_guardfile" do
++ let(:evaluator) { instance_double("Guard::Guardfile::Evaluator") }
++ let(:generator) { instance_double("Guard::Guardfile::Generator") }
++ let(:state) { instance_double("Guard::Internals::State") }
++ let(:session) { instance_double("Guard::Internals::Session") }
++
++ before do
++ stub_file("Gemfile")
++
++ allow(evaluator).to receive(:evaluate)
++ allow(generator).to receive(:create_guardfile)
++ allow(generator).to receive(:initialize_all_templates)
++
++ allow(session).to receive(:evaluator_options)
++ allow(state).to receive(:session).and_return(session)
++
++ allow(Guard::Internals::State).to receive(:new).and_return(state)
++ allow(Guard::Guardfile::Evaluator).to receive(:new).and_return(evaluator)
++ allow(Guard::Guardfile::Generator).to receive(:new).and_return(generator)
++ end
++
++ context "with bare option" do
++ before do
++ expect(options).to receive(:[]).with(:bare).and_return(true)
++ end
++
++ it "Only creates the Guardfile without initializing any Guard template" do
++ allow(evaluator).to receive(:evaluate).
++ and_raise(Guard::Guardfile::Evaluator::NoGuardfileError)
++
++ allow(File).to receive(:exist?).with("Gemfile").and_return(false)
++ expect(generator).to receive(:create_guardfile)
++ expect(generator).to_not receive(:initialize_template)
++ expect(generator).to_not receive(:initialize_all_templates)
++
++ subject.initialize_guardfile
++ end
++
++ it "returns an exit code" do
++ # TODO: ideally, we'd capture known exceptions and return nonzero
++ expect(subject.initialize_guardfile).to be_zero
++ end
++ end
++
++ context "with no bare option" do
++ before do
++ expect(options).to receive(:[]).with(:bare).and_return(false)
++ end
++
++ it "evaluates created or existing guardfile" do
++ expect(evaluator).to receive(:evaluate)
++ subject.initialize_guardfile
++ end
++
++ it "creates a Guardfile" do
++ expect(evaluator).to receive(:evaluate).
++ and_raise(Guard::Guardfile::Evaluator::NoGuardfileError).once
++ expect(evaluator).to receive(:evaluate)
++
++ expect(Guard::Guardfile::Generator).to receive(:new).
++ and_return(generator)
++ expect(generator).to receive(:create_guardfile)
++
++ subject.initialize_guardfile
++ end
++
++ it "initializes templates of all installed Guards" do
++ allow(File).to receive(:exist?).with("Gemfile").and_return(false)
++
++ expect(generator).to receive(:initialize_all_templates)
++
++ subject.initialize_guardfile
++ end
++
++ it "initializes each passed template" do
++ allow(File).to receive(:exist?).with("Gemfile").and_return(false)
++
++ expect(generator).to receive(:initialize_template).with("rspec")
++ expect(generator).to receive(:initialize_template).with("pow")
++
++ subject.initialize_guardfile(%w(rspec pow))
++ end
++
++ context "when passed a guard name" do
++ context "when the Guardfile is empty" do
++ before do
++ allow(evaluator).to receive(:evaluate).
++ and_raise Guard::Guardfile::Evaluator::NoPluginsError
++ allow(generator).to receive(:initialize_template)
++ end
++
++ it "works without without errors" do
++ expect(subject.initialize_guardfile(%w(rspec))).to be_zero
++ end
++
++ it "adds the template" do
++ expect(generator).to receive(:initialize_template).with("rspec")
++ subject.initialize_guardfile(%w(rspec))
++ end
++ end
++
++ it "initializes the template of the passed Guard" do
++ expect(generator).to receive(:initialize_template).with("rspec")
++ subject.initialize_guardfile(%w(rspec))
++ end
++ end
++
++ it "returns an exit code" do
++ expect(subject.initialize_guardfile).to be_zero
++ end
++
++ context "when passed an unknown guard name" do
++ before do
++ expect(generator).to receive(:initialize_template).with("foo").
++ and_raise(Guard::Guardfile::Generator::NoSuchPlugin, "foo")
++ end
++
++ it "returns an exit code" do
++ expect(::Guard::UI).to receive(:error).with(
++ "Could not load 'guard/foo' or '~/.guard/templates/foo'"\
++ " or find class Guard::Foo\n"
++ )
++ expect(subject.initialize_guardfile(%w(foo))).to be(1)
++ end
++ end
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/cli_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/cli_spec.rb
+@@ -0,0 +1,155 @@
++require "guard/cli"
++
++RSpec.describe Guard::CLI do
++ let(:valid_environment) { instance_double("Guard::Cli::Environments::Valid") }
++ let(:bare_environment) do
++ instance_double("Guard::Cli::Environments::EvaluateOnly")
++ end
++
++ let(:dsl_describer) { instance_double("Guard::DslDescriber") }
++
++ before do
++ @options = {}
++ allow(subject).to receive(:options).and_return(@options)
++ allow(::Guard::DslDescriber).to receive(:new).with(no_args).
++ and_return(dsl_describer)
++
++ allow(Guard::Cli::Environments::EvaluateOnly).to receive(:new).
++ and_return(bare_environment)
++
++ allow(Guard::Cli::Environments::Valid).to receive(:new).
++ and_return(valid_environment)
++ end
++
++ describe "#start" do
++ before do
++ allow(valid_environment).to receive(:start_guard).and_return(0)
++ end
++
++ it "delegates to Guard::Environment.start" do
++ pending "needs JRuby support first" if defined?(JRUBY_VERSION)
++
++ expect(valid_environment).to receive(:start_guard).and_return(0)
++ begin
++ subject.start
++ rescue SystemExit
++ end
++ end
++
++ it "exits with given exit code" do
++ pending "needs JRuby support first" if defined?(JRUBY_VERSION)
++
++ allow(valid_environment).to receive(:start_guard).and_return(4)
++ expect { subject.start }.to raise_error(SystemExit) do |exception|
++ expect(exception.status).to eq(4)
++ exception
++ end
++ end
++
++ it "passes options" do
++ pending "needs JRuby support first" if defined?(JRUBY_VERSION)
++
++ expect(Guard::Cli::Environments::Valid).to receive(:new).with(@options).
++ and_return(valid_environment)
++ begin
++ subject.start
++ rescue SystemExit
++ end
++ end
++ end
++
++ describe "#list" do
++ before do
++ allow(bare_environment).to receive(:evaluate)
++ allow(dsl_describer).to receive(:list)
++ subject.list
++ end
++
++ it "calls the evaluation" do
++ expect(bare_environment).to have_received(:evaluate)
++ end
++
++ it "outputs the Guard plugins list" do
++ expect(dsl_describer).to have_received(:list)
++ end
++ end
++
++ describe "#notifiers" do
++ before do
++ allow(bare_environment).to receive(:evaluate)
++ allow(dsl_describer).to receive(:notifiers)
++ subject.notifiers
++ end
++
++ it "calls the evaluation" do
++ expect(bare_environment).to have_received(:evaluate)
++ end
++
++ it "outputs the notifiers list" do
++ expect(dsl_describer).to have_received(:notifiers)
++ end
++ end
++
++ describe "#version" do
++ it "shows the current version" do
++ expect(STDOUT).to receive(:puts).with(/#{ ::Guard::VERSION }/)
++ subject.version
++ end
++ end
++
++ describe "#init" do
++ before do
++ allow(Guard::Cli::Environments::Valid).to receive(:new).
++ and_return(valid_environment)
++ allow(valid_environment).to receive(:initialize_guardfile).and_return(0)
++ end
++
++ it "delegates to Guard::Environment.start" do
++ begin
++ subject.init
++ rescue SystemExit
++ end
++ end
++
++ it "exits with given exit code" do
++ allow(valid_environment).to receive(:initialize_guardfile).and_return(4)
++ expect { subject.init }.to raise_error(SystemExit) do |exception|
++ expect(exception.status).to eq(4)
++ end
++ end
++
++ it "passes options" do
++ expect(Guard::Cli::Environments::Valid).to receive(:new).with(@options).
++ and_return(valid_environment)
++ begin
++ subject.init
++ rescue SystemExit
++ end
++ end
++
++ it "passes plugin names" do
++ plugins = [double("plugin1"), double("plugin2")]
++ expect(valid_environment).to receive(:initialize_guardfile).with(plugins)
++ begin
++ subject.init(*plugins)
++ rescue SystemExit
++ end
++ end
++ end
++
++ describe "#show" do
++ before do
++ allow(bare_environment).to receive(:evaluate)
++ allow(dsl_describer).to receive(:show)
++ subject.show
++ end
++
++ it "calls the evaluation" do
++ expect(bare_environment).to have_received(:evaluate)
++ end
++
++ it "outputs the Guard::DslDescriber.list result" do
++ expect(dsl_describer).to have_received(:show)
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/commander_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/commander_spec.rb
+@@ -0,0 +1,272 @@
++require "guard/commander"
++
++RSpec.describe Guard::Commander do
++ subject { Guard }
++
++ let(:interactor) { instance_double("Guard::Interactor") }
++ let(:runner) { instance_double("Guard::Runner", run: true) }
++
++ let(:scope) { instance_double("Guard::Internals::Scope") }
++ let(:state) { instance_double("Guard::Internals::State") }
++ let(:session) { instance_double("Guard::Internals::Session") }
++
++ before do
++ allow(state).to receive(:scope).and_return(scope)
++ allow(state).to receive(:session).and_return(session)
++ allow(Guard).to receive(:state).and_return(state)
++
++ allow(Guard::Interactor).to receive(:new) { interactor }
++ allow(Guard::Runner).to receive(:new).and_return(runner)
++ end
++
++ describe ".start" do
++ let(:listener) do
++ instance_double("Listen::Listener", start: true, stop: true)
++ end
++
++ let(:watched_dir) { Dir.pwd }
++
++ before do
++ stub_guardfile(" ")
++ stub_user_guard_rb
++
++ # from stop()
++ allow(Guard).to receive(:setup)
++ allow(Guard).to receive(:listener).and_return(listener)
++ allow(session).to receive(:watchdirs).and_return(%w(dir1 dir2))
++ allow(Guard).to receive(:interactor).and_return(interactor)
++
++ # Simulate Ctrl-D in Pry, or Ctrl-C in non-interactive mode
++ allow(interactor).to receive(:foreground).and_return(:exit)
++
++ allow(interactor).to receive(:background)
++ allow(Guard::Notifier).to receive(:disconnect)
++ end
++
++ it "calls Guard setup" do
++ expect(Guard).to receive(:setup).with(foo: "bar")
++ Guard.start(foo: "bar")
++ end
++
++ it "displays an info message" do
++ expect(Guard::UI).to receive(:info).
++ with("Guard is now watching at 'dir1', 'dir2'")
++
++ Guard.start
++ end
++
++ it "tell the runner to run the :start task" do
++ expect(runner).to receive(:run).with(:start)
++ allow(listener).to receive(:stop)
++ Guard.start
++ end
++
++ it "start the listener" do
++ expect(listener).to receive(:start)
++
++ Guard.start
++ end
++
++ context "when finished" do
++ it "stops everything" do
++ expect(interactor).to receive(:foreground).and_return(:exit)
++
++ # From stop()
++ expect(interactor).to receive(:background)
++ expect(listener).to receive(:stop)
++ expect(runner).to receive(:run).with(:stop)
++ expect(Guard::UI).to receive(:info).with("Bye bye...", reset: true)
++
++ Guard.start
++ end
++ end
++ end
++
++ describe ".stop" do
++ let(:runner) { instance_double("Guard::Runner", run: true) }
++ let(:listener) { instance_double("Listen::Listener", stop: true) }
++
++ before do
++ allow(Guard::Notifier).to receive(:disconnect)
++ allow(Guard).to receive(:listener).and_return(listener)
++ allow(listener).to receive(:stop)
++ allow(Guard).to receive(:interactor).and_return(interactor)
++ allow(interactor).to receive(:background)
++
++ Guard.stop
++ end
++
++ it "turns off the interactor" do
++ expect(interactor).to have_received(:background)
++ end
++
++ it "turns the notifier off" do
++ expect(Guard::Notifier).to have_received(:disconnect)
++ end
++
++ it "tell the runner to run the :stop task" do
++ expect(runner).to have_received(:run).with(:stop)
++ end
++
++ it "stops the listener" do
++ expect(listener).to have_received(:stop)
++ end
++ end
++
++ describe ".reload" do
++ let(:runner) { instance_double("Guard::Runner", run: true) }
++ let(:group) { instance_double("Guard::Group", name: "frontend") }
++
++ before do
++ allow(Guard::Notifier).to receive(:connect)
++ allow(Guard::UI).to receive(:info)
++ allow(Guard::UI).to receive(:clear)
++
++ allow(scope).to receive(:titles).and_return(["all"])
++
++ stub_guardfile(" ")
++ stub_user_guard_rb
++ end
++
++ it "clears the screen" do
++ expect(Guard::UI).to receive(:clear)
++
++ Guard.reload
++ end
++
++ it "reloads Guard" do
++ expect(runner).to receive(:run).with(:reload, groups: [group])
++ Guard.reload(groups: [group])
++ end
++ end
++
++ describe ".run_all" do
++ let(:group) { instance_double("Guard::Group", name: "frontend") }
++
++ before do
++ allow(::Guard::Notifier).to receive(:connect)
++ allow(::Guard::UI).to receive(:action_with_scopes)
++ allow(::Guard::UI).to receive(:clear)
++ end
++
++ context "with a given scope" do
++ it "runs all with the scope" do
++ expect(runner).to receive(:run).with(:run_all, groups: [group])
++
++ subject.run_all(groups: [group])
++ end
++ end
++
++ context "with an empty scope" do
++ it "runs all" do
++ expect(runner).to receive(:run).with(:run_all, {})
++
++ subject.run_all
++ end
++ end
++ end
++
++ describe ".pause" do
++ context "when unpaused" do
++ let(:listener) { instance_double("Listen::Listener") }
++
++ before do
++ allow(::Guard::Notifier).to receive(:connect)
++ allow(Guard).to receive(:listener).and_return(listener)
++ allow(listener).to receive(:paused?) { false }
++ end
++
++ [:toggle, nil, :paused].each do |mode|
++ context "with #{mode.inspect}" do
++ before do
++ allow(listener).to receive(:pause)
++ end
++
++ it "pauses" do
++ expect(listener).to receive(:pause)
++ Guard.pause(mode)
++ end
++
++ it "shows a message" do
++ expected = /File event handling has been paused/
++ expect(Guard::UI).to receive(:info).with(expected)
++ Guard.pause(mode)
++ end
++ end
++ end
++
++ context "with :unpaused" do
++ it "does nothing" do
++ expect(listener).to_not receive(:start)
++ expect(listener).to_not receive(:pause)
++ Guard.pause(:unpaused)
++ end
++ end
++
++ context "with invalid parameter" do
++ it "raises an ArgumentError" do
++ expect { Guard.pause(:invalid) }.
++ to raise_error(ArgumentError, "invalid mode: :invalid")
++ end
++ end
++ end
++
++ context "when already paused" do
++ let(:listener) { instance_double("Listen::Listener") }
++
++ before do
++ allow(::Guard::Notifier).to receive(:connect)
++ allow(Guard).to receive(:listener).and_return(listener)
++ allow(listener).to receive(:paused?) { true }
++ end
++
++ [:toggle, nil, :unpaused].each do |mode|
++ context "with #{mode.inspect}" do
++ before do
++ allow(listener).to receive(:start)
++ end
++
++ it "unpauses" do
++ expect(listener).to receive(:start)
++ Guard.pause(mode)
++ end
++
++ it "shows a message" do
++ expected = /File event handling has been resumed/
++ expect(Guard::UI).to receive(:info).with(expected)
++ Guard.pause(mode)
++ end
++ end
++ end
++
++ context "with :paused" do
++ it "does nothing" do
++ expect(listener).to_not receive(:start)
++ expect(listener).to_not receive(:pause)
++ Guard.pause(:paused)
++ end
++ end
++
++ context "with invalid parameter" do
++ it "raises an ArgumentError" do
++ expect { Guard.pause(:invalid) }.
++ to raise_error(ArgumentError, "invalid mode: :invalid")
++ end
++ end
++ end
++ end
++
++ describe ".show" do
++ let(:dsl_describer) { instance_double("Guard::DslDescriber") }
++
++ before do
++ allow(Guard::DslDescriber).to receive(:new).with(no_args).
++ and_return(dsl_describer)
++ end
++
++ it "shows list of plugins" do
++ expect(dsl_describer).to receive(:show)
++ Guard.show
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/commands/all_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/commands/all_spec.rb
+@@ -0,0 +1,83 @@
++require "guard/plugin"
++
++require "guard/commands/all"
++
++require "guard/internals/session"
++require "guard/internals/state"
++
++RSpec.describe Guard::Commands::All do
++ let(:foo_group) { instance_double(Guard::Group) }
++ let(:bar_guard) { instance_double(Guard::Plugin) }
++ let(:output) { instance_double(Pry::Output) }
++
++ let(:state) { instance_double("Guard::Internals::State") }
++ let(:session) { instance_double("Guard::Internals::Session") }
++
++ class FakePry < Pry::Command
++ def self.output
++ end
++ end
++
++ before do
++ allow(session).to receive(:convert_scope).with(given_scope).
++ and_return(converted_scope)
++
++ allow(state).to receive(:session).and_return(session)
++ allow(Guard).to receive(:state).and_return(state)
++
++ allow(FakePry).to receive(:output).and_return(output)
++ allow(Pry::Commands).to receive(:create_command).with("all") do |&block|
++ FakePry.instance_eval(&block)
++ end
++
++ described_class.import
++ end
++
++ context "without scope" do
++ let(:given_scope) { [] }
++ let(:converted_scope) { [{ groups: [], plugins: [] }, []] }
++
++ it "runs the :run_all action" do
++ expect(Guard).to receive(:async_queue_add).
++ with([:guard_run_all, groups: [], plugins: []])
++
++ FakePry.process
++ end
++ end
++
++ context "with a valid Guard group scope" do
++ let(:given_scope) { ["foo"] }
++ let(:converted_scope) { [{ groups: [foo_group], plugins: [] }, []] }
++
++ it "runs the :run_all action with the given scope" do
++ expect(Guard).to receive(:async_queue_add).
++ with([:guard_run_all, groups: [foo_group], plugins: []])
++
++ FakePry.process("foo")
++ end
++ end
++
++ context "with a valid Guard plugin scope" do
++ let(:given_scope) { ["bar"] }
++ let(:converted_scope) { [{ groups: [], plugins: [bar_guard] }, []] }
++
++ it "runs the :run_all action with the given scope" do
++ expect(Guard).to receive(:async_queue_add).
++ with([:guard_run_all, plugins: [bar_guard], groups: []])
++
++ FakePry.process("bar")
++ end
++ end
++
++ context "with an invalid scope" do
++ let(:given_scope) { ["baz"] }
++ let(:converted_scope) { [{ groups: [], plugins: [] }, ["baz"]] }
++
++ it "does not run the action" do
++ expect(output).to receive(:puts).with("Unknown scopes: baz")
++ expect(Guard).to_not receive(:async_queue_add)
++
++ FakePry.process("baz")
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/commands/change_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/commands/change_spec.rb
+@@ -0,0 +1,46 @@
++require "guard/commands/change"
++
++RSpec.describe Guard::Commands::Change do
++ let(:output) { instance_double(Pry::Output) }
++
++ class FakePry < Pry::Command
++ def self.output
++ end
++ end
++
++ before do
++ allow(FakePry).to receive(:output).and_return(output)
++ allow(Pry::Commands).to receive(:create_command).with("change") do |&block|
++ FakePry.instance_eval(&block)
++ end
++
++ described_class.import
++ end
++
++ context "with a file" do
++ it "runs the :run_on_changes action with the given file" do
++ expect(::Guard).to receive(:async_queue_add).
++ with(modified: ["foo"], added: [], removed: [])
++
++ FakePry.process("foo")
++ end
++ end
++
++ context "with multiple files" do
++ it "runs the :run_on_changes action with the given files" do
++ expect(::Guard).to receive(:async_queue_add).
++ with(modified: %w(foo bar baz), added: [], removed: [])
++
++ FakePry.process("foo", "bar", "baz")
++ end
++ end
++
++ context "without a file" do
++ it "does not run the :run_on_changes action" do
++ expect(::Guard).to_not receive(:async_queue_add)
++ expect(output).to receive(:puts).with("Please specify a file.")
++
++ FakePry.process
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/commands/notification_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/commands/notification_spec.rb
+@@ -0,0 +1,24 @@
++require "guard/commands/notification"
++
++RSpec.describe Guard::Commands::Notification do
++ let(:output) { instance_double(Pry::Output) }
++
++ class FakePry < Pry::Command
++ def self.output; end
++ end
++
++ before do
++ allow(FakePry).to receive(:output).and_return(output)
++ allow(Pry::Commands).to receive(:create_command).
++ with("notification") do |&block|
++ FakePry.instance_eval(&block)
++ end
++
++ described_class.import
++ end
++
++ it "toggles the Guard notifier" do
++ expect(::Guard::Notifier).to receive(:toggle)
++ FakePry.process
++ end
++end
+Index: ruby-guard/spec/lib/guard/commands/pause_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/commands/pause_spec.rb
+@@ -0,0 +1,22 @@
++require "guard/commands/pause"
++
++RSpec.describe Guard::Commands::Pause do
++ class FakePry < Pry::Command
++ def self.output
++ end
++ end
++
++ before do
++ allow(FakePry).to receive(:output).and_return(output)
++ allow(Pry::Commands).to receive(:create_command).with("pause") do |&block|
++ FakePry.instance_eval(&block)
++ end
++
++ described_class.import
++ end
++
++ it "tells Guard to pause" do
++ expect(::Guard).to receive(:async_queue_add).with([:guard_pause])
++ FakePry.process
++ end
++end
+Index: ruby-guard/spec/lib/guard/commands/reload_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/commands/reload_spec.rb
+@@ -0,0 +1,77 @@
++require "guard/commands/reload"
++
++require "guard/internals/session"
++require "guard/internals/state"
++
++RSpec.describe Guard::Commands::Reload do
++ let(:output) { instance_double(Pry::Output) }
++
++ let(:state) { instance_double("Guard::Internals::State") }
++ let(:session) { instance_double("Guard::Internals::Session") }
++
++ let(:foo_group) { instance_double(Guard::Group) }
++ let(:bar_guard) { instance_double(Guard::Plugin) }
++
++ class FakePry < Pry::Command
++ def self.output; end
++ end
++
++ before do
++ allow(session).to receive(:convert_scope).with(given_scope).
++ and_return(converted_scope)
++
++ allow(state).to receive(:session).and_return(session)
++ allow(Guard).to receive(:state).and_return(state)
++
++ allow(FakePry).to receive(:output).and_return(output)
++ allow(Pry::Commands).to receive(:create_command).with("reload") do |&block|
++ FakePry.instance_eval(&block)
++ end
++
++ described_class.import
++ end
++
++ context "without scope" do
++ let(:given_scope) { [] }
++ let(:converted_scope) { [{ groups: [], plugins: [] }, []] }
++
++ it "triggers the :reload action" do
++ expect(Guard).to receive(:async_queue_add).
++ with([:guard_reload, { groups: [], plugins: [] }])
++ FakePry.process
++ end
++ end
++
++ context "with a valid Guard group scope" do
++ let(:given_scope) { ["foo"] }
++ let(:converted_scope) { [{ groups: [foo_group], plugins: [] }, []] }
++
++ it "triggers the :reload action with the given scope" do
++ expect(Guard).to receive(:async_queue_add).
++ with([:guard_reload, { groups: [foo_group], plugins: [] }])
++ FakePry.process("foo")
++ end
++ end
++
++ context "with a valid Guard plugin scope" do
++ let(:given_scope) { ["bar"] }
++ let(:converted_scope) { [{ groups: [], plugins: [bar_guard] }, []] }
++
++ it "triggers the :reload action with the given scope" do
++ expect(Guard).to receive(:async_queue_add).
++ with([:guard_reload, { plugins: [bar_guard], groups: [] }])
++ FakePry.process("bar")
++ end
++ end
++
++ context "with an invalid scope" do
++ let(:given_scope) { ["baz"] }
++ let(:converted_scope) { [{ groups: [], plugins: [] }, ["baz"]] }
++
++ it "does not trigger the action" do
++ allow(output).to receive(:puts).with("Unknown scopes: baz")
++ expect(Guard).to_not receive(:async_queue_add)
++ FakePry.process("baz")
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/commands/scope_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/commands/scope_spec.rb
+@@ -0,0 +1,81 @@
++require "guard/commands/scope"
++
++require "guard/internals/session"
++require "guard/internals/state"
++
++RSpec.describe Guard::Commands::Scope do
++ let(:output) { instance_double(Pry::Output) }
++
++ let(:state) { instance_double("Guard::Internals::State") }
++ let(:scope) { instance_double("Guard::Internals::Scope") }
++ let(:session) { instance_double("Guard::Internals::Session") }
++
++ let(:foo_group) { instance_double(Guard::Group) }
++ let(:bar_guard) { instance_double(Guard::PluginUtil) }
++
++ class FakePry < Pry::Command
++ def self.output; end
++ end
++
++ before do
++ allow(session).to receive(:convert_scope).with(given_scope).
++ and_return(converted_scope)
++
++ allow(state).to receive(:session).and_return(session)
++ allow(Guard).to receive(:state).and_return(state)
++
++ allow(FakePry).to receive(:output).and_return(output)
++ allow(Pry::Commands).to receive(:create_command).with("scope") do |&block|
++ FakePry.instance_eval(&block)
++ end
++
++ allow(state).to receive(:scope).and_return(scope)
++ allow(Guard).to receive(:state).and_return(state)
++
++ described_class.import
++ end
++
++ context "without scope" do
++ let(:given_scope) { [] }
++ let(:converted_scope) { [{ groups: [], plugins: [] }, []] }
++
++ it "does not call :scope= and shows usage" do
++ expect(output).to receive(:puts).with("Usage: scope <scope>")
++ expect(scope).to_not receive(:from_interactor)
++ FakePry.process
++ end
++ end
++
++ context "with a valid Guard group scope" do
++ let(:given_scope) { ["foo"] }
++ let(:converted_scope) { [{ groups: [foo_group], plugins: [] }, []] }
++
++ it "sets up the scope with the given scope" do
++ expect(scope).to receive(:from_interactor).
++ with(groups: [foo_group], plugins: [])
++ FakePry.process("foo")
++ end
++ end
++
++ context "with a valid Guard plugin scope" do
++ let(:given_scope) { ["bar"] }
++ let(:converted_scope) { [{ groups: [], plugins: [bar_guard] }, []] }
++
++ it "runs the :scope= action with the given scope" do
++ expect(scope).to receive(:from_interactor).
++ with(plugins: [bar_guard], groups: [])
++ FakePry.process("bar")
++ end
++ end
++
++ context "with an invalid scope" do
++ let(:given_scope) { ["baz"] }
++ let(:converted_scope) { [{ groups: [], plugins: [] }, ["baz"]] }
++
++ it "does not change the scope and shows unknown scopes" do
++ expect(output).to receive(:puts).with("Unknown scopes: baz")
++ expect(scope).to_not receive(:from_interactor)
++ FakePry.process("baz")
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/commands/show_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/commands/show_spec.rb
+@@ -0,0 +1,26 @@
++require "guard/commands/show"
++
++# TODO: we only need the async queue
++require "guard"
++
++RSpec.describe Guard::Commands::Show do
++ let(:output) { instance_double(Pry::Output) }
++
++ class FakePry < Pry::Command
++ def self.output; end
++ end
++
++ before do
++ allow(FakePry).to receive(:output).and_return(output)
++ allow(Pry::Commands).to receive(:create_command).with("show") do |&block|
++ FakePry.instance_eval(&block)
++ end
++
++ described_class.import
++ end
++
++ it "tells Guard to output DSL description" do
++ expect(::Guard).to receive(:async_queue_add).with([:guard_show])
++ FakePry.process
++ end
++end
+Index: ruby-guard/spec/lib/guard/config_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/config_spec.rb
+@@ -0,0 +1,22 @@
++require "guard/config"
++
++RSpec.describe Guard::Config, exclude_stubs: [:Nenv] do
++ it { is_expected.to respond_to(:strict?) }
++ it { is_expected.to respond_to(:silence_deprecations?) }
++
++ describe ".strict?" do
++ before do
++ allow(subject).to receive(:strict?).and_return(result)
++ end
++
++ context "when GUARD_STRICT is set to a 'true' value" do
++ let(:result) { true }
++ it { is_expected.to be_strict }
++ end
++
++ context "when GUARD_STRICT is set to a 'false' value" do
++ let(:result) { false }
++ it { is_expected.to_not be_strict }
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/deprecated/dsl_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/deprecated/dsl_spec.rb
+@@ -0,0 +1,57 @@
++require "guard/config"
++
++unless Guard::Config.new.strict?
++
++ # Require listen now, so the requiring below doesn't use File methods
++ require "listen"
++
++ require "guard/deprecated/dsl"
++
++ require "guard/ui"
++ require "guard/config"
++
++ RSpec.describe Guard::Deprecated::Dsl do
++ subject do
++ module TestModule; end.tap { |mod| described_class.add_deprecated(mod) }
++ end
++
++ describe ".evaluate_guardfile" do
++ before { stub_user_guard_rb }
++ before { stub_guardfile(" ") }
++ before { stub_user_guardfile }
++ before { stub_user_project_guardfile }
++ let(:evaluator) { instance_double("Guard::Guardfile::Evaluator") }
++
++ before do
++ # TODO: this is a workaround for a bad require loop
++ allow_any_instance_of(Guard::Config).to receive(:strict?).
++ and_return(false)
++
++ require "guard/guardfile/evaluator"
++
++ allow(Guard::Guardfile::Evaluator).to receive(:new).
++ and_return(evaluator)
++
++ allow(evaluator).to receive(:evaluate_guardfile)
++
++ allow(Guard::UI).to receive(:deprecation)
++ end
++
++ it "displays a deprecation warning to the user" do
++ expect(Guard::UI).to receive(:deprecation).
++ with(Guard::Deprecated::Dsl::ClassMethods::EVALUATE_GUARDFILE)
++
++ subject.evaluate_guardfile
++ end
++
++ it "delegates to Guard::Guardfile::Generator" do
++ expect(Guard::Guardfile::Evaluator).to receive(:new).
++ with(foo: "bar") { evaluator }
++
++ expect(evaluator).to receive(:evaluate_guardfile)
++
++ subject.evaluate_guardfile(foo: "bar")
++ end
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/deprecated/evaluator_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/deprecated/evaluator_spec.rb
+@@ -0,0 +1,50 @@
++require "guard/config"
++
++unless Guard::Config.new.strict?
++
++ require "guard/deprecated/evaluator"
++ require "guard/internals/state"
++
++ RSpec.describe Guard::Deprecated::Evaluator do
++ subject do
++ class TestClass
++ def evaluate
++ end
++ end
++ described_class.add_deprecated(TestClass)
++ TestClass.new
++ end
++
++ let(:state) { instance_double("Guard::Internals::State") }
++
++ before do
++ allow(Guard::UI).to receive(:deprecation)
++ allow(Guard).to receive(:state).and_return(state)
++ end
++
++ describe "#evaluate_guardfile" do
++ before do
++ allow(subject).to receive(:evaluate)
++ end
++
++ it "displays a deprecation warning to the user" do
++ expect(Guard::UI).to receive(:deprecation).
++ with(Guard::Deprecated::Evaluator::EVALUATE_GUARDFILE)
++ subject.evaluate_guardfile
++ end
++
++ it "calls the recommended method" do
++ expect(subject).to receive(:evaluate)
++ subject.evaluate_guardfile
++ end
++ end
++
++ describe "#reevaluate_guardfile" do
++ it "displays a deprecation warning to the user" do
++ expect(Guard::UI).to receive(:deprecation).
++ with(Guard::Deprecated::Evaluator::REEVALUATE_GUARDFILE)
++ subject.reevaluate_guardfile
++ end
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/deprecated/guard_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/deprecated/guard_spec.rb
+@@ -0,0 +1,422 @@
++require "guard/config"
++
++unless Guard::Config.new.strict?
++
++ # require guard, to avoid circular require
++ require "guard"
++ # require "guard/deprecated/guard"
++
++ require "guard/config"
++
++ RSpec.describe Guard::Deprecated::Guard do
++ let(:session) { instance_double("Guard::Internals::Session") }
++ let(:state) { instance_double("Guard::Internals::State") }
++ let(:plugins) { instance_double("Guard::Internals::Plugins") }
++ let(:groups) { instance_double("Guard::Internals::Groups") }
++ let(:scope) { instance_double("Guard::Internals::Scope") }
++
++ subject do
++ module TestModule
++ def self.listener
++ end
++
++ def self._pluginless_guardfile?
++ false
++ end
++ end
++ TestModule.tap { |mod| described_class.add_deprecated(mod) }
++ end
++
++ before do
++ allow(session).to receive(:evaluator_options).and_return({})
++ allow(state).to receive(:scope).and_return(scope)
++ allow(state).to receive(:session).and_return(session)
++ allow(session).to receive(:plugins).and_return(plugins)
++ allow(session).to receive(:groups).and_return(groups)
++ allow(::Guard).to receive(:state).and_return(state)
++ allow(Guard::UI).to receive(:deprecation)
++ allow(plugins).to receive(:all)
++ allow(groups).to receive(:all)
++ end
++
++ describe ".guards" do
++ before do
++ end
++
++ it "displays a deprecation warning to the user" do
++ expect(Guard::UI).to receive(:deprecation).
++ with(Guard::Deprecated::Guard::ClassMethods::GUARDS)
++ subject.guards
++ end
++
++ it "delegates to Plugins" do
++ expect(plugins).to receive(:all).with(group: "backend")
++ subject.guards(group: "backend")
++ end
++ end
++
++ describe ".add_guard" do
++ before { allow(plugins).to receive(:add).with("rspec", {}) }
++
++ it "displays a deprecation warning to the user" do
++ expect(Guard::UI).to receive(:deprecation).
++ with(Guard::Deprecated::Guard::ClassMethods::ADD_GUARD)
++
++ subject.add_guard("rspec")
++ end
++
++ it "delegates to Guard.plugins" do
++ expect(subject).to receive(:add_plugin).with("rspec", group: "backend")
++
++ subject.add_guard("rspec", group: "backend")
++ end
++ end
++
++ describe ".get_guard_class" do
++ let(:plugin_util) do
++ instance_double("Guard::PluginUtil", plugin_class: true)
++ end
++
++ before do
++ allow(Guard::PluginUtil).to receive(:new).with("rspec").
++ and_return(plugin_util)
++ end
++
++ it "displays a deprecation warning to the user" do
++ expect(Guard::UI).to receive(:deprecation).
++ with(Guard::Deprecated::Guard::ClassMethods::GET_GUARD_CLASS)
++ subject.get_guard_class("rspec")
++ end
++
++ it "delegates to Guard::PluginUtil" do
++ expect(plugin_util).to receive(:plugin_class).
++ with(fail_gracefully: false)
++ subject.get_guard_class("rspec")
++ end
++
++ describe ":fail_gracefully" do
++ it "pass it to get_guard_class" do
++ expect(plugin_util).to receive(:plugin_class).
++ with(fail_gracefully: true)
++ subject.get_guard_class("rspec", true)
++ end
++ end
++ end
++
++ describe ".locate_guard" do
++ let(:plugin_util) do
++ instance_double("Guard::PluginUtil", plugin_location: true)
++ end
++
++ before do
++ allow(Guard::PluginUtil).to receive(:new) { plugin_util }
++ end
++
++ it "displays a deprecation warning to the user" do
++ expect(Guard::UI).to receive(:deprecation).
++ with(Guard::Deprecated::Guard::ClassMethods::LOCATE_GUARD)
++
++ subject.locate_guard("rspec")
++ end
++
++ it "delegates to Guard::PluginUtil" do
++ expect(Guard::PluginUtil).to receive(:new).with("rspec") { plugin_util }
++ expect(plugin_util).to receive(:plugin_location)
++
++ subject.locate_guard("rspec")
++ end
++ end
++
++ describe ".guard_gem_names" do
++ before { allow(Guard::PluginUtil).to receive(:plugin_names) }
++
++ it "displays a deprecation warning to the user" do
++ expect(Guard::UI).to receive(:deprecation).
++ with(Guard::Deprecated::Guard::ClassMethods::GUARD_GEM_NAMES)
++
++ subject.guard_gem_names
++ end
++
++ it "delegates to Guard::PluginUtil" do
++ expect(Guard::PluginUtil).to receive(:plugin_names)
++
++ subject.guard_gem_names
++ end
++ end
++
++ describe ".running" do
++ it "show deprecation warning" do
++ expect(Guard::UI).to receive(:deprecation).
++ with(Guard::Deprecated::Guard::ClassMethods::RUNNING)
++
++ subject.running
++ end
++ end
++
++ describe ".lock" do
++ it "show deprecation warning" do
++ expect(Guard::UI).to receive(:deprecation).
++ with(Guard::Deprecated::Guard::ClassMethods::LOCK)
++
++ subject.lock
++ end
++ end
++
++ describe ".listener=" do
++ it "show deprecation warning" do
++ expect(Guard::UI).to receive(:deprecation).
++ with(Guard::Deprecated::Guard::ClassMethods::LISTENER_ASSIGN)
++
++ subject.listener = 123
++ end
++
++ it "provides and alternative implementation" do
++ subject.listener = 123
++ end
++ end
++
++ describe "reset_evaluator" do
++ it "show deprecation warning" do
++ expect(Guard::UI).to receive(:deprecation).
++ with(Guard::Deprecated::Guard::ClassMethods::RESET_EVALUATOR)
++ subject.reset_evaluator({})
++ end
++ end
++
++ describe "evaluator" do
++ before do
++ allow(Guard::Guardfile::Evaluator).to receive(:new).
++ and_return(double("evaluator"))
++ end
++ it "show deprecation warning" do
++ expect(Guard::UI).to receive(:deprecation).
++ with(Guard::Deprecated::Guard::ClassMethods::EVALUATOR)
++ subject.evaluator
++ end
++ end
++
++ describe "evaluate_guardfile" do
++ let(:evaluator) { instance_double("Guard::Guardfile::Evaluator") }
++
++ before do
++ allow(::Guard::Guardfile::Evaluator).to receive(:new).
++ and_return(evaluator)
++ allow(evaluator).to receive(:evaluate)
++ end
++
++ it "show deprecation warning" do
++ expect(Guard::UI).to receive(:deprecation).
++ with(Guard::Deprecated::Guard::ClassMethods::EVALUATOR)
++ subject.evaluate_guardfile
++ end
++
++ it "evaluates the guardfile" do
++ expect(evaluator).to receive(:evaluate)
++ subject.evaluate_guardfile
++ end
++ end
++
++ describe "options" do
++ before do
++ allow(session).to receive(:clearing?)
++ allow(session).to receive(:debug?)
++ allow(session).to receive(:watchdirs)
++ allow(session).to receive(:notify_options).and_return({})
++ allow(session).to receive(:interactor_name)
++ end
++
++ it "show deprecation warning" do
++ expect(Guard::UI).to receive(:deprecation).
++ with(Guard::Deprecated::Guard::ClassMethods::OPTIONS)
++ subject.options
++ end
++
++ describe ":clear" do
++ before do
++ allow(session).to receive(:clearing?).and_return(clearing)
++ end
++ context "when being set to true" do
++ let(:clearing) { true }
++ it "sets the clearing option accordingly" do
++ expect(session).to receive(:clearing).with(true)
++ subject.options[:clear] = true
++ end
++ end
++
++ context "when being set to false" do
++ let(:clearing) { false }
++ it "sets the clearing option accordingly" do
++ expect(session).to receive(:clearing).with(false)
++ subject.options[:clear] = false
++ end
++ end
++
++ context "when being read" do
++ context "when not set" do
++ let(:clearing) { false }
++ it "provides an alternative implementation" do
++ expect(subject.options).to include(clear: false)
++ end
++ end
++
++ context "when set" do
++ let(:clearing) { true }
++ it "provides an alternative implementation" do
++ expect(subject.options).to include(clear: true)
++ end
++ end
++ end
++ end
++
++ # TODO: other options?
++ end
++
++ describe ".add_group" do
++ before do
++ allow(groups).to receive(:add)
++ end
++
++ it "show deprecation warning" do
++ expect(Guard::UI).to receive(:deprecation).
++ with(Guard::Deprecated::Guard::ClassMethods::ADD_GROUP)
++ subject.add_group(:foo)
++ end
++
++ it "adds a group" do
++ group = instance_double("Guard::Group")
++ expect(groups).to receive(:add).with(:foo, bar: 3).and_return(group)
++ expect(subject.add_group(:foo, bar: 3)).to eq(group)
++ end
++ end
++
++ describe ".add_plugin" do
++ before do
++ allow(plugins).to receive(:add)
++ end
++
++ it "show deprecation warning" do
++ expect(Guard::UI).to receive(:deprecation).
++ with(Guard::Deprecated::Guard::ClassMethods::ADD_PLUGIN)
++ subject.add_plugin(:foo)
++ end
++
++ it "adds a plugin" do
++ plugin = instance_double("Guard::Plugin")
++ expect(plugins).to receive(:add).with(:foo, bar: 3).and_return(plugin)
++ expect(subject.add_plugin(:foo, bar: 3)).to be(plugin)
++ end
++ end
++
++ describe ".group" do
++ let(:array) { instance_double(Array) }
++
++ before do
++ allow(groups).to receive(:all).with(:foo).and_return(array)
++ allow(array).to receive(:first)
++ end
++
++ it "show deprecation warning" do
++ expect(Guard::UI).to receive(:deprecation).
++ with(Guard::Deprecated::Guard::ClassMethods::GROUP)
++ subject.group(:foo)
++ end
++
++ it "provides a similar implementation" do
++ group = instance_double("Guard::Group")
++ expect(array).to receive(:first).and_return(group)
++ expect(subject.group(:foo)).to be(group)
++ end
++ end
++
++ describe ".plugin" do
++ let(:array) { instance_double(Array) }
++ let(:plugin) { instance_double("Guard::Plugin") }
++
++ before do
++ allow(plugins).to receive(:all).with(:foo).and_return(array)
++ allow(array).to receive(:first).and_return(plugin)
++ end
++
++ it "show deprecation warning" do
++ expect(Guard::UI).to receive(:deprecation).
++ with(Guard::Deprecated::Guard::ClassMethods::PLUGIN)
++ subject.plugin(:foo)
++ end
++
++ it "provides a similar implementation" do
++ expect(subject.plugin(:foo)).to be(plugin)
++ end
++ end
++
++ describe ".groups" do
++ let(:array) { instance_double(Array) }
++
++ before do
++ allow(groups).to receive(:all).with(:foo).and_return(array)
++ end
++
++ it "show deprecation warning" do
++ expect(Guard::UI).to receive(:deprecation).
++ with(Guard::Deprecated::Guard::ClassMethods::GROUPS)
++ subject.groups(:foo)
++ end
++
++ it "provides a similar implementation" do
++ expect(subject.groups(:foo)).to be(array)
++ end
++ end
++
++ describe ".plugins" do
++ let(:array) { instance_double(Array) }
++
++ before do
++ allow(plugins).to receive(:all).with(:foo).and_return(array)
++ end
++
++ it "show deprecation warning" do
++ expect(Guard::UI).to receive(:deprecation).
++ with(Guard::Deprecated::Guard::ClassMethods::PLUGINS)
++ subject.plugins(:foo)
++ end
++
++ it "provides a similar implementation" do
++ expect(subject.plugins(:foo)).to be(array)
++ end
++ end
++
++ describe ".scope" do
++ let(:hash) { instance_double(Hash) }
++
++ before do
++ allow(scope).to receive(:to_hash).and_return(hash)
++ end
++
++ it "show deprecation warning" do
++ expect(Guard::UI).to receive(:deprecation).
++ with(Guard::Deprecated::Guard::ClassMethods::SCOPE)
++ subject.scope
++ end
++
++ it "provides a similar implementation" do
++ expect(subject.scope).to be(hash)
++ end
++ end
++
++ describe ".scope=" do
++ before do
++ allow(scope).to receive(:from_interactor).with(foo: :bar)
++ end
++
++ it "show deprecation warning" do
++ expect(Guard::UI).to receive(:deprecation).
++ with(Guard::Deprecated::Guard::ClassMethods::SCOPE_ASSIGN)
++ subject.scope = { foo: :bar }
++ end
++
++ it "provides a similar implementation" do
++ expect(scope).to receive(:from_interactor).with(foo: :bar)
++ subject.scope = { foo: :bar }
++ end
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/deprecated/guardfile_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/deprecated/guardfile_spec.rb
+@@ -0,0 +1,93 @@
++require "guard/config"
++
++unless Guard::Config.new.strict?
++
++ require "guard/deprecated/guardfile"
++
++ RSpec.describe Guard::Deprecated::Guardfile do
++ subject do
++ module TestModule; end.tap { |mod| described_class.add_deprecated(mod) }
++ end
++
++ let(:generator) { instance_double("Guard::Guardfile::Generator") }
++
++ before do
++ allow(Guard::UI).to receive(:deprecation)
++ end
++
++ describe ".create_guardfile" do
++ before do
++ allow(File).to receive(:exist?).with("Guardfile").and_return(false)
++ template = Guard::Guardfile::Generator::GUARDFILE_TEMPLATE
++ allow(FileUtils).to receive(:cp).with(template, "Guardfile")
++
++ allow(Guard::Guardfile::Generator).to receive(:new).
++ and_return(generator)
++
++ allow(generator).to receive(:create_guardfile)
++ end
++
++ it "displays a deprecation warning to the user" do
++ expect(Guard::UI).to receive(:deprecation).
++ with(Guard::Deprecated::Guardfile::ClassMethods::CREATE_GUARDFILE)
++
++ subject.create_guardfile
++ end
++
++ it "delegates to Guard::Guardfile::Generator" do
++ expect(Guard::Guardfile::Generator).to receive(:new).
++ with(foo: "bar") { generator }
++
++ expect(generator).to receive(:create_guardfile)
++
++ subject.create_guardfile(foo: "bar")
++ end
++ end
++
++ describe ".initialize_template" do
++ before do
++ expect(Guard::Guardfile::Generator).to receive(:new) do
++ generator
++ end
++
++ allow(generator).to receive(:initialize_template)
++ end
++
++ it "displays a deprecation warning to the user" do
++ expect(Guard::UI).to receive(:deprecation).
++ with(Guard::Deprecated::Guardfile::ClassMethods::INITIALIZE_TEMPLATE)
++
++ subject.initialize_template("rspec")
++ end
++
++ it "delegates to Guard::Guardfile::Generator" do
++ expect(generator).to receive(:initialize_template).with("rspec")
++
++ subject.initialize_template("rspec")
++ end
++ end
++
++ describe ".initialize_all_templates" do
++ before do
++ expect(Guard::Guardfile::Generator).to receive(:new) do
++ generator
++ end
++
++ allow(generator).to receive(:initialize_all_templates)
++ end
++
++ it "displays a deprecation warning to the user" do
++ expect(Guard::UI).to receive(:deprecation).
++ with(described_class::ClassMethods::INITIALIZE_ALL_TEMPLATES)
++
++ subject.initialize_all_templates
++ end
++
++ it "delegates to Guard::Guardfile::Generator" do
++ expect(generator).to receive(:initialize_all_templates)
++
++ subject.initialize_all_templates
++ end
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/deprecated/watcher_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/deprecated/watcher_spec.rb
+@@ -0,0 +1,49 @@
++require "guard/config"
++
++unless Guard::Config.new.strict?
++
++ require "guard/deprecated/watcher"
++ require "guard/guardfile/evaluator"
++
++ RSpec.describe Guard::Deprecated::Watcher do
++ let(:session) { instance_double("Guard::Internals::Session") }
++
++ subject do
++ module TestModule; end.tap { |mod| described_class.add_deprecated(mod) }
++ end
++
++ let(:evaluator) { instance_double("Guard::Guardfile::Evaluator") }
++ let(:options) { { guardfile: "foo" } }
++
++ let(:state) { instance_double("Guard::Internals::State") }
++
++ before do
++ allow(session).to receive(:evaluator_options).and_return(options)
++ allow(state).to receive(:session).and_return(session)
++ allow(Guard).to receive(:state).and_return(state)
++
++ allow(evaluator).to receive(:guardfile_path).
++ and_return(File.expand_path("foo"))
++
++ allow(::Guard::Guardfile::Evaluator).to receive(:new).with(options).
++ and_return(evaluator)
++
++ allow(Guard::UI).to receive(:deprecation)
++ end
++
++ describe ".match_guardfile?" do
++ it "displays a deprecation warning to the user" do
++ expect(Guard::UI).to receive(:deprecation).
++ with(Guard::Deprecated::Watcher::ClassMethods::MATCH_GUARDFILE)
++
++ files = %w(foo bar)
++ subject.match_guardfile?(files)
++ end
++
++ it "matches against current guardfile" do
++ expect(subject.match_guardfile?(%w(foo bar))).to be(true)
++ expect(subject.match_guardfile?(%w(bar))).to be(false)
++ end
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/dsl_describer_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/dsl_describer_spec.rb
+@@ -0,0 +1,164 @@
++# encoding: utf-8
++require "guard/plugin"
++require "guard/dsl_describer"
++require "formatador"
++
++RSpec.describe Guard::DslDescriber do
++ let(:interactor) { instance_double(Guard::Interactor) }
++ let(:env) { double("ENV") }
++
++ let(:session) { instance_double("Guard::Internals::Session") }
++ let(:plugins) { instance_double("Guard::Internals::Plugins") }
++ let(:groups) { instance_double("Guard::Internals::Groups") }
++ let(:state) { instance_double("Guard::Internals::State") }
++
++ before do
++ allow(session).to receive(:groups).and_return(groups)
++ allow(session).to receive(:plugins).and_return(plugins)
++ allow(state).to receive(:session).and_return(session)
++ allow(Guard).to receive(:state).and_return(state)
++
++ allow(env).to receive(:[]).with("GUARD_NOTIFY_PID")
++ allow(env).to receive(:[]).with("GUARD_NOTIFY")
++ allow(env).to receive(:[]).with("GUARD_NOTIFIERS")
++ allow(env).to receive(:[]=).with("GUARD_NOTIFIERS", anything)
++
++ allow(Guard::Notifier).to receive(:turn_on)
++
++ stub_const "Guard::Test", class_double("Guard::Plugin")
++ stub_const "Guard::Another", class_double("Guard::Plugin")
++
++ @output = ""
++
++ # Strip escape sequences
++ allow(STDOUT).to receive(:tty?).and_return(false)
++
++ # Capture formatador output
++ Thread.current[:formatador] = Formatador.new
++ allow(Thread.current[:formatador]).to receive(:print) do |msg|
++ @output << msg
++ end
++ end
++
++ describe "#list" do
++ let(:result) do
++ <<-OUTPUT
++ +---------+-----------+
++ | Plugin | Guardfile |
++ +---------+-----------+
++ | Another | ✔ |
++ | Even | ✘ |
++ | More | ✘ |
++ | Test | ✔ |
++ +---------+-----------+
++ OUTPUT
++ end
++
++ let(:another) { instance_double("Guard::Plugin", title: "Another") }
++ let(:test) { instance_double("Guard::Plugin", title: "Test") }
++
++ before do
++ allow(plugins).to receive(:all).with("another").and_return([another])
++ allow(plugins).to receive(:all).with("test").and_return([test])
++ allow(plugins).to receive(:all).with("even").and_return([])
++ allow(plugins).to receive(:all).with("more").and_return([])
++
++ allow(Guard::PluginUtil).to receive(:plugin_names) do
++ %w(test another even more)
++ end
++ end
++
++ it "lists the available Guards declared as strings or symbols" do
++ subject.list
++ expect(@output).to eq result
++ end
++ end
++
++ describe ".show" do
++ let(:result) do
++ <<-OUTPUT
++ +---------+---------+--------+-------+
++ | Group | Plugin | Option | Value |
++ +---------+---------+--------+-------+
++ | Default | Test | a | :b |
++ | | | c | :d |
++ +---------+---------+--------+-------+
++ | A | Test | x | 1 |
++ | | | y | 2 |
++ +---------+---------+--------+-------+
++ | B | Another | | |
++ +---------+---------+--------+-------+
++ OUTPUT
++ end
++
++ before do
++ allow(groups).to receive(:all).and_return [
++ instance_double("Guard::Group", name: :default, title: "Default"),
++ instance_double("Guard::Group", name: :a, title: "A"),
++ instance_double("Guard::Group", name: :b, title: "B"),
++ ]
++
++ allow(plugins).to receive(:all).with(group: :default) do
++ options = { a: :b, c: :d }
++ [instance_double("Guard::Plugin", title: "Test", options: options)]
++ end
++
++ allow(plugins).to receive(:all).with(group: :a) do
++ options = { x: 1, y: 2 }
++ [instance_double("Guard::Plugin", title: "Test", options: options)]
++ end
++
++ allow(plugins).to receive(:all).with(group: :b).and_return [
++ instance_double("Guard::Plugin", title: "Another", options: [])
++ ]
++ end
++
++ it "shows the Guards and their options" do
++ subject.show
++ expect(@output).to eq result
++ end
++ end
++
++ describe ".notifiers" do
++ let(:result) do
++ <<-OUTPUT
++ +----------------+-----------+------+--------+-------+
++ | Name | Available | Used | Option | Value |
++ +----------------+-----------+------+--------+-------+
++ | gntp | ✔ | ✔ | sticky | true |
++ +----------------+-----------+------+--------+-------+
++ | terminal_title | ✘ | ✘ | | |
++ +----------------+-----------+------+--------+-------+
++ OUTPUT
++ end
++
++ before do
++ allow(Guard::Notifier).to receive(:supported).and_return(
++ gntp: ::Notiffany::Notifier::GNTP,
++ terminal_title: ::Notiffany::Notifier::TerminalTitle
++ )
++
++ allow(Guard::Notifier).to receive(:connect).once.ordered
++ allow(Guard::Notifier).to receive(:detected).
++ and_return([{ name: :gntp, options: { sticky: true } }])
++
++ allow(Guard::Notifier).to receive(:disconnect).once.ordered
++ end
++
++ it "properly connects and disconnects" do
++ expect(Guard::Notifier).to receive(:connect).once.ordered
++ expect(::Guard::Notifier).to receive(:detected).once.ordered.and_return [
++ { name: :gntp, options: { sticky: true } }
++ ]
++
++ expect(Guard::Notifier).to receive(:disconnect).once.ordered
++
++ subject.notifiers
++ end
++
++ it "shows the notifiers and their options" do
++ subject.notifiers
++ expect(@output).to eq result
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/dsl_reader_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/dsl_reader_spec.rb
+@@ -0,0 +1,58 @@
++require "guard/dsl_reader"
++
++RSpec.describe Guard::DslReader, exclude_stubs: [Guard::Dsl] do
++ methods = %w(
++ initialize guard notification interactor group watch callback
++ ignore ignore! logger scope directories clearing
++ ).map(&:to_sym)
++
++ methods.each do |meth|
++ describe "\##{meth} signature" do
++ it "matches base signature" do
++ expected = Guard::Dsl.instance_method(meth).arity
++ expect(subject.method(meth).arity).to eq(expected)
++ end
++ end
++ end
++
++ describe "guard" do
++ context "when it is a String" do
++ let(:name) { "foo" }
++ it "works without errors" do
++ expect { subject.guard(name, bar: :baz) }.to_not raise_error
++ end
++
++ it "reports the name as a String" do
++ subject.guard("foo", bar: :baz)
++ expect(subject.plugin_names).to eq(%w(foo))
++ end
++ end
++
++ context "when it is a Symbol" do
++ let(:name) { :foo }
++ it "works without errors" do
++ expect { subject.guard(name, bar: :baz) }.to_not raise_error
++ end
++
++ it "reports the name as a String" do
++ subject.guard(name, bar: :baz)
++ expect(subject.plugin_names).to eq(%w(foo))
++ end
++ end
++ end
++
++ describe "plugin_names" do
++ it "returns encountered names" do
++ subject.guard("foo", bar: :baz)
++ subject.guard("bar", bar: :baz)
++ subject.guard("baz", bar: :baz)
++ expect(subject.plugin_names).to eq(%w(foo bar baz))
++ end
++ end
++
++ describe "notification" do
++ it "handles arguments without errors" do
++ expect { subject.notification(:off) }.to_not raise_error
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/dsl_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/dsl_spec.rb
+@@ -0,0 +1,671 @@
++require "guard/plugin"
++
++require "guard/dsl"
++
++RSpec.describe Guard::Dsl do
++ let(:ui_config) { instance_double("Guard::UI::Config") }
++
++ let(:guardfile_evaluator) { instance_double(Guard::Guardfile::Evaluator) }
++ let(:interactor) { instance_double(Guard::Interactor) }
++ let(:listener) { instance_double("Listen::Listener") }
++
++ let(:session) { instance_double("Guard::Internals::Session") }
++ let(:plugins) { instance_double("Guard::Internals::Plugins") }
++ let(:groups) { instance_double("Guard::Internals::Groups") }
++ let(:state) { instance_double("Guard::Internals::State") }
++ let(:scope) { instance_double("Guard::Internals::Scope") }
++
++ let(:evaluator) do
++ proc do |contents|
++ Guard::Dsl.new.evaluate(contents, "", 1)
++ end
++ end
++
++ before do
++ stub_user_guard_rb
++ stub_const "Guard::Foo", instance_double(Guard::Plugin)
++ stub_const "Guard::Bar", instance_double(Guard::Plugin)
++ stub_const "Guard::Baz", instance_double(Guard::Plugin)
++ allow(Guard::Notifier).to receive(:turn_on)
++ allow(Guard::Interactor).to receive(:new).and_return(interactor)
++
++ allow(state).to receive(:scope).and_return(scope)
++ allow(session).to receive(:plugins).and_return(plugins)
++ allow(session).to receive(:groups).and_return(groups)
++ allow(state).to receive(:session).and_return(session)
++ allow(Guard).to receive(:state).and_return(state)
++
++ # For backtrace cleanup
++ allow(ENV).to receive(:[]).with("GEM_HOME").and_call_original
++ allow(ENV).to receive(:[]).with("GEM_PATH").and_call_original
++
++ allow(Guard::UI::Config).to receive(:new).and_return(ui_config)
++ end
++
++ describe "#ignore" do
++ context "with ignore regexps" do
++ let(:contents) { "ignore %r{^foo}, /bar/" }
++
++ it "adds ignored regexps to the listener" do
++ expect(session).to receive(:guardfile_ignore=).with([/^foo/, /bar/])
++ evaluator.call(contents)
++ end
++ end
++
++ context "with multiple ignore calls" do
++ let(:contents) { "ignore(/foo/); ignore(/bar/)" }
++
++ it "adds all ignored regexps to the listener" do
++ expect(session).to receive(:guardfile_ignore=).with([/foo/]).once
++ expect(session).to receive(:guardfile_ignore=).with([/bar/]).once
++ evaluator.call(contents)
++ end
++ end
++ end
++
++ describe "#ignore!" do
++ context "when ignoring only foo* and *bar*" do
++ let(:contents) { "ignore! %r{^foo}, /bar/" }
++
++ it "replaces listener regexps" do
++ expect(session).to receive(:guardfile_ignore_bang=).
++ with([[/^foo/, /bar/]])
++
++ evaluator.call(contents)
++ end
++ end
++
++ context "when ignoring *.txt and *.zip and ignoring! only foo*" do
++ let(:contents) { "ignore! %r{.txt$}, /.*\\.zip/\n ignore! %r{^foo}" }
++
++ it "replaces listener ignores, but keeps ignore! ignores" do
++ allow(session).to receive(:guardfile_ignore_bang=).
++ with([[/.txt$/, /.*\.zip/]])
++
++ expect(session).to receive(:guardfile_ignore_bang=).
++ with([[/.txt$/, /.*\.zip/], [/^foo/]])
++
++ evaluator.call(contents)
++ end
++ end
++ end
++
++ # TODO: remove this hack (after deprecating filter)
++ def method_for(klass, meth)
++ klass.instance_method(meth)
++ end
++
++ # TODO: deprecated #filter
++ describe "#filter alias method" do
++ subject { method_for(described_class, :filter) }
++ it { is_expected.to eq(method_for(described_class, :ignore)) }
++ end
++
++ # TODO: deprecated #filter
++ describe "#filter! alias method" do
++ subject { method_for(described_class, :filter!) }
++ it { is_expected.to eq(method_for(described_class, :ignore!)) }
++ end
++
++ describe "#notification" do
++ context "when notification" do
++ let(:contents) { "notification :growl" }
++
++ it "adds a notification to the notifier" do
++ expect(session).to receive(:guardfile_notification=).with(growl: {})
++
++ evaluator.call(contents)
++ end
++ end
++
++ context "with multiple notifications" do
++ let(:contents) do
++ "notification :growl\nnotification :ruby_gntp, host: '192.168.1.5'"
++ end
++
++ it "adds multiple notifiers" do
++ expect(session).to receive(:guardfile_notification=).with(growl: {})
++ expect(session).to receive(:guardfile_notification=).with(
++ ruby_gntp: { host: "192.168.1.5" }
++ )
++
++ evaluator.call(contents)
++ end
++ end
++ end
++
++ describe "#interactor" do
++ context "with interactor :off" do
++ let(:contents) { "interactor :off" }
++ it "disables the interactions with :off" do
++ expect(Guard::Interactor).to receive(:enabled=).with(false)
++ evaluator.call(contents)
++ end
++ end
++
++ context "with interactor options" do
++ let(:contents) { 'interactor option1: \'a\', option2: 123' }
++ it "passes the options to the interactor" do
++ expect(Guard::Interactor).to receive(:options=).
++ with(option1: "a", option2: 123)
++
++ evaluator.call(contents)
++ end
++ end
++ end
++
++ describe "#group" do
++ context "no plugins in group" do
++ let(:contents) { "group :w" }
++
++ it "displays an error" do
++ expect(::Guard::UI).to receive(:error).
++ with("No Guard plugins found in the group 'w',"\
++ " please add at least one.")
++
++ evaluator.call(contents)
++ end
++ end
++
++ context "group named :all" do
++ let(:contents) { "group :all" }
++
++ it "raises an error" do
++ expect { evaluator.call(contents) }.
++ to raise_error(
++ Guard::Dsl::Error,
++ /'all' is not an allowed group name!/
++ )
++ end
++ end
++
++ context 'group named "all"' do
++ let(:contents) { "group 'all'" }
++
++ it "raises an error" do
++ expect { evaluator.call(contents) }.
++ to raise_error(
++ Guard::Dsl::Error,
++ /'all' is not an allowed group name!/
++ )
++ end
++ end
++
++ context "with a valid guardfile" do
++ let(:contents) { valid_guardfile_string }
++
++ it "evaluates all groups" do
++ expect(groups).to receive(:add).with(:w, {})
++ expect(groups).to receive(:add).with(:y, {})
++ expect(groups).to receive(:add).with(:x, halt_on_fail: true)
++
++ expect(plugins).to receive(:add).
++ with(:pow, watchers: [], callbacks: [], group: :default)
++
++ expect(plugins).to receive(:add).
++ with(:test, watchers: [], callbacks: [], group: :w)
++
++ expect(plugins).to receive(:add).
++ with(:rspec, watchers: [], callbacks: [], group: :x).twice
++
++ expect(plugins).to receive(:add).
++ with(:less, watchers: [], callbacks: [], group: :y)
++
++ expect(session).to receive(:guardfile_notification=).with(growl: {})
++ evaluator.call(contents)
++ end
++ end
++
++ context "with multiple names" do
++ let(:contents) { "group :foo, :bar do; end" }
++ it "adds all given groups" do
++ expect(groups).to receive(:add).with(:foo, {})
++ expect(groups).to receive(:add).with(:bar, {})
++
++ evaluator.call(contents)
++ end
++ end
++ end
++
++ describe "#guard" do
++ context "with single-quoted name" do
++ let(:contents) { 'guard \'test\'' }
++
++ it "loads a guard specified as a quoted string from the DSL" do
++ expect(plugins).to receive(:add).
++ with("test", watchers: [], callbacks: [], group: :default)
++
++ evaluator.call(contents)
++ end
++ end
++
++ context "with double-quoted name" do
++ let(:contents) { 'guard "test"' }
++
++ it "loads a guard specified as a double quoted string from the DSL" do
++ expect(plugins).to receive(:add).
++ with("test", watchers: [], callbacks: [], group: :default)
++
++ evaluator.call(contents)
++ end
++ end
++
++ context "with symbol for name" do
++ let(:contents) { "guard :test" }
++
++ it "loads a guard specified as a symbol from the DSL" do
++ expect(plugins).to receive(:add).
++ with(:test, watchers: [], callbacks: [], group: :default)
++
++ evaluator.call(contents)
++ end
++ end
++
++ context "with name as symbol in parens" do
++ let(:contents) { "guard(:test)" }
++
++ it "adds the plugin" do
++ expect(plugins).to receive(:add).
++ with(:test, watchers: [], callbacks: [], group: :default)
++ evaluator.call(contents)
++ end
++ end
++
++ context "with options" do
++ let(:contents) { 'guard \'test\', opt_a: 1, opt_b: \'fancy\'' }
++
++ it "passes options to plugin" do
++ options = {
++ watchers: [],
++ callbacks: [],
++ opt_a: 1,
++ opt_b: "fancy",
++ group: :default
++ }
++
++ expect(plugins).to receive(:add).with("test", options)
++ evaluator.call(contents)
++ end
++ end
++
++ context "with groups" do
++ let(:contents) { "group :foo do; group :bar do; guard :test; end; end" }
++
++ it "adds plugin with group info" do
++ expect(groups).to receive(:add).with(:foo, {})
++ expect(groups).to receive(:add).with(:bar, {})
++ expect(plugins).to receive(:add).
++ with(:test, watchers: [], callbacks: [], group: :bar)
++
++ evaluator.call(contents)
++ end
++ end
++
++ context "with plugins in custom and default groups" do
++ let(:contents) do
++ "group :foo do; group :bar do; guard :test; end; end; guard :rspec"
++ end
++
++ it "assigns plugins to correct groups" do
++ expect(groups).to receive(:add).with(:foo, {})
++ expect(groups).to receive(:add).with(:bar, {})
++
++ expect(plugins).to receive(:add).
++ with(:test, watchers: [], callbacks: [], group: :bar)
++
++ expect(plugins).to receive(:add).
++ with(:rspec, watchers: [], callbacks: [], group: :default)
++
++ evaluator.call(contents)
++ end
++ end
++ end
++
++ describe "#watch" do
++ # TODO: this is testing too much
++ context "with watchers" do
++ let(:watcher_a) do
++ instance_double("Guard::Watcher", pattern: "a", action: proc { "b" })
++ end
++
++ let(:watcher_c) do
++ instance_double("Guard::Watcher", pattern: "c", action: nil)
++ end
++
++ let(:contents) do
++ '
++ guard :dummy do
++ watch(\'a\') { \'b\' }
++ watch(\'c\')
++ end'
++ end
++
++ it "should receive watchers when specified" do
++ call_params = {
++ watchers: [anything, anything],
++ callbacks: [],
++ group: :default
++ }
++
++ expect(plugins).to receive(:add).
++ with(:dummy, call_params) do |_, options|
++ expect(options[:watchers].size).to eq 2
++ expect(options[:watchers][0].pattern).to eq "a"
++ expect(options[:watchers][0].action.call).to eq proc { "b" }.call
++ expect(options[:watchers][1].pattern).to eq "c"
++ expect(options[:watchers][1].action).to be_nil
++ end
++
++ allow(Guard::Watcher).to receive(:new).with("a", anything).
++ and_return(watcher_a)
++
++ allow(Guard::Watcher).to receive(:new).with("c", nil).
++ and_return(watcher_c)
++
++ evaluator.call(contents)
++ end
++ end
++
++ context "with watch in main scope" do
++ let(:contents) { 'watch(\'a\')' }
++ let(:watcher) do
++ instance_double("Guard::Watcher", pattern: "a", action: nil)
++ end
++
++ it "should create an implicit no-op guard when outside a guard block" do
++ plugin_options = {
++ watchers: [anything],
++ callbacks: [],
++ group: :default
++ }
++
++ expect(plugins).to receive(:add).
++ with(:plugin, plugin_options) do |_, options|
++ expect(options[:watchers].size).to eq 1
++ expect(options[:watchers][0].pattern).to eq "a"
++ expect(options[:watchers][0].action).to be_nil
++ end
++
++ allow(Guard::Watcher).to receive(:new).with("a", nil).
++ and_return(watcher)
++
++ evaluator.call(contents)
++ end
++ end
++ end
++
++ describe "#callback" do
++ context "with " do
++ let(:contents) do
++ '
++ guard :rspec do
++
++ callback(:start_end) do |plugin, event, args|
++ "#{plugin.title} executed \'#{event}\' hook with #{args}!"
++ end
++
++ callback(MyCustomCallback, [:start_begin, :run_all_begin])
++ end'
++ end
++
++ it "creates callbacks for the guard" do
++ class MyCustomCallback
++ def self.call(_plugin, _event, _args)
++ # do nothing
++ end
++ end
++
++ params = {
++ watchers: [],
++ callbacks: [anything, anything],
++ group: :default
++ }
++
++ expect(plugins).to receive(:add).with(:rspec, params) do |_, opt|
++ # TODO: this whole block is too verbose, tests too many things at
++ # once and needs refactoring
++
++ expect(opt[:callbacks].size).to eq 2
++
++ callback_0 = opt[:callbacks][0]
++
++ expect(callback_0[:events]).to eq :start_end
++
++ plugin = instance_double("Guard::Plugin", title: "RSpec")
++ result = callback_0[:listener].call(plugin, :start_end, "foo")
++
++ expect(result).to eq 'RSpec executed \'start_end\' hook'\
++ " with foo!"
++
++ callback_1 = opt[:callbacks][1]
++ expect(callback_1[:events]).to eq [:start_begin, :run_all_begin]
++ expect(callback_1[:listener]).to eq MyCustomCallback
++ end
++
++ evaluator.call(contents)
++ end
++ end
++
++ context "without a guard block" do
++ let(:contents) do
++ '
++ callback(:start_end) do |plugin, event, args|
++ "#{plugin} executed \'#{event}\' hook with #{args}!"
++ end
++
++ callback(MyCustomCallback, [:start_begin, :run_all_begin])'
++ end
++
++ it "fails" do
++ expect { evaluator.call(contents) }.to raise_error(/guard block/i)
++ end
++ end
++ end
++
++ describe "#logger" do
++ before do
++ Guard::UI.options = nil
++ allow(ui_config).to receive(:merge!)
++ end
++
++ after do
++ Guard::UI.reset_logger
++ Guard::UI.options = nil
++ end
++
++ describe "options" do
++ let(:contents) { "" }
++
++ before do
++ evaluator.call(contents)
++ end
++
++ subject { ui_config }
++
++ context "with logger level :errror" do
++ let(:contents) { "logger level: :error" }
++ it { is_expected.to have_received(:merge!).with(level: :error) }
++ end
++
++ context "with logger level 'errror'" do
++ let(:contents) { 'logger level: \'error\'' }
++ it { is_expected.to have_received(:merge!).with(level: :error) }
++ end
++
++ context "with logger template" do
++ let(:contents) { 'logger template: \':message - :severity\'' }
++ it do
++ is_expected.to have_received(:merge!).
++ with(template: ":message - :severity")
++ end
++ end
++
++ context "with a logger time format" do
++ let(:contents) { 'logger time_format: \'%Y\'' }
++ it { is_expected.to have_received(:merge!).with(time_format: "%Y") }
++ end
++
++ context "with a logger only filter from a symbol" do
++ let(:contents) { "logger only: :cucumber" }
++ it { is_expected.to have_received(:merge!).with(only: /cucumber/i) }
++ end
++
++ context "with logger only filter from a string" do
++ let(:contents) { 'logger only: \'jasmine\'' }
++ it { is_expected.to have_received(:merge!).with(only: /jasmine/i) }
++ end
++
++ context "with logger only filter from an array of symbols and string" do
++ let(:contents) { 'logger only: [:rspec, \'cucumber\']' }
++ it do
++ is_expected.to have_received(:merge!).
++ with(only: /rspec|cucumber/i)
++ end
++ end
++
++ context "with logger except filter from a symbol" do
++ let(:contents) { "logger except: :jasmine" }
++ it { is_expected.to have_received(:merge!).with(except: /jasmine/i) }
++ end
++
++ context "with logger except filter from a string" do
++ let(:contents) { 'logger except: \'jasmine\'' }
++ it { is_expected.to have_received(:merge!).with(except: /jasmine/i) }
++ end
++
++ context "with logger except filter from array of symbols and string" do
++ let(:contents) { 'logger except: [:rspec, \'cucumber\', :jasmine]' }
++ it do
++ is_expected.to have_received(:merge!).
++ with(except: /rspec|cucumber|jasmine/i)
++ end
++ end
++ end
++
++ context "with invalid options" do
++ context "for the log level" do
++ let(:contents) { "logger level: :baz" }
++
++ it "shows a warning" do
++ expect(Guard::UI).to receive(:warning).
++ with "Invalid log level `baz` ignored."\
++ " Please use either :debug, :info, :warn or :error."
++
++ evaluator.call(contents)
++ end
++
++ it "does not set the invalid value" do
++ expect(ui_config).to receive(:merge!).with({})
++ evaluator.call(contents)
++ end
++ end
++
++ context "when having both the :only and :except options" do
++ let(:contents) { "logger only: :jasmine, except: :rspec" }
++
++ it "shows a warning" do
++ expect(Guard::UI).to receive(:warning).
++ with "You cannot specify the logger options"\
++ " :only and :except at the same time."
++ evaluator.call(contents)
++ end
++
++ it "removes the options" do
++ expect(ui_config).to receive(:merge!).with({})
++ evaluator.call(contents)
++ end
++ end
++ end
++ end
++
++ describe "#scope" do
++ context "with any parameters" do
++ let(:contents) { "scope plugins: [:foo, :bar]" }
++
++ it "sets the guardfile's default scope" do
++ expect(session).to receive(:guardfile_scope).with(plugins: [:foo, :bar])
++ evaluator.call(contents)
++ end
++ end
++ end
++
++ describe "#directories" do
++ context "with valid directories" do
++ let(:contents) { "directories %w(foo bar)" }
++ before do
++ allow(Dir).to receive(:exist?).with("foo").and_return(true)
++ allow(Dir).to receive(:exist?).with("bar").and_return(true)
++ end
++
++ it "sets the watchdirs to given values" do
++ expect(session).to receive(:watchdirs=).with(%w(foo bar))
++ evaluator.call(contents)
++ end
++ end
++
++ context "with no parameters" do
++ let(:contents) { "directories []" }
++
++ it "sets the watchdirs to empty" do
++ expect(session).to receive(:watchdirs=).with([])
++ evaluator.call(contents)
++ end
++ end
++
++ context "with non-existing directory" do
++ let(:contents) { "directories ['foo']" }
++
++ before do
++ allow(Dir).to receive(:exist?).with("foo").and_return(false)
++ end
++
++ it "fails with an error" do
++ expect(session).to_not receive(:watchdirs=)
++ expect do
++ evaluator.call(contents)
++ end.to raise_error(Guard::Dsl::Error, /Directory "foo" does not exist!/)
++ end
++ end
++ end
++
++ describe "#clear" do
++ context "with clear :off" do
++ let(:contents) { "clearing :off" }
++ it "disables clearing the screen after every task" do
++ expect(session).to receive(:clearing).with(false)
++ evaluator.call(contents)
++ end
++ end
++
++ context "with clear :on" do
++ let(:contents) { "clearing :on" }
++ it "enabled clearing the screen after every task" do
++ expect(session).to receive(:clearing).with(true)
++ evaluator.call(contents)
++ end
++ end
++ end
++
++ private
++
++ def valid_guardfile_string
++ '
++ notification :growl
++
++ guard :pow
++
++ group :w do
++ guard :test
++ end
++
++ group :x, halt_on_fail: true do
++ guard :rspec
++ guard :rspec
++ end
++
++ group :y do
++ guard :less
++ end
++ '
++ end
++end
+Index: ruby-guard/spec/lib/guard/group_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/group_spec.rb
+@@ -0,0 +1,34 @@
++require "guard/group"
++
++RSpec.describe Guard::Group do
++ subject { described_class.new(name, options) }
++
++ let(:name) { :foo }
++ let(:options) { {} }
++
++ describe "#name" do
++ specify { expect(subject.name).to eq :foo }
++
++ context "when initialized from a string" do
++ let(:name) { "foo" }
++ specify { expect(subject.name).to eq :foo }
++ end
++ end
++
++ describe "#options" do
++ context "when provided" do
++ let(:options) { { halt_on_fail: true } }
++ specify { expect(subject.options).to eq options }
++ end
++ end
++
++ describe "#title" do
++ specify { expect(subject.title).to eq "Foo" }
++ end
++
++ describe "#to_s" do
++ specify do
++ expect(subject.to_s).to eq "#<Guard::Group @name=foo @options={}>"
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/guardfile/evaluator_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/guardfile/evaluator_spec.rb
+@@ -0,0 +1,220 @@
++require "guard/guardfile/evaluator"
++
++# TODO: shouldn't be necessary
++require "guard"
++
++RSpec.describe Guard::Guardfile::Evaluator do
++ let(:options) { {} }
++ subject { described_class.new(options) }
++
++ let!(:local_guardfile) { (Pathname.pwd + "Guardfile").to_s }
++ let!(:home_guardfile) { (Pathname("~").expand_path + ".Guardfile").to_s }
++ let!(:home_config) { (Pathname("~").expand_path + ".guard.rb").to_s }
++
++ let(:valid_guardfile_string) { "group :foo; do guard :bar; end; end; " }
++
++ let(:dsl) { instance_double("Guard::Dsl") }
++
++ let(:rel_guardfile) do
++ Pathname("../relative_path_to_Guardfile").expand_path.to_s
++ end
++
++ before do
++ allow(Guard::Interactor).to receive(:new).with(false)
++ allow(Guard::Dsl).to receive(:new).and_return(dsl)
++ allow(dsl).to receive(:instance_eval)
++ end
++
++ describe ".evaluate" do
++ describe "error cases" do
++ context "with an invalid Guardfile" do
++ let(:options) { { contents: "guard :foo Bad Guardfile" } }
++
++ it "displays an error message and raises original exception" do
++ stub_user_guard_rb
++
++ allow(dsl).to receive(:evaluate).
++ and_raise(Guard::Dsl::Error,
++ "Invalid Guardfile, original error is:")
++
++ expect { subject.evaluate }.to raise_error(Guard::Dsl::Error)
++ end
++ end
++
++ context "with no Guardfile at all" do
++ it "displays an error message and exits" do
++ stub_guardfile
++ stub_user_guardfile
++ stub_user_project_guardfile
++
++ expect { subject.evaluate }.
++ to raise_error(Guard::Guardfile::Evaluator::NoGuardfileError)
++ end
++ end
++
++ context "with a problem reading a Guardfile" do
++ let(:path) { File.expand_path("Guardfile") }
++
++ before do
++ stub_user_project_guardfile
++ stub_guardfile(" ") do
++ fail Errno::EACCES.new("permission error")
++ end
++ end
++
++ it "displays an error message and exits" do
++ expect(Guard::UI).to receive(:error).with(/^Error reading file/)
++ expect { subject.evaluate }.to raise_error(SystemExit)
++ end
++ end
++
++ context "with empty Guardfile content" do
++ let(:options) { { contents: "" } }
++
++ it "displays an error message about no plugins" do
++ stub_user_guard_rb
++ stub_guardfile(" ")
++ allow(dsl).to receive(:evaluate).with("", "", 1)
++
++ expect { subject.evaluate }.
++ to raise_error(Guard::Guardfile::Evaluator::NoPluginsError)
++ end
++ end
++
++ context "when provided :contents is nil" do
++ before do
++ # Anything
++ stub_guardfile("guard :foo")
++
++ stub_user_guard_rb
++ stub_user_project_guardfile
++ stub_user_guardfile
++ end
++
++ it "does not raise error and skip it" do
++ allow(dsl).to receive(:evaluate).with("guard :foo", anything, 1)
++
++ expect(Guard::UI).to_not receive(:error)
++ expect do
++ described_class.new(contents: nil).evaluate
++ end.to_not raise_error
++ end
++ end
++
++ context "with a non-existing Guardfile given" do
++ let(:non_existing_path) { "/non/existing/path/to/Guardfile" }
++ let(:options) { { guardfile: non_existing_path } }
++
++ before do
++ stub_file(non_existing_path)
++ end
++
++ it "raises error" do
++ expect { subject.evaluate }.
++ to raise_error(Guard::Guardfile::Evaluator::NoCustomGuardfile)
++ end
++ end
++ end
++
++ describe "selection of the Guardfile data contents" do
++ context "with a valid :contents option" do
++ before do
++ stub_user_guard_rb
++ allow(dsl).to receive(:evaluate)
++ end
++
++ context "with inline content and other Guardfiles available" do
++ let(:inline_code) { "guard :foo" }
++ let(:options) do
++ {
++ contents: inline_code,
++ guardfile: "/abc/Guardfile"
++ }
++ end
++
++ before do
++ stub_file("/abc/Guardfile", "guard :bar")
++ stub_guardfile("guard :baz")
++ stub_user_guardfile("guard :buz")
++ end
++
++ it "gives ultimate precedence to inline content" do
++ expect(dsl).to receive(:evaluate).with(inline_code, "", 1)
++ subject.evaluate
++ end
++ end
++ end
++
++ context "with the :guardfile option" do
++ let(:options) { { guardfile: "../relative_path_to_Guardfile" } }
++
++ before do
++ stub_file(File.expand_path("../relative_path_to_Guardfile"),
++ valid_guardfile_string)
++ allow(dsl).to receive(:evaluate).
++ with(valid_guardfile_string, anything, 1)
++ end
++ end
++ end
++ end
++
++ describe "#inline?" do
++ before do
++ allow(dsl).to receive(:evaluate)
++ stub_guardfile("guard :bar")
++ stub_user_guard_rb
++ subject.evaluate
++ end
++
++ context "when content is provided" do
++ let(:options) { { guardfile_contents: "guard :foo" } }
++ it { is_expected.to be_inline }
++ end
++
++ context "when no content is provided" do
++ let(:options) { {} }
++ it { is_expected.to_not be_inline }
++ end
++ end
++
++ describe ".guardfile_include?" do
++ subject do
++ evaluator = described_class.new(options)
++ evaluator.evaluate
++ evaluator
++ end
++
++ let(:dsl_reader) { instance_double(Guard::DslReader) }
++
++ before do
++ allow(dsl).to receive(:evaluate)
++ allow(Guard::DslReader).to receive(:new).and_return(dsl_reader)
++ allow(dsl_reader).to receive(:evaluate)
++ stub_user_guard_rb
++ end
++
++ context "when plugin is present" do
++ let(:options) { { contents: 'guard "test" {watch("c")}' } }
++
++ it "returns true" do
++ allow(dsl_reader).
++ to receive(:evaluate).with('guard "test" {watch("c")}', "", 1)
++
++ allow(dsl_reader).to receive(:plugin_names).and_return(["test"])
++ expect(subject).to be_guardfile_include("test")
++ end
++ end
++
++ context "when plugin is not present" do
++ let(:options) { { contents: 'guard "other" {watch("c")}' } }
++
++ it "returns false" do
++ allow(dsl_reader).
++ to receive(:evaluate).with('guard "test" {watch("c")}', "", 1)
++
++ allow(dsl_reader).to receive(:plugin_names).and_return(["other"])
++ expect(subject).to_not be_guardfile_include("test")
++ end
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/guardfile/generator_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/guardfile/generator_spec.rb
+@@ -0,0 +1,141 @@
++require "guard/guardfile/generator"
++
++RSpec.describe Guard::Guardfile::Generator do
++ let(:plugin_util) { instance_double("Guard::PluginUtil") }
++ let(:guardfile_generator) { described_class.new }
++
++ it "has a valid Guardfile template" do
++ allow(File).to receive(:exist?).
++ with(described_class::GUARDFILE_TEMPLATE).and_call_original
++
++ expect(File.exist?(described_class::GUARDFILE_TEMPLATE)).to be_truthy
++ end
++
++ describe "#create_guardfile" do
++ context "with an existing Guardfile" do
++ before do
++ allow_any_instance_of(Pathname).to receive(:exist?).and_return(true)
++ end
++
++ it "does not copy the Guardfile template or notify the user" do
++ expect(::Guard::UI).to_not receive(:info)
++ expect(FileUtils).to_not receive(:cp)
++ begin
++ subject.create_guardfile
++ rescue SystemExit
++ end
++ end
++
++ it "does not display information" do
++ expect(::Guard::UI).to_not receive(:info)
++ begin
++ subject.create_guardfile
++ rescue SystemExit
++ end
++ end
++
++ it "displays an error message" do
++ expect(::Guard::UI).to receive(:error).
++ with(%r{Guardfile already exists at .*/Guardfile})
++ begin
++ subject.create_guardfile
++ rescue SystemExit
++ end
++ end
++
++ it "aborts" do
++ expect { subject.create_guardfile }.to raise_error(SystemExit)
++ end
++ end
++
++ context "without an existing Guardfile" do
++ before do
++ allow_any_instance_of(Pathname).to receive(:exist?).and_return(false)
++ allow(FileUtils).to receive(:cp)
++ end
++
++ it "does not display any kind of error or abort" do
++ expect(::Guard::UI).to_not receive(:error)
++ expect(described_class).to_not receive(:abort)
++ described_class.new.create_guardfile
++ end
++
++ it "copies the Guardfile template and notifies the user" do
++ expect(::Guard::UI).to receive(:info)
++ expect(FileUtils).to receive(:cp)
++
++ described_class.new.create_guardfile
++ end
++ end
++ end
++
++ describe "#initialize_template" do
++ context "with an installed Guard implementation" do
++ before do
++ expect(Guard::PluginUtil).to receive(:new) { plugin_util }
++
++ expect(plugin_util).to receive(:plugin_class) do
++ double("Guard::Foo").as_null_object
++ end
++ end
++
++ it "initializes the Guard" do
++ expect(plugin_util).to receive(:add_to_guardfile)
++ described_class.new.initialize_template("foo")
++ end
++ end
++
++ context "with a user defined template" do
++ let(:template) { File.join(described_class::HOME_TEMPLATES, "/bar") }
++
++ it "copies the Guardfile template and initializes the Guard" do
++ expect(IO).to receive(:read).
++ with(template).and_return "Template content"
++
++ expected = "\nTemplate content\n"
++
++ expect(IO).to receive(:binwrite).
++ with("Guardfile", expected, open_args: ["a"])
++
++ allow(plugin_util).to receive(:plugin_class).with(fail_gracefully: true)
++
++ allow(Guard::PluginUtil).to receive(:new).with("bar").
++ and_return(plugin_util)
++
++ described_class.new.initialize_template("bar")
++ end
++ end
++
++ context "when the passed guard can't be found" do
++ before do
++ expect(::Guard::PluginUtil).to receive(:new) { plugin_util }
++ allow(plugin_util).to receive(:plugin_class) { nil }
++ path = File.expand_path("~/.guard/templates/foo")
++ expect(IO).to receive(:read).with(path) do
++ fail Errno::ENOENT
++ end
++ end
++
++ it "notifies the user about the problem" do
++ expect { described_class.new.initialize_template("foo") }.
++ to raise_error(Guard::Guardfile::Generator::Error)
++ end
++ end
++ end
++
++ describe "#initialize_all_templates" do
++ let(:plugins) { %w(rspec spork phpunit) }
++
++ before do
++ expect(::Guard::PluginUtil).to receive(:plugin_names) { plugins }
++ end
++
++ it "calls Guard.initialize_template on all installed plugins" do
++ plugins.each do |g|
++ expect(subject).to receive(:initialize_template).with(g)
++ end
++
++ subject.initialize_all_templates
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/interactor_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/interactor_spec.rb
+@@ -0,0 +1,166 @@
++require "guard/interactor"
++
++# TODO: this shouldn't be necessary
++require "guard/jobs/pry_wrapper"
++require "guard/jobs/sleep"
++
++RSpec.describe Guard::Interactor do
++ let!(:pry_interactor) { instance_double("Guard::Jobs::PryWrapper") }
++ let!(:sleep_interactor) { instance_double("Guard::Jobs::Sleep") }
++ let(:pry_class) { class_double("Guard::Jobs::PryWrapper") }
++ let(:sleep_class) { class_double("Guard::Jobs::Sleep") }
++
++ before do
++ stub_const("Guard::Jobs::PryWrapper", pry_class)
++ stub_const("Guard::Jobs::Sleep", sleep_class)
++
++ allow(Guard::Jobs::PryWrapper).to receive(:new).and_return(pry_interactor)
++ allow(Guard::Jobs::Sleep).to receive(:new).and_return(sleep_interactor)
++
++ @interactor_enabled = described_class.enabled?
++ described_class.enabled = nil
++ end
++
++ after { described_class.enabled = @interactor_enabled }
++
++ describe ".enabled & .enabled=" do
++ it "returns true by default" do
++ expect(described_class).to be_enabled
++ end
++
++ context "interactor not enabled" do
++ before { described_class.enabled = false }
++
++ it "returns false" do
++ expect(described_class).to_not be_enabled
++ end
++ end
++ end
++
++ describe ".options & .options=" do
++ before { described_class.options = nil }
++
++ it "returns {} by default" do
++ expect(described_class.options).to eq({})
++ end
++
++ context "options set to { foo: :bar }" do
++ before { described_class.options = { foo: :bar } }
++
++ it "returns { foo: :bar }" do
++ expect(described_class.options).to eq(foo: :bar)
++ end
++ end
++ end
++
++ context "when enabled" do
++ before { described_class.enabled = true }
++
++ describe "#foreground" do
++ it "starts Pry" do
++ expect(pry_interactor).to receive(:foreground)
++ subject.foreground
++ end
++ end
++
++ describe "#background" do
++ it "hides Pry" do
++ expect(pry_interactor).to receive(:background)
++ subject.background
++ end
++ end
++
++ describe "#handle_interrupt" do
++ it "interrupts Pry" do
++ expect(pry_interactor).to receive(:handle_interrupt)
++ subject.handle_interrupt
++ end
++ end
++ end
++
++ context "when disabled" do
++ before { described_class.enabled = false }
++
++ describe "#foreground" do
++ it "sleeps" do
++ expect(sleep_interactor).to receive(:foreground)
++ subject.foreground
++ end
++ end
++
++ describe "#background" do
++ it "wakes up from sleep" do
++ expect(sleep_interactor).to receive(:background)
++ subject.background
++ end
++ end
++
++ describe "#handle_interrupt" do
++ it "interrupts sleep" do
++ expect(sleep_interactor).to receive(:handle_interrupt)
++ subject.handle_interrupt
++ end
++ end
++ end
++
++ describe "job selection" do
++ subject do
++ Guard::Interactor.new(no_interactions)
++ Guard::Interactor
++ end
++
++ before do
++ Guard::Interactor.enabled = dsl_enabled
++ end
++
++ context "when enabled from the DSL" do
++ let(:dsl_enabled) { true }
++
++ context "when enabled from the commandline" do
++ let(:no_interactions) { false }
++ it "uses only pry" do
++ expect(pry_class).to receive(:new)
++ expect(sleep_class).to_not receive(:new)
++ subject
++ end
++ it { is_expected.to be_enabled }
++ end
++
++ context "when disabled from the commandline" do
++ let(:no_interactions) { true }
++ it "uses only sleeper" do
++ expect(pry_class).to_not receive(:new)
++ expect(sleep_class).to receive(:new)
++ subject
++ end
++
++ # TODO: this is both a useless case and incorrect value
++ it { is_expected.to be_enabled }
++ end
++ end
++
++ context "when disabled from the DSL" do
++ let(:dsl_enabled) { false }
++
++ context "when enabled from the commandline" do
++ let(:no_interactions) { false }
++ it "uses only sleeper" do
++ expect(pry_class).to_not receive(:new)
++ expect(sleep_class).to receive(:new)
++ subject
++ end
++ it { is_expected.to_not be_enabled }
++ end
++
++ context "when disabled from the commandline" do
++ let(:no_interactions) { true }
++ it "uses only sleeper" do
++ expect(pry_class).to_not receive(:new)
++ expect(sleep_class).to receive(:new)
++ subject
++ end
++ it { is_expected.to_not be_enabled }
++ end
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/internals/debugging_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/internals/debugging_spec.rb
+@@ -0,0 +1,112 @@
++require "guard/internals/debugging"
++
++RSpec.describe Guard::Internals::Debugging do
++ let(:null) { IO::NULL }
++ let(:ui) { class_double(::Guard::UI) }
++ let(:tracing) { class_spy(::Guard::Internals::Tracing) }
++
++ before do
++ stub_const("::Guard::Internals::Tracing", tracing)
++ stub_const("::Guard::UI", ui)
++ allow(ui).to receive(:debug)
++ allow(ui).to receive(:level=)
++ allow(Thread).to receive(:abort_on_exception=)
++ end
++
++ after do
++ described_class.send(:_reset)
++ end
++
++ describe "#start" do
++ it "traces Kernel.system" do
++ expect(tracing).to receive(:trace).with(Kernel, :system) do |*_, &block|
++ expect(ui).to receive(:debug).with("Command execution: foo")
++ block.call "foo"
++ end
++ described_class.start
++ end
++
++ it "traces Kernel.`" do
++ expect(tracing).to receive(:trace).with(Kernel, :`) do |*_, &block|
++ expect(ui).to receive(:debug).with("Command execution: foo")
++ block.call("foo")
++ end
++
++ described_class.start
++ end
++
++ it "traces Open3.popen3" do
++ expect(tracing).to receive(:trace).with(Open3, :popen3) do |*_, &block|
++ expect(ui).to receive(:debug).with("Command execution: foo")
++ block.call("foo")
++ end
++
++ described_class.start
++ end
++
++ it "traces Kernel.spawn" do
++ expect(tracing).to receive(:trace).with(Kernel, :spawn) do |*_, &block|
++ expect(ui).to receive(:debug).with("Command execution: foo")
++ block.call("foo")
++ end
++
++ described_class.start
++ end
++
++ context "when not started" do
++ before { described_class.start }
++
++ it "sets logger to debug" do
++ expect(ui).to have_received(:level=).with(Logger::DEBUG)
++ end
++
++ it "makes threads abort on exceptions" do
++ expect(Thread).to have_received(:abort_on_exception=).with(true)
++ end
++ end
++
++ context "when already started" do
++ before do
++ allow(tracing).to receive(:trace)
++ described_class.start
++ end
++
++ it "does not set log level" do
++ expect(ui).to_not receive(:level=)
++ described_class.start
++ end
++ end
++ end
++
++ describe "#stop" do
++ context "when already started" do
++ before do
++ described_class.start
++ described_class.stop
++ end
++
++ it "sets logger level to info" do
++ expect(ui).to have_received(:level=).with(Logger::INFO)
++ end
++
++ it "untraces Kernel.system" do
++ expect(tracing).to have_received(:untrace).with(Kernel, :system)
++ end
++
++ it "untraces Kernel.`" do
++ expect(tracing).to have_received(:untrace).with(Kernel, :`)
++ end
++
++ it "untraces Open3.popen3" do
++ expect(tracing).to have_received(:untrace).with(Kernel, :popen3)
++ end
++ end
++
++ context "when not started" do
++ it "does not set logger level" do
++ described_class.stop
++ expect(ui).to_not have_received(:level=)
++ end
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/internals/groups_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/internals/groups_spec.rb
+@@ -0,0 +1,121 @@
++require "guard/internals/groups"
++
++RSpec.describe Guard::Internals::Groups do
++ describe "#all" do
++ let(:common) { instance_double("Guard::Group", name: :common) }
++ let(:default) { instance_double("Guard::Group", name: :default) }
++
++ before do
++ allow(Guard::Group).to receive(:new).with(:common).and_return(common)
++ allow(Guard::Group).to receive(:new).with(:default).and_return(default)
++ end
++
++ context "with only default groups" do
++ it "initializes the groups" do
++ expect(subject.all.map(&:name)).to eq [:common, :default]
++ end
++ end
++
++ context "with existing groups" do
++ let(:frontend) { instance_double("Guard::Group", name: :frontend) }
++ let(:backend) { instance_double("Guard::Group", name: :backend) }
++
++ before do
++ allow(Guard::Group).to receive(:new).with(:frontend, {}).
++ and_return(frontend)
++
++ allow(Guard::Group).to receive(:new).with(:backend, {}).
++ and_return(backend)
++
++ subject.add(:frontend)
++ subject.add(:backend)
++ end
++
++ context "with no arguments" do
++ let(:args) { [] }
++ it "returns all groups" do
++ expect(subject.all(*args)).to eq [common, default, frontend, backend]
++ end
++ end
++
++ context "with a string argument" do
++ it "returns an array of groups if plugins are found" do
++ expect(subject.all("backend")).to eq [backend]
++ end
++ end
++
++ context "with a symbol argument matching a group" do
++ it "returns an array of groups if plugins are found" do
++ expect(subject.all(:backend)).to eq [backend]
++ end
++ end
++
++ context "with a symbol argument not matching a group" do
++ it "returns an empty array when no group is found" do
++ expect(subject.all(:foo)).to be_empty
++ end
++ end
++
++ context "with a regexp argument matching a group" do
++ it "returns an array of groups" do
++ expect(subject.all(/^back/)).to eq [backend]
++ end
++ end
++
++ context "with a regexp argument not matching a group" do
++ it "returns an empty array when no group is found" do
++ expect(subject.all(/back$/)).to be_empty
++ end
++ end
++ end
++ end
++
++ # TOOD: test adding with options
++ describe "#add" do
++ let(:common) { instance_double("Guard::Group", name: :common) }
++ let(:default) { instance_double("Guard::Group", name: :default) }
++
++ before do
++ allow(Guard::Group).to receive(:new).with(:common).and_return(common)
++ allow(Guard::Group).to receive(:new).with(:default).and_return(default)
++ end
++
++ context "with existing groups" do
++ let(:frontend) { instance_double("Guard::Group", name: :frontend) }
++ let(:backend) { instance_double("Guard::Group", name: :backend) }
++
++ before do
++ allow(Guard::Group).to receive(:new).with("frontend", {}).
++ and_return(frontend)
++
++ subject.add("frontend")
++ end
++
++ it "add the given group" do
++ subject.add("frontend")
++ expect(subject.all).to match_array([common, default, frontend])
++ end
++
++ it "add the given group with options" do
++ subject.add("frontend", foo: :bar)
++ expect(subject.all).to match_array([common, default, frontend])
++ end
++
++ # TODO: what if group is added multiple times with different options?
++
++ context "with an existing group" do
++ before { subject.add("frontend") }
++
++ it "does not add duplicate groups when name is a string" do
++ subject.add("frontend")
++ expect(subject.all).to match_array([common, default, frontend])
++ end
++
++ it "does not add duplicate groups when name is a symbol" do
++ subject.add(:frontend)
++ expect(subject.all).to match_array([common, default, frontend])
++ end
++ end
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/internals/plugins_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/internals/plugins_spec.rb
+@@ -0,0 +1,138 @@
++require "guard/internals/plugins"
++
++RSpec.describe Guard::Internals::Plugins do
++ def stub_plugin(name, group)
++ instance_double("Guard::Plugin", name: name, group: group)
++ end
++
++ # TODO: all this is crazy
++ let(:frontend) { instance_double("Guard::Group", name: :frontend) }
++ let(:backend) { instance_double("Guard::Group", name: :backend) }
++
++ let(:foo_bar_frontend) { stub_plugin("foobar", frontend) }
++ let(:foo_baz_frontend) { stub_plugin("foobaz", frontend) }
++ let(:foo_bar_backend) { stub_plugin("foobar", backend) }
++ let(:foo_baz_backend) { stub_plugin("foobaz", backend) }
++
++ let(:pu_foobar) { instance_double("Guard::PluginUtil") }
++ let(:pu_foobaz) { instance_double("Guard::PluginUtil") }
++
++ before do
++ allow(Guard::PluginUtil).to receive(:new).with("foobar").
++ and_return(pu_foobar)
++
++ allow(Guard::PluginUtil).to receive(:new).with("foobaz").
++ and_return(pu_foobaz)
++
++ allow(pu_foobar).to receive(:initialize_plugin).with(group: "frontend").
++ and_return(foo_bar_frontend)
++
++ allow(pu_foobaz).to receive(:initialize_plugin).with(group: "frontend").
++ and_return(foo_baz_frontend)
++
++ allow(pu_foobar).to receive(:initialize_plugin).with(group: "backend").
++ and_return(foo_bar_backend)
++
++ allow(pu_foobaz).to receive(:initialize_plugin).with(group: "backend").
++ and_return(foo_baz_backend)
++ end
++
++ describe "#all" do
++ before do
++ subject.add("foobar", group: "frontend")
++ subject.add("foobaz", group: "frontend")
++ subject.add("foobar", group: "backend")
++ subject.add("foobaz", group: "backend")
++ end
++
++ context "with no arguments" do
++ let(:args) { [] }
++ it "returns all plugins" do
++ expect(subject.all(*args)).to eq [
++ foo_bar_frontend,
++ foo_baz_frontend,
++ foo_bar_backend,
++ foo_baz_backend
++ ]
++ end
++ end
++
++ context "find a plugin by as string" do
++ it "returns an array of plugins if plugins are found" do
++ expect(subject.all("foo-bar")).
++ to match_array([foo_bar_backend, foo_bar_frontend])
++ end
++ end
++
++ context "find a plugin by as symbol" do
++ it "returns an array of plugins if plugins are found" do
++ expect(subject.all(:'foo-bar')).
++ to match_array([foo_bar_backend, foo_bar_frontend])
++ end
++
++ it "returns an empty array when no plugin is found" do
++ expect(subject.all("foo-foo")).to be_empty
++ end
++ end
++
++ context "find plugins matching a regexp" do
++ it "returns an array of plugins if plugins are found" do
++ expect(subject.all(/^foobar/)).
++ to match_array([foo_bar_backend, foo_bar_frontend])
++ end
++
++ it "returns an empty array when no plugin is found" do
++ expect(subject.all(/foo$/)).to be_empty
++ end
++ end
++
++ context "find plugins by their group as a string" do
++ it "returns an array of plugins if plugins are found" do
++ expect(subject.all(group: "backend")).
++ to eq [foo_bar_backend, foo_baz_backend]
++ end
++ end
++
++ context "find plugins by their group as a symbol" do
++ it "returns an array of plugins if plugins are found" do
++ expect(subject.all(group: :frontend)).
++ to eq [foo_bar_frontend, foo_baz_frontend]
++ end
++
++ it "returns an empty array when no plugin is found" do
++ expect(subject.all(group: :unknown)).to be_empty
++ end
++ end
++
++ context "find plugins by their group & name" do
++ it "returns an array of plugins if plugins are found" do
++ expect(subject.all(group: "backend", name: "foo-bar")).
++ to eq [foo_bar_backend]
++ end
++
++ it "returns an empty array when no plugin is found" do
++ expect(subject.all(group: :unknown, name: :'foo-baz')).
++ to be_empty
++ end
++ end
++ end
++
++ describe "#remove" do
++ before do
++ subject.add("foobar", group: "frontend")
++ subject.add("foobaz", group: "frontend")
++ subject.add("foobar", group: "backend")
++ subject.add("foobaz", group: "backend")
++ end
++
++ it "removes given plugin" do
++ subject.remove(foo_bar_frontend)
++
++ expect(subject.all).to match_array [
++ foo_baz_frontend,
++ foo_bar_backend,
++ foo_baz_backend
++ ]
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/internals/scope_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/internals/scope_spec.rb
+@@ -0,0 +1,93 @@
++require "guard/internals/scope"
++
++RSpec.describe Guard::Internals::Scope do
++ let(:session) { instance_double("Guard::Internals::Session") }
++ let(:state) { instance_double("Guard::Internals::State") }
++
++ let(:groups) { instance_double("Guard::Internals::Groups") }
++ let(:plugins) { instance_double("Guard::Internals::Plugins") }
++
++ let(:foo_plugin) { instance_double("Guard::Plugin", name: :foo) }
++ let(:bar_plugin) { instance_double("Guard::Plugin", name: :bar) }
++ let(:baz_plugin) { instance_double("Guard::Plugin", name: :baz) }
++
++ let(:foo_group) { instance_double("Guard::Group", name: :foo) }
++ let(:bar_group) { instance_double("Guard::Group", name: :bar) }
++ let(:baz_group) { instance_double("Guard::Group", name: :baz) }
++
++ before do
++ allow(groups).to receive(:all).with("foo").and_return([foo_group])
++ allow(groups).to receive(:all).with("bar").and_return([bar_group])
++ allow(groups).to receive(:all).with("baz").and_return([baz_group])
++ allow(groups).to receive(:all).with(:baz).and_return([baz_group])
++
++ allow(plugins).to receive(:all).with("foo").and_return([foo_plugin])
++ allow(plugins).to receive(:all).with("bar").and_return([bar_plugin])
++ allow(plugins).to receive(:all).with("baz").and_return([baz_plugin])
++ allow(plugins).to receive(:all).with(:baz).and_return([baz_plugin])
++
++ allow(session).to receive(:cmdline_plugins).and_return([])
++ allow(session).to receive(:cmdline_groups).and_return([])
++ allow(session).to receive(:groups).and_return(groups)
++ allow(session).to receive(:plugins).and_return(plugins)
++
++ allow(state).to receive(:session).and_return(session)
++ allow(Guard).to receive(:state).and_return(state)
++
++ allow(session).to receive(:guardfile_plugin_scope).and_return([])
++ allow(session).to receive(:guardfile_group_scope).and_return([])
++ end
++
++ # TODO: move to Session?
++ describe "#to_hash" do
++ [:group, :plugin].each do |scope|
++ describe scope.inspect do
++ let(:hash) do
++ subject.to_hash[:"#{scope}s"].map(&:name).map(&:to_s)
++ end
++
++ # NOTE: interactor returns objects
++ context "when set from interactor" do
++ before do
++ stub_obj = send("baz_#{scope}")
++ subject.from_interactor(:"#{scope}s" => stub_obj)
++ end
++
++ it "uses interactor scope" do
++ expect(hash).to contain_exactly("baz")
++ end
++ end
++
++ context "when not set in interactor" do
++ context "when set in commandline" do
++ before do
++ allow(session).to receive(:"cmdline_#{scope}s").
++ and_return(%w(baz))
++ end
++
++ it "uses commandline scope" do
++ expect(hash).to contain_exactly("baz")
++ end
++ end
++
++ context "when not set in commandline" do
++ context "when set in Guardfile" do
++ before do
++ allow(session).to receive(:"guardfile_#{scope}_scope").
++ and_return(%w(baz))
++ end
++
++ it "uses guardfile scope" do
++ expect(hash).to contain_exactly("baz")
++ end
++ end
++ end
++ end
++ end
++ end
++ end
++
++ describe "#titles" do
++ pending
++ end
++end
+Index: ruby-guard/spec/lib/guard/internals/session_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/internals/session_spec.rb
+@@ -0,0 +1,282 @@
++require "guard/internals/session"
++
++RSpec.describe Guard::Internals::Session do
++ let(:options) { {} }
++ subject { described_class.new(options) }
++
++ let(:plugins) { instance_double("Guard::Internals::Plugins") }
++ let(:groups) { instance_double("Guard::Internals::Plugins") }
++
++ before do
++ allow(Guard::Internals::Plugins).to receive(:new).and_return(plugins)
++ allow(Guard::Internals::Groups).to receive(:new).and_return(groups)
++ end
++
++ describe "#initialize" do
++ describe "#listener_args" do
++ subject { described_class.new(options).listener_args }
++
++ context "with a single watchdir" do
++ let(:options) { { watchdir: ["/usr"] } }
++ let(:dir) { Gem.win_platform? ? "C:/usr" : "/usr" }
++ it { is_expected.to eq [:to, dir, {}] }
++ end
++
++ context "with multiple watchdirs" do
++ let(:options) { { watchdir: ["/usr", "/bin"] } }
++ let(:dir1) { Gem.win_platform? ? "C:/usr" : "/usr" }
++ let(:dir2) { Gem.win_platform? ? "C:/bin" : "/bin" }
++ it { is_expected.to eq [:to, dir1, dir2, {}] }
++ end
++
++ context "with force_polling option" do
++ let(:options) { { force_polling: true } }
++ it { is_expected.to eq [:to, Dir.pwd, force_polling: true] }
++ end
++
++ context "with latency option" do
++ let(:options) { { latency: 1.5 } }
++ it { is_expected.to eq [:to, Dir.pwd, latency: 1.5] }
++ end
++ end
++
++ context "with the plugin option" do
++ let(:options) do
++ {
++ plugin: %w(cucumber jasmine),
++ guardfile_contents: "guard :jasmine do; end; "\
++ "guard :cucumber do; end; guard :coffeescript do; end"
++ }
++ end
++
++ let(:jasmine) { instance_double("Guard::Plugin") }
++ let(:cucumber) { instance_double("Guard::Plugin") }
++ let(:coffeescript) { instance_double("Guard::Plugin") }
++
++ before do
++ stub_const "Guard::Jasmine", jasmine
++ stub_const "Guard::Cucumber", cucumber
++ stub_const "Guard::CoffeeScript", coffeescript
++ end
++
++ it "initializes the plugin scope" do
++ allow(plugins).to receive(:add).with("cucumber", {}).
++ and_return(cucumber)
++
++ allow(plugins).to receive(:add).with("jasmine", {}).
++ and_return(jasmine)
++
++ expect(subject.cmdline_plugins).to match_array(%w(cucumber jasmine))
++ end
++ end
++
++ context "with the group option" do
++ let(:options) do
++ {
++ group: %w(backend frontend),
++ guardfile_contents: "group :backend do; end; "\
++ "group :frontend do; end; group :excluded do; end"
++ }
++ end
++
++ before do
++ g3 = instance_double("Guard::Group", name: :backend, options: {})
++ g4 = instance_double("Guard::Group", name: :frontend, options: {})
++ allow(Guard::Group).to receive(:new).with("backend", {}).and_return(g3)
++ allow(Guard::Group).to receive(:new).with("frontend", {}).and_return(g4)
++ end
++
++ it "initializes the group scope" do
++ expect(subject.cmdline_groups).to match_array(%w(backend frontend))
++ end
++ end
++ end
++
++ describe "#clearing" do
++ context "when not set" do
++ context "when clearing is not set from commandline" do
++ it { is_expected.to_not be_clearing }
++ end
++
++ context "when clearing is set from commandline" do
++ let(:options) { { clear: false } }
++ it { is_expected.to_not be_clearing }
++ end
++ end
++
++ context "when set from guardfile" do
++ context "when set to :on" do
++ before { subject.clearing(true) }
++ it { is_expected.to be_clearing }
++ end
++
++ context "when set to :off" do
++ before { subject.clearing(false) }
++ it { is_expected.to_not be_clearing }
++ end
++ end
++ end
++
++ describe "#guardfile_ignore=" do
++ context "when set from guardfile" do
++ before { subject.guardfile_ignore = [/foo/] }
++ specify { expect(subject.guardfile_ignore).to eq([/foo/]) }
++ end
++
++ context "when set multiple times from guardfile" do
++ before do
++ subject.guardfile_ignore = [/foo/]
++ subject.guardfile_ignore = [/bar/]
++ end
++ specify { expect(subject.guardfile_ignore).to eq([/foo/, /bar/]) }
++ end
++
++ context "when unset" do
++ specify { expect(subject.guardfile_ignore).to eq([]) }
++ end
++ end
++
++ describe "#guardfile_ignore_bang=" do
++ context "when set from guardfile" do
++ before { subject.guardfile_ignore_bang = [/foo/] }
++ specify { expect(subject.guardfile_ignore_bang).to eq([/foo/]) }
++ end
++
++ context "when unset" do
++ specify { expect(subject.guardfile_ignore_bang).to eq([]) }
++ end
++ end
++
++ describe "#guardfile_scope" do
++ before do
++ subject.guardfile_scope(scope)
++ end
++
++ context "with a groups scope" do
++ let(:scope) { { groups: [:foo] } }
++ it "sets the groups" do
++ expect(subject.guardfile_group_scope).to eq([:foo])
++ end
++ end
++
++ context "with a group scope" do
++ let(:scope) { { group: [:foo] } }
++ it "sets the groups" do
++ expect(subject.guardfile_group_scope).to eq([:foo])
++ end
++ end
++
++ context "with a plugin scope" do
++ let(:scope) { { plugin: [:foo] } }
++ it "sets the plugins" do
++ expect(subject.guardfile_plugin_scope).to eq([:foo])
++ end
++ end
++
++ context "with a plugins scope" do
++ let(:scope) { { plugins: [:foo] } }
++ it "sets the plugins" do
++ expect(subject.guardfile_plugin_scope).to eq([:foo])
++ end
++ end
++ end
++
++ describe ".convert_scope" do
++ let(:foo) { instance_double("Guard::Plugin", name: "foo") }
++ let(:bar) { instance_double("Guard::Plugin", name: "bar") }
++ let(:backend) { instance_double("Guard::Group", name: "backend") }
++ let(:frontend) { instance_double("Guard::Group", name: "frontend") }
++
++ before do
++ stub_const "Guard::Foo", class_double("Guard::Plugin")
++ stub_const "Guard::Bar", class_double("Guard::Plugin")
++
++ allow(plugins).to receive(:all).with("backend").and_return([])
++ allow(plugins).to receive(:all).with("frontend").and_return([])
++ allow(plugins).to receive(:all).with("foo").and_return([foo])
++ allow(plugins).to receive(:all).with("bar").and_return([bar])
++ allow(plugins).to receive(:all).with("unknown").and_return([])
++ allow(plugins).to receive(:all).with("scope").and_return([])
++
++ allow(groups).to receive(:all).with("backend").and_return([backend])
++ allow(groups).to receive(:all).with("frontend").and_return([frontend])
++ allow(groups).to receive(:all).with("unknown").and_return([])
++ allow(groups).to receive(:all).with("scope").and_return([])
++ end
++
++ it "returns a group scope" do
++ scopes, = subject.convert_scope %w(backend)
++ expect(scopes).to eq(groups: [backend], plugins: [])
++ scopes, = subject.convert_scope %w(frontend)
++ expect(scopes).to eq(groups: [frontend], plugins: [])
++ end
++
++ it "returns a plugin scope" do
++ scopes, = subject.convert_scope %w(foo)
++ expect(scopes).to eq(plugins: [foo], groups: [])
++ scopes, = subject.convert_scope %w(bar)
++ expect(scopes).to eq(plugins: [bar], groups: [])
++ end
++
++ it "returns multiple group scopes" do
++ scopes, = subject.convert_scope %w(backend frontend)
++ expected = { groups: [backend, frontend], plugins: [] }
++ expect(scopes).to eq(expected)
++ end
++
++ it "returns multiple plugin scopes" do
++ scopes, = subject.convert_scope %w(foo bar)
++ expect(scopes).to eq(plugins: [foo, bar], groups: [])
++ end
++
++ it "returns a plugin and group scope" do
++ scopes, = subject.convert_scope %w(foo backend)
++ expect(scopes).to eq(plugins: [foo], groups: [backend])
++ end
++
++ it "returns the unkown scopes" do
++ _, unknown = subject.convert_scope %w(unknown scope)
++ expect(unknown).to eq %w(unknown scope)
++ end
++ end
++
++ describe "#guardfile_notification=" do
++ context "when set from guardfile" do
++ before do
++ subject.guardfile_notification = { foo: { bar: :baz } }
++ end
++
++ specify do
++ expect(subject.notify_options).to eq(
++ notify: true,
++ notifiers: {
++ foo: { bar: :baz }
++ }
++ )
++ end
++ end
++
++ context "when set multiple times from guardfile" do
++ before do
++ subject.guardfile_notification = { foo: { param: 1 } }
++ subject.guardfile_notification = { bar: { param: 2 } }
++ end
++
++ it "merges results" do
++ expect(subject.notify_options).to eq(
++ notify: true,
++ notifiers: {
++ foo: { param: 1 },
++ bar: { param: 2 }
++ }
++ )
++ end
++ end
++
++ context "when unset" do
++ specify do
++ expect(subject.notify_options).to eq(notify: true, notifiers: {})
++ end
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/internals/state_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/internals/state_spec.rb
+@@ -0,0 +1,45 @@
++require "guard/internals/state"
++
++RSpec.describe Guard::Internals::State do
++ let(:options) { {} }
++ subject { described_class.new(options) }
++
++ let(:scope) { instance_double("Guard::Internals::Scope") }
++ let(:plugins) { instance_double("Guard::Internals::Plugins") }
++ let(:groups) { instance_double("Guard::Internals::Groups") }
++ let(:session) { instance_double("Guard::Internals::Session") }
++
++ before do
++ allow(Guard::Internals::Session).to receive(:new).and_return(session)
++ allow(Guard::Internals::Scope).to receive(:new).and_return(scope)
++ allow(session).to receive(:debug?).and_return(false)
++ allow(session).to receive(:plugins).and_return(plugins)
++ allow(session).to receive(:groups).and_return(groups)
++ end
++
++ describe "#initialize" do
++ describe "debugging" do
++ let(:options) { { debug: debug } }
++ before do
++ allow(session).to receive(:debug?).and_return(debug)
++ expect(Guard::Internals::Session).to receive(:new).with(debug: debug)
++ end
++
++ context "when debug is set to true" do
++ let(:debug) { true }
++ it "sets up debugging" do
++ expect(Guard::Internals::Debugging).to receive(:start)
++ subject
++ end
++ end
++
++ context "when debug is set to false" do
++ let(:debug) { false }
++ it "does not set up debugging" do
++ expect(Guard::Internals::Debugging).to_not receive(:start)
++ subject
++ end
++ end
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/internals/tracing_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/internals/tracing_spec.rb
+@@ -0,0 +1,113 @@
++require "guard/internals/tracing"
++
++RSpec.describe Guard::Internals::Tracing do
++ let(:null) { IO::NULL }
++
++ # NOTE: Calling system() is different from calling Kernel.system()
++ #
++ # We can capture system() calls by stubbing Kernel.system, but to capture
++ # Kernel.system() calls, we need to stub the module's metaclass methods.
++ #
++ # Stubbing just Kernel.system isn't "deep" enough, but not only that,
++ # we don't want to stub here, we want to TEST the stubbing
++ #
++ describe "Module method tracing" do
++ let(:result) { Kernel.send(meth, *args) }
++ subject { result }
++
++ let(:callback) { double("callback", call: true) }
++
++ # Since we can't stub the C code in Ruby, only "right" way to test this is:
++ # actually call a real command and compare the output
++ before { allow(Kernel).to receive(meth).and_call_original }
++
++ context "when tracing" do
++ before do
++ described_class.trace(Kernel, meth) { |*args| callback.call(*args) }
++ subject
++ end
++
++ after { described_class.untrace(Kernel, meth) }
++
++ context "with no command arguments" do
++ let(:args) { ["echo >#{null}"] }
++
++ context "when #system" do
++ let(:meth) { "system" }
++
++ it { is_expected.to eq(true) }
++
++ it "outputs command" do
++ expect(callback).to have_received(:call).with("echo >#{null}")
++ end
++ end
++
++ context "when backticks" do
++ let(:meth) { :` }
++
++ it { is_expected.to eq("") }
++
++ it "outputs command" do
++ expect(callback).to have_received(:call).with("echo >#{null}")
++ end
++ end
++ end
++
++ context "with command arguments" do
++ let(:args) { %w(true 123) }
++
++ context "when #system" do
++ let(:meth) { "system" }
++
++ it { is_expected.to eq(true) }
++
++ it "outputs command arguments" do
++ expect(callback).to have_received(:call).with("true", "123")
++ end
++ end
++ end
++ end
++
++ context "when not tracing" do
++ before { subject }
++
++ context "with no command arguments" do
++ let(:args) { ["echo test > #{null}"] }
++
++ context "when #system" do
++ let(:meth) { :system }
++
++ it { is_expected.to eq(true) }
++
++ it "does not output anything" do
++ expect(callback).to_not have_received(:call)
++ end
++ end
++
++ context "when backticks" do
++ let(:meth) { :` }
++
++ it { is_expected.to eq("") }
++
++ it "does not output anything" do
++ expect(callback).to_not have_received(:call)
++ end
++ end
++ end
++
++ context "with command arguments" do
++ let(:args) { %w(true 123) }
++
++ context "when #system" do
++ let(:meth) { :system }
++
++ it { is_expected.to eq(true) }
++
++ it "does not output anything" do
++ expect(callback).to_not have_received(:call)
++ end
++ end
++ end
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/internals/traps_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/internals/traps_spec.rb
+@@ -0,0 +1,34 @@
++require "guard/internals/traps"
++
++RSpec.describe Guard::Internals::Traps do
++ describe ".handle" do
++ let(:signal_class) { class_double(Signal) }
++
++ before do
++ stub_const("Signal", signal_class)
++ end
++
++ context "with a supported signal name" do
++ let(:signal) { "USR1" }
++
++ it "sets up a handler" do
++ allow(Signal).to receive(:list).and_return("USR1" => 10)
++ allow(Signal).to receive(:trap).with(signal) do |_, &block|
++ block.call
++ end
++
++ expect { |b| described_class.handle(signal, &b) }.to yield_control
++ end
++ end
++
++ context "with an unsupported signal name" do
++ let(:signal) { "ABCD" }
++
++ it "does not set a handler" do
++ allow(Signal).to receive(:list).and_return("KILL" => 9)
++ expect(Signal).to_not receive(:trap)
++ described_class.handle(signal)
++ end
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/jobs/pry_wrapper_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/jobs/pry_wrapper_spec.rb
+@@ -0,0 +1,183 @@
++require "guard/jobs/pry_wrapper"
++
++RSpec.describe Guard::Jobs::PryWrapper do
++ subject { described_class.new({}) }
++ let(:listener) { instance_double("Listen::Listener") }
++ let(:pry_config) { double("pry_config") }
++ let(:pry_history) { double("pry_history") }
++ let(:pry_commands) { double("pry_commands") }
++ let(:pry_hooks) { double("pry_hooks") }
++ let(:terminal_settings) { instance_double("Guard::Jobs::TerminalSettings") }
++
++ let(:session) { instance_double("Guard::Internals::Session") }
++ let(:plugins) { instance_double("Guard::Internals::Plugins") }
++ let(:groups) { instance_double("Guard::Internals::Groups") }
++ let(:state) { instance_double("Guard::Internals::State") }
++ let(:scope) { instance_double("Guard::Internals::Scope") }
++
++ before do
++ # TODO: this are here to mock out Pry completely
++ allow(pry_config).to receive(:prompt=)
++ allow(pry_config).to receive(:should_load_rc=)
++ allow(pry_config).to receive(:should_load_local_rc=)
++ allow(pry_config).to receive(:hooks).and_return(pry_hooks)
++ allow(pry_config).to receive(:history).and_return(pry_history)
++ allow(pry_config).to receive(:commands).and_return(pry_commands)
++ allow(pry_history).to receive(:file=)
++ allow(pry_commands).to receive(:alias_command)
++ allow(pry_commands).to receive(:create_command)
++ allow(pry_commands).to receive(:command)
++ allow(pry_commands).to receive(:block_command)
++ allow(pry_hooks).to receive(:add_hook)
++
++ allow(Guard).to receive(:listener).and_return(listener)
++ allow(Pry).to receive(:config).and_return(pry_config)
++ allow(Shellany::Sheller).to receive(:run).with(*%w(hash stty)) { false }
++
++ allow(groups).to receive(:all).and_return([])
++ allow(session).to receive(:groups).and_return(groups)
++
++ allow(plugins).to receive(:all).and_return([])
++ allow(session).to receive(:plugins).and_return(plugins)
++ allow(state).to receive(:session).and_return(session)
++ allow(state).to receive(:scope).and_return(scope)
++ allow(Guard).to receive(:state).and_return(state)
++
++ allow(Guard::Commands::All).to receive(:import)
++ allow(Guard::Commands::Change).to receive(:import)
++ allow(Guard::Commands::Reload).to receive(:import)
++ allow(Guard::Commands::Pause).to receive(:import)
++ allow(Guard::Commands::Notification).to receive(:import)
++ allow(Guard::Commands::Show).to receive(:import)
++ allow(Guard::Commands::Scope).to receive(:import)
++
++ allow(Guard::Jobs::TerminalSettings).to receive(:new).
++ and_return(terminal_settings)
++
++ allow(terminal_settings).to receive(:configurable?).and_return(false)
++ allow(terminal_settings).to receive(:save)
++ allow(terminal_settings).to receive(:restore)
++ end
++
++ describe "#foreground" do
++ before do
++ allow(Pry).to receive(:start) do
++ # sleep for a long time (anything > 0.6)
++ sleep 2
++ end
++ end
++
++ after do
++ subject.background
++ end
++
++ it "waits for Pry thread to finish" do
++ was_alive = false
++
++ Thread.new do
++ sleep 0.1
++ was_alive = subject.send(:thread).alive?
++ subject.background
++ end
++
++ subject.foreground # blocks
++ expect(was_alive).to be
++ end
++
++ it "prevents the Pry thread from being killed too quickly" do
++ start = Time.now.to_f
++
++ Thread.new do
++ sleep 0.1
++ subject.background
++ end
++
++ subject.foreground # blocks
++ killed_moment = Time.now.to_f
++
++ expect(killed_moment - start).to be > 0.5
++ end
++
++ it "return :stopped when brought into background" do
++ Thread.new do
++ sleep 0.1
++ subject.background
++ end
++
++ expect(subject.foreground).to be(:stopped)
++ end
++ end
++
++ describe "#background" do
++ before do
++ allow(Pry).to receive(:start) do
++ # 0.5 is enough for Pry, so we use 0.4
++ sleep 0.4
++ end
++ end
++
++ it "kills the Pry thread" do
++ subject.foreground
++ sleep 1 # give Pry 0.5 sec to boot
++ subject.background
++ sleep 0.25 # to let Pry get killed asynchronously
++
++ expect(subject.send(:thread)).to be_nil
++ end
++ end
++
++ describe "#_prompt(ending_char)" do
++ let(:prompt) { subject.send(:_prompt, ">") }
++
++ before do
++ allow(Shellany::Sheller).to receive(:run).with(*%w(hash stty)) { false }
++ allow(scope).to receive(:titles).and_return(["all"])
++
++ allow(listener).to receive(:paused?).and_return(false)
++
++ expect(Pry).to receive(:view_clip).and_return("main")
++ end
++
++ let(:pry) { instance_double(Pry, input_array: []) }
++
++ context "Guard is not paused" do
++ it 'displays "guard"' do
++ expect(prompt.call(double, 0, pry)).
++ to eq "[0] guard(main)> "
++ end
++ end
++
++ context "Guard is paused" do
++ before do
++ allow(listener).to receive(:paused?).and_return(true)
++ end
++
++ it 'displays "pause"' do
++ expect(prompt.call(double, 0, pry)).
++ to eq "[0] pause(main)> "
++ end
++ end
++
++ context "with a groups scope" do
++ before do
++ allow(scope).to receive(:titles).and_return(%w(Backend Frontend))
++ end
++
++ it "displays the group scope title in the prompt" do
++ expect(prompt.call(double, 0, pry)).
++ to eq "[0] Backend,Frontend guard(main)> "
++ end
++ end
++
++ context "with a plugins scope" do
++ before do
++ allow(scope).to receive(:titles).and_return(%w(RSpec Ronn))
++ end
++
++ it "displays the group scope title in the prompt" do
++ result = prompt.call(double, 0, pry)
++ expect(result).to eq "[0] RSpec,Ronn guard(main)> "
++ end
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/jobs/sleep_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/jobs/sleep_spec.rb
+@@ -0,0 +1,59 @@
++require "guard/jobs/sleep"
++
++RSpec.describe Guard::Jobs::Sleep do
++ subject { described_class.new({}) }
++
++ describe "#foreground" do
++ it "sleeps" do
++ status = "unknown"
++
++ Thread.new do
++ sleep 0.1
++ status = Thread.main.status
++ subject.background
++ end
++
++ subject.foreground
++
++ expect(status).to eq("sleep")
++ end
++
++ it "returns :stopped when put to background" do
++ Thread.new do
++ sleep 0.1
++ subject.background
++ end
++
++ expect(subject.foreground).to eq(:stopped)
++ end
++ end
++
++ describe "#background" do
++ it "wakes up main thread" do
++ status = "unknown"
++
++ Thread.new do
++ sleep 0.1 # give enough time for foreground to put main thread to sleep
++
++ subject.background
++
++ sleep 0.1 # cause test to fail every time (without busy loop below)
++
++ status = Thread.main.status
++
++ Thread.main.wakeup # to get "red" in TDD without hanging
++ end
++
++ subject.foreground # go to sleep
++
++ # Keep main thread busy until above thread has a chance to get status
++ begin
++ value = 0
++ Timeout.timeout(0.1) { loop { value += 1 } }
++ rescue Timeout::Error
++ end
++
++ expect(status).to eq("run")
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/notifier_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/notifier_spec.rb
+@@ -0,0 +1,81 @@
++require "guard/notifier"
++
++RSpec.describe Guard::Notifier do
++ subject { described_class }
++ let(:notifier) { instance_double("Notiffany::Notifier") }
++
++ before do
++ allow(Notiffany::Notifier).to receive(:new).and_return(notifier)
++ end
++
++ after do
++ Guard::Notifier.instance_variable_set(:@notifier, nil)
++ end
++
++ describe "toggle_notification" do
++ before do
++ allow(notifier).to receive(:enabled?).and_return(true)
++ end
++
++ context "with available notifiers" do
++ context "when currently on" do
++ before do
++ allow(notifier).to receive(:active?).and_return(true)
++ subject.connect
++ end
++
++ it "suspends notifications" do
++ expect(notifier).to receive(:turn_off)
++ subject.toggle
++ end
++ end
++
++ context "when currently off" do
++ before do
++ subject.connect
++ allow(notifier).to receive(:active?).and_return(false)
++ end
++
++ it "resumes notifications" do
++ expect(notifier).to receive(:turn_on)
++ subject.toggle
++ end
++ end
++ end
++ end
++
++ describe ".notify" do
++ before do
++ subject.connect
++ allow(notifier).to receive(:notify)
++ end
++
++ context "with no options" do
++ it "notifies" do
++ expect(notifier).to receive(:notify).with("A", {})
++ subject.notify("A")
++ end
++ end
++
++ context "with multiple parameters" do
++ it "notifies" do
++ expect(notifier).to receive(:notify).
++ with("A", priority: 2, image: :failed)
++ subject.notify("A", priority: 2, image: :failed)
++ end
++ end
++
++ context "with a runtime error" do
++ before do
++ allow(notifier).to receive(:notify).and_raise(RuntimeError, "an error")
++ end
++
++ it "shows an error" do
++ expect(Guard::UI).to receive(:error).
++ with(/Notification failed for .+: an error/)
++
++ subject.notify("A", priority: 2, image: :failed)
++ end
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/options_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/options_spec.rb
+@@ -0,0 +1,31 @@
++require "guard/options"
++
++RSpec.describe Guard::Options do
++ describe ".initialize" do
++ it "handles nil options" do
++ expect { described_class.new(nil) }.to_not raise_error
++ end
++
++ it "has indifferent access" do
++ options = described_class.new({ foo: "bar" }, "foo2" => "baz")
++
++ expect(options[:foo]).to eq "bar"
++ expect(options["foo"]).to eq "bar"
++
++ expect(options[:foo2]).to eq "baz"
++ expect(options["foo2"]).to eq "baz"
++ end
++
++ it "can be passed defaults" do
++ options = described_class.new({}, foo: "bar")
++
++ expect(options[:foo]).to eq "bar"
++ end
++
++ it "merges the sensible defaults to the given options" do
++ options = described_class.new({ plugin: ["rspec"] }, plugin: ["test"])
++
++ expect(options[:plugin]).to eq ["rspec"]
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/plugin_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/plugin_spec.rb
+@@ -0,0 +1,235 @@
++require "guard/plugin"
++
++require "guard/watcher"
++
++RSpec.describe Guard::Plugin do
++ let(:default) { instance_double("Guard::Group") }
++ let(:test) { instance_double("Guard::Group") }
++
++ let(:session) { instance_double("Guard::Internals::Session") }
++ let(:groups) { instance_double("Guard::Internals::Groups") }
++ let(:state) { instance_double("Guard::Internals::State") }
++
++ before do
++ allow(groups).to receive(:add).with(:default).and_return(default)
++ allow(groups).to receive(:add).with(:test).and_return(test)
++
++ allow(session).to receive(:groups).and_return(groups)
++ allow(state).to receive(:session).and_return(session)
++ allow(Guard).to receive(:state).and_return(state)
++ end
++
++ # TODO: this should already be done in spec_helper!
++ after do
++ klass = described_class
++ klass.instance_variables.each do |var|
++ klass.instance_variable_set(var, nil)
++ end
++ end
++
++ describe "#initialize" do
++ it "assigns the defined watchers" do
++ watchers = [double("foo")]
++ expect(Guard::Plugin.new(watchers: watchers).watchers).to eq watchers
++ end
++
++ it "assigns the defined options" do
++ options = { a: 1, b: 2 }
++ expect(Guard::Plugin.new(options).options).to eq options
++ end
++
++ context "with a group in the options" do
++ it "assigns the given group" do
++ expect(Guard::Plugin.new(group: :test).group).to eq test
++ end
++ end
++
++ context "without a group in the options" do
++ it "assigns a default group" do
++ allow(groups).to receive(:add).with(:default).and_return(default)
++ expect(Guard::Plugin.new.group).to eq default
++ end
++ end
++
++ context "with a callback" do
++ it "adds the callback" do
++ block = instance_double(Proc)
++ events = [:start_begin, :start_end]
++ callbacks = [{ events: events, listener: block }]
++ Guard::Plugin.new(callbacks: callbacks)
++ expect(Guard::Plugin.callbacks.first[0][0].callbacks).to eq(callbacks)
++ end
++ end
++ end
++
++ context "with a plugin instance" do
++ subject do
++ module Guard
++ class DuMmy < Guard::Plugin
++ end
++ end
++ Guard::DuMmy
++ end
++
++ after do
++ Guard.send(:remove_const, :DuMmy)
++ end
++
++ describe ".non_namespaced_classname" do
++ it "remove the Guard:: namespace" do
++ expect(subject.non_namespaced_classname).to eq "DuMmy"
++ end
++ end
++
++ describe ".non_namespaced_name" do
++ it "remove the Guard:: namespace and downcase" do
++ expect(subject.non_namespaced_name).to eq "dummy"
++ end
++ end
++
++ describe ".template" do
++ before do
++ allow(File).to receive(:read)
++ end
++
++ it "reads the default template" do
++ expect(File).to receive(:read).
++ with("/guard-dummy/lib/guard/dummy/templates/Guardfile") { true }
++
++ subject.template("/guard-dummy")
++ end
++ end
++
++ describe "#name" do
++ it "outputs the short plugin name" do
++ expect(subject.new.name).to eq "dummy"
++ end
++ end
++
++ describe "#title" do
++ it "outputs the plugin title" do
++ expect(subject.new.title).to eq "DuMmy"
++ end
++ end
++
++ describe "#to_s" do
++ let(:default) { instance_double("Guard::Group", name: :default) }
++
++ it "output the short plugin name" do
++ expect(subject.new.to_s).
++ to match(/#<Guard::DuMmy @name=dummy .*>/)
++ end
++ end
++ end
++
++ let(:listener) { instance_double(Proc, call: nil) }
++
++ describe ".add_callback" do
++ let(:foo) { double("foo plugin") }
++
++ it "can add a run_on_modifications callback" do
++ described_class.add_callback(
++ listener,
++ foo,
++ :run_on_modifications_begin
++ )
++
++ result = described_class.callbacks[[foo, :run_on_modifications_begin]]
++ expect(result).to include(listener)
++ end
++
++ it "can add multiple callbacks" do
++ described_class.add_callback(listener, foo, [:event1, :event2])
++
++ result = described_class.callbacks[[foo, :event1]]
++ expect(result).to include(listener)
++
++ result = described_class.callbacks[[foo, :event2]]
++ expect(result).to include(listener)
++ end
++ end
++
++ describe ".notify" do
++ let(:foo) { double("foo plugin") }
++ let(:bar) { double("bar plugin") }
++
++ before do
++ described_class.add_callback(listener, foo, :start_begin)
++ end
++
++ it "sends :call to the given Guard class's start_begin callback" do
++ expect(listener).to receive(:call).with(foo, :start_begin, "args")
++ described_class.notify(foo, :start_begin, "args")
++ end
++
++ it "sends :call to the given Guard class's start_begin callback" do
++ expect(listener).to receive(:call).with(foo, :start_begin, "args")
++ described_class.notify(foo, :start_begin, "args")
++ end
++
++ it "runs only the given callbacks" do
++ listener2 = double("listener2")
++ described_class.add_callback(listener2, foo, :start_end)
++ expect(listener2).to_not receive(:call).with(foo, :start_end)
++ described_class.notify(foo, :start_begin)
++ end
++
++ it "runs callbacks only for the guard given" do
++ described_class.add_callback(listener, bar, :start_begin)
++ expect(listener).to_not receive(:call).with(bar, :start_begin)
++ described_class.notify(foo, :start_begin)
++ end
++ end
++
++ describe "#hook" do
++ let(:foo) { double("foo plugin") }
++
++ before do
++ described_class.add_callback(listener, foo, :start_begin)
++ end
++
++ it "notifies the hooks" do
++ class Foo < described_class
++ def run_all
++ hook :begin
++ hook :end
++ end
++ end
++
++ foo = Foo.new
++ expect(described_class).to receive(:notify).with(foo, :run_all_begin)
++ expect(described_class).to receive(:notify).with(foo, :run_all_end)
++ foo.run_all
++ end
++
++ it "passes the hooks name" do
++ class Foo < described_class
++ def start
++ hook "my_hook"
++ end
++ end
++
++ foo = Foo.new
++ expect(described_class).to receive(:notify).with(foo, :my_hook)
++ foo.start
++ end
++
++ it "accepts extra arguments" do
++ class Foo < described_class
++ def stop
++ hook :begin, "args"
++ hook "special_sauce", "first_arg", "second_arg"
++ end
++ end
++ foo = Foo.new
++
++ expect(described_class).to receive(:notify).
++ with(foo, :stop_begin, "args")
++
++ expect(described_class).to receive(:notify).
++ with(foo, :special_sauce, "first_arg", "second_arg")
++
++ foo.stop
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/plugin_util_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/plugin_util_spec.rb
+@@ -0,0 +1,303 @@
++require "guard/plugin_util"
++
++require "guard/guardfile/evaluator"
++
++RSpec.describe Guard::PluginUtil do
++ let(:guard_rspec_class) { class_double("Guard::Plugin") }
++ let(:guard_rspec) { instance_double("Guard::Plugin") }
++ let(:evaluator) { instance_double("Guard::Guardfile::Evaluator") }
++ let(:session) { instance_double("Guard::Internals::Session") }
++ let(:state) { instance_double("Guard::Internals::State") }
++
++ before do
++ allow(session).to receive(:evaluator_options).and_return({})
++ allow(state).to receive(:session).and_return(session)
++ allow(Guard).to receive(:state).and_return(state)
++ allow(Guard::Guardfile::Evaluator).to receive(:new).and_return(evaluator)
++ end
++
++ describe ".plugin_names" do
++ before do
++ spec = Gem::Specification
++ gems = [
++ instance_double(spec, name: "guard-myplugin"),
++ instance_double(spec, name: "gem1", full_gem_path: "/gem1"),
++ instance_double(spec, name: "gem2", full_gem_path: "/gem2"),
++ instance_double(spec, name: "guard-compat"),
++ ]
++ allow(File).to receive(:exist?).
++ with("/gem1/lib/guard/gem1.rb") { false }
++
++ allow(File).to receive(:exist?).
++ with("/gem2/lib/guard/gem2.rb") { true }
++
++ gem = class_double(Gem::Specification)
++ stub_const("Gem::Specification", gem)
++ expect(Gem::Specification).to receive(:find_all) { gems }
++ end
++
++ it "returns the list of guard gems" do
++ expect(described_class.plugin_names).to include("myplugin")
++ end
++
++ it "returns the list of embedded guard gems" do
++ expect(described_class.plugin_names).to include("gem2")
++ end
++
++ it "ignores guard-compat" do
++ expect(described_class.plugin_names).to_not include("compat")
++ end
++ end
++
++ describe "#initialize" do
++ it "accepts a name without guard-" do
++ expect(described_class.new("rspec").name).to eq "rspec"
++ end
++
++ it "accepts a name with guard-" do
++ expect(described_class.new("guard-rspec").name).to eq "rspec"
++ end
++ end
++
++ describe "#initialize_plugin" do
++ let(:plugin_util) { described_class.new("rspec") }
++
++ before do
++ allow_any_instance_of(described_class).
++ to receive(:plugin_class).
++ and_return(guard_rspec_class)
++ end
++
++ context "with a plugin inheriting from Guard::Plugin" do
++ before do
++ expect(guard_rspec_class).to receive(:superclass) { ::Guard::Plugin }
++ end
++
++ it "instantiate the plugin using the new API" do
++ options = { watchers: ["watcher"], group: "foo" }
++ expect(guard_rspec_class).to receive(:new).with(options) { guard_rspec }
++
++ expect(plugin_util.initialize_plugin(options)).to eq guard_rspec
++ end
++ end
++ end
++
++ describe "#plugin_location" do
++ subject { described_class.new("rspec") }
++
++ it "returns the path of a Guard gem" do
++ expect(Gem::Specification).to receive(:find_by_name).
++ with("guard-rspec") { double(full_gem_path: "gems/guard-rspec") }
++ expect(subject.plugin_location).to eq "gems/guard-rspec"
++ end
++ end
++
++ describe "#plugin_class" do
++ after do
++ # TODO: use RSpec's stub const
++ consts = [:Classname,
++ :DashedClassName,
++ :UnderscoreClassName,
++ :VSpec,
++ :Inline]
++
++ consts.each do |const|
++ begin
++ Guard.send(:remove_const, const)
++ rescue NameError
++ end
++ end
++ end
++
++ it "reports an error if the class is not found" do
++ expect(::Guard::UI).to receive(:error).with(/Could not load/)
++ expect(::Guard::UI).to receive(:error).with(/Error is: cannot load/)
++ expect(::Guard::UI).to receive(:error).with(/plugin_util.rb/)
++
++ plugin = described_class.new("notAGuardClass")
++ allow(plugin).to receive(:require).with("guard/notaguardclass").
++ and_raise(LoadError, "cannot load such file --")
++
++ plugin.plugin_class
++ end
++
++ context "with a nested Guard class" do
++ it "resolves the Guard class from string" do
++ plugin = described_class.new("classname")
++ expect(plugin).to receive(:require) do |classname|
++ expect(classname).to eq "guard/classname"
++ module Guard
++ class Classname
++ end
++ end
++ end
++ expect(plugin.plugin_class).to eq Guard::Classname
++ end
++
++ it "resolves the Guard class from symbol" do
++ plugin = described_class.new(:classname)
++ expect(plugin).to receive(:require) do |classname|
++ expect(classname).to eq "guard/classname"
++ module Guard
++ class Classname
++ end
++ end
++ end
++ expect(plugin.plugin_class).to eq Guard::Classname
++ end
++ end
++
++ context "with a name with dashes" do
++ it "returns the Guard class" do
++ plugin = described_class.new("dashed-class-name")
++ expect(plugin).to receive(:require) do |classname|
++ expect(classname).to eq "guard/dashed-class-name"
++ module Guard
++ class DashedClassName
++ end
++ end
++ end
++ expect(plugin.plugin_class).to eq Guard::DashedClassName
++ end
++ end
++
++ context "with a name with underscores" do
++ it "returns the Guard class" do
++ plugin = described_class.new("underscore_class_name")
++ expect(plugin).to receive(:require) do |classname|
++ expect(classname).to eq "guard/underscore_class_name"
++ module Guard
++ class UnderscoreClassName
++ end
++ end
++ end
++ expect(plugin.plugin_class).to eq Guard::UnderscoreClassName
++ end
++ end
++
++ context "with a name like VSpec" do
++ it "returns the Guard class" do
++ plugin = described_class.new("vspec")
++ mod = nil
++ allow(plugin).to receive(:require) do |classname|
++ expect(classname).to eq "guard/vspec"
++ module Guard
++ class VSpec
++ end
++ end
++ mod = Guard::VSpec
++ end
++ expect(plugin.plugin_class).to eq mod
++ expect(mod).to be
++ end
++ end
++
++ context "with an inline Guard class" do
++ subject { described_class.new("inline") }
++ let(:plugin_class) { class_double("Guard::Plugin") }
++
++ it "returns the Guard class" do
++ allow(Guard).to receive(:constants).and_return([:Inline])
++ allow(Guard).to receive(:const_get).with(:Inline).
++ and_return(plugin_class)
++
++ expect(subject).to_not receive(:require)
++ expect(subject.plugin_class).to eq plugin_class
++ end
++ end
++
++ context "when set to fail gracefully" do
++ options = { fail_gracefully: true }
++ subject { described_class.new("notAGuardClass") }
++ it "does not print error messages on fail" do
++ expect(::Guard::UI).to_not receive(:error)
++ plugin = subject
++ allow(plugin).to receive(:require).and_raise(LoadError)
++ expect(subject.plugin_class(options)).to be_nil
++ end
++ end
++ end
++
++ describe "#add_to_guardfile" do
++ before do
++ allow(Guard::Guardfile::Evaluator).to receive(:new).and_return(evaluator)
++ allow(evaluator).to receive(:evaluate)
++ end
++
++ context "when the Guard is already in the Guardfile" do
++ before do
++ allow(evaluator).to receive(:guardfile_include?) { true }
++ end
++
++ it "shows an info message" do
++ expect(::Guard::UI).to receive(:info).
++ with "Guardfile already includes myguard guard"
++
++ described_class.new("myguard").add_to_guardfile
++ end
++ end
++
++ context "when Guardfile is empty" do
++ let(:plugin_util) { described_class.new("myguard") }
++ let(:plugin_class) { class_double("Guard::Plugin") }
++ let(:location) { "/Users/me/projects/guard-myguard" }
++ let(:gem_spec) { instance_double("Gem::Specification") }
++ let(:io) { StringIO.new }
++
++ before do
++ allow(evaluator).to receive(:evaluate).
++ and_raise(Guard::Guardfile::Evaluator::NoPluginsError)
++
++ allow(gem_spec).to receive(:full_gem_path).and_return(location)
++ allow(evaluator).to receive(:guardfile_include?) { false }
++ allow(Guard).to receive(:constants).and_return([:MyGuard])
++ allow(Guard).to receive(:const_get).with(:MyGuard).
++ and_return(plugin_class)
++
++ allow(Gem::Specification).to receive(:find_by_name).
++ with("guard-myguard").and_return(gem_spec)
++
++ allow(plugin_class).to receive(:template).with(location).
++ and_return("Template content")
++
++ allow(File).to receive(:read).with("Guardfile") { "Guardfile content" }
++ allow(File).to receive(:open).with("Guardfile", "wb").and_yield io
++ end
++
++ it "appends the template to the Guardfile" do
++ plugin_util.add_to_guardfile
++ expect(io.string).to eq "Guardfile content\n\nTemplate content\n"
++ end
++ end
++
++ context "when the Guard is not in the Guardfile" do
++ let(:plugin_util) { described_class.new("myguard") }
++ let(:plugin_class) { class_double("Guard::Plugin") }
++ let(:location) { "/Users/me/projects/guard-myguard" }
++ let(:gem_spec) { instance_double("Gem::Specification") }
++ let(:io) { StringIO.new }
++
++ before do
++ allow(gem_spec).to receive(:full_gem_path).and_return(location)
++ allow(evaluator).to receive(:guardfile_include?) { false }
++ allow(Guard).to receive(:constants).and_return([:MyGuard])
++ allow(Guard).to receive(:const_get).with(:MyGuard).
++ and_return(plugin_class)
++
++ allow(Gem::Specification).to receive(:find_by_name).
++ with("guard-myguard").and_return(gem_spec)
++
++ allow(plugin_class).to receive(:template).with(location).
++ and_return("Template content")
++
++ allow(File).to receive(:read).with("Guardfile") { "Guardfile content" }
++ allow(File).to receive(:open).with("Guardfile", "wb").and_yield io
++ end
++
++ it "appends the template to the Guardfile" do
++ plugin_util.add_to_guardfile
++ expect(io.string).to eq "Guardfile content\n\nTemplate content\n"
++ end
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/runner_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/runner_spec.rb
+@@ -0,0 +1,439 @@
++require "guard/runner"
++
++require "guard/plugin"
++
++RSpec.describe Guard::Runner do
++ let(:ui_config) { instance_double("Guard::UI::Config") }
++ let(:backend_group) do
++ instance_double("Guard::Group", options: {}, name: :backend)
++ end
++
++ let(:frontend_group) do
++ instance_double("Guard::Group", options: {}, name: :frontend)
++ end
++
++ let(:foo_plugin) { double("foo", group: backend_group, hook: nil) }
++ let(:bar_plugin) { double("bar", group: frontend_group, hook: nil) }
++ let(:baz_plugin) { double("baz", group: frontend_group, hook: nil) }
++
++ let(:scope) { instance_double("Guard::Internals::Scope") }
++ let(:plugins) { instance_double("Guard::Internals::Plugins") }
++ let(:state) { instance_double("Guard::Internals::State") }
++ let(:session) { instance_double("Guard::Internals::Session") }
++
++ before do
++ allow(session).to receive(:plugins).and_return(plugins)
++ allow(state).to receive(:session).and_return(session)
++ allow(state).to receive(:scope).and_return(scope)
++ allow(Guard).to receive(:state).and_return(state)
++
++ allow(Guard::UI::Config).to receive(:new).and_return(ui_config)
++ end
++
++ before do
++ Guard::UI.options = nil
++ end
++
++ after do
++ Guard::UI.reset_logger
++ Guard::UI.options = nil
++ end
++
++ describe "#run" do
++ before do
++ allow(scope).to receive(:grouped_plugins).with({}).
++ and_return([[nil, [foo_plugin, bar_plugin, baz_plugin]]])
++
++ allow(ui_config).to receive(:with_progname).and_yield
++ end
++
++ it "executes supervised task on all registered plugins implementing it" do
++ [foo_plugin, bar_plugin].each do |plugin|
++ expect(plugin).to receive(:my_hard_task)
++ end
++
++ subject.run(:my_hard_task)
++ end
++
++ it "marks an action as unit of work" do
++ expect(Lumberjack).to receive(:unit_of_work)
++ subject.run(:my_task)
++ end
++
++ context "with interrupted task" do
++ before do
++ allow(foo_plugin).to receive(:failing).and_raise(Interrupt)
++ # allow(Guard).to receive(:plugins).and_return([foo_plugin])
++ end
++
++ it "catches the thrown symbol" do
++ expect { subject.run(:failing) }.to_not throw_symbol(:task_has_failed)
++ end
++ end
++
++ context "with a scope" do
++ let(:scope_hash) { { plugin: :bar } }
++
++ it "executes the supervised task on the specified plugin only" do
++ expect(scope).to receive(:grouped_plugins).with(scope_hash).
++ and_return([[nil, [bar_plugin]]])
++
++ expect(bar_plugin).to receive(:my_task)
++ expect(foo_plugin).to_not receive(:my_task)
++ expect(baz_plugin).to_not receive(:my_task)
++
++ subject.run(:my_task, scope_hash)
++ end
++ end
++
++ context "with no scope" do
++ let(:scope_hash) { nil }
++
++ it "executes the supervised task using current scope" do
++ expect(bar_plugin).to receive(:my_task)
++ expect(foo_plugin).to receive(:my_task)
++ expect(baz_plugin).to receive(:my_task)
++
++ subject.run(:my_task, scope_hash)
++ end
++ end
++ end
++
++ describe "#run_on_changes" do
++ let(:changes) { [[], [], []] }
++ let(:watcher_module) { Guard::Watcher }
++
++ before do
++ allow(watcher_module).to receive(:match_files) { [] }
++ allow(Guard::UI).to receive(:clear)
++
++ allow(foo_plugin).to receive(:regular_without_arg) { fail "not stubbed" }
++ allow(foo_plugin).to receive(:regular_with_arg) { fail "not stubbed" }
++ allow(foo_plugin).to receive(:failing) { fail "not stubbed" }
++
++ # TODO: runner shouldn't have to know about these
++ allow(foo_plugin).to receive(:run_on_modifications) { fail "not stubbed" }
++ allow(foo_plugin).to receive(:run_on_change) { fail "not stubbed" }
++ allow(foo_plugin).to receive(:run_on_additions) { fail "not stubbed" }
++ allow(foo_plugin).to receive(:run_on_removals) { fail "not stubbed" }
++ allow(foo_plugin).to receive(:run_on_deletion) { fail "not stubbed" }
++
++ allow(foo_plugin).to receive(:my_task)
++ allow(bar_plugin).to receive(:my_task)
++ allow(baz_plugin).to receive(:my_task)
++
++ allow(foo_plugin).to receive(:name).and_return("Foo")
++
++ allow(scope).to receive(:grouped_plugins) do |args|
++ fail "stub me (#{args.inspect})!"
++ end
++
++ # disable reevaluator
++ allow(scope).to receive(:grouped_plugins).with(group: :common).
++ and_return([[nil, []]])
++
++ # foo in default group
++ allow(scope).to receive(:grouped_plugins).with(group: :default).
++ and_return([[nil, [foo_plugin]]])
++
++ allow(scope).to receive(:grouped_plugins).with(no_args).
++ and_return([[nil, [foo_plugin]]])
++
++ allow(ui_config).to receive(:with_progname).and_yield
++ end
++
++ it "always calls UI.clearable" do
++ expect(Guard::UI).to receive(:clearable)
++ expect(scope).to receive(:grouped_plugins).with(no_args).
++ and_return([[nil, [foo_plugin]]])
++
++ subject.run_on_changes(*changes)
++ end
++
++ context "when clearable" do
++ it "clear UI" do
++ expect(Guard::UI).to receive(:clear)
++ expect(scope).to receive(:grouped_plugins).with(no_args).
++ and_return([[nil, [foo_plugin]]])
++ subject.run_on_changes(*changes)
++ end
++ end
++
++ context "with no changes" do
++ it "does not run any task" do
++ %w(
++ run_on_modifications
++ run_on_change
++ run_on_additions
++ run_on_removals
++ run_on_deletion
++ ).each do |task|
++ expect(foo_plugin).to_not receive(task.to_sym)
++ end
++ subject.run_on_changes(*changes)
++ end
++ end
++
++ context "with modified files but modified paths is empty" do
++ let(:modified) { %w(file.txt image.png) }
++
++ before do
++ changes[0] = modified
++ expect(watcher_module).to receive(:match_files).once.
++ with(foo_plugin, modified).and_return([])
++
++ # stub so respond_to? works
++ end
++
++ it "does not call run anything" do
++ expect(foo_plugin).to_not receive(:run_on_modifications)
++ subject.run_on_changes(*changes)
++ end
++ end
++
++ context "with modified paths" do
++ let(:modified) { %w(file.txt image.png) }
++
++ before do
++ changes[0] = modified
++ expect(watcher_module).to receive(:match_files).
++ with(foo_plugin, modified).and_return(modified)
++ end
++
++ it "executes the :run_first_task_found task" do
++ expect(foo_plugin).to receive(:run_on_modifications).with(modified) {}
++ subject.run_on_changes(*changes)
++ end
++ end
++
++ context "with added files but added paths is empty" do
++ let(:added) { %w(file.txt image.png) }
++
++ before do
++ changes[0] = added
++ expect(watcher_module).to receive(:match_files).once.
++ with(foo_plugin, added).and_return([])
++ end
++
++ it "does not call run anything" do
++ expect(foo_plugin).to_not receive(:run_on_additions)
++ subject.run_on_changes(*changes)
++ end
++ end
++
++ context "with added paths" do
++ let(:added) { %w(file.txt image.png) }
++
++ before do
++ changes[1] = added
++ expect(watcher_module).to receive(:match_files).
++ with(foo_plugin, added).and_return(added)
++ end
++
++ it "executes the :run_on_additions task" do
++ expect(foo_plugin).to receive(:run_on_additions).with(added) {}
++ subject.run_on_changes(*changes)
++ end
++ end
++
++ context "with non-matching removed paths" do
++ let(:removed) { %w(file.txt image.png) }
++
++ before do
++ changes[2] = removed
++ expect(watcher_module).to receive(:match_files).once.
++ with(foo_plugin, removed) { [] }
++
++ # stub so respond_to? works
++ allow(foo_plugin).to receive(:run_on_removals)
++ end
++
++ it "does not call tasks" do
++ expect(foo_plugin).to_not receive(:run_on_removals)
++ subject.run_on_changes(*changes)
++ end
++ end
++
++ context "with matching removed paths" do
++ let(:removed) { %w(file.txt image.png) }
++
++ before do
++ changes[2] = removed
++ expect(watcher_module).to receive(:match_files).
++ with(foo_plugin, removed) { removed }
++ end
++
++ it "executes the :run_on_removals task" do
++ expect(foo_plugin).to receive(:run_on_removals).with(removed) {}
++ subject.run_on_changes(*changes)
++ end
++ end
++ end
++
++ describe "#_supervise" do
++ before do
++ allow(ui_config).to receive(:with_progname).and_yield
++ end
++
++ it "executes the task on the passed guard" do
++ expect(foo_plugin).to receive(:my_task)
++ subject.send(:_supervise, foo_plugin, :my_task)
++ end
++
++ context "with a task that succeeds" do
++ context "without any arguments" do
++ before do
++ allow(foo_plugin).to receive(:regular_without_arg) { true }
++ end
++
++ it "does not remove the Guard" do
++ expect(plugins).to_not receive(:remove)
++ subject.send(:_supervise, foo_plugin, :regular_without_arg)
++ end
++
++ it "returns the result of the task" do
++ result = subject.send(:_supervise, foo_plugin, :regular_without_arg)
++ expect(result).to be_truthy
++ end
++
++ it "calls :begin and :end hooks" do
++ expect(foo_plugin).to receive(:hook).
++ with("regular_without_arg_begin")
++
++ expect(foo_plugin).to receive(:hook).
++ with("regular_without_arg_end", true)
++
++ subject.send(:_supervise, foo_plugin, :regular_without_arg)
++ end
++
++ it "passes the result of the supervised method to the :end hook" do
++ expect(foo_plugin).to receive(:hook).
++ with("regular_without_arg_begin")
++
++ expect(foo_plugin).to receive(:hook).
++ with("regular_without_arg_end", true)
++
++ subject.send(:_supervise, foo_plugin, :regular_without_arg)
++ end
++ end
++
++ context "with arguments" do
++ before do
++ allow(foo_plugin).to receive(:regular_with_arg).
++ with("given_path") { "I'm a success" }
++ end
++
++ it "does not remove the Guard" do
++ expect(plugins).to_not receive(:remove)
++ subject.send(
++ :_supervise,
++ foo_plugin,
++ :regular_with_arg,
++ "given_path"
++ )
++ end
++
++ it "returns the result of the task" do
++ result = subject.send(
++ :_supervise,
++ foo_plugin,
++ :regular_with_arg,
++ "given_path"
++ )
++
++ expect(result).to eq "I'm a success"
++ end
++ end
++ end
++
++ context "with a task that throws :task_has_failed" do
++ before do
++ allow(foo_plugin).to receive(:failing) { throw :task_has_failed }
++ end
++
++ context "in a group" do
++ context "with halt_on_fail: true" do
++ before { backend_group.options[:halt_on_fail] = true }
++
++ it "throws :task_has_failed" do
++ expect do
++ subject.send(:_supervise, foo_plugin, :failing)
++ end.to throw_symbol(:task_has_failed)
++ end
++ end
++
++ context "with halt_on_fail: false" do
++ before { backend_group.options[:halt_on_fail] = false }
++
++ it "catches :task_has_failed" do
++ expect do
++ subject.send(:_supervise, foo_plugin, :failing)
++ end.to_not throw_symbol(:task_has_failed)
++ end
++ end
++ end
++ end
++
++ context "with a task that raises an exception" do
++ before do
++ allow(foo_plugin).to receive(:failing) { fail "I break your system" }
++ allow(plugins).to receive(:remove).with(foo_plugin)
++ end
++
++ it "removes the Guard" do
++ expect(plugins).to receive(:remove).with(foo_plugin) {}
++ subject.send(:_supervise, foo_plugin, :failing)
++ end
++
++ it "display an error to the user" do
++ expect(::Guard::UI).to receive :error
++ expect(::Guard::UI).to receive :info
++
++ subject.send(:_supervise, foo_plugin, :failing)
++ end
++
++ it "returns the exception" do
++ failing_result = subject.send(:_supervise, foo_plugin, :failing)
++ expect(failing_result).to be_kind_of(Exception)
++ expect(failing_result.message).to eq "I break your system"
++ end
++
++ it "calls the default begin hook but not the default end hook" do
++ expect(foo_plugin).to receive(:hook).with("failing_begin")
++ expect(foo_plugin).to_not receive(:hook).with("failing_end")
++ subject.send(:_supervise, foo_plugin, :failing)
++ end
++ end
++ end
++
++ describe ".stopping_symbol_for" do
++ let(:guard_plugin) { instance_double("Guard::Plugin") }
++ let(:group) { instance_double("Guard::Group", title: "Foo") }
++
++ before do
++ allow(guard_plugin).to receive(:group).and_return(group)
++ end
++
++ context "for a group with :halt_on_fail" do
++ before do
++ allow(group).to receive(:options).and_return(halt_on_fail: true)
++ end
++
++ it "returns :no_catch" do
++ symbol = described_class.stopping_symbol_for(guard_plugin)
++ expect(symbol).to eq :no_catch
++ end
++ end
++
++ context "for a group without :halt_on_fail" do
++ before do
++ allow(group).to receive(:options).and_return(halt_on_fail: false)
++ end
++
++ it "returns :task_has_failed" do
++ symbol = described_class.stopping_symbol_for(guard_plugin)
++ expect(symbol).to eq :task_has_failed
++ end
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/terminal_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/terminal_spec.rb
+@@ -0,0 +1,65 @@
++require "guard/terminal"
++
++RSpec.describe Guard::Terminal do
++ subject { described_class }
++ it { is_expected.to respond_to(:clear) }
++
++ let(:sheller) { class_double("Shellany::Sheller") }
++
++ before do
++ stub_const("Shellany::Sheller", sheller)
++ end
++
++ describe ".clear" do
++ context "when on UNIX" do
++ before { allow(Gem).to receive(:win_platform?).and_return(false) }
++
++ context "when the clear command exists" do
++ let(:result) { [0, "\e[H\e[2J", ""] }
++
++ it "clears the screen using 'clear'" do
++ expect(sheller).to receive(:system).with("printf '\33c\e[3J';").
++ and_return(result)
++ ::Guard::Terminal.clear
++ end
++ end
++
++ context "when the clear command fails" do
++ let(:result) { [nil, nil, "Guard failed to run \"clear;\""] }
++
++ before do
++ allow(sheller).to receive(:system).with("printf '\33c\e[3J';").
++ and_return(result)
++ end
++
++ it "fails" do
++ expect { ::Guard::Terminal.clear }.
++ to raise_error(Errno::ENOENT, /Guard failed to run "clear;"/)
++ end
++ end
++ end
++
++ context "when on Windows" do
++ before { allow(Gem).to receive(:win_platform?).and_return(true) }
++
++ it "clears the screen" do
++ result = [0, "\f", ""]
++ expect(sheller).to receive(:system).with("cls").and_return(result)
++ ::Guard::Terminal.clear
++ end
++
++ context "when the clear command fails" do
++ let(:result) { [nil, nil, "Guard failed to run \"cls\""] }
++
++ before do
++ allow(sheller).to receive(:system).with("cls").and_return(result)
++ end
++
++ it "fails" do
++ expect { ::Guard::Terminal.clear }.
++ to raise_error(Errno::ENOENT, /Guard failed to run "cls"/)
++ end
++ end
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/ui/config_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/ui/config_spec.rb
+@@ -0,0 +1,73 @@
++require "guard/ui/config"
++
++RSpec.describe Guard::UI::Config do
++ describe "#device" do
++ context "when not set" do
++ context "when accessed as a method" do
++ it "returns $stderr" do
++ expect(subject.device).to be($stderr)
++ end
++ end
++
++ context "when accessed as a string" do
++ it "returns $stderr" do
++ expect(subject["device"]).to be($stderr)
++ end
++ end
++
++ context "when accessed as a symbol" do
++ it "returns $stderr" do
++ expect(subject[:device]).to be($stderr)
++ end
++ end
++ end
++ end
++
++ describe "#logger_config" do
++ let(:options) { {} }
++ subject { described_class.new(options) }
++
++ let(:logger_config) { instance_double("Guard::UI::Logger::Config") }
++
++ before do
++ allow(Guard::UI::Logger::Config).to receive(:new).
++ and_return(logger_config)
++ end
++
++ context "with defaults" do
++ it "provides a logger config" do
++ expect(subject.logger_config).to be(logger_config)
++ end
++ end
++
++ context "with deprecated options set" do
++ context "when set using a string" do
++ subject { described_class.new('time_format': "foo") }
++
++ it "passes deprecated options to logger" do
++ expect(Guard::UI::Logger::Config).to receive(:new).
++ with(time_format: "foo")
++ subject
++ end
++
++ it "provides a logger config" do
++ expect(subject.logger_config).to be(logger_config)
++ end
++ end
++
++ context "when set using a symbol" do
++ let(:options) { { time_format: "foo" } }
++
++ it "passes deprecated options to logger" do
++ expect(Guard::UI::Logger::Config).to receive(:new).
++ with(time_format: "foo")
++ subject
++ end
++
++ it "provides a logger config" do
++ expect(subject.logger_config).to be(logger_config)
++ end
++ end
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/ui/logger_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/ui/logger_spec.rb
+@@ -0,0 +1,22 @@
++require "guard/ui/logger"
++
++RSpec.describe Guard::UI::Logger::Config do
++ describe "defaults" do
++ it "flushes device by default" do
++ expect(subject[:flush_seconds]).to eq(0)
++ end
++ end
++
++ describe "#level=" do
++ context "with a valid value" do
++ before do
++ subject.level = Logger::WARN
++ end
++
++ it "stores the level" do
++ expect(subject[:level]).to eq(Logger::WARN)
++ expect(subject["level"]).to eq(Logger::WARN)
++ end
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/ui_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/ui_spec.rb
+@@ -0,0 +1,363 @@
++require "guard/notifier"
++
++# NOTE: this is here so that no UI does not require anything,
++# since it could be activated by guard plugins during development
++# (it they are tested by other guard plugins)
++#
++# TODO: regardless, the dependency on Guard.state should be removed
++#
++require "guard/ui"
++
++require "guard/internals/session"
++
++RSpec.describe Guard::UI do
++ let(:interactor) { instance_double("Guard::Interactor") }
++ let(:logger) { instance_double("Lumberjack::Logger") }
++ let(:config) { instance_double("Guard::UI::Config") }
++ let(:logger_config) { instance_double("Guard::UI::Logger::Config") }
++
++ let(:terminal) { class_double("Guard::Terminal") }
++
++ let(:session) { instance_double("Guard::Internals::Session") }
++ let(:state) { instance_double("Guard::Internals::State") }
++ let(:scope) { instance_double("Guard::Internals::Scope") }
++
++ before do
++ allow(state).to receive(:scope).and_return(scope)
++ allow(state).to receive(:session).and_return(session)
++ allow(Guard).to receive(:state).and_return(state)
++
++ stub_const("Guard::Terminal", terminal)
++
++ allow(Guard::Notifier).to receive(:turn_on) {}
++
++ allow(Lumberjack::Logger).to receive(:new).and_return(logger)
++ allow(Guard::UI::Config).to receive(:new).and_return(config)
++ allow(Guard::UI::Logger::Config).to receive(:new).and_return(logger_config)
++
++ # The spec helper stubs all UI classes, so other specs doesn't have
++ # to explicit take care of it. We unstub and move the stubs one layer
++ # down just for this spec.
++ allow(Guard::UI).to receive(:info).and_call_original
++ allow(Guard::UI).to receive(:warning).and_call_original
++ allow(Guard::UI).to receive(:error).and_call_original
++ allow(Guard::UI).to receive(:deprecation).and_call_original
++ allow(Guard::UI).to receive(:debug).and_call_original
++
++ allow(logger).to receive(:info)
++ allow(logger).to receive(:warn)
++ allow(logger).to receive(:error)
++ allow(logger).to receive(:debug)
++
++ allow(config).to receive(:device)
++ allow(config).to receive(:only)
++ allow(config).to receive(:except)
++
++ allow(config).to receive(:logger_config).and_return(logger_config)
++
++ allow($stderr).to receive(:print)
++ end
++
++ before do
++ Guard::UI.options = nil
++ end
++
++ after do
++ Guard::UI.reset_logger
++ Guard::UI.options = nil
++ end
++
++ describe ".logger" do
++ before do
++ allow(config).to receive(:device).and_return(device)
++ end
++
++ context "with no logger set yet" do
++ let(:device) { "foo.log" }
++
++ it "returns the logger instance" do
++ expect(Guard::UI.logger).to be(logger)
++ end
++
++ it "sets the logger device" do
++ expect(Lumberjack::Logger).to receive(:new).
++ with(device, logger_config)
++
++ Guard::UI.logger
++ end
++ end
++ end
++
++ describe ".level=" do
++ before do
++ allow(logger).to receive(:level=)
++ allow(logger_config).to receive(:level=)
++ end
++
++ context "when logger is set up" do
++ before { Guard::UI.logger }
++
++ it "sets the logger's level" do
++ level = Logger::WARN
++ expect(logger).to receive(:level=).with(level)
++ Guard::UI.level = level
++ end
++
++ it "sets the logger's config level" do
++ level = Logger::WARN
++ expect(logger_config).to receive(:level=).with(level)
++ Guard::UI.level = level
++ end
++ end
++
++ context "when logger is not set up yet" do
++ before { Guard::UI.reset_logger }
++
++ it "sets the logger's config level" do
++ level = Logger::WARN
++ expect(logger_config).to receive(:level=).with(level)
++ Guard::UI.level = level
++ end
++
++ it "does not autocreate the logger" do
++ level = Logger::WARN
++ expect(logger).to_not receive(:level=).with(level)
++ Guard::UI.level = level
++ end
++ end
++ end
++
++ describe ".options=" do
++ let(:new_config) { instance_double("Guard::UI::Config") }
++
++ before do
++ allow(Guard::UI::Config).to receive(:new).with(hi: :ho).
++ and_return(new_config)
++
++ allow(new_config).to receive(:[]).with(:hi).and_return(:ho)
++ end
++
++ it "sets the logger options" do
++ Guard::UI.options = { hi: :ho }
++ expect(Guard::UI.options[:hi]).to eq :ho
++ end
++ end
++
++ shared_examples_for "a logger method" do
++ it "resets the line with the :reset option" do
++ expect(Guard::UI).to receive :reset_line
++ Guard::UI.send(ui_method, input, reset: true)
++ end
++
++ it "logs the message with the given severity" do
++ expect(logger).to receive(severity).with(output)
++ Guard::UI.send(ui_method, input)
++ end
++
++ context "with the :only option" do
++ before { allow(config).to receive(:only).and_return(/A/) }
++
++ it "allows logging matching messages" do
++ expect(logger).to receive(severity).with(output)
++ Guard::UI.send(ui_method, input, plugin: "A")
++ end
++
++ it "prevents logging other messages" do
++ expect(logger).to_not receive(severity)
++ Guard::UI.send(ui_method, input, plugin: "B")
++ end
++ end
++
++ context "with the :except option" do
++ before { allow(config).to receive(:except).and_return(/A/) }
++
++ it "prevents logging matching messages" do
++ expect(logger).to_not receive(severity)
++ Guard::UI.send(ui_method, input, plugin: "A")
++ end
++
++ it "allows logging other messages" do
++ expect(logger).to receive(severity).with(output)
++ Guard::UI.send(ui_method, input, plugin: "B")
++ end
++ end
++ end
++
++ describe ".info" do
++ it_behaves_like "a logger method" do
++ let(:ui_method) { :info }
++ let(:severity) { :info }
++ let(:input) { "Info" }
++ let(:output) { "Info" }
++ end
++ end
++
++ describe ".warning" do
++ it_behaves_like "a logger method" do
++ let(:ui_method) { :warning }
++ let(:severity) { :warn }
++ let(:input) { "Warning" }
++ let(:output) { "\e[0;33mWarning\e[0m" }
++ end
++ end
++
++ describe ".error" do
++ it_behaves_like "a logger method" do
++ let(:ui_method) { :error }
++ let(:severity) { :error }
++ let(:input) { "Error" }
++ let(:output) { "\e[0;31mError\e[0m" }
++ end
++ end
++
++ describe ".deprecation" do
++ before do
++ allow(ENV).to receive(:[]).with("GUARD_GEM_SILENCE_DEPRECATIONS").
++ and_return(value)
++ end
++
++ context "with GUARD_GEM_SILENCE_DEPRECATIONS set to 1" do
++ let(:value) { "1" }
++
++ it "silences deprecations" do
++ expect(Guard::UI.logger).to_not receive(:warn)
++ Guard::UI.deprecation "Deprecator message"
++ end
++ end
++
++ context "with GUARD_GEM_SILENCE_DEPRECATIONS unset" do
++ let(:value) { nil }
++
++ it_behaves_like "a logger method" do
++ let(:ui_method) { :deprecation }
++ let(:severity) { :warn }
++ let(:input) { "Deprecated" }
++ let(:output) do
++ /^\e\[0;33mDeprecated\nDeprecation backtrace: .*\e\[0m$/m
++ end
++ end
++ end
++ end
++
++ describe ".debug" do
++ it_behaves_like "a logger method" do
++ let(:ui_method) { :debug }
++ let(:severity) { :debug }
++ let(:input) { "Debug" }
++ let(:output) { "\e[0;33mDebug\e[0m" }
++ end
++ end
++
++ describe ".clear" do
++ context "with UI set up and ready" do
++ before do
++ allow(session).to receive(:clear?).and_return(false)
++ Guard::UI.reset_and_clear
++ end
++
++ context "when clear option is disabled" do
++ it "does not clear the output" do
++ expect(terminal).to_not receive(:clear)
++ Guard::UI.clear
++ end
++ end
++
++ context "when clear option is enabled" do
++ before do
++ allow(session).to receive(:clear?).and_return(true)
++ end
++
++ context "when the screen is marked as needing clearing" do
++ before { Guard::UI.clearable }
++
++ it "clears the output" do
++ expect(terminal).to receive(:clear)
++ Guard::UI.clear
++ end
++
++ it "clears the output only once" do
++ expect(terminal).to receive(:clear).once
++ Guard::UI.clear
++ Guard::UI.clear
++ end
++
++ context "when the command fails" do
++ before do
++ allow(terminal).to receive(:clear).
++ and_raise(Errno::ENOENT, "failed to run command")
++ end
++
++ it "shows a warning" do
++ expect(logger).to receive(:warn) do |arg|
++ expect(arg).to match(/failed to run command/)
++ end
++ Guard::UI.clear
++ end
++ end
++ end
++
++ context "when the screen has just been cleared" do
++ before { Guard::UI.clear }
++
++ it "does not clear" do
++ expect(terminal).to_not receive(:clear)
++ Guard::UI.clear
++ end
++
++ context "when forced" do
++ let(:opts) { { force: true } }
++
++ it "clears the outputs if forced" do
++ expect(terminal).to receive(:clear)
++ Guard::UI.clear(opts)
++ end
++ end
++ end
++ end
++ end
++ end
++
++ describe ".action_with_scopes" do
++ let(:rspec) { double("Rspec", title: "Rspec") }
++ let(:jasmine) { double("Jasmine", title: "Jasmine") }
++ let(:group) { instance_double("Guard::Group", title: "Frontend") }
++
++ context "with a plugins scope" do
++ it "shows the plugin scoped action" do
++ allow(scope).to receive(:titles).with(plugins: [rspec, jasmine]).
++ and_return(%w(Rspec Jasmine))
++
++ expect(Guard::UI).to receive(:info).with("Reload Rspec, Jasmine")
++ Guard::UI.action_with_scopes("Reload", plugins: [rspec, jasmine])
++ end
++ end
++
++ context "with a groups scope" do
++ it "shows the group scoped action" do
++ allow(scope).to receive(:titles).with(groups: [group]).
++ and_return(%w(Frontend))
++
++ expect(Guard::UI).to receive(:info).with("Reload Frontend")
++ Guard::UI.action_with_scopes("Reload", groups: [group])
++ end
++ end
++
++ context "without a scope" do
++ context "with a global plugin scope" do
++ it "shows the global plugin scoped action" do
++ allow(scope).to receive(:titles).and_return(%w(Rspec Jasmine))
++ expect(Guard::UI).to receive(:info).with("Reload Rspec, Jasmine")
++ Guard::UI.action_with_scopes("Reload", {})
++ end
++ end
++
++ context "with a global group scope" do
++ it "shows the global group scoped action" do
++ allow(scope).to receive(:titles).and_return(%w(Frontend))
++ expect(Guard::UI).to receive(:info).with("Reload Frontend")
++ Guard::UI.action_with_scopes("Reload", {})
++ end
++ end
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/watcher/pattern/deprecated_regexp_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/watcher/pattern/deprecated_regexp_spec.rb
+@@ -0,0 +1,28 @@
++require "guard/watcher/pattern/deprecated_regexp"
++
++RSpec.describe Guard::Watcher::Pattern::DeprecatedRegexp do
++ describe ".deprecated?" do
++ specify { expect(described_class.new("^spec_helper.rb")).to be_deprecated }
++ specify { expect(described_class.new("spec_helper.rb$")).to be_deprecated }
++ end
++
++ describe "Matcher returned by .convert" do
++ let(:matcher) { Guard::Watcher::Pattern::Matcher }
++
++ before { allow(matcher).to receive(:new) }
++
++ {
++ "^foo.rb" => /^foo.rb/,
++ "foo.rb$" => /foo.rb$/,
++ 'foo\.rb' => /foo\.rb/,
++ ".*rb" => /.*rb/,
++ }.each do |pattern, regexp|
++ context "with #{pattern}" do
++ it "creates a Matcher with #{regexp}" do
++ expect(matcher).to receive(:new).with(regexp)
++ described_class.convert(pattern)
++ end
++ end
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/watcher/pattern/match_result_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/watcher/pattern/match_result_spec.rb
+@@ -0,0 +1,46 @@
++require "guard/watcher/pattern/match_result"
++
++RSpec.describe Guard::Watcher::Pattern::MatchResult do
++ let(:match_result) { double("match_data") }
++ let(:original_value) { "foo/bar.rb" }
++ subject { described_class.new(match_result, original_value) }
++
++ describe "#initialize" do
++ context "with valid arguments" do
++ it "does not fail" do
++ expect { subject }.to_not raise_error
++ end
++ end
++ end
++
++ describe "#[]" do
++ context "with a valid match" do
++ let(:match_result) { double("match_data", to_a: %w(foo bar baz)) }
++
++ context "when asked for the non-first item" do
++ let(:index) { 1 }
++ it "returns the value at given index" do
++ expect(subject[index]).to eq("bar")
++ end
++ end
++
++ context "when asked for the first item" do
++ let(:index) { 0 }
++ it "returns the full original value" do
++ expect(subject[index]).to eq("foo/bar.rb")
++ end
++ end
++
++ context "when asked for a name match via a symbol" do
++ let(:index) { :foo }
++ before do
++ allow(match_result).to receive(:[]).with(:foo).and_return("baz")
++ end
++
++ it "returns the value by name" do
++ expect(subject[index]).to eq("baz")
++ end
++ end
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/watcher/pattern/matcher_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/watcher/pattern/matcher_spec.rb
+@@ -0,0 +1,82 @@
++require "guard/watcher/pattern/matcher"
++
++RSpec.describe Guard::Watcher::Pattern::Matcher do
++ subject { described_class.new(obj) }
++ describe "#match" do
++ let(:expected) { double("match_result") }
++
++ context "when constructed with valid matcher object" do
++ let(:obj) { double("matcher") }
++
++ context "when matched against a Pathname" do
++ before do
++ allow(obj).to receive(:match).and_return(expected)
++ end
++ let(:filename) { Pathname("foo.rb") }
++
++ it "returns the match result" do
++ expect(subject.match(filename)).to be(expected)
++ end
++
++ it "passes the Pathname to the matcher" do
++ allow(obj).to receive(:match).with(filename)
++ subject.match(filename)
++ end
++ end
++
++ context "when matched against a String" do
++ before do
++ allow(obj).to receive(:match).and_return(expected)
++ end
++ let(:filename) { "foo.rb" }
++
++ it "returns the match result" do
++ expect(subject.match(filename)).to be(expected)
++ end
++
++ it "passes a Pathname to the matcher" do
++ allow(obj).to receive(:match).with(Pathname(filename))
++ subject.match(filename)
++ end
++ end
++ end
++ end
++
++ describe "integration" do
++ describe "#match result" do
++ subject { described_class.new(obj).match(filename) }
++ context "when constructed with valid regexp" do
++ let(:obj) { /foo.rb$/ }
++
++ context "when matched file is a string" do
++ context "when filename matches" do
++ let(:filename) { "foo.rb" }
++ specify { expect(subject.to_a).to eq(["foo.rb"]) }
++ end
++
++ context "when filename does not match" do
++ let(:filename) { "bar.rb" }
++ specify { expect(subject).to be_nil }
++ end
++ end
++
++ context "when matched file is an unclean Pathname" do
++ context "when filename matches" do
++ let(:filename) { Pathname("./foo.rb") }
++ specify { expect(subject.to_a).to eq(["foo.rb"]) }
++ end
++
++ context "when filename does not match" do
++ let(:filename) { Pathname("./bar.rb") }
++ specify { expect(subject).to be_nil }
++ end
++ end
++
++ context "when matched file contains a $" do
++ let(:filename) { Pathname("lib$/foo.rb") }
++ specify { expect(subject.to_a).to eq(["foo.rb"]) }
++ end
++ end
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/watcher/pattern/pathname_path_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/watcher/pattern/pathname_path_spec.rb
+@@ -0,0 +1,35 @@
++require "guard/watcher/pattern/pathname_path"
++
++RSpec.describe Guard::Watcher::Pattern::PathnamePath do
++ subject { described_class.new(path) }
++ describe "#match result" do
++ subject { described_class.new(path).match(filename) }
++ context "when constructed with an unclean Pathname" do
++ let(:path) { Pathname("./foo.rb") }
++
++ context "when matched file is a string" do
++ context "when filename matches" do
++ let(:filename) { "foo.rb" }
++ specify { expect(subject).to eq([Pathname("foo.rb")]) }
++ end
++
++ context "when filename does not match" do
++ let(:filename) { "bar.rb" }
++ specify { expect(subject).to be_nil }
++ end
++ end
++
++ context "when matched file is an unclean Pathname" do
++ context "when filename matches" do
++ let(:filename) { Pathname("./foo.rb") }
++ specify { expect(subject).to eq([Pathname("foo.rb")]) }
++ end
++
++ context "when filename does not match" do
++ let(:filename) { Pathname("./bar.rb") }
++ specify { expect(subject).to be_nil }
++ end
++ end
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/watcher/pattern/simple_path_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/watcher/pattern/simple_path_spec.rb
+@@ -0,0 +1,35 @@
++require "guard/watcher/pattern/simple_path"
++
++RSpec.describe Guard::Watcher::Pattern::SimplePath do
++ subject { described_class.new(path) }
++
++ describe "#match result" do
++ context "when constructed with filename string" do
++ let(:path) { "foo.rb" }
++
++ context "when matched file is a string" do
++ context "when filename matches" do
++ let(:filename) { "foo.rb" }
++ specify { expect(subject.match(filename)).to eq(["foo.rb"]) }
++ end
++
++ context "when filename does not match" do
++ let(:filename) { "bar.rb" }
++ specify { expect(subject.match(filename)).to be_nil }
++ end
++ end
++
++ context "when matched file is an unclean Pathname" do
++ context "when filename matches" do
++ let(:filename) { Pathname("./foo.rb") }
++ specify { expect(subject.match(filename)).to eq(["foo.rb"]) }
++ end
++
++ context "when filename does not match" do
++ let(:filename) { Pathname("./bar.rb") }
++ specify { expect(subject.match(filename)).to be_nil }
++ end
++ end
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/watcher/pattern_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/watcher/pattern_spec.rb
+@@ -0,0 +1,37 @@
++require "guard/watcher/pattern"
++
++RSpec.describe Guard::Watcher::Pattern do
++ describe ".create" do
++ subject { described_class.create(pattern) }
++
++ context "when a string is given" do
++ let(:pattern) { "foo.rb" }
++ it { is_expected.to be_a(described_class::SimplePath) }
++ end
++
++ context "when a Pathname is given" do
++ let(:pattern) { Pathname("foo.rb") }
++ it { is_expected.to be_a(described_class::PathnamePath) }
++ end
++
++ context "when an regexp string is given" do
++ let(:pattern) { "^foo.*$" }
++ it { is_expected.to be_a(described_class::Matcher) }
++ it "shows a warning" do
++ expect(described_class::DeprecatedRegexp).
++ to receive(:show_deprecation).with(pattern)
++ subject
++ end
++ end
++
++ context "when a regexp is given" do
++ let(:pattern) { /foo\.rb/ }
++ it { is_expected.to be_a(described_class::Matcher) }
++ end
++
++ context "when a custom matcher" do
++ let(:pattern) { Class.new { def match; end } }
++ it { is_expected.to be_a(described_class::Matcher) }
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard/watcher_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard/watcher_spec.rb
+@@ -0,0 +1,351 @@
++require "guard/watcher"
++
++# TODO: shouldn't be needed
++require "guard/guardfile/evaluator"
++
++RSpec.describe Guard::Watcher do
++ let(:args) { [] }
++ subject { described_class.new(*args) }
++ describe "#initialize" do
++ context "with no arguments" do
++ let(:args) { [] }
++ it "raises an error" do
++ expect { subject }.to raise_error(ArgumentError)
++ end
++ end
++
++ context "with a pattern parameter" do
++ let(:pattern) { ["spec_helper.rb"] }
++ let(:args) { [pattern] }
++
++ it "creates a matcher" do
++ expect(described_class::Pattern).to receive(:create).with(pattern)
++ subject
++ end
++ end
++ end
++
++ describe "#action" do
++ it "sets the action to nothing by default" do
++ expect(described_class.new(/spec_helper\.rb/).action).to be_nil
++ end
++
++ it "sets the action to the supplied block" do
++ action = ->(m) { "spec/#{m[1]}_spec.rb" }
++ expect(described_class.new(%r{^lib/(.*).rb}, action).action).to eq action
++ end
++ end
++
++ describe ".match_files" do
++ let(:plugin) { instance_double("Guard::Plugin", options: {}) }
++
++ def matched(files)
++ described_class.match_files(plugin, files)
++ end
++
++ context "without a watcher action" do
++ before do
++ allow(plugin).to receive(:watchers).
++ and_return([described_class.new(pattern)])
++ end
++
++ context "with a regex pattern" do
++ let(:pattern) { /.*_spec\.rb/ }
++ it "returns the paths that matches the regex" do
++ expect(matched(%w(foo_spec.rb foo.rb))).to eq %w(foo_spec.rb)
++ end
++ end
++
++ context "with a string pattern" do
++ let(:pattern) { "foo_spec.rb" }
++ it "returns the path that matches the string" do
++ expect(matched(%w(foo_spec.rb foo.rb))).to eq ["foo_spec.rb"]
++ end
++ end
++ end
++
++ context "with a watcher action without parameter" do
++ context "for a watcher that matches file strings" do
++ before do
++ klass = described_class
++ allow(plugin).to receive(:watchers).and_return(
++ [
++ klass.new("spec_helper.rb", -> { "spec" }),
++ klass.new("addition.rb", -> { 1 + 1 }),
++ klass.new("hash.rb", -> { Hash[:foo, "bar"] }),
++ klass.new("array.rb", -> { %w(foo bar) }),
++ klass.new("blank.rb", -> { "" }),
++ klass.new(/^uptime\.rb/, -> { "" })
++ ]
++ )
++ end
++
++ it "returns a single file specified within the action" do
++ expect(matched(%w(spec_helper.rb))).to eq ["spec"]
++ end
++
++ it "returns multiple files specified within the action" do
++ expect(matched(%w(hash.rb))).to eq %w(foo bar)
++ end
++
++ it "combines files from results of different actions" do
++ expect(matched(%w(spec_helper.rb array.rb))).to eq %w(spec foo bar)
++ end
++
++ context "when action returns non-string or array of non-strings" do
++ it "returns nothing" do
++ expect(matched(%w(addition.rb))).to eq []
++ end
++ end
++
++ it "returns nothing if the action response is empty" do
++ expect(matched(%w(blank.rb))).to eq []
++ end
++
++ it "returns nothing if the action returns nothing" do
++ expect(matched(%w(uptime.rb))).to eq []
++ end
++ end
++
++ context "for a watcher that matches information objects" do
++ before do
++ allow(plugin).to receive(:options).and_return(any_return: true)
++
++ klass = described_class
++ allow(plugin).to receive(:watchers).and_return(
++ [
++ klass.new("spec_helper.rb", -> { "spec" }),
++ klass.new("addition.rb", -> { 1 + 1 }),
++ klass.new("hash.rb", -> { Hash[:foo, "bar"] }),
++ klass.new("array.rb", -> { %w(foo bar) }),
++ klass.new("blank.rb", -> { "" }),
++ klass.new(/^uptime\.rb/, -> { "" })
++ ]
++ )
++ end
++
++ it "returns a single file specified within the action" do
++ expect(matched(%w(spec_helper.rb)).class).to be Array
++ expect(matched(%w(spec_helper.rb))).to_not be_empty
++ end
++
++ it "returns multiple files specified within the action" do
++ expect(matched(%w(hash.rb))).to eq [{ foo: "bar" }]
++ end
++
++ it "combines the results of different actions" do
++ expect(matched(%w(spec_helper.rb array.rb))).
++ to eq ["spec", %w(foo bar)]
++ end
++
++ it "returns the evaluated addition argument in an array" do
++ expect(matched(%w(addition.rb)).class).to be(Array)
++ expect(matched(%w(addition.rb))[0]).to eq 2
++ end
++
++ it "returns nothing if the action response is empty string" do
++ expect(matched(%w(blank.rb))).to eq [""]
++ end
++
++ it "returns nothing if the action returns empty string" do
++ expect(matched(%w(uptime.rb))).to eq [""]
++ end
++ end
++ end
++
++ context "with a watcher action that takes a parameter" do
++ context "for a watcher that matches file strings" do
++ before do
++ klass = described_class
++ allow(plugin).to receive(:watchers).and_return [
++ klass.new(%r{lib/(.*)\.rb}, ->(m) { "spec/#{m[1]}_spec.rb" }),
++ klass.new(/addition(.*)\.rb/, ->(_m) { 1 + 1 }),
++ klass.new("hash.rb", ->(_m) { Hash[:foo, "bar"] }),
++ klass.new(/array(.*)\.rb/, ->(_m) { %w(foo bar) }),
++ klass.new(/blank(.*)\.rb/, ->(_m) { "" }),
++ klass.new(/^uptime\.rb/, -> { "" })
++ ]
++ end
++
++ it "returns a substituted single file specified within the action" do
++ expect(matched(%w(lib/foo.rb))).to eq ["spec/foo_spec.rb"]
++ end
++
++ it "returns multiple files specified within the action" do
++ expect(matched(%w(hash.rb))).to eq %w(foo bar)
++ end
++
++ it "combines results of different actions" do
++ expect(matched(%w(lib/foo.rb array.rb))).
++ to eq %w(spec/foo_spec.rb foo bar)
++ end
++
++ it "returns nothing if action returns non-string or non-string array" do
++ expect(matched(%w(addition.rb))).to eq []
++ end
++
++ it "returns nothing if the action response is empty" do
++ expect(matched(%w(blank.rb))).to eq []
++ end
++
++ it "returns nothing if the action returns nothing" do
++ expect(matched(%w(uptime.rb))).to eq []
++ end
++ end
++
++ context "for a watcher that matches information objects" do
++ before do
++ allow(plugin).to receive(:options).and_return(any_return: true)
++
++ kl = described_class
++ allow(plugin).to receive(:watchers).and_return(
++ [
++ kl.new(%r{lib/(.*)\.rb}, ->(m) { "spec/#{m[1]}_spec.rb" }),
++ kl.new(/addition(.*)\.rb/, ->(m) { (1 + 1).to_s + m[0] }),
++ kl.new("hash.rb", ->(m) { { foo: "bar", file_name: m[0] } }),
++ kl.new(/array(.*)\.rb/, ->(m) { ["foo", "bar", m[0]] }),
++ kl.new(/blank(.*)\.rb/, ->(_m) { "" }),
++ kl.new(/^uptime\.rb/, -> { "" })
++ ]
++ )
++ end
++
++ it "returns a substituted single file specified within the action" do
++ expect(matched(%w(lib/foo.rb))).to eq %w(spec/foo_spec.rb)
++ end
++
++ it "returns a hash specified within the action" do
++ expect(matched(%w(hash.rb))).to eq [
++ { foo: "bar", file_name: "hash.rb" }
++ ]
++ end
++
++ it "combinines results of different actions" do
++ expect(matched(%w(lib/foo.rb array.rb))).
++ to eq ["spec/foo_spec.rb", %w(foo bar array.rb)]
++ end
++
++ it "returns the evaluated addition argument + the path" do
++ expect(matched(%w(addition.rb))).to eq ["2addition.rb"]
++ end
++
++ it "returns nothing if the action response is empty string" do
++ expect(matched(%w(blank.rb))).to eq [""]
++ end
++
++ it "returns nothing if the action returns is IO::NULL" do
++ expect(matched(%w(uptime.rb))).to eq [""]
++ end
++ end
++ end
++
++ context "with an exception that is raised" do
++ before do
++ allow(plugin).to receive(:watchers).and_return(
++ [described_class.new("evil.rb", -> { fail "EVIL" })]
++ )
++ end
++
++ it "displays the error and backtrace" do
++ expect(Guard::UI).to receive(:error) do |msg|
++ expect(msg).to include("Problem with watch action!")
++ expect(msg).to include("EVIL")
++ end
++
++ described_class.match_files(plugin, ["evil.rb"])
++ end
++ end
++
++ context "for ambiguous watchers" do
++ before do
++ expect(plugin).to receive(:watchers).and_return [
++ described_class.new("awesome_helper.rb", -> {}),
++ described_class.new(/.+some_helper.rb/, -> { "foo.rb" }),
++ described_class.new(/.+_helper.rb/, -> { "bar.rb" }),
++ ]
++ end
++
++ context "when the :first_match option is turned off" do
++ before do
++ allow(plugin).to receive(:options).and_return(first_match: false)
++ end
++
++ it "returns multiple files by combining the results of the watchers" do
++ expect(described_class.match_files(
++ plugin, ["awesome_helper.rb"]
++ )).to eq(["foo.rb", "bar.rb"])
++ end
++ end
++
++ context "when the :first_match option is turned on" do
++ before do
++ plugin.options[:first_match] = true
++ end
++
++ it "returns only the files from the first watcher" do
++ expect(described_class.match_files(
++ plugin, ["awesome_helper.rb"]
++ )).to eq(["foo.rb"])
++ end
++ end
++ end
++ end
++
++ describe "#match" do
++ subject { described_class.new(pattern).match(file) }
++
++ let(:matcher) { instance_double(described_class::Pattern::Matcher) }
++ let(:match) { instance_double(described_class::Pattern::MatchResult) }
++
++ before do
++ allow(described_class::Pattern).to receive(:create).with(pattern).
++ and_return(matcher)
++
++ allow(matcher).to receive(:match).with(pattern).
++ and_return(match_data)
++
++ allow(described_class::Pattern::MatchResult).to receive(:new).
++ with(match_data, file).and_return(match)
++ end
++
++ context "with a valid pattern" do
++ let(:pattern) { "foo.rb" }
++ context "with a valid file name to match" do
++ let(:file) { "foo.rb" }
++ context "when matching is successful" do
++ let(:match_data) { double("match data", to_a: ["foo"]) }
++ it "returns the match result" do
++ expect(subject).to be(match)
++ end
++ end
++
++ context "when matching is not successful" do
++ let(:match_data) { nil }
++ it "returns nil" do
++ expect(subject).to be_nil
++ end
++ end
++ end
++ end
++ end
++
++ describe "integration" do
++ describe "#match" do
++ subject { described_class.new(pattern) }
++ context "with a named regexp pattern" do
++ let(:pattern) { /(?<foo>.*)_spec\.rb/ }
++
++ context "with a watcher that matches a file" do
++ specify do
++ expect(subject.match("bar_spec.rb")[0]).to eq("bar_spec.rb")
++ expect(subject.match("bar_spec.rb")[1]).to eq("bar")
++ end
++
++ it "provides the match by name" do
++ expect(subject.match("bar_spec.rb")[:foo]).to eq("bar")
++ end
++ end
++ end
++ end
++ end
++end
+Index: ruby-guard/spec/lib/guard_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/lib/guard_spec.rb
+@@ -0,0 +1,247 @@
++require "guard"
++
++RSpec.describe Guard do
++ # Initialize before Guard::Interactor const is stubbed
++ let!(:interactor) { instance_double("Guard::Interactor") }
++
++ let(:guardfile) { File.expand_path("Guardfile") }
++ let(:traps) { Guard::Internals::Traps }
++
++ let(:evaluator) { instance_double("Guard::Guardfile::Evaluator") }
++
++ let(:plugins) { instance_double("Guard::Internals::Plugins") }
++ let(:scope) { instance_double("Guard::Internals::Scope") }
++ let(:session) { instance_double("Guard::Internals::Session") }
++ let(:state) { instance_double("Guard::Internals::State") }
++ let(:queue) { instance_double("Guard::Internals::Queue") }
++
++ before do
++ allow(Guard::Interactor).to receive(:new).and_return(interactor)
++ allow(Guard::Guardfile::Evaluator).to receive(:new).and_return(evaluator)
++
++ allow(session).to receive(:debug?).and_return(false)
++ allow(session).to receive(:plugins).and_return(plugins)
++ allow(state).to receive(:session).and_return(session)
++ allow(Guard::Internals::Session).to receive(:new).and_return(session)
++ allow(Guard::Internals::Scope).to receive(:new).and_return(scope)
++ allow(Guard::Internals::Queue).to receive(:new).and_return(queue)
++ end
++
++ # TODO: setup has too many responsibilities
++ describe ".setup" do
++ subject { Guard.setup(options) }
++
++ let(:options) { { my_opts: true, guardfile: guardfile } }
++
++ let(:listener) { instance_double("Listen::Listener") }
++
++ before do
++ allow(Listen).to receive(:to).with(Dir.pwd, {}) { listener }
++
++ stub_guardfile(" ")
++ stub_user_guard_rb
++
++ g1 = instance_double("Guard::Group", name: :common, options: {})
++ g2 = instance_double("Guard::Group", name: :default, options: {})
++ allow(Guard::Group).to receive(:new).with(:common).and_return(g1)
++ allow(Guard::Group).to receive(:new).with(:default).and_return(g2)
++
++ allow(evaluator).to receive(:inline?).and_return(false)
++ allow(evaluator).to receive(:custom?).and_return(false)
++ allow(evaluator).to receive(:evaluate)
++ allow(Guard::Guardfile::Evaluator).to receive(:new).and_return(evaluator)
++
++ allow(Guard::Notifier).to receive(:connect)
++
++ allow(Guard::UI).to receive(:reset_and_clear)
++ allow(plugins).to receive(:all).and_return([])
++
++ allow(session).to receive(:listener_args).and_return([:to, Dir.pwd, {}])
++ allow(session).to receive(:evaluator_options).and_return({})
++ allow(session).to receive(:cmdline_groups).and_return({})
++ allow(session).to receive(:cmdline_plugins).and_return({})
++ allow(session).to receive(:notify_options).and_return(notify: true)
++ allow(session).to receive(:interactor_name).and_return(:foo)
++ allow(session).to receive(:guardfile_ignore).and_return([])
++ allow(session).to receive(:guardfile_ignore_bang).and_return([])
++
++ allow(listener).to receive(:ignore)
++ allow(listener).to receive(:ignore!)
++
++ allow(Guard::Internals::State).to receive(:new).and_return(state)
++ end
++
++ it "returns itself for chaining" do
++ expect(subject).to be Guard
++ end
++
++ it "initializes the listener" do
++ allow(Listen).to receive(:to).
++ with("/foo", latency: 2, wait_for_delay: 1).and_return(listener)
++
++ allow(session).to receive(:listener_args).and_return(
++ [:to, "/foo", { latency: 2, wait_for_delay: 1 }]
++ )
++ subject
++ end
++
++ it "initializes the interactor" do
++ expect(Guard::Interactor).to receive(:new).with(false)
++ subject
++ end
++
++ context "trapping signals" do
++ before do
++ allow(traps).to receive(:handle)
++ end
++
++ it "sets up USR1 trap for pausing" do
++ expect(traps).to receive(:handle).with("USR1") { |_, &b| b.call }
++ expect(Guard).to receive(:async_queue_add).
++ with([:guard_pause, :paused])
++ subject
++ end
++
++ it "sets up USR2 trap for unpausing" do
++ expect(traps).to receive(:handle).with("USR2") { |_, &b| b.call }
++ expect(Guard).to receive(:async_queue_add).
++ with([:guard_pause, :unpaused])
++ subject
++ end
++
++ it "sets up INT trap for cancelling or quitting interactor" do
++ expect(traps).to receive(:handle).with("INT") { |_, &b| b.call }
++ expect(interactor).to receive(:handle_interrupt)
++ subject
++ end
++ end
++
++ it "evaluates the Guardfile" do
++ expect(evaluator).to receive(:evaluate)
++ allow(Guard::Guardfile::Evaluator).to receive(:new).and_return(evaluator)
++
++ subject
++ end
++
++ describe "listener" do
++ subject { listener }
++
++ context "with ignores 'ignore(/foo/)' and 'ignore!(/bar/)'" do
++ before do
++ allow(evaluator).to receive(:evaluate) do
++ allow(session).to receive(:guardfile_ignore).and_return([/foo/])
++ allow(session).to receive(:guardfile_ignore_bang).
++ and_return([/bar/])
++ end
++ Guard.setup(options)
++ end
++
++ it { is_expected.to have_received(:ignore).with([/foo/]) }
++ it { is_expected.to have_received(:ignore!).with([/bar/]) }
++ end
++
++ context "without ignores" do
++ before { Guard.setup(options) }
++ it { is_expected.to_not have_received(:ignore) }
++ it { is_expected.to_not have_received(:ignore!) }
++ end
++ end
++
++ it "displays an error message when no guard are defined in Guardfile" do
++ expect(Guard::UI).to receive(:error).
++ with("No plugins found in Guardfile, please add at least one.")
++
++ subject
++ end
++
++ it "connects to the notifier" do
++ expect(Guard::Notifier).to receive(:connect).with(notify: true)
++ subject
++ end
++
++ context "with the group option" do
++ let(:options) { { group: %w(frontend backend) } }
++ it "passes options to session" do
++ expect(Guard::Internals::State).to receive(:new).with(options)
++ subject
++ end
++ end
++
++ context "with the plugin option" do
++ let(:options) { { plugin: %w(cucumber jasmine) } }
++ it "passes options to session" do
++ expect(Guard::Internals::State).to receive(:new).with(options)
++ subject
++ end
++ end
++
++ describe ".interactor" do
++ subject { Guard::Interactor }
++
++ before do
++ expect(session).to receive(:interactor_name).and_return(type)
++ Guard.setup(options)
++ end
++
++ context "with interactions enabled" do
++ let(:type) { :pry_wrapper }
++ let(:options) { { no_interactions: false } }
++ it { is_expected.to have_received(:new).with(false) }
++ end
++
++ context "with interactions disabled" do
++ let(:type) { :sleep }
++ let(:options) { { no_interactions: true } }
++ it { is_expected.to have_received(:new).with(true) }
++ end
++ end
++
++ describe "UI" do
++ subject { Guard::UI }
++
++ context "when clearing is configured" do
++ before { Guard.setup(options) }
++ it { is_expected.to have_received(:reset_and_clear) }
++ end
++ end
++ end
++
++ describe "._relative_pathname" do
++ subject { Guard.send(:_relative_pathname, raw_path) }
++
++ let(:pwd) { Pathname("/project") }
++
++ before { allow(Pathname).to receive(:pwd).and_return(pwd) }
++
++ context "with file in project directory" do
++ let(:raw_path) { "/project/foo" }
++ it { is_expected.to eq(Pathname("foo")) }
++ end
++
++ context "with file within project" do
++ let(:raw_path) { "/project/spec/models/foo_spec.rb" }
++ it { is_expected.to eq(Pathname("spec/models/foo_spec.rb")) }
++ end
++
++ context "with file in parent directory" do
++ let(:raw_path) { "/foo" }
++ it { is_expected.to eq(Pathname("../foo")) }
++ end
++
++ context "with file on another drive (e.g. Windows)" do
++ let(:raw_path) { "d:/project/foo" }
++ let(:pathname) { instance_double(Pathname) }
++
++ before do
++ allow_any_instance_of(Pathname).to receive(:relative_path_from).
++ with(pwd).and_raise(ArgumentError)
++ end
++
++ it { is_expected.to eq(Pathname.new("d:/project/foo")) }
++ end
++ end
++
++ describe "#relevant_changes?" do
++ pending
++ end
++end
+Index: ruby-guard/spec/spec_helper.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/spec_helper.rb
+@@ -0,0 +1,290 @@
++# This file was generated by the `rspec --init` command. Conventionally, all
++# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
++# The generated `.rspec` file contains `--require spec_helper` which will cause
++# this file to always be loaded, without a need to explicitly require it in any
++# files.
++#
++# Given that it is always loaded, you are encouraged to keep this file as
++# light-weight as possible. Requiring heavyweight dependencies from this file
++# will add to the boot time of your test suite on EVERY test run, even for an
++# individual file that may not need all of that loaded. Instead, consider making
++# a separate helper file that requires the additional dependencies and performs
++# the additional setup, and require it from the spec files that actually need
++# it.
++#
++# The `.rspec` file also contains a few flags that are not defaults but that
++# users commonly want.
++#
++
++require "fileutils"
++
++require "simplecov"
++SimpleCov.start
++
++ENV["GUARD_SPECS_RUNNING"] = "1"
++
++path = "#{File.expand_path('..', __FILE__)}/support/**/*.rb"
++Dir[path].each { |f| require f }
++
++# TODO: these shouldn't be necessary with proper specs
++
++def stub_guardfile(contents = nil, &block)
++ stub_file(File.expand_path("Guardfile"), contents, &block)
++end
++
++def stub_user_guardfile(contents = nil, &block)
++ stub_file(File.expand_path("~/.Guardfile"), contents, &block)
++end
++
++def stub_user_guard_rb(contents = nil, &block)
++ stub_file(File.expand_path("~/.guard.rb"), contents, &block)
++end
++
++def stub_user_project_guardfile(contents = nil, &block)
++ stub_file(File.expand_path(".Guardfile"), contents, &block)
++end
++
++def stub_mod(mod, excluded)
++ mod.constants.each do |klass_name|
++ klass = mod.const_get(klass_name)
++ if klass.is_a?(Class)
++ unless klass == described_class
++ unless excluded.include?(klass)
++ inst = instance_double(klass)
++ allow(klass).to receive(:new).and_return(inst)
++ # TODO: use object_double?
++ class_double(klass.to_s).
++ as_stubbed_const(transfer_nested_constants: true)
++ end
++ end
++ elsif klass.is_a?(Module)
++ stub_mod(klass, excluded)
++ end
++ end
++end
++
++def stub_file(path, contents = nil, &block)
++ exists = !contents.nil?
++ allow(File).to receive(:exist?).with(path).and_return(exists)
++ if exists
++ if block.nil?
++ allow(IO).to receive(:read).with(path).and_return(contents)
++ else
++ allow(IO).to receive(:read).with(path) do
++ yield
++ end
++ end
++ else
++ allow(IO).to receive(:read).with(path) do
++ fail Errno::ENOENT
++ end
++ end
++end
++
++# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
++RSpec.configure do |config|
++ # rspec-expectations config goes here. You can use an alternate
++ # assertion/expectation library such as wrong or the stdlib/minitest
++ # assertions if you prefer.
++ config.expect_with :rspec do |expectations|
++ # This option will default to `true` in RSpec 4. It makes the `description`
++ # and `failure_message` of custom matchers include text for helper methods
++ # defined using `chain`, e.g.:
++ # be_bigger_than(2).and_smaller_than(4).description
++ # # => "be bigger than 2 and smaller than 4"
++ # ...rather than:
++ # # => "be bigger than 2"
++ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
++ end
++
++ # rspec-mocks config goes here. You can use an alternate test double
++ # library (such as bogus or mocha) by changing the `mock_with` option here.
++ config.mock_with :rspec do |mocks|
++ # Prevents you from mocking or stubbing a method that does not exist on
++ # a real object. This is generally recommended, and will default to
++ # `true` in RSpec 4.
++ mocks.verify_partial_doubles = true
++ end
++
++ # The settings below are suggested to provide a good initial experience
++ # with RSpec, but feel free to customize to your heart's content.
++
++ # These two settings work together to allow you to limit a spec run
++ # to individual examples or groups you care about by tagging them with
++ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
++ # get run.
++ # config.filter_run :focus
++ config.filter_run focus: ENV["CI"] != "true"
++
++ config.run_all_when_everything_filtered = true
++
++ # Limits the available syntax to the non-monkey patched syntax that is
++ # recommended.
++ #
++ # For more details, see:
++ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
++ # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
++ # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
++ config.disable_monkey_patching!
++
++ # This setting enables warnings. It's recommended, but in some cases may
++ # be too noisy due to issues in dependencies.
++ # config.warnings = true
++
++ # Many RSpec users commonly either run the entire suite or an individual
++ # file, and it's useful to allow more verbose output when running an
++ # individual spec file.
++ if config.files_to_run.one?
++ # Use the documentation formatter for detailed output,
++ # unless a formatter has already been configured
++ # (e.g. via a command-line flag).
++ #
++ # This is set in .rspec file
++ # config.default_formatter = "doc"
++ end
++
++ # Print the 10 slowest examples and example groups at the
++ # end of the spec run, to help surface which specs are running
++ # particularly slow.
++ # config.profile_examples = 10
++
++ # Run specs in random order to surface order dependencies. If you find an
++ # order dependency and want to debug it, you can fix the order by providing
++ # the seed, which is printed after each run.
++ # --seed 1234
++ config.order = :random
++
++ # Seed global randomization in this process using the `--seed` CLI option.
++ # Setting this allows you to use `--seed` to deterministically reproduce
++ # test failures related to randomization by passing the same `--seed` value
++ # as the one that triggered the failure.
++ Kernel.srand config.seed
++
++ config.raise_errors_for_deprecations!
++
++ config.mock_with :rspec do |mocks|
++ mocks.verify_doubled_constant_names = true
++ mocks.verify_partial_doubles = true
++ end
++
++ config.before(:each) do |example|
++ stub_const("FileUtils", class_double(FileUtils))
++
++ excluded = []
++ excluded += Array(example.metadata[:exclude_stubs])
++ excluded << Guard::Config if Guard.constants.include?(:Config)
++ excluded << Guard::Options if Guard.constants.include?(:Options)
++ excluded << Guard::Jobs::Base if Guard.constants.include?(:Jobs)
++
++ excluded << Guard::DuMmy if Guard.constants.include?(:DuMmy)
++
++ if Guard.constants.include?(:Notifier)
++ if Guard::Notifier.constants.include?(:NotServer)
++ excluded << Guard::Notifier::NotServer
++ end
++ if Guard::Notifier.constants.include?(:FooBar)
++ excluded << Guard::Notifier::FooBar
++ end
++ if Guard::Notifier.constants.include?(:Base)
++ excluded << Guard::Notifier::Base
++ end
++ end
++
++ modules = [Guard]
++ modules << Listen if Object.const_defined?(:Listen)
++ modules << Shellany if Object.const_defined?(:Shellany)
++ modules << Notiffany if Object.const_defined?(:Notiffany)
++ modules.each do |mod|
++ stub_mod(mod, excluded)
++ end
++
++ allow(ENV).to receive(:[]=) do |*args|
++ abort "stub me: ENV[#{args.first}]= #{args.map(&:inspect)[1..-1] * ','}!"
++ end
++
++ allow(ENV).to receive(:[]) do |*args|
++ abort "stub me: ENV[#{args.first}]!"
++ end
++
++ allow(ENV).to receive(:key?) do |*args|
++ fail "stub me: ENV.key?(#{args.first})!"
++ end
++
++ # NOTE: call original, so we can run tests depending on this variable
++ allow(ENV).to receive(:[]).with("GUARD_STRICT").and_call_original
++
++ # FIXME: instead, properly stub PluginUtil in the evaluator specs!
++ # and remove this!
++ allow(ENV).to receive(:[]).with("SPEC_OPTS").and_call_original
++
++ # FIXME: properly stub out Pry instead of this!
++ allow(ENV).to receive(:[]).with("ANSICON").and_call_original
++ allow(ENV).to receive(:[]).with("TERM").and_call_original
++
++ # Needed for debugging
++ allow(ENV).to receive(:[]).with("DISABLE_PRY").and_call_original
++ allow(ENV).to receive(:[]).with("PRYRC").and_call_original
++ allow(ENV).to receive(:[]).with("PAGER").and_call_original
++
++ # Workarounds for Cli inheriting from Thor
++ allow(ENV).to receive(:[]).with("ANSICON").and_call_original
++ allow(ENV).to receive(:[]).with("THOR_SHELL").and_call_original
++ allow(ENV).to receive(:[]).with("GEM_SKIP").and_call_original
++
++ %w(read write exist?).each do |meth|
++ allow(File).to receive(meth.to_sym).with(anything) do |*args, &_block|
++ abort "stub me! (File.#{meth}(#{args.map(&:inspect).join(', ')}))"
++ end
++ end
++
++ %w(read write binwrite binread).each do |meth|
++ allow(IO).to receive(meth.to_sym).with(anything) do |*args, &_block|
++ abort "stub me! (IO.#{meth}(#{args.map(&:inspect).join(', ')}))"
++ end
++ end
++
++ %w(exist?).each do |meth|
++ allow_any_instance_of(Pathname).
++ to receive(meth.to_sym) do |*args, &_block|
++ obj = args.first
++ formatted_args = args[1..-1].map(&:inspect).join(", ")
++ abort "stub me! (#{obj.inspect}##{meth}(#{formatted_args}))"
++ end
++ end
++
++ allow(Dir).to receive(:exist?).with(anything) do |*args, &_block|
++ abort "stub me! (Dir#exist?(#{args.map(&:inspect) * ', '}))"
++ end
++
++ if Guard.const_defined?("UI") && Guard::UI.respond_to?(:info)
++ # Stub all UI methods, so no visible output appears for the UI class
++ allow(Guard::UI).to receive(:info)
++ allow(Guard::UI).to receive(:warning)
++ allow(Guard::UI).to receive(:error)
++ allow(Guard::UI).to receive(:debug)
++ allow(Guard::UI).to receive(:deprecation)
++ end
++
++ allow(Kernel).to receive(:system) do |*args|
++ fail "stub for Kernel.system() called with: #{args.inspect}"
++ end
++
++ # TODO: use metadata to stub out all used classes
++ if Guard.const_defined?("Sheller")
++ unless example.metadata[:sheller_specs]
++ allow(Guard::Sheller).to receive(:run) do |*args|
++ fail "stub for Sheller.run() called with: #{args.inspect}"
++ end
++ end
++ end
++ end
++
++ config.after(:each) do
++ # Reset everything
++ (Guard.constants + [Guard]).each do |klass|
++ klass.instance_variables.each do |var|
++ klass.instance_variable_set(var, nil)
++ end
++ end
++ end
++end
+Index: ruby-guard/spec/support/gems_helper.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/support/gems_helper.rb
+@@ -0,0 +1,20 @@
++def growl_installed?
++ require "growl"
++ true
++rescue LoadError
++ false
++end
++
++def libnotify_installed?
++ require "libnotify"
++ true
++rescue LoadError
++ false
++end
++
++def rbnotifu_installed?
++ require "rb-notifu"
++ true
++rescue LoadError
++ false
++end
+Index: ruby-guard/spec/support/platform_helper.rb
+===================================================================
+--- /dev/null
++++ ruby-guard/spec/support/platform_helper.rb
+@@ -0,0 +1,11 @@
++def mac?
++ RbConfig::CONFIG["target_os"] =~ /darwin/i
++end
++
++def linux?
++ RbConfig::CONFIG["target_os"] =~ /linux/i
++end
++
++def windows?
++ RbConfig::CONFIG["target_os"] =~ /mswin|mingw/i
++end
diff --git a/debian/patches/disable_simplecov.patch b/debian/patches/disable_simplecov.patch
new file mode 100644
index 0000000..1018244
--- /dev/null
+++ b/debian/patches/disable_simplecov.patch
@@ -0,0 +1,19 @@
+Description: disable simplecov
+Author: HIGUCHI Daisuke (VDR dai) <dai at debian.org>
+Forwarded: not-needed
+Last-Update: 2017-11-28
+
+Index: ruby-guard/spec/spec_helper.rb
+===================================================================
+--- ruby-guard.orig/spec/spec_helper.rb
++++ ruby-guard/spec/spec_helper.rb
+@@ -18,9 +18,6 @@
+
+ require "fileutils"
+
+-require "simplecov"
+-SimpleCov.start
+-
+ ENV["GUARD_SPECS_RUNNING"] = "1"
+
+ path = "#{File.expand_path('..', __FILE__)}/support/**/*.rb"
diff --git a/debian/patches/pending_examples.patch b/debian/patches/pending_examples.patch
new file mode 100644
index 0000000..840c009
--- /dev/null
+++ b/debian/patches/pending_examples.patch
@@ -0,0 +1,27 @@
+Description: pending examples
+Author: HIGUCHI Daisuke (VDR dai) <dai at debian.org>
+Forwarded: not-needed
+Last-Update: 2017-11-28
+
+Index: ruby-guard/spec/lib/guard/plugin_util_spec.rb
+===================================================================
+--- ruby-guard.orig/spec/lib/guard/plugin_util_spec.rb
++++ ruby-guard/spec/lib/guard/plugin_util_spec.rb
+@@ -16,7 +16,7 @@ RSpec.describe Guard::PluginUtil do
+ allow(Guard::Guardfile::Evaluator).to receive(:new).and_return(evaluator)
+ end
+
+- describe ".plugin_names" do
++ xdescribe ".plugin_names" do
+ before do
+ spec = Gem::Specification
+ gems = [
+@@ -224,7 +224,7 @@ RSpec.describe Guard::PluginUtil do
+ allow(evaluator).to receive(:evaluate)
+ end
+
+- context "when the Guard is already in the Guardfile" do
++ xcontext "when the Guard is already in the Guardfile" do
+ before do
+ allow(evaluator).to receive(:guardfile_include?) { true }
+ end
diff --git a/debian/patches/series b/debian/patches/series
new file mode 100644
index 0000000..ac1efd7
--- /dev/null
+++ b/debian/patches/series
@@ -0,0 +1,4 @@
+do_not_use_gem_bin_path.patch
+add_specs.patch
+disable_simplecov.patch
+pending_examples.patch
diff --git a/debian/ruby-tests.rake b/debian/ruby-tests.rake
new file mode 100644
index 0000000..6e530f3
--- /dev/null
+++ b/debian/ruby-tests.rake
@@ -0,0 +1,7 @@
+require "rspec/core/rake_task"
+
+RSpec::Core::RakeTask.new(:spec) do |t|
+ t.rspec_opts = "-I spec -r spec_helper -f d --no-fail-fast"
+end
+
+task :default => :spec
diff --git a/debian/rules b/debian/rules
index 3454d59..7ab40e2 100755
--- a/debian/rules
+++ b/debian/rules
@@ -4,3 +4,6 @@ export GEM2DEB_TEST_RUNNER = --check-dependencies
%:
dh $@ --buildsystem=ruby --with ruby
+
+override_dh_auto_install:
+ PATH="$(CURDIR)/bin:$$PATH" dh_auto_install
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-ruby-extras/ruby-guard.git
More information about the Pkg-ruby-extras-commits
mailing list