synthesis 0.0.15 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README CHANGED
@@ -82,6 +82,10 @@ Or, in the case of RSpec, it is equivalent to:
82
82
 
83
83
  Either <tt>"mocha_standalone"</tt> or <tt>"spec/mocks"</tt> need to be required before using <tt>mock_instance</tt>.
84
84
 
85
+ == Git
86
+
87
+ Public clone URL: git://github.com/gmalamid/synthesis.git
88
+
85
89
  == Known Issues
86
90
 
87
91
  Reporting the location (filename and line number) of tested/untested expectations doesn't work as intended with the Expectations adapter.
data/Rakefile CHANGED
@@ -58,7 +58,7 @@ end
58
58
 
59
59
  gem_spec = Gem::Specification.new do |s|
60
60
  s.name = 'synthesis'
61
- s.version = '0.0.15'
61
+ s.version = '0.1.0'
62
62
  s.platform = Gem::Platform::RUBY
63
63
  s.rubyforge_project = "synthesis"
64
64
  s.summary, s.description = 'A tool for Synthesized Testing'
@@ -17,6 +17,7 @@ module Synthesis
17
17
  Mocha::Expectation.extend(ExpectationInterceptor)
18
18
  Mocha::Expectation.record_expected_argument_types_on(:with)
19
19
  Mocha::Expectation.record_expected_return_values_on(:returns)
20
+ Mocha::Expectation.record_expected_return_values_on(:raises)
20
21
  end
21
22
 
22
23
  def stop_collecting_expectations
@@ -18,6 +18,7 @@ module Synthesis
18
18
  Mocha::Expectation.extend(ExpectationInterceptor)
19
19
  Mocha::Expectation.record_expected_argument_types_on(:with)
20
20
  Mocha::Expectation.record_expected_return_values_on(:returns)
21
+ Mocha::Expectation.record_expected_return_values_on(:raises)
21
22
  end
22
23
 
23
24
  def stop_collecting_expectations
@@ -22,6 +22,7 @@ module Synthesis
22
22
  Spec::Mocks::MessageExpectation.extend(ExpectationInterceptor)
23
23
  Spec::Mocks::MessageExpectation.record_expected_argument_types_on(:with)
24
24
  Spec::Mocks::MessageExpectation.record_expected_return_values_on(:and_return)
25
+ Spec::Mocks::MessageExpectation.record_expected_return_values_on(:and_raise)
25
26
  end
26
27
 
27
28
  def stop_collecting_expectations
@@ -51,8 +51,8 @@ module Synthesis
51
51
  args.map { |arg| arg.class }
52
52
  end
53
53
 
54
- def return_value_types
55
- @return_values.map { |val| val.class }.uniq
54
+ def return_value_type
55
+ @return_values[0] ? @return_values[0].class : nil
56
56
  end
57
57
 
58
58
  def add_return_values(*vals)
@@ -79,7 +79,7 @@ module Synthesis
79
79
  end
80
80
 
81
81
  def to_s
82
- "(#{return_value_types * ", "}) " +
82
+ "(#{return_value_type}) " +
83
83
  "#{@receiver.name}.#{@method}(#{@args.map { |arg| arg.class } * ', '})" +
84
84
  "in #{@track}"
85
85
  end
@@ -99,8 +99,7 @@ module Synthesis
99
99
  end
100
100
 
101
101
  def to_s
102
- "(#{return_value_types * ", "}) " +
103
- "#{meta_receiver.name}.new.#{@method}" +
102
+ "(#{return_value_type}) #{meta_receiver.name}.new.#{@method}" +
104
103
  "(#{@args.map { |arg| arg.class } * ', '})" +
105
104
  "in #{@track}"
106
105
  end
@@ -6,7 +6,7 @@ module Synthesis
6
6
  # Intercept the mock object framework's expectation method for declaring a mocked
7
7
  # method's arguments so that Synthesis can record them.
8
8
  def record_expected_argument_types_on(method_name)
