shoulda-matchers 2.6.2 → 2.7.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|