mongoid7-rspec-callbacks 1.0.0.pre.816289031
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![RSpec](https://github.com/dazzl-tv/mongoid-rspec-callbacks/actions/workflows/rspec.yml/badge.svg?branch=develop&event=pull_request)](https://github.com/dazzl-tv/mongoid-rspec-callbacks/actions/workflows/rspec.yml)
|
3
|
+
[![Linter](https://github.com/dazzl-tv/mongoid-rspec-callbacks/actions/workflows/linter.yml/badge.svg)](https://github.com/dazzl-tv/mongoid-rspec-callbacks/actions/workflows/linter.yml)
|
4
|
+
[![Gem Version](https://badge.fury.io/rb/mongoid-rspec-callbacks.svg)](https://badge.fury.io/rb/mongoid-rspec-callbacks)
|
5
|
+
[![Docs](https://inch-ci.org/github/dazzl-tv/mongoid-rspec-callbacks.svg)](https://inch-ci.org/github/dazzl-tv/mongoid-rspec-callbacks)
|
6
|
+
[![Maintainability](https://api.codeclimate.com/v1/badges/2538546ea7419c1d5ea1/maintainability)](https://codeclimate.com/github/dazzl-tv/mongoid-rspec-callbacks/maintainability)
|
7
|
+
[![Test Coverage](https://api.codeclimate.com/v1/badges/2538546ea7419c1d5ea1/test_coverage)](https://codeclimate.com/github/dazzl-tv/mongoid-rspec-callbacks/test_coverage)
|
8
|
+
[![Known Vulnerabilities](https://snyk.io/test/github/dazzl-tv/mongoid-rspec-callbacks/badge.svg)](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
|