transpec 1.8.0 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,16 +8,22 @@ require 'ast'
8
8
  module Transpec
9
9
  class Syntax
10
10
  class OperatorMatcher < Syntax
11
- include Mixin::Send, Util, ::AST::Sexp
11
+ extend ::AST::Sexp
12
+ include Mixin::Send, Util
12
13
 
13
14
  OPERATORS = [:==, :===, :<, :<=, :>, :>=, :=~].freeze
15
+ BE_NODE = s(:send, nil, :be)
14
16
 
15
17
  def self.standalone?
16
18
  false
17
19
  end
18
20
 
19
- def self.target_method?(receiver_node, method_name)
20
- !receiver_node.nil? && OPERATORS.include?(method_name)
21
+ def self.target_node?(node, runtime_data = nil)
22
+ node = node.parent_node if node == BE_NODE
23
+ receiver_node, method_name, *_ = *node
24
+ return false if receiver_node.nil?
25
+ return false unless OPERATORS.include?(method_name)
26
+ check_target_node_dynamically(node, runtime_data)
21
27
  end
22
28
 
23
29
  add_dynamic_analysis_request do |rewriter|
@@ -26,6 +32,16 @@ module Transpec
26
32
  end
27
33
  end
28
34
 
35
+ def initialize(node, source_rewriter = nil, runtime_data = nil, report = nil)
36
+ operator_node = if node == BE_NODE
37
+ node.parent_node
38
+ else
39
+ node
40
+ end
41
+
42
+ super(operator_node, source_rewriter, runtime_data, report)
43
+ end
44
+
29
45
  def convert_operator!(parenthesize_arg = true)
30
46
  case method_name
31
47
  when :==
@@ -126,7 +142,7 @@ module Transpec
126
142
  end
127
143
 
128
144
  def be_node
129
- if receiver_node == s(:send, nil, :be)
145
+ if receiver_node == BE_NODE
130
146
  receiver_node
131
147
  else
132
148
  nil
@@ -3,12 +3,12 @@
3
3
  require 'transpec/syntax'
4
4
  require 'transpec/syntax/mixin/send'
5
5
  require 'transpec/syntax/mixin/owned_matcher'
6
- require 'transpec/syntax/mixin/any_instance_block'
6
+ require 'transpec/syntax/mixin/messaging_host'
7
7
 
8
8
  module Transpec
9
9
  class Syntax
10
10
  class Receive < Syntax
11
- include Mixin::Send, Mixin::OwnedMatcher, Mixin::AnyInstanceBlock
11
+ include Mixin::Send, Mixin::OwnedMatcher, Mixin::MessagingHost
12
12
 
13
13
  attr_reader :expectation
14
14
 
@@ -16,13 +16,16 @@ module Transpec
16
16
  receiver_node.nil? && method_name == :receive
17
17
  end
18
18
 
19
+ def remove_useless_and_return!
20
+ removed = super
21
+ return unless removed
22
+ @report.records << ReceiveUselessAndReturnRecord.new(self)
23
+ end
24
+
19
25
  def add_receiver_arg_to_any_instance_implementation_block!
20
26
  added = super
21
27
  return unless added
22
- @report.records << Record.new(
23
- "#{@expectation.method_name}(Klass).to receive(:message) { |arg| }",
24
- "#{@expectation.method_name}(Klass).to receive(:message) { |instance, arg| }"
25
- )
28
+ @report.records << ReceiveAnyInstanceBlockRecord.new(self)
26
29
  end
27
30
 
28
31
  def any_instance?
@@ -33,6 +36,18 @@ module Transpec
33
36
  return unless any_instance?
34
37
  super || @expectation.block_node
35
38
  end
39
+
40
+ class ReceiveAnyInstanceBlockRecord < AnyInstanceBlockRecord
41
+ def base_syntax
42
+ "#{@host.expectation.method_name}(Klass).to receive(:message)"
43
+ end
44
+ end
45
+
46
+ class ReceiveUselessAndReturnRecord < UselessAndReturnRecord
47
+ def base_syntax
48
+ "#{@host.expectation.method_name_for_instance}(obj).to receive(:message)"
49
+ end
50
+ end
36
51
  end
37
52
  end
38
53
  end
@@ -3,14 +3,13 @@
3
3
  require 'transpec/syntax'
4
4
  require 'transpec/syntax/mixin/expectizable'
5
5
  require 'transpec/syntax/mixin/monkey_patch_any_instance'
6
- require 'transpec/syntax/mixin/allow_no_message'
7
- require 'transpec/syntax/mixin/any_instance_block'
6
+ require 'transpec/syntax/mixin/messaging_host'
7
+ require 'transpec/util'
8
8
 
9
9
  module Transpec
10
10
  class Syntax
11
11
  class ShouldReceive < Syntax
12
- include Mixin::Expectizable, Mixin::MonkeyPatchAnyInstance, Mixin::AnyInstanceBlock,
13
- Mixin::AllowNoMessage
12
+ include Mixin::Expectizable, Mixin::MonkeyPatchAnyInstance, Mixin::MessagingHost, Util
14
13
 
15
14
  alias_method :useless_expectation?, :allow_no_message?
16
15
 
@@ -61,7 +60,7 @@ module Transpec
61
60
  end
62
61
 
63
62
  convert_to_syntax!('allow', negative_form)
64
- remove_allowance_for_no_message!
63
+ remove_no_message_allowance!
65
64
 
66
65
  register_record(AllowRecord, negative_form)
67
66
  end
@@ -70,13 +69,17 @@ module Transpec
70
69
  return unless useless_expectation?
71
70
 
72
71
  replace(selector_range, 'stub')
73
- remove_allowance_for_no_message!
72
+ remove_no_message_allowance!
74
73
 
75
74
  register_record(StubRecord)
76
75
  end
77
76
 
77
+ def remove_useless_and_return!
78
+ super && register_record(MonkeyPatchUselessAndReturnRecord)
79
+ end
80
+
78
81
  def add_receiver_arg_to_any_instance_implementation_block!
79
- super && register_record(AnyInstanceBlockRecord)
82
+ super && register_record(MonkeyPatchAnyInstanceBlockRecord)
80
83
  end
81
84
 
82
85
  private
@@ -112,7 +115,7 @@ module Transpec
112
115
  def broken_block_nodes
113
116
  @broken_block_nodes ||= [
114
117
  block_node_taken_by_with_method_with_no_normal_args,
115
- block_node_following_message_expectation_method
118
+ block_node_followed_by_fluent_method
116
119
  ].compact.uniq
117
120
  end
118
121
 
@@ -128,7 +131,7 @@ module Transpec
128
131
  # (args
129
132
  # (arg :block_arg)) nil)
130
133
  def block_node_taken_by_with_method_with_no_normal_args
131
- each_chained_method_node do |chained_node, child_node|
134
+ each_backward_chained_node(node, :child_as_second_arg) do |chained_node, child_node|
132
135
  next unless chained_node.block_type?
133
136
  return nil unless child_node.children[1] == :with
134
137
  return nil if child_node.children[2]
@@ -146,8 +149,8 @@ module Transpec
146
149
  # (sym :method_name))
147
150
  # (args
148
151
  # (arg :block_arg)) nil) :once)
149
- def block_node_following_message_expectation_method
150
- each_chained_method_node do |chained_node, child_node|
152
+ def block_node_followed_by_fluent_method
153
+ each_backward_chained_node(node, :child_as_second_arg) do |chained_node, child_node|
151
154
  next unless chained_node.send_type?
152
155
  return child_node if child_node.block_type?
153
156
  end
@@ -74,6 +74,52 @@ module Transpec
74
74
  parent_node
75
75
  end
76
76
 
77
+ def each_forward_chained_node(origin_node, mode = nil)
78
+ return to_enum(__method__, origin_node, mode) unless block_given?
79
+
80
+ yield origin_node if mode == :include_origin
81
+
82
+ parent_node = origin_node
83
+
84
+ loop do
85
+ child_node = parent_node.children.first
86
+
87
+ return unless child_node
88
+ return unless [:send, :block].include?(child_node.type)
89
+
90
+ if mode == :parent_as_second_arg
91
+ yield child_node, parent_node
92
+ else
93
+ yield child_node
94
+ end
95
+
96
+ parent_node = child_node
97
+ end
98
+
99
+ nil
100
+ end
101
+
102
+ def each_backward_chained_node(origin_node, mode = nil)
103
+ return to_enum(__method__, origin_node, mode) unless block_given?
104
+
105
+ yield origin_node if mode == :include_origin
106
+
107
+ origin_node.each_ancestor_node.reduce(origin_node) do |child_node, parent_node|
108
+ return unless [:send, :block].include?(parent_node.type)
109
+ return unless parent_node.children.first.equal?(child_node)
110
+
111
+ if mode == :child_as_second_arg
112
+ yield parent_node, child_node
113
+ else
114
+ yield parent_node
115
+ end
116
+
117
+ parent_node
118
+ end
119
+
120
+ nil
121
+ end
122
+
77
123
  def indentation_of_line(arg)
78
124
  line = case arg
79
125
  when AST::Node then arg.loc.expression.source_line
@@ -4,7 +4,7 @@ module Transpec
4
4
  # http://semver.org/
5
5
  module Version
6
6
  MAJOR = 1
7
- MINOR = 8
7
+ MINOR = 9
8
8
  PATCH = 0
9
9
 
10
10
  def self.to_s
@@ -367,7 +367,7 @@ module Transpec
367
367
 
368
368
  describe '#process_expect' do
369
369
  let(:expect_object) { double('expect_object', receive_matcher: receive_object).as_null_object }
370
- let(:receive_object) { double('receive_object') }
370
+ let(:receive_object) { double('receive_object').as_null_object }
371
371
 
372
372
  context 'when Configuration#convert_have_items? is true' do
373
373
  before { configuration.convert_have_items = true }
@@ -400,6 +400,11 @@ module Transpec
400
400
  end
401
401
  end
402
402
 
403
+ it "invokes #process_useless_and_return with the expect's #receive matcher" do
404
+ converter.should_receive(:process_useless_and_return).with(receive_object)
405
+ converter.process_expect(expect_object)
406
+ end
407
+
403
408
  it "invokes #process_any_instance_block with the expect's #receive matcher" do
404
409
  converter.should_receive(:process_any_instance_block).with(receive_object)
405
410
  converter.process_expect(expect_object)
@@ -408,7 +413,12 @@ module Transpec
408
413
 
409
414
  describe '#process_allow' do
410
415
  let(:allow_object) { double('allow_object', receive_matcher: receive_object).as_null_object }
411
- let(:receive_object) { double('receive_object') }
416
+ let(:receive_object) { double('receive_object').as_null_object }
417
+
418
+ it "invokes #process_useless_and_return with the allow's #receive matcher" do
419
+ converter.should_receive(:process_useless_and_return).with(receive_object)
420
+ converter.process_allow(allow_object)
421
+ end
412
422
 
413
423
  it "invokes #process_any_instance_block with the allow's #receive matcher" do
414
424
  converter.should_receive(:process_any_instance_block).with(receive_object)
@@ -573,9 +583,14 @@ module Transpec
573
583
  end
574
584
  end
575
585
 
586
+ it 'invokes #process_useless_and_return with the should_receive' do
587
+ converter.should_receive(:process_useless_and_return).with(should_receive_object)
588
+ converter.process_should_receive(should_receive_object)
589
+ end
590
+
576
591
  it 'invokes #process_any_instance_block with the should_receive' do
577
592
  converter.should_receive(:process_any_instance_block).with(should_receive_object)
578
- converter.process_allow(should_receive_object)
593
+ converter.process_should_receive(should_receive_object)
579
594
  end
580
595
  end
581
596
 
@@ -610,16 +625,16 @@ module Transpec
610
625
  end
611
626
  end
612
627
 
613
- shared_examples 'invokes MethodStub#remove_allowance_for_no_message!' do
614
- it 'invokes MethodStub#remove_allowance_for_no_message!' do
615
- method_stub_object.should_receive(:remove_allowance_for_no_message!)
628
+ shared_examples 'invokes MethodStub#remove_no_message_allowance!' do
629
+ it 'invokes MethodStub#remove_no_message_allowance!' do
630
+ method_stub_object.should_receive(:remove_no_message_allowance!)
616
631
  converter.process_method_stub(method_stub_object)
617
632
  end
618
633
  end
619
634
 
