thrift 0.8.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/benchmark/gen-rb/benchmark_constants.rb +3 -2
  2. data/benchmark/gen-rb/benchmark_service.rb +52 -52
  3. data/benchmark/gen-rb/benchmark_types.rb +3 -2
  4. data/ext/binary_protocol_accelerated.c +5 -2
  5. data/ext/bytes.c +36 -0
  6. data/ext/bytes.h +31 -0
  7. data/ext/compact_protocol.c +7 -4
  8. data/ext/constants.h +4 -0
  9. data/ext/extconf.rb +3 -1
  10. data/ext/memory_buffer.c +11 -8
  11. data/ext/thrift_native.c +9 -0
  12. data/lib/thrift.rb +2 -0
  13. data/lib/thrift/bytes.rb +131 -0
  14. data/lib/thrift/protocol/base_protocol.rb +10 -0
  15. data/lib/thrift/protocol/binary_protocol.rb +5 -5
  16. data/lib/thrift/protocol/compact_protocol.rb +4 -3
  17. data/lib/thrift/protocol/json_protocol.rb +765 -0
  18. data/lib/thrift/transport/base_transport.rb +22 -20
  19. data/lib/thrift/transport/buffered_transport.rb +16 -10
  20. data/lib/thrift/transport/framed_transport.rb +11 -10
  21. data/lib/thrift/transport/http_client_transport.rb +7 -5
  22. data/lib/thrift/transport/io_stream_transport.rb +1 -1
  23. data/lib/thrift/transport/memory_buffer_transport.rb +6 -6
  24. data/lib/thrift/transport/socket.rb +4 -2
  25. data/spec/ThriftSpec.thrift +52 -1
  26. data/spec/base_protocol_spec.rb +44 -45
  27. data/spec/base_transport_spec.rb +49 -50
  28. data/spec/binary_protocol_accelerated_spec.rb +9 -13
  29. data/spec/binary_protocol_spec.rb +15 -10
  30. data/spec/binary_protocol_spec_shared.rb +62 -12
  31. data/spec/bytes_spec.rb +160 -0
  32. data/spec/client_spec.rb +13 -14
  33. data/spec/compact_protocol_spec.rb +3 -2
  34. data/spec/exception_spec.rb +39 -40
  35. data/spec/gen-rb/nonblocking_service.rb +193 -193
  36. data/spec/gen-rb/thrift_spec_constants.rb +3 -2
  37. data/spec/gen-rb/thrift_spec_types.rb +455 -262
  38. data/spec/http_client_spec.rb +16 -9
  39. data/spec/json_protocol_spec.rb +513 -0
  40. data/spec/mongrel_http_server_spec.rb +19 -22
  41. data/spec/nonblocking_server_spec.rb +18 -20
  42. data/spec/processor_spec.rb +13 -16
  43. data/spec/serializer_spec.rb +17 -19
  44. data/spec/server_socket_spec.rb +6 -7
  45. data/spec/server_spec.rb +46 -58
  46. data/spec/socket_spec.rb +11 -11
  47. data/spec/socket_spec_shared.rb +1 -1
  48. data/spec/spec_helper.rb +13 -10
  49. data/spec/struct_nested_containers_spec.rb +191 -0
  50. data/spec/struct_spec.rb +84 -86
  51. data/spec/types_spec.rb +65 -66
  52. data/spec/union_spec.rb +44 -46
  53. data/spec/unix_socket_spec.rb +8 -9
  54. data/test/debug_proto/gen-rb/debug_proto_test_constants.rb +8 -7
  55. data/test/debug_proto/gen-rb/debug_proto_test_types.rb +24 -23
  56. data/test/debug_proto/gen-rb/empty_service.rb +1 -1
  57. data/test/debug_proto/gen-rb/inherited.rb +3 -3
  58. data/test/debug_proto/gen-rb/reverse_order_service.rb +1 -1
  59. data/test/debug_proto/gen-rb/service_for_exception_with_a_map.rb +3 -3
  60. data/test/debug_proto/gen-rb/srv.rb +2 -2
  61. metadata +43 -49
