xspec 0.0.2 → 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.
- checksums.yaml +4 -4
- data/README.md +22 -50
- data/bin/xspec +4 -2
- data/lib/xspec.rb +18 -11
- data/lib/xspec/data_structures.rb +15 -15
- data/lib/xspec/defaults.rb +6 -6
- data/lib/xspec/dsl.rb +5 -0
- data/lib/xspec/evaluators.rb +316 -22
- data/lib/xspec/notifiers.rb +2 -0
- data/lib/xspec/schedulers.rb +39 -0
- data/spec/integration/rspec_expectations_spec.rb +3 -3
- data/spec/spec_helper.rb +0 -2
- data/spec/unit/assertion_spec.rb +7 -7
- data/spec/unit/doubles_spec.rb +93 -115
- data/xspec.gemspec +2 -2
- metadata +4 -4
- data/lib/xspec/assertion_contexts.rb +0 -382
data/lib/xspec/notifiers.rb
CHANGED
@@ -0,0 +1,39 @@
|
|
1
|
+
# # Schedulers
|
2
|
+
|
3
|
+
# Schedulers are responsible for collecting all units of work to be run and
|
4
|
+
# scheduling them.
|
5
|
+
module XSpec
|
6
|
+
module Scheduler
|
7
|
+
# The serial scheduler, unsurprisingly, runs all units of works serially in
|
8
|
+
# a loop. It is about as simple a scheduler as you can imagine. Parents
|
9
|
+
# are responsible for actually executing the work.
|
10
|
+
class Serial
|
11
|
+
def initialize(opts = {})
|
12
|
+
@clock = opts.fetch(:clock, ->{ Time.now.to_f })
|
13
|
+
end
|
14
|
+
|
15
|
+
def run(context, notifier)
|
16
|
+
notifier.run_start
|
17
|
+
|
18
|
+
context.nested_units_of_work.each do |x|
|
19
|
+
notifier.evaluate_start(x)
|
20
|
+
|
21
|
+
start_time = clock.()
|
22
|
+
errors = x.immediate_parent.execute(x)
|
23
|
+
finish_time = clock.()
|
24
|
+
|
25
|
+
result = ExecutedUnitOfWork.new(x, errors, finish_time - start_time)
|
26
|
+
notifier.evaluate_finish(result)
|
27
|
+
end
|
28
|
+
|
29
|
+
notifier.run_finish
|
30
|
+
end
|
31
|
+
|
32
|
+
protected
|
33
|
+
|
34
|
+
attr_reader :clock
|
35
|
+
end
|
36
|
+
|
37
|
+
DEFAULT = Serial.new
|
38
|
+
end
|
39
|
+
end
|
@@ -1,11 +1,11 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
require 'xspec/
|
3
|
+
require 'xspec/evaluators'
|
4
4
|
|
5
5
|
it 'integrates with rspec' do
|
6
6
|
opts = {
|
7
|
-
|
8
|
-
include XSpec::
|
7
|
+
evaluator: XSpec::Evaluator.stack {
|
8
|
+
include XSpec::Evaluator::RSpecExpectations
|
9
9
|
}
|
10
10
|
}
|
11
11
|
|
data/spec/spec_helper.rb
CHANGED
data/spec/unit/assertion_spec.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe 'simple assertion context' do
|
4
|
-
let(:subject) { Class.new { include XSpec::
|
5
|
-
include XSpec::
|
4
|
+
let(:subject) { Class.new { include XSpec::Evaluator.stack {
|
5
|
+
include XSpec::Evaluator::Simple
|
6
6
|
}}.new }
|
7
7
|
|
8
8
|
describe 'assert' do
|
@@ -14,7 +14,7 @@ describe 'simple assertion context' do
|
|
14
14
|
begin
|
15
15
|
subject.assert(false)
|
16
16
|
fail "Assertion did not fail"
|
17
|
-
rescue XSpec::
|
17
|
+
rescue XSpec::Evaluator::Simple::AssertionFailed => e
|
18
18
|
assert_equal "assertion failed", e.message
|
19
19
|
end
|
20
20
|
end
|
@@ -23,7 +23,7 @@ describe 'simple assertion context' do
|
|
23
23
|
begin
|
24
24
|
subject.assert(false, "nope")
|
25
25
|
fail "Assertion did not fail"
|
26
|
-
rescue XSpec::
|
26
|
+
rescue XSpec::Evaluator::Simple::AssertionFailed => e
|
27
27
|
assert_equal "nope", e.message
|
28
28
|
end
|
29
29
|
end
|
@@ -38,7 +38,7 @@ describe 'simple assertion context' do
|
|
38
38
|
begin
|
39
39
|
subject.assert_equal("a", "b")
|
40
40
|
fail "Assertion did not fail"
|
41
|
-
rescue XSpec::
|
41
|
+
rescue XSpec::Evaluator::Simple::AssertionFailed => e
|
42
42
|
assert_include 'want: "a"', e.message
|
43
43
|
assert_include 'got: "b"', e.message
|
44
44
|
end
|
@@ -50,7 +50,7 @@ describe 'simple assertion context' do
|
|
50
50
|
begin
|
51
51
|
subject.fail
|
52
52
|
assert false, "fail did not fail"
|
53
|
-
rescue XSpec::
|
53
|
+
rescue XSpec::Evaluator::Simple::AssertionFailed => e
|
54
54
|
assert_equal "failed", e.message
|
55
55
|
end
|
56
56
|
end
|
@@ -59,7 +59,7 @@ describe 'simple assertion context' do
|
|
59
59
|
begin
|
60
60
|
subject.fail ":("
|
61
61
|
assert false, "fail did not fail"
|
62
|
-
rescue XSpec::
|
62
|
+
rescue XSpec::Evaluator::Simple::AssertionFailed => e
|
63
63
|
assert_equal ":(", e.message
|
64
64
|
end
|
65
65
|
end
|
data/spec/unit/doubles_spec.rb
CHANGED
@@ -6,127 +6,135 @@ class LoadedClass
|
|
6
6
|
end
|
7
7
|
|
8
8
|
describe 'doubles assertion context' do
|
9
|
-
let(:subject) { Class.new { include XSpec::
|
10
|
-
include XSpec::
|
9
|
+
let(:subject) { Class.new { include XSpec::Evaluator.stack {
|
10
|
+
include XSpec::Evaluator::Doubles
|
11
11
|
}}.new }
|
12
12
|
|
13
13
|
it 'converts double exceptions to failures' do
|
14
14
|
result = subject.call(XSpec::UnitOfWork.new(nil, ->{
|
15
|
-
raise XSpec::
|
15
|
+
raise XSpec::Evaluator::Doubles::DoubleFailure, "nope"
|
16
16
|
}))
|
17
17
|
assert_equal "nope", result[0].message
|
18
18
|
end
|
19
19
|
|
20
20
|
describe 'doubles of unloaded classes' do
|
21
|
-
it 'allows
|
22
|
-
assert_equal
|
21
|
+
it 'allows a stub to be used multiple times' do
|
22
|
+
assert_equal 1, subject.instance_eval {
|
23
23
|
double = instance_double('Bogus')
|
24
|
-
|
25
|
-
double.foo
|
24
|
+
stub(double).foo("a") { 1 }
|
25
|
+
double.foo("a")
|
26
|
+
double.foo("a")
|
26
27
|
}
|
27
28
|
end
|
28
29
|
|
29
|
-
it 'allows any return value to be
|
30
|
+
it 'allows any return value to be stubbed' do
|
30
31
|
assert_equal 1, subject.instance_eval {
|
31
32
|
double = instance_double('Bogus')
|
32
|
-
|
33
|
-
|
33
|
+
stub(double).foo("a") { 2 }
|
34
|
+
stub(double).foo("b") { 3 }
|
34
35
|
double.foo("b") - double.foo("a")
|
35
36
|
}
|
36
37
|
end
|
37
38
|
|
38
39
|
it 'requires matching method name' do
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
}
|
45
|
-
fail "no error raised"
|
46
|
-
rescue XSpec::AssertionContext::Doubles::DoubleFailure => e
|
47
|
-
assert_include "Unexpectedly received", e.message
|
48
|
-
assert_include 'bar("a")', e.message
|
49
|
-
end
|
40
|
+
assert_equal nil, subject.instance_eval {
|
41
|
+
double = instance_double('Bogus')
|
42
|
+
stub(double).foo("a") { 1 }
|
43
|
+
double.bar("a")
|
44
|
+
}
|
50
45
|
end
|
51
46
|
|
52
47
|
it 'requires exact arguments' do
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
}
|
59
|
-
fail "no error raised"
|
60
|
-
rescue XSpec::AssertionContext::Doubles::DoubleFailure => e
|
61
|
-
assert_include "Unexpectedly received", e.message
|
62
|
-
assert_include 'foo("b")', e.message
|
63
|
-
end
|
48
|
+
assert_equal nil, subject.instance_eval {
|
49
|
+
double = instance_double('Bogus')
|
50
|
+
stub(double).foo("a") { 1 }
|
51
|
+
double.foo("b")
|
52
|
+
}
|
64
53
|
end
|
65
54
|
end
|
66
55
|
|
67
|
-
describe '
|
68
|
-
it '
|
56
|
+
describe 'verify' do
|
57
|
+
it 'can verify a method was called with no setup' do
|
69
58
|
assert subject.instance_eval {
|
70
59
|
double = instance_double('Bogus')
|
71
|
-
expect(double).foo
|
72
60
|
double.foo
|
73
|
-
|
61
|
+
verify(double).foo
|
74
62
|
true
|
75
63
|
}
|
76
64
|
end
|
77
65
|
|
78
|
-
it '
|
66
|
+
it 'can verify a method that was stubbed' do
|
67
|
+
assert subject.instance_eval {
|
68
|
+
double = instance_double('Bogus')
|
69
|
+
stub(double).foo { 1 }
|
70
|
+
double.foo
|
71
|
+
verify(double).foo
|
72
|
+
true
|
73
|
+
}
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'raises if method was not called' do
|
79
77
|
begin
|
80
78
|
subject.instance_eval {
|
81
79
|
double = instance_double('Bogus')
|
82
|
-
|
83
|
-
|
80
|
+
double.bar
|
81
|
+
verify(double).foo("b")
|
84
82
|
}
|
85
83
|
fail "no error raised"
|
86
|
-
rescue XSpec::
|
87
|
-
assert_include "
|
88
|
-
assert_include 'foo(
|
84
|
+
rescue XSpec::Evaluator::Doubles::DoubleFailure => e
|
85
|
+
assert_include "Did not receive", e.message
|
86
|
+
assert_include 'foo("b")', e.message
|
89
87
|
end
|
90
88
|
end
|
91
89
|
|
92
|
-
it '
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
ret
|
109
|
-
}
|
90
|
+
it 'raises if method was not called with right arguments' do
|
91
|
+
begin
|
92
|
+
subject.instance_eval {
|
93
|
+
double = instance_double('Bogus')
|
94
|
+
double.foo("a")
|
95
|
+
double.foo("b")
|
96
|
+
verify(double).foo("c")
|
97
|
+
}
|
98
|
+
fail "no error raised"
|
99
|
+
rescue XSpec::Evaluator::Doubles::DoubleFailure => e
|
100
|
+
assert_include "Did not receive", e.message
|
101
|
+
assert_include 'foo("b")', e.message
|
102
|
+
assert_include "Did receive", e.message
|
103
|
+
assert_include 'foo("a")', e.message
|
104
|
+
assert_include 'foo("b")', e.message
|
105
|
+
end
|
110
106
|
end
|
111
107
|
end
|
112
108
|
|
113
109
|
describe 'instance_double' do
|
114
110
|
describe 'when doubled class is loaded' do
|
115
|
-
it 'allows instance methods to be
|
111
|
+
it 'allows instance methods to be stubbed' do
|
116
112
|
assert subject.instance_eval {
|
117
113
|
double = instance_double('LoadedClass')
|
118
|
-
|
114
|
+
stub(double).instance_method { 123 }
|
119
115
|
}
|
120
116
|
end
|
121
117
|
|
122
|
-
it 'does not allow non-existing methods to be
|
118
|
+
it 'does not allow non-existing methods to be stubbed' do
|
119
|
+
begin
|
120
|
+
assert subject.instance_eval {
|
121
|
+
double = instance_double('LoadedClass')
|
122
|
+
stub(double).bogus_method { 123 }
|
123
|
+
}
|
124
|
+
fail "no error raised"
|
125
|
+
rescue XSpec::Evaluator::Doubles::DoubleFailure => e
|
126
|
+
assert_include "LoadedClass#bogus_method", e.message
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'does not allow non-existing methods to be verified' do
|
123
131
|
begin
|
124
132
|
assert subject.instance_eval {
|
125
133
|
double = instance_double('LoadedClass')
|
126
|
-
|
134
|
+
verify(double).bogus_method { 123 }
|
127
135
|
}
|
128
136
|
fail "no error raised"
|
129
|
-
rescue XSpec::
|
137
|
+
rescue XSpec::Evaluator::Doubles::DoubleFailure => e
|
130
138
|
assert_include "LoadedClass#bogus_method", e.message
|
131
139
|
end
|
132
140
|
end
|
@@ -135,21 +143,33 @@ describe 'doubles assertion context' do
|
|
135
143
|
|
136
144
|
describe 'class_double' do
|
137
145
|
describe 'when doubled class is loaded' do
|
138
|
-
it 'allows instance methods to be
|
146
|
+
it 'allows instance methods to be stubbed' do
|
139
147
|
assert subject.instance_eval {
|
140
148
|
double = class_double('LoadedClass')
|
141
|
-
|
149
|
+
stub(double).class_method { 123 }
|
142
150
|
}
|
143
151
|
end
|
144
152
|
|
145
|
-
it 'does not allow non-existing methods to be
|
153
|
+
it 'does not allow non-existing methods to be stubbed' do
|
146
154
|
begin
|
147
155
|
assert subject.instance_eval {
|
148
156
|
double = class_double('LoadedClass')
|
149
|
-
|
157
|
+
stub(double).bogus_method { 123 }
|
150
158
|
}
|
151
159
|
fail "no error raised"
|
152
|
-
rescue XSpec::
|
160
|
+
rescue XSpec::Evaluator::Doubles::DoubleFailure => e
|
161
|
+
assert_include "LoadedClass.bogus_method", e.message
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
it 'does not allow non-existing methods to be verified' do
|
166
|
+
begin
|
167
|
+
assert subject.instance_eval {
|
168
|
+
double = class_double('LoadedClass')
|
169
|
+
verify(double).bogus_method
|
170
|
+
}
|
171
|
+
fail "no error raised"
|
172
|
+
rescue XSpec::Evaluator::Doubles::DoubleFailure => e
|
153
173
|
assert_include "LoadedClass.bogus_method", e.message
|
154
174
|
end
|
155
175
|
end
|
@@ -158,8 +178,8 @@ describe 'doubles assertion context' do
|
|
158
178
|
end
|
159
179
|
|
160
180
|
describe 'strict doubles assertion context' do
|
161
|
-
let(:subject) { Class.new { include XSpec::
|
162
|
-
include XSpec::
|
181
|
+
let(:subject) { Class.new { include XSpec::Evaluator.stack {
|
182
|
+
include XSpec::Evaluator::Doubles.with(:strict)
|
163
183
|
}}.new }
|
164
184
|
|
165
185
|
it 'allows doubling of loaded classes' do
|
@@ -170,50 +190,8 @@ describe 'strict doubles assertion context' do
|
|
170
190
|
begin
|
171
191
|
subject.instance_double("Bogus")
|
172
192
|
fail "no error raised"
|
173
|
-
rescue XSpec::
|
193
|
+
rescue XSpec::Evaluator::Doubles::DoubleFailure => e
|
174
194
|
assert_include "Bogus", e.message
|
175
195
|
end
|
176
196
|
end
|
177
197
|
end
|
178
|
-
|
179
|
-
describe 'auto-verifying doubles assertion context' do
|
180
|
-
let(:subject) { Class.new { include XSpec::AssertionContext.stack {
|
181
|
-
include XSpec::AssertionContext::Doubles.with(:auto_verify)
|
182
|
-
}}.new }
|
183
|
-
|
184
|
-
it 'verifies all used instance doubles on successful result' do
|
185
|
-
result = subject.call(XSpec::UnitOfWork.new(nil, ->{
|
186
|
-
double = instance_double('Bogus')
|
187
|
-
expect(double).foo
|
188
|
-
}))
|
189
|
-
|
190
|
-
assert_equal 1, result.length
|
191
|
-
assert_include "did not receive", result[0].message
|
192
|
-
assert_include "foo()", result[0].message
|
193
|
-
end
|
194
|
-
|
195
|
-
it 'verifies all used class doubles on successful result' do
|
196
|
-
result = subject.call(XSpec::UnitOfWork.new(nil, ->{
|
197
|
-
double = class_double('Bogus')
|
198
|
-
expect(double).foo
|
199
|
-
}))
|
200
|
-
|
201
|
-
assert_equal 1, result.length
|
202
|
-
assert_include "did not receive", result[0].message
|
203
|
-
assert_include "foo()", result[0].message
|
204
|
-
end
|
205
|
-
|
206
|
-
it 'does not verify doubles if errors occurred' do
|
207
|
-
result = subject.call(XSpec::UnitOfWork.new(nil, ->{
|
208
|
-
double = instance_double('Bogus')
|
209
|
-
expect(double).foo
|
210
|
-
fail "nope"
|
211
|
-
}))
|
212
|
-
assert_equal 1, result.length
|
213
|
-
assert_include "nope", result[0].message
|
214
|
-
end
|
215
|
-
|
216
|
-
it 'returns successful result if all doubles are valid' do
|
217
|
-
assert_equal [], subject.call(XSpec::UnitOfWork.new(nil, ->{}))
|
218
|
-
end
|
219
|
-
end
|
data/xspec.gemspec
CHANGED
@@ -11,7 +11,7 @@ Gem::Specification.new do |gem|
|
|
11
11
|
gem.homepage = "http://github.com/xaviershay/xspec"
|
12
12
|
|
13
13
|
gem.executables = []
|
14
|
-
gem.required_ruby_version = '>= 1.
|
14
|
+
gem.required_ruby_version = '>= 2.1.0'
|
15
15
|
gem.files = Dir.glob("{spec,lib}/**/*.rb") + %w(
|
16
16
|
README.md
|
17
17
|
xspec.gemspec
|
@@ -22,6 +22,6 @@ Gem::Specification.new do |gem|
|
|
22
22
|
gem.bindir = "bin"
|
23
23
|
gem.executables << "xspec"
|
24
24
|
gem.license = "Apache 2.0"
|
25
|
-
gem.version = "0.0
|
25
|
+
gem.version = "0.1.0"
|
26
26
|
gem.has_rdoc = false
|
27
27
|
end
|