xenon 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. metadata +13 -145
  3. data/.codeclimate.yml +0 -18
  4. data/.gitignore +0 -25
  5. data/.rspec +0 -3
  6. data/.travis.yml +0 -6
  7. data/Gemfile +0 -13
  8. data/Guardfile +0 -16
  9. data/LICENSE +0 -22
  10. data/README.md +0 -86
  11. data/Rakefile +0 -8
  12. data/examples/hello_world/config.ru +0 -3
  13. data/examples/hello_world/hello_world.rb +0 -17
  14. data/lib/xenon.rb +0 -253
  15. data/lib/xenon/auth.rb +0 -63
  16. data/lib/xenon/errors.rb +0 -5
  17. data/lib/xenon/etag.rb +0 -48
  18. data/lib/xenon/headers.rb +0 -112
  19. data/lib/xenon/headers/accept.rb +0 -34
  20. data/lib/xenon/headers/accept_charset.rb +0 -59
  21. data/lib/xenon/headers/accept_encoding.rb +0 -63
  22. data/lib/xenon/headers/accept_language.rb +0 -59
  23. data/lib/xenon/headers/authorization.rb +0 -50
  24. data/lib/xenon/headers/cache_control.rb +0 -56
  25. data/lib/xenon/headers/content_type.rb +0 -23
  26. data/lib/xenon/headers/if_match.rb +0 -53
  27. data/lib/xenon/headers/if_modified_since.rb +0 -22
  28. data/lib/xenon/headers/if_none_match.rb +0 -53
  29. data/lib/xenon/headers/if_range.rb +0 -45
  30. data/lib/xenon/headers/if_unmodified_since.rb +0 -22
  31. data/lib/xenon/headers/user_agent.rb +0 -65
  32. data/lib/xenon/headers/www_authenticate.rb +0 -70
  33. data/lib/xenon/media_type.rb +0 -162
  34. data/lib/xenon/parsers/basic_rules.rb +0 -86
  35. data/lib/xenon/parsers/header_rules.rb +0 -60
  36. data/lib/xenon/parsers/media_type.rb +0 -53
  37. data/lib/xenon/quoted_string.rb +0 -20
  38. data/lib/xenon/routing/directives.rb +0 -14
  39. data/lib/xenon/routing/header_directives.rb +0 -32
  40. data/lib/xenon/routing/method_directives.rb +0 -26
  41. data/lib/xenon/routing/param_directives.rb +0 -22
  42. data/lib/xenon/routing/path_directives.rb +0 -37
  43. data/lib/xenon/routing/route_directives.rb +0 -51
  44. data/lib/xenon/routing/security_directives.rb +0 -20
  45. data/lib/xenon/version.rb +0 -3
  46. data/spec/spec_helper.rb +0 -94
  47. data/spec/xenon/etag_spec.rb +0 -19
  48. data/spec/xenon/headers/accept_charset_spec.rb +0 -31
  49. data/spec/xenon/headers/accept_encoding_spec.rb +0 -40
  50. data/spec/xenon/headers/accept_language_spec.rb +0 -33
  51. data/spec/xenon/headers/accept_spec.rb +0 -54
  52. data/spec/xenon/headers/authorization_spec.rb +0 -47
  53. data/spec/xenon/headers/cache_control_spec.rb +0 -64
  54. data/spec/xenon/headers/if_match_spec.rb +0 -73
  55. data/spec/xenon/headers/if_modified_since_spec.rb +0 -19
  56. data/spec/xenon/headers/if_none_match_spec.rb +0 -79
  57. data/spec/xenon/headers/if_range_spec.rb +0 -45
  58. data/spec/xenon/headers/if_unmodified_since_spec.rb +0 -19
  59. data/spec/xenon/headers/user_agent_spec.rb +0 -67
  60. data/spec/xenon/headers/www_authenticate_spec.rb +0 -43
  61. data/spec/xenon/media_type_spec.rb +0 -267
  62. data/xenon.gemspec +0 -30
