xenon 0.0.3 → 0.0.4

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