shoulda-matchers 2.6.2 → 2.7.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/Appraisals +6 -1
- data/Gemfile +1 -1
- data/Gemfile.lock +26 -22
- data/NEWS.md +52 -1
- data/README.md +8 -6
- data/Rakefile +1 -1
- data/doc_config/gh-pages/index.html.erb +1 -1
- data/doc_config/yard/templates/default/fulldoc/html/css/global.css +1 -1
- data/doc_config/yard/templates/default/fulldoc/html/css/style.css +26 -0
- data/features/rails_integration.feature +18 -3
- data/features/step_definitions/rails_steps.rb +21 -3
- data/gemfiles/3.0.gemfile +1 -1
- data/gemfiles/3.0.gemfile.lock +30 -24
- data/gemfiles/3.1.gemfile +1 -1
- data/gemfiles/3.1.gemfile.lock +32 -26
- data/gemfiles/3.1_1.9.2.gemfile +1 -1
- data/gemfiles/3.1_1.9.2.gemfile.lock +22 -19
- data/gemfiles/3.2.gemfile +1 -1
- data/gemfiles/3.2.gemfile.lock +32 -26
- data/gemfiles/3.2_1.9.2.gemfile +1 -1
- data/gemfiles/3.2_1.9.2.gemfile.lock +8 -8
- data/gemfiles/4.0.0.gemfile +2 -2
- data/gemfiles/4.0.0.gemfile.lock +35 -31
- data/gemfiles/4.0.1.gemfile +2 -2
- data/gemfiles/4.0.1.gemfile.lock +24 -22
- data/gemfiles/4.1.gemfile +1 -1
- data/gemfiles/4.1.gemfile.lock +26 -22
- data/lib/shoulda/matchers/action_controller/filter_param_matcher.rb +10 -3
- data/lib/shoulda/matchers/action_controller/set_session_matcher.rb +24 -6
- data/lib/shoulda/matchers/active_model.rb +2 -2
- data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +1 -1
- data/lib/shoulda/matchers/active_model/ensure_length_of_matcher.rb +1 -1
- data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +5 -3
- data/lib/shoulda/matchers/active_model/{ensure_exclusion_of_matcher.rb → validate_exclusion_of_matcher.rb} +20 -10
- data/lib/shoulda/matchers/active_model/{ensure_inclusion_of_matcher.rb → validate_inclusion_of_matcher.rb} +52 -28
- data/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb +28 -19
- data/lib/shoulda/matchers/active_record.rb +18 -16
- data/lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb +4 -4
- data/lib/shoulda/matchers/active_record/association_matcher.rb +17 -12
- data/lib/shoulda/matchers/active_record/association_matchers/join_table_matcher.rb +86 -0
- data/lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb +19 -0
- data/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb +2 -1
- data/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb +138 -0
- data/lib/shoulda/matchers/independent.rb +3 -2
- data/lib/shoulda/matchers/independent/{delegate_matcher.rb → delegate_method_matcher.rb} +69 -49
- data/lib/shoulda/matchers/independent/delegate_method_matcher/stubbed_target.rb +37 -0
- data/lib/shoulda/matchers/independent/delegate_method_matcher/target_not_defined_error.rb +15 -0
- data/lib/shoulda/matchers/version.rb +1 -1
- data/lib/shoulda/matchers/warn.rb +30 -2
- data/spec/shoulda/matchers/action_controller/filter_param_matcher_spec.rb +6 -0
- data/spec/shoulda/matchers/action_controller/set_session_matcher_spec.rb +67 -5
- data/spec/shoulda/matchers/action_controller/strong_parameters_matcher_spec.rb +9 -9
- data/spec/shoulda/matchers/active_model/validate_absence_of_matcher_spec.rb +30 -3
- data/spec/shoulda/matchers/active_model/{ensure_exclusion_of_matcher_spec.rb → validate_exclusion_of_matcher_spec.rb} +29 -13
- data/spec/shoulda/matchers/active_model/{ensure_inclusion_of_matcher_spec.rb → validate_inclusion_of_matcher_spec.rb} +34 -16
- data/spec/shoulda/matchers/active_model/validate_uniqueness_of_matcher_spec.rb +35 -0
- data/spec/shoulda/matchers/active_record/association_matcher_spec.rb +56 -1
- data/spec/shoulda/matchers/active_record/define_enum_for_matcher_spec.rb +101 -0
- data/spec/shoulda/matchers/doublespeak/object_double_spec.rb +6 -6
- data/spec/shoulda/matchers/independent/{delegate_matcher → delegate_method_matcher}/stubbed_target_spec.rb +1 -1
- data/spec/shoulda/matchers/independent/{delegate_matcher_spec.rb → delegate_method_matcher_spec.rb} +88 -29
- data/spec/spec_helper.rb +2 -3
- data/spec/support/fail_with_message_including_matcher.rb +14 -3
- data/spec/support/fail_with_message_matcher.rb +14 -2
- data/spec/support/rails_versions.rb +4 -0
- metadata +19 -14
- data/lib/shoulda/matchers/independent/delegate_matcher/stubbed_target.rb +0 -35
@@ -1,19 +1,21 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
11
|
-
require
|
12
|
-
require
|
13
|
-
require
|
14
|
-
require
|
15
|
-
require
|
16
|
-
require
|
1
|
+
require "shoulda/matchers/active_record/association_matcher"
|
2
|
+
require "shoulda/matchers/active_record/association_matchers"
|
3
|
+
require "shoulda/matchers/active_record/association_matchers/counter_cache_matcher"
|
4
|
+
require "shoulda/matchers/active_record/association_matchers/inverse_of_matcher"
|
5
|
+
require "shoulda/matchers/active_record/association_matchers/join_table_matcher"
|
6
|
+
require "shoulda/matchers/active_record/association_matchers/order_matcher"
|
7
|
+
require "shoulda/matchers/active_record/association_matchers/through_matcher"
|
8
|
+
require "shoulda/matchers/active_record/association_matchers/dependent_matcher"
|
9
|
+
require "shoulda/matchers/active_record/association_matchers/source_matcher"
|
10
|
+
require "shoulda/matchers/active_record/association_matchers/model_reflector"
|
11
|
+
require "shoulda/matchers/active_record/association_matchers/model_reflection"
|
12
|
+
require "shoulda/matchers/active_record/association_matchers/option_verifier"
|
13
|
+
require "shoulda/matchers/active_record/have_db_column_matcher"
|
14
|
+
require "shoulda/matchers/active_record/have_db_index_matcher"
|
15
|
+
require "shoulda/matchers/active_record/have_readonly_attribute_matcher"
|
16
|
+
require "shoulda/matchers/active_record/serialize_matcher"
|
17
|
+
require "shoulda/matchers/active_record/accept_nested_attributes_for_matcher"
|
18
|
+
require "shoulda/matchers/active_record/define_enum_for_matcher"
|
17
19
|
|
18
20
|
module Shoulda
|
19
21
|
module Matchers
|
@@ -5,7 +5,7 @@ module Shoulda
|
|
5
5
|
# `accepts_nested_attributes_for` macro.
|
6
6
|
#
|
7
7
|
# class Car < ActiveRecord::Base
|
8
|
-
#
|
8
|
+
# accepts_nested_attributes_for :doors
|
9
9
|
# end
|
10
10
|
#
|
11
11
|
# # RSpec
|
@@ -26,7 +26,7 @@ module Shoulda
|
|
26
26
|
# specified.
|
27
27
|
#
|
28
28
|
# class Car < ActiveRecord::Base
|
29
|
-
#
|
29
|
+
# accepts_nested_attributes_for :mirrors, allow_destroy: true
|
30
30
|
# end
|
31
31
|
#
|
32
32
|
# # RSpec
|
@@ -48,7 +48,7 @@ module Shoulda
|
|
48
48
|
# Use `limit` to assert that the `:limit` option was specified.
|
49
49
|
#
|
50
50
|
# class Car < ActiveRecord::Base
|
51
|
-
#
|
51
|
+
# accepts_nested_attributes_for :windows, limit: 3
|
52
52
|
# end
|
53
53
|
#
|
54
54
|
# # RSpec
|
@@ -71,7 +71,7 @@ module Shoulda
|
|
71
71
|
# specified.
|
72
72
|
#
|
73
73
|
# class Car < ActiveRecord::Base
|
74
|
-
#
|
74
|
+
# accepts_nested_attributes_for :engine, update_only: true
|
75
75
|
# end
|
76
76
|
#
|
77
77
|
# # RSpec
|
@@ -847,9 +847,9 @@ module Shoulda
|
|
847
847
|
(polymorphic? || class_exists?) &&
|
848
848
|
foreign_key_exists? &&
|
849
849
|
class_name_correct? &&
|
850
|
+
join_table_correct? &&
|
850
851
|
autosave_correct? &&
|
851
852
|
conditions_correct? &&
|
852
|
-
join_table_exists? &&
|
853
853
|
validate_correct? &&
|
854
854
|
touch_correct? &&
|
855
855
|
submatchers_match?
|
@@ -889,7 +889,8 @@ module Shoulda
|
|
889
889
|
end
|
890
890
|
|
891
891
|
def missing_options
|
892
|
-
[missing, failing_submatchers.map(&:missing_option)]
|
892
|
+
missing_options = [missing, failing_submatchers.map(&:missing_option)]
|
893
|
+
missing_options.flatten.compact.join(', ')
|
893
894
|
end
|
894
895
|
|
895
896
|
def failing_submatchers
|
@@ -946,6 +947,20 @@ module Shoulda
|
|
946
947
|
end
|
947
948
|
end
|
948
949
|
|
950
|
+
def join_table_correct?
|
951
|
+
if macro != :has_and_belongs_to_many || join_table_matcher.matches?(@subject)
|
952
|
+
true
|
953
|
+
else
|
954
|
+
@missing = join_table_matcher.failure_message
|
955
|
+
false
|
956
|
+
end
|
957
|
+
end
|
958
|
+
|
959
|
+
def join_table_matcher
|
960
|
+
@join_table_matcher ||=
|
961
|
+
AssociationMatchers::JoinTableMatcher.new(self, reflector)
|
962
|
+
end
|
963
|
+
|
949
964
|
def class_exists?
|
950
965
|
associated_class
|
951
966
|
true
|
@@ -980,16 +995,6 @@ module Shoulda
|
|
980
995
|
end
|
981
996
|
end
|
982
997
|
|
983
|
-
def join_table_exists?
|
984
|
-
if macro != :has_and_belongs_to_many ||
|
985
|
-
model_class.connection.tables.include?(join_table)
|
986
|
-
true
|
987
|
-
else
|
988
|
-
@missing = "join table #{join_table} doesn't exist"
|
989
|
-
false
|
990
|
-
end
|
991
|
-
end
|
992
|
-
|
993
998
|
def validate_correct?
|
994
999
|
if option_verifier.correct_for_boolean?(:validate, options[:validate])
|
995
1000
|
true
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module Shoulda
|
2
|
+
module Matchers
|
3
|
+
module ActiveRecord
|
4
|
+
module AssociationMatchers
|
5
|
+
# @private
|
6
|
+
class JoinTableMatcher
|
7
|
+
attr_reader :failure_message
|
8
|
+
|
9
|
+
alias :missing_option :failure_message
|
10
|
+
|
11
|
+
delegate :model_class, :join_table, :associated_class,
|
12
|
+
to: :association_matcher
|
13
|
+
|
14
|
+
delegate :connection, to: :model_class
|
15
|
+
|
16
|
+
def initialize(association_matcher, reflector)
|
17
|
+
@association_matcher = association_matcher
|
18
|
+
@reflector = reflector
|
19
|
+
end
|
20
|
+
|
21
|
+
def matches?(subject)
|
22
|
+
join_table_exists? &&
|
23
|
+
join_table_has_correct_columns?
|
24
|
+
end
|
25
|
+
|
26
|
+
def join_table_exists?
|
27
|
+
if connection.tables.include?(join_table)
|
28
|
+
true
|
29
|
+
else
|
30
|
+
@failure_message = missing_table_message
|
31
|
+
false
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def join_table_has_correct_columns?
|
36
|
+
if missing_columns.empty?
|
37
|
+
true
|
38
|
+
else
|
39
|
+
@failure_message = missing_columns_message
|
40
|
+
false
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
protected
|
45
|
+
|
46
|
+
attr_reader :association_matcher, :reflector
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
delegate :foreign_key, :association_foreign_key, to: :reflector
|
51
|
+
|
52
|
+
def missing_columns
|
53
|
+
@missing_columns ||= expected_join_table_columns.select do |key|
|
54
|
+
!actual_join_table_columns.include?(key)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def expected_join_table_columns
|
59
|
+
[foreign_key, association_foreign_key]
|
60
|
+
end
|
61
|
+
|
62
|
+
def actual_join_table_columns
|
63
|
+
connection.columns(join_table).map(&:name)
|
64
|
+
end
|
65
|
+
|
66
|
+
def missing_table_message
|
67
|
+
"join table #{join_table} doesn't exist"
|
68
|
+
end
|
69
|
+
|
70
|
+
def missing_columns_message
|
71
|
+
missing = missing_columns.join(', ')
|
72
|
+
"join table #{join_table} missing #{column_label}: #{missing}"
|
73
|
+
end
|
74
|
+
|
75
|
+
def column_label
|
76
|
+
if missing_columns.count > 1
|
77
|
+
'columns'
|
78
|
+
else
|
79
|
+
'column'
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -45,6 +45,25 @@ module Shoulda
|
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
|
+
def foreign_key
|
49
|
+
if has_and_belongs_to_many_reflection
|
50
|
+
has_and_belongs_to_many_reflection.foreign_key
|
51
|
+
elsif reflection.respond_to?(:primary_key_name)
|
52
|
+
reflection.primary_key_name
|
53
|
+
else
|
54
|
+
reflection.foreign_key
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def association_foreign_key
|
59
|
+
if has_and_belongs_to_many_reflection
|
60
|
+
join_model = has_and_belongs_to_many_reflection.options[:class]
|
61
|
+
join_model.right_reflection.foreign_key
|
62
|
+
else
|
63
|
+
reflection.association_foreign_key
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
48
67
|
protected
|
49
68
|
|
50
69
|
attr_reader :reflection, :subject
|
@@ -5,7 +5,8 @@ module Shoulda
|
|
5
5
|
# @private
|
6
6
|
class ModelReflector
|
7
7
|
delegate :associated_class, :through?, :join_table,
|
8
|
-
:association_relation, :polymorphic?,
|
8
|
+
:association_relation, :polymorphic?, :foreign_key,
|
9
|
+
:association_foreign_key, to: :reflection
|
9
10
|
|
10
11
|
def initialize(subject, name)
|
11
12
|
@subject = subject
|
@@ -0,0 +1,138 @@
|
|
1
|
+
module Shoulda
|
2
|
+
module Matchers
|
3
|
+
module ActiveRecord
|
4
|
+
# The `define_enum_for` matcher is used to test that the `enum` macro has
|
5
|
+
# been used to decorate an attribute with enum methods.
|
6
|
+
#
|
7
|
+
# class Process < ActiveRecord::Base
|
8
|
+
# enum status: [:running, :stopped, :suspended]
|
9
|
+
# end
|
10
|
+
#
|
11
|
+
# # RSpec
|
12
|
+
# describe Process do
|
13
|
+
# it { should define_enum_for(:status) }
|
14
|
+
# end
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# # Test::Unit
|
18
|
+
# class ProcessTest < ActiveSupport::TestCase
|
19
|
+
# should define_enum_for(:status)
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# #### Qualifiers
|
23
|
+
#
|
24
|
+
# ##### with
|
25
|
+
#
|
26
|
+
# Use `with` to test that the enum has been defined with a certain set of
|
27
|
+
# known values.
|
28
|
+
#
|
29
|
+
# class Process < ActiveRecord::Base
|
30
|
+
# enum status: [:running, :stopped, :suspended]
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# # RSpec
|
34
|
+
# describe Process do
|
35
|
+
# it do
|
36
|
+
# should define_enum_for(:status).
|
37
|
+
# with([:running, :stopped, :suspended])
|
38
|
+
# end
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
# # Test::Unit
|
42
|
+
# class ProcessTest < ActiveSupport::TestCase
|
43
|
+
# should define_enum_for(:status).
|
44
|
+
# with([:running, :stopped, :suspended])
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# @return [DefineEnumForMatcher]
|
48
|
+
#
|
49
|
+
def define_enum_for(attribute_name)
|
50
|
+
DefineEnumForMatcher.new(attribute_name)
|
51
|
+
end
|
52
|
+
|
53
|
+
# @private
|
54
|
+
class DefineEnumForMatcher
|
55
|
+
def initialize(attribute_name)
|
56
|
+
@attribute_name = attribute_name
|
57
|
+
@options = {}
|
58
|
+
end
|
59
|
+
|
60
|
+
def with(expected_enum_values)
|
61
|
+
options[:expected_enum_values] = expected_enum_values
|
62
|
+
self
|
63
|
+
end
|
64
|
+
|
65
|
+
def matches?(subject)
|
66
|
+
@model = subject
|
67
|
+
enum_defined? && enum_values_match?
|
68
|
+
end
|
69
|
+
|
70
|
+
def failure_message
|
71
|
+
"Expected #{expectation}"
|
72
|
+
end
|
73
|
+
alias :failure_message_for_should :failure_message
|
74
|
+
|
75
|
+
def failure_message_when_negated
|
76
|
+
"Did not expect #{expectation}"
|
77
|
+
end
|
78
|
+
alias :failure_message_for_should_not :failure_message_when_negated
|
79
|
+
|
80
|
+
def description
|
81
|
+
desc = "define :#{attribute_name} as an enum"
|
82
|
+
|
83
|
+
if options[:expected_enum_values]
|
84
|
+
desc << " with #{options[:expected_enum_values]}"
|
85
|
+
end
|
86
|
+
|
87
|
+
desc
|
88
|
+
end
|
89
|
+
|
90
|
+
protected
|
91
|
+
|
92
|
+
attr_reader :model, :attribute_name, :options
|
93
|
+
|
94
|
+
def expectation
|
95
|
+
"#{model.class.name} to #{description}"
|
96
|
+
end
|
97
|
+
|
98
|
+
def expected_enum_values
|
99
|
+
hashify(options[:expected_enum_values]).with_indifferent_access
|
100
|
+
end
|
101
|
+
|
102
|
+
def enum_method
|
103
|
+
attribute_name.to_s.pluralize
|
104
|
+
end
|
105
|
+
|
106
|
+
def actual_enum_values
|
107
|
+
model.class.send(enum_method)
|
108
|
+
end
|
109
|
+
|
110
|
+
def enum_defined?
|
111
|
+
model.class.respond_to?(enum_method)
|
112
|
+
end
|
113
|
+
|
114
|
+
def enum_values_match?
|
115
|
+
expected_enum_values.empty? || actual_enum_values == expected_enum_values
|
116
|
+
end
|
117
|
+
|
118
|
+
def hashify(value)
|
119
|
+
if value.nil?
|
120
|
+
return {}
|
121
|
+
end
|
122
|
+
|
123
|
+
if value.is_a?(Array)
|
124
|
+
new_value = {}
|
125
|
+
|
126
|
+
value.each_with_index do |v, i|
|
127
|
+
new_value[v] = i
|
128
|
+
end
|
129
|
+
|
130
|
+
new_value
|
131
|
+
else
|
132
|
+
value
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
@@ -1,5 +1,6 @@
|
|
1
|
-
require 'shoulda/matchers/independent/
|
2
|
-
require 'shoulda/matchers/independent/
|
1
|
+
require 'shoulda/matchers/independent/delegate_method_matcher'
|
2
|
+
require 'shoulda/matchers/independent/delegate_method_matcher/stubbed_target'
|
3
|
+
require 'shoulda/matchers/independent/delegate_method_matcher/target_not_defined_error'
|
3
4
|
|
4
5
|
module Shoulda
|
5
6
|
module Matchers
|
@@ -70,10 +70,12 @@ module Shoulda
|
|
70
70
|
# ##### with_arguments
|
71
71
|
#
|
72
72
|
# Use `with_arguments` to assert that the delegate method is called with
|
73
|
-
# certain arguments.
|
73
|
+
# certain arguments. Note that this qualifier can only be used when the
|
74
|
+
# delegating method takes no arguments; it does not support delegating
|
75
|
+
# or delegate methods that take arbitrary arguments.
|
74
76
|
#
|
75
|
-
# Here, when Courier#
|
76
|
-
# hash:
|
77
|
+
# Here, when Courier#deliver_package calls PostOffice#deliver_package, it
|
78
|
+
# adds an options hash:
|
77
79
|
#
|
78
80
|
# class Courier
|
79
81
|
# attr_reader :post_office
|
@@ -82,39 +84,39 @@ module Shoulda
|
|
82
84
|
# @post_office = PostOffice.new
|
83
85
|
# end
|
84
86
|
#
|
85
|
-
# def
|
86
|
-
# post_office.
|
87
|
+
# def deliver_package
|
88
|
+
# post_office.deliver_package(expedited: true)
|
87
89
|
# end
|
88
90
|
# end
|
89
91
|
#
|
90
92
|
# # RSpec
|
91
93
|
# describe Courier do
|
92
94
|
# it do
|
93
|
-
# should delegate_method(:
|
95
|
+
# should delegate_method(:deliver_package).
|
94
96
|
# to(:post_office).
|
95
|
-
# as(:ship).
|
96
97
|
# with_arguments(expedited: true)
|
97
98
|
# end
|
98
99
|
# end
|
99
100
|
#
|
100
101
|
# # Test::Unit
|
101
102
|
# class CourierTest < Test::Unit::TestCase
|
102
|
-
# should delegate_method(:
|
103
|
+
# should delegate_method(:deliver_package).
|
103
104
|
# to(:post_office).
|
104
|
-
# as(:ship).
|
105
105
|
# with_arguments(expedited: true)
|
106
106
|
# end
|
107
107
|
#
|
108
|
-
# @return [
|
108
|
+
# @return [DelegateMethodMatcher]
|
109
109
|
#
|
110
110
|
def delegate_method(delegating_method)
|
111
|
-
|
111
|
+
DelegateMethodMatcher.new(delegating_method, self)
|
112
112
|
end
|
113
113
|
|
114
114
|
# @private
|
115
|
-
class
|
116
|
-
def initialize(delegating_method)
|
115
|
+
class DelegateMethodMatcher
|
116
|
+
def initialize(delegating_method, context)
|
117
117
|
@delegating_method = delegating_method
|
118
|
+
@context = context
|
119
|
+
|
118
120
|
@method_on_target = @delegating_method
|
119
121
|
@target_double = Doublespeak::ObjectDouble.new
|
120
122
|
|
@@ -135,9 +137,18 @@ module Shoulda
|
|
135
137
|
end
|
136
138
|
|
137
139
|
def description
|
138
|
-
|
139
|
-
"
|
140
|
-
|
140
|
+
string = "delegate #{formatted_delegating_method_name} to " +
|
141
|
+
"#{formatted_target_method_name} object"
|
142
|
+
|
143
|
+
if delegated_arguments.any?
|
144
|
+
string << " passing arguments #{delegated_arguments.inspect}"
|
145
|
+
end
|
146
|
+
|
147
|
+
if method_on_target != delegating_method
|
148
|
+
string << " as #{formatted_method_on_target}"
|
149
|
+
end
|
150
|
+
|
151
|
+
string
|
141
152
|
end
|
142
153
|
|
143
154
|
def to(target_method)
|
@@ -156,58 +167,73 @@ module Shoulda
|
|
156
167
|
end
|
157
168
|
|
158
169
|
def failure_message
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
base.strip
|
170
|
+
"Expected #{class_under_test} to #{description}\n" +
|
171
|
+
"Method calls sent to " +
|
172
|
+
"#{formatted_target_method_name(include_module: true)}:" +
|
173
|
+
formatted_calls_on_target
|
164
174
|
end
|
165
175
|
alias failure_message_for_should failure_message
|
166
176
|
|
167
177
|
def failure_message_when_negated
|
168
|
-
|
169
|
-
add_clarifications_to(base)
|
170
|
-
base << ', but it did'
|
178
|
+
"Expected #{class_under_test} not to #{description}, but it did"
|
171
179
|
end
|
172
180
|
alias failure_message_for_should_not failure_message_when_negated
|
173
181
|
|
174
182
|
protected
|
175
183
|
|
176
184
|
attr_reader \
|
185
|
+
:context,
|
177
186
|
:delegated_arguments,
|
178
187
|
:delegating_method,
|
179
188
|
:method,
|
180
189
|
:method_on_target,
|
181
|
-
:subject,
|
182
190
|
:subject_double_collection,
|
183
191
|
:target_double,
|
184
192
|
:target_method
|
185
193
|
|
186
|
-
def
|
187
|
-
|
188
|
-
|
189
|
-
end
|
194
|
+
def subject
|
195
|
+
@subject || context.subject
|
196
|
+
end
|
190
197
|
|
191
|
-
|
192
|
-
|
198
|
+
def class_under_test
|
199
|
+
if subject.is_a?(Class)
|
200
|
+
subject
|
201
|
+
else
|
202
|
+
subject.class
|
193
203
|
end
|
204
|
+
end
|
194
205
|
|
195
|
-
|
206
|
+
def formatted_method_on_target(options = {})
|
207
|
+
formatted_method_name_for(method_on_target, options)
|
196
208
|
end
|
197
209
|
|
198
|
-
def formatted_delegating_method_name
|
199
|
-
formatted_method_name_for(delegating_method)
|
210
|
+
def formatted_delegating_method_name(options = {})
|
211
|
+
formatted_method_name_for(delegating_method, options)
|
200
212
|
end
|
201
213
|
|
202
|
-
def formatted_target_method_name
|
203
|
-
formatted_method_name_for(target_method)
|
214
|
+
def formatted_target_method_name(options = {})
|
215
|
+
formatted_method_name_for(target_method, options)
|
204
216
|
end
|
205
217
|
|
206
|
-
def formatted_method_name_for(method_name)
|
218
|
+
def formatted_method_name_for(method_name, options)
|
219
|
+
possible_class_under_test(options) +
|
220
|
+
class_or_instance_method_indicator +
|
221
|
+
method_name.to_s
|
222
|
+
end
|
223
|
+
|
224
|
+
def possible_class_under_test(options)
|
225
|
+
if options[:include_module]
|
226
|
+
class_under_test.to_s
|
227
|
+
else
|
228
|
+
""
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
def class_or_instance_method_indicator
|
207
233
|
if subject.is_a?(Class)
|
208
|
-
|
234
|
+
'.'
|
209
235
|
else
|
210
|
-
|
236
|
+
'#'
|
211
237
|
end
|
212
238
|
end
|
213
239
|
|
@@ -226,11 +252,11 @@ module Shoulda
|
|
226
252
|
end
|
227
253
|
|
228
254
|
def subject_has_target_method?
|
229
|
-
subject.respond_to?(target_method)
|
255
|
+
subject.respond_to?(target_method, true)
|
230
256
|
end
|
231
257
|
|
232
258
|
def ensure_target_method_is_present!
|
233
|
-
if target_method.
|
259
|
+
if target_method.to_s.empty?
|
234
260
|
raise TargetNotDefinedError
|
235
261
|
end
|
236
262
|
end
|
@@ -280,15 +306,9 @@ module Shoulda
|
|
280
306
|
string << " (none)"
|
281
307
|
end
|
282
308
|
|
283
|
-
string
|
284
|
-
end
|
309
|
+
string.rstrip!
|
285
310
|
|
286
|
-
|
287
|
-
class TargetNotDefinedError < StandardError
|
288
|
-
def message
|
289
|
-
'Delegation needs a target. Use the #to method to define one, e.g.
|
290
|
-
`post_office.should delegate(:deliver_mail).to(:mailman)`'.squish
|
291
|
-
end
|
311
|
+
string
|
292
312
|
end
|
293
313
|
end
|
294
314
|
end
|