simplecov 0.9.2 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -7
- data/.gitignore +0 -1
- data/.rubocop.yml +69 -0
- data/CHANGELOG.md +39 -22
- data/Gemfile +16 -15
- data/MIT-LICENSE +1 -1
- data/README.md +183 -178
- data/Rakefile +16 -7
- data/doc/alternate-formatters.md +36 -0
- data/doc/commercial-services.md +20 -0
- data/doc/editor-integration.md +13 -0
- data/features/rspec_basic.feature +3 -2
- data/features/rspec_groups_and_filters_complex.feature +2 -0
- data/features/rspec_groups_using_filter_class.feature +3 -2
- data/features/step_definitions/html_steps.rb +6 -7
- data/features/step_definitions/simplecov_steps.rb +18 -16
- data/features/step_definitions/transformers.rb +2 -2
- data/features/step_definitions/web_steps.rb +4 -4
- data/features/support/env.rb +17 -15
- data/lib/simplecov.rb +35 -24
- data/lib/simplecov/command_guesser.rb +33 -34
- data/lib/simplecov/configuration.rb +238 -234
- data/lib/simplecov/defaults.rb +37 -36
- data/lib/simplecov/exit_codes.rb +7 -5
- data/lib/simplecov/file_list.rb +38 -36
- data/lib/simplecov/filter.rb +12 -2
- data/lib/simplecov/formatter.rb +2 -2
- data/lib/simplecov/formatter/simple_formatter.rb +1 -1
- data/lib/simplecov/jruby_fix.rb +4 -4
- data/lib/simplecov/last_run.rb +15 -13
- data/lib/simplecov/merge_helpers.rb +26 -27
- data/lib/simplecov/no_defaults.rb +2 -2
- data/lib/simplecov/profiles.rb +21 -19
- data/lib/simplecov/railtie.rb +1 -1
- data/lib/simplecov/railties/tasks.rake +7 -7
- data/lib/simplecov/result.rb +5 -5
- data/lib/simplecov/result_merger.rb +65 -62
- data/lib/simplecov/source_file.rb +23 -24
- data/lib/simplecov/version.rb +20 -1
- data/simplecov.gemspec +14 -12
- data/test/faked_project/Gemfile +5 -5
- data/test/faked_project/Rakefile +4 -4
- data/test/faked_project/features/step_definitions/my_steps.rb +3 -4
- data/test/faked_project/features/support/env.rb +5 -5
- data/test/faked_project/lib/faked_project.rb +1 -1
- data/test/faked_project/lib/faked_project/some_class.rb +3 -4
- data/test/faked_project/spec/faked_spec.rb +2 -2
- data/test/faked_project/spec/forking_spec.rb +7 -0
- data/test/faked_project/spec/meta_magic_spec.rb +1 -1
- data/test/faked_project/spec/some_class_spec.rb +3 -3
- data/test/faked_project/spec/spec_helper.rb +4 -8
- data/test/faked_project/test/faked_test.rb +2 -2
- data/test/faked_project/test/meta_magic_test.rb +1 -1
- data/test/faked_project/test/some_class_test.rb +3 -3
- data/test/faked_project/test/test_helper.rb +5 -9
- data/test/fixtures/app/controllers/sample_controller.rb +1 -1
- data/test/fixtures/app/models/user.rb +1 -1
- data/test/fixtures/deleted_source_sample.rb +3 -3
- data/test/fixtures/frameworks/rspec_bad.rb +4 -4
- data/test/fixtures/frameworks/rspec_good.rb +4 -4
- data/test/fixtures/frameworks/testunit_bad.rb +3 -3
- data/test/fixtures/frameworks/testunit_good.rb +3 -3
- data/test/fixtures/resultset2.rb +0 -1
- data/test/fixtures/sample.rb +1 -1
- data/test/fixtures/utf-8.rb +1 -1
- data/test/helper.rb +8 -8
- data/test/test_1_8_fallbacks.rb +6 -6
- data/test/test_command_guesser.rb +7 -7
- data/test/test_deleted_source.rb +2 -2
- data/test/test_file_list.rb +8 -6
- data/test/test_filters.rb +29 -13
- data/test/test_merge_helpers.rb +26 -23
- data/test/test_result.rb +32 -23
- data/test/test_return_codes.rb +3 -3
- data/test/test_source_file.rb +4 -4
- data/test/test_source_file_line.rb +13 -13
- metadata +145 -63
- data/lib/simplecov/json.rb +0 -27
@@ -1,11 +1,11 @@
|
|
1
|
-
require
|
1
|
+
require "rake/testtask"
|
2
2
|
Rake::TestTask.new do |t|
|
3
|
-
t.name =
|
3
|
+
t.name = "simplecov"
|
4
4
|
t.loader = :direct # uses require() which skips PWD in Ruby 1.9
|
5
|
-
t.libs.push
|
6
|
-
t.test_files = FileList[
|
7
|
-
t.ruby_opts.push
|
5
|
+
t.libs.push "test", "spec", Dir.pwd
|
6
|
+
t.test_files = FileList["{test,spec}/**/*_{test,spec}.rb"]
|
7
|
+
t.ruby_opts.push "-r", "simplecov", "-e", "SimpleCov.start(:rails)".inspect
|
8
8
|
end
|
9
9
|
|
10
|
-
require
|
11
|
-
CLOBBER.include
|
10
|
+
require "rake/clean"
|
11
|
+
CLOBBER.include "coverage"
|
data/lib/simplecov/result.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "digest/sha1"
|
2
|
+
require "forwardable"
|
3
3
|
|
4
4
|
module SimpleCov
|
5
5
|
#
|
@@ -57,9 +57,9 @@ module SimpleCov
|
|
57
57
|
@command_name ||= SimpleCov.command_name
|
58
58
|
end
|
59
59
|
|
60
|
-
# Returns a hash representation of this Result that can be used for marshalling it into
|
60
|
+
# Returns a hash representation of this Result that can be used for marshalling it into JSON
|
61
61
|
def to_hash
|
62
|
-
{command_name => {"coverage" => original_result.reject {|filename,
|
62
|
+
{command_name => {"coverage" => original_result.reject { |filename, _| !filenames.include?(filename) }, "timestamp" => created_at.to_i}}
|
63
63
|
end
|
64
64
|
|
65
65
|
# Loads a SimpleCov::Result#to_hash dump
|
@@ -71,7 +71,7 @@ module SimpleCov
|
|
71
71
|
result
|
72
72
|
end
|
73
73
|
|
74
|
-
|
74
|
+
private
|
75
75
|
|
76
76
|
# Applies all configured SimpleCov filters on this result's source files
|
77
77
|
def filter!
|
@@ -1,85 +1,88 @@
|
|
1
|
+
require "json"
|
2
|
+
|
1
3
|
#
|
2
4
|
# Singleton that is responsible for caching, loading and merging
|
3
5
|
# SimpleCov::Results into a single result for coverage analysis based
|
4
6
|
# upon multiple test suites.
|
5
7
|
#
|
6
|
-
module SimpleCov
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
module SimpleCov
|
9
|
+
module ResultMerger
|
10
|
+
class << self
|
11
|
+
# The path to the .resultset.json cache file
|
12
|
+
def resultset_path
|
13
|
+
File.join(SimpleCov.coverage_path, ".resultset.json")
|
14
|
+
end
|
12
15
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
+
def resultset_writelock
|
17
|
+
File.join(SimpleCov.coverage_path, ".resultset.json.lock")
|
18
|
+
end
|
16
19
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
20
|
+
# Loads the cached resultset from JSON and returns it as a Hash
|
21
|
+
def resultset
|
22
|
+
if stored_data
|
23
|
+
begin
|
24
|
+
JSON.parse(stored_data)
|
25
|
+
rescue
|
26
|
+
{}
|
27
|
+
end
|
28
|
+
else
|
23
29
|
{}
|
24
30
|
end
|
25
|
-
else
|
26
|
-
{}
|
27
31
|
end
|
28
|
-
end
|
29
32
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
33
|
+
# Returns the contents of the resultset cache as a string or if the file is missing or empty nil
|
34
|
+
def stored_data
|
35
|
+
return unless File.exist?(resultset_path)
|
36
|
+
data = File.read(resultset_path)
|
37
|
+
return if data.nil? || data.length < 2
|
38
|
+
data
|
36
39
|
end
|
37
|
-
end
|
38
40
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
41
|
+
# Gets the resultset hash and re-creates all included instances
|
42
|
+
# of SimpleCov::Result from that.
|
43
|
+
# All results that are above the SimpleCov.merge_timeout will be
|
44
|
+
# dropped. Returns an array of SimpleCov::Result items.
|
45
|
+
def results
|
46
|
+
results = []
|
47
|
+
resultset.each do |command_name, data|
|
48
|
+
result = SimpleCov::Result.from_hash(command_name => data)
|
49
|
+
# Only add result if the timeout is above the configured threshold
|
50
|
+
if (Time.now - result.created_at) < SimpleCov.merge_timeout
|
51
|
+
results << result
|
52
|
+
end
|
50
53
|
end
|
54
|
+
results
|
51
55
|
end
|
52
|
-
results
|
53
|
-
end
|
54
56
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
57
|
+
#
|
58
|
+
# Gets all SimpleCov::Results from cache, merges them and produces a new
|
59
|
+
# SimpleCov::Result with merged coverage data and the command_name
|
60
|
+
# for the result consisting of a join on all source result's names
|
61
|
+
#
|
62
|
+
def merged_result
|
63
|
+
merged = {}
|
64
|
+
results.each do |result|
|
65
|
+
merged = result.original_result.merge_resultset(merged)
|
66
|
+
end
|
67
|
+
result = SimpleCov::Result.new(merged)
|
68
|
+
# Specify the command name
|
69
|
+
result.command_name = results.map(&:command_name).sort.join(", ")
|
70
|
+
result
|
64
71
|
end
|
65
|
-
result = SimpleCov::Result.new(merged)
|
66
|
-
# Specify the command name
|
67
|
-
result.command_name = results.map(&:command_name).sort.join(", ")
|
68
|
-
result
|
69
|
-
end
|
70
72
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
73
|
+
# Saves the given SimpleCov::Result in the resultset cache
|
74
|
+
def store_result(result)
|
75
|
+
File.open(resultset_writelock, "w+") do |f|
|
76
|
+
f.flock(File::LOCK_EX)
|
77
|
+
new_set = resultset
|
78
|
+
command_name, data = result.to_hash.first
|
79
|
+
new_set[command_name] = data
|
80
|
+
File.open(resultset_path, "w+") do |f_|
|
81
|
+
f_.puts JSON.pretty_generate(new_set)
|
82
|
+
end
|
80
83
|
end
|
84
|
+
true
|
81
85
|
end
|
82
|
-
true
|
83
86
|
end
|
84
87
|
end
|
85
88
|
end
|
@@ -25,26 +25,26 @@ module SimpleCov
|
|
25
25
|
alias_method :number, :line_number
|
26
26
|
|
27
27
|
def initialize(src, line_number, coverage)
|
28
|
-
|
29
|
-
|
30
|
-
|
28
|
+
fail ArgumentError, "Only String accepted for source" unless src.is_a?(String)
|
29
|
+
fail ArgumentError, "Only Fixnum accepted for line_number" unless line_number.is_a?(Fixnum)
|
30
|
+
fail ArgumentError, "Only Fixnum and nil accepted for coverage" unless coverage.is_a?(Fixnum) || coverage.nil?
|
31
31
|
@src, @line_number, @coverage = src, line_number, coverage
|
32
32
|
@skipped = false
|
33
33
|
end
|
34
34
|
|
35
35
|
# Returns true if this is a line that should have been covered, but was not
|
36
36
|
def missed?
|
37
|
-
|
37
|
+
!never? && !skipped? && coverage.zero?
|
38
38
|
end
|
39
39
|
|
40
40
|
# Returns true if this is a line that has been covered
|
41
41
|
def covered?
|
42
|
-
|
42
|
+
!never? && !skipped? && coverage > 0
|
43
43
|
end
|
44
44
|
|
45
45
|
# Returns true if this line is not relevant for coverage
|
46
46
|
def never?
|
47
|
-
|
47
|
+
!skipped? && coverage.nil?
|
48
48
|
end
|
49
49
|
|
50
50
|
# Flags this line as skipped
|
@@ -55,16 +55,16 @@ module SimpleCov
|
|
55
55
|
# Returns true if this line was skipped, false otherwise. Lines are skipped if they are wrapped with
|
56
56
|
# # :nocov: comment lines.
|
57
57
|
def skipped?
|
58
|
-
|
58
|
+
!!skipped
|
59
59
|
end
|
60
60
|
|
61
61
|
# The status of this line - either covered, missed, skipped or never. Useful i.e. for direct use
|
62
62
|
# as a css class in report generation
|
63
63
|
def status
|
64
|
-
return
|
65
|
-
return
|
66
|
-
return
|
67
|
-
return
|
64
|
+
return "skipped" if skipped?
|
65
|
+
return "never" if never?
|
66
|
+
return "missed" if missed?
|
67
|
+
return "covered" if covered?
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
@@ -78,7 +78,7 @@ module SimpleCov
|
|
78
78
|
|
79
79
|
def initialize(filename, coverage)
|
80
80
|
@filename, @coverage = filename, coverage
|
81
|
-
File.open(filename, "rb") {|f| @src = f.readlines }
|
81
|
+
File.open(filename, "rb") { |f| @src = f.readlines }
|
82
82
|
end
|
83
83
|
|
84
84
|
# Returns all source lines for this file as instances of SimpleCov::SourceFile::Line,
|
@@ -94,7 +94,7 @@ module SimpleCov
|
|
94
94
|
# Initialize lines
|
95
95
|
@lines = []
|
96
96
|
src.each_with_index do |src, i|
|
97
|
-
@lines << SimpleCov::SourceFile::Line.new(src, i+1, coverage[i])
|
97
|
+
@lines << SimpleCov::SourceFile::Line.new(src, i + 1, coverage[i])
|
98
98
|
end
|
99
99
|
process_skipped_lines!
|
100
100
|
@lines
|
@@ -103,14 +103,14 @@ module SimpleCov
|
|
103
103
|
|
104
104
|
# Access SimpleCov::SourceFile::Line source lines by line number
|
105
105
|
def line(number)
|
106
|
-
lines[number-1]
|
106
|
+
lines[number - 1]
|
107
107
|
end
|
108
108
|
|
109
109
|
# The coverage for this file in percent. 0 if the file has no relevant lines
|
110
110
|
def covered_percent
|
111
|
-
return 100.0 if lines.length
|
111
|
+
return 100.0 if lines.length.zero? || lines.length == never_lines.count
|
112
112
|
relevant_lines = lines.count - never_lines.count - skipped_lines.count
|
113
|
-
if relevant_lines
|
113
|
+
if relevant_lines.zero?
|
114
114
|
0.0
|
115
115
|
else
|
116
116
|
Float((covered_lines.count) * 100.0 / relevant_lines.to_f)
|
@@ -118,7 +118,7 @@ module SimpleCov
|
|
118
118
|
end
|
119
119
|
|
120
120
|
def covered_strength
|
121
|
-
return 0.0 if lines.length
|
121
|
+
return 0.0 if lines.length.zero? || lines.length == never_lines.count
|
122
122
|
|
123
123
|
lines_strength = 0
|
124
124
|
lines.each do |c|
|
@@ -127,7 +127,7 @@ module SimpleCov
|
|
127
127
|
|
128
128
|
effective_lines_count = Float(lines.count - never_lines.count - skipped_lines.count)
|
129
129
|
|
130
|
-
if effective_lines_count
|
130
|
+
if effective_lines_count.zero?
|
131
131
|
0.0
|
132
132
|
else
|
133
133
|
strength = lines_strength / effective_lines_count
|
@@ -137,24 +137,24 @@ module SimpleCov
|
|
137
137
|
|
138
138
|
# Returns all covered lines as SimpleCov::SourceFile::Line
|
139
139
|
def covered_lines
|
140
|
-
@covered_lines ||= lines.select
|
140
|
+
@covered_lines ||= lines.select(&:covered?)
|
141
141
|
end
|
142
142
|
|
143
143
|
# Returns all lines that should have been, but were not covered
|
144
144
|
# as instances of SimpleCov::SourceFile::Line
|
145
145
|
def missed_lines
|
146
|
-
@missed_lines ||= lines.select
|
146
|
+
@missed_lines ||= lines.select(&:missed?)
|
147
147
|
end
|
148
148
|
|
149
149
|
# Returns all lines that are not relevant for coverage as
|
150
150
|
# SimpleCov::SourceFile::Line instances
|
151
151
|
def never_lines
|
152
|
-
@never_lines ||= lines.select
|
152
|
+
@never_lines ||= lines.select(&:never?)
|
153
153
|
end
|
154
154
|
|
155
155
|
# Returns all lines that were skipped as SimpleCov::SourceFile::Line instances
|
156
156
|
def skipped_lines
|
157
|
-
@skipped_lines ||= lines.select
|
157
|
+
@skipped_lines ||= lines.select(&:skipped?)
|
158
158
|
end
|
159
159
|
|
160
160
|
# Returns the number of relevant lines (covered + missed)
|
@@ -175,7 +175,7 @@ module SimpleCov
|
|
175
175
|
end
|
176
176
|
end
|
177
177
|
|
178
|
-
|
178
|
+
private
|
179
179
|
|
180
180
|
# ruby 1.9 could use Float#round(places) instead
|
181
181
|
# @return [Float]
|
@@ -185,4 +185,3 @@ module SimpleCov
|
|
185
185
|
end
|
186
186
|
end
|
187
187
|
end
|
188
|
-
|
data/lib/simplecov/version.rb
CHANGED
@@ -1,3 +1,22 @@
|
|
1
1
|
module SimpleCov
|
2
|
-
VERSION = "0.
|
2
|
+
VERSION = "0.10.0"
|
3
|
+
def VERSION.to_a
|
4
|
+
split(".").map(&:to_i)
|
5
|
+
end
|
6
|
+
|
7
|
+
def VERSION.major
|
8
|
+
to_a[0]
|
9
|
+
end
|
10
|
+
|
11
|
+
def VERSION.minor
|
12
|
+
to_a[1]
|
13
|
+
end
|
14
|
+
|
15
|
+
def VERSION.patch
|
16
|
+
to_a[2]
|
17
|
+
end
|
18
|
+
|
19
|
+
def VERSION.pre
|
20
|
+
to_a[3]
|
21
|
+
end
|
3
22
|
end
|
data/simplecov.gemspec
CHANGED
@@ -1,25 +1,27 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require 'simplecov/version'
|
1
|
+
$LOAD_PATH.push File.expand_path("../lib", __FILE__)
|
2
|
+
require "simplecov/version"
|
4
3
|
|
5
4
|
Gem::Specification.new do |gem|
|
6
|
-
gem.name =
|
5
|
+
gem.name = "simplecov"
|
7
6
|
gem.version = SimpleCov::VERSION
|
8
7
|
gem.platform = Gem::Platform::RUBY
|
9
8
|
gem.authors = ["Christoph Olszowka"]
|
10
|
-
gem.email = [
|
11
|
-
gem.homepage =
|
12
|
-
gem.description = %
|
9
|
+
gem.email = ["christoph at olszowka de"]
|
10
|
+
gem.homepage = "http://github.com/colszowka/simplecov"
|
11
|
+
gem.description = %(Code coverage for Ruby 1.9+ with a powerful configuration library and automatic merging of coverage across test suites)
|
13
12
|
gem.summary = gem.description
|
14
13
|
gem.license = "MIT"
|
15
14
|
|
16
15
|
gem.required_ruby_version = ">= 1.8.7"
|
17
|
-
|
18
|
-
gem.add_dependency
|
19
|
-
gem.add_dependency
|
16
|
+
|
17
|
+
gem.add_dependency "json", "~> 1.8"
|
18
|
+
gem.add_dependency "simplecov-html", "~> 0.10.0"
|
19
|
+
gem.add_dependency "docile", "~> 1.1.0"
|
20
|
+
|
21
|
+
gem.add_development_dependency "bundler", "~> 1.9"
|
20
22
|
|
21
23
|
gem.files = `git ls-files`.split("\n")
|
22
24
|
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
23
|
-
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
24
|
-
gem.require_paths = [
|
25
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
26
|
+
gem.require_paths = ["lib"]
|
25
27
|
end
|
data/test/faked_project/Gemfile
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
source
|
1
|
+
source "https://rubygems.org"
|
2
2
|
|
3
|
-
gem
|
4
|
-
gem
|
5
|
-
gem
|
6
|
-
gem
|
3
|
+
gem "simplecov", :path => "../../../"
|
4
|
+
gem "rake"
|
5
|
+
gem "rspec", ">= 2.6.0"
|
6
|
+
gem "cucumber"
|
data/test/faked_project/Rakefile
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
require
|
1
|
+
require "bundler"
|
2
2
|
|
3
|
-
require
|
3
|
+
require "rake/testtask"
|
4
4
|
Rake::TestTask.new(:test) do |test|
|
5
|
-
test.libs <<
|
6
|
-
test.test_files = FileList[
|
5
|
+
test.libs << "lib" << "test"
|
6
|
+
test.test_files = FileList["test/**/*_test.rb"].sort
|
7
7
|
test.verbose = true
|
8
8
|
end
|
@@ -7,7 +7,7 @@ When /^I write my cukes for the fake project$/ do
|
|
7
7
|
end
|
8
8
|
|
9
9
|
Then /^I make all neccessary tests in a single step$/ do
|
10
|
-
expect(FakedProject.foo).to eq(
|
10
|
+
expect(FakedProject.foo).to eq("bar")
|
11
11
|
|
12
12
|
expect(FrameworkSpecific.cucumber).to eq("Only tested in Cucumber")
|
13
13
|
|
@@ -17,7 +17,6 @@ Then /^I make all neccessary tests in a single step$/ do
|
|
17
17
|
expect(FakedProject.new.dynamic).to eq("A dynamically defined instance method")
|
18
18
|
|
19
19
|
something = SomeClass.new("foo")
|
20
|
-
expect(something.reverse).to eq(
|
21
|
-
expect(something.compare_with(
|
20
|
+
expect(something.reverse).to eq("oof")
|
21
|
+
expect(something.compare_with("foo")).to be true
|
22
22
|
end
|
23
|
-
|