expectation 0.3.1 → 1.0.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.
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