shoulda-matchers 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. data/.gitignore +11 -0
  2. data/.travis.yml +13 -0
  3. data/Appraisals +4 -6
  4. data/CONTRIBUTING.md +38 -0
  5. data/Gemfile +8 -5
  6. data/Gemfile.lock +77 -41
  7. data/NEWS.md +32 -0
  8. data/README.md +84 -0
  9. data/Rakefile +5 -36
  10. data/features/rails_integration.feature +88 -0
  11. data/features/step_definitions/rails_steps.rb +111 -0
  12. data/features/support/env.rb +5 -0
  13. data/gemfiles/3.0.gemfile +14 -0
  14. data/gemfiles/3.0.gemfile.lock +142 -0
  15. data/gemfiles/3.1.gemfile +16 -0
  16. data/gemfiles/3.1.gemfile.lock +164 -0
  17. data/lib/shoulda/matchers/action_controller/assign_to_matcher.rb +6 -9
  18. data/lib/shoulda/matchers/action_controller/filter_param_matcher.rb +1 -3
  19. data/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb +10 -6
  20. data/lib/shoulda/matchers/action_controller/render_template_matcher.rb +1 -4
  21. data/lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb +6 -6
  22. data/lib/shoulda/matchers/action_controller/respond_with_content_type_matcher.rb +11 -10
  23. data/lib/shoulda/matchers/action_controller/respond_with_matcher.rb +0 -2
  24. data/lib/shoulda/matchers/action_controller/route_matcher.rb +17 -14
  25. data/lib/shoulda/matchers/action_controller/set_session_matcher.rb +24 -16
  26. data/lib/shoulda/matchers/action_controller/set_the_flash_matcher.rb +52 -15
  27. data/lib/shoulda/matchers/action_mailer.rb +1 -1
  28. data/lib/shoulda/matchers/action_mailer/{have_sent_email.rb → have_sent_email_matcher.rb} +37 -21
  29. data/lib/shoulda/matchers/active_model.rb +1 -0
  30. data/lib/shoulda/matchers/active_model/allow_mass_assignment_of_matcher.rb +9 -10
  31. data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +60 -33
  32. data/lib/shoulda/matchers/active_model/ensure_length_of_matcher.rb +0 -1
  33. data/lib/shoulda/matchers/active_model/helpers.rb +13 -9
  34. data/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb +63 -0
  35. data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +38 -8
  36. data/lib/shoulda/matchers/active_model/validation_matcher.rb +1 -5
  37. data/lib/shoulda/matchers/active_record.rb +3 -1
  38. data/lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb +127 -0
  39. data/lib/shoulda/matchers/active_record/association_matcher.rb +19 -7
  40. data/lib/shoulda/matchers/active_record/have_db_column_matcher.rb +20 -5
  41. data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +4 -10
  42. data/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb +3 -7
  43. data/lib/shoulda/matchers/active_record/query_the_database_matcher.rb +107 -0
  44. data/lib/shoulda/matchers/active_record/serialize_matcher.rb +111 -0
  45. data/lib/shoulda/matchers/integrations/rspec.rb +0 -1
  46. data/lib/shoulda/matchers/version.rb +1 -1
  47. data/shoulda-matchers.gemspec +30 -0
  48. data/spec/fixtures/addresses.yml +3 -0
  49. data/spec/fixtures/friendships.yml +0 -0
  50. data/spec/fixtures/posts.yml +5 -0
  51. data/spec/fixtures/products.yml +0 -0
  52. data/spec/fixtures/taggings.yml +0 -0
  53. data/spec/fixtures/tags.yml +9 -0
  54. data/spec/fixtures/users.yml +6 -0
  55. data/spec/shoulda/action_controller/assign_to_matcher_spec.rb +61 -0
  56. data/spec/shoulda/action_controller/filter_param_matcher_spec.rb +20 -0
  57. data/spec/shoulda/action_controller/redirect_to_matcher_spec.rb +40 -0
  58. data/spec/shoulda/action_controller/render_template_matcher_spec.rb +69 -0
  59. data/spec/shoulda/action_controller/render_with_layout_matcher_spec.rb +47 -0
  60. data/spec/shoulda/action_controller/respond_with_content_type_matcher_spec.rb +28 -0
  61. data/spec/shoulda/action_controller/respond_with_matcher_spec.rb +83 -0
  62. data/spec/shoulda/action_controller/route_matcher_spec.rb +65 -0
  63. data/spec/shoulda/action_controller/set_session_matcher_spec.rb +46 -0
  64. data/spec/shoulda/action_controller/set_the_flash_matcher_spec.rb +124 -0
  65. data/spec/shoulda/action_mailer/have_sent_email_spec.rb +293 -0
  66. data/spec/shoulda/active_model/allow_mass_assignment_of_matcher_spec.rb +95 -0
  67. data/spec/shoulda/active_model/allow_value_matcher_spec.rb +91 -0
  68. data/spec/shoulda/active_model/ensure_exclusion_of_matcher_spec.rb +57 -0
  69. data/spec/shoulda/active_model/ensure_inclusion_of_matcher_spec.rb +71 -0
  70. data/spec/shoulda/active_model/ensure_length_of_matcher_spec.rb +125 -0
  71. data/spec/shoulda/active_model/helpers_spec.rb +100 -0
  72. data/spec/shoulda/active_model/validate_acceptance_of_matcher_spec.rb +43 -0
  73. data/spec/shoulda/active_model/validate_confirmation_of_matcher_spec.rb +48 -0
  74. data/spec/shoulda/active_model/validate_format_of_matcher_spec.rb +38 -0
  75. data/spec/shoulda/active_model/validate_numericality_of_matcher_spec.rb +62 -0
  76. data/spec/shoulda/active_model/validate_presence_of_matcher_spec.rb +121 -0
  77. data/spec/shoulda/active_model/validate_uniqueness_of_matcher_spec.rb +143 -0
  78. data/spec/shoulda/active_record/accept_nested_attributes_for_matcher_spec.rb +84 -0
  79. data/spec/shoulda/active_record/association_matcher_spec.rb +449 -0
  80. data/spec/shoulda/active_record/have_db_column_matcher_spec.rb +185 -0
  81. data/spec/shoulda/active_record/have_db_index_matcher_spec.rb +88 -0
  82. data/spec/shoulda/active_record/have_readonly_attributes_matcher_spec.rb +46 -0
  83. data/spec/shoulda/active_record/query_the_database_matcher_spec.rb +45 -0
  84. data/spec/shoulda/active_record/serialize_matcher_spec.rb +81 -0
  85. data/spec/spec_helper.rb +31 -0
  86. data/spec/support/model_builder.rb +149 -0
  87. metadata +211 -60
  88. data/CONTRIBUTION_GUIDELINES.rdoc +0 -10
  89. data/README.rdoc +0 -80
