377 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			377 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
| require "testing_env"
 | |
| require "fileutils"
 | |
| require "pathname"
 | |
| require "formulary"
 | |
| require "cmd/audit"
 | |
| 
 | |
| class FormulaTextTests < Homebrew::TestCase
 | |
|   def setup
 | |
|     @dir = mktmpdir
 | |
|   end
 | |
| 
 | |
|   def teardown
 | |
|     FileUtils.rm_rf @dir
 | |
|   end
 | |
| 
 | |
|   def formula_text(name, body = nil, options = {})
 | |
|     path = Pathname.new "#{@dir}/#{name}.rb"
 | |
|     path.open("w") do |f|
 | |
|       f.write <<-EOS.undent
 | |
|         class #{Formulary.class_s(name)} < Formula
 | |
|           #{body}
 | |
|         end
 | |
|         #{options[:patch]}
 | |
|       EOS
 | |
|     end
 | |
|     FormulaText.new path
 | |
|   end
 | |
| 
 | |
|   def test_simple_valid_formula
 | |
|     ft = formula_text "valid", 'url "http://www.example.com/valid-1.0.tar.gz"'
 | |
| 
 | |
|     refute ft.has_DATA?, "The formula should not have DATA"
 | |
|     refute ft.has_END?, "The formula should not have __END__"
 | |
|     assert ft.has_trailing_newline?, "The formula should have a trailing newline"
 | |
| 
 | |
|     assert ft =~ /\burl\b/, "The formula should match 'url'"
 | |
|     assert_nil ft.line_number(/desc/), "The formula should not match 'desc'"
 | |
|     assert_equal 2, ft.line_number(/\burl\b/)
 | |
|     assert ft.include?("Valid"), "The formula should include \"Valid\""
 | |
|   end
 | |
| 
 | |
|   def test_trailing_newline
 | |
|     ft = formula_text "newline"
 | |
|     assert ft.has_trailing_newline?, "The formula must have a trailing newline"
 | |
|   end
 | |
| 
 | |
|   def test_has_data
 | |
|     ft = formula_text "data", "patch :DATA"
 | |
|     assert ft.has_DATA?, "The formula must have DATA"
 | |
|   end
 | |
| 
 | |
|   def test_has_end
 | |
|     ft = formula_text "end", "", :patch => "__END__\na patch here"
 | |
|     assert ft.has_END?, "The formula must have __END__"
 | |
|     assert_equal "class End < Formula\n  \nend", ft.without_patch
 | |
|   end
 | |
| end
 | |
| 
 | |
| class FormulaAuditorTests < Homebrew::TestCase
 | |
|   def setup
 | |
|     @dir = mktmpdir
 | |
|   end
 | |
| 
 | |
|   def teardown
 | |
|     FileUtils.rm_rf @dir
 | |
|   end
 | |
| 
 | |
|   def formula_auditor(name, text, options = {})
 | |
|     path = Pathname.new "#{@dir}/#{name}.rb"
 | |
|     path.open("w") { |f| f.write text }
 | |
|     FormulaAuditor.new Formulary.factory(path), options
 | |
|   end
 | |
| 
 | |
|   def test_init_no_problems
 | |
|     fa = formula_auditor "foo", <<-EOS.undent
 | |
|       class Foo < Formula
 | |
|         url "http://example.com/foo-1.0.tgz"
 | |
|       end
 | |
|     EOS
 | |
| 
 | |
|     assert_equal [], fa.problems
 | |
|   end
 | |
| 
 | |
|   def test_audit_file_permissions
 | |
|     File.stubs(:umask).returns 022
 | |
|     fa = formula_auditor "foo", <<-EOS.undent
 | |
|       class Foo < Formula
 | |
|         url "http://example.com/foo-1.0.tgz"
 | |
|       end
 | |
|     EOS
 | |
| 
 | |
|     path = fa.formula.path
 | |
|     path.chmod 0400
 | |
| 
 | |
|     fa.audit_file
 | |
|     assert_equal ["Incorrect file permissions (400): chmod 644 #{path}"],
 | |
|       fa.problems
 | |
|   end
 | |
| 
 | |
|   def test_audit_file_data_no_end
 | |
