mosquito 0.1.2 → 0.1.3
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/CHANGELOG +22 -0
- data/Manifest.txt +10 -16
- data/README.txt +54 -29
- data/Rakefile +29 -2
- data/lib/mosquito.rb +444 -87
- data/public/bare.rb +71 -0
- data/public/blog.rb +1 -6
- data/public/blog/controllers.rb +157 -110
- data/public/blog/models.rb +8 -9
- data/public/blog/views.rb +59 -61
- data/test/sage_advice_cases/parsing_arrays.rb +25 -0
- data/test/test_bare.rb +66 -0
- data/test/test_blog.rb +140 -26
- data/test/test_helpers.rb +20 -0
- data/test/test_mock_request.rb +292 -0
- data/test/test_mock_upload.rb +55 -0
- metadata +31 -18
- data/public/homepage.rb +0 -64
- data/test/test_homepage.rb +0 -23
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'camping'
|
3
|
+
|
4
|
+
Camping.goes :ParsingArrays
|
5
|
+
|
6
|
+
class ParsingArrays::Controllers::Klonk < ParsingArrays::Controllers::R('/')
|
7
|
+
def get; render :foam; end
|
8
|
+
def post; input.inspect; end
|
9
|
+
end
|
10
|
+
|
11
|
+
module ParsingArrays::Views
|
12
|
+
def foam
|
13
|
+
h2 "This is multipart with arrays"
|
14
|
+
form(:method => :post, :enctype => 'multipart/form-data') { _inputs }
|
15
|
+
h2 "This is urlencoded with arrays"
|
16
|
+
form(:method => :post, :enctype => 'application/x-www-form-urlencoded') { _inputs }
|
17
|
+
end
|
18
|
+
|
19
|
+
def _inputs
|
20
|
+
input :type => :text, :name => "array", :value => '1'
|
21
|
+
input :type => :text, :name => "array", :value => '2'
|
22
|
+
input :type => :text, :name => "array", :value => '3'
|
23
|
+
input :type => :submit, :name => 'flush', :value => 'Observe'
|
24
|
+
end
|
25
|
+
end
|
data/test/test_bare.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/../lib/mosquito"
|
2
|
+
require File.dirname(__FILE__) + "/../public/bare"
|
3
|
+
|
4
|
+
# When you got a few Camping apps in one process you actually install the session
|
5
|
+
# for all of them simply by including. We want to test operation without sessions so we
|
6
|
+
# call this app Bare, which comes before Blog.
|
7
|
+
class TestBare < Camping::FunctionalTest
|
8
|
+
|
9
|
+
test "should get index with success" do
|
10
|
+
get '/'
|
11
|
+
assert_response :success
|
12
|
+
assert_no_session
|
13
|
+
assert_match_body %r!Charles!
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_get_without_arguments_should_give_us_the_index_page
|
17
|
+
get
|
18
|
+
assert_response :success
|
19
|
+
assert_match_body %r!Charles!
|
20
|
+
end
|
21
|
+
|
22
|
+
test "should get page with success" do
|
23
|
+
get '/sample'
|
24
|
+
assert_response :success
|
25
|
+
assert_no_session
|
26
|
+
assert_match_body %r!<p>A sample page</p>!
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_request_uri_preserves_query_vars
|
30
|
+
get '/sample', :somevar => 10
|
31
|
+
assert_equal '/bare/sample?somevar=10', @request['REQUEST_URI']
|
32
|
+
end
|
33
|
+
|
34
|
+
test "should assert_no_match_body" do
|
35
|
+
get '/sample'
|
36
|
+
assert_no_match_body /Rubber\s+Bubblegum\s+Burt Reynolds\s+Hippopotamus/
|
37
|
+
end
|
38
|
+
|
39
|
+
test "should return error" do
|
40
|
+
get '/error'
|
41
|
+
assert_response :error
|
42
|
+
end
|
43
|
+
|
44
|
+
test "should return 404 error" do
|
45
|
+
get '/error404'
|
46
|
+
assert_response 404
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_assigning_verbatim_post_payload
|
50
|
+
post '/sample', 'foo=bar&plain=flat'
|
51
|
+
@request.body.rewind
|
52
|
+
assert_equal 'foo=bar&plain=flat', @request.body.read
|
53
|
+
end
|
54
|
+
|
55
|
+
test "should redirect" do
|
56
|
+
get '/redirect'
|
57
|
+
assert_redirected_to '/faq'
|
58
|
+
end
|
59
|
+
|
60
|
+
# test "should send file" do
|
61
|
+
# get '/file'
|
62
|
+
# assert_response :success
|
63
|
+
# # TODO
|
64
|
+
# end
|
65
|
+
|
66
|
+
end
|
data/test/test_blog.rb
CHANGED
@@ -1,31 +1,51 @@
|
|
1
1
|
require File.dirname(__FILE__) + "/../lib/mosquito"
|
2
2
|
require File.dirname(__FILE__) + "/../public/blog"
|
3
|
-
|
4
3
|
Blog.create
|
5
4
|
include Blog::Models
|
6
5
|
|
7
6
|
class TestBlog < Camping::FunctionalTest
|
8
|
-
|
9
7
|
fixtures :blog_posts, :blog_users, :blog_comments
|
10
|
-
|
8
|
+
|
11
9
|
def setup
|
12
10
|
super
|
13
|
-
#
|
11
|
+
# We inject the session into the blog here to prevent it from attaching to Bare as well. Normally this
|
12
|
+
# should not happen but we need to take sides to test for sessioneless Camping compliance.
|
13
|
+
unless @sesion_set
|
14
|
+
Blog.send(:include, Camping::Session)
|
15
|
+
ActiveRecord::Migration.suppress_messages do
|
16
|
+
::Camping::Models::Session.create_schema
|
17
|
+
end
|
18
|
+
@sesion_set = true
|
19
|
+
end
|
14
20
|
end
|
15
|
-
|
21
|
+
|
16
22
|
def test_cookies
|
17
23
|
get '/cookies'
|
18
|
-
assert_cookie 'awesome_cookie', 'camping
|
24
|
+
assert_cookie 'awesome_cookie', 'camping for good'
|
25
|
+
assert_equal @state.awesome_data, 'camping for good'
|
26
|
+
get '/'
|
19
27
|
assert_equal @state.awesome_data, 'camping for good'
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_cookies_persisted_across_requests_and_escaping_properly_handled
|
31
|
+
@cookies["asgård"] = 'Wøbble'
|
32
|
+
get '/cookies'
|
33
|
+
assert_equal 'asgård=W%C3%B8bble', @request['HTTP_COOKIE'], "The cookie val shouldbe escaped"
|
34
|
+
assert_response :success
|
35
|
+
assert_equal 'Wøbble', @cookies["asgård"]
|
36
|
+
|
20
37
|
get '/'
|
21
38
|
assert_equal @state.awesome_data, 'camping for good'
|
39
|
+
assert_equal 'Wøbble', @cookies["asgård"]
|
22
40
|
end
|
23
|
-
|
41
|
+
|
24
42
|
def test_index
|
25
43
|
get
|
26
44
|
assert_response :success
|
27
45
|
assert_match_body %r!>blog<!
|
28
46
|
assert_not_equal @state.awesome_data, 'camping for good'
|
47
|
+
assert_kind_of Array, @assigns[:posts]
|
48
|
+
assert_kind_of Post, assigns[:posts].first
|
29
49
|
end
|
30
50
|
|
31
51
|
def test_view
|
@@ -33,7 +53,7 @@ class TestBlog < Camping::FunctionalTest
|
|
33
53
|
assert_response :success
|
34
54
|
assert_match_body %r!The quick fox jumped over the lazy dog!
|
35
55
|
end
|
36
|
-
|
56
|
+
|
37
57
|
def test_styles
|
38
58
|
get 'styles.css'
|
39
59
|
assert_match_body %r!Utopia!
|
@@ -52,20 +72,105 @@ class TestBlog < Camping::FunctionalTest
|
|
52
72
|
|
53
73
|
def test_comment
|
54
74
|
assert_difference(Comment) {
|
55
|
-
post 'comment',
|
56
|
-
|
57
|
-
|
75
|
+
post 'comment', {
|
76
|
+
:post_username => 'jim',
|
77
|
+
:post_body => 'Nice article.',
|
78
|
+
:post_id => 1
|
79
|
+
}
|
58
80
|
assert_response :redirect
|
59
81
|
assert_redirected_to '/view/1'
|
60
82
|
}
|
61
83
|
end
|
62
84
|
|
85
|
+
def test_sage_advice_raised_when_getting_with_files
|
86
|
+
assert_raise(Mosquito::SageAdvice) do
|
87
|
+
get '/view/1', :afile => Mosquito::MockUpload.new("apic.jpg")
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_session_roundtrip_across_successive_requests
|
92
|
+
get '/session-roundtrip'
|
93
|
+
assert @state.has_key?(:flag_in_session)
|
94
|
+
|
95
|
+
assert_session_started
|
96
|
+
post '/session-roundtrip'
|
97
|
+
assert @state.has_key?(:second_flag), "The :second_flag key in the session gets set only if the previous flag was present"
|
98
|
+
assert_session_started
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_request_uri_has_no_double_slashes
|
102
|
+
get '/session-roundtrip'
|
103
|
+
assert_equal "/blog/session-roundtrip", @request['REQUEST_URI']
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_follow_redirect
|
107
|
+
get '/redirector'
|
108
|
+
assert_response :redirect
|
109
|
+
|
110
|
+
assert_redirected_to '/sniffer?one=two'
|
111
|
+
|
112
|
+
follow_redirect
|
113
|
+
roundtipped_params = YAML::load(StringIO.new(@response.body))
|
114
|
+
ref = {"one" => "two"}.with_indifferent_access
|
115
|
+
assert_equal ref, roundtipped_params
|
116
|
+
end
|
117
|
+
|
118
|
+
def test_request_honors_verbatim_query_string_and_passed_params
|
119
|
+
assert_nothing_raised do
|
120
|
+
get '/sniffer?one=2&foo=baz', :taing => 44
|
121
|
+
end
|
122
|
+
|
123
|
+
roundtripped = YAML::load(StringIO.new(@response.body.to_s))
|
124
|
+
ref = {"taing"=>"44", "one" => "2", "foo" => "baz"}
|
125
|
+
assert_equal ref, roundtripped
|
126
|
+
end
|
127
|
+
|
128
|
+
def test_uplaod_gets_a_quick_uplaod_handle
|
129
|
+
file = upload("pic.jpg")
|
130
|
+
assert_kind_of Mosquito::MockUpload, file
|
131
|
+
end
|
132
|
+
|
133
|
+
def test_intrinsic_methods
|
134
|
+
# This WILL use mocks when we get to it from more pressing matters
|
135
|
+
delete '/rest'
|
136
|
+
assert_equal 'Called delete', @response.body
|
137
|
+
|
138
|
+
put '/rest'
|
139
|
+
assert_equal 'Called put', @response.body
|
140
|
+
end
|
141
|
+
|
142
|
+
def calling_with_an_absolute_url_should_relativize
|
143
|
+
assert_equal 'test.host', @request.domain
|
144
|
+
put 'http://test.host/blog/rest'
|
145
|
+
assert_nothing_raised do
|
146
|
+
assert_equal 'Called put', @response.body
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def test_calling_with_an_absolute_url_outside_of_the_default_test_host_must_raise
|
151
|
+
assert_equal 'test.host', @request.domain
|
152
|
+
assert_raise(Mosquito::NonLocalRequest) do
|
153
|
+
put 'http://yahoo.com/blog/rest'
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def test_calling_with_an_absolute_url_outside_of_the_custom_test_host_must_raise
|
158
|
+
@request.domain = 'foo.bar'
|
159
|
+
assert_raise(Mosquito::NonLocalRequest) do
|
160
|
+
put 'http://test.host/blog/rest'
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
63
164
|
end
|
64
165
|
|
65
|
-
class TestPost < Camping::
|
166
|
+
class TestPost < Camping::ModelTest
|
66
167
|
|
67
168
|
fixtures :blog_posts, :blog_users, :blog_comments
|
68
|
-
|
169
|
+
|
170
|
+
def test_fixtures_path_is_relative_to_the_testcase
|
171
|
+
assert_equal 'test/fixtures/', self.class.fixture_path
|
172
|
+
end
|
173
|
+
|
69
174
|
def test_create
|
70
175
|
post = create
|
71
176
|
assert post.valid?
|
@@ -83,19 +188,21 @@ class TestPost < Camping::UnitTest
|
|
83
188
|
assert_equal original_count - 1, Post.count
|
84
189
|
end
|
85
190
|
|
86
|
-
private
|
191
|
+
private
|
87
192
|
|
88
193
|
def create(options={})
|
89
|
-
Post.create({
|
90
|
-
|
91
|
-
|
194
|
+
Post.create({
|
195
|
+
:user_id => 1,
|
196
|
+
:title => "Title",
|
197
|
+
:body => "Body"
|
198
|
+
}.merge(options))
|
92
199
|
end
|
93
|
-
|
200
|
+
|
94
201
|
end
|
95
202
|
|
96
|
-
class TestUser < Camping::
|
203
|
+
class TestUser < Camping::ModelTest
|
97
204
|
|
98
|
-
fixtures :blog_posts, :blog_users, :blog_comments
|
205
|
+
fixtures :blog_posts, :blog_users, :blog_comments
|
99
206
|
|
100
207
|
def test_create
|
101
208
|
user = create
|
@@ -108,12 +215,19 @@ class TestUser < Camping::UnitTest
|
|
108
215
|
assert_not_nil user.errors.on(:username)
|
109
216
|
end
|
110
217
|
|
111
|
-
|
112
|
-
|
218
|
+
test "should require username" do
|
219
|
+
assert_no_difference(User, :count) do
|
220
|
+
User.create(:username => nil)
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
private
|
225
|
+
|
113
226
|
def create(options={})
|
114
|
-
User.create({
|
115
|
-
|
227
|
+
User.create({
|
228
|
+
:username => 'godfrey',
|
229
|
+
:password => 'password'
|
230
|
+
}.merge(options))
|
116
231
|
end
|
117
|
-
|
118
|
-
end
|
119
232
|
|
233
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/../lib/mosquito"
|
2
|
+
|
3
|
+
class TestHelpers < Camping::ModelTest
|
4
|
+
# http://rubyforge.org/tracker/index.php?func=detail&aid=8921&group_id=351&atid=1416
|
5
|
+
def test_supports_old_style_and_new_style_fixture_generation
|
6
|
+
assert self.respond_to?(:create_fixtures), "Oldstyle method should work"
|
7
|
+
assert self.class.respond_to?(:fixtures), "Newstyle method should work"
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_stash_and_unstash
|
11
|
+
someval = {:foo => "bar"}
|
12
|
+
assert_nothing_raised do
|
13
|
+
assert_equal someval, Mosquito::stash(someval)
|
14
|
+
end
|
15
|
+
|
16
|
+
retr = Mosquito.unstash
|
17
|
+
assert_nil Mosquito.unstash, "There is nothing stashed now"
|
18
|
+
assert_equal retr, someval, "The value should be retrieved"
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,292 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/../lib/mosquito"
|
2
|
+
|
3
|
+
$KCODE = 'u'
|
4
|
+
# Sadly, Camping does not mandate UTF-8 - but we will use it here to torment the
|
5
|
+
# URL-escaping routines wïs ze ümlåuts.
|
6
|
+
|
7
|
+
# We use Sniffer to check if our request is parsed properly. After being called Sniffer
|
8
|
+
# will raise a Messenger exception with the @input inside.
|
9
|
+
Camping.goes :Sniffer
|
10
|
+
class Sniffer::Controllers::ParamPeeker < Sniffer::Controllers::R('/')
|
11
|
+
class Messenger < RuntimeError
|
12
|
+
attr_reader :packet
|
13
|
+
def initialize(packet)
|
14
|
+
@packet = packet
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def post
|
19
|
+
raise Messenger.new(input.dup)
|
20
|
+
end
|
21
|
+
alias_method :get, :post
|
22
|
+
end
|
23
|
+
|
24
|
+
class Sniffer::Controllers::ServerError
|
25
|
+
def get(*a)
|
26
|
+
raise a.pop
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class TestMockRequest < Test::Unit::TestCase
|
31
|
+
include Mosquito
|
32
|
+
|
33
|
+
def setup
|
34
|
+
@parsed_input = nil
|
35
|
+
@req = MockRequest.new
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_default_domain_and_port
|
39
|
+
assert_equal 'test.host', @req.to_hash['SERVER_NAME']
|
40
|
+
assert_equal 'test.host', @req.to_hash['HTTP_HOST']
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_envars_translate_to_readers
|
44
|
+
%w( server_name path_info accept_encoding user_agent
|
45
|
+
script_name server_protocol cache_control accept_language
|
46
|
+
host remote_addr server_software keep_alive referer accept_charset
|
47
|
+
version request_uri server_port gateway_interface accept connection
|
48
|
+
request_method).map do | envar |
|
49
|
+
true_value = (@req[envar.upcase] || @req["HTTP_" + envar.upcase])
|
50
|
+
assert_not_nil true_value,
|
51
|
+
"The environment of the default request should provide #{envar.upcase} or HTTP_#{envar.upcase}"
|
52
|
+
assert_nothing_raised do
|
53
|
+
assert_equal true_value, @req.send(envar), "The request should understand the reader for #{envar}"
|
54
|
+
assert_equal true_value, @req.send(envar.upcase), "The request should understand the reader for #{envar.upcase} " +
|
55
|
+
"for backwards compatibility"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_accessor_for_query_string
|
61
|
+
assert @req.respond_to?(:query_string), "The request must have a reader for query string"
|
62
|
+
assert @req.respond_to?(:query_string=), "The request must have a writer for query string"
|
63
|
+
|
64
|
+
qs = "one=two&foo=bar"
|
65
|
+
assert_nothing_raised { @req.query_string = qs }
|
66
|
+
assert_equal "?one=two&foo=bar", @req.query_string,
|
67
|
+
"The request should return the query string segment with a question mark"
|
68
|
+
|
69
|
+
qs = "?one=two&foo=bar"
|
70
|
+
assert_equal "?one=two&foo=bar", @req.query_string,
|
71
|
+
"The request should return the query string segment with one and only one question mark"
|
72
|
+
|
73
|
+
assert_equal '/?one=two&foo=bar', @req['REQUEST_URI'],
|
74
|
+
"The assigned query string should be propargated to REQUEST_URI"
|
75
|
+
|
76
|
+
assert_equal 'one=two&foo=bar', @req['QUERY_STRING'],
|
77
|
+
"The assigned query string should be propargated to QUERY_STRING"
|
78
|
+
|
79
|
+
@req.query_string = ''
|
80
|
+
assert_equal '/', @req['REQUEST_URI'], "The query part should be removed from the REQUEST_URI along with the qmark"
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_query_string_composition_from_params
|
84
|
+
composable_hash = {
|
85
|
+
:foo => "bar",
|
86
|
+
:user => {
|
87
|
+
:login => "boss",
|
88
|
+
:password => "secret",
|
89
|
+
:friend_ids => [1, 2, 3]
|
90
|
+
}
|
91
|
+
}
|
92
|
+
|
93
|
+
assert @req.respond_to?(:query_string_params=)
|
94
|
+
@req.query_string_params = composable_hash
|
95
|
+
|
96
|
+
ref = '?foo=bar&user[friend_ids]=1&user[friend_ids]=2&user[friend_ids]=3&user[login]=boss&user[password]=secret'
|
97
|
+
assert_equal normalize_qs(ref), normalize_qs(@req.query_string)
|
98
|
+
assert_equal "/"+ref, @req['REQUEST_URI'], "The query string parameters should be propagated to the " +
|
99
|
+
"request uri and be in their sorted form"
|
100
|
+
assert_equal normalize_qs(ref), normalize_qs(@req["QUERY_STRING"]), "The query string should also land in QUERY_STRING"
|
101
|
+
end
|
102
|
+
|
103
|
+
def test_qs_assignment_with_empty_hash_unsets_envar
|
104
|
+
@req.query_string_params = {}
|
105
|
+
assert_equal '', @req.query_string, "When an empty hash is assigned the query string should be empty"
|
106
|
+
assert_nil @req.to_hash['QUERY_STRING'], "The key for QUERY_STRING should be unset in the environment"
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_multipart_boundary_generation
|
110
|
+
boundaries = (1..40).map do
|
111
|
+
@req.generate_boundary
|
112
|
+
end
|
113
|
+
assert_equal boundaries.uniq.length, boundaries.length, "All boundaries generated should be unique"
|
114
|
+
assert_equal boundaries, boundaries.grep(/^msqto\-/), "All boundaries should be prepended with msqto-"
|
115
|
+
end
|
116
|
+
|
117
|
+
def test_method_missing_is_indeed_missing
|
118
|
+
assert_raise(NoMethodError) { @req.kaboodle! }
|
119
|
+
end
|
120
|
+
|
121
|
+
def test_extract_values
|
122
|
+
t = {
|
123
|
+
:foo => "bar",
|
124
|
+
:bar => {
|
125
|
+
:baz => [1,2,3],
|
126
|
+
:bam => "trunk",
|
127
|
+
},
|
128
|
+
:sequence => "xyz"
|
129
|
+
}
|
130
|
+
assert_equal ["bar", "1", "2" , "3", "trunk", "xyz"].sort, @req.send(:extract_values, t).map(&:to_s).sort,
|
131
|
+
"should properly extract infinitely deeply nested values"
|
132
|
+
end
|
133
|
+
|
134
|
+
def test_post_composition_with_urlencoding
|
135
|
+
assert_equal 'GET', @req['REQUEST_METHOD'], "The default request method is GET"
|
136
|
+
|
137
|
+
@req.post_params = {:hello => "welæcome", :name => "john", :data => {:values => [1,2,3] } }
|
138
|
+
assert_kind_of StringIO, @req.body, "The request body is an IO"
|
139
|
+
assert_equal 'POST', @req['REQUEST_METHOD'],
|
140
|
+
"When the parameters are assigned the request should be switched to POST"
|
141
|
+
assert_equal "application/x-www-form-urlencoded", @req['CONTENT_TYPE'],
|
142
|
+
"The content-type should be switched accordingly"
|
143
|
+
assert_equal normalize_qs('data[values]=1&data[values]=2&data[values]=3&hello=wel%C3%A6come&name=john'), normalize_qs(@req.body.read),
|
144
|
+
"The body should now contain URL-encoded form parameters"
|
145
|
+
end
|
146
|
+
|
147
|
+
def test_post_composition_accepts_verbatim_strings_as_payload
|
148
|
+
assert_equal 'GET', @req['REQUEST_METHOD'], "The default request method is GET"
|
149
|
+
@req.post_params = 'foo=bar&baz=bad'
|
150
|
+
assert_equal 'POST', @req['REQUEST_METHOD']
|
151
|
+
assert_equal "application/x-www-form-urlencoded", @req['CONTENT_TYPE'],
|
152
|
+
"The content-type should be switched accordingly"
|
153
|
+
assert_equal 'foo=bar&baz=bad', @req.body.read, "The payload should have been assigned directly"
|
154
|
+
end
|
155
|
+
|
156
|
+
def test_append_to_query_string
|
157
|
+
@req.append_to_query_string "x=y&boo=2"
|
158
|
+
@req.append_to_query_string "zaz=taing&schmoo=tweed"
|
159
|
+
assert_equal "x=y&boo=2&zaz=taing&schmoo=tweed", @req["QUERY_STRING"]
|
160
|
+
end
|
161
|
+
|
162
|
+
# We could let that one slip but why? If someone does TDD he deserves gratification
|
163
|
+
def test_post_composition_requiring_multipart_with_arrays_warns_the_noble_developer_and_everyone_stays_happy
|
164
|
+
assert_raise(Mosquito::SageAdvice) do
|
165
|
+
@req.post_params = {:hello => "welcome", :name => "john", :arrayed => [1, 2, 3], :somefile => MockUpload.new("pic.jpg") }
|
166
|
+
end
|
167
|
+
|
168
|
+
assert_nothing_raised do
|
169
|
+
@req.post_params = {:hello => "welcome", :name => "john", :arrayed => [1, 2, 3], :not_a_file => "shtaink" }
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
# We could let that one slip but why? If someone does TDD he deserves gratification
|
174
|
+
def test_get_composition_with_files_warns_the_noble_developer_and_he_quickly_corrects_himself
|
175
|
+
assert_raise(Mosquito::SageAdvice) do
|
176
|
+
@req.query_string_params = {:hello => "welcome", :somefile => MockUpload.new("pic.jpg") }
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
def test_post_composition_from_values_requiring_multipart
|
181
|
+
assert_equal 'GET', @req['REQUEST_METHOD'], "The default request method is GET"
|
182
|
+
|
183
|
+
@req.post_params = {:hello => "welcome", :name => "john", :somefile => MockUpload.new("pic.jpg") }
|
184
|
+
|
185
|
+
assert_kind_of StringIO, @req.body, "The request body is an IO"
|
186
|
+
assert_equal 'POST', @req['REQUEST_METHOD'], "When the parameters are assigned the request should be switched to POST"
|
187
|
+
ctype, boundary = @req['CONTENT_TYPE'].split(/=/)
|
188
|
+
boundary_with_prefix = "--" + boundary
|
189
|
+
assert_equal "multipart/form-data; boundary", ctype, "The content-type should be switched accordingly"
|
190
|
+
|
191
|
+
@req.body.rewind
|
192
|
+
output = @req.body.read.split("\r")
|
193
|
+
ref_segments = [
|
194
|
+
"--#{boundary}",
|
195
|
+
"\nContent-Disposition: form-data; name=\"hello\"",
|
196
|
+
"\n", "\nwelcome", "\n--#{boundary}",
|
197
|
+
"\nContent-Disposition: form-data; name=\"name\"",
|
198
|
+
"\n",
|
199
|
+
"\njohn",
|
200
|
+
"\n--#{boundary}",
|
201
|
+
"\nContent-Disposition: form-data; name=\"somefile\"; filename=\"pic.jpg\"",
|
202
|
+
"\nContent-Type: image/jpeg", "\nContent-Length: 120",
|
203
|
+
"\n",
|
204
|
+
/\nStub file pic\.jpg \n([AZ-az]{120})\n/,
|
205
|
+
"\n--#{boundary}--"
|
206
|
+
]
|
207
|
+
|
208
|
+
ref_segments.each_with_index do | ref, idx |
|
209
|
+
if ref == String
|
210
|
+
assert_equal ref, output[idx], "The segment #{idx} should be #{ref}"
|
211
|
+
elsif ref == Regexp
|
212
|
+
assert_match ref, output[idx], "The segment #{idx} should match #{ref}"
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
private
|
218
|
+
# Remove the question mark, sort the pairs
|
219
|
+
def normalize_qs(query_string)
|
220
|
+
"?" + query_string.to_s.gsub(/^\?/, '').split(/&/).sort.join('&')
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
|
225
|
+
class TestMockRequestWithRoundtrip < Test::Unit::TestCase
|
226
|
+
include Mosquito
|
227
|
+
def setup
|
228
|
+
@parsed_input = nil
|
229
|
+
@req = MockRequest.new
|
230
|
+
end
|
231
|
+
|
232
|
+
def test_multipart_post_properly_roundtripped
|
233
|
+
@req.post_params = {:hello => "welcome", :name => "john", :somefile => MockUpload.new("pic.jpg") }
|
234
|
+
|
235
|
+
run_request!
|
236
|
+
|
237
|
+
# Reference is something like this
|
238
|
+
# {"name"=>"john", "somefile"=>{"name"=>"somefile", "type"=>"image/jpeg",
|
239
|
+
# "tempfile"=>#<File:/tmp/C.9366.0>, "filename"=>"pic.jpg"}, "hello"=>"welcome"}
|
240
|
+
|
241
|
+
assert_equal "john", @parsed_input["name"]
|
242
|
+
assert_kind_of Hash, @parsed_input["somefile"]
|
243
|
+
assert_equal "somefile", @parsed_input["somefile"]["name"]
|
244
|
+
assert_equal "pic.jpg", @parsed_input["somefile"]["filename"]
|
245
|
+
assert_equal "image/jpeg", @parsed_input["somefile"]["type"]
|
246
|
+
assert_kind_of Tempfile, @parsed_input["somefile"]["tempfile"]
|
247
|
+
|
248
|
+
|
249
|
+
@req.post_params = {:hello => "welcome", :name => "john", :arrayed => [1, 2, 3], :somefile => "instead" }
|
250
|
+
assert_kind_of StringIO, @req.body, "The request body is an IO"
|
251
|
+
assert_match /urlencoded/, @req['CONTENT_TYPE'], "The ctype should have been switched back to urlencoded"
|
252
|
+
|
253
|
+
run_request!
|
254
|
+
|
255
|
+
ref = {"name"=>"john", "arrayed"=>["1", "2", "3"], "somefile"=>"instead", "hello"=>"welcome"}
|
256
|
+
assert_equal ref, @parsed_input, "Camping should have parsed our params just like so"
|
257
|
+
end
|
258
|
+
|
259
|
+
def test_reader_and_writer_for_domain
|
260
|
+
assert_nothing_raised { assert_equal 'test.host', @req.domain }
|
261
|
+
assert_nothing_raised { @req.domain = "foo.dzing" }
|
262
|
+
|
263
|
+
assert_equal 'foo.dzing', @req.domain
|
264
|
+
assert_equal 'foo.dzing', @req['SERVER_NAME']
|
265
|
+
assert_equal 'foo.dzing', @req['HTTP_HOST']
|
266
|
+
end
|
267
|
+
|
268
|
+
def test_query_string_properly_roundtripped
|
269
|
+
parsed = {"user"=> {"friend_äidéis"=>["1", "2", "3"], "paßwort"=>"secret", "login"=>"boss"}, "foo"=>"bar"}
|
270
|
+
@req.query_string_params = parsed
|
271
|
+
run_request!
|
272
|
+
assert_equal parsed, @parsed_input
|
273
|
+
end
|
274
|
+
|
275
|
+
def test_urlencoded_post_properly_roundtripped
|
276
|
+
assert_equal 'GET', @req['REQUEST_METHOD'], "The default request method is GET"
|
277
|
+
|
278
|
+
@req.post_params = {:hello => "welæcome", :name => "john", :data => {:values => [1,2,3] } }
|
279
|
+
run_request!
|
280
|
+
ref = {"name"=>"john", "hello"=>"welæcome", "data"=>{"values"=>["1", "2", "3"]}}
|
281
|
+
assert_equal ref, @parsed_input, "Camping should have parsed our input like so"
|
282
|
+
end
|
283
|
+
private
|
284
|
+
def run_request!
|
285
|
+
@req.body.rewind
|
286
|
+
begin
|
287
|
+
Sniffer.run(@req.body, @req.to_hash)
|
288
|
+
rescue Sniffer::Controllers::ParamPeeker::Messenger => e
|
289
|
+
@parsed_input = e.packet
|
290
|
+
end
|
291
|
+
end
|
292
|
+
end
|