mutant 0.8.10 → 0.8.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (247) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -4
  3. data/Changelog.md +8 -0
  4. data/README.md +112 -43
  5. data/Rakefile +2 -16
  6. data/circle.yml +1 -1
  7. data/config/flay.yml +2 -2
  8. data/config/flog.yml +1 -1
  9. data/config/reek.yml +3 -4
  10. data/config/rubocop.yml +53 -16
  11. data/lib/mutant.rb +27 -6
  12. data/lib/mutant/ast/meta/const.rb +2 -0
  13. data/lib/mutant/ast/meta/optarg.rb +2 -0
  14. data/lib/mutant/ast/meta/resbody.rb +2 -0
  15. data/lib/mutant/ast/meta/restarg.rb +2 -0
  16. data/lib/mutant/ast/meta/send.rb +4 -0
  17. data/lib/mutant/ast/meta/symbol.rb +2 -0
  18. data/lib/mutant/ast/named_children.rb +14 -4
  19. data/lib/mutant/ast/nodes.rb +3 -1
  20. data/lib/mutant/ast/regexp.rb +53 -0
  21. data/lib/mutant/ast/regexp/transformer.rb +185 -0
  22. data/lib/mutant/ast/regexp/transformer/alternative.rb +39 -0
  23. data/lib/mutant/ast/regexp/transformer/character_set.rb +46 -0
  24. data/lib/mutant/ast/regexp/transformer/direct.rb +99 -0
  25. data/lib/mutant/ast/regexp/transformer/options_group.rb +66 -0
  26. data/lib/mutant/ast/regexp/transformer/quantifier.rb +112 -0
  27. data/lib/mutant/ast/regexp/transformer/recursive.rb +50 -0
  28. data/lib/mutant/ast/regexp/transformer/root.rb +29 -0
  29. data/lib/mutant/ast/regexp/transformer/text.rb +55 -0
  30. data/lib/mutant/ast/types.rb +92 -5
  31. data/lib/mutant/cli.rb +2 -14
  32. data/lib/mutant/color.rb +1 -1
  33. data/lib/mutant/config.rb +1 -3
  34. data/lib/mutant/expression/methods.rb +1 -1
  35. data/lib/mutant/expression/namespace.rb +2 -2
  36. data/lib/mutant/expression/parser.rb +1 -1
  37. data/lib/mutant/integration.rb +10 -28
  38. data/lib/mutant/isolation.rb +9 -60
  39. data/lib/mutant/isolation/fork.rb +72 -0
  40. data/lib/mutant/isolation/none.rb +25 -0
  41. data/lib/mutant/matcher/config.rb +2 -0
  42. data/lib/mutant/matcher/method/singleton.rb +5 -4
  43. data/lib/mutant/meta.rb +11 -4
  44. data/lib/mutant/meta/example.rb +2 -116
  45. data/lib/mutant/meta/example/dsl.rb +22 -19
  46. data/lib/mutant/meta/example/verification.rb +86 -0
  47. data/lib/mutant/mutator.rb +22 -49
  48. data/lib/mutant/mutator/node.rb +15 -19
  49. data/lib/mutant/mutator/node/and_asgn.rb +1 -1
  50. data/lib/mutant/mutator/node/argument.rb +10 -5
  51. data/lib/mutant/mutator/node/arguments.rb +5 -9
  52. data/lib/mutant/mutator/node/begin.rb +4 -17
  53. data/lib/mutant/mutator/node/block.rb +1 -1
  54. data/lib/mutant/mutator/node/break.rb +1 -1
  55. data/lib/mutant/mutator/node/class.rb +21 -0
  56. data/lib/mutant/mutator/node/conditional_loop.rb +1 -1
  57. data/lib/mutant/mutator/node/define.rb +1 -1
  58. data/lib/mutant/mutator/node/defined.rb +1 -1
  59. data/lib/mutant/mutator/node/dstr.rb +1 -1
  60. data/lib/mutant/mutator/node/dsym.rb +1 -1
  61. data/lib/mutant/mutator/node/generic.rb +3 -3
  62. data/lib/mutant/mutator/node/kwbegin.rb +1 -1
  63. data/lib/mutant/mutator/node/literal.rb +9 -0
  64. data/lib/mutant/mutator/node/literal/boolean.rb +1 -1
  65. data/lib/mutant/mutator/node/literal/fixnum.rb +2 -2
  66. data/lib/mutant/mutator/node/literal/float.rb +4 -6
  67. data/lib/mutant/mutator/node/literal/hash.rb +1 -1
  68. data/lib/mutant/mutator/node/literal/nil.rb +1 -1
  69. data/lib/mutant/mutator/node/literal/range.rb +2 -19
  70. data/lib/mutant/mutator/node/literal/regex.rb +43 -3
  71. data/lib/mutant/mutator/node/literal/string.rb +1 -1
  72. data/lib/mutant/mutator/node/literal/symbol.rb +2 -4
  73. data/lib/mutant/mutator/node/masgn.rb +1 -1
  74. data/lib/mutant/mutator/node/match_current_line.rb +1 -1
  75. data/lib/mutant/mutator/node/mlhs.rb +2 -3
  76. data/lib/mutant/mutator/node/named_value/access.rb +2 -2
  77. data/lib/mutant/mutator/node/named_value/constant_assignment.rb +4 -3
  78. data/lib/mutant/mutator/node/named_value/variable_assignment.rb +4 -4
  79. data/lib/mutant/mutator/node/next.rb +1 -1
  80. data/lib/mutant/mutator/node/nthref.rb +1 -1
  81. data/lib/mutant/mutator/node/or_asgn.rb +1 -1
  82. data/lib/mutant/mutator/node/regexp.rb +44 -0
  83. data/lib/mutant/mutator/node/regopt.rb +31 -0
  84. data/lib/mutant/mutator/node/resbody.rb +1 -1
  85. data/lib/mutant/mutator/node/rescue.rb +1 -3
  86. data/lib/mutant/mutator/node/return.rb +1 -1
  87. data/lib/mutant/mutator/node/send.rb +43 -3
  88. data/lib/mutant/mutator/node/send/attribute_assignment.rb +4 -1
  89. data/lib/mutant/mutator/node/send/conditional.rb +23 -0
  90. data/lib/mutant/mutator/node/send/index.rb +1 -1
  91. data/lib/mutant/mutator/node/splat.rb +1 -1
  92. data/lib/mutant/mutator/node/when.rb +1 -1
  93. data/lib/mutant/mutator/node/yield.rb +1 -1
  94. data/lib/mutant/mutator/util.rb +0 -30
  95. data/lib/mutant/mutator/util/array.rb +4 -16
  96. data/lib/mutant/parallel.rb +1 -1
  97. data/lib/mutant/parallel/worker.rb +1 -1
  98. data/lib/mutant/registry.rb +44 -0
  99. data/lib/mutant/reporter/cli/format.rb +2 -0
  100. data/lib/mutant/reporter/cli/printer.rb +2 -2
  101. data/lib/mutant/reporter/cli/printer/config.rb +0 -1
  102. data/lib/mutant/reporter/cli/printer/env_progress.rb +1 -11
  103. data/lib/mutant/reporter/cli/printer/mutation_progress_result.rb +1 -1
  104. data/lib/mutant/reporter/cli/printer/mutation_result.rb +2 -0
  105. data/lib/mutant/reporter/cli/tput.rb +1 -1
  106. data/lib/mutant/reporter/sequence.rb +3 -0
  107. data/lib/mutant/require_highjack.rb +6 -2
  108. data/lib/mutant/result.rb +1 -1
  109. data/lib/mutant/subject.rb +5 -5
  110. data/lib/mutant/subject/method/instance.rb +1 -2
  111. data/lib/mutant/util.rb +18 -0
  112. data/lib/mutant/version.rb +1 -1
  113. data/lib/mutant/zombifier.rb +5 -3
  114. data/meta/and.rb +1 -1
  115. data/meta/and_asgn.rb +1 -1
  116. data/meta/array.rb +2 -2
  117. data/meta/begin.rb +2 -2
  118. data/meta/block.rb +7 -7
  119. data/meta/block_pass.rb +1 -1
  120. data/meta/blockarg.rb +1 -1
  121. data/meta/break.rb +1 -1
  122. data/meta/case.rb +2 -2
  123. data/meta/casgn.rb +11 -2
  124. data/meta/cbase.rb +1 -1
  125. data/meta/class.rb +10 -0
  126. data/meta/const.rb +9 -1
  127. data/meta/csend.rb +8 -0
  128. data/meta/cvar.rb +1 -1
  129. data/meta/cvasgn.rb +1 -1
  130. data/meta/date.rb +4 -4
  131. data/meta/def.rb +14 -14
  132. data/meta/defined.rb +1 -1
  133. data/meta/dstr.rb +1 -1
  134. data/meta/dsym.rb +1 -1
  135. data/meta/ensure.rb +1 -1
  136. data/meta/false.rb +1 -1
  137. data/meta/float.rb +3 -3
  138. data/meta/gvar.rb +1 -1
  139. data/meta/gvasgn.rb +1 -1
  140. data/meta/hash.rb +1 -1
  141. data/meta/if.rb +17 -3
  142. data/meta/int.rb +1 -1
  143. data/meta/ivar.rb +1 -1
  144. data/meta/ivasgn.rb +14 -1
  145. data/meta/kwarg.rb +8 -0
  146. data/meta/kwbegin.rb +1 -1
  147. data/meta/kwoptarg.rb +11 -0
  148. data/meta/lvar.rb +1 -1
  149. data/meta/lvasgn.rb +1 -1
  150. data/meta/masgn.rb +1 -1
  151. data/meta/match_current_line.rb +2 -2
  152. data/meta/next.rb +1 -1
  153. data/meta/nil.rb +1 -1
  154. data/meta/nthref.rb +5 -5
  155. data/meta/op_assgn.rb +1 -1
  156. data/meta/or.rb +1 -1
  157. data/meta/or_asgn.rb +5 -5
  158. data/meta/range.rb +2 -8
  159. data/meta/redo.rb +1 -1
  160. data/meta/regexp.rb +106 -0
  161. data/meta/regexp/regexp_bol_anchor.rb +13 -0
  162. data/meta/regexp/regexp_bos_anchor.rb +26 -0
  163. data/meta/regexp/regexp_root_expression.rb +13 -0
  164. data/meta/regopt.rb +8 -0
  165. data/meta/rescue.rb +49 -4
  166. data/meta/restarg.rb +6 -9
  167. data/meta/return.rb +2 -2
  168. data/meta/self.rb +1 -1
  169. data/meta/send.rb +228 -55
  170. data/meta/str.rb +1 -1
  171. data/meta/super.rb +3 -3
  172. data/meta/{symbol.rb → sym.rb} +1 -1
  173. data/meta/true.rb +1 -1
  174. data/meta/until.rb +1 -1
  175. data/meta/while.rb +2 -2
  176. data/meta/yield.rb +1 -1
  177. data/mutant-rspec.gemspec +2 -2
  178. data/mutant.gemspec +6 -5
  179. data/spec/integration/mutant/isolation/fork_spec.rb +8 -0
  180. data/spec/integration/mutant/rspec_spec.rb +1 -1
  181. data/spec/integration/mutant/test_mutator_handles_types_spec.rb +1 -2
  182. data/spec/integrations.yml +93 -24
  183. data/spec/spec_helper.rb +12 -7
  184. data/spec/support/compress_helper.rb +1 -1
  185. data/spec/support/corpus.rb +115 -50
  186. data/spec/support/fake_actor.rb +5 -5
  187. data/spec/support/file_system.rb +1 -1
  188. data/spec/support/ice_nine_config.rb +3 -3
  189. data/spec/support/ruby_vm.rb +11 -12
  190. data/spec/support/shared_context.rb +22 -13
  191. data/spec/support/test_app.rb +1 -1
  192. data/spec/support/warning.rb +64 -0
  193. data/spec/support/warnings.yml +4 -0
  194. data/spec/support/xspec.rb +177 -0
  195. data/spec/unit/mutant/actor/env_spec.rb +2 -2
  196. data/spec/unit/mutant/actor/sender_spec.rb +1 -1
  197. data/spec/unit/mutant/ast/meta/send_spec.rb +1 -1
  198. data/spec/unit/mutant/ast/named_children_spec.rb +26 -0
  199. data/spec/unit/mutant/ast/regexp/parse_spec.rb +7 -0
  200. data/spec/unit/mutant/ast/regexp/supported_predicate_spec.rb +14 -0
  201. data/spec/unit/mutant/ast/regexp/transformer/lookup_table/table_spec.rb +19 -0
  202. data/spec/unit/mutant/ast/regexp/transformer/lookup_table_spec.rb +33 -0
  203. data/spec/unit/mutant/ast/regexp/transformer_spec.rb +19 -0
  204. data/spec/unit/mutant/ast/regexp_spec.rb +617 -0
  205. data/spec/unit/mutant/cli_spec.rb +7 -45
  206. data/spec/unit/mutant/context_spec.rb +4 -7
  207. data/spec/unit/mutant/env/{boostrap_spec.rb → bootstrap_spec.rb} +2 -2
  208. data/spec/unit/mutant/env_spec.rb +13 -16
  209. data/spec/unit/mutant/expression/namespace/{flat_spec.rb → exact_spec.rb} +0 -0
  210. data/spec/unit/mutant/integration/rspec_spec.rb +2 -2
  211. data/spec/unit/mutant/integration_spec.rb +14 -0
  212. data/spec/unit/mutant/isolation/fork_spec.rb +155 -0
  213. data/spec/unit/mutant/isolation/none_spec.rb +16 -0
  214. data/spec/unit/mutant/loader_spec.rb +1 -1
  215. data/spec/unit/mutant/matcher/methods/instance_spec.rb +2 -4
  216. data/spec/unit/mutant/meta/example/dsl_spec.rb +106 -0
  217. data/spec/unit/mutant/meta/example/verification_spec.rb +120 -0
  218. data/spec/unit/mutant/meta/example_spec.rb +32 -0
  219. data/spec/unit/mutant/mutator/node_spec.rb +37 -4
  220. data/spec/unit/mutant/mutator_spec.rb +21 -0
  221. data/spec/unit/mutant/{runner → parallel}/driver_spec.rb +0 -0
  222. data/spec/unit/mutant/parallel/master_spec.rb +13 -13
  223. data/spec/unit/mutant/registry_spec.rb +47 -0
  224. data/spec/unit/mutant/reporter/cli/printer/config_spec.rb +0 -4
  225. data/spec/unit/mutant/reporter/cli/printer/env_progress_spec.rb +0 -8
  226. data/spec/unit/mutant/reporter/cli/printer/env_result_spec.rb +0 -2
  227. data/spec/unit/mutant/reporter/cli/printer/status_progressive_spec.rb +0 -8
  228. data/spec/unit/mutant/reporter/cli/printer/status_spec.rb +0 -34
  229. data/spec/unit/mutant/reporter/cli_spec.rb +0 -22
  230. data/spec/unit/mutant/repository/diff_spec.rb +6 -6
  231. data/spec/unit/mutant/require_highjack_spec.rb +38 -14
  232. data/spec/unit/mutant/result/env_spec.rb +1 -4
  233. data/spec/unit/mutant/runner_spec.rb +1 -1
  234. data/spec/unit/mutant/subject/method/instance_spec.rb +1 -1
  235. data/spec/unit/mutant/subject_spec.rb +3 -3
  236. data/spec/unit/mutant/util/one_spec.rb +20 -0
  237. data/spec/unit/mutant/zombifier_spec.rb +18 -18
  238. data/test_app/{Gemfile.rspec3.3 → Gemfile.rspec3.5} +2 -2
  239. metadata +94 -24
  240. data/TODO +0 -21
  241. data/lib/mutant/mutator/node/blockarg.rb +0 -13
  242. data/lib/mutant/mutator/node/restarg.rb +0 -13
  243. data/lib/mutant/mutator/registry.rb +0 -49
  244. data/meta/boolean.rb +0 -13
  245. data/meta/regex.rb +0 -19
  246. data/spec/unit/mutant/isolation_spec.rb +0 -104
  247. data/spec/unit/mutant/mutator/registry_spec.rb +0 -57
