mutant 0.8.0 → 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (187) hide show
  1. checksums.yaml +4 -4
  2. data/Changelog.md +7 -0
  3. data/config/flay.yml +1 -1
  4. data/config/reek.yml +1 -0
  5. data/lib/mutant.rb +10 -3
  6. data/lib/mutant/actor.rb +2 -5
  7. data/lib/mutant/actor/env.rb +1 -3
  8. data/lib/mutant/actor/mailbox.rb +2 -4
  9. data/lib/mutant/actor/receiver.rb +0 -2
  10. data/lib/mutant/actor/sender.rb +0 -1
  11. data/lib/mutant/ast.rb +22 -28
  12. data/lib/mutant/ast/meta.rb +8 -88
  13. data/lib/mutant/ast/named_children.rb +1 -8
  14. data/lib/mutant/ast/sexp.rb +0 -2
  15. data/lib/mutant/cache.rb +1 -3
  16. data/lib/mutant/cli.rb +9 -19
  17. data/lib/mutant/color.rb +0 -3
  18. data/lib/mutant/config.rb +6 -2
  19. data/lib/mutant/context.rb +2 -4
  20. data/lib/mutant/context/scope.rb +10 -16
  21. data/lib/mutant/delegator.rb +0 -3
  22. data/lib/mutant/diff.rb +8 -17
  23. data/lib/mutant/env.rb +3 -5
  24. data/lib/mutant/env/bootstrap.rb +32 -39
  25. data/lib/mutant/expression.rb +14 -132
  26. data/lib/mutant/expression/method.rb +25 -42
  27. data/lib/mutant/expression/methods.rb +17 -29
  28. data/lib/mutant/expression/namespace.rb +33 -28
  29. data/lib/mutant/expression/parser.rb +71 -0
  30. data/lib/mutant/integration.rb +17 -16
  31. data/lib/mutant/isolation.rb +14 -14
  32. data/lib/mutant/loader.rb +2 -4
  33. data/lib/mutant/matcher.rb +1 -11
  34. data/lib/mutant/matcher/chain.rb +0 -1
  35. data/lib/mutant/matcher/compiler.rb +19 -52
  36. data/lib/mutant/matcher/config.rb +65 -5
  37. data/lib/mutant/matcher/filter.rb +11 -1
  38. data/lib/mutant/matcher/method.rb +11 -21
  39. data/lib/mutant/matcher/method/instance.rb +2 -16
  40. data/lib/mutant/matcher/method/singleton.rb +3 -20
  41. data/lib/mutant/matcher/methods.rb +11 -21
  42. data/lib/mutant/matcher/namespace.rb +0 -4
  43. data/lib/mutant/matcher/null.rb +0 -1
  44. data/lib/mutant/matcher/scope.rb +0 -12
  45. data/lib/mutant/meta.rb +0 -1
  46. data/lib/mutant/meta/example.rb +12 -26
  47. data/lib/mutant/meta/example/dsl.rb +1 -8
  48. data/lib/mutant/mutation.rb +6 -14
  49. data/lib/mutant/mutator.rb +2 -14
  50. data/lib/mutant/mutator/node.rb +6 -33
  51. data/lib/mutant/mutator/node/and_asgn.rb +0 -1
  52. data/lib/mutant/mutator/node/argument.rb +0 -5
  53. data/lib/mutant/mutator/node/arguments.rb +1 -7
  54. data/lib/mutant/mutator/node/begin.rb +0 -2
  55. data/lib/mutant/mutator/node/binary.rb +0 -3
  56. data/lib/mutant/mutator/node/block.rb +0 -2
  57. data/lib/mutant/mutator/node/break.rb +0 -1
  58. data/lib/mutant/mutator/node/case.rb +0 -3
  59. data/lib/mutant/mutator/node/conditional_loop.rb +0 -1
  60. data/lib/mutant/mutator/node/const.rb +0 -1
  61. data/lib/mutant/mutator/node/define.rb +0 -1
  62. data/lib/mutant/mutator/node/defined.rb +0 -1
  63. data/lib/mutant/mutator/node/dstr.rb +0 -1
  64. data/lib/mutant/mutator/node/dsym.rb +0 -1
  65. data/lib/mutant/mutator/node/generic.rb +0 -1
  66. data/lib/mutant/mutator/node/if.rb +0 -4
  67. data/lib/mutant/mutator/node/kwbegin.rb +0 -1
  68. data/lib/mutant/mutator/node/literal/array.rb +0 -2
  69. data/lib/mutant/mutator/node/literal/boolean.rb +0 -1
  70. data/lib/mutant/mutator/node/literal/fixnum.rb +2 -5
  71. data/lib/mutant/mutator/node/literal/float.rb +1 -4
  72. data/lib/mutant/mutator/node/literal/hash.rb +0 -3
  73. data/lib/mutant/mutator/node/literal/nil.rb +0 -1
  74. data/lib/mutant/mutator/node/literal/range.rb +1 -5
  75. data/lib/mutant/mutator/node/literal/regex.rb +1 -3
  76. data/lib/mutant/mutator/node/literal/string.rb +0 -1
  77. data/lib/mutant/mutator/node/literal/symbol.rb +0 -1
  78. data/lib/mutant/mutator/node/masgn.rb +0 -1
  79. data/lib/mutant/mutator/node/match_current_line.rb +0 -1
  80. data/lib/mutant/mutator/node/mlhs.rb +0 -1
  81. data/lib/mutant/mutator/node/named_value/access.rb +0 -1
  82. data/lib/mutant/mutator/node/named_value/constant_assignment.rb +0 -2
  83. data/lib/mutant/mutator/node/named_value/variable_assignment.rb +0 -2
  84. data/lib/mutant/mutator/node/next.rb +0 -1
  85. data/lib/mutant/mutator/node/noop.rb +0 -1
  86. data/lib/mutant/mutator/node/nthref.rb +0 -1
  87. data/lib/mutant/mutator/node/op_asgn.rb +0 -1
  88. data/lib/mutant/mutator/node/or_asgn.rb +1 -2
  89. data/lib/mutant/mutator/node/resbody.rb +0 -2
  90. data/lib/mutant/mutator/node/rescue.rb +1 -6
  91. data/lib/mutant/mutator/node/return.rb +0 -1
  92. data/lib/mutant/mutator/node/send.rb +16 -17
  93. data/lib/mutant/mutator/node/send/attribute_assignment.rb +0 -3
  94. data/lib/mutant/mutator/node/send/binary.rb +0 -1
  95. data/lib/mutant/mutator/node/send/index.rb +0 -3
  96. data/lib/mutant/mutator/node/splat.rb +0 -1
  97. data/lib/mutant/mutator/node/super.rb +0 -1
  98. data/lib/mutant/mutator/node/when.rb +2 -7
  99. data/lib/mutant/mutator/node/yield.rb +0 -1
  100. data/lib/mutant/mutator/node/zsuper.rb +0 -1
  101. data/lib/mutant/mutator/registry.rb +1 -4
  102. data/lib/mutant/mutator/util.rb +0 -2
  103. data/lib/mutant/mutator/util/array.rb +0 -3
  104. data/lib/mutant/mutator/util/symbol.rb +0 -1
  105. data/lib/mutant/parallel.rb +3 -9
  106. data/lib/mutant/parallel/master.rb +7 -17
  107. data/lib/mutant/parallel/source.rb +2 -7
  108. data/lib/mutant/parallel/worker.rb +1 -5
  109. data/lib/mutant/reporter.rb +0 -4
  110. data/lib/mutant/reporter/cli.rb +1 -8
  111. data/lib/mutant/reporter/cli/format.rb +7 -18
  112. data/lib/mutant/reporter/cli/printer.rb +2 -12
  113. data/lib/mutant/reporter/cli/printer/config.rb +1 -4
  114. data/lib/mutant/reporter/cli/printer/env_progress.rb +3 -7
  115. data/lib/mutant/reporter/cli/printer/env_result.rb +0 -1
  116. data/lib/mutant/reporter/cli/printer/mutation_progress_result.rb +0 -2
  117. data/lib/mutant/reporter/cli/printer/mutation_result.rb +3 -11
  118. data/lib/mutant/reporter/cli/printer/status.rb +1 -4
  119. data/lib/mutant/reporter/cli/printer/status_progressive.rb +1 -3
  120. data/lib/mutant/reporter/cli/printer/subject_progress.rb +0 -5
  121. data/lib/mutant/reporter/cli/printer/subject_result.rb +0 -1
  122. data/lib/mutant/reporter/cli/printer/test_result.rb +0 -1
  123. data/lib/mutant/reporter/cli/tput.rb +4 -1
  124. data/lib/mutant/reporter/trace.rb +2 -4
  125. data/lib/mutant/repository.rb +88 -0
  126. data/lib/mutant/require_highjack.rb +0 -1
  127. data/lib/mutant/result.rb +25 -48
  128. data/lib/mutant/runner.rb +7 -16
  129. data/lib/mutant/runner/sink.rb +3 -11
  130. data/lib/mutant/selector.rb +1 -2
  131. data/lib/mutant/selector/expression.rb +1 -2
  132. data/lib/mutant/subject.rb +10 -21
  133. data/lib/mutant/subject/method.rb +11 -12
  134. data/lib/mutant/subject/method/instance.rb +1 -5
  135. data/lib/mutant/subject/method/singleton.rb +1 -3
  136. data/lib/mutant/test.rb +1 -2
  137. data/lib/mutant/version.rb +2 -2
  138. data/lib/mutant/warning_filter.rb +2 -7
  139. data/lib/mutant/zombifier.rb +6 -10
  140. data/meta/send.rb +8 -0
  141. data/spec/spec_helper.rb +5 -1
  142. data/spec/support/corpus.rb +5 -9
  143. data/spec/support/rb_bug.rb +0 -1
  144. data/spec/support/rspec.rb +0 -1
  145. data/spec/support/ruby_vm.rb +0 -2
  146. data/spec/unit/mutant/ast/meta/send_spec.rb +42 -0
  147. data/spec/unit/mutant/ast/named_children_spec.rb +51 -0
  148. data/spec/unit/mutant/ast/sexp_spec.rb +36 -0
  149. data/spec/unit/mutant/ast_spec.rb +8 -0
  150. data/spec/unit/mutant/cli_spec.rb +34 -19
  151. data/spec/unit/mutant/context/scope_spec.rb +11 -0
  152. data/spec/unit/mutant/env/boostrap_spec.rb +5 -2
  153. data/spec/unit/mutant/env_spec.rb +14 -15
  154. data/spec/unit/mutant/expression/method_spec.rb +10 -14
  155. data/spec/unit/mutant/expression/methods_spec.rb +24 -11
  156. data/spec/unit/mutant/expression/namespace/flat_spec.rb +5 -6
  157. data/spec/unit/mutant/expression/namespace/recursive_spec.rb +16 -10
  158. data/spec/unit/mutant/expression/parser_spec.rb +67 -0
  159. data/spec/unit/mutant/expression_spec.rb +24 -57
  160. data/spec/unit/mutant/integration/rspec_spec.rb +7 -7
  161. data/spec/unit/mutant/integration_spec.rb +2 -2
  162. data/spec/unit/mutant/isolation_spec.rb +31 -29
  163. data/spec/unit/mutant/matcher/compiler/subject_prefix_spec.rb +2 -2
  164. data/spec/unit/mutant/matcher/compiler_spec.rb +27 -58
  165. data/spec/unit/mutant/matcher/config_spec.rb +45 -0
  166. data/spec/unit/mutant/matcher/filter_spec.rb +12 -5
  167. data/spec/unit/mutant/matcher/method/instance_spec.rb +0 -1
  168. data/spec/unit/mutant/matcher/method/singleton_spec.rb +0 -1
  169. data/spec/unit/mutant/matcher/namespace_spec.rb +4 -4
  170. data/spec/unit/mutant/parallel/worker_spec.rb +1 -1
  171. data/spec/unit/mutant/reporter/cli/printer/config_spec.rb +4 -4
  172. data/spec/unit/mutant/reporter/cli/printer/env_progress_spec.rb +7 -7
  173. data/spec/unit/mutant/reporter/cli/printer/env_result_spec.rb +2 -2
  174. data/spec/unit/mutant/reporter/cli/printer/status_progressive_spec.rb +2 -2
  175. data/spec/unit/mutant/reporter/cli/printer/status_spec.rb +12 -12
  176. data/spec/unit/mutant/reporter/cli/printer/subject_progress_spec.rb +1 -1
  177. data/spec/unit/mutant/reporter/cli_spec.rb +9 -10
  178. data/spec/unit/mutant/repository/diff_spec.rb +80 -0
  179. data/spec/unit/mutant/repository/subject_filter_spec.rb +28 -0
  180. data/spec/unit/mutant/result/env_spec.rb +1 -1
  181. data/spec/unit/mutant/runner_spec.rb +0 -1
  182. data/spec/unit/mutant/selector/expression_spec.rb +14 -14
  183. data/spec/unit/mutant/subject/method/instance_spec.rb +2 -2
  184. data/spec/unit/mutant/subject/method/singleton_spec.rb +2 -2
  185. data/spec/unit/mutant/subject_spec.rb +5 -2
  186. metadata +20 -3
  187. data/spec/support/mutation_verifier.rb +0 -96
