Skip to content

Commit

Permalink
Created gem version 0.1.0. I reorganized the files so the gem is easi…
Browse files Browse the repository at this point in the history
…er to use

and updated the README.
  • Loading branch information
Martin Bilski authored and Martin Bilski committed Sep 5, 2011
1 parent cf685c0 commit b8f2ebf
Show file tree
Hide file tree
Showing 11 changed files with 351 additions and 298 deletions.
20 changes: 20 additions & 0 deletions MIT-LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
Copyright (c) 2011 Martin Bilski

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ A set of rspec matchers and helpers that make it easier to write specs for [cram
Quick start
-----------

require 'rspec/cramp'

describe HelloWorld, :cramp => true do
def app
HelloWorld
Expand Down Expand Up @@ -39,10 +41,11 @@ The matcher is fairly flexible, supports regular expressions and also works with
Project status
--------------

**IMPORTANT:** This is work in progress. I haven't created a gem yet.
**IMPORTANT:** This is work in progress.

1. There are still some things I'll take care of soon (esp. better failure messages).
2. I extracted the code from one of my projects and rewrote the matchers from scratch test-first. Still, after the weekend I plan to actually use it to replace the 'legacy' matchers in my project; this will probably uncover some bugs and may make me add more functionality.
1. I have created a gem and restructured the files 'a bit'. I'll publish the gem soon in its current form. Right now, you can build it using the provided gemspec.
2. There are still some things I'll take care of soon (esp. better failure messages).
3. I extracted the code from one of my projects and rewrote the matchers from scratch test-first. Still, after the weekend I plan to actually use it to replace the 'legacy' matchers in my project; this will probably uncover some bugs and may make me add more functionality. *UPDATE: I'm working on it right now.*

If you have any comments regarding the code as it is now (I know it's a bit messy), please feel free to tweet [@MartinBilski](http://twitter.com/#!/MartinBilski)

Expand Down
133 changes: 0 additions & 133 deletions lib/mock_response.rb

This file was deleted.

6 changes: 6 additions & 0 deletions lib/rspec/cramp.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
require 'cramp'

require 'rspec/cramp/extensions/cramp/action'
require 'rspec/cramp/matchers/respond_with'
require 'rspec/cramp/mock_response'
require 'rspec/cramp/shared_context'
17 changes: 17 additions & 0 deletions lib/rspec/cramp/extensions/cramp/action.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Monkey-patch so that even if there is an exception raised in on_start or in on_finish
# the exception dump is rendered so that:
# - you can match against it in your spec,
# - get method doesn't time out waiting for anything to be rendered (may not be true for on_finish).
#
module Cramp
class Action
alias :old_handle_exception :handle_exception
def handle_exception(exception)
if @_state != :init
handler = ExceptionHandler.new(@env, exception)
render handler.pretty
end
old_handle_exception(exception)
end
end
end
16 changes: 16 additions & 0 deletions lib/rspec/cramp/matchers/respond_with.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# respond_to RSpec matcher.
# See spec/examples for sample usage.
#
RSpec::Matchers.define :respond_with do |options = {}|
match do |response|
@actual_response = response
response.matching?(options)
end

failure_message_for_should do
@actual_response.last_failure_message_for_should
end
failure_message_for_should_not do
@actual_response.last_failure_message_for_should_not
end
end
135 changes: 135 additions & 0 deletions lib/rspec/cramp/mock_response.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
module RSpec
module Cramp

# Response from get, post etc. methods called in rspecs.
class MockResponse
def initialize(response)
@status = response[0]
@headers = response[1]
@body = response[2]
end

def read_body(max_chunks = 1, &block)
if @body.is_a? ::Cramp::Body
stopping = false
deferred_body = @body
chunks = []
deferred_body.each do |chunk|
chunks << chunk unless stopping
if chunks.count >= max_chunks
@body = chunks
stopping = true
block.call if block
EM.next_tick { EM.stop }
end
end
end
end

def [](i)
[@status, @headers, @body][i]
end

def body
if @body.is_a? ::Cramp::Body
raise "Error: Something went wrong or body is not loaded yet (use response.read_body do { })."
end
@body
end

def headers
@headers
end

def status
@status
end

def matching?(match_options)
expected_status = match_options.delete(:status)
expected_header = match_options.delete(:headers)
expected_body = match_options.delete(:body)
expected_chunks = match_options.delete(:chunks)
raise "Unsupported match option" unless match_options.empty?
matching_status?(expected_status) && matching_headers?(expected_header) && matching_body?(expected_body) &&
matching_chunks?(expected_chunks)
end

def last_failure_message_for_should
# TODO Better failure message showing the specific mismatches that made it fail.
"expected #{@failure_info[:expected]} in #{@failure_info[:what].to_s} but got: #{@failure_info[:actual]}"
end
def last_failure_message_for_should_not
# TODO Better failure message showing the specific successful matches that made it fail.
"expected response not to match the conditions but got: #{[@status, @headers, @body].inspect}"
end

private

def matching_response_element?(what, actual, expected)
is_match = if expected.nil?
true # No expectation set.
elsif actual.nil?
false
elsif expected.is_a? Regexp
actual.to_s.match(expected)
elsif expected.is_a? Integer
actual.to_i == expected
elsif expected.is_a? String
actual.to_s == expected
else
raise "Unsupported type"
end
@failure_info = is_match ? {} : {:what => what, :actual => actual, :expected => format_expected(expected)}
is_match
end

def resolve_status(status)
case status
when :ok then /^2[0-9][0-9]$/
when :error then /^[^2][0-9][0-9]$/
else status
end
end

def format_expected(expected)
expected.is_a?(Regexp) ? "/#{expected.source}/" : expected.inspect
end

def matching_status?(expected_status)
matching_response_element?(:status, @status, resolve_status(expected_status))
end

def matching_header_values?(expected_header)
expected_header.find do |ek, ev|
@headers.find { |ak, av| matching_response_element?(:headers, ak, ek) && !matching_response_element?(:headers, av, ev) } != nil
end == nil
end

def matching_header_keys?(expected_header)
is_match = @headers.keys.find do |actual|
expected_header.keys.find {|expected| matching_response_element?(:headers, actual, expected)} != nil
end != nil
@failure_info = is_match ? {} : {:what => :headers, :actual => @headers.keys.inspect, :expected => expected_header.keys.inspect}
is_match
end

def matching_headers?(expected_header)
expected_header.nil? ||
(matching_header_keys?(expected_header) && matching_header_values?(expected_header))
end

def matching_body?(expected_body)
actual_body = @body.is_a?(Array) ? @body.join("") : @body
matching_response_element?(:body, actual_body, expected_body)
end

def matching_chunks?(expected_chunks)
expected_chunks.nil? || (@body.is_a?(Array) &&
@body.zip(expected_chunks).find do |actual, expected|
!matching_response_element?(:chunks, actual, expected)
end.nil?)
end
end
end
end
Loading

0 comments on commit b8f2ebf

Please sign in to comment.