mutant 0.11.16 → 0.11.17

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ebfdb4dba80abb7c2b06b6b057cebf6db686b598219979ed3d0730b6e5a9ed82
4
- data.tar.gz: ee03173b094cf29a9d21ad30b383a0b01b8cac7b7ba1132f24f36c25e9e4fee3
3
+ metadata.gz: 32bc27a55a33df968de61bde922b6318d158bf5f3ab0d3676720e2ba8e9ac2db
4
+ data.tar.gz: 20a7a9db2b3a034d9579bca78bfcca98d3e25117937407696bad239263c3b402
5
5
  SHA512:
6
- metadata.gz: 90d9c06d5a2900441b49b3bc0fa039b11bb296e389af41927f711431855a28369a8e31faf0b1cc5ba74ab09c6300c21002ac30c0d6eae6b3d63eac3129a692e8
7
- data.tar.gz: 725ecfb369b3c28133d898f3405bb5cec8f780027c8e7c05de59c225719924fde51e192186d2f7a2199a57352b056401fa562a67d75409a637d182bbb50d9390
6
+ metadata.gz: 4297d6e5172b74dc1e776739c68a5980cbda44581e38b06f76ed2ee395b816b2d664e146b98ac8c9a5f25e31e2b6078016398db862d0b96675299fbc3bc2cc49
7
+ data.tar.gz: f899277fb892b69bfac0b988e84fb9955036ea415cf2c55fecb90976bc3cdd9dd249d5bac1c154039df3c8af37db04b2d2d0c97003eac01c539371a7c9804d41
data/bin/mutant CHANGED
@@ -1,55 +1,64 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- trap('INT') do |status|
5
- effective_status = status ? status + 128 : 128
6
- exit! effective_status
7
- end
4
+ module Mutant
5
+ # Record executable timestamp
6
+ @executable_timestamp = Process.clock_gettime(Process::CLOCK_MONOTONIC)
7
+
8
+ trap('INT') do |status|
9
+ effective_status = status ? status + 128 : 128
10
+ exit! effective_status
11
+ end
8
12
 
9
- require 'mutant'
13
+ require 'mutant'
10
14
 
11
- Mutant::CLI.parse(
12
- arguments: ARGV,
13
- world: Mutant::WORLD
14
- ).either(
15
- ->(message) { Mutant::WORLD.stderr.puts(message); Kernel.exit(false) },
16
- # rubocop:disable Metrics/BlockLength
17
- lambda do |command|
18
- status =
15
+ WORLD.record(:cli_parse) do
16
+ CLI.parse(
17
+ arguments: ARGV,
18
+ world: Mutant::WORLD
19
+ )
20
+ end.either(
21
+ ->(message) { Mutant::WORLD.stderr.puts(message); Kernel.exit(false) },
22
+ # rubocop:disable Metrics/BlockLength
23
+ lambda do |command|
19
24
  if command.zombie?
20
- $stderr.puts('Running mutant zombified!')
21
- Mutant::Zombifier.call(
22
- namespace: :Zombie,
23
- load_path: $LOAD_PATH,
24
- kernel: Kernel,
25
- pathname: Pathname,
26
- require_highjack: Mutant::RequireHighjack
27
- .public_method(:call)
28
- .to_proc
29
- .curry
30
- .call(Kernel),
31
- root_require: 'mutant',
32
- includes: %w[
33
- adamantium
34
- anima
35
- concord
36
- equalizer
37
- mprelude
38
- mutant
39
- unparser
40
- variable
41
- ]
42
- )
25
+ command = WORLD.record(:zombify) do
26
+ $stderr.puts('Running mutant zombified!')
27
+ Zombifier.call(
28
+ namespace: :Zombie,
29
+ load_path: $LOAD_PATH,
30
+ kernel: Kernel,
31
+ pathname: Pathname,
32
+ require_highjack: RequireHighjack
33
+ .public_method(:call)
34
+ .to_proc
35
+ .curry
36
+ .call(Kernel),
37
+ root_require: 'mutant',
38
+ includes: %w[
39
+ adamantium
40
+ anima
41
+ concord
42
+ equalizer
43
+ mprelude
44
+ mutant
45
+ unparser
46
+ variable
47
+ ]
48
+ )
43
49
 
44
- Zombie::Mutant::CLI.parse(
45
- arguments: ARGV,
46
- world: Zombie::Mutant::WORLD
47
- ).from_right.call
48
- else
49
- command.call
50
+ Zombie::Mutant::CLI.parse(
51
+ arguments: ARGV,
52
+ world: Mutant::WORLD
53
+ ).from_right
54
+ end
50
55
  end
51
56
 
52
- Kernel.exit(status)
53
- end
54
- # rubocop:enable Metrics/BlockLength
55
- )
57
+ WORLD.record(:execute) { command.call }.tap do |status|
58
+ WORLD.recorder.print_profile(WORLD.stderr) if command.print_profile?
59
+ WORLD.kernel.exit(status)
60
+ end
61
+ end
62
+ # rubocop:enable Metrics/BlockLength
63
+ )
64
+ end
@@ -7,6 +7,8 @@ module Mutant
7
7
  # the impure world to produce an environment.
8
8
  #
9
9
  # env = config interpreted against the world
10
+ #
11
+ # rubocop:disable Metrics/ModuleLength
10
12
  module Bootstrap
11
13
  include Adamantium, Anima.new(:config, :parser, :world)
12
14
 
@@ -30,66 +32,94 @@ module Mutant
30
32
  #
31
33
  # rubocop:disable Metrics/MethodLength
32
34
  def self.call(env)
