r_spec 1.0.0.beta2 → 1.0.0.beta7
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 +183 -35
- data/lib/r_spec.rb +58 -8
- data/lib/r_spec/console.rb +38 -0
- data/lib/r_spec/dsl.rb +300 -69
- data/lib/r_spec/error.rb +14 -0
- data/lib/r_spec/error/pending_expectation.rb +28 -0
- data/lib/r_spec/error/reserved_method.rb +11 -0
- data/lib/r_spec/error/undefined_described_class.rb +11 -0
- data/lib/r_spec/error/undefined_subject.rb +11 -0
- data/lib/r_spec/expectation_helper.rb +10 -0
- data/lib/r_spec/expectation_helper/it.rb +41 -0
- data/lib/r_spec/expectation_helper/its.rb +25 -0
- data/lib/r_spec/expectation_helper/shared.rb +82 -0
- data/lib/r_spec/expectation_target.rb +19 -82
- data/lib/r_spec/expectation_target/base.rb +82 -0
- data/lib/r_spec/expectation_target/block.rb +51 -0
- data/lib/r_spec/expectation_target/value.rb +44 -0
- metadata +35 -10
- data/lib/r_spec/log.rb +0 -24
- data/lib/r_spec/pending.rb +0 -24
- data/lib/r_spec/test.rb +0 -7
data/lib/r_spec/error.rb
ADDED
@@ -0,0 +1,14 @@
|
|
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
|
@@ -0,0 +1,28 @@
|
|
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
|
+
valid: false
|
24
|
+
)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,10 @@
|
|
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
|
@@ -0,0 +1,41 @@
|
|
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
|
@@ -0,0 +1,25 @@
|
|
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
|
@@ -0,0 +1,82 @@
|
|
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,93 +1,30 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require_relative File.join("expectation_target", "block")
|
4
|
+
require_relative File.join("expectation_target", "value")
|
4
5
|
|
5
6
|
module RSpec
|
6
7
|
# Wraps the target of an expectation.
|
7
8
|
#
|
8
|
-
# @
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
# Instantiate a new expectation target.
|
21
|
-
#
|
22
|
-
# @param actual [#object_id] The actual value.
|
23
|
-
#
|
24
|
-
# @api private
|
25
|
-
def initialize(actual)
|
26
|
-
@actual = actual
|
27
|
-
end
|
9
|
+
# @api private
|
10
|
+
module ExpectationTarget
|
11
|
+
# @param undefined_value A sentinel value to be able to tell when the user
|
12
|
+
# did not pass an argument. We can't use `nil` for that because `nil` is a
|
13
|
+
# valid value to pass.
|
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
|
+
def self.call(undefined_value, value, block)
|
19
|
+
if undefined_value.equal?(value)
|
20
|
+
raise ::ArgumentError, "Pass either an argument or a block" unless block
|
28
21
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
# expect("foo".upcase).to eq("foo")
|
33
|
-
#
|
34
|
-
# @param matcher [#matches?] The matcher.
|
35
|
-
#
|
36
|
-
# @raise (see #result)
|
37
|
-
# @return (see #result)
|
38
|
-
def to(matcher)
|
39
|
-
absolute_requirement(matcher: matcher, negate: false)
|
40
|
-
end
|
22
|
+
Block.new(block)
|
23
|
+
else
|
24
|
+
raise ::ArgumentError, "Can't pass both an argument and a block" if block
|
41
25
|
|
42
|
-
|
43
|
-
|
44
|
-
# @example _Absolute prohibition_ definition
|
45
|
-
# expect("foo".size).not_to be(4)
|
46
|
-
#
|
47
|
-
# @param (see #to)
|
48
|
-
#
|
49
|
-
# @raise (see #result)
|
50
|
-
# @return (see #result)
|
51
|
-
def not_to(matcher)
|
52
|
-
absolute_requirement(matcher: matcher, negate: true)
|
53
|
-
end
|
54
|
-
|
55
|
-
protected
|
56
|
-
|
57
|
-
# @param matcher [#matches?] The matcher.
|
58
|
-
# @param negate [Boolean] Positive or negative assertion?
|
59
|
-
#
|
60
|
-
# @raise (see #result)
|
61
|
-
# @return (see #result)
|
62
|
-
def absolute_requirement(matcher:, negate:)
|
63
|
-
result(
|
64
|
-
matcher: matcher,
|
65
|
-
negate: negate,
|
66
|
-
passed: negate ^ matcher.matches? { @actual }
|
67
|
-
)
|
68
|
-
end
|
69
|
-
|
70
|
-
# @param matcher [#matches?] The matcher.
|
71
|
-
# @param negate [Boolean] Positive or negative assertion?
|
72
|
-
# @param passed [Boolean] The result of an expectation.
|
73
|
-
#
|
74
|
-
# @return [nil] Write a message to STDOUT.
|
75
|
-
#
|
76
|
-
# @raise [SystemExit] Terminate execution immediately by calling
|
77
|
-
# `Kernel.exit(false)` with a failure message written to STDERR.
|
78
|
-
def result(matcher:, negate:, passed:)
|
79
|
-
puts " " + ::Expresenter.call(passed).with(
|
80
|
-
actual: @actual,
|
81
|
-
error: nil,
|
82
|
-
expected: matcher.expected,
|
83
|
-
got: passed,
|
84
|
-
negate: negate,
|
85
|
-
valid: passed,
|
86
|
-
matcher: matcher.class.to_sym,
|
87
|
-
level: :MUST
|
88
|
-
).colored_string
|
89
|
-
rescue ::Expresenter::Fail => e
|
90
|
-
abort " #{e.colored_string}"
|
26
|
+
Value.new(value)
|
27
|
+
end
|
91
28
|
end
|
92
29
|
end
|
93
30
|
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "expresenter"
|
4
|
+
|
5
|
+
require_relative File.join("..", "console")
|
6
|
+
|
7
|
+
module RSpec
|
8
|
+
module ExpectationTarget
|
9
|
+
# Abstract expectation target base class.
|
10
|
+
#
|
11
|
+
# @note `RSpec::ExpectationTarget::Base` is not intended to be instantiated
|
12
|
+
# directly by users. Use `expect` instead.
|
13
|
+
class Base
|
14
|
+
# Instantiate a new expectation target.
|
15
|
+
#
|
16
|
+
# @param actual [#object_id] The actual value of the code to evaluate.
|
17
|
+
def initialize(actual)
|
18
|
+
@actual = actual
|
19
|
+
end
|
20
|
+
|
21
|
+
# Runs the given expectation, passing if `matcher` returns true.
|
22
|
+
#
|
23
|
+
# @example _Absolute requirement_ definition
|
24
|
+
# expect { "foo".upcase }.to eq("foo")
|
25
|
+
#
|
26
|
+
# @param matcher [#matches?] The matcher.
|
27
|
+
#
|
28
|
+
# @raise (see #result)
|
29
|
+
# @return (see #result)
|
30
|
+
#
|
31
|
+
# @api public
|
32
|
+
def to(matcher)
|
33
|
+
absolute_requirement(matcher: matcher, negate: false)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Runs the given expectation, passing if `matcher` returns false.
|
37
|
+
#
|
38
|
+
# @example _Absolute prohibition_ definition
|
39
|
+
# expect { "foo".size }.not_to be(4)
|
40
|
+
#
|
41
|
+
# @param (see #to)
|
42
|
+
#
|
43
|
+
# @raise (see #result)
|
44
|
+
# @return (see #result)
|
45
|
+
#
|
46
|
+
# @api public
|
47
|
+
def not_to(matcher)
|
48
|
+
absolute_requirement(matcher: matcher, negate: true)
|
49
|
+
end
|
50
|
+
|
51
|
+
protected
|
52
|
+
|
53
|
+
# @param actual [#object_id] The actual value.
|
54
|
+
# @param error [Exception, nil] Any raised exception.
|
55
|
+
# @param got [Boolean, nil] Any returned value.
|
56
|
+
# @param matcher [#matches?] The matcher.
|
57
|
+
# @param negate [Boolean] The assertion is positive or negative.
|
58
|
+
# @param valid [Boolean] The result of an expectation.
|
59
|
+
#
|
60
|
+
# @return [nil] Write a message to STDOUT.
|
61
|
+
#
|
62
|
+
# @raise [SystemExit] Terminate execution immediately by calling
|
63
|
+
# `Kernel.exit(false)` with a failure message written to STDERR.
|
64
|
+
#
|
65
|
+
# @api private
|
66
|
+
def result(actual:, error:, got:, matcher:, negate:, valid:)
|
67
|
+
Console.passed_spec ::Expresenter.call(valid).with(
|
68
|
+
actual: actual,
|
69
|
+
error: error,
|
70
|
+
expected: matcher.expected,
|
71
|
+
got: got,
|
72
|
+
negate: negate,
|
73
|
+
valid: valid,
|
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
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spectus/exam"
|
4
|
+
|
5
|
+
require_relative "base"
|
6
|
+
|
7
|
+
module RSpec
|
8
|
+
module ExpectationTarget
|
9
|
+
# Wraps the target of an expectation with a block.
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# expect { something } # => ExpectationTarget::Block wrapping something
|
13
|
+
#
|
14
|
+
# # used with `to`
|
15
|
+
# expect { actual }.to be(42)
|
16
|
+
#
|
17
|
+
# # with `not_to`
|
18
|
+
# expect { actual }.not_to be(4)
|
19
|
+
#
|
20
|
+
# @note `RSpec::ExpectationTarget::Block` is not intended to be instantiated
|
21
|
+
# directly by users. Use `expect` instead.
|
22
|
+
class Block < Base
|
23
|
+
protected
|
24
|
+
|
25
|
+
# @param matcher [#matches?] The matcher.
|
26
|
+
# @param negate [Boolean] The assertion is positive or negative.
|
27
|
+
#
|
28
|
+
# @return [nil] Write a message to STDOUT.
|
29
|
+
#
|
30
|
+
# @raise [SystemExit] Terminate execution immediately by calling
|
31
|
+
# `Kernel.exit(false)` with a failure message written to STDERR.
|
32
|
+
def absolute_requirement(matcher:, negate:)
|
33
|
+
exam = ::Spectus::Exam.new(
|
34
|
+
callable: @actual,
|
35
|
+
isolation: false,
|
36
|
+
negate: negate,
|
37
|
+
matcher: matcher
|
38
|
+
)
|
39
|
+
|
40
|
+
result(
|
41
|
+
actual: exam.actual,
|
42
|
+
error: exam.exception,
|
43
|
+
got: exam.got,
|
44
|
+
matcher: matcher,
|
45
|
+
negate: negate,
|
46
|
+
valid: exam.valid?
|
47
|
+
)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|