webbed 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +22 -0
- data/.travis.yml +7 -0
- data/.yardopts +6 -0
- data/Gemfile +5 -13
- data/Guardfile +5 -0
- data/README.md +36 -31
- data/Rakefile +7 -14
- data/lib/webbed.rb +28 -6
- data/lib/webbed/generic_message.rb +27 -15
- data/lib/webbed/headers.rb +2 -0
- data/lib/webbed/helpers/entity_headers_helper.rb +62 -0
- data/lib/webbed/helpers/method_helper.rb +83 -0
- data/lib/webbed/helpers/rack_request_helper.rb +86 -0
- data/lib/webbed/helpers/rack_response_helper.rb +56 -0
- data/lib/webbed/helpers/request_headers_helper.rb +62 -0
- data/lib/webbed/helpers/request_uri_helper.rb +34 -0
- data/lib/webbed/helpers/response_headers_helper.rb +48 -0
- data/lib/webbed/helpers/scheme_helper.rb +26 -0
- data/lib/webbed/http_version.rb +88 -33
- data/lib/webbed/media_type.rb +160 -0
- data/lib/webbed/method.rb +63 -33
- data/lib/webbed/request.rb +65 -21
- data/lib/webbed/response.rb +65 -24
- data/lib/webbed/status_code.rb +84 -17
- data/lib/webbed/version.rb +1 -1
- data/test/support/assertions.rb +17 -0
- data/test/support/runner.rb +326 -0
- data/test/test_helper.rb +13 -0
- data/test/webbed/generic_message_test.rb +44 -0
- data/test/webbed/headers_test.rb +31 -0
- data/test/webbed/helpers/entity_headers_helper_test.rb +68 -0
- data/test/webbed/helpers/method_helper_test.rb +151 -0
- data/test/webbed/helpers/rack_request_helper_test.rb +108 -0
- data/test/webbed/helpers/rack_response_helper_test.rb +33 -0
- data/test/webbed/helpers/request_headers_helper_test.rb +57 -0
- data/test/webbed/helpers/request_uri_helper_test.rb +32 -0
- data/test/webbed/helpers/response_headers_helper_test.rb +46 -0
- data/test/webbed/helpers/scheme_helper_test.rb +28 -0
- data/test/webbed/http_version_test.rb +52 -0
- data/test/webbed/media_type_test.rb +100 -0
- data/test/webbed/method_test.rb +160 -0
- data/test/webbed/request_test.rb +74 -0
- data/test/webbed/response_test.rb +86 -0
- data/test/webbed/status_code_test.rb +105 -0
- data/webbed.gemspec +31 -0
- metadata +128 -41
data/lib/webbed/version.rb
CHANGED
@@ -0,0 +1,17 @@
|
|
1
|
+
module WebbedTest
|
2
|
+
module Assertions
|
3
|
+
def assert_comparable(smaller, larger)
|
4
|
+
assert_operator smaller, :<, larger
|
5
|
+
assert_operator smaller, :<=, larger
|
6
|
+
|
7
|
+
refute_operator larger, :<, smaller
|
8
|
+
refute_operator larger, :<=, smaller
|
9
|
+
|
10
|
+
assert_operator larger, :>, smaller
|
11
|
+
assert_operator larger, :>=, smaller
|
12
|
+
|
13
|
+
refute_operator smaller, :>, larger
|
14
|
+
refute_operator smaller, :>=, larger
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,326 @@
|
|
1
|
+
require 'minitest/unit'
|
2
|
+
require 'ansi'
|
3
|
+
require 'progressbar'
|
4
|
+
|
5
|
+
# Code has been borrowed and modified from MiniTest, written by Ryan Davis of
|
6
|
+
# Seattle.rb. MiniTest is licensed under the MIT License, and can be found on
|
7
|
+
# GitHub at https://github.com/seattlerb/minitest.
|
8
|
+
#
|
9
|
+
# This code is also heavily based upon these gists as well:
|
10
|
+
# * https://gist.github.com/356945
|
11
|
+
# * https://gist.github.com/960669
|
12
|
+
#
|
13
|
+
# TODO: Add documentation to everything.
|
14
|
+
|
15
|
+
module Perfection
|
16
|
+
class Reporter
|
17
|
+
def runner
|
18
|
+
Perfection::Runner.runner
|
19
|
+
end
|
20
|
+
|
21
|
+
def print(*args)
|
22
|
+
runner.output.print(*args)
|
23
|
+
end
|
24
|
+
|
25
|
+
def puts(*args)
|
26
|
+
runner.output.puts(*args)
|
27
|
+
end
|
28
|
+
|
29
|
+
def before_suites(suites); end
|
30
|
+
def after_suites(suites); end
|
31
|
+
def before_suite(suite); end
|
32
|
+
def after_suite(suite); end
|
33
|
+
def before_test(suite, test); end
|
34
|
+
def pass(suite, test); end
|
35
|
+
def skip(suite, test, e); end
|
36
|
+
def failure(suite, test, e); end
|
37
|
+
def error(suite, test, e); end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Takes a signficant amount of code from Jef Kreefmeijer's Fuubar. Fuubar is
|
41
|
+
# licensed under the MIT License and can be found at:
|
42
|
+
# https://github.com/jeffkreeftmeijer/fuubar.
|
43
|
+
class ProgressReporter < Reporter
|
44
|
+
include ANSI::Code
|
45
|
+
|
46
|
+
INFO_PADDING = 2
|
47
|
+
|
48
|
+
def before_suites(suites)
|
49
|
+
puts 'Started'
|
50
|
+
puts
|
51
|
+
|
52
|
+
@color = GREEN
|
53
|
+
@finished_count = 0
|
54
|
+
@progress = ProgressBar.new("0/#{runner.test_count}", runner.test_count, runner.output)
|
55
|
+
@progress.bar_mark = '='
|
56
|
+
end
|
57
|
+
|
58
|
+
def increment
|
59
|
+
with_color do
|
60
|
+
@finished_count += 1
|
61
|
+
@progress.instance_variable_set('@title', "#{@finished_count}/#{runner.test_count}")
|
62
|
+
@progress.inc
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def pass(suite, test)
|
67
|
+
increment
|
68
|
+
end
|
69
|
+
|
70
|
+
def skip(suite, test, e)
|
71
|
+
@color = YELLOW unless @color == RED
|
72
|
+
print(yellow { 'SKIP' })
|
73
|
+
print_test_with_time(suite, test)
|
74
|
+
puts
|
75
|
+
puts
|
76
|
+
increment
|
77
|
+
end
|
78
|
+
|
79
|
+
def failure(suite, test, e)
|
80
|
+
@color = RED
|
81
|
+
print(red { 'FAIL' })
|
82
|
+
print_test_with_time(suite, test)
|
83
|
+
puts
|
84
|
+
print_info(e)
|
85
|
+
puts
|
86
|
+
increment
|
87
|
+
end
|
88
|
+
|
89
|
+
def error(suite, test, e)
|
90
|
+
@color = RED
|
91
|
+
print(red { 'ERROR' })
|
92
|
+
print_test_with_time(suite, test)
|
93
|
+
puts
|
94
|
+
print_info(e)
|
95
|
+
puts
|
96
|
+
increment
|
97
|
+
end
|
98
|
+
|
99
|
+
def after_suites(suites)
|
100
|
+
with_color { @progress.finish }
|
101
|
+
|
102
|
+
total_time = Time.now - runner.start_time
|
103
|
+
|
104
|
+
puts
|
105
|
+
puts('Finished in %.5fs' % total_time)
|
106
|
+
print('%d tests, %d assertions, ' % [runner.test_count, runner.assertion_count])
|
107
|
+
print(red { '%d failures, %d errors, ' } % [runner.failures, runner.errors])
|
108
|
+
print(yellow { '%d skips' } % runner.skips)
|
109
|
+
puts
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
def print_test_with_time(suite, test)
|
115
|
+
total_time = Time.now - runner.test_start_time
|
116
|
+
print(" #{suite}##{test} (%.2fs)#{clr}" % total_time)
|
117
|
+
end
|
118
|
+
|
119
|
+
def print_info(e)
|
120
|
+
e.message.each_line { |line| puts pad(line) }
|
121
|
+
|
122
|
+
trace = MiniTest.filter_backtrace(e.backtrace)
|
123
|
+
trace.each { |line| puts pad(line) }
|
124
|
+
end
|
125
|
+
|
126
|
+
def pad(str)
|
127
|
+
' ' * INFO_PADDING + str
|
128
|
+
end
|
129
|
+
|
130
|
+
def with_color
|
131
|
+
print @color
|
132
|
+
yield
|
133
|
+
print CLEAR
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
class SpecReporter < Reporter
|
138
|
+
include ANSI::Code
|
139
|
+
|
140
|
+
TEST_PADDING = 2
|
141
|
+
INFO_PADDING = 8
|
142
|
+
MARK_SIZE = 5
|
143
|
+
|
144
|
+
def before_suites(suites)
|
145
|
+
puts 'Started'
|
146
|
+
puts
|
147
|
+
end
|
148
|
+
|
149
|
+
def after_suites(suites)
|
150
|
+
total_time = Time.now - runner.start_time
|
151
|
+
|
152
|
+
puts('Finished in %.5fs' % total_time)
|
153
|
+
print('%d tests, %d assertions, ' % [runner.test_count, runner.assertion_count])
|
154
|
+
print(red { '%d failures, %d errors, ' } % [runner.failures, runner.errors])
|
155
|
+
print(yellow { '%d skips' } % runner.skips)
|
156
|
+
puts
|
157
|
+
end
|
158
|
+
|
159
|
+
def before_suite(suite)
|
160
|
+
puts suite
|
161
|
+
end
|
162
|
+
|
163
|
+
def after_suite(suite)
|
164
|
+
puts
|
165
|
+
end
|
166
|
+
|
167
|
+
def pass(suite, test)
|
168
|
+
print(green { pad_mark('PASS') })
|
169
|
+
print_test_with_time(test)
|
170
|
+
puts
|
171
|
+
end
|
172
|
+
|
173
|
+
def skip(suite, test, e)
|
174
|
+
print(yellow { pad_mark('SKIP') })
|
175
|
+
print_test_with_time(test)
|
176
|
+
puts
|
177
|
+
end
|
178
|
+
|
179
|
+
def failure(suite, test, e)
|
180
|
+
print(red { pad_mark('FAIL') })
|
181
|
+
print_test_with_time(test)
|
182
|
+
puts
|
183
|
+
print_info(e)
|
184
|
+
puts
|
185
|
+
end
|
186
|
+
|
187
|
+
def error(suite, test, e)
|
188
|
+
print(red { pad_mark('ERROR') })
|
189
|
+
print_test_with_time(test)
|
190
|
+
puts
|
191
|
+
print_info(e)
|
192
|
+
puts
|
193
|
+
end
|
194
|
+
|
195
|
+
private
|
196
|
+
|
197
|
+
def print_test_with_time(test)
|
198
|
+
total_time = Time.now - runner.test_start_time
|
199
|
+
print(" #{test} (%.2fs)" % total_time)
|
200
|
+
end
|
201
|
+
|
202
|
+
def print_info(e)
|
203
|
+
e.message.each_line { |line| puts pad(line, INFO_PADDING) }
|
204
|
+
|
205
|
+
trace = MiniTest.filter_backtrace(e.backtrace)
|
206
|
+
trace.each { |line| puts pad(line, INFO_PADDING) }
|
207
|
+
end
|
208
|
+
|
209
|
+
def pad(str, size)
|
210
|
+
' ' * size + str
|
211
|
+
end
|
212
|
+
|
213
|
+
def pad_mark(str)
|
214
|
+
pad("%#{MARK_SIZE}s" % str, TEST_PADDING)
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
class Runner < MiniTest::Unit
|
219
|
+
class << self
|
220
|
+
attr_writer :reporter
|
221
|
+
|
222
|
+
def reporter
|
223
|
+
@reporter ||= ProgressReporter.new
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
attr_accessor :suite_start_time, :test_start_time
|
228
|
+
|
229
|
+
def reporter
|
230
|
+
self.class.reporter
|
231
|
+
end
|
232
|
+
|
233
|
+
def puke(suite, method, e)
|
234
|
+
case e
|
235
|
+
when MiniTest::Skip then
|
236
|
+
@skips += 1
|
237
|
+
[:skip, e]
|
238
|
+
when MiniTest::Assertion then
|
239
|
+
@failures += 1
|
240
|
+
[:failure, e]
|
241
|
+
else
|
242
|
+
@errors += 1
|
243
|
+
[:error, e]
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
def _run_anything(type)
|
248
|
+
suites = TestCase.send("#{type}_suites")
|
249
|
+
return if suites.empty?
|
250
|
+
|
251
|
+
@test_count = suites.inject(0) { |acc, suite| acc + suite.send("#{type}_methods").length }
|
252
|
+
@assertion_count = 0
|
253
|
+
|
254
|
+
@start_time = Time.now
|
255
|
+
reporter.before_suites(suites)
|
256
|
+
fix_sync { _run_suites(suites, type) }
|
257
|
+
reporter.after_suites(suites)
|
258
|
+
end
|
259
|
+
|
260
|
+
def _run_suites(suites, type)
|
261
|
+
suites.each { |suite| _run_suite(suite, type) }
|
262
|
+
end
|
263
|
+
|
264
|
+
def _run_suite(suite, type)
|
265
|
+
run_suite_header(suite, type)
|
266
|
+
|
267
|
+
filter = options[:filter] || '/./'
|
268
|
+
filter = Regexp.new($1) if filter =~ /\/(.*)\//
|
269
|
+
|
270
|
+
tests = suite.send("#{type}_methods").grep(filter)
|
271
|
+
|
272
|
+
unless tests.empty?
|
273
|
+
@suite_start_time = Time.now
|
274
|
+
reporter.before_suite(suite)
|
275
|
+
_run_tests(suite, tests)
|
276
|
+
reporter.after_suite(suite)
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
private
|
281
|
+
|
282
|
+
def run_suite_header(suite, type)
|
283
|
+
header_method = "#{type}_suite_header"
|
284
|
+
send(header_method, suite) if respond_to?(header_method)
|
285
|
+
end
|
286
|
+
|
287
|
+
def _run_tests(suite, tests)
|
288
|
+
suite.startup if suite.respond_to?(:startup)
|
289
|
+
tests.each { |test| _run_test(suite, test) }
|
290
|
+
ensure
|
291
|
+
suite.shutdown if suite.respond_to?(:shutdown)
|
292
|
+
end
|
293
|
+
|
294
|
+
def _run_test(suite, test)
|
295
|
+
@test_start_time = Time.now
|
296
|
+
reporter.before_test(suite, test)
|
297
|
+
|
298
|
+
suite_instance = suite.new(test)
|
299
|
+
suite_instance._assertions = 0
|
300
|
+
|
301
|
+
result = fix_result(suite_instance.run(self))
|
302
|
+
@assertion_count += suite_instance._assertions
|
303
|
+
|
304
|
+
case result[0]
|
305
|
+
when :pass then reporter.pass(suite, test)
|
306
|
+
when :skip then reporter.skip(suite, test, result[1])
|
307
|
+
when :failure then reporter.failure(suite, test, result[1])
|
308
|
+
else reporter.error(suite, test, result[1])
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
def fix_result(result)
|
313
|
+
result == '.' ? [:pass, nil] : result
|
314
|
+
end
|
315
|
+
|
316
|
+
def fix_sync
|
317
|
+
sync = output.respond_to?(:'sync=') # stupid emacs
|
318
|
+
old_sync, output.sync = output.sync, true if sync
|
319
|
+
yield
|
320
|
+
output.sync = old_sync if sync
|
321
|
+
end
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
Perfection::Runner.runner = Perfection::Runner.new
|
326
|
+
Perfection::Runner.reporter = Perfection::ProgressReporter.new
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require 'mocha'
|
4
|
+
require 'test_declarative'
|
5
|
+
require 'webbed'
|
6
|
+
|
7
|
+
Dir[File.dirname(__FILE__) + '/support/**/*.rb'].each { |f| require f }
|
8
|
+
|
9
|
+
module WebbedTest
|
10
|
+
class TestCase < MiniTest::Unit::TestCase
|
11
|
+
include Assertions
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module WebbedTest
|
4
|
+
class GenericMessageTest < TestCase
|
5
|
+
def setup
|
6
|
+
@klass = Class.new
|
7
|
+
@klass.instance_eval { include Webbed::GenericMessage }
|
8
|
+
@message = @klass.new
|
9
|
+
end
|
10
|
+
|
11
|
+
test '#initialize' do
|
12
|
+
assert_nil @message.http_version
|
13
|
+
assert_nil @message.headers
|
14
|
+
assert_nil @message.entity_body
|
15
|
+
end
|
16
|
+
|
17
|
+
test '#http_version' do
|
18
|
+
@message.http_version = 'HTTP/1.0'
|
19
|
+
|
20
|
+
assert_instance_of Webbed::HTTPVersion, @message.http_version
|
21
|
+
assert_equal 1.0, @message.http_version
|
22
|
+
end
|
23
|
+
|
24
|
+
test '#headers' do
|
25
|
+
@message.headers = { 'Host' => 'foo.com' }
|
26
|
+
|
27
|
+
assert_instance_of Webbed::Headers, @message.headers
|
28
|
+
assert_equal 'foo.com', @message.headers['Host']
|
29
|
+
end
|
30
|
+
|
31
|
+
test '#entity_body' do
|
32
|
+
@message.entity_body = 'foo'
|
33
|
+
assert_equal 'foo', @message.entity_body
|
34
|
+
end
|
35
|
+
|
36
|
+
test '#to_s' do
|
37
|
+
@message.expects(:start_line).returns("Start Line\r\n")
|
38
|
+
@message.expects(:headers).returns("Headers\r\n")
|
39
|
+
@message.expects(:entity_body).returns('Entity Body')
|
40
|
+
|
41
|
+
assert_equal "Start Line\r\nHeaders\r\n\r\nEntity Body", @message.to_s
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
# TODO: Add more tests to this. Since it was stolen from Rack, I'm pretty darn
|
4
|
+
# sure that it works correctly. Still, as a matter of principle, it should have
|
5
|
+
# all the necessary tests to make sure it works correctly when it changes. But
|
6
|
+
# yeah, very low priority at the moment.
|
7
|
+
module WebbedTest
|
8
|
+
class HeadersTest < TestCase
|
9
|
+
test '#initialize without headers' do
|
10
|
+
assert Webbed::Headers.new.empty?
|
11
|
+
end
|
12
|
+
|
13
|
+
test '#initialize with headers' do
|
14
|
+
headers = Webbed::Headers.new({ 'Host' => 'foo.com' })
|
15
|
+
|
16
|
+
refute headers.empty?
|
17
|
+
assert_equal 'foo.com', headers['Host']
|
18
|
+
assert_equal 'foo.com', headers['host']
|
19
|
+
assert_equal 'foo.com', headers['HOST']
|
20
|
+
end
|
21
|
+
|
22
|
+
test '#to_s' do
|
23
|
+
headers = Webbed::Headers.new({
|
24
|
+
'Content-Type' => 'application/json',
|
25
|
+
'Host' => 'foo.com'
|
26
|
+
})
|
27
|
+
|
28
|
+
assert_equal "Content-Type: application/json\r\nHost: foo.com\r\n", headers.to_s
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module WebbedTest
|
4
|
+
module HelperTest
|
5
|
+
class EntityHeadersHelperTest < TestCase
|
6
|
+
def setup
|
7
|
+
@request = Webbed::Request.new('GET', '*', {}, '')
|
8
|
+
@response = Webbed::Response.new(200, {}, '')
|
9
|
+
end
|
10
|
+
|
11
|
+
test '#content_length' do
|
12
|
+
[@request, @response].each do |message|
|
13
|
+
assert_nil message.content_length
|
14
|
+
|
15
|
+
message.headers['Content-Length'] = 9876
|
16
|
+
assert_equal 9876, message.content_length
|
17
|
+
|
18
|
+
message.content_length = 123
|
19
|
+
assert_equal 123, message.content_length
|
20
|
+
assert_equal '123', message.headers['Content-Length']
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
test '#content_location' do
|
25
|
+
[@request, @response].each do |message|
|
26
|
+
assert_nil message.content_location
|
27
|
+
|
28
|
+
message.headers['Content-Location'] = 'http://google.com'
|
29
|
+
assert_instance_of Addressable::URI, message.content_location
|
30
|
+
assert_equal 'http://google.com', message.content_location.to_s
|
31
|
+
|
32
|
+
message.content_location = 'http://example.com/testing'
|
33
|
+
assert_instance_of Addressable::URI, message.content_location
|
34
|
+
assert_equal 'http://example.com/testing', message.content_location.to_s
|
35
|
+
assert_equal 'http://example.com/testing', message.headers['Content-Location']
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
test '#content_md5' do
|
40
|
+
[@request, @response].each do |message|
|
41
|
+
assert_nil message.content_md5
|
42
|
+
|
43
|
+
message.headers['Content-MD5'] = 'asdfasdf'
|
44
|
+
assert_equal 'asdfasdf', message.content_md5
|
45
|
+
|
46
|
+
message.content_md5 = ';lkj;lkj'
|
47
|
+
assert_equal ';lkj;lkj', message.content_md5
|
48
|
+
assert_equal ';lkj;lkj', message.headers['Content-MD5']
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
test '#content_type' do
|
53
|
+
[@request, @response].each do |message|
|
54
|
+
assert_nil message.content_type
|
55
|
+
|
56
|
+
message.headers['Content-Type'] = 'text/html'
|
57
|
+
assert_instance_of Webbed::MediaType, message.content_type
|
58
|
+
assert_equal 'text/html', message.content_type.to_s
|
59
|
+
|
60
|
+
message.content_type = 'application/json'
|
61
|
+
assert_instance_of Webbed::MediaType, message.content_type
|
62
|
+
assert_equal 'application/json', message.content_type.to_s
|
63
|
+
assert_equal 'application/json', message.headers['Content-Type']
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|