@@ -17,22 +17,21 @@
17
17
  # under the License.
18
18
  #
19
19
 
20
- require File.expand_path("#{File.dirname(__FILE__)}/spec_helper")
20
+ require 'spec_helper'
21
21
 
22
- class ThriftBaseTransportSpec < Spec::ExampleGroup
23
- include Thrift
22
+ describe 'BaseTransport' do
24
23
 
25
- describe TransportException do
24
+ describe Thrift::TransportException do
26
25
  it "should make type accessible" do
27
- exc = TransportException.new(TransportException::ALREADY_OPEN, "msg")
28
- exc.type.should == TransportException::ALREADY_OPEN
26
+ exc = Thrift::TransportException.new(Thrift::TransportException::ALREADY_OPEN, "msg")
27
+ exc.type.should == Thrift::TransportException::ALREADY_OPEN
29
28
  exc.message.should == "msg"
30
29
  end
31
30
  end
32
31
 
33
- describe BaseTransport do
32
+ describe Thrift::BaseTransport do
34
33
  it "should read the specified size" do
35
- transport = BaseTransport.new
34
+ transport = Thrift::BaseTransport.new
36
35
  transport.should_receive(:read).with(40).ordered.and_return("10 letters")
37
36
  transport.should_receive(:read).with(30).ordered.and_return("fifteen letters")
38
37
  transport.should_receive(:read).with(15).ordered.and_return("more characters")
@@ -42,47 +41,47 @@ class ThriftBaseTransportSpec < Spec::ExampleGroup
42
41
  it "should stub out the rest of the methods" do
43
42
  # can't test for stubbiness, so just make sure they're defined
44
43
  [:open?, :open, :close, :read, :write, :flush].each do |sym|
45
- BaseTransport.method_defined?(sym).should be_true
44
+ Thrift::BaseTransport.method_defined?(sym).should be_true
46
45
  end
47
46
  end
48
47
 
49
48
  it "should alias << to write" do
50
- BaseTransport.instance_method(:<<).should == BaseTransport.instance_method(:write)
49
+ Thrift::BaseTransport.instance_method(:<<).should == Thrift::BaseTransport.instance_method(:write)
51
50
  end
52
51
  end
53
52
 
54
- describe BaseServerTransport do
53
+ describe Thrift::BaseServerTransport do
55
54
  it "should stub out its methods" do
56
55
  [:listen, :accept, :close].each do |sym|
57
- BaseServerTransport.method_defined?(sym).should be_true
56
+ Thrift::BaseServerTransport.method_defined?(sym).should be_true
58
57
  end
59
58
  end
60
59
  end
61
60
 
62
- describe BaseTransportFactory do
61
+ describe Thrift::BaseTransportFactory do
63
62
  it "should return the transport it's given" do
64
63
  transport = mock("Transport")
65
- BaseTransportFactory.new.get_transport(transport).should eql(transport)
64
+ Thrift::BaseTransportFactory.new.get_transport(transport).should eql(transport)
66
65
  end
67
66
  end
68
67
 
69
- describe BufferedTransport do
68
+ describe Thrift::BufferedTransport do
70
69
  it "should pass through everything but write/flush/read" do
71
70
  trans = mock("Transport")
72
71
  trans.should_receive(:open?).ordered.and_return("+ open?")
73
72
  trans.should_receive(:open).ordered.and_return("+ open")
74
73
  trans.should_receive(:flush).ordered # from the close
75
74
  trans.should_receive(:close).ordered.and_return("+ close")
76
- btrans = BufferedTransport.new(trans)
75
+ btrans = Thrift::BufferedTransport.new(trans)
77
76
  btrans.open?.should == "+ open?"
78
77
  btrans.open.should == "+ open"
79
78
  btrans.close.should == "+ close"
80
79
  end
81
-
82
- it "should buffer reads in chunks of #{BufferedTransport::DEFAULT_BUFFER}" do
80
+
81
+ it "should buffer reads in chunks of #{Thrift::BufferedTransport::DEFAULT_BUFFER}" do
83
82
  trans = mock("Transport")