@@ -1,6 +1,6 @@
1
1
  RSpec.describe Mutant::Actor::Env do
2
- let(:thread) { instance_double(Thread) }
3
- let(:thread_root) { instance_double(Thread.singleton_class) }
2
+ let(:thread) { instance_double(Thread) }
3
+ let(:thread_root) { class_double(Thread) }
4
4
 
5
5
  let(:object) { described_class.new(thread_root) }
6
6
 
@@ -1,5 +1,5 @@
1
1
  RSpec.describe Mutant::Actor::Sender do
2
- let(:object) { described_class.new(condition_variable, mutex, messages) }
2
+ let(:object) { described_class.new(condition_variable, mutex, messages) }
3
3
 
4
4
  let(:condition_variable) { instance_double(ConditionVariable) }
5
5
  let(:mutex) { instance_double(Mutex) }
@@ -23,7 +23,7 @@ RSpec.describe Mutant::AST::Meta::Send do
23
23
  ].map do |values|
24
24
  new(Hash[anima.attribute_names.zip(values)])
25
25
  end.freeze
26
- end
26
+ end # Expectation
27
27
 
28
28
  # Rspec should have a build in for this kind of "n-dimensional assertion with context"
29
29
  (Expectation.anima.attribute_names - %i[name]).each do |name|
