r_spec 1.0.0 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/lib/r_spec/dsl.rb DELETED
@@ -1,348 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "aw"
4
-
5
- require_relative "console"
6
- require_relative "error"
7
- require_relative "expectation_helper"
8
-
9
- module RSpec
10
- # Abstract class for handling the domain-specific language.
11
- class Dsl
12
- BEFORE_METHOD = :initialize
13
- AFTER_METHOD = :terminate
14
-
15
- private_constant :BEFORE_METHOD, :AFTER_METHOD
16
-
17
- # Executes the given block before each spec in the current context runs.
18
- #
19
- # @example
20
- # require "r_spec"
21
- #
22
- # RSpec.describe Integer do
23
- # before do
24
- # @value = 123
25
- # end
26
- #
27
- # it { expect(@value).to be 123 }
28
- #
29
- # describe "nested" do
30
- # before do
31
- # @value -= 81
32
- # end
33
- #
34
- # it { expect(@value).to be 42 }
35
- # end
36
- #
37
- # it { expect(@value).to be 123 }
38
- # end
39
- #
40
- # # Output to the console
41
- # # Success: expected to be 123.
42
- # # Success: expected to be 42.
43
- # # Success: expected to be 123.
44
- #
45
- # @param block [Proc] The content to execute at the class initialization.
46
- def self.before(&block)
47
- define_method(BEFORE_METHOD) do
48
- super()
49
- instance_eval(&block)
50
- end
51
-
52
- private BEFORE_METHOD
53
- end
54
-
55
- # Executes the given block after each spec in the current context runs.
56
- #
57
- # @example
58
- # require "r_spec"
59
- #
60
- # RSpec.describe Integer do
61
- # after do
62
- # puts "That is the answer to everything."
63
- # end
64
- #
65
- # it { expect(42).to be 42 }
66
- # end
67
- #
68
- # # Output to the console
69
- # # Success: expected to be 42.
70
- # # That is the answer to everything.
71
- #
72
- # @param block [Proc] The content to execute at the class initialization.
73
- def self.after(&block)
74
- define_method(AFTER_METHOD) do
75
- instance_exec(&block)
76
- super()
77
- end
78
-
79
- private AFTER_METHOD
80
- end
81
-
82
- # Sets a user-defined property.
83
- #
84
- # @example
85
- # require "r_spec"
86
- #
87
- # RSpec.describe "Name stories" do
88
- # let(:name) { "Bob" }
89
- #
90
- # it { expect(name).to eq "Bob" }
91
- #
92
- # context "with last name" do
93
- # let(:name) { "#{super()} Smith" }
94
- #
95
- # it { expect(name).to eq "Bob Smith" }
96
- # end
97
- # end
98
- #
99
- # # Output to the console
100
- # # Success: expected to eq "Bob".
101
- # # Success: expected to eq "Bob Smith".
102
- #
103
- # @param name [String, Symbol] The name of the property.
104
- # @param block [Proc] The content of the method to define.
105
- #
106
- # @return [Symbol] A private method that define the block content.
107
- def self.let(name, *args, **kwargs, &block)
108
- raise Error::ReservedMethod if [BEFORE_METHOD, AFTER_METHOD].include?(name.to_sym)
109
-
110
- private define_method(name, *args, **kwargs, &block)
111
- end
112
-
113
- # Sets a user-defined property named {#subject}.
114
- #
115
- # @example
116
- # require "r_spec"
117
- #
118
- # RSpec.describe Array do
119
- # subject { [1, 2, 3] }
120
- #
121
- # it "has the prescribed elements" do
122
- # expect(subject).to eq([1, 2, 3])
123
- # end
124
- # end
125
- #
126
- # # Output to the console
127
- # # Success: expected to eq [1, 2, 3].
128
- #
129
- # @param block [Proc] The subject to set.
130
- # @return [Symbol] A {#subject} method that define the block content.
131
- def self.subject(&block)
132
- let(__method__, &block)
133
- end
134
-
135
- # Defines an example group that describes a unit to be tested.
136
- #
137
- # @example
138
- # require "r_spec"
139
- #
140
- # RSpec.describe String do
141
- # describe "+" do
142
- # it("concats") { expect("foo" + "bar").to eq "foobar" }
143
- # end
144
- # end
145
- #
146
- # # Output to the console
147
- # # Success: expected to eq "foobar".
148
- #
149
- # @param const [Module, String] A module to include in block context.
150
- # @param block [Proc] The block to define the specs.
151
- def self.describe(const, &block)
152
- desc = ::Class.new(self)
153
- desc.let(:described_class) { const } if const.is_a?(::Module)
154
- desc.instance_eval(&block)
155
- end
156
-
157
- # Defines an example group that establishes a specific context, like _empty
158
- # array_ versus _array with elements_.
159
- #
160
- # Unlike {.describe}, the block is evaluated in isolation in order to scope
161
- # possible side effects inside its context.
162
- #
163
- # @example
164
- # require "r_spec"
165
- #
166
- # RSpec.describe "web resource" do
167
- # context "when resource is not found" do
168
- # pending "responds with 404"
169
- # end
170
- #
171
- # context "when resource is found" do
172
- # pending "responds with 200"
173
- # end
174
- # end
175
- #
176
- # # Output to the console
177
- # # Warning: responds with 404.
178
- # # Warning: responds with 200.
179
- #
180
- # @param _description [String] A description that usually begins with
181
- # "when", "with" or "without".
182
- # @param block [Proc] The block to define the specs.
183
- def self.context(_description, &block)
184
- desc = ::Class.new(self)
185
- ::Aw.fork! { desc.instance_eval(&block) }
186
- end
187
-
188
- # Defines a concrete test case.
189
- #
190
- # The test is performed by the block supplied to `&block`.
191
- #
192
- # @example The integer after 41
193
- # require "r_spec"
194
- #
195
- # RSpec.describe Integer do
196
- # it { expect(41.next).to be 42 }
197
- # end
198
- #
199
- # # Output to the console
200
- # # Success: expected to be 42.
201
- #
202
- # @example A division by zero
203
- # require "r_spec"
204
- #
205
- # RSpec.describe Integer do
206
- # subject { 41 }
207
- #
208
- # it { is_expected.to be_an_instance_of described_class }
209
- #
210
- # it "raises an error" do
211
- # expect { subject / 0 }.to raise_exception ZeroDivisionError
212
- # end
213
- # end
214
- #
215
- # # Output to the console
216
- # # Success: expected 41 to be an instance of Integer.
217
- # # Success: divided by 0.
218
- #
219
- # It can be used inside a {.describe} or {.context} section.
220
- #
221
- # @param _name [String, nil] The name of the spec.
222
- # @param block [Proc] An expectation to evaluate.
223
- #
224
- # @raise (see ExpectationTarget::Base#result)
225
- # @return (see ExpectationTarget::Base#result)
226
- def self.it(_name = nil, &block)
227
- raise ::ArgumentError, "Missing example block" unless block
228
-
229
- example = ::Class.new(self) { include ExpectationHelper::It }.new
230
- example.instance_eval(&block)
231
- rescue ::SystemExit
232
- Console.source(*block.source_location)
233
-
234
- exit false
235
- ensure
236
- example&.send(AFTER_METHOD)
237
- end
238
-
239
- # Use the {.its} method to define a single spec that specifies the actual
240
- # value of an attribute of the subject using
241
- # {ExpectationHelper::Its#is_expected}.
242
- #
243
- # @example The integer after 41
244
- # require "r_spec"
245
- #
246
- # RSpec.describe Integer do
247
- # subject { 41 }
248
- #
249
- # its(:next) { is_expected.to be 42 }
250
- # end
251
- #
252
- # # Output to the console
253
- # # Success: expected to be 42.
254
- #
255
- # @example A division by zero
256
- # require "r_spec"
257
- #
258
- # RSpec.describe Integer do
259
- # subject { 41 }
260
- #
261
- # its(:/, 0) { is_expected.to raise_exception ZeroDivisionError }
262
- # end
263
- #
264
- # # Output to the console
265
- # # Success: divided by 0.
266
- #
267
- # @example A spec without subject
268
- # require "r_spec"
269
- #
270
- # RSpec.describe Integer do
271
- # its(:boom) { is_expected.to raise_exception RSpec::Error::UndefinedSubject }
272
- # end
273
- #
274
- # # Output to the console
275
- # # Success: subject not explicitly defined.
276
- #
277
- # @param attribute [String, Symbol] The property to call to subject.
278
- # @param args [Array] An optional list of arguments.
279
- # @param kwargs [Hash] An optional list of keyword arguments.
280
- # @param block [Proc] An expectation to evaluate.
281
- #
282
- # @raise (see ExpectationTarget::Base#result)
283
- # @return (see ExpectationTarget::Base#result)
284
- def self.its(attribute, *args, **kwargs, &block)
285
- raise ::ArgumentError, "Missing example block" unless block
286
-
287
- example = ::Class.new(self) do
288
- include ExpectationHelper::Its
289
-
290
- define_method(:actual) do
291
- subject.public_send(attribute, *args, **kwargs)
292
- end
293
- end.new
294
-
295
- example.instance_eval(&block)
296
- rescue ::SystemExit
297
- Console.source(*block.source_location)
298
-
299
- exit false
300
- ensure
301
- example&.send(AFTER_METHOD)
302
- end
303
-
304
- # Defines a pending test case.
305
- #
306
- # `&block` is never evaluated. It can be used to describe behaviour that is
307
- # not yet implemented.
308
- #
309
- # @example
310
- # require "r_spec"
311
- #
312
- # RSpec.describe "an example" do
313
- # pending "is implemented but waiting" do
314
- # expect something to be finished
315
- # end
316
- #
317
- # pending "is not yet implemented and waiting"
318
- # end
319
- #
320
- # # Output to the console
321
- # # Warning: is implemented but waiting.
322
- # # Warning: is not yet implemented and waiting.
323
- #
324
- # @param message [String] The reason why the example is pending.
325
- #
326
- # @return [nil] Write a message to STDOUT.
327
- #
328
- # @api public
329
- def self.pending(message)
330
- Console.passed_spec Error::PendingExpectation.result(message)
331
- end
332
-
333
- private
334
-
335
- def described_class
336
- raise Error::UndefinedDescribedClass,
337
- "the first argument to at least one example group must be a module"
338
- end
339
-
340
- def subject
341
- raise Error::UndefinedSubject, "subject not explicitly defined"
342
- end
343
-
344
- define_method(AFTER_METHOD) do
345
- # do nothing by default
346
- end
347
- end
348
- end
@@ -1,27 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "expresenter"
4
-
5
- module RSpec
6
- module Error
7
- # Exception for pending expectations.
8
- #
9
- # @api private
10
- class PendingExpectation < ::RuntimeError
11
- # @param message [String] The not implemented expectation description.
12
- #
13
- # @return [nil] Write a pending expectation to STDOUT.
14
- def self.result(message)
15
- ::Expresenter.call(true).with(
16
- actual: new(message),
17
- error: nil,
18
- expected: self,
19
- got: false,
20
- matcher: :raise_exception,
21
- negate: true,
22
- level: :SHOULD
23
- )
24
- end
25
- end
26
- end
27
- end
@@ -1,11 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RSpec
4
- module Error
5
- # Exception for reserved methods.
6
- #
7
- # @api private
8
- class ReservedMethod < ::RuntimeError
9
- end
10
- end
11
- end
@@ -1,11 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RSpec
4
- module Error
5
- # Exception for undefined described classes.
6
- #
7
- # @api private
8
- class UndefinedDescribedClass < ::RuntimeError
9
- end
10
- end
11
- end
@@ -1,11 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RSpec
4
- module Error
5
- # Exception for undefined subjects.
6
- #
7
- # @api private
8
- class UndefinedSubject < ::RuntimeError
9
- end
10
- end
11
- end
data/lib/r_spec/error.rb DELETED
@@ -1,14 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative File.join("error", "pending_expectation")
4
- require_relative File.join("error", "reserved_method")
5
- require_relative File.join("error", "undefined_described_class")
6
- require_relative File.join("error", "undefined_subject")
7
-
8
- module RSpec
9
- # Namespace for exceptions.
10
- #
11
- # @api private
12
- module Error
13
- end
14
- end
@@ -1,41 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "shared"
4
- require_relative File.join("..", "expectation_target")
5
-
6
- module RSpec
7
- module ExpectationHelper
8
- # {RSpec::Dsl.it}'s expectation helper module.
9
- module It
10
- include Shared
11
-
12
- # Create an expectation for a spec.
13
- #
14
- # @param value [#object_id, nil] An actual value.
15
- # @param block [#call, nil] A code to evaluate.
16
- #
17
- # @return [Block, Value] The wrapped target of an expectation.
18
- #
19
- # @example
20
- # expect("foo") # => #<RSpec::ExpectationTarget::Value:0x00007fb6b82311a0 @actual="foo">
21
- # expect { Boom } # => #<RSpec::ExpectationTarget::Block:0x00007fb6b8263df8 @callable=#<Proc:0x00007fb6b8263e20>>
22
- #
23
- # @api public
24
- def expect(value = self.class.superclass, &block)
25
- ExpectationTarget.call(self.class.superclass, value, block)
26
- end
27
-
28
- # Wraps the target of an expectation with the subject as actual value.
29
- #
30
- # @return [Block] The wrapped target of an expectation.
31
- #
32
- # @example
33
- # is_expected # => #<RSpec::ExpectationTarget::Block:0x00007fb6b8263df8 @callable=#<Proc:0x00007fb6b8263e20>>
34
- #
35
- # @api public
36
- def is_expected
37
- expect { subject }
38
- end
39
- end
40
- end
41
- end
@@ -1,25 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "shared"
4
- require_relative File.join("..", "expectation_target", "block")
5
-
6
- module RSpec
7
- module ExpectationHelper
8
- # {RSpec::Dsl.its}'s expectation helper module.
9
- module Its
10
- include Shared
11
-
12
- # Wraps the target of an expectation with the actual value.
13
- #
14
- # @return [Block] The wrapped target of an expectation.
15
- #
16
- # @example
17
- # is_expected # => #<RSpec::ExpectationTarget::Block:0x00007fb6b8263df8 @callable=#<Proc:0x00007fb6b8263e20>>
18
- #
19
- # @api public
20
- def is_expected
21
- ExpectationTarget::Block.new(method(:actual))
22
- end
23
- end
24
- end
25
- end
@@ -1,82 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "matchi/rspec"
4
-
5
- require_relative File.join("..", "error", "pending_expectation")
6
-
7
- module RSpec
8
- module ExpectationHelper
9
- # Abstract expectation helper base module.
10
- #
11
- # This module defines a number of methods to create expectations, which are
12
- # automatically included into examples.
13
- #
14
- # It also includes a collection of expectation matchers 🤹
15
- #
16
- # @example Equivalence matcher
17
- # matcher = eql("foo") # => Matchi::Matcher::Eql.new("foo")
18
- # matcher.matches? { "foo" } # => true
19
- # matcher.matches? { "bar" } # => false
20
- #
21
- # matcher = eq("foo") # => Matchi::Matcher::Eq.new("foo")
22
- # matcher.matches? { "foo" } # => true
23
- # matcher.matches? { "bar" } # => false
24
- #
25
- # @example Identity matcher
26
- # object = "foo"
27
- #
28
- # matcher = equal(object) # => Matchi::Matcher::Equal.new(object)
29
- # matcher.matches? { object } # => true
30
- # matcher.matches? { "foo" } # => false
31
- #
32
- # matcher = be(object) # => Matchi::Matcher::Be.new(object)
33
- # matcher.matches? { object } # => true
34
- # matcher.matches? { "foo" } # => false
35
- #
36
- # @example Regular expressions matcher
37
- # matcher = match(/^foo$/) # => Matchi::Matcher::Match.new(/^foo$/)
38
- # matcher.matches? { "foo" } # => true
39
- # matcher.matches? { "bar" } # => false
40
- #
41
- # @example Expecting errors matcher
42
- # matcher = raise_exception(NameError) # => Matchi::Matcher::RaiseException.new(NameError)
43
- # matcher.matches? { Boom } # => true
44
- # matcher.matches? { true } # => false
45
- #
46
- # @example Truth matcher
47
- # matcher = be_true # => Matchi::Matcher::BeTrue.new
48
- # matcher.matches? { true } # => true
49
- # matcher.matches? { false } # => false
50
- # matcher.matches? { nil } # => false
51
- # matcher.matches? { 4 } # => false
52
- #
53
- # @example Untruth matcher
54
- # matcher = be_false # => Matchi::Matcher::BeFalse.new
55
- # matcher.matches? { false } # => true
56
- # matcher.matches? { true } # => false
57
- # matcher.matches? { nil } # => false
58
- # matcher.matches? { 4 } # => false
59
- #
60
- # @example Nil matcher
61
- # matcher = be_nil # => Matchi::Matcher::BeNil.new
62
- # matcher.matches? { nil } # => true
63
- # matcher.matches? { false } # => false
64
- # matcher.matches? { true } # => false
65
- # matcher.matches? { 4 } # => false
66
- #
67
- # @example Type/class matcher
68
- # matcher = be_instance_of(String) # => Matchi::Matcher::BeInstanceOf.new(String)
69
- # matcher.matches? { "foo" } # => true
70
- # matcher.matches? { 4 } # => false
71
- #
72
- # matcher = be_an_instance_of(String) # => Matchi::Matcher::BeAnInstanceOf.new(String)
73
- # matcher.matches? { "foo" } # => true
74
- # matcher.matches? { 4 } # => false
75
- #
76
- # @see https://github.com/fixrb/matchi
77
- # @see https://github.com/fixrb/matchi-rspec
78
- module Shared
79
- include ::Matchi::Helper
80
- end
81
- end
82
- end
@@ -1,10 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative File.join("expectation_helper", "it")
4
- require_relative File.join("expectation_helper", "its")
5
-
6
- module RSpec
7
- # Namespace for {Dsl.it} and {Dsl.its}'s helper modules.
8
- module ExpectationHelper
9
- end
10
- end
@@ -1,82 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "expresenter"
4
- require "test_tube"
5
-
6
- require_relative File.join("..", "console")
7
-
8
- module RSpec
9
- module ExpectationTarget
10
- # Abstract expectation target base class.
11
- #
12
- # @note `RSpec::ExpectationTarget::Base` is not intended to be instantiated
13
- # directly by users. Use `expect` instead.
14
- class Base
15
- # Instantiate a new expectation target.
16
- #
17
- # @param actual [#object_id] The actual value of the code to evaluate.
18
- def initialize(actual)
19
- @actual = actual
20
- end
21
-
22
- # Runs the given expectation, passing if `matcher` returns true.
23
- #
24
- # @example _Absolute requirement_ definition
25
- # expect { "foo".upcase }.to eq("foo")
26
- #
27
- # @param matcher [#matches?] The matcher.
28
- #
29
- # @raise (see #result)
30
- # @return (see #result)
31
- #
32
- # @api public
33
- def to(matcher)
34
- absolute_requirement(matcher: matcher, negate: false)
35
- end
36
-
37
- # Runs the given expectation, passing if `matcher` returns false.
38
- #
39
- # @example _Absolute prohibition_ definition
40
- # expect { "foo".size }.not_to be(4)
41
- #
42
- # @param (see #to)
43
- #
44
- # @raise (see #result)
45
- # @return (see #result)
46
- #
47
- # @api public
48
- def not_to(matcher)
49
- absolute_requirement(matcher: matcher, negate: true)
50
- end
51
-
52
- protected
53
-
54
- # @param passed [Boolean] The high expectation passed or failed.
55
- # @param actual [#object_id] The actual value.
56
- # @param error [Exception, nil] Any raised exception.
57
- # @param got [Boolean, nil] Any returned value.
58
- # @param matcher [#matches?] The matcher.
59
- # @param negate [Boolean] The assertion is positive or negative.
60
- #
61
- # @return [nil] Write a message to STDOUT.
62
- #
63
- # @raise [SystemExit] Terminate execution immediately by calling
64
- # `Kernel.exit(false)` with a failure message written to STDERR.
65
- #
66
- # @api private
67
- def result(passed, actual:, error:, got:, matcher:, negate:)
68
- Console.passed_spec ::Expresenter.call(passed).with(
69
- actual: actual,
70
- error: error,
71
- expected: matcher.expected,
72
- got: got,
73
- negate: negate,
74
- matcher: matcher.class.to_sym,
75
- level: :MUST
76
- )
77
- rescue ::Expresenter::Fail => e
78
- Console.failed_spec(e)
79
- end
80
- end
81
- end
82
- end