|     fa = formula_auditor "foo", <<-EOS.undent
 | |
|       class Foo < Formula
 | |
|         url "http://example.com/foo-1.0.tgz"
 | |
|         patch :DATA
 | |
|       end
 | |
|     EOS
 | |
|     fa.audit_file
 | |
|     assert_equal ["'DATA' was found, but no '__END__'"], fa.problems
 | |
|   end
 | |
| 
 | |
|   def test_audit_file_end_no_data
 | |
|     fa = formula_auditor "foo", <<-EOS.undent
 | |
|       class Foo < Formula
 | |
|         url "http://example.com/foo-1.0.tgz"
 | |
|       end
 | |
|       __END__
 | |
|       a patch goes here
 | |
|     EOS
 | |
|     fa.audit_file
 | |
|     assert_equal ["'__END__' was found, but 'DATA' is not used"], fa.problems
 | |
|   end
 | |
| 
 | |
|   def test_audit_file_no_trailing_newline
 | |
|     fa = formula_auditor "foo", 'class Foo<Formula; url "file:///foo-1.0.tgz";end'
 | |
|     fa.audit_file
 | |
|     assert_equal ["File should end with a newline"], fa.problems
 | |
|   end
 | |
| 
 | |
|   def test_audit_file_not_strict_no_issue
 | |
|     fa = formula_auditor "foo", <<-EOS.undent
 | |
|       class Foo < Formula
 | |
|         url "http://example.com/foo-1.0.tgz"
 | |
|         homepage "http://example.com"
 | |
|       end
 | |
|     EOS
 | |
|     fa.audit_file
 | |
|     assert_equal [], fa.problems
 | |
|   end
 | |
| 
 | |
|   def test_audit_file_strict_ordering_issue
 | |
|     fa = formula_auditor "foo", <<-EOS.undent, :strict => true
 | |
|       class Foo < Formula
 | |
|         url "http://example.com/foo-1.0.tgz"
 | |
|         homepage "http://example.com"
 | |
|       end
 | |
|     EOS
 | |
|     fa.audit_file
 | |
|     assert_equal ["`homepage` (line 3) should be put before `url` (line 2)"],
 | |
|       fa.problems
 | |
|   end
 | |
| 
 | |
|   def test_audit_file_strict_resource_placement
 | |
|     fa = formula_auditor "foo", <<-EOS.undent, :strict => true
 | |
|       class Foo < Formula
 | |
|         url "https://example.com/foo-1.0.tgz"
 | |
| 
 | |
|         resource "foo2" do
 | |
|           url "https://example.com/foo-2.0.tgz"
 | |
|         end
 | |
| 
 | |
|         depends_on "openssl"
 | |
|       end
 | |
|     EOS
 | |
|     fa.audit_file
 | |
|     assert_equal ["`depends_on` (line 8) should be put before `resource` (line 4)"],
 | |
|       fa.problems
 | |
|   end
 | |
| 
 | |
|   def test_audit_file_strict_plist_placement
 | |
|     fa = formula_auditor "foo", <<-EOS.undent, :strict => true
 | |
|       class Foo < Formula
 | |
|         url "https://example.com/foo-1.0.tgz"
 | |
| 
 | |
|         test do
 | |
|           assert_match "Dogs are terrific", shell_output("./dogs")
 | |
|         end
 | |
| 
 | |
|         def plist
 | |
|         end
 | |
|       end
 | |
|     EOS
 | |
|     fa.audit_file
 | |
|     assert_equal ["`plist block` (line 8) should be put before `test block` (line 4)"],
 | |
|       fa.problems
 | |
|   end
 | |
| 
 | |
|   def test_audit_file_strict_url_outside_of_stable_block
 | |
|     fa = formula_auditor "foo", <<-EOS.undent, :strict => true
 | |
|       class Foo < Formula
 | |
|         url "http://example.com/foo-1.0.tgz"
 | |
|         stable do
 | |
|           # stuff
 | |
|         end
 | |
|       end
 | |
|     EOS
 | |
|     fa.audit_file
 | |
|     assert_equal ["`url` should be put inside `stable block`"], fa.problems
 | |
|   end
 | |
| 
 | |
|   def test_audit_file_strict_head_and_head_do
 | |