@@ -20,6 +20,7 @@ module Shoulda # :nodoc:
20
20
  end
21
21
 
22
22
  class AssignToMatcher # :nodoc:
23
+ attr_reader :failure_message, :negative_failure_message
23
24
 
24
25
  def initialize(variable)
25
26
  @variable = variable.to_s
@@ -44,8 +45,6 @@ module Shoulda # :nodoc:
44
45
  assigned_value? && kind_of_expected_class? && equal_to_expected_value?
45
46
  end
46
47
 
47
- attr_reader :failure_message, :negative_failure_message
48
-
49
48
  def description
50
49
  description = "assign @#{@variable}"
51
50
  description << " with a kind of #{@expected_class}" if @expected_class
@@ -60,15 +59,15 @@ module Shoulda # :nodoc:
60
59
  private
61
60
 
62
61
  def assigned_value?
63
- if !@controller.instance_variables.map(&:to_s).include?("@#{@variable}")
64
- @failure_message =
65
- "Expected action to assign a value for @#{@variable}"
66
- false
67
- else
62
+ if @controller.instance_variables.map(&:to_s).include?("@#{@variable}")
68
63
  @negative_failure_message =
69
64
  "Didn't expect action to assign a value for @#{@variable}, " <<
70
65
  "but it was assigned to #{assigned_value.inspect}"
71
66
  true
67
+ else
68
+ @failure_message =
69
+ "Expected action to assign a value for @#{@variable}"
70
+ false
72
71
  end
73
72
  end
74
73
 
@@ -106,9 +105,7 @@ module Shoulda # :nodoc:
106
105
  def assigned_value
107
106
  @controller.instance_variable_get("@#{@variable}")
108
107
  end
109
-
110
108
  end
111
-
112
109
  end
113
110
  end
114
111
  end
@@ -12,7 +12,6 @@ module Shoulda # :nodoc:
12
12
  end
13
13
 
14
14
  class FilterParamMatcher # :nodoc:
15
-
16
15
  def initialize(key)
17
16
  @key = key.to_s
18
17
  end
@@ -41,10 +40,9 @@ module Shoulda # :nodoc:
41
40
  end
42
41
 
43
42
  def filtered_keys
