# frozen_string_literal: true # test_coverage reporter for Solargraph module SolargraphTestCoverage class TestCoverageReporter < Solargraph::Diagnostics::Base include Helpers # # LSP Diagnostic method # # @return [Array] # def diagnose(source, _api_map) return [] if source.code.empty? || exclude_file?(source.location.filename) return [test_missing_error(source)] unless File.file?(test_file(source)) messages(source) rescue ChildFailedError [] end private def messages(source) messages = [ line_warnings(source), branch_warnings(source), test_passing_error(source) ] messages.flatten.compact end def line_warnings(source) uncovered_lines(results(source)).map { |line| line_coverage_warning(source, line) } end def branch_warnings(source) uncovered_branches(results(source)).map { |branch| branch_coverage_warning(source, branch.report) } end def test_passing_error(source) results(source)[:test_status] ? [] : [test_failing_error(source)] end # # Creates LSP warning message for missing line coverage # # @return [Hash] # def line_coverage_warning(source, line) return unless Config.line_coverage? { range: Solargraph::Range.from_to(line, 0, line, source.code.lines[line].length).to_hash, severity: Solargraph::Diagnostics::Severities::WARNING, source: 'TestCoverage', message: 'Line is missing test coverage' } end # # Creates LSP warning message for missing branch coverage # We need to correct the line number (-1), since the coverage module # starts counting lines at 1, while the LSP (source.code.line) is an array # with an index starting at 0 # # @return [Hash] # def branch_coverage_warning(source, report) return unless Config.branch_coverage? { range: Solargraph::Range.from_to(report[:line] - 1, 0, report[:line] - 1, source.code.lines[report[:line] - 1].length).to_hash, severity: Solargraph::Diagnostics::Severities::WARNING, source: 'TestCoverage', message: "'#{report[:type].upcase}' branch is missing test coverage" } end # # Creates LSP error message if test is failing # # @return [Hash] # def test_failing_error(source) return unless Config.test_failing_coverage? { range: Solargraph::Range.from_to(0, 0, 0, source.code.lines[0].length).to_hash, severity: Solargraph::Diagnostics::Severities::ERROR, source: 'TestCoverage', message: 'Unit Test is currently failing.' } end # # Creates LSP error message if no test file can be found # # @return [Hash] # def test_missing_error(source) return unless Config.test_missing_coverage? { range: Solargraph::Range.from_to(0, 0, 0, source.code.lines[0].length).to_hash, severity: Solargraph::Diagnostics::Severities::ERROR, source: 'TestCoverage', message: "No unit test file found at #{test_file(source)}" } end end end