ae_test_coverage 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/ae_test_coverage.rb +82 -0
- data/lib/ae_test_coverage/collectors/action_view/asset_tag_collector.rb +43 -0
- data/lib/ae_test_coverage/collectors/action_view/asset_tag_helper.rb +33 -0
- data/lib/ae_test_coverage/collectors/action_view/rendered_template_collector.rb +46 -0
- data/lib/ae_test_coverage/collectors/active_record/association_collector.rb +25 -0
- data/lib/ae_test_coverage/collectors/active_record/association_helper.rb +14 -0
- data/lib/ae_test_coverage/collectors/active_record/attribute_reader_collector.rb +25 -0
- data/lib/ae_test_coverage/collectors/active_record/attribute_reader_helper.rb +14 -0
- data/lib/ae_test_coverage/collectors/active_record/attribute_writer_collector.rb +25 -0
- data/lib/ae_test_coverage/collectors/active_record/attribute_writer_helper.rb +14 -0
- data/lib/ae_test_coverage/collectors/active_record/model_collector.rb +47 -0
- data/lib/ae_test_coverage/collectors/active_record/model_file_finder.rb +24 -0
- data/lib/ae_test_coverage/collectors/ruby_coverage_collector.rb +43 -0
- data/lib/ae_test_coverage/collectors/sprockets_asset_collector.rb +26 -0
- data/lib/ae_test_coverage/collectors/webpacker/helpers.rb +33 -0
- data/lib/ae_test_coverage/collectors/webpacker/webpacker_app_collector.rb +38 -0
- data/lib/ae_test_coverage/test_coverage_methods.rb +61 -0
- data/lib/ae_test_coverage/version.rb +5 -0
- metadata +143 -0
checksums.yaml
ADDED
@@ -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
|
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: []
|