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.
- checksums.yaml +7 -0
- data/lib/contracts.rb +197 -0
- data/lib/core/exception.rb +15 -0
- data/lib/expectation/assertions.rb +19 -23
- data/lib/expectation/version.rb +1 -1
- data/lib/expectation.rb +59 -112
- data/test/assertions_test.rb +2 -1
- data/test/contracts_module_test.rb +48 -0
- data/test/contracts_singleton_test.rb +28 -0
- data/test/contracts_test.rb +88 -0
- data/test/coverage/assets/0.10.0/application.css +799 -0
- data/test/coverage/assets/0.10.0/application.js +1707 -0
- data/test/coverage/assets/0.10.0/colorbox/border.png +0 -0
- data/test/coverage/assets/0.10.0/colorbox/controls.png +0 -0
- data/test/coverage/assets/0.10.0/colorbox/loading.gif +0 -0
- data/test/coverage/assets/0.10.0/colorbox/loading_background.png +0 -0
- data/test/coverage/assets/0.10.0/favicon_green.png +0 -0
- data/test/coverage/assets/0.10.0/favicon_red.png +0 -0
- data/test/coverage/assets/0.10.0/favicon_yellow.png +0 -0
- data/test/coverage/assets/0.10.0/loading.gif +0 -0
- data/test/coverage/assets/0.10.0/magnify.png +0 -0
- data/test/coverage/assets/0.10.0/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/test/coverage/assets/0.10.0/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/test/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/test/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/test/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/test/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/test/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/test/coverage/assets/0.10.0/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/test/coverage/assets/0.10.0/smoothness/images/ui-icons_222222_256x240.png +0 -0
- data/test/coverage/assets/0.10.0/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
- data/test/coverage/assets/0.10.0/smoothness/images/ui-icons_454545_256x240.png +0 -0
- data/test/coverage/assets/0.10.0/smoothness/images/ui-icons_888888_256x240.png +0 -0
- data/test/coverage/assets/0.10.0/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/test/coverage/index.html +72 -0
- data/test/exception_extension_test.rb +19 -0
- data/test/expection_test.rb +46 -0
- data/test/matching_test.rb +77 -0
- data/test/test_helper.rb +20 -7
- metadata +42 -18
- 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
|
-
|
32
|
-
|
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
|
-
|
38
|
-
assert_block("Expectation(s) should fail, but didn't") { !good }
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
end
|
36
|
+
exc = nil
|
43
37
|
|
44
|
-
|
45
|
-
|
46
|
-
|
38
|
+
begin
|
39
|
+
Expectation.expect!(*expectation, &block)
|
40
|
+
rescue Expectation::Error
|
41
|
+
exc = $!
|
42
|
+
end
|
47
43
|
|
48
|
-
|
49
|
-
|
44
|
+
assert_block("Expectation(s) should fail, but didn't") { exc }
|
45
|
+
end
|
50
46
|
end
|
data/lib/expectation/version.rb
CHANGED
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
|
-
|
28
|
-
|
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
|
-
|
50
|
-
|
51
|
-
|
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
|
-
#
|
75
|
-
#
|
76
|
-
def
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
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
|
-
|
58
|
+
match! expectation, :truish
|
83
59
|
end
|
84
60
|
end
|
85
61
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
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
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
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
|
-
#
|
119
|
-
#
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
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
|
145
|
-
end
|
91
|
+
return if match
|
146
92
|
|
147
|
-
|
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
|
-
|
153
|
-
|
154
|
-
|
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
|
data/test/assertions_test.rb
CHANGED
@@ -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
|