verified_double 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,5 +2,5 @@ language: ruby
2
2
  rvm:
3
3
  - 1.9.3
4
4
  script:
5
- - bundle exec rspec
5
+ - bundle exec rspec -r ./spec/spec_helper.rb
6
6
  - bundle exec cucumber
@@ -0,0 +1,12 @@
1
+ 0.0.2 - 2013-06-22
2
+ ------------------
3
+
4
+ * Passes #1: Customizing arguments and return values.
5
+ * Set rspec-fire to 1.1 for the meantime.
6
+
7
+ 0.0.1 - 2013-06-02
8
+ ------------------
9
+
10
+ * Initial release. Passes "I want to be informed if the mocks I use are verified by contract tests" feature.
11
+
12
+
@@ -0,0 +1,12 @@
1
+ 0.0.2 - 2013-06-22
2
+ ------------------
3
+
4
+ * Passes #1: Customizing arguments and return values.
5
+ * Set rspec-fire to 1.1 for the meantime.
6
+
7
+ 0.0.1 - 2013-06-02
8
+ ------------------
9
+
10
+ * Initial release. Passes "I want to be informed if the mocks I use are verified by contract tests" feature.
11
+
12
+
@@ -0,0 +1,105 @@
1
+ Feature: Customizing arguments and return values
2
+ As a developer
3
+ I want the ability to make contract arguments and return values more or less specific
4
+
5
+ Background:
6
+ Given the following classes:
7
+ """
8
+ class ObjectUnderTest
9
+ def do_something(collaborator, input)
10
+ collaborator.some_method(input)
11
+ end
12
+ end
13
+
14
+ class Collaborator
15
+ def some_method(input)
16
+ end
17
+ end
18
+ """
19
+
20
+ And the test suite has an after(:suite) callback asking VerifiedDouble to report unverified doubles:
21
+ """
22
+ require 'verified_double'
23
+ require 'main'
24
+
25
+ RSpec.configure do |config|
26
+ config.after :suite do
27
+ VerifiedDouble::ReportUnverifiedSignatures.new(VerifiedDouble.registry, self).execute
28
+ end
29
+ end
30
+ """
31
+
32
+ And a test that uses VerifiedDouble to mock an object:
33
+ """
34
+ require 'spec_helper'
35
+ describe ObjectUnderTest do
36
+ let(:input) { :input }
37
+ let(:output) { :output }
38
+ let(:instance_double) { VerifiedDouble.of_instance('Collaborator') }
39
+
40
+ it "tests something" do
41
+ instance_double.should_receive(:some_method).with(input).and_return(output)
42
+ ObjectUnderTest.new.do_something(instance_double, input)
43
+ end
44
+ end
45
+ """
46
+
47
+ Scenario: More general argument
48
+ Given the test suite has a contract test for the mock:
49
+ """
50
+ require 'spec_helper'
51
+
52
+ describe 'Collaborator' do
53
+ it "tests something", verifies_contract: 'Collaborator#some_method(Object)=>Symbol' do
54
+ # do nothing
55
+ end
56
+ end
57
+ """
58
+
59
+ When I run the test suite
60
+ Then I should not see any output saying the mock is unverified
61
+
62
+ Scenario: More specific argument
63
+ Given the test suite has a contract test for the mock:
64
+ """
65
+ require 'spec_helper'
66
+
67
+ describe 'Collaborator' do
68
+ it "tests something", verifies_contract: 'Collaborator#some_method(:input)=>Symbol' do
69
+ # do nothing
70
+ end
71
+ end
72
+ """
73
+
74
+ When I run the test suite
75
+ Then I should not see any output saying the mock is unverified
76
+
77
+ Scenario: More general return value
78
+ Given the test suite has a contract test for the mock:
79
+ """
80
+ require 'spec_helper'
81
+
82
+ describe 'Collaborator' do
83
+ it "tests something", verifies_contract: 'Collaborator#some_method(Symbol)=>Object' do
84
+ # do nothing
85
+ end
86
+ end
87
+ """
88
+
89
+ When I run the test suite
90
+ Then I should not see any output saying the mock is unverified
91
+
92
+ Scenario: More specific return value
93
+ Given the test suite has a contract test for the mock:
94
+ """
95
+ require 'spec_helper'
96
+
97
+ describe 'Collaborator' do
98
+ it "tests something", verifies_contract: 'Collaborator#some_method(Symbol)=>:output' do
99
+ # do nothing
100
+ end
101
+ end
102
+ """
103
+
104
+ When I run the test suite
105
+ Then I should not see any output saying the mock is unverified
@@ -1,10 +1,13 @@
1
1
  require 'rspec/fire'
2
2
 
3
+ require 'verified_double/boolean'
3
4
  require 'verified_double/get_registered_signatures'
4
5
  require 'verified_double/get_unverified_signatures'
5
6
  require 'verified_double/get_verified_signatures'
6
7
  require 'verified_double/method_signature'
8
+ require 'verified_double/method_signature_value'
7
9
  require 'verified_double/output_unverified_signatures'
10
+ require 'verified_double/parse_method_signature'
8
11
  require 'verified_double/recording_double'
9
12
  require 'verified_double/report_unverified_signatures'
10
13
 
