package proto import ( "bytes" "math" "testing" ) func TestAppendVarint(t *testing.T) { m := AppendVarint(nil, 1, 42) f, w, v, r, err := Parse(m) if err != nil { t.Fatal(err) } if len(r) != 0 { t.Fatal("unexpected trailing bytes:", r) } if w != Varint { t.Fatal("unexpected wire type:", t) } if f != 1 { t.Fatal("unexpected field number:", f) } if u := v.Varint(); u != 42 { t.Fatal("value mismatch, want 42 but got", u) } } func TestAppendVarlen(t *testing.T) { m := AppendVarlen(nil, 1, []byte("Hello World!")) f, w, v, r, err := Parse(m) if err != nil { t.Fatal(err) } if len(r) != 0 { t.Fatal("unexpected trailing bytes:", r) } if w != Varlen { t.Fatal("unexpected wire type:", t) } if f != 1 { t.Fatal("unexpected field number:", f) } if string(v) != "Hello World!" { t.Fatalf("value mismatch, want \"Hello World!\" but got %q", v) } } func TestAppendFixed32(t *testing.T) { m := AppendFixed32(nil, 1, 42) f, w, v, r, err := Parse(m) if err != nil { t.Fatal(err) } if len(r) != 0 { t.Fatal("unexpected trailing bytes:", r) } if w != Fixed32 { t.Fatal("unexpected wire type:", t) } if f != 1 { t.Fatal("unexpected field number:", f) } if u := v.Fixed32(); u != 42 { t.Fatal("value mismatch, want 42 but got", u) } } func TestAppendFixed64(t *testing.T) { m := AppendFixed64(nil, 1, 42) f, w, v, r, err := Parse(m) if err != nil { t.Fatal(err) } if len(r) != 0 { t.Fatal("unexpected trailing bytes:", r) } if w != Fixed64 { t.Fatal("unexpected wire type:", t) } if f != 1 { t.Fatal("unexpected field number:", f) } if u := v.Fixed64(); u != 42 { t.Fatal("value mismatch, want 42 but got", u) } } func TestDecodeFromAppend(t *testing.T) { m := RawMessage(nil) m = AppendVarint(m, 1, math.MaxUint64) m = AppendVarlen(m, 2, []byte("Hello World!")) m = AppendFixed32(m, 3, math.Float32bits(42.0)) m = AppendFixed64(m, 4, math.Float64bits(1234.0)) type M struct { I int S string F32 float32 F64 float64 } x := M{} if err := Unmarshal(m, &x); err != nil { t.Fatal(err) } if x.I != -1 { t.Errorf("x.I=%d", x.I) } if x.S != "Hello World!" { t.Errorf("x.S=%q", x.S) } if x.F32 != 42 { t.Errorf("x.F32=%g", x.F32) } if x.F64 != 1234 { t.Errorf("x.F64=%g", x.F64) } } func TestDecodeFixture(t *testing.T) { m := loadProtobuf(t, "message.pb") m = assertParse(t, m, 1, Varint, makeVarint(10)) m = assertParse(t, m, 2, Varint, makeVarint(20)) m = assertParse(t, m, 3, Varint, makeVarint(30)) m = assertParse(t, m, 4, Varlen, []byte("Hello World!")) assertEmpty(t, m) } func assertParse(t *testing.T, m RawMessage, f FieldNumber, w WireType, b []byte) RawMessage { t.Helper() f0, w0, b0, m, err := Parse(m) if err != nil { t.Fatal(err) } if f0 != f { t.Errorf("field number mismatch, want %d but got %d", f, f0) } if w0 != w { t.Errorf("wire type mismatch, want %d but got %d", w, w0) } if !bytes.Equal(b0, b) { t.Errorf("value mismatch, want %v but got %v", b, b0) } return m } func assertEmpty(t *testing.T, m RawMessage) { t.Helper() if len(m) != 0 { t.Errorf("unexpected content remained in the protobuf message: %v", m) } } func BenchmarkScan(b *testing.B) { m, _ := Marshal(&message{ A: 1, B: 2, C: 3, S: submessage{ X: "hello", Y: "world", }, }) for i := 0; i < b.N; i++ { Scan(m, func(f FieldNumber, t WireType, v RawValue) (bool, error) { switch f { case 1, 2, 3: return true, nil case 4: err := Scan(v, func(f FieldNumber, t WireType, v RawValue) (bool, error) { switch f { case 1, 2: return true, nil default: b.Error("invalid field number:", f) return false, nil } }) return err != nil, err default: b.Error("invalid field number:", f) return false, nil } }) } }