33
- env = load_hooks(env)
34
- .tap(&method(:infect))
35
- .with(matchable_scopes: matchable_scopes(env))
36
-
37
- subjects = start_subject(env, Matcher.from_config(env.config.matcher).call(env))
38
-
39
- Integration.setup(env).fmap do |integration|
40
- env.with(
41
- integration: integration,
42
- mutations: subjects.flat_map(&:mutations),
43
- selector: Selector::Expression.new(integration),
44
- subjects: subjects
45
- )
35
+ env.record(:bootstrap) do
36
+ env = load_hooks(env)
37
+ .tap(&method(:infect))
38
+ .with(matchable_scopes: matchable_scopes(env))
39
+
40
+ matched_subjects = env.record(:subject_match) do
41
+ Matcher.from_config(env.config.matcher).call(env)
42
+ end
43
+
44
+ selected_subjects = subject_select(env, matched_subjects)
45
+
46
+ mutations = env.record(:mutation_generate) do
47
+ selected_subjects.flat_map(&:mutations)
48
+ end
49
+
50
+ Integration.setup(env).fmap do |integration|
51
+ env.with(
52
+ integration: integration,
53
+ mutations: mutations,
54
+ selector: Selector::Expression.new(integration),
55
+ subjects: selected_subjects
56
+ )
57
+ end
46
58
  end
47
59
  end
48
60
  # rubocop:enable Metrics/MethodLength
49
61
 
50
62
  def self.load_hooks(env)
51
- env.with(hooks: Hooks.load_config(env.config))
63
+ env.record(__method__) do
64
+ env.with(hooks: Hooks.load_config(env.config))
65
+ end
52
66
  end
53
67
  private_class_method :load_hooks
54
68
 
55
- def self.start_subject(env, subjects)
56
- start_expressions = env.config.matcher.start_expressions
69
+ def self.subject_select(env, subjects)
70
+ env.record(__method__) do
71
+ start_expressions = env.config.matcher.start_expressions
57
72
 
58
- return subjects if start_expressions.empty?
73
+ return subjects if start_expressions.empty?
59
74
 
60
- subjects.drop_while do |subject|
61
- start_expressions.none? do |expression|
62
- expression.prefix?(subject.expression)
75
+ subjects.drop_while do |subject|
76
+ start_expressions.none? do |expression|
77
+ expression.prefix?(subject.expression)
78
+ end
63
79
  end
64
80
  end
65
81
  end
66
- private_class_method :start_subject
82
+ private_class_method :subject_select
67
83
 
84
+ # rubocop:disable Metrics/AbcSize
85
+ # rubocop:disable Metrics/MethodLength
68
86
  def self.infect(env)
69
- config, hooks, world = env.config, env.hooks, env.world
87
+ env.record(__method__) do
88
+ config, hooks, world = env.config, env.hooks, env.world
70
89
 
71
- hooks.run(:env_infection_pre, env)
90
+ env.record(:hooks_env_infection_pre) do
91
+ hooks.run(:env_infection_pre, env)
92
+ end
72
93
 
73
- config.environment_variables.each do |key, value|
74
- world.environment_variables[key] = value
75
- end
94
+ env.record(:require_target) do
95
+ config.environment_variables.each do |key, value|
96
+ world.environment_variables[key] = value
97
+ end
76
98
 
77
- config.includes.each(&world.load_path.public_method(:<<))
78
- config.requires.each(&world.kernel.public_method(:require))
99
+ config.includes.each(&world.load_path.public_method(:<<))
100
+ config.requires.each(&world.kernel.public_method(:require))
101
+ end
79
102
 
80
- hooks.run(:env_infection_post, env)
103
+ env.record(:hooks_env_infection_post) do
104
+ hooks.run(:env_infection_post, env)
105
+ end
106
+ end
81
107
  end
82
108
  private_class_method :infect
109
+ # rubocop:enable Metrics/AbcSize
110
+ # rubocop:enable Metrics/MethodLength
83
111
 
84
112
  def self.matchable_scopes(env)
85
- config = env.config
113
+ env.record(__method__) do
114
+ config = env.config
86
115
 
87
- scopes = env.world.object_space.each_object(Module).each_with_object([]) do |scope, aggregate|
88
- expression = expression(config.reporter, config.expression_parser, scope) || next
89
- aggregate << Scope.new(scope, expression)
90
- end
116
+ scopes = env.world.object_space.each_object(Module).each_with_object([]) do |scope, aggregate|
117
+ expression = expression(config.reporter, config.expression_parser, scope) || next
118
+ aggregate << Scope.new(scope, expression)
119
+ end
91
120
 
92
- scopes.sort_by { |scope| scope.expression.syntax }
121
+ scopes.sort_by { |scope| scope.expression.syntax }
122
+ end
93
123
  end
94
124
  private_class_method :matchable_scopes
95
125
 
@@ -132,4 +162,5 @@ module Mutant
132
162
  end
133
163
  private_class_method :semantics_warning
134
164
  end # Bootstrap
165
+ # rubocop:enable Metrics/ModuleLength
135
166
  end # Mutant
@@ -27,8 +27,8 @@ module Mutant
27
27
  def bootstrap
28
28
  env = Env.empty(world, @config)
29
29
 
30
- Config.load_config_file(env)
31
- .fmap(&method(:expand))
30
+ env
31
+ .record(:config) { Config.load_config_file(env).fmap(&method(:expand)) }
32
32
  .bind { Bootstrap.call(env.with(config: @config)) }
33
33
  end
34
34
 
@@ -4,7 +4,13 @@ module Mutant
4
4
  module CLI
5
5
  # rubocop:disable Metrics/ClassLength
6
6
  class Command
7
- include AbstractType, Anima.new(:world, :main, :parent, :zombie)
7
+ include AbstractType, Anima.new(
8
+ :main,
9
+ :parent,
10
+ :print_profile,
11
+ :world,
12
+ :zombie
13
+ )
8
14
 
9
15
  OPTIONS = [].freeze
10
16
  SUBCOMMANDS = [].freeze
@@ -21,12 +27,13 @@ module Mutant
21
27
  # @return [Command]
22
28
  #
23
29
  # rubocop:disable Metrics/ParameterLists
