expectation 0.3.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/lib/contracts.rb +197 -0
  3. data/lib/core/exception.rb +15 -0
  4. data/lib/expectation/assertions.rb +19 -23
  5. data/lib/expectation/version.rb +1 -1
  6. data/lib/expectation.rb +59 -112
  7. data/test/assertions_test.rb +2 -1
  8. data/test/contracts_module_test.rb +48 -0
  9. data/test/contracts_singleton_test.rb +28 -0
  10. data/test/contracts_test.rb +88 -0
  11. data/test/coverage/assets/0.10.0/application.css +799 -0
  12. data/test/coverage/assets/0.10.0/application.js +1707 -0
  13. data/test/coverage/assets/0.10.0/colorbox/border.png +0 -0
  14. data/test/coverage/assets/0.10.0/colorbox/controls.png +0 -0
  15. data/test/coverage/assets/0.10.0/colorbox/loading.gif +0 -0
  16. data/test/coverage/assets/0.10.0/colorbox/loading_background.png +0 -0
  17. data/test/coverage/assets/0.10.0/favicon_green.png +0 -0
  18. data/test/coverage/assets/0.10.0/favicon_red.png +0 -0
  19. data/test/coverage/assets/0.10.0/favicon_yellow.png +0 -0
  20. data/test/coverage/assets/0.10.0/loading.gif +0 -0
  21. data/test/coverage/assets/0.10.0/magnify.png +0 -0
  22. data/test/coverage/assets/0.10.0/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  23. data/test/coverage/assets/0.10.0/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  24. data/test/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  25. data/test/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  26. data/test/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  27. data/test/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  28. data/test/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  29. data/test/coverage/assets/0.10.0/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  30. data/test/coverage/assets/0.10.0/smoothness/images/ui-icons_222222_256x240.png +0 -0
  31. data/test/coverage/assets/0.10.0/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
  32. data/test/coverage/assets/0.10.0/smoothness/images/ui-icons_454545_256x240.png +0 -0
  33. data/test/coverage/assets/0.10.0/smoothness/images/ui-icons_888888_256x240.png +0 -0
  34. data/test/coverage/assets/0.10.0/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
  35. data/test/coverage/index.html +72 -0
  36. data/test/exception_extension_test.rb +19 -0
  37. data/test/expection_test.rb +46 -0
  38. data/test/matching_test.rb +77 -0
  39. data/test/test_helper.rb +20 -7
  40. metadata +42 -18
  41. data/test/expect_test.rb +0 -119
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ba45fedcad85c3bc355804668620c834db45f2a1
4
+ data.tar.gz: 19766d7a77e76bd18e51e246ab1fee0ed0be3209
5
+ SHA512:
6
+ metadata.gz: 321eeaddc541552fd4261b5b6b9ca5f2095280abdc974ef3cb104077f5fee924d4d53cdf3218d839decf553099073276e0fa3d22dae07af26ca1ca77030e1654
7
+ data.tar.gz: 6b40a3e8403b34dea1eac1d877b62c62a1a0d5d7de9798cda203e1492305e32fbe00ba5fc252803c746c6b9b4e47772a1c66d1787866f440e3a6f3aa88063551
data/lib/contracts.rb ADDED
@@ -0,0 +1,197 @@
1
+ #--
2
+ # Author:: radiospiel (mailto:eno@radiospiel.org)
3
+ # Copyright:: Copyright (c) 2011, 2012 radiospiel
4
+ # License:: Distributes under the terms of the Modified BSD License, see LICENSE.BSD for details.
5
+ #++
6
+
7
+ # The Contract module provides annotation support. That basically
8
+ # means you can define expectations outside (or, to be more specific, before)
9
+ # the function definition.
10
+ #
11
+ # We currently support the following annotations:
12
+ #
13
+ # - expects!
14
+ # - returns!
15
+ #
16
+ # == Example
17
+ #
18
+ # class Foo
19
+ #
20
+ # +Expects(value1: Fixnum, value2: /.@./)
21
+ # +Returns(Fixnum)
22
+ #
23
+ # def bar(value1, value2)
24
+ # end
25
+ # end
26
+ #
27
+ module Contracts
28
+ class Error < ArgumentError; end
29
+
30
+ def self.current_contracts
31
+ Thread.current[:current_contracts] ||= []
32
+ end
33
+
34
+ def self.consume_current_contracts
35
+ r, Thread.current[:current_contracts] = Thread.current[:current_contracts], nil
36
+ r
37
+ end
38
+
39
+ def self.included(klass)
40
+ klass.extend ClassMethods
41
+ end
42
+
43
+ class AnnotatedMethod
44
+ def initialize(method, annotations)
45
+ @method = method
46
+
47
+ @before_annotations = annotations.select { |annotation| annotation.respond_to?(:before_call) }
48
+ @after_annotations = annotations.select { |annotation| annotation.respond_to?(:after_call) }
49
+ @exception_annotations = annotations.select { |annotation| annotation.respond_to?(:on_exception) }
50
+
51
+ annotations.each do |annotation|
52
+ annotation.method = method
53
+ end
54
+ end
55
+
56
+ def invoke(receiver, *args, &blk)
57
+ @before_annotations.each do |annotation|
58
+ annotation.before_call(receiver, *args, &blk)
59
+ end
60
+
61
+ # instance methods are UnboundMethod, class methods are Method.
62
+ rv = @method.is_a?(Method) ? @method.call(*args, &blk)
63
+ : @method.bind(receiver).call(*args, &blk)
64
+
65
+ @after_annotations.each do |annotation|
66
+ annotation.after_call(rv, receiver, *args, &blk)
67
+ end
68
+
69
+ return rv
70
+ rescue StandardError => exc
71
+ @exception_annotations.each do |annotation|
72
+ annotation.on_exception(exc, receiver, *args, &blk)
73
+ end
74
+ raise exc
75
+ end
76
+ end
77
+
78
+ module ClassMethods
79
+ def singleton_method_added(name)
80
+ if annotations = Contracts.consume_current_contracts
81
+ method = singleton_method(name)
82
+ annotated_method = Contracts::AnnotatedMethod.new(method, annotations)
83
+
84
+ klass = self
85
+
86
+ define_singleton_method name do |*args, &blk|
87
+ annotated_method.invoke klass, *args, &blk
88
+ end
89
+ end
90
+
91
+ super
92
+ end
93
+
94
+ def method_added(name)
95
+ if annotations = Contracts.consume_current_contracts
96
+ method = instance_method(name)
97
+ annotated_method = Contracts::AnnotatedMethod.new(method, annotations)
98
+
99
+ define_method name do |*args, &blk|
100
+ annotated_method.invoke self, *args, &blk
101
+ end
102
+ end
103
+
104
+ super
105
+ end
106
+ end
107
+
108
+ #
109
+ # A Base contract.
110
+ class Base
111
+ #
112
+ # This is the unary "+" operator. It adds the contract to the current_contracts array.
113
+ def +@
114
+ Contracts.current_contracts << self
115
+ end
116
+
117
+ #
118
+ # contains the method once the contract is initialized, which happens
119
+ # in the Class#{singleton_,}method_added callback.
120
+ attr :method, true
121
+
122
+ #
123
+ # Returns a description of the method; i.e. Class#name or Class.name
124
+ def method_name
125
+ if method.is_a?(Method) # A singleton method?
126
+ # The method owner is the singleton class of the class. Sadly, the
127
+ # the singleton class has no name; hence we try to construct the name
128
+ # from its to_s description.
129
+ klass_name = method.owner.to_s.gsub(/#<(.*?):(.*)>/, "\\2")
130
+ "#{klass_name}.#{method.name}"
131
+ else
132
+ "#{method.owner}##{method.name}"
133
+ end
134
+ end
135
+ end
136
+ end
137
+
138
+ require "expectation"
139
+
140
+ class Contracts::Expects < Contracts::Base
141
+ attr :expectations
142
+
143
+ def initialize(expectations)
144
+ @expectations = expectations
145
+ end
146
+
147
+ def before_call(receiver, *args, &blk)
148
+ @parameter_names ||= method.parameters.map(&:last)
149
+
150
+ @parameter_names.each_with_index do |parameter_name, idx|
151
+ next unless expectation = expectations[parameter_name]
152
+
153
+ Expectation.match! args[idx], expectation
154
+ end
155
+ rescue Expectation::Error
156
+ raise Contracts::Error, "#{$!} in call to `#{method_name}`", caller[5..-1]
157
+ end
158
+ end
159
+
160
+ module Contracts::ClassMethods
161
+ def Expects(expectation)
162
+ expect! expectation => Hash
163
+ Contracts::Expects.new(expectation)
164
+ end
165
+ end
166
+
167
+ class Contracts::Returns < Contracts::Base
168
+ attr :expectation
169
+
170
+ def initialize(expectation)
171
+ @expectation = expectation
172
+ end
173
+
174
+ def after_call(rv, receiver, *args, &blk)
175
+ Expectation.match! rv, expectation
176
+ rescue Expectation::Error
177
+ raise Contracts::Error, "#{$!} in return of `#{method_name}`", caller[5..-1]
178
+ end
179
+ end
180
+
181
+ module Contracts::ClassMethods
182
+ def Returns(expectation)
183
+ Contracts::Returns.new(expectation)
184
+ end
185
+ end
186
+
187
+ class Contracts::Nothrows < Contracts::Base
188
+ def on_exception(rv, method, receiver, *args, &blk)
189
+ raise Contracts::Error, "Nothrow method `#{method_name}` raised exception: #{$!}", caller[5..-1]
190
+ end
191
+ end
192
+
193
+ module Contracts::ClassMethods
194
+ def Nothrow
195
+ Contracts::Nothrows.new
196
+ end
197
+ end
@@ -0,0 +1,15 @@
1
+ #--
2
+ # Author:: radiospiel (mailto:eno@radiospiel.org)
3
+ # Copyright:: Copyright (c) 2011, 2012 radiospiel
4
+ # License:: Distributes under the terms of the Modified BSD License, see LICENSE.BSD for details.
5
+ #++
6
+
7
+ class Exception
8
+ # Create an ArgumentError with an adjusted backtrace. We don't want to
9
+ # see the user all the annotation internals.
10
+ def reraise_with_current_backtrace!
11
+ set_backtrace caller[2..-1]
12
+ raise self
13
+ end
14
+ end
15
+
@@ -3,24 +3,16 @@
3
3
  # Copyright:: Copyright (c) 2011, 2012 radiospiel
4
4
  # License:: Distributes under the terms of the Modified BSD License, see LICENSE.BSD for details.
5
5
  #++
6
- # By requiring "expectation/assertions" you add expect! und unexpect! assertions
7
- # to your test/unit testcases.
8
6
 
9
- if !defined?(::Expectation::Assertions)
10
-
11
- if !defined?(::Expectation)
12
- require_relative "../expectation"
13
- end
14
7
 
15
8
  # The Expectation::Assertions module provides expect! and inexpect!
16
9
  # assertions to use from within test cases.
17
10
  #
18
11
  # == Example
19
- #
20
- # require_relative 'test_helper'
21
- # require 'expectation/assertions'
22
12
  #
23
13
  # class ExpectationTest < Test::Unit::TestCase
14
+ # include Expectation::Assertions
15
+ #
24
16
  # def test_one
25
17
  # end
26
18
  # end
@@ -28,23 +20,27 @@ end
28
20
  module Expectation::Assertions
29
21
  # verifies the passed in expectations
30
22
  def expect!(*expectation, &block)
31
- good = Expectation.met_expectations?(*expectation, &block)
32
- assert_block(Expectation.last_error) { good }
23
+ exc = nil
24
+
25
+ begin
26
+ Expectation.expect!(*expectation, &block)
27
+ rescue Expectation::Error
28
+ exc = $!
29
+ end
30
+
31
+ assert_block(exc && exc.message) { !exc }
33
32
  end
34
33
 
35
34
  # verifies the failure of the passed in expectations
36
35
  def inexpect!(*expectation, &block)
37
- good = Expectation.met_expectations?(*expectation, &block)
38
- assert_block("Expectation(s) should fail, but didn't") { !good }
39
- end
40
- end
41
-
42
- end
36
+ exc = nil
43
37
 
44
- if !defined?(Test::Unit)
45
- STDERR.puts "Please load 'test/unit' first"
46
- end
38
+ begin
39
+ Expectation.expect!(*expectation, &block)
40
+ rescue Expectation::Error
41
+ exc = $!
42
+ end
47
43
 
48
- class Test::Unit::TestCase
49
- include Expectation::Assertions
44
+ assert_block("Expectation(s) should fail, but didn't") { exc }
45
+ end
50
46
  end
@@ -4,5 +4,5 @@
4
4
  # License:: Distributes under the terms of the Modified BSD License, see LICENSE.BSD for details.
5
5
  module Expectation
6
6
  # The expectation gem's version.
7
- VERSION="0.3.1"
7
+ VERSION="1.0.0"
8
8
  end
data/lib/expectation.rb CHANGED
@@ -3,6 +3,12 @@
3
3
  # Copyright:: Copyright (c) 2011, 2012 radiospiel
4
4
  # License:: Distributes under the terms of the Modified BSD License, see LICENSE.BSD for details.
5
5
  #++
6
+
7
+ module Expectation; end
8
+
9
+ require_relative "core/exception"
10
+ require_relative "expectation/assertions"
11
+
6
12
  # The Expectation module implements methods to verify one or more values
7
13
  # against set of expectations. This is a subset of
8
14
  # design-by-contract programming (see http://en.wikipedia.org/wiki/Design_by_contract)
@@ -24,136 +30,77 @@
24
30
  # end
25
31
 
26
32
  module Expectation
27
- def self.timeout=(timeout)
28
- Thread.current[:expectation_timeout] = timeout
29
- end
30
-
31
- def self.timeout
32
- Thread.current[:expectation_timeout]
33
- end
34
-
35
- def self.last_error=(error)
36
- Thread.current[:expectation_last_error] = error
37
- end
38
-
39
- def self.last_error
40
- Thread.current[:expectation_last_error]
41
- end
42
-
43
- def expect!(*expectations, &block)
44
- return if Expectation.met_expectations?(*expectations, &block)
45
-
46
- # build exception with adjusted backtrace.
47
- backtrace = caller #[3 .. -1]
33
+ class Error < ArgumentError
34
+ attr :value, :expectation, :info
48
35
 
49
- e = ArgumentError.new Expectation.last_error
50
- e.singleton_class.send(:define_method, :backtrace) do
51
- backtrace
36
+ def initialize(value, expectation, info = nil)
37
+ @value, @expectation, @info =
38
+ value, expectation, info
39
+ end
40
+
41
+ def to_s
42
+ message = "#{value.inspect} does not match #{expectation.inspect}"
43
+ message += ", #{info}" if info
44
+ message
52
45
  end
53
-
54
- raise e
55
- end
56
-
57
- # Verifies a number of expectations. If one or more expectations are
58
- # not met it raises an ArgumentError.
59
- #
60
- # This method can be enabled or disabled at runtime using
61
- # Expectation.enable and Expectation.disable.
62
- def expect(*expectations, &block)
63
- expect!(*expectations, &block)
64
- end
65
-
66
- # A do nothing expect method. This is the standin for expect, when
67
- # Expectation are disabled.
68
- def expect_dummy!(*expectations, &block) #:nodoc:
69
46
  end
70
47
 
71
- # Verifies a number of expectations. Raises an ArgumentError if one
72
- # or more expectations are not met.
73
48
  #
74
- # In contrast to Expectation#expect this method can not be
75
- # disabled at runtime.
76
- def self.met_expectations?(*expectations, &block)
77
- return false unless expectations.all? do |expectation|
78
- case expectation
79
- when Hash
80
- expectation.all? { |value, e| Expectation.verify! value, e }
49
+ # Verifies a number of expectations. If one or more expectations are
50
+ # not met it raises an ArgumentError (on the first failing expectation).
51
+ def expect!(*expectations, &block)
52
+ expectations.each do |expectation|
53
+ if expectation.is_a?(Hash)
54
+ expectation.all? do |actual, exp|
55
+ match! actual, exp
56
+ end
81
57
  else
82
- Expectation.verify! expectation, :truish
58
+ match! expectation, :truish
83
59
  end
84
60
  end
85
61
 
86
- return true unless block_given?
87
-
88
- # Dynamic expectation? When Expectation.timeout is set, we test the
89
- # dynamic expectation, i.e. the block, for a certain time period.
90
- begin
91
- timeout, Expectation.timeout = Expectation.timeout, nil
62
+ match! block, :__block if block
63
+ rescue Error
64
+ $!.reraise_with_current_backtrace!
65
+ end
92
66
 
93
- runs = timeout ? (timeout / 0.05).to_i : 0
94
- runs = 1 if runs < 1
95
-
96
- runs.times.any? do
97
- next true if Expectation.verify! 1, block
98
- Thread.send :sleep, 0.05
99
- false
100
- end
101
- ensure
102
- Expectation.timeout = timeout
103
- end
104
- end
105
-
106
- # Does a value meet the expectation? Retruns +true+ or +false+.
107
- def self.met?(value, expectation) #:nodoc:
108
- case expectation
109
- when :truish then !!value
110
- when :fail then false
111
- when Array then expectation.any? { |e| met?(value, e) }
112
- when Proc then expectation.arity == 0 ? expectation.call : expectation.call(value)
113
- when Regexp then value.is_a?(String) && expectation =~ value
114
- else expectation === value
115
- end
67
+ #
68
+ # Does a value match an expectation?
69
+ def match?(value, expectation)
70
+ match! value, expectation
71
+ true
72
+ rescue Error
73
+ false
116
74
  end
117
75
 
118
- # Verifies a value against an expectation; returns true if ok,
119
- # false if the expectation was not met. In case of an error
120
- # the Expectation.last_error value is set.
121
- def self.verify!(value, expectation)
122
- failed_value, failed_expectation, message = value, expectation, nil
123
-
124
- # Test expectation, collect failed_value, failed_expectation, failed_message
125
- unless expectation.is_a?(Hash)
126
- good = met?(value, expectation)
127
- else
128
- good = met?(value, Hash)
129
- if good
130
- good = expectation.all? do |key, expect|
131
- next true if met?(value[key], expect)
132
-
133
- failed_value, failed_expectation, message = value[key], expect, "at key #{key.inspect}"
134
- false
135
- end
136
- end
76
+ # Matches a value against an expectation. Raises an Expectation::Error
77
+ # if the expectation could not be matched.
78
+ def match!(value, expectation, key=nil)
79
+ match = case expectation
80
+ when :truish then !!value
81
+ when :fail then false
82
+ when Array then expectation.any? { |e| _match?(value, e) }
83
+ when Proc then expectation.arity == 0 ? expectation.call : expectation.call(value)
84
+ when Regexp then value.is_a?(String) && expectation =~ value
85
+ when :__block then value.call
86
+ when Hash then Hash === value &&
87
+ expectation.each { |key, exp| match! value[key], exp, key }
88
+ else expectation === value
137
89
  end
138
-
139
- # are we good?
140
- return true if good
141
-
142
- Expectation.last_error = "#{failed_value.inspect} does not meet expectation #{failed_expectation.inspect}#{message && ", #{message}"}"
143
90
 
144
- return false
145
- end
91
+ return if match
146
92
 
147
- # Enable the Expectation#expect method.
148
- def self.enable
149
- alias_method :expect, :expect!
93
+ raise Error.new(value, expectation, key && "at key #{key.inspect}")
150
94
  end
151
95
 
152
- # Disable the Expectation#expect method.
153
- def self.disable
154
- alias_method :expect, :expect_dummy!
96
+ private
97
+
98
+ def _match?(value, expectation)
99
+ match! value, expectation
100
+ true
101
+ rescue Error
102
+ false
155
103
  end
156
104
  end
157
105
 
158
- Expectation.enable
159
106
  Object.send :include, Expectation
@@ -2,9 +2,10 @@
2
2
  # Copyright:: Copyright (c) 2011, 2012 radiospiel
3
3
  # License:: Distributes under the terms of the Modified BSD License, see LICENSE.BSD for details.
4
4
  require_relative 'test_helper'
5
- require "expectation/assertions"
6
5
 
7
6
  class AssertionsTest < Test::Unit::TestCase
7
+ include Expectation::Assertions
8
+
8
9
  def test_expectations
9
10
  expect! 1 => 1
10
11
  inexpect! 1 => 2
@@ -0,0 +1,48 @@
1
+ # Author:: radiospiel (mailto:eno@radiospiel.org)
2
+ # Copyright:: Copyright (c) 2011, 2012 radiospiel
3
+ # License:: Distributes under the terms of the Modified BSD License, see LICENSE.BSD for details.
4
+ require_relative 'test_helper'
5
+
6
+ require "contracts"
7
+
8
+ class ContractsModuleTest < Test::Unit::TestCase
9
+ module M
10
+ include Contracts
11
+
12
+ +Expects(one: 1)
13
+ def needs_one(one)
14
+ one * 2
15
+ end
16
+ end
17
+
18
+ class Klass
19
+ extend M
20
+ end
21
+
22
+ class Instance
23
+ include M
24
+ end
25
+
26
+ def test_class_method
27
+ assert_nothing_raised() {
28
+ Klass.needs_one(1)
29
+ }
30
+
31
+ e = assert_raise(Contracts::Error) {
32
+ Klass.needs_one(2)
33
+ }
34
+ assert e.backtrace.first.include?("test/contracts_module_test.rb:")
35
+ end
36
+
37
+ def test_instance_method
38
+ instance = Instance.new
39
+ assert_nothing_raised() {
40
+ instance.needs_one(1)
41
+ }
42
+
43
+ e = assert_raise(Contracts::Error) {
44
+ instance.needs_one(2)
45
+ }
46
+ assert e.backtrace.first.include?("test/contracts_module_test.rb:")
47
+ end
48
+ end
@@ -0,0 +1,28 @@
1
+ # Author:: radiospiel (mailto:eno@radiospiel.org)
2
+ # Copyright:: Copyright (c) 2011, 2012 radiospiel
3
+ # License:: Distributes under the terms of the Modified BSD License, see LICENSE.BSD for details.
4
+ require_relative 'test_helper'
5
+
6
+ require "contracts"
7
+
8
+ class ContractsSingletonTest < Test::Unit::TestCase
9
+ class Foo
10
+ include Contracts
11
+
12
+ +Expects(one: 1)
13
+ def self.klass_method(one)
14
+ one * 2
15
+ end
16
+ end
17
+
18
+ def test_class_method
19
+ assert_nothing_raised() {
20
+ Foo.klass_method(1)
21
+ }
22
+
23
+ e = assert_raise(Contracts::Error) {
24
+ Foo.klass_method(2)
25
+ }
26
+ assert e.backtrace.first.include?("test/contracts_singleton_test.rb:")
27
+ end
28
+ end
@@ -0,0 +1,88 @@
1
+ # Author:: radiospiel (mailto:eno@radiospiel.org)
2
+ # Copyright:: Copyright (c) 2011, 2012 radiospiel
3
+ # License:: Distributes under the terms of the Modified BSD License, see LICENSE.BSD for details.
4
+ require_relative 'test_helper'
5
+
6
+ require "contracts"
7
+
8
+ class ContractsTest < Test::Unit::TestCase
9
+ class Foo
10
+ include Contracts
11
+
12
+ +Expects(a: 1)
13
+ def sum(a, b, c)
14
+ a + b + c
15
+ end
16
+
17
+ +Returns(2)
18
+ def returns_arg(r)
19
+ r
20
+ end
21
+
22
+ +Expects(v: Fixnum)
23
+ def throw_on_one(v)
24
+ raise if v == 1
25
+ end
26
+
27
+ +Nothrow()
28
+ def unexpected_throw_on_one(v)
29
+ raise if v == 1
30
+ end
31
+ end
32
+
33
+ attr :foo
34
+
35
+ def setup
36
+ @foo = Foo.new
37
+ end
38
+
39
+ def test_contracts_check_number_of_arguments
40
+ e = assert_raise(ArgumentError) {
41
+ foo.sum(1) # scripts/test:67:in `f': wrong number of arguments (1 for 3) (ArgumentError)
42
+ }
43
+ assert e.backtrace.first.include?("test/contracts_test.rb:")
44
+ end
45
+
46
+ def test_expects_contract
47
+ rv = nil
48
+ assert_nothing_raised() { rv = foo.sum(1,2,3) }
49
+ assert_equal(rv, 6)
50
+
51
+ e = assert_raise(Contracts::Error) {
52
+ foo.sum(2,2,3)
53
+ }
54
+ assert e.backtrace.first.include?("test/contracts_test.rb:")
55
+ end
56
+
57
+ def test_returns_contract
58
+ assert_nothing_raised() {
59
+ foo.returns_arg(2)
60
+ }
61
+
62
+ e = assert_raise(Contracts::Error) {
63
+ foo.returns_arg(1)
64
+ }
65
+ assert e.backtrace.first.include?("test/contracts_test.rb:")
66
+ end
67
+
68
+ def test_nothrow_contract
69
+ assert_nothing_raised() {
70
+ foo.unexpected_throw_on_one(2)
71
+ }
72
+
73
+ e = assert_raise(Contracts::Error) {
74
+ foo.unexpected_throw_on_one(1)
75
+ }
76
+ assert e.backtrace.first.include?("test/contracts_test.rb:")
77
+ end
78
+
79
+ def test_still_throws_fine
80
+ assert_nothing_raised() {
81
+ foo.throw_on_one(2)
82
+ }
83
+
84
+ assert_raise(RuntimeError) {
85
+ foo.throw_on_one(1)
86
+ }
87
+ end
88
+ end