@@ -8,6 +8,14 @@ RSpec.describe Mutant::AST::NamedChildren do
8
8
  end
9
9
  end
10
10
 
11
+ def publish
12
+ klass.class_eval do
13
+ public :foo, :bar
14
+
15
+ public :remaining_children, :remaining_children_indices, :remaining_children_with_index
16
+ end
17
+ end
18
+
11
19
  let(:instance) { klass.new(node) }
12
20
 
13
21
  let(:node_foo) { s(:foo) }
@@ -17,26 +25,42 @@ RSpec.describe Mutant::AST::NamedChildren do
17
25
  let(:node) { s(:node, node_foo, node_bar, node_baz) }
18
26
 
19
27
  describe 'generated methods' do
28
+ specify 'are private by default' do
29
+ %i[
30
+ foo
31
+ bar
32
+ remaining_children
33
+ remaining_children_indices
34
+ remaining_children_with_index
35
+ ].each do |name|
36
+ expect(klass.private_instance_methods.include?(name)).to be(true)
37
+ end
38
+ end
39
+
20
40
  describe '#remaining_children' do
21
41
  it 'returns remaining unnamed children' do
42
+ publish
22
43
  expect(instance.remaining_children).to eql([node_baz])
23
44
  end
24
45
  end
25
46
 
