joebadmo-rack-test 0.6.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.
- data/.document +4 -0
- data/.gitignore +6 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +31 -0
- data/History.txt +163 -0
- data/MIT-LICENSE.txt +19 -0
- data/README.rdoc +60 -0
- data/Rakefile +33 -0
- data/Thorfile +114 -0
- data/lib/rack/mock_session.rb +66 -0
- data/lib/rack/test.rb +302 -0
- data/lib/rack/test/cookie_jar.rb +176 -0
- data/lib/rack/test/methods.rb +82 -0
- data/lib/rack/test/mock_digest_request.rb +29 -0
- data/lib/rack/test/uploaded_file.rb +50 -0
- data/lib/rack/test/utils.rb +136 -0
- data/rack-test.gemspec +80 -0
- data/spec/fixtures/bar.txt +1 -0
- data/spec/fixtures/config.ru +3 -0
- data/spec/fixtures/fake_app.rb +143 -0
- data/spec/fixtures/foo.txt +1 -0
- data/spec/rack/test/cookie_spec.rb +211 -0
- data/spec/rack/test/digest_auth_spec.rb +46 -0
- data/spec/rack/test/multipart_spec.rb +145 -0
- data/spec/rack/test/uploaded_file_spec.rb +22 -0
- data/spec/rack/test/utils_spec.rb +122 -0
- data/spec/rack/test_spec.rb +489 -0
- data/spec/spec_helper.rb +66 -0
- data/spec/support/matchers/body.rb +9 -0
- data/spec/support/matchers/challenge.rb +11 -0
- metadata +110 -0
@@ -0,0 +1,82 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
|
3
|
+
module Rack
|
4
|
+
module Test
|
5
|
+
|
6
|
+
# This module serves as the primary integration point for using Rack::Test
|
7
|
+
# in a testing environment. It depends on an app method being defined in the
|
8
|
+
# same context, and provides the Rack::Test API methods (see Rack::Test::Session
|
9
|
+
# for their documentation).
|
10
|
+
#
|
11
|
+
# Example:
|
12
|
+
#
|
13
|
+
# class HomepageTest < Test::Unit::TestCase
|
14
|
+
# include Rack::Test::Methods
|
15
|
+
#
|
16
|
+
# def app
|
17
|
+
# MyApp.new
|
18
|
+
# end
|
19
|
+
# end
|
20
|
+
module Methods
|
21
|
+
extend Forwardable
|
22
|
+
|
23
|
+
def rack_mock_session(name = :default) # :nodoc:
|
24
|
+
return build_rack_mock_session unless name
|
25
|
+
|
26
|
+
@_rack_mock_sessions ||= {}
|
27
|
+
@_rack_mock_sessions[name] ||= build_rack_mock_session
|
28
|
+
end
|
29
|
+
|
30
|
+
def build_rack_mock_session # :nodoc:
|
31
|
+
Rack::MockSession.new(app)
|
32
|
+
end
|
33
|
+
|
34
|
+
def rack_test_session(name = :default) # :nodoc:
|
35
|
+
return build_rack_test_session(name) unless name
|
36
|
+
|
37
|
+
@_rack_test_sessions ||= {}
|
38
|
+
@_rack_test_sessions[name] ||= build_rack_test_session(name)
|
39
|
+
end
|
40
|
+
|
41
|
+
def build_rack_test_session(name) # :nodoc:
|
42
|
+
Rack::Test::Session.new(rack_mock_session(name))
|
43
|
+
end
|
44
|
+
|
45
|
+
def current_session # :nodoc:
|
46
|
+
rack_test_session(_current_session_names.last)
|
47
|
+
end
|
48
|
+
|
49
|
+
def with_session(name) # :nodoc:
|
50
|
+
_current_session_names.push(name)
|
51
|
+
yield rack_test_session(name)
|
52
|
+
_current_session_names.pop
|
53
|
+
end
|
54
|
+
|
55
|
+
def _current_session_names # :nodoc:
|
56
|
+
@_current_session_names ||= [:default]
|
57
|
+
end
|
58
|
+
|
59
|
+
METHODS = [
|
60
|
+
:request,
|
61
|
+
:get,
|
62
|
+
:post,
|
63
|
+
:put,
|
64
|
+
:patch,
|
65
|
+
:delete,
|
66
|
+
:options,
|
67
|
+
:head,
|
68
|
+
:follow_redirect!,
|
69
|
+
:header,
|
70
|
+
:set_cookie,
|
71
|
+
:clear_cookies,
|
72
|
+
:authorize,
|
73
|
+
:basic_authorize,
|
74
|
+
:digest_authorize,
|
75
|
+
:last_response,
|
76
|
+
:last_request
|
77
|
+
]
|
78
|
+
|
79
|
+
def_delegators :current_session, *METHODS
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Rack
|
2
|
+
module Test
|
3
|
+
|
4
|
+
class MockDigestRequest # :nodoc:
|
5
|
+
|
6
|
+
def initialize(params)
|
7
|
+
@params = params
|
8
|
+
end
|
9
|
+
|
10
|
+
def method_missing(sym)
|
11
|
+
if @params.has_key? k = sym.to_s
|
12
|
+
return @params[k]
|
13
|
+
end
|
14
|
+
|
15
|
+
super
|
16
|
+
end
|
17
|
+
|
18
|
+
def method
|
19
|
+
@params['method']
|
20
|
+
end
|
21
|
+
|
22
|
+
def response(password)
|
23
|
+
Rack::Auth::Digest::MD5.new(nil).send :digest, self, password
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require "tempfile"
|
2
|
+
require "fileutils"
|
3
|
+
|
4
|
+
module Rack
|
5
|
+
module Test
|
6
|
+
|
7
|
+
# Wraps a Tempfile with a content type. Including one or more UploadedFile's
|
8
|
+
# in the params causes Rack::Test to build and issue a multipart request.
|
9
|
+
#
|
10
|
+
# Example:
|
11
|
+
# post "/photos", "file" => Rack::Test::UploadedFile.new("me.jpg", "image/jpeg")
|
12
|
+
class UploadedFile
|
13
|
+
|
14
|
+
# The filename, *not* including the path, of the "uploaded" file
|
15
|
+
attr_reader :original_filename
|
16
|
+
|
17
|
+
# The content type of the "uploaded" file
|
18
|
+
attr_accessor :content_type
|
19
|
+
|
20
|
+
def initialize(path, content_type = "text/plain", binary = false)
|
21
|
+
raise "#{path} file does not exist" unless ::File.exist?(path)
|
22
|
+
|
23
|
+
@content_type = content_type
|
24
|
+
@original_filename = ::File.basename(path)
|
25
|
+
|
26
|
+
@tempfile = Tempfile.new(@original_filename)
|
27
|
+
@tempfile.set_encoding(Encoding::BINARY) if @tempfile.respond_to?(:set_encoding)
|
28
|
+
@tempfile.binmode if binary
|
29
|
+
|
30
|
+
FileUtils.copy_file(path, @tempfile.path)
|
31
|
+
end
|
32
|
+
|
33
|
+
def path
|
34
|
+
@tempfile.path
|
35
|
+
end
|
36
|
+
|
37
|
+
alias_method :local_path, :path
|
38
|
+
|
39
|
+
def method_missing(method_name, *args, &block) #:nodoc:
|
40
|
+
@tempfile.__send__(method_name, *args, &block)
|
41
|
+
end
|
42
|
+
|
43
|
+
def respond_to?(method_name, include_private = false) #:nodoc:
|
44
|
+
@tempfile.respond_to?(method_name, include_private) || super
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
module Rack
|
2
|
+
module Test
|
3
|
+
|
4
|
+
module Utils # :nodoc:
|
5
|
+
include Rack::Utils
|
6
|
+
|
7
|
+
def build_nested_query(value, prefix = nil)
|
8
|
+
case value
|
9
|
+
when Array
|
10
|
+
value.map do |v|
|
11
|
+
unless unescape(prefix) =~ /\[\]$/
|
12
|
+
prefix = "#{prefix}[]"
|
13
|
+
end
|
14
|
+
build_nested_query(v, "#{prefix}")
|
15
|
+
end.join("&")
|
16
|
+
when Hash
|
17
|
+
value.map do |k, v|
|
18
|
+
build_nested_query(v, prefix ? "#{prefix}[#{escape(k)}]" : escape(k))
|
19
|
+
end.join("&")
|
20
|
+
when NilClass
|
21
|
+
prefix.to_s
|
22
|
+
else
|
23
|
+
"#{prefix}=#{escape(value)}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
module_function :build_nested_query
|
28
|
+
|
29
|
+
def build_multipart(params, first = true)
|
30
|
+
if first
|
31
|
+
unless params.is_a?(Hash)
|
32
|
+
raise ArgumentError, "value must be a Hash"
|
33
|
+
end
|
34
|
+
|
35
|
+
multipart = false
|
36
|
+
query = lambda { |value|
|
37
|
+
case value
|
38
|
+
when Array
|
39
|
+
value.each(&query)
|
40
|
+
when Hash
|
41
|
+
value.values.each(&query)
|
42
|
+
when UploadedFile
|
43
|
+
multipart = true
|
44
|
+
end
|
45
|
+
}
|
46
|
+
params.values.each(&query)
|
47
|
+
return nil unless multipart
|
48
|
+
end
|
49
|
+
|
50
|
+
flattened_params = Hash.new
|
51
|
+
|
52
|
+
params.each do |key, value|
|
53
|
+
k = first ? key.to_s : "[#{key}]"
|
54
|
+
|
55
|
+
case value
|
56
|
+
when Array
|
57
|
+
value.map do |v|
|
58
|
+
|
59
|
+
if (v.is_a?(Hash))
|
60
|
+
build_multipart(v, false).each { |subkey, subvalue|
|
61
|
+
flattened_params["#{k}[]#{subkey}"] = subvalue
|
62
|
+
}
|
63
|
+
else
|
64
|
+
flattened_params["#{k}[]"] = value
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
when Hash
|
69
|
+
build_multipart(value, false).each { |subkey, subvalue|
|
70
|
+
flattened_params[k + subkey] = subvalue
|
71
|
+
}
|
72
|
+
else
|
73
|
+
flattened_params[k] = value
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
if first
|
78
|
+
build_parts(flattened_params)
|
79
|
+
else
|
80
|
+
flattened_params
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
module_function :build_multipart
|
85
|
+
|
86
|
+
private
|
87
|
+
def build_parts(parameters)
|
88
|
+
parameters.map { |name, value|
|
89
|
+
if value.respond_to?(:original_filename)
|
90
|
+
build_file_part(name, value)
|
91
|
+
|
92
|
+
elsif value.is_a?(Array) and value.all? { |v| v.respond_to?(:original_filename) }
|
93
|
+
value.map do |v|
|
94
|
+
build_file_part(name, v)
|
95
|
+
end.join
|
96
|
+
|
97
|
+
else
|
98
|
+
primitive_part = build_primitive_part(name, value)
|
99
|
+
Rack::Test.encoding_aware_strings? ? primitive_part.force_encoding('BINARY') : primitive_part
|
100
|
+
end
|
101
|
+
|
102
|
+
}.join + "--#{MULTIPART_BOUNDARY}--\r"
|
103
|
+
end
|
104
|
+
|
105
|
+
def build_primitive_part(parameter_name, value)
|
106
|
+
unless value.is_a? Array
|
107
|
+
value = [value]
|
108
|
+
end
|
109
|
+
value.map do |v|
|
110
|
+
<<-EOF
|
111
|
+
--#{MULTIPART_BOUNDARY}\r
|
112
|
+
Content-Disposition: form-data; name="#{parameter_name}"\r
|
113
|
+
\r
|
114
|
+
#{v}\r
|
115
|
+
EOF
|
116
|
+
end.join
|
117
|
+
end
|
118
|
+
|
119
|
+
def build_file_part(parameter_name, uploaded_file)
|
120
|
+
::File.open(uploaded_file.path, "rb") do |physical_file|
|
121
|
+
physical_file.set_encoding(Encoding::BINARY) if physical_file.respond_to?(:set_encoding)
|
122
|
+
<<-EOF
|
123
|
+
--#{MULTIPART_BOUNDARY}\r
|
124
|
+
Content-Disposition: form-data; name="#{parameter_name}"; filename="#{escape(uploaded_file.original_filename)}"\r
|
125
|
+
Content-Type: #{uploaded_file.content_type}\r
|
126
|
+
Content-Length: #{::File.stat(uploaded_file.path).size}\r
|
127
|
+
\r
|
128
|
+
#{physical_file.read}\r
|
129
|
+
EOF
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
end
|
data/rack-test.gemspec
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = 'joebadmo-rack-test'
|
5
|
+
s.version = "0.6.1"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Bryan Helmkamp"]
|
9
|
+
s.date = %q{2011-07-27}
|
10
|
+
s.description = %q{Rack::Test is a small, simple testing API for Rack apps. It can be used on its
|
11
|
+
own or as a reusable starting point for Web frameworks and testing libraries
|
12
|
+
to build on. Most of its initial functionality is an extraction of Merb 1.0's
|
13
|
+
request helpers feature.}
|
14
|
+
s.email = %q{bryan@brynary.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"README.rdoc",
|
17
|
+
"MIT-LICENSE.txt"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".gitignore",
|
22
|
+
"Gemfile",
|
23
|
+
"Gemfile.lock",
|
24
|
+
"History.txt",
|
25
|
+
"MIT-LICENSE.txt",
|
26
|
+
"README.rdoc",
|
27
|
+
"Rakefile",
|
28
|
+
"Thorfile",
|
29
|
+
"lib/rack/mock_session.rb",
|
30
|
+
"lib/rack/test.rb",
|
31
|
+
"lib/rack/test/cookie_jar.rb",
|
32
|
+
"lib/rack/test/methods.rb",
|
33
|
+
"lib/rack/test/mock_digest_request.rb",
|
34
|
+
"lib/rack/test/uploaded_file.rb",
|
35
|
+
"lib/rack/test/utils.rb",
|
36
|
+
"rack-test.gemspec",
|
37
|
+
"spec/fixtures/bar.txt",
|
38
|
+
"spec/fixtures/config.ru",
|
39
|
+
"spec/fixtures/fake_app.rb",
|
40
|
+
"spec/fixtures/foo.txt",
|
41
|
+
"spec/rack/test/cookie_spec.rb",
|
42
|
+
"spec/rack/test/digest_auth_spec.rb",
|
43
|
+
"spec/rack/test/multipart_spec.rb",
|
44
|
+
"spec/rack/test/uploaded_file_spec.rb",
|
45
|
+
"spec/rack/test/utils_spec.rb",
|
46
|
+
"spec/rack/test_spec.rb",
|
47
|
+
"spec/spec_helper.rb",
|
48
|
+
"spec/support/matchers/body.rb",
|
49
|
+
"spec/support/matchers/challenge.rb"
|
50
|
+
]
|
51
|
+
s.homepage = %q{http://github.com/brynary/rack-test}
|
52
|
+
s.require_paths = ["lib"]
|
53
|
+
s.rubyforge_project = %q{rack-test}
|
54
|
+
s.rubygems_version = %q{1.6.1}
|
55
|
+
s.summary = %q{Simple testing API built on Rack}
|
56
|
+
s.test_files = [
|
57
|
+
"spec/fixtures/fake_app.rb",
|
58
|
+
"spec/rack/test/cookie_spec.rb",
|
59
|
+
"spec/rack/test/digest_auth_spec.rb",
|
60
|
+
"spec/rack/test/multipart_spec.rb",
|
61
|
+
"spec/rack/test/uploaded_file_spec.rb",
|
62
|
+
"spec/rack/test/utils_spec.rb",
|
63
|
+
"spec/rack/test_spec.rb",
|
64
|
+
"spec/spec_helper.rb",
|
65
|
+
"spec/support/matchers/body.rb",
|
66
|
+
"spec/support/matchers/challenge.rb"
|
67
|
+
]
|
68
|
+
|
69
|
+
if s.respond_to? :specification_version then
|
70
|
+
s.specification_version = 3
|
71
|
+
|
72
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
73
|
+
s.add_runtime_dependency(%q<rack>, [">= 1.0"])
|
74
|
+
else
|
75
|
+
s.add_dependency(%q<rack>, [">= 1.0"])
|
76
|
+
end
|
77
|
+
else
|
78
|
+
s.add_dependency(%q<rack>, [">= 1.0"])
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
baz
|
@@ -0,0 +1,143 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "sinatra/base"
|
3
|
+
|
4
|
+
module Rack
|
5
|
+
module Test
|
6
|
+
|
7
|
+
class FakeApp < Sinatra::Base
|
8
|
+
head "/" do
|
9
|
+
"meh"
|
10
|
+
end
|
11
|
+
|
12
|
+
options "/" do
|
13
|
+
[200, {}, ""]
|
14
|
+
end
|
15
|
+
|
16
|
+
get "/" do
|
17
|
+
"Hello, GET: #{params.inspect}"
|
18
|
+
end
|
19
|
+
|
20
|
+
get "/redirect" do
|
21
|
+
redirect "/redirected"
|
22
|
+
end
|
23
|
+
|
24
|
+
get "/redirected" do
|
25
|
+
"You've been redirected"
|
26
|
+
end
|
27
|
+
|
28
|
+
get "/void" do
|
29
|
+
[200, {}, ""]
|
30
|
+
end
|
31
|
+
|
32
|
+
get "/cookies/show" do
|
33
|
+
request.cookies.inspect
|
34
|
+
end
|
35
|
+
|
36
|
+
get "/COOKIES/show" do
|
37
|
+
request.cookies.inspect
|
38
|
+
end
|
39
|
+
|
40
|
+
get "/not-cookies/show" do
|
41
|
+
request.cookies.inspect
|
42
|
+
end
|
43
|
+
|
44
|
+
get "/cookies/set-secure" do
|
45
|
+
raise if params["value"].nil?
|
46
|
+
|
47
|
+
response.set_cookie("secure-cookie", :value => params["value"], :secure => true)
|
48
|
+
"Set"
|
49
|
+
end
|
50
|
+
|
51
|
+
get "/cookies/set-simple" do
|
52
|
+
raise if params["value"].nil?
|
53
|
+
|
54
|
+
response.set_cookie "simple", params["value"]
|
55
|
+
"Set"
|
56
|
+
end
|
57
|
+
|
58
|
+
post "/cookies/default-path" do
|
59
|
+
raise if params["value"].nil?
|
60
|
+
|
61
|
+
response.set_cookie "simple", params["value"]
|
62
|
+
"Set"
|
63
|
+
end
|
64
|
+
|
65
|
+
get "/cookies/default-path" do
|
66
|
+
response.cookies.inspect
|
67
|
+
end
|
68
|
+
|
69
|
+
get "/cookies/delete" do
|
70
|
+
response.delete_cookie "value"
|
71
|
+
end
|
72
|
+
|
73
|
+
get "/cookies/count" do
|
74
|
+
old_value = request.cookies["count"].to_i || 0
|
75
|
+
new_value = (old_value + 1).to_s
|
76
|
+
|
77
|
+
response.set_cookie("count", :value => new_value)
|
78
|
+
new_value
|
79
|
+
end
|
80
|
+
|
81
|
+
get "/cookies/set" do
|
82
|
+
raise if params["value"].nil?
|
83
|
+
|
84
|
+
response.set_cookie("value", {
|
85
|
+
:value => params["value"],
|
86
|
+
:path => "/cookies",
|
87
|
+
:expires => Time.now + 10
|
88
|
+
})
|
89
|
+
"Set"
|
90
|
+
end
|
91
|
+
|
92
|
+
get "/cookies/domain" do
|
93
|
+
old_value = request.cookies["count"].to_i || 0
|
94
|
+
new_value = (old_value + 1).to_s
|
95
|
+
|
96
|
+
response.set_cookie("count", :value => new_value, :domain => "localhost.com")
|
97
|
+
new_value
|
98
|
+
end
|
99
|
+
|
100
|
+
get "/cookies/subdomain" do
|
101
|
+
old_value = request.cookies["count"].to_i || 0
|
102
|
+
new_value = (old_value + 1).to_s
|
103
|
+
|
104
|
+
response.set_cookie("count", :value => new_value, :domain => ".example.org")
|
105
|
+
new_value
|
106
|
+
end
|
107
|
+
|
108
|
+
get "/cookies/set-uppercase" do
|
109
|
+
raise if params["value"].nil?
|
110
|
+
|
111
|
+
response.set_cookie("VALUE", {
|
112
|
+
:value => params["value"],
|
113
|
+
:path => "/cookies",
|
114
|
+
:expires => Time.now + 10
|
115
|
+
})
|
116
|
+
"Set"
|
117
|
+
end
|
118
|
+
|
119
|
+
get "/cookies/set-multiple" do
|
120
|
+
response.set_cookie("key1", :value => "value1")
|
121
|
+
response.set_cookie("key2", :value => "value2")
|
122
|
+
"Set"
|
123
|
+
end
|
124
|
+
|
125
|
+
post "/" do
|
126
|
+
"Hello, POST: #{params.inspect}"
|
127
|
+
end
|
128
|
+
|
129
|
+
put "/" do
|
130
|
+
"Hello, PUT: #{params.inspect}"
|
131
|
+
end
|
132
|
+
|
133
|
+
patch "/" do
|
134
|
+
"Hello, PUT: #{params.inspect}"
|
135
|
+
end
|
136
|
+
|
137
|
+
delete "/" do
|
138
|
+
"Hello, DELETE: #{params.inspect}"
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
end
|