24
- def self.parse(arguments:, parent: nil, world:, zombie: false)
30
+ def self.parse(arguments:, parent: nil, print_profile: false, world:, zombie: false)
25
31
  new(
26
- main: nil,
27
- parent: parent,
28
- world: world,
29
- zombie: zombie
32
+ main: nil,
33
+ parent: parent,
34
+ print_profile: print_profile,
35
+ world: world,
36
+ zombie: zombie
30
37
  ).__send__(:parse, arguments)
31
38
  end
32
39
  # rubocop:enable Metrics/ParameterLists
@@ -59,7 +66,8 @@ module Mutant
59
66
  [*parent&.full_name, self.class.command_name].join(' ')
60
67
  end
61
68
 
62
- alias_method :zombie?, :zombie
69
+ alias_method :print_profile?, :print_profile
70
+ alias_method :zombie?, :zombie
63
71
 
64
72
  abstract_method :action
65
73
 
@@ -136,6 +144,10 @@ module Mutant
136
144
  capture_main { world.stdout.puts("mutant-#{VERSION}"); true }
137
145
  end
138
146
 
147
+ parser.on('--profile', 'Profile mutant execution') do
148
+ @print_profile = true
149
+ end
150
+
139
151
  parser.on('--zombie', 'Run mutant zombified') do
140
152
  @zombie = true
141
153
  end
@@ -176,10 +188,11 @@ module Mutant
176
188
  else
177
189
  find_command(command_name).bind do |command|
178
190
  command.parse(
179
- arguments: arguments,
180
- parent: self,
181
- world: world,
182
- zombie: zombie
191
+ arguments: arguments,
192
+ parent: self,
193
+ print_profile: print_profile,
194
+ world: world,
195
+ zombie: zombie
183
196
  )
184
197
  end
185
198
  end
data/lib/mutant/env.rb CHANGED
@@ -134,6 +134,15 @@ module Mutant
134
134
  end
135
135
  memoize :test_subject_ratio
136
136
 
137
+ # Record segment
138
+ #
139
+ # @param [Symbol] name
140
+ #
141
+ # @return [self]
142
+ def record(name, &block)
143
+ world.record(name, &block)
144
+ end
145
+
137
146
  private
138
147
 
139
148
  def run_mutation_tests(mutation, tests)
@@ -49,6 +49,7 @@ module Mutant
49
49
  def finalize(status)
50
50
  status.tap do
51
51
  if status.done?
52
+ workers.each(&:signal)
52
53
  workers.each(&:join)
53
54
  threads.each(&:join)
54
55
  end
@@ -77,8 +77,12 @@ module Mutant
77
77
  self
78
78
  end
79
79
 
80
- def join
80
+ def signal
81
81
  process.kill('TERM', pid)
82
+ self
83
+ end
84
+
85
+ def join
82
86
  process.wait(pid)
83
87
  self
84
88
  end
data/lib/mutant/runner.rb CHANGED
@@ -15,15 +15,17 @@ module Mutant
15
15
  def self.run_mutation_analysis(env)
16
16
  reporter = reporter(env)
17
17
 
18
- run_driver(
19
- reporter,
20
- Parallel.async(env.world, mutation_test_config(env))
21
- ).tap do |result|
22
- reporter.report(result)
23
- end
18
+ env
19
+ .record(:analysis) { run_driver(reporter, async_driver(env)) }
20
+ .tap { |result| env.record(:report) { reporter.report(result) } }
24
21
  end
25
22
  private_class_method :run_mutation_analysis
26
23
 
24
+ def self.async_driver(env)
25
+ Parallel.async(env.world, mutation_test_config(env))
26
+ end
27
+ private_class_method :async_driver
28
+
27
29
  def self.run_driver(reporter, driver)
28
30
  Signal.trap('INT') do
29
31
  driver.stop
@@ -0,0 +1,124 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mutant
4
+ class Segment
5
+ class Recorder
6
+ include Anima.new(
7
+ :gen_id,
8
+ :parent_id,
9
+ :recording_start,
10
+ :root_id,
11
+ :segments,
12
+ :timer
13
+ )
14
+
15
+ private(*anima.attribute_names)
16
+
17
+ # rubocop:disable Metrics/MethodLength
18
+ def record(name)
19
+ start = timer.now
20
+ parent_id = parent_id()
21
+
22
+ @parent_id = id = gen_id.call
23
+
24
+ yield.tap do
25
+ segments << Segment.new(
26
+ id: id,
27
+ name: name,
28
+ parent_id: parent_id,
29
+ timestamp_end: timer.now,
30
+ timestamp_start: start
31
+ )
32
+ end
33
+ ensure
34
+ @parent_id = parent_id
35
+ end
36
+ # rubocop:enable Metrics/MethodLength
37
+
38
+ def print_profile(io)
39
+ print_node(io, tree, 0)
40
+ end
41
+
42
+ private
43
+
44
+ class Node
45
+ include Adamantium, Anima.new(:value, :children)
46
+ end
47
+ private_constant :Node
48
+
49
+ def tree
50
+ id_index = {}
51
+ parent_index = {}
52
+
53
+ final_segments.each do |segment|
54
+ id_index[segment.id] = segment
55
+
56
+ (parent_index[segment.parent_id] ||= []) << segment
57
+ end
58
+
59
+ build_node(
60
+ value: id_index.fetch(root_id),
61
+ parent_index: parent_index
62
+ )
63
+ end
64
+
65
+ def final_segments
66
+ timestamp_end = timer.now
67
+
68
+ segments.map do |segment|
69
+ if segment.timestamp_end
70
+ segment
71
+ else
72
+ segment.with(timestamp_end: timestamp_end)
73
+ end
74
+ end
75
+ end
76
+
77
+ def build_node(value:, parent_index:)
78
+ Node.new(
79
+ value: value,
80
+ children: build_children(
81
+ parent_id: value.id,
82
+ parent_index: parent_index
83
+ )
84
+ )
85
+ end
86
+
87
+ def build_children(parent_id:, parent_index:)
88
+ parent_index
89
+ .fetch(parent_id, EMPTY_ARRAY)
90
+ .map { |value| build_node(value: value, parent_index: parent_index) }
91
+ end
92
+
93
+ def print_node(io, node, indent)
94
+ segment = node.value
95
+
96
+ indent_str = ' ' * indent
97
+
98
+ print_line(io, :offset_start, segment, indent_str)
99
+
100
+ return unless node.children.any?
101
+
102
+ node.children.each do |child|
103
+ print_node(io, child, indent.succ)
104
+ end
105
+ print_line(io, :offset_end, segment, indent_str)
106
+ end
107
+
108
+ # rubocop:disable Metrics/ParameterLists
109
+ # rubocop:disable Style/FormatStringToken
110
+ def print_line(io, offset, segment, indent_str)
111
+ io.puts(
112
+ '%4.4f: (%4.4fs) %s %s' % [
113
+ segment.public_send(offset, recording_start),
114
+ segment.elapsed,
115
+ indent_str,
116
+ segment.name
117
+ ]
118
+ )
119
+ end
120
+ # rubocop:enable Metrics/ParameterLists
121
+ # rubocop:enable Style/FormatStringToken
122
+ end # Recorder
123
+ end # Segment
124
+ end # Mutant
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mutant
4
+ class Segment
5
+ include Adamantium, Anima.new(
6
+ :id,
7
+ :name,
8
+ :parent_id,
9
+ :timestamp_end,
10
+ :timestamp_start
11
+ )
12
+
13
+ def elapsed
14
+ timestamp_end - timestamp_start
15
+ end
16
+
17
+ def offset_start(recording_start)
18
+ timestamp_start - recording_start
19
+ end
20
+
21
+ def offset_end(recording_start)
22
+ timestamp_end - recording_start
23
+ end
24
+ end # Segment
25
+ end # Mutant
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Mutant
4
4
  # Current mutant version
