Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RSpec::Support::Source.from_file crashes in File.read if Encoding.default_internal would cause a lossy conversion #354

Open
julik opened this issue Oct 18, 2018 · 8 comments

Comments

@julik
Copy link

julik commented Oct 18, 2018

Subject of the issue

I was doing work on one of my gems and accidentally removed rack-test from the gemspec. When I try to load rspec (run bundle exec rspec) RSpec instead of telling me which require() has failed raises an encoding error in RSpec::Support::Source.from_file. The encoding error is very non-descriptive and obscures the actual issue at hand (missing dependency). This results in a backtrace like this

julik@nanobuk <redacted_directory> (remove-jeweler) $ bspec
bundler: failed to load command: rspec (/Users/julik/.rbenv/versions/2.5.1/bin/rspec)
Encoding::UndefinedConversionError: U+043D from UTF-8 to ASCII-8BIT
  /Users/julik/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rspec-support-3.8.0/lib/rspec/support/source.rb:12:in `read'
  /Users/julik/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rspec-support-3.8.0/lib/rspec/support/source.rb:12:in `from_file'
  /Users/julik/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rspec-core-3.8.0/lib/rspec/core/world.rb:150:in `source_from_file'
  /Users/julik/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rspec-core-3.8.0/lib/rspec/core/formatters/snippet_extractor.rb:18:in `source_from_file'
  /Users/julik/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rspec-core-3.8.0/lib/rspec/core/formatters/snippet_extractor.rb:30:in `extract_expression_lines_at'
  /Users/julik/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rspec-core-3.8.0/lib/rspec/core/formatters/exception_presenter.rb:218:in `read_failed_lines'
  /Users/julik/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rspec-core-3.8.0/lib/rspec/core/formatters/exception_presenter.rb:163:in `failure_slash_error_lines'
  /Users/julik/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rspec-core-3.8.0/lib/rspec/core/formatters/exception_presenter.rb:150:in `block in failure_lines'
  /Users/julik/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rspec-core-3.8.0/lib/rspec/core/formatters/exception_presenter.rb:149:in `tap'
  /Users/julik/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rspec-core-3.8.0/lib/rspec/core/formatters/exception_presenter.rb:149:in `failure_lines'
  /Users/julik/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rspec-core-3.8.0/lib/rspec/core/formatters/exception_presenter.rb:34:in `colorized_message_lines'
  /Users/julik/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rspec-core-3.8.0/lib/rspec/core/formatters/exception_presenter.rb:240:in `formatted_message_and_backtrace'
  /Users/julik/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rspec-core-3.8.0/lib/rspec/core/formatters/exception_presenter.rb:86:in `fully_formatted_lines'
  /Users/julik/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rspec-core-3.8.0/lib/rspec/core/formatters/exception_presenter.rb:78:in `fully_formatted'
  /Users/julik/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rspec-core-3.8.0/lib/rspec/core/reporter.rb:161:in `notify_non_example_exception'
  /Users/julik/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rspec-core-3.8.0/lib/rspec/core/configuration.rb:2037:in `rescue in load_file_handling_errors'
  /Users/julik/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rspec-core-3.8.0/lib/rspec/core/configuration.rb:2033:in `load_file_handling_errors'
  /Users/julik/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rspec-core-3.8.0/lib/rspec/core/configuration.rb:1560:in `block in load_spec_files'
  /Users/julik/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rspec-core-3.8.0/lib/rspec/core/configuration.rb:1558:in `each'
  /Users/julik/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rspec-core-3.8.0/lib/rspec/core/configuration.rb:1558:in `load_spec_files'
  /Users/julik/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rspec-core-3.8.0/lib/rspec/core/runner.rb:98:in `setup'
  /Users/julik/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rspec-core-3.8.0/lib/rspec/core/runner.rb:86:in `run'
  /Users/julik/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rspec-core-3.8.0/lib/rspec/core/runner.rb:71:in `run'
  /Users/julik/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rspec-core-3.8.0/lib/rspec/core/runner.rb:45:in `invoke'
  /Users/julik/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rspec-core-3.8.0/exe/rspec:4:in `<top (required)>'
  /Users/julik/.rbenv/versions/2.5.1/bin/rspec:23:in `load'
  /Users/julik/.rbenv/versions/2.5.1/bin/rs

Your environment

  • Ruby version: ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-darwin16]
  • rspec-support version: 3.8.0

Outputting

      def self.from_file(path)
        $stderr.puts Encoding.default_internal
        $stderr.puts Encoding.default_external

at the head of the method prints

ASCII-8BIT
UTF-8

Steps to reproduce

Create the following spec file in an empty directory:

spec/boom_spec.rb:

# Make sure we catch all the possible encoding bugs
Encoding.default_internal = Encoding::BINARY

describe UndeclaredModule do # the missing constant can be anything
  it 'crashes and does not even parse this' do
    header = 'привет'
  end
end

and add a Gemfile with the usual stanza

source :rubygems
gem "rspec"

Run bundle install and then bundle exec rspec as per usual.

Expected behavior

For the given spec, the spec runner tells me that the UndeclaredModule is a missing constant (or something descriptive at least).

Actual behavior

Rspec runner will crash with an encoding error in File.read.

Recommended fix

Change File.read to File.binread. As it stands the source reader is not internal encoding resilient - it expects that Ruby will be able to read the file correctly and convert it, but since the conversion in this case would be lossy (UTF8 source to ASCII internal) Ruby raises an error.

@JonRowe
Copy link
Member

JonRowe commented Feb 5, 2019

@julik Sorry for the delay, I've verified this and built a fix over on #364 if you have any ideas how to replicate this in a spec (we need to somehow produce invalid contents from within Ruby) I'd be grateful.

@julik
Copy link
Author

julik commented Feb 6, 2019

Appreciated. I don't think you can replicate this from "within" a running rspec suite - you would need to run a separate process that is configured in a specific way.

@JonRowe
Copy link
Member

JonRowe commented Feb 6, 2019

The error is actually just down to loading a file with bad encoding, I just can't seem to produce the invalid encoding!

@julik
Copy link
Author

julik commented Feb 6, 2019

The issue here is in the default_internal declaration. If what is in your file is valid but not representable in the internal encoding the exception gets raised. So any Unicode file would do as long as the internal encoding is ASCII

@JonRowe
Copy link
Member

JonRowe commented Feb 6, 2019

Hm well problem is solved for now with a note explaining how to test :)

@julik
Copy link
Author

julik commented Feb 6, 2019

Awesome!

@benoittgt
Copy link
Member

Hm well problem is solved for now with a note explaining how to test :)

Does it means we should close this issue? 😊

@JonRowe
Copy link
Member

JonRowe commented Jun 13, 2019

I think it should remain open until #364 can be merged

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants