loading
Generated 2023-10-08T17:25:37+00:00

All Files ( 100.0% covered at 32.17 hits/line )

5 files in total.
205 relevant lines, 205 lines covered and 0 lines missed. ( 100.0% )
0 total branches, 0 branches covered and 0 branches missed. ( 100.0% )
File % covered Lines Relevant Lines Lines covered Lines missed Avg. Hits / Line Branch Coverage Branches Covered branches Missed branches
lib/simplecov_small_badge.rb 100.00 % 27 10 10 0 2.40 100.00 % 0 0 0
lib/simplecov_small_badge/configuration.rb 100.00 % 55 15 15 0 132.80 100.00 % 0 0 0
lib/simplecov_small_badge/formatter.rb 100.00 % 75 40 40 0 68.75 100.00 % 0 0 0
spec/simplecov_small_badge_formatter_spec.rb 100.00 % 200 115 115 0 1.50 100.00 % 0 0 0
spec/support/mocks.rb 100.00 % 53 25 25 0 66.24 100.00 % 0 0 0

lib/simplecov_small_badge.rb

100.0% lines covered

100.0% branches covered

10 relevant lines. 10 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. # Ensure we are using a compatible version of SimpleCov
  3. skipped # :nocov:
  4. skipped if defined?(SimpleCov::VERSION) &&
  5. skipped Gem::Version.new(SimpleCov::VERSION) < Gem::Version.new('0.7.1')
  6. skipped raise 'The version of SimpleCov you are using is too old. '\
  7. skipped 'Please update with `gem install simplecov` or `bundle update simplecov`'
  8. skipped end
  9. skipped # :nocov:
  10. 1 require 'simplecov_small_badge/configuration'
  11. # :nodoc:
  12. 1 module SimpleCovSmallBadge
  13. 1 @configuration = Configuration.new
  14. 1 def self.configure
  15. 1 yield config
  16. end
  17. 1 def self.config
  18. 14 @configuration
  19. end
  20. end
  21. 1 $LOAD_PATH.unshift(File.join(File.dirname(__FILE__)))
  22. 1 require 'simplecov_small_badge/version'
  23. 1 require 'simplecov_small_badge/formatter'

lib/simplecov_small_badge/configuration.rb

100.0% lines covered

100.0% branches covered

15 relevant lines. 15 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module SimpleCovSmallBadge
  3. # Class to keep all the valid documentations that are required to build the
  4. # badge
  5. 1 class Configuration
  6. # Set up config variables.
  7. # rubocop:disable Metrics/MethodLength
  8. 1 def self.options
  9. {
  10. 48 with_groups: false,
  11. background: '#fff',
  12. title_prefix: 'scov',
  13. title_background: '#555',
  14. title_font: 'Verdana,sans-serif',
  15. font_size: 11,
  16. title_color: '#fff',
  17. coverage_background_bad: '#ff0000',
  18. coverage_background_unknown: '#cccc00',
  19. coverage_background_good: '#4dc71f',
  20. coverage_font: 'Verdana,sans-serif',
  21. coverage_font_color: '#fff',
  22. coverage_font_size: 11,
  23. badge_height: 20,
  24. badge_width: 120,
  25. filename_prefix: 'coverage_badge',
  26. output_path: SimpleCov.coverage_path,
  27. log_level: 'info',
  28. rounded_border: true,
  29. rounded_edge_radius: 3,
  30. percent_sign: '%'
  31. }
  32. end
  33. # rubocop:enable Metrics/MethodLength
  34. # set up class variables and getters/setters
  35. 1 options.each_key do |opt|
  36. 64 define_method(opt) { instance_variable_get "@#{opt}" }
  37. 504 define_method("#{opt}=") { |val| instance_variable_set("@#{opt}", val) }
  38. end
  39. 1 def initialize(**opts)
  40. 23 SimpleCovSmallBadge::Configuration
  41. 483 .options.merge(opts).each { |opt, v| send(:"#{opt}=", v) }
  42. end
  43. 1 def to_hash
  44. 36 hash = {}
  45. 36 instance_variables.each do |var|
  46. 756 hash[var.to_s.delete('@').to_sym] = instance_variable_get(var)
  47. end
  48. 36 hash
  49. end
  50. end
  51. end

lib/simplecov_small_badge/formatter.rb

100.0% lines covered

100.0% branches covered

