hexdump 0.3.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +5 -6
  3. data/.gitignore +1 -0
  4. data/.yardopts +1 -1
  5. data/ChangeLog.md +79 -6
  6. data/Gemfile +3 -0
  7. data/LICENSE.txt +1 -1
  8. data/README.md +500 -137
  9. data/benchmark.rb +29 -22
  10. data/gemspec.yml +2 -1
  11. data/hexdump.gemspec +1 -4
  12. data/lib/hexdump/chars.rb +46 -0
  13. data/lib/hexdump/core_ext/file.rb +68 -6
  14. data/lib/hexdump/core_ext/io.rb +2 -2
  15. data/lib/hexdump/core_ext/kernel.rb +5 -0
  16. data/lib/hexdump/core_ext/string.rb +2 -2
  17. data/lib/hexdump/core_ext/string_io.rb +2 -2
  18. data/lib/hexdump/core_ext.rb +5 -4
  19. data/lib/hexdump/format_string.rb +43 -0
  20. data/lib/hexdump/hexdump.rb +766 -75
  21. data/lib/hexdump/mixin.rb +192 -0
  22. data/lib/hexdump/module_methods.rb +132 -0
  23. data/lib/hexdump/numeric/binary.rb +55 -0
  24. data/lib/hexdump/numeric/char_or_int.rb +95 -0
  25. data/lib/hexdump/numeric/decimal.rb +56 -0
  26. data/lib/hexdump/numeric/exceptions.rb +11 -0
  27. data/lib/hexdump/numeric/hexadecimal.rb +59 -0
  28. data/lib/hexdump/numeric/octal.rb +55 -0
  29. data/lib/hexdump/numeric.rb +5 -0
  30. data/lib/hexdump/reader.rb +313 -0
  31. data/lib/hexdump/theme/ansi.rb +82 -0
  32. data/lib/hexdump/theme/rule.rb +159 -0
  33. data/lib/hexdump/theme.rb +61 -0
  34. data/lib/hexdump/type.rb +233 -0
  35. data/lib/hexdump/types.rb +108 -0
  36. data/lib/hexdump/version.rb +1 -1
  37. data/lib/hexdump.rb +14 -3
  38. data/spec/chars_spec.rb +76 -0
  39. data/spec/core_ext_spec.rb +10 -6
  40. data/spec/format_string_spec.rb +22 -0
  41. data/spec/hexdump_class_spec.rb +1708 -0
  42. data/spec/hexdump_module_spec.rb +23 -0
  43. data/spec/mixin_spec.rb +37 -0
  44. data/spec/numeric/binary_spec.rb +239 -0
  45. data/spec/numeric/char_or_int_spec.rb +210 -0
  46. data/spec/numeric/decimal_spec.rb +317 -0
  47. data/spec/numeric/hexadecimal_spec.rb +320 -0
  48. data/spec/numeric/octal_spec.rb +239 -0
  49. data/spec/reader_spec.rb +866 -0
  50. data/spec/spec_helper.rb +2 -0
  51. data/spec/theme/ansi_spec.rb +242 -0
  52. data/spec/theme/rule_spec.rb +199 -0
  53. data/spec/theme_spec.rb +94 -0
  54. data/spec/type_spec.rb +317 -0
  55. data/spec/types_spec.rb +904 -0
  56. metadata +42 -12
  57. data/.gemtest +0 -0
  58. data/lib/hexdump/dumper.rb +0 -419
  59. data/lib/hexdump/extensions.rb +0 -2
  60. data/spec/dumper_spec.rb +0 -329
  61. data/spec/hexdump_spec.rb +0 -30
