solargraph_test_coverage 0.2.4 → 0.2.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: afacac1a6d557ea7ef39c86081fc7f3aafcb7e09c3a8243679e9d252ba47a2c7
4
- data.tar.gz: 9e929da5ff5873ef3c044edebb4a96575cb47f4bfb9b2d36121082257ac03569
3
+ metadata.gz: c76dedeaddccb806778b5846c3587233919f1d78088edde15bb7b61681013896
4
+ data.tar.gz: 387c79384703dd5e92dddf31995982539a233094c7b985ad2977ff1265b2c16c
5
5
  SHA512:
6
- metadata.gz: 58b77e64736847a4d5d6fedb3c67f7b76e6af6056e844926356269c052b8bfe5f29af0c1f76e916f2e26d1ddb5c5628d3d324f53c890ceeff55f289959409b8c
7
- data.tar.gz: 92e5f351f941d99103339f80fb05450e1393cb5929f584cd7d080759450f9cd31422a71d51ba847664b1217b88c761f1f132f346f280106580c8c806ba1c6bd9
6
+ metadata.gz: 8d80b6d4abe2d40414c5dbc84652c1c4161a5b1d439b79e232414a1cbfbab1f27c51cf11e4d00a940309a01d5813ef59b4d88e57374ba1ce8ef81725b56b0c6a
7
+ data.tar.gz: 8bb2180c520a7b8b1c9dcecb191b68fc3c4be7c68c65cd2b4b5bc1ec6f8a40102f069cba5d0e4edebdd28753631657a4f50eb3886b6cbc1bde74c5cee293f70b
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- solargraph_test_coverage (0.2.3)
4
+ solargraph_test_coverage (0.2.4)
5
5
  solargraph (~> 0.40, > 0.40)
6
6
 
7
7
  GEM
@@ -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
- class << self
7
- #
8
- # Builds an array of Branch objects for every branch in results hash.
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
- branches.map do |branch_data, hit_count|
17
- type, _id, start_line, _start_col, end_line, _end_col = branch_data
10
+ branches.map do |branch_data, hit_count|
11
+ type, _id, start_line, _start_col, end_line, _end_col = branch_data
18
12
 
19
- new(start_line: start_line, end_line: end_line, coverage: hit_count,
20
- inline: start_line == condition_start_line, type: type)
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
- class Config
7
- class << self
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
- def exclude_paths
28
- plugin_config['exclude_paths']
29
- end
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
- def line_coverage?
32
- plugin_config['coverage'].include? 'line'
33
- end
22
+ def preload_rails?
23
+ plugin_config['preload_rails']
24
+ end
34
25
 
35
- def branch_coverage?
36
- plugin_config['coverage'].include? 'branch'
37
- end
26
+ def exclude_paths
27
+ plugin_config['exclude_paths']
28
+ end
38
29
 
39
- def test_failing_coverage?
40
- plugin_config['coverage'].include? 'test_failing'
41
- end
30
+ def line_coverage?
31
+ plugin_config['coverage'].include? 'line'
32
+ end
42
33
 
43
- def test_missing_coverage?
44
- plugin_config['coverage'].include? 'test_missing'
45
- end
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
- def test_framework
48
- plugin_config['test_framework']
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
- def test_dir
52
- case test_framework
53
- when 'rspec'
54
- 'spec'
55
- when 'minitest'
56
- 'test'
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
- def test_file_suffix
61
- case test_framework
62
- when 'rspec'
63
- '_spec.rb'
64
- when 'minitest'
65
- '_test.rb'
66
- end
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
- private
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
- def plugin_config
72
- @plugin_config ||= workspace_config.tap do |config|
73
- DEFAULTS.each_key { |key| config[key] = DEFAULTS[key] unless config.key?(key) }
74
- end
75
- end
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
- def workspace_config
78
- Solargraph::Workspace::Config.new(Dir.pwd).raw_data.fetch('test_coverage', {})
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,12 +5,9 @@ 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
8
  # Executes block in forked process, and captures returned value of that block
10
9
  # Returns result of block
11
10
  #