5
- VERSION = '0.11.16'
5
+ VERSION = '0.11.17'
6
6
  end # Mutant
data/lib/mutant/world.rb CHANGED
@@ -19,6 +19,7 @@ module Mutant
19
19
  :pathname,
20
20
  :process,
21
21
  :random,
22
+ :recorder,
22
23
  :stderr,
23
24
  :stdout,
24
25
  :thread,
@@ -77,5 +78,9 @@ module Mutant
77
78
  Timer::Deadline::None.new
78
79
  end
79
80
  end
81
+
82
+ def record(name, &block)
83
+ recorder.record(name, &block)
84
+ end
80
85
  end # World
81
86
  end # Mutant
data/lib/mutant.rb CHANGED
@@ -1,32 +1,54 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'diff/lcs'
4
- require 'diff/lcs/hunk'
5
- require 'digest/sha1'
6
- require 'etc'
7
- require 'irb'
8
- require 'json'
9
- require 'open3'
10
- require 'optparse'
11
- require 'parser'
12
- require 'parser/current'
13
- require 'pathname'
14
- require 'regexp_parser'
15
- require 'set'
16
- require 'singleton'
17
- require 'sorbet-runtime'
18
- require 'stringio'
19
- require 'unparser'
20
- require 'yaml'
21
-
22
- # This setting is done to make errors within the parallel
23
- # reporter / execution visible in the main thread.
24
- Thread.abort_on_exception = true
25
-
26
3
  # Library namespace
27
4
  #
28
5
  # @api private
6
+ # rubocop:disable Metrics/ModuleLength
29
7
  module Mutant
8
+ # Boot timing infrastructure
9
+ get_timestamp = lambda do
10
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
11
+ end
12
+
13
+ library_timestamp = get_timestamp.call
14
+ boot_events = []
15
+
16
+ record = lambda do |name, &block|
17
+ start = get_timestamp.call
18
+
19
+ block.call.tap do
20
+ boot_events << [name, start, get_timestamp.call]
21
+ end
22
+ end
23
+
24
+ record.call(:require_dependencies) do
25
+ %w[
26
+ diff/lcs
27
+ diff/lcs/hunk
28
+ digest/sha1
29
+ etc
30
+ irb
31
+ json
32
+ open3
33
+ optparse
34
+ parser
35
+ parser/current
36
+ pathname
37
+ regexp_parser
38
+ securerandom
39
+ set
40
+ singleton
41
+ sorbet-runtime
42
+ stringio
43
+ unparser
44
+ yaml
45
+ ].each { |name| require(name) }
46
+ end
47
+
48
+ # This setting is done to make errors within the parallel
49
+ # reporter / execution visible in the main thread.
50
+ Thread.abort_on_exception = true
51
+
30
52
  AbstractType = Unparser::AbstractType
31
53
  Adamantium = Unparser::Adamantium
32
54
  Anima = Unparser::Anima
@@ -43,211 +65,264 @@ module Mutant
43
65
 