@@ -0,0 +1,11 @@
1
+ RSpec.describe Mutant::Context::Scope do
2
+ let(:object) { described_class.new(scope, source_path) }
3
+ let(:scope) { double('scope', name: double('name')) }
4
+ let(:source_path) { double('source path') }
5
+
6
+ describe '#identification' do
7
+ subject { object.identification }
8
+
9
+ it { should be(scope.name) }
10
+ end
11
+ end
@@ -9,6 +9,8 @@ RSpec.describe Mutant::Env::Bootstrap do
9
9
  )
10
10
  end
11
11
 
12
+ let(:integration) { Mutant::Integration::Null.new(config) }
13
+
12
14
  let(:expected_env) do
13
15
  Mutant::Env.new(
14
16
  cache: Mutant::Cache.new,
@@ -16,8 +18,9 @@ RSpec.describe Mutant::Env::Bootstrap do
16
18
  matchable_scopes: [],
17
19
  mutations: [],
18
20
  config: config,
19
- selector: Mutant::Selector::Expression.new(config.integration),
20
- actor_env: Mutant::Actor::Env.new(Thread)
21
+ selector: Mutant::Selector::Expression.new(integration),
22
+ actor_env: Mutant::Actor::Env.new(Thread),
23
+ integration: integration
21
24
  )
