synthesis 0.0.15 → 0.1.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.
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