Skip to content

Commit

Permalink
Merge pull request #652 from guard/acceptance_tests
Browse files Browse the repository at this point in the history
Acceptance tests
  • Loading branch information
e2 committed Oct 29, 2014
2 parents 3a3369c + 9374fca commit d2cd5e1
Show file tree
Hide file tree
Showing 20 changed files with 214 additions and 35 deletions.
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ group :development, :test do
gem "guard-rspec", require: false
gem "rspec", ">= 3.0.0"
gem "guard-rubocop", require: false
gem "guard-cucumber", require: false
gem "aruba", require: false
end

# The development group will not be
Expand Down
8 changes: 8 additions & 0 deletions Guardfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ group :specs do
watch(%r{.+\.rb$}) { |m| m[0] }
watch(%r{(?:.+/)?\.rubocop\.yml$}) { |m| File.dirname(m[0]) }
end

guard "cucumber", keep_failed: true, all_on_start: false do
watch(%r{^features/.+\.feature$})
watch(%r{^features/support/.+$}) { "features" }
watch(%r{^features/step_definitions/(.+)_steps\.rb$}) do |m|
Dir[File.join("**/#{m[1]}.feature")][0] || "features"
end
end
end

if !defined?(JRUBY_VERSION)
Expand Down
18 changes: 17 additions & 1 deletion Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,27 @@ require "bundler/gem_tasks"

require "rspec/core/rake_task"
RSpec::Core::RakeTask.new(:spec)
task default: :spec
task default: [:spec, :features]

require "guard/rake_task"
Guard::RakeTask.new(:guard, "--plugin ronn")

require "cucumber/rake/task"

Cucumber::Rake::Task.new(:features) do |t|
t.cucumber_opts = "features --format pretty"
end

# Coveralls:
#
# TODO: uncomment to merge results from RSpec and Cucumber
# require "coveralls/rake/task"
# Coveralls::RakeTask.new
# task :default => [:spec, :features, 'coveralls:push']
#
# TODO: for the above to work, also change Coveralls.wear_merged! instead of
# wear! in spec/spec_helper.rb

class Releaser
def initialize(options = {})
@project_name = options.delete(:project_name) do
Expand Down
9 changes: 7 additions & 2 deletions bin/guard
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
#!/usr/bin/env ruby

require "guard"
require "guard/cli"

Guard::CLI.start
begin
require "guard/aruba_adapter"
rescue LoadError => e
abort "#{e.inspect} - perhaps you need to run using `bundle exec`?"
end

Guard::ArubaAdapter.new(ARGV.dup).execute!
15 changes: 15 additions & 0 deletions features/init.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Feature: Guard "init" command

In order to quickly start a new project with Guard
As a user
I want Guard to create a Guardfile template for me

Scenario: Create an empty Guardfile
When I run `guard init -b`
Then the output should match /Writing new Guardfile to .*Guardfile$/
And the file "Guardfile" should contain "# A sample Guardfile"

Scenario: Create a Guardfile using a plugin's template
When I run `guard init rspec`
Then the output should match /Writing new Guardfile to .*Guardfile$/
And the file "Guardfile" should match /^guard :rspec, cmd: 'bundle exec rspec' do$/
26 changes: 26 additions & 0 deletions features/show.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
Feature: Show

In order to know the defined groups and plugins
As a developer using Guard
I want to see a table of groups and plugins

Scenario: Show error when no Guardfile
When I run `guard show`
Then the output should match /No Guardfile found, please create one with `guard init`\./
And the exit status should not be 0

Scenario: Show error when Guardfile has no plugins
Given an empty file named "Guardfile"
When I run `guard show`
Then the output should match /No Guard plugins found in Guardfile, please add at least one\.$/
# TODO: this step fails
# And the exit status should not be 0

Scenario: Show plugins and their configuration
Given a file named "Guardfile" with:
"""
guard :ronn do
end
"""
When I run `guard show`
Then the output should match /^| Default | Ronn\s+ |/
8 changes: 8 additions & 0 deletions features/support/env.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
require "aruba"
require "aruba/cucumber"

require "aruba/in_process"
require "guard/aruba_adapter"

Aruba::InProcess.main_class = Guard::ArubaAdapter
Aruba::process = Aruba::InProcess
9 changes: 9 additions & 0 deletions features/version.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Feature: Guard "version" command