@@ -0,0 +1,4 @@
1
+ module VerifiedDouble
2
+ module Boolean
3
+ end
4
+ end
@@ -5,7 +5,7 @@ module VerifiedDouble
5
5
  end
6
6
 
7
7
  def execute
8
- @double_registry.map(&:method_signatures).flatten.map(&:to_s).uniq
8
+ @double_registry.map(&:method_signatures).flatten.uniq
9
9
  end
10
10
  end
11
11
  end
@@ -5,7 +5,9 @@ module VerifiedDouble
5
5
  end
6
6
 
7
7
  def execute
8
- @get_registered_signatures.execute - @get_verified_signatures.execute
8
+ @get_registered_signatures.execute.select{|registered_signature|
9
+ @get_verified_signatures.execute.all?{|verified_signature|
10
+ ! registered_signature.accepts?(verified_signature) } }
9
11
  end
10
12
  end
11
13
  end
@@ -11,6 +11,7 @@ module VerifiedDouble
11
11
  .map{|example| example.metadata[:verifies_contract] }
12
12
  .compact
13
13
  .uniq
14
+ .map{|method_signature_string| ParseMethodSignature.new(method_signature_string).execute }
14
15
  end
15
16
  end
16
17
  end
@@ -1,16 +1,55 @@
1
1
  module VerifiedDouble
2
2
  class MethodSignature
3
- attr_accessor :args, :method, :recording_double, :return_value
3
+ attr_accessor :args, :class_name, :method, :method_operator, :return_values
4
4
 
5
- def initialize(recording_double)
6
- @recording_double = recording_double
5
+ def initialize(attributes = {})
6
+ attributes.each do |name, value|
7
+ self.send "#{name}=", value
8
+ end
9
+ end
10
+
11
+ def accepts?(other)
12
+ self.class_name == other.class_name &&
13
+ self.method_operator == other.method_operator &&
14
+ self.method == other.method &&
15
+ self.args.size == other.args.size &&
16
+ (0 ... args.size).all?{|i| self.args[i].accepts?(other.args[i]) } &&
17
+ self.return_values.size == other.return_values.size &&
18
+ (0 ... return_values.size).all?{|i| self.return_values[i].accepts?(other.return_values[i]) }
19
+ end
20
+
21
+ def args
22
+ @args ||= []
23
+ end
24
+
25
+ def eql?(other)
26
+ to_s.eql?(other.to_s)
27
+ end
28
+
29
+ def hash
30
+ to_s.hash
31
+ end
32
+
33
+ def recommended_verified_signature
34
+ self.clone.tap do |result|
35
+ result.args = result.args.map{|arg| arg.recommended_value }
36
+ result.return_values = result.return_values.map{|return_value| return_value.recommended_value }
37
+ end
38
+ end
39
+
40
+ def return_values
41
+ @return_values ||= []
7
42
  end
8
43
 
9
44
  def to_s
45
+ args_string = args.map(&:value).map{|v| v || 'nil'}.join(', ')
46
+ return_values_string = return_values.map(&:value).map{|v| v || 'nil'}.join(', ')
47
+ return_values_string = nil if return_values_string.empty?
48
+
10
49
  result = [
11
- "#{recording_double.class_name}#{recording_double.method_operator}#{method}(#{args && args.map(&:class).join(', ')})",
12
- return_value && return_value.class]
13
- result.compact.join("=>")
50
+ "#{class_name}#{method_operator}#{method}(#{args_string})",
51
+ return_values_string]
52
+ result.flatten.compact.join("=>")
14
53
  end
15
54
  end
16
55
  end
@@ -0,0 +1,29 @@
1
+ module VerifiedDouble
2
+ class MethodSignatureValue
3
+ attr_reader :value
4
+
5
+ def initialize(value)
6
+ @value = value
7
+ end
8
+
9
+ def accepts?(other)
10
+ if self.value.is_a?(Class) || ! other.value.is_a?(Class)
11
+ self.value == other.value
12
+ else
13
+ self.modified_class.ancestors.include?(other.value)
14
+ end
15
+ end
16
+
17
+ def modified_class
18
+ if value == true or value == false
19
+ VerifiedDouble::Boolean
20
+ else
21
+ value.class
22
+ end
23
+ end
24
+
25
+ def recommended_value
26
+ self.class.new(self.modified_class)
27
+ end
28
+ end
29
+ end
@@ -6,7 +6,7 @@ module VerifiedDouble
6
6
 
7
7
  def execute
8
8
  if unverified_signatures.any?
9
- output = ["The following mocks are not verified:" ] + unverified_signatures
9
+ output = ["The following mocks are not verified:" ] + unverified_signatures.map(&:recommended_verified_signature)
10
10
  puts output.join("\n")
11
11
  end
12
12
  end
