simplecov-reports 0.0.4.ooyala

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +18 -0
  3. data/Gemfile +7 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +66 -0
  6. data/Rakefile +73 -0
  7. data/lib/simplecov-html-extended.rb +50 -0
  8. data/lib/simplecov/configuration.rb +98 -0
  9. data/lib/simplecov/reports.rb +5 -0
  10. data/lib/simplecov/reports/author_report.rb +180 -0
  11. data/lib/simplecov/reports/file_report.rb +97 -0
  12. data/lib/simplecov/reports/version.rb +5 -0
  13. data/lib/simplecov/source_file.rb +39 -0
  14. data/simplecov-reports.gemspec +29 -0
  15. data/test/fixtures/author_report/author_stats_file1.rb +23 -0
  16. data/test/fixtures/author_report/author_stats_file2.rb +26 -0
  17. data/test/fixtures/author_report/best_author_tolerance.rb +264 -0
  18. data/test/fixtures/file_report/classes_covered.rb +80 -0
  19. data/test/fixtures/file_report/classes_not_covered.rb +37 -0
  20. data/test/fixtures/file_report/classes_partially_covered.rb +11 -0
  21. data/test/fixtures/file_report/methods_covered.rb +38 -0
  22. data/test/fixtures/file_report/methods_not_covered.rb +39 -0
  23. data/test/fixtures/file_report/methods_partially_covered.rb +13 -0
  24. data/test/fixtures/line enhancer/line_enhancer_fixture.rb +1 -0
  25. data/test/helper.rb +19 -0
  26. data/test/memory_measure.rb +0 -0
  27. data/test/test_all_reports.rb +35 -0
  28. data/test/test_author_stats.rb +89 -0
  29. data/test/test_best_author_stage1.rb +75 -0
  30. data/test/test_best_author_stage2.rb +75 -0
  31. data/test/test_best_author_stage3.rb +86 -0
  32. data/test/test_best_author_stage4.rb +97 -0
  33. data/test/test_best_author_stage5.rb +97 -0
  34. data/test/test_file_reports.rb +159 -0
  35. data/test/test_html_reports.rb +43 -0
  36. data/test/test_line_enhancer.rb +26 -0
  37. data/views/author_report.erb +37 -0
  38. data/views/file_report.erb +21 -0
  39. metadata +203 -0
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ YmU1NzU3NjE3NmZjNGExMTE4MWM2ZWJhOGJhMmNkMjY2Nzk5ZDA3Nw==
5
+ data.tar.gz: !binary |-
6
+ ZWY3ODQ0MjE2MTk2MjBmMzI0NmMzODU3MzFjMjZiZjY0OWE4ZDcyNg==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ NTQ3ZjdlOTVkNWVlYTc2ZWJiYTRiNzAwMDE2NWIwNzY1NmZjMWJkNmJjOWIz
10
+ ZmEzOWNlNzI1ZjE5OWMyYjFhYTA4YTQwYzgzMWY5MDFmNWMzODNlNDgwM2Nk
11
+ ZWQzYjEwZGU3ZDA1Mjk4MmJiZmQ1ZjY4ODYyMzE4ZWExNzc3ODM=
12
+ data.tar.gz: !binary |-
13
+ MzRjODIwZDFmNTMwMzZhYTIzYjQwNDA3NTNlYTg1Y2QzYzRmZjEwMzM3NjZm
14
+ OGJkNjJhOWQ5ZDg3OTgzMzhlYmFkZTAzMWMxN2Y5ZjcwZTM2NDgzNGFjMGI1
15
+ YmQ1NzQwZmM3M2E4YjhiZDAyY2Q0OGZhYWNmODBmMTM1N2ZjYmI=
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .idea/
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in simplecov-reports.gemspec
4
+ gemspec
5
+
6
+ # gem "simplecov", :path => "/Users/rkonda/repos/qa/tools/simplecov"
7
+ # gem "simplecov-html", :path => "/Users/rkonda/repos/qa/tools/simplecov-html"
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Rajesh Konda
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,66 @@
1
+ # Simplecov::Reports
2
+
3
+ This gem provides author and file analysis based reports to be generated when simplecov generates code
4
+ coverage reports.
5
+
6
+ Author reports include 'best author' and 'author stats'. File analysis based reports include 'api', 'class',
7
+ 'method' and 'configure' coverage reports.
8
+
9
+ 'api' coverage report gives statistics about the api methods (as specified using Sinatra) that are missing
10
+ coverage. 'class' coverage report gives statistics about the classes that are missing coverage. 'method'
11
+ coverage report gives statistics about all the methods/functions that are missing coverage. 'configure'
12
+ coverage report gives statistics about all the 'configure' blocks (as specified using Sinatra) that are
13
+ missing coverage.
14
+
15
+ ## Installation
16
+
17
+ Add this line to your application's Gemfile:
18
+
19
+ gem 'simplecov-reports'
20
+
21
+ And then execute:
22
+
23
+ $ bundle
24
+
25
+ Or install it yourself as:
26
+
27
+ $ gem install simplecov-reports
28
+
29
+ ## Usage
30
+
31
+ * require the gem in your .simplecov file
32
+
33
+ `require "simplecov/reports"`
34
+
35
+ * specify reports you would like to generate, eg.,
36
+
37
+ ```ruby
38
+ add_report :type => SimpleCov::Configuration::ReportTypes::ItemsMissingCoverage::Api
39
+ add_report :type => SimpleCov::Configuration::ReportTypes::ItemsMissingCoverage::Class
40
+ add_report :type => SimpleCov::Configuration::ReportTypes::ItemsMissingCoverage::Method
41
+ add_report :type => SimpleCov::Configuration::ReportTypes::ItemsMissingCoverage::Configure
42
+ add_report(:type => SimpleCov::Configuration::ReportTypes::Author,
43
+ :sub_types => [
44
+ SimpleCov::Configuration::ReportTypes::Author::BestAuthor,
45
+ SimpleCov::Configuration::ReportTypes::Author::AuthorStats
46
+ ],
47
+ :best_authors_count => 4)
48
+ ```
49
+
50
+ ### Author reports configuration
51
+
52
+ The following options can be passed to the Author report as seen in the example above.
53
+
54
+ * `:best-authors-count` : The minimum number of authors to show in the best authors list as long as their coverage satisfies `best-author-cutoff` (default: 3).
55
+ * `:best-author-tolerance` : Percentage value that limits how authors are selected to show in best authors list. Given m, the most number of lines written by any author, this value v, is the percentage of m, that is a normal cutoff for choosing the best authors. All the authors that have written `v/100 * m` or more lines of code are selected (default: 50.0)
56
+ * `:best-author-cutoff` : Percentage value that limits how authors are selected to show in best authors list. Given m, the most number of lines written by any author, this value v, is the percentage of m, that is the absolute cutoff for choosing the best authors. All the authors that have written `v/100 * m` or more lines of code are selected, unless the 'best_author_count' is reached (default: 15.0)
57
+ * `:author-report-from` : Starting date from which authoring is considered, for author stats reports. Format: YYYY-MM-DD HH:MM:SS (-/+)HHMM (default: 1900-12-31 00:00:00 -0000)
58
+ * `:author-report-to` : Ending date to which authoring is considered, for author stats reports. Format: YYYY-MM-DD HH:MM:SS (-/+)HHMM (default: 2025-12-31 00:00:00 -0000)
59
+
60
+ ## Contributing
61
+
62
+ 1. Fork it
63
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
64
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
65
+ 4. Push to the branch (`git push origin my-new-feature`)
66
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,73 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/testtask'
3
+
4
+
5
+ task :test => [
6
+ "test_all_reports",
7
+ "test_best_author",
8
+ "test_file_reports",
9
+ "test_html_reports",
10
+ "test_line_enhancer"
11
+ ]
12
+
13
+ Rake::TestTask.new(:test_all_reports) do |test|
14
+ test.libs << 'lib' << 'test'
15
+ test.test_files = FileList['test/test_all_reports.rb']
16
+ test.verbose = true
17
+ end
18
+
19
+ task :test_best_author => [
20
+ "test_best_author_stage1",
21
+ "test_best_author_stage2",
22
+ "test_best_author_stage3",
23
+ "test_best_author_stage4",
24
+ "test_best_author_stage5",
25
+ ]
26
+
27
+ Rake::TestTask.new(:test_best_author_stage1) do |test|
28
+ test.libs << 'lib' << 'test'
29
+ test.test_files = FileList['test/test_best_author_stage1.rb']
30
+ test.verbose = true
31
+ end
32
+
33
+ Rake::TestTask.new(:test_best_author_stage2) do |test|
34
+ test.libs << 'lib' << 'test'
35
+ test.test_files = FileList['test/test_best_author_stage2.rb']
36
+ test.verbose = true
37
+ end
38
+
39
+ Rake::TestTask.new(:test_best_author_stage3) do |test|
40
+ test.libs << 'lib' << 'test'
41
+ test.test_files = FileList['test/test_best_author_stage3.rb']
42
+ test.verbose = true
43
+ end
44
+
45
+ Rake::TestTask.new(:test_best_author_stage4) do |test|
46
+ test.libs << 'lib' << 'test'
47
+ test.test_files = FileList['test/test_best_author_stage4.rb']
48
+ test.verbose = true
49
+ end
50
+
51
+ Rake::TestTask.new(:test_best_author_stage5) do |test|
52
+ test.libs << 'lib' << 'test'
53
+ test.test_files = FileList['test/test_best_author_stage5.rb']
54
+ test.verbose = true
55
+ end
56
+
57
+ Rake::TestTask.new(:test_file_reports) do |test|
58
+ test.libs << 'lib' << 'test'
59
+ test.test_files = FileList['test/test_file_reports.rb']
60
+ test.verbose = true
61
+ end
62
+
63
+ Rake::TestTask.new(:test_html_reports) do |test|
64
+ test.libs << 'lib' << 'test'
65
+ test.test_files = FileList['test/test_html_reports.rb']
66
+ test.verbose = true
67
+ end
68
+
69
+ Rake::TestTask.new(:test_line_enhancer) do |test|
70
+ test.libs << 'lib' << 'test'
71
+ test.test_files = FileList['test/test_line_enhancer.rb']
72
+ test.verbose = true
73
+ end
@@ -0,0 +1,50 @@
1
+ require "simplecov-html"
2
+
3
+
4
+ module SimpleCov
5
+ module Formatter
6
+ class HTMLFormatter
7
+ def formatted_file_report(report)
8
+ case report[:type][:subtype]
9
+ when :api
10
+ when :class
11
+ when :method
12
+ when :configure
13
+ end
14
+ title = "#{report[:type]} #{report[:type][:subtype]}"
15
+ title_id = title.gsub(/^[^a-zA-Z]+/, '').gsub(/[^a-zA-Z0-9\-\_]/, '')
16
+ template('file_report').result(binding)
17
+ end
18
+
19
+ def formatted_author_report(report)
20
+ generated_source = ""
21
+ report[:sub_reports].each do |sub_report|
22
+ case sub_report[:type]
23
+ when :best_authors
24
+ when :author_stats
25
+ end
26
+ title = "#{report[:type]} #{sub_report[:type]}"
27
+ title_id = title.gsub(/^[^a-zA-Z]+/, '').gsub(/[^a-zA-Z0-9\-\_]/, '')
28
+ generated_source += template('author_report').result(binding)
29
+ end
30
+ generated_source
31
+ end
32
+ end
33
+
34
+ # Add report formatters
35
+ formatters = {
36
+ :file_report => :formatted_file_report,
37
+ :author_report => :formatted_author_report
38
+ }
39
+
40
+ HTMLFormatter.add_report_formatters(formatters)
41
+
42
+ # Author report would like to add author information to the source file view
43
+ HTMLFormatter::Views::SourceFile.add_line_attribute "author", lambda { |line| line.author }
44
+ HTMLFormatter::Views::SourceFile.add_line_attribute "authored_date", lambda { |line| line.date }
45
+
46
+ # Add the "views" directory in this gem as a path to finding erb files
47
+ gem_root = File.expand_path(File.join(File.dirname(__FILE__), ".."))
48
+ HTMLFormatter.erb_files.append_path(File.join(gem_root, "views"))
49
+ end
50
+ end
@@ -0,0 +1,98 @@
1
+ #
2
+ # Enhancements to SimpleCov::Configuration for generating reports
3
+ #
4
+ require "simplecov"
5
+
6
+ module SimpleCov::Configuration
7
+
8
+ module ReportTypes
9
+ module ItemsMissingCoverage
10
+ module Api
11
+ def self.get_specification(options)
12
+ { :type => :file_report,
13
+ :options => {
14
+ :report_type => :api
15
+ }
16
+ }
17
+ end
18
+ end
19
+
20
+ module Class
21
+ def self.get_specification(options)
22
+ { :type => :file_report,
23
+ :options => {
24
+ :report_type => :class
25
+ }
26
+ }
27
+ end
28
+ end
29
+
30
+ module Method
31
+ def self.get_specification(options)
32
+ { :type => :file_report,
33
+ :options => {
34
+ :report_type => :method
35
+ }
36
+ }
37
+ end
38
+ end
39
+
40
+ module Configure
41
+ def self.get_specification(options)
42
+ { :type => :file_report,
43
+ :options => {
44
+ :report_type => :configure
45
+ }
46
+ }
47
+ end
48
+ end
49
+ end # module ItemsMissingCoverage
50
+
51
+ module Author
52
+ def self.get_specification(options)
53
+ specification =
54
+ { :type => :author_report,
55
+ :options => {
56
+ :report_types => {},
57
+ :best_authors_count =>
58
+ options.has_key?(:best_authors_count) ? options[:best_authors_count] : 3,
59
+
60
+ :best_author_tolerance =>
61
+ options.has_key?(:best_author_tolerance) ? options[:best_author_tolerance] : 50.00,
62
+
63
+ :best_author_cutoff =>
64
+ options.has_key?(:best_author_cutoff) ? options[:best_author_cutoff] : 15.00,
65
+
66
+ :author_report_from =>
67
+ options.has_key?(:author_report_from) ? options[:author_report_from] : "1900-12-31 00:00:00 -0000",
68
+
69
+ :author_report_to =>
70
+ options.has_key?(:author_report_to) ? options[:author_report_to] : "2025-12-31 00:00:00 -0000"
71
+ }
72
+ }
73
+
74
+ options[:sub_types].each do |author_type|
75
+ specification = author_type.get_specification(options, specification)
76
+ end
77
+ specification
78
+ end
79
+
80
+ module BestAuthor
81
+ def self.get_specification(options, specification)
82
+ specification[:options][:report_types][:best_authors] = true
83
+ specification
84
+ end
85
+ end
86
+
87
+ module AuthorStats
88
+ def self.get_specification(options, specification)
89
+ specification[:options][:report_types][:author_stats] = true
90
+ specification
91
+ end
92
+ end
93
+ end # module Author
94
+
95
+ end # module ReportTypes
96
+
97
+ end # module SimpleCov::Configuration
98
+
@@ -0,0 +1,5 @@
1
+ require_relative "reports/author_report"
2
+ require_relative "reports/file_report"
3
+ require_relative "reports/version"
4
+ require_relative "configuration"
5
+ require_relative "../simplecov-html-extended"
@@ -0,0 +1,180 @@
1
+ #
2
+ # AuthorReport gives statistics on coverage mapped to the authors of the code.
3
+ #
4
+
5
+ require "algorithms"
6
+ require "simplecov"
7
+ require_relative "../source_file"
8
+
9
+ module SimpleCov
10
+ class AuthorReport < Report
11
+ attr_reader :author_stats_mapping, :best_author_stats_mapping
12
+
13
+ def initialize(options)
14
+ @options = options
15
+ @report_types = options[:report_types]
16
+
17
+ # For each author, there is a mapping to a file/linesOfCode map
18
+ # 'file/linesOfCode map': mapping from file name to the stats about coverage for code
19
+ @author_stats_mapping = {}
20
+ @best_author_stats_mapping = {}
21
+ end
22
+
23
+ def generate(files)
24
+ compute_author_stats_mapping(files)
25
+ if @report_types[:best_authors]
26
+ compute_best_authors
27
+ end
28
+
29
+ @report = {
30
+ :type => {
31
+ :main => :author_report,
32
+ },
33
+ :sub_reports => []
34
+ }
35
+
36
+ if @report_types[:best_authors]
37
+ @report[:sub_reports] <<
38
+ {
39
+ :type => :best_authors,
40
+ :title => "Best Authors",
41
+ :items => @best_author_stats_mapping
42
+ }
43
+ end
44
+
45
+ if @report_types[:author_stats]
46
+ @report[:sub_reports] <<
47
+ {
48
+ :type => :author_stats,
49
+ :title => "Author Stats",
50
+ :items => @author_stats_mapping
51
+ }
52
+ end
53
+
54
+ @report
55
+ end
56
+
57
+ private
58
+ def compute_author_stats_mapping(files)
59
+ files.each do |file|
60
+ file.lines.each do |line|
61
+ next if line.author.nil? || line.date.nil?
62
+ next if(line.date < Time.parse(@options[:author_report_from]) ||
63
+ line.date > Time.parse(@options[:author_report_to]))
64
+
65
+ @author_stats_mapping[line.author] = @author_stats_mapping[line.author] || {}
66
+ files_stats = @author_stats_mapping[line.author][:files] =
67
+ @author_stats_mapping[line.author][:files] || ItemMap.new
68
+ files_stats[file] =
69
+ files_stats[file] || {}
70
+
71
+ if line.missed?
72
+ files_stats[file][:missed] =
73
+ files_stats[file][:missed] || 0
74
+ files_stats[file][:missed] += 1
75
+ elsif line.covered?
76
+ files_stats[file][:covered] =
77
+ files_stats[file][:covered] || 0
78
+ files_stats[file][:covered] += 1
79
+ end
80
+ end
81
+
82
+ @author_stats_mapping.keys.each do |author_name|
83
+ files_stats = @author_stats_mapping[author_name][:files]
84
+ next if files_stats[file].nil?
85
+ files_stats[file][:covered] =
86
+ files_stats[file][:covered] || 0
87
+ files_stats[file][:missed] =
88
+ files_stats[file][:missed] || 0
89
+
90
+ if files_stats[file][:covered] == 0 &&
91
+ files_stats[file][:missed] == 0
92
+ files_stats.delete(file)
93
+ next
94
+ end
95
+
96
+ files_stats[file][:total] =
97
+ files_stats[file][:covered] +
98
+ files_stats[file][:missed]
99
+ files_stats[file][:coverage] =
100
+ compute_coverage(files_stats[file])
101
+ end
102
+ end
103
+
104
+ @author_stats_mapping.keys.each do |author_name|
105
+ total_lines = 0
106
+ total_covered_lines = 0
107
+
108
+ author_stats = @author_stats_mapping[author_name]
109
+ author_stats[:files].keys.each do |file|
110
+ total_lines += author_stats[:files][file][:missed] +
111
+ author_stats[:files][file][:covered]
112
+ total_covered_lines += author_stats[:files][file][:covered]
113
+ end
114
+ author_stats[:total_coverage] = {}
115
+ author_stats[:total_coverage][:missed] = total_lines - total_covered_lines
116
+ author_stats[:total_coverage][:covered] = total_covered_lines
117
+ author_stats[:total_coverage][:total] =
118
+ author_stats[:total_coverage][:missed] +
119
+ author_stats[:total_coverage][:covered]
120
+ author_stats[:total_coverage][:coverage] =
121
+ compute_coverage(author_stats[:total_coverage])
122
+ end
123
+
124
+ @author_stats_mapping
125
+ end # compute_author_stats_mapping
126
+
127
+ def compute_coverage(file_stats)
128
+ return 0 if file_stats[:total] == 0
129
+ 100 * file_stats[:covered].to_f / file_stats[:total]
130
+ end
131
+
132
+ def compute_best_authors
133
+ all_authors_queue = Containers::PriorityQueue.new
134
+ significant_authors_queue = Containers::PriorityQueue.new
135
+
136
+ @author_stats_mapping.keys.each do |author_name|
137
+ author_stats = @author_stats_mapping[author_name]
138
+ all_authors_queue.push(author_name, author_stats[:total_coverage][:total])
139
+ end
140
+
141
+ most_total_author = all_authors_queue.pop
142
+ return if most_total_author.nil?
143
+ significant_authors_queue.push(most_total_author,
144
+ @author_stats_mapping[most_total_author][:total_coverage][:coverage])
145
+ author_count = 1
146
+ while(author_name = all_authors_queue.pop) != nil &&
147
+ (
148
+ comparable( @author_stats_mapping[most_total_author][:total_coverage][:total],
149
+ @author_stats_mapping[author_name][:total_coverage][:total]) ||
150
+ (
151
+ comparable_cutoff( @author_stats_mapping[most_total_author][:total_coverage][:total],
152
+ @author_stats_mapping[author_name][:total_coverage][:total]) &&
153
+ author_count < @options[:best_authors_count]
154
+ )
155
+ )
156
+ significant_authors_queue.push(author_name,
157
+ @author_stats_mapping[author_name][:total_coverage][:coverage])
158
+ author_count += 1
159
+ end
160
+
161
+ author_count = 0
162
+ while (author_name = significant_authors_queue.pop) != nil
163
+ @best_author_stats_mapping[author_name] = @author_stats_mapping[author_name]
164
+ author_count += 1
165
+ end
166
+ end # compute_best_authors
167
+
168
+ def comparable(baseline, candidate)
169
+ candidate.to_f / baseline * 100 >= @options[:best_author_tolerance]
170
+ end
171
+
172
+ def comparable_cutoff(baseline, candidate)
173
+ candidate.to_f / baseline * 100 >= @options[:best_author_cutoff]
174
+ end
175
+
176
+ end # class AuthorReport
177
+
178
+ end # module SimpleCov
179
+
180
+ SimpleCov::Report.register(:author_report, SimpleCov::AuthorReport)