40 relevant lines. 40 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'repo_small_badge/image'
  3. 1 require 'simplecov_small_badge/configuration'
  4. 1 module SimpleCovSmallBadge
  5. # Basic Badge Formater Class that creates the badges.
  6. 1 class Formatter
  7. 1 def initialize(output = nil)
  8. 13 @output = output || $stdout
  9. 13 @config = SimpleCovSmallBadge.config
  10. end
  11. 1 def format(result)
  12. 13 percent = result.source_files.covered_percent.round(0)
  13. 13 @image = RepoSmallBadge::Image.new(map_image_config(state(percent)))
  14. 13 badge('total', 'total', percent)
  15. 13 group_percent_from_result(result) do |name, title, cov_percent|
  16. 9 badge(name, title, cov_percent.round(0))
  17. end
  18. end
  19. 1 private
  20. 1 def badge(name, title, percent)
  21. 22 percent_txt = percent_text(percent)
  22. 22 @image.config_merge(map_image_config(state(percent)))
  23. 22 @image.badge(name, title, percent_txt)
  24. end
  25. 1 def percent_text(percent)
  26. 22 "#{percent}#{@config.percent_sign}"
  27. end
  28. 1 def state(covered_percent)
  29. 35 if line_coverage_minimum&.positive?
  30. 27 if covered_percent >= line_coverage_minimum
  31. 13 'good'
  32. else
  33. 14 'bad'
  34. end
  35. else
  36. 8 'unknown'
  37. end
  38. end
  39. 1 def line_coverage_minimum
  40. 62 minimums = SimpleCov.minimum_coverage
  41. 62 minimums[SimpleCov.primary_coverage]
  42. end
  43. 1 def map_image_config(state)
  44. 35 hash = {}
  45. 35 @config.to_hash.map do |key, value|
  46. 735 key = key
  47. .to_s.sub(/^coverage_background_#{state}/, 'value_background')
  48. .to_sym
  49. 735 key = key.to_s.sub(/^coverage_/, 'value_').to_sym
  50. 735 hash[key] = value
  51. end
  52. 35 hash
  53. end
  54. # converts the result to a hash consisting of the groupname
  55. # array of percentage (integer in percent), strength float
  56. # and the state [ 'good', 'bad', 'unknown' ]
  57. # consolidated for each group.
  58. 1 def group_percent_from_result(result)
  59. 13 result.groups.each do |name, files|
  60. 9 covered = files.covered_percent.round(0)
  61. 9 yield name, name, covered, covered
  62. end
  63. end
  64. end
  65. end

spec/simplecov_small_badge_formatter_spec.rb

100.0% lines covered

100.0% branches covered

115 relevant lines. 115 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'spec_helper'
  3. 1 describe SimpleCovSmallBadge::Formatter do
  4. 1 include TestSimpleCovSmallBadge::Mocks
  5. 1 describe '#format' do
  6. 1 context 'bad result' do
  7. 1 it do
  8. 1 allow(SimpleCov).to receive(:minimum_coverage).and_return(line: 90)
  9. 1 mock_repo_badge_image(cov: '50%', state: 'bad')
  10. 1 result = mock_result(50)
  11. 1 expect(subject.format(result)).to be_truthy
  12. end
  13. end
  14. 1 context 'good result' do
  15. 1 it do
  16. 1 allow(SimpleCov).to receive(:minimum_coverage).and_return(line: 100)
  17. 1 image_mock = mock_repo_badge_image(title: 'total', name: 'total',
  18. cov: '100%')
  19. 1 mock_repo_badge_image(title: 'library', name: 'library',
  20. cov: '100%', mock: image_mock)
  21. 1 result = mock_result(100, 'library' => mock_result_group(100))
  22. 1 expect(subject.format(result)).to be_truthy
  23. end
  24. 1 it do
  25. 1 allow(SimpleCov).to receive(:minimum_coverage).and_return(line: 90)
  26. 1 image_mock = mock_repo_badge_image(title: 'total', name: 'total',
  27. cov: '90%')
  28. 1 mock_repo_badge_image(title: 'library', name: 'library',
  29. cov: '90%', mock: image_mock)
  30. 1 result = mock_result(90, 'library' => mock_result_group(90))
  31. 1 expect(subject.format(result)).to be_truthy
  32. end
  33. end
  34. 1 context 'bad result' do
  35. 1 it do
  36. 1 allow(SimpleCov).to receive(:minimum_coverage).and_return(line: 91)
  37. 1 image_mock = mock_repo_badge_image(title: 'total', name: 'total',
  38. cov: '90%', state: 'bad')
  39. 1 mock_repo_badge_image(title: 'library', name: 'library',
  40. cov: '90%', state: 'bad', mock: image_mock)
  41. 1 result = mock_result(90, 'library' => mock_result_group(90))
  42. 1 expect(subject.format(result)).to be_truthy
  43. end
  44. end
  45. 1 context 'unknown result' do
  46. 1 it do
  47. 1 allow(SimpleCov).to receive(:minimum_coverage).and_return({})
  48. 1 image_mock = mock_repo_badge_image(title: 'total', name: 'total',
  49. cov: '90%', state: 'unknown')
  50. 1 mock_repo_badge_image(title: 'library', name: 'library',
  51. cov: '90%', state: 'unknown', mock: image_mock)
  52. 1 result = mock_result(90, 'library' => mock_result_group(90))
  53. 1 expect(subject.format(result)).to be_truthy
  54. end
  55. end
  56. 1 context 'mixed result' do
  57. 1 it do
  58. 1 allow(SimpleCov).to receive(:minimum_coverage).and_return(line: 90)
  59. 1 image_mock = mock_repo_badge_image(title: 'total', name: 'total',
  60. cov: '89%', state: 'bad')
  61. 1 mock_repo_badge_image(title: 'library', name: 'library',
  62. cov: '90%', state: 'good', mock: image_mock)
  63. 1 result = mock_result(89, 'library' => mock_result_group(90))
  64. 1 expect(subject.format(result)).to be_truthy
  65. end
  66. end
  67. 1 context 'with branch coverage' do
  68. 1 before do
  69. 7 SimpleCov.enable_coverage :branch
  70. 7 SimpleCov.primary_coverage :branch
  71. 7 allow(SimpleCov).to receive(:minimum_coverage)
  72. .and_return(minimum_coverage)
  73. end
  74. 1 after do
  75. 7 SimpleCov.clear_coverage_criteria
  76. 7 SimpleCov.enable_coverage :line
  77. 7 SimpleCov.primary_coverage :line
  78. end
  79. 1 context 'when coverage is lower than required' do
  80. 2 let(:minimum_coverage) { { branch: 90, line: 100 } }
  81. 2 let(:coverage) { 50 }
  82. 2 let(:expected_state) { 'bad' }
  83. 1 it 'is bad' do
  84. 1 mock_repo_badge_image(cov: "#{coverage}%", state: expected_state)
  85. 1 result = mock_result(coverage)
  86. 1 subject.format(result)
  87. end
  88. end
  89. 1 context 'when coverage is lower than required with groups' do
  90. 2 let(:minimum_coverage) { { branch: 91, line: 100 } }
  91. 2 let(:coverage) { 90 }
  92. 2 let(:expected_state) { 'bad' }
  93. 1 it 'is bad' do
  94. 1 image_mock = mock_repo_badge_image(title: 'total', name: 'total',
  95. cov: "#{coverage}%",
  96. state: expected_state)
  97. 1 mock_repo_badge_image(title: 'library', name: 'library',
  98. cov: "#{coverage}%", state: expected_state,
  99. mock: image_mock)
  100. 1 result = mock_result(coverage,
  101. 'library' => mock_result_group(coverage))
  102. 1 subject.format(result)
  103. end
  104. end
  105. 1 context 'when coverage is greater than or equal to that required' do
  106. 2 let(:minimum_coverage) { { branch: 100, line: 10 } }
  107. 2 let(:coverage) { 100 }
  108. 2 let(:expected_state) { 'good' }
  109. 1 it 'is good' do
  110. 1 mock_repo_badge_image(cov: '100%', state: expected_state)
  111. 1 result = mock_result(coverage)
  112. 1 subject.format(result)
  113. end
  114. end
  115. 1 context 'when coverage is greater than or equal to that required with groups' do
  116. 2 let(:minimum_coverage) { { branch: 100, line: 10 } }
  117. 2 let(:coverage) { 100 }
  118. 1 let(:expected_state) { 'good' }
  119. 1 it 'is good' do
  120. 1 image_mock = mock_repo_badge_image(title: 'total', name: 'total',
  121. cov: "#{coverage}%")
  122. 1 mock_repo_badge_image(title: 'library', name: 'library',
  123. cov: "#{coverage}%", mock: image_mock)
  124. 1 result = mock_result(coverage, 'library' => mock_result_group(coverage))
  125. 1 subject.format(result)
  126. end
  127. end
  128. 1 context 'when minimum coverage is not set' do
  129. 2 let(:minimum_coverage) { {} }
  130. 2 let(:coverage) { 90 }
  131. 2 let(:expected_state) { 'unknown' }
  132. 1 it 'is unknown' do
  133. 1 mock_repo_badge_image(cov: "#{coverage}%",
  134. state: expected_state)
  135. 1 result = mock_result(coverage)
  136. 1 expect(subject.format(result)).to be_truthy
  137. end
  138. end
  139. 1 context 'when minimum coverage is not set with groups' do
  140. 2 let(:minimum_coverage) { {} }
  141. 2 let(:coverage) { 90 }
  142. 2 let(:expected_state) { 'unknown' }
  143. 1 it 'is unknown' do
  144. 1 image_mock = mock_repo_badge_image(title: 'total', name: 'total',
  145. cov: "#{coverage}%",
  146. state: expected_state)
  147. 1 mock_repo_badge_image(title: 'library', name: 'library',
  148. cov: "#{coverage}%", state: expected_state,
  149. mock: image_mock)
  150. 1 result = mock_result(coverage,
  151. 'library' => mock_result_group(coverage))
  152. 1 expect(subject.format(result)).to be_truthy
  153. end
  154. end
  155. 1 context 'when global coverage is lower but group coverage is as required' do
  156. 2 let(:minimum_coverage) { { branch: 90, line: 10 } }
  157. 2 let(:global_coverage) { 89 }
  158. 2 let(:group_coverage) { 90 }
  159. 2 let(:global_state) { 'bad' }
  160. 2 let(:group_state) { 'good' }
  161. 1 it 'is mixed' do
  162. 1 image_mock = mock_repo_badge_image(title: 'total', name: 'total',
  163. cov: "#{global_coverage}%",
  164. state: global_state)
  165. 1 mock_repo_badge_image(title: 'library', name: 'library',
  166. cov: "#{group_coverage}%",
  167. state: group_state,
  168. mock: image_mock)
  169. 1 result = mock_result(global_coverage,
  170. 'library' => mock_result_group(group_coverage))
  171. 1 subject.format(result)
  172. end
  173. end
  174. end
  175. end
  176. end

spec/support/mocks.rb

100.0% lines covered

100.0% branches covered

25 relevant lines. 25 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module TestSimpleCovSmallBadge
  3. 1 module Mocks
  4. # rubocop:disable Metrics/ParameterLists
  5. 1 def mock_repo_badge_image(cov: 100, name: 'total',
  6. title: 'total',
  7. state: 'good',
  8. config: {},
  9. mock: instance_double('Image'))
  10. 22 config = map_config_options(config, state)
  11. 22 allow(RepoSmallBadge::Image).to receive(:new)
  12. .with(config).and_return(mock)
  13. 22 allow(mock).to receive(:config_merge).with(config).and_return(config)
  14. 22 allow(mock).to receive(:badge).with(name, title, cov)
  15. 22 mock
  16. end
  17. # rubocop:enable Metrics/ParameterLists
  18. 1 def map_config_options(config_hash, state)
  19. 22 hash = {}
  20. 22 SimpleCovSmallBadge::Configuration.options.merge(config_hash)
  21. .map do |key, value|
  22. 462 key = key.to_s
  23. .sub(/^coverage_background_#{state}/, 'value_background')
  24. .to_sym
  25. 462 key = key.to_s.sub(/^coverage_/, 'value_').to_sym
  26. 462 hash[key] = value
  27. end
  28. 22 hash
  29. end
  30. 1 def mock_result(total_cov, groups_hash = {})
  31. 13 result_double = instance_double('Result')
  32. 13 allow(result_double)
  33. .to receive_message_chain('source_files.covered_percent')
  34. .and_return(total_cov)
  35. 13 allow(result_double).to receive('groups').and_return(groups_hash)
  36. 13 result_double
  37. end
  38. 1 def mock_result_group(cov, strength = 1)
  39. 9 group_double = instance_double('Group')
  40. 9 allow(group_double)
  41. .to receive('covered_percent')
  42. .and_return(cov)
  43. 9 allow(group_double)
  44. .to receive('covered_strength')
  45. .and_return(strength)
  46. 9 group_double
  47. end
  48. end
  49. end