9
- @original_with = method_name
9
+ (@original_methods ||= []) << method_name
10
10
 
11
11
  class_eval do
12
12
  alias_method "intercepted_#{method_name}", method_name
@@ -26,7 +26,7 @@ module Synthesis
26
26
  # Intercept the mock object framework's expectation method for declaring a mocked
27
27
  # method's return values so that Synthesis can record them.
28
28
  def record_expected_return_values_on(method_name)
29
- @original_returns = method_name
29
+ (@original_methods ||= []) << method_name
30
30
 
31
31
  class_eval do
32
32
  alias_method "intercepted_#{method_name}", method_name
@@ -43,12 +43,14 @@ module Synthesis
43
43
  # undefine their intercepted counterparts. Undefine the synthesis_expectation
44
44
  # accessors.
45
45
  def stop_intercepting!
46
- with_method, returns_method = @original_with, @original_returns
46
+ @original_methods.each do |m|
47
+ class_eval do
48
+ alias_method m, "intercepted_#{m}"
49
+ remove_method "intercepted_#{m}"
50
+ end
51
+ end
52
+
47
53
  class_eval do
48
- alias_method with_method, "intercepted_#{with_method}"
49
- alias_method returns_method, "intercepted_#{returns_method}"
50
- remove_method "intercepted_#{with_method}"
51
- remove_method "intercepted_#{returns_method}"
52
54
  remove_method :synthesis_expectation
53
55
  remove_method :synthesis_expectation=
54
56
  end
@@ -17,7 +17,7 @@ module Synthesis
17
17
 
18
18
  def return_values_match?
19
19
  return true unless @expectation_one.return_values_defined? || @expectation_two.return_values_defined?
20
- @expectation_one.return_value_types == @expectation_two.return_value_types
20
+ @expectation_one.return_value_type == @expectation_two.return_value_type
21
21
  end
22
22
  end
23
23
  end
@@ -72,7 +72,9 @@ module Synthesis
72
72
  end
73
73
 
74
74
  def ignore?(obj)
75
- ignored.include?(obj.class) || (obj.is_a?(Class) && ignored.include?(obj)) || obj.is_a?(MOCK_OBJECT)
75
+ ignored.include?(obj.class) ||
76
+ (obj.is_a?(Class) && ignored.include?(obj)) ||
77
+ obj.is_a?(MOCK_OBJECT)
76
78
  end
77
79
 
78
80
  def reset!
@@ -15,9 +15,14 @@ module Synthesis
15
15
  alias_method "__recordable__#{meth}".intern, meth
16
16
  class_eval <<-end_eval
17
17
  def #{meth}(*args, &block)
18
- return_value = send("__recordable__#{meth}", *args, &block)
19
- MethodInvocationWatcher.invoked(self, "#{meth}".intern, args, [return_value])
20
- return_value
18
+ begin
19
+ return_value = send("__recordable__#{meth}", *args, &block)
20
+ MethodInvocationWatcher.invoked(self, "#{meth}".intern, args, [return_value])
21
+ return_value
22
+ rescue Exception => e
23
+ MethodInvocationWatcher.invoked(self, "#{meth}".intern, args, [e])
24
+ raise e
25
+ end
21
26
  end
22
27
  end_eval
23
28
  end
@@ -26,9 +31,14 @@ module Synthesis
26
31
  def magic_recordable_method(meth)
27
32
  class_eval <<-end_eval
28
33
  def #{meth}(*args)
