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.
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