webbed 0.1.1 → 0.2.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/.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
|