84
- trans.should_receive(:read).with(BufferedTransport::DEFAULT_BUFFER).and_return("lorum ipsum dolor emet")
85
- btrans = BufferedTransport.new(trans)
83
+ trans.should_receive(:read).with(Thrift::BufferedTransport::DEFAULT_BUFFER).and_return("lorum ipsum dolor emet")
84
+ btrans = Thrift::BufferedTransport.new(trans)
86
85
  btrans.read(6).should == "lorum "
87
86
  btrans.read(6).should == "ipsum "
88
87
  btrans.read(6).should == "dolor "
@@ -91,7 +90,7 @@ class ThriftBaseTransportSpec < Spec::ExampleGroup
91
90
 
92
91
  it "should buffer writes and send them on flush" do
93
92
  trans = mock("Transport")
94
- btrans = BufferedTransport.new(trans)
93
+ btrans = Thrift::BufferedTransport.new(trans)
95
94
  btrans.write("one/")
96
95
  btrans.write("two/")
97
96
  btrans.write("three/")
@@ -102,7 +101,7 @@ class ThriftBaseTransportSpec < Spec::ExampleGroup
102
101
 
103
102
  it "should only send buffered data once" do
104
103
  trans = mock("Transport")
105
- btrans = BufferedTransport.new(trans)
104
+ btrans = Thrift::BufferedTransport.new(trans)
106
105
  btrans.write("one/")
107
106
  btrans.write("two/")
108
107
  btrans.write("three/")
@@ -112,39 +111,39 @@ class ThriftBaseTransportSpec < Spec::ExampleGroup
112
111
  # Nothing to flush with no data
113
112
  btrans.flush
114
113
  end
115
-
114
+
116
115
  it "should flush on close" do
117
116
  trans = mock("Transport")
118
117
  trans.should_receive(:close)
119
- btrans = BufferedTransport.new(trans)
118
+ btrans = Thrift::BufferedTransport.new(trans)
120
119
  btrans.should_receive(:flush)
121
120
  btrans.close
122
121
  end
123
-
122
+
124
123
  it "should not write to socket if there's no data" do
125
124
  trans = mock("Transport")
126
125
  trans.should_receive(:flush)
127
- btrans = BufferedTransport.new(trans)
126
+ btrans = Thrift::BufferedTransport.new(trans)
128
127
  btrans.flush
129
128
  end
130
129
  end
131
130
 
132
- describe BufferedTransportFactory do
131
+ describe Thrift::BufferedTransportFactory do
133
132
  it "should wrap the given transport in a BufferedTransport" do
134
133
  trans = mock("Transport")
135
134
  btrans = mock("BufferedTransport")
136
- BufferedTransport.should_receive(:new).with(trans).and_return(btrans)
137
- BufferedTransportFactory.new.get_transport(trans).should == btrans
135
+ Thrift::BufferedTransport.should_receive(:new).with(trans).and_return(btrans)
136
+ Thrift::BufferedTransportFactory.new.get_transport(trans).should == btrans
138
137
  end
139
138
  end
140
139
 
141
- describe FramedTransport do
140
+ describe Thrift::FramedTransport do
142
141
  before(:each) do
143
142
  @trans = mock("Transport")
144
143
  end
145
144
 
146
145
  it "should pass through open?/open/close" do
147
- ftrans = FramedTransport.new(@trans)
146
+ ftrans = Thrift::FramedTransport.new(@trans)
148
147
  @trans.should_receive(:open?).ordered.and_return("+ open?")
149
148
  @trans.should_receive(:open).ordered.and_return("+ open")
150
149
  @trans.should_receive(:close).ordered.and_return("+ close")
@@ -154,13 +153,13 @@ class ThriftBaseTransportSpec < Spec::ExampleGroup
154
153
  end
155
154
 
156
155
  it "should pass through read when read is turned off" do
157
- ftrans = FramedTransport.new(@trans, false, true)
156
+ ftrans = Thrift::FramedTransport.new(@trans, false, true)
158
157
  @trans.should_receive(:read).with(17).ordered.and_return("+ read")