12
- # @return [Object]
13
- #
14
11
  def self.run
15
12
  read, write = IO.pipe
16
13
 
@@ -0,0 +1,81 @@
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 test_file(source)
13
+ relative_filepath = source.location.filename.sub(Dir.pwd, '').split('/').reject(&:empty?)
14
+ relative_filepath[0] = Config.test_dir
15
+
16
+ File.join(Dir.pwd, relative_filepath.join('/')).sub('.rb', Config.test_file_suffix)
17
+ end
18
+
19
+ # @return [Hash]
20
+ def run_test(source)
21
+ ForkProcess.run do
22
+ Coverage.start(lines: true, branches: true)
23
+ runner = TestRunner.with(test_file(source)).run!
24
+ Coverage.result.fetch(source.location.filename, {}).merge({ test_status: runner.passed? })
25
+ end
26
+ end
27
+
28
+ def messages(source, results)
29
+ messages = [
30
+ line_warnings(source, results),
31
+ branch_warnings(source, results),
32
+ test_passing_error(source, results)
33
+ ]
34
+
35
+ messages.flatten.compact
36
+ end
37
+
38
+ def line_warnings(source, results)
39
+ uncovered_lines(results).map { |line| line_coverage_warning(source, line) }
40
+ end
41
+
42
+ def branch_warnings(source, results)
43
+ uncovered_branches(results).map { |branch| branch_coverage_warning(source, branch.report) }
44
+ end
45
+
46
+ def test_passing_error(source, results)
47
+ results[:test_status] ? [] : [test_failing_error(source)]
48
+ end
49
+
50
+ # Adapted from SingleCov
51
+ # Coverage returns nil for untestable lines (like 'do', 'end', 'if' keywords)
52
+ # otherwise returns int showing how many times a line was called
53
+ #
54
+ # [nil, 1, 0, 1, 0] -> [3, 5]
55
+ # Returns array of line numbers with 0 coverage
56
+ def uncovered_lines(results)
57
+ return [] unless results[:lines]
58
+
59
+ results[:lines].each_with_index
60
+ .select { |c, _| c&.zero? }
61
+ .map { |_, i| i }
62
+ .compact
63
+ end
64
+
65
+ def uncovered_branches(results)
66
+ Branch.build_from(results).reject(&:covered?)
67
+ end
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
+ def self.test_path
74
+ File.join(Dir.pwd, Config.test_dir)
75
+ end
76
+
77
+ def test_path
78
+ ReporterHelpers.test_path
79
+ end
80
+ end
81
+ end
@@ -3,11 +3,8 @@
3
3
  # test_coverage reporter for Solargraph
4
4
  module SolargraphTestCoverage
5
5
  class TestCoverageReporter < Solargraph::Diagnostics::Base
6
- include Helpers
6
+ include ReporterHelpers
7
7
 
8
- # LSP Diagnostic method
9
- # @return [Array]
10
- #
11
8
  def diagnose(source, _api_map)
12
9
  return [] if source.code.empty? || exclude_file?(source.location.filename)
