mongoid7-rspec-callbacks 1.0.0.pre.816289031
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/COPYING +674 -0
- data/Gemfile +6 -0
- data/LICENSE +14 -0
- data/README.md +65 -0
- data/Rakefile +8 -0
- data/lib/matchers/association_callbacks.rb +86 -0
- data/lib/matchers/callbacks.rb +157 -0
- data/lib/matchers/set_callbacks.rb +78 -0
- data/lib/mongoid-rspec-callbacks/info.rb +35 -0
- data/lib/mongoid_rspec_callbacks.rb +6 -0
- data/spec/band_spec.rb +8 -0
- data/spec/profile_spec.rb +10 -0
- data/spec/spec_helper.rb +24 -0
- data/spec/studio_spec.rb +8 -0
- data/spec/support/models/band.rb +18 -0
- data/spec/support/models/profile.rb +33 -0
- data/spec/support/models/studio.rb +20 -0
- data/spec/support/models/user.rb +29 -0
- data/spec/user_spec.rb +26 -0
- metadata +251 -0
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
Copyright (c) 2013 Luis Ciudad
|
2
|
+
|
3
|
+
This program is free software: you can redistribute it and/or modify
|
4
|
+
it under the terms of the GNU General Public License as published by
|
5
|
+
the Free Software Foundation, either version 3 of the License, or
|
6
|
+
(at your option) any later version.
|
7
|
+
|
8
|
+
This program is distributed in the hope that it will be useful,
|
9
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
GNU General Public License for more details.
|
12
|
+
|
13
|
+
You should have received a copy of the GNU General Public License
|
14
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
data/README.md
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
# Mongoid::Rspec::Callbacks
|
2
|
+
[](https://github.com/dazzl-tv/mongoid-rspec-callbacks/actions/workflows/rspec.yml)
|
3
|
+
[](https://github.com/dazzl-tv/mongoid-rspec-callbacks/actions/workflows/linter.yml)
|
4
|
+
[](https://badge.fury.io/rb/mongoid-rspec-callbacks)
|
5
|
+
[](https://inch-ci.org/github/dazzl-tv/mongoid-rspec-callbacks)
|
6
|
+
[](https://codeclimate.com/github/dazzl-tv/mongoid-rspec-callbacks/maintainability)
|
7
|
+
[](https://codeclimate.com/github/dazzl-tv/mongoid-rspec-callbacks/test_coverage)
|
8
|
+
[](https://snyk.io/test/github/dazzl-tv/mongoid-rspec-callbacks)
|
9
|
+
|
10
|
+
http://rubygems.org/gems/mongoid-rspec-callbacks
|
11
|
+
|
12
|
+
RSpec Callbacks matchers for Mongoid 7.x and ActiveSupport 6.x
|
13
|
+
|
14
|
+
This gem is meant to be use with [mongoid-rpsec](http://rubygems.org/gems/mongoid-rspec), altought it works by itself.
|
15
|
+
|
16
|
+
Syntax is the same as [shoulda-callback-matchers](https://github.com/beatrichartz/shoulda-callback-matchers).
|
17
|
+
|
18
|
+
By now, only ``on`` option is supported.
|
19
|
+
|
20
|
+
## Installation
|
21
|
+
|
22
|
+
Add to your Gemfile
|
23
|
+
|
24
|
+
```
|
25
|
+
gem 'mongoid-rspec-callbacks'
|
26
|
+
```
|
27
|
+
|
28
|
+
Drop in existing or dedicated support file in spec/support (spec/support/mongoid.rb)
|
29
|
+
|
30
|
+
```
|
31
|
+
RSpec.configure do |configuration|
|
32
|
+
configuration.include Mongoid::Matchers
|
33
|
+
end
|
34
|
+
```
|
35
|
+
|
36
|
+
## Callbacks Matchers
|
37
|
+
|
38
|
+
```
|
39
|
+
describe User do
|
40
|
+
it { should callback(:method).before(:save) }
|
41
|
+
it { should callback(:method).after(:save) }
|
42
|
+
it { should callback(:method, :method2).before(:validation) }
|
43
|
+
it { should callback(:method).after(:validation).on(:create) }
|
44
|
+
end
|
45
|
+
```
|
46
|
+
|
47
|
+
## Set Callbacks Matchers
|
48
|
+
|
49
|
+
```
|
50
|
+
describe User do
|
51
|
+
it { is_expected.to set_callback(:save, :arround) }
|
52
|
+
it { is_expected.to set_callback(:validation, :after) }
|
53
|
+
end
|
54
|
+
```
|
55
|
+
|
56
|
+
## Association Callbacks Matchers
|
57
|
+
|
58
|
+
```
|
59
|
+
describe User do
|
60
|
+
it { is_expected.to association_callback(:has_many,
|
61
|
+
:add,
|
62
|
+
:after,
|
63
|
+
:send_email_to_subscribers) }
|
64
|
+
end
|
65
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mongoid
|
4
|
+
module Matchers
|
5
|
+
# Create an matcher for set_callback method
|
6
|
+
#
|
7
|
+
# Usage:
|
8
|
+
#
|
9
|
+
# it { is_expected.to association_callback(:has_many,
|
10
|
+
# :add,
|
11
|
+
# :after,
|
12
|
+
# :send_email_to_subscribers) }
|
13
|
+
class HaveAssociationCallbackMatcher
|
14
|
+
CONTEXTS = %i[before after].freeze
|
15
|
+
OPERATIONS = %i[add remove].freeze
|
16
|
+
RELATIONS = %i[embeds_many has_many and has_and_belongs_to_many].freeze
|
17
|
+
|
18
|
+
def initialize(*args)
|
19
|
+
@relation = args[0]
|
20
|
+
@type = args[1]
|
21
|
+
@hook = args[2]
|
22
|
+
@method = args[3]
|
23
|
+
end
|
24
|
+
|
25
|
+
def matches?(klass)
|
26
|
+
@model = klass
|
27
|
+
|
28
|
+
return false unless \
|
29
|
+
relation_is_correct? ||
|
30
|
+
context_is_correct? ||
|
31
|
+
operation_is_correct? ||
|
32
|
+
callback_is_correct?
|
33
|
+
|
34
|
+
testings_presence_method_callback
|
35
|
+
end
|
36
|
+
|
37
|
+
def description
|
38
|
+
"be association_callback(:#{@type}, :#{@hook})"
|
39
|
+
end
|
40
|
+
|
41
|
+
def failure_message
|
42
|
+
message_error
|
43
|
+
end
|
44
|
+
|
45
|
+
def failure_message_when_negated
|
46
|
+
message_error
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def relation_is_correct?
|
52
|
+
RELATIONS.include?(@relation)
|
53
|
+
end
|
54
|
+
|
55
|
+
def context_is_correct?
|
56
|
+
CONTEXTS.include?(@hook)
|
57
|
+
end
|
58
|
+
|
59
|
+
def operation_is_correct?
|
60
|
+
OPERATIONS.include?(@type)
|
61
|
+
end
|
62
|
+
|
63
|
+
def callback_is_correct?
|
64
|
+
@model.class.respond_to?(:"_#{@type}_callbacks")
|
65
|
+
end
|
66
|
+
|
67
|
+
def testings_presence_method_callback
|
68
|
+
@model.methods.include?(:"#{@method}")
|
69
|
+
end
|
70
|
+
|
71
|
+
def message_error
|
72
|
+
<<-ERROR
|
73
|
+
expected #{@model} have method callback to association :
|
74
|
+
has_many <relation>, #{@hook}: :#{@method}
|
75
|
+
|
76
|
+
def #{@method}
|
77
|
+
end
|
78
|
+
ERROR
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def association_callback(*args)
|
83
|
+
HaveAssociationCallbackMatcher.new(*args)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,157 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mongoid
|
4
|
+
module Matchers
|
5
|
+
# Create an matcher for callback method
|
6
|
+
#
|
7
|
+
# Usage:
|
8
|
+
#
|
9
|
+
# it { is_expected.to callback(:callback1).before(:save) }
|
10
|
+
# it { is_expected.to callback(:callback2).after(:save) }
|
11
|
+
# it { is_expected.to callback(:callback1, :callback2).before(:validation) }
|
12
|
+
# it { is_expected.to callback(:callback3).after(:validation).on(:create) }
|
13
|
+
class HaveCallbackMatcher
|
14
|
+
KINDS = %w[before around after].freeze
|
15
|
+
|
16
|
+
# Set methods to look for
|
17
|
+
def initialize(*args)
|
18
|
+
@methods = args || []
|
19
|
+
end
|
20
|
+
|
21
|
+
# Set when callback is fired using @kind and @operation
|
22
|
+
KINDS.each do |kind|
|
23
|
+
define_method(kind.to_sym) do |op|
|
24
|
+
@operation = op
|
25
|
+
@kind = kind.to_sym
|
26
|
+
self
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Set on condition
|
31
|
+
def on(action)
|
32
|
+
@context = action
|
33
|
+
self
|
34
|
+
end
|
35
|
+
|
36
|
+
def matches?(klass)
|
37
|
+
return false unless @kind
|
38
|
+
if @no_op == !klass.class.respond_to?(:"_#{@operation}_callbacks")
|
39
|
+
return false
|
40
|
+
end
|
41
|
+
|
42
|
+
@guess = nil
|
43
|
+
@methods.each do |method|
|
44
|
+
filter = filters_method(klass, method)
|
45
|
+
|
46
|
+
return false unless filter
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def failure_message
|
51
|
+
message(true)
|
52
|
+
end
|
53
|
+
|
54
|
+
def failure_message_when_negated
|
55
|
+
message(false)
|
56
|
+
end
|
57
|
+
|
58
|
+
def description
|
59
|
+
methods = @methods
|
60
|
+
|
61
|
+
"be callback(:#{methods.join(', ')})#{expl_operation}#{expl_context}"
|
62
|
+
end
|
63
|
+
|
64
|
+
protected
|
65
|
+
|
66
|
+
def expl_operation
|
67
|
+
@operation ? ".#{@kind}(:#{@operation})" : ''
|
68
|
+
end
|
69
|
+
|
70
|
+
def expl_context
|
71
|
+
@context ? ".on(:#{@context})" : ''
|
72
|
+
end
|
73
|
+
|
74
|
+
def message(should)
|
75
|
+
return msg_op_invalid if @no_op
|
76
|
+
|
77
|
+
@kind ? message_kind(should) : message_not_kind
|
78
|
+
end
|
79
|
+
|
80
|
+
def msg_op_invalid
|
81
|
+
'Invalid operation. Use :initialize, :build, :validation,' \
|
82
|
+
':create, :find, :update, :upsert, :save or :destroy'
|
83
|
+
end
|
84
|
+
|
85
|
+
def message_kind(should)
|
86
|
+
<<-MESSAGE
|
87
|
+
Expected method#{@methods.size > 1 ? 's' : ''}#{expr_called(should)}
|
88
|
+
#{"#{@kind}" "#{@operation}" if @operation}
|
89
|
+
#{"on #{@context}" if @context}
|
90
|
+
#{msg_guess}
|
91
|
+
#{"#{@guess.kind} #{@operation}" if @guess}
|
92
|
+
#{'on another context' if @guess && !@context_match}
|
93
|
+
MESSAGE
|
94
|
+
end
|
95
|
+
|
96
|
+
def expr_called(should)
|
97
|
+
"#{@methods.join(', ')} #{should ? '' : 'not '}to be called"
|
98
|
+
end
|
99
|
+
|
100
|
+
def msg_guess
|
101
|
+
if @guess
|
102
|
+
", but got method #{@guess.filter} called"
|
103
|
+
else
|
104
|
+
', but no callback found'
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def message_not_kind
|
109
|
+
<<-MESSAGE
|
110
|
+
Callback#{@methods.size > 1 ? 's' : ''} #{@methods.join(', ')} can
|
111
|
+
not be tested against undefined lifecycle.
|
112
|
+
Use .before, .after or .around
|
113
|
+
MESSAGE
|
114
|
+
end
|
115
|
+
|
116
|
+
private
|
117
|
+
|
118
|
+
def filters_method(klass, method)
|
119
|
+
klass.class.send(:"_#{@operation}_callbacks").detect do |callback|
|
120
|
+
# Save callback instance in order to print information
|
121
|
+
# about it in case of failure
|
122
|
+
@guess = callback if callback.filter == method
|
123
|
+
check_filter?(callback,
|
124
|
+
method) and check_kind?(callback,
|
125
|
+
@kind) and check_context?(
|
126
|
+
callback, @context
|
127
|
+
)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def check_filter?(callback, method)
|
132
|
+
callback.filter == method
|
133
|
+
end
|
134
|
+
|
135
|
+
def check_kind?(callback, kind)
|
136
|
+
callback.kind == kind
|
137
|
+
end
|
138
|
+
|
139
|
+
def check_context?(callback, context)
|
140
|
+
return true unless context
|
141
|
+
|
142
|
+
options = callback.instance_variable_get(:@if)
|
143
|
+
@context_match = options.select { |option| option.is_a?(Proc) }
|
144
|
+
|
145
|
+
@context_match.detect do |option|
|
146
|
+
option.call(ValidationContext.new(context))
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
ValidationContext = Struct.new :validation_context
|
152
|
+
|
153
|
+
def callback(*args)
|
154
|
+
HaveCallbackMatcher.new(*args)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mongoid
|
4
|
+
module Matchers
|
5
|
+
# Create an matcher for set_callback method
|
6
|
+
#
|
7
|
+
# Usage:
|
8
|
+
#
|
9
|
+
# it { is_expected.to set_callback(:save, :arround) }
|
10
|
+
# it { is_expected.to set_callback(:validation, :after) }
|
11
|
+
class HaveSetCallbackMatcher
|
12
|
+
CONTEXTS = %i[before arround after].freeze
|
13
|
+
OPERATIONS = %i[initialize build validation create
|
14
|
+
find update upsert save destroy].freeze
|
15
|
+
|
16
|
+
def initialize(*args)
|
17
|
+
@type = args[0]
|
18
|
+
@hook = args[1]
|
19
|
+
end
|
20
|
+
|
21
|
+
def matches?(klass)
|
22
|
+
@model = klass
|
23
|
+
|
24
|
+
return false unless \
|
25
|
+
context_is_correct? ||
|
26
|
+
operation_is_correct? ||
|
27
|
+
callback_is_correct?
|
28
|
+
|
29
|
+
testings_presence_callback
|
30
|
+
end
|
31
|
+
|
32
|
+
def description
|
33
|
+
"be set_callback(:#{@type}, :#{@hook})"
|
34
|
+
end
|
35
|
+
|
36
|
+
def failure_message
|
37
|
+
message_error
|
38
|
+
end
|
39
|
+
|
40
|
+
def failure_message_when_negated
|
41
|
+
message_error
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def context_is_correct?
|
47
|
+
CONTEXTS.include?(@hook)
|
48
|
+
end
|
49
|
+
|
50
|
+
def operation_is_correct?
|
51
|
+
OPERATIONS.include?(@type)
|
52
|
+
end
|
53
|
+
|
54
|
+
def callback_is_correct?
|
55
|
+
@model.class.respond_to?(:"_#{@type}_callbacks")
|
56
|
+
end
|
57
|
+
|
58
|
+
def testings_presence_callback
|
59
|
+
@model.class.send("_#{@type}_callbacks".to_sym).select do |cb|
|
60
|
+
cb.filter.eql?(@hook.to_sym)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def message_error
|
65
|
+
<<-ERROR
|
66
|
+
expected #{@model} have method callback :
|
67
|
+
set_callback(:#{@type}, :#{@hook}) |document|
|
68
|
+
# My callback execution ...
|
69
|
+
end
|
70
|
+
ERROR
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def set_callback(*args)
|
75
|
+
HaveSetCallbackMatcher.new(*args)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mongoid
|
4
|
+
module Rspec
|
5
|
+
module Callbacks
|
6
|
+
# Define version to gem
|
7
|
+
VERSION = '1.0.0'
|
8
|
+
|
9
|
+
# Name to gem
|
10
|
+
GEM_NAME = 'mongoid7-rspec-callbacks'
|
11
|
+
|
12
|
+
# Authors
|
13
|
+
AUTHORS = ['VAILLANT Jeremy'].freeze
|
14
|
+
|
15
|
+
# Emails
|
16
|
+
EMAILS = ['jeremy@dazzl.tv'].freeze
|
17
|
+
|
18
|
+
# Licence
|
19
|
+
LICENSE = 'GPL-3.0'
|
20
|
+
|
21
|
+
# Define a summary description to gem
|
22
|
+
SUMMARY = 'RSpec Callbacks matchers for Mongoid'
|
23
|
+
|
24
|
+
# Define a long description to gem
|
25
|
+
DESCRIPTION = <<-DESC
|
26
|
+
This gem is meant to be use with mongoid-rpsec,
|
27
|
+
altought it works by itself. Syntax is the same
|
28
|
+
as shoulda-callback-matchers.
|
29
|
+
DESC
|
30
|
+
|
31
|
+
# Define homepage
|
32
|
+
HOMEPAGE = 'http://github.com/dazzl-tv/mongoid-rspec-callbacks'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|