159
158
  ftrans.read(17).should == "+ read"
160
159
  end
161
160
 
162
161
  it "should pass through write/flush when write is turned off" do
163
- ftrans = FramedTransport.new(@trans, true, false)
162
+ ftrans = Thrift::FramedTransport.new(@trans, true, false)
164
163
  @trans.should_receive(:write).with("foo").ordered.and_return("+ write")
165
164
  @trans.should_receive(:flush).ordered.and_return("+ flush")
166
165
  ftrans.write("foo").should == "+ write"
@@ -171,21 +170,21 @@ class ThriftBaseTransportSpec < Spec::ExampleGroup
171
170
  frame = "this is a frame"
172
171
  @trans.should_receive(:read_all).with(4).and_return("\000\000\000\017")
173
172
  @trans.should_receive(:read_all).with(frame.length).and_return(frame)
174
- FramedTransport.new(@trans).read(frame.length + 10).should == frame
173
+ Thrift::FramedTransport.new(@trans).read(frame.length + 10).should == frame
175
174
  end
176
175
 
177
176
  it "should return slices of the frame when asked for < the frame's length" do
178
177
  frame = "this is a frame"
179
178
  @trans.should_receive(:read_all).with(4).and_return("\000\000\000\017")
180
179
  @trans.should_receive(:read_all).with(frame.length).and_return(frame)
181
- ftrans = FramedTransport.new(@trans)
180
+ ftrans = Thrift::FramedTransport.new(@trans)
182
181
  ftrans.read(4).should == "this"
183
182
  ftrans.read(4).should == " is "
184
183
  ftrans.read(16).should == "a frame"
185
184
  end
186
185
 
187
186
  it "should return nothing if asked for <= 0" do
188
- FramedTransport.new(@trans).read(-2).should == ""
187
+ Thrift::FramedTransport.new(@trans).read(-2).should == ""
189
188
  end
190
189
 
191
190
  it "should pull a new frame when the first is exhausted" do
@@ -194,7 +193,7 @@ class ThriftBaseTransportSpec < Spec::ExampleGroup
194
193
  @trans.should_receive(:read_all).with(4).and_return("\000\000\000\017", "\000\000\000\021")
195
194
  @trans.should_receive(:read_all).with(frame.length).and_return(frame)
196
195
  @trans.should_receive(:read_all).with(frame2.length).and_return(frame2)
197
- ftrans = FramedTransport.new(@trans)
196
+ ftrans = Thrift::FramedTransport.new(@trans)
198
197
  ftrans.read(4).should == "this"
199
198
  ftrans.read(8).should == " is a fr"
200
199
  ftrans.read(6).should == "ame"
@@ -203,7 +202,7 @@ class ThriftBaseTransportSpec < Spec::ExampleGroup
203
202
  end
204
203
 
205
204
  it "should buffer writes" do
206
- ftrans = FramedTransport.new(@trans)
205
+ ftrans = Thrift::FramedTransport.new(@trans)
207
206
  @trans.should_not_receive(:write)
208
207
  ftrans.write("foo")
209
208
  ftrans.write("bar")
@@ -211,7 +210,7 @@ class ThriftBaseTransportSpec < Spec::ExampleGroup
211
210
  end
212
211
 
213
212
  it "should write slices of the buffer" do
214
- ftrans = FramedTransport.new(@trans)
213
+ ftrans = Thrift::FramedTransport.new(@trans)
215
214
  ftrans.write("foobar", 3)
216
215
  ftrans.write("barfoo", 1)
217
216
  @trans.stub!(:flush)
@@ -220,7 +219,7 @@ class ThriftBaseTransportSpec < Spec::ExampleGroup
220
219
  end
221
220
 
222
221
  it "should flush frames with a 4-byte header" do
223
- ftrans = FramedTransport.new(@trans)
222
+ ftrans = Thrift::FramedTransport.new(@trans)
224
223
  @trans.should_receive(:write).with("\000\000\000\035one/two/three/this is a frame").ordered
