webbed 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/.gitignore +22 -0
  2. data/.travis.yml +7 -0
  3. data/.yardopts +6 -0
  4. data/Gemfile +5 -13
  5. data/Guardfile +5 -0
  6. data/README.md +36 -31
  7. data/Rakefile +7 -14
  8. data/lib/webbed.rb +28 -6
  9. data/lib/webbed/generic_message.rb +27 -15
  10. data/lib/webbed/headers.rb +2 -0
  11. data/lib/webbed/helpers/entity_headers_helper.rb +62 -0
  12. data/lib/webbed/helpers/method_helper.rb +83 -0
  13. data/lib/webbed/helpers/rack_request_helper.rb +86 -0
  14. data/lib/webbed/helpers/rack_response_helper.rb +56 -0
  15. data/lib/webbed/helpers/request_headers_helper.rb +62 -0
  16. data/lib/webbed/helpers/request_uri_helper.rb +34 -0
  17. data/lib/webbed/helpers/response_headers_helper.rb +48 -0
  18. data/lib/webbed/helpers/scheme_helper.rb +26 -0
  19. data/lib/webbed/http_version.rb +88 -33
  20. data/lib/webbed/media_type.rb +160 -0
  21. data/lib/webbed/method.rb +63 -33
  22. data/lib/webbed/request.rb +65 -21
  23. data/lib/webbed/response.rb +65 -24
  24. data/lib/webbed/status_code.rb +84 -17
  25. data/lib/webbed/version.rb +1 -1
  26. data/test/support/assertions.rb +17 -0
  27. data/test/support/runner.rb +326 -0
  28. data/test/test_helper.rb +13 -0
  29. data/test/webbed/generic_message_test.rb +44 -0
  30. data/test/webbed/headers_test.rb +31 -0
  31. data/test/webbed/helpers/entity_headers_helper_test.rb +68 -0
  32. data/test/webbed/helpers/method_helper_test.rb +151 -0
  33. data/test/webbed/helpers/rack_request_helper_test.rb +108 -0
  34. data/test/webbed/helpers/rack_response_helper_test.rb +33 -0
  35. data/test/webbed/helpers/request_headers_helper_test.rb +57 -0
  36. data/test/webbed/helpers/request_uri_helper_test.rb +32 -0
  37. data/test/webbed/helpers/response_headers_helper_test.rb +46 -0
  38. data/test/webbed/helpers/scheme_helper_test.rb +28 -0
  39. data/test/webbed/http_version_test.rb +52 -0
  40. data/test/webbed/media_type_test.rb +100 -0
  41. data/test/webbed/method_test.rb +160 -0
  42. data/test/webbed/request_test.rb +74 -0
  43. data/test/webbed/response_test.rb +86 -0
  44. data/test/webbed/status_code_test.rb +105 -0
  45. data/webbed.gemspec +31 -0
  46. metadata +128 -41
@@ -1,3 +1,3 @@
1
1
  module Webbed
2
- VERSION = '0.1.1'
2
+ VERSION = '0.2.0'
3
3
  end
@@ -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
@@ -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