solargraph_test_coverage 0.2.3 → 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +3 -3
- data/README.md +9 -5
- data/lib/solargraph_test_coverage/branch.rb +7 -40
- data/lib/solargraph_test_coverage/config.rb +103 -61
- data/lib/solargraph_test_coverage/fork_process.rb +23 -15
- data/lib/solargraph_test_coverage/reporter_helpers.rb +87 -0
- data/lib/solargraph_test_coverage/test_coverage_reporter.rb +4 -57
- data/lib/solargraph_test_coverage/test_runner.rb +13 -1
- data/lib/solargraph_test_coverage/version.rb +1 -1
- data/lib/solargraph_test_coverage.rb +4 -3
- metadata +3 -3
- data/lib/solargraph_test_coverage/helpers.rb +0 -127
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b7c7bd9d2a4a3b6184942c28ce619023f098a515ca356e8534788adb93f9cb96
|
4
|
+
data.tar.gz: 11850e7e7184658995b6e15479e8c3c87527f4b945c8b8bc9ab446242c5dba32
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d4901017237a8e5cfc49e8a0228776c48929304ebb043bdd9c89500e56db2c4d7349b01838c911a3080900ca1d657b07f2d29a921d0cc39b2da96efe517d1443
|
7
|
+
data.tar.gz: c00ecc7e6c928c42a93abda3f976e3d0811934f21f21362a40711dbc449244a3e443d683a6c6204955ea3ec28989226f41d5b371344238594d78c86b3fb98987
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
solargraph_test_coverage (0.2.
|
4
|
+
solargraph_test_coverage (0.2.6)
|
5
5
|
solargraph (~> 0.40, > 0.40)
|
6
6
|
|
7
7
|
GEM
|
@@ -19,7 +19,7 @@ GEM
|
|
19
19
|
kramdown (~> 2.0)
|
20
20
|
nokogiri (1.12.4-x86_64-darwin)
|
21
21
|
racc (~> 1.4)
|
22
|
-
parallel (1.
|
22
|
+
parallel (1.21.0)
|
23
23
|
parser (3.0.2.0)
|
24
24
|
ast (~> 2.4.1)
|
25
25
|
racc (1.5.2)
|
@@ -29,7 +29,7 @@ GEM
|
|
29
29
|
reverse_markdown (2.0.0)
|
30
30
|
nokogiri
|
31
31
|
rexml (3.2.5)
|
32
|
-
rubocop (1.
|
32
|
+
rubocop (1.21.0)
|
33
33
|
parallel (~> 1.10)
|
34
34
|
parser (>= 3.0.0.0)
|
35
35
|
rainbow (>= 2.2.2, < 4.0)
|
data/README.md
CHANGED
@@ -33,12 +33,13 @@ test_coverage:
|
|
33
33
|
preload_rails: true
|
34
34
|
test_framework: rspec # or minitest
|
35
35
|
coverage:
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
36
|
+
- line
|
37
|
+
- branch
|
38
|
+
- test_failing
|
39
|
+
- test_missing
|
40
40
|
exclude_paths:
|
41
|
-
|
41
|
+
- 'app/controller'
|
42
|
+
- 'concerns'
|
42
43
|
```
|
43
44
|
|
44
45
|
|
@@ -50,6 +51,9 @@ And then execute:
|
|
50
51
|
Or install it yourself as:
|
51
52
|
|
52
53
|
$ gem install solargraph_test_coverage
|
54
|
+
|
55
|
+
A note on testing framework:
|
56
|
+
Since both Minitest and RSpec are supported, neither are direct dependencies of this gem. Therefore, you have to have them installed separately either via your bundle or via `gem install`.
|
53
57
|
|
54
58
|
## Usage
|
55
59
|
|
@@ -3,22 +3,15 @@
|
|
3
3
|
module SolargraphTestCoverage
|
4
4
|
# Adapted from SimpleCov - Small class that turns branch coverage data into something easier to work with
|
5
5
|
class Branch
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
#
|
10
|
-
# @return [Array]
|
11
|
-
#
|
12
|
-
def build_from(results)
|
13
|
-
results.fetch(:branches, {}).flat_map do |condition, branches|
|
14
|
-
_condition_type, _condition_id, condition_start_line, * = condition
|
6
|
+
def self.build_from(results)
|
7
|
+
results.fetch(:branches, {}).flat_map do |condition, branches|
|
8
|
+
_condition_type, _condition_id, condition_start_line, * = condition
|
15
9
|
|
16
|
-
|
17
|
-
|
10
|
+
branches.map do |branch_data, hit_count|
|
11
|
+
type, _id, start_line, _start_col, end_line, _end_col = branch_data
|
18
12
|
|
19
|
-
|
20
|
-
|
21
|
-
end
|
13
|
+
new(start_line: start_line, end_line: end_line, coverage: hit_count,
|
14
|
+
inline: start_line == condition_start_line, type: type)
|
22
15
|
end
|
23
16
|
end
|
24
17
|
end
|
@@ -33,44 +26,18 @@ module SolargraphTestCoverage
|
|
33
26
|
@type = type
|
34
27
|
end
|
35
28
|
|
36
|
-
#
|
37
|
-
# Predicate method for @inline instance variable
|
38
|
-
#
|
39
|
-
# @return [Boolean]
|
40
|
-
#
|
41
29
|
def inline?
|
42
30
|
@inline
|
43
31
|
end
|
44
32
|
|
45
|
-
#
|
46
|
-
# Return true if there is relevant count defined > 0
|
47
|
-
#
|
48
|
-
# @return [Boolean]
|
49
|
-
#
|
50
33
|
def covered?
|
51
34
|
coverage.positive?
|
52
35
|
end
|
53
36
|
|
54
|
-
#
|
55
|
-
# The line on which we want to report the coverage
|
56
|
-
#
|
57
|
-
# Usually we choose the line above the start of the branch (so that it shows up
|
58
|
-
# at if/else) because that
|
59
|
-
# * highlights the condition
|
60
|
-
# * makes it distinguishable if the first line of the branch is an inline branch
|
61
|
-
# (see the nested_branches fixture)
|
62
|
-
#
|
63
|
-
# @return [Integer]
|
64
|
-
#
|
65
37
|
def report_line
|
66
38
|
inline? ? start_line : start_line - 1
|
67
39
|
end
|
68
40
|
|
69
|
-
#
|
70
|
-
# Return array with coverage count and badge
|
71
|
-
#
|
72
|
-
# @return [Hash]
|
73
|
-
#
|
74
41
|
def report
|
75
42
|
{ type: type, line: report_line }
|
76
43
|
end
|
@@ -1,82 +1,124 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# frozen_string_literal = true
|
4
|
-
|
5
3
|
module SolargraphTestCoverage
|
6
|
-
|
7
|
-
|
8
|
-
DEFAULTS = {
|
9
|
-
'preload_rails' => true, # can be true or false - performance optimization
|
10
|
-
'test_framework' => 'rspec', # can be 'rspec' or 'minitest'
|
11
|
-
'coverage' => [ # All diagnostics are enabled by default
|
12
|
-
'line', # Specifying an array with fewer diagnostics will overwrite this
|
13
|
-
'branch',
|
14
|
-
'test_failing',
|
15
|
-
'test_missing'
|
16
|
-
],
|
17
|
-
'exclude_paths' => [ # don't attempt to find/run a spec for files that match these paths
|
18
|
-
'app/controller',
|
19
|
-
'concerns'
|
20
|
-
]
|
21
|
-
}.freeze
|
22
|
-
|
23
|
-
def preload_rails?
|
24
|
-
plugin_config['preload_rails']
|
25
|
-
end
|
4
|
+
module Config
|
5
|
+
extend self
|
26
6
|
|
27
|
-
|
28
|
-
|
29
|
-
|
7
|
+
DEFAULTS = {
|
8
|
+
'preload_rails' => true, # can be true or false - performance optimization
|
9
|
+
'test_framework' => 'rspec', # can be 'rspec' or 'minitest'
|
10
|
+
'coverage' => [ # All diagnostics are enabled by default
|
11
|
+
'line', # Specifying an array with fewer diagnostics will overwrite this
|
12
|
+
'branch',
|
13
|
+
'test_failing',
|
14
|
+
'test_missing'
|
15
|
+
],
|
16
|
+
'exclude_paths' => [ # don't attempt to find/run a spec for files that match these paths
|
17
|
+
'app/controller',
|
18
|
+
'concerns'
|
19
|
+
]
|
20
|
+
}.freeze
|
30
21
|
|
31
|
-
|
32
|
-
|
33
|
-
|
22
|
+
def preload_rails?
|
23
|
+
plugin_config['preload_rails']
|
24
|
+
end
|
34
25
|
|
35
|
-
|
36
|
-
|
37
|
-
|
26
|
+
def exclude_paths
|
27
|
+
plugin_config['exclude_paths']
|
28
|
+
end
|
38
29
|
|
39
|
-
|
40
|
-
|
41
|
-
|
30
|
+
def line_coverage?
|
31
|
+
plugin_config['coverage'].include? 'line'
|
32
|
+
end
|
42
33
|
|
43
|
-
|
44
|
-
|
45
|
-
|
34
|
+
def branch_coverage?
|
35
|
+
plugin_config['coverage'].include? 'branch'
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_failing_coverage?
|
39
|
+
plugin_config['coverage'].include? 'test_failing'
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_missing_coverage?
|
43
|
+
plugin_config['coverage'].include? 'test_missing'
|
44
|
+
end
|
46
45
|
|
47
|
-
|
48
|
-
|
46
|
+
def test_framework
|
47
|
+
plugin_config['test_framework']
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_dir
|
51
|
+
case test_framework
|
52
|
+
when 'rspec'
|
53
|
+
'spec'
|
54
|
+
when 'minitest'
|
55
|
+
'test'
|
49
56
|
end
|
57
|
+
end
|
50
58
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
end
|
59
|
+
def test_file_suffix
|
60
|
+
case test_framework
|
61
|
+
when 'rspec'
|
62
|
+
'_spec.rb'
|
63
|
+
when 'minitest'
|
64
|
+
'_test.rb'
|
58
65
|
end
|
66
|
+
end
|
59
67
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
68
|
+
def require_testing_framework!
|
69
|
+
case test_framework
|
70
|
+
when 'rspec'
|
71
|
+
require 'rspec/core'
|
72
|
+
when 'minitest'
|
73
|
+
require 'minitest/autorun'
|
74
|
+
else
|
75
|
+
raise UnknownTestingGem
|
67
76
|
end
|
77
|
+
end
|
68
78
|
|
69
|
-
|
79
|
+
# This gives us a nice speed-boost when running test in child process
|
80
|
+
#
|
81
|
+
# We rescue the LoadError since Solargraph would catch it otherwise,
|
82
|
+
# and not load the plugin at all.
|
83
|
+
#
|
84
|
+
# Adding the spec/ directory to the $LOAD_PATH lets 'require "spec_helper"'
|
85
|
+
# commonly found in rails_helper work.
|
86
|
+
#
|
87
|
+
# If Coverage was started in Rails/Spec helper by SimpleCov,
|
88
|
+
# calling Coverage.result after requiring stops and resets it.
|
89
|
+
#
|
90
|
+
# This is a bit experimental
|
91
|
+
#
|
92
|
+
def preload_rails!
|
93
|
+
return if defined?(Rails) || !File.file?('spec/rails_helper.rb')
|
70
94
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
95
|
+
$LOAD_PATH.unshift(test_path) unless $LOAD_PATH.include?(test_path)
|
96
|
+
|
97
|
+
require File.join(test_path, 'rails_helper')
|
98
|
+
Coverage.result(stop: true, clear: true) if Coverage.running?
|
99
|
+
|
100
|
+
true
|
101
|
+
rescue LoadError => e
|
102
|
+
Solargraph::Logging.logger.warn "LoadError when trying to require 'rails_helper'"
|
103
|
+
Solargraph::Logging.logger.warn "[#{e.class}] #{e.message}"
|
76
104
|
|
77
|
-
|
78
|
-
|
105
|
+
false
|
106
|
+
end
|
107
|
+
|
108
|
+
private
|
109
|
+
|
110
|
+
def plugin_config
|
111
|
+
@plugin_config ||= workspace_config.tap do |config|
|
112
|
+
DEFAULTS.each_key { |key| config[key] = DEFAULTS[key] unless config.key?(key) }
|
79
113
|
end
|
80
114
|
end
|
115
|
+
|
116
|
+
def workspace_config
|
117
|
+
Solargraph::Workspace::Config.new(Dir.pwd).raw_data.fetch('test_coverage', {})
|
118
|
+
end
|
119
|
+
|
120
|
+
def test_path
|
121
|
+
ReporterHelpers.test_path
|
122
|
+
end
|
81
123
|
end
|
82
124
|
end
|
@@ -5,28 +5,36 @@ module SolargraphTestCoverage
|
|
5
5
|
# When called with a block, runs the content of said block in a new (forked) process
|
6
6
|
# the return value of the process/block can be captured and used in parent process
|
7
7
|
class ForkProcess
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
read, write = IO.pipe
|
8
|
+
def self.call(&block)
|
9
|
+
new.run(&block)
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@read, @write = IO.pipe
|
14
|
+
end
|
16
15
|
|
16
|
+
def run(&block)
|
17
17
|
pid = fork do
|
18
|
-
read.close
|
19
|
-
|
20
|
-
Marshal.dump(result, write)
|
18
|
+
@read.close
|
19
|
+
Marshal.dump(run_block_with_timeout(&block), @write)
|
21
20
|
exit!(0) # skips exit handlers.
|
22
21
|
end
|
23
22
|
|
24
|
-
write.close
|
25
|
-
result = read.read
|
23
|
+
@write.close
|
24
|
+
result = @read.read
|
25
|
+
|
26
26
|
Process.wait(pid)
|
27
|
-
raise ChildFailedError if result.nil?
|
27
|
+
raise ChildFailedError if result.nil?
|
28
|
+
|
29
|
+
Marshal.load(result).tap { |r| raise ChildFailedError if r.nil? }
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
28
33
|
|
29
|
-
|
34
|
+
def run_block_with_timeout(&block)
|
35
|
+
Timeout.timeout(30, &block)
|
36
|
+
rescue StandardError
|
37
|
+
nil
|
30
38
|
end
|
31
39
|
end
|
32
40
|
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolargraphTestCoverage
|
4
|
+
# Some helper functions for the diagnostics
|
5
|
+
module ReporterHelpers
|
6
|
+
def exclude_file?(source_filename)
|
7
|
+
return true if source_filename.start_with? test_path
|
8
|
+
|
9
|
+
Config.exclude_paths.any? { |path| source_filename.sub(Dir.pwd, '').include? path }
|
10
|
+
end
|
11
|
+
|
12
|
+
def using_debugger?(source)
|
13
|
+
source.code.include?('binding.pry') ||
|
14
|
+
source.code.include?('byebug') ||
|
15
|
+
source.code.include?('debugger')
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_file(source)
|
19
|
+
relative_filepath = source.location.filename.sub(Dir.pwd, '').split('/').reject(&:empty?)
|
20
|
+
relative_filepath[0] = Config.test_dir
|
21
|
+
|
22
|
+
File.join(Dir.pwd, relative_filepath.join('/')).sub('.rb', Config.test_file_suffix)
|
23
|
+
end
|
24
|
+
|
25
|
+
# @return [Hash]
|
26
|
+
def run_test(source)
|
27
|
+
ForkProcess.call do
|
28
|
+
Coverage.start(lines: true, branches: true)
|
29
|
+
runner = TestRunner.with(test_file(source)).run!
|
30
|
+
Coverage.result.fetch(source.location.filename, {}).merge({ test_status: runner.passed? })
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def messages(source, results)
|
35
|
+
messages = [
|
36
|
+
line_warnings(source, results),
|
37
|
+
branch_warnings(source, results),
|
38
|
+
test_passing_error(source, results)
|
39
|
+
]
|
40
|
+
|
41
|
+
messages.flatten.compact
|
42
|
+
end
|
43
|
+
|
44
|
+
def line_warnings(source, results)
|
45
|
+
uncovered_lines(results).map { |line| line_coverage_warning(source, line) }
|
46
|
+
end
|
47
|
+
|
48
|
+
def branch_warnings(source, results)
|
49
|
+
uncovered_branches(results).map { |branch| branch_coverage_warning(source, branch.report) }
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_passing_error(source, results)
|
53
|
+
results[:test_status] ? [] : [test_failing_error(source)]
|
54
|
+
end
|
55
|
+
|
56
|
+
# Adapted from SingleCov
|
57
|
+
# Coverage returns nil for untestable lines (like 'do', 'end', 'if' keywords)
|
58
|
+
# otherwise returns int showing how many times a line was called
|
59
|
+
#
|
60
|
+
# [nil, 1, 0, 1, 0] -> [3, 5]
|
61
|
+
# Returns array of line numbers with 0 coverage
|
62
|
+
def uncovered_lines(results)
|
63
|
+
return [] unless results[:lines]
|
64
|
+
|
65
|
+
results[:lines].each_with_index
|
66
|
+
.select { |c, _| c&.zero? }
|
67
|
+
.map { |_, i| i }
|
68
|
+
.compact
|
69
|
+
end
|
70
|
+
|
71
|
+
def uncovered_branches(results)
|
72
|
+
Branch.build_from(results).reject(&:covered?)
|
73
|
+
end
|
74
|
+
|
75
|
+
def range(start_line, start_column, end_line, end_column)
|
76
|
+
Solargraph::Range.from_to(start_line, start_column, end_line, end_column).to_hash
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.test_path
|
80
|
+
File.join(Dir.pwd, Config.test_dir)
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_path
|
84
|
+
ReporterHelpers.test_path
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -3,13 +3,10 @@
|
|
3
3
|
# test_coverage reporter for Solargraph
|
4
4
|
module SolargraphTestCoverage
|
5
5
|
class TestCoverageReporter < Solargraph::Diagnostics::Base
|
6
|
-
include
|
6
|
+
include ReporterHelpers
|
7
7
|
|
8
|
-
# LSP Diagnostic method
|
9
|
-
# @return [Array]
|
10
|
-
#
|
11
8
|
def diagnose(source, _api_map)
|
12
|
-
return [] if source.code.empty? || exclude_file?(source.location.filename)
|
9
|
+
return [] if source.code.empty? || using_debugger?(source) || exclude_file?(source.location.filename)
|
13
10
|
return [test_missing_error(source)] unless File.file?(test_file(source))
|
14
11
|
|
15
12
|
results = run_test(source)
|
@@ -20,43 +17,6 @@ module SolargraphTestCoverage
|
|
20
17
|
|
21
18
|
private
|
22
19
|
|
23
|
-
# Compiles all diagnostic messages for source file
|
24
|
-
# @return [Array]
|
25
|
-
#
|
26
|
-
def messages(source, results)
|
27
|
-
messages = [
|
28
|
-
line_warnings(source, results),
|
29
|
-
branch_warnings(source, results),
|
30
|
-
test_passing_error(source, results)
|
31
|
-
]
|
32
|
-
|
33
|
-
messages.flatten.compact
|
34
|
-
end
|
35
|
-
|
36
|
-
# Creates array of warnings for uncovered lines
|
37
|
-
# @return [Array]
|
38
|
-
#
|
39
|
-
def line_warnings(source, results)
|
40
|
-
uncovered_lines(results).map { |line| line_coverage_warning(source, line) }
|
41
|
-
end
|
42
|
-
|
43
|
-
# Creates array of warnings for uncovered branches
|
44
|
-
# @return [Array]
|
45
|
-
#
|
46
|
-
def branch_warnings(source, results)
|
47
|
-
uncovered_branches(results).map { |branch| branch_coverage_warning(source, branch.report) }
|
48
|
-
end
|
49
|
-
|
50
|
-
# Creates array containing error for failing spec
|
51
|
-
# @return [Array]
|
52
|
-
#
|
53
|
-
def test_passing_error(source, results)
|
54
|
-
results[:test_status] ? [] : [test_failing_error(source)]
|
55
|
-
end
|
56
|
-
|
57
|
-
# Creates LSP warning message for missing line coverage
|
58
|
-
# @return [Hash]
|
59
|
-
#
|
60
20
|
def line_coverage_warning(source, line)
|
61
21
|
return unless Config.line_coverage?
|
62
22
|
|
@@ -68,11 +28,6 @@ module SolargraphTestCoverage
|
|
68
28
|
}
|
69
29
|
end
|
70
30
|
|
71
|
-
# Creates LSP warning message for missing branch coverage
|
72
|
-
# Line numbers are off by 1, since Branch Coverage starts counting at 1, not 0
|
73
|
-
#
|
74
|
-
# @return [Hash]
|
75
|
-
#
|
76
31
|
def branch_coverage_warning(source, report)
|
77
32
|
return unless Config.branch_coverage?
|
78
33
|
|
@@ -84,9 +39,6 @@ module SolargraphTestCoverage
|
|
84
39
|
}
|
85
40
|
end
|
86
41
|
|
87
|
-
# Creates LSP error message if test file is failing
|
88
|
-
# @return [Hash]
|
89
|
-
#
|
90
42
|
def test_failing_error(source)
|
91
43
|
return unless Config.test_failing_coverage?
|
92
44
|
|
@@ -98,19 +50,14 @@ module SolargraphTestCoverage
|
|
98
50
|
}
|
99
51
|
end
|
100
52
|
|
101
|
-
#
|
102
|
-
# Creates LSP error message if no test file can be found
|
103
|
-
#
|
104
|
-
# @return [Hash]
|
105
|
-
#
|
106
53
|
def test_missing_error(source)
|
107
54
|
return unless Config.test_missing_coverage?
|
108
55
|
|
109
56
|
{
|
110
57
|
range: range(0, 0, 0, source.code.lines[0].length),
|
111
|
-
severity: Solargraph::Diagnostics::Severities::
|
58
|
+
severity: Solargraph::Diagnostics::Severities::HINT,
|
112
59
|
source: 'TestCoverage',
|
113
|
-
message: "No
|
60
|
+
message: "No test file found at '#{test_file(source).sub("#{Dir.pwd}/", '')}'"
|
114
61
|
}
|
115
62
|
end
|
116
63
|
end
|
@@ -18,10 +18,14 @@ module SolargraphTestCoverage
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def run!
|
21
|
-
@result = test_framework_runner.run(
|
21
|
+
@result = test_framework_runner.run(test_options)
|
22
22
|
self
|
23
23
|
end
|
24
24
|
|
25
|
+
def test_options
|
26
|
+
raise NotImplementedError
|
27
|
+
end
|
28
|
+
|
25
29
|
def passed?
|
26
30
|
raise NotImplementedError
|
27
31
|
end
|
@@ -33,6 +37,10 @@ module SolargraphTestCoverage
|
|
33
37
|
|
34
38
|
# Test Runner Subclass for RSpec
|
35
39
|
class RSpecRunner < TestRunner
|
40
|
+
def test_options
|
41
|
+
[@test_file, '-o', '/dev/null']
|
42
|
+
end
|
43
|
+
|
36
44
|
def passed?
|
37
45
|
@result&.zero?
|
38
46
|
end
|
@@ -44,6 +52,10 @@ module SolargraphTestCoverage
|
|
44
52
|
|
45
53
|
# Test Runner Subclass for Minitest
|
46
54
|
class MinitestRunner < TestRunner
|
55
|
+
def test_options
|
56
|
+
[@test_file]
|
57
|
+
end
|
58
|
+
|
47
59
|
def passed?
|
48
60
|
@result
|
49
61
|
end
|
@@ -3,21 +3,22 @@
|
|
3
3
|
require 'solargraph_test_coverage/version'
|
4
4
|
require 'solargraph_test_coverage/branch'
|
5
5
|
require 'solargraph_test_coverage/fork_process'
|
6
|
-
require 'solargraph_test_coverage/
|
6
|
+
require 'solargraph_test_coverage/reporter_helpers'
|
7
7
|
require 'solargraph_test_coverage/config'
|
8
8
|
require 'solargraph_test_coverage/test_runner'
|
9
9
|
require 'solargraph_test_coverage/test_coverage_reporter'
|
10
10
|
|
11
11
|
require 'solargraph'
|
12
12
|
require 'coverage'
|
13
|
+
require 'timeout'
|
13
14
|
|
14
15
|
module SolargraphTestCoverage
|
15
16
|
class ChildFailedError < StandardError; end
|
16
17
|
|
17
18
|
class UnknownTestingGem < StandardError; end
|
18
19
|
|
19
|
-
|
20
|
-
|
20
|
+
Config.require_testing_framework!
|
21
|
+
Config.preload_rails! if Config.preload_rails?
|
21
22
|
|
22
23
|
Solargraph::Diagnostics.register 'test_coverage', TestCoverageReporter
|
23
24
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: solargraph_test_coverage
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cameron Kolkey
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-09-
|
11
|
+
date: 2021-09-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: solargraph
|
@@ -48,7 +48,7 @@ files:
|
|
48
48
|
- lib/solargraph_test_coverage/branch.rb
|
49
49
|
- lib/solargraph_test_coverage/config.rb
|
50
50
|
- lib/solargraph_test_coverage/fork_process.rb
|
51
|
-
- lib/solargraph_test_coverage/
|
51
|
+
- lib/solargraph_test_coverage/reporter_helpers.rb
|
52
52
|
- lib/solargraph_test_coverage/test_coverage_reporter.rb
|
53
53
|
- lib/solargraph_test_coverage/test_runner.rb
|
54
54
|
- lib/solargraph_test_coverage/version.rb
|
@@ -1,127 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module SolargraphTestCoverage
|
4
|
-
# Some helper functions for the diagnostics
|
5
|
-
module Helpers
|
6
|
-
# Determines if a file should be excluded from running diagnostics
|
7
|
-
# @return [Boolean]
|
8
|
-
#
|
9
|
-
def exclude_file?(source_filename)
|
10
|
-
return true if source_filename.start_with? Helpers.test_path
|
11
|
-
|
12
|
-
Config.exclude_paths.each { |path| return true if source_filename.sub(Dir.pwd, '').include? path }
|
13
|
-
|
14
|
-
false
|
15
|
-
end
|
16
|
-
|
17
|
-
# Attempts to find the corresponding unit test file
|
18
|
-
# @return [String]
|
19
|
-
#
|
20
|
-
def test_file(source)
|
21
|
-
relative_filepath = source.location.filename.sub(Dir.pwd, '').split('/').reject(&:empty?)
|
22
|
-
relative_filepath[0] = Config.test_dir
|
23
|
-
|
24
|
-
File.join(Dir.pwd, relative_filepath.join('/'))
|
25
|
-
.sub('.rb', Config.test_file_suffix)
|
26
|
-
end
|
27
|
-
|
28
|
-
# Runs test file in a child process with specified testing framework
|
29
|
-
# Returns coverage results for current working file
|
30
|
-
#
|
31
|
-
# @return [Hash]
|
32
|
-
#
|
33
|
-
def run_test(source)
|
34
|
-
ForkProcess.run do
|
35
|
-
Coverage.start(lines: true, branches: true)
|
36
|
-
runner = TestRunner.with(test_file(source)).run!
|
37
|
-
Coverage.result.fetch(source.location.filename, {}).merge({ test_status: runner.passed? })
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
# Adapted from SingleCov
|
42
|
-
# Coverage returns nil for untestable lines (like do, end, if keywords)
|
43
|
-
# otherwise returns int showing how many times a line was called
|
44
|
-
#
|
45
|
-
# [nil, 1, 0, 1, 0] -> [3, 5]
|
46
|
-
#
|
47
|
-
# @return [Array]
|
48
|
-
#
|
49
|
-
def uncovered_lines(results)
|
50
|
-
results.fetch(:lines)
|
51
|
-
.each_with_index
|
52
|
-
.select { |c, _| c&.zero? }
|
53
|
-
.map { |_, i| i }
|
54
|
-
.compact
|
55
|
-
end
|
56
|
-
|
57
|
-
# Builds a new Branch object for each branch tested from results hash
|
58
|
-
# Then removes branches which have test coverage
|
59
|
-
#
|
60
|
-
# @return [Array]
|
61
|
-
#
|
62
|
-
def uncovered_branches(results)
|
63
|
-
Branch.build_from(results).reject(&:covered?)
|
64
|
-
end
|
65
|
-
|
66
|
-
# Builds a range for warnings/errors
|
67
|
-
# @return [Hash]
|
68
|
-
#
|
69
|
-
def range(start_line, start_column, end_line, end_column)
|
70
|
-
Solargraph::Range.from_to(start_line, start_column, end_line, end_column).to_hash
|
71
|
-
end
|
72
|
-
|
73
|
-
# requires the specified testing framework
|
74
|
-
# @return [Boolean]
|
75
|
-
#
|
76
|
-
def self.require_testing_framework!
|
77
|
-
case Config.test_framework
|
78
|
-
when 'rspec'
|
79
|
-
require 'rspec/core'
|
80
|
-
when 'minitest'
|
81
|
-
require 'minitest/autorun'
|
82
|
-
else
|
83
|
-
raise UnknownTestingGem
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
# Only called once, when gem is loaded
|
88
|
-
# Preloads rails via spec/rails_helper if Rails isn't already defined
|
89
|
-
# This gives us a nice speed-boost when running test in child process
|
90
|
-
#
|
91
|
-
# We rescue the LoadError since Solargraph would catch it otherwise,
|
92
|
-
# and not load the plugin at all.
|
93
|
-
#
|
94
|
-
# Adding the spec/ directory to the $LOAD_PATH lets 'require "spec_helper"'
|
95
|
-
# commonly found in rails_helper work.
|
96
|
-
#
|
97
|
-
# If Coverage was started in Rails/Spec helper by SimpleCov,
|
98
|
-
# calling Coverage.result after requiring stops and resets it.
|
99
|
-
#
|
100
|
-
# This is a bit experimental - I'm not sure if there will be downstream side-effects
|
101
|
-
#
|
102
|
-
# @return [Boolean]
|
103
|
-
#
|
104
|
-
def self.preload_rails!
|
105
|
-
return if defined?(Rails) || !File.file?('spec/rails_helper.rb')
|
106
|
-
|
107
|
-
$LOAD_PATH.unshift(test_path) unless $LOAD_PATH.include?(test_path)
|
108
|
-
|
109
|
-
require File.join(test_path, 'rails_helper')
|
110
|
-
Coverage.result(stop: true, clear: true) if Coverage.running?
|
111
|
-
|
112
|
-
true
|
113
|
-
rescue LoadError => e
|
114
|
-
Solargraph::Logging.logger.warn "LoadError when trying to require 'rails_helper'"
|
115
|
-
Solargraph::Logging.logger.warn "[#{e.class}] #{e.message}"
|
116
|
-
|
117
|
-
false
|
118
|
-
end
|
119
|
-
|
120
|
-
# Returns absolute path for test folder
|
121
|
-
# @return [String]
|
122
|
-
#
|
123
|
-
def self.test_path
|
124
|
-
File.join(Dir.pwd, Config.test_dir)
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|