29
- return_value = method_missing(:#{meth}, *args)
30
- MethodInvocationWatcher.invoked(self, "#{meth}".intern, args, [return_value])
31
- return_value
34
+ begin
35
+ return_value = method_missing(:#{meth}, *args)
36
+ MethodInvocationWatcher.invoked(self, "#{meth}".intern, args, [return_value])
37
+ return_value
38
+ rescue Exception => e
39
+ MethodInvocationWatcher.invoked(self, "#{meth}".intern, args, [e])
40
+ raise e
41
+ end
32
42
  end
33
43
 
34
44
  def __recordable__#{meth}() raise "Don't ever call me" end
@@ -15,23 +15,4 @@ module Spec::Mocks::Methods
15
15
 
16
16
  return instance
17
17
  end
18
-
19
- # Don't know if this sucks or not...
20
-
21
- # def stub_instance
22
- # class_eval do
23
- # alias original_initialize initialize
24
- # def initialize()end
25
- # end
26
- #
27
- # instance = new
28
- # stub!(:new).and_return(instance)
29
- #
30
- # class_eval do
31
- # alias initialize original_initialize
32
- # undef original_initialize
33
- # end
34
- #
35
- # return instance
36
- # end
37
- end
18
+ end
@@ -20,6 +20,7 @@ class MochaExpectationTest < Test::Unit::TestCase
20
20
  def test_passes_return_values_to_synthesis_expectation
21
21
  @mocha_expectation.synthesis_expectation = @synthesis_expectation
22
22
  @mocha_expectation.returns(:rock)
23
- assert_equal([Fixnum, Symbol], @synthesis_expectation.return_value_types)
23
+ return_values = @synthesis_expectation.instance_variable_get(:@return_values)
24
+ assert_equal([1, :rock], return_values)
24
25
  end
25
26
  end
@@ -2,6 +2,6 @@ require File.dirname(__FILE__) + "/helper"
2
2
 
3
3
  class ClassTest < Test::Unit::TestCase
4
4
  def test_has_singleton_expectation
5
- assert_instance_of Synthesis::Expectation::Singleton, Hash.expectation(:foo, :track)
5
+ assert_instance_of(Synthesis::Expectation::Singleton, Hash.expectation(:foo, :track))
6
6
  end
7
7
  end
@@ -32,19 +32,19 @@ module Synthesis
32
32
  ExpectationRecord.add_expectation Object.new, :foo, :track
33
33
  matcher = Expectation.new Object.new, :bar, :track
34
34
  actual_instance = ExpectationRecord[matcher]
35
- assert_kind_of Expectation::NilExpectation, actual_instance
35
+ assert_kind_of(Expectation::NilExpectation, actual_instance)
36
36
  end
37
37
 
38
38
  def test_does_not_add_expectation_for_ignored_class
39
39
  ExpectationRecord.ignore(Hash)
40
40
  ExpectationRecord.add_expectation(Hash, :foo, :track)
41
- assert ExpectationRecord.expectations.empty?
41
+ assert(ExpectationRecord.expectations.empty?)
42
42
  end
43
43
 
44
44
  def test_does_not_add_expectation_for_ignored_object
45
45
  ExpectationRecord.ignore(Hash)
46
46
  ExpectationRecord.add_expectation(Hash.new, :foo, :track)
47
- assert ExpectationRecord.expectations.empty?
47
+ assert(ExpectationRecord.expectations.empty?)
48
48
  end
49
49
 
50
50
  def test_returns_added_expectation_on_add
@@ -52,9 +52,9 @@ module Synthesis
52
52
  assert_equal([Symbol, String], expectation.arg_types)
53
53
  end
54
54
 
55
- def test_return_value_types
56
- expectation = Expectation.new(String.new, :new, :track, [], [:sym, "str"])
57
- assert_equal([Symbol, String], expectation.return_value_types)
55
+ def test_return_value_type
56
+ expectation = Expectation.new(String.new, :new, :track, [], [:sym])
57
+ assert_equal(Symbol, expectation.return_value_type)
58
58
  end
59
59
 
60
60
  def test_adds_return_value
@@ -90,5 +90,10 @@ module Synthesis
90
90
  expectation.add_return_values("rock")
91
91
  assert_equal(expectation, expectation.explode)
92
92
  end
93
+
94
+ def test_returns_nil_when_no_return_values_on_return_value_type
95
+ expectation = Expectation.new(String, :new, :track, [])
96
+ assert_nil(expectation.return_value_type)
97
+ end
93
98
  end
94
99
  end
@@ -1,3 +1,3 @@
1
1
  %w(test/unit rubygems mocha).each { |l| require l }
2
2
  require File.dirname(__FILE__) + "/../../lib/synthesis"
3
- MOCK_OBJECT = Class.new {} # FIXME: should find a better way of doing this...
3
+ MOCK_OBJECT = Class.new {}
@@ -10,7 +10,7 @@ module Synthesis
10
10
  ExpectationRecord.add_expectation(Hash, :to_s, :track, []).add_return_values(1)
11
11
  MethodInvocationWatcher.invoked(Hash, :to_s, [], [1])
12
12
  expectation = ExpectationRecord.expectations.to_a.first
13
- assert expectation.invoked?
13
+ assert(expectation.invoked?)
14
14
  end
15
15
  end
16
16
  end
@@ -2,6 +2,6 @@ require File.dirname(__FILE__) + "/helper"
2
2
 
3
3
  class ModuleTest < Test::Unit::TestCase
4
4
  def test_has_singleton_expectation
5
- assert_instance_of Synthesis::Expectation::Singleton, Module.new.expectation(:foo, :track)
5
+ assert_instance_of(Synthesis::Expectation::Singleton, Module.new.expectation(:foo, :track))
6
6
  end
7
7
  end
@@ -2,6 +2,6 @@ require File.dirname(__FILE__) + "/helper"
2
2
 
3
3
  class ObjectTest < Test::Unit::TestCase
4
4
  def test_has_instance_expectation
5
- assert_instance_of Synthesis::Expectation::Instance, Object.new.expectation(:foo, :track)
5
+ assert_instance_of(Synthesis::Expectation::Instance, Object.new.expectation(:foo, :track))
6
6
  end
7
7
  end
@@ -4,14 +4,14 @@ module Synthesis
4
4
  class RecordableTest < Test::Unit::TestCase
5
5
  def test_redefines_method
6
6
  foo = Class.new { def a; end }
7
- foo.extend Recordable
7
+ foo.extend(Recordable)
8
8
  foo.recordable_method(:a)
9
9
  assert_respond_to(foo.new, :__recordable__a)
10
10
  end
11
11
 
12
12
  def test_records_method_invocation
13
13
  foo = Class.new { def b; end }
14
- foo.extend Recordable
14
+ foo.extend(Recordable)
15
15
  foo.recordable_method(:b)
16
16
  bar = foo.new
17
17
  MethodInvocationWatcher.expects(:invoked).with(bar, :b, [], [nil])
@@ -20,7 +20,7 @@ module Synthesis
20
20
 
21
21
  def test_does_not_redefine_already_redefined_method
22
22
  foo = Class.new { def b; end }
23
- foo.extend Recordable
23
+ foo.extend(Recordable)
24
24
  foo.stubs(:method_defined?).returns(true)
25
25
  foo.expects(:alias_method).never
26
26
  foo.recordable_method(:b)
@@ -28,39 +28,89 @@ module Synthesis
28
28
 
29
29
  def test_defines_non_existent_method
30
30
  foo = Class.new
31
- foo.extend Recordable
31
+ foo.extend(Recordable)
32
32
  foo.recordable_method(:bar)
33
33
  assert_respond_to(foo.new, :bar)
34
34
  end
35
35
 
36
36
  def test_defines_non_existent_method_recordable_placeholder_method
37
37
  foo = Class.new
38
- foo.extend Recordable
38
+ foo.extend(Recordable)
39
39
  foo.recordable_method(:bar)
40
40
  assert_respond_to(foo.new, :__recordable__bar)
41
41
  end
42
42
 
43
43
  def test_non_existed_method_placeholder_raises
44
44
  foo = Class.new
45
- foo.extend Recordable
45
+ foo.extend(Recordable)
46
46
  foo.recordable_method(:bar)
47
47
  assert_raise(RuntimeError) { foo.new.__recordable__bar }
48
48
  end
49
49
 
50
50
  def test_does_not_redefine_already_defined_magic_method
51
51
  foo = Class.new
52
- foo.extend Recordable
52
+ foo.extend(Recordable)
53
53
  foo.recordable_method(:b)
54
54
  foo.expects(:alias_method).never
55
55
  end
56
56
 
57
57
  def test_records_magic_method_invocation
58
58
  foo = Class.new {def method_missing(meth, *args) :magic! end}
59
- foo.extend Recordable
59
+ foo.extend(Recordable)
60
60
  foo.recordable_method(:b)
61
61
  bar = foo.new
62
62
  MethodInvocationWatcher.expects(:invoked).with(bar, :b, [], [:magic!])
63
63
  bar.b
64
64
  end
65
+
66
+ def test_records_raised_exception
67
+ begin
68
+ foo = Class.new {def bar() raise end}
69
+ foo.extend(Recordable)
70
+ foo.recordable_method(:bar)
71
+ inst = foo.new
72
+ matcher = Expectation.new(inst, :bar, nil, [])
73
+ matcher.add_return_values(RuntimeError.new)
74
+ not_found = Expectation::NilExpectation.new
75
+ ExpectationRecord.expects(:[]).with(matcher).returns(not_found)
76
+ inst.bar
77
+ rescue => e
78
+ raise e unless e.is_a?(RuntimeError)
79
+ end
80
+ end
81
+
82
+ def test_reraises_recorded_exception
83
+ assert_raise(RuntimeError) do
84
+ foo = Class.new {def bar() raise end}
85
+ foo.extend(Recordable)
86
+ foo.recordable_method(:bar)
87
+ foo.new.bar
88
+ end
89
+ end
90
+
91
+ def test_records_raised_exception_for_magic_method
92
+ begin
93
+ foo = Class.new {def method_missing(m, *a) raise end}
94
+ foo.extend(Recordable)
95
+ foo.recordable_method(:bar)
96
+ inst = foo.new
97
+ matcher = Expectation.new(inst, :bar, nil, [])
98
+ matcher.add_return_values(RuntimeError.new)
99
+ not_found = Expectation::NilExpectation.new
100
+ ExpectationRecord.expects(:[]).with(matcher).returns(not_found)
101
+ inst.bar
102
+ rescue => e
103
+ raise e unless e.is_a?(RuntimeError)
104
+ end
105
+ end
106
+
107
+ def test_reraises_recorded_exception_for_magic_method
108
+ assert_raise(RuntimeError) do
109
+ foo = Class.new {def method_missing(m, *a) raise end}
110
+ foo.extend(Recordable)
111
+ foo.recordable_method(:bar)
112
+ foo.new.bar
113
+ end
114
+ end
65
115
  end
66
116
  end
@@ -6,4 +6,13 @@ Expectations do
6
6
  expect Storage.new('whatever').to.receive(:save).with('METAL - rock') do |storage|
7
7
  DataBrander.new(storage).save_branded 'rock'
8
8
  end
9
+
10
+ expect Storage.new("").to.receive(:ouch!).raises(Problem.new) do |storage|
11
+ begin
12
+ DataBrander.new(storage).dont_do_this
13
+ rescue Problem
14
+ return true
15
+ end
16
+ fail
17
+ end
9
18
  end
@@ -11,4 +11,8 @@ Expectations do
11
11
  FileUtils.rm_f 'test.txt'
12
12
  end
13
13
  end
14
+
15
+ expect Problem do
16
+ Storage.new("").ouch!
17
+ end
14
18
  end
@@ -2,10 +2,10 @@
2
2
  require File.dirname(__FILE__) + "/../../test_project"
3
3
 
4
4
  class DataBranderTest < Test::Unit::TestCase
5
- def test_saves_branded_to_pstore
6
- pstore = Storage.new 'whatever'
7
- pstore.expects(:save).with('METAL - rock')
8
- DataBrander.new(pstore).save_branded('rock')
5
+ def test_saves_branded_to_storage
6
+ storage = Storage.new 'whatever'
7
+ storage.expects(:save).with('METAL - rock')
8
+ DataBrander.new(storage).save_branded('rock')
9
9
  end
10
10
 
11
11
  def test_ignores_total_ducks
@@ -13,4 +13,10 @@ class DataBranderTest < Test::Unit::TestCase
13
13
  m.expects(:foo)
14
14
  m.foo
15
15
  end
16
+
17
+ def test_delegates_problem
18
+ storage = Storage.new("")
19
+ storage.expects(:ouch!).raises(Problem.new)
20
+ assert_raise(Problem) { DataBrander.new(storage).dont_do_this }
21
+ end
16
22
  end
@@ -9,4 +9,8 @@ class StorageTest < Test::Unit::TestCase
9
9
  ensure
10
10
  FileUtils.rm_f('test.txt')
11
11
  end
12
+
13
+ def test_ouch_raises_problem
14
+ assert_raise(Problem) { Storage.new("").ouch! }
15
+ end
12
16
  end
@@ -13,4 +13,10 @@ describe DataBrander do
13
13
  m.should_receive(:foo)
14
14
  m.foo
15
15
  end
16
+
17
+ it "should delegate problem" do
18
+ storage = Storage.new("")
19
+ storage.should_receive(:ouch!).and_raise(Problem.new)
20
+ proc {DataBrander.new(storage).dont_do_this}.should raise_error(Problem)
21
+ end
16
22
  end
@@ -10,4 +10,8 @@ describe Storage do
10
10
  FileUtils.rm_f('test.txt')
11
11
  end
12
12
  end
13
+
14
+ it "should raise problem on ouch!" do
15
+ proc { Storage.new("").ouch! }.should raise_error(Problem)
16
+ end
13
17
  end
@@ -1,3 +1,31 @@
1
- $: << File.dirname(__FILE__) + '/lib/'
2
- require "storage"
3
- require "data_brander"
1
+ class DataBrander
2
+ BRAND = "METAL"
3
+
4
+ def initialize(storage)
5
+ @storage = storage
6
+ end
7
+
8
+ def save_branded(data)
9
+ @storage.save "#{BRAND} - #{data}"
10
+ end
11
+
12
+ def dont_do_this
13
+ @storage.ouch!
14
+ end
15
+ end
16
+
17
+ class Storage
18
+ def initialize(filename)
19
+ @filename = filename
20
+ end
21
+
22
+ def save(val)
23
+ File.open(@filename, 'w') {|f| f << val}
24
+ end
25
+
26
+ def ouch!
27
+ raise Problem
28
+ end
29
+ end
30
+
31
+ class Problem < Exception;end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: synthesis
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.15
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stuart Caborn, George Malamidis
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-05-25 00:00:00 +01:00
12
+ date: 2008-05-29 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -65,8 +65,6 @@ files:
65
65
  - test/synthesis/recordable_test.rb
66
66
  - test_project/expectations/test/data_brander_test.rb
67
67
  - test_project/expectations/test/storage_test.rb
68
- - test_project/lib/data_brander.rb
69
- - test_project/lib/storage.rb
70
68
  - test_project/mocha/test/data_brander_test.rb
71
69
  - test_project/mocha/test/storage_test.rb
72
70
  - test_project/rspec/data_brander_spec.rb
@@ -1,11 +0,0 @@
1
- class DataBrander
2
- BRAND = "METAL"
3
-
4
- def initialize(pstore)
5
- @pstore = pstore
6
- end
7
-
8
- def save_branded(data)
9
- @pstore.save "#{BRAND} - #{data}"
10
- end
11
- end
@@ -1,9 +0,0 @@
1
- class Storage
2
- def initialize(filename)
3
- @filename = filename
4
- end
5
-
6
- def save(val)
7
- File.open(@filename, 'w') {|f| f << val}
8
- end
9
- end