26
47
  describe '#remaining_children_indices' do
27
48
  it 'returns remaining unnamed children indices' do
49
+ publish
28
50
  expect(instance.remaining_children_indices).to eql([2])
29
51
  end
30
52
  end
31
53
 
32
54
  describe '#remaining_children_with_index' do
33
55
  it 'returns remaining unnamed children indices' do
56
+ publish
34
57
  expect(instance.remaining_children_with_index).to eql([[node_baz, 2]])
35
58
  end
36
59
  end
37
60
 
38
61
  describe '#foo' do
39
62
  it 'returns named child foo' do
63
+ publish
40
64
  expect(instance.foo).to be(node_foo)
41
65
  end
42
66
  end
@@ -44,6 +68,7 @@ RSpec.describe Mutant::AST::NamedChildren do
44
68
  describe '#bar' do
45
69
  context 'when node is present' do
46
70
  it 'returns named child bar' do
71
+ publish
47
72
  expect(instance.bar).to be(node_bar)
48
73
  end
49
74
  end
@@ -52,6 +77,7 @@ RSpec.describe Mutant::AST::NamedChildren do
52
77
  let(:node) { s(:node, node_foo) }
53
78
 
54
79
  it 'returns nil' do
80
+ publish
55
81
  expect(instance.bar).to be(nil)
56
82
  end
57
83
  end
