370 lines
8.2 KiB
Go
370 lines
8.2 KiB
Go
|
package dbus
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"encoding/binary"
|
||
|
"io/ioutil"
|
||
|
"math"
|
||
|
"reflect"
|
||
|
"testing"
|
||
|
)
|
||
|
|
||
|
var protoTests = []struct {
|
||
|
vs []interface{}
|
||
|
bigEndian []byte
|
||
|
littleEndian []byte
|
||
|
}{
|
||
|
{
|
||
|
[]interface{}{int32(0)},
|
||
|
[]byte{0, 0, 0, 0},
|
||
|
[]byte{0, 0, 0, 0},
|
||
|
},
|
||
|
{
|
||
|
[]interface{}{true, false},
|
||
|
[]byte{0, 0, 0, 1, 0, 0, 0, 0},
|
||
|
[]byte{1, 0, 0, 0, 0, 0, 0, 0},
|
||
|
},
|
||
|
{
|
||
|
[]interface{}{byte(0), uint16(12), int16(32), uint32(43)},
|
||
|
[]byte{0, 0, 0, 12, 0, 32, 0, 0, 0, 0, 0, 43},
|
||
|
[]byte{0, 0, 12, 0, 32, 0, 0, 0, 43, 0, 0, 0},
|
||
|
},
|
||
|
{
|
||
|
[]interface{}{int64(-1), uint64(1<<64 - 1)},
|
||
|
bytes.Repeat([]byte{255}, 16),
|
||
|
bytes.Repeat([]byte{255}, 16),
|
||
|
},
|
||
|
{
|
||
|
[]interface{}{math.Inf(+1)},
|
||
|
[]byte{0x7f, 0xf0, 0, 0, 0, 0, 0, 0},
|
||
|
[]byte{0, 0, 0, 0, 0, 0, 0xf0, 0x7f},
|
||
|
},
|
||
|
{
|
||
|
[]interface{}{"foo"},
|
||
|
[]byte{0, 0, 0, 3, 'f', 'o', 'o', 0},
|
||
|
[]byte{3, 0, 0, 0, 'f', 'o', 'o', 0},
|
||
|
},
|
||
|
{
|
||
|
[]interface{}{Signature{"ai"}},
|
||
|
[]byte{2, 'a', 'i', 0},
|
||
|
[]byte{2, 'a', 'i', 0},
|
||
|
},
|
||
|
{
|
||
|
[]interface{}{[]int16{42, 256}},
|
||
|
[]byte{0, 0, 0, 4, 0, 42, 1, 0},
|
||
|
[]byte{4, 0, 0, 0, 42, 0, 0, 1},
|
||
|
},
|
||
|
{
|
||
|
[]interface{}{MakeVariant("foo")},
|
||
|
[]byte{1, 's', 0, 0, 0, 0, 0, 3, 'f', 'o', 'o', 0},
|
||
|
[]byte{1, 's', 0, 0, 3, 0, 0, 0, 'f', 'o', 'o', 0},
|
||
|
},
|
||
|
{
|
||
|
[]interface{}{MakeVariant(MakeVariant(Signature{"v"}))},
|
||
|
[]byte{1, 'v', 0, 1, 'g', 0, 1, 'v', 0},
|
||
|
[]byte{1, 'v', 0, 1, 'g', 0, 1, 'v', 0},
|
||
|
},
|
||
|
{
|
||
|
[]interface{}{map[int32]bool{42: true}},
|
||
|
[]byte{0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 1},
|
||
|
[]byte{8, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 1, 0, 0, 0},
|
||
|
},
|
||
|
{
|
||
|
[]interface{}{map[string]Variant{}, byte(42)},
|
||
|
[]byte{0, 0, 0, 0, 0, 0, 0, 0, 42},
|
||
|
[]byte{0, 0, 0, 0, 0, 0, 0, 0, 42},
|
||
|
},
|
||
|
{
|
||
|
[]interface{}{[]uint64{}, byte(42)},
|
||
|
[]byte{0, 0, 0, 0, 0, 0, 0, 0, 42},
|
||
|
[]byte{0, 0, 0, 0, 0, 0, 0, 0, 42},
|
||
|
},
|
||
|
}
|
||
|
|
||
|
func TestProto(t *testing.T) {
|
||
|
for i, v := range protoTests {
|
||
|
buf := new(bytes.Buffer)
|
||
|
bigEnc := newEncoder(buf, binary.BigEndian)
|
||
|
bigEnc.Encode(v.vs...)
|
||
|
marshalled := buf.Bytes()
|
||
|
if bytes.Compare(marshalled, v.bigEndian) != 0 {
|
||
|
t.Errorf("test %d (marshal be): got '%v', but expected '%v'\n", i+1, marshalled,
|
||
|
v.bigEndian)
|
||
|
}
|
||
|
buf.Reset()
|
||
|
litEnc := newEncoder(buf, binary.LittleEndian)
|
||
|
litEnc.Encode(v.vs...)
|
||
|
marshalled = buf.Bytes()
|
||
|
if bytes.Compare(marshalled, v.littleEndian) != 0 {
|
||
|
t.Errorf("test %d (marshal le): got '%v', but expected '%v'\n", i+1, marshalled,
|
||
|
v.littleEndian)
|
||
|
}
|
||
|
unmarshalled := reflect.MakeSlice(reflect.TypeOf(v.vs),
|
||
|
0, 0)
|
||
|
for i := range v.vs {
|
||
|
unmarshalled = reflect.Append(unmarshalled,
|
||
|
reflect.New(reflect.TypeOf(v.vs[i])))
|
||
|
}
|
||
|
bigDec := newDecoder(bytes.NewReader(v.bigEndian), binary.BigEndian)
|
||
|
vs, err := bigDec.Decode(SignatureOf(v.vs...))
|
||
|
if err != nil {
|
||
|
t.Errorf("test %d (unmarshal be): %s\n", i+1, err)
|
||
|
continue
|
||
|
}
|
||
|
if !reflect.DeepEqual(vs, v.vs) {
|
||
|
t.Errorf("test %d (unmarshal be): got %#v, but expected %#v\n", i+1, vs, v.vs)
|
||
|
}
|
||
|
litDec := newDecoder(bytes.NewReader(v.littleEndian), binary.LittleEndian)
|
||
|
vs, err = litDec.Decode(SignatureOf(v.vs...))
|
||
|
if err != nil {
|
||
|
t.Errorf("test %d (unmarshal le): %s\n", i+1, err)
|
||
|
continue
|
||
|
}
|
||
|
if !reflect.DeepEqual(vs, v.vs) {
|
||
|
t.Errorf("test %d (unmarshal le): got %#v, but expected %#v\n", i+1, vs, v.vs)
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestProtoMap(t *testing.T) {
|
||
|
m := map[string]uint8{
|
||
|
"foo": 23,
|
||
|
"bar": 2,
|
||
|
}
|
||
|
var n map[string]uint8
|
||
|
buf := new(bytes.Buffer)
|
||
|
enc := newEncoder(buf, binary.LittleEndian)
|
||
|
enc.Encode(m)
|
||
|
dec := newDecoder(buf, binary.LittleEndian)
|
||
|
vs, err := dec.Decode(Signature{"a{sy}"})
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
if err = Store(vs, &n); err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
if len(n) != 2 || n["foo"] != 23 || n["bar"] != 2 {
|
||
|
t.Error("got", n)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestProtoVariantStruct(t *testing.T) {
|
||
|
var variant Variant
|
||
|
v := MakeVariant(struct {
|
||
|
A int32
|
||
|
B int16
|
||
|
}{1, 2})
|
||
|
buf := new(bytes.Buffer)
|
||
|
enc := newEncoder(buf, binary.LittleEndian)
|
||
|
enc.Encode(v)
|
||
|
dec := newDecoder(buf, binary.LittleEndian)
|
||
|
vs, err := dec.Decode(Signature{"v"})
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
if err = Store(vs, &variant); err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
sl := variant.Value().([]interface{})
|
||
|
v1, v2 := sl[0].(int32), sl[1].(int16)
|
||
|
if v1 != int32(1) {
|
||
|
t.Error("got", v1, "as first int")
|
||
|
}
|
||
|
if v2 != int16(2) {
|
||
|
t.Error("got", v2, "as second int")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestProtoStructTag(t *testing.T) {
|
||
|
type Bar struct {
|
||
|
A int32
|
||
|
B chan interface{} `dbus:"-"`
|
||
|
C int32
|
||
|
}
|
||
|
var bar1, bar2 Bar
|
||
|
bar1.A = 234
|
||
|
bar2.C = 345
|
||
|
buf := new(bytes.Buffer)
|
||
|
enc := newEncoder(buf, binary.LittleEndian)
|
||
|
enc.Encode(bar1)
|
||
|
dec := newDecoder(buf, binary.LittleEndian)
|
||
|
vs, err := dec.Decode(Signature{"(ii)"})
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
if err = Store(vs, &bar2); err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
if bar1 != bar2 {
|
||
|
t.Error("struct tag test: got", bar2)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestProtoStoreStruct(t *testing.T) {
|
||
|
var foo struct {
|
||
|
A int32
|
||
|
B string
|
||
|
c chan interface{}
|
||
|
D interface{} `dbus:"-"`
|
||
|
}
|
||
|
src := []interface{}{[]interface{}{int32(42), "foo"}}
|
||
|
err := Store(src, &foo)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestProtoStoreNestedStruct(t *testing.T) {
|
||
|
var foo struct {
|
||
|
A int32
|
||
|
B struct {
|
||
|
C string
|
||
|
D float64
|
||
|
}
|
||
|
}
|
||
|
src := []interface{}{
|
||
|
[]interface{}{
|
||
|
int32(42),
|
||
|
[]interface{}{
|
||
|
"foo",
|
||
|
3.14,
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
err := Store(src, &foo)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestMessage(t *testing.T) {
|
||
|
buf := new(bytes.Buffer)
|
||
|
message := new(Message)
|
||
|
message.Type = TypeMethodCall
|
||
|
message.serial = 32
|
||
|
message.Headers = map[HeaderField]Variant{
|
||
|
FieldPath: MakeVariant(ObjectPath("/org/foo/bar")),
|
||
|
FieldMember: MakeVariant("baz"),
|
||
|
}
|
||
|
message.Body = make([]interface{}, 0)
|
||
|
err := message.EncodeTo(buf, binary.LittleEndian)
|
||
|
if err != nil {
|
||
|
t.Error(err)
|
||
|
}
|
||
|
_, err = DecodeMessage(buf)
|
||
|
if err != nil {
|
||
|
t.Error(err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestProtoStructInterfaces(t *testing.T) {
|
||
|
b := []byte{42}
|
||
|
vs, err := newDecoder(bytes.NewReader(b), binary.LittleEndian).Decode(Signature{"(y)"})
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
if vs[0].([]interface{})[0].(byte) != 42 {
|
||
|
t.Errorf("wrongs results (got %v)", vs)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// ordinary org.freedesktop.DBus.Hello call
|
||
|
var smallMessage = &Message{
|
||
|
Type: TypeMethodCall,
|
||
|
serial: 1,
|
||
|
Headers: map[HeaderField]Variant{
|
||
|
FieldDestination: MakeVariant("org.freedesktop.DBus"),
|
||
|
FieldPath: MakeVariant(ObjectPath("/org/freedesktop/DBus")),
|
||
|
FieldInterface: MakeVariant("org.freedesktop.DBus"),
|
||
|
FieldMember: MakeVariant("Hello"),
|
||
|
},
|
||
|
}
|
||
|
|
||
|
// org.freedesktop.Notifications.Notify
|
||
|
var bigMessage = &Message{
|
||
|
Type: TypeMethodCall,
|
||
|
serial: 2,
|
||
|
Headers: map[HeaderField]Variant{
|
||
|
FieldDestination: MakeVariant("org.freedesktop.Notifications"),
|
||
|
FieldPath: MakeVariant(ObjectPath("/org/freedesktop/Notifications")),
|
||
|
FieldInterface: MakeVariant("org.freedesktop.Notifications"),
|
||
|
FieldMember: MakeVariant("Notify"),
|
||
|
FieldSignature: MakeVariant(Signature{"susssasa{sv}i"}),
|
||
|
},
|
||
|
Body: []interface{}{
|
||
|
"app_name",
|
||
|
uint32(0),
|
||
|
"dialog-information",
|
||
|
"Notification",
|
||
|
"This is the body of a notification",
|
||
|
[]string{"ok", "Ok"},
|
||
|
map[string]Variant{
|
||
|
"sound-name": MakeVariant("dialog-information"),
|
||
|
},
|
||
|
int32(-1),
|
||
|
},
|
||
|
}
|
||
|
|
||
|
func BenchmarkDecodeMessageSmall(b *testing.B) {
|
||
|
var err error
|
||
|
var rd *bytes.Reader
|
||
|
|
||
|
b.StopTimer()
|
||
|
buf := new(bytes.Buffer)
|
||
|
err = smallMessage.EncodeTo(buf, binary.LittleEndian)
|
||
|
if err != nil {
|
||
|
b.Fatal(err)
|
||
|
}
|
||
|
decoded := buf.Bytes()
|
||
|
b.StartTimer()
|
||
|
for i := 0; i < b.N; i++ {
|
||
|
rd = bytes.NewReader(decoded)
|
||
|
_, err = DecodeMessage(rd)
|
||
|
if err != nil {
|
||
|
b.Fatal(err)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func BenchmarkDecodeMessageBig(b *testing.B) {
|
||
|
var err error
|
||
|
var rd *bytes.Reader
|
||
|
|
||
|
b.StopTimer()
|
||
|
buf := new(bytes.Buffer)
|
||
|
err = bigMessage.EncodeTo(buf, binary.LittleEndian)
|
||
|
if err != nil {
|
||
|
b.Fatal(err)
|
||
|
}
|
||
|
decoded := buf.Bytes()
|
||
|
b.StartTimer()
|
||
|
for i := 0; i < b.N; i++ {
|
||
|
rd = bytes.NewReader(decoded)
|
||
|
_, err = DecodeMessage(rd)
|
||
|
if err != nil {
|
||
|
b.Fatal(err)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func BenchmarkEncodeMessageSmall(b *testing.B) {
|
||
|
var err error
|
||
|
for i := 0; i < b.N; i++ {
|
||
|
err = smallMessage.EncodeTo(ioutil.Discard, binary.LittleEndian)
|
||
|
if err != nil {
|
||
|
b.Fatal(err)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func BenchmarkEncodeMessageBig(b *testing.B) {
|
||
|
var err error
|
||
|
for i := 0; i < b.N; i++ {
|
||
|
err = bigMessage.EncodeTo(ioutil.Discard, binary.LittleEndian)
|
||
|
if err != nil {
|
||
|
b.Fatal(err)
|
||
|
}
|
||
|
}
|
||
|
}
|