depix 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/test/test_dict.rb ADDED
@@ -0,0 +1,650 @@
1
+ require File.dirname(__FILE__) + '/../lib/depix/dict'
2
+ require 'test/unit'
3
+
4
+ include Depix
5
+
6
+ module FieldConformity
7
+ def conform_field!(f)
8
+ assert_respond_to f, :name
9
+ assert_respond_to f, :length
10
+ assert_respond_to f, :pattern
11
+ assert_respond_to f, :req
12
+ assert_respond_to f, :req?
13
+ assert_respond_to f, :rtype
14
+ assert_respond_to f, :explain
15
+ end
16
+ end
17
+
18
+ class FieldExplainsItself < Test::Unit::TestCase
19
+ def test_explain
20
+ f = Field.new :rtype => self.class, :desc => "Eats people"
21
+ assert_equal "(FieldExplainsItself) Eats people", f.explain
22
+ end
23
+
24
+ def test_explain_with_verbatim
25
+ f = Field.new :desc => "Eats people"
26
+ assert_equal "Eats people", f.explain
27
+ end
28
+
29
+ def test_explain_with_verbatim_and_required
30
+ f = Field.new :desc => "Eats people", :req => true
31
+ assert_equal "Eats people - required", f.explain
32
+ end
33
+
34
+ def test_explain_with_no_data
35
+ f = Field.new
36
+ assert_equal "", f.explain
37
+ end
38
+
39
+ def test_explaion_for_empty_array
40
+ f = ArrayField.new
41
+ assert_equal "Empty array", f.explain
42
+ end
43
+
44
+ def test_explain_for_array_with_members
45
+ f = ArrayField.new :members => [U8Field.new, U8Field.new], :desc => "Eats babies"
46
+ assert_equal "(Array of 2 Integer fields) Eats babies", f.explain
47
+ end
48
+
49
+ def test_explain_for_nested_struct
50
+ f = InnerField.new :cast => self.class, :desc => "Link to test case"
51
+ assert_equal "(FieldExplainsItself) Link to test case", f.explain
52
+ end
53
+
54
+ end
55
+
56
+ class TestField < Test::Unit::TestCase
57
+ include FieldConformity
58
+
59
+ def test_field_responds_to_all_meths
60
+ f = Field.new
61
+ conform_field!(f)
62
+
63
+ assert_respond_to f, :name=
64
+ assert_respond_to f, :length=
65
+ assert_respond_to f, :pattern=
66
+ assert_respond_to f, :req=
67
+ end
68
+
69
+ def test_field_supports_hash_initialization
70
+ f = Field.new :name => "foo", :length => 3, :pattern => "C3"
71
+ assert_equal ["foo", 3, "C3"], [f.name, f.length, f.pattern]
72
+ end
73
+
74
+ def test_req?
75
+ f = Field.new :name => "foo"
76
+ assert !f.req?
77
+
78
+ f = Field.new :name => "foo", :req => false
79
+ assert !f.req?
80
+
81
+ f = Field.new :name => "foo", :req => true
82
+ assert f.req?
83
+ end
84
+
85
+ def test_consume_for_field
86
+ f = Field.new :name => "foo"
87
+
88
+ assert_respond_to f, :consume!
89
+ assert_nil f.consume!([])
90
+ assert_equal 1, f.consume!([1])
91
+ assert_equal 2, f.consume!([2,"foo"])
92
+
93
+ ar = [1,2,3]
94
+ f.consume!(ar)
95
+ assert_equal [2,3], ar
96
+ end
97
+
98
+ def test_consume_for_inner_field
99
+ catcher = Class.new do
100
+ def self.consume!(arg)
101
+ raise RuntimeError if arg == ["julik"]
102
+ end
103
+ end
104
+
105
+ f = InnerField.new :cast => catcher
106
+ assert_respond_to f, :consume!
107
+
108
+ assert_raise(RuntimeError) { f.consume!(["julik"]) }
109
+ end
110
+
111
+ def test_consume_for_array
112
+ f = ArrayField.new :members => [Field.new, Field.new]
113
+ assert_respond_to f, :consume!
114
+
115
+ assert_equal [1,2], f.consume!([1,2])
116
+ end
117
+ end
118
+
119
+ class TestArrayField < Test::Unit::TestCase
120
+ include FieldConformity
121
+
122
+ def test_array_field_conform_field!s_to_field_and_has_extra_methods
123
+ f = ArrayField.new
124
+ conform_field!(f)
125
+
126
+ assert_respond_to f, :name=
127
+
128
+ assert_raise(NoMethodError) { f.length = 1 }
129
+ assert_raise(NoMethodError) { f.pattern = 'C' }
130
+ end
131
+
132
+ def test_array_field_has_members
133
+ f = ArrayField.new
134
+ assert_respond_to f, :members
135
+ assert_respond_to f, :members=
136
+ end
137
+
138
+ def test_rtype_for_array_field_is_array
139
+ casted = ArrayField.new(:members => [])
140
+ assert_equal Array, casted.rtype
141
+ end
142
+
143
+ def test_array_field_accumulates_lengths_and_patterns_from_members
144
+ f = ArrayField.new(:members => [
145
+ Field.new(:name => :foo, :length => 1, :pattern => "C"),
146
+ Field.new(:name => :bar, :length => 2, :pattern => "C2"),
147
+ ])
148
+
149
+ assert_equal 3, f.length
150
+ assert_equal "CC2", f.pattern
151
+ end
152
+ end
153
+
154
+ class TestInnerField < Test::Unit::TestCase
155
+
156
+ include FieldConformity
157
+
158
+ def test_inner_field_conforms_to_field_and_has_extra_methods
159
+ f = InnerField.new
160
+ conform_field!(f)
161
+
162
+ assert_respond_to f, :cast
163
+ assert_respond_to f, :cast=
164
+
165
+ assert_raise(NoMethodError) { f.length = 1 }
166
+ assert_raise(NoMethodError) { f.pattern = 'C' }
167
+ end
168
+
169
+ def test_inner_field_asks_cast_for_pattern_and_length
170
+ sample = Struct.new(:length, :pattern).new
171
+ sample.length, sample.pattern = 123, "C123"
172
+
173
+ casted = InnerField.new(:cast => sample)
174
+ assert_equal 123, casted.length
175
+ assert_equal 'C123', casted.pattern
176
+ end
177
+
178
+ def test_rtype_for_inner_field_is_cast
179
+ c = Class.new
180
+ casted = InnerField.new(:cast => c)
181
+ assert_equal c, casted.rtype
182
+ end
183
+ end
184
+
185
+ class TestWideIntField < Test::Unit::TestCase
186
+ include FieldConformity
187
+
188
+ def test_u32_field_contorms_to_basics
189
+ f = U32Field.new :name => :foo
190
+ conform_field!(f)
191
+
192
+ assert_equal "N", f.pattern
193
+ assert_equal 4, f.length
194
+ assert_equal :foo, f.name
195
+ assert_equal 66, f.clean(66)
196
+ assert_equal nil, f.clean(0xFFFFFFFF)
197
+ end
198
+ end
199
+
200
+ class TestCharField < Test::Unit::TestCase
201
+ include FieldConformity
202
+
203
+ def test_char_field_conforms_to_basics
204
+ f = CharField.new :name => :foo
205
+ conform_field!(f)
206
+ end
207
+
208
+ def test_char_field_pads
209
+ f = CharField.new :name => :foo, :length => 15
210
+
211
+ assert_equal "A15", f.pattern
212
+ assert_equal 15, f.length
213
+ assert_equal String, f.rtype
214
+ end
215
+
216
+ def test_char_field_clean_inner_nulls
217
+ f = CharField.new :name => :foo, :length => 15
218
+ assert_equal "foo", f.clean("\0\0foo")
219
+ end
220
+
221
+ def test_char_field_clean_blank
222
+ f = CharField.new :name => :foo, :length => 15
223
+ assert_equal nil, f.clean("\0")
224
+ end
225
+ end
226
+
227
+ class TestFloatField < Test::Unit::TestCase
228
+ include FieldConformity
229
+
230
+ def test_r32_field_contorms_to_basics
231
+ f = R32Field.new :name => :foo
232
+ conform_field!(f)
233
+
234
+ the_nan = Class.new do
235
+ def nan?; true; end
236
+ end.new
237
+
238
+ assert_equal "g", f.pattern
239
+ assert_equal 4, f.length
240
+ assert_equal :foo, f.name
241
+ assert_equal Float, f.rtype
242
+ assert_equal nil, f.clean(the_nan)
243
+ end
244
+ end
245
+
246
+ class TestSmallintField < Test::Unit::TestCase
247
+ include FieldConformity
248
+
249
+ def test_smallint_conformity
250
+ f = U8Field.new :name => :foo
251
+ conform_field!(f)
252
+ end
253
+
254
+ def test_smallint_operation
255
+ f = U8Field.new
256
+
257
+ assert_equal 'c', f.pattern
258
+ assert_equal 1, f.length
259
+ assert_equal Integer, f.rtype
260
+ end
261
+
262
+ def test_smallint_clean
263
+ f = U8Field.new
264
+
265
+ assert_equal nil, f.clean(0xFF)
266
+ assert_equal 10, f.clean(10)
267
+ end
268
+
269
+ end
270
+
271
+ class TestDoubleField < Test::Unit::TestCase
272
+ include FieldConformity
273
+
274
+ def test_double_conformity
275
+ f = U16Field.new :name => :foo
276
+ conform_field!(f)
277
+ end
278
+
279
+ def test_double_operation
280
+ f = U16Field.new
281
+
282
+ assert_equal 'n', f.pattern
283
+ assert_equal 2, f.length
284
+ assert_equal Integer, f.rtype
285
+ end
286
+
287
+ def test_double_clean
288
+ f = U16Field.new
289
+
290
+ assert_equal nil, f.clean(0xFFFF)
291
+ assert_equal 10, f.clean(10)
292
+ end
293
+ end
294
+
295
+ class TestFillerField < Test::Unit::TestCase
296
+ include FieldConformity
297
+
298
+ def test_field_conformity
299
+ f = Filler.new
300
+ conform_field!(f)
301
+ assert_equal "x1", f.pattern
302
+ end
303
+
304
+ def test_pattern_discards_value
305
+ data = [1,2,3].pack("ccc")
306
+ filler = Filler.new(:length => 3)
307
+ unpacked = data.unpack(filler.pattern)
308
+ assert_equal [], unpacked
309
+ end
310
+
311
+ def test_consume_does_not_touch_stack
312
+ data = [1,2,3]
313
+ data.freeze
314
+ assert_nothing_raised { Filler.new(:length => 1).consume(data) }
315
+ end
316
+
317
+ end
318
+
319
+ class TestFieldEmit < Test::Unit::TestCase
320
+ include FieldConformity
321
+
322
+ def test_emit_short
323
+ f = Field.emit_u8
324
+ conform_field!(f)
325
+
326
+ f = Field.emit_u8(:desc => "Dick length")
327
+ conform_field!(f)
328
+ assert_equal "c", f.pattern
329
+ assert_equal 1, f.length
330
+ end
331
+
332
+ def test_emit_double
333
+ f = Field.emit_u16
334
+ conform_field!(f)
335
+
336
+ f = Field.emit_u16(:desc => "Dick length")
337
+ conform_field!(f)
338
+ assert_equal "n", f.pattern
339
+ assert_equal 2, f.length
340
+ end
341
+
342
+ def test_emit_char
343
+ f = Field.emit_char
344
+ conform_field!(f)
345
+
346
+ assert_equal "A1", f.pattern
347
+ assert_equal 1, f.length
348
+
349
+ f = Field.emit_char :length => 3
350
+ conform_field!(f)
351
+
352
+ assert_equal "A3", f.pattern
353
+ assert_equal 3, f.length
354
+ end
355
+
356
+ def test_emit_float
357
+ f = Field.emit_r32
358
+ conform_field!(f)
359
+
360
+ assert_equal "g", f.pattern
361
+ assert_equal 4, f.length
362
+ end
363
+ end
364
+
365
+ class TestDict < Test::Unit::TestCase
366
+
367
+ def test_dict_has_a_fields_array
368
+ dict_class = Class.new(Dict)
369
+ assert_respond_to dict_class, :fields
370
+ assert_equal [], dict_class.fields
371
+ end
372
+
373
+ def test_dict_fields_array_not_class_shared
374
+ d1, d2 = (0..1).map{|_| Class.new(Dict) }
375
+
376
+ d1.fields << 1
377
+ d2.fields << 2
378
+ assert_not_equal d1.fields, d2.fields
379
+ end
380
+
381
+ def test_dict_responds_to_emit_methods_from_fields
382
+ c = Class.new(Dict)
383
+
384
+ emitter_methods = Field.methods.grep(/^emit_/)
385
+ emitter_methods.each do | m |
386
+ assert_respond_to c, m.gsub(/^emit_/, '')
387
+ end
388
+ end
389
+
390
+ def test_empty_dict_has_empty_template
391
+ c = Class.new(Dict)
392
+ assert_respond_to c, :pattern
393
+ assert_equal '', c.pattern
394
+ assert_equal 0, c.length
395
+ end
396
+
397
+ def test_dict_assembles_template
398
+ c = Class.new(Dict)
399
+ c.fields << Field.emit_char
400
+ c.fields << Field.emit_char
401
+
402
+ assert_respond_to c, :pattern
403
+ assert_equal 'A1A1', c.pattern
404
+ assert_equal 2, c.length
405
+ end
406
+
407
+ end
408
+
409
+ class TestDictConsume < Test::Unit::TestCase
410
+ def test_dict_consume
411
+ c = Class.new(Dict)
412
+ c.char :foo
413
+ c.char :bar
414
+
415
+ result = c.consume!(["a", "b"])
416
+ assert_kind_of c, result
417
+
418
+ assert_equal "a", result.foo
419
+ assert_equal "b", result.bar
420
+ end
421
+ end
422
+
423
+ class TestDictEmitDSL < Test::Unit::TestCase
424
+
425
+ def test_dict_emit_char
426
+ c = Class.new(Dict)
427
+ c.char :tag, :desc => "Some name"
428
+
429
+ assert c.instance_methods.include?("tag")
430
+
431
+ assert_equal 1, c.fields.length
432
+ field = c.fields[0]
433
+
434
+ assert_equal 1, field.length
435
+ assert_equal "A1", field.pattern
436
+ assert_equal :tag, field.name
437
+ end
438
+
439
+ def test_dict_emit_char_with_length
440
+ c = Class.new(Dict)
441
+ c.char :joe, 3, :desc => "Some name"
442
+
443
+ assert c.instance_methods.include?("joe")
444
+
445
+ assert_equal 1, c.fields.length
446
+ field = c.fields[0]
447
+ assert_equal 3, field.length
448
+ assert_equal "A3", field.pattern
449
+ assert_equal :joe, field.name
450
+ end
451
+
452
+ def test_dict_emit_u32
453
+ c = Class.new(Dict)
454
+ c.u32 :num, :desc => "Huge number"
455
+
456
+ assert c.instance_methods.include?("num")
457
+
458
+ assert_equal 1, c.fields.length
459
+ field = c.fields[0]
460
+ assert_equal 4, field.length
461
+ assert_equal "N", field.pattern
462
+ assert_equal :num, field.name
463
+ end
464
+
465
+ def test_dict_emit_r32
466
+ c = Class.new(Dict)
467
+ c.r32 :joe, :req => true
468
+
469
+ assert c.instance_methods.include?("joe")
470
+
471
+ assert_equal 1, c.fields.length
472
+ field = c.fields[0]
473
+ assert_equal 4, field.length
474
+ assert_equal "g", field.pattern
475
+ assert_equal true, field.req?
476
+ end
477
+
478
+ def test_dict_emit_u8
479
+ c = Class.new(Dict)
480
+ c.u8 :joe, :req => true
481
+
482
+ assert c.instance_methods.include?("joe")
483
+
484
+ assert_equal 1, c.fields.length
485
+
486
+ field = c.fields[0]
487
+ assert_equal 1, field.length
488
+ assert_equal "c", field.pattern
489
+ assert_equal true, field.req?
490
+ end
491
+
492
+ def test_dict_emit_u16
493
+ c = Class.new(Dict)
494
+ c.u16 :joe, :req => true, :desc => "A little bit of numbers"
495
+
496
+ assert c.instance_methods.include?("joe")
497
+
498
+ assert_equal 1, c.fields.length
499
+
500
+ field = c.fields[0]
501
+
502
+ assert_equal 2, field.length
503
+ assert_equal "n", field.pattern
504
+ assert_equal "A little bit of numbers", field.desc
505
+ end
506
+
507
+ def test_dict_emit_array
508
+ c = Class.new(Dict)
509
+ c.array :point, :u32, :desc => "Two coordinates"
510
+
511
+ assert c.instance_methods.include?("point")
512
+
513
+ assert_equal 1, c.fields.length
514
+ field = c.fields[0]
515
+
516
+ assert_kind_of ArrayField, field
517
+ assert_equal "Two coordinates", field.desc
518
+ assert_equal 1, field.members.length
519
+ assert_equal U32Field, field.members[0].class
520
+ end
521
+
522
+ def test_dict_emit_inner
523
+ c = Class.new(Dict)
524
+ c2 = Class.new(Dict)
525
+
526
+ c.inner :nest, c2, :desc => "Nested struct"
527
+
528
+ assert c.instance_methods.include?("nest")
529
+
530
+ assert_equal 1, c.fields.length
531
+ f = c.fields[0]
532
+
533
+ assert_kind_of InnerField, f
534
+ assert_equal "Nested struct", f.desc
535
+ assert_equal c2, f.cast
536
+ end
537
+
538
+ def test_dict_emit_array_of_substructs
539
+ c = Class.new(Dict)
540
+ c2 = Class.new(Dict)
541
+
542
+ c2.u32 :some_num
543
+ c.array :inners, c2, 8, :desc => "Inner items"
544
+
545
+ assert c.instance_methods.include?("inners")
546
+
547
+ assert_equal 1, c.fields.length
548
+ f = c.fields[0]
549
+
550
+ assert_kind_of ArrayField, f
551
+ assert_equal "Inner items", f.desc
552
+
553
+ assert_equal 8, f.members.length, "8 inner members should be there"
554
+
555
+ mem = f.members[0]
556
+ assert_equal c2, mem.cast
557
+ end
558
+ end
559
+
560
+ class TestDictCompact < Test::Unit::TestCase
561
+ def test_only_with_interspersed_fields
562
+ c = Class.new(Dict) do
563
+ u8 :some
564
+ u8 :another
565
+ u8 :third
566
+ end
567
+
568
+ distill = c.only(:another)
569
+
570
+ assert_equal distill.length, c.length, "The distilled struct should occupy the same space"
571
+
572
+ assert distill.ancestors.include?(c)
573
+ assert_equal 3, distill.fields.length
574
+
575
+ assert_kind_of Filler, distill.fields[0]
576
+ assert_equal 1, distill.fields[0].length
577
+
578
+ assert_kind_of U8Field, distill.fields[1]
579
+ assert_equal 1, distill.fields[0].length
580
+
581
+ assert_kind_of Filler, distill.fields[2]
582
+ assert_equal 1, distill.fields[2].length
583
+
584
+ end
585
+
586
+ def test_only_with_fields_in_a_row
587
+ c = Class.new(Dict) do
588
+ u8 :some
589
+ u32 :another
590
+ u8 :third
591
+ u32 :fourth
592
+ char :fifth, 10
593
+ end
594
+
595
+ distill = c.only(:third)
596
+ assert_equal distill.length, c.length, "The distilled struct should occupy the same space"
597
+ assert_equal 3, distill.fields.length
598
+
599
+ assert_kind_of Filler, distill.fields[0]
600
+ assert_equal 5, distill.fields[0].length
601
+
602
+ assert_kind_of Filler, distill.fields[2]
603
+ assert_equal 14, distill.fields[2].length
604
+ end
605
+
606
+ def test_get_filler
607
+ c = Class.new(Dict) do
608
+ u32 :some
609
+ end
610
+
611
+ filler = c.filler
612
+ assert_equal filler.length, c.length
613
+ assert_equal 1, c.fields.length
614
+ end
615
+
616
+ def test_filler_parses_the_same
617
+ c = Class.new(Dict) do
618
+ u8 :first
619
+ u8 :second
620
+ u8 :third
621
+ end
622
+
623
+ distill = c.only(:second)
624
+
625
+ data = [1,2,3].pack("ccc")
626
+
627
+ base_r = c.apply!(data)
628
+ assert_not_nil base_r.first
629
+ assert_not_nil base_r.third
630
+ assert_equal 2, base_r.second
631
+
632
+ r = distill.apply!(data)
633
+ assert_nil r.first
634
+ assert_nil r.third
635
+ assert_equal 2, r.second
636
+ end
637
+ end
638
+
639
+ class TestDictApply < Test::Unit::TestCase
640
+ def test_apply
641
+ struct = Class.new(Dict) do
642
+ char :name, "julik".length
643
+ char :module, "depix".length
644
+ end
645
+
646
+ result = struct.apply!("julikdepix")
647
+ assert_equal "julik", result.name
648
+ assert_equal "depix", result.module
649
+ end
650
+ end