44
- Rails.application.config.filter_parameters.map { |filter| filter.to_s }
43
+ Rails.application.config.filter_parameters.map(&:to_s)
45
44
  end
46
45
  end
47
-
48
46
  end
49
47
  end
50
48
  end
@@ -13,6 +13,7 @@ module Shoulda # :nodoc:
13
13
  end
14
14
 
15
15
  class RedirectToMatcher # :nodoc:
16
+ attr_reader :failure_message, :negative_failure_message
16
17
 
17
18
  def initialize(url_or_description, context, &block)
18
19
  if block
@@ -35,8 +36,6 @@ module Shoulda # :nodoc:
35
36
  redirects_to_url?
36
37
  end
37
38
 
38
- attr_reader :failure_message, :negative_failure_message
39
-
40
39
  def description
41
40
  "redirect to #{@location}"
42
41
  end
@@ -44,10 +43,9 @@ module Shoulda # :nodoc:
44
43
  private
45
44
 
46
45
  def redirects_to_url?
47
- @url = @context.instance_eval(&@url_block) if @url_block
48
46
  begin
49
- @context.send(:assert_redirected_to, @url)
50
- @negative_failure_message = "Didn't expect to redirect to #{@url}"
47
+ @context.send(:assert_redirected_to, url)
48
+ @negative_failure_message = "Didn't expect to redirect to #{url}"
51
49
  true
52
50
  rescue Shoulda::Matchers::AssertionError => error
53
51
  @failure_message = error.message
@@ -55,8 +53,14 @@ module Shoulda # :nodoc:
55
53
  end
56
54
  end
57
55
 
56
+ def url
57
+ if @url_block
58
+ @context.instance_eval(&@url_block)
59
+ else
60
+ @url
61
+ end
62
+ end
58
63
  end
59
-
60
64
  end
61
65
  end
62
66
  end
@@ -21,6 +21,7 @@ module Shoulda # :nodoc:
21
21
  end
22
22
 
23
23
  class RenderTemplateMatcher # :nodoc:
24
+ attr_reader :failure_message, :negative_failure_message
24
25
 
25
26
  def initialize(options, message, context)
26
27
  @options = options
@@ -34,8 +35,6 @@ module Shoulda # :nodoc:
34
35
  renders_template?
35
36
  end
36
37
 
37
- attr_reader :failure_message, :negative_failure_message
38
-
39
38
  def description
40
39
  "render template #{@template}"
41
40
  end
@@ -57,9 +56,7 @@ module Shoulda # :nodoc:
57
56
  false
58
57
  end
59
58
  end
60
-
61
59
  end
62
-
63
60
  end
64
61
  end
65
62
  end
@@ -56,8 +56,11 @@ module Shoulda # :nodoc:
56
56
  end
57
57
 
58
58
  def rendered_with_expected_layout?
59
- return true if @expected_layout.nil?
60
- rendered_layouts.include?(@expected_layout)
59
+ if @expected_layout.nil?
60
+ true
61
+ else
62
+ rendered_layouts.include?(@expected_layout)
63
+ end
61
64
  end
62
65
 
63
66
  def rendered_layouts
@@ -85,15 +88,12 @@ module Shoulda # :nodoc:
85
88
 
86
89
  def result
87
90
  if rendered_with_layout?
88
- "rendered with " <<
89
- rendered_layouts.map { |layout| layout.inspect }.join(", ")
91
+ "rendered with " + rendered_layouts.map(&:inspect).join(", ")
90
92
  else
91
93
  "rendered without a layout"
92
94
  end
93
95
  end
94
-
95
96
  end
96
-
97
97
  end
98
98
  end
99
99
  end
@@ -22,13 +22,8 @@ module Shoulda # :nodoc:
22
22
  end
23
23
 
24
24
  class RespondWithContentTypeMatcher # :nodoc:
25
-
26
25
  def initialize(content_type)
27
- @content_type = if content_type.is_a?(Symbol)
28
- lookup_by_extension(content_type)
29
- else
30
- content_type
31
- end
26
+ @content_type = look_up_content_type(content_type)
32
27
  end
33
28
 
34
29
  def description
@@ -58,17 +53,23 @@ module Shoulda # :nodoc:
58
53
  @controller.response.content_type.to_s
59
54
  end
60
55
 
61
- def lookup_by_extension(extension)
56
+ def look_up_by_extension(extension)
62
57
  Mime::Type.lookup_by_extension(extension.to_s).to_s
63
58
  end
64
59
 
60
+ def look_up_content_type(content_type)
61
+ if content_type.is_a?(Symbol)
62
+ look_up_by_extension(content_type)
63
+ else
64
+ content_type
65
+ end
66
+ end
67
+
65
68
  def expectation
