python-pickle 0.1.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.
- checksums.yaml +7 -0
- data/.document +3 -0
- data/.github/workflows/ruby.yml +27 -0
- data/.gitignore +5 -0
- data/.rspec +1 -0
- data/.yardopts +1 -0
- data/ChangeLog.md +14 -0
- data/Gemfile +15 -0
- data/LICENSE.txt +20 -0
- data/README.md +149 -0
- data/Rakefile +13 -0
- data/gemspec.yml +25 -0
- data/lib/python/pickle/byte_array.rb +40 -0
- data/lib/python/pickle/deserializer.rb +595 -0
- data/lib/python/pickle/exceptions.rb +12 -0
- data/lib/python/pickle/instruction.rb +52 -0
- data/lib/python/pickle/instructions/add_items.rb +26 -0
- data/lib/python/pickle/instructions/append.rb +24 -0
- data/lib/python/pickle/instructions/appends.rb +26 -0
- data/lib/python/pickle/instructions/bin_bytes.rb +32 -0
- data/lib/python/pickle/instructions/bin_bytes8.rb +32 -0
- data/lib/python/pickle/instructions/bin_float.rb +29 -0
- data/lib/python/pickle/instructions/bin_get.rb +27 -0
- data/lib/python/pickle/instructions/bin_int1.rb +29 -0
- data/lib/python/pickle/instructions/bin_put.rb +29 -0
- data/lib/python/pickle/instructions/bin_string.rb +32 -0
- data/lib/python/pickle/instructions/bin_unicode.rb +32 -0
- data/lib/python/pickle/instructions/bin_unicode8.rb +32 -0
- data/lib/python/pickle/instructions/build.rb +24 -0
- data/lib/python/pickle/instructions/byte_array8.rb +32 -0
- data/lib/python/pickle/instructions/dict.rb +17 -0
- data/lib/python/pickle/instructions/dup.rb +24 -0
- data/lib/python/pickle/instructions/empty_dict.rb +26 -0
- data/lib/python/pickle/instructions/empty_list.rb +26 -0
- data/lib/python/pickle/instructions/empty_set.rb +26 -0
- data/lib/python/pickle/instructions/empty_tuple.rb +26 -0
- data/lib/python/pickle/instructions/ext1.rb +29 -0
- data/lib/python/pickle/instructions/ext2.rb +29 -0
- data/lib/python/pickle/instructions/ext4.rb +29 -0
- data/lib/python/pickle/instructions/float.rb +24 -0
- data/lib/python/pickle/instructions/frame.rb +29 -0
- data/lib/python/pickle/instructions/frozen_set.rb +26 -0
- data/lib/python/pickle/instructions/get.rb +27 -0
- data/lib/python/pickle/instructions/global.rb +62 -0
- data/lib/python/pickle/instructions/has_length_and_value.rb +58 -0
- data/lib/python/pickle/instructions/has_value.rb +50 -0
- data/lib/python/pickle/instructions/int.rb +24 -0
- data/lib/python/pickle/instructions/list.rb +24 -0
- data/lib/python/pickle/instructions/long.rb +24 -0
- data/lib/python/pickle/instructions/long1.rb +32 -0
- data/lib/python/pickle/instructions/long4.rb +32 -0
- data/lib/python/pickle/instructions/long_bin_get.rb +27 -0
- data/lib/python/pickle/instructions/mark.rb +24 -0
- data/lib/python/pickle/instructions/memoize.rb +26 -0
- data/lib/python/pickle/instructions/new_false.rb +24 -0
- data/lib/python/pickle/instructions/new_obj.rb +26 -0
- data/lib/python/pickle/instructions/new_obj_ex.rb +26 -0
- data/lib/python/pickle/instructions/new_true.rb +24 -0
- data/lib/python/pickle/instructions/next_buffer.rb +26 -0
- data/lib/python/pickle/instructions/none.rb +24 -0
- data/lib/python/pickle/instructions/pop.rb +24 -0
- data/lib/python/pickle/instructions/pop_mark.rb +24 -0
- data/lib/python/pickle/instructions/proto.rb +29 -0
- data/lib/python/pickle/instructions/put.rb +24 -0
- data/lib/python/pickle/instructions/readonly_buffer.rb +26 -0
- data/lib/python/pickle/instructions/reduce.rb +24 -0
- data/lib/python/pickle/instructions/set_item.rb +24 -0
- data/lib/python/pickle/instructions/set_items.rb +26 -0
- data/lib/python/pickle/instructions/short_bin_bytes.rb +32 -0
- data/lib/python/pickle/instructions/short_bin_string.rb +32 -0
- data/lib/python/pickle/instructions/short_bin_unicode.rb +32 -0
- data/lib/python/pickle/instructions/stack_global.rb +26 -0
- data/lib/python/pickle/instructions/stop.rb +24 -0
- data/lib/python/pickle/instructions/string.rb +24 -0
- data/lib/python/pickle/instructions/tuple.rb +24 -0
- data/lib/python/pickle/instructions/tuple1.rb +24 -0
- data/lib/python/pickle/instructions/tuple2.rb +24 -0
- data/lib/python/pickle/instructions/tuple3.rb +24 -0
- data/lib/python/pickle/protocol.rb +56 -0
- data/lib/python/pickle/protocol0.rb +399 -0
- data/lib/python/pickle/protocol1.rb +183 -0
- data/lib/python/pickle/protocol2.rb +229 -0
- data/lib/python/pickle/protocol3.rb +163 -0
- data/lib/python/pickle/protocol4.rb +285 -0
- data/lib/python/pickle/protocol5.rb +218 -0
- data/lib/python/pickle/py_class.rb +75 -0
- data/lib/python/pickle/py_object.rb +141 -0
- data/lib/python/pickle/tuple.rb +19 -0
- data/lib/python/pickle/version.rb +6 -0
- data/lib/python/pickle.rb +226 -0
- data/python-pickle.gemspec +62 -0
- data/spec/byte_array_spec.rb +54 -0
- data/spec/deserializer_spec.rb +1201 -0
- data/spec/fixtures/ascii_str_v3.pkl +0 -0
- data/spec/fixtures/ascii_str_v4.pkl +0 -0
- data/spec/fixtures/ascii_str_v5.pkl +0 -0
- data/spec/fixtures/bin_str_v0.pkl +3 -0
- data/spec/fixtures/bin_str_v1.pkl +0 -0
- data/spec/fixtures/bin_str_v2.pkl +0 -0
- data/spec/fixtures/bin_str_v3.pkl +0 -0
- data/spec/fixtures/bin_str_v4.pkl +0 -0
- data/spec/fixtures/bin_str_v5.pkl +0 -0
- data/spec/fixtures/bytearray_v0.pkl +10 -0
- data/spec/fixtures/bytearray_v1.pkl +0 -0
- data/spec/fixtures/bytearray_v2.pkl +0 -0
- data/spec/fixtures/bytearray_v3.pkl +0 -0
- data/spec/fixtures/bytearray_v4.pkl +0 -0
- data/spec/fixtures/bytearray_v5.pkl +0 -0
- data/spec/fixtures/class_v0.pkl +4 -0
- data/spec/fixtures/class_v1.pkl +0 -0
- data/spec/fixtures/class_v2.pkl +0 -0
- data/spec/fixtures/class_v3.pkl +0 -0
- data/spec/fixtures/class_v4.pkl +0 -0
- data/spec/fixtures/class_v5.pkl +0 -0
- data/spec/fixtures/dict_v0.pkl +6 -0
- data/spec/fixtures/dict_v1.pkl +0 -0
- data/spec/fixtures/dict_v2.pkl +0 -0
- data/spec/fixtures/dict_v3.pkl +0 -0
- data/spec/fixtures/dict_v4.pkl +0 -0
- data/spec/fixtures/dict_v5.pkl +0 -0
- data/spec/fixtures/escaped_str_v0.pkl +3 -0
- data/spec/fixtures/escaped_str_v1.pkl +0 -0
- data/spec/fixtures/escaped_str_v2.pkl +0 -0
- data/spec/fixtures/false_v0.pkl +2 -0
- data/spec/fixtures/false_v1.pkl +2 -0
- data/spec/fixtures/false_v2.pkl +1 -0
- data/spec/fixtures/false_v3.pkl +1 -0
- data/spec/fixtures/false_v4.pkl +1 -0
- data/spec/fixtures/false_v5.pkl +1 -0
- data/spec/fixtures/float_v0.pkl +2 -0
- data/spec/fixtures/float_v1.pkl +1 -0
- data/spec/fixtures/float_v2.pkl +1 -0
- data/spec/fixtures/float_v3.pkl +1 -0
- data/spec/fixtures/float_v4.pkl +0 -0
- data/spec/fixtures/float_v5.pkl +0 -0
- data/spec/fixtures/function_v0.pkl +4 -0
- data/spec/fixtures/function_v1.pkl +0 -0
- data/spec/fixtures/function_v2.pkl +0 -0
- data/spec/fixtures/function_v3.pkl +0 -0
- data/spec/fixtures/function_v4.pkl +0 -0
- data/spec/fixtures/function_v5.pkl +0 -0
- data/spec/fixtures/hex_str_v0.pkl +3 -0
- data/spec/fixtures/hex_str_v1.pkl +0 -0
- data/spec/fixtures/hex_str_v2.pkl +0 -0
- data/spec/fixtures/int_v0.pkl +2 -0
- data/spec/fixtures/int_v1.pkl +1 -0
- data/spec/fixtures/int_v2.pkl +1 -0
- data/spec/fixtures/int_v3.pkl +1 -0
- data/spec/fixtures/int_v4.pkl +1 -0
- data/spec/fixtures/int_v5.pkl +1 -0
- data/spec/fixtures/list_v0.pkl +7 -0
- data/spec/fixtures/list_v1.pkl +0 -0
- data/spec/fixtures/list_v2.pkl +0 -0
- data/spec/fixtures/list_v3.pkl +0 -0
- data/spec/fixtures/list_v4.pkl +0 -0
- data/spec/fixtures/list_v5.pkl +0 -0
- data/spec/fixtures/long_v0.pkl +2 -0
- data/spec/fixtures/long_v1.pkl +2 -0
- data/spec/fixtures/long_v2.pkl +0 -0
- data/spec/fixtures/long_v3.pkl +0 -0
- data/spec/fixtures/long_v4.pkl +0 -0
- data/spec/fixtures/long_v5.pkl +0 -0
- data/spec/fixtures/nested_dict_v0.pkl +12 -0
- data/spec/fixtures/nested_dict_v1.pkl +0 -0
- data/spec/fixtures/nested_dict_v2.pkl +0 -0
- data/spec/fixtures/nested_dict_v3.pkl +0 -0
- data/spec/fixtures/nested_dict_v4.pkl +0 -0
- data/spec/fixtures/nested_dict_v5.pkl +0 -0
- data/spec/fixtures/nested_list_v0.pkl +9 -0
- data/spec/fixtures/nested_list_v1.pkl +0 -0
- data/spec/fixtures/nested_list_v2.pkl +0 -0
- data/spec/fixtures/nested_list_v3.pkl +0 -0
- data/spec/fixtures/nested_list_v4.pkl +0 -0
- data/spec/fixtures/nested_list_v5.pkl +0 -0
- data/spec/fixtures/none_v0.pkl +1 -0
- data/spec/fixtures/none_v1.pkl +1 -0
- data/spec/fixtures/none_v2.pkl +1 -0
- data/spec/fixtures/none_v3.pkl +1 -0
- data/spec/fixtures/none_v4.pkl +1 -0
- data/spec/fixtures/none_v5.pkl +1 -0
- data/spec/fixtures/object_v0.pkl +19 -0
- data/spec/fixtures/object_v1.pkl +0 -0
- data/spec/fixtures/object_v2.pkl +0 -0
- data/spec/fixtures/object_v3.pkl +0 -0
- data/spec/fixtures/object_v4.pkl +0 -0
- data/spec/fixtures/object_v5.pkl +0 -0
- data/spec/fixtures/str_v0.pkl +3 -0
- data/spec/fixtures/str_v1.pkl +0 -0
- data/spec/fixtures/str_v2.pkl +0 -0
- data/spec/fixtures/str_v3.pkl +0 -0
- data/spec/fixtures/str_v4.pkl +0 -0
- data/spec/fixtures/str_v5.pkl +0 -0
- data/spec/fixtures/true_v0.pkl +2 -0
- data/spec/fixtures/true_v1.pkl +2 -0
- data/spec/fixtures/true_v2.pkl +1 -0
- data/spec/fixtures/true_v3.pkl +1 -0
- data/spec/fixtures/true_v4.pkl +1 -0
- data/spec/fixtures/true_v5.pkl +1 -0
- data/spec/fixtures/unicode_str_v0.pkl +3 -0
- data/spec/fixtures/unicode_str_v1.pkl +0 -0
- data/spec/fixtures/unicode_str_v2.pkl +0 -0
- data/spec/fixtures/unicode_str_v3.pkl +0 -0
- data/spec/fixtures/unicode_str_v4.pkl +0 -0
- data/spec/fixtures/unicode_str_v5.pkl +0 -0
- data/spec/generate_pickles2.py +41 -0
- data/spec/generate_pickles3.py +40 -0
- data/spec/integration/load/protocol0_spec.rb +258 -0
- data/spec/integration/load/protocol1_spec.rb +258 -0
- data/spec/integration/load/protocol2_spec.rb +258 -0
- data/spec/integration/load/protocol3_spec.rb +258 -0
- data/spec/integration/load/protocol4_spec.rb +258 -0
- data/spec/integration/load/protocol5_spec.rb +258 -0
- data/spec/integration/parse/protocol0_spec.rb +467 -0
- data/spec/integration/parse/protocol1_spec.rb +459 -0
- data/spec/integration/parse/protocol2_spec.rb +471 -0
- data/spec/integration/parse/protocol3_spec.rb +407 -0
- data/spec/integration/parse/protocol4_spec.rb +439 -0
- data/spec/integration/parse/protocol5_spec.rb +419 -0
- data/spec/pickle_spec.rb +163 -0
- data/spec/protocol0_read_instruction_examples.rb +211 -0
- data/spec/protocol0_spec.rb +445 -0
- data/spec/protocol1_read_instruction_examples.rb +156 -0
- data/spec/protocol1_spec.rb +59 -0
- data/spec/protocol2_read_instruction_examples.rb +135 -0
- data/spec/protocol2_spec.rb +128 -0
- data/spec/protocol3_read_instruction_examples.rb +29 -0
- data/spec/protocol3_spec.rb +32 -0
- data/spec/protocol4_read_instruction_examples.rb +142 -0
- data/spec/protocol4_spec.rb +58 -0
- data/spec/protocol5_spec.rb +68 -0
- data/spec/py_class_spec.rb +62 -0
- data/spec/py_object_spec.rb +149 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/tuple_spec.rb +18 -0
- metadata +325 -0
@@ -0,0 +1,211 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
shared_examples_for "Protocol0#read_instruction examples" do
|
4
|
+
context "when the opcode is 40" do
|
5
|
+
let(:io) { StringIO.new(40.chr) }
|
6
|
+
|
7
|
+
it "must return Python::Pickle::Instructions::MARK" do
|
8
|
+
expect(subject.read_instruction).to be(
|
9
|
+
Python::Pickle::Instructions::MARK
|
10
|
+
)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context "when the opcode is 46" do
|
15
|
+
let(:io) { StringIO.new(46.chr) }
|
16
|
+
|
17
|
+
it "must return Python::Pickle::Instructions::STOP" do
|
18
|
+
expect(subject.read_instruction).to be(
|
19
|
+
Python::Pickle::Instructions::STOP
|
20
|
+
)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context "when the opcode is 48" do
|
25
|
+
let(:io) { StringIO.new(48.chr) }
|
26
|
+
|
27
|
+
it "must return Python::Pickle::Instructions::POP" do
|
28
|
+
expect(subject.read_instruction).to be(
|
29
|
+
Python::Pickle::Instructions::POP
|
30
|
+
)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context "when the opcode is 49" do
|
35
|
+
let(:io) { StringIO.new(49.chr) }
|
36
|
+
|
37
|
+
it "must return Python::Pickle::Instructions::POP_MARK" do
|
38
|
+
expect(subject.read_instruction).to be(
|
39
|
+
Python::Pickle::Instructions::POP_MARK
|
40
|
+
)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context "when the opcode is 50" do
|
45
|
+
let(:io) { StringIO.new(50.chr) }
|
46
|
+
|
47
|
+
it "must return Python::Pickle::Instructions::DUP" do
|
48
|
+
expect(subject.read_instruction).to be(
|
49
|
+
Python::Pickle::Instructions::DUP
|
50
|
+
)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context "when the opcode is 50" do
|
55
|
+
let(:io) { StringIO.new(50.chr) }
|
56
|
+
|
57
|
+
it "must return Python::Pickle::Instructions::DUP" do
|
58
|
+
expect(subject.read_instruction).to be(
|
59
|
+
Python::Pickle::Instructions::DUP
|
60
|
+
)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context "when the opcode is 73" do
|
65
|
+
let(:int) { 1234 }
|
66
|
+
let(:io) { StringIO.new("#{73.chr}#{int}\n") }
|
67
|
+
|
68
|
+
it "must return a Python::Pickle::Instructions::Int object" do
|
69
|
+
expect(subject.read_instruction).to eq(
|
70
|
+
Python::Pickle::Instructions::Int.new(int)
|
71
|
+
)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context "when the opcode is 76" do
|
76
|
+
let(:long) { (2**64)-1 }
|
77
|
+
let(:io) { StringIO.new("#{76.chr}#{long}L\n") }
|
78
|
+
|
79
|
+
it "must return a Python::Pickle::Instructions::Long object" do
|
80
|
+
expect(subject.read_instruction).to eq(
|
81
|
+
Python::Pickle::Instructions::Long.new(long)
|
82
|
+
)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context "when the opcode is 78" do
|
87
|
+
let(:io) { StringIO.new(78.chr) }
|
88
|
+
|
89
|
+
it "must return Python::Pickle::Instructions::NONE" do
|
90
|
+
expect(subject.read_instruction).to be(
|
91
|
+
Python::Pickle::Instructions::NONE
|
92
|
+
)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context "when the opcode is 82" do
|
97
|
+
let(:io) { StringIO.new(82.chr) }
|
98
|
+
|
99
|
+
it "must return Python::Pickle::Instructions::REDUCE" do
|
100
|
+
expect(subject.read_instruction).to be(
|
101
|
+
Python::Pickle::Instructions::REDUCE
|
102
|
+
)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
context "when the opcode is 86" do
|
107
|
+
let(:string) { 'ABC' }
|
108
|
+
let(:io) { StringIO.new("#{86.chr}#{string}\n") }
|
109
|
+
|
110
|
+
it "must return a Python::Pickle::Instructions::String object" do
|
111
|
+
expect(subject.read_instruction).to eq(
|
112
|
+
Python::Pickle::Instructions::String.new(string)
|
113
|
+
)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
context "when the opcode is 97" do
|
118
|
+
let(:io) { StringIO.new(97.chr) }
|
119
|
+
|
120
|
+
it "must return Python::Pickle::Instructions::APPEND" do
|
121
|
+
expect(subject.read_instruction).to be(
|
122
|
+
Python::Pickle::Instructions::APPEND
|
123
|
+
)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
context "when the opcode is 98" do
|
128
|
+
let(:io) { StringIO.new(98.chr) }
|
129
|
+
|
130
|
+
it "must return Python::Pickle::Instructions::BUILD" do
|
131
|
+
expect(subject.read_instruction).to be(
|
132
|
+
Python::Pickle::Instructions::BUILD
|
133
|
+
)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
context "when the opcode is 99" do
|
138
|
+
let(:namespace) { "foo" }
|
139
|
+
let(:name) { "bar" }
|
140
|
+
|
141
|
+
let(:io) { StringIO.new("#{99.chr}#{namespace}\n#{name}\n") }
|
142
|
+
|
143
|
+
it "must return Python::Pickle::Instructions::GLOBAL" do
|
144
|
+
expect(subject.read_instruction).to eq(
|
145
|
+
Python::Pickle::Instructions::Global.new(namespace,name)
|
146
|
+
)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
context "when the opcode is 100" do
|
151
|
+
let(:io) { StringIO.new(100.chr) }
|
152
|
+
|
153
|
+
it "must return Python::Pickle::Instructions::DICT" do
|
154
|
+
expect(subject.read_instruction).to be(
|
155
|
+
Python::Pickle::Instructions::DICT
|
156
|
+
)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
context "when the opcode is 103" do
|
161
|
+
let(:index) { 1 }
|
162
|
+
let(:io) { StringIO.new("#{103.chr}#{index}\n") }
|
163
|
+
|
164
|
+
it "must return a Python::Pickle::Instructions::Get object" do
|
165
|
+
expect(subject.read_instruction).to eq(
|
166
|
+
Python::Pickle::Instructions::Get.new(index)
|
167
|
+
)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
context "when the opcode is 108" do
|
172
|
+
let(:io) { StringIO.new(108.chr) }
|
173
|
+
|
174
|
+
it "must return Python::Pickle::Instructions::LIST" do
|
175
|
+
expect(subject.read_instruction).to be(
|
176
|
+
Python::Pickle::Instructions::LIST
|
177
|
+
)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
context "when the opcode is 112" do
|
182
|
+
let(:index) { 1 }
|
183
|
+
let(:io) { StringIO.new("#{112.chr}#{index}\n") }
|
184
|
+
|
185
|
+
it "must return a Python::Pickle::Instructions::Put object" do
|
186
|
+
expect(subject.read_instruction).to eq(
|
187
|
+
Python::Pickle::Instructions::Put.new(index)
|
188
|
+
)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
context "when the opcode is 115" do
|
193
|
+
let(:io) { StringIO.new(115.chr) }
|
194
|
+
|
195
|
+
it "must return Python::Pickle::Instructions::SETITEM" do
|
196
|
+
expect(subject.read_instruction).to be(
|
197
|
+
Python::Pickle::Instructions::SETITEM
|
198
|
+
)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
context "when the opcode is 116" do
|
203
|
+
let(:io) { StringIO.new(116.chr) }
|
204
|
+
|
205
|
+
it "must return Python::Pickle::Instructions::TUPLE" do
|
206
|
+
expect(subject.read_instruction).to be(
|
207
|
+
Python::Pickle::Instructions::TUPLE
|
208
|
+
)
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
@@ -0,0 +1,445 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'python/pickle/protocol0'
|
3
|
+
|
4
|
+
require 'protocol0_read_instruction_examples'
|
5
|
+
|
6
|
+
describe Python::Pickle::Protocol0 do
|
7
|
+
let(:pickle) { '' }
|
8
|
+
let(:io) { StringIO.new(pickle) }
|
9
|
+
|
10
|
+
subject { described_class.new(io) }
|
11
|
+
|
12
|
+
describe "#read_hex_escaped_char" do
|
13
|
+
let(:io) { StringIO.new("41") }
|
14
|
+
subject { described_class.new(io) }
|
15
|
+
|
16
|
+
it "must return the character represented by the hex byte value" do
|
17
|
+
expect(subject.read_hex_escaped_char).to eq('A')
|
18
|
+
end
|
19
|
+
|
20
|
+
context "when the hex string starts with a non-hex character" do
|
21
|
+
let(:io) { StringIO.new("G1") }
|
22
|
+
|
23
|
+
it do
|
24
|
+
expect {
|
25
|
+
subject.read_hex_escaped_char
|
26
|
+
}.to raise_error(Python::Pickle::InvalidFormat,"invalid hex escape character: \"\\xG1\"")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context "when the hex string ends with a non-hex character" do
|
31
|
+
let(:io) { StringIO.new("1G") }
|
32
|
+
|
33
|
+
it do
|
34
|
+
expect {
|
35
|
+
subject.read_hex_escaped_char
|
36
|
+
}.to raise_error(Python::Pickle::InvalidFormat,"invalid hex escape character: \"\\x1G\"")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context "when the hex string ends prematurely" do
|
41
|
+
let(:io) { StringIO.new("1") }
|
42
|
+
|
43
|
+
it do
|
44
|
+
expect {
|
45
|
+
subject.read_hex_escaped_char
|
46
|
+
}.to raise_error(Python::Pickle::InvalidFormat,"invalid hex escape character: \"\\x1\"")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "#read_escaped_char" do
|
52
|
+
context "when the next character is 'x'" do
|
53
|
+
let(:io) { StringIO.new("x41") }
|
54
|
+
|
55
|
+
it "must decode the hex escaped character" do
|
56
|
+
expect(subject.read_escaped_char).to eq('A')
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context "when the next character is 't'" do
|
61
|
+
let(:io) { StringIO.new("t") }
|
62
|
+
|
63
|
+
it "must return '\\t'" do
|
64
|
+
expect(subject.read_escaped_char).to eq("\t")
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context "when the next character is 'n'" do
|
69
|
+
let(:io) { StringIO.new("n") }
|
70
|
+
|
71
|
+
it "must return '\\n'" do
|
72
|
+
expect(subject.read_escaped_char).to eq("\n")
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context "when the next character is 'r'" do
|
77
|
+
let(:io) { StringIO.new("r") }
|
78
|
+
|
79
|
+
it "must return '\\r'" do
|
80
|
+
expect(subject.read_escaped_char).to eq("\r")
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context "when the next character is '\\'" do
|
85
|
+
let(:io) { StringIO.new("\\") }
|
86
|
+
|
87
|
+
it "must return '\\'" do
|
88
|
+
expect(subject.read_escaped_char).to eq("\\")
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context "when the next character is '\\''" do
|
93
|
+
let(:io) { StringIO.new("'") }
|
94
|
+
|
95
|
+
it "must return '\\''" do
|
96
|
+
expect(subject.read_escaped_char).to eq("'")
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context "when the next character is another character" do
|
101
|
+
let(:io) { StringIO.new("a") }
|
102
|
+
|
103
|
+
it do
|
104
|
+
expect {
|
105
|
+
subject.read_escaped_char
|
106
|
+
}.to raise_error(Python::Pickle::InvalidFormat,"invalid backslash escape character: \"\\a\"")
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe "#read_nl_string" do
|
112
|
+
let(:string) { "foo" }
|
113
|
+
let(:io) { StringIO.new("#{string}\n") }
|
114
|
+
|
115
|
+
it "must read the characters until a '\\n' character is encountered" do
|
116
|
+
expect(subject.read_nl_string).to eq(string)
|
117
|
+
end
|
118
|
+
|
119
|
+
context "when the stream prematurely ends" do
|
120
|
+
let(:io) { StringIO.new("#{string}") }
|
121
|
+
|
122
|
+
it do
|
123
|
+
expect {
|
124
|
+
subject.read_nl_string
|
125
|
+
}.to raise_error(Python::Pickle::InvalidFormat,"unexpected end of stream after the end of a newline terminated string")
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
describe "#read_string" do
|
131
|
+
let(:string) { 'ABC' }
|
132
|
+
let(:io) { StringIO.new("'#{string}'\n") }
|
133
|
+
|
134
|
+
it "must read the characters within the single-quotes and return the string" do
|
135
|
+
expect(subject.read_string).to eq(string)
|
136
|
+
end
|
137
|
+
|
138
|
+
it "must return an ASCII 8bit encoded String" do
|
139
|
+
expect(subject.read_string.encoding).to eq(Encoding::ASCII_8BIT)
|
140
|
+
end
|
141
|
+
|
142
|
+
context "when the string contains backslash escaped characters" do
|
143
|
+
let(:string) { "ABC\\t\\n\\r\\\\\\'" }
|
144
|
+
|
145
|
+
it "must decode the backslash escaped characters" do
|
146
|
+
expect(subject.read_string).to eq("ABC\t\n\r\\'")
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
context "when the string contains hex escaped characters" do
|
151
|
+
let(:string) { "ABC\\x41\\x42\\x43" }
|
152
|
+
|
153
|
+
it "must decode the hex escaped characters" do
|
154
|
+
expect(subject.read_string).to eq("ABCABC")
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
context "when the next character is not a \"'\"" do
|
159
|
+
let(:io) { StringIO.new("#{string}'") }
|
160
|
+
|
161
|
+
it do
|
162
|
+
expect {
|
163
|
+
subject.read_string
|
164
|
+
}.to raise_error(Python::Pickle::InvalidFormat,"cannot find beginning single-quote of string")
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
context "when the string does not end with a single-quote" do
|
169
|
+
let(:io) { StringIO.new("'#{string}") }
|
170
|
+
|
171
|
+
it do
|
172
|
+
expect {
|
173
|
+
subject.read_string
|
174
|
+
}.to raise_error(Python::Pickle::InvalidFormat,"unexpected end of stream after the end of a single-quoted string")
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
context "when the character after the ending single-quote is not a '\\n' character" do
|
179
|
+
let(:io) { StringIO.new("'#{string}'XXX") }
|
180
|
+
|
181
|
+
it do
|
182
|
+
expect {
|
183
|
+
subject.read_string
|
184
|
+
}.to raise_error(Python::Pickle::InvalidFormat,"expected a '\\n' character following the string, but was \"X\"")
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
describe "#read_unicode_escaped_char16" do
|
190
|
+
let(:io) { StringIO.new("1234") }
|
191
|
+
subject { described_class.new(io) }
|
192
|
+
|
193
|
+
it "must read four hex characters and represent the unicode character represented by them" do
|
194
|
+
expect(subject.read_unicode_escaped_char16).to eq('ሴ')
|
195
|
+
end
|
196
|
+
|
197
|
+
context "when the hex string starts with a non-hex character" do
|
198
|
+
let(:io) { StringIO.new("G234") }
|
199
|
+
|
200
|
+
it do
|
201
|
+
expect {
|
202
|
+
subject.read_unicode_escaped_char16
|
203
|
+
}.to raise_error(Python::Pickle::InvalidFormat,"invalid unicode escape character: \"\\uG234\"")
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
context "when the hex string ends with a non-hex character" do
|
208
|
+
let(:io) { StringIO.new("123G") }
|
209
|
+
|
210
|
+
it do
|
211
|
+
expect {
|
212
|
+
subject.read_unicode_escaped_char16
|
213
|
+
}.to raise_error(Python::Pickle::InvalidFormat,"invalid unicode escape character: \"\\u123G\"")
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
context "when the hex string ends prematurely" do
|
218
|
+
let(:io) { StringIO.new("123") }
|
219
|
+
|
220
|
+
it do
|
221
|
+
expect {
|
222
|
+
subject.read_unicode_escaped_char16
|
223
|
+
}.to raise_error(Python::Pickle::InvalidFormat,"invalid unicode escape character: \"\\u123\"")
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
describe "#read_unicode_escaped_char32" do
|
229
|
+
let(:io) { StringIO.new("00001234") }
|
230
|
+
subject { described_class.new(io) }
|
231
|
+
|
232
|
+
it "must read eight hex characters and represent the unicode character represented by them" do
|
233
|
+
expect(subject.read_unicode_escaped_char32).to eq('ሴ')
|
234
|
+
end
|
235
|
+
|
236
|
+
context "when the hex string starts with a non-hex character" do
|
237
|
+
let(:io) { StringIO.new("G2345678") }
|
238
|
+
|
239
|
+
it do
|
240
|
+
expect {
|
241
|
+
subject.read_unicode_escaped_char32
|
242
|
+
}.to raise_error(Python::Pickle::InvalidFormat,"invalid unicode escape character: \"\\UG2345678\"")
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
context "when the hex string ends with a non-hex character" do
|
247
|
+
let(:io) { StringIO.new("1234567G") }
|
248
|
+
|
249
|
+
it do
|
250
|
+
expect {
|
251
|
+
subject.read_unicode_escaped_char32
|
252
|
+
}.to raise_error(Python::Pickle::InvalidFormat,"invalid unicode escape character: \"\\U1234567G\"")
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
context "when the hex string ends prematurely" do
|
257
|
+
let(:io) { StringIO.new("0000123") }
|
258
|
+
|
259
|
+
it do
|
260
|
+
expect {
|
261
|
+
subject.read_unicode_escaped_char32
|
262
|
+
}.to raise_error(Python::Pickle::InvalidFormat,"invalid unicode escape character: \"\\U0000123\"")
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
describe "#read_unicode_escaped_char" do
|
268
|
+
end
|
269
|
+
|
270
|
+
describe "#read_unicode" do
|
271
|
+
let(:string) { 'ABC' }
|
272
|
+
let(:io) { StringIO.new("#{string}\n") }
|
273
|
+
|
274
|
+
it "must read the characters within the single-quotes and return the string" do
|
275
|
+
expect(subject.read_unicode_string).to eq(string)
|
276
|
+
end
|
277
|
+
|
278
|
+
it "must return a UTF-8 encoded String" do
|
279
|
+
expect(subject.read_unicode_string.encoding).to eq(Encoding::UTF_8)
|
280
|
+
end
|
281
|
+
|
282
|
+
context "when the string contains unicode escaped characters" do
|
283
|
+
let(:string) { "ABC\\u0041\\u0042\\u0043" }
|
284
|
+
|
285
|
+
it "must decode the hex escaped characters" do
|
286
|
+
expect(subject.read_unicode_string).to eq("ABCABC")
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
context "when the string does not end with a '\\n' character" do
|
291
|
+
let(:io) { StringIO.new("#{string}") }
|
292
|
+
|
293
|
+
it do
|
294
|
+
expect {
|
295
|
+
subject.read_unicode_string
|
296
|
+
}.to raise_error(Python::Pickle::InvalidFormat,"unexpected end of stream while parsing unicode string: #{string.inspect}")
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
describe "#read_float" do
|
302
|
+
let(:float) { 1234.5678 }
|
303
|
+
let(:io) { StringIO.new("#{float}\n") }
|
304
|
+
|
305
|
+
it "must read until the newline and decode the read digits" do
|
306
|
+
expect(subject.read_float).to eq(float)
|
307
|
+
end
|
308
|
+
|
309
|
+
context "when a non-numeric character is read" do
|
310
|
+
let(:io) { StringIO.new("12.3x4\n") }
|
311
|
+
|
312
|
+
it do
|
313
|
+
expect {
|
314
|
+
subject.read_float
|
315
|
+
}.to raise_error(Python::Pickle::InvalidFormat,"encountered a non-numeric character while reading a float: \"x\"")
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
context "when the stream ends prematurely" do
|
320
|
+
let(:string) { '123.' }
|
321
|
+
let(:io) { StringIO.new(string) }
|
322
|
+
|
323
|
+
it do
|
324
|
+
expect {
|
325
|
+
subject.read_float
|
326
|
+
}.to raise_error(Python::Pickle::InvalidFormat,"unexpected end of stream while parsing a float: #{string.inspect}")
|
327
|
+
end
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
describe "#read_int" do
|
332
|
+
let(:int) { 1234 }
|
333
|
+
let(:io) { StringIO.new("#{int}\n") }
|
334
|
+
|
335
|
+
it "must read until the newline and decode the read digits" do
|
336
|
+
expect(subject.read_int).to eq(int)
|
337
|
+
end
|
338
|
+
|
339
|
+
context "when the next characters are '00\\n'" do
|
340
|
+
let(:io) { StringIO.new("00\n") }
|
341
|
+
|
342
|
+
it "must return false" do
|
343
|
+
expect(subject.read_int).to be(false)
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
context "when the next characters are '01\\n'" do
|
348
|
+
let(:io) { StringIO.new("01\n") }
|
349
|
+
|
350
|
+
it "must return true" do
|
351
|
+
expect(subject.read_int).to be(true)
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
context "when a non-numeric character is read" do
|
356
|
+
let(:io) { StringIO.new("100x00\n") }
|
357
|
+
|
358
|
+
it do
|
359
|
+
expect {
|
360
|
+
subject.read_int
|
361
|
+
}.to raise_error(Python::Pickle::InvalidFormat,"encountered a non-numeric character while reading an integer: \"x\"")
|
362
|
+
end
|
363
|
+
end
|
364
|
+
|
365
|
+
context "when the stream ends prematurely" do
|
366
|
+
let(:string) { '1234' }
|
367
|
+
let(:io) { StringIO.new(string) }
|
368
|
+
|
369
|
+
it do
|
370
|
+
expect {
|
371
|
+
subject.read_int
|
372
|
+
}.to raise_error(Python::Pickle::InvalidFormat,"unexpected end of stream while parsing an integer: #{string.inspect}")
|
373
|
+
end
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
describe "#read_long" do
|
378
|
+
let(:long) { (2**64) - 1 }
|
379
|
+
let(:io) { StringIO.new("#{long}L\n") }
|
380
|
+
|
381
|
+
it "must read until a 'L' character and decode the read digits" do
|
382
|
+
expect(subject.read_long).to eq(long)
|
383
|
+
end
|
384
|
+
|
385
|
+
context "when a non-numeric character is read" do
|
386
|
+
let(:io) { StringIO.new("1234x678L\n") }
|
387
|
+
|
388
|
+
it do
|
389
|
+
expect {
|
390
|
+
subject.read_long
|
391
|
+
}.to raise_error(Python::Pickle::InvalidFormat,"encountered a non-numeric character while reading a long integer: \"x\"")
|
392
|
+
end
|
393
|
+
end
|
394
|
+
|
395
|
+
context "when the stream ends prematurely" do
|
396
|
+
let(:string) { '1234' }
|
397
|
+
let(:io) { StringIO.new(string) }
|
398
|
+
|
399
|
+
it do
|
400
|
+
expect {
|
401
|
+
subject.read_long
|
402
|
+
}.to raise_error(Python::Pickle::InvalidFormat,"unexpected end of stream while parsing a long integer: #{string.inspect}")
|
403
|
+
end
|
404
|
+
end
|
405
|
+
|
406
|
+
context "when the stream ends just after the terminating 'L'" do
|
407
|
+
let(:string) { '1234L' }
|
408
|
+
let(:io) { StringIO.new(string) }
|
409
|
+
|
410
|
+
it do
|
411
|
+
expect {
|
412
|
+
subject.read_long
|
413
|
+
}.to raise_error(Python::Pickle::InvalidFormat,"unexpected end of stream after the end of an integer")
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
context "when there is no newline character after the terminating 'L'" do
|
418
|
+
let(:string) { "1234Lx" }
|
419
|
+
let(:io) { StringIO.new(string) }
|
420
|
+
|
421
|
+
it do
|
422
|
+
expect {
|
423
|
+
subject.read_long
|
424
|
+
}.to raise_error(Python::Pickle::InvalidFormat,"expected a '\\n' character following the integer, but was \"x\"")
|
425
|
+
end
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
429
|
+
let(:fixtures_dir) { File.join(__dir__,'fixtures') }
|
430
|
+
|
431
|
+
describe "#read_instruction" do
|
432
|
+
include_context "Protocol0#read_instruction examples"
|
433
|
+
|
434
|
+
context "when the opcode isn't reocgnized" do
|
435
|
+
let(:opcode) { 255 }
|
436
|
+
let(:io) { StringIO.new(opcode.chr) }
|
437
|
+
|
438
|
+
it do
|
439
|
+
expect {
|
440
|
+
subject.read_instruction
|
441
|
+
}.to raise_error(Python::Pickle::InvalidFormat,"invalid opcode (#{opcode.inspect}) for protocol 0")
|
442
|
+
end
|
443
|
+
end
|
444
|
+
end
|
445
|
+
end
|