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()) }
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()) } }
func TestGetSetArrayValue(t *testing.T) { { const val = 42 for _, tt := range []struct { n string len int t ffi.Type val interface{} }{ {"uint8[10]", 10, ffi.C_uint8, [10]uint8{}}, {"uint16[10]", 10, ffi.C_uint16, [10]uint16{}}, {"uint32[10]", 10, ffi.C_uint32, [10]uint32{}}, {"uint64[10]", 10, ffi.C_uint64, [10]uint64{}}, } { ctyp, err := ffi.NewArrayType(tt.len, tt.t) if err != nil { t.Errorf(err.Error()) } cval := ffi.New(ctyp) eq(t, tt.n, cval.Type().Name()) eq(t, ctyp.Kind(), cval.Kind()) gtyp := reflect.TypeOf(tt.val) gval := reflect.New(gtyp).Elem() eq(t, gval.Len(), cval.Len()) for i := 0; i < gval.Len(); i++ { eq(t, gval.Index(i).Uint(), cval.Index(i).Uint()) gval.Index(i).SetUint(val) cval.Index(i).SetUint(val) eq(t, gval.Index(i).Uint(), cval.Index(i).Uint()) } } } { const val = 42 for _, tt := range []struct { n string len int t ffi.Type val interface{} }{ {"int8[10]", 10, ffi.C_int8, [10]int8{}}, {"int16[10]", 10, ffi.C_int16, [10]int16{}}, {"int32[10]", 10, ffi.C_int32, [10]int32{}}, {"int64[10]", 10, ffi.C_int64, [10]int64{}}, } { ctyp, err := ffi.NewArrayType(tt.len, tt.t) if err != nil { t.Errorf(err.Error()) } cval := ffi.New(ctyp) eq(t, tt.n, cval.Type().Name()) eq(t, ctyp.Kind(), cval.Kind()) gtyp := reflect.TypeOf(tt.val) gval := reflect.New(gtyp).Elem() eq(t, gval.Len(), cval.Len()) for i := 0; i < gval.Len(); i++ { eq(t, gval.Index(i).Int(), cval.Index(i).Int()) gval.Index(i).SetInt(val) cval.Index(i).SetInt(val) eq(t, gval.Index(i).Int(), cval.Index(i).Int()) } } } { const val = -66.2 for _, tt := range []struct { n string len int t ffi.Type val interface{} }{ {"float[10]", 10, ffi.C_float, [10]float32{}}, {"double[10]", 10, ffi.C_double, [10]float64{}}, // FIXME: go has no long double equivalent //{"long double[10]", 10, ffi.C_longdouble, [10]float128{}}, } { ctyp, err := ffi.NewArrayType(tt.len, tt.t) if err != nil { t.Errorf(err.Error()) } cval := ffi.New(ctyp) eq(t, tt.n, cval.Type().Name()) eq(t, ctyp.Kind(), cval.Kind()) gtyp := reflect.TypeOf(tt.val) gval := reflect.New(gtyp).Elem() eq(t, gval.Len(), cval.Len()) for i := 0; i < gval.Len(); i++ { eq(t, gval.Index(i).Float(), cval.Index(i).Float()) gval.Index(i).SetFloat(val) cval.Index(i).SetFloat(val) eq(t, gval.Index(i).Float(), cval.Index(i).Float()) } } } }
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()) } } } }
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()) }
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) } } }