THRIFT-248. ruby: Factor BinaryProtocolAccelerated into separate protocol and struct components
This patch replaces the "binaryprotocolaccelerated" c extension with the "thrift_native" c extension. This new extension creates native implementations for the struct.rb #write and #read methods, Thrift::BinaryProtocol, and Thrift::MemoryBuffer, but keeps ruby-level interfaces, allowing all protocols to benefit from the struct code and the memory buffer. There is however an additional cost associated with going through this ruby layer, but the increased interoperability seems to be well worth it.
git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@739895 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/lib/rb/spec/binaryprotocol_spec_shared.rb b/lib/rb/spec/binaryprotocol_spec_shared.rb
index ced15b4..78e2ccb 100644
--- a/lib/rb/spec/binaryprotocol_spec_shared.rb
+++ b/lib/rb/spec/binaryprotocol_spec_shared.rb
@@ -2,7 +2,7 @@
shared_examples_for 'a binary protocol' do
before(:each) do
- @trans = mock("MockTransport")
+ @trans = Thrift::MemoryBuffer.new
@prot = protocol_class.new(@trans)
end
@@ -12,295 +12,241 @@
end
it "should write the message header" do
- @prot.should_receive(:write_i32).with(protocol_class.const_get(:VERSION_1) | Thrift::MessageTypes::CALL).ordered
- @prot.should_receive(:write_string).with('testMessage').ordered
- @prot.should_receive(:write_i32).with(17).ordered
@prot.write_message_begin('testMessage', Thrift::MessageTypes::CALL, 17)
+ @trans.read(1000).should == [protocol_class.const_get(:VERSION_1) | Thrift::MessageTypes::CALL, "testMessage".size, "testMessage", 17].pack("NNa11N")
end
# message footer is a noop
it "should write the field header" do
- @prot.should_receive(:write_byte).with(Thrift::Types::DOUBLE).ordered
- @prot.should_receive(:write_i16).with(3).ordered
@prot.write_field_begin('foo', Thrift::Types::DOUBLE, 3)
+ @trans.read(1000).should == [Thrift::Types::DOUBLE, 3].pack("cn")
end
-
+
# field footer is a noop
-
+
it "should write the STOP field" do
- @prot.should_receive(:write_byte).with(Thrift::Types::STOP)
@prot.write_field_stop
+ @trans.read(1).should == "\000"
end
-
+
it "should write the map header" do
- @prot.should_receive(:write_byte).with(Thrift::Types::STRING).ordered
- @prot.should_receive(:write_byte).with(Thrift::Types::LIST).ordered
- @prot.should_receive(:write_i32).with(17).ordered
@prot.write_map_begin(Thrift::Types::STRING, Thrift::Types::LIST, 17)
+ @trans.read(1000).should == [Thrift::Types::STRING, Thrift::Types::LIST, 17].pack("ccN");
end
-
+
# map footer is a noop
-
+
it "should write the list header" do
- @prot.should_receive(:write_byte).with(Thrift::Types::I16).ordered
- @prot.should_receive(:write_i32).with(42).ordered
@prot.write_list_begin(Thrift::Types::I16, 42)
+ @trans.read(1000).should == [Thrift::Types::I16, 42].pack("cN")
end
-
+
# list footer is a noop
-
+
it "should write the set header" do
- @prot.should_receive(:write_byte).with(Thrift::Types::BOOL).ordered
- @prot.should_receive(:write_i32).with(2).ordered
- @prot.write_set_begin(Thrift::Types::BOOL, 2)
+ @prot.write_set_begin(Thrift::Types::I16, 42)
+ @trans.read(1000).should == [Thrift::Types::I16, 42].pack("cN")
end
-
+
it "should write a bool" do
- @prot.should_receive(:write_byte).with(1).ordered
@prot.write_bool(true)
- @prot.should_receive(:write_byte).with(0).ordered
@prot.write_bool(false)
+ @trans.read(1000).should == "\001\000"
end
-
+
it "should treat a nil bool as false" do
- @prot.should_receive(:write_byte).with(0)
@prot.write_bool(nil)
+ @trans.read(1).should == "\000"
end
-
+
it "should write a byte" do
# byte is small enough, let's check -128..127
(-128..127).each do |i|
- @trans.should_receive(:write).with([i].pack('c')).ordered
@prot.write_byte(i)
+ @trans.read(1).should == [i].pack('c')
end
(-128..127).each do |i|
end
# handing it numbers out of signed range should clip
@trans.rspec_verify
(128..255).each do |i|
- @trans.should_receive(:write).with([i].pack('c')).ordered
@prot.write_byte(i)
+ @trans.read(1).should == [i].pack('c')
end
# and lastly, a Bignum is going to error out
lambda { @prot.write_byte(2**65) }.should raise_error(RangeError)
end
-
+
it "should error gracefully when trying to write a nil byte" do
lambda { @prot.write_byte(nil) }.should raise_error
end
-
+
it "should write an i16" do
# try a random scattering of values
# include the signed i16 minimum/maximum
- @trans.should_receive(:write).with("\200\000").ordered
- @trans.should_receive(:write).with("\374\000").ordered
- @trans.should_receive(:write).with("\000\021").ordered
- @trans.should_receive(:write).with("\000\000").ordered
- @trans.should_receive(:write).with("\330\360").ordered
- @trans.should_receive(:write).with("\006\273").ordered
- @trans.should_receive(:write).with("\177\377").ordered
[-2**15, -1024, 17, 0, -10000, 1723, 2**15-1].each do |i|
@prot.write_i16(i)
end
# and try something out of signed range, it should clip
- @trans.should_receive(:write).with("\200\005").ordered
@prot.write_i16(2**15 + 5)
+
+ @trans.read(1000).should == "\200\000\374\000\000\021\000\000\330\360\006\273\177\377\200\005"
+
# a Bignum should error
# lambda { @prot.write_i16(2**65) }.should raise_error(RangeError)
end
-
+
it "should error gracefully when trying to write a nil i16" do
lambda { @prot.write_i16(nil) }.should raise_error
end
-
+
it "should write an i32" do
# try a random scattering of values
# include the signed i32 minimum/maximum
- @trans.should_receive(:write).with("\200\000\000\000").ordered
- @trans.should_receive(:write).with("\377\376\037\r").ordered
- @trans.should_receive(:write).with("\377\377\366\034").ordered
- @trans.should_receive(:write).with("\377\377\377\375").ordered
- @trans.should_receive(:write).with("\000\000\000\000").ordered
- @trans.should_receive(:write).with("\000#\340\203").ordered
- @trans.should_receive(:write).with("\000\0000+").ordered
- @trans.should_receive(:write).with("\177\377\377\377").ordered
[-2**31, -123123, -2532, -3, 0, 2351235, 12331, 2**31-1].each do |i|
@prot.write_i32(i)
end
# try something out of signed range, it should clip
- @trans.should_receive(:write).with("\200\000\000\005").ordered
- @prot.write_i32(2 ** 31 + 5)
- # lambda { @prot.write_i32(2 ** 65 + 5) }.should raise_error(RangeError)
+ @trans.read(1000).should == "\200\000\000\000" + "\377\376\037\r" + "\377\377\366\034" + "\377\377\377\375" + "\000\000\000\000" + "\000#\340\203" + "\000\0000+" + "\177\377\377\377"
+ [2 ** 31 + 5, 2 ** 65 + 5].each do |i|
+ lambda { @prot.write_i32(i) }.should raise_error(RangeError)
+ end
end
-
+
it "should error gracefully when trying to write a nil i32" do
lambda { @prot.write_i32(nil) }.should raise_error
end
-
+
it "should write an i64" do
# try a random scattering of values
# try the signed i64 minimum/maximum
- @trans.should_receive(:write).with("\200\000\000\000\000\000\000\000").ordered
- @trans.should_receive(:write).with("\377\377\364\303\035\244+]").ordered
- @trans.should_receive(:write).with("\377\377\377\377\376\231:\341").ordered
- @trans.should_receive(:write).with("\377\377\377\377\377\377\377\026").ordered
- @trans.should_receive(:write).with("\000\000\000\000\000\000\000\000").ordered
- @trans.should_receive(:write).with("\000\000\000\000\000\000\004\317").ordered
- @trans.should_receive(:write).with("\000\000\000\000\000#\340\204").ordered
- @trans.should_receive(:write).with("\000\000\000\002\340\311~\365").ordered
- @trans.should_receive(:write).with("\177\377\377\377\377\377\377\377").ordered
[-2**63, -12356123612323, -23512351, -234, 0, 1231, 2351236, 12361236213, 2**63-1].each do |i|
@prot.write_i64(i)
end
# try something out of signed range, it should clip
- @trans.should_receive(:write).with("\200\000\000\000\000\000\000\005").ordered
- @prot.write_i64(2**63 + 5)
- # lambda { @prot.write_i64(2 ** 65 + 5) }.should raise_error(RangeError)
+ @trans.read(1000).should == ["\200\000\000\000\000\000\000\000",
+ "\377\377\364\303\035\244+]",
+ "\377\377\377\377\376\231:\341",
+ "\377\377\377\377\377\377\377\026",
+ "\000\000\000\000\000\000\000\000",
+ "\000\000\000\000\000\000\004\317",
+ "\000\000\000\000\000#\340\204",
+ "\000\000\000\002\340\311~\365",
+ "\177\377\377\377\377\377\377\377"].join("")
+ lambda { @prot.write_i64(2 ** 65 + 5) }.should raise_error(RangeError)
end
-
+
it "should error gracefully when trying to write a nil i64" do
lambda { @prot.write_i64(nil) }.should raise_error
end
-
+
it "should write a double" do
# try a random scattering of values, including min/max
- @trans.should_receive(:write).with([Float::MIN].pack('G')).ordered
- @trans.should_receive(:write).with("\300\223<\234\355\221hs").ordered
- @trans.should_receive(:write).with("\300\376\0173\256\024z\341").ordered
- @trans.should_receive(:write).with("\3007<2\336\372v\324").ordered
- @trans.should_receive(:write).with("\000\000\000\000\000\000\000\000").ordered
- @trans.should_receive(:write).with("@\310\037\220\365\302\217\\").ordered
- @trans.should_receive(:write).with("@\200Y\327\n=p\244").ordered
- @trans.should_receive(:write).with([Float::MAX].pack('G')).ordered
- [Float::MIN, -1231.15325, -123123.23, -23.23515123, 0, 12351.1325, 523.23, Float::MAX].each do |f|
+ values = [Float::MIN,-1231.15325, -123123.23, -23.23515123, 0, 12351.1325, 523.23, Float::MAX]
+ values.each do |f|
@prot.write_double(f)
+ @trans.read(1000).should == [f].pack("G")
end
end
-
+
it "should error gracefully when trying to write a nil double" do
lambda { @prot.write_double(nil) }.should raise_error
end
-
+
it "should write a string" do
str = "hello world"
- @prot.should_receive(:write_i32).with(str.length).ordered
- @trans.should_receive(:write).with(str).ordered
@prot.write_string(str)
+ @trans.read(1000).should == [str.size].pack("N") + str
end
-
+
it "should error gracefully when trying to write a nil string" do
lambda { @prot.write_string(nil) }.should raise_error
end
-
+
# message footer is a noop
-
+
it "should read a field header" do
- @prot.should_receive(:read_byte).ordered.and_return(Thrift::Types::STRING)
- @prot.should_receive(:read_i16).ordered.and_return(3)
+ @trans.write([Thrift::Types::STRING, 3].pack("cn"))
@prot.read_field_begin.should == [nil, Thrift::Types::STRING, 3]
end
-
+
# field footer is a noop
-
+
it "should read a stop field" do
- @prot.should_receive(:read_byte).and_return(Thrift::Types::STOP)
- @prot.should_not_receive(:read_i16)
+ @trans.write([Thrift::Types::STOP].pack("c"));
@prot.read_field_begin.should == [nil, Thrift::Types::STOP, 0]
end
it "should read a map header" do
- @prot.should_receive(:read_byte).and_return(Thrift::Types::DOUBLE, Thrift::Types::I64)
- @prot.should_receive(:read_i32).and_return(42)
+ @trans.write([Thrift::Types::DOUBLE, Thrift::Types::I64, 42].pack("ccN"))
@prot.read_map_begin.should == [Thrift::Types::DOUBLE, Thrift::Types::I64, 42]
end
-
+
# map footer is a noop
-
+
it "should read a list header" do
- @prot.should_receive(:read_byte).ordered.and_return(Thrift::Types::STRING)
- @prot.should_receive(:read_i32).and_return(17)
+ @trans.write([Thrift::Types::STRING, 17].pack("cN"))
@prot.read_list_begin.should == [Thrift::Types::STRING, 17]
end
-
+
# list footer is a noop
-
+
it "should read a set header" do
- @prot.should_receive(:read_byte).ordered.and_return(Thrift::Types::MAP)
- @prot.should_receive(:read_i32).ordered.and_return(42)
- @prot.read_set_begin.should == [Thrift::Types::MAP, 42]
+ @trans.write([Thrift::Types::STRING, 17].pack("cN"))
+ @prot.read_set_begin.should == [Thrift::Types::STRING, 17]
end
-
+
# set footer is a noop
-
+
it "should read a bool" do
- @prot.should_receive(:read_byte).and_return(1, 0)
+ @trans.write("\001\000");
@prot.read_bool.should == true
@prot.read_bool.should == false
end
-
+
it "should read a byte" do
- # try a scattering of values, including min/max
- @trans.should_receive(:read_all).with(1).and_return(
- "\200", "\307", "\375",
- "\000", "\021", "\030", "\177"
- )
[-128, -57, -3, 0, 17, 24, 127].each do |i|
+ @trans.write([i].pack("c"))
@prot.read_byte.should == i
end
end
-
+
it "should read an i16" do
# try a scattering of values, including min/max
- @trans.should_receive(:read_all).with(2).and_return(
- "\200\000", "\353\213", "\376\237",
- "\000\000", "\005\367", "\b\272", "\177\377"
- )
[-2**15, -5237, -353, 0, 1527, 2234, 2**15-1].each do |i|
+ @trans.write([i].pack("n"));
@prot.read_i16.should == i
end
end
-
+
it "should read an i32" do
# try a scattering of values, including min/max
- @trans.should_receive(:read_all).with(4).and_return(
- "\200\000\000\000", "\377\374i\213", "\377\377\347\244",
- "\000\000\000\000", "\000\000\t/", "\000\001\340\363", "\177\377\377\377"
- )
[-2**31, -235125, -6236, 0, 2351, 123123, 2**31-1].each do |i|
+ @trans.write([i].pack("N"))
@prot.read_i32.should == i
end
end
-
+
it "should read an i64" do
# try a scattering of values, including min/max
- @trans.should_receive(:read_all).with(8).and_return(
- "\200\000\000\000\000\000\000\000", "\377\377\377\377\370\243Z\b",
- "\377\377\377\377\377\377\3476", "\000\000\000\000\000\000\000\000",
- "\000\000\000\000\000\000\000 ", "\000\000\000\000\213\332\t\223",
- "\177\377\377\377\377\377\377\377"
- )
[-2**63, -123512312, -6346, 0, 32, 2346322323, 2**63-1].each do |i|
+ @trans.write([i >> 32, i & 0xFFFFFFFF].pack("NN"))
@prot.read_i64.should == i
end
end
-
+
it "should read a double" do
# try a random scattering of values, including min/max
- @trans.should_receive(:read_all).with(8).and_return(
- [Float::MIN].pack('G'), "\301\f9\370\374\362\317\226",
- "\300t3\274x \243\016", "\000\000\000\000\000\000\000\000", "@^\317\fCo\301Y",
- "AA\360A\217\317@\260", [Float::MAX].pack('G')
- )
[Float::MIN, -231231.12351, -323.233513, 0, 123.2351235, 2351235.12351235, Float::MAX].each do |f|
+ @trans.write([f].pack("G"));
@prot.read_double.should == f
end
end
-
+
it "should read a string" do
str = "hello world"
- @prot.should_receive(:read_i32).and_return(str.length)
- @trans.should_receive(:read_all).with(str.length).and_return(str)
+ @trans.write([str.size].pack("N") + str)
@prot.read_string.should == str
end
end
diff --git a/lib/rb/spec/binaryprotocolaccelerated_spec.rb b/lib/rb/spec/binaryprotocolaccelerated_spec.rb
index 6a3cc39..a2ddc55 100644
--- a/lib/rb/spec/binaryprotocolaccelerated_spec.rb
+++ b/lib/rb/spec/binaryprotocolaccelerated_spec.rb
@@ -6,133 +6,91 @@
class ThriftBinaryProtocolAcceleratedSpec < Spec::ExampleGroup
include Thrift
- describe BinaryProtocolAccelerated do
- # given that BinaryProtocolAccelerated only actually overrides read_message_begin
- # this shared spec isn't going to do much, but it's still worth including
- # for future-proofing in case we start overriding individual methods
+ describe Thrift::BinaryProtocolAccelerated do
+ # since BinaryProtocolAccelerated should be directly equivalent to
+ # BinaryProtocol, we don't need any custom specs!
it_should_behave_like 'a binary protocol'
def protocol_class
BinaryProtocolAccelerated
end
- before(:each) do
- @buffer = ""
- @trans.stub!(:borrow).and_return { @buffer }
- @trans.stub!(:consume!).and_return do |*args|
- n = args.first || 0
- @buffer.slice!(0,n)
- end
- end
-
- it "should read a message header" do
- @buffer = "\200\001\000\002\000\000\000\vtestMessage\000\000\000*"
- # @prot.should_receive(:read_i32).and_return(protocol_class.const_get(:VERSION_1) | Thrift::MessageTypes::REPLY, 42)
- # @prot.should_receive(:read_string).and_return('testMessage')
- @prot.read_message_begin.should == ['testMessage', Thrift::MessageTypes::REPLY, 42]
- end
-
- it "should raise an exception if the message header has the wrong version" do
- @buffer = "\000\000\000\v"
- # @prot.should_receive(:read_i32).and_return(42)
- lambda { @prot.read_message_begin }.should raise_error(Thrift::ProtocolException, 'Missing version identifier') do |e|
- e.type == Thrift::ProtocolException::BAD_VERSION
- end
- end
-
- it "should encode a struct with all fields set identically to Thrift::BinaryProtocol" do
- foo = SpecNamespace::Foo.new(:complex => {5 => {"foo" => 1.2}, 17 => {"bar" => 3.14159, "baz" => 5.8}})
- @prot.encode_binary(foo).should == "\r\000\005\b\r\000\000\000\002\000\000\000\005\v\004\000\000\000\001\000\
-\000\000\003foo?\363333333\000\000\000\021\v\004\000\000\000\002\000\000\000\003baz@\027333333\000\000\000\003bar@\
-\t!\371\360\e\206n\016\000\006\006\000\000\000\003\000\005\000\021\000\357\b\000\001\000\000\0005\v\000\002\000\000\
-\000\005words\f\000\003\v\000\001\000\000\000\rhello, world!\000\017\000\004\b\000\000\000\004\000\000\000\001\000\
-\000\000\002\000\000\000\002\000\000\000\003\000"
- end
-
- it "should encode a struct with missing fields identically to Thrift::BinaryProtocol" do
- foo = SpecNamespace::Foo.new(:simple => nil, :ints => nil)
- @prot.encode_binary(foo).should == "\016\000\006\006\000\000\000\003\000\005\000\021\000\357\v\000\002\000\000\
-\000\005words\f\000\003\v\000\001\000\000\000\rhello, world!\000\000"
- end
-
- it "should decode a struct with all fields set identically to Thrift::BinaryProtocol" do
- foo = SpecNamespace::Foo.new(:complex => {5 => {"foo" => 1.2}, 17 => {"bar" => 3.14159, "baz" => 5.8}})
- trans = Thrift::MemoryBuffer.new("\r\000\005\b\r\000\000\000\002\000\000\000\005\v\004\000\000\000\001\000\
-\000\000\003foo?\363333333\000\000\000\021\v\004\000\000\000\002\000\000\000\003baz@\027333333\000\000\000\003bar@\
-\t!\371\360\e\206n\016\000\006\006\000\000\000\003\000\005\000\021\000\357\b\000\001\000\000\0005\v\000\002\000\000\
-\000\005words\f\000\003\v\000\001\000\000\000\rhello, world!\000\017\000\004\b\000\000\000\004\000\000\000\001\000\
-\000\000\002\000\000\000\002\000\000\000\003\000")
- @prot.decode_binary(SpecNamespace::Foo.new, trans).should == foo
- end
-
- it "should decode a struct with missing fields identically to Thrift::BinaryProtocol" do
- trans = Thrift::MemoryBuffer.new("\016\000\006\006\000\000\000\003\000\005\000\021\000\357\v\000\002\000\000\
-\000\005words\f\000\003\v\000\001\000\000\000\rhello, world!\000\000")
- @prot.decode_binary(SpecNamespace::Foo.new, trans).should == SpecNamespace::Foo.new
- end
-
- it "should encode a string with null bytes in it" do
- foo = SpecNamespace::Hello.new(:greeting => "Hello\000World!")
- @prot.encode_binary(foo).should == "\v\000\001\000\000\000\fHello\000World!\000"
- end
-
- it "should decode a string with null bytes in it" do
- trans = Thrift::MemoryBuffer.new("\v\000\001\000\000\000\fHello\000World!\000")
- @prot.decode_binary(SpecNamespace::Hello.new, trans).should == SpecNamespace::Hello.new(:greeting => "Hello\000World!")
- end
-
- it "should error when encoding a struct with a nil value in a list" do
- Thrift.type_checking = false
- sl = SpecNamespace::SimpleList
- hello = SpecNamespace::Hello
- # nil counts as false for bools
- # lambda { @prot.encode_binary(sl.new(:bools => [true, false, nil, false])) }.should raise_error
- lambda { @prot.encode_binary(sl.new(:bytes => [1, 2, nil, 3])) }.should raise_error
- lambda { @prot.encode_binary(sl.new(:i16s => [1, 2, nil, 3])) }.should raise_error
- lambda { @prot.encode_binary(sl.new(:i32s => [1, 2, nil, 3])) }.should raise_error
- lambda { @prot.encode_binary(sl.new(:i64s => [1, 2, nil, 3])) }.should raise_error
- lambda { @prot.encode_binary(sl.new(:doubles => [1.0, 2.0, nil, 3.0])) }.should raise_error
- lambda { @prot.encode_binary(sl.new(:strings => ["one", "two", nil, "three"])) }.should raise_error
- lambda { @prot.encode_binary(sl.new(:lists => [[1, 2], nil, [3, 4]])) }.should raise_error
- lambda { @prot.encode_binary(sl.new(:maps => [{1 => 2}, nil, {3 => 4}])) }.should raise_error
- lambda { @prot.encode_binary(sl.new(:sets => [Set.new([1, 2]), nil, Set.new([3, 4])])) }.should raise_error
- lambda { @prot.encode_binary(sl.new(:structs => [hello.new, nil, hello.new(:greeting => "hi")])) }.should raise_error
- end
-
- it "should error when encoding a non-nil, non-correctly-typed value in a list" do
- Thrift.type_checking = false
- sl = SpecNamespace::SimpleList
- hello = SpecNamespace::Hello
- # bool should accept any value
- # lambda { @prot.encode_binary(sl.new(:bools => [true, false, 3])) }.should raise_error
- lambda { @prot.encode_binary(sl.new(:bytes => [1, 2, "3", 5])) }.should raise_error
- lambda { @prot.encode_binary(sl.new(:i16s => ["one", 2, 3])) }.should raise_error
- lambda { @prot.encode_binary(sl.new(:i32s => [[1,2], 3, 4])) }.should raise_error
- lambda { @prot.encode_binary(sl.new(:i64s => [{1 => 2}, 3, 4])) }.should raise_error
- lambda { @prot.encode_binary(sl.new(:doubles => ["one", 2.3, 3.4])) }.should raise_error
- lambda { @prot.encode_binary(sl.new(:strings => ["one", "two", 3, 4])) }.should raise_error
- lambda { @prot.encode_binary(sl.new(:lists => [{1 => 2}, [3, 4]])) }.should raise_error
- lambda { @prot.encode_binary(sl.new(:maps => [{1 => 2}, [3, 4]])) }.should raise_error
- lambda { @prot.encode_binary(sl.new(:sets => [Set.new([1, 2]), 3, 4])) }.should raise_error
- lambda { @prot.encode_binary(sl.new(:structs => [3, "four"])) }.should raise_error
- end
-
- it "should error when given nil to encode" do
- lambda { @prot.encode_binary(nil) }.should raise_error
- end
-
- it "should error when encoding an improper object where a container is expected" do
- Thrift.type_checking = false
- sl = SpecNamespace::SimpleList
- lambda { @prot.encode_binary(sl.new(:strings => {"one" => "two", nil => "three"})) }.should raise_error
- lambda { @prot.encode_binary(sl.new(:maps => [[1, 2]])) }.should raise_error
- end
-
- it "should accept arrays and hashes as sets" do
- Thrift.type_checking = false
- sl = SpecNamespace::SimpleList
- lambda { @prot.encode_binary(sl.new(:sets => [[1, 2], {3 => true, 4 => true}])) }.should_not raise_error
- end
+# before(:each) do
+# @buffer = ""
+# @trans.stub!(:borrow).and_return { @buffer }
+# @trans.stub!(:consume!).and_return do |*args|
+# n = args.first || 0
+# @buffer.slice!(0,n)
+# end
+# end
+#
+#
+# it "should raise an exception if the message header has the wrong version" do
+# @buffer = "\000\000\000\v"
+# # @prot.should_receive(:read_i32).and_return(42)
+# lambda { @prot.read_message_begin }.should raise_error(Thrift::ProtocolException, 'Missing version identifier') do |e|
+# e.type == Thrift::ProtocolException::BAD_VERSION
+# end
+# end
+#
+# it "should encode a string with null bytes in it" do
+# foo = SpecNamespace::Hello.new(:greeting => "Hello\000World!")
+# @prot.encode_binary(foo).should == "\v\000\001\000\000\000\fHello\000World!\000"
+# end
+#
+# it "should decode a string with null bytes in it" do
+# trans = Thrift::MemoryBuffer.new("\v\000\001\000\000\000\fHello\000World!\000")
+# @prot.decode_binary(SpecNamespace::Hello.new, trans).should == SpecNamespace::Hello.new(:greeting => "Hello\000World!")
+# end
+#
+# it "should error when encoding a struct with a nil value in a list" do
+# Thrift.type_checking = false
+# sl = SpecNamespace::SimpleList
+# hello = SpecNamespace::Hello
+# # nil counts as false for bools
+# # lambda { @prot.encode_binary(sl.new(:bools => [true, false, nil, false])) }.should raise_error
+# lambda { @prot.encode_binary(sl.new(:bytes => [1, 2, nil, 3])) }.should raise_error
+# lambda { @prot.encode_binary(sl.new(:i16s => [1, 2, nil, 3])) }.should raise_error
+# lambda { @prot.encode_binary(sl.new(:i32s => [1, 2, nil, 3])) }.should raise_error
+# lambda { @prot.encode_binary(sl.new(:i64s => [1, 2, nil, 3])) }.should raise_error
+# lambda { @prot.encode_binary(sl.new(:doubles => [1.0, 2.0, nil, 3.0])) }.should raise_error
+# lambda { @prot.encode_binary(sl.new(:strings => ["one", "two", nil, "three"])) }.should raise_error
+# lambda { @prot.encode_binary(sl.new(:lists => [[1, 2], nil, [3, 4]])) }.should raise_error
+# lambda { @prot.encode_binary(sl.new(:maps => [{1 => 2}, nil, {3 => 4}])) }.should raise_error
+# lambda { @prot.encode_binary(sl.new(:sets => [Set.new([1, 2]), nil, Set.new([3, 4])])) }.should raise_error
+# lambda { @prot.encode_binary(sl.new(:structs => [hello.new, nil, hello.new(:greeting => "hi")])) }.should raise_error
+# end
+#
+# it "should error when encoding a non-nil, non-correctly-typed value in a list" do
+# Thrift.type_checking = false
+# sl = SpecNamespace::SimpleList
+# hello = SpecNamespace::Hello
+# # bool should accept any value
+# # lambda { @prot.encode_binary(sl.new(:bools => [true, false, 3])) }.should raise_error
+# lambda { @prot.encode_binary(sl.new(:bytes => [1, 2, "3", 5])) }.should raise_error
+# lambda { @prot.encode_binary(sl.new(:i16s => ["one", 2, 3])) }.should raise_error
+# lambda { @prot.encode_binary(sl.new(:i32s => [[1,2], 3, 4])) }.should raise_error
+# lambda { @prot.encode_binary(sl.new(:i64s => [{1 => 2}, 3, 4])) }.should raise_error
+# lambda { @prot.encode_binary(sl.new(:doubles => ["one", 2.3, 3.4])) }.should raise_error
+# lambda { @prot.encode_binary(sl.new(:strings => ["one", "two", 3, 4])) }.should raise_error
+# lambda { @prot.encode_binary(sl.new(:lists => [{1 => 2}, [3, 4]])) }.should raise_error
+# lambda { @prot.encode_binary(sl.new(:maps => [{1 => 2}, [3, 4]])) }.should raise_error
+# lambda { @prot.encode_binary(sl.new(:sets => [Set.new([1, 2]), 3, 4])) }.should raise_error
+# lambda { @prot.encode_binary(sl.new(:structs => [3, "four"])) }.should raise_error
+# end
+#
+# it "should error when encoding an improper object where a container is expected" do
+# Thrift.type_checking = false
+# sl = SpecNamespace::SimpleList
+# lambda { @prot.encode_binary(sl.new(:strings => {"one" => "two", nil => "three"})) }.should raise_error
+# lambda { @prot.encode_binary(sl.new(:maps => [[1, 2]])) }.should raise_error
+# end
+#
+# it "should accept arrays and hashes as sets" do
+# Thrift.type_checking = false
+# sl = SpecNamespace::SimpleList
+# lambda { @prot.encode_binary(sl.new(:sets => [[1, 2], {3 => true, 4 => true}])) }.should_not raise_error
+# end
end
describe BinaryProtocolAcceleratedFactory do
diff --git a/lib/rb/spec/protocol_spec.rb b/lib/rb/spec/protocol_spec.rb
index 917ca45..a681cd8 100644
--- a/lib/rb/spec/protocol_spec.rb
+++ b/lib/rb/spec/protocol_spec.rb
@@ -1,4 +1,5 @@
require File.dirname(__FILE__) + '/spec_helper'
+require "thrift_native"
class ThriftProtocolSpec < Spec::ExampleGroup
include Thrift
@@ -94,18 +95,23 @@
['field 3', Types::MAP, 3],
[nil, Types::STOP, 0]
)
- @prot.should_receive(:skip).with(Types::STRING).ordered
- @prot.should_receive(:skip).with(Types::I32).ordered
- @prot.should_receive(:skip).with(Types::MAP).ordered
@prot.should_receive(:read_field_end).exactly(3).times
+ @prot.should_receive(:read_string).exactly(3).times
+ @prot.should_receive(:read_i32).ordered
+ @prot.should_receive(:read_map_begin).ordered.and_return([Types::STRING, Types::STRING, 1])
+ # @prot.should_receive(:read_string).exactly(2).times
+ @prot.should_receive(:read_map_end).ordered
@prot.should_receive(:read_struct_end).ordered
real_skip.call(Types::STRUCT)
end
it "should skip maps" do
real_skip = @prot.method(:skip)
- @prot.should_receive(:read_map_begin).ordered.and_return([Types::STRING, Types::STRUCT, 7])
- @prot.should_receive(:skip).ordered.exactly(14).times # once per key and once per value
+ @prot.should_receive(:read_map_begin).ordered.and_return([Types::STRING, Types::STRUCT, 1])
+ @prot.should_receive(:read_string).ordered
+ @prot.should_receive(:read_struct_begin).ordered.and_return(["some_struct"])
+ @prot.should_receive(:read_field_begin).ordered.and_return([nil, Types::STOP, nil]);
+ @prot.should_receive(:read_struct_end).ordered
@prot.should_receive(:read_map_end).ordered
real_skip.call(Types::MAP)
end
@@ -113,7 +119,7 @@
it "should skip sets" do
real_skip = @prot.method(:skip)
@prot.should_receive(:read_set_begin).ordered.and_return([Types::I64, 9])
- @prot.should_receive(:skip).with(Types::I64).ordered.exactly(9).times
+ @prot.should_receive(:read_i64).ordered.exactly(9).times
@prot.should_receive(:read_set_end)
real_skip.call(Types::SET)
end
@@ -121,7 +127,7 @@
it "should skip lists" do
real_skip = @prot.method(:skip)
@prot.should_receive(:read_list_begin).ordered.and_return([Types::DOUBLE, 11])
- @prot.should_receive(:skip).with(Types::DOUBLE).ordered.exactly(11).times
+ @prot.should_receive(:read_double).ordered.exactly(11).times
@prot.should_receive(:read_list_end)
real_skip.call(Types::LIST)
end
diff --git a/lib/rb/spec/serializer_spec.rb b/lib/rb/spec/serializer_spec.rb
index fe5a86a..78a11ab 100644
--- a/lib/rb/spec/serializer_spec.rb
+++ b/lib/rb/spec/serializer_spec.rb
@@ -8,15 +8,17 @@
describe Serializer do
it "should serialize structs to binary by default" do
- serializer = Serializer.new
+ serializer = Serializer.new(Thrift::BinaryProtocolAcceleratedFactory.new)
data = serializer.serialize(Hello.new(:greeting => "'Ello guv'nor!"))
data.should == "\x0B\x00\x01\x00\x00\x00\x0E'Ello guv'nor!\x00"
end
it "should serialize structs to the given protocol" do
- protocol = mock("Protocol")
+ protocol = Protocol.new(mock("transport"))
protocol.should_receive(:write_struct_begin).with("SpecNamespace::Hello")
- protocol.should_receive(:write_field).with("greeting", Types::STRING, 1, "Good day")
+ protocol.should_receive(:write_field_begin).with("greeting", Types::STRING, 1)
+ protocol.should_receive(:write_string).with("Good day")
+ protocol.should_receive(:write_field_end)
protocol.should_receive(:write_field_stop)
protocol.should_receive(:write_struct_end)
protocolFactory = mock("ProtocolFactory")
@@ -34,11 +36,11 @@
end
it "should deserialize structs from the given protocol" do
- protocol = mock("Protocol")
+ protocol = Protocol.new(mock("transport"))
protocol.should_receive(:read_struct_begin).and_return("SpecNamespace::Hello")
protocol.should_receive(:read_field_begin).and_return(["greeting", Types::STRING, 1],
[nil, Types::STOP, 0])
- protocol.should_receive(:read_type).with(Types::STRING).and_return("Good day")
+ protocol.should_receive(:read_string).and_return("Good day")
protocol.should_receive(:read_field_end)
protocol.should_receive(:read_struct_end)
protocolFactory = mock("ProtocolFactory")
diff --git a/lib/rb/spec/spec_helper.rb b/lib/rb/spec/spec_helper.rb
index 53d2b80..a9e1374 100644
--- a/lib/rb/spec/spec_helper.rb
+++ b/lib/rb/spec/spec_helper.rb
@@ -31,3 +31,5 @@
Thrift.type_checking = true
end
end
+
+require "thrift_native"
\ No newline at end of file
diff --git a/lib/rb/spec/struct_spec.rb b/lib/rb/spec/struct_spec.rb
index 4dc8714..1a22f57 100644
--- a/lib/rb/spec/struct_spec.rb
+++ b/lib/rb/spec/struct_spec.rb
@@ -1,6 +1,8 @@
require File.dirname(__FILE__) + '/spec_helper'
require File.dirname(__FILE__) + '/gen-rb/ThriftSpec_types'
+# require "binaryprotocolaccelerated"
+
class ThriftStructSpec < Spec::ExampleGroup
include Thrift
include SpecNamespace
@@ -54,7 +56,7 @@
it "should read itself off the wire" do
struct = Foo.new
- prot = mock("Protocol")
+ prot = Protocol.new(mock("transport"))
prot.should_receive(:read_struct_begin).twice
prot.should_receive(:read_struct_end).twice
prot.should_receive(:read_field_begin).and_return(
@@ -79,14 +81,14 @@
prot.should_receive(:read_list_end)
prot.should_receive(:read_set_begin).and_return([Types::I16, 2])
prot.should_receive(:read_set_end)
- prot.should_receive(:read_type).with(Types::I32).and_return(
+ prot.should_receive(:read_i32).and_return(
1, 14, # complex keys
42, # simple
4, 23, 4, 29 # ints
)
- prot.should_receive(:read_type).with(Types::STRING).and_return("pi", "e", "feigenbaum", "apple banana", "what's up?")
- prot.should_receive(:read_type).with(Types::DOUBLE).and_return(Math::PI, Math::E, 4.669201609)
- prot.should_receive(:read_type).with(Types::I16).and_return(2, 3)
+ prot.should_receive(:read_string).and_return("pi", "e", "feigenbaum", "apple banana", "what's up?")
+ prot.should_receive(:read_double).and_return(Math::PI, Math::E, 4.669201609)
+ prot.should_receive(:read_i16).and_return(2, 3)
prot.should_not_receive(:skip)
struct.read(prot)
@@ -100,7 +102,7 @@
it "should skip unexpected fields in structs and use default values" do
struct = Foo.new
- prot = mock("Protocol")
+ prot = Protocol.new(mock("transport"))
prot.should_receive(:read_struct_begin)
prot.should_receive(:read_struct_end)
prot.should_receive(:read_field_begin).and_return(
@@ -112,10 +114,12 @@
[nil, Types::STOP, 0]
)
prot.should_receive(:read_field_end).exactly(5).times
- prot.should_receive(:read_type).with(Types::I32).and_return(42)
- prot.should_receive(:read_type).with(Types::STRING).and_return("foobar")
+ prot.should_receive(:read_i32).and_return(42)
+ prot.should_receive(:read_string).and_return("foobar")
prot.should_receive(:skip).with(Types::STRUCT)
prot.should_receive(:skip).with(Types::MAP)
+ # prot.should_receive(:read_map_begin).and_return([Types::I32, Types::I32, 0])
+ # prot.should_receive(:read_map_end)
prot.should_receive(:skip).with(Types::I32)
struct.read(prot)
@@ -128,31 +132,35 @@
end
it "should write itself to the wire" do
- prot = mock("Protocol")
+ prot = Protocol.new(mock("transport")) #mock("Protocol")
prot.should_receive(:write_struct_begin).with("SpecNamespace::Foo")
- prot.should_receive(:write_struct_end)
+ prot.should_receive(:write_struct_begin).with("SpecNamespace::Hello")
+ prot.should_receive(:write_struct_end).twice
prot.should_receive(:write_field_begin).with('ints', Types::LIST, 4)
+ prot.should_receive(:write_i32).with(1)
+ prot.should_receive(:write_i32).with(2).twice
+ prot.should_receive(:write_i32).with(3)
prot.should_receive(:write_field_begin).with('complex', Types::MAP, 5)
+ prot.should_receive(:write_i32).with(5)
+ prot.should_receive(:write_string).with('foo')
+ prot.should_receive(:write_double).with(1.23)
prot.should_receive(:write_field_begin).with('shorts', Types::SET, 6)
- prot.should_receive(:write_field_stop)
- prot.should_receive(:write_field_end).exactly(3).times
- prot.should_receive(:write_field).with('simple', Types::I32, 1, 53)
- prot.should_receive(:write_field).with('hello', Types::STRUCT, 3, Hello.new(:greeting => 'hello, world!'))
+ prot.should_receive(:write_i16).with(5)
+ prot.should_receive(:write_i16).with(17)
+ prot.should_receive(:write_i16).with(239)
+ prot.should_receive(:write_field_stop).twice
+ prot.should_receive(:write_field_end).exactly(6).times
+ prot.should_receive(:write_field_begin).with('simple', Types::I32, 1)
+ prot.should_receive(:write_i32).with(53)
+ prot.should_receive(:write_field_begin).with('hello', Types::STRUCT, 3)
+ prot.should_receive(:write_field_begin).with('greeting', Types::STRING, 1)
+ prot.should_receive(:write_string).with('hello, world!')
prot.should_receive(:write_map_begin).with(Types::I32, Types::MAP, 1)
prot.should_receive(:write_map_begin).with(Types::STRING, Types::DOUBLE, 1)
- prot.should_receive(:write_type).with(Types::I32, 5) # complex/1/key
- prot.should_receive(:write_type).with(Types::STRING, "foo") # complex/1/value/1/key
- prot.should_receive(:write_type).with(Types::DOUBLE, 1.23) # complex/1/value/1/value
prot.should_receive(:write_map_end).twice
prot.should_receive(:write_list_begin).with(Types::I32, 4)
- prot.should_receive(:write_type).with(Types::I32, 1)
- prot.should_receive(:write_type).with(Types::I32, 2).twice
- prot.should_receive(:write_type).with(Types::I32, 3)
prot.should_receive(:write_list_end)
prot.should_receive(:write_set_begin).with(Types::I16, 3)
- prot.should_receive(:write_type).with(Types::I16, 5)
- prot.should_receive(:write_type).with(Types::I16, 17)
- prot.should_receive(:write_type).with(Types::I16, 239)
prot.should_receive(:write_set_end)
struct = Foo.new
@@ -199,12 +207,15 @@
e.message.should == "something happened"
e.code.should == 1
# ensure it gets serialized properly, this is the really important part
- prot = mock("Protocol")
+ prot = Protocol.new(mock("trans"))
prot.should_receive(:write_struct_begin).with("SpecNamespace::Xception")
prot.should_receive(:write_struct_end)
- prot.should_receive(:write_field).with('message', Types::STRING, 1, "something happened")
- prot.should_receive(:write_field).with('code', Types::I32, 2, 1)
+ prot.should_receive(:write_field_begin).with('message', Types::STRING, 1)#, "something happened")
+ prot.should_receive(:write_string).with("something happened")
+ prot.should_receive(:write_field_begin).with('code', Types::I32, 2)#, 1)
+ prot.should_receive(:write_i32).with(1)
prot.should_receive(:write_field_stop)
+ prot.should_receive(:write_field_end).twice
e.write(prot)
end
@@ -216,12 +227,15 @@
rescue Thrift::Exception => e
e.message.should == "something happened"
e.code.should == 5
- prot = mock("Protocol")
+ prot = Protocol.new(mock("trans"))
prot.should_receive(:write_struct_begin).with("SpecNamespace::Xception")
prot.should_receive(:write_struct_end)
- prot.should_receive(:write_field).with('message', Types::STRING, 1, "something happened")
- prot.should_receive(:write_field).with('code', Types::I32, 2, 5)
+ prot.should_receive(:write_field_begin).with('message', Types::STRING, 1)
+ prot.should_receive(:write_string).with("something happened")
+ prot.should_receive(:write_field_begin).with('code', Types::I32, 2)
+ prot.should_receive(:write_i32).with(5)
prot.should_receive(:write_field_stop)
+ prot.should_receive(:write_field_end).twice
e.write(prot)
end