22
25
  end
23
26
 
@@ -8,26 +8,26 @@ RSpec.describe Mutant::Env do
8
8
  selector: selector,
9
9
  subjects: [],
10
10
  mutations: [],
11
- matchable_scopes: []
11
+ matchable_scopes: [],
12
+ integration: integration
12
13
  )
13
14
  end
14
15
 
16
+ let(:integration) { integration_class.new(config) }
17
+
15
18
  let(:config) do
16
- Mutant::Config::DEFAULT.update(
17
- isolation: isolation,
18
- integration: integration
19
- )
19
+ Mutant::Config::DEFAULT.update(isolation: isolation, integration: integration_class)
20
20
  end
21
21
 
22
- let(:integration) { double('Integration') }
23
- let(:isolation) { double('Isolation') }
24
- let(:mutation) { Mutant::Mutation::Evil.new(mutation_subject, Mutant::AST::Nodes::N_NIL) }
25
- let(:wrapped_node) { double('Wrapped Node') }
26
- let(:context) { double('Context') }
27
- let(:test_a) { double('Test A') }
28
- let(:test_b) { double('Test B') }
29
- let(:tests) { [test_a, test_b] }
30
- let(:selector) { double('Selector') }
22
+ let(:isolation) { double('Isolation') }
23
+ let(:mutation) { Mutant::Mutation::Evil.new(mutation_subject, Mutant::AST::Nodes::N_NIL) }
24
+ let(:wrapped_node) { double('Wrapped Node') }
25
+ let(:context) { double('Context') }
26
+ let(:test_a) { double('Test A') }
27
+ let(:test_b) { double('Test B') }
28
+ let(:tests) { [test_a, test_b] }
29
+ let(:selector) { double('Selector') }
30
+ let(:integration_class) { Mutant::Integration::Null }
31
31
 
32
32
  let(:mutation_subject) do
33
33
  double(
@@ -59,7 +59,6 @@ RSpec.describe Mutant::Env do
59
59
  expect(mutation_subject).to receive(:prepare).and_return(mutation_subject).ordered
60
60
  expect(context).to receive(:root).with(s(:nil)).and_return(wrapped_node).ordered
61
61
  expect(Mutant::Loader::Eval).to receive(:call).with(wrapped_node, mutation_subject).and_return(nil).ordered
62
- expect(integration).to receive(:call).with(tests).and_return(test_result).ordered
63
62
  end
64
63
 
65
64
  include_examples 'mutation kill'
@@ -1,9 +1,8 @@
1
1
  RSpec.describe Mutant::Expression::Method do
2
-
3
- let(:object) { described_class.parse(input) }
4
- let(:env) { Fixtures::TEST_ENV }
5
- let(:instance_method) { 'TestApp::Literal#string' }
6
- let(:singleton_method) { 'TestApp::Literal.string' }
2
+ let(:object) { parse_expression(input) }
3
+ let(:env) { Fixtures::TEST_ENV }
4
+ let(:instance_method) { 'TestApp::Literal#string' }
5
+ let(:singleton_method) { 'TestApp::Literal.string' }
7
6
 
8
7
  describe '#match_length' do
9
8
  let(:input) { instance_method }
@@ -11,13 +10,13 @@ RSpec.describe Mutant::Expression::Method do
11
10
  subject { object.match_length(other) }
12
11
 
13
12
  context 'when other is an equivalent expression' do
14
- let(:other) { described_class.parse(object.syntax) }
13
+ let(:other) { parse_expression(object.syntax) }
15
14
 
16
15
  it { should be(object.syntax.length) }
17
16
  end
18
17
 
19
18
  context 'when other is an unequivalent expression' do
20
- let(:other) { described_class.parse('Foo*') }
19
+ let(:other) { parse_expression('Foo*') }
21
20
 
22
21
  it { should be(0) }
23
22
  end
@@ -30,19 +29,16 @@ RSpec.describe Mutant::Expression::Method do
30
29
  let(:input) { instance_method }
31
30
 
32
31
  it 'returns correct matcher' do
33
- should eql(
34
- Mutant::Matcher::Method::Instance.new(
35
- env,
36
- TestApp::Literal, TestApp::Literal.instance_method(:string)
37
- )
38
- )
32
+ expect(subject.map(&:expression)).to eql([object])
39
33
  end
40
34
  end
41
35
 
42
36
  context 'with a singleton method' do
43
37
  let(:input) { singleton_method }
44
38
 
45
- it { should eql(Mutant::Matcher::Method::Singleton.new(env, TestApp::Literal, TestApp::Literal.method(:string))) }
39
+ it 'returns correct matcher' do
40
+ expect(subject.map(&:expression)).to eql([object])
41
+ end
46
42
  end
47
43
  end
48
44
  end
@@ -1,45 +1,58 @@
1
1
  RSpec.describe Mutant::Expression::Methods do
2
-
3
- let(:object) { described_class.parse(input) }
4
- let(:env) { Fixtures::TEST_ENV }
5
- let(:instance_methods) { 'TestApp::Literal#' }
6
- let(:singleton_methods) { 'TestApp::Literal.' }
2
+ let(:env) { Fixtures::TEST_ENV }
3
+ let(:object) { described_class.new(attributes) }
7
4
 
8
5
  describe '#match_length' do
9
- let(:input) { instance_methods }
6
+ let(:attributes) { { scope_name: 'TestApp::Literal', scope_symbol: '#' } }
10
7
 
11
8
  subject { object.match_length(other) }
12
9
 
13
10
  context 'when other is an equivalent expression' do
14
- let(:other) { described_class.parse(object.syntax) }
11
+ let(:other) { parse_expression(object.syntax) }
15
12
 
16
13
  it { should be(object.syntax.length) }
17
14
  end
18
15
 
19
16
  context 'when other is matched' do
20
- let(:other) { described_class.parse('TestApp::Literal#foo') }
17
+ let(:other) { parse_expression('TestApp::Literal#foo') }
21
18
 
22
19
  it { should be(object.syntax.length) }
23
20
  end
24
21
 
25
22
  context 'when other is an not matched expression' do
26
- let(:other) { described_class.parse('Foo*') }
23
+ let(:other) { parse_expression('Foo*') }
27
24
 
28
25
  it { should be(0) }
29
26
  end
30
27
  end
31
28
 
29
+ describe '#syntax' do
30
+ subject { object.syntax }
31
+
32
+ context 'with an instance method' do
33
+ let(:attributes) { { scope_name: 'TestApp::Literal', scope_symbol: '#' } }
34
+
35
+ it { should eql('TestApp::Literal#') }
36
+ end
37
+
38
+ context 'with a singleton method' do
39
+ let(:attributes) { { scope_name: 'TestApp::Literal', scope_symbol: '.' } }
40
+
41
+ it { should eql('TestApp::Literal.') }
42
+ end
43
+ end
44
+
32
45
  describe '#matcher' do
33
46
  subject { object.matcher(env) }
34
47
 
35
48
  context 'with an instance method' do
36
- let(:input) { instance_methods }
49
+ let(:attributes) { { scope_name: 'TestApp::Literal', scope_symbol: '#' } }
37
50
 
38
51
  it { should eql(Mutant::Matcher::Methods::Instance.new(env, TestApp::Literal)) }
39
52
  end
40
53
 
41
54
  context 'with a singleton method' do
42
- let(:input) { singleton_methods }
55
+ let(:attributes) { { scope_name: 'TestApp::Literal', scope_symbol: '.' } }
43
56
 
44
57
  it { should eql(Mutant::Matcher::Methods::Singleton.new(env, TestApp::Literal)) }
45
58
  end
@@ -1,8 +1,7 @@
1
1
  RSpec.describe Mutant::Expression::Namespace::Exact do
2
-
3
- let(:object) { described_class.parse(input) }
4
- let(:env) { Fixtures::TEST_ENV }
5
- let(:input) { 'TestApp::Literal' }
2
+ let(:object) { parse_expression(input) }
3
+ let(:env) { Fixtures::TEST_ENV }
4
+ let(:input) { 'TestApp::Literal' }
6
5
 
7
6
  describe '#matcher' do
8
7
  subject { object.matcher(env) }
@@ -14,13 +13,13 @@ RSpec.describe Mutant::Expression::Namespace::Exact do
14
13
  subject { object.match_length(other) }
15
14
 
16
15
  context 'when other is an equivalent expression' do
17
- let(:other) { described_class.parse(object.syntax) }
16
+ let(:other) { parse_expression(object.syntax) }
18
17
 
19
18
  it { should be(object.syntax.length) }
20
19
  end
21
20
 
22
21
  context 'when other is an unequivalent expression' do
23
- let(:other) { described_class.parse('Foo*') }
22
+ let(:other) { parse_expression('Foo*') }
24
23
 
25
24
  it { should be(0) }
26
25
  end
@@ -1,8 +1,8 @@
1
1
  RSpec.describe Mutant::Expression::Namespace::Recursive do
2
2
 
3
- let(:object) { described_class.parse(input) }
4
- let(:input) { 'TestApp::Literal*' }
5
- let(:env) { Fixtures::TEST_ENV }
3
+ let(:object) { parse_expression(input) }
4
+ let(:input) { 'TestApp::Literal*' }
5
+ let(:env) { Fixtures::TEST_ENV }
6
6
 
7
7
  describe '#matcher' do
8
8
  subject { object.matcher(env) }
@@ -10,48 +10,54 @@ RSpec.describe Mutant::Expression::Namespace::Recursive do
10
10
  it { should eql(Mutant::Matcher::Namespace.new(env, object)) }
11
11
  end
12
12
 
13
+ describe '#syntax' do
14
+ subject { object.syntax }
15
+
16
+ it { should eql(input) }
17
+ end
18
+
13
19
  describe '#match_length' do
14
20
  subject { object.match_length(other) }
15
21
 
16
22
  context 'when other is an equivalent expression' do
17
- let(:other) { described_class.parse(object.syntax) }
23
+ let(:other) { parse_expression(object.syntax) }
18
24
 
19
25
  it { should be(0) }
20
26
  end
21
27
 
22
28
  context 'when other expression describes a shorter prefix' do
23
- let(:other) { described_class.parse('TestApp') }
29
+ let(:other) { parse_expression('TestApp') }
24
30
 
25
31
  it { should be(0) }
26
32
  end
27
33
 
28
34
  context 'when other expression describes adjacent namespace' do
29
- let(:other) { described_class.parse('TestApp::LiteralFoo') }
35
+ let(:other) { parse_expression('TestApp::LiteralFoo') }
30
36
 
31
37
  it { should be(0) }
32
38
  end
33
39
 
34
40
  context 'when other expression describes root namespace' do
35
- let(:other) { described_class.parse('TestApp::Literal') }
41
+ let(:other) { parse_expression('TestApp::Literal') }
36
42
 
37
43
  it { should be(16) }
38
44
  end
39
45
 
40
46
  context 'when other expression describes a longer prefix' do
41
47
  context 'on constants' do
42
- let(:other) { described_class.parse('TestApp::Literal::Deep') }
48
+ let(:other) { parse_expression('TestApp::Literal::Deep') }
43
49
 
44
50
  it { should be(input[0..-2].length) }
45
51
  end
46
52
 
47
53
  context 'on singleton method' do
48
- let(:other) { described_class.parse('TestApp::Literal.foo') }
54
+ let(:other) { parse_expression('TestApp::Literal.foo') }
49
55
 
50
56
  it { should be(input[0..-2].length) }
51
57
  end
52
58
 
53
59
  context 'on instance method' do
54
- let(:other) { described_class.parse('TestApp::Literal#foo') }
60
+ let(:other) { parse_expression('TestApp::Literal#foo') }
55
61
 
56
62
  it { should be(input[0..-2].length) }
57
63
  end
@@ -0,0 +1,67 @@
1
+ RSpec.describe Mutant::Expression::Parser do
2
+ let(:object) { Mutant::Config::DEFAULT.expression_parser }
3
+
4
+ describe '#call' do
5
+ subject { object.call(input) }
6
+
7
+ context 'on nonsense' do
8
+ let(:input) { 'foo bar' }
9
+
10
+ it 'raises an exception' do
11
+ expect { subject }.to raise_error(
12
+ Mutant::Expression::Parser::InvalidExpressionError,
13
+ 'Expression: "foo bar" is not valid'
14
+ )
15
+ end
16
+ end
17
+
18
+ context 'on a valid expression' do
19
+ let(:input) { 'Foo' }
20
+
21
+ it { should eql(Mutant::Expression::Namespace::Exact.new(scope_name: 'Foo')) }
22
+ end
23
+ end
24
+
25
+ describe '.try_parse' do
26
+ subject { object.try_parse(input) }
27
+
28
+ context 'on nonsense' do
29
+ let(:input) { 'foo bar' }
30
+
31
+ it { should be(nil) }
32
+ end
33
+
34
+ context 'on a valid expression' do
35
+ let(:input) { 'Foo' }
36
+
37
+ it { should eql(Mutant::Expression::Namespace::Exact.new(scope_name: 'Foo')) }
38
+ end
39
+
40
+ context 'on ambiguous expression' do
41
+ let(:object) { described_class.new([test_a, test_b]) }
42
+
43
+ let(:test_a) do
44
+ Class.new(Mutant::Expression) do
45
+ include Anima.new
46
+ const_set(:REGEXP, /\Atest-syntax\z/.freeze)
47
+ end
48
+ end
49
+
50
+ let(:test_b) do
51
+ Class.new(Mutant::Expression) do
52
+ include Anima.new
53
+ const_set(:REGEXP, /^test-syntax$/.freeze)
54
+ end
55
+ end
56
+
57
+ let(:input) { 'test-syntax' }
58
+
59
+ it 'raises expected exception' do
60
+ expect { subject }.to raise_error(
61
+ Mutant::Expression::Parser::AmbiguousExpressionError,
62
+ 'Ambiguous expression: "test-syntax"'
63
+ )
64
+ end
65
+ end
66
+ end
67
+ end
@@ -1,80 +1,47 @@
1
1
  RSpec.describe Mutant::Expression do
2
2
  let(:object) { described_class }
3
3
 
4
- describe '.try_parse' do
5
- subject { object.try_parse(input) }
4
+ let(:parser) { Mutant::Config::DEFAULT.expression_parser }
6
5
 
7
- context 'on nonsense' do
8
- let(:input) { 'foo bar' }
6
+ describe '#prefix?' do
7
+ let(:object) { parser.call('Foo*') }
9
8
 
10
- it { should be(nil) }
11
- end
9
+ subject { object.prefix?(other) }
12
10
 
13
- context 'on a valid expression' do
14
- let(:input) { 'Foo' }
11
+ context 'when object is a prefix of other' do
12
+ let(:other) { parser.call('Foo::Bar') }
15
13
 
16
- it { should eql(Mutant::Expression::Namespace::Exact.new('Foo')) }
14
+ it { should be(true) }
17
15
  end
18
16
 
19
- context 'on ambiguous expression' do
20
- class ExpressionA < Mutant::Expression
21
- register(/\Atest-syntax\z/)
22
- end
17
+ context 'when other is not a prefix of other' do
18
+ let(:other) { parser.call('Bar') }
23
19
 
24
- class ExpressionB < Mutant::Expression
25
- register(/^test-syntax$/)
26
- end
27
-
28
- let(:input) { 'test-syntax' }
29
-
30
- it 'raises an exception' do
31
- expect { subject }.to raise_error(
32
- Mutant::Expression::AmbiguousExpressionError,
33
- 'Ambiguous expression: "test-syntax"'
34
- )
35
- end
20
+ it { should be(false) }
36
21
  end
37
22
  end
38
23
 
39
- describe '#inspect' do
40
- let(:object) { described_class.parse('Foo') }
41
- subject { object.inspect }
42
-
43
- it { should eql('<Mutant::Expression: Foo>') }
44
- it_should_behave_like 'an idempotent method'
45
- end
46
-
47
- describe '#_dump' do
48
- let(:object) { described_class.parse('Foo') }
49
- subject { object._dump(double('Level')) }
50
-
51
- it { should eql('Foo') }
52
- end
53
-
54
- describe '.parse' do
55
- subject { object.parse(input) }
56
-
57
- context 'on nonsense' do
58
- let(:input) { 'foo bar' }
24
+ describe '.try_parse' do
25
+ let(:object) do
26
+ Class.new(described_class) do
27
+ include Anima.new(:foo)
59
28
 
60
- it 'raises an exception' do
61
- expect { subject }.to raise_error(
62
- Mutant::Expression::InvalidExpressionError,
63
- 'Expression: "foo bar" is not valid'
64
- )
29
+ const_set(:REGEXP, /(?<foo>foo)/)
65
30
  end
66
31
  end
67
32
 
68
- context 'on a valid expression' do
69
- let(:input) { 'Foo' }
33
+ subject { object.try_parse(input) }
34
+
35
+ context 'on successful parse' do
36
+ let(:input) { 'foo' }
70
37
 
71
- it { should eql(Mutant::Expression::Namespace::Exact.new('Foo')) }
38
+ it { should eql(object.new(foo: 'foo')) }
72
39
  end
73
- end
74
40
 
75
- describe '._load' do
76
- subject { described_class._load('Foo') }
41
+ context 'on unsuccessful parse' do
42
+ let(:input) { 'bar' }
77
43
 
78
- it { should eql(described_class.parse('Foo')) }
44
+ it { should be(nil) }
45
+ end
79
46
  end
80
47
  end