oortle-yajl-ruby 0.5.8

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 (132) hide show
  1. data/.gitignore +6 -0
  2. data/CHANGELOG.md +177 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +270 -0
  5. data/Rakefile +35 -0
  6. data/VERSION.yml +4 -0
  7. data/benchmark/encode.rb +46 -0
  8. data/benchmark/encode_json_and_marshal.rb +35 -0
  9. data/benchmark/encode_json_and_yaml.rb +47 -0
  10. data/benchmark/http.rb +30 -0
  11. data/benchmark/parse.rb +49 -0
  12. data/benchmark/parse_json_and_marshal.rb +47 -0
  13. data/benchmark/parse_json_and_yaml.rb +56 -0
  14. data/benchmark/parse_stream.rb +48 -0
  15. data/benchmark/subjects/item.json +1 -0
  16. data/benchmark/subjects/ohai.json +1216 -0
  17. data/benchmark/subjects/ohai.marshal_dump +0 -0
  18. data/benchmark/subjects/ohai.yml +975 -0
  19. data/benchmark/subjects/twitter_search.json +1 -0
  20. data/benchmark/subjects/twitter_stream.json +430 -0
  21. data/benchmark/subjects/unicode.json +1 -0
  22. data/examples/http/twitter_search_api.rb +15 -0
  23. data/examples/http/twitter_stream_api.rb +27 -0
  24. data/examples/parsing/from_file.rb +14 -0
  25. data/examples/parsing/from_stdin.rb +9 -0
  26. data/examples/parsing/from_string.rb +15 -0
  27. data/ext/api/yajl_common.h +85 -0
  28. data/ext/api/yajl_gen.h +123 -0
  29. data/ext/api/yajl_parse.h +182 -0
  30. data/ext/extconf.rb +8 -0
  31. data/ext/yajl.c +157 -0
  32. data/ext/yajl_alloc.c +65 -0
  33. data/ext/yajl_alloc.h +50 -0
  34. data/ext/yajl_buf.c +119 -0
  35. data/ext/yajl_buf.h +73 -0
  36. data/ext/yajl_bytestack.h +85 -0
  37. data/ext/yajl_encode.c +179 -0
  38. data/ext/yajl_encode.h +44 -0
  39. data/ext/yajl_ext.c +774 -0
  40. data/ext/yajl_ext.h +74 -0
  41. data/ext/yajl_gen.c +290 -0
  42. data/ext/yajl_lex.c +744 -0
  43. data/ext/yajl_lex.h +135 -0
  44. data/ext/yajl_parser.c +447 -0
  45. data/ext/yajl_parser.h +79 -0
  46. data/lib/yajl.rb +80 -0
  47. data/lib/yajl/bzip2.rb +11 -0
  48. data/lib/yajl/bzip2/stream_reader.rb +29 -0
  49. data/lib/yajl/bzip2/stream_writer.rb +15 -0
  50. data/lib/yajl/deflate.rb +6 -0
  51. data/lib/yajl/deflate/stream_reader.rb +38 -0
  52. data/lib/yajl/deflate/stream_writer.rb +21 -0
  53. data/lib/yajl/gzip.rb +6 -0
  54. data/lib/yajl/gzip/stream_reader.rb +28 -0
  55. data/lib/yajl/gzip/stream_writer.rb +14 -0
  56. data/lib/yajl/http_stream.rb +150 -0
  57. data/lib/yajl/json_gem.rb +14 -0
  58. data/lib/yajl/json_gem/encoding.rb +40 -0
  59. data/lib/yajl/json_gem/parsing.rb +26 -0
  60. data/spec/encoding/encoding_spec.rb +186 -0
  61. data/spec/http/fixtures/http.bzip2.dump +0 -0
  62. data/spec/http/fixtures/http.deflate.dump +0 -0
  63. data/spec/http/fixtures/http.gzip.dump +0 -0
  64. data/spec/http/fixtures/http.raw.dump +1226 -0
  65. data/spec/http/http_spec.rb +158 -0
  66. data/spec/json_gem_compatibility/compatibility_spec.rb +178 -0
  67. data/spec/parsing/active_support_spec.rb +64 -0
  68. data/spec/parsing/chunked_spec.rb +98 -0
  69. data/spec/parsing/fixtures/fail.15.json +1 -0
  70. data/spec/parsing/fixtures/fail.16.json +1 -0
  71. data/spec/parsing/fixtures/fail.17.json +1 -0
  72. data/spec/parsing/fixtures/fail.26.json +1 -0
  73. data/spec/parsing/fixtures/fail11.json +1 -0
  74. data/spec/parsing/fixtures/fail12.json +1 -0
  75. data/spec/parsing/fixtures/fail13.json +1 -0
  76. data/spec/parsing/fixtures/fail14.json +1 -0
  77. data/spec/parsing/fixtures/fail19.json +1 -0
  78. data/spec/parsing/fixtures/fail20.json +1 -0
  79. data/spec/parsing/fixtures/fail21.json +1 -0
  80. data/spec/parsing/fixtures/fail22.json +1 -0
  81. data/spec/parsing/fixtures/fail23.json +1 -0
  82. data/spec/parsing/fixtures/fail24.json +1 -0
  83. data/spec/parsing/fixtures/fail25.json +1 -0
  84. data/spec/parsing/fixtures/fail27.json +2 -0
  85. data/spec/parsing/fixtures/fail28.json +2 -0
  86. data/spec/parsing/fixtures/fail3.json +1 -0
  87. data/spec/parsing/fixtures/fail4.json +1 -0
  88. data/spec/parsing/fixtures/fail5.json +1 -0
  89. data/spec/parsing/fixtures/fail6.json +1 -0
  90. data/spec/parsing/fixtures/fail9.json +1 -0
  91. data/spec/parsing/fixtures/pass.array.json +6 -0
  92. data/spec/parsing/fixtures/pass.codepoints_from_unicode_org.json +1 -0
  93. data/spec/parsing/fixtures/pass.contacts.json +1 -0
  94. data/spec/parsing/fixtures/pass.db100.xml.json +1 -0
  95. data/spec/parsing/fixtures/pass.db1000.xml.json +1 -0
  96. data/spec/parsing/fixtures/pass.dc_simple_with_comments.json +11 -0
  97. data/spec/parsing/fixtures/pass.deep_arrays.json +1 -0
  98. data/spec/parsing/fixtures/pass.difficult_json_c_test_case.json +1 -0
  99. data/spec/parsing/fixtures/pass.difficult_json_c_test_case_with_comments.json +1 -0
  100. data/spec/parsing/fixtures/pass.doubles.json +1 -0
  101. data/spec/parsing/fixtures/pass.empty_array.json +1 -0
  102. data/spec/parsing/fixtures/pass.empty_string.json +1 -0
  103. data/spec/parsing/fixtures/pass.escaped_bulgarian.json +4 -0
  104. data/spec/parsing/fixtures/pass.escaped_foobar.json +1 -0
  105. data/spec/parsing/fixtures/pass.item.json +1 -0
  106. data/spec/parsing/fixtures/pass.json-org-sample1.json +23 -0
  107. data/spec/parsing/fixtures/pass.json-org-sample2.json +11 -0
  108. data/spec/parsing/fixtures/pass.json-org-sample3.json +26 -0
  109. data/spec/parsing/fixtures/pass.json-org-sample4-nows.json +88 -0
  110. data/spec/parsing/fixtures/pass.json-org-sample4.json +89 -0
  111. data/spec/parsing/fixtures/pass.json-org-sample5.json +27 -0
  112. data/spec/parsing/fixtures/pass.map-spain.xml.json +1 -0
  113. data/spec/parsing/fixtures/pass.ns-invoice100.xml.json +1 -0
  114. data/spec/parsing/fixtures/pass.ns-soap.xml.json +1 -0
  115. data/spec/parsing/fixtures/pass.numbers-fp-4k.json +6 -0
  116. data/spec/parsing/fixtures/pass.numbers-fp-64k.json +61 -0
  117. data/spec/parsing/fixtures/pass.numbers-int-4k.json +11 -0
  118. data/spec/parsing/fixtures/pass.numbers-int-64k.json +154 -0
  119. data/spec/parsing/fixtures/pass.twitter-search.json +1 -0
  120. data/spec/parsing/fixtures/pass.twitter-search2.json +1 -0
  121. data/spec/parsing/fixtures/pass.unicode.json +3315 -0
  122. data/spec/parsing/fixtures/pass.yelp.json +1 -0
  123. data/spec/parsing/fixtures/pass1.json +56 -0
  124. data/spec/parsing/fixtures/pass2.json +1 -0
  125. data/spec/parsing/fixtures/pass3.json +6 -0
  126. data/spec/parsing/fixtures_spec.rb +41 -0
  127. data/spec/parsing/one_off_spec.rb +54 -0
  128. data/spec/rcov.opts +4 -0
  129. data/spec/spec.opts +2 -0
  130. data/spec/spec_helper.rb +6 -0
  131. data/yajl-ruby.gemspec +179 -0
  132. metadata +198 -0
