sparqcode_cane 1.3.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3 @@
1
+ module Cane
2
+ VERSION = '1.3.0.1'
3
+ end
@@ -0,0 +1,49 @@
1
+ require 'stringio'
2
+
3
+ module Cane
4
+
5
+ # Computes a string to be displayed as output from an array of violations
6
+ # computed by the checks.
7
+ class ViolationFormatter < Struct.new(:violations)
8
+ def to_s
9
+ return '' if violations.empty?
10
+
11
+ grouped_violations.map do |description, violations|
12
+ format_group_header(description, violations) +
13
+ format_violations(violations)
14
+ end.flatten.join("\n") + "\n\n"
15
+ end
16
+
17
+ protected
18
+
19
+ def format_group_header(description, violations)
20
+ ["", "%s (%i):" % [description, violations.length], ""]
21
+ end
22
+
23
+ def format_violations(violations)
24
+ column_widths = calculate_columm_widths(violations)
25
+
26
+ violations.map do |violation|
27
+ format_violation(violation, column_widths)
28
+ end
29
+ end
30
+
31
+ def format_violation(violation, column_widths)
32
+ [
33
+ ' ' + violation.columns.map.with_index { |column, index|
34
+ "%-#{column_widths[index]}s" % column
35
+ }.join(' ')
36
+ ]
37
+ end
38
+
39
+ def calculate_columm_widths(violations)
40
+ violations.map { |violation|
41
+ violation.columns.map { |x| x.to_s.length }
42
+ }.transpose.map(&:max)
43
+ end
44
+
45
+ def grouped_violations
46
+ violations.group_by(&:description)
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,81 @@
1
+ require 'spec_helper'
2
+
3
+ require 'cane/abc_check'
4
+
5
+ describe Cane::AbcCheck do
6
+ it 'creates an AbcMaxViolation for each method above the threshold' do
7
+ file_name = make_file(<<-RUBY)
8
+ class Harness
9
+ def not_complex
10
+ true
11
+ end
12
+
13
+ def complex_method(a)
14
+ b = a
15
+ return b if b > 3
16
+ end
17
+ end
18
+ RUBY
19
+
20
+ violations = described_class.new(files: file_name, max: 1).violations
21
+ violations.length.should == 1
22
+ violations[0].should be_instance_of(Cane::AbcMaxViolation)
23
+ violations[0].columns.should == [file_name, "Harness > complex_method", 2]
24
+ end
25
+
26
+ it 'sorts violations by complexity' do
27
+ file_name = make_file(<<-RUBY)
28
+ class Harness
29
+ def not_complex
30
+ true
31
+ end
32
+
33
+ def complex_method(a)
34
+ b = a
35
+ return b if b > 3
36
+ end
37
+ end
38
+ RUBY
39
+
40
+ violations = described_class.new(files: file_name, max: 0).violations
41
+ violations.length.should == 2
42
+ complexities = violations.map(&:complexity)
43
+ complexities.should == complexities.sort.reverse
44
+ end
45
+
46
+ it 'creates a SyntaxViolation when code cannot be parsed' do
47
+ file_name = make_file(<<-RUBY)
48
+ class Harness
49
+ RUBY
50
+
51
+ violations = described_class.new(files: file_name).violations
52
+ violations.length.should == 1
53
+ violations[0].should be_instance_of(Cane::SyntaxViolation)
54
+ violations[0].columns.should == [file_name]
55
+ violations[0].description.should be_instance_of(String)
56
+ end
57
+
58
+ def self.it_should_extract_method_name(method_name, label=method_name)
59
+ it "creates an AbcMaxViolation for #{method_name}" do
60
+ file_name = make_file(<<-RUBY)
61
+ class Harness
62
+ def #{method_name}(a)
63
+ b = a
64
+ return b if b > 3
65
+ end
66
+ end
67
+ RUBY
68
+
69
+ violations = described_class.new(files: file_name, max: 1).violations
70
+ violations[0].detail.should == "Harness > #{label}"
71
+ end
72
+ end
73
+
74
+ # These method names all create different ASTs. Which is weird.
75
+ it_should_extract_method_name 'a'
76
+ it_should_extract_method_name 'self.a', 'a'
77
+ it_should_extract_method_name 'next'
78
+ it_should_extract_method_name 'GET'
79
+ it_should_extract_method_name '`'
80
+ it_should_extract_method_name '>='
81
+ end
@@ -0,0 +1,130 @@
1
+ require 'spec_helper'
2
+ require "stringio"
3
+ require 'cane/cli'
4
+
5
+ describe 'Cane' do
6
+ def capture_stdout &block
7
+ real_stdout, $stdout = $stdout, StringIO.new
8
+ yield
9
+ $stdout.string
10
+ ensure
11
+ $stdout = real_stdout
12
+ end
13
+
14
+ def run(cli_args)
15
+ result = nil
16
+ output = capture_stdout do
17
+ result = Cane::CLI.run(cli_args.split(' '))
18
+ end
19
+
20
+ [output, result ? 0 : 1]
21
+ end
22
+
23
+ it 'fails if ABC metric does not meet requirements' do
24
+ file_name = make_file(<<-RUBY)
25
+ class Harness
26
+ def complex_method(a)
27
+ if a < 2
28
+ return "low"
29
+ else
30
+ return "high"
31
+ end
32
+ end
33
+ end
34
+ RUBY
35
+
36
+ _, exitstatus = run("--abc-glob #{file_name} --abc-max 1")
37
+
38
+ exitstatus.should == 1
39
+ end
40
+
41
+ it 'fails if style metrics do not meet requirements' do
42
+ file_name = make_file("whitespace ")
43
+
44
+ output, exitstatus = run("--style-glob #{file_name}")
45
+ exitstatus.should == 1
46
+ output.should include("Lines violated style requirements")
47
+ end
48
+
49
+ it 'allows measure to be configured' do
50
+ file_name = make_file("toolong")
51
+
52
+ output, exitstatus = run("--style-glob #{file_name} --style-measure 3")
53
+ exitstatus.should == 1
54
+ output.should include("Lines violated style requirements")
55
+ end
56
+
57
+ it 'does not include trailing new lines in the character count' do
58
+ file_name = make_file('#' * 80 + "\n" + '#' * 80)
59
+
60
+ output, exitstatus = run("--style-glob #{file_name} --style-measure 80")
61
+ exitstatus.should == 0
62
+ output.should be_empty
63
+ end
64
+
65
+ it 'allows upper bound of failed checks' do
66
+ file_name = make_file("whitespace ")
67
+
68
+ output, exitstatus = run("--style-glob #{file_name} --max-violations 1")
69
+ exitstatus.should == 0
70
+ output.should include("Lines violated style requirements")
71
+ end
72
+
73
+ it 'allows checking of a value in a file' do
74
+ file_name = make_file("89")
75
+
76
+ output, exitstatus = run("--gte #{file_name},90")
77
+ exitstatus.should == 1
78
+ output.should include("Quality threshold crossed")
79
+ end
80
+
81
+ it 'allows checking of class documentation' do
82
+ file_name = make_file("class NoDoc")
83
+
84
+ output, exitstatus = run("--doc-glob #{file_name}")
85
+ exitstatus.should == 1
86
+ output.should include("Classes are not documented")
87
+ end
88
+
89
+ context 'with a .cane file' do
90
+ before(:each) do
91
+ file_name = make_file("class NoDoc")
92
+ make_dot_cane("--doc-glob #{file_name}")
93
+ end
94
+
95
+ after(:each) do
96
+ unmake_dot_cane
97
+ end
98
+
99
+ it 'loads options from a .cane file' do
100
+ output, exitstatus = run('')
101
+
102
+ exitstatus.should == 1
103
+ output.should include("Classes are not documented")
104
+ end
105
+ end
106
+
107
+ it 'displays a help message' do
108
+ output, exitstatus = run("--help")
109
+
110
+ exitstatus.should == 0
111
+ output.should include("Usage:")
112
+ end
113
+
114
+ it 'displays version' do
115
+ output, exitstatus = run("--version")
116
+
117
+ exitstatus.should == 0
118
+ output.should include(Cane::VERSION)
119
+ end
120
+
121
+ it 'uses the last of conflicting arguments' do
122
+ file_name = make_file("class NoDoc")
123
+
124
+ run("--doc-glob #{file_name} --no-doc").should ==
125
+ run("--no-doc")
126
+
127
+ run("--no-doc --doc-glob #{file_name}").should ==
128
+ run("--doc-glob #{file_name}")
129
+ end
130
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ require 'cane/doc_check'
4
+
5
+ describe Cane::DocCheck do
6
+ it 'creates a DocViolation for each undocumented class' do
7
+ file_name = make_file <<-RUBY
8
+ # This class is documented
9
+ class Doc; end
10
+ class NoDoc; end # No doc
11
+ class AlsoNoDoc; end
12
+ [:class]
13
+ # class Ignore
14
+ class Meta
15
+ class << self; end
16
+ end
17
+ RUBY
18
+
19
+ violations = described_class.new(files: file_name).violations
20
+ violations.length.should == 2
21
+
22
+ violations[0].should be_instance_of(Cane::UndocumentedClassViolation)
23
+ violations[0].file_name.should == file_name
24
+ violations[0].number.should == 3
25
+
26
+ violations[1].should be_instance_of(Cane::UndocumentedClassViolation)
27
+ violations[1].file_name.should == file_name
28
+ violations[1].number.should == 4
29
+ end
30
+ end
@@ -0,0 +1,37 @@
1
+ require 'tempfile'
2
+
3
+ # Keep a reference to all tempfiles so they are not garbage collected until the
4
+ # process exits.
5
+ $tempfiles = []
6
+
7
+ def make_file(content)
8
+ tempfile = Tempfile.new('cane')
9
+ $tempfiles << tempfile
10
+ tempfile.print(content)
11
+ tempfile.flush
12
+ tempfile.path
13
+ end
14
+
15
+ def make_dot_cane(content)
16
+ File.open('./.cane', 'w') do |f|
17
+ f.puts content
18
+ end
19
+ end
20
+
21
+ def unmake_dot_cane
22
+ FileUtils.rm('./.cane')
23
+ end
24
+
25
+ require 'simplecov'
26
+
27
+ class SimpleCov::Formatter::QualityFormatter
28
+ def format(result)
29
+ SimpleCov::Formatter::HTMLFormatter.new.format(result)
30
+ File.open("coverage/covered_percent", "w") do |f|
31
+ f.puts result.source_files.covered_percent.to_i
32
+ end
33
+ end
34
+ end
35
+
36
+ SimpleCov.formatter = SimpleCov::Formatter::QualityFormatter
37
+ SimpleCov.start
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ require 'cane/style_check'
4
+
5
+ describe Cane::StyleCheck do
6
+ it 'creates a StyleViolation for each method above the threshold' do
7
+ ruby = [
8
+ "def test ",
9
+ "\t1",
10
+ "end"
11
+ ].join("\n")
12
+ file_name = make_file(ruby)
13
+
14
+ violations = Cane::StyleCheck.new(files: file_name, measure: 80).violations
15
+ violations.length.should == 2
16
+ violations[0].should be_instance_of(StyleViolation)
17
+ end
18
+ end
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+
3
+ require 'cane/threshold_check'
4
+
5
+ describe ThresholdCheck do
6
+ it 'returns a value of unavailable when file cannot be read' do
7
+ check = ThresholdCheck.new([[:>=, 'bogus_file', 20]])
8
+ violations = check.violations
9
+ violations.length.should == 1
10
+ violations[0].to_s.should include("unavailable")
11
+ end
12
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ require 'cane/violation_formatter'
4
+
5
+ describe Cane::ViolationFormatter do
6
+ def violation(description)
7
+ stub("violation",
8
+ description: description,
9
+ columns: []
10
+ )
11
+ end
12
+
13
+ it 'includes number of violations in the group header' do
14
+ described_class.new([violation("FAIL")]).to_s.should include("(1)")
15
+ end
16
+ end
metadata ADDED
@@ -0,0 +1,130 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sparqcode_cane
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.3.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Xavier Shay, Mike Emery
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-05-18 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '2.0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '2.0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: simplecov
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ description: Fails your build if code quality thresholds are not met
63
+ email:
64
+ - xavier@squareup.com, mike@sparqcode.com
65
+ executables:
66
+ - cane
67
+ extensions: []
68
+ extra_rdoc_files: []
69
+ files:
70
+ - spec/abc_check_spec.rb
71
+ - spec/cane_spec.rb
72
+ - spec/doc_check_spec.rb
73
+ - spec/spec_helper.rb
74
+ - spec/style_check_spec.rb
75
+ - spec/threshold_check_spec.rb
76
+ - spec/violation_formatter_spec.rb
77
+ - lib/cane/abc_check.rb
78
+ - lib/cane/abc_max_violation.rb
79
+ - lib/cane/cli/spec.rb
80
+ - lib/cane/cli/translator.rb
81
+ - lib/cane/cli.rb
82
+ - lib/cane/doc_check.rb
83
+ - lib/cane/rake_task.rb
84
+ - lib/cane/style_check.rb
85
+ - lib/cane/style_violation.rb
86
+ - lib/cane/syntax_violation.rb
87
+ - lib/cane/threshold_check.rb
88
+ - lib/cane/threshold_violation.rb
89
+ - lib/cane/version.rb
90
+ - lib/cane/violation_formatter.rb
91
+ - lib/cane.rb
92
+ - README.md
93
+ - HISTORY.md
94
+ - LICENSE
95
+ - cane.gemspec
96
+ - bin/cane
97
+ homepage: http://github.com/square/cane
98
+ licenses: []
99
+ post_install_message:
100
+ rdoc_options: []
101
+ require_paths:
102
+ - lib
103
+ required_ruby_version: !ruby/object:Gem::Requirement
104
+ none: false
105
+ requirements:
106
+ - - ! '>='
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ required_rubygems_version: !ruby/object:Gem::Requirement
110
+ none: false
111
+ requirements:
112
+ - - ! '>='
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ requirements: []
116
+ rubyforge_project:
117
+ rubygems_version: 1.8.24
118
+ signing_key:
119
+ specification_version: 3
120
+ summary: Fails your build if code quality thresholds are not met. Provides complexity
121
+ and style checkers built-in, and allows integration with with custom quality metrics. SPARQCode
122
+ changed it so that instead of ABC checks it does cyclomatic complexity.
123
+ test_files:
124
+ - spec/abc_check_spec.rb
125
+ - spec/cane_spec.rb
126
+ - spec/doc_check_spec.rb
127
+ - spec/spec_helper.rb
128
+ - spec/style_check_spec.rb
129
+ - spec/threshold_check_spec.rb
130
+ - spec/violation_formatter_spec.rb