66
69
  "content type to be #{@content_type}, " <<
67
- "but was #{response_content_type}"
70
+ "but was #{response_content_type}"
68
71
  end
69
-
70
72
  end
71
-
72
73
  end
73
74
  end
74
75
  end
@@ -77,9 +77,7 @@ module Shoulda # :nodoc:
77
77
  def expectation
78
78
  "response to be a #{@status}, but was #{response_code}"
79
79
  end
80
-
81
80
  end
82
-
83
81
  end
84
82
  end
85
83
  end
@@ -27,16 +27,16 @@ module Shoulda # :nodoc:
27
27
  end
28
28
 
29
29
  class RouteMatcher # :nodoc:
30
-
31
30
  def initialize(method, path, context)
32
31
  @method = method
33
32
  @path = path
34
33
  @context = context
35
34
  end
36
35
 
36
+ attr_reader :failure_message, :negative_failure_message
37
+
37
38
  def to(params)
38
- @params = params
39
- stringify_params!
39
+ @params = stringify_params(params)
40
40
  self
41
41
  end
42
42
 
@@ -46,26 +46,31 @@ module Shoulda # :nodoc:
46
46
  end
47
47
 
48
48
  def matches?(controller)
49
- @controller = controller
50
- guess_controller!
49
+ guess_controller!(controller)
51
50
  route_recognized?
52
51
  end
53
52
 
54
- attr_reader :failure_message, :negative_failure_message
55
-
56
53
  def description
57
54
  "route #{@method.to_s.upcase} #{@path} to/from #{@params.inspect}"
58
55
  end
59
56
 
60
57
  private
61
58
 
62
- def guess_controller!
63
- @params[:controller] ||= @controller.controller_path
59
+ def guess_controller!(controller)
60
+ @params[:controller] ||= controller.controller_path
64
61
  end
65
62
 
66
- def stringify_params!
67
- @params.each do |key, value|
68
- @params[key] = value.is_a?(Array) ? value.collect {|v| v.to_param } : value.to_param
63
+ def stringify_params(params)
64
+ params.each do |key, value|
65
+ params[key] = stringify(value)
66
+ end
67
+ end
68
+
69
+ def stringify(value)
70
+ if value.is_a?(Array)
71
+ value.map(&:to_param)
72
+ else
73
+ value.to_param
69
74
  end
70
75
  end
71
76
 
@@ -85,9 +90,7 @@ module Shoulda # :nodoc:
85
90
  false
86
91
  end
87
92
  end
88
-
89
93
  end
90
-
91
94
  end
92
95
  end
93
96
  end
@@ -14,7 +14,6 @@ module Shoulda # :nodoc:
14
14
  end
15
15
 
16
16
  class SetSessionMatcher # :nodoc:
17
-
18
17
  def initialize(key)
19
18
  @key = key.to_s
20
19
  end
@@ -27,8 +26,10 @@ module Shoulda # :nodoc:
27
26
 
28
27
  def matches?(controller)
29
28
  @controller = controller
30
- @value = @context.instance_eval(&@value_block) if @value_block
31
- (assigned_value? && assigned_correct_value?) || cleared_value?
29
+ if @value_block
30
+ @value = @context.instance_eval(&@value_block)
31
+ end
32
+ assigned_correct_value? || cleared_value?
32
33
  end
33
34
 
34
35
  def failure_message
@@ -41,7 +42,9 @@ module Shoulda # :nodoc:
41
42
 
42
43
  def description
43
44
  description = "set session variable #{@key.inspect}"
44
- description << " to #{@value.inspect}" if defined?(@value)
45
+ if @value
46
+ description << " to #{@value.inspect}"
47
+ end
45
48
  description
46
49
  end
47
50
 
@@ -61,25 +64,24 @@ module Shoulda # :nodoc:
61
64
  end
62
65
 
63
66
  def assigned_correct_value?
64
- return true if @value.nil?
65
- assigned_value == @value
67
+ if assigned_value?
68
+ if @value.nil?
69
+ true
70
+ else
71
+ assigned_value == @value
72
+ end
73
+ end
66
74
  end
67
75
 
68
76
  def assigned_value
69
77
  session[@key]
70
78
  end
71
79
 
72
- def session
73
- if @controller.request.respond_to?(:session)
74
- @controller.request.session.to_hash
75
- else
76
- @controller.response.session.data
77
- end
78
- end
79
-
80
80
  def expectation
81
81
  expectation = "session variable #{@key} to be set"
