webmachine-test 0.1.0

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.
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source :rubygems
2
+
3
+ gem 'rake'
4
+ gem 'rspec'
5
+ gem 'ZenTest'
6
+ gem 'webmachine', :git => 'https://github.com/seancribbs/webmachine-ruby'
data/README.md ADDED
@@ -0,0 +1,100 @@
1
+ # Webmachine::Test
2
+
3
+ [![travis](https://secure.travis-ci.org/bernd/webmachine-test.png)](http://travis-ci.org/bernd/webmachine-test)
4
+
5
+ ## WARNING
6
+
7
+ This library is still under development and incomplete!
8
+
9
+ It will be merged into [webmachine-ruby](https://github.com/seancribbs/webmachine-ruby)
10
+ when it's ready.
11
+
12
+ ## Description
13
+
14
+ Webmachine::Test provides a testing API for
15
+ [webmachine-ruby](https://github.com/seancribbs/webmachine-ruby) inspired by
16
+ [rack-test](https://github.com/brynary/rack-test).
17
+
18
+ ## Example Usage
19
+
20
+ ### Application
21
+
22
+ ```ruby
23
+ require 'webmachine'
24
+
25
+ class MyResource < Webmachine::Resource
26
+ def content_types_provided
27
+ [['text/plain', :to_text]]
28
+ end
29
+
30
+ def to_text
31
+ 'OK'
32
+ end
33
+ end
34
+
35
+ MyApp = Webmachine::Application.new.tap do |app|
36
+ app.add_route(['*'], MyResource)
37
+ end
38
+
39
+ # decouple runner from application so that adapter
40
+ # does not start and block test thread
41
+ #
42
+ # MyApp.run
43
+ ```
44
+
45
+ ### Test with Test::Unit
46
+
47
+ ```ruby
48
+ class MyAppTest < Test::Unit::TestCase
49
+ include Webmachine::Test
50
+
51
+ def test_get_root_succeeds
52
+ get '/'
53
+ assert_equal 200, response.code
54
+ end
55
+
56
+ def test_get_root_replies_with_string_ok
57
+ get '/'
58
+ assert_equal 'OK', response.body
59
+ end
60
+
61
+ def test_get_root_replies_with_content_type_of_text_plain
62
+ get '/'
63
+ assert_equal 'text/plain', response.headers['Content-Type']
64
+ end
65
+
66
+ def app
67
+ MyApp
68
+ end
69
+ end
70
+ ```
71
+
72
+ ### Test with RSpec
73
+
74
+ ```ruby
75
+ require 'webmachine/test'
76
+ require 'myapp'
77
+
78
+ describe MyApp do
79
+ include Webmachine::Test
80
+
81
+ let(:app) { MyApp }
82
+
83
+ describe 'GET /' do
84
+ it 'succeeds' do
85
+ get '/'
86
+ response.code.should == 200
87
+ end
88
+
89
+ it 'replies with the string OK' do
90
+ get '/'
91
+ response.body.should == 'OK'
92
+ end
93
+
94
+ it 'replies with a content type of text/plain' do
95
+ get '/'
96
+ response.headers['Content-Type'].should == 'text/plain'
97
+ end
98
+ end
99
+ end
100
+ ```
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ desc 'Run specs'
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task :default => :spec
@@ -0,0 +1,46 @@
1
+ # :stopdoc:
2
+
3
+ # Stolen from ruby core's uri/common.rb, with modifications to support 1.8.x
4
+ #
5
+ # https://github.com/ruby/ruby/blob/trunk/lib/uri/common.rb
6
+ #
7
+ # (via rack)
8
+
9
+ module URI
10
+ TBLENCWWWCOMP_ = {} # :nodoc:
11
+ 256.times do |i|
12
+ TBLENCWWWCOMP_[i.chr] = '%%%02X' % i
13
+ end
14
+ TBLENCWWWCOMP_[' '] = '+'
15
+ TBLENCWWWCOMP_.freeze
16
+ TBLDECWWWCOMP_ = {} # :nodoc:
17
+ 256.times do |i|
18
+ h, l = i>>4, i&15
19
+ TBLDECWWWCOMP_['%%%X%X' % [h, l]] = i.chr
20
+ TBLDECWWWCOMP_['%%%x%X' % [h, l]] = i.chr
21
+ TBLDECWWWCOMP_['%%%X%x' % [h, l]] = i.chr
22
+ TBLDECWWWCOMP_['%%%x%x' % [h, l]] = i.chr
23
+ end
24
+ TBLDECWWWCOMP_['+'] = ' '
25
+ TBLDECWWWCOMP_.freeze
26
+
27
+ # Encode given +s+ to URL-encoded form data.
28
+ #
29
+ # This method doesn't convert *, -, ., 0-9, A-Z, _, a-z, but does convert SP
30
+ # (ASCII space) to + and converts others to %XX.
31
+ #
32
+ # This is an implementation of
33
+ # http://www.w3.org/TR/html5/forms.html#url-encoded-form-data
34
+ #
35
+ # See URI.decode_www_form_component, URI.encode_www_form
36
+ def self.encode_www_form_component(s)
37
+ str = s.to_s
38
+ if RUBY_VERSION < "1.9" && $KCODE =~ /u/i
39
+ str.gsub(/([^ a-zA-Z0-9_.-]+)/) do
40
+ '%' + $1.unpack('H2' * Rack::Utils.bytesize($1)).join('%').upcase
41
+ end.tr(' ', '+')
42
+ else
43
+ str.gsub(/[^*\-.0-9A-Z_a-z]/) {|m| TBLENCWWWCOMP_[m]}
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,90 @@
1
+ require 'stringio'
2
+ require 'uri'
3
+
4
+ # Ruby 1.8 does not have URI.encode_www_form_component.
5
+ unless URI.respond_to?(:encode_www_form_component)
6
+ require 'webmachine/test/backports/uri'
7
+ end
8
+
9
+ module Webmachine
10
+ module Test
11
+ class Session
12
+ HTTP_METHODS = %W(HEAD GET PUT POST PATCH DELETE OPTIONS)
13
+
14
+ def initialize(app)
15
+ @headers = Webmachine::Headers.new
16
+ @body = nil
17
+ @req = nil
18
+ @res = nil
19
+ @app = app
20
+ end
21
+
22
+ # Returns the request object.
23
+ def request
24
+ @req || webmachine_test_error('No request object yet. Issue a request first.')
25
+ end
26
+
27
+ # Returns the response object after a request has been made.
28
+ def response
29
+ @res || webmachine_test_error('No response yet. Issue a request first!')
30
+ end
31
+
32
+ # Set a single header for the next request.
33
+ def header(name, value)
34
+ @headers[name] = value
35
+ end
36
+
37
+ # Set the request body.
38
+ def body(value)
39
+ @body = value.respond_to?(:read) ? value : StringIO.new(value.to_s)
40
+ end
41
+
42
+ HTTP_METHODS.each do |method|
43
+ class_eval <<-__RUBY
44
+ def #{method.downcase}(uri, options = {})
45
+ do_request('#{method.upcase}', uri, options)
46
+ end
47
+ __RUBY
48
+ end
49
+
50
+ private
51
+ def webmachine_test_error(msg)
52
+ raise Webmachine::Test::Error.new(msg)
53
+ end
54
+
55
+ def do_request(method, uri, options)
56
+ uri = URI.parse(uri)
57
+ uri.scheme ||= 'http'
58
+ uri.host ||= 'localhost'
59
+
60
+ add_query_params(uri, options[:params])
61
+
62
+ # Set some default headers and merge the provided ones.
63
+ @headers['Host'] = [uri.host, uri.port].compact.join(':') unless @headers['Host']
64
+ @headers['Accept'] = '*/*' unless @headers['Accept']
65
+
66
+ options[:headers] ||= {}
67
+ options[:headers].each { |k, v| @headers[k] = v }
68
+
69
+ @body ||= options[:body] || StringIO.new
70
+
71
+ @req = Webmachine::Request.new(method, uri, @headers, @body)
72
+ @res = Webmachine::Response.new
73
+
74
+ @app.dispatcher.dispatch(@req, @res)
75
+ return @res
76
+ end
77
+
78
+ def add_query_params(uri, params)
79
+ if params
80
+ q = params.map do |k, v|
81
+ k, v = URI.encode_www_form_component(k), URI.encode_www_form_component(v)
82
+ "#{k}=#{v}"
83
+ end.join('&')
84
+
85
+ uri.query = uri.query ? [uri.query, q].join('&') : q
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,5 @@
1
+ module Webmachine
2
+ module Test
3
+ VERSION = '0.1.0'
4
+ end
5
+ end
@@ -0,0 +1,22 @@
1
+ require 'forwardable'
2
+ require 'webmachine'
3
+ require 'webmachine/test/session'
4
+
5
+ module Webmachine
6
+ module Test
7
+ extend Forwardable
8
+
9
+ # Exception class for Test errors.
10
+ class Error < StandardError
11
+ end
12
+
13
+ def current_session
14
+ @session ||= Webmachine::Test::Session.new(app)
15
+ end
16
+
17
+ def_delegators :current_session, :request, :header, :headers, :body, :response,
18
+ :get, :post, :put, :patch, :delete,
19
+ :options, :head
20
+ end
21
+ end
22
+
@@ -0,0 +1,11 @@
1
+ require 'webmachine'
2
+
3
+ class TestResource < Webmachine::Resource
4
+ def content_types_provided
5
+ [['text/plain', :to_text]]
6
+ end
7
+
8
+ def to_text
9
+ 'OK'
10
+ end
11
+ end
@@ -0,0 +1,19 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ require 'webmachine/application'
5
+ require 'webmachine/test'
6
+ require 'fixtures/test_resource'
7
+
8
+ module WebmachineTestApplication
9
+ def app
10
+ @app ||= Webmachine::Application.new.tap do |test_app|
11
+ test_app.add_route(['*'], TestResource)
12
+ end
13
+ end
14
+ end
15
+
16
+ RSpec.configure do |c|
17
+ c.include WebmachineTestApplication
18
+ end
19
+
@@ -0,0 +1,145 @@
1
+ require 'spec_helper'
2
+
3
+ describe Webmachine::Test::Session do
4
+ include Webmachine::Test
5
+
6
+ describe "#request" do
7
+ it "returns the Webmachine::Request object" do
8
+ get '/'
9
+ request.should be_a(Webmachine::Request)
10
+ end
11
+
12
+ context "without a request" do
13
+ it "raises an exception" do
14
+ expect { request }.to raise_error(Webmachine::Test::Error)
15
+ end
16
+ end
17
+ end
18
+
19
+ describe "#response" do
20
+ it "returns the Webmachine::Response object" do
21
+ get '/'
22
+ response.should be_a(Webmachine::Response)
23
+ end
24
+
25
+ context "without a request" do
26
+ it "raises an exception" do
27
+ expect { response }.to raise_error(Webmachine::Test::Error)
28
+ end
29
+ end
30
+ end
31
+
32
+ shared_examples_for "a HTTP verb" do
33
+ it "executes a GET request" do
34
+ send verb, '/'
35
+ request.method.should == verb.upcase
36
+ end
37
+
38
+ it "sets the provided header" do
39
+ send verb, '/', :headers => {'Accept' => 'application/x-gunzip'}
40
+ request.headers['Accept'].should == 'application/x-gunzip'
41
+ end
42
+
43
+ context "with a complete URI" do
44
+ it "sets the correct host header" do
45
+ send verb, 'http://example.com:3000/foo'
46
+ request.headers['Host'].should == 'example.com:3000'
47
+ end
48
+ end
49
+
50
+ context "with an incomplete URI" do
51
+ it "sets the correct host header" do
52
+ send verb, '/foo'
53
+ request.headers['Host'].should == 'localhost'
54
+ end
55
+ end
56
+
57
+ it "accepts query parameters in the path" do
58
+ send verb,'/?lang=en&foo=bar'
59
+ request.query['lang'].should == 'en'
60
+ request.query['foo'].should == 'bar'
61
+ end
62
+
63
+ it "accepts query parameters in the options hash" do
64
+ send verb, '/?foo=bar', :params => {'lang' => 'en'}
65
+ request.query['lang'].should == 'en'
66
+ request.query['foo'].should == 'bar'
67
+ end
68
+
69
+ it "escapes the query parameters" do
70
+ expect {
71
+ send verb, '/', :params => {'test' => 'foo bar'}
72
+ }.to_not raise_error(URI::InvalidComponentError)
73
+ end
74
+
75
+ it "encodes the query key and value." do
76
+ send verb, '/', :params => { "foo=" => "bar=" }
77
+ request.uri.query.should == "foo%3D=bar%3D"
78
+ end
79
+
80
+ it "returns the Webmachine::Request object" do
81
+ send(verb, '/').should be_a(Webmachine::Response)
82
+ end
83
+ end
84
+
85
+ describe "#get" do
86
+ let(:verb) { 'get' }
87
+ it_should_behave_like "a HTTP verb"
88
+ end
89
+
90
+ describe "#post" do
91
+ let(:verb) { 'post' }
92
+ it_should_behave_like "a HTTP verb"
93
+ end
94
+
95
+ describe "#put" do
96
+ let(:verb) { 'put' }
97
+ it_should_behave_like "a HTTP verb"
98
+ end
99
+
100
+ describe "#patch" do
101
+ let(:verb) { 'patch' }
102
+ it_should_behave_like "a HTTP verb"
103
+ end
104
+
105
+ describe "#delete" do
106
+ let(:verb) { 'delete' }
107
+ it_should_behave_like "a HTTP verb"
108
+ end
109
+
110
+ describe "#head" do
111
+ let(:verb) { 'head' }
112
+ it_should_behave_like "a HTTP verb"
113
+ end
114
+
115
+ describe "#options" do
116
+ let(:verb) { 'options' }
117
+ it_should_behave_like "a HTTP verb"
118
+ end
119
+
120
+ describe "#header" do
121
+ it "sets the given header value" do
122
+ header('Foo', 'bar-baz')
123
+ get '/'
124
+ request.headers['Foo'].should == 'bar-baz'
125
+ end
126
+ end
127
+
128
+ describe "#body" do
129
+ context "given a string" do
130
+ it "sets the body" do
131
+ body('test body')
132
+ get '/'
133
+ request.body.read.should == 'test body'
134
+ end
135
+ end
136
+
137
+ context "given an IO object" do
138
+ it "sets the body" do
139
+ body(StringIO.new('foo'))
140
+ get '/'
141
+ request.body.read.should == 'foo'
142
+ end
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "webmachine/test/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "webmachine-test"
7
+ s.version = Webmachine::Test::VERSION
8
+ s.authors = ["Bernd Ahlers"]
9
+ s.email = ["bernd@tuneafish.de"]
10
+ s.homepage = ""
11
+ s.summary = %q{Test API for webmachine-ruby}
12
+ s.description = <<-DESC.gsub(/\s+/, ' ')
13
+ Webmachine::Test provides a testing API for webmachine-ruby inspired
14
+ by rack-test.
15
+ DESC
16
+
17
+ s.rubyforge_project = "webmachine-test"
18
+
19
+ s.files = `git ls-files`.split("\n").reject {|f| f =~ /^\./ }
20
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
21
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
22
+ s.require_paths = ["lib"]
23
+
24
+ s.add_runtime_dependency(%q<webmachine>)
25
+ end
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: webmachine-test
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Bernd Ahlers
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-07-07 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: webmachine
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ description: ! ' Webmachine::Test provides a testing API for webmachine-ruby inspired
31
+ by rack-test. '
32
+ email:
33
+ - bernd@tuneafish.de
34
+ executables: []
35
+ extensions: []
36
+ extra_rdoc_files: []
37
+ files:
38
+ - Gemfile
39
+ - README.md
40
+ - Rakefile
41
+ - lib/webmachine/test.rb
42
+ - lib/webmachine/test/backports/uri.rb
43
+ - lib/webmachine/test/session.rb
44
+ - lib/webmachine/test/version.rb
45
+ - spec/fixtures/test_resource.rb
46
+ - spec/spec_helper.rb
47
+ - spec/webmachine/test/session_spec.rb
48
+ - webmachine-test.gemspec
49
+ homepage: ''
50
+ licenses: []
51
+ post_install_message:
52
+ rdoc_options: []
53
+ require_paths:
54
+ - lib
55
+ required_ruby_version: !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ! '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ! '>='
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ requirements: []
68
+ rubyforge_project: webmachine-test
69
+ rubygems_version: 1.8.24
70
+ signing_key:
71
+ specification_version: 3
72
+ summary: Test API for webmachine-ruby
73
+ test_files: []