use safe_popen_read instead of popen_read

RuboCop requires using Utils.safe_popen_read and Utils.safe_popen_write
instead of Utils.popen_read and Utils.popen_write respectively.

Using the "safe" version means that an error will be shown if the
command fails. Previously, when using `popen_read`, a failed command can
go unnoticed and have negative consequences that go undetected (as
happened for pipend in
https://github.com/Homebrew/homebrew-core/pull/55682)

RuboCop does not require Utils.safe_popen_read in a test do block
because there can be some legitimate uses for Utils.popen_read in these
cases.
This commit is contained in:
Rylan Polster 2020-06-04 21:05:38 -04:00
parent 9788735eb2
commit 0faf17b1e6
2 changed files with 123 additions and 0 deletions

View File

@ -195,6 +195,34 @@ module RuboCop
end
end
class ShellCmd < FormulaCop
def audit_formula(_node, _class_node, _parent_class_node, body_node)
test = find_block(body_node, :test)
[:popen_read, :popen_write].each do |unsafe_command|
test_methods = []
unless test.nil?
find_instance_method_call(test, "Utils", unsafe_command) do |method|
test_methods << method.source_range
end
end
find_instance_method_call(body_node, "Utils", unsafe_command) do |method|
unless test_methods.include?(method.source_range)
problem "Use `Utils.safe_#{unsafe_command}` instead of `Utils.#{unsafe_command}`"
end
end
end
end
def autocorrect(node)
lambda do |corrector|
corrector.replace(node.loc.selector, "safe_#{node.method_name}")
end
end
end
class Miscellaneous < FormulaCop
def audit_formula(_node, _class_node, _parent_class_node, body_node)
# FileUtils is included in Formula

View File

@ -345,6 +345,101 @@ describe RuboCop::Cop::FormulaAudit::MpiCheck do
end
end
describe RuboCop::Cop::FormulaAudit::ShellCmd do
subject(:cop) { described_class.new }
context "When auditing shell commands" do
it "Utils.popen_read should become Utils.safe_popen_read" do
expect_offense(<<~RUBY)
class Foo < Formula
def install
Utils.popen_read "foo"
^^^^^^^^^^^^^^^^^^^^^^ Use `Utils.safe_popen_read` instead of `Utils.popen_read`
end
end
RUBY
end
it "Utils.safe_popen_write should become Utils.popen_write" do
expect_offense(<<~RUBY)
class Foo < Formula
def install
Utils.popen_write "foo"
^^^^^^^^^^^^^^^^^^^^^^^ Use `Utils.safe_popen_write` instead of `Utils.popen_write`
end
end
RUBY
end
it "does not correct Utils.popen_read in test block" do
expect_no_offenses(<<~RUBY)
class Foo < Formula
def install; end
test do
Utils.popen_read "foo"
end
end
RUBY
end
it "corrects Utils.popen_read to Utils.safe_popen_read" do
source = <<~RUBY
class Foo < Formula
def install
Utils.popen_read "foo"
end
end
RUBY
corrected_source = <<~RUBY
class Foo < Formula
def install
Utils.safe_popen_read "foo"
end
end
RUBY
new_source = autocorrect_source(source)
expect(new_source).to eq(corrected_source)
end
it "corrects Utils.popen_write to Utils.safe_popen_write" do
source = <<~RUBY
class Foo < Formula
def install
Utils.popen_write "foo"
end
end
RUBY
corrected_source = <<~RUBY
class Foo < Formula
def install
Utils.safe_popen_write "foo"
end
end
RUBY
new_source = autocorrect_source(source)
expect(new_source).to eq(corrected_source)
end
it "does not correct to Utils.safe_popen_read in test block" do
source = <<~RUBY
class Foo < Formula
def install; end
test do
Utils.popen_write "foo"
end
end
RUBY
new_source = autocorrect_source(source)
expect(new_source).to eq(source)
end
end
end
describe RuboCop::Cop::FormulaAudit::Miscellaneous do
subject(:cop) { described_class.new }