620
- shared_examples 'does not invoke MethodStub#remove_allowance_for_no_message!' do
621
- it 'does not invoke MethodStub#remove_allowance_for_no_message!' do
622
- method_stub_object.should_not_receive(:remove_allowance_for_no_message!)
635
+ shared_examples 'does not invoke MethodStub#remove_no_message_allowance!' do
636
+ it 'does not invoke MethodStub#remove_no_message_allowance!' do
637
+ method_stub_object.should_not_receive(:remove_no_message_allowance!)
623
638
  converter.process_method_stub(method_stub_object)
624
639
  end
625
640
  end
@@ -634,7 +649,7 @@ module Transpec
634
649
  before { method_stub_object.stub(:hash_arg?).and_return(false) }
635
650
  include_examples 'invokes MethodStub#allowize!'
636
651
  include_examples 'does not invoke MethodStub#convert_deprecated_method!'
637
- include_examples 'invokes MethodStub#remove_allowance_for_no_message!'
652
+ include_examples 'invokes MethodStub#remove_no_message_allowance!'
638
653
  end
639
654
 
640
655
  context 'and MethodStub#hash_arg? is true' do
@@ -647,14 +662,14 @@ module Transpec
647
662
  before { rspec_version.stub(:receive_messages_available?).and_return(true) }
648
663
  include_examples 'invokes MethodStub#allowize!'
649
664
  include_examples 'does not invoke MethodStub#convert_deprecated_method!'
650
- include_examples 'invokes MethodStub#remove_allowance_for_no_message!'
665
+ include_examples 'invokes MethodStub#remove_no_message_allowance!'
651
666
  end
652
667
 
653
668
  context 'and RSpecVersion#receive_messages_available? is false' do
654
669
  before { rspec_version.stub(:receive_messages_available?).and_return(false) }
655
670
  include_examples 'invokes MethodStub#allowize!'
656
671
  include_examples 'does not invoke MethodStub#convert_deprecated_method!'
657
- include_examples 'invokes MethodStub#remove_allowance_for_no_message!'
672
+ include_examples 'invokes MethodStub#remove_no_message_allowance!'
658
673
  end
659
674
  end
660
675
 
@@ -665,14 +680,14 @@ module Transpec
665
680
  before { rspec_version.stub(:receive_messages_available?).and_return(true) }
666
681
  include_examples 'invokes MethodStub#allowize!'
667
682
  include_examples 'does not invoke MethodStub#convert_deprecated_method!'
668
- include_examples 'invokes MethodStub#remove_allowance_for_no_message!'
683
+ include_examples 'invokes MethodStub#remove_no_message_allowance!'
669
684
  end
670
685
 
671
686
  context 'and RSpecVersion#receive_messages_available? is false' do
672
687
  before { rspec_version.stub(:receive_messages_available?).and_return(false) }
673
688
  include_examples 'does not invoke MethodStub#allowize!'
674
689
  include_examples 'invokes MethodStub#convert_deprecated_method!'
675
- include_examples 'invokes MethodStub#remove_allowance_for_no_message!'
690
+ include_examples 'invokes MethodStub#remove_no_message_allowance!'
676
691
  end
677
692
  end
678
693
  end
@@ -686,7 +701,7 @@ module Transpec
686
701
 
687
702
  include_examples 'invokes MethodStub#allowize!'
688
703
  include_examples 'does not invoke MethodStub#convert_deprecated_method!'
689
- include_examples 'does not invoke MethodStub#remove_allowance_for_no_message!'
704
+ include_examples 'does not invoke MethodStub#remove_no_message_allowance!'
690
705
  end
691
706
  end
692
707
 
@@ -698,7 +713,7 @@ module Transpec
698
713
 
699
714
  include_examples 'does not invoke MethodStub#allowize!'
700
715
  include_examples 'invokes MethodStub#convert_deprecated_method!'
701
- include_examples 'invokes MethodStub#remove_allowance_for_no_message!'
716
+ include_examples 'invokes MethodStub#remove_no_message_allowance!'
702
717
  end
703
718
 
704
719
  context 'and Configuration#convert_deprecated_method? is false' do
@@ -706,13 +721,18 @@ module Transpec
706
721
 
707
722
  include_examples 'does not invoke MethodStub#allowize!'
708
723
  include_examples 'does not invoke MethodStub#convert_deprecated_method!'