@@ -1,64 +0,0 @@
1
- require 'xenon/headers/cache_control'
2
-
3
- describe Xenon::Headers::CacheControl do
4
-
5
- context '::parse' do
6
- ['max-age', 'max-stale', 'min-fresh', 's-maxage'].each do |dir|
7
- it "can parse the #{dir} directive" do
8
- header = Xenon::Headers::CacheControl.parse("#{dir}=5")
9
- expect(header.directives.size).to eq(1)
10
- expect(header.directives[0].to_s).to eq("#{dir}=5")
11
- end
12
-
13
- it "can parse the #{dir} directive with a quoted value" do # should not be sent by clients but is permitted
14
- header = Xenon::Headers::CacheControl.parse("#{dir}=\"5\"")
15
- expect(header.directives.size).to eq(1)
16
- expect(header.directives[0].to_s).to eq("#{dir}=5")
17
- end
18
- end
19
-
20
- ['no-cache', 'no-store', 'no-transform', 'only-if-cached', 'must-revalidate', 'public', 'proxy-revalidate'].each do |dir|
21
- it "can parse the #{dir} directive" do
22
- header = Xenon::Headers::CacheControl.parse("#{dir}")
23
- expect(header.directives.size).to eq(1)
24
- expect(header.directives[0].to_s).to eq("#{dir}")
25
- end
26
- end
27
-
28
- it "can parse the private directive with no field names" do
29
- header = Xenon::Headers::CacheControl.parse('private')
30
- expect(header.directives.size).to eq(1)
31
- expect(header.directives[0].to_s).to eq('private')
32
- end
33
-
34
- # TODO: private directive with field names
35
-
36
- it 'can parse extension directives with quoted string values' do
37
- header = Xenon::Headers::CacheControl.parse('ext="hello \"world\""')
38
- expect(header.directives.size).to eq(1)
39
- expect(header.directives[0].name).to eq('ext')
40
- expect(header.directives[0].value).to eq("hello \"world\"")
41
- end
42
-
43
- it 'can parse more complex directives' do
44
- header = Xenon::Headers::CacheControl.parse('public, max-age=3600, must-revalidate')
45
- expect(header.directives.size).to eq(3)
46
- expect(header.directives[0].to_s).to eq('public')
47
- expect(header.directives[1].to_s).to eq('max-age=3600')
48
- expect(header.directives[2].to_s).to eq('must-revalidate')
49
- end
50
- end
51
-
52
- context '#merge' do
53
- it 'can merge two headers and maintain directive order' do
54
- h1 = Xenon::Headers::CacheControl.parse('public, max-age=3600')
55
- h2 = Xenon::Headers::CacheControl.parse('must-revalidate')
56
- header = h1.merge(h2)
57
- expect(header.directives.size).to eq(3)
58
- expect(header.directives[0].to_s).to eq('public')
59
- expect(header.directives[1].to_s).to eq('max-age=3600')
60
- expect(header.directives[2].to_s).to eq('must-revalidate')
61
- end
62
- end
63
-
64
- end
@@ -1,73 +0,0 @@
1
- require 'xenon/headers/if_match'
2
-
3
- describe Xenon::Headers::IfMatch do
4
-
5
- context '::parse' do
6
- it 'can parse a single etag' do
7
- header = Xenon::Headers::IfMatch.parse('"xyzzy"')
8
- expect(header.etags.size).to eq(1)
9
- expect(header.etags[0]).to eq(Xenon::ETag.new('xyzzy'))
10
- end
11
-
12
- it 'can parse multiple etags' do
13
- header = Xenon::Headers::IfMatch.parse('"xyzzy", "r2d2xxxx", "c3piozzzz"')
14
- expect(header.etags.size).to eq(3)
15
- expect(header.etags[0]).to eq(Xenon::ETag.new('xyzzy'))
16
- expect(header.etags[1]).to eq(Xenon::ETag.new('r2d2xxxx'))
17
- expect(header.etags[2]).to eq(Xenon::ETag.new('c3piozzzz'))
18
- end
19
-
20
- it 'can parse a wildcard header' do
21
- header = Xenon::Headers::IfMatch.parse('*')
22
- expect(header.etags.size).to eq(0)
23
- end
24
- end
25
-
26
- context '#merge' do
27
- it 'can merge two headers and maintain etag order' do
28
- h1 = Xenon::Headers::IfMatch.parse('"xyzzy", "r2d2xxxx"')
29
- h2 = Xenon::Headers::IfMatch.parse('"c3piozzzz"')
30
- header = h1.merge(h2)
31
- expect(header.etags.size).to eq(3)
32
- expect(header.etags[0]).to eq(Xenon::ETag.new('xyzzy'))
33
- expect(header.etags[1]).to eq(Xenon::ETag.new('r2d2xxxx'))
34
- expect(header.etags[2]).to eq(Xenon::ETag.new('c3piozzzz'))
35
- end
36
-
37
- it 'raises a protocol error when trying to merge into a wildcard header' do
38
- h1 = Xenon::Headers::IfMatch.parse('*')
39
- h2 = Xenon::Headers::IfMatch.parse('"c3piozzzz"')
40
- expect { h1.merge(h2) }.to raise_error(Xenon::ProtocolError)
41
- end
42
-
43
- it 'raises a protocol error when trying to merge a wildcard into a header' do
44
- h1 = Xenon::Headers::IfMatch.parse('"xyzzy"')
45
- h2 = Xenon::Headers::IfMatch.parse('*')
46
- expect { h1.merge(h2) }.to raise_error(Xenon::ProtocolError)
47
- end
48
-
49
- it 'raises a protocol error when trying to merge two wildcard headers' do
50
- h1 = Xenon::Headers::IfMatch.parse('*')
51
- h2 = Xenon::Headers::IfMatch.parse('*')
52
- expect { h1.merge(h2) }.to raise_error(Xenon::ProtocolError)
53
- end
54
- end
55
-
56
- context '#to_s' do
57
- it 'returns the string representation a single etag' do
58
- header = Xenon::Headers::IfMatch.parse('"xyzzy"')
59
- expect(header.to_s).to eq('"xyzzy"')
60
- end
61
-
62
- it 'returns the string representation of multiple etags' do
63
- header = Xenon::Headers::IfMatch.parse('"xyzzy", "r2d2xxxx", "c3piozzzz"')
64
- expect(header.to_s).to eq('"xyzzy", "r2d2xxxx", "c3piozzzz"')
65
- end
66
-
67
- it 'returns the string representation of a wildcard header' do
68
- header = Xenon::Headers::IfMatch.wildcard
69
- expect(header.to_s).to eq('*')
70
- end
71
- end
72
-
73
- end
@@ -1,19 +0,0 @@
1
- require 'xenon/headers/if_modified_since'
2
-
3
- describe Xenon::Headers::IfModifiedSince do
4
-
5
- context '::parse' do
6
- it 'can parse an http date' do
7
- header = Xenon::Headers::IfModifiedSince.parse('Sat, 29 Oct 1994 19:43:31 GMT')
8
- expect(header.date).to eq(Time.utc(1994, 10, 29, 19, 43, 31))
9
- end
10
- end
11
-
12
- context '#to_s' do
13
- it 'returns the http date format' do
14
- header = Xenon::Headers::IfModifiedSince.new(Time.utc(1994, 10, 29, 19, 43, 31))
15
- expect(header.to_s).to eq('Sat, 29 Oct 1994 19:43:31 GMT')
16
- end
17
- end
18
-
19
- end
@@ -1,79 +0,0 @@
1
- require 'xenon/headers/if_none_match'
2
-
3
- describe Xenon::Headers::IfNoneMatch do
4
-
5
- context '::parse' do
6
- it 'can parse a single strong etag' do
7
- header = Xenon::Headers::IfNoneMatch.parse('"xyzzy"')
8
- expect(header.etags.size).to eq(1)
9
- expect(header.etags[0]).to eq(Xenon::ETag.new('xyzzy'))
10
- end
11
-
12
- it 'can parse a single weak etag' do
13
- header = Xenon::Headers::IfNoneMatch.parse('W/"xyzzy"')
14
- expect(header.etags.size).to eq(1)
15
- expect(header.etags[0]).to eq(Xenon::ETag.new('xyzzy', weak: true))
16
- end
17
-
18
- it 'can parse multiple etags' do
19
- header = Xenon::Headers::IfNoneMatch.parse('"xyzzy", W/"r2d2xxxx", "c3piozzzz"')
20
- expect(header.etags.size).to eq(3)
21
- expect(header.etags[0]).to eq(Xenon::ETag.new('xyzzy'))
22
- expect(header.etags[1]).to eq(Xenon::ETag.new('r2d2xxxx', weak: true))
23
- expect(header.etags[2]).to eq(Xenon::ETag.new('c3piozzzz'))
24
- end
25
-
26
- it 'can parse a wildcard header' do
27
- header = Xenon::Headers::IfNoneMatch.parse('*')
28
- expect(header.etags.size).to eq(0)
29
- end
30
- end
31
-
32
- context '#merge' do
33
- it 'can merge two headers and maintain etag order' do
34
- h1 = Xenon::Headers::IfNoneMatch.parse('"xyzzy", W/"r2d2xxxx"')
35
- h2 = Xenon::Headers::IfNoneMatch.parse('"c3piozzzz"')
36
- header = h1.merge(h2)
37
- expect(header.etags.size).to eq(3)
38
- expect(header.etags[0]).to eq(Xenon::ETag.new('xyzzy'))
39
- expect(header.etags[1]).to eq(Xenon::ETag.new('r2d2xxxx', weak: true))
40
- expect(header.etags[2]).to eq(Xenon::ETag.new('c3piozzzz'))
41
- end
42
-
43
- it 'raises a protocol error when trying to merge into a wildcard header' do
44
- h1 = Xenon::Headers::IfNoneMatch.parse('*')
45
- h2 = Xenon::Headers::IfNoneMatch.parse('"c3piozzzz"')
46
- expect { h1.merge(h2) }.to raise_error(Xenon::ProtocolError)
47
- end
48
-
49
- it 'raises a protocol error when trying to merge a wildcard into a header' do
50
- h1 = Xenon::Headers::IfNoneMatch.parse('"xyzzy"')
51
- h2 = Xenon::Headers::IfNoneMatch.parse('*')
52
- expect { h1.merge(h2) }.to raise_error(Xenon::ProtocolError)
53
- end
54
-
55
- it 'raises a protocol error when trying to merge two wildcard headers' do
56
- h1 = Xenon::Headers::IfNoneMatch.parse('*')
57
- h2 = Xenon::Headers::IfNoneMatch.parse('*')
58
- expect { h1.merge(h2) }.to raise_error(Xenon::ProtocolError)
59
- end
60
- end
61
-
62
- context '#to_s' do
63
- it 'returns the string representation a single etag' do
64
- header = Xenon::Headers::IfNoneMatch.parse('"xyzzy"')
65
- expect(header.to_s).to eq('"xyzzy"')
66
- end
67
-
68
- it 'returns the string representation of multiple etags' do
69
- header = Xenon::Headers::IfNoneMatch.parse('"xyzzy", W/"r2d2xxxx", "c3piozzzz"')
70
- expect(header.to_s).to eq('"xyzzy", W/"r2d2xxxx", "c3piozzzz"')
71
- end
72
-
73
- it 'returns the string representation of a wildcard header' do
74
- header = Xenon::Headers::IfNoneMatch.wildcard
75
- expect(header.to_s).to eq('*')
76
- end
77
- end
78
-
79
- end
@@ -1,45 +0,0 @@
1
- require 'xenon/headers/if_range'
2
-
3
- describe Xenon::Headers::IfRange do
4
-
5
- context '::parse' do
6
- it 'can parse an http date' do
7
- header = Xenon::Headers::IfRange.parse('Sat, 29 Oct 1994 19:43:31 GMT')
8
- expect(header.date).to eq(Time.utc(1994, 10, 29, 19, 43, 31))
9
- end
10
-
11
- it 'can parse an obsolete RFC 850 date' do
12
- header = Xenon::Headers::IfRange.parse('Sunday, 06-Nov-94 08:49:37 GMT')
13
- expect(header.date).to eq(Time.utc(1994, 11, 6, 8, 49, 37))
14
- end
15
-
16
- it 'can parse an obsolete asctime date' do
17
- header = Xenon::Headers::IfRange.parse('Sun Nov 6 08:49:37 1994')
18
- expect(header.date).to eq(Time.utc(1994, 11, 6, 8, 49, 37))
19
- end
20
-
21
- it 'can parse a strong etag' do
22
- header = Xenon::Headers::IfRange.parse('"xyzzy"')
23
- expect(header.etag).to_not be_nil
24
- expect(header.etag.opaque_tag).to eq 'xyzzy'
25
- expect(header.etag).to be_strong
26
- end
27
-
28
- it 'should raise a ProtocolError if the etag is weak' do
29
- expect { Xenon::Headers::IfRange.parse('W/"xyzzy"') }.to raise_error Xenon::ProtocolError
30
- end
31
- end
32
-
33
- context '#to_s' do
34
- it 'returns the http date format for dates' do
35
- header = Xenon::Headers::IfRange.new(Time.utc(1994, 10, 29, 19, 43, 31))
36
- expect(header.to_s).to eq('Sat, 29 Oct 1994 19:43:31 GMT')
37
- end
38
-
39
- it 'returns the etag format for etags' do
40
- header = Xenon::Headers::IfRange.new(Xenon::ETag.new('xyzzy'))
41
- expect(header.to_s).to eq('"xyzzy"')
42
- end
43
- end
44
-
45
- end
@@ -1,19 +0,0 @@
1
- require 'xenon/headers/if_unmodified_since'
2
-
3
- describe Xenon::Headers::IfUnmodifiedSince do
4
-
5
- context '::parse' do
6
- it 'can parse an http date' do
7
- header = Xenon::Headers::IfUnmodifiedSince.parse('Sat, 29 Oct 1994 19:43:31 GMT')
8
- expect(header.date).to eq(Time.utc(1994, 10, 29, 19, 43, 31))
9
- end
10
- end
11
-
12
- context '#to_s' do
13
- it 'returns the http date format' do
14
- header = Xenon::Headers::IfUnmodifiedSince.new(Time.utc(1994, 10, 29, 19, 43, 31))
15
- expect(header.to_s).to eq('Sat, 29 Oct 1994 19:43:31 GMT')
16
- end
17
- end
18
-
19
- end
@@ -1,67 +0,0 @@
1
- require 'xenon/headers/user_agent'
2
-
3
- describe Xenon::Headers::UserAgent do
4
-
5
- context '::parse' do
6
- it 'can parse a user agent with a product name' do
7
- header = Xenon::Headers::UserAgent.parse('Mozilla')
8
- expect(header.products.size).to eq(1)
9
- expect(header.products[0].name).to eq('Mozilla')
10
- expect(header.products[0].version).to be_nil
11
- expect(header.products[0].comment).to be_nil
12
- end
13
-
14
- it 'can parse a user agent with a product name and version' do
15
- header = Xenon::Headers::UserAgent.parse('Mozilla/5.0')
16
- expect(header.products.size).to eq(1)
17
- expect(header.products[0].name).to eq('Mozilla')
18
- expect(header.products[0].version).to eq('5.0')
19
- expect(header.products[0].comment).to be_nil
20
- end
21
-
22
- it 'can parse a user agent with a product name and comment' do
23
- header = Xenon::Headers::UserAgent.parse('Mozilla (Macintosh; Intel Mac OS X 10_10_2)')
24
- expect(header.products.size).to eq(1)
25
- expect(header.products[0].name).to eq('Mozilla')
26
- expect(header.products[0].version).to be_nil
27
- expect(header.products[0].comment).to eq('Macintosh; Intel Mac OS X 10_10_2')
28
- end
29
-
30
- it 'can parse a user agent with a product name, version and comment' do
31
- header = Xenon::Headers::UserAgent.parse('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2)')
32
- expect(header.products.size).to eq(1)
33
- expect(header.products[0].name).to eq('Mozilla')
34
- expect(header.products[0].version).to eq('5.0')
35
- expect(header.products[0].comment).to eq('Macintosh; Intel Mac OS X 10_10_2')
36
- end
37
-
38
- it 'can parse a user agent with multiple comments' do
39
- header = Xenon::Headers::UserAgent.parse('Mozilla/5.0 (Macintosh) (Intel Mac OS X 10_10_2)')
40
- expect(header.products.size).to eq(2)
41
- expect(header.products[0].name).to eq('Mozilla')
42
- expect(header.products[0].version).to eq('5.0')
43
- expect(header.products[0].comment).to eq('Macintosh')
44
- expect(header.products[1].name).to be_nil
45
- expect(header.products[1].version).to be_nil
46
- expect(header.products[1].comment).to eq('Intel Mac OS X 10_10_2')
47
- end
48
-
49
- it 'can parse a typical Chrome user agent' do
50
- header = Xenon::Headers::UserAgent.parse('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.89 Safari/537.36')
51
- expect(header.products.size).to eq(4)
52
- expect(header.products[0].name).to eq('Mozilla')
53
- expect(header.products[0].version).to eq('5.0')
54
- expect(header.products[0].comment).to eq('Macintosh; Intel Mac OS X 10_10_2')
55
- expect(header.products[1].name).to eq('AppleWebKit')
56
- expect(header.products[1].version).to eq('537.36')
57
- expect(header.products[1].comment).to eq('KHTML, like Gecko')
58
- expect(header.products[2].name).to eq('Chrome')
59
- expect(header.products[2].version).to eq('41.0.2272.89')
60
- expect(header.products[2].comment).to be_nil
61
- expect(header.products[3].name).to eq('Safari')
62
- expect(header.products[3].version).to eq('537.36')
63
- expect(header.products[3].comment).to be_nil
64
- end
65
- end
66
-
67
- end
@@ -1,43 +0,0 @@
1
- require 'xenon/headers/www_authenticate'
2
-
3
- describe Xenon::Headers::WWWAuthenticate do
4
-
5
- context '::parse' do
6
-
7
- it 'can parse a Basic challenge with a realm' do
8
- header = Xenon::Headers::WWWAuthenticate.parse('Basic realm="simple"')
9
- expect(header.challenges.size).to eq(1)
10
- expect(header.challenges[0].auth_scheme).to eq('Basic')
11
- expect(header.challenges[0].realm).to eq('simple')
12
- end
13
-
14
- it 'can parse a Digest challenge with a realm' do
15
- header = Xenon::Headers::WWWAuthenticate.parse('Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41"')
16
- expect(header.challenges.size).to eq(1)
17
- expect(header.challenges[0].auth_scheme).to eq('Digest')
18
- expect(header.challenges[0].realm).to eq('testrealm@host.com')
19
- expect(header.challenges[0].qop).to eq('auth,auth-int')
20
- expect(header.challenges[0].nonce).to eq('dcd98b7102dd2f0e8b11d0f600bfb0c093')
21
- expect(header.challenges[0].opaque).to eq('5ccc069c403ebaf9f0171e9517f40e41')
22
- end
23
-
24
- it 'can parse a custom challenge' do
25
- header = Xenon::Headers::WWWAuthenticate.parse('Newauth realm="apps", type=1, title="Login to \"apps\""')
26
- expect(header.challenges.size).to eq(1)
27
- expect(header.challenges[0].auth_scheme).to eq('Newauth')
28
- expect(header.challenges[0].realm).to eq('apps')
29
- expect(header.challenges[0].type).to eq('1')
30
- expect(header.challenges[0].title).to eq('Login to "apps"')
31
- end
32
-
33
- it 'can parse multiple challenges' do
34
- header = Xenon::Headers::WWWAuthenticate.parse('Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41", Basic realm="simple", Newauth realm="apps", type=1, title="Login to \"apps\""')
35
- expect(header.challenges.size).to eq(3)
36
- expect(header.challenges[0].auth_scheme).to eq('Digest')
37
- expect(header.challenges[1].auth_scheme).to eq('Basic')
38
- expect(header.challenges[2].auth_scheme).to eq('Newauth')
39
- end
40
-
41
-
42
- end
43
- end
@@ -1,267 +0,0 @@
1
- require 'xenon/media_type'
2
-
3
- describe Xenon::MediaType do
4
-
5
- context '::parse' do
6
- it 'can parse basic media types' do
7
- mt = Xenon::MediaType.parse('application/json')
8
- expect(mt.type).to eq('application')
9
- expect(mt.subtype).to eq('json')
10
- end
11
- it 'can parse media types with a subtype suffix' do
12
- mt = Xenon::MediaType.parse('application/rss+xml')
13
- expect(mt.type).to eq('application')
14
- expect(mt.subtype).to eq('rss+xml')
15
- end
16
-
17
- it 'can parse media types with parameters' do
18
- mt = Xenon::MediaType.parse('text/plain; format=flowed; paged')
19
- expect(mt.type).to eq('text')
20
- expect(mt.subtype).to eq('plain')
21
- expect(mt.params).to eq({ 'format' => 'flowed', 'paged' => nil })
22
- end
23
-
24
- it 'strips whitespace around separators' do
25
- mt = Xenon::MediaType.parse('text/plain ; format = flowed ; paged')
26
- expect(mt.type).to eq('text')
27
- expect(mt.subtype).to eq('plain')
28
- expect(mt.params).to eq({ 'format' => 'flowed', 'paged' => nil })
29
- end
30
-
31
- it 'raises an error when the media type contains wildcards' do
32
- expect { Xenon::MediaType.parse('*/*') }.to raise_error(Xenon::ParseError)
33
- expect { Xenon::MediaType.parse('application/*') }.to raise_error(Xenon::ParseError)
34
- end
35
-
36
- it 'raises an error when the media type is invalid' do
37
- expect { Xenon::MediaType.parse('application') }.to raise_error(Xenon::ParseError)
38
- expect { Xenon::MediaType.parse('application; foo=bar') }.to raise_error(Xenon::ParseError)
39
- expect { Xenon::MediaType.parse('/json') }.to raise_error(Xenon::ParseError)
40
- expect { Xenon::MediaType.parse('/json; foo=bar') }.to raise_error(Xenon::ParseError)
41
- end
42
- end
43
-
44
- %w(application audio image message multipart text video).each do |type|
45
- context "#{type}?" do
46
- it "returns true when the root type is '#{type}'" do
47
- mt = Xenon::MediaType.new(type, 'dummy')
48
- expect(mt.send("#{type}?")).to eq(true)
49
- end
50
-
51
- it "returns false when the root type is not '#{type}'" do
52
- mt = Xenon::MediaType.new('dummy', 'dummy')
53
- expect(mt.send("#{type}?")).to eq(false)
54
- end
55
- end
56
- end
57
-
58
- { experimental?: 'x', personal?: 'prs', vendor?: 'vnd' }.each do |method, prefix|
59
- context method do
60
- it "returns true when the subtype starts with '#{prefix}.'" do
61
- mt = Xenon::MediaType.new('application', "#{prefix}.dummy")
62
- expect(mt.send(method)).to eq(true)
63
- end
64
-
65
- it "returns false when the subtype does not start with '#{prefix}.'" do
66
- mt = Xenon::MediaType.new('application', "dummy.dummy")
67
- expect(mt.send(method)).to eq(false)
68
- end
69
- end
70
- end
71
-
72
- %w(ber der fastinfoset json wbxml xml zip).each do |format|
73
- context "#{format}?" do
74
- it "returns true when the subtype is '#{format}'" do
75
- mt = Xenon::MediaType.new('application', format)
76
- expect(mt.send("#{format}?")).to eq(true)
77
- end
78
-
79
- it "returns true when the subtype ends with '+#{format}'" do
80
- mt = Xenon::MediaType.new('application', "dummy+#{format}")
81
- expect(mt.send("#{format}?")).to eq(true)
82
- end
83
-
84
- it "returns false when the subtype is not '#{format}' and does not end with '+#{format}'" do
85
- mt = Xenon::MediaType.new('dummy', 'dummy+dummy')
86
- expect(mt.send("#{format}?")).to eq(false)
87
- end
88
- end
89
- end
90
-
91
- context '#to_s' do
92
- it 'returns the string representation of a media type' do
93
- mt = Xenon::MediaType.new('text', 'plain', 'format' => 'flowed', 'paged' => nil)
94
- expect(mt.to_s).to eq('text/plain; format=flowed; paged')
95
- end
96
- end
97
-
98
- end
99
-
100
- describe Xenon::MediaRange do
101
-
102
- context '::parse' do
103
- it 'can parse basic media ranges' do
104
- mt = Xenon::MediaRange.parse('application/json')
105
- expect(mt.type).to eq('application')
106
- expect(mt.subtype).to eq('json')
107
- end
108
-
109
- it 'can parse media ranges with parameters' do
110
- mt = Xenon::MediaRange.parse('text/plain; format=flowed; paged')
111
- expect(mt.type).to eq('text')
112
- expect(mt.subtype).to eq('plain')
113
- expect(mt.params).to eq({ 'format' => 'flowed', 'paged' => nil })
114
- end
115
-
116
- it 'strips whitespace around separators' do
117
- mt = Xenon::MediaRange.parse('text/plain ; format = flowed ; paged')
118
- expect(mt.type).to eq('text')
119
- expect(mt.subtype).to eq('plain')
120
- expect(mt.params).to eq({ 'format' => 'flowed', 'paged' => nil })
121
- end
122
-
123
- it 'can parse media ranges with subtype wildcards' do
124
- mt = Xenon::MediaRange.parse('application/*')
125
- expect(mt.type).to eq('application')
126
- expect(mt.subtype).to eq('*')
127
- end
128
-
129
- it 'can parse media ranges with type and subtype wildcards' do
130
- mt = Xenon::MediaRange.parse('*/*')
131
- expect(mt.type).to eq('*')
132
- expect(mt.subtype).to eq('*')
133
- end
134
-
135
- it 'extracts q from the parameters' do
136
- mt = Xenon::MediaRange.parse('text/plain; q=0.8; format=flowed; paged')
137
- expect(mt.type).to eq('text')
138
- expect(mt.subtype).to eq('plain')
139
- expect(mt.q).to eq(0.8)
140
- expect(mt.params).to eq({ 'format' => 'flowed', 'paged' => nil })
141
- end
142
-
143
- it 'uses the default value for q if the value is not numeric' do
144
- mt = Xenon::MediaRange.parse('application/json; q=foo')
145
- expect(mt.type).to eq('application')
146
- expect(mt.subtype).to eq('json')
147
- expect(mt.q).to eq(Xenon::MediaRange::DEFAULT_Q)
148
- end
149
-
150
- it 'raises an error when the media range is invalid' do
151
- expect { Xenon::MediaRange.parse('application') }.to raise_error(Xenon::ParseError)
152
- expect { Xenon::MediaRange.parse('application; foo=bar') }.to raise_error(Xenon::ParseError)
153
- expect { Xenon::MediaRange.parse('*/json') }.to raise_error(Xenon::ParseError)
154
- expect { Xenon::MediaRange.parse('/json') }.to raise_error(Xenon::ParseError)
155
- expect { Xenon::MediaRange.parse('/json; foo=bar') }.to raise_error(Xenon::ParseError)
156
- end
157
- end
158
-
159
- context '#<=>' do
160
- it 'considers a wildcard type less than a regular type' do
161
- mr1 = Xenon::MediaRange.new('*', '*')
162
- mr2 = Xenon::MediaRange.new('text', '*')
163
- expect(mr1 <=> mr2).to eq(-1)
164
- end
165
-
166
- it 'considers a wildcard subtype less than a regular subtype' do
167
- mr1 = Xenon::MediaRange.new('application', '*')
168
- mr2 = Xenon::MediaRange.new('text', 'plain')
169
- expect(mr1 <=> mr2).to eq(-1)
170
- end
171
-
172
- it 'considers media ranges with type and subtype equal' do
173
- mr1 = Xenon::MediaRange.new('application', 'json')
174
- mr2 = Xenon::MediaRange.new('text', 'plain')
175
- expect(mr1 <=> mr2).to eq(0)
176
- end
177
-
178
- it 'considers a media range with parameters greater than one without' do
179
- mr1 = Xenon::MediaRange.new('text', 'plain', 'format' => 'flowed')
180
- mr2 = Xenon::MediaRange.new('text', 'plain')
181
- expect(mr1 <=> mr2).to eq(1)
182
- end
183
-
184
- it 'does not consider the quality when one media range is more specific' do
185
- mr1 = Xenon::MediaRange.new('application', '*', 'q' => '0.3')
186
- mr2 = Xenon::MediaRange.new('*', '*', 'q' => '0.5')
187
- expect(mr1 <=> mr2).to eq(1)
188
- end
189
-
190
- it 'considers the quality when media ranges are equally specific' do
191
- mr1 = Xenon::MediaRange.new('application', 'json', 'q' => '0.8')
192
- mr2 = Xenon::MediaRange.new('application', 'xml')
193
- expect(mr1 <=> mr2).to eq(-1)
194
- end
195
- end
196
-
197
- %i(=~ ===).each do |name|
198
- context "##{name}" do
199
- it 'returns true when the type and subtype are wildcards' do
200
- mr = Xenon::MediaRange.new('*', '*')
201
- mt = Xenon::MediaType.new('application', 'json')
202
- expect(mr.send(name, mt)).to eq(true)
203
- end
204
-
205
- it 'returns true when the type matches and subtype is a wildcard' do
206
- mr = Xenon::MediaRange.new('application', '*')
207
- mt = Xenon::MediaType.new('application', 'json')
208
- expect(mr.send(name, mt)).to eq(true)
209
- end
210
-
211
- it 'returns true when the type and subtype match exactly' do
212
- mr = Xenon::MediaRange.new('application', 'json')
213
- mt = Xenon::MediaType.new('application', 'json')
214
- expect(mr.send(name, mt)).to eq(true)
215
- end
216
-
217
- it 'returns true when the type, subtype and parameters match exactly' do
218
- mr = Xenon::MediaRange.new('text', 'plain', 'format' => 'flowed')
219
- mt = Xenon::MediaType.new('text', 'plain', 'format' => 'flowed', 'paged' => nil)
220
- expect(mr.send(name, mt)).to eq(true)
221
- end
222
-
223
- it 'returns true when the the media type has more specific parameters' do
224
- mr = Xenon::MediaRange.new('text', 'plain')
225
- mt = Xenon::MediaType.new('text', 'plain', 'format' => 'flowed', 'paged' => nil)
226
- expect(mr.send(name, mt)).to eq(true)
227
- end
228
-
229
- it 'returns false when the type is different' do
230
- mr = Xenon::MediaRange.new('text', 'json')
231
- mt = Xenon::MediaType.new('application', 'json')
232
- expect(mr.send(name, mt)).to eq(false)
233
- end
234
-
235
- it 'returns false when the type matches but subtype is different' do
236
- mr = Xenon::MediaRange.new('application', 'xml')
237
- mt = Xenon::MediaType.new('application', 'json')
238
- expect(mr.send(name, mt)).to eq(false)
239
- end
240
-
241
- it 'returns false when the media range has more specific parameters' do
242
- mr = Xenon::MediaRange.new('text', 'plain', 'format' => 'flowed', 'paged' => nil)
243
- mt = Xenon::MediaType.new('text', 'plain')
244
- expect(mr.send(name, mt)).to eq(false)
245
- end
246
-
247
- it 'returns false when the media range has a different parameter value' do
248
- mr = Xenon::MediaRange.new('text', 'plain', 'format' => 'flowed')
249
- mt = Xenon::MediaType.new('text', 'plain', 'format' => 'linear')
250
- expect(mr.send(name, mt)).to eq(false)
251
- end
252
- end
253
- end
254
-
255
- context '#to_s' do
256
- it 'returns the string representation of a media range' do
257
- mt = Xenon::MediaRange.new('text', 'plain', 'q' => 0.8, 'format' => 'flowed', 'paged' => nil)
258
- expect(mt.to_s).to eq('text/plain; format=flowed; paged; q=0.8')
259
- end
260
-
261
- it 'omits the q parameter when it is 1.0' do
262
- mt = Xenon::MediaRange.new('application', 'json', 'q' => 1.0)
263
- expect(mt.to_s).to eq('application/json')
264
- end
265
- end
266
-
267
- end