225
224
  @trans.should_receive(:flush).ordered
226
225
  ftrans.write("one/")
@@ -231,7 +230,7 @@ class ThriftBaseTransportSpec < Spec::ExampleGroup
231
230
  end
232
231
 
233
232
  it "should not flush the same buffered data twice" do
234
- ftrans = FramedTransport.new(@trans)
233
+ ftrans = Thrift::FramedTransport.new(@trans)
235
234
  @trans.should_receive(:write).with("\000\000\000\007foo/bar")
236
235
  @trans.stub!(:flush)
237
236
  ftrans.write("foo")
@@ -242,22 +241,22 @@ class ThriftBaseTransportSpec < Spec::ExampleGroup
242
241
  end
243
242
  end
244
243
 
245
- describe FramedTransportFactory do
244
+ describe Thrift::FramedTransportFactory do
246
245
  it "should wrap the given transport in a FramedTransport" do
247
246
  trans = mock("Transport")
248
- FramedTransport.should_receive(:new).with(trans)
249
- FramedTransportFactory.new.get_transport(trans)
247
+ Thrift::FramedTransport.should_receive(:new).with(trans)
248
+ Thrift::FramedTransportFactory.new.get_transport(trans)
250
249
  end
251
250
  end
252
251
 
253
- describe MemoryBufferTransport do
252
+ describe Thrift::MemoryBufferTransport do
254
253
  before(:each) do
255
- @buffer = MemoryBufferTransport.new
254
+ @buffer = Thrift::MemoryBufferTransport.new
256
255
  end
257
256
 
258
257
  it "should accept a buffer on input and use it directly" do
259
258
  s = "this is a test"
260
- @buffer = MemoryBufferTransport.new(s)
259
+ @buffer = Thrift::MemoryBufferTransport.new(s)
261
260
  @buffer.read(4).should == "this"
262
261
  s.slice!(-4..-1)
263
262
  @buffer.read(@buffer.available).should == " is a "
@@ -307,7 +306,7 @@ class ThriftBaseTransportSpec < Spec::ExampleGroup
307
306
  @buffer.write " bar"
308
307
  @buffer.read(@buffer.available).should == "foo bar"
309
308
  end
310
-
309
+
311
310
  it "should throw an EOFError when there isn't enough data in the buffer" do
312
311
  @buffer.reset_buffer("")
313
312
  lambda{@buffer.read(1)}.should raise_error(EOFError)
@@ -317,11 +316,11 @@ class ThriftBaseTransportSpec < Spec::ExampleGroup
317
316
  end
318
317
  end
319
318
 
320
- describe IOStreamTransport do
319
+ describe Thrift::IOStreamTransport do
321
320
  before(:each) do
322
321
  @input = mock("Input", :closed? => false)
323
322
  @output = mock("Output", :closed? => false)
324
- @trans = IOStreamTransport.new(@input, @output)
323
+ @trans = Thrift::IOStreamTransport.new(@input, @output)
325
324
  end
326
325
 
327
326
  it "should be open as long as both input or output are open" do
@@ -17,27 +17,23 @@
17
17
  # under the License.
18
18
  #
19
19
 
20
- require File.expand_path("#{File.dirname(__FILE__)}/spec_helper")
20
+ require 'spec_helper'
21
21
  require File.expand_path("#{File.dirname(__FILE__)}/binary_protocol_spec_shared")
22
22
 
23
23
  if defined? Thrift::BinaryProtocolAccelerated
24
24
 
25
- class ThriftBinaryProtocolAcceleratedSpec < Spec::ExampleGroup
26
- include Thrift
25
+ describe 'BinaryProtocolAccelerated' do
26
+ # since BinaryProtocolAccelerated should be directly equivalent to
27
+ # BinaryProtocol, we don't need any custom specs!
28
+ it_should_behave_like 'a binary protocol'
27
29
 