|     fa = formula_auditor "foo", <<-EOS.undent, :strict => true
 | |
|       class Foo < Formula
 | |
|         head "http://example.com/foo.git"
 | |
|         head do
 | |
|           # stuff
 | |
|         end
 | |
|       end
 | |
|     EOS
 | |
|     fa.audit_file
 | |
|     assert_equal ["Should not have both `head` and `head do`"], fa.problems
 | |
|   end
 | |
| 
 | |
|   def test_audit_file_strict_bottle_and_bottle_do
 | |
|     fa = formula_auditor "foo", <<-EOS.undent, :strict => true
 | |
|       class Foo < Formula
 | |
|         url "http://example.com/foo-1.0.tgz"
 | |
|         bottle do
 | |
|           # bottles go here
 | |
|         end
 | |
|         bottle :unneeded
 | |
|       end
 | |
|     EOS
 | |
|     fa.audit_file
 | |
|     assert_equal ["Should not have `bottle :unneeded/:disable` and `bottle do`"],
 | |
|       fa.problems
 | |
|   end
 | |
| 
 | |
|   def test_audit_class_no_test
 | |
|     fa = formula_auditor "foo", <<-EOS.undent
 | |
|       class Foo < Formula
 | |
|         url "http://example.com/foo-1.0.tgz"
 | |
|       end
 | |
|     EOS
 | |
|     fa.audit_class
 | |
|     assert_equal [], fa.problems
 | |
| 
 | |
|     fa = formula_auditor "foo", <<-EOS.undent, :strict => true
 | |
|       class Foo < Formula
 | |
|         url "http://example.com/foo-1.0.tgz"
 | |
|       end
 | |
|     EOS
 | |
|     fa.audit_class
 | |
|     assert_equal ["A `test do` test block should be added"], fa.problems
 | |
|   end
 | |
| 
 | |
|   def test_audit_class_github_gist_formula
 | |
|     needs_compat
 | |
|     require "compat/formula_specialties"
 | |
| 
 | |
|     ARGV.stubs(:homebrew_developer?).returns false
 | |
|     fa = shutup do
 | |
|       formula_auditor "foo", <<-EOS.undent
 | |
|         class Foo < GithubGistFormula
 | |
|           url "http://example.com/foo-1.0.tgz"
 | |
|         end
 | |
|       EOS
 | |
|     end
 | |
|     fa.audit_class
 | |
|     assert_equal ["GithubGistFormula is deprecated, use Formula instead"],
 | |
|       fa.problems
 | |
|   end
 | |
| 
 | |
|   def test_audit_class_script_file_formula
 | |
|     needs_compat
 | |
|     require "compat/formula_specialties"
 | |
| 
 | |
|     ARGV.stubs(:homebrew_developer?).returns false
 | |
|     fa = formula_auditor "foo", <<-EOS.undent
 | |
|       class Foo < ScriptFileFormula
 | |
|         url "http://example.com/foo-1.0.tgz"
 | |
|       end
 | |
|     EOS
 | |
|     fa.audit_class
 | |
|     assert_equal ["ScriptFileFormula is deprecated, use Formula instead"],
 | |
|       fa.problems
 | |
|   end
 | |
| 
 | |
|   def test_audit_class_aws_formula
 | |
|     needs_compat
 | |
|     require "compat/formula_specialties"
 | |
| 
 | |
|     ARGV.stubs(:homebrew_developer?).returns false
 | |
|     fa = formula_auditor "foo", <<-EOS.undent
 | |
|       class Foo < AmazonWebServicesFormula
 | |
|         url "http://example.com/foo-1.0.tgz"
 | |
|       end
 | |
|     EOS
 | |
|     fa.audit_class
 | |
|     assert_equal ["AmazonWebServicesFormula is deprecated, use Formula instead"],
 | |
|       fa.problems
 | |
|   end
 | |
| 
 | |
|   def test_audit_line_pkgshare
 | |
|     fa = formula_auditor "foo", <<-EOS.undent, :strict => true
 | |
|       class Foo < Formula
 | |
|         url "http://example.com/foo-1.0.tgz"
 | |
|       end
 | |
|     EOS
 | |
|     fa.audit_line 'ohai "#{share}/foo"', 3
 | |