@@ -0,0 +1,866 @@
1
+ require 'spec_helper'
2
+ require 'hexdump/reader'
3
+ require 'hexdump/types'
4
+
5
+ describe Hexdump::Reader do
6
+ describe "#initialize" do
7
+ let(:type) { Hexdump::TYPES[:uint8] }
8
+
9
+ subject { described_class.new(type) }
10
+
11
+ it "must set #type" do
12
+ expect(subject.type).to eq(type)
13
+ end
14
+
15
+ it "must default #offset to nil" do
16
+ expect(subject.offset).to be(nil)
17
+ end
18
+
19
+ it "must default #length to nil" do
20
+ expect(subject.length).to be(nil)
21
+ end
22
+
23
+ it "must default #zero_pad? to false" do
24
+ expect(subject.zero_pad?).to be(false)
25
+ end
26
+
27
+ context "when offset: is given" do
28
+ let(:offset) { 2 }
29
+
30
+ subject { described_class.new(type, offset: offset) }
31
+
32
+ it "must set #offset" do
33
+ expect(subject.offset).to eq(offset)
34
+ end
35
+ end
36
+
37
+ context "when length: is given" do
38
+ let(:length) { 256 }
39
+
40
+ subject { described_class.new(type, length: length) }
41
+
42
+ it "must set #length" do
43
+ expect(subject.length).to eq(length)
44
+ end
45
+ end
46
+
47
+ context "when zero_pad: is true" do
48
+ subject { described_class.new(type, zero_pad: true) }
49
+
50
+ it "must enable #zero_pad?" do
51
+ expect(subject.zero_pad?).to be(true)
52
+ end
53
+ end
54
+ end
55
+
56
+ let(:type) { Hexdump::TYPES[:byte] }
57
+
58
+ subject { described_class.new(type) }
59
+
60
+ describe "#each_byte" do
61
+ let(:type) { Hexdump::TYPES[:uint8] }
62
+
63
+ let(:chars) { %w[A B C D] }
64
+ let(:data) { chars.join }
65
+ let(:bytes) { data.bytes }
66
+
67
+ it "must yield each byte from the given data" do
68
+ expect { |b|
69
+ subject.each_byte(data,&b)
70
+ }.to yield_successive_args(*bytes)
71
+ end
72
+
73
+ context "when #offset is > 0" do
74
+ let(:offset) { 2 }
75
+ let(:bytes) { data.bytes[offset..-1] }
76
+
77
+ subject { described_class.new(type, offset: offset) }
78
+
79
+ it "must offset the first N bytes before yielding any bytes" do
80
+ expect { |b|
81
+ subject.each_byte(data,&b)
82
+ }.to yield_successive_args(*bytes)
83
+ end
84
+ end
85
+
86
+ context "when #length is set" do
87
+ let(:length) { 3 }
88
+ let(:bytes) { data.bytes[0,length] }
89
+
90
+ subject { described_class.new(type, length: length) }
91
+
92
+ it "must read at most N bytes" do
93
+ expect { |b|
94
+ subject.each_byte(data,&b)
95
+ }.to yield_successive_args(*bytes)
96
+ end
97
+ end
98
+
99
+ context "when no block is given" do
100
+ it "must return an Enumerator" do
101
+ expect(subject.each_byte(data)).to be_kind_of(Enumerator)
102
+ end
103
+ end
104
+ end
105
+
106
+ describe "#each_slice" do
107
+ context "when type has size of 1" do
108
+ let(:type) { Hexdump::TYPES[:int8] }
109
+ let(:chars) { %w[A B C D] }
110
+ let(:data) { "ABCD" }
111
+
112
+ it "must yield each consequetize character" do
113
+ expect { |b|
114
+ subject.each_slice(data,&b)
115
+ }.to yield_successive_args(*chars)
116
+ end
117
+
118
+ context "and when #offset is > 0" do
119
+ let(:offset) { 2 }
120
+ let(:chars) { %w[C D] }
121
+
122
+ subject { described_class.new(type, offset: offset) }
123
+
124
+ it "must offset the first N bytes before reading each character" do
125
+ expect { |b|
126
+ subject.each_slice(data,&b)
127
+ }.to yield_successive_args(*chars)
128
+ end
129
+ end
130
+
131
+ context "and when #length is set" do
132
+ let(:length) { 3 }
133
+ let(:chars) { %w[A B C] }
134
+
135
+ subject { described_class.new(type, length: length) }
136
+
137
+ it "must read at most N bytes" do
138
+ expect { |b|
139
+ subject.each_slice(data,&b)
140
+ }.to yield_successive_args(*chars)
141
+ end
142
+ end
143
+ end
144
+
145
+ context "when type has size > 1" do
146
+ let(:type) { Hexdump::TYPES[:int16] }
147
+ let(:slices) { %w[AA BB CC DD EE FF] }
148
+ let(:data) { "AABBCCDDEEFF" }
149
+
150
+ it "must yield each slice of the String" do
151
+ expect { |b|
152
+ subject.each_slice(data,&b)
153
+ }.to yield_successive_args(*slices)
154
+ end
155
+
156
+ it "must yield a new String instance for each slice" do
157
+ yielded_object_ids = []
158
+
159
+ subject.each_slice(data) do |slice|
160
+ yielded_object_ids << slice.object_id
161
+ end
162
+
163
+ expect(yielded_object_ids.uniq).to eq(yielded_object_ids)
164
+ end
165
+
166
+ context "and when #offset is > 0" do
167
+ let(:offset) { 3 }
168
+ let(:slices) { %w[BC CD DE EF F] }
169
+
170
+ subject { described_class.new(type, offset: offset) }
171
+
172
+ it "must offset the first N bytes before reading each slice" do
173
+ expect { |b|
174
+ subject.each_slice(data,&b)
175
+ }.to yield_successive_args(*slices)
176
+ end
177
+ end
178
+
179
+ context "and when #length is set" do
180
+ let(:length) { 7 }
181
+ let(:slices) { %w[AA BB CC D] }
182
+
183
+ subject { described_class.new(type, length: length) }
184
+
185
+ it "must read at most N bytes" do
186
+ expect { |b|
187
+ subject.each_slice(data,&b)
188
+ }.to yield_successive_args(*slices)
189
+ end
190
+ end
191
+
192
+ context "when the given data is not evenly divisible by the type's size" do
193
+ let(:type) { Hexdump::TYPES[:int32] }
194
+ let(:slices) { %w[AABB CCDD E] }
195
+ let(:data) { "AABBCCDDE" }
196
+
197
+ it "must yield the reamining data" do
198
+ expect { |b|
199
+ subject.each_slice(data,&b)
200
+ }.to yield_successive_args('AABB', 'CCDD', "E")
201
+ end
202
+
203
+ context "but #zero_pad? is true" do
204
+ subject { described_class.new(type, zero_pad: true) }
205
+
206
+ it "must zero out the rest of the buffer" do
207
+ expect { |b|
208
+ subject.each_slice(data,&b)
209
+ }.to yield_successive_args('AABB', 'CCDD', "E\0\0\0")
210
+ end
211
+ end
212
+ end
213
+ end
214
+ end
215
+
216
+ describe "#each_uint" do
217
+ context "when the type has size of 1" do
218
+ let(:bytes) { [0x41, 0x42, 0x43, 0x44] }
219
+ let(:raw) { bytes.map(&:chr) }
220
+ let(:data) { raw.join }
221
+ let(:type) { Hexdump::TYPES[:uint8] }
222
+
223
+ it "must yield each byte" do
224
+ expect { |b|
225
+ subject.each_uint(data,&b)
226
+ }.to yield_successive_args(*raw.zip(bytes))
227
+ end
228
+ end
229
+
230
+ context "when the type has size of 2" do
231
+ let(:uints) { [0xfa01, 0xfb02, 0xfc03, 0xfd04] }
232
+
233
+ context "when the type is little-endian" do
234
+ let(:type) { Hexdump::TYPES[:uint16_le] }
235
+ let(:raw) { uints.map { |uint| [uint].pack('S<') } }
236
+ let(:data) { raw.join }
237
+
238
+ it "must decode the bytes in little-endian order" do
239
+ expect { |b|
240
+ subject.each_uint(data,&b)
241
+ }.to yield_successive_args(*raw.zip(uints))
242
+ end
243
+
244
+ context "but there is not enough bytes to decode a value" do
245
+ let(:data) { "\x11".encode(Encoding::BINARY) }
246
+
247
+ it "must yield remaining bytes and nil" do
248
+ expect { |b|
249
+ subject.each_uint(data,&b)
250
+ }.to yield_with_args(data,nil)
251
+ end
252
+
253
+ context "but #zero_pad? is true" do
254
+ subject { described_class.new(type, zero_pad: true) }
255
+
256
+ it "must yield the zero-padded data and partially decoded uint" do
257
+ expect { |b|
258
+ subject.each_uint(data,&b)
259
+ }.to yield_with_args("#{data}\x00",0x0011)
260
+ end
261
+ end
262
+ end
263
+ end
264
+
265
+ context "when the type is big-endian" do
266
+ let(:type) { Hexdump::TYPES[:uint16_be] }
267
+ let(:raw) { uints.map { |uint| [uint].pack('S>') } }
268
+ let(:data) { raw.join }
269
+
270
+ it "must decode the bytes in big-endian order" do
271
+ expect { |b|
272
+ subject.each_uint(data,&b)
273
+ }.to yield_successive_args(*raw.zip(uints))
274
+ end
275
+
276
+ context "but there is not enough bytes to decode a value" do
277
+ let(:data) { "\x11".encode(Encoding::BINARY) }
278
+
279
+ it "must yield remaining bytes and nil" do
280
+ expect { |b|
281
+ subject.each_uint(data,&b)
282
+ }.to yield_with_args(data,nil)
283
+ end
284
+
285
+ context "but #zero_pad? is true" do
286
+ subject { described_class.new(type, zero_pad: true) }
287
+
288
+ it "must yield the zero-padded data and partially decoded uint" do
289
+ expect { |b|
290
+ subject.each_uint(data,&b)
291
+ }.to yield_with_args("#{data}\x00",0x1100)
292
+ end
293
+ end
294
+ end
295
+ end
296
+ end
297
+
298
+ context "when the type has size of 4" do
299
+ let(:uints) { [0xffeedd01, 0xffccbb02, 0xffaa9903, 0xff887704] }
300
+
301
+ context "when the type is little-endian" do
302
+ let(:type) { Hexdump::TYPES[:uint32_le] }
303
+ let(:raw) { uints.map { |uint| [uint].pack('L<') } }
304
+ let(:data) { raw.join }
305
+
306
+ it "must decode the bytes in little-endian order" do
307
+ expect { |b|
308
+ subject.each_uint(data,&b)
309
+ }.to yield_successive_args(*raw.zip(uints))
310
+ end
311
+
312
+ context "but there is not enough bytes to decode a value" do
313
+ let(:data) { "\x11\x22\x33".encode(Encoding::BINARY) }
314
+
315
+ it "must yield nil and the remaining bytes" do
316
+ expect { |b|
317
+ subject.each_uint(data,&b)
318
+ }.to yield_with_args(data,nil)
319
+ end
320
+
321
+ context "but #zero_pad? is true" do
322
+ subject { described_class.new(type, zero_pad: true) }
323
+
324
+ it "must yield the zero-padded data and partially decoded uint" do
325
+ expect { |b|
326
+ subject.each_uint(data,&b)
327
+ }.to yield_with_args("#{data}\x00",0x00332211)
328
+ end
329
+ end
330
+ end
331
+ end
332
+
333
+ context "when the type is big-endian" do
334
+ let(:type) { Hexdump::TYPES[:uint32_be] }
335
+ let(:raw) { uints.map { |uint| [uint].pack('L>') } }
336
+ let(:data) { raw.join }
337
+
338
+ it "must decode the bytes in big-endian order" do
339
+ expect { |b|
340
+ subject.each_uint(data,&b)
341
+ }.to yield_successive_args(*raw.zip(uints))
342
+ end
343
+
344
+ context "but there is not enough bytes to decode a value" do
345
+ let(:data) { "\x11\x22\x33".encode(Encoding::BINARY) }
346
+
347
+ it "must yield the remaining bytes and nil" do
348
+ expect { |b|
349
+ subject.each_uint(data,&b)
350
+ }.to yield_with_args(data,nil)
351
+ end
352
+
353
+ context "but #zero_pad? is true" do
354
+ subject { described_class.new(type, zero_pad: true) }
355
+
356
+ it "must yield the zero-padded data and partially decoded uint" do
357
+ expect { |b|
358
+ subject.each_uint(data,&b)
359
+ }.to yield_with_args("#{data}\x00",0x11223300)
360
+ end
361
+ end
362
+ end
363
+ end
364
+ end
365
+
366
+ context "when the type has size of 8" do
367
+ let(:uints) { [0xffffffff11223344, 0xffffffff55667788, 0xffffffff99aabbcc, 0xffffffffddeeff00] }
368
+
369
+ context "when the type is little-endian" do
370
+ let(:type) { Hexdump::TYPES[:uint64_le] }
371
+ let(:raw) { uints.map { |uint| [uint].pack('Q<') } }
372
+ let(:data) { raw.join }
373
+
374
+ it "must decode the bytes in little-endian order" do
375
+ expect { |b|
376
+ subject.each_uint(data,&b)
377
+ }.to yield_successive_args(*raw.zip(uints))
378
+ end
379
+
380
+ context "but there is not enough bytes to decode a value" do
381
+ let(:data) { "\x11\x22\x33\x44\x55\x66\x77".encode(Encoding::BINARY) }
382
+
383
+ it "must yield the remaining bytes and nil" do
384
+ expect { |b|
385
+ subject.each_uint(data,&b)
386
+ }.to yield_with_args(data,nil)
387
+ end
388
+
389
+ context "but #zero_pad? is true" do
390
+ subject { described_class.new(type, zero_pad: true) }
391
+
392
+ it "must yield the zero-padded data and partially decoded uint" do
393
+ expect { |b|
394
+ subject.each_uint(data,&b)
395
+ }.to yield_with_args("#{data}\x00",0x0077665544332211)
396
+ end
397
+ end
398
+ end
399
+ end
400
+
401
+ context "when the type is big-endian" do
402
+ let(:type) { Hexdump::TYPES[:uint64_be] }
403
+ let(:raw) { uints.map { |uint| [uint].pack('Q>') } }
404
+ let(:data) { raw.join }
405
+
406
+ it "must decode the bytes in big-endian order" do
407
+ expect { |b|
408
+ subject.each_uint(data,&b)
409
+ }.to yield_successive_args(*raw.zip(uints))
410
+ end
411
+
412
+ context "but there is not enough bytes to decode a value" do
413
+ let(:data) { "\x11\x22\x33\x44\x55\x66\x77".encode(Encoding::BINARY) }
414
+
415
+ it "must yield the remaining bytes and nil" do
416
+ expect { |b|
417
+ subject.each_uint(data,&b)
418
+ }.to yield_with_args(data,nil)
419
+ end
420
+
421
+ context "but #zero_pad? is true" do
422
+ subject { described_class.new(type, zero_pad: true) }
423
+
424
+ it "must yield the zero-padded data and partially decoded uint" do
425
+ expect { |b|
426
+ subject.each_uint(data,&b)
427
+ }.to yield_with_args("#{data}\x00",0x1122334455667700)
428
+ end
429
+ end
430
+ end
431
+ end
432
+ end
433
+
434
+ context "when the given data does not define #each_byte" do
435
+ it do
436
+ expect {
437
+ subject.each_uint(Object.new).to_a
438
+ }.to raise_error(ArgumentError)
439
+ end
440
+ end
441
+ end
442
+
443
+ describe "#each_int" do
444
+ context "when the type has size of 1" do
445
+ let(:ints) { [0x01, -0x02, 0x03, -0x04] }
446
+ let(:type) { Hexdump::TYPES[:int8] }
447
+ let(:raw) { ints.map { |int| [int].pack('c') } }
448
+ let(:data) { raw.join }
449
+
450
+ it "must decode the bytes" do
451
+ expect { |b|
452
+ subject.each_int(data,&b)
453
+ }.to yield_successive_args(*raw.zip(ints))
454
+ end
455
+ end
456
+
457
+ context "when the type has size of 2" do
458
+ let(:ints) { [0x0001, -0x0002, 0x0003, -0x0004] }
459
+
460
+ context "when the type is little-endian" do
461
+ let(:type) { Hexdump::TYPES[:int16_le] }
462
+ let(:raw) { ints.map { |int| [int].pack('s<') } }
463
+ let(:data) { raw.join }
464
+
465
+ it "must decode the bytes in little-endian order" do
466
+ expect { |b|
467
+ subject.each_int(data,&b)
468
+ }.to yield_successive_args(*raw.zip(ints))
469
+ end
470
+
471
+ context "but there is not enough bytes to decode a value" do
472
+ let(:data) { "\x11".encode(Encoding::BINARY) }
473
+
474
+ it "must yield the remaining bytes and nil" do
475
+ expect { |b|
476
+ subject.each_int(data,&b)
477
+ }.to yield_with_args(data, nil)
478
+ end
479
+
480
+ context "but #zero_pad? is true" do
481
+ subject { described_class.new(type, zero_pad: true) }
482
+
483
+ it "must yield the zero-padded data and partially decoded int" do
484
+ expect { |b|
485
+ subject.each_int(data,&b)
486
+ }.to yield_with_args("#{data}\x00",0x11)
487
+ end
488
+ end
489
+ end
490
+ end
491
+
492
+ context "when the type is big-endian" do
493
+ let(:type) { Hexdump::TYPES[:int16_be] }
494
+ let(:raw) { ints.map { |int| [int].pack('s>') } }
495
+ let(:data) { raw.join }
496
+
497
+ it "must decode the bytes in big-endian order" do
498
+ expect { |b|
499
+ subject.each_int(data,&b)
500
+ }.to yield_successive_args(*raw.zip(ints))
501
+ end
502
+
503
+ context "but there is not enough bytes to decode a value" do
504
+ let(:data) { "\x11".encode(Encoding::BINARY) }
505
+
506
+ it "must yield the remaining bytes and nil" do
507
+ expect { |b|
508
+ subject.each_int(data,&b)
509
+ }.to yield_with_args(data, nil)
510
+ end
511
+
512
+ context "but #zero_pad? is true" do
513
+ subject { described_class.new(type, zero_pad: true) }
514
+
515
+ it "must yield the zero-padded data and partially decoded int" do
516
+ expect { |b|
517
+ subject.each_int(data,&b)
518
+ }.to yield_with_args("#{data}\x00",0x1100)
519
+ end
520
+ end
521
+ end
522
+ end
523
+ end
524
+
525
+ context "when the type has size of 4" do
526
+ let(:ints) { [0x00aa0001, -0x00bb0002, 0x00cc0003, -0x00dd0004] }
527
+
528
+ context "when the type is little-endian" do
529
+ let(:type) { Hexdump::TYPES[:int32_le] }
530
+ let(:raw) { ints.map { |int| [int].pack('l<') } }
531
+ let(:data) { raw.join }
532
+
533
+ it "must decode the bytes in little-endian order" do
534
+ expect { |b|
535
+ subject.each_int(data,&b)
536
+ }.to yield_successive_args(*raw.zip(ints))
537
+ end
538
+
539
+ context "but there is not enough bytes to decode a value" do
540
+ let(:data) { "\x11\x22\x33".encode(Encoding::BINARY) }
541
+
542
+ it "must yield the remaining bytes and nil" do
543
+ expect { |b|
544
+ subject.each_int(data,&b)
545
+ }.to yield_with_args(data, nil)
546
+ end
547
+
548
+ context "but #zero_pad? is true" do
549
+ subject { described_class.new(type, zero_pad: true) }
550
+
551
+ it "must yield the zero-padded data and partially decoded int" do
552
+ expect { |b|
553
+ subject.each_int(data,&b)
554
+ }.to yield_with_args("#{data}\x00",0x00332211)
555
+ end
556
+ end
557
+ end
558
+ end
559
+
560
+ context "when the type is big-endian" do
561
+ let(:type) { Hexdump::TYPES[:int32_be] }
562
+ let(:raw) { ints.map { |int| [int].pack('l>') } }
563
+ let(:data) { raw.join }
564
+
565
+ it "must decode the bytes in big-endian order" do
566
+ expect { |b|
567
+ subject.each_int(data,&b)
568
+ }.to yield_successive_args(*raw.zip(ints))
569
+ end
570
+
571
+ context "but there is not enough bytes to decode a value" do
572
+ let(:data) { "\x11\x22\x33".encode(Encoding::BINARY) }
573
+
574
+ it "must yield the remaining bytes and nil" do
575
+ expect { |b|
576
+ subject.each_int(data,&b)
577
+ }.to yield_with_args(data, nil)
578
+ end
579
+
580
+ context "but #zero_pad? is true" do
581
+ subject { described_class.new(type, zero_pad: true) }
582
+
583
+ it "must yield the zero-padded data and partially decoded int" do
584
+ expect { |b|
585
+ subject.each_int(data,&b)
586
+ }.to yield_with_args("#{data}\x00",0x11223300)
587
+ end
588
+ end
589
+ end
590
+ end
591
+ end
592
+
593
+ context "when the type has size of 8" do
594
+ let(:ints) { [0x1122334400aa0001, -0x1122334400bb0002, 0x1122334400cc0003, -0x1122334400dd0004] }
595
+
596
+ context "when the type is little-endian" do
597
+ let(:type) { Hexdump::TYPES[:int64_le] }
598
+ let(:raw) { ints.map { |int| [int].pack('q<') } }
599
+ let(:data) { raw.join }
600
+
601
+ it "must decode the bytes in little-endian order" do
602
+ expect { |b|
603
+ subject.each_int(data,&b)
604
+ }.to yield_successive_args(*raw.zip(ints))
605
+ end
606
+
607
+ context "but there is not enough bytes to decode a value" do
608
+ let(:data) { "\x11\x22\x33\x44\x55\x66\x77".encode(Encoding::BINARY) }
609
+
610
+ it "must yield the remaining bytes and nil" do
611
+ expect { |b|
612
+ subject.each_int(data,&b)
613
+ }.to yield_with_args(data, nil)
614
+ end
615
+
616
+ context "but #zero_pad? is true" do
617
+ subject { described_class.new(type, zero_pad: true) }
618
+
619
+ it "must yield the zero-padded data and partially decoded int" do
620
+ expect { |b|
621
+ subject.each_int(data,&b)
622
+ }.to yield_with_args("#{data}\x00",0x0077665544332211)
623
+ end
624
+ end
625
+ end
626
+ end
627
+
628
+ context "when the type is big-endian" do
629
+ let(:type) { Hexdump::TYPES[:int64_be] }
630
+ let(:raw) { ints.map { |int| [int].pack('q>') } }
631
+ let(:data) { raw.join }
632
+
633
+ it "must decode the bytes in big-endian order" do
634
+ expect { |b|
635
+ subject.each_int(data,&b)
636
+ }.to yield_successive_args(*raw.zip(ints))
637
+ end
638
+
639
+ context "but there is not enough bytes to decode a value" do
640
+ let(:data) { "\x11\x22\x33\x44\x55\x66\x77".encode(Encoding::BINARY) }
641
+
642
+ it "must yield nil and the remaining bytes" do
643
+ expect { |b|
644
+ subject.each_int(data,&b)
645
+ }.to yield_with_args(data, nil)
646
+ end
647
+
648
+ context "but #zero_pad? is true" do
649
+ subject { described_class.new(type, zero_pad: true) }
650
+
651
+ it "must yield the zero-padded data and partially decoded int" do
652
+ expect { |b|
653
+ subject.each_int(data,&b)
654
+ }.to yield_with_args("#{data}\x00",0x1122334455667700)
655
+ end
656
+ end
657
+ end
658
+ end
659
+ end
660
+
661
+ context "when the given data does not define #each_byte" do
662
+ it do
663
+ expect {
664
+ subject.each_int(Object.new).to_a
665
+ }.to raise_error(ArgumentError)
666
+ end
667
+ end
668
+ end
669
+
670
+ describe "#each_float" do
671
+ let(:type) { Hexdump::TYPES[:float] }
672
+
673
+ context "when the type has size of 4" do
674
+ let(:floats) { [1.0, -3.0, 5.0, -7.0, 9.0] }
675
+
676
+ context "when the type is little-endian" do
677
+ let(:type) { Hexdump::TYPES[:float_le] }
678
+ let(:raw) { floats.map { |float| [float].pack('e') } }
679
+ let(:data) { raw.join }
680
+
681
+ it "must decode the bytes in little-endian order" do
682
+ expect { |b|
683
+ subject.each_float(data,&b)
684
+ }.to yield_successive_args(*raw.zip(floats))
685
+ end
686
+
687
+ context "but there is not enough bytes to decode a value" do
688
+ let(:data) { "\x01\x02\x03".encode(Encoding::BINARY) }
689
+
690
+ it "must yield the remaining bytes and nil" do
691
+ expect { |b|
692
+ subject.each_float(data,&b)
693
+ }.to yield_with_args(data, nil)
694
+ end
695
+
696
+ context "but #zero_pad? is true" do
697
+ subject { described_class.new(type, zero_pad: true) }
698
+
699
+ it "must yield the zero-padded data and partially decoded float" do
700
+ expect { |b|
701
+ subject.each_float(data,&b)
702
+ }.to yield_with_args("#{data}\x00",2.7622535458617227e-40)
703
+ end
704
+ end
705
+ end
706
+ end
707
+
708
+ context "when the type is big-endian" do
709
+ let(:type) { Hexdump::TYPES[:float_be] }
710
+ let(:raw) { floats.map { |float| [float].pack('g') } }
711
+ let(:data) { raw.join }
712
+
713
+ it "must decode the bytes in big-endian order" do
714
+ expect { |b|
715
+ subject.each_float(data,&b)
716
+ }.to yield_successive_args(*raw.zip(floats))
717
+ end
718
+
719
+ context "but there is not enough bytes to decode a value" do
720
+ let(:data) { "\x01\x02\x03".encode(Encoding::BINARY) }
721
+
722
+ it "must yield the remaining bytes and nil" do
723
+ expect { |b|
724
+ subject.each_float(data,&b)
725
+ }.to yield_with_args(data, nil)
726
+ end
727
+
728
+ context "but #zero_pad? is true" do
729
+ subject { described_class.new(type, zero_pad: true) }
730
+
731
+ it "must yield the zero-padded data and partially decoded float" do
732
+ expect { |b|
733
+ subject.each_float(data,&b)
734
+ }.to yield_with_args("#{data}\x00",2.387938139551892e-38)
735
+ end
736
+ end
737
+ end
738
+ end
739
+ end
740
+
741
+ context "when the type has size of 8" do
742
+ let(:floats) { [1.2, -3.4, 5.6, -7.8, 9.0] }
743
+
744
+ context "when the type is little-endian" do
745
+ let(:type) { Hexdump::TYPES[:double_le] }
746
+ let(:raw) { floats.map { |float| [float].pack('E') } }
747
+ let(:data) { raw.join }
748
+
749
+ it "must decode the bytes in little-endian order" do
750
+ expect { |b|
751
+ subject.each_float(data,&b)
752
+ }.to yield_successive_args(*raw.zip(floats))
753
+ end
754
+
755
+ context "but there is not enough bytes to decode a value" do
756
+ let(:data) { "\x01\x02\x03\x04\x05\x06\x07".encode(Encoding::BINARY) }
757
+
758
+ it "must yield the remaining bytes and nil" do
759
+ expect { |b|
760
+ subject.each_float(data,&b)
761
+ }.to yield_with_args(data, nil)
762
+ end
763
+
764
+ context "but #zero_pad? is true" do
765
+ subject { described_class.new(type, zero_pad: true) }
766
+
767
+ it "must yield the zero-padded data and partially decoded float" do
768
+ expect { |b|
769
+ subject.each_float(data,&b)
770
+ }.to yield_with_args("#{data}\x00",9.76739841864353e-309)
771
+ end
772
+ end
773
+ end
774
+ end
775
+
776
+ context "when the type is big-endian" do
777
+ let(:type) { Hexdump::TYPES[:double_be] }
778
+ let(:raw) { floats.map { |float| [float].pack('G') } }
779
+ let(:data) { raw.join }
780
+
781
+ it "must decode the bytes in big-endian order" do
782
+ expect { |b|
783
+ subject.each_float(data,&b)
784
+ }.to yield_successive_args(*raw.zip(floats))
785
+ end
786
+
787
+ context "but there is not enough bytes to decode a value" do
788
+ let(:data) { "\x01\x02\x03\x04\x05\x06\x07".encode(Encoding::BINARY) }
789
+
790
+ it "must yield the remaining bytes and nil" do
791
+ expect { |b|
792
+ subject.each_float(data,&b)
793
+ }.to yield_with_args(data, nil)
794
+ end
795
+
796
+ context "but #zero_pad? is true" do
797
+ subject { described_class.new(type, zero_pad: true) }
798
+
799
+ it "must yield the zero-padded data and partially decoded float" do
800
+ expect { |b|
801
+ subject.each_float(data,&b)
802
+ }.to yield_with_args("#{data}\x00",8.207880399131826e-304)
803
+ end
804
+ end
805
+ end
806
+ end
807
+ end
808
+
809
+ context "when the given data does not define #each_byte" do
810
+ it do
811
+ expect {
812
+ subject.each_float(Object.new).to_a
813
+ }.to raise_error(ArgumentError)
814
+ end
815
+ end
816
+ end
817
+
818
+ describe "#each" do
819
+ context "when #type is a UInt" do
820
+ let(:type) { Hexdump::TYPES[:uint32] }
821
+ let(:uints) { [1, 2, 3] }
822
+ let(:raw) { uints.map { |uint| [uint].pack('L') } }
823
+ let(:data) { raw.join }
824
+
825
+ it "must yield decoded integers" do
826
+ expect { |b|
827
+ subject.each(data,&b)
828
+ }.to yield_successive_args(*raw.zip(uints))
829
+ end
830
+ end
831
+
832
+ context "when #type is a Int" do
833
+ let(:type) { Hexdump::TYPES[:int32] }
834
+ let(:ints) { [1, 2, 3] }
835
+ let(:raw) { ints.map { |int| [int].pack('l') } }
836
+ let(:data) { raw.join }
837
+
838
+ it "must yield decoded integers" do
839
+ expect { |b|
840
+ subject.each(data,&b)
841
+ }.to yield_successive_args(*raw.zip(ints))
842
+ end
843
+ end
844
+
845
+ context "when #type is a Float" do
846
+ let(:type) { Hexdump::TYPES[:float] }
847
+ let(:floats) { [1.0, 2.0, 3.0] }
848
+ let(:raw) { floats.map { |float| [float].pack('e') } }
849
+ let(:data) { raw.join }
850
+
851
+ it "must yield decoded integers" do
852
+ expect { |b|
853
+ subject.each(data,&b)
854
+ }.to yield_successive_args(*raw.zip(floats))
855
+ end
856
+ end
857
+
858
+ context "when the given data does not define #each_byte" do
859
+ it do
860
+ expect {
861
+ subject.each(Object.new).to_a
862
+ }.to raise_error(ArgumentError)
863
+ end
864
+ end
865
+ end
866
+ end