GitHub PullRequestReviewCommentEvent at 2014-05-03 08:02:19
Repository: rspec-rails
Actor: JonRowe
Payload: {"comment":{"url":"https://api.github.com/repos/rspec/rspec-rails/pulls/comments/12255397","id":12255397,"diff_hunk":"@@ -0,0 +1,311 @@\n+# The following code inspired and modified from Rails' `assert_response`:\n+#\n+#   https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/testing/assertions/response.rb#L22-L38\n+#\n+# Thank you to all the Rails devs who did the heavy lifting on this!\n+\n+module RSpec::Rails::Matchers\n+  # Namespace for various implementations of `have_http_status`.\n+  #\n+  # @api private\n+  module HaveHttpStatus\n+    # Instantiates an instance of the proper matcher based on the provided\n+    # `target`.\n+    #\n+    # @param target [Object] expected http status or code\n+    # @return response matcher instance\n+    def self.matcher_for_status(target)\n+      if GenericStatus.valid_statuses.include?(target)\n+        GenericStatus.new(target)\n+      elsif Symbol === target\n+        SymbolicStatus.new(target)\n+      else\n+        NumericCode.new(target)\n+      end\n+    end\n+\n+    # @private\n+    # Hack to support `Capybara::Session` without having to load Capybara or\n+    # catch `NameError`s for the undefined constants\n+    #\n+    # Checks if the provided object responds to the interfaces:\n+    # - `status_code`\n+    # - `response_headers`\n+    #\n+    # @return [Boolean]\n+    ActsAsCapybaraSession = lambda { |o|\n+      o.respond_to?(:status_code) && o.respond_to?(:response_headers)\n+    }\n+\n+    # @private\n+    # Conversion function to coerce the provided object into an\n+    # `ActionDispatch::TestResponse`.\n+    #\n+    # @param obj [Object] object to convert to a response\n+    # @return [ActionDispatch::TestResponse]\n+    def as_test_response(obj)\n+      case obj\n+      when ::ActionDispatch::Response\n+        ::ActionDispatch::TestResponse.from_response(obj)\n+      when ::ActionDispatch::TestResponse\n+        obj\n+      when ActsAsCapybaraSession\n+        ::ActionDispatch::TestResponse.new.tap{ |resp|\n+          resp.status  = obj.status_code\n+          resp.headers = obj.response_headers\n+          resp.body    = obj.body\n+        }\n+      else\n+        raise ArgumentError, \"Invalid response type: #{obj}\"\n+      end\n+    end\n+    module_function :as_test_response\n+\n+    # @private\n+    # Provides an implementation for `have_http_status` matching against\n+    # numeric http status codes.\n+    #\n+    # Not intended to be instantiated directly.\n+    #\n+    # @example\n+    #   expect(response).to have_http_status(404)\n+    #\n+    # @see RSpec::Rails::Matchers.have_http_status\n+    class NumericCode < RSpec::Matchers::BuiltIn::BaseMatcher\n+      include HaveHttpStatus\n+\n+      def initialize(code)\n+        @expected = code.to_i\n+        @actual = nil\n+      end\n+\n+      # @param [Object] response object providing an http code to match\n+      # @return [Boolean] `true` if the numeric code matched the `response` code\n+      def matches?(response)\n+        response = as_test_response(response)\n+        @actual = response.response_code\n+        expected == @actual\n+      end\n+\n+      # @return [String] explaining why the match failed\n+      def failure_message\n+        \"expected the response to have status code #{expected.inspect}\" +\n+          \" but it was #{actual.inspect}\"\n+      end\n+\n+      # @return [String] explaining why the match failed\n+      def failure_message_when_negated\n+        \"expected the response not to have status code #{expected.inspect}\" +\n+          \" but it did\"\n+      end\n+    end\n+\n+    # @private\n+    # Provides an implementation for `have_http_status` matching against\n+    # Rack symbol http status codes.\n+    #\n+    # Not intended to be instantiated directly.\n+    #\n+    # @example\n+    #   expect(response).to have_http_status(:created)\n+    #\n+    # @see RSpec::Rails::Matchers.have_http_status\n+    # @see https://github.com/rack/rack/blob/master/lib/rack/utils.rb `Rack::Utils::SYMBOL_TO_STATUS_CODE`\n+    class SymbolicStatus < RSpec::Matchers::BuiltIn::BaseMatcher\n+      include HaveHttpStatus\n+\n+      def initialize(status)\n+        @expected_status = status\n+        @actual = nil\n+        unless set_expected_code!\n+          raise ArgumentError, \"Invalid HTTP status: #{status.inspect}\"\n+        end\n+      end\n+\n+      # @param [Object] response object providing an http code to match\n+      # @return [Boolean] `true` if Rack's associated numeric HTTP code matched\n+      #   the `response` code\n+      def matches?(response)\n+        response = as_test_response(response)\n+        @actual = response.response_code\n+        expected == @actual\n+      end\n+\n+      # @return [String] explaining why the match failed\n+      def failure_message\n+        actual_message = if status = actual_status\n+                           \"#{status.inspect} (#{actual})\"\n+                         else\n+                           actual.to_s\n+                         end\n+        \"expected the response to have status code #{expected_message} but it\" +\n+          \" was #{actual_message}\"\n+      end\n+\n+      # @return [String] explaining why the match failed\n+      def failure_message_when_negated\n+        \"expected the response not to have status code #{expected_message} \" +\n+          \"but it did\"\n+      end\n+\n+      # The initialized expected status symbol\n+      attr_reader :expected_status\n+      private :expected_status\n+\n+    private\n+\n+      # Reverse lookup of the Rack status code symbol based on the numeric http\n+      # code\n+      #\n+      # @return [Symbol] representing the actual http numeric code\n+      def actual_status\n+        status, _ = Rack::Utils::SYMBOL_TO_STATUS_CODE.find{ |_, c| c == actual }\n+        status\n+      end\n+\n+      # @return [String] formating the expected status and associated code\n+      def expected_message\n+        \"#{expected_status.inspect} (#{expected})\"\n+      end\n+\n+      # Sets `expected` to the numeric http code based on the Rack\n+      # `expected_status` status\n+      #\n+      # @see Rack::Utils::SYMBOL_TO_STATUS_CODE\n+      # @return [nil] if an associated code could not be found\n+      def set_expected_code!\n+        @expected ||= Rack::Utils::SYMBOL_TO_STATUS_CODE[expected_status]\n+      end\n+    end\n+\n+    # @private","path":"lib/rspec/rails/matchers/have_http_status.rb","position":181,"original_position":181,"commit_id":"1f405b301f61b655c699cc083a3771ca8f088535","original_commit_id":"1f405b301f61b655c699cc083a3771ca8f088535","user":{"login":"JonRowe","id":162976,"avatar_url":"https://avatars.githubusercontent.com/u/162976?","gravatar_id":"d79fc498d7a5b2ce12180890247476f0","url":"https://api.github.com/users/JonRowe","html_url":"https://github.com/JonRowe","followers_url":"https://api.github.com/users/JonRowe/followers","following_url":"https://api.github.com/users/JonRowe/following{/other_user}","gists_url":"https://api.github.com/users/JonRowe/gists{/gist_id}","starred_url":"https://api.github.com/users/JonRowe/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/JonRowe/subscriptions","organizations_url":"https://api.github.com/users/JonRowe/orgs","repos_url":"https://api.github.com/users/JonRowe/repos","events_url":"https://api.github.com/users/JonRowe/events{/privacy}","received_events_url":"https://api.github.com/users/JonRowe/received_events","type":"User","site_admin":false},"body":"Same point about `@private` as above","created_at":"2014-05-03T08:02:19Z","updated_at":"2014-05-03T08:02:19Z","html_url":"https://github.com/rspec/rspec-rails/pull/987#discussion_r12255397","pull_request_url":"https://api.github.com/repos/rspec/rspec-rails/pulls/987","_links":{"self":{"href":"https://api.github.com/repos/rspec/rspec-rails/pulls/comments/12255397"},"html":{"href":"https://github.com/rspec/rspec-rails/pull/987#discussion_r12255397"},"pull_request":{"href":"https://api.github.com/repos/rspec/rspec-rails/pulls/987"}}}}