@@ -0,0 +1,49 @@
1
+ module VerifiedDouble
2
+ class ParseMethodSignature
3
+ attr_reader :string
4
+
5
+ def initialize(string)
6
+ @string = string
7
+ end
8
+
9
+ def args
10
+ results = string.scan(/\((.*)\)/)[0]
11
+ if results
12
+ results[0].split(',').map{|arg| MethodSignatureValue.new(eval(arg)) }
13
+ else
14
+ []
15
+ end
16
+ end
17
+
18
+ def class_name
19
+ string.scan(/(.*)[\.\#]/)[0][0]
20
+ end
21
+
22
+ def execute
23
+ MethodSignature.new(
24
+ class_name: class_name,
25
+ method_operator: method_operator,
26
+ method: method,
27
+ args: args,
28
+ return_values: return_values)
29
+ end
30
+
31
+ def method
32
+ string.scan(/[\.\#](.*?)(=>|\(|$)/)[0][0]
33
+ end
34
+
35
+ def method_operator
36
+ string.scan(/[\.\#]/)[0][0]
37
+ end
38
+
39
+ def return_values
40
+ results = string.scan(/=>(.*)/)[0]
41
+ if results
42
+ results[0].split(',').map{|return_value|
43
+ MethodSignatureValue.new(eval(return_value)) }
44
+ else
45
+ []
46
+ end
47
+ end
48
+ end
49
+ end
@@ -8,7 +8,7 @@ module VerifiedDouble
8
8
  end
9
9
 
10
10
  def and_return(return_value)
11
- self.method_signatures.last.return_value = return_value
11
+ self.method_signatures.last.return_values = [MethodSignatureValue.new(return_value)]
12
12
  @double_call.and_return(return_value)
13
13
  self
14
14
  end
@@ -38,8 +38,11 @@ module VerifiedDouble
38
38
  end
39
39
 
40
40
  def should_receive(method)
41
- method_signature = MethodSignature.new(self)
42
- method_signature.method = method
41
+ method_signature = MethodSignature.new(
42
+ class_name: class_name,
43
+ method_operator: method_operator,
44
+ method: method.to_s)
45
+
43
46
  self.method_signatures << method_signature
44
47
  @double_call = super(method)
45
48
  self
@@ -50,7 +53,8 @@ module VerifiedDouble
50
53
  end
51
54
 
52
55
  def with(*args)
53
- self.method_signatures.last.args = args
56
+ self.method_signatures.last.args =
57
+ args.map{|arg| MethodSignatureValue.new(arg) }
54
58
  @double_call.with(*args)
55
59
  self
56
60
  end
@@ -1,3 +1,3 @@
1
1
  module VerifiedDouble
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -2,6 +2,14 @@ require 'active_support/core_ext/string'
2
2
  require 'pry'
3
3
  require 'rspec/fire'
4
4
 
5
+ require 'verified_double/boolean'
6
+
7
+ # Requiring because these are Value objects.
8
+ # As value objects, we treat them as primitives.
9
+ # Hence, there should be no need to mock or stub them.
10
+ require "verified_double/method_signature"
11
+ require "verified_double/method_signature_value"
12
+
5
13
  RSpec.configure do |config|
6
14
  config.include(RSpec::Fire)
7
15
  end
@@ -3,10 +3,10 @@ require 'verified_double/get_registered_signatures'
3
3
 
4
4
  describe VerifiedDouble::GetRegisteredSignatures do
5
5
  let(:method_signature_1) {
6
- fire_double('VerifiedDouble::MethodSignature', to_s: 'method_signature_1') }
6
+ VerifiedDouble::MethodSignature.new(class_name: 'Object', method_operator: '#', method: 'to_s') }
7
7
 
8
8
  let(:method_signature_2) {
9
- fire_double('VerifiedDouble::MethodSignature', to_s: 'method_signature_2') }
9
+ VerifiedDouble::MethodSignature.new(class_name: 'Object', method_operator: '#', method: 'inspect') }
10
10
 
11
11
  let(:recording_double_1) {
12
12
  fire_double('VerifiedDouble::RecordingDouble',
@@ -23,7 +23,7 @@ describe VerifiedDouble::GetRegisteredSignatures do
23
23
  let(:double_registry){ [recording_double_1, recording_double_2] }
24
24
 
25
25
  it "maps and flattens the method signatures of the recording doubles" do
26
- expect(subject.execute).to eq(['method_signature_1', 'method_signature_2'])
26
+ expect(subject.execute).to eq([method_signature_1, method_signature_2])
27
27
  end
28
28
  end
29
29
 
@@ -35,7 +35,7 @@ describe VerifiedDouble::GetRegisteredSignatures do
35
35
  let(:double_registry){ [recording_double_1, recording_double_2] }
36
36
 
37
37
  it "returns distinct method signatures" do
38
- expect(subject.execute).to eq(['method_signature_1'])
38
+ expect(subject.execute).to eq([method_signature_1])
39
39
  end
40
40
  end
41
41
  end
@@ -11,16 +11,40 @@ describe VerifiedDouble::GetUnverifiedSignatures do
11
11
  subject { described_class.new(get_registered_signatures_service, get_verified_signatures_service) }
12
12
 
13
13
  describe "#execute" do
14
- it "subtracts verified_signatures from registered_signatures" do
14
+ let(:registered_signature) {
15
+ VerifiedDouble::MethodSignature.new(
16
+ class_name: 'Person',
17
+ method: 'find',
18
+ method_operator: '.',
19
+ args: [VerifiedDouble::MethodSignatureValue.new(1)]) }
20
+
21
+ let(:registered_signature_without_match) {
22
+ VerifiedDouble::MethodSignature.new(
23
+ class_name: 'Person',
24
+ method: 'save!',
25
+ method_operator: '#') }
26
+
27
+ let(:verified_signature) {
28
+ VerifiedDouble::MethodSignature.new(
29
+ class_name: 'Person',
30
+ method: 'find',
31
+ method_operator: '.',
32
+ args: [VerifiedDouble::MethodSignatureValue.new(Object)]) }
33
+
34
+ it "retains registered signatures that cannot accept any of the verified_signatures" do
35
+ expect(registered_signature.accepts?(verified_signature)).to be_true
36
+ expect(registered_signature_without_match.accepts?(verified_signature)).to be_false
37
+
15
38
  get_registered_signatures_service
16
39
  .should_receive(:execute)
17
- .and_return([:verified_signature, :unverified_signature])
40
+ .and_return([registered_signature, registered_signature_without_match])
18
41
 
19
42
  get_verified_signatures_service
20
43
  .should_receive(:execute)
21
- .and_return([:verified_signature])
44
+ .at_least(:once)
45
+ .and_return([verified_signature])
22
46
 
23
- expect(subject.execute).to eq([:unverified_signature])
47
+ expect(subject.execute).to eq([registered_signature_without_match])
24
48
  end
25
49
  end
26
50
  end
@@ -2,7 +2,16 @@ require 'unit_helper'
2
2
  require 'verified_double/get_verified_signatures'
3
3
 
4
4
  describe VerifiedDouble::GetVerifiedSignatures do
5
+ let(:method_signature) { VerifiedDouble::MethodSignature.new }
6
+
5
7
  let(:nested_example_group){ double(:nested_example_group) }
8
+
9
+ let(:parse_method_signature_service) {
10
+ fire_double('VerifiedDouble::ParseMethodSignature') }
11
+
12
+ let(:parse_method_signature_service_class) {
13
+ fire_class_double('VerifiedDouble::ParseMethodSignature').as_replaced_constant }
14
+
6
15
  subject { described_class.new(nested_example_group) }
7
16
 
8
17
  describe "#execute" do
@@ -18,14 +27,35 @@ describe VerifiedDouble::GetVerifiedSignatures do
18
27
  nested_example_group
19
28
  .stub_chain(:class, :descendant_filtered_examples)
20
29
  .and_return([example_with_verified_contract_tag, example_without_verified_contract_tag])
21
- expect(subject.execute).to eq([example_with_verified_contract_tag.metadata[:verifies_contract]])
30
+
31
+ parse_method_signature_service_class
32
+ .should_receive(:new)
33
+ .with(example_with_verified_contract_tag.metadata[:verifies_contract])
34
+ .and_return(parse_method_signature_service)
35
+
36
+ parse_method_signature_service
37
+ .should_receive(:execute)
38
+ .and_return(method_signature)
39
+
40
+ expect(subject.execute).to eq([method_signature])
22
41
  end
23
42
 
24
43
  it "returns unique signatures" do
25
44
  nested_example_group
26
45
  .stub_chain(:class, :descendant_filtered_examples)
27
46
  .and_return([example_with_verified_contract_tag, example_with_verified_contract_tag])
28
- expect(subject.execute).to eq([example_with_verified_contract_tag.metadata[:verifies_contract]])
47
+
48
+ parse_method_signature_service_class
49
+ .should_receive(:new)
50
+ .with(example_with_verified_contract_tag.metadata[:verifies_contract])
51
+ .at_least(:once)
52
+ .and_return(parse_method_signature_service)
53
+
54
+ parse_method_signature_service
55
+ .should_receive(:execute)
56
+ .and_return(method_signature)
57
+
58
+ expect(subject.execute).to eq([method_signature])
29
59
  end
30
60
  end
31
61
  end
@@ -2,49 +2,152 @@ require 'unit_helper'
2
2
  require 'verified_double/method_signature'
3
3
 
4
4
  describe VerifiedDouble::MethodSignature do
5
- describe "#to_s" do
6
- let(:recording_double) {
7
- fire_double('VerifiedDouble::RecordingDouble',
8
- class_name: 'Dummy',
9
- method_operator: '#') }
5
+ class Dummy
6
+ end
7
+
8
+ let(:attributes){
9
+ { class_name: 'Dummy',
10
+ method_operator: '#' } }
11
+
12
+ describe "#initialize" do
13
+ it { expect(subject.return_values).to be_empty }
14
+ it { expect(subject.args).to be_empty }
15
+ end
10
16
 
17
+ describe "#to_s" do
11
18
  subject {
12
- described_class.new(recording_double).tap {|method_signature|
19
+ described_class.new(attributes).tap {|method_signature|
13
20
  method_signature.method = 'do_something' } }
14
21
 
15
22
  context "when there are args" do
16
- it "includes the args in the result" do
17
- subject.args = [1, {}]
18
- expect(subject.to_s).to eq("Dummy#do_something(Fixnum, Hash)")
23
+ it "includes the arg values in the result" do
24
+ subject.args = [VerifiedDouble::MethodSignatureValue.new(1), VerifiedDouble::MethodSignatureValue.new({})]
25
+ expect(subject.to_s).to eq("Dummy#do_something(1, {})")
19
26
  end
20
27
  end
21
28
 
22
29
  context "when there are no args" do
23
30
  it "displays an empty parenthesis for the args of the result" do
24
- expect(subject.return_value).to be_nil
31
+ expect(subject.args).to be_empty
25
32
  expect(subject.to_s).to eq("Dummy#do_something()")
26
33
  end
27
34
  end
28
35
 
29
36
  context "when there is a nil arg" do
30
- it "displays a nil class for the arg of the result" do
31
- subject.args = [nil]
32
- expect(subject.to_s).to eq("Dummy#do_something(NilClass)")
37
+ it "displays nil for the arg of the result" do
38
+ subject.args = [VerifiedDouble::MethodSignatureValue.new(nil)]
39
+ expect(subject.to_s).to eq("Dummy#do_something(nil)")
33
40
  end
34
41
  end
35
42
 
36
43
  context "where there is a return value" do
37
44
  it "displays the return value" do
38
- subject.return_value = true
39
- expect(subject.to_s).to eq("Dummy#do_something()=>TrueClass")
45
+ subject.return_values = [VerifiedDouble::MethodSignatureValue.new(true)]
46
+ expect(subject.to_s).to eq("Dummy#do_something()=>true")
40
47
  end
41
48
  end
42
49
 
43
50
  context "where there is no return value" do
44
51
  it "does not include the hash rocket in the result" do
45
- expect(subject.return_value).to be_nil
52
+ expect(subject.return_values).to be_empty
46
53
  expect(subject.to_s).to eq("Dummy#do_something()")
47
54
  end
48
55
  end
49
56
  end
57
+
58
+ context "multiple method signatures with the same #to_s" do
59
+ let(:method_signature){
60
+ described_class.new(attributes).tap {|method_signature|
61
+ method_signature.method = 'do_something' } }
62
+
63
+ let(:method_signature_with_same_to_s){
64
+ described_class.new(attributes).tap {|method_signature|
65
+ method_signature.method = 'do_something' } }
66
+
67
+ it { expect(method_signature.to_s).to eq(method_signature_with_same_to_s.to_s) }
68
+ it { expect(method_signature.hash).to eq(method_signature_with_same_to_s.hash) }
69
+ it { expect(method_signature.eql?(method_signature_with_same_to_s)).to be_true }
70
+ it { expect([method_signature, method_signature_with_same_to_s].uniq == [method_signature]).to be_true }
71
+ end
72
+
73
+ describe "#accepts?(other)" do
74
+ let(:method_signature){
75
+ described_class.new(
76
+ class_name: 'Dummy',
77
+ method_operator: '.',
78
+ method: 'find',
79
+ args: [VerifiedDouble::MethodSignatureValue.new(1)],
80
+ return_values: [VerifiedDouble::MethodSignatureValue.new(Dummy.new)]) }
81
+
82
+ subject { method_signature.accepts?(other) }
83
+
84
+ context "where self has same attributes as other" do
85
+ let(:other){ method_signature.clone }
86
+ it { expect(subject).to be_true }
87
+ end
88
+
89
+ context "where self and other have different class names" do
90
+ let(:other){ method_signature.clone.tap{|ms| ms.class_name = 'Object' } }
91
+ it { expect(subject).to be_false }
92
+ end
93
+
94
+ context "where self and other have different method operators" do
95
+ let(:other){ method_signature.clone.tap{|ms| ms.method_operator = '#' } }
96
+ it { expect(subject).to be_false }
97
+ end
98
+
99
+ context "where self and other have different methods" do
100
+ let(:other){ method_signature.clone.tap{|ms| ms.method = 'destroy' } }
101
+ it { expect(subject).to be_false }
102
+ end
103
+
104
+ context "where self and other have different number of args" do
105
+ let(:other){
106
+ method_signature.clone.tap{|ms|
107
+ ms.args = [VerifiedDouble::MethodSignatureValue.new(1), VerifiedDouble::MethodSignatureValue.new(2)] } }
108
+
109
+ it { expect(subject).to be_false }
110
+ end
111
+
112
+ context "where not all of self's args accept the args of other" do
113
+ let(:other){
114
+ method_signature.clone.tap{|ms|
115
+ ms.args = [VerifiedDouble::MethodSignatureValue.new(2)] } }
116
+
117
+ it { expect(subject).to be_false }
118
+ end
119
+
120
+ context "where self and other have different number of return values" do
121
+ let(:other){
122
+ method_signature.clone.tap{|ms|
123
+ ms.return_values = [VerifiedDouble::MethodSignatureValue.new(1), VerifiedDouble::MethodSignatureValue.new(2)] } }
124
+
125
+ it { expect(subject).to be_false }
126
+ end
127
+
128
+ context "where not all of self's return values accept the return values of other" do
129
+ let(:other){
130
+ method_signature.clone.tap{|ms|
131
+ ms.return_values = [VerifiedDouble::MethodSignatureValue.new(Symbol)] } }
132
+
133
+ it { expect(subject).to be_false }
134
+ end
135
+ end
136
+
137
+ describe "#recommended_verified_signature" do
138
+ let(:method_signature){
139
+ described_class.new(
140
+ class_name: 'Dummy',
141
+ method_operator: '.',
142
+ method: 'find',
143
+ args: [VerifiedDouble::MethodSignatureValue.new(1)],
144
+ return_values: [VerifiedDouble::MethodSignatureValue.new(Dummy.new)]) }
145
+
146
+ subject { method_signature.recommended_verified_signature }
147
+
148
+ it "is a method signature that is recommended for the user to verify" do
149
+ expect(subject.args[0].value).to eq(method_signature.args[0].recommended_value.value)
150
+ expect(subject.return_values[0].value).to eq(method_signature.return_values[0].recommended_value.value)
151
+ end
152
+ end
50
153
  end
@@ -0,0 +1,82 @@
1
+ require 'unit_helper'
2
+ require 'verified_double/method_signature_value'
3
+
4
+ describe VerifiedDouble::MethodSignatureValue do
5
+ let(:value){ :some_value }
6
+
7
+ describe "#initialize" do
8
+ it "requires a value from a method signature" do
9
+ described_class.new(value)
10
+ end
11
+ end
12
+
13
+ describe "#accepts?(other)" do
14
+ subject { this.accepts?(other) }
15
+
16
+ context "where self's value is an actual class and other's value matches it" do
17
+ let(:this){ described_class.new(Fixnum) }
18
+ let(:other){ described_class.new(Fixnum) }
19
+ it { expect(subject).to be_true }
20
+ end
21
+
22
+ context "where self's value is an actual class and other's value does not match it" do
23
+ let(:this){ described_class.new(Fixnum) }
24
+ let(:other){ described_class.new(Object) }
25
+ it { expect(subject).to be_false }
26
+ end
27
+
28
+ context "where the other value is an instance and self's value matches it" do
29
+ let(:this){ described_class.new(1) }
30
+ let(:other){ described_class.new(1) }
31
+ it { expect(subject).to be_true }
32
+ end
33
+
34
+ context "where the other value is an instance and self's value does not it" do
35
+ let(:this){ described_class.new(2) }
36
+ let(:other){ described_class.new(1) }
37
+ it { expect(subject).to be_false }
38
+ end
39
+
40
+ context "where self is an instance and the other's class is an ancestor of self's modified class" do
41
+ let(:this){ described_class.new(1) }
42
+ let(:other){ described_class.new(Object) }
43
+ it { expect(subject).to be_true }
44
+ end
45
+
46
+ context "where self is an instance and the other's class is not an ancestor of self's modified class" do
47
+ let(:this){ described_class.new(1) }
48
+ let(:other){ described_class.new(Float) }
49
+ it { expect(subject).to be_false }
50
+ end
51
+ end
52
+
53
+ describe "#modified_class" do
54
+ subject { method_signature_value.modified_class }
55
+
56
+ context "where the value is true" do
57
+ let(:method_signature_value) { described_class.new(true) }
58
+ it { expect(subject).to eq(VerifiedDouble::Boolean) }
59
+ end
60
+
61
+ context "where the value is false" do
62
+ let(:method_signature_value) { described_class.new(false) }
63
+ it { expect(subject).to eq(VerifiedDouble::Boolean) }
64
+ end
65
+
66
+ context "where the value is not true or false" do
67
+ let(:method_signature_value) { described_class.new(1) }
68
+ it "is the class of the value" do
69
+ expect(subject).to eq(Fixnum)
70
+ end
71
+ end
72
+ end
73
+
74
+ describe "#recommended_value" do
75
+ subject { described_class.new(value) }
76
+
77
+ it "is a version of self that will be recommended to users to verify" do
78
+ expect(subject.recommended_value.value).to eq(subject.modified_class)
79
+ expect(subject.recommended_value.value).to_not eq(subject)
80
+ end
81
+ end
82
+ end
@@ -2,10 +2,25 @@ require 'unit_helper'
2
2
  require 'verified_double/output_unverified_signatures'
3
3
 
4
4
  describe VerifiedDouble::OutputUnverifiedSignatures do
5
+ class Dummy
6
+ end
7
+
5
8
  let(:get_unverified_signatures_service){
6
9
  fire_double('VerifiedDouble::GetUnverifiedSignatures') }
7
10
 
8
- let(:unverified_signatures){ %w(UNVERIFIED_SIGNATURES_1 UNVERIFIED_SIGNATURES_2) }
11
+ let(:unverified_signatures){ [
12
+ VerifiedDouble::MethodSignature.new(
13
+ class_name: 'Dummy',
14
+ method_operator: '.',
15
+ method: 'find',
16
+ args: [VerifiedDouble::MethodSignatureValue.new(1)],
17
+ return_values: [VerifiedDouble::MethodSignatureValue.new(Dummy.new)]),
18
+ VerifiedDouble::MethodSignature.new(
19
+ class_name: 'Dummy',
20
+ method_operator: '.',
21
+ method: 'where',
22
+ args: [VerifiedDouble::MethodSignatureValue.new(id: 1)],
23
+ return_values: [VerifiedDouble::MethodSignatureValue.new(Dummy.new)]) ] }
9
24
 
10
25
  subject { described_class.new(get_unverified_signatures_service) }
11
26
 
@@ -20,10 +35,15 @@ describe VerifiedDouble::OutputUnverifiedSignatures do
20
35
  end
21
36
 
22
37
  context "where there are unverified_signatures" do
23
- it "should output the unverified_signatures" do
38
+ it "should output the recommended versions of the unverified_signatures" do
24
39
  get_unverified_signatures_service.should_receive(:execute).and_return(unverified_signatures)
25
- subject.should_receive(:puts).with("The following mocks are not verified:\nUNVERIFIED_SIGNATURES_1\nUNVERIFIED_SIGNATURES_2")
26
40
 
41
+ lines = [
42
+ "The following mocks are not verified:",
43
+ unverified_signatures[0].recommended_verified_signature,
44
+ unverified_signatures[1].recommended_verified_signature ]
45
+
46
+ subject.should_receive(:puts).with(lines.join("\n"))
27
47
  subject.execute
28
48
  end
29
49
  end
@@ -0,0 +1,95 @@
1
+ require 'unit_helper'
2
+ require 'verified_double/parse_method_signature'
3
+
4
+ describe VerifiedDouble::ParseMethodSignature do
5
+ subject { described_class.new(string) }
6
+
7
+ describe "#execute" do
8
+ let(:string){ "Class#method(:arg_1, :arg_2)=>:return_value" }
9
+
10
+ subject { described_class.new(string).execute }
11
+
12
+ it "returns a method signature from the signature string" do
13
+ expect(subject).to be_a(VerifiedDouble::MethodSignature)
14
+ expect(subject.class_name).to eq(subject.class_name)
15
+ expect(subject.method_operator).to eq(subject.method_operator)
16
+ expect(subject.method).to eq(subject.method)
17
+ expect(subject.args).to eq(subject.args)
18
+ expect(subject.return_values).to eq(subject.return_values)
19
+ end
20
+ end
21
+
22
+ describe "#method_operator" do
23
+ context "for Class.method" do
24
+ let(:string){ "Class.method" }
25
+ it { expect(subject.method_operator).to eq('.') }
26
+ end
27
+
28
+ context "for Class#method" do
29
+ let(:string){ "Class#method" }
30
+ it { expect(subject.method_operator).to eq('#') }
31
+ end
32
+ end
33
+
34
+ describe "#class_name" do
35
+ context "for Class.method" do
36
+ let(:string){ "Class.method" }
37
+ it { expect(subject.class_name).to eq('Class') }
38
+ end
39
+ end
40
+
41
+ describe "#method" do
42
+ context "for Class.method" do
43
+ let(:string){ "Class.method_1!?" }
44
+ it { expect(subject.method).to eq('method_1!?') }
45
+ end
46
+
47
+ context "for Class.method(:arg_1, :arg_2)" do
48
+ let(:string){ "Class.method_1!?(:arg_1, :arg_2)" }
49
+ it { expect(subject.method).to eq('method_1!?') }
50
+ end
51
+
52
+ context "for Class.method=>return_value" do
53
+ let(:string){ "Class.method_1!?=>return_value" }
54
+ it { expect(subject.method).to eq('method_1!?') }
55
+ end
56
+ end
57
+
58
+
59
+ describe "#args" do
60
+ context "for Class.method(:arg_1, :arg_2)" do
61
+ let(:string){ "Class.method(:arg_1, :arg_2)" }
62
+
63
+ it "builds method signature values from the evals of the args" do
64
+ expect(subject.args.map(&:value)).to eq([:arg_1, :arg_2])
65
+ end
66
+ end
67
+
68
+ context "for Class.method" do
69
+ let(:string){ "Class.method" }
70
+ it { expect(subject.args).to eq([]) }
71
+ end
72
+
73
+ context "for Class.method=>:return_value" do
74
+ let(:string){ "Class.method=>:return_value" }
75
+ it { expect(subject.args).to eq([]) }
76
+ end
77
+ end
78
+
79
+ describe "#return_values" do
80
+ context "for Class.method=>:return_value" do
81
+ let(:string){ "Class.method=>:return_value" }
82
+ it { expect(subject.return_values.map(&:value)).to eq([:return_value]) }
83
+ end
84
+
85
+ context "for Class.method" do
86
+ let(:string){ "Class.method" }
87
+ it { expect(subject.return_values).to be_empty }
88
+ end
89
+
90
+ context "for Class.method(:arg_1, :arg_2)" do
91
+ let(:string){ "Class.method(:arg_1, :arg_2)" }
92
+ it { expect(subject.return_values).to be_empty }
93
+ end
94
+ end
95
+ end
@@ -104,7 +104,7 @@ describe VerifiedDouble::RecordingDouble do
104
104
  subject.should_receive(:to_s)
105
105
  subject.should_receive(:inspect)
106
106
 
107
- expect(subject.method_signatures.map(&:method)).to eq([:to_s, :inspect])
107
+ expect(subject.method_signatures.map(&:method)).to eq(['to_s', 'inspect'])
108
108
 
109
109
  subject.to_s
110
110
  subject.inspect
@@ -115,7 +115,8 @@ describe VerifiedDouble::RecordingDouble do
115
115
  it "sets the args of the last method signature" do
116
116
  subject.should_receive(:to_s).with(:arg_1, :arg_2)
117
117
 
118
- expect(subject.method_signatures[0].args).to eq([:arg_1, :arg_2])
118
+ expect(subject.method_signatures[0].args).to be_all{|arg| arg.is_a?(VerifiedDouble::MethodSignatureValue) }
119
+ expect(subject.method_signatures[0].args.map(&:value)).to eq([:arg_1, :arg_2])
119
120
 
120
121
  subject.to_s(:arg_1, :arg_2)
121
122
  end
@@ -125,7 +126,10 @@ describe VerifiedDouble::RecordingDouble do
125
126
  it "sets the return value of the last method signature" do
126
127
  subject.should_receive(:to_s).with(:arg_1, :arg_2).and_return(:return_value)
127
128
 
128
- expect(subject.method_signatures[0].return_value).to eq(:return_value)
129
+ return_values = subject.method_signatures[0].return_values
130
+ expect(return_values).to have(1).return_value
131
+ expect(return_values.first).to be_a(VerifiedDouble::MethodSignatureValue)
132
+ expect(return_values.first.value).to eq(:return_value)
129
133
 
130
134
  subject.to_s(:arg_1, :arg_2)
131
135
  end
@@ -18,7 +18,7 @@ Gem::Specification.new do |gem|
18
18
  gem.require_paths = ["lib"]
19
19
 
20
20
  gem.add_runtime_dependency "rspec"
21
- gem.add_runtime_dependency "rspec-fire"
21
+ gem.add_runtime_dependency "rspec-fire", '~> 1.1.3'
22
22
 
23
23
  gem.add_development_dependency "aruba"
24
24
  gem.add_development_dependency "cucumber"
metadata CHANGED
@@ -2,14 +2,14 @@
2
2
  name: verified_double
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.1
5
+ version: 0.0.2
6
6
  platform: ruby
7
7
  authors:
8
8
  - George Mendoza
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-06-02 00:00:00.000000000 Z
12
+ date: 2013-06-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  type: :runtime
@@ -32,16 +32,16 @@ dependencies:
32
32
  requirement: !ruby/object:Gem::Requirement
33
33
  none: false
34
34
  requirements:
35
- - - ! '>='
35
+ - - ~>
36
36
  - !ruby/object:Gem::Version
37
- version: '0'
37
+ version: 1.1.3
38
38
  prerelease: false
39
39
  version_requirements: !ruby/object:Gem::Requirement
40
40
  none: false
41
41
  requirements:
42
- - - ! '>='
42
+ - - ~>
43
43
  - !ruby/object:Gem::Version
44
- version: '0'
44
+ version: 1.1.3
45
45
  name: rspec-fire
46
46
  - !ruby/object:Gem::Dependency
47
47
  type: :development
@@ -116,20 +116,26 @@ extra_rdoc_files: []
116
116
  files:
117
117
  - .gitignore
118
118
  - .travis.yml
119
+ - CHANGELOG.markdown
119
120
  - Gemfile
120
121
  - LICENSE.txt
121
122
  - README.md
122
123
  - Rakefile
124
+ - features/CHANGELOG.markdown
125
+ - features/customizing_arguments_and_return_values.feature
123
126
  - features/readme.md
124
127
  - features/step_definitions/verified_double_steps.rb
125
128
  - features/support/requires.rb
126
129
  - features/verified_double.feature
127
130
  - lib/verified_double.rb
131
+ - lib/verified_double/boolean.rb
128
132
  - lib/verified_double/get_registered_signatures.rb
129
133
  - lib/verified_double/get_unverified_signatures.rb
130
134
  - lib/verified_double/get_verified_signatures.rb
131
135
  - lib/verified_double/method_signature.rb
136
+ - lib/verified_double/method_signature_value.rb
132
137
  - lib/verified_double/output_unverified_signatures.rb
138
+ - lib/verified_double/parse_method_signature.rb
133
139
  - lib/verified_double/recording_double.rb
134
140
  - lib/verified_double/report_unverified_signatures.rb
135
141
  - lib/verified_double/verify_doubles_service.rb
@@ -140,7 +146,9 @@ files:
140
146
  - spec/verified_double/get_unverified_signatures_spec.rb
141
147
  - spec/verified_double/get_verified_signatures_spec.rb
142
148
  - spec/verified_double/method_signature_spec.rb
149
+ - spec/verified_double/method_signature_value_spec.rb
143
150
  - spec/verified_double/output_unverified_signatures_spec.rb
151
+ - spec/verified_double/parse_method_signature_spec.rb
144
152
  - spec/verified_double/recording_double_spec.rb
145
153
  - spec/verified_double/report_unverified_signatures_spec.rb
146
154
  - spec/verified_double/verify_doubles_service_spec.rb
@@ -172,6 +180,8 @@ specification_version: 3
172
180
  summary: VerifiedDouble would record any mock made in the test suite. It would then
173
181
  verify if the mock is valid by checking if there is a test against it.
174
182
  test_files:
183
+ - features/CHANGELOG.markdown
184
+ - features/customizing_arguments_and_return_values.feature
175
185
  - features/readme.md
176
186
  - features/step_definitions/verified_double_steps.rb
177
187
  - features/support/requires.rb
@@ -182,7 +192,9 @@ test_files:
182
192
  - spec/verified_double/get_unverified_signatures_spec.rb
183
193
  - spec/verified_double/get_verified_signatures_spec.rb
184
194
  - spec/verified_double/method_signature_spec.rb
195
+ - spec/verified_double/method_signature_value_spec.rb
185
196
  - spec/verified_double/output_unverified_signatures_spec.rb
197
+ - spec/verified_double/parse_method_signature_spec.rb
186
198
  - spec/verified_double/recording_double_spec.rb
187
199
  - spec/verified_double/report_unverified_signatures_spec.rb
188
200
  - spec/verified_double/verify_doubles_service_spec.rb