28
- describe Thrift::BinaryProtocolAccelerated do
29
- # since BinaryProtocolAccelerated should be directly equivalent to
30
- # BinaryProtocol, we don't need any custom specs!
31
- it_should_behave_like 'a binary protocol'
32
-
33
- def protocol_class
34
- BinaryProtocolAccelerated
35
- end
30
+ def protocol_class
31
+ Thrift::BinaryProtocolAccelerated
36
32
  end
37
33
 
38
- describe BinaryProtocolAcceleratedFactory do
34
+ describe Thrift::BinaryProtocolAcceleratedFactory do
39
35
  it "should create a BinaryProtocolAccelerated" do
40
- BinaryProtocolAcceleratedFactory.new.get_protocol(mock("MockTransport")).should be_instance_of(BinaryProtocolAccelerated)
36
+ Thrift::BinaryProtocolAcceleratedFactory.new.get_protocol(mock("MockTransport")).should be_instance_of(Thrift::BinaryProtocolAccelerated)
41
37
  end
42
38
  end
43
39
  end
@@ -17,17 +17,22 @@
17
17
  # under the License.
18
18
  #
19
19
 
20
- require File.expand_path("#{File.dirname(__FILE__)}/spec_helper")
20
+ require 'spec_helper'
21
21
  require File.expand_path("#{File.dirname(__FILE__)}/binary_protocol_spec_shared")
22
22
 
23
- class ThriftBinaryProtocolSpec < Spec::ExampleGroup
24
- include Thrift
23
+ describe 'BinaryProtocol' do
25
24
 
26
- describe BinaryProtocol do
27
- it_should_behave_like 'a binary protocol'
25
+ it_should_behave_like 'a binary protocol'
28
26
 
29
- def protocol_class
30
- BinaryProtocol
27
+ def protocol_class
28
+ Thrift::BinaryProtocol
29
+ end
30
+
31
+ describe Thrift::BinaryProtocol do
32
+
33
+ before(:each) do
34
+ @trans = Thrift::MemoryBufferTransport.new
35
+ @prot = protocol_class.new(@trans)
31
36
  end
32
37
 
33
38
  it "should read a message header" do
@@ -47,15 +52,15 @@ class ThriftBinaryProtocolSpec < Spec::ExampleGroup
47
52
  it "should raise an exception if the message header does not exist and strict_read is enabled" do
48
53
  @prot.should_receive(:read_i32).and_return(42)
49
54
  @prot.should_receive(:strict_read).and_return(true)
50
- lambda { @prot.read_message_begin }.should raise_error(Thrift::ProtocolException, 'No version identifier, old protocol client?') do |e|
55
+ lambda { @prot.read_message_begin }.should raise_error(Thrift::ProtocolException, 'No version identifier, old protocol client?') do |e|
51
56
  e.type == Thrift::ProtocolException::BAD_VERSION
52
57
  end
53
58
  end
54
59
  end
55
60
 
56
- describe BinaryProtocolFactory do
61
+ describe Thrift::BinaryProtocolFactory do
57
62
  it "should create a BinaryProtocol" do
58
- BinaryProtocolFactory.new.get_protocol(mock("MockTransport")).should be_instance_of(BinaryProtocol)
63
+ Thrift::BinaryProtocolFactory.new.get_protocol(mock("MockTransport")).should be_instance_of(Thrift::BinaryProtocol)
59
64
  end
60
65
  end
61
66
  end
@@ -1,3 +1,4 @@
1
+ # encoding: ascii-8bit
1
2
  #
2
3
  # Licensed to the Apache Software Foundation (ASF) under one
3
4
  # or more contributor license agreements. See the NOTICE file
@@ -17,7 +18,7 @@
17
18
  # under the License.
18
19
  #
19
20
 
20
- require File.expand_path("#{File.dirname(__FILE__)}/spec_helper")
21
+ require 'spec_helper'
21
22
 
22
23
  shared_examples_for 'a binary protocol' do
23
24
  before(:each) do
@@ -192,13 +193,41 @@ shared_examples_for 'a binary protocol' do
192
193
  it "should error gracefully when trying to write a nil double" do
193
194
  lambda { @prot.write_double(nil) }.should raise_error