|     assert_equal "Use \#{pkgshare} instead of \#{share}/foo", fa.problems.shift
 | |
| 
 | |
|     fa.audit_line 'ohai "#{share}/foo/bar"', 3
 | |
|     assert_equal "Use \#{pkgshare} instead of \#{share}/foo", fa.problems.shift
 | |
| 
 | |
|     fa.audit_line 'ohai share/"foo"', 3
 | |
|     assert_equal 'Use pkgshare instead of (share/"foo")', fa.problems.shift
 | |
| 
 | |
|     fa.audit_line 'ohai share/"foo/bar"', 3
 | |
|     assert_equal 'Use pkgshare instead of (share/"foo")', fa.problems.shift
 | |
| 
 | |
|     fa.audit_line 'ohai "#{share}/foo-bar"', 3
 | |
|     assert_equal [], fa.problems
 | |
|     fa.audit_line 'ohai share/"foo-bar"', 3
 | |
|     assert_equal [], fa.problems
 | |
|     fa.audit_line 'ohai share/"bar"', 3
 | |
|     assert_equal [], fa.problems
 | |
|   end
 | |
| 
 | |
|   # Regression test for https://github.com/Homebrew/legacy-homebrew/pull/48744
 | |
|   # Formulae with "++" in their name would break various audit regexps:
 | |
|   #   Error: nested *?+ in regexp: /^libxml++3\s/
 | |
|   def test_audit_plus_plus_name
 | |
|     fa = formula_auditor "foolibc++", <<-EOS.undent, :strict => true
 | |
|       class Foolibcxx < Formula
 | |
|         desc "foolibc++ is a test"
 | |
|         url "http://example.com/foo-1.0.tgz"
 | |
|       end
 | |
|     EOS
 | |
| 
 | |
|     fa.audit_desc
 | |
|     assert_equal "Description shouldn't include the formula name",
 | |
|       fa.problems.shift
 | |
| 
 | |
|     fa.audit_line 'ohai "#{share}/foolibc++"', 3
 | |
|     assert_equal "Use \#{pkgshare} instead of \#{share}/foolibc++", fa.problems.shift
 | |
| 
 | |
|     fa.audit_line 'ohai share/"foolibc++"', 3
 | |
|     assert_equal 'Use pkgshare instead of (share/"foolibc++")', fa.problems.shift
 | |
|   end
 | |
| 
 | |
|   def test_audit_line_space_in_class_inheritance
 | |
|     fa = formula_auditor "foo", "class Foo<Formula; url '/foo-1.0.tgz'; end"
 | |
|     fa.audit_line "class Foo<Formula", 1
 | |
|     assert_equal "Use a space in class inheritance: class Foo < Formula",
 | |
|       fa.problems.shift
 | |
|   end
 | |
| 
 | |
|   def test_audit_line_default_template
 | |
|     fa = formula_auditor "foo", "class Foo < Formula; url '/foo-1.0.tgz'; end"
 | |
| 
 | |
|     fa.audit_line '# system "cmake", ".", *std_cmake_args', 3
 | |
|     assert_equal "Commented cmake call found",
 | |
|       fa.problems.shift
 | |
| 
 | |
|     fa.audit_line "# PLEASE REMOVE", 3
 | |
|     assert_equal "Please remove default template comments",
 | |
|       fa.problems.shift
 | |
|   end
 | |
| 
 | |
|   def test_audit_github_repository_no_api
 | |
|     fa = formula_auditor "foo", <<-EOS.undent, :strict => true, :online => true
 | |
|       class Foo < Formula
 | |
|         homepage "https://github.com/example/example"
 | |
|         url "http://example.com/foo-1.0.tgz"
 | |
|       end
 | |
|     EOS
 | |
| 
 | |
|     original_value = ENV["HOMEBREW_NO_GITHUB_API"]
 | |
|     ENV["HOMEBREW_NO_GITHUB_API"] = "1"
 | |
| 
 | |
|     fa.audit_github_repository
 | |
|     assert_equal [], fa.problems
 | |
|   ensure
 | |
|     ENV["HOMEBREW_NO_GITHUB_API"] = original_value
 | |
|   end
 | |
| end
 | 
