1// Copyright 2019 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// The protoreflect tag disables fast-path methods, including legacy ones.
6// +build !protoreflect
7
8package proto_test
9
10import (
11	"bytes"
12	"errors"
13	"fmt"
14	"testing"
15
16	"google.golang.org/protobuf/internal/impl"
17	"google.golang.org/protobuf/proto"
18	"google.golang.org/protobuf/runtime/protoiface"
19
20	legacypb "google.golang.org/protobuf/internal/testprotos/legacy"
21)
22
23type selfMarshaler struct {
24	bytes []byte
25	err   error
26}
27
28func (m selfMarshaler) Reset()        {}
29func (m selfMarshaler) ProtoMessage() {}
30
31func (m selfMarshaler) String() string {
32	return fmt.Sprintf("selfMarshaler{bytes:%v, err:%v}", m.bytes, m.err)
33}
34
35func (m selfMarshaler) Marshal() ([]byte, error) {
36	return m.bytes, m.err
37}
38
39func (m *selfMarshaler) Unmarshal(b []byte) error {
40	m.bytes = b
41	return m.err
42}
43
44func TestLegacyMarshalMethod(t *testing.T) {
45	for _, test := range []selfMarshaler{
46		{bytes: []byte("marshal")},
47		{bytes: []byte("marshal"), err: errors.New("some error")},
48	} {
49		m := impl.Export{}.MessageOf(test).Interface()
50		b, err := proto.Marshal(m)
51		if err != test.err || !bytes.Equal(b, test.bytes) {
52			t.Errorf("proto.Marshal(%v) = %v, %v; want %v, %v", test, b, err, test.bytes, test.err)
53		}
54		if gotSize, wantSize := proto.Size(m), len(test.bytes); gotSize != wantSize {
55			t.Fatalf("proto.Size(%v) = %v, want %v", test, gotSize, wantSize)
56		}
57
58		prefix := []byte("prefix")
59		want := append(prefix, test.bytes...)
60		b, err = proto.MarshalOptions{}.MarshalAppend(prefix, m)
61		if err != test.err || !bytes.Equal(b, want) {
62			t.Errorf("MarshalAppend(%v, %v) = %v, %v; want %v, %v", prefix, test, b, err, test.bytes, test.err)
63		}
64
65		b, err = proto.MarshalOptions{
66			Deterministic: true,
67		}.MarshalAppend(nil, m)
68		if err != test.err || !bytes.Equal(b, test.bytes) {
69			t.Errorf("MarshalOptions{Deterministic:true}.MarshalAppend(nil, %v) = %v, %v; want %v, %v", test, b, err, test.bytes, test.err)
70		}
71	}
72}
73
74func TestLegacyUnmarshalMethod(t *testing.T) {
75	sm := &selfMarshaler{}
76	m := impl.Export{}.MessageOf(sm).Interface()
77	want := []byte("unmarshal")
78	if err := proto.Unmarshal(want, m); err != nil {
79		t.Fatalf("proto.Unmarshal(selfMarshaler{}) = %v, want nil", err)
80	}
81	if !bytes.Equal(sm.bytes, want) {
82		t.Fatalf("proto.Unmarshal(selfMarshaler{}): Marshal method not called")
83	}
84}
85
86type descPanicSelfMarshaler struct{}
87
88const descPanicSelfMarshalerBytes = "bytes"
89
90func (m *descPanicSelfMarshaler) Reset()                      {}
91func (m *descPanicSelfMarshaler) ProtoMessage()               {}
92func (m *descPanicSelfMarshaler) Descriptor() ([]byte, []int) { panic("Descriptor method panics") }
93func (m *descPanicSelfMarshaler) String() string              { return "descPanicSelfMarshaler{}" }
94func (m *descPanicSelfMarshaler) Marshal() ([]byte, error) {
95	return []byte(descPanicSelfMarshalerBytes), nil
96}
97
98func TestSelfMarshalerDescriptorPanics(t *testing.T) {
99	m := &descPanicSelfMarshaler{}
100	got, err := proto.Marshal(impl.Export{}.MessageOf(m).Interface())
101	want := []byte(descPanicSelfMarshalerBytes)
102	if err != nil || !bytes.Equal(got, want) {
103		t.Fatalf("proto.Marshal(%v) = %v, %v; want %v, nil", m, got, err, want)
104	}
105}
106
107type descSelfMarshaler struct {
108	someField int // some non-generated field
109}
110
111const descSelfMarshalerBytes = "bytes"
112
113func (m *descSelfMarshaler) Reset()        {}
114func (m *descSelfMarshaler) ProtoMessage() {}
115func (m *descSelfMarshaler) Descriptor() ([]byte, []int) {
116	return ((*legacypb.Legacy)(nil)).GetF1().Descriptor()
117}
118func (m *descSelfMarshaler) String() string {
119	return "descSelfMarshaler{}"
120}
121func (m *descSelfMarshaler) Marshal() ([]byte, error) {
122	return []byte(descSelfMarshalerBytes), nil
123}
124
125func TestSelfMarshalerWithDescriptor(t *testing.T) {
126	m := &descSelfMarshaler{}
127	got, err := proto.Marshal(impl.Export{}.MessageOf(m).Interface())
128	want := []byte(descSelfMarshalerBytes)
129	if err != nil || !bytes.Equal(got, want) {
130		t.Fatalf("proto.Marshal(%v) = %v, %v; want %v, nil", m, got, err, want)
131	}
132}
133
134func TestDecodeFastCheckInitialized(t *testing.T) {
135	for _, test := range testValidMessages {
136		if !test.checkFastInit {
137			continue
138		}
139		for _, message := range test.decodeTo {
140			t.Run(fmt.Sprintf("%s (%T)", test.desc, message), func(t *testing.T) {
141				m := message.ProtoReflect().New()
142				opts := proto.UnmarshalOptions{
143					AllowPartial: true,
144				}
145				out, err := opts.UnmarshalState(protoiface.UnmarshalInput{
146					Buf:     test.wire,
147					Message: m,
148				})
149				if err != nil {
150					t.Fatalf("Unmarshal error: %v", err)
151				}
152				if got, want := (out.Flags&protoiface.UnmarshalInitialized != 0), !test.partial; got != want {
153					t.Errorf("out.Initialized = %v, want %v", got, want)
154				}
155			})
156		}
157	}
158}
159
160type selfMerger struct {
161	src protoiface.MessageV1
162}
163
164func (*selfMerger) Reset()         {}
165func (*selfMerger) ProtoMessage()  {}
166func (*selfMerger) String() string { return "selfMerger{}" }
167func (m *selfMerger) Merge(src protoiface.MessageV1) {
168	m.src = src
169}
170
171func TestLegacyMergeMethod(t *testing.T) {
172	src := &selfMerger{}
173	dst := &selfMerger{}
174	proto.Merge(
175		impl.Export{}.MessageOf(dst).Interface(),
176		impl.Export{}.MessageOf(src).Interface(),
177	)
178	if got, want := dst.src, src; got != want {
179		t.Errorf("Merge(dst, src): want dst.src = src, got %v", got)
180	}
181	if got := src.src; got != nil {
182		t.Errorf("Merge(dst, src): want src.src = nil, got %v", got)
183	}
184}
185