ae_test_coverage 1.1.0
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 +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: []
|