@@ -0,0 +1,7 @@
1
+ RSpec.describe Mutant::AST::Regexp, '.parse' do
2
+ before { stub_const('RUBY_VERSION', '2.3.9') }
3
+
4
+ it 'parses using minor ruby version' do
5
+ expect(described_class.parse(/foo/).to_re).to eql(/foo/)
6
+ end
7
+ end
@@ -0,0 +1,14 @@
1
+ RSpec.describe Mutant::AST::Regexp, '.supported?' do
2
+ subject { described_class.supported?(expression) }
3
+
4
+ let(:expression) { described_class.parse(regexp) }
5
+ let(:regexp) { /foo/ }
6
+
7
+ it { should be(true) }
8
+
9
+ context 'conditional regular expressions' do
10
+ let(:regexp) { /((?(1)(foo)(bar)))/ }
11
+
12
+ it { should be(false) }
13
+ end
14
+ end
@@ -0,0 +1,19 @@
1
+ RSpec.describe Mutant::AST::Regexp::Transformer::LookupTable::Table do
2
+ subject { table.lookup(:regexp_fake_thing) }
3
+
4
+ let(:expression_class) { class_double(Regexp::Expression) }
5
+
6
+ let(:table) do
7
+ described_class.create(
8
+ [:regexp_fake_thing, %i[thing fake], expression_class]
9
+ )
10
+ end
11
+
12
+ its(:token) { should eql(Regexp::Token.new(:thing, :fake)) }
13
+
14
+ its(:regexp_class) { should be(expression_class) }
15
+
16
+ it 'exposes list of types' do
17
+ expect(table.types).to eql([:regexp_fake_thing])
18
+ end
19
+ end
@@ -0,0 +1,33 @@
1
+ RSpec.describe Mutant::AST::Regexp::Transformer::LookupTable do
2
+ subject(:pair) { mapper.new(s(:regexp_fake)).pair }
3
+
4
+ let(:table) { instance_double(described_class::Table) }
5
+ let(:token) { ::Regexp::Token.new }
6
+ let(:klass) { ::Regexp::Expression }
7
+
8
+ let(:mapping) do
9
+ described_class::Mapping.new(token, klass)
10
+ end
11
+
12
+ let(:mapper) do
13
+ fake_table = table
14
+
15
+ Class.new do
16
+ include Concord.new(:node), Mutant::AST::Regexp::Transformer::LookupTable
17
+
18
+ const_set(:TABLE, fake_table)
19
+
20
+ def pair
21
+ [expression_token, expression_class]
22
+ end
23
+ end
24
+ end
25
+
26
+ before do
27
+ allow(table).to receive(:lookup).with(:regexp_fake).and_return(mapping)
28
+ end
29
+
30
+ it 'constructs regexp lookup table' do
31
+ expect(pair).to eql([token, klass])
32
+ end
33
+ end
@@ -0,0 +1,19 @@
1
+ RSpec.describe Mutant::AST::Regexp::Transformer do
2
+ before do
3
+ stub_const("#{described_class}::REGISTRY", Mutant::Registry.new)
4
+ end
5
+
6
+ it 'registers types to a given class' do
7
+ klass = Class.new(described_class) { register(:regexp_bos_anchor) }
8
+
9
+ expect(described_class.lookup(:regexp_bos_anchor)).to be(klass)
10
+ end
11
+
12
+ it 'rejects duplicate registrations' do
13
+ Class.new(described_class) { register(:regexp_bos_anchor) }
14
+
15
+ expect { Class.new(described_class) { register(:regexp_bos_anchor) } }
16
+ .to raise_error(Mutant::Registry::RegistryError)
17
+ .with_message('Duplicate type registration: :regexp_bos_anchor')
18
+ end
19
+ end
@@ -0,0 +1,617 @@
1
+ module RegexpSpec
2
+ class Expression < SimpleDelegator
3
+ NO_EXPRESSIONS = Object.new.freeze
4
+
5
+ include Equalizer.new(:type, :token, :text, :quantifier, :expressions)
6
+
7
+ def quantifier
8
+ return Quantifier::NONE unless quantified?
9
+
10
+ Quantifier.new(super())
11
+ end
12
+
13
+ def expressions
14
+ return NO_EXPRESSIONS if terminal?
15
+
16
+ super().map(&self.class.public_method(:new))
17
+ end
18
+
19
+ class Quantifier < SimpleDelegator
20
+ NONE = Object.new.freeze
21
+
22
+ include Equalizer.new(:token, :text, :mode, :min, :max)
23
+ end # Quantifier
24
+ end # Expression
25
+
26
+ RSpec.shared_context 'regexp transformation' do
27
+ let(:parsed) { Mutant::AST::Regexp.parse(regexp) }
28
+ let(:ast) { Mutant::AST::Regexp.to_ast(parsed) }
29
+ let(:expression) { Mutant::AST::Regexp.to_expression(ast) }
30
+
31
+ def expect_frozen_expression(expression, root = expression)
32
+ expect(expression.frozen?).to(
33
+ be(true),
34
+ "Expected #{root} to be deep frozen"
35
+ )
36
+
37
+ return if expression.terminal?
38
+
39
+ expression.expressions.each do |subexpression|
40
+ expect_frozen_expression(subexpression, root)
41
+ end
42
+ end
43
+
44
+ it 'transforms into ast' do
45
+ expect(ast).to eql(expected)
46
+ end
47
+
48
+ it 'deep freezes expression mapping' do
49
+ expect_frozen_expression(expression)
50
+ end
51
+
52
+ it 'transforms ast back to expression' do
53
+ expect(Expression.new(expression)).to eql(Expression.new(parsed))
54
+ end
55
+ end
56
+
57
+ RSpec.shared_context 'regexp round trip' do
58
+ let(:round_trip) { expression.to_re }
59
+
60
+ it 'round trips Regexp' do
61
+ expect(round_trip).to eql(regexp)
62
+ end
63
+ end
64
+
65
+ def self.expect_mapping(regexp, type, &block)
66
+ RSpec.describe Mutant::AST::Regexp::Transformer.lookup(type) do
67
+ context "when mapping #{regexp.inspect}" do
68
+ let(:regexp) { regexp }
69
+ let(:expected, &block)
70
+
71
+ include_context 'regexp transformation'
72
+
73
+ return if regexp.encoding.name.eql?('ASCII-8BIT')
74
+
75
+ include_context 'regexp round trip'
76
+ end
77
+ end
78
+ end
79
+ end # RegexpSpec
80
+
81
+ RegexpSpec.expect_mapping(/A/, :regexp_root_expression) do
82
+ s(:regexp_root_expression,
83
+ s(:regexp_literal_literal, 'A'))
84
+ end
85
+
86
+ RegexpSpec.expect_mapping(/\p{Alpha}/, :regexp_alpha_property) do
87
+ s(:regexp_root_expression,
88
+ s(:regexp_alpha_property))
89
+ end
90
+
91
+ RegexpSpec.expect_mapping(/foo|bar/, :regexp_alternation_meta) do
92
+ s(:regexp_root_expression,
93
+ s(:regexp_alternation_meta,
94
+ s(:regexp_sequence_expression,
95
+ s(:regexp_literal_literal, 'foo')),
96
+ s(:regexp_sequence_expression,
97
+ s(:regexp_literal_literal, 'bar'))))
98
+ end
99
+
100
+ RegexpSpec.expect_mapping(/(?>a)/, :regexp_atomic_group) do
101
+ s(:regexp_root_expression,
102
+ s(:regexp_atomic_group,
103
+ s(:regexp_literal_literal, 'a')))
104
+ end
105
+
106
+ RegexpSpec.expect_mapping(/\\/, :regexp_backslash_escape) do
107
+ s(:regexp_root_expression,
108
+ s(:regexp_backslash_escape, '\\\\'))
109
+ end
110
+
111
+ RegexpSpec.expect_mapping(/^/, :regexp_bol_anchor) do
112
+ s(:regexp_root_expression,
113
+ s(:regexp_bol_anchor))
114
+ end
115
+
116
+ RegexpSpec.expect_mapping(/\A/, :regexp_bos_anchor) do
117
+ s(:regexp_root_expression,
118
+ s(:regexp_bos_anchor))
119
+ end
120
+
121
+ RegexpSpec.expect_mapping(/(foo)/, :regexp_capture_group) do
122
+ s(:regexp_root_expression,
123
+ s(:regexp_capture_group,
124
+ s(:regexp_literal_literal, 'foo')))
125
+ end
126
+
127
+ RegexpSpec.expect_mapping(/()\1/, :regexp_number_backref) do
128
+ s(:regexp_root_expression,
129
+ s(:regexp_capture_group),
130
+ s(:regexp_number_backref, '\\1'))
131
+ end
132
+
133
+ RegexpSpec.expect_mapping(/(a)*/, :regexp_capture_group) do
134
+ s(:regexp_root_expression,
135
+ s(:regexp_greedy_zero_or_more, 0, -1,
136
+ s(:regexp_capture_group,
137
+ s(:regexp_literal_literal, 'a'))))
138
+ end
139
+
140
+ RegexpSpec.expect_mapping(/\r/, :regexp_carriage_escape) do
141
+ s(:regexp_root_expression,
142
+ s(:regexp_carriage_escape))
143
+ end
144
+
145
+ RegexpSpec.expect_mapping(/\a/, :regexp_bell_escape) do
146
+ s(:regexp_root_expression,
147
+ s(:regexp_bell_escape))
148
+ end
149
+
150
+ RegexpSpec.expect_mapping(/\?/, :regexp_zero_or_one_escape) do
151
+ s(:regexp_root_expression,
152
+ s(:regexp_zero_or_one_escape))
153
+ end
154
+
155
+ RegexpSpec.expect_mapping(/\|/, :regexp_alternation_escape) do
156
+ s(:regexp_root_expression,
157
+ s(:regexp_alternation_escape))
158
+ end
159
+
160
+ RegexpSpec.expect_mapping(/\c2/, :regexp_control_escape) do
161
+ s(:regexp_root_expression,
162
+ s(:regexp_control_escape, '\\c2'))
163
+ end
164
+
165
+ RegexpSpec.expect_mapping(/\M-B/n, :regexp_meta_sequence_escape) do
166
+ s(:regexp_root_expression,
167
+ s(:regexp_meta_sequence_escape, '\M-B'))
168
+ end
169
+
170
+ RegexpSpec.expect_mapping(/\K/, :regexp_mark_keep) do
171
+ s(:regexp_root_expression,
172
+ s(:regexp_mark_keep))
173
+ end
174
+
175
+ RegexpSpec.expect_mapping(/\e/, :regexp_escape_escape) do
176
+ s(:regexp_root_expression,
177
+ s(:regexp_escape_escape))
178
+ end
179
+
180
+ RegexpSpec.expect_mapping(/\f/, :regexp_form_feed_escape) do
181
+ s(:regexp_root_expression,
182
+ s(:regexp_form_feed_escape))
183
+ end
184
+
185
+ RegexpSpec.expect_mapping(/\v/, :regexp_vertical_tab_escape) do
186
+ s(:regexp_root_expression,
187
+ s(:regexp_vertical_tab_escape))
188
+ end
189
+
190
+ RegexpSpec.expect_mapping(/\e/, :regexp_escape_escape) do
191
+ s(:regexp_root_expression,
192
+ s(:regexp_escape_escape))
193
+ end
194
+
195
+ RegexpSpec.expect_mapping(/[ab]+/, :regexp_character_set) do
196
+ s(:regexp_root_expression,
197
+ s(:regexp_greedy_one_or_more, 1, -1,
198
+ s(:regexp_character_set, 'a', 'b')))
199
+ end
200
+
201
+ RegexpSpec.expect_mapping(/[ab]/, :regexp_character_set) do
202
+ s(:regexp_root_expression,
203
+ s(:regexp_character_set, 'a', 'b'))
204
+ end
205
+
206
+ RegexpSpec.expect_mapping(/[a-j]/, :regexp_character_set) do
207
+ s(:regexp_root_expression,
208
+ s(:regexp_character_set, 'a-j'))
209
+ end
210
+
211
+ RegexpSpec.expect_mapping(/\u{9879}/, :regexp_codepoint_list_escape) do
212
+ s(:regexp_root_expression,
213
+ s(:regexp_codepoint_list_escape, '\\u{9879}'))
214
+ end
215
+
216
+ RegexpSpec.expect_mapping(/(?#foo)/, :regexp_comment_group) do
217
+ s(:regexp_root_expression,
218
+ s(:regexp_comment_group, '(?#foo)'))
219
+ end
220
+
221
+ RegexpSpec.expect_mapping(/(?x-: # comment
222
+ )/, :regexp_comment_free_space) do
223
+ s(:regexp_root_expression,
224
+ s(:regexp_options_group, {
225
+ m: false,
226
+ i: false,
227
+ x: true,
228
+ d: false,
229
+ a: false,
230
+ u: false
231
+ },
232
+ s(:regexp_whitespace_free_space, ' '),
233
+ s(:regexp_comment_free_space, "# comment\n")))
234
+ end
235
+
236
+ RegexpSpec.expect_mapping(/\d/, :regexp_digit_type) do
237
+ s(:regexp_root_expression,
238
+ s(:regexp_digit_type))
239
+ end
240
+
241
+ RegexpSpec.expect_mapping(/\./, :regexp_dot_escape) do
242
+ s(:regexp_root_expression,
243
+ s(:regexp_dot_escape))
244
+ end
245
+
246
+ RegexpSpec.expect_mapping(/.+/, :regexp_dot_meta) do
247
+ s(:regexp_root_expression,
248
+ s(:regexp_greedy_one_or_more, 1, -1,
249
+ s(:regexp_dot_meta)))
250
+ end
251
+
252
+ RegexpSpec.expect_mapping(/$/, :regexp_eol_anchor) do
253
+ s(:regexp_root_expression,
254
+ s(:regexp_eol_anchor))
255
+ end
256
+
257
+ RegexpSpec.expect_mapping(/\$/, :regexp_eol_escape) do
258
+ s(:regexp_root_expression,
259
+ s(:regexp_eol_escape))
260
+ end
261
+
262
+ RegexpSpec.expect_mapping(/\z/, :regexp_eos_anchor) do
263
+ s(:regexp_root_expression,
264
+ s(:regexp_eos_anchor))
265
+ end
266
+
267
+ RegexpSpec.expect_mapping(/\Z/, :regexp_eos_ob_eol_anchor) do
268
+ s(:regexp_root_expression,
269
+ s(:regexp_eos_ob_eol_anchor))
270
+ end
271
+
272
+ RegexpSpec.expect_mapping(/a{1,}/, :regexp_greedy_interval) do
273
+ s(:regexp_root_expression,
274
+ s(:regexp_greedy_interval, 1, -1,
275
+ s(:regexp_literal_literal, 'a')))
276
+ end
277
+
278
+ RegexpSpec.expect_mapping(/.{2}/, :regexp_greedy_interval) do
279
+ s(:regexp_root_expression,
280
+ s(:regexp_greedy_interval, 2, 2,
281
+ s(:regexp_dot_meta)))
282
+ end
283
+
284
+ RegexpSpec.expect_mapping(/.{3,5}/, :regexp_greedy_interval) do
285
+ s(:regexp_root_expression,
286
+ s(:regexp_greedy_interval, 3, 5,
287
+ s(:regexp_dot_meta)))
288
+ end
289
+
290
+ RegexpSpec.expect_mapping(/.{,3}/, :regexp_greedy_interval) do
291
+ s(:regexp_root_expression,
292
+ s(:regexp_greedy_interval, 0, 3,
293
+ s(:regexp_dot_meta)))
294
+ end
295
+
296
+ RegexpSpec.expect_mapping(/.+/, :regexp_greedy_one_or_more) do
297
+ s(:regexp_root_expression,
298
+ s(:regexp_greedy_one_or_more, 1, -1,
299
+ s(:regexp_dot_meta)))
300
+ end
301
+
302
+ RegexpSpec.expect_mapping(/[ab]+/, :regexp_greedy_one_or_more) do
303
+ s(:regexp_root_expression,
304
+ s(:regexp_greedy_one_or_more, 1, -1,
305
+ s(:regexp_character_set, 'a', 'b')))
306
+ end
307
+
308
+ RegexpSpec.expect_mapping(/(a)*/, :regexp_greedy_zero_or_more) do
309
+ s(:regexp_root_expression,
310
+ s(:regexp_greedy_zero_or_more, 0, -1,
311
+ s(:regexp_capture_group,
312
+ s(:regexp_literal_literal, 'a'))))
313
+ end
314
+
315
+ RegexpSpec.expect_mapping(/.*/, :regexp_greedy_zero_or_more) do
316
+ s(:regexp_root_expression,
317
+ s(:regexp_greedy_zero_or_more, 0, -1,
318
+ s(:regexp_dot_meta)))
319
+ end
320
+
321
+ RegexpSpec.expect_mapping(/.?/, :regexp_greedy_zero_or_one) do
322
+ s(:regexp_root_expression,
323
+ s(:regexp_greedy_zero_or_one, 0, 1,
324
+ s(:regexp_dot_meta)))
325
+ end
326
+
327
+ RegexpSpec.expect_mapping(/\)/, :regexp_group_close_escape) do
328
+ s(:regexp_root_expression,
329
+ s(:regexp_group_close_escape))
330
+ end
331
+
332
+ RegexpSpec.expect_mapping(/\(/, :regexp_group_open_escape) do
333
+ s(:regexp_root_expression,
334
+ s(:regexp_group_open_escape))
335
+ end
336
+
337
+ RegexpSpec.expect_mapping(/\xFF/n, :regexp_hex_escape) do
338
+ s(:regexp_root_expression,
339
+ s(:regexp_hex_escape, '\\xFF'))
340
+ end
341
+
342
+ RegexpSpec.expect_mapping(/\h/, :regexp_hex_type) do
343
+ s(:regexp_root_expression,
344
+ s(:regexp_hex_type))
345
+ end
346
+
347
+ RegexpSpec.expect_mapping(/\H/, :regexp_hex_type) do
348
+ s(:regexp_root_expression,
349
+ s(:regexp_nonhex_type))
350
+ end
351
+
352
+ RegexpSpec.expect_mapping(/\}/, :regexp_interval_close_escape) do
353
+ s(:regexp_root_expression,
354
+ s(:regexp_interval_close_escape))
355
+ end
356
+
357
+ RegexpSpec.expect_mapping(/\{/, :regexp_interval_open_escape) do
358
+ s(:regexp_root_expression,
359
+ s(:regexp_interval_open_escape))
360
+ end
361
+
362
+ RegexpSpec.expect_mapping(/\p{L}/, :regexp_letter_any_property) do
363
+ s(:regexp_root_expression,
364
+ s(:regexp_letter_any_property))
365
+ end
366
+
367
+ RegexpSpec.expect_mapping(/\-/, :regexp_literal_escape) do
368
+ s(:regexp_root_expression,
369
+ s(:regexp_literal_escape, '\\-'))
370
+ end
371
+
372
+ RegexpSpec.expect_mapping(/\ /, :regexp_literal_escape) do
373
+ s(:regexp_root_expression,
374
+ s(:regexp_literal_escape, '\\ '))
375
+ end
376
+
377
+ RegexpSpec.expect_mapping(/\#/, :regexp_literal_escape) do
378
+ s(:regexp_root_expression,
379
+ s(:regexp_literal_escape, '\\#'))
380
+ end
381
+
382
+ RegexpSpec.expect_mapping(/\:/, :regexp_literal_escape) do
383
+ s(:regexp_root_expression,
384
+ s(:regexp_literal_escape, '\\:'))
385
+ end
386
+
387
+ RegexpSpec.expect_mapping(/\</, :regexp_literal_escape) do
388
+ s(:regexp_root_expression,
389
+ s(:regexp_literal_escape, '\\<'))
390
+ end
391
+
392
+ RegexpSpec.expect_mapping(/foo/, :regexp_literal_literal) do
393
+ s(:regexp_root_expression,
394
+ s(:regexp_literal_literal, 'foo'))
395
+ end
396
+
397
+ RegexpSpec.expect_mapping(/a+/, :regexp_literal_literal) do
398
+ s(:regexp_root_expression,
399
+ s(:regexp_greedy_one_or_more, 1, -1,
400
+ s(:regexp_literal_literal, 'a')))
401
+ end
402
+
403
+ RegexpSpec.expect_mapping(/(?=a)/, :regexp_lookahead_assertion) do
404
+ s(:regexp_root_expression,
405
+ s(:regexp_lookahead_assertion,
406
+ s(:regexp_literal_literal, 'a')))
407
+ end
408
+
409
+ RegexpSpec.expect_mapping(/(?<=a)/, :regexp_lookbehind_assertion) do
410
+ s(:regexp_root_expression,
411
+ s(:regexp_lookbehind_assertion,
412
+ s(:regexp_literal_literal, 'a')))
413
+ end
414
+
415
+ RegexpSpec.expect_mapping(/\G/, :regexp_match_start_anchor) do
416
+ s(:regexp_root_expression,
417
+ s(:regexp_match_start_anchor))
418
+ end
419
+
420
+ RegexpSpec.expect_mapping(/(?<foo>)/, :regexp_named_group) do
421
+ s(:regexp_root_expression,
422
+ s(:regexp_named_group, '(?<foo>'))
423
+ end
424
+
425
+ RegexpSpec.expect_mapping(/(?<a>)\g<a>/, :regexp_name_call_backref) do
426
+ s(:regexp_root_expression,
427
+ s(:regexp_named_group, '(?<a>'),
428
+ s(:regexp_name_call_backref, '\\g<a>'))
429
+ end
430
+
431
+ RegexpSpec.expect_mapping(/\n/, :regexp_newline_escape) do
432
+ s(:regexp_root_expression,
433
+ s(:regexp_newline_escape))
434
+ end
435
+
436
+ RegexpSpec.expect_mapping(/(?!a)/, :regexp_nlookahead_assertion) do
437
+ s(:regexp_root_expression,
438
+ s(:regexp_nlookahead_assertion,
439
+ s(:regexp_literal_literal, 'a')))
440
+ end
441
+
442
+ RegexpSpec.expect_mapping(/(?<!a)/, :regexp_nlookbehind_assertion) do
443
+ s(:regexp_root_expression,
444
+ s(:regexp_nlookbehind_assertion,
445
+ s(:regexp_literal_literal, 'a')))
446
+ end
447
+
448
+ RegexpSpec.expect_mapping(/\D/, :regexp_nondigit_type) do
449
+ s(:regexp_root_expression,
450
+ s(:regexp_nondigit_type))
451
+ end
452
+
453
+ RegexpSpec.expect_mapping(/\S/, :regexp_nonspace_type) do
454
+ s(:regexp_root_expression,
455
+ s(:regexp_nonspace_type))
456
+ end
457
+
458
+ RegexpSpec.expect_mapping(/\B/, :regexp_nonword_boundary_anchor) do
459
+ s(:regexp_root_expression,
460
+ s(:regexp_nonword_boundary_anchor))
461
+ end
462
+
463
+ RegexpSpec.expect_mapping(/\W/, :regexp_nonword_type) do
464
+ s(:regexp_root_expression,
465
+ s(:regexp_nonword_type))
466
+ end
467
+
468
+ RegexpSpec.expect_mapping(/\+/, :regexp_one_or_more_escape) do
469
+ s(:regexp_root_expression,
470
+ s(:regexp_one_or_more_escape))
471
+ end
472
+
473
+ RegexpSpec.expect_mapping(/(?i-:a)+/, :regexp_options_group) do
474
+ s(:regexp_root_expression,
475
+ s(:regexp_greedy_one_or_more, 1, -1,
476
+ s(:regexp_options_group,
477
+ {
478
+ m: false,
479
+ i: true,
480
+ x: false,
481
+ d: false,
482
+ a: false,
483
+ u: false
484
+ },
485
+ s(:regexp_literal_literal, 'a'))))
486
+ end
487
+
488
+ RegexpSpec.expect_mapping(/(?x-: #{"\n"} )/, :regexp_whitespace_free_space) do
489
+ s(:regexp_root_expression,
490
+ s(:regexp_options_group,
491
+ {
492
+ m: false,
493
+ i: false,
494
+ x: true,
495
+ d: false,
496
+ a: false,
497
+ u: false
498
+ },
499
+ s(:regexp_whitespace_free_space, " \n ")))
500
+ end
501
+
502
+ RegexpSpec.expect_mapping(/(?:a)/, :regexp_passive_group) do
503
+ s(:regexp_root_expression,
504
+ s(:regexp_passive_group,
505
+ s(:regexp_literal_literal, 'a')))
506
+ end
507
+
508
+ RegexpSpec.expect_mapping(/.{1,3}+/, :regexp_possessive_interval) do
509
+ s(:regexp_root_expression,
510
+ s(:regexp_possessive_interval, 1, 3,
511
+ s(:regexp_dot_meta)))
512
+ end
513
+
514
+ RegexpSpec.expect_mapping(/.++/, :regexp_possessive_one_or_more) do
515
+ s(:regexp_root_expression,
516
+ s(:regexp_possessive_one_or_more, 1, -1,
517
+ s(:regexp_dot_meta)))
518
+ end
519
+
520
+ RegexpSpec.expect_mapping(/.*+/, :regexp_possessive_zero_or_more) do
521
+ s(:regexp_root_expression,
522
+ s(:regexp_possessive_zero_or_more, 0, -1,
523
+ s(:regexp_dot_meta)))
524
+ end
525
+
526
+ RegexpSpec.expect_mapping(/.?+/, :regexp_possessive_zero_or_one) do
527
+ s(:regexp_root_expression,
528
+ s(:regexp_possessive_zero_or_one, 0, 1,
529
+ s(:regexp_dot_meta)))
530
+ end
531
+
532
+ RegexpSpec.expect_mapping(/.{1,3}?/, :regexp_reluctant_interval) do
533
+ s(:regexp_root_expression,
534
+ s(:regexp_reluctant_interval, 1, 3,
535
+ s(:regexp_dot_meta)))
536
+ end
537
+
538
+ RegexpSpec.expect_mapping(/.+?/, :regexp_reluctant_one_or_more) do
539
+ s(:regexp_root_expression,
540
+ s(:regexp_reluctant_one_or_more, 1, -1,
541
+ s(:regexp_dot_meta)))
542
+ end
543
+
544
+ RegexpSpec.expect_mapping(/.*?/, :regexp_reluctant_zero_or_more) do
545
+ s(:regexp_root_expression,
546
+ s(:regexp_reluctant_zero_or_more, 0, -1,
547
+ s(:regexp_dot_meta)))
548
+ end
549
+
550
+ RegexpSpec.expect_mapping(/\p{Arabic}/, :regexp_script_arabic_property) do
551
+ s(:regexp_root_expression,
552
+ s(:regexp_script_arabic_property))
553
+ end
554
+
555
+ RegexpSpec.expect_mapping(/\p{Han}/, :regexp_script_han_property) do
556
+ s(:regexp_root_expression,
557
+ s(:regexp_script_han_property))
558
+ end
559
+
560
+ RegexpSpec.expect_mapping(/\p{Hangul}/, :regexp_script_hangul_property) do
561
+ s(:regexp_root_expression,
562
+ s(:regexp_script_hangul_property))
563
+ end
564
+
565
+ RegexpSpec.expect_mapping(/\p{Hiragana}/, :regexp_script_hiragana_property) do
566
+ s(:regexp_root_expression,
567
+ s(:regexp_script_hiragana_property))
568
+ end
569
+
570
+ RegexpSpec.expect_mapping(/\p{Katakana}/, :regexp_script_katakana_property) do
571
+ s(:regexp_root_expression,
572
+ s(:regexp_script_katakana_property))
573
+ end
574
+
575
+ RegexpSpec.expect_mapping(/foo|bar/, :regexp_sequence_expression) do
576
+ s(:regexp_root_expression,
577
+ s(:regexp_alternation_meta,
578
+ s(:regexp_sequence_expression,
579
+ s(:regexp_literal_literal, 'foo')),
580
+ s(:regexp_sequence_expression,
581
+ s(:regexp_literal_literal, 'bar'))))
582
+ end
583
+
584
+ RegexpSpec.expect_mapping(/\]/, :regexp_set_close_escape) do
585
+ s(:regexp_root_expression,
586
+ s(:regexp_set_close_escape))
587
+ end
588
+
589
+ RegexpSpec.expect_mapping(/\[/, :regexp_set_open_escape) do
590
+ s(:regexp_root_expression,
591
+ s(:regexp_set_open_escape))
592
+ end
593
+
594
+ RegexpSpec.expect_mapping(/\s/, :regexp_space_type) do
595
+ s(:regexp_root_expression,
596
+ s(:regexp_space_type))
597
+ end
598
+
599
+ RegexpSpec.expect_mapping(/\t/, :regexp_tab_escape) do
600
+ s(:regexp_root_expression,
601
+ s(:regexp_tab_escape, '\\t'))
602
+ end
603
+
604
+ RegexpSpec.expect_mapping(/\b/, :regexp_word_boundary_anchor) do
605
+ s(:regexp_root_expression,
606
+ s(:regexp_word_boundary_anchor))
607
+ end
608
+
609
+ RegexpSpec.expect_mapping(/\w/, :regexp_word_type) do
610
+ s(:regexp_root_expression,
611
+ s(:regexp_word_type))
612
+ end
613
+
614
+ RegexpSpec.expect_mapping(/\*/, :regexp_zero_or_more_escape) do
615
+ s(:regexp_root_expression,
616
+ s(:regexp_zero_or_more_escape))
617
+ end