francois-shoulda 2.0.5.4 → 2.10.1

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.
Files changed (109) hide show
  1. data/README.rdoc +60 -10
  2. data/Rakefile +7 -7
  3. data/lib/shoulda.rb +7 -15
  4. data/lib/shoulda/action_controller.rb +28 -0
  5. data/lib/shoulda/action_controller/helpers.rb +47 -0
  6. data/lib/shoulda/action_controller/macros.rb +277 -0
  7. data/lib/shoulda/action_controller/matchers.rb +37 -0
  8. data/lib/shoulda/action_controller/matchers/assign_to_matcher.rb +109 -0
  9. data/lib/shoulda/action_controller/matchers/filter_param_matcher.rb +57 -0
  10. data/lib/shoulda/action_controller/matchers/render_with_layout_matcher.rb +81 -0
  11. data/lib/shoulda/action_controller/matchers/respond_with_content_type_matcher.rb +70 -0
  12. data/lib/shoulda/action_controller/matchers/respond_with_matcher.rb +81 -0
  13. data/lib/shoulda/action_controller/matchers/route_matcher.rb +93 -0
  14. data/lib/shoulda/action_controller/matchers/set_session_matcher.rb +87 -0
  15. data/lib/shoulda/action_controller/matchers/set_the_flash_matcher.rb +85 -0
  16. data/lib/shoulda/action_mailer.rb +1 -1
  17. data/lib/shoulda/action_mailer/assertions.rb +32 -33
  18. data/lib/shoulda/action_view.rb +10 -0
  19. data/lib/shoulda/action_view/macros.rb +56 -0
  20. data/lib/shoulda/active_record.rb +6 -2
  21. data/lib/shoulda/active_record/assertions.rb +62 -89
  22. data/lib/shoulda/active_record/helpers.rb +40 -0
  23. data/lib/shoulda/active_record/macros.rb +520 -684
  24. data/lib/shoulda/active_record/matchers.rb +42 -0
  25. data/lib/shoulda/active_record/matchers/allow_mass_assignment_of_matcher.rb +83 -0
  26. data/lib/shoulda/active_record/matchers/allow_value_matcher.rb +102 -0
  27. data/lib/shoulda/active_record/matchers/association_matcher.rb +226 -0
  28. data/lib/shoulda/active_record/matchers/ensure_inclusion_of_matcher.rb +87 -0
  29. data/lib/shoulda/active_record/matchers/ensure_length_of_matcher.rb +141 -0
  30. data/lib/shoulda/active_record/matchers/have_db_column_matcher.rb +169 -0
  31. data/lib/shoulda/active_record/matchers/have_index_matcher.rb +105 -0
  32. data/lib/shoulda/active_record/matchers/have_named_scope_matcher.rb +125 -0
  33. data/lib/shoulda/active_record/matchers/have_readonly_attribute_matcher.rb +59 -0
  34. data/lib/shoulda/active_record/matchers/validate_acceptance_of_matcher.rb +41 -0
  35. data/lib/shoulda/active_record/matchers/validate_numericality_of_matcher.rb +39 -0
  36. data/lib/shoulda/active_record/matchers/validate_presence_of_matcher.rb +60 -0
  37. data/lib/shoulda/active_record/matchers/validate_uniqueness_of_matcher.rb +148 -0
  38. data/lib/shoulda/active_record/matchers/validation_matcher.rb +56 -0
  39. data/lib/shoulda/assertions.rb +50 -40
  40. data/lib/shoulda/autoload_macros.rb +46 -0
  41. data/lib/shoulda/context.rb +124 -126
  42. data/lib/shoulda/helpers.rb +5 -7
  43. data/lib/shoulda/macros.rb +63 -64
  44. data/lib/shoulda/private_helpers.rb +16 -18
  45. data/lib/shoulda/rails.rb +5 -11
  46. data/lib/shoulda/rspec.rb +11 -0
  47. data/lib/shoulda/tasks/list_tests.rake +6 -1
  48. data/lib/shoulda/test_unit.rb +19 -0
  49. data/rails/init.rb +7 -1
  50. data/test/README +2 -2
  51. data/test/fail_macros.rb +15 -15
  52. data/test/fixtures/tags.yml +1 -1
  53. data/test/functional/posts_controller_test.rb +46 -26
  54. data/test/functional/users_controller_test.rb +0 -19
  55. data/test/matchers/active_record/allow_mass_assignment_of_matcher_test.rb +68 -0
  56. data/test/matchers/active_record/allow_value_matcher_test.rb +41 -0
  57. data/test/matchers/active_record/association_matcher_test.rb +258 -0
  58. data/test/matchers/active_record/ensure_inclusion_of_matcher_test.rb +80 -0
  59. data/test/matchers/active_record/ensure_length_of_matcher_test.rb +158 -0
  60. data/test/matchers/active_record/have_db_column_matcher_test.rb +169 -0
  61. data/test/matchers/active_record/have_index_matcher_test.rb +74 -0
  62. data/test/matchers/active_record/have_named_scope_matcher_test.rb +65 -0
  63. data/test/matchers/active_record/have_readonly_attributes_matcher_test.rb +29 -0
  64. data/test/matchers/active_record/validate_acceptance_of_matcher_test.rb +44 -0
  65. data/test/matchers/active_record/validate_numericality_of_matcher_test.rb +52 -0
  66. data/test/matchers/active_record/validate_presence_of_matcher_test.rb +86 -0
  67. data/test/matchers/active_record/validate_uniqueness_of_matcher_test.rb +147 -0
  68. data/test/matchers/controller/assign_to_matcher_test.rb +35 -0
  69. data/test/matchers/controller/filter_param_matcher_test.rb +32 -0
  70. data/test/matchers/controller/render_with_layout_matcher_test.rb +33 -0
  71. data/test/matchers/controller/respond_with_content_type_matcher_test.rb +27 -0
  72. data/test/matchers/controller/respond_with_matcher_test.rb +106 -0
  73. data/test/matchers/controller/route_matcher_test.rb +58 -0
  74. data/test/matchers/controller/set_session_matcher_test.rb +31 -0
  75. data/test/matchers/controller/set_the_flash_matcher.rb +41 -0
  76. data/test/model_builder.rb +106 -0
  77. data/test/other/autoload_macro_test.rb +18 -0
  78. data/test/other/helpers_test.rb +58 -0
  79. data/test/other/private_helpers_test.rb +1 -1
  80. data/test/other/should_test.rb +16 -16
  81. data/test/rails_root/app/controllers/posts_controller.rb +6 -5
  82. data/test/rails_root/app/models/pets/dog.rb +10 -0
  83. data/test/rails_root/app/models/treat.rb +3 -0
  84. data/test/rails_root/app/models/user.rb +4 -3
  85. data/test/rails_root/app/views/layouts/posts.rhtml +2 -0
  86. data/test/rails_root/config/database.yml +1 -1
  87. data/test/rails_root/config/environment.rb +1 -1
  88. data/test/rails_root/config/environments/{sqlite3.rb → test.rb} +0 -0
  89. data/test/rails_root/db/migrate/001_create_users.rb +3 -2
  90. data/test/rails_root/db/migrate/011_create_treats.rb +12 -0
  91. data/test/rails_root/test/shoulda_macros/custom_macro.rb +6 -0
  92. data/test/rails_root/vendor/gems/gem_with_macro-0.0.1/shoulda_macros/gem_macro.rb +6 -0
  93. data/test/rails_root/vendor/plugins/plugin_with_macro/shoulda_macros/plugin_macro.rb +6 -0
  94. data/test/rspec_test.rb +207 -0
  95. data/test/test_helper.rb +3 -1
  96. data/test/unit/address_test.rb +1 -23
  97. data/test/unit/dog_test.rb +5 -2
  98. data/test/unit/post_test.rb +7 -3
  99. data/test/unit/product_test.rb +2 -2
  100. data/test/unit/tag_test.rb +2 -1
  101. data/test/unit/user_test.rb +25 -9
  102. metadata +84 -23
  103. data/lib/shoulda/controller.rb +0 -30
  104. data/lib/shoulda/controller/formats/html.rb +0 -201
  105. data/lib/shoulda/controller/formats/xml.rb +0 -170
  106. data/lib/shoulda/controller/helpers.rb +0 -64
  107. data/lib/shoulda/controller/macros.rb +0 -316
  108. data/lib/shoulda/controller/resource_options.rb +0 -236
  109. data/test/rails_root/app/models/dog.rb +0 -5
