From 7633b9672f36d0ca3f339d53fc42959648fef8ef Mon Sep 17 00:00:00 2001 From: Jakob Borg Date: Mon, 30 Jun 2014 12:56:09 +0200 Subject: [PATCH] XDR incorrect encoding of uint16; tests and benchmarks --- xdr/bench_test.go | 57 ++++++++++++++++++++++++++++++++++++++++++ xdr/bench_xdr_test.go | 53 +++++++++++++++++++++++++++++++++++++++ xdr/encdec_test.go | 51 +++++++++++++++++++++++++++++++++++++ xdr/encdec_xdr_test.go | 57 ++++++++++++++++++++++++++++++++++++++++++ xdr/reader.go | 2 +- xdr/refl_test.go | 45 +++++++++++++++++++++++++++++++++ xdr/writer.go | 8 +++--- 7 files changed, 268 insertions(+), 5 deletions(-) create mode 100644 xdr/bench_test.go create mode 100644 xdr/bench_xdr_test.go create mode 100644 xdr/encdec_test.go create mode 100644 xdr/encdec_xdr_test.go create mode 100644 xdr/refl_test.go diff --git a/xdr/bench_test.go b/xdr/bench_test.go new file mode 100644 index 000000000..1d6e0a2b3 --- /dev/null +++ b/xdr/bench_test.go @@ -0,0 +1,57 @@ +// Copyright (C) 2014 Jakob Borg and other contributors. All rights reserved. +// Use of this source code is governed by an MIT-style license that can be +// found in the LICENSE file. + +package xdr_test + +import ( + "bytes" + "testing" +) + +type XDRBenchStruct struct { + I1 uint64 + I2 uint32 + I3 uint16 + Bs []byte + S string +} + +var res []byte // no to be optimized away +var s = XDRBenchStruct{ + I1: 42, + I2: 43, + I3: 44, + Bs: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}, + S: "Hello World!", +} +var e = s.MarshalXDR() + +func BenchmarkThisMarshal(b *testing.B) { + for i := 0; i < b.N; i++ { + res = s.MarshalXDR() + } +} + +func BenchmarkThisUnmarshal(b *testing.B) { + var t XDRBenchStruct + for i := 0; i < b.N; i++ { + err := t.UnmarshalXDR(e) + if err != nil { + b.Fatal(err) + } + } +} + +func BenchmarkEncode(b *testing.B) { + bs := make([]byte, 0, 65536) + buf := bytes.NewBuffer(bs) + + for i := 0; i < b.N; i++ { + _, err := s.EncodeXDR(buf) + if err != nil { + b.Fatal(err) + } + buf.Reset() + } +} diff --git a/xdr/bench_xdr_test.go b/xdr/bench_xdr_test.go new file mode 100644 index 000000000..b016acfaf --- /dev/null +++ b/xdr/bench_xdr_test.go @@ -0,0 +1,53 @@ +// Copyright (C) 2014 Jakob Borg and other contributors. All rights reserved. +// Use of this source code is governed by an MIT-style license that can be +// found in the LICENSE file. + +package xdr_test + +import ( + "bytes" + "io" + + "github.com/calmh/syncthing/xdr" +) + +func (o XDRBenchStruct) EncodeXDR(w io.Writer) (int, error) { + var xw = xdr.NewWriter(w) + return o.encodeXDR(xw) +} + +func (o XDRBenchStruct) MarshalXDR() []byte { + var buf bytes.Buffer + var xw = xdr.NewWriter(&buf) + o.encodeXDR(xw) + return buf.Bytes() +} + +func (o XDRBenchStruct) encodeXDR(xw *xdr.Writer) (int, error) { + xw.WriteUint64(o.I1) + xw.WriteUint32(o.I2) + xw.WriteUint16(o.I3) + xw.WriteBytes(o.Bs) + xw.WriteString(o.S) + return xw.Tot(), xw.Error() +} + +func (o *XDRBenchStruct) DecodeXDR(r io.Reader) error { + xr := xdr.NewReader(r) + return o.decodeXDR(xr) +} + +func (o *XDRBenchStruct) UnmarshalXDR(bs []byte) error { + var buf = bytes.NewBuffer(bs) + var xr = xdr.NewReader(buf) + return o.decodeXDR(xr) +} + +func (o *XDRBenchStruct) decodeXDR(xr *xdr.Reader) error { + o.I1 = xr.ReadUint64() + o.I2 = xr.ReadUint32() + o.I3 = xr.ReadUint16() + o.Bs = xr.ReadBytes() + o.S = xr.ReadString() + return xr.Error() +} diff --git a/xdr/encdec_test.go b/xdr/encdec_test.go new file mode 100644 index 000000000..1d93daf17 --- /dev/null +++ b/xdr/encdec_test.go @@ -0,0 +1,51 @@ +// Copyright (C) 2014 Jakob Borg and other contributors. All rights reserved. +// Use of this source code is governed by an MIT-style license that can be +// found in the LICENSE file. + +package xdr_test + +import ( + "bytes" + "testing" + "testing/quick" +) + +// Contains all supported types +type TestStruct struct { + I int + I16 int16 + UI16 uint16 + I32 int32 + UI32 uint32 + I64 int64 + UI64 uint64 + BS []byte + S string +} + +func TestEncDec(t *testing.T) { + fn := func(t0 TestStruct) bool { + bs := t0.MarshalXDR() + var t1 TestStruct + err := t1.UnmarshalXDR(bs) + if err != nil { + t.Fatal(err) + } + + // Not comparing with DeepEqual since we'll unmarshal nil slices as empty + if t0.I != t1.I || + t0.I16 != t1.I16 || t0.UI16 != t1.UI16 || + t0.I32 != t1.I32 || t0.UI32 != t1.UI32 || + t0.I64 != t1.I64 || t0.UI64 != t1.UI64 || + bytes.Compare(t0.BS, t1.BS) != 0 || + t0.S != t1.S { + t.Logf("%#v", t0) + t.Logf("%#v", t1) + return false + } + return true + } + if err := quick.Check(fn, nil); err != nil { + t.Error(err) + } +} diff --git a/xdr/encdec_xdr_test.go b/xdr/encdec_xdr_test.go new file mode 100644 index 000000000..a2964c358 --- /dev/null +++ b/xdr/encdec_xdr_test.go @@ -0,0 +1,57 @@ +package xdr_test + +import ( + "bytes" + "io" + + "github.com/calmh/syncthing/xdr" +) + +func (o TestStruct) EncodeXDR(w io.Writer) (int, error) { + var xw = xdr.NewWriter(w) + return o.encodeXDR(xw) +} + +func (o TestStruct) MarshalXDR() []byte { + var buf bytes.Buffer + var xw = xdr.NewWriter(&buf) + o.encodeXDR(xw) + return buf.Bytes() +} + +func (o TestStruct) encodeXDR(xw *xdr.Writer) (int, error) { + xw.WriteUint64(uint64(o.I)) + xw.WriteUint16(uint16(o.I16)) + xw.WriteUint16(o.UI16) + xw.WriteUint32(uint32(o.I32)) + xw.WriteUint32(o.UI32) + xw.WriteUint64(uint64(o.I64)) + xw.WriteUint64(o.UI64) + xw.WriteBytes(o.BS) + xw.WriteString(o.S) + return xw.Tot(), xw.Error() +} + +func (o *TestStruct) DecodeXDR(r io.Reader) error { + xr := xdr.NewReader(r) + return o.decodeXDR(xr) +} + +func (o *TestStruct) UnmarshalXDR(bs []byte) error { + var buf = bytes.NewBuffer(bs) + var xr = xdr.NewReader(buf) + return o.decodeXDR(xr) +} + +func (o *TestStruct) decodeXDR(xr *xdr.Reader) error { + o.I = int(xr.ReadUint64()) + o.I16 = int16(xr.ReadUint16()) + o.UI16 = xr.ReadUint16() + o.I32 = int32(xr.ReadUint32()) + o.UI32 = xr.ReadUint32() + o.I64 = int64(xr.ReadUint64()) + o.UI64 = xr.ReadUint64() + o.BS = xr.ReadBytes() + o.S = xr.ReadString() + return xr.Error() +} diff --git a/xdr/reader.go b/xdr/reader.go index a634d9dff..b668a6f0b 100644 --- a/xdr/reader.go +++ b/xdr/reader.go @@ -105,7 +105,7 @@ func (r *Reader) ReadUint16() uint16 { return 0 } - v := uint16(r.b[1]) | uint16(r.b[0])<<8 + v := uint16(r.b[3]) | uint16(r.b[2])<<8 if debug { dl.Debugf("@0x%x: rd uint16=%d (0x%04x)", s, v, v) diff --git a/xdr/refl_test.go b/xdr/refl_test.go new file mode 100644 index 000000000..abccbdb26 --- /dev/null +++ b/xdr/refl_test.go @@ -0,0 +1,45 @@ +// Copyright (C) 2014 Jakob Borg and other contributors. All rights reserved. +// Use of this source code is governed by an MIT-style license that can be +// found in the LICENSE file. + +// +build refl + +package xdr_test + +import ( + "bytes" + "testing" + + refl "github.com/davecgh/go-xdr/xdr" +) + +func TestCompareMarshals(t *testing.T) { + e0 := s.MarshalXDR() + e1, err := refl.Marshal(s) + if err != nil { + t.Fatal(err) + } + if bytes.Compare(e0, e1) != 0 { + t.Fatalf("Encoding mismatch;\n\t%x (this)\n\t%x (refl)", e0, e1) + } +} + +func BenchmarkReflMarshal(b *testing.B) { + var err error + for i := 0; i < b.N; i++ { + res, err = refl.Marshal(s) + if err != nil { + b.Fatal(err) + } + } +} + +func BenchmarkReflUnmarshal(b *testing.B) { + var t XDRBenchStruct + for i := 0; i < b.N; i++ { + _, err := refl.Unmarshal(e, &t) + if err != nil { + b.Fatal(err) + } + } +} diff --git a/xdr/writer.go b/xdr/writer.go index d56624974..3ac552903 100644 --- a/xdr/writer.go +++ b/xdr/writer.go @@ -79,10 +79,10 @@ func (w *Writer) WriteUint16(v uint16) (int, error) { dl.Debugf("wr uint16=%d", v) } - w.b[0] = byte(v >> 8) - w.b[1] = byte(v) - w.b[2] = 0 - w.b[3] = 0 + w.b[0] = 0 + w.b[1] = 0 + w.b[2] = byte(v >> 8) + w.b[3] = byte(v) var l int l, w.err = w.w.Write(w.b[:4])