thrift 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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