Ejemplo n.º 1
0
func TestGetSetStructValue(t *testing.T) {

	const val = 42
	arr10, err := ffi.NewArrayType(10, ffi.C_int32)
	if err != nil {
		t.Errorf(err.Error())
	}

	ctyp, err := ffi.NewStructType(
		"struct_ssv",
		[]ffi.Field{
			{"F1", ffi.C_uint16},
			{"F2", arr10},
			{"F3", ffi.C_int32},
			{"F4", ffi.C_uint16},
		})
	eq(t, "struct_ssv", ctyp.Name())
	eq(t, ffi.Struct, ctyp.Kind())
	eq(t, 4, ctyp.NumField())

	cval := ffi.New(ctyp)
	eq(t, ctyp.Kind(), cval.Kind())
	eq(t, ctyp.NumField(), cval.NumField())
	eq(t, uint64(0), cval.Field(0).Uint())
	for i := 0; i < arr10.Len(); i++ {
		eq(t, int64(0), cval.Field(1).Index(i).Int())
	}
	eq(t, int64(0), cval.Field(2).Int())
	eq(t, uint64(0), cval.Field(3).Uint())

	// set everything to 'val'
	cval.Field(0).SetUint(val)
	for i := 0; i < arr10.Len(); i++ {
		cval.Field(1).Index(i).SetInt(val)
	}
	cval.Field(2).SetInt(val)
	cval.Field(3).SetUint(val)

	// test values back
	eq(t, uint64(val), cval.Field(0).Uint())
	for i := 0; i < arr10.Len(); i++ {
		eq(t, int64(val), cval.Field(1).Index(i).Int())
	}
	eq(t, int64(val), cval.Field(2).Int())
	eq(t, uint64(val), cval.Field(3).Uint())

	// test values back - by field name
	eq(t, uint64(val), cval.FieldByName("F1").Uint())
	for i := 0; i < arr10.Len(); i++ {
		eq(t, int64(val), cval.FieldByName("F2").Index(i).Int())
	}
	eq(t, int64(val), cval.FieldByName("F3").Int())
	eq(t, uint64(val), cval.FieldByName("F4").Uint())
}
Ejemplo n.º 2
0
func TestNewSliceType(t *testing.T) {

	capSize := 2 * unsafe.Sizeof(reflect.SliceHeader{}.Cap)

	s_t, err := ffi.NewStructType("s_0", []ffi.Field{{"a", ffi.C_int32}})
	if err != nil {
		t.Errorf(err.Error())
	}

	p_s_t, err := ffi.NewPointerType(s_t)
	if err != nil {
		t.Errorf(err.Error())
	}

	for _, table := range []struct {
		name string
		elem ffi.Type
	}{
		{"uint8[]", ffi.C_uint8},
		{"uint16[]", ffi.C_uint16},
		{"uint32[]", ffi.C_uint32},
		{"uint64[]", ffi.C_uint64},
		{"int8[]", ffi.C_int8},
		{"int16[]", ffi.C_int16},
		{"int32[]", ffi.C_int32},
		{"int64[]", ffi.C_int64},

		{"float[]", ffi.C_float},
		{"double[]", ffi.C_double},

		{"s_0[]", s_t},
		{"s_0*[]", p_s_t},
	} {
		typ, err := ffi.NewSliceType(table.elem)
		if err != nil {
			t.Errorf(err.Error())
		}
		eq(t, table.name, typ.Name())
		eq(t, table.elem, typ.Elem())
		eq(t, capSize+ffi.C_pointer.Size(), typ.Size())
		//eq(t, table.n, typ.Len())
		eq(t, ffi.Slice, typ.Kind())
	}
}
Ejemplo n.º 3
0
func TestNewArrayType(t *testing.T) {

	s_t, err := ffi.NewStructType("s_0", []ffi.Field{{"a", ffi.C_int32}})
	if err != nil {
		t.Errorf(err.Error())
	}

	p_s_t, err := ffi.NewPointerType(s_t)
	if err != nil {
		t.Errorf(err.Error())
	}

	for _, table := range []struct {
		name string
		n    int
		elem ffi.Type
	}{
		{"uint8[10]", 10, ffi.C_uint8},
		{"uint16[10]", 10, ffi.C_uint16},
		{"uint32[10]", 10, ffi.C_uint32},
		{"uint64[10]", 10, ffi.C_uint64},
		{"int8[10]", 10, ffi.C_int8},
		{"int16[10]", 10, ffi.C_int16},
		{"int32[10]", 10, ffi.C_int32},
		{"int64[10]", 10, ffi.C_int64},

		{"float[10]", 10, ffi.C_float},
		{"double[10]", 10, ffi.C_double},

		{"s_0[10]", 10, s_t},
		{"s_0*[10]", 10, p_s_t},
	} {
		typ, err := ffi.NewArrayType(table.n, table.elem)
		if err != nil {
			t.Errorf(err.Error())
		}
		eq(t, table.name, typ.Name())
		eq(t, table.elem, typ.Elem())
		eq(t, uintptr(table.n)*table.elem.Size(), typ.Size())
		eq(t, table.n, typ.Len())
		eq(t, ffi.Array, typ.Kind())
	}
}
Ejemplo n.º 4
0
func TestNewPointerType(t *testing.T) {
	s_t, err := ffi.NewStructType("s_0", []ffi.Field{{"a", ffi.C_int32}})
	if err != nil {
		t.Errorf(err.Error())
	}

	p_s_t, err := ffi.NewPointerType(s_t)
	if err != nil {
		t.Errorf(err.Error())
	}

	for _, table := range []struct {
		name string
		elem ffi.Type
	}{
		{"int8*", ffi.C_int8},
		{"int16*", ffi.C_int16},
		{"int32*", ffi.C_int32},
		{"int64*", ffi.C_int64},
		{"uint8*", ffi.C_uint8},
		{"uint16*", ffi.C_uint16},
		{"uint32*", ffi.C_uint32},
		{"uint64*", ffi.C_uint64},

		{"float*", ffi.C_float},
		{"double*", ffi.C_double},

		{"s_0*", s_t},
		{"s_0**", p_s_t},
	} {
		typ, err := ffi.NewPointerType(table.elem)
		if err != nil {
			t.Errorf(err.Error())
		}
		eq(t, table.name, typ.Name())
		eq(t, table.elem, typ.Elem())
		eq(t, ffi.C_pointer.Size(), typ.Size())
		eq(t, ffi.Ptr, typ.Kind())
	}
}
Ejemplo n.º 5
0
func TestEncoderDecoder(t *testing.T) {
	arr_10, _ := ffi.NewArrayType(10, ffi.C_int32)
	sli_10, _ := ffi.NewSliceType(ffi.C_int32)

	const sz = 10
	{
		const val = 42
		for _, v := range []interface{}{
			int(val),
			int8(val),
			int16(val),
			int32(val),
			int64(val),
		} {
			ct := ffi.TypeOf(v)
			cv := ffi.New(ct)
			enc := ffi.NewEncoder(cv)
			err := enc.Encode(v)
			if err != nil {
				t.Errorf(err.Error())
			}
			eq(t, int64(val), cv.Int())

			// now decode back
			vv := reflect.New(reflect.TypeOf(v))
			dec := ffi.NewDecoder(cv)
			err = dec.Decode(vv.Interface())
			if err != nil {
				t.Errorf(err.Error())
			}
			eq(t, vv.Elem().Int(), cv.Int())
		}
	}

	{
		const val = 42
		for _, v := range []interface{}{
			uint(val),
			uint8(val),
			uint16(val),
			uint32(val),
			uint64(val),
		} {
			ct := ffi.TypeOf(v)
			cv := ffi.New(ct)
			enc := ffi.NewEncoder(cv)
			err := enc.Encode(v)
			if err != nil {
				t.Errorf(err.Error())
			}
			eq(t, uint64(val), cv.Uint())

			// now decode back
			vv := reflect.New(reflect.TypeOf(v))
			dec := ffi.NewDecoder(cv)
			err = dec.Decode(vv.Interface())
			if err != nil {
				t.Errorf(err.Error())
			}
			eq(t, vv.Elem().Uint(), cv.Uint())
		}
	}
	{
		const val = 42.0
		for _, v := range []interface{}{
			float32(val),
			float64(val),
		} {
			ct := ffi.TypeOf(v)
			cv := ffi.New(ct)
			enc := ffi.NewEncoder(cv)
			err := enc.Encode(v)
			if err != nil {
				t.Errorf(err.Error())
			}
			eq(t, float64(val), cv.Float())

			// now decode back
			vv := reflect.New(reflect.TypeOf(v))
			dec := ffi.NewDecoder(cv)
			err = dec.Decode(vv.Interface())
			if err != nil {
				t.Errorf(err.Error())
			}
			eq(t, vv.Elem().Float(), cv.Float())
		}
	}
	{
		const val = 42
		ctyp, err := ffi.NewStructType(
			"struct_ints",
			[]ffi.Field{
				{"F1", ffi.C_int8},
				{"F2", ffi.C_int16},
				{"F3", ffi.C_int32},
				{"F4", ffi.C_int64},
			})
		if err != nil {
			t.Errorf(err.Error())
		}
		cval := ffi.New(ctyp)
		gval := struct {
			F1 int8
			F2 int16
			F3 int32
			F4 int64
		}{val + 1, val + 1, val + 1, val + 1}
		err = ffi.Associate(ctyp, reflect.TypeOf(gval))
		if err != nil {
			t.Errorf(err.Error())
		}

		enc := ffi.NewEncoder(cval)
		err = enc.Encode(gval)
		if err != nil {
			t.Errorf(err.Error())
		}

		rval := reflect.ValueOf(gval)
		for i := 0; i < ctyp.NumField(); i++ {
			eq(t, rval.Field(i).Int(), cval.Field(i).Int())
		}

		// now decode back
		vv := reflect.New(rval.Type())
		dec := ffi.NewDecoder(cval)
		err = dec.Decode(vv.Interface())
		if err != nil {
			t.Errorf(err.Error())
		}
		rval = vv.Elem()
		for i := 0; i < ctyp.NumField(); i++ {
			eq(t, rval.Field(i).Int(), cval.Field(i).Int())
		}
	}
	{
		const val = 42
		ctyp, err := ffi.NewStructType(
			"struct_ints_arr10",
			[]ffi.Field{
				{"F1", ffi.C_int8},
				{"F2", ffi.C_int16},
				{"A1", arr_10},
				{"F3", ffi.C_int32},
				{"F4", ffi.C_int64},
			})
		if err != nil {
			t.Errorf(err.Error())
		}
		cval := ffi.New(ctyp)
		gval := struct {
			F1 int8
			F2 int16
			A1 [sz]int32
			F3 int32
			F4 int64
		}{
			val + 1, val + 1,
			[sz]int32{
				val, val, val, val, val,
				val, val, val, val, val,
			},
			val + 1, val + 1,
		}
		err = ffi.Associate(ctyp, reflect.TypeOf(gval))
		if err != nil {
			t.Errorf(err.Error())
		}
		enc := ffi.NewEncoder(cval)
		err = enc.Encode(gval)
		if err != nil {
			t.Errorf(err.Error())
		}

		rval := reflect.ValueOf(gval)
		eq(t, rval.Field(0).Int(), cval.Field(0).Int())
		eq(t, rval.Field(1).Int(), cval.Field(1).Int())
		eq(t, rval.Field(3).Int(), cval.Field(3).Int())
		eq(t, rval.Field(4).Int(), cval.Field(4).Int())
		rfield := cval.Field(2)
		cfield := cval.Field(2)
		eq(t, rfield.Len(), cfield.Len())
		for i := 0; i < cfield.Len(); i++ {
			eq(t, rfield.Index(i).Int(), cfield.Index(i).Int())
		}

		// now decode back
		vv := reflect.New(rval.Type())
		dec := ffi.NewDecoder(cval)
		err = dec.Decode(vv.Interface())
		if err != nil {
			t.Errorf(err.Error())
		}
		rval = vv.Elem()
		eq(t, rval.Field(0).Int(), cval.Field(0).Int())
		eq(t, rval.Field(1).Int(), cval.Field(1).Int())
		eq(t, rval.Field(3).Int(), cval.Field(3).Int())
		eq(t, rval.Field(4).Int(), cval.Field(4).Int())
		rfield = cval.Field(2)
		cfield = cval.Field(2)
		eq(t, rfield.Len(), cfield.Len())
		for i := 0; i < cfield.Len(); i++ {
			eq(t, rfield.Index(i).Int(), cfield.Index(i).Int())
		}
	}
	{
		const val = 42
		ctyp, err := ffi.NewStructType(
			"struct_ints_sli10",
			[]ffi.Field{
				{"F1", ffi.C_int8},
				{"F2", ffi.C_int16},
				{"S1", sli_10},
				{"F3", ffi.C_int32},
				{"F4", ffi.C_int64},
			})
		if err != nil {
			t.Errorf(err.Error())
		}
		cval := ffi.New(ctyp)
		gval := struct {
			F1 int8
			F2 int16
			S1 []int32
			F3 int32
			F4 int64
		}{
			val + 1, val + 1,
			[]int32{
				val, val, val, val, val,
				val, val, val, val, val,
			},
			val + 1, val + 1,
		}
		err = ffi.Associate(ctyp, reflect.TypeOf(gval))
		if err != nil {
			t.Errorf(err.Error())
		}
		enc := ffi.NewEncoder(cval)
		err = enc.Encode(gval)
		if err != nil {
			t.Errorf(err.Error())
		}

		rval := reflect.ValueOf(gval)
		eq(t, rval.Field(0).Int(), cval.Field(0).Int())
		eq(t, rval.Field(1).Int(), cval.Field(1).Int())
		eq(t, rval.Field(3).Int(), cval.Field(3).Int())
		eq(t, rval.Field(4).Int(), cval.Field(4).Int())
		rfield := cval.Field(2)
		cfield := cval.Field(2)
		eq(t, rfield.Len(), cfield.Len())
		for i := 0; i < cfield.Len(); i++ {
			eq(t, rfield.Index(i).Int(), cfield.Index(i).Int())
		}

		// now decode back
		vv := reflect.New(rval.Type())
		dec := ffi.NewDecoder(cval)
		err = dec.Decode(vv.Interface())
		if err != nil {
			t.Errorf(err.Error())
		}
		rval = vv.Elem()
		eq(t, rval.Field(0).Int(), cval.Field(0).Int())
		eq(t, rval.Field(1).Int(), cval.Field(1).Int())
		eq(t, rval.Field(3).Int(), cval.Field(3).Int())
		eq(t, rval.Field(4).Int(), cval.Field(4).Int())
		rfield = cval.Field(2)
		cfield = cval.Field(2)
		eq(t, rfield.Len(), cfield.Len())
		for i := 0; i < cfield.Len(); i++ {
			eq(t, rfield.Index(i).Int(), cfield.Index(i).Int())
		}
	}
	{
		const val = 42
		ctyp, err := ffi.NewArrayType(sz, ffi.C_int32)
		if err != nil {
			t.Errorf(err.Error())
		}
		cval := ffi.New(ctyp)
		gval := [sz]int32{
			val, val, val, val, val,
			val, val, val, val, val,
		}
		err = ffi.Associate(ctyp, reflect.TypeOf(gval))
		if err != nil {
			t.Errorf(err.Error())
		}
		enc := ffi.NewEncoder(cval)
		err = enc.Encode(gval)
		if err != nil {
			t.Errorf(err.Error())
		}
		for i := 0; i < cval.Type().Len(); i++ {
			eq(t, int64(val), cval.Index(i).Int())
		}

		// now decode back
		vv := reflect.New(reflect.TypeOf(gval))
		dec := ffi.NewDecoder(cval)
		err = dec.Decode(vv.Interface())
		if err != nil {
			t.Errorf(err.Error())
		}
		for i := 0; i < cval.Type().Len(); i++ {
			eq(t, vv.Elem().Index(i).Int(), cval.Index(i).Int())
		}

	}

	{
		const val = 42
		ctyp, err := ffi.NewArrayType(sz, ffi.C_float)
		if err != nil {
			t.Errorf(err.Error())
		}
		cval := ffi.New(ctyp)
		gval := [sz]float32{
			val, val, val, val, val,
			val, val, val, val, val,
		}
		enc := ffi.NewEncoder(cval)
		err = enc.Encode(gval)
		if err != nil {
			t.Errorf(err.Error())
		}
		for i := 0; i < cval.Type().Len(); i++ {
			eq(t, float64(val), cval.Index(i).Float())
		}
		// now decode back
		vv := reflect.New(reflect.TypeOf(gval))
		dec := ffi.NewDecoder(cval)
		err = dec.Decode(vv.Interface())
		if err != nil {
			t.Errorf(err.Error())
		}
		for i := 0; i < cval.Type().Len(); i++ {
			eq(t, vv.Elem().Index(i).Float(), cval.Index(i).Float())
		}

	}

	{
		const val = 42
		ctyp, err := ffi.NewSliceType(ffi.C_int32)
		if err != nil {
			t.Errorf(err.Error())
		}
		cval := ffi.MakeSlice(ctyp, sz, sz)
		gval := []int32{
			val, val, val, val, val,
			val, val, val, val, val,
		}
		enc := ffi.NewEncoder(cval)
		err = enc.Encode(gval)
		if err != nil {
			t.Errorf(err.Error())
		}
		for i := 0; i < cval.Len(); i++ {
			eq(t, int64(val), cval.Index(i).Int())
		}
		// now decode back
		vv := reflect.New(reflect.TypeOf(gval))
		dec := ffi.NewDecoder(cval)
		err = dec.Decode(vv.Interface())
		if err != nil {
			t.Errorf(err.Error())
		}
		for i := 0; i < cval.Len(); i++ {
			eq(t, vv.Elem().Index(i).Int(), cval.Index(i).Int())
		}
	}
	{
		const val = 42
		ctyp, err := ffi.NewSliceType(ffi.C_float)
		if err != nil {
			t.Errorf(err.Error())
		}
		cval := ffi.MakeSlice(ctyp, sz, sz)
		gval := []float32{
			val, val, val, val, val,
			val, val, val, val, val,
		}
		enc := ffi.NewEncoder(cval)
		err = enc.Encode(gval)
		if err != nil {
			t.Errorf(err.Error())
		}
		for i := 0; i < cval.Len(); i++ {
			eq(t, float64(val), cval.Index(i).Float())
		}
		{
			// now decode back
			vv := reflect.New(reflect.TypeOf(gval))
			dec := ffi.NewDecoder(cval)
			err = dec.Decode(vv.Interface())
			if err != nil {
				t.Errorf(err.Error())
			}
			for i := 0; i < cval.Len(); i++ {
				eq(t, vv.Elem().Index(i).Float(), cval.Index(i).Float())
			}
		}
	}
}
Ejemplo n.º 6
0
func TestValueOf(t *testing.T) {
	{
		const val = 42
		for _, v := range []interface{}{
			int(val),
			int8(val),
			int16(val),
			int32(val),
			int64(val),
		} {
			eq(t, int64(val), ffi.ValueOf(v).Int())
		}
	}

	{
		const val = 42
		for _, v := range []interface{}{
			uint(val),
			uint8(val),
			uint16(val),
			uint32(val),
			uint64(val),
		} {
			eq(t, uint64(val), ffi.ValueOf(v).Uint())
		}
	}
	{
		const val = 42.0
		for _, v := range []interface{}{
			float32(val),
			float64(val),
		} {
			eq(t, float64(val), ffi.ValueOf(v).Float())
		}
	}
	{
		const val = 42
		ctyp, err := ffi.NewStructType(
			"struct_ints",
			[]ffi.Field{
				{"F1", ffi.C_int8},
				{"F2", ffi.C_int16},
				{"F3", ffi.C_int32},
				{"F4", ffi.C_int64},
			})
		if err != nil {
			t.Errorf(err.Error())
		}
		cval := ffi.New(ctyp)
		for i := 0; i < ctyp.NumField(); i++ {
			cval.Field(i).SetInt(int64(val))
			eq(t, int64(val), cval.Field(i).Int())
		}
		gval := struct {
			F1 int8
			F2 int16
			F3 int32
			F4 int64
		}{val + 1, val + 1, val + 1, val + 1}
		rval := reflect.ValueOf(gval)
		eq(t, rval.NumField(), cval.NumField())
		for i := 0; i < ctyp.NumField(); i++ {
			eq(t, rval.Field(i).Int()-1, cval.Field(i).Int())
		}
		cval = ffi.ValueOf(gval)
		for i := 0; i < ctyp.NumField(); i++ {
			eq(t, rval.Field(i).Int(), cval.Field(i).Int())
		}
	}
}
Ejemplo n.º 7
0
func TestGetSetStructWithSliceValue(t *testing.T) {

	const val = 42
	arr10, err := ffi.NewArrayType(10, ffi.C_int32)
	if err != nil {
		t.Errorf(err.Error())
	}
	slityp, err := ffi.NewSliceType(ffi.C_int32)
	if err != nil {
		t.Errorf(err.Error())
	}

	ctyp, err := ffi.NewStructType(
		"struct_sswsv",
		[]ffi.Field{
			{"F1", ffi.C_uint16},
			{"F2", arr10},
			{"F3", ffi.C_int32},
			{"F4", ffi.C_uint16},
			{"F5", slityp},
		})
	eq(t, "struct_sswsv", ctyp.Name())
	eq(t, ffi.Struct, ctyp.Kind())
	eq(t, 5, ctyp.NumField())

	cval := ffi.New(ctyp)
	eq(t, ctyp.Kind(), cval.Kind())
	eq(t, ctyp.NumField(), cval.NumField())
	eq(t, uint64(0), cval.Field(0).Uint())
	for i := 0; i < arr10.Len(); i++ {
		eq(t, int64(0), cval.Field(1).Index(i).Int())
	}
	eq(t, int64(0), cval.Field(2).Int())
	eq(t, uint64(0), cval.Field(3).Uint())
	eq(t, int(0), cval.Field(4).Len())
	eq(t, int(0), cval.Field(4).Len())

	goval := struct {
		F1 uint16
		F2 [10]int32
		F3 int32
		F4 uint16
		F5 []int32
	}{
		F1: val,
		F2: [10]int32{val, val, val, val, val,
			val, val, val, val, val},
		F3: val,
		F4: val,
		F5: make([]int32, 2, 3),
	}
	goval.F5[0] = val
	goval.F5[1] = val

	cval.SetValue(reflect.ValueOf(goval))

	eq(t, uint64(val), cval.Field(0).Uint())
	for i := 0; i < arr10.Len(); i++ {
		eq(t, int64(val), cval.Field(1).Index(i).Int())
	}
	eq(t, int64(val), cval.Field(2).Int())
	eq(t, uint64(val), cval.Field(3).Uint())
	eq(t, int(2), cval.Field(4).Len())
	// FIXME: should we get the 'cap' from go ?
	eq(t, int( /*3*/ 2), cval.Field(4).Cap())
	eq(t, int64(val), cval.Field(4).Index(0).Int())
	eq(t, int64(val), cval.Field(4).Index(1).Int())
}
Ejemplo n.º 8
0
func TestNewStructType(t *testing.T) {

	arr10, err := ffi.NewArrayType(10, ffi.C_int32)
	if err != nil {
		t.Errorf(err.Error())
	}
	eq(t, int(10), arr10.Len())

	for _, table := range []struct {
		name    string
		fields  []ffi.Field
		size    uintptr
		offsets []uintptr
	}{
		{"struct_0",
			[]ffi.Field{{"a", ffi.C_int}},
			ffi.C_int.Size(),
			[]uintptr{0},
		},
		{"struct_1",
			[]ffi.Field{
				{"a", ffi.C_int},
				{"b", ffi.C_int},
			},
			ffi.C_int.Size() + ffi.C_int.Size(),
			[]uintptr{0, ffi.C_int.Size()},
		},
		{"struct_2",
			[]ffi.Field{
				{"F1", ffi.C_uint8},
				{"F2", ffi.C_int16},
				{"F3", ffi.C_int32},
				{"F4", ffi.C_uint8},
			},
			12,
			[]uintptr{0, 2, 4, 8},
		},
		//FIXME: 32b/64b alignement differ!!
		// make 2 tests!
		// {"struct_3",
		// 	[]ffi.Field{
		// 		{"F1", ffi.C_uint8},
		// 		{"F2", arr10},
		// 		{"F3", ffi.C_int32},
		// 		{"F4", ffi.C_uint8},
		// 	},
		// 	56,
		// 	[]uintptr{0, 8, 48, 52},
		// },
	} {
		typ, err := ffi.NewStructType(table.name, table.fields)
		if err != nil {
			t.Errorf(err.Error())
		}
		eq(t, table.name, typ.Name())
		//eq(t, table.size, typ.Size())
		if table.size != typ.Size() {
			t.Errorf("expected size [%d] got [%d] (type=%q)", table.size, typ.Size(), table.name)
		}
		eq(t, len(table.offsets), typ.NumField())
		for i := 0; i < typ.NumField(); i++ {
			if table.offsets[i] != typ.Field(i).Offset {
				t.Errorf("type=%q field=%d: expected offset [%d]. got [%d]", table.name, i, table.offsets[i], typ.Field(i).Offset)
			}
			//eq(t, table.offsets[i], typ.Field(i).Offset)
		}
		eq(t, ffi.Struct, typ.Kind())
	}

	// test type mismatch
	n := "struct_type_err"
	st, err := ffi.NewStructType(n, []ffi.Field{{"a", ffi.C_int}})
	if err != nil {
		t.Errorf(err.Error())
	}
	{
		// check we get the exact same instance
		st_dup, err := ffi.NewStructType(n, []ffi.Field{{"a", ffi.C_int}})
		if err != nil {
			t.Errorf(err.Error())
		}
		if !reflect.DeepEqual(st_dup, st) {
			t.Errorf("NewStructType is not idem-potent")
		}
	}
	{
		_, err := ffi.NewStructType(
			n,
			[]ffi.Field{{"a", ffi.C_int}, {"b", ffi.C_int}})
		if err == nil {
			t.Errorf("failed to raise an error")
		}
		errmsg := fmt.Sprintf("ffi.NewStructType: inconsistent re-declaration of [%s]", n)
		if err.Error() != errmsg {
			t.Errorf("failed to detect number of fields differ: %v", err)
		}
	}
	{
		_, err := ffi.NewStructType(n, []ffi.Field{{"b", ffi.C_int}})
		if err == nil {
			t.Errorf("failed to raise an error")
		}
		errmsg := fmt.Sprintf("ffi.NewStructType: inconsistent re-declaration of [%s] (field #0 name mismatch)", n)
		if err.Error() != errmsg {
			t.Errorf("failed to detect field-name mismatch: %v", err)
		}
	}
	{
		_, err := ffi.NewStructType(n, []ffi.Field{{"a", ffi.C_uint}})
		if err == nil {
			t.Errorf("failed to raise an error")
		}
		errmsg := fmt.Sprintf("ffi.NewStructType: inconsistent re-declaration of [%s] (field #0 type mismatch)", n)
		if err.Error() != errmsg {
			t.Errorf("failed to detect field-type mismatch: %v", err)
		}
	}
}