ae_test_coverage 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 50dbd85d09d8e913781ba926e51d4a2f2c0b067cd1adda6d70a68971ef9efff0
4
+ data.tar.gz: 71a897c4163320ed8a7ad8be672cfedbde65d2d1b876e8cbf5f10145248d21da
5
+ SHA512:
6
+ metadata.gz: 6591eb80941f55aa63028c3be3a6f4c870a64760425811bc7b819350921d70f8dc442307c3245a3b695589188f057e8d70467ba4357d2989e022527f1642be5c
7
+ data.tar.gz: '0996828626e12f9a29a4b87cc3c51aab3ae1b02bffcf9ac452f87da3d407cb12fe1a1db6c1bf13d663436294de38d6d057538b404de1034e0d41096a85d36ac3'
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails/railtie'
4
+ require 'active_record'
5
+
6
+ require 'ae_test_coverage/version'
7
+ require 'ae_test_coverage/test_coverage_methods'
8
+
9
+ require 'ae_test_coverage/collectors/ruby_coverage_collector'
10
+ require 'ae_test_coverage/collectors/active_record/association_collector'
11
+ require 'ae_test_coverage/collectors/active_record/attribute_reader_collector'
12
+ require 'ae_test_coverage/collectors/active_record/attribute_writer_collector'
13
+ require 'ae_test_coverage/collectors/action_view/asset_tag_collector'
14
+ require 'ae_test_coverage/collectors/action_view/rendered_template_collector'
15
+ require 'ae_test_coverage/collectors/webpacker/webpacker_app_collector'
16
+ require 'ae_test_coverage/collectors/sprockets_asset_collector'
17
+
18
+ module AeTestCoverage
19
+ class Config
20
+ attr_accessor :enabled_collector_classes
21
+ attr_accessor :webpacker_app_locations
22
+ attr_accessor :file_exclusion_check
23
+ attr_accessor :enable_check
24
+ attr_accessor :coverage_path
25
+ attr_accessor :sprockets_asset_collector_class
26
+
27
+ def initialize
28
+ @enabled_collector_classes = [
29
+ AeTestCoverage::Collectors::RubyCoverageCollector,
30
+ AeTestCoverage::Collectors::ActiveRecord::AssociationCollector,
31
+ AeTestCoverage::Collectors::ActiveRecord::AttributeWriterCollector,
32
+ AeTestCoverage::Collectors::ActiveRecord::AttributeReaderCollector,
33
+ AeTestCoverage::Collectors::ActionView::RenderedTemplateCollector,
34
+ AeTestCoverage::Collectors::ActionView::AssetTagCollector,
35
+ AeTestCoverage::Collectors::Webpacker::WebpackerAppCollector
36
+ ]
37
+ @webpacker_app_locations = []
38
+ @file_exclusion_check = Proc.new { |file| false }
39
+ @enable_check = Proc.new { false }
40
+ @coverage_path = './coverage'
41
+ @sprockets_asset_collector_class = AeTestCoverage::Collectors::SprocketsAssetCollector
42
+ end
43
+ end
44
+
45
+ class << self
46
+ attr_accessor :single_test_coverage_enabled, :coverage_collectors
47
+
48
+ def configure
49
+ @config ||= Config.new
50
+ yield @config
51
+ end
52
+
53
+ def config
54
+ @config ||= Config.new
55
+ end
56
+
57
+ def initialize_collectors
58
+ if enabled?
59
+ @coverage_collectors = {}
60
+ config.enabled_collector_classes.each do |coverage_collector_class|
61
+ coverage_collectors[coverage_collector_class] = coverage_collector_class.new
62
+ end
63
+ end
64
+ end
65
+
66
+ def start_coverage
67
+ if self.enabled?
68
+ coverage_collectors.values.each do |coverage_collector|
69
+ coverage_collector.on_start
70
+ end
71
+ end
72
+ end
73
+
74
+ def exclude_file?(file)
75
+ AeTestCoverage.config.file_exclusion_check.call(file)
76
+ end
77
+
78
+ def enabled?
79
+ AeTestCoverage.config.enable_check.call
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ae_test_coverage/collectors/action_view/asset_tag_helper'
4
+
5
+ module AeTestCoverage
6
+ module Collectors
7
+ module ActionView
8
+ class AssetTagCollector
9
+ @@action_view_hook_set = false
10
+
11
+ def initialize
12
+ unless @@action_view_hook_set
13
+ ActiveSupport.on_load(:action_view) do
14
+ prepend AeTestCoverage::Collectors::ActionView::AssetTagHelper
15
+ end
16
+ @@action_view_hook_set = true
17
+ end
18
+ end
19
+
20
+ def on_start
21
+ @covered_assets_collection = Set.new
22
+ end
23
+
24
+ def add_covered_assets(*assets)
25
+ @covered_assets_collection&.merge(assets)
26
+ end
27
+
28
+ def covered_files
29
+ test_assets = Set.new(
30
+ @covered_assets_collection.flat_map do |asset_path|
31
+ AeTestCoverage.config.sprockets_asset_collector_class.new(asset_path).collect
32
+ end
33
+ )
34
+ {}.tap do |coverage_data|
35
+ test_assets.to_a.map do |asset_uri|
36
+ coverage_data[URI.parse(asset_uri).path] = {asset: true}
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AeTestCoverage
4
+ module Collectors
5
+ module ActionView
6
+ module AssetTagHelper
7
+ def javascript_include_tag(*sources)
8
+ AeTestCoverage.coverage_collectors[AssetTagCollector].add_covered_assets(*js_sources(sources))
9
+ super
10
+ end
11
+
12
+ def stylesheet_link_tag(*sources)
13
+ AeTestCoverage.coverage_collectors[AssetTagCollector].add_covered_assets(*css_sources(sources))
14
+ super
15
+ end
16
+
17
+ private
18
+
19
+ def sources_without_options(sources)
20
+ sources.last.is_a?(Hash) ? sources[0...-1] : sources
21
+ end
22
+
23
+ def js_sources(sources)
24
+ sources_without_options(sources).map { |source| "#{source}.js" }
25
+ end
26
+
27
+ def css_sources(sources)
28
+ sources_without_options(sources).map { |source| "#{source}.css" }
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AeTestCoverage
4
+ module Collectors
5
+ module ActionView
6
+ class RenderedTemplateCollector
7
+ class << self
8
+ attr_reader :subscriber
9
+
10
+ def subscribe(collector)
11
+ @subscriber = ActiveSupport::Notifications.subscribe('!render_template.action_view') do |_name, _start, _finish, _id, payload|
12
+ collector.add_covered_templates(payload[:identifier])
13
+ end
14
+ end
15
+
16
+ def unsubscribe
17
+ if @subscriber
18
+ ActiveSupport::Notifications.unsubscribe(@subscriber)
19
+ @subscriber = nil
20
+ end
21
+ end
22
+ end
23
+
24
+ def initialize
25
+ RenderedTemplateCollector.subscribe(self) unless RenderedTemplateCollector.subscriber.present?
26
+ end
27
+
28
+ def on_start
29
+ @covered_templates_collection = Set.new
30
+ end
31
+
32
+ def add_covered_templates(*tempates)
33
+ @covered_templates_collection&.merge(tempates)
34
+ end
35
+
36
+ def covered_files
37
+ {}.tap do |coverage_data|
38
+ @covered_templates_collection.map do |template_file|
39
+ coverage_data[template_file] = {template: true}
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ae_test_coverage/collectors/active_record/model_collector'
4
+ require 'ae_test_coverage/collectors/active_record/association_helper'
5
+
6
+ module AeTestCoverage
7
+ module Collectors
8
+ module ActiveRecord
9
+ class AssociationCollector < ModelCollector
10
+
11
+ private
12
+
13
+ def set_hook
14
+ ActiveSupport.on_load(:active_record) do
15
+ include AssociationHelper
16
+ end
17
+ end
18
+
19
+ def data
20
+ {association_referenced: true}
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AeTestCoverage
4
+ module Collectors
5
+ module ActiveRecord
6
+ module AssociationHelper
7
+ def association(name)
8
+ AeTestCoverage.coverage_collectors[AssociationCollector].add_covered_models(self.class)
9
+ super
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ae_test_coverage/collectors/active_record/model_collector'
4
+ require 'ae_test_coverage/collectors/active_record/attribute_reader_helper'
5
+
6
+ module AeTestCoverage
7
+ module Collectors
8
+ module ActiveRecord
9
+ class AttributeReaderCollector < ModelCollector
10
+
11
+ private
12
+
13
+ def set_hook
14
+ ActiveSupport.on_load(:active_record) do
15
+ include AttributeReaderHelper
16
+ end
17
+ end
18
+
19
+ def data
20
+ {attribute_referenced: true}
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AeTestCoverage
4
+ module Collectors
5
+ module ActiveRecord
6
+ module AttributeReaderHelper
7
+ def _read_attribute(attr_name)
8
+ AeTestCoverage.coverage_collectors[AttributeReaderCollector].add_covered_models(self.class)
9
+ super
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ae_test_coverage/collectors/active_record/model_collector'
4
+ require 'ae_test_coverage/collectors/active_record/attribute_writer_helper'
5
+
6
+ module AeTestCoverage
7
+ module Collectors
8
+ module ActiveRecord
9
+ class AttributeWriterCollector < ModelCollector
10
+
11
+ private
12
+
13
+ def set_hook
14
+ ActiveSupport.on_load(:active_record) do
15
+ include AttributeWriterHelper
16
+ end
17
+ end
18
+
19
+ def data
20
+ {attribute_written: true}
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AeTestCoverage
4
+ module Collectors
5
+ module ActiveRecord
6
+ module AttributeWriterHelper
7
+ def _write_attribute(attr_name, value)
8
+ AeTestCoverage.coverage_collectors[AttributeWriterCollector].add_covered_models(self.class)
9
+ super
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ae_test_coverage/collectors/active_record/model_file_finder'
4
+
5
+ module AeTestCoverage
6
+ module Collectors
7
+ module ActiveRecord
8
+ class ModelCollector
9
+
10
+ def initialize
11
+ set_hook
12
+ end
13
+
14
+ def on_start
15
+ @covered_model_collection = Set.new
16
+ end
17
+
18
+ def add_covered_models(*models)
19
+ @covered_model_collection&.merge(models)
20
+ end
21
+
22
+ def covered_files
23
+ {}.tap do |coverage_data|
24
+ @covered_model_collection.each do |model|
25
+ file = ModelFileFinder.new.file_path(model)
26
+ coverage_data[file] = data
27
+ end
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def set_hook
34
+ raise 'Not Implemented'
35
+ ActiveSupport.on_load(:active_record) do
36
+ raise "helper_module is not defined" unless @@helper_module.present?
37
+ include @@helper_module
38
+ end
39
+ end
40
+
41
+ def data
42
+ nil
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AeTestCoverage
4
+ module Collectors
5
+ module ActiveRecord
6
+ class ModelFileFinder
7
+ def file_path(model)
8
+ Rails.application.config.paths['app/models'].each do |model_root|
9
+ path = Rails.root.join(model_root, "#{model.name.underscore}.rb").to_s
10
+ return path if File.exist?(path)
11
+ end
12
+ Rails::Engine.subclasses.each do |engine|
13
+ engine.paths['app/models'].each do |model_root|
14
+ path = engine.root.join(model_root, "#{model.name.underscore}.rb").to_s
15
+ return path if File.exist?(path)
16
+ end
17
+ end
18
+
19
+ nil
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AeTestCoverage
4
+ module Collectors
5
+ class RubyCoverageCollector
6
+ @@initialized = false
7
+
8
+ def initialize
9
+ unless @@initialized
10
+ require 'coverage'
11
+ Coverage.start(oneshot_lines: true, methods: true)
12
+ @@initialized = true
13
+ end
14
+ end
15
+
16
+ def on_start
17
+ Coverage.result(clear: true)
18
+ end
19
+
20
+ def covered_files
21
+ coverage = Coverage.result(clear: true)
22
+ {}.tap do |coverage_data|
23
+ coverage.each do |file, data|
24
+ next if AeTestCoverage.exclude_file?(file)
25
+
26
+ called_methods = data[:methods].select { |_, call_count| call_count > 0 }
27
+ oneshot_lines = reject_oneshot_lines_from_methods(called_methods, data[:oneshot_lines])
28
+ coverage_data[file] = {methods: called_methods, oneshot_lines: oneshot_lines} unless called_methods.empty? && oneshot_lines.empty?
29
+ end
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def reject_oneshot_lines_from_methods(methods, oneshot_lines)
36
+ return [] if oneshot_lines.blank?
37
+
38
+ ranges_covered_by_called_methods = methods.keys.map { |method_data| method_data[2]..method_data[4] }
39
+ oneshot_lines.reject { |line| ranges_covered_by_called_methods.any? { |range| range.include?(line) } }
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AeTestCoverage
4
+ module Collectors
5
+ class SprocketsAssetCollector
6
+ def initialize(asset_path)
7
+ @asset_path = asset_path
8
+ end
9
+
10
+ def collect
11
+ asset = ::Rails.application.assets[@asset_path]
12
+ # It's not clear why an asset would not be found in the cache. It happens but it seems to happen rarely and repeatably
13
+ # If there is a bug with assets changes not triggering a test to run, look here to see if the asset was not included
14
+ # as a dependency because it was not found in the cache
15
+
16
+ if asset.nil?
17
+ puts "Skipping asset #{@asset_path} because it was not found in the cache"
18
+ []
19
+ else
20
+ asset.metadata[:dependencies].select { |d| d.ends_with?('.js', '.es6', '.css', '.scss') }
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AeTestCoverage
4
+ module Collectors
5
+ module Webpacker
6
+ module Helpers
7
+ def javascript_packs_with_chunks_tag(*names, **options)
8
+ raise(StandardError, 'AeTestCoverage.config.webpacker_app_locations must be set to collect webpacker app coverage') if AeTestCoverage.config.webpacker_app_locations.blank?
9
+
10
+ globs = names.flat_map do |name|
11
+ app_home = javascript_app_home(name)
12
+ raise(StandardError, "Unable to locate source location for javascript app #{name}") unless Dir.exist?(app_home)
13
+
14
+ [
15
+ File.join(app_home, 'src', '**.{scss,css,js}'),
16
+ File.join(app_home, 'package*.json')
17
+ ]
18
+ end
19
+ AeTestCoverage.coverage_collectors[WebpackerAppCollector].add_covered_globs(*globs)
20
+ super
21
+ end
22
+
23
+ def javascript_app_home(name)
24
+ AeTestCoverage.config.webpacker_app_locations.map do |potential_app_root|
25
+ File.join(potential_app_root, name)
26
+ end.detect do |potential_app_home|
27
+ Dir.exist?(potential_app_home)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ae_test_coverage/collectors/webpacker/helpers'
4
+
5
+ module AeTestCoverage
6
+ module Collectors
7
+ module Webpacker
8
+ class WebpackerAppCollector
9
+ @@hook_set = false
10
+
11
+ def initialize
12
+ unless @@hook_set
13
+ ActiveSupport.on_load(:action_view) do
14
+ prepend AeTestCoverage::Collectors::Webpacker::Helpers
15
+ end
16
+ end
17
+ @@hook_set = true
18
+ end
19
+
20
+ def on_start
21
+ @covered_globs = Set.new
22
+ end
23
+
24
+ def add_covered_globs(*globs)
25
+ @covered_globs&.merge(globs)
26
+ end
27
+
28
+ def covered_files
29
+ {}.tap do |coverage_data|
30
+ @covered_globs.each do |glob_pattern|
31
+ coverage_data[glob_pattern] = { glob: true }
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AeTestCoverage
4
+ module TestCoverageMethods
5
+ def start_recording_code_coverage
6
+ if AeTestCoverage.enabled?
7
+ AeTestCoverage.coverage_collectors.each do |coverage_collector_class, coverage_collector|
8
+ coverage_collector.on_start
9
+ end
10
+ end
11
+ end
12
+
13
+ def write_code_coverage_artifact
14
+ if AeTestCoverage.enabled?
15
+ cleanup_stubs
16
+ test_filename = method(name_of_test).source_location[0]
17
+ FileUtils.mkdir_p(coverage_path)
18
+ f = File.open(coverage_file_name, 'w')
19
+ cleaned_coverage = {}.tap do |cleaned|
20
+ AeTestCoverage.coverage_collectors.values.each do |coverage_collector|
21
+ coverage_collector.covered_files.each do |covered_file, coverage_data|
22
+ next if AeTestCoverage.exclude_file?(covered_file)
23
+ cleaned[covered_file] ||= {}
24
+ cleaned[covered_file][coverage_collector.class.name] = coverage_data
25
+ end
26
+ end
27
+ end
28
+ coverage_file_data = {
29
+ filename: test_filename,
30
+ coverage: cleaned_coverage
31
+ }
32
+ f.write(coverage_file_data.to_json)
33
+ f.close
34
+ end
35
+ end
36
+
37
+ def name_of_test
38
+ method_name
39
+ end
40
+
41
+ def coverage_path
42
+ AeTestCoverage.config.coverage_path
43
+ end
44
+
45
+ def coverage_file_name
46
+ basename = "#{self.class.name}__#{name_of_test}.json".tr(' /', '__')
47
+ max_filename_length = 255
48
+ basename = trim_front(basename, max_filename_length - coverage_path.length)
49
+ File.join(coverage_path, basename)
50
+ end
51
+
52
+ def trim_front(str, max_length)
53
+ str.length > max_length ? str[-max_length...] : str
54
+ end
55
+
56
+ def cleanup_stubs
57
+ File.unstub(:open)
58
+ File.unstub(:directory?)
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AeTestCoverage
4
+ VERSION = '1.1.0'
5
+ end
metadata ADDED
@@ -0,0 +1,143 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ae_test_coverage
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Appfolio
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-08-31 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: railties
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "<"
18
+ - !ruby/object:Gem::Version
19
+ version: '7'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "<"
25
+ - !ruby/object:Gem::Version
26
+ version: '7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activerecord
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "<"
32
+ - !ruby/object:Gem::Version
33
+ version: '7'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "<"
39
+ - !ruby/object:Gem::Version
40
+ version: '7'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.15'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.15'
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '5.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '5.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '10.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '10.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: simplecov
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: Tools for collecting code coverage from tests
98
+ email:
99
+ executables: []
100
+ extensions: []
101
+ extra_rdoc_files: []
102
+ files:
103
+ - lib/ae_test_coverage.rb
104
+ - lib/ae_test_coverage/collectors/action_view/asset_tag_collector.rb
105
+ - lib/ae_test_coverage/collectors/action_view/asset_tag_helper.rb
106
+ - lib/ae_test_coverage/collectors/action_view/rendered_template_collector.rb
107
+ - lib/ae_test_coverage/collectors/active_record/association_collector.rb
108
+ - lib/ae_test_coverage/collectors/active_record/association_helper.rb
109
+ - lib/ae_test_coverage/collectors/active_record/attribute_reader_collector.rb
110
+ - lib/ae_test_coverage/collectors/active_record/attribute_reader_helper.rb
111
+ - lib/ae_test_coverage/collectors/active_record/attribute_writer_collector.rb
112
+ - lib/ae_test_coverage/collectors/active_record/attribute_writer_helper.rb
113
+ - lib/ae_test_coverage/collectors/active_record/model_collector.rb
114
+ - lib/ae_test_coverage/collectors/active_record/model_file_finder.rb
115
+ - lib/ae_test_coverage/collectors/ruby_coverage_collector.rb
116
+ - lib/ae_test_coverage/collectors/sprockets_asset_collector.rb
117
+ - lib/ae_test_coverage/collectors/webpacker/helpers.rb
118
+ - lib/ae_test_coverage/collectors/webpacker/webpacker_app_collector.rb
119
+ - lib/ae_test_coverage/test_coverage_methods.rb
120
+ - lib/ae_test_coverage/version.rb
121
+ homepage:
122
+ licenses: []
123
+ metadata: {}
124
+ post_install_message:
125
+ rdoc_options: []
126
+ require_paths:
127
+ - lib
128
+ required_ruby_version: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ required_rubygems_version: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ requirements: []
139
+ rubygems_version: 3.1.4
140
+ signing_key:
141
+ specification_version: 4
142
+ summary: Tools for collecting code coverage from tests
143
+ test_files: []