709
- include_examples 'does not invoke MethodStub#remove_allowance_for_no_message!'
724
+ include_examples 'does not invoke MethodStub#remove_no_message_allowance!'
710
725
  end
711
726
  end
712
727
 
728
+ it 'invokes #process_useless_and_return with the method stub' do
729
+ converter.should_receive(:process_useless_and_return).with(method_stub_object)
730
+ converter.process_method_stub(method_stub_object)
731
+ end
732
+
713
733
  it 'invokes #process_any_instance_block with the method stub' do
714
734
  converter.should_receive(:process_any_instance_block).with(method_stub_object)
715
- converter.process_allow(method_stub_object)
735
+ converter.process_method_stub(method_stub_object)
716
736
  end
717
737
  end
718
738
 
@@ -1047,6 +1067,28 @@ module Transpec
1047
1067
  end
1048
1068
  end
1049
1069
 
1070
+ describe '#process_useless_and_return' do
1071
+ let(:messaging_host) { double('messaging host').as_null_object }
1072
+
1073
+ context 'when Configuration#convert_deprecated_method? returns true' do
1074
+ before { configuration.convert_deprecated_method = true }
1075
+
1076
+ it 'invokes #remove_useless_and_return!' do
1077
+ messaging_host.should_receive(:remove_useless_and_return!)
1078
+ converter.process_useless_and_return(messaging_host)
1079
+ end
1080
+ end
1081
+
1082
+ context 'when Configuration#convert_deprecated_method? returns false' do
1083
+ before { configuration.convert_deprecated_method = false }
1084
+
1085
+ it 'does nothing' do
1086
+ messaging_host.should_not_receive(:remove_useless_and_return!)
1087
+ converter.process_useless_and_return(messaging_host)
1088
+ end
1089
+ end
1090
+ end
1091
+
1050
1092
  describe '#process_any_instance_block' do
1051
1093
  let(:messaging_host) { double('messaging host').as_null_object }
1052
1094
 
@@ -27,37 +27,69 @@ module Transpec
27
27
  end
28
28
 
29
29
  describe '#matcher_node' do
30
- context 'when the matcher is taking a block' do
30
+ let(:matcher_name) { expect_object.matcher_node.children[1] }
31
+
32
+ context 'when the matcher is not taking a block' do
31
33
  let(:source) do
32
34
  <<-END
33
35
  describe 'example' do
34
36
  it 'is empty' do
35
- expect(subject).to receive(:foo) { }
37
+ expect(subject).to be_empty
36
38
  end
37
39
  end
38
40
  END
39
41
  end
40
42
 
41
43
  it 'returns send node of the matcher' do
42
- method_name = expect_object.matcher_node.children[1]
43
- method_name.should == :receive
44
+ matcher_name.should == :be_empty
44
45
  end
45
46
  end
46
47
 
47
- context 'when the matcher is not taking a block' do
48
+ context 'when the matcher is taking a block' do
48
49
  let(:source) do
49
50
  <<-END
50
51
  describe 'example' do
51
- it 'is empty' do
52
- expect(subject).to be_empty
52
+ it 'receives :foo' do
53
+ expect(subject).to receive(:foo) { }
53
54
  end
54
55
  end
55
56
  END
56
57
  end
57
58
 
58
59
  it 'returns send node of the matcher' do
59
- method_name = expect_object.matcher_node.children[1]
60
- method_name.should == :be_empty
60
+ matcher_name.should == :receive
61
+ end
62
+ end
63
+
64
+ context 'when the matcher is chained by another method' do
65
+ let(:source) do
66
+ <<-END
67
+ describe 'example' do
68
+ it 'receives :foo twice' do
69
+ expect(subject).to receive(:foo).twice
70
+ end
71
+ end
72
+ END
73
+ end
74
+
75
+ it 'returns the first node of the chain' do
76
+ matcher_name.should == :receive
77
+ end
78
+ end
79
+
80
+ context 'when the matcher is chained by another method that is taking a block' do
81
+ let(:source) do
82
+ <<-END
83
+ describe 'example' do
84
+ it 'receives :foo twice' do
85
+ expect(subject).to receive(:foo).twice { }
86
+ end
87
+ end
88
+ END
89
+ end
90
+
91
+ it 'returns the first node of the chain' do
92
+ matcher_name.should == :receive
61
93
  end
62
94
  end
63
95
  end