82
- expectation << " to #{@value.inspect}" if @value
82
+ if @value
83
+ expectation << " to #{@value.inspect}"
84
+ end
83
85
  expectation
84
86
  end
85
87
 
@@ -91,8 +93,14 @@ module Shoulda # :nodoc:
91
93
  end
92
94
  end
93
95
 
96
+ def session
97
+ if @controller.request.respond_to?(:session)
98
+ @controller.request.session.to_hash
99
+ else
100
+ @controller.response.session.data
101
+ end
102
+ end
94
103
  end
95
-
96
104
  end
97
105
  end
98
106
  end
@@ -10,6 +10,7 @@ module Shoulda # :nodoc:
10
10
  # it { should set_the_flash }
11
11
  # it { should set_the_flash.to("Thank you for placing this order.") }
12
12
  # it { should set_the_flash.to(/created/i) }
13
+ # it { should set_the_flash[:alert].to("Password doesn't match") }
13
14
  # it { should set_the_flash.to(/logged in/i).now }
14
15
  # it { should_not set_the_flash }
15
16
  def set_the_flash
@@ -17,6 +18,7 @@ module Shoulda # :nodoc:
17
18
  end
18
19
 
19
20
  class SetTheFlashMatcher # :nodoc:
21
+ attr_reader :failure_message, :negative_failure_message
20
22
 
21
23
  def to(value)
22
24
  @value = value
@@ -28,15 +30,18 @@ module Shoulda # :nodoc:
28
30
  self
29
31
  end
30
32
 
33
+ def [](key)
34
+ @key = key
35
+ self
36
+ end
37
+
31
38
  def matches?(controller)
32
39
  @controller = controller
33
40
  sets_the_flash? && string_value_matches? && regexp_value_matches?
34
41
  end
35
42
 
36
- attr_reader :failure_message, :negative_failure_message
37
-
38
43
  def description
39
- description = "set the flash"
44
+ description = "set the #{expected_flash_invocation}"
40
45
  description << " to #{@value.inspect}" unless @value.nil?
41
46
  description
42
47
  end
@@ -52,29 +57,48 @@ module Shoulda # :nodoc:
52
57
  private
53
58
 
54
59
  def sets_the_flash?
55
- !flash.blank?
60
+ flash_values.any?
56
61
  end
57
62
 
58
63
  def string_value_matches?
59
- return true unless String === @value
60
- flash.to_hash.values.any? {|value| value == @value }
64
+ if @value.is_a?(String)
65
+ flash_values.any? {|value| value == @value }
66
+ else
67
+ true
68
+ end
61
69
  end
62
70
 
63
71
  def regexp_value_matches?
64
- return true unless Regexp === @value
65
- flash.to_hash.values.any? {|value| value =~ @value }
72
+ if @value.is_a?(Regexp)
73
+ flash_values.any? {|value| value =~ @value }
74
+ else
75
+ true
76
+ end
77
+ end
78
+
79
+ def flash_values
80
+ if @key
81
+ [flash.to_hash[@key]]
82
+ else
83
+ flash.to_hash.values
84
+ end
66
85
  end
67
86
 
68
87
  def flash
69
- return @flash if @flash
70
- @flash = @controller.flash.dup
71
- @flash.instance_variable_set(:@used, @controller.flash.instance_variable_get(:@used).dup)
72
- @flash.sweep unless @now
73
- @flash
88
+ if @flash
89
+ @flash
90
+ else
91
+ @flash = @controller.flash.dup
92
+ @flash.instance_variable_set(:@used, @controller.flash.instance_variable_get(:@used).dup)
93
+ if ! @now
94
+ @flash.sweep
95
+ end
96
+ @flash
97
+ end
74
98
  end
75
99
 
76
100
  def expectation
77
- expectation = "the flash#{".now" if @now} to be set"
101
+ expectation = "the #{expected_flash_invocation} to be set"
78
102
  expectation << " to #{@value.inspect}" unless @value.nil?
79
103
  expectation << ", but #{flash_description}"
80
104
  expectation
@@ -88,8 +112,21 @@ module Shoulda # :nodoc:
88
112
  end
89
113
  end
90
114
 
91
- end
115
+ def expected_flash_invocation
116
+ now = ""
117
+ key = ""
92
118
 
119
+ if @now
120
+ now = ".now"
121
+ end
122
+
123
+ if @key
124
+ key = "[:#{@key}]"
125
+ end
126
+
127
+ "flash#{now}#{key}"
128
+ end
129
+ end
93
130
  end
94
131
  end
95
132
  end