@@ -0,0 +1,158 @@
1
+ # encoding: UTF-8
2
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb')
3
+ require 'yajl/bzip2'
4
+ require 'yajl/gzip'
5
+ require 'yajl/deflate'
6
+ require 'yajl/http_stream'
7
+
8
+ def parse_off_headers(io)
9
+ io.each_line do |line|
10
+ if line == "\r\n" # end of the headers
11
+ break
12
+ end
13
+ end
14
+ end
15
+
16
+ describe "Yajl HTTP GET request" do
17
+ before(:all) do
18
+ raw = File.new(File.expand_path(File.dirname(__FILE__) + '/fixtures/http.raw.dump'), 'r')
19
+ parse_off_headers(raw)
20
+ @template_hash = Yajl::Parser.parse(raw)
21
+
22
+ raw.rewind
23
+ parse_off_headers(raw)
24
+ @template_hash_symbolized = Yajl::Parser.parse(raw, :symbolize_keys => true)
25
+
26
+ @deflate = File.new(File.expand_path(File.dirname(__FILE__) + '/fixtures/http.deflate.dump'), 'r')
27
+ @gzip = File.new(File.expand_path(File.dirname(__FILE__) + '/fixtures/http.gzip.dump'), 'r')
28
+ end
29
+
30
+ after(:each) do
31
+ @file_path = nil
32
+ end
33
+
34
+ def prepare_mock_request_dump(format=:raw)
35
+ @request = File.new(File.expand_path(File.dirname(__FILE__) + "/fixtures/http.#{format}.dump"), 'r')
36
+ @uri = 'file://'+File.expand_path(File.dirname(__FILE__) + "/fixtures/http/http.#{format}.dump")
37
+ TCPSocket.should_receive(:new).and_return(@request)
38
+ @request.should_receive(:write)
39
+ @uri.should_receive(:host).at_least(2).times
40
+ @uri.should_receive(:port)
41
+ @uri.should_receive(:path)
42
+ @uri.should_receive(:query)
43
+ @uri.should_receive(:userinfo)
44
+ end
45
+
46
+ it "should parse a raw response" do
47
+ prepare_mock_request_dump :raw
48
+ @template_hash.should == Yajl::HttpStream.get(@uri)
49
+ end
50
+
51
+ it "should parse a raw response and symbolize keys" do
52
+ prepare_mock_request_dump :raw
53
+ @template_hash_symbolized.should == Yajl::HttpStream.get(@uri, :symbolize_keys => true)
54
+ end
55
+
56
+ it "should parse a bzip2 compressed response" do
57
+ prepare_mock_request_dump :bzip2
58
+ @template_hash.should == Yajl::HttpStream.get(@uri)
59
+ end
60
+
61
+ it "should parse a bzip2 compressed response and symbolize keys" do
62
+ prepare_mock_request_dump :bzip2
63
+ @template_hash_symbolized.should == Yajl::HttpStream.get(@uri, :symbolize_keys => true)
64
+ end
65
+
66
+ it "should parse a deflate compressed response" do
67
+ prepare_mock_request_dump :deflate
68
+ @template_hash.should == Yajl::HttpStream.get(@uri)
69
+ end
70
+
71
+ it "should parse a deflate compressed response and symbolize keys" do
72
+ prepare_mock_request_dump :deflate
73
+ @template_hash_symbolized.should == Yajl::HttpStream.get(@uri, :symbolize_keys => true)
74
+ end
75
+
76
+ it "should parse a gzip compressed response" do
77
+ prepare_mock_request_dump :gzip
78
+ @template_hash.should == Yajl::HttpStream.get(@uri)
79
+ end
80
+
81
+ it "should parse a gzip compressed response and symbolize keys" do
82
+ prepare_mock_request_dump :gzip
83
+ @template_hash_symbolized.should == Yajl::HttpStream.get(@uri, :symbolize_keys => true)
84
+ end
85
+ end
86
+
87
+ describe "Yajl HTTP POST request" do
88
+ before(:all) do
89
+ raw = File.new(File.expand_path(File.dirname(__FILE__) + '/fixtures/http.raw.dump'), 'r')
90
+ parse_off_headers(raw)
91
+ @template_hash = Yajl::Parser.parse(raw)
92
+
93
+ raw.rewind
94
+ parse_off_headers(raw)
95
+ @template_hash_symbolized = Yajl::Parser.parse(raw, :symbolize_keys => true)
96
+
97
+ @deflate = File.new(File.expand_path(File.dirname(__FILE__) + '/fixtures/http.deflate.dump'), 'r')
98
+ @gzip = File.new(File.expand_path(File.dirname(__FILE__) + '/fixtures/http.gzip.dump'), 'r')
99
+
100
+ @params = {:a => 1, :b => 'has spaces'}
101
+ end
102
+
103
+ after(:each) do
104
+ @file_path = nil
105
+ end
106
+
107
+ def prepare_mock_request_dump(format=:raw)
108
+ @request = File.new(File.expand_path(File.dirname(__FILE__) + "/fixtures/http.#{format}.dump"), 'r')
109
+ @uri = 'file://'+File.expand_path(File.dirname(__FILE__) + "/fixtures/http/http.#{format}.dump")
110
+ TCPSocket.should_receive(:new).and_return(@request)
111
+ @request.should_receive(:write)
112
+ @uri.should_receive(:host).at_least(2).times
113
+ @uri.should_receive(:port)
114
+ @uri.should_receive(:path)
115
+ @uri.should_receive(:query)
116
+ @uri.should_receive(:userinfo)
117
+ end
118
+
119
+ it "should parse a raw response" do
120
+ prepare_mock_request_dump :raw
121
+ @template_hash.should == Yajl::HttpStream.post(@uri, @params)
122
+ end
123
+
124
+ it "should parse a raw response and symbolize keys" do
125
+ prepare_mock_request_dump :raw
126
+ @template_hash_symbolized.should == Yajl::HttpStream.post(@uri, @params, :symbolize_keys => true)
127
+ end
128
+
129
+ it "should parse a bzip2 compressed response" do
130
+ prepare_mock_request_dump :bzip2
131
+ @template_hash.should == Yajl::HttpStream.post(@uri, @params)
132
+ end
133
+
134
+ it "should parse a bzip2 compressed response and symbolize keys" do
135
+ prepare_mock_request_dump :bzip2
136
+ @template_hash_symbolized.should == Yajl::HttpStream.post(@uri, @params, :symbolize_keys => true)
137
+ end
138
+
139
+ it "should parse a deflate compressed response" do
140
+ prepare_mock_request_dump :deflate
141
+ @template_hash.should == Yajl::HttpStream.post(@uri, @params)
142
+ end
143
+
144
+ it "should parse a deflate compressed response and symbolize keys" do
145
+ prepare_mock_request_dump :deflate
146
+ @template_hash_symbolized.should == Yajl::HttpStream.post(@uri, @params, :symbolize_keys => true)
147
+ end
148
+
149
+ it "should parse a gzip compressed response" do
150
+ prepare_mock_request_dump :gzip
151
+ @template_hash.should == Yajl::HttpStream.post(@uri, @params)
152
+ end
153
+
154
+ it "should parse a gzip compressed response and symbolize keys" do
155
+ prepare_mock_request_dump :gzip
156
+ @template_hash_symbolized.should == Yajl::HttpStream.post(@uri, @params, :symbolize_keys => true)
157
+ end
158
+ end
@@ -0,0 +1,178 @@
1
+ # encoding: UTF-8
2
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb')
3
+
4
+ class Dummy; end
5
+
6
+ describe "JSON Gem compatability API" do
7
+ it "shoud not mixin #to_json on base objects until compatability has been enabled" do
8
+ d = Dummy.new
9
+
10
+ d.respond_to?(:to_json).should_not be_true
11
+ "".respond_to?(:to_json).should_not be_true
12
+ 1.respond_to?(:to_json).should_not be_true
13
+ "1.5".to_f.respond_to?(:to_json).should_not be_true
14
+ [].respond_to?(:to_json).should_not be_true
15
+ {:foo => "bar"}.respond_to?(:to_json).should_not be_true
16
+ true.respond_to?(:to_json).should_not be_true
17
+ false.respond_to?(:to_json).should_not be_true
18
+ nil.respond_to?(:to_json).should_not be_true
19
+ end
20
+
21
+ it "should mixin #to_json on base objects after compatability has been enabled" do
22
+ Yajl::Encoder.enable_json_gem_compatability
23
+ d = Dummy.new
24
+
25
+ d.respond_to?(:to_json).should be_true
26
+ "".respond_to?(:to_json).should be_true
27
+ 1.respond_to?(:to_json).should be_true
28
+ "1.5".to_f.respond_to?(:to_json).should be_true
29
+ [].respond_to?(:to_json).should be_true
30
+ {:foo => "bar"}.respond_to?(:to_json).should be_true
31
+ true.respond_to?(:to_json).should be_true
32
+ false.respond_to?(:to_json).should be_true
33
+ nil.respond_to?(:to_json).should be_true
34
+ end
35
+
36
+ it "should require yajl/json_gem to enable the compatability API" do
37
+ require 'yajl/json_gem'
38
+
39
+ defined?(JSON).should be_true
40
+
41
+ JSON.respond_to?(:parse).should be_true
42
+ JSON.respond_to?(:generate).should be_true
43
+ JSON.respond_to?(:pretty_generate).should be_true
44
+ JSON.respond_to?(:load).should be_true
45
+ JSON.respond_to?(:dump).should be_true
46
+ end
47
+
48
+ it "should allow default parsing options be set with JSON.default_options" do
49
+ default = JSON.default_options[:symbolize_keys]
50
+ JSON.parse('{"foo": 1234}').should === {"foo" => 1234}
51
+ JSON.default_options[:symbolize_keys] = true
52
+ JSON.parse('{"foo": 1234}').should === {:foo => 1234}
53
+ JSON.default_options[:symbolize_keys] = default # ensure the rest of the test cases expect the default
54
+ end
55
+
56
+ context "ported tests for Unicode" do
57
+ it "should be able to encode and parse unicode" do
58
+ pending if RUBY_VERSION.include?('1.9') # FIXME: Some string encoding problem with 1.9
59
+ '""'.should eql(''.to_json)
60
+ '"\\b"'.should eql("\b".to_json)
61
+ '"\u0001"'.should eql(0x1.chr.to_json)
62
+ '"\u001F"'.should eql(0x1f.chr.to_json)
63
+ '" "'.should eql(' '.to_json)
64
+ "\"#{0x7f.chr}\"".should eql(0x7f.chr.to_json)
65
+ utf8 = [ "© ≠ €! \01" ]
66
+ json = '["© ≠ €! \u0001"]'
67
+ json.should eql(utf8.to_json)
68
+ utf8.should eql(JSON.parse(json))
69
+ utf8 = ["\343\201\202\343\201\204\343\201\206\343\201\210\343\201\212"]
70
+ json = "[\"あいうえお\"]"
71
+ json.should eql(utf8.to_json)
72
+ utf8.should eql(JSON.parse(json))
73
+ utf8 = ['საქართველო']
74
+ json = "[\"საქართველო\"]"
75
+ json.should eql(utf8.to_json)
76
+ utf8.should eql(JSON.parse(json))
77
+ '["Ã"]'.should eql(JSON.generate(["Ã"]))
78
+ ["€"].should eql(JSON.parse('["\u20ac"]'))
79
+ utf8_str = "\xf0\xa0\x80\x81"
80
+ utf8 = [utf8_str]
81
+ json = "[\"#{utf8_str}\"]"
82
+ json.should eql(JSON.generate(utf8))
83
+ utf8.should eql(JSON.parse(json))
84
+ end
85
+ end
86
+
87
+ context "ported tests for generation" do
88
+ before(:all) do
89
+ @hash = {
90
+ 'a' => 2,
91
+ 'b' => 3.141,
92
+ 'c' => 'c',
93
+ 'd' => [ 1, "b", 3.14 ],
94
+ 'e' => { 'foo' => 'bar' },
95
+ 'g' => "blah",
96
+ 'h' => 1000.0,
97
+ 'i' => 0.001
98
+ }
99
+
100
+ @json2 = '{"a":2,"b":3.141,"c":"c","d":[1,"b",3.14],"e":{"foo":"bar"},"g":"blah","h":1000.0,"i":0.001}'
101
+
102
+ @json3 = %{
103
+ {
104
+ "a": 2,
105
+ "b": 3.141,
106
+ "c": "c",
107
+ "d": [1, "b", 3.14],
108
+ "e": {"foo": "bar"},
109
+ "g": "blah",
110
+ "h": 1000.0,
111
+ "i": 0.001
112
+ }
113
+ }.chomp
114
+ end
115
+
116
+ it "should be able to unparse" do
117
+ json = JSON.generate(@hash)
118
+ JSON.parse(@json2).should == JSON.parse(json)
119
+ parsed_json = JSON.parse(json)
120
+ @hash.should == parsed_json
121
+ json = JSON.generate({1=>2})
122
+ '{"1":2}'.should eql(json)
123
+ parsed_json = JSON.parse(json)
124
+ {"1"=>2}.should == parsed_json
125
+ end
126
+
127
+ it "should be able to unparse pretty" do
128
+ json = JSON.pretty_generate(@hash)
129
+ JSON.parse(@json3).should == JSON.parse(json)
130
+ parsed_json = JSON.parse(json)
131
+ @hash.should == parsed_json
132
+ json = JSON.pretty_generate({1=>2})
133
+ test = "{\n \"1\": 2\n}".chomp
134
+ test.should == json
135
+ parsed_json = JSON.parse(json)
136
+ {"1"=>2}.should == parsed_json
137
+ end
138
+ end
139
+
140
+ context "ported fixture tests" do
141
+ fixtures = File.join(File.dirname(__FILE__), '../parsing/fixtures/*.json')
142
+ passed, failed = Dir[fixtures].partition { |f| f['pass'] }
143
+ JSON_PASSED = passed.inject([]) { |a, f| a << [ f, File.read(f) ] }.sort
144
+ JSON_FAILED = failed.inject([]) { |a, f| a << [ f, File.read(f) ] }.sort
145
+
146
+ JSON_FAILED.each do |name, source|
147
+ it "should not be able to parse #{File.basename(name)} as an IO" do
148
+ lambda {
149
+ JSON.parse(StringIO.new(source))
150
+ }.should raise_error(Yajl::ParseError)
151
+ end
152
+ end
153
+
154
+ JSON_FAILED.each do |name, source|
155
+ it "should not be able to parse #{File.basename(name)} as a string" do
156
+ lambda {
157
+ JSON.parse(source)
158
+ }.should raise_error(Yajl::ParseError)
159
+ end
160
+ end
161
+
162
+ JSON_PASSED.each do |name, source|
163
+ it "should be able to parse #{File.basename(name)} as an IO" do
164
+ lambda {
165
+ JSON.parse(StringIO.new(source))
166
+ }.should_not raise_error(Yajl::ParseError)
167
+ end
168
+ end
169
+
170
+ JSON_PASSED.each do |name, source|
171
+ it "should be able to parse #{File.basename(name)} as a string" do
172
+ lambda {
173
+ JSON.parse(source)
174
+ }.should_not raise_error(Yajl::ParseError)
175
+ end
176
+ end
177
+ end
178
+ end
@@ -0,0 +1,64 @@
1
+ # encoding: UTF-8
2
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb')
3
+
4
+ describe "ActiveSupport test cases" do
5
+ TESTS = {
6
+ %q({"returnTo":{"\/categories":"\/"}}) => {"returnTo" => {"/categories" => "/"}},
7
+ %q({"return\\"To\\":":{"\/categories":"\/"}}) => {"return\"To\":" => {"/categories" => "/"}},
8
+ %q({"returnTo":{"\/categories":1}}) => {"returnTo" => {"/categories" => 1}},
9
+ %({"returnTo":[1,"a"]}) => {"returnTo" => [1, "a"]},
10
+ %({"returnTo":[1,"\\"a\\",", "b"]}) => {"returnTo" => [1, "\"a\",", "b"]},
11
+ %({"a": "'", "b": "5,000"}) => {"a" => "'", "b" => "5,000"},
12
+ %({"a": "a's, b's and c's", "b": "5,000"}) => {"a" => "a's, b's and c's", "b" => "5,000"},
13
+ # multibyte
14
+ %({"matzue": "松江", "asakusa": "浅草"}) => {"matzue" => "松江", "asakusa" => "浅草"},
15
+ %({"a": "2007-01-01"}) => {'a' => "2007-01-01"},
16
+ %({"a": "2007-01-01 01:12:34 Z"}) => {'a' => "2007-01-01 01:12:34 Z"},
17
+ # no time zone
18
+ %({"a": "2007-01-01 01:12:34"}) => {'a' => "2007-01-01 01:12:34"},
19
+ # needs to be *exact*
20
+ %({"a": " 2007-01-01 01:12:34 Z "}) => {'a' => " 2007-01-01 01:12:34 Z "},
21
+ %({"a": "2007-01-01 : it's your birthday"}) => {'a' => "2007-01-01 : it's your birthday"},
22
+ %([]) => [],
23
+ %({}) => {},
24
+ %({"a":1}) => {"a" => 1},
25
+ %({"a": ""}) => {"a" => ""},
26
+ %({"a":"\\""}) => {"a" => "\""},
27
+ %({"a": null}) => {"a" => nil},
28
+ %({"a": true}) => {"a" => true},
29
+ %({"a": false}) => {"a" => false},
30
+ %q({"a": "http:\/\/test.host\/posts\/1"}) => {"a" => "http://test.host/posts/1"},
31
+ %q({"a": "\u003cunicode\u0020escape\u003e"}) => {"a" => "<unicode escape>"},
32
+ %q({"a": "\\\\u0020skip double backslashes"}) => {"a" => "\\u0020skip double backslashes"},
33
+ %q({"a": "\u003cbr /\u003e"}) => {'a' => "<br />"},
34
+ %q({"b":["\u003ci\u003e","\u003cb\u003e","\u003cu\u003e"]}) => {'b' => ["<i>","<b>","<u>"]}
35
+ }
36
+
37
+ TESTS.each do |json, expected|
38
+ it "should be able to parse #{json} as an IO" do
39
+ lambda {
40
+ Yajl::Parser.parse(StringIO.new(json)).should == expected
41
+ }.should_not raise_error(Yajl::ParseError)
42
+ end
43
+ end
44
+
45
+ TESTS.each do |json, expected|
46
+ it "should be able to parse #{json} as a string" do
47
+ lambda {
48
+ Yajl::Parser.parse(json).should == expected
49
+ }.should_not raise_error(Yajl::ParseError)
50
+ end
51
+ end
52
+
53
+ it "should fail parsing {: 1} as an IO" do
54
+ lambda {
55
+ Yajl::Parser.parse(StringIO.new("{: 1}"))
56
+ }.should raise_error(Yajl::ParseError)
57
+ end
58
+
59
+ it "should fail parsing {: 1} as a string" do
60
+ lambda {
61
+ Yajl::Parser.parse("{: 1}")
62
+ }.should raise_error(Yajl::ParseError)
63
+ end
64
+ end
@@ -0,0 +1,98 @@
1
+ # encoding: UTF-8
2
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb')
3
+ require 'stringio'
4
+
5
+ describe "Chunked parser" do
6
+ before(:all) do
7
+ @final = [{"abc" => 123}, {"def" => 456}]
8
+ end
9
+
10
+ before(:each) do
11
+ @callback = lambda { |hash|
12
+ # no-op
13
+ }
14
+ @parser = Yajl::Parser.new
15
+ @parser.on_parse_complete = @callback
16
+ end
17
+
18
+ it "should parse a single chunk" do
19
+ @callback.should_receive(:call).with(@final)
20
+ @parser << '[{"abc": 123},{"def": 456}]'
21
+ end
22
+
23
+ it "should parse a single chunk, 3 times" do
24
+ @callback.should_receive(:call).with(@final).exactly(3).times
25
+ @parser << '[{"abc": 123},{"def": 456}]'
26
+ @parser << '[{"abc": 123},{"def": 456}]'
27
+ @parser << '[{"abc": 123},{"def": 456}]'
28
+ end
29
+
30
+ it "should parse in two chunks" do
31
+ @callback.should_receive(:call).with(@final)
32
+ @parser << '[{"abc": 123},'
33
+ @parser << '{"def": 456}]'
34
+ end
35
+
36
+ it "should parse in 2 chunks, twice" do
37
+ @callback.should_receive(:call).with(@final).exactly(2).times
38
+ @parser << '[{"abc": 123},'
39
+ @parser << '{"def": 456}]'
40
+ @parser << '[{"abc": 123},'
41
+ @parser << '{"def": 456}]'
42
+ end
43
+
44
+ it "should parse 2 JSON strings, in 3 chunks" do
45
+ @callback.should_receive(:call).with(@final).exactly(2).times
46
+ @parser << '[{"abc": 123},'
47
+ @parser << '{"def": 456}][{"abc": 123},{"def":'
48
+ @parser << ' 456}]'
49
+ end
50
+
51
+ it "should parse 2 JSON strings in 1 chunk" do
52
+ @callback.should_receive(:call).with(@final).exactly(2).times
53
+ @parser << '[{"abc": 123},{"def": 456}][{"abc": 123},{"def": 456}]'
54
+ end
55
+
56
+ it "should parse 2 JSON strings from an IO" do
57
+ @callback.should_receive(:call).with(@final).exactly(2).times
58
+ @parser.parse(StringIO.new('[{"abc": 123},{"def": 456}][{"abc": 123},{"def": 456}]'))
59
+ end
60
+
61
+ it "should parse a JSON string an IO and fire callback once" do
62
+ @callback.should_receive(:call).with(@final)
63
+ @parser.parse(StringIO.new('[{"abc": 123},{"def": 456}]'))
64
+ end
65
+
66
+ it "should parse twitter_stream.json and fire callback 430 times" do
67
+ path = File.expand_path(File.dirname(__FILE__) + '/../../benchmark/subjects/twitter_stream.json')
68
+ json = File.new(path, 'r')
69
+ @callback.should_receive(:call).exactly(430).times
70
+ lambda {
71
+ @parser.parse(json)
72
+ }.should_not raise_error(Yajl::ParseError)
73
+ end
74
+
75
+ it "should parse twitter_stream.json and fire callback 430 times, with a block as the callback" do
76
+ path = File.expand_path(File.dirname(__FILE__) + '/../../benchmark/subjects/twitter_stream.json')
77
+ json = File.new(path, 'r')
78
+ @callback.should_receive(:call).exactly(0).times
79
+ @parser.on_parse_complete = nil
80
+ lambda {
81
+ times = 0
82
+ @parser.parse(json) do |hsh|
83
+ times += 1
84
+ end
85
+ times.should eql(430)
86
+ }.should_not raise_error(Yajl::ParseError)
87
+ end
88
+
89
+ it "should raise a Yajl::ParseError error if multiple JSON strings were found when no on_parse_complete callback assigned" do
90
+ path = File.expand_path(File.dirname(__FILE__) + '/../../benchmark/subjects/twitter_stream.json')
91
+ json = File.new(path, 'r')
92
+ @parser.on_parse_complete = nil
93
+ @callback.should_receive(:call).exactly(0).times
94
+ lambda {
95
+ @parser.parse(json)
96
+ }.should raise_error(Yajl::ParseError)
97
+ end
98
+ end