194
195
  end
195
-
196
- it "should write a string" do
197
- str = "hello world"
198
- @prot.write_string(str)
199
- @trans.read(@trans.available).should == [str.size].pack("N") + str
196
+
197
+ if RUBY_VERSION >= '1.9'
198
+ it 'should write a string' do
199
+ str = 'abc'
200
+ @prot.write_string(str)
201
+ a = @trans.read(@trans.available)
202
+ a.encoding.should == Encoding::BINARY
203
+ a.unpack('C*').should == [0x00, 0x00, 0x00, 0x03, 0x61, 0x62, 0x63]
204
+ end
205
+
206
+ it 'should write a string with unicode characters' do
207
+ str = "abc \u20AC \u20AD".encode('UTF-8')
208
+ @prot.write_string(str)
209
+ a = @trans.read(@trans.available)
210
+ a.encoding.should == Encoding::BINARY
211
+ a.unpack('C*').should == [0x00, 0x00, 0x00, 0x0B, 0x61, 0x62, 0x63, 0x20,
212
+ 0xE2, 0x82, 0xAC, 0x20, 0xE2, 0x82, 0xAD]
213
+ end
214
+
215
+ it 'should write should write a string with unicode characters and transcoding' do
216
+ str = "abc \u20AC".encode('ISO-8859-15')
217
+ @prot.write_string(str)
218
+ a = @trans.read(@trans.available)
219
+ a.encoding.should == Encoding::BINARY
220
+ a.unpack('C*').should == [0x00, 0x00, 0x00, 0x07, 0x61, 0x62, 0x63, 0x20, 0xE2, 0x82, 0xAC]
221
+ end
222
+ else
223
+ it 'should write a string' do
224
+ str = 'abc'
225
+ @prot.write_string(str)
226
+ a = @trans.read(@trans.available)
227
+ a.unpack('C*').should == [0x00, 0x00, 0x00, 0x03, 0x61, 0x62, 0x63]
228
+ end
200
229
  end
201
-
230
+
202
231
  it "should error gracefully when trying to write a nil string" do
203
232
  lambda { @prot.write_string(nil) }.should raise_error
204
233
  end
@@ -294,11 +323,32 @@ shared_examples_for 'a binary protocol' do
294
323
  @prot.read_double.should == f
295
324
  end
296
325
  end
297
-
298
- it "should read a string" do
299
- str = "hello world"
300
- @trans.write([str.size].pack("N") + str)
301
- @prot.read_string.should == str
326
+
327
+ if RUBY_VERSION >= '1.9'
328
+ it 'should read a string' do
329
+ # i32 of value 3, followed by three characters/UTF-8 bytes 'a', 'b', 'c'
330
+ buffer = [0x00, 0x00, 0x00, 0x03, 0x61, 0x62, 0x63].pack('C*')
331
+ @trans.write(buffer)
332
+ a = @prot.read_string
333
+ a.should == 'abc'.encode('UTF-8')
334
+ a.encoding.should == Encoding::UTF_8
335
+ end
336
+
337
+ it 'should read a string containing unicode characters from UTF-8 encoded buffer' do
338
+ # i32 of value 3, followed by one character U+20AC made up of three bytes
339
+ buffer = [0x00, 0x00, 0x00, 0x03, 0xE2, 0x82, 0xAC].pack('C*')
340
+ @trans.write(buffer)
341
+ a = @prot.read_string
342
+ a.should == "\u20AC".encode('UTF-8')
343
+ a.encoding.should == Encoding::UTF_8
344
+ end
345
+ else
346
+ it 'should read a string' do
347
+ # i32 of value 3, followed by three characters/UTF-8 bytes 'a', 'b', 'c'
348
+ buffer = [0x00, 0x00, 0x00, 0x03, 0x61, 0x62, 0x63].pack('C*')
349
+ @trans.write(buffer)
350
+ @prot.read_string.should == 'abc'
351
+ end
302
352
  end
303
353
 
304
354
  it "should perform a complete rpc with no args or return" do