#!/usr/bin/env ruby require File.expand_path(File.dirname(__FILE__)) + '/spec_common' require 'bindata/struct' require 'bindata/int' context "A Struct with hidden fields" do context_setup do eval <<-END class TestStruct < BinData::Struct hide :b, 'c' int8 :a int8 'b', :initial_value => 10 int8 :c int8 :d, :value => :b end END @obj = TestStruct.new end specify "should only show fields that aren't hidden" do @obj.field_names.should == ["a", "d"] end specify "should be able to access hidden fields directly" do @obj.b.should == 10 @obj.c = 15 @obj.c.should == 15 @obj.should respond_to?(:b=) end specify "should not include hidden fields in snapshot" do @obj.b = 5 @obj.snapshot.should == {"a" => 0, "d" => 5} end end context "Defining a Struct" do specify "should fail on non registered types" do lambda { eval <<-END class BadType < BinData::Struct non_registerd_type :a end END }.should raise_error(TypeError) end specify "should fail on duplicate names" do lambda { eval <<-END class DuplicateName < BinData::Struct int8 :a int8 :b int8 :a end END }.should raise_error(SyntaxError) end end context "A Struct with multiple fields" do setup do fields = [ [:int8, :a], [:int8, :b] ] @obj = BinData::Struct.new(:fields => fields) @obj.a = 1 @obj.b = 2 end specify "should return num_bytes" do @obj.num_bytes(:a).should == 1 @obj.num_bytes(:b).should == 1 @obj.num_bytes.should == 2 end specify "should clear" do @obj.a = 6 @obj.clear @obj.clear?.should be_true end specify "should clear individual elements" do @obj.a = 6 @obj.b = 7 @obj.clear(:a) @obj.clear?(:a).should be_true @obj.clear?(:b).should be_false end specify "should write ordered" do io = StringIO.new @obj.write(io) io.rewind io.read.should == "\x01\x02" end specify "should read ordered" do io = StringIO.new "\x03\x04" @obj.read(io) @obj.a.should == 3 @obj.b.should == 4 end specify "should return a snapshot" do snap = @obj.snapshot snap.a.should == 1 snap.b.should == 2 snap.should == { "a" => 1, "b" => 2 } end specify "should return field_names" do @obj.field_names.should == ["a", "b"] end specify "should fail on unknown method call" do lambda { @obj.does_not_exist }.should raise_error(NoMethodError) end end context "A Struct with a value method" do context_setup do eval <<-END class StructWithValue < BinData::Struct int8 :a int8 :b def value a end end END @obj = StructWithValue.new end specify "should be single value object" do @obj.should be_a_single_value end specify "should have no field names" do @obj.field_names.should be_empty end specify "should not respond to field accesses" do @obj.should_not respond_to?(:a) end end context "A Struct with nested structs" do context_setup do eval <<-END class StructInner1 < BinData::Struct int8 :w, :initial_value => 3 int8 :x, :value => :the_val end class StructInner2 < BinData::Struct int8 :y, :value => lambda { parent.b.w } int8 :z end class StructOuter < BinData::Struct int8 :a, :initial_value => 6 struct_inner1 :b, :the_val => :a struct_inner2 nil end END @obj = StructOuter.new end specify "should included nested field names" do @obj.field_names.should == ["a", "b", "y", "z"] end specify "should access nested fields" do @obj.a.should == 6 @obj.b.w.should == 3 @obj.b.x.should == 6 @obj.y.should == 3 end specify "should return correct offset of" do @obj.offset_of("b").should == 1 @obj.offset_of("y").should == 3 @obj.offset_of("z").should == 4 end end