@@ -0,0 +1,37 @@
1
+ require 'shoulda/action_controller/matchers/assign_to_matcher'
2
+ require 'shoulda/action_controller/matchers/filter_param_matcher'
3
+ require 'shoulda/action_controller/matchers/set_the_flash_matcher'
4
+ require 'shoulda/action_controller/matchers/render_with_layout_matcher'
5
+ require 'shoulda/action_controller/matchers/respond_with_matcher'
6
+ require 'shoulda/action_controller/matchers/respond_with_content_type_matcher'
7
+ require 'shoulda/action_controller/matchers/set_session_matcher'
8
+ require 'shoulda/action_controller/matchers/route_matcher'
9
+
10
+ module Shoulda # :nodoc:
11
+ module ActionController # :nodoc:
12
+
13
+ # By using the macro helpers you can quickly and easily create concise and
14
+ # easy to read test suites.
15
+ #
16
+ # This code segment:
17
+ #
18
+ # describe UsersController, "on GET to show with a valid id" do
19
+ # before(:each) do
20
+ # get :show, :id => User.first.to_param
21
+ # end
22
+ #
23
+ # it { should assign_to(:user) }
24
+ # it { should respond_with(:success) }
25
+ # it { should render_template(:show) }
26
+ # it { should not_set_the_flash) }
27
+ #
28
+ # it "should do something else really cool" do
29
+ # assigns[:user].id.should == 1
30
+ # end
31
+ # end
32
+ #
33
+ # Would produce 5 tests for the show action
34
+ module Matchers
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,109 @@
1
+ module Shoulda # :nodoc:
2
+ module ActionController # :nodoc:
3
+ module Matchers
4
+
5
+ # Ensures that the controller assigned to the named instance variable.
6
+ #
7
+ # Options:
8
+ # * <tt>with_kind_of</tt> - The expected class of the instance variable
9
+ # being checked.
10
+ # * <tt>with</tt> - The value that should be assigned.
11
+ #
12
+ # Example:
13
+ #
14
+ # it { should assign_to(:user) }
15
+ # it { should_not assign_to(:user) }
16
+ # it { should assign_to(:user).with_kind_of(User) }
17
+ # it { should assign_to(:user).with(@user) }
18
+ def assign_to(variable)
19
+ AssignToMatcher.new(variable)
20
+ end
21
+
22
+ class AssignToMatcher # :nodoc:
23
+
24
+ def initialize(variable)
25
+ @variable = variable.to_s
26
+ end
27
+
28
+ def with_kind_of(expected_class)
29
+ @expected_class = expected_class
30
+ self
31
+ end
32
+
33
+ def with(expected_value)
34
+ @expected_value = expected_value
35
+ self
36
+ end
37
+
38
+ def matches?(controller)
39
+ @controller = controller
40
+ assigned_value? && kind_of_expected_class? && equal_to_expected_value?
41
+ end
42
+
43
+ attr_reader :failure_message, :negative_failure_message
44
+
45
+ def description
46
+ description = "assign @#{@variable}"
47
+ description << " with a kind of #{@expected_class}" if @expected_class
48
+ description
49
+ end
50
+
51
+ private
52
+
53
+ def assigned_value?
54
+ if assigned_value.nil?
55
+ @failure_message =
56
+ "Expected action to assign a value for @#{@variable}"
57
+ false
58
+ else
59
+ @negative_failure_message =
60
+ "Didn't expect action to assign a value for @#{@variable}, " <<
61
+ "but it was assigned to #{assigned_value.inspect}"
62
+ true
63
+ end
64
+ end
65
+
66
+ def kind_of_expected_class?
67
+ return true unless @expected_class
68
+ if assigned_value.kind_of?(@expected_class)
69
+ @negative_failure_message =
70
+ "Didn't expect action to assign a kind of #{@expected_class} " <<
71
+ "for #{@variable}, but got one anyway"
72
+ true
73
+ else
74
+ @failure_message =
75
+ "Expected action to assign a kind of #{@expected_class} " <<
76
+ "for #{@variable}, but got #{@variable.inspect} " <<
77
+ "(#{@variable.class.name})"
78
+ false
79
+ end
80
+ end
81
+
82
+ def equal_to_expected_value?
83
+ return true unless @expected_value
84
+ if @expected_value == assigned_value
85
+ @negative_failure_message =
86
+ "Didn't expect action to assign #{@expected_value.inspect} " <<
87
+ "for #{@variable}, but got it anyway"
88
+ true
89
+ else
90
+ @failure_message =
91
+ "Expected action to assign #{@expected_value.inspect} " <<
92
+ "for #{@variable}, but got #{assigned_value.inspect}"
93
+ false
94
+ end
95
+ end
96
+
97
+ def assigned_value
98
+ assigns[@variable]
99
+ end
100
+
101
+ def assigns
102
+ @controller.response.template.assigns
103
+ end
104
+
105
+ end
106
+
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,57 @@
1
+ module Shoulda # :nodoc:
2
+ module ActionController # :nodoc:
3
+ module Matchers
4
+
5
+ # Ensures that filter_parameter_logging is set for the specified key.
6
+ #
7
+ # Example:
8
+ #
9
+ # it { should filter_param(:password) }
10
+ def filter_param(key)
11
+ FilterParamMatcher.new(key)
12
+ end
13
+
14
+ class FilterParamMatcher # :nodoc:
15
+
16
+ def initialize(key)
17
+ @key = key.to_s
18
+ end
19
+
20
+ def matches?(controller)
21
+ @controller = controller
22
+ filters_params? && filters_key?
23
+ end
24
+
25
+ def failure_message
26
+ "Expected #{@key} to be filtered"
27
+ end
28
+
29
+ def negative_failure_message
30
+ "Did not expect #{@key} to be filtered"
31
+ end
32
+
33
+ def description
34
+ "filter #{@key}"
35
+ end
36
+
37
+ private
38
+
39
+ def filters_params?
40
+ @controller.respond_to?(:filter_parameters)
41
+ end
42
+
43
+ def filters_key?
44
+ filtered_value == '[FILTERED]'
45
+ end
46
+
47
+ def filtered_value
48
+ filtered = @controller.send(:filter_parameters,
49
+ @key.to_s => @key.to_s)
50
+ filtered[@key.to_s]
51
+ end
52
+
53
+ end
54
+
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,81 @@
1
+ module Shoulda # :nodoc:
2
+ module ActionController # :nodoc:
3
+ module Matchers
4
+
5
+ # Ensures that the controller rendered with the given layout.
6
+ #
7
+ # Example:
8
+ #
9
+ # it { should render_with_layout }
10
+ # it { should render_with_layout(:special) }
11
+ # it { should_not render_with_layout }
12
+ def render_with_layout(layout = nil)
13
+ RenderWithLayout.new(layout)
14
+ end
15
+
16
+ class RenderWithLayout # :nodoc:
17
+
18
+ def initialize(layout)
19
+ @layout = layout.to_s unless layout.nil?
20
+ end
21
+
22
+ def matches?(controller)
23
+ @controller = controller
24
+ rendered_with_layout? && rendered_with_expected_layout?
25
+ end
26
+
27
+ def failure_message
28
+ "Expected #{expectation}, but #{result}"
29
+ end
30
+
31
+ def negative_failure_message
32
+ "Did not expect #{expectation}, but #{result}"
33
+ end
34
+
35
+ def description
36
+ description = "render with "
37
+ if @layout.nil?
38
+ description << "a layout"
39
+ else
40
+ description << "the #{@layout.inspect} layout"
41
+ end
42
+ description
43
+ end
44
+
45
+ private
46
+
47
+ def rendered_with_layout?
48
+ !layout.blank?
49
+ end
50
+
51
+ def rendered_with_expected_layout?
52
+ return true if @layout.nil?
53
+ layout == @layout
54
+ end
55
+
56
+ def layout
57
+ layout = @controller.response.layout
58
+ if layout.nil?
59
+ nil
60
+ else
61
+ layout.split('/').last
62
+ end
63
+ end
64
+
65
+ def expectation
66
+ "to #{description}"
67
+ end
68
+
69
+ def result
70
+ if rendered_with_layout?
71
+ "rendered with the #{layout.inspect} layout"
72
+ else
73
+ "rendered without a layout"
74
+ end
75
+ end
76
+
77
+ end
78
+
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,70 @@
1
+ module Shoulda # :nodoc:
2
+ module ActionController # :nodoc:
3
+ module Matchers
4
+
5
+ # Ensures a controller responded with expected 'response' content type.
6
+ #
7
+ # You can pass an explicit content type such as 'application/rss+xml'
8
+ # or its symbolic equivalent :rss
9
+ # or a regular expression such as /rss/
10
+ #
11
+ # Example:
12
+ #
13
+ # it { should respond_with_content_type(:xml) }
14
+ # it { should respond_with_content_type(:csv) }
15
+ # it { should respond_with_content_type(:atom) }
16
+ # it { should respond_with_content_type(:yaml) }
17
+ # it { should respond_with_content_type(:text) }
18
+ # it { should respond_with_content_type('application/rss+xml') }
19
+ # it { should respond_with_content_type(/json/) }
20
+ def respond_with_content_type(content_type)
21
+ RespondWithContentTypeMatcher.new(content_type)
22
+ end
23
+
24
+ class RespondWithContentTypeMatcher # :nodoc:
25
+
26
+ 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
32
+ end
33
+
34
+ def matches?(controller)
35
+ @controller = controller
36
+ if @content_type.is_a?(Regexp)
37
+ response_content_type =~ @content_type
38
+ else
39
+ response_content_type == @content_type
40
+ end
41
+ end
42
+
43
+ def failure_message
44
+ "Expected #{expectation}"
45
+ end
46
+
47
+ def negative_failure_message
48
+ "Did not expect #{expectation}"
49
+ end
50
+
51
+ protected
52
+
53
+ def response_content_type
54
+ @controller.response.content_type
55
+ end
56
+
57
+ def lookup_by_extension(extension)
58
+ Mime::Type.lookup_by_extension(extension.to_s).to_s
59
+ end
60
+
61
+ def expectation
62
+ "content type to be #{@content_type}, " <<
63
+ "but was #{response_content_type}"
64
+ end
65
+
66
+ end
67
+
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,81 @@
1
+ module Shoulda # :nodoc:
2
+ module ActionController # :nodoc:
3
+ module Matchers
4
+
5
+ # Ensures a controller responded with expected 'response' status code.
6
+ #
7
+ # You can pass an explicit status number like 200, 301, 404, 500
8
+ # or its symbolic equivalent :success, :redirect, :missing, :error.
9
+ # See ActionController::StatusCodes for a full list.
10
+ #
11
+ # Example:
12
+ #
13
+ # it { should respond_with(:success) }
14
+ # it { should respond_with(:redirect) }
15
+ # it { should respond_with(:missing) }
16
+ # it { should respond_with(:error) }
17
+ # it { should respond_with(501) }
18
+ def respond_with(status)
19
+ RespondWithMatcher.new(status)
20
+ end
21
+
22
+ class RespondWithMatcher # :nodoc:
23
+
24
+ def initialize(status)
25
+ @status = symbol_to_status_code(status)
26
+ end
27
+
28
+ def matches?(controller)
29
+ @controller = controller
30
+ correct_status_code? || correct_status_code_range?
31
+ end
32
+
33
+ def failure_message
34
+ "Expected #{expectation}"
35
+ end
36
+
37
+ def negative_failure_message
38
+ "Did not expect #{expectation}"
39
+ end
40
+
41
+ def description
42
+ "respond with #{@status}"
43
+ end
44
+
45
+ protected
46
+
47
+ def correct_status_code?
48
+ response_code == @status
49
+ end
50
+
51
+ def correct_status_code_range?
52
+ @status.is_a?(Range) &&
53
+ @status.include?(response_code)
54
+ end
55
+
56
+ def response_code
57
+ @controller.response.response_code
58
+ end
59
+
60
+ def symbol_to_status_code(potential_symbol)
61
+ case potential_symbol
62
+ when :success then 200
63
+ when :redirect then 300..399
64
+ when :missing then 404
65
+ when :error then 500..599
66
+ when Symbol
67
+ ::ActionController::StatusCodes::SYMBOL_TO_STATUS_CODE[potential_symbol]
68
+ else
69
+ potential_symbol
70
+ end
71
+ end
72
+
73
+ def expectation
74
+ "response to be a #{@status}, but was #{response_code}"
75
+ end
76
+
77
+ end
78
+
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,93 @@
1
+ module Shoulda # :nodoc:
2
+ module ActionController # :nodoc:
3
+ module Matchers
4
+
5
+ # Ensures that requesting +path+ using +method+ routes to +options+.
6
+ #
7
+ # If you don't specify a controller, it will use the controller from the
8
+ # example group.
9
+ #
10
+ # +to_param+ is called on the +options+ given.
11
+ #
12
+ # Examples:
13
+ #
14
+ # it { should route(:get, "/posts").
15
+ # to(:controller => :posts, :action => :index) }
16
+ # it { should route(:get, "/posts/new").to(:action => :new) }
17
+ # it { should route(:post, "/posts").to(:action => :create) }
18
+ # it { should route(:get, "/posts/1").to(:action => :show, :id => 1) }
19
+ # it { should route(:edit, "/posts/1").to(:action => :show, :id => 1) }
20
+ # it { should route(:put, "/posts/1").to(:action => :update, :id => 1) }
21
+ # it { should route(:delete, "/posts/1").
22
+ # to(:action => :destroy, :id => 1) }
23
+ # it { should route(:get, "/users/1/posts/1").
24
+ # to(:action => :show, :id => 1, :user_id => 1) }
25
+ def route(method, path)
26
+ RouteMatcher.new(method, path, self)
27
+ end
28
+
29
+ class RouteMatcher # :nodoc:
30
+
31
+ def initialize(method, path, context)
32
+ @method = method
33
+ @path = path
34
+ @context = context
35
+ end
36
+
37
+ def to(params)
38
+ @params = params
39
+ self
40
+ end
41
+
42
+ def in_context(context)
43
+ @context = context
44
+ self
45
+ end
46
+
47
+ def matches?(controller)
48
+ @controller = controller
49
+ guess_controller!
50
+ stringify_params!
51
+ route_recognized?
52
+ end
53
+
54
+ attr_reader :failure_message, :negative_failure_message
55
+
56
+ def description
57
+ "route #{@method.to_s.upcase} #{@path} to/from #{@params.inspect}"
58
+ end
59
+
60
+ private
61
+
62
+ def guess_controller!
63
+ @params[:controller] ||= @controller.controller_path
64
+ end
65
+
66
+ def stringify_params!
67
+ @params.each do |key, value|
68
+ @params[key] = value.to_param
69
+ end
70
+ end
71
+
72
+ def route_recognized?
73
+ begin
74
+ @context.send(:assert_routing,
75
+ { :method => @method, :path => @path },
76
+ @params)
77
+
78
+ @negative_failure_message = "Didn't expect to #{description}"
79
+ true
80
+ rescue ::ActionController::RoutingError => error
81
+ @failure_message = error.message
82
+ false
83
+ rescue Test::Unit::AssertionFailedError => error
84
+ @failure_message = error.message
85
+ false
86
+ end
87
+ end
88
+
89
+ end
90
+
91
+ end
92
+ end
93
+ end