In order to know if the Guard is up to date
As a user
I want to get the Guard version

Scenario: Show Guard's version
When I run `guard version`
Then the output should match /^Guard version \d+.\d+.\d+$/
8 changes: 7 additions & 1 deletion lib/guard.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,14 @@ class << self
attr_accessor :runner, :listener, :lock, :running

# Called by Pry scope command
attr_reader :scope

def scope=(new_scope)
@scope = new_scope
@scope.dup.freeze
end

def scope
@scope.dup.freeze
end

# Smart accessor for retrieving specific plugins at once.
Expand Down Expand Up @@ -137,6 +141,8 @@ def groups(filter = nil)
@groups.select { |group| group.name == filter.to_sym }
when Regexp
@groups.select { |group| group.name.to_s =~ filter }
else
fail "Invalid filter: #{filter.inspect}"
end
end

Expand Down
55 changes: 55 additions & 0 deletions lib/guard/aruba_adapter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
require "guard/cli"

module Guard
class ArubaAdapter
def initialize(argv, stdin = STDIN, stdout = STDOUT, stderr = STDERR,
kernel = Kernel)
@argv = argv
@stdin = stdin
@stdout = stdout
@stderr = stderr
@kernel = kernel
::Guard::UI.options = ::Guard::UI.options.merge(flush_seconds: 0)
end

def execute!
exit_code = execute
# Proxy our exit code back to the injected kernel.
@kernel.exit(exit_code)
end

def execute
# Thor accesses these streams directly rather than letting
# them be injected, so we replace them...
$stderr = @stderr
$stdin = @stdin
$stdout = @stdout

# Run our normal Thor app the way we know and love.
::Guard::CLI.start(@argv)

# Thor::Base#start does not have a return value, assume
# success if no exception is raised.
0
rescue StandardError => e
# The ruby interpreter would pipe this to STDERR and exit 1 in the case
# of an unhandled exception
b = e.backtrace
b.unshift("#{b.shift}: #{e.message} (#{e.class})")
@stderr.puts(b.map { |s| "\tfrom #{s}" }.join("\n"))
1
rescue SystemExit => e
e.status
ensure
# flush the logger so the output doesn't appear in next CLI invocation
::Guard::UI.logger.flush
::Guard::UI.logger.close
::Guard::UI.reset_logger

# ...then we put them back.
$stderr = STDERR
$stdin = STDIN
$stdout = STDOUT
end
end
end
2 changes: 1 addition & 1 deletion lib/guard/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ def notifiers
# @see Guard::VERSION
#
def version
STDOUT.puts "Guard version #{ ::Guard::VERSION }"
$stdout.puts "Guard version #{ ::Guard::VERSION }"
end

desc "init [GUARDS]", "Generates a Guardfile at the current directory"\
Expand Down
2 changes: 1 addition & 1 deletion lib/guard/commands/scope.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def process(*entries)
return
end

::Guard.scope = scope
::Guard.setup_scope(scope)
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/guard/guardfile/evaluator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ def initialize(opts = {})
#
def evaluate_guardfile
_fetch_guardfile_contents
::Guard.add_builtin_plugins(guardfile_path)
_instance_eval_guardfile(guardfile_contents)
::Guard.add_builtin_plugins(guardfile_path)
end

# Re-evaluates the `Guardfile` to update
Expand Down
29 changes: 15 additions & 14 deletions lib/guard/runner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ def _scoped_plugins(scopes = {})
end
else
_current_groups_scope(scopes).each do |group|
fail "Invalid group: #{group.inspect}" unless group.respond_to?(:name)
current_plugin = nil
block_return = catch :task_has_failed do
::Guard.plugins(group: group.name).each do |guard|
Expand All @@ -151,13 +152,9 @@ def _scoped_plugins(scopes = {})
# @return [Array<Guard::Plugin>] the plugins to scope to
#
def _current_plugins_scope(scope)
if plugins = _find_non_empty_plugins_scope(scope)
Array(plugins).map do |plugin|
plugin.is_a?(Symbol) ? ::Guard.plugin(plugin) : plugin
end
else
nil
end
return nil unless (plugins = _find_non_empty_plugins_scope(scope))

Array(plugins).map { |plugin| _instantiate(:plugin, plugin) }
end

# Returns the current groups scope.
Expand All @@ -168,21 +165,24 @@ def _current_plugins_scope(scope)
# @return [Array<Guard::Group>] the groups to scope to
#
def _current_groups_scope(scope)
Array(_find_non_empty_groups_scope(scope)).map do |group|
group.is_a?(Symbol) ? ::Guard.group(group) : group
end
groups = _find_non_empty_groups_scope(scope)
Array(groups).map { |group| _instantiate(:group, group) }
end

def _instantiate(meth, obj)
(obj.is_a?(Symbol) || obj.is_a?(String)) ? ::Guard.send(meth, obj) : obj
end

# Find the first non empty element in the given possibilities
#
def _find_non_empty_scope(type, local_scope, *additional_possibilities)
found = [
local_scope[:"#{type}s"],
local_scope[type.to_sym],
[local_scope[type.to_sym]],
::Guard.scope[:"#{type}s"],
additional_possibilities.flatten
].compact.detect { |a| !Array(a).empty? }
found ? [::Guard.group(:common)] + Array(found) : found
]
found.compact.detect { |a| !Array(a).compact.empty? }
end

# Find the first non empty plugins scope
Expand All @@ -194,7 +194,8 @@ def _find_non_empty_plugins_scope(scope)
# Find the first non empty groups scope
#
def _find_non_empty_groups_scope(scope)
_find_non_empty_scope(:group, scope, ::Guard.groups)
common = [::Guard.group(:common)]
common + _find_non_empty_scope(:group, scope, ::Guard.groups)
end
end
end
19 changes: 12 additions & 7 deletions lib/guard/setuper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -127,12 +127,11 @@ def restore_scope
def setup_scope(scope = {})
# TODO: there should be a special Scope class instead
scope = _prepare_scope(scope)
{ groups: :add_group, plugins: :plugin }.each do |type, meth|
next unless scope[type].any?
::Guard.scope[type] = scope[type].map do |item|
::Guard.send(meth, item)
end
end

::Guard.scope = {
groups: scope[:groups].map { |item| ::Guard.add_group(item) },
plugins: scope[:plugins].map { |item| ::Guard.plugin(item) },
}
end

# Evaluates the Guardfile content. It displays an error message if no
Expand Down Expand Up @@ -346,9 +345,15 @@ def _prepare_scope(scope)
plugins = Array(options[:plugin])
plugins = Array(scope[:plugins] || scope[:plugin]) if plugins.empty?

# Convert objects to names
plugins.map! { |p| p.respond_to?(:name) ? p.name : p }

groups = Array(options[:group])
groups = Array(scope[:groups] || scope[:group]) if groups.empty?

# Convert objects to names
groups.map! { |g| g.respond_to?(:name) ? g.name : g }

{ plugins: plugins, groups: groups }
end

Expand All @@ -365,7 +370,7 @@ def _reset_for_tests
@watchdirs = nil
@listener = nil
@interactor = nil
::Guard.scope = nil
@scope = nil
end
end
end
8 changes: 8 additions & 0 deletions lib/guard/ui.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ def logger
end
end

# Since logger is global, for Aruba in-process to properly
# separate output between calls, we need to reset
#
# We don't use logger=() since it's expected to be a Lumberjack instance
def reset_logger
@logger = nil
end

# Get the logger options
#
# @return [Hash] the logger options
Expand Down
8 changes: 5 additions & 3 deletions spec/lib/guard/commands/scope_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@
let(:given_scope) { ["foo"] }
let(:converted_scope) { [{ groups: [foo_group], plugins: [] }, []] }

it "runs the :scope= action with the given scope" do
expect(Guard).to receive(:scope=).with(groups: [foo_group], plugins: [])
it "sets up the scope with the given scope" do
expect(Guard).to receive(:setup_scope).
with(groups: [foo_group], plugins: [])
Pry.run_command "scope foo"
end
end
Expand All @@ -44,7 +45,8 @@
let(:converted_scope) { [{ groups: [], plugins: [bar_guard] }, []] }

it "runs the :scope= action with the given scope" do
expect(Guard).to receive(:scope=).with(plugins: [bar_guard], groups: [])
expect(Guard).to receive(:setup_scope).
with(plugins: [bar_guard], groups: [])
Pry.run_command "scope bar"
end
end
Expand Down

0 comments on commit d2cd5e1

Please sign in to comment.