13
10
  return [test_missing_error(source)] unless File.file?(test_file(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::ERROR,
58
+ severity: Solargraph::Diagnostics::Severities::HINT,
112
59
  source: 'TestCoverage',
113
- message: "No unit test file found at #{test_file(source)}"
60
+ message: "No test file found at '#{test_file(source).sub("#{Dir.pwd}/", '')}'"
114
61
  }
115
62
  end
116
63
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SolargraphTestCoverage
4
- VERSION = '0.2.4'
4
+ VERSION = '0.2.5'
5
5
  end
@@ -3,7 +3,7 @@
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/helpers'
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'
@@ -16,8 +16,8 @@ module SolargraphTestCoverage
16
16
 
17
17
  class UnknownTestingGem < StandardError; end
18
18
 
19
- Helpers.require_testing_framework!
20
- Helpers.preload_rails! if Config.preload_rails?
19
+ Config.require_testing_framework!
20
+ Config.preload_rails! if Config.preload_rails?
21
21
 
22
22
  Solargraph::Diagnostics.register 'test_coverage', TestCoverageReporter
23
23
  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
4
+ version: 0.2.5
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-03 00:00:00.000000000 Z
11
+ date: 2021-09-09 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/helpers.rb
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,109 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SolargraphTestCoverage
4
- # Some helper functions for the diagnostics
5
- module Helpers
6
- # @return [Boolean]
7
- def exclude_file?(source_filename)
8
- return true if source_filename.start_with? Helpers.test_path
9
-
10
- Config.exclude_paths.each { |path| return true if source_filename.sub(Dir.pwd, '').include? path }
11
-
12
- false
13
- end
14
-
15
- # @return [String]
16
- def test_file(source)
17
- relative_filepath = source.location.filename.sub(Dir.pwd, '').split('/').reject(&:empty?)
18
- relative_filepath[0] = Config.test_dir
19
-
20
- File.join(Dir.pwd, relative_filepath.join('/'))
21
- .sub('.rb', Config.test_file_suffix)
22
- end
23
-
24
- # @return [Hash]
25
- def run_test(source)
26
- ForkProcess.run do
27
- Coverage.start(lines: true, branches: true)
28
- runner = TestRunner.with(test_file(source)).run!
29
- Coverage.result.fetch(source.location.filename, {}).merge({ test_status: runner.passed? })
30
- end
31
- end
32
-
33
- # Adapted from SingleCov
34
- # Coverage returns nil for untestable lines (like do, end, if keywords)
35
- # otherwise returns int showing how many times a line was called
36
- #
37
- # [nil, 1, 0, 1, 0] -> [3, 5]
38
- #
39
- # @return [Array]
40
- #
41
- def uncovered_lines(results)
42
- return [] unless results[:lines]
43
-
44
- results[:lines].each_with_index
45
- .select { |c, _| c&.zero? }
46
- .map { |_, i| i }
47
- .compact
48
- end
49
-
50
- # @return [Array]
51
- def uncovered_branches(results)
52
- Branch.build_from(results).reject(&:covered?)
53
- end
54
-
55
- # @return [Hash]
56
- def range(start_line, start_column, end_line, end_column)
57
- Solargraph::Range.from_to(start_line, start_column, end_line, end_column).to_hash
58
- end
59
-
60
- def self.require_testing_framework!
61
- case Config.test_framework
62
- when 'rspec'
63
- require 'rspec/core'
64
- when 'minitest'
65
- require 'minitest/autorun'
66
- else
67
- raise UnknownTestingGem
68
- end
69
- end
70
-
71
- # Only called once, when gem is loaded
72
- # Preloads rails via spec/rails_helper if Rails isn't already defined
73
- # This gives us a nice speed-boost when running test in child process
74
- #
75
- # We rescue the LoadError since Solargraph would catch it otherwise,
76
- # and not load the plugin at all.
77
- #
78
- # Adding the spec/ directory to the $LOAD_PATH lets 'require "spec_helper"'
79
- # commonly found in rails_helper work.
80
- #
81
- # If Coverage was started in Rails/Spec helper by SimpleCov,
82
- # calling Coverage.result after requiring stops and resets it.
83
- #
84
- # This is a bit experimental - I'm not sure if there will be downstream side-effects
85
- #
86
- # @return [Boolean]
87
- #
88
- def self.preload_rails!
89
- return if defined?(Rails) || !File.file?('spec/rails_helper.rb')
90
-
91
- $LOAD_PATH.unshift(test_path) unless $LOAD_PATH.include?(test_path)
92
-
93
- require File.join(test_path, 'rails_helper')
94
- Coverage.result(stop: true, clear: true) if Coverage.running?
95
-
96
- true
97
- rescue LoadError => e
98
- Solargraph::Logging.logger.warn "LoadError when trying to require 'rails_helper'"
99
- Solargraph::Logging.logger.warn "[#{e.class}] #{e.message}"
100
-
101
- false
102
- end
103
-
104
- # @return [String]
105
- def self.test_path
106
- File.join(Dir.pwd, Config.test_dir)
107
- end
108
- end
109
- end