rack 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.
Potentially problematic release.
This version of rack might be problematic. Click here for more details.
- data/AUTHORS +3 -0
- data/COPYING +18 -0
- data/KNOWN-ISSUES +18 -0
- data/RDOX +144 -0
- data/README +154 -0
- data/Rakefile +174 -0
- data/SPEC +132 -0
- data/bin/rackup +148 -0
- data/contrib/rack_logo.svg +111 -0
- data/example/lobster.ru +4 -0
- data/lib/rack.rb +67 -0
- data/lib/rack/adapter/camping.rb +16 -0
- data/lib/rack/adapter/rails.rb +65 -0
- data/lib/rack/builder.rb +52 -0
- data/lib/rack/cascade.rb +26 -0
- data/lib/rack/commonlogger.rb +56 -0
- data/lib/rack/file.rb +108 -0
- data/lib/rack/handler/cgi.rb +57 -0
- data/lib/rack/handler/fastcgi.rb +81 -0
- data/lib/rack/handler/mongrel.rb +57 -0
- data/lib/rack/handler/webrick.rb +56 -0
- data/lib/rack/lint.rb +394 -0
- data/lib/rack/lobster.rb +65 -0
- data/lib/rack/mock.rb +183 -0
- data/lib/rack/recursive.rb +57 -0
- data/lib/rack/reloader.rb +64 -0
- data/lib/rack/request.rb +112 -0
- data/lib/rack/response.rb +114 -0
- data/lib/rack/showexceptions.rb +344 -0
- data/lib/rack/urlmap.rb +50 -0
- data/lib/rack/utils.rb +176 -0
- data/test/cgi/lighttpd.conf +20 -0
- data/test/cgi/test +9 -0
- data/test/cgi/test.fcgi +9 -0
- data/test/cgi/test.ru +7 -0
- data/test/spec_rack_camping.rb +44 -0
- data/test/spec_rack_cascade.rb +35 -0
- data/test/spec_rack_cgi.rb +82 -0
- data/test/spec_rack_commonlogger.rb +32 -0
- data/test/spec_rack_fastcgi.rb +82 -0
- data/test/spec_rack_file.rb +32 -0
- data/test/spec_rack_lint.rb +317 -0
- data/test/spec_rack_lobster.rb +45 -0
- data/test/spec_rack_mock.rb +150 -0
- data/test/spec_rack_mongrel.rb +87 -0
- data/test/spec_rack_recursive.rb +77 -0
- data/test/spec_rack_request.rb +219 -0
- data/test/spec_rack_response.rb +110 -0
- data/test/spec_rack_showexceptions.rb +21 -0
- data/test/spec_rack_urlmap.rb +140 -0
- data/test/spec_rack_utils.rb +57 -0
- data/test/spec_rack_webrick.rb +89 -0
- data/test/testrequest.rb +43 -0
- metadata +117 -0
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'test/spec'
|
2
|
+
require 'testrequest'
|
3
|
+
|
4
|
+
pid = fork {
|
5
|
+
exec "cd #{File.join(File.dirname(__FILE__), 'cgi')} && lighttpd -D -f lighttpd.conf"
|
6
|
+
}
|
7
|
+
|
8
|
+
at_exit {
|
9
|
+
Process.kill 15, pid
|
10
|
+
}
|
11
|
+
|
12
|
+
context "Rack::Handler::FastCGI" do
|
13
|
+
include TestRequest::Helpers
|
14
|
+
|
15
|
+
setup do
|
16
|
+
@host = '0.0.0.0'
|
17
|
+
@port = 9203
|
18
|
+
end
|
19
|
+
|
20
|
+
specify "should respond" do
|
21
|
+
lambda {
|
22
|
+
GET("/test.fcgi")
|
23
|
+
}.should.not.raise
|
24
|
+
end
|
25
|
+
|
26
|
+
specify "should be a lighttpd" do
|
27
|
+
GET("/test.fcgi")
|
28
|
+
status.should.be 200
|
29
|
+
response["SERVER_SOFTWARE"].should =~ /lighttpd/
|
30
|
+
response["HTTP_VERSION"].should.equal "HTTP/1.1"
|
31
|
+
response["SERVER_PROTOCOL"].should.equal "HTTP/1.1"
|
32
|
+
response["SERVER_PORT"].should.equal "9203"
|
33
|
+
response["SERVER_NAME"].should =~ "0.0.0.0"
|
34
|
+
end
|
35
|
+
|
36
|
+
specify "should have rack headers" do
|
37
|
+
GET("/test.fcgi")
|
38
|
+
response["rack.version"].should.equal [0,1]
|
39
|
+
response["rack.multithread"].should.be false
|
40
|
+
response["rack.multiprocess"].should.be true
|
41
|
+
response["rack.run_once"].should.be false
|
42
|
+
end
|
43
|
+
|
44
|
+
specify "should have CGI headers on GET" do
|
45
|
+
GET("/test.fcgi")
|
46
|
+
response["REQUEST_METHOD"].should.equal "GET"
|
47
|
+
response["SCRIPT_NAME"].should.equal "/test.fcgi"
|
48
|
+
response["REQUEST_PATH"].should.equal "/"
|
49
|
+
response["PATH_INFO"].should.be.nil
|
50
|
+
response["QUERY_STRING"].should.equal ""
|
51
|
+
response["test.postdata"].should.equal ""
|
52
|
+
|
53
|
+
GET("/test.fcgi/foo?quux=1")
|
54
|
+
response["REQUEST_METHOD"].should.equal "GET"
|
55
|
+
response["SCRIPT_NAME"].should.equal "/test.fcgi"
|
56
|
+
response["REQUEST_PATH"].should.equal "/"
|
57
|
+
response["PATH_INFO"].should.equal "/foo"
|
58
|
+
response["QUERY_STRING"].should.equal "quux=1"
|
59
|
+
end
|
60
|
+
|
61
|
+
specify "should have CGI headers on POST" do
|
62
|
+
POST("/test.fcgi", {"rack-form-data" => "23"}, {'X-test-header' => '42'})
|
63
|
+
status.should.equal 200
|
64
|
+
response["REQUEST_METHOD"].should.equal "POST"
|
65
|
+
response["SCRIPT_NAME"].should.equal "/test.fcgi"
|
66
|
+
response["REQUEST_PATH"].should.equal "/"
|
67
|
+
response["QUERY_STRING"].should.equal ""
|
68
|
+
response["HTTP_X_TEST_HEADER"].should.equal "42"
|
69
|
+
response["test.postdata"].should.equal "rack-form-data=23"
|
70
|
+
end
|
71
|
+
|
72
|
+
specify "should support HTTP auth" do
|
73
|
+
GET("/test.fcgi", {:user => "ruth", :passwd => "secret"})
|
74
|
+
response["HTTP_AUTHORIZATION"].should.equal "Basic cnV0aDpzZWNyZXQ="
|
75
|
+
end
|
76
|
+
|
77
|
+
specify "should set status" do
|
78
|
+
GET("/test.fcgi?secret")
|
79
|
+
status.should.equal 403
|
80
|
+
response["rack.url_scheme"].should.equal "http"
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'test/spec'
|
2
|
+
|
3
|
+
require 'rack/file'
|
4
|
+
require 'rack/lint'
|
5
|
+
|
6
|
+
require 'rack/mock'
|
7
|
+
|
8
|
+
context "Rack::File" do
|
9
|
+
DOCROOT = File.expand_path(File.dirname(__FILE__))
|
10
|
+
|
11
|
+
specify "serves files" do
|
12
|
+
res = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT))).
|
13
|
+
get("/cgi/test")
|
14
|
+
|
15
|
+
res.should.be.ok
|
16
|
+
res.should =~ /ruby/
|
17
|
+
end
|
18
|
+
|
19
|
+
specify "does not allow directory traversal" do
|
20
|
+
res = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT))).
|
21
|
+
get("/cgi/../test")
|
22
|
+
|
23
|
+
res.should.be.forbidden
|
24
|
+
end
|
25
|
+
|
26
|
+
specify "404s if it can't find the file" do
|
27
|
+
res = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT))).
|
28
|
+
get("/cgi/blubb")
|
29
|
+
|
30
|
+
res.should.be.not_found
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,317 @@
|
|
1
|
+
require 'test/spec'
|
2
|
+
require 'stringio'
|
3
|
+
|
4
|
+
require 'rack/lint'
|
5
|
+
require 'rack/mock'
|
6
|
+
|
7
|
+
context "Rack::Lint" do
|
8
|
+
def env(*args)
|
9
|
+
Rack::MockRequest.env_for("/", *args)
|
10
|
+
end
|
11
|
+
|
12
|
+
specify "passes valid request" do
|
13
|
+
lambda {
|
14
|
+
Rack::Lint.new(lambda { |env|
|
15
|
+
[200, {"Content-type" => "test/plain"}, "foo"]
|
16
|
+
}).call(env({}))
|
17
|
+
}.should.not.raise
|
18
|
+
end
|
19
|
+
|
20
|
+
specify "notices fatal errors" do
|
21
|
+
lambda { Rack::Lint.new(nil).call }.should.raise(Rack::Lint::LintError).
|
22
|
+
message.should.match(/No env given/)
|
23
|
+
end
|
24
|
+
|
25
|
+
specify "notices environment errors" do
|
26
|
+
lambda { Rack::Lint.new(nil).call 5 }.should.raise(Rack::Lint::LintError).
|
27
|
+
message.should.match(/not a Hash/)
|
28
|
+
|
29
|
+
lambda {
|
30
|
+
e = env
|
31
|
+
e.delete("REQUEST_METHOD")
|
32
|
+
Rack::Lint.new(nil).call(e)
|
33
|
+
}.should.raise(Rack::Lint::LintError).
|
34
|
+
message.should.match(/missing required key REQUEST_METHOD/)
|
35
|
+
|
36
|
+
lambda {
|
37
|
+
e = env
|
38
|
+
e.delete("SERVER_NAME")
|
39
|
+
Rack::Lint.new(nil).call(e)
|
40
|
+
}.should.raise(Rack::Lint::LintError).
|
41
|
+
message.should.match(/missing required key SERVER_NAME/)
|
42
|
+
|
43
|
+
|
44
|
+
lambda {
|
45
|
+
Rack::Lint.new(nil).call(env("HTTP_CONTENT_TYPE" => "text/plain"))
|
46
|
+
}.should.raise(Rack::Lint::LintError).
|
47
|
+
message.should.match(/contains HTTP_CONTENT_TYPE/)
|
48
|
+
|
49
|
+
lambda {
|
50
|
+
Rack::Lint.new(nil).call(env("HTTP_CONTENT_LENGTH" => "42"))
|
51
|
+
}.should.raise(Rack::Lint::LintError).
|
52
|
+
message.should.match(/contains HTTP_CONTENT_LENGTH/)
|
53
|
+
|
54
|
+
lambda {
|
55
|
+
Rack::Lint.new(nil).call(env("FOO" => Object.new))
|
56
|
+
}.should.raise(Rack::Lint::LintError).
|
57
|
+
message.should.match(/non-string value/)
|
58
|
+
|
59
|
+
lambda {
|
60
|
+
Rack::Lint.new(nil).call(env("rack.version" => "0.2"))
|
61
|
+
}.should.raise(Rack::Lint::LintError).
|
62
|
+
message.should.match(/must be an Array/)
|
63
|
+
|
64
|
+
lambda {
|
65
|
+
Rack::Lint.new(nil).call(env("rack.url_scheme" => "gopher"))
|
66
|
+
}.should.raise(Rack::Lint::LintError).
|
67
|
+
message.should.match(/url_scheme unknown/)
|
68
|
+
|
69
|
+
lambda {
|
70
|
+
Rack::Lint.new(nil).call(env("REQUEST_METHOD" => "FUCKUP"))
|
71
|
+
}.should.raise(Rack::Lint::LintError).
|
72
|
+
message.should.match(/REQUEST_METHOD unknown/)
|
73
|
+
|
74
|
+
lambda {
|
75
|
+
Rack::Lint.new(nil).call(env("SCRIPT_NAME" => "howdy"))
|
76
|
+
}.should.raise(Rack::Lint::LintError).
|
77
|
+
message.should.match(/must start with/)
|
78
|
+
|
79
|
+
lambda {
|
80
|
+
Rack::Lint.new(nil).call(env("PATH_INFO" => "../foo"))
|
81
|
+
}.should.raise(Rack::Lint::LintError).
|
82
|
+
message.should.match(/must start with/)
|
83
|
+
|
84
|
+
lambda {
|
85
|
+
Rack::Lint.new(nil).call(env("CONTENT_LENGTH" => "xcii"))
|
86
|
+
}.should.raise(Rack::Lint::LintError).
|
87
|
+
message.should.match(/Invalid CONTENT_LENGTH/)
|
88
|
+
|
89
|
+
lambda {
|
90
|
+
e = env
|
91
|
+
e.delete("PATH_INFO")
|
92
|
+
e.delete("SCRIPT_NAME")
|
93
|
+
Rack::Lint.new(nil).call(e)
|
94
|
+
}.should.raise(Rack::Lint::LintError).
|
95
|
+
message.should.match(/One of .* must be set/)
|
96
|
+
|
97
|
+
lambda {
|
98
|
+
Rack::Lint.new(nil).call(env("SCRIPT_NAME" => "/"))
|
99
|
+
}.should.raise(Rack::Lint::LintError).
|
100
|
+
message.should.match(/cannot be .* make it ''/)
|
101
|
+
end
|
102
|
+
|
103
|
+
specify "notices input errors" do
|
104
|
+
lambda {
|
105
|
+
Rack::Lint.new(nil).call(env("rack.input" => ""))
|
106
|
+
}.should.raise(Rack::Lint::LintError).
|
107
|
+
message.should.match(/does not respond to #gets/)
|
108
|
+
end
|
109
|
+
|
110
|
+
specify "notices error errors" do
|
111
|
+
lambda {
|
112
|
+
Rack::Lint.new(nil).call(env("rack.errors" => ""))
|
113
|
+
}.should.raise(Rack::Lint::LintError).
|
114
|
+
message.should.match(/does not respond to #puts/)
|
115
|
+
end
|
116
|
+
|
117
|
+
specify "notices status errors" do
|
118
|
+
lambda {
|
119
|
+
Rack::Lint.new(lambda { |env|
|
120
|
+
["cc", {}, ""]
|
121
|
+
}).call(env({}))
|
122
|
+
}.should.raise(Rack::Lint::LintError).
|
123
|
+
message.should.match(/must be >100 seen as integer/)
|
124
|
+
|
125
|
+
lambda {
|
126
|
+
Rack::Lint.new(lambda { |env|
|
127
|
+
[42, {}, ""]
|
128
|
+
}).call(env({}))
|
129
|
+
}.should.raise(Rack::Lint::LintError).
|
130
|
+
message.should.match(/must be >100 seen as integer/)
|
131
|
+
end
|
132
|
+
|
133
|
+
specify "notices header errors" do
|
134
|
+
lambda {
|
135
|
+
Rack::Lint.new(lambda { |env|
|
136
|
+
[200, Object.new, ""]
|
137
|
+
}).call(env({}))
|
138
|
+
}.should.raise(Rack::Lint::LintError).
|
139
|
+
message.should.match(/should respond to #each/)
|
140
|
+
|
141
|
+
lambda {
|
142
|
+
Rack::Lint.new(lambda { |env|
|
143
|
+
[200, {true=>false}, ""]
|
144
|
+
}).call(env({}))
|
145
|
+
}.should.raise(Rack::Lint::LintError).
|
146
|
+
message.should.match(/header key must be a string/)
|
147
|
+
|
148
|
+
lambda {
|
149
|
+
Rack::Lint.new(lambda { |env|
|
150
|
+
[200, {"Status" => "404"}, ""]
|
151
|
+
}).call(env({}))
|
152
|
+
}.should.raise(Rack::Lint::LintError).
|
153
|
+
message.should.match(/must not contain Status/)
|
154
|
+
|
155
|
+
lambda {
|
156
|
+
Rack::Lint.new(lambda { |env|
|
157
|
+
[200, {"Content-Type:" => "text/plain"}, ""]
|
158
|
+
}).call(env({}))
|
159
|
+
}.should.raise(Rack::Lint::LintError).
|
160
|
+
message.should.match(/must not contain :/)
|
161
|
+
|
162
|
+
lambda {
|
163
|
+
Rack::Lint.new(lambda { |env|
|
164
|
+
[200, {"Content-" => "text/plain"}, ""]
|
165
|
+
}).call(env({}))
|
166
|
+
}.should.raise(Rack::Lint::LintError).
|
167
|
+
message.should.match(/must not end/)
|
168
|
+
|
169
|
+
lambda {
|
170
|
+
Rack::Lint.new(lambda { |env|
|
171
|
+
[200, {"..%%quark%%.." => "text/plain"}, ""]
|
172
|
+
}).call(env({}))
|
173
|
+
}.should.raise(Rack::Lint::LintError).
|
174
|
+
message.should.match(/invalid header/)
|
175
|
+
|
176
|
+
lambda {
|
177
|
+
Rack::Lint.new(lambda { |env|
|
178
|
+
[200, {"Foo" => Object.new}, ""]
|
179
|
+
}).call(env({}))
|
180
|
+
}.should.raise(Rack::Lint::LintError).
|
181
|
+
message.should.match(/must respond to #each/)
|
182
|
+
|
183
|
+
lambda {
|
184
|
+
Rack::Lint.new(lambda { |env|
|
185
|
+
[200, {"Foo" => [1,2,3]}, ""]
|
186
|
+
}).call(env({}))
|
187
|
+
}.should.raise(Rack::Lint::LintError).
|
188
|
+
message.should.match(/must consist of Strings/)
|
189
|
+
|
190
|
+
|
191
|
+
lambda {
|
192
|
+
Rack::Lint.new(lambda { |env|
|
193
|
+
[200, {"Foo-Bar" => "text\000plain"}, ""]
|
194
|
+
}).call(env({}))
|
195
|
+
}.should.raise(Rack::Lint::LintError).
|
196
|
+
message.should.match(/invalid header/)
|
197
|
+
end
|
198
|
+
|
199
|
+
specify "notices content-type errors" do
|
200
|
+
lambda {
|
201
|
+
Rack::Lint.new(lambda { |env|
|
202
|
+
[200, {}, ""]
|
203
|
+
}).call(env({}))
|
204
|
+
}.should.raise(Rack::Lint::LintError).
|
205
|
+
message.should.match(/No Content-Type/)
|
206
|
+
|
207
|
+
lambda {
|
208
|
+
Rack::Lint.new(lambda { |env|
|
209
|
+
[201, {"Content-Type" => "text/plain"}, ""]
|
210
|
+
}).call(env({}))
|
211
|
+
}.should.raise(Rack::Lint::LintError).
|
212
|
+
message.should.match(/Content-Type header found/)
|
213
|
+
|
214
|
+
lambda {
|
215
|
+
Rack::Lint.new(lambda { |env|
|
216
|
+
[201, {"Content-type" => "text/plain"}, ""]
|
217
|
+
}).call(env({}))
|
218
|
+
}.should.raise(Rack::Lint::LintError).
|
219
|
+
message.should.match(/Content-Type header found/)
|
220
|
+
end
|
221
|
+
|
222
|
+
specify "notices body errors" do
|
223
|
+
lambda {
|
224
|
+
status, header, body = Rack::Lint.new(lambda { |env|
|
225
|
+
[200, {"Content-type" => "text/plain"}, [1,2,3]]
|
226
|
+
}).call(env({}))
|
227
|
+
body.each { |part| }
|
228
|
+
}.should.raise(Rack::Lint::LintError).
|
229
|
+
message.should.match(/yielded non-string/)
|
230
|
+
end
|
231
|
+
|
232
|
+
specify "notices input handling errors" do
|
233
|
+
lambda {
|
234
|
+
Rack::Lint.new(lambda { |env|
|
235
|
+
env["rack.input"].gets("\r\n")
|
236
|
+
[201, {"Content-type" => "text/plain"}, ""]
|
237
|
+
}).call(env({}))
|
238
|
+
}.should.raise(Rack::Lint::LintError).
|
239
|
+
message.should.match(/gets called with arguments/)
|
240
|
+
|
241
|
+
lambda {
|
242
|
+
Rack::Lint.new(lambda { |env|
|
243
|
+
env["rack.input"].read("foo")
|
244
|
+
[201, {"Content-type" => "text/plain"}, ""]
|
245
|
+
}).call(env({}))
|
246
|
+
}.should.raise(Rack::Lint::LintError).
|
247
|
+
message.should.match(/read called with too many arguments/)
|
248
|
+
|
249
|
+
weirdio = Object.new
|
250
|
+
class << weirdio
|
251
|
+
def gets
|
252
|
+
42
|
253
|
+
end
|
254
|
+
|
255
|
+
def read
|
256
|
+
23
|
257
|
+
end
|
258
|
+
|
259
|
+
def each
|
260
|
+
yield 23
|
261
|
+
yield 42
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
lambda {
|
266
|
+
Rack::Lint.new(lambda { |env|
|
267
|
+
env["rack.input"].gets
|
268
|
+
[201, {"Content-type" => "text/plain"}, ""]
|
269
|
+
}).call(env("rack.input" => weirdio))
|
270
|
+
}.should.raise(Rack::Lint::LintError).
|
271
|
+
message.should.match(/gets didn't return a String/)
|
272
|
+
|
273
|
+
lambda {
|
274
|
+
Rack::Lint.new(lambda { |env|
|
275
|
+
env["rack.input"].each { |x| }
|
276
|
+
[201, {"Content-type" => "text/plain"}, ""]
|
277
|
+
}).call(env("rack.input" => weirdio))
|
278
|
+
}.should.raise(Rack::Lint::LintError).
|
279
|
+
message.should.match(/each didn't yield a String/)
|
280
|
+
|
281
|
+
lambda {
|
282
|
+
Rack::Lint.new(lambda { |env|
|
283
|
+
env["rack.input"].read
|
284
|
+
[201, {"Content-type" => "text/plain"}, ""]
|
285
|
+
}).call(env("rack.input" => weirdio))
|
286
|
+
}.should.raise(Rack::Lint::LintError).
|
287
|
+
message.should.match(/read didn't return a String/)
|
288
|
+
|
289
|
+
|
290
|
+
lambda {
|
291
|
+
Rack::Lint.new(lambda { |env|
|
292
|
+
env["rack.input"].close
|
293
|
+
[201, {"Content-type" => "text/plain"}, ""]
|
294
|
+
}).call(env({}))
|
295
|
+
}.should.raise(Rack::Lint::LintError).
|
296
|
+
message.should.match(/close must not be called/)
|
297
|
+
end
|
298
|
+
|
299
|
+
specify "notices error handling errors" do
|
300
|
+
lambda {
|
301
|
+
Rack::Lint.new(lambda { |env|
|
302
|
+
env["rack.errors"].write(42)
|
303
|
+
[201, {"Content-type" => "text/plain"}, ""]
|
304
|
+
}).call(env({}))
|
305
|
+
}.should.raise(Rack::Lint::LintError).
|
306
|
+
message.should.match(/write not called with a String/)
|
307
|
+
|
308
|
+
lambda {
|
309
|
+
Rack::Lint.new(lambda { |env|
|
310
|
+
env["rack.errors"].close
|
311
|
+
[201, {"Content-type" => "text/plain"}, ""]
|
312
|
+
}).call(env({}))
|
313
|
+
}.should.raise(Rack::Lint::LintError).
|
314
|
+
message.should.match(/close must not be called/)
|
315
|
+
end
|
316
|
+
|
317
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'test/spec'
|
2
|
+
|
3
|
+
require 'rack/lobster'
|
4
|
+
require 'rack/mock'
|
5
|
+
|
6
|
+
context "Rack::Lobster::LambdaLobster" do
|
7
|
+
specify "should be a single lambda" do
|
8
|
+
Rack::Lobster::LambdaLobster.should.be.kind_of Proc
|
9
|
+
end
|
10
|
+
|
11
|
+
specify "should look like a lobster" do
|
12
|
+
res = Rack::MockRequest.new(Rack::Lobster::LambdaLobster).get("/")
|
13
|
+
res.should.be.ok
|
14
|
+
res.body.should.include "(,(,,(,,,("
|
15
|
+
res.body.should.include "?flip"
|
16
|
+
end
|
17
|
+
|
18
|
+
specify "should be flippable" do
|
19
|
+
res = Rack::MockRequest.new(Rack::Lobster::LambdaLobster).get("/?flip")
|
20
|
+
res.should.be.ok
|
21
|
+
res.body.should.include "(,,,(,,(,("
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context "Rack::Lobster" do
|
26
|
+
specify "should look like a lobster" do
|
27
|
+
res = Rack::MockRequest.new(Rack::Lobster.new).get("/")
|
28
|
+
res.should.be.ok
|
29
|
+
res.body.should.include "(,(,,(,,,("
|
30
|
+
res.body.should.include "?flip"
|
31
|
+
res.body.should.include "crash"
|
32
|
+
end
|
33
|
+
|
34
|
+
specify "should be flippable" do
|
35
|
+
res = Rack::MockRequest.new(Rack::Lobster.new).get("/?flip=left")
|
36
|
+
res.should.be.ok
|
37
|
+
res.body.should.include "(,,,(,,(,("
|
38
|
+
end
|
39
|
+
|
40
|
+
specify "should provide crashing for testing purposes" do
|
41
|
+
lambda {
|
42
|
+
Rack::MockRequest.new(Rack::Lobster.new).get("/?flip=crash")
|
43
|
+
}.should.raise
|
44
|
+
end
|
45
|
+
end
|