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.
Files changed (235) hide show
  1. checksums.yaml +7 -0
  2. data/.document +3 -0
  3. data/.github/workflows/ruby.yml +27 -0
  4. data/.gitignore +5 -0
  5. data/.rspec +1 -0
  6. data/.yardopts +1 -0
  7. data/ChangeLog.md +14 -0
  8. data/Gemfile +15 -0
  9. data/LICENSE.txt +20 -0
  10. data/README.md +149 -0
  11. data/Rakefile +13 -0
  12. data/gemspec.yml +25 -0
  13. data/lib/python/pickle/byte_array.rb +40 -0
  14. data/lib/python/pickle/deserializer.rb +595 -0
  15. data/lib/python/pickle/exceptions.rb +12 -0
  16. data/lib/python/pickle/instruction.rb +52 -0
  17. data/lib/python/pickle/instructions/add_items.rb +26 -0
  18. data/lib/python/pickle/instructions/append.rb +24 -0
  19. data/lib/python/pickle/instructions/appends.rb +26 -0
  20. data/lib/python/pickle/instructions/bin_bytes.rb +32 -0
  21. data/lib/python/pickle/instructions/bin_bytes8.rb +32 -0
  22. data/lib/python/pickle/instructions/bin_float.rb +29 -0
  23. data/lib/python/pickle/instructions/bin_get.rb +27 -0
  24. data/lib/python/pickle/instructions/bin_int1.rb +29 -0
  25. data/lib/python/pickle/instructions/bin_put.rb +29 -0
  26. data/lib/python/pickle/instructions/bin_string.rb +32 -0
  27. data/lib/python/pickle/instructions/bin_unicode.rb +32 -0
  28. data/lib/python/pickle/instructions/bin_unicode8.rb +32 -0
  29. data/lib/python/pickle/instructions/build.rb +24 -0
  30. data/lib/python/pickle/instructions/byte_array8.rb +32 -0
  31. data/lib/python/pickle/instructions/dict.rb +17 -0
  32. data/lib/python/pickle/instructions/dup.rb +24 -0
  33. data/lib/python/pickle/instructions/empty_dict.rb +26 -0
  34. data/lib/python/pickle/instructions/empty_list.rb +26 -0
  35. data/lib/python/pickle/instructions/empty_set.rb +26 -0
  36. data/lib/python/pickle/instructions/empty_tuple.rb +26 -0
  37. data/lib/python/pickle/instructions/ext1.rb +29 -0
  38. data/lib/python/pickle/instructions/ext2.rb +29 -0
  39. data/lib/python/pickle/instructions/ext4.rb +29 -0
  40. data/lib/python/pickle/instructions/float.rb +24 -0
  41. data/lib/python/pickle/instructions/frame.rb +29 -0
  42. data/lib/python/pickle/instructions/frozen_set.rb +26 -0
  43. data/lib/python/pickle/instructions/get.rb +27 -0
  44. data/lib/python/pickle/instructions/global.rb +62 -0
  45. data/lib/python/pickle/instructions/has_length_and_value.rb +58 -0
  46. data/lib/python/pickle/instructions/has_value.rb +50 -0
  47. data/lib/python/pickle/instructions/int.rb +24 -0
  48. data/lib/python/pickle/instructions/list.rb +24 -0
  49. data/lib/python/pickle/instructions/long.rb +24 -0
  50. data/lib/python/pickle/instructions/long1.rb +32 -0
  51. data/lib/python/pickle/instructions/long4.rb +32 -0
  52. data/lib/python/pickle/instructions/long_bin_get.rb +27 -0
  53. data/lib/python/pickle/instructions/mark.rb +24 -0
  54. data/lib/python/pickle/instructions/memoize.rb +26 -0
  55. data/lib/python/pickle/instructions/new_false.rb +24 -0
  56. data/lib/python/pickle/instructions/new_obj.rb +26 -0
  57. data/lib/python/pickle/instructions/new_obj_ex.rb +26 -0
  58. data/lib/python/pickle/instructions/new_true.rb +24 -0
  59. data/lib/python/pickle/instructions/next_buffer.rb +26 -0
  60. data/lib/python/pickle/instructions/none.rb +24 -0
  61. data/lib/python/pickle/instructions/pop.rb +24 -0
  62. data/lib/python/pickle/instructions/pop_mark.rb +24 -0
  63. data/lib/python/pickle/instructions/proto.rb +29 -0
  64. data/lib/python/pickle/instructions/put.rb +24 -0
  65. data/lib/python/pickle/instructions/readonly_buffer.rb +26 -0
  66. data/lib/python/pickle/instructions/reduce.rb +24 -0
  67. data/lib/python/pickle/instructions/set_item.rb +24 -0
  68. data/lib/python/pickle/instructions/set_items.rb +26 -0
  69. data/lib/python/pickle/instructions/short_bin_bytes.rb +32 -0
  70. data/lib/python/pickle/instructions/short_bin_string.rb +32 -0
  71. data/lib/python/pickle/instructions/short_bin_unicode.rb +32 -0
  72. data/lib/python/pickle/instructions/stack_global.rb +26 -0
  73. data/lib/python/pickle/instructions/stop.rb +24 -0
  74. data/lib/python/pickle/instructions/string.rb +24 -0
  75. data/lib/python/pickle/instructions/tuple.rb +24 -0
  76. data/lib/python/pickle/instructions/tuple1.rb +24 -0
  77. data/lib/python/pickle/instructions/tuple2.rb +24 -0
  78. data/lib/python/pickle/instructions/tuple3.rb +24 -0
  79. data/lib/python/pickle/protocol.rb +56 -0
  80. data/lib/python/pickle/protocol0.rb +399 -0
  81. data/lib/python/pickle/protocol1.rb +183 -0
  82. data/lib/python/pickle/protocol2.rb +229 -0
  83. data/lib/python/pickle/protocol3.rb +163 -0
  84. data/lib/python/pickle/protocol4.rb +285 -0
  85. data/lib/python/pickle/protocol5.rb +218 -0
  86. data/lib/python/pickle/py_class.rb +75 -0
  87. data/lib/python/pickle/py_object.rb +141 -0
  88. data/lib/python/pickle/tuple.rb +19 -0
  89. data/lib/python/pickle/version.rb +6 -0
  90. data/lib/python/pickle.rb +226 -0
  91. data/python-pickle.gemspec +62 -0
  92. data/spec/byte_array_spec.rb +54 -0
  93. data/spec/deserializer_spec.rb +1201 -0
  94. data/spec/fixtures/ascii_str_v3.pkl +0 -0
  95. data/spec/fixtures/ascii_str_v4.pkl +0 -0
  96. data/spec/fixtures/ascii_str_v5.pkl +0 -0
  97. data/spec/fixtures/bin_str_v0.pkl +3 -0
  98. data/spec/fixtures/bin_str_v1.pkl +0 -0
  99. data/spec/fixtures/bin_str_v2.pkl +0 -0
  100. data/spec/fixtures/bin_str_v3.pkl +0 -0
  101. data/spec/fixtures/bin_str_v4.pkl +0 -0
  102. data/spec/fixtures/bin_str_v5.pkl +0 -0
  103. data/spec/fixtures/bytearray_v0.pkl +10 -0
  104. data/spec/fixtures/bytearray_v1.pkl +0 -0
  105. data/spec/fixtures/bytearray_v2.pkl +0 -0
  106. data/spec/fixtures/bytearray_v3.pkl +0 -0
  107. data/spec/fixtures/bytearray_v4.pkl +0 -0
  108. data/spec/fixtures/bytearray_v5.pkl +0 -0
  109. data/spec/fixtures/class_v0.pkl +4 -0
  110. data/spec/fixtures/class_v1.pkl +0 -0
  111. data/spec/fixtures/class_v2.pkl +0 -0
  112. data/spec/fixtures/class_v3.pkl +0 -0
  113. data/spec/fixtures/class_v4.pkl +0 -0
  114. data/spec/fixtures/class_v5.pkl +0 -0
  115. data/spec/fixtures/dict_v0.pkl +6 -0
  116. data/spec/fixtures/dict_v1.pkl +0 -0
  117. data/spec/fixtures/dict_v2.pkl +0 -0
  118. data/spec/fixtures/dict_v3.pkl +0 -0
  119. data/spec/fixtures/dict_v4.pkl +0 -0
  120. data/spec/fixtures/dict_v5.pkl +0 -0
  121. data/spec/fixtures/escaped_str_v0.pkl +3 -0
  122. data/spec/fixtures/escaped_str_v1.pkl +0 -0
  123. data/spec/fixtures/escaped_str_v2.pkl +0 -0
  124. data/spec/fixtures/false_v0.pkl +2 -0
  125. data/spec/fixtures/false_v1.pkl +2 -0
  126. data/spec/fixtures/false_v2.pkl +1 -0
  127. data/spec/fixtures/false_v3.pkl +1 -0
  128. data/spec/fixtures/false_v4.pkl +1 -0
  129. data/spec/fixtures/false_v5.pkl +1 -0
  130. data/spec/fixtures/float_v0.pkl +2 -0
  131. data/spec/fixtures/float_v1.pkl +1 -0
  132. data/spec/fixtures/float_v2.pkl +1 -0
  133. data/spec/fixtures/float_v3.pkl +1 -0
  134. data/spec/fixtures/float_v4.pkl +0 -0
  135. data/spec/fixtures/float_v5.pkl +0 -0
  136. data/spec/fixtures/function_v0.pkl +4 -0
  137. data/spec/fixtures/function_v1.pkl +0 -0
  138. data/spec/fixtures/function_v2.pkl +0 -0
  139. data/spec/fixtures/function_v3.pkl +0 -0
  140. data/spec/fixtures/function_v4.pkl +0 -0
  141. data/spec/fixtures/function_v5.pkl +0 -0
  142. data/spec/fixtures/hex_str_v0.pkl +3 -0
  143. data/spec/fixtures/hex_str_v1.pkl +0 -0
  144. data/spec/fixtures/hex_str_v2.pkl +0 -0
  145. data/spec/fixtures/int_v0.pkl +2 -0
  146. data/spec/fixtures/int_v1.pkl +1 -0
  147. data/spec/fixtures/int_v2.pkl +1 -0
  148. data/spec/fixtures/int_v3.pkl +1 -0
  149. data/spec/fixtures/int_v4.pkl +1 -0
  150. data/spec/fixtures/int_v5.pkl +1 -0
  151. data/spec/fixtures/list_v0.pkl +7 -0
  152. data/spec/fixtures/list_v1.pkl +0 -0
  153. data/spec/fixtures/list_v2.pkl +0 -0
  154. data/spec/fixtures/list_v3.pkl +0 -0
  155. data/spec/fixtures/list_v4.pkl +0 -0
  156. data/spec/fixtures/list_v5.pkl +0 -0
  157. data/spec/fixtures/long_v0.pkl +2 -0
  158. data/spec/fixtures/long_v1.pkl +2 -0
  159. data/spec/fixtures/long_v2.pkl +0 -0
  160. data/spec/fixtures/long_v3.pkl +0 -0
  161. data/spec/fixtures/long_v4.pkl +0 -0
  162. data/spec/fixtures/long_v5.pkl +0 -0
  163. data/spec/fixtures/nested_dict_v0.pkl +12 -0
  164. data/spec/fixtures/nested_dict_v1.pkl +0 -0
  165. data/spec/fixtures/nested_dict_v2.pkl +0 -0
  166. data/spec/fixtures/nested_dict_v3.pkl +0 -0
  167. data/spec/fixtures/nested_dict_v4.pkl +0 -0
  168. data/spec/fixtures/nested_dict_v5.pkl +0 -0
  169. data/spec/fixtures/nested_list_v0.pkl +9 -0
  170. data/spec/fixtures/nested_list_v1.pkl +0 -0
  171. data/spec/fixtures/nested_list_v2.pkl +0 -0
  172. data/spec/fixtures/nested_list_v3.pkl +0 -0
  173. data/spec/fixtures/nested_list_v4.pkl +0 -0
  174. data/spec/fixtures/nested_list_v5.pkl +0 -0
  175. data/spec/fixtures/none_v0.pkl +1 -0
  176. data/spec/fixtures/none_v1.pkl +1 -0
  177. data/spec/fixtures/none_v2.pkl +1 -0
  178. data/spec/fixtures/none_v3.pkl +1 -0
  179. data/spec/fixtures/none_v4.pkl +1 -0
  180. data/spec/fixtures/none_v5.pkl +1 -0
  181. data/spec/fixtures/object_v0.pkl +19 -0
  182. data/spec/fixtures/object_v1.pkl +0 -0
  183. data/spec/fixtures/object_v2.pkl +0 -0
  184. data/spec/fixtures/object_v3.pkl +0 -0
  185. data/spec/fixtures/object_v4.pkl +0 -0
  186. data/spec/fixtures/object_v5.pkl +0 -0
  187. data/spec/fixtures/str_v0.pkl +3 -0
  188. data/spec/fixtures/str_v1.pkl +0 -0
  189. data/spec/fixtures/str_v2.pkl +0 -0
  190. data/spec/fixtures/str_v3.pkl +0 -0
  191. data/spec/fixtures/str_v4.pkl +0 -0
  192. data/spec/fixtures/str_v5.pkl +0 -0
  193. data/spec/fixtures/true_v0.pkl +2 -0
  194. data/spec/fixtures/true_v1.pkl +2 -0
  195. data/spec/fixtures/true_v2.pkl +1 -0
  196. data/spec/fixtures/true_v3.pkl +1 -0
  197. data/spec/fixtures/true_v4.pkl +1 -0
  198. data/spec/fixtures/true_v5.pkl +1 -0
  199. data/spec/fixtures/unicode_str_v0.pkl +3 -0
  200. data/spec/fixtures/unicode_str_v1.pkl +0 -0
  201. data/spec/fixtures/unicode_str_v2.pkl +0 -0
  202. data/spec/fixtures/unicode_str_v3.pkl +0 -0
  203. data/spec/fixtures/unicode_str_v4.pkl +0 -0
  204. data/spec/fixtures/unicode_str_v5.pkl +0 -0
  205. data/spec/generate_pickles2.py +41 -0
  206. data/spec/generate_pickles3.py +40 -0
  207. data/spec/integration/load/protocol0_spec.rb +258 -0
  208. data/spec/integration/load/protocol1_spec.rb +258 -0
  209. data/spec/integration/load/protocol2_spec.rb +258 -0
  210. data/spec/integration/load/protocol3_spec.rb +258 -0
  211. data/spec/integration/load/protocol4_spec.rb +258 -0
  212. data/spec/integration/load/protocol5_spec.rb +258 -0
  213. data/spec/integration/parse/protocol0_spec.rb +467 -0
  214. data/spec/integration/parse/protocol1_spec.rb +459 -0
  215. data/spec/integration/parse/protocol2_spec.rb +471 -0
  216. data/spec/integration/parse/protocol3_spec.rb +407 -0
  217. data/spec/integration/parse/protocol4_spec.rb +439 -0
  218. data/spec/integration/parse/protocol5_spec.rb +419 -0
  219. data/spec/pickle_spec.rb +163 -0
  220. data/spec/protocol0_read_instruction_examples.rb +211 -0
  221. data/spec/protocol0_spec.rb +445 -0
  222. data/spec/protocol1_read_instruction_examples.rb +156 -0
  223. data/spec/protocol1_spec.rb +59 -0
  224. data/spec/protocol2_read_instruction_examples.rb +135 -0
  225. data/spec/protocol2_spec.rb +128 -0
  226. data/spec/protocol3_read_instruction_examples.rb +29 -0
  227. data/spec/protocol3_spec.rb +32 -0
  228. data/spec/protocol4_read_instruction_examples.rb +142 -0
  229. data/spec/protocol4_spec.rb +58 -0
  230. data/spec/protocol5_spec.rb +68 -0
  231. data/spec/py_class_spec.rb +62 -0
  232. data/spec/py_object_spec.rb +149 -0
  233. data/spec/spec_helper.rb +3 -0
  234. data/spec/tuple_spec.rb +18 -0
  235. metadata +325 -0