44
66
  ENV_VARIABLE_KEY_VALUE_REGEXP = /\A(?<key>#{env_key}+)=(?<value>.*)\z/.freeze
45
67
  ENV_VARIABLE_KEY_REGEXP = /\A#{env_key}\z/.freeze
46
- end # Mutant
47
68
 
48
- require 'mutant/procto'
49
- require 'mutant/transform'
50
- require 'mutant/variable'
51
- require 'mutant/bootstrap'
52
- require 'mutant/version'
53
- require 'mutant/env'
54
- require 'mutant/pipe'
55
- require 'mutant/util'
56
- require 'mutant/registry'
57
- require 'mutant/ast'
58
- require 'mutant/ast/sexp'
59
- require 'mutant/ast/types'
60
- require 'mutant/ast/nodes'
61
- require 'mutant/ast/named_children'
62
- require 'mutant/ast/node_predicates'
63
- require 'mutant/ast/find_metaclass_containing'
64
- require 'mutant/ast/regexp'
65
- require 'mutant/ast/regexp/transformer'
66
- require 'mutant/ast/regexp/transformer/direct'
67
- require 'mutant/ast/regexp/transformer/named_group'
68
- require 'mutant/ast/regexp/transformer/options_group'
69
- require 'mutant/ast/regexp/transformer/quantifier'
70
- require 'mutant/ast/regexp/transformer/recursive'
71
- require 'mutant/ast/regexp/transformer/root'
72
- require 'mutant/ast/regexp/transformer/text'
73
- require 'mutant/ast/meta'
74
- require 'mutant/ast/meta/send'
75
- require 'mutant/ast/meta/const'
76
- require 'mutant/ast/meta/symbol'
77
- require 'mutant/ast/meta/optarg'
78
- require 'mutant/ast/meta/resbody'
79
- require 'mutant/ast/pattern'
80
- require 'mutant/ast/pattern/lexer'
81
- require 'mutant/ast/pattern/parser'
82
- require 'mutant/ast/pattern/source'
83
- require 'mutant/ast/pattern/token'
84
- require 'mutant/ast/structure'
85
- require 'mutant/parser'
86
- require 'mutant/isolation'
87
- require 'mutant/isolation/exception'
88
- require 'mutant/isolation/fork'
89
- require 'mutant/isolation/none'
90
- require 'mutant/parallel'
91
- require 'mutant/parallel/driver'
92
- require 'mutant/parallel/source'
93
- require 'mutant/parallel/worker'
94
- require 'mutant/require_highjack'
95
- require 'mutant/mutation'
96
- require 'mutant/mutation/config'
97
- require 'mutant/mutator'
98
- require 'mutant/mutator/util'
99
- require 'mutant/mutator/util/array'
100
- require 'mutant/mutator/util/symbol'
101
- require 'mutant/mutator/node'
102
- require 'mutant/mutator/node/generic'
103
- require 'mutant/mutator/node/regexp'
104
- require 'mutant/mutator/node/regexp/alternation_meta'
105
- require 'mutant/mutator/node/regexp/beginning_of_line_anchor'
106
- require 'mutant/mutator/node/regexp/capture_group'
107
- require 'mutant/mutator/node/regexp/named_group'
108
- require 'mutant/mutator/node/regexp/character_type'
109
- require 'mutant/mutator/node/regexp/end_of_line_anchor'
110
- require 'mutant/mutator/node/regexp/end_of_string_or_before_end_of_line_anchor'
111
- require 'mutant/mutator/node/regexp/zero_or_more'
112
- require 'mutant/mutator/node/literal'
113
- require 'mutant/mutator/node/literal/boolean'
114
- require 'mutant/mutator/node/literal/range'
115
- require 'mutant/mutator/node/literal/symbol'
116
- require 'mutant/mutator/node/literal/string'
117
- require 'mutant/mutator/node/literal/integer'
118
- require 'mutant/mutator/node/literal/float'
119
- require 'mutant/mutator/node/literal/array'
120
- require 'mutant/mutator/node/literal/hash'
121
- require 'mutant/mutator/node/literal/regex'
122
- require 'mutant/mutator/node/literal/nil'
123
- require 'mutant/mutator/node/argument'
124
- require 'mutant/mutator/node/arguments'
125
- require 'mutant/mutator/node/begin'
126
- require 'mutant/mutator/node/binary'
127
- require 'mutant/mutator/node/const'
128
- require 'mutant/mutator/node/dynamic_literal'
129
- require 'mutant/mutator/node/kwbegin'
130
- require 'mutant/mutator/node/named_value/access'
131
- require 'mutant/mutator/node/named_value/constant_assignment'
132
- require 'mutant/mutator/node/named_value/variable_assignment'
133
- require 'mutant/mutator/node/next'
134
- require 'mutant/mutator/node/break'
135
- require 'mutant/mutator/node/noop'
136
- require 'mutant/mutator/node/or_asgn'
137
- require 'mutant/mutator/node/and_asgn'
138
- require 'mutant/mutator/node/defined'
139
- require 'mutant/mutator/node/op_asgn'
140
- require 'mutant/mutator/node/conditional_loop'
141
- require 'mutant/mutator/node/yield'
142
- require 'mutant/mutator/node/super'
143
- require 'mutant/mutator/node/zsuper'
144
- require 'mutant/mutator/node/send'
145
- require 'mutant/mutator/node/send/binary'
146
- require 'mutant/mutator/node/send/conditional'
147
- require 'mutant/mutator/node/send/attribute_assignment'
148
- require 'mutant/mutator/node/when'
149
- require 'mutant/mutator/node/class'
150
- require 'mutant/mutator/node/sclass'
151
- require 'mutant/mutator/node/define'
152
- require 'mutant/mutator/node/mlhs'
153
- require 'mutant/mutator/node/nthref'
154
- require 'mutant/mutator/node/masgn'
155
- require 'mutant/mutator/node/module'
156
- require 'mutant/mutator/node/return'
157
- require 'mutant/mutator/node/block'
158
- require 'mutant/mutator/node/block_pass'
159
- require 'mutant/mutator/node/if'
160
- require 'mutant/mutator/node/case'
161
- require 'mutant/mutator/node/splat'
162
- require 'mutant/mutator/node/regopt'
163
- require 'mutant/mutator/node/resbody'
164
- require 'mutant/mutator/node/rescue'
165
- require 'mutant/mutator/node/match_current_line'
166
- require 'mutant/mutator/node/index'
167
- require 'mutant/mutator/node/procarg_zero'
168
- require 'mutant/mutator/node/kwargs'
169
- require 'mutant/mutator/node/numblock'
170
- require 'mutant/loader'
171
- require 'mutant/context'
172
- require 'mutant/scope'
173
- require 'mutant/subject'
174
- require 'mutant/subject/config'
175
- require 'mutant/subject/method'
176
- require 'mutant/subject/method/instance'
177
- require 'mutant/subject/method/singleton'
178
- require 'mutant/subject/method/metaclass'
179
- require 'mutant/matcher'
180
- require 'mutant/matcher/chain'
181
- require 'mutant/matcher/config'
182
- require 'mutant/matcher/descendants'
183
- require 'mutant/matcher/filter'
184
- require 'mutant/matcher/method'
185
- require 'mutant/matcher/method/instance'
186
- require 'mutant/matcher/method/metaclass'
187
- require 'mutant/matcher/method/singleton'
188
- require 'mutant/matcher/methods'
189
- require 'mutant/matcher/namespace'
190
- require 'mutant/matcher/null'
191
- require 'mutant/matcher/scope'
192
- require 'mutant/matcher/static'
193
- require 'mutant/expression'
194
- require 'mutant/expression/descendants'
195
- require 'mutant/expression/method'
196
- require 'mutant/expression/methods'
197
- require 'mutant/expression/namespace'
198
- require 'mutant/expression/parser'
199
- require 'mutant/test'
200
- require 'mutant/timer'
201
- require 'mutant/integration'
202
- require 'mutant/integration/null'
203
- require 'mutant/selector'
204
- require 'mutant/selector/expression'
205
- require 'mutant/selector/null'
206
- require 'mutant/world'
207
- require 'mutant/hooks'
208
- require 'mutant/config'
209
- require 'mutant/config/coverage_criteria'
210
- require 'mutant/cli'
211
- require 'mutant/cli/command'
212
- require 'mutant/cli/command/subscription'
213
- require 'mutant/cli/command/environment'
214
- require 'mutant/cli/command/environment/irb'
215
- require 'mutant/cli/command/environment/run'
216
- require 'mutant/cli/command/environment/show'
217
- require 'mutant/cli/command/environment/subject'
218
- require 'mutant/cli/command/environment/test'
219
- require 'mutant/cli/command/util'
220
- require 'mutant/cli/command/root'
221
- require 'mutant/runner'
222
- require 'mutant/runner/sink'
223
- require 'mutant/result'
224
- require 'mutant/reporter'
225
- require 'mutant/reporter/null'
226
- require 'mutant/reporter/sequence'
227
- require 'mutant/reporter/cli'
228
- require 'mutant/reporter/cli/printer'
229
- require 'mutant/reporter/cli/printer/config'
230
- require 'mutant/reporter/cli/printer/coverage_result'
231
- require 'mutant/reporter/cli/printer/env'
232
- require 'mutant/reporter/cli/printer/env_progress'
233
- require 'mutant/reporter/cli/printer/env_result'
234
- require 'mutant/reporter/cli/printer/isolation_result'
235
- require 'mutant/reporter/cli/printer/mutation'
236
- require 'mutant/reporter/cli/printer/mutation_result'
237
- require 'mutant/reporter/cli/printer/status_progressive'
238
- require 'mutant/reporter/cli/printer/subject_result'
239
- require 'mutant/reporter/cli/format'
240
- require 'mutant/repository'
241
- require 'mutant/repository/diff'
242
- require 'mutant/repository/diff/ranges'
243
- require 'mutant/zombifier'
244
- require 'mutant/range'
245
- require 'mutant/license'
246
- require 'mutant/license/subscription'
247
- require 'mutant/license/subscription/opensource'
248
- require 'mutant/license/subscription/commercial'
69
+ # rubocop:disable Metrics/BlockLength
70
+ record.call(:require_mutant_lib) do
71
+ require 'mutant/procto'
72
+ require 'mutant/transform'
73
+ require 'mutant/variable'
74
+ require 'mutant/bootstrap'
75
+ require 'mutant/version'
76
+ require 'mutant/env'
77
+ require 'mutant/pipe'
78
+ require 'mutant/util'
79
+ require 'mutant/registry'
80
+ require 'mutant/ast'
81
+ require 'mutant/ast/sexp'
82
+ require 'mutant/ast/types'
83
+ require 'mutant/ast/nodes'
84
+ require 'mutant/ast/named_children'
85
+ require 'mutant/ast/node_predicates'
86
+ require 'mutant/ast/find_metaclass_containing'
87
+ require 'mutant/ast/regexp'
88
+ require 'mutant/ast/regexp/transformer'
89
+ require 'mutant/ast/regexp/transformer/direct'
90
+ require 'mutant/ast/regexp/transformer/named_group'
91
+ require 'mutant/ast/regexp/transformer/options_group'
92
+ require 'mutant/ast/regexp/transformer/quantifier'
93
+ require 'mutant/ast/regexp/transformer/recursive'
94
+ require 'mutant/ast/regexp/transformer/root'
95
+ require 'mutant/ast/regexp/transformer/text'
96
+ require 'mutant/ast/meta'
97
+ require 'mutant/ast/meta/send'
98
+ require 'mutant/ast/meta/const'
99
+ require 'mutant/ast/meta/symbol'
100
+ require 'mutant/ast/meta/optarg'
101
+ require 'mutant/ast/meta/resbody'
102
+ require 'mutant/ast/pattern'
103
+ require 'mutant/ast/pattern/lexer'
104
+ require 'mutant/ast/pattern/parser'
105
+ require 'mutant/ast/pattern/source'
106
+ require 'mutant/ast/pattern/token'
107
+ require 'mutant/ast/structure'
108
+ require 'mutant/parser'
109
+ require 'mutant/isolation'
110
+ require 'mutant/isolation/exception'
111
+ require 'mutant/isolation/fork'
112
+ require 'mutant/isolation/none'
113
+ require 'mutant/parallel'
114
+ require 'mutant/parallel/driver'
115
+ require 'mutant/parallel/source'
116
+ require 'mutant/parallel/worker'
117
+ require 'mutant/require_highjack'
118
+ require 'mutant/mutation'
119
+ require 'mutant/mutation/config'
120
+ require 'mutant/mutator'
121
+ require 'mutant/mutator/util'
122
+ require 'mutant/mutator/util/array'
123
+ require 'mutant/mutator/util/symbol'
124
+ require 'mutant/mutator/node'
125
+ require 'mutant/mutator/node/generic'
126
+ require 'mutant/mutator/node/regexp'
127
+ require 'mutant/mutator/node/regexp/alternation_meta'
128
+ require 'mutant/mutator/node/regexp/beginning_of_line_anchor'
129
+ require 'mutant/mutator/node/regexp/capture_group'
130
+ require 'mutant/mutator/node/regexp/named_group'
131
+ require 'mutant/mutator/node/regexp/character_type'
132
+ require 'mutant/mutator/node/regexp/end_of_line_anchor'
133
+ require 'mutant/mutator/node/regexp/end_of_string_or_before_end_of_line_anchor'
134
+ require 'mutant/mutator/node/regexp/zero_or_more'
135
+ require 'mutant/mutator/node/literal'
136
+ require 'mutant/mutator/node/literal/boolean'
137
+ require 'mutant/mutator/node/literal/range'
138
+ require 'mutant/mutator/node/literal/symbol'
139
+ require 'mutant/mutator/node/literal/string'
140
+ require 'mutant/mutator/node/literal/integer'
141
+ require 'mutant/mutator/node/literal/float'
142
+ require 'mutant/mutator/node/literal/array'
143
+ require 'mutant/mutator/node/literal/hash'
144
+ require 'mutant/mutator/node/literal/regex'
145
+ require 'mutant/mutator/node/literal/nil'
146
+ require 'mutant/mutator/node/argument'
147
+ require 'mutant/mutator/node/arguments'
148
+ require 'mutant/mutator/node/begin'
149
+ require 'mutant/mutator/node/binary'
150
+ require 'mutant/mutator/node/const'
151
+ require 'mutant/mutator/node/dynamic_literal'
152
+ require 'mutant/mutator/node/kwbegin'
153
+ require 'mutant/mutator/node/named_value/access'
154
+ require 'mutant/mutator/node/named_value/constant_assignment'
155
+ require 'mutant/mutator/node/named_value/variable_assignment'
156
+ require 'mutant/mutator/node/next'
157
+ require 'mutant/mutator/node/break'
158
+ require 'mutant/mutator/node/noop'
159
+ require 'mutant/mutator/node/or_asgn'
160
+ require 'mutant/mutator/node/and_asgn'
161
+ require 'mutant/mutator/node/defined'
162
+ require 'mutant/mutator/node/op_asgn'
163
+ require 'mutant/mutator/node/conditional_loop'
164
+ require 'mutant/mutator/node/yield'
165
+ require 'mutant/mutator/node/super'
166
+ require 'mutant/mutator/node/zsuper'
167
+ require 'mutant/mutator/node/send'
168
+ require 'mutant/mutator/node/send/binary'
169
+ require 'mutant/mutator/node/send/conditional'
170
+ require 'mutant/mutator/node/send/attribute_assignment'
171
+ require 'mutant/mutator/node/when'
172
+ require 'mutant/mutator/node/class'
173
+ require 'mutant/mutator/node/sclass'
174
+ require 'mutant/mutator/node/define'
175
+ require 'mutant/mutator/node/mlhs'
176
+ require 'mutant/mutator/node/nthref'
177
+ require 'mutant/mutator/node/masgn'
178
+ require 'mutant/mutator/node/module'
179
+ require 'mutant/mutator/node/return'
180
+ require 'mutant/mutator/node/block'
181
+ require 'mutant/mutator/node/block_pass'
182
+ require 'mutant/mutator/node/if'
183
+ require 'mutant/mutator/node/case'
184
+ require 'mutant/mutator/node/splat'
185
+ require 'mutant/mutator/node/regopt'
186
+ require 'mutant/mutator/node/resbody'
187
+ require 'mutant/mutator/node/rescue'
188
+ require 'mutant/mutator/node/match_current_line'
189
+ require 'mutant/mutator/node/index'
190
+ require 'mutant/mutator/node/procarg_zero'
191
+ require 'mutant/mutator/node/kwargs'
192
+ require 'mutant/mutator/node/numblock'
193
+ require 'mutant/loader'
194
+ require 'mutant/context'
195
+ require 'mutant/scope'
196
+ require 'mutant/subject'
197
+ require 'mutant/subject/config'
198
+ require 'mutant/subject/method'
199
+ require 'mutant/subject/method/instance'
200
+ require 'mutant/subject/method/singleton'
201
+ require 'mutant/subject/method/metaclass'
202
+ require 'mutant/matcher'
203
+ require 'mutant/matcher/chain'
204
+ require 'mutant/matcher/config'
205
+ require 'mutant/matcher/descendants'
206
+ require 'mutant/matcher/filter'
207
+ require 'mutant/matcher/method'
208
+ require 'mutant/matcher/method/instance'
209
+ require 'mutant/matcher/method/metaclass'
210
+ require 'mutant/matcher/method/singleton'
211
+ require 'mutant/matcher/methods'
212
+ require 'mutant/matcher/namespace'
213
+ require 'mutant/matcher/null'
214
+ require 'mutant/matcher/scope'
215
+ require 'mutant/matcher/static'
216
+ require 'mutant/expression'
217
+ require 'mutant/expression/descendants'
218
+ require 'mutant/expression/method'
219
+ require 'mutant/expression/methods'
220
+ require 'mutant/expression/namespace'
221
+ require 'mutant/expression/parser'
222
+ require 'mutant/test'
223
+ require 'mutant/timer'
224
+ require 'mutant/integration'
225
+ require 'mutant/integration/null'
226
+ require 'mutant/selector'
227
+ require 'mutant/selector/expression'
228
+ require 'mutant/selector/null'
229
+ require 'mutant/world'
230
+ require 'mutant/hooks'
231
+ require 'mutant/config'
232
+ require 'mutant/config/coverage_criteria'
233
+ require 'mutant/cli'
234
+ require 'mutant/cli/command'
235
+ require 'mutant/cli/command/subscription'
236
+ require 'mutant/cli/command/environment'
237
+ require 'mutant/cli/command/environment/irb'
238
+ require 'mutant/cli/command/environment/run'
239
+ require 'mutant/cli/command/environment/show'
240
+ require 'mutant/cli/command/environment/subject'
241
+ require 'mutant/cli/command/environment/test'
242
+ require 'mutant/cli/command/util'
243
+ require 'mutant/cli/command/root'
244
+ require 'mutant/runner'
245
+ require 'mutant/runner/sink'
246
+ require 'mutant/result'
247
+ require 'mutant/reporter'
248
+ require 'mutant/reporter/null'
249
+ require 'mutant/reporter/sequence'
250
+ require 'mutant/reporter/cli'
251
+ require 'mutant/reporter/cli/printer'
252
+ require 'mutant/reporter/cli/printer/config'
253
+ require 'mutant/reporter/cli/printer/coverage_result'
254
+ require 'mutant/reporter/cli/printer/env'
255
+ require 'mutant/reporter/cli/printer/env_progress'
256
+ require 'mutant/reporter/cli/printer/env_result'
257
+ require 'mutant/reporter/cli/printer/isolation_result'
258
+ require 'mutant/reporter/cli/printer/mutation'
259
+ require 'mutant/reporter/cli/printer/mutation_result'
260
+ require 'mutant/reporter/cli/printer/status_progressive'
261
+ require 'mutant/reporter/cli/printer/subject_result'
262
+ require 'mutant/reporter/cli/format'
263
+ require 'mutant/repository'
264
+ require 'mutant/repository/diff'
265
+ require 'mutant/repository/diff/ranges'
266
+ require 'mutant/zombifier'
267
+ require 'mutant/range'
268
+ require 'mutant/license'
269
+ require 'mutant/license/subscription'
270
+ require 'mutant/license/subscription/opensource'
271
+ require 'mutant/license/subscription/commercial'
272
+ require 'mutant/segment'
273
+ require 'mutant/segment/recorder'
274
+ end
275
+ # rubocop:enable Metrics/BlockLength
276
+
277
+ gen_id = SecureRandom.method(:uuid)
278
+
279
+ # Transform boot events into segments
280
+ if instance_variable_defined?(:@executable_timestamp)
281
+ recording_start = @executable_timestamp
282
+
283
+ executable_segment =
284
+ Segment.new(
285
+ id: gen_id.call,
286
+ name: :executable,
287
+ parent_id: nil,
288
+ timestamp_end: nil,
289
+ timestamp_start: @executable_timestamp
290
+ )
291
+
292
+ remove_instance_variable(:@executable_timestamp)
293
+ else
294
+ recording_start = library_timestamp
295
+ end
296
+
297
+ library_segment = Segment.new(
298
+ id: gen_id.call,
299
+ name: :library,
300
+ parent_id: executable_segment&.id,
301
+ timestamp_end: nil,
302
+ timestamp_start: library_timestamp
303
+ )
304
+
305
+ boot_segments = boot_events.map do |name, timestamp_start, timestamp_end|
306
+ Segment.new(
307
+ id: gen_id.call,
308
+ name: name,
309
+ parent_id: library_segment.id,
310
+ timestamp_end: timestamp_end,
311
+ timestamp_start: timestamp_start
312
+ )
313
+ end
314
+
315
+ timer = Timer.new(Process)
316
+
317
+ recorder = Segment::Recorder.new(
318
+ gen_id: gen_id,
319
+ root_id: (executable_segment || library_segment).id,
320
+ parent_id: library_segment.id,
321
+ recording_start: recording_start,
322
+ segments: [*executable_segment, library_segment, *boot_segments],
323
+ timer: timer
324
+ )
249
325
 
250
- module Mutant
251
326
  WORLD = World.new(
252
327
  condition_variable: ConditionVariable,
253
328
  environment_variables: ENV,
@@ -264,10 +339,11 @@ module Mutant
264
339
  pathname: Pathname,
265
340
  process: Process,
266
341
  random: Random,
342
+ recorder: recorder,
267
343
  stderr: $stderr,
268
344
  stdout: $stdout,
269
345
  thread: Thread,
270
- timer: Timer.new(Process)
346
+ timer: timer
271
347
  )
272
348
 
273
349
  # Reopen class to initialize constant to avoid dep circle
@@ -281,8 +357,8 @@ module Mutant
281
357
  Expression::Namespace::Exact,
282
358
  Expression::Namespace::Recursive
283
359
  ]),
284
- fail_fast: false,
285
360
  environment_variables: EMPTY_HASH,
361
+ fail_fast: false,
286
362
  hooks: EMPTY_ARRAY,
287
363
  includes: EMPTY_ARRAY,
288
364
  integration: nil,
@@ -308,3 +384,4 @@ module Mutant
308
384
  )
309
385
  end
310
386
  end # Mutant
387
+ # rubocop:enable Metrics/ModuleLength
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mutant
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.16
4
+ version: 0.11.17
5
5
  platform: ruby
6
6
  authors:
7
7
  - Markus Schirp
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-09-11 00:00:00.000000000 Z
11
+ date: 2022-11-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: diff-lcs
@@ -356,6 +356,8 @@ files:
356
356
  - lib/mutant/runner.rb
357
357
  - lib/mutant/runner/sink.rb
358
358
  - lib/mutant/scope.rb
359
+ - lib/mutant/segment.rb
360
+ - lib/mutant/segment/recorder.rb
359
361
  - lib/mutant/selector.rb
360
362
  - lib/mutant/selector/expression.rb
361
363
  - lib/mutant/selector/null.rb