Skip to content

Commit

Permalink
Detect whether raise_errors_for_deprecations! is enabled in user's specs
Browse files Browse the repository at this point in the history
This closes #80.
  • Loading branch information
yujinakayama committed Jul 16, 2014
1 parent 1a0c04c commit 45f8571
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 44 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## Development

* Detect whether RSpec configuration `config.raise_errors_for_deprecations!` which interferes with Transpec's dynamic analysis is enabled in the user's specs and abort processing if so. ([#80](https://github.com/yujinakayama/transpec/issues/80))

## v2.3.3

* Fix failure on dynamic analysis when there's a RSpec-like method invocation in a context that undefines `Object` methods (e.g. `after` callback in [factory_girl definition context](https://github.com/thoughtbot/factory_girl/blob/v4.4.0/lib/factory_girl/definition_proxy.rb#L3-L7)). ([#66](https://github.com/yujinakayama/transpec/issues/66))
Expand Down
53 changes: 23 additions & 30 deletions lib/transpec/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,8 @@ def run(args)
return false
end

begin
process(paths)
rescue DynamicAnalyzer::AnalysisError
warn_dynamic_analysis_error
return false
end
done = process(paths)
return false unless done

display_summary
generate_commit_message
Expand All @@ -49,10 +45,9 @@ def run(args)
end

def process(paths)
runtime_data = nil

unless config.skip_dynamic_analysis?
runtime_data = run_dynamic_analysis(paths)
return false unless runtime_data
end

spec_suite = SpecSuite.new(paths, runtime_data)
Expand All @@ -65,6 +60,26 @@ def process(paths)
spec_suite.specs.each do |spec|
convert_spec(spec, spec_suite)
end

true
end

def run_dynamic_analysis(paths)
runtime_data = nil

puts 'Copying the project for dynamic analysis...'

DynamicAnalyzer.new(rspec_command: config.rspec_command) do |analyzer|
puts "Running dynamic analysis with command #{analyzer.rspec_command.inspect}..."
runtime_data = analyzer.analyze(paths)
end

puts

runtime_data
rescue DynamicAnalyzer::AnalysisError => error
warn "\n" + error.message.color(:red)
return nil
end

def convert_spec(spec, spec_suite)
Expand Down Expand Up @@ -96,21 +111,6 @@ def fail_if_should_not_continue!
end
end

def run_dynamic_analysis(paths)
runtime_data = nil

puts 'Copying the project for dynamic analysis...'

DynamicAnalyzer.new(rspec_command: config.rspec_command) do |analyzer|
puts "Running dynamic analysis with command #{analyzer.rspec_command.inspect}..."
runtime_data = analyzer.analyze(paths)
end

puts

runtime_data
end

def display_summary
puts

Expand Down Expand Up @@ -145,13 +145,6 @@ def display_final_guide
puts "Done! Now run #{'rspec'.bright} and check if everything is green."
end

def warn_dynamic_analysis_error
warn 'Failed running dynamic analysis. ' \
'Transpec runs your specs in a copied project directory. ' \
'If your project requires some special setup or commands to run specs, ' \
'use -c/--rspec-command option.'
end

def warn_syntax_error(error)
warn "Syntax error at #{error.diagnostic.location}. Skipping the file.".color(:red)
end
Expand Down
9 changes: 7 additions & 2 deletions lib/transpec/dynamic_analyzer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ module Transpec
class DynamicAnalyzer
ANALYSIS_MODULE = 'Transpec'
ANALYSIS_METHOD = 'analyze'
RUNTIME_DATA_ERROR_MESSAGE_KEY = :error_message
HELPER_TEMPLATE_FILE = 'transpec_analysis_helper.rb.erb'
RESULT_FILE = 'transpec_analysis_result.json'

Expand Down Expand Up @@ -113,8 +114,12 @@ def load_analysis_result
File.open(RESULT_FILE) do |file|
RuntimeData.load(file)
end
rescue
raise AnalysisError
rescue Errno::ENOENT
message = 'Failed running dynamic analysis. ' \
'Transpec runs your specs in a copied project directory. ' \
'If your project requires some special setup or commands to run specs, ' \
'use -c/--rspec-command option.'
raise AnalysisError, message
end

class AnalysisError < StandardError; end
Expand Down
3 changes: 3 additions & 0 deletions lib/transpec/dynamic_analyzer/runtime_data.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ def self.load(string_or_io)
end

def initialize(data = CompatibleOpenStruct.new)
error_message = data[RUNTIME_DATA_ERROR_MESSAGE_KEY]
fail AnalysisError, error_message if error_message

@data = data
end

Expand Down
30 changes: 29 additions & 1 deletion lib/transpec/dynamic_analyzer/transpec_analysis_helper.rb.erb
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,44 @@ module <%= ANALYSIS_MODULE %>
object
end

at_exit do
def error_message=(message)
data[<%= RUNTIME_DATA_ERROR_MESSAGE_KEY.inspect %>] = message
end

def validate_rspec_configuration!(config)
deprecation_stream_name = config.deprecation_stream.class.name

if deprecation_stream_name.start_with?('RSpec::Core::Formatters::DeprecationFormatter')
self.error_message = 'Aborted dynamic analysis. ' \
'Disable `RSpec.configure { |c| c.raise_errors_for_deprecations! }` ' \
"in your spec because it interferes with Transpec's dynamic analysis."
save_result
exit(1)
end
end

def save_result
# Use JSON rather than Marshal so that:
# * Unknown third-party class information won't be serialized.
# (Such objects are stored as a string.)
# * Singleton method information won't be serialized.
# (With Marshal.load, `singleton can't be dumped (TypeError)` will be raised.)
require 'json'

path = File.join(@base_path, '<%= RESULT_FILE %>')

File.open(path, 'w') do |file|
JSON.dump(data, file)
end
end

at_exit do
save_result
end
end

RSpec.configure do |config|
config.before(:suite) do
Transpec.validate_rspec_configuration!(config)
end
end
10 changes: 0 additions & 10 deletions spec/transpec/cli_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,6 @@ module Transpec

context "when the project's RSpec dependency is older than the required version" do
before do
Git.stub(:command_available?).and_return(false)
cli.project.stub(:rspec_version).and_return(RSpecVersion.new('2.13.0'))
end

Expand All @@ -148,19 +147,10 @@ module Transpec

context 'when analysis error is raised in the dynamic analysis' do
before do
Git.stub(:command_available?).and_return(false)
DynamicAnalyzer.any_instance.stub(:analyze).and_raise(DynamicAnalyzer::AnalysisError)
end

include_examples 'aborts processing'

it 'suggests using -c/--rspec-command option' do
cli.should_receive(:warn) do |message|
message.should include('use -c/--rspec-command')
end

cli.run(args)
end
end

context 'when a syntax error is raised while processing files' do
Expand Down
47 changes: 46 additions & 1 deletion spec/transpec/dynamic_analyzer_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,8 @@ def find_node_in_file(file_path, &block)
let(:source) { 'exit!' }

it 'raises AnalysisError' do
-> { dynamic_analyzer.analyze }.should raise_error(DynamicAnalyzer::AnalysisError)
-> { dynamic_analyzer.analyze }
.should raise_error(DynamicAnalyzer::AnalysisError, /Failed running dynamic analysis/)
end
end

Expand Down Expand Up @@ -248,6 +249,50 @@ class SomeProxy
end
end

context 'when a deprecated syntax is used with `RSpec.configure { |c| c.raise_errors_for_deprecations! }`' do
include CacheHelper

around do |example|
with_cached_dir('rspec-2.99-project') do |cached|
unless cached
create_file('Gemfile', <<-END)
source 'https://rubygems.org'
gem 'rspec', '~> 2.99'
END

Project.new.with_bundler_clean_env do
`bundle install --path vendor/bundle`
end

create_file('spec/spec_helper.rb', <<-END)
RSpec.configure do |config|
config.raise_errors_for_deprecations!
end
END
end

example.run
end
end

let(:source) do
<<-END
require 'spec_helper'
describe 'example' do
it 'is deprecated syntax' do
mock('something')
end
end
END
end

it 'raises AnalysisError with a warning message about `raise_errors_for_deprecations!`' do
-> { dynamic_analyzer.analyze }
.should raise_error(DynamicAnalyzer::AnalysisError, /raise_errors_for_deprecations!/)
end
end

runtime_data_cache = {}

subject(:runtime_data) do
Expand Down

0 comments on commit 45f8571

Please sign in to comment.