@@ -0,0 +1,471 @@
1
+ require 'spec_helper'
2
+ require 'python/pickle'
3
+
4
+ describe Python::Pickle do
5
+ let(:fixtures_dir) { File.join(__dir__,'..','..','fixtures') }
6
+
7
+ describe ".parse" do
8
+ context "when given a Pickle protocol 2 stream" do
9
+ let(:io) { File.open(file) }
10
+
11
+ context "and it contains a serialized None" do
12
+ let(:file) { File.join(fixtures_dir,'none_v2.pkl') }
13
+
14
+ it "must return a Python::Pickle::Instructions::NONE" do
15
+ expect(subject.parse(io)).to eq(
16
+ [
17
+ Python::Pickle::Instructions::Proto.new(2),
18
+ Python::Pickle::Instructions::NONE,
19
+ Python::Pickle::Instructions::STOP
20
+ ]
21
+ )
22
+ end
23
+
24
+ context "and when a block is given" do
25
+ it "must yield each parsed instruction" do
26
+ expect {|b|
27
+ subject.parse(io,&b)
28
+ }.to yield_successive_args(
29
+ Python::Pickle::Instructions::Proto.new(2),
30
+ Python::Pickle::Instructions::NONE,
31
+ Python::Pickle::Instructions::STOP
32
+ )
33
+ end
34
+ end
35
+ end
36
+
37
+ context "and it contains a serialized True" do
38
+ let(:file) { File.join(fixtures_dir,'true_v2.pkl') }
39
+
40
+ it "must return a Python::Pickle::Instructions::Int containing a true value" do
41
+ expect(subject.parse(io)).to eq(
42
+ [
43
+ Python::Pickle::Instructions::Proto.new(2),
44
+ Python::Pickle::Instructions::NEWTRUE,
45
+ Python::Pickle::Instructions::STOP
46
+ ]
47
+ )
48
+ end
49
+
50
+ context "and when a block is given" do
51
+ it "must yield each parsed instruction" do
52
+ expect {|b|
53
+ subject.parse(io,&b)
54
+ }.to yield_successive_args(
55
+ Python::Pickle::Instructions::Proto.new(2),
56
+ Python::Pickle::Instructions::NEWTRUE,
57
+ Python::Pickle::Instructions::STOP
58
+ )
59
+ end
60
+ end
61
+ end
62
+
63
+ context "and it contains a serialized False" do
64
+ let(:file) { File.join(fixtures_dir,'false_v2.pkl') }
65
+
66
+ it "must return a Python::Pickle::Instructions::Int with a false value" do
67
+ expect(subject.parse(io)).to eq(
68
+ [
69
+ Python::Pickle::Instructions::Proto.new(2),
70
+ Python::Pickle::Instructions::NEWFALSE,
71
+ Python::Pickle::Instructions::STOP
72
+ ]
73
+ )
74
+ end
75
+
76
+ context "and when a block is given" do
77
+ it "must yield each parsed instruction" do
78
+ expect {|b|
79
+ subject.parse(io,&b)
80
+ }.to yield_successive_args(
81
+ Python::Pickle::Instructions::Proto.new(2),
82
+ Python::Pickle::Instructions::NEWFALSE,
83
+ Python::Pickle::Instructions::STOP
84
+ )
85
+ end
86
+ end
87
+ end
88
+
89
+ context "and it contains a serialized integer" do
90
+ let(:file) { File.join(fixtures_dir,'int_v2.pkl') }
91
+
92
+ it "must return a Python::Pickle::Instructions::BinInt1 with the decoded number" do
93
+ expect(subject.parse(io)).to eq(
94
+ [
95
+ Python::Pickle::Instructions::Proto.new(2),
96
+ Python::Pickle::Instructions::BinInt1.new(42),
97
+ Python::Pickle::Instructions::STOP
98
+ ]
99
+ )
100
+ end
101
+
102
+ context "and when a block is given" do
103
+ it "must yield each parsed instruction" do
104
+ expect {|b|
105
+ subject.parse(io,&b)
106
+ }.to yield_successive_args(
107
+ Python::Pickle::Instructions::Proto.new(2),
108
+ Python::Pickle::Instructions::BinInt1.new(42),
109
+ Python::Pickle::Instructions::STOP
110
+ )
111
+ end
112
+ end
113
+ end
114
+
115
+ context "and it contains a long integer" do
116
+ let(:file) { File.join(fixtures_dir,'long_v2.pkl') }
117
+
118
+ it "must return a Python::Pickle::Instructions::Long with the decoded number" do
119
+ expect(subject.parse(io)).to eq(
120
+ [
121
+ Python::Pickle::Instructions::Proto.new(2),
122
+ Python::Pickle::Instructions::Long1.new(9,18446744073709551615),
123
+ Python::Pickle::Instructions::STOP
124
+ ]
125
+ )
126
+ end
127
+
128
+ context "and when a block is given" do
129
+ it "must yield each parsed instruction" do
130
+ expect {|b|
131
+ subject.parse(io,&b)
132
+ }.to yield_successive_args(
133
+ Python::Pickle::Instructions::Proto.new(2),
134
+ Python::Pickle::Instructions::Long1.new(9,18446744073709551615),
135
+ Python::Pickle::Instructions::STOP
136
+ )
137
+ end
138
+ end
139
+ end
140
+
141
+ context "and it contains a serialized floating-point number" do
142
+ let(:float) { 3.141592653589793 }
143
+ let(:file) { File.join(fixtures_dir,'float_v2.pkl') }
144
+
145
+ it "must return a Python::Pickle::Instructions::BinFloat with the decoded number" do
146
+ expect(subject.parse(io)).to eq(
147
+ [
148
+ Python::Pickle::Instructions::Proto.new(2),
149
+ Python::Pickle::Instructions::BinFloat.new(float),
150
+ Python::Pickle::Instructions::STOP
151
+ ]
152
+ )
153
+ end
154
+
155
+ context "and when a block is given" do
156
+ it "must yield each parsed instruction" do
157
+ expect {|b|
158
+ subject.parse(io,&b)
159
+ }.to yield_successive_args(
160
+ Python::Pickle::Instructions::Proto.new(2),
161
+ Python::Pickle::Instructions::BinFloat.new(float),
162
+ Python::Pickle::Instructions::STOP
163
+ )
164
+ end
165
+ end
166
+ end
167
+
168
+ context "and it contains a plain string" do
169
+ let(:string) { "ABC" }
170
+ let(:length) { string.bytesize }
171
+ let(:file) { File.join(fixtures_dir,'str_v2.pkl') }
172
+
173
+ it "must return a Python::Pickle::Instructions::ShortBinString with the decoded number" do
174
+ expect(subject.parse(io)).to eq(
175
+ [
176
+ Python::Pickle::Instructions::Proto.new(2),
177
+ Python::Pickle::Instructions::ShortBinString.new(length,string),
178
+ Python::Pickle::Instructions::BinPut.new(0),
179
+ Python::Pickle::Instructions::STOP
180
+ ]
181
+ )
182
+ end
183
+
184
+ context "and when a block is given" do
185
+ it "must yield each parsed instruction" do
186
+ expect {|b|
187
+ subject.parse(io,&b)
188
+ }.to yield_successive_args(
189
+ Python::Pickle::Instructions::Proto.new(2),
190
+ Python::Pickle::Instructions::ShortBinString.new(length,string),
191
+ Python::Pickle::Instructions::BinPut.new(0),
192
+ Python::Pickle::Instructions::STOP
193
+ )
194
+ end
195
+ end
196
+ end
197
+
198
+ context "and it contains a string with backslash-escaped characters" do
199
+ let(:string) { "ABC\t\n\r\\'\"" }
200
+ let(:length) { string.bytesize }
201
+ let(:file) { File.join(fixtures_dir,'escaped_str_v2.pkl') }
202
+
203
+ it "must return a Python::Pickle::Instructions::ShortBinString with the decoded number" do
204
+ expect(subject.parse(io)).to eq(
205
+ [
206
+ Python::Pickle::Instructions::Proto.new(2),
207
+ Python::Pickle::Instructions::ShortBinString.new(length,string),
208
+ Python::Pickle::Instructions::BinPut.new(0),
209
+ Python::Pickle::Instructions::STOP
210
+ ]
211
+ )
212
+ end
213
+
214
+ context "and when a block is given" do
215
+ it "must yield each parsed instruction" do
216
+ expect {|b|
217
+ subject.parse(io,&b)
218
+ }.to yield_successive_args(
219
+ Python::Pickle::Instructions::Proto.new(2),
220
+ Python::Pickle::Instructions::ShortBinString.new(length,string),
221
+ Python::Pickle::Instructions::BinPut.new(0),
222
+ Python::Pickle::Instructions::STOP
223
+ )
224
+ end
225
+ end
226
+ end
227
+
228
+ context "and it contains a string with hex-escaped characters" do
229
+ let(:string) { (0..255).map(&:chr).join }
230
+ let(:length) { string.bytesize }
231
+ let(:file) { File.join(fixtures_dir,'bin_str_v2.pkl') }
232
+
233
+ it "must return a Python::Pickle::Instructions::BinString with the decoded number" do
234
+ expect(subject.parse(io)).to eq(
235
+ [
236
+ Python::Pickle::Instructions::Proto.new(2),
237
+ Python::Pickle::Instructions::BinString.new(length,string),
238
+ Python::Pickle::Instructions::BinPut.new(0),
239
+ Python::Pickle::Instructions::STOP
240
+ ]
241
+ )
242
+ end
243
+
244
+ context "and when a block is given" do
245
+ it "must yield each parsed instruction" do
246
+ expect {|b|
247
+ subject.parse(io,&b)
248
+ }.to yield_successive_args(
249
+ Python::Pickle::Instructions::Proto.new(2),
250
+ Python::Pickle::Instructions::BinString.new(length,string),
251
+ Python::Pickle::Instructions::BinPut.new(0),
252
+ Python::Pickle::Instructions::STOP
253
+ )
254
+ end
255
+ end
256
+ end
257
+
258
+ context "and it contains a UTF string" do
259
+ let(:string) { "ABC\u265E\u265F\u{1F600}" }
260
+ let(:length) { string.bytesize }
261
+ let(:file) { File.join(fixtures_dir,'unicode_str_v2.pkl') }
262
+
263
+ it "must return a Python::Pickle::Instructions::BinUnicode with the decoded number" do
264
+ expect(subject.parse(io)).to eq(
265
+ [
266
+ Python::Pickle::Instructions::Proto.new(2),
267
+ Python::Pickle::Instructions::BinUnicode.new(length,string),
268
+ Python::Pickle::Instructions::BinPut.new(0),
269
+ Python::Pickle::Instructions::STOP
270
+ ]
271
+ )
272
+ end
273
+
274
+ context "and when a block is given" do
275
+ it "must yield each parsed instruction" do
276
+ expect {|b|
277
+ subject.parse(io,&b)
278
+ }.to yield_successive_args(
279
+ Python::Pickle::Instructions::Proto.new(2),
280
+ Python::Pickle::Instructions::BinUnicode.new(length,string),
281
+ Python::Pickle::Instructions::BinPut.new(0),
282
+ Python::Pickle::Instructions::STOP
283
+ )
284
+ end
285
+ end
286
+ end
287
+
288
+ context "and it contains a list type" do
289
+ let(:file) { File.join(fixtures_dir,'list_v2.pkl') }
290
+
291
+ it "must return an Array of parsed instructions" do
292
+ expect(subject.parse(io)).to eq(
293
+ [
294
+ Python::Pickle::Instructions::Proto.new(2),
295
+ Python::Pickle::Instructions::EMPTY_LIST,
296
+ Python::Pickle::Instructions::BinPut.new(0),
297
+ Python::Pickle::Instructions::MARK,
298
+ Python::Pickle::Instructions::NONE,
299
+ Python::Pickle::Instructions::NEWTRUE,
300
+ Python::Pickle::Instructions::NEWFALSE,
301
+ Python::Pickle::Instructions::BinInt1.new(42),
302
+ Python::Pickle::Instructions::ShortBinString.new(3,"ABC"),
303
+ Python::Pickle::Instructions::BinPut.new(1),
304
+ Python::Pickle::Instructions::APPENDS,
305
+ Python::Pickle::Instructions::STOP
306
+ ]
307
+ )
308
+ end
309
+
310
+ context "and when a block is given" do
311
+ it "must yield each parsed instruction" do
312
+ expect {|b|
313
+ subject.parse(io,&b)
314
+ }.to yield_successive_args(
315
+ Python::Pickle::Instructions::Proto.new(2),
316
+ Python::Pickle::Instructions::EMPTY_LIST,
317
+ Python::Pickle::Instructions::BinPut.new(0),
318
+ Python::Pickle::Instructions::MARK,
319
+ Python::Pickle::Instructions::NONE,
320
+ Python::Pickle::Instructions::NEWTRUE,
321
+ Python::Pickle::Instructions::NEWFALSE,
322
+ Python::Pickle::Instructions::BinInt1.new(42),
323
+ Python::Pickle::Instructions::ShortBinString.new(3,"ABC"),
324
+ Python::Pickle::Instructions::BinPut.new(1),
325
+ Python::Pickle::Instructions::APPENDS,
326
+ Python::Pickle::Instructions::STOP
327
+ )
328
+ end
329
+ end
330
+ end
331
+
332
+ context "and it contains a dict type" do
333
+ let(:file) { File.join(fixtures_dir,'dict_v2.pkl') }
334
+
335
+ it "must return an Array of parsed instructions" do
336
+ expect(subject.parse(io)).to eq(
337
+ [
338
+ Python::Pickle::Instructions::Proto.new(2),
339
+ Python::Pickle::Instructions::EMPTY_DICT,
340
+ Python::Pickle::Instructions::BinPut.new(0),
341
+ Python::Pickle::Instructions::ShortBinString.new(3,"foo"),
342
+ Python::Pickle::Instructions::BinPut.new(1),
343
+ Python::Pickle::Instructions::ShortBinString.new(3,"bar"),
344
+ Python::Pickle::Instructions::BinPut.new(2),
345
+ Python::Pickle::Instructions::SETITEM,
346
+ Python::Pickle::Instructions::STOP
347
+ ]
348
+ )
349
+ end
350
+
351
+ context "and when a block is given" do
352
+ it "must yield each parsed instruction" do
353
+ expect {|b|
354
+ subject.parse(io,&b)
355
+ }.to yield_successive_args(
356
+ Python::Pickle::Instructions::Proto.new(2),
357
+ Python::Pickle::Instructions::EMPTY_DICT,
358
+ Python::Pickle::Instructions::BinPut.new(0),
359
+ Python::Pickle::Instructions::ShortBinString.new(3,"foo"),
360
+ Python::Pickle::Instructions::BinPut.new(1),
361
+ Python::Pickle::Instructions::ShortBinString.new(3,"bar"),
362
+ Python::Pickle::Instructions::BinPut.new(2),
363
+ Python::Pickle::Instructions::SETITEM,
364
+ Python::Pickle::Instructions::STOP
365
+ )
366
+ end
367
+ end
368
+ end
369
+
370
+ context "and it contains an object type" do
371
+ let(:file) { File.join(fixtures_dir,'object_v2.pkl') }
372
+
373
+ it "must return an Array of parsed instructions" do
374
+ expect(subject.parse(io)).to eq(
375
+ [
376
+ Python::Pickle::Instructions::Proto.new(2),
377
+ Python::Pickle::Instructions::Global.new('__main__','MyClass'),
378
+ Python::Pickle::Instructions::BinPut.new(0),
379
+ Python::Pickle::Instructions::EMPTY_TUPLE,
380
+ Python::Pickle::Instructions::NEWOBJ,
381
+ Python::Pickle::Instructions::BinPut.new(1),
382
+ Python::Pickle::Instructions::EMPTY_DICT,
383
+ Python::Pickle::Instructions::BinPut.new(2),
384
+ Python::Pickle::Instructions::MARK,
385
+ Python::Pickle::Instructions::ShortBinString.new(1,'y'),
386
+ Python::Pickle::Instructions::BinPut.new(3),
387
+ Python::Pickle::Instructions::BinInt1.new(66),
388
+ Python::Pickle::Instructions::ShortBinString.new(1,'x'),
389
+ Python::Pickle::Instructions::BinPut.new(4),
390
+ Python::Pickle::Instructions::BinInt1.new(65),
391
+ Python::Pickle::Instructions::SETITEMS,
392
+ Python::Pickle::Instructions::BUILD,
393
+ Python::Pickle::Instructions::STOP
394
+ ]
395
+ )
396
+ end
397
+
398
+ context "and when a block is given" do
399
+ it "must yield each parsed instruction" do
400
+ expect {|b|
401
+ subject.parse(io,&b)
402
+ }.to yield_successive_args(
403
+ Python::Pickle::Instructions::Proto.new(2),
404
+ Python::Pickle::Instructions::Global.new('__main__','MyClass'),
405
+ Python::Pickle::Instructions::BinPut.new(0),
406
+ Python::Pickle::Instructions::EMPTY_TUPLE,
407
+ Python::Pickle::Instructions::NEWOBJ,
408
+ Python::Pickle::Instructions::BinPut.new(1),
409
+ Python::Pickle::Instructions::EMPTY_DICT,
410
+ Python::Pickle::Instructions::BinPut.new(2),
411
+ Python::Pickle::Instructions::MARK,
412
+ Python::Pickle::Instructions::ShortBinString.new(1,'y'),
413
+ Python::Pickle::Instructions::BinPut.new(3),
414
+ Python::Pickle::Instructions::BinInt1.new(66),
415
+ Python::Pickle::Instructions::ShortBinString.new(1,'x'),
416
+ Python::Pickle::Instructions::BinPut.new(4),
417
+ Python::Pickle::Instructions::BinInt1.new(65),
418
+ Python::Pickle::Instructions::SETITEMS,
419
+ Python::Pickle::Instructions::BUILD,
420
+ Python::Pickle::Instructions::STOP
421
+ )
422
+ end
423
+ end
424
+ end
425
+
426
+ context "and it contains a bytearray type" do
427
+ let(:file) { File.join(fixtures_dir,'bytearray_v2.pkl') }
428
+
429
+ it "must return an Array of parsed instructions" do
430
+ expect(subject.parse(io)).to eq(
431
+ [
432
+ Python::Pickle::Instructions::Proto.new(2),
433
+ Python::Pickle::Instructions::Global.new('__builtin__','bytearray'),
434
+ Python::Pickle::Instructions::BinPut.new(0),
435
+ Python::Pickle::Instructions::BinUnicode.new(3,'ABC'),
436
+ Python::Pickle::Instructions::BinPut.new(1),
437
+ Python::Pickle::Instructions::ShortBinString.new(7,'latin-1'),
438
+ Python::Pickle::Instructions::BinPut.new(2),
439
+ Python::Pickle::Instructions::TUPLE2,
440
+ Python::Pickle::Instructions::BinPut.new(3),
441
+ Python::Pickle::Instructions::REDUCE,
442
+ Python::Pickle::Instructions::BinPut.new(4),
443
+ Python::Pickle::Instructions::STOP
444
+ ]
445
+ )
446
+ end
447
+
448
+ context "and when a block is given" do
449
+ it "must yield each parsed instruction" do
450
+ expect {|b|
451
+ subject.parse(io,&b)
452
+ }.to yield_successive_args(
453
+ Python::Pickle::Instructions::Proto.new(2),
454
+ Python::Pickle::Instructions::Global.new('__builtin__','bytearray'),
455
+ Python::Pickle::Instructions::BinPut.new(0),
456
+ Python::Pickle::Instructions::BinUnicode.new(3,'ABC'),
457
+ Python::Pickle::Instructions::BinPut.new(1),
458
+ Python::Pickle::Instructions::ShortBinString.new(7,'latin-1'),
459
+ Python::Pickle::Instructions::BinPut.new(2),
460
+ Python::Pickle::Instructions::TUPLE2,
461
+ Python::Pickle::Instructions::BinPut.new(3),
462
+ Python::Pickle::Instructions::REDUCE,
463
+ Python::Pickle::Instructions::BinPut.new(4),
464
+ Python::Pickle::Instructions::STOP
465
+ )
466
+ end
467
+ end
468
+ end
469
+ end
470
+ end
471
+ end