1package pgs
2
3import (
4	"errors"
5	"testing"
6
7	desc "github.com/golang/protobuf/descriptor"
8	"github.com/golang/protobuf/proto"
9	"github.com/golang/protobuf/protoc-gen-go/descriptor"
10	"github.com/golang/protobuf/ptypes/any"
11	"github.com/stretchr/testify/assert"
12)
13
14func TestMsg_Name(t *testing.T) {
15	t.Parallel()
16
17	m := &msg{desc: &descriptor.DescriptorProto{Name: proto.String("msg")}}
18
19	assert.Equal(t, "msg", m.Name().String())
20}
21
22func TestMsg_FullyQualifiedName(t *testing.T) {
23	t.Parallel()
24
25	m := &msg{fqn: "msg"}
26	assert.Equal(t, m.fqn, m.FullyQualifiedName())
27}
28
29func TestMsg_Syntax(t *testing.T) {
30	t.Parallel()
31
32	m := &msg{}
33	f := dummyFile()
34	f.addMessage(m)
35
36	assert.Equal(t, f.Syntax(), m.Syntax())
37}
38
39func TestMsg_Package(t *testing.T) {
40	t.Parallel()
41
42	m := &msg{}
43	f := dummyFile()
44	f.addMessage(m)
45
46	assert.NotNil(t, m.Package())
47	assert.Equal(t, f.Package(), m.Package())
48}
49
50func TestMsg_File(t *testing.T) {
51	t.Parallel()
52
53	m := &msg{}
54	pm := dummyMsg()
55	pm.addMessage(m)
56
57	assert.NotNil(t, m.File())
58	assert.Equal(t, pm.File(), m.File())
59}
60
61func TestMsg_BuildTarget(t *testing.T) {
62	t.Parallel()
63
64	m := &msg{}
65	f := dummyFile()
66	f.addMessage(m)
67
68	assert.False(t, m.BuildTarget())
69	f.buildTarget = true
70	assert.True(t, m.BuildTarget())
71}
72
73func TestMsg_Descriptor(t *testing.T) {
74	t.Parallel()
75
76	m := &msg{desc: &descriptor.DescriptorProto{}}
77	assert.Equal(t, m.desc, m.Descriptor())
78}
79
80func TestMsg_Parent(t *testing.T) {
81	t.Parallel()
82
83	m := &msg{}
84	pm := dummyMsg()
85	pm.addMessage(m)
86
87	assert.Equal(t, pm, m.Parent())
88}
89
90func TestMsg_IsMapEntry(t *testing.T) {
91	t.Parallel()
92
93	m := &msg{desc: &descriptor.DescriptorProto{}}
94	assert.False(t, m.IsMapEntry())
95
96	m.desc.Options = &descriptor.MessageOptions{
97		MapEntry: proto.Bool(true),
98	}
99	assert.True(t, m.IsMapEntry())
100}
101
102func TestMsg_Enums(t *testing.T) {
103	t.Parallel()
104
105	m := &msg{}
106	assert.Empty(t, m.Enums())
107
108	sm := &msg{}
109	sm.addEnum(&enum{})
110	m.addMessage(sm)
111
112	m.addEnum(&enum{})
113	assert.Len(t, m.Enums(), 1)
114}
115
116func TestMsg_AllEnums(t *testing.T) {
117	t.Parallel()
118
119	m := &msg{}
120	assert.Empty(t, m.AllEnums())
121
122	sm := &msg{}
123	sm.addEnum(&enum{})
124	m.addMessage(sm)
125
126	m.addEnum(&enum{})
127	assert.Len(t, m.AllEnums(), 2)
128}
129
130func TestMsg_Messages(t *testing.T) {
131	t.Parallel()
132
133	m := &msg{}
134	assert.Empty(t, m.Messages())
135
136	sm := &msg{}
137	sm.addMessage(&msg{})
138	m.addMessage(sm)
139
140	assert.Len(t, m.Messages(), 1)
141}
142
143func TestMsg_AllMessages(t *testing.T) {
144	t.Parallel()
145
146	m := &msg{}
147	assert.Empty(t, m.AllMessages())
148
149	sm := &msg{}
150	sm.addMessage(&msg{})
151	m.addMessage(sm)
152
153	assert.Len(t, m.AllMessages(), 2)
154}
155
156func TestMsg_MapEntries(t *testing.T) {
157	t.Parallel()
158
159	m := &msg{}
160	assert.Empty(t, m.MapEntries())
161
162	m.addMapEntry(&msg{})
163	assert.Len(t, m.MapEntries(), 1)
164}
165
166func TestMsg_Fields(t *testing.T) {
167	t.Parallel()
168
169	m := &msg{}
170	assert.Empty(t, m.Fields())
171
172	m.addField(&field{})
173	m.addField(&field{oneof: &oneof{}})
174	assert.Len(t, m.Fields(), 2)
175}
176
177func TestMsg_NonOneOfFields(t *testing.T) {
178	t.Parallel()
179
180	m := &msg{}
181	assert.Empty(t, m.NonOneOfFields())
182
183	m.addField(&field{})
184	m.addField(&field{oneof: &oneof{}})
185	m.addField(&field{})
186	assert.Len(t, m.NonOneOfFields(), 2)
187}
188
189func TestMsg_OneOfFields(t *testing.T) {
190	t.Parallel()
191
192	o := &oneof{}
193	o.addField(&field{})
194
195	m := &msg{}
196	m.addField(&field{})
197	m.addField(&field{})
198
199	assert.Empty(t, m.OneOfFields())
200	m.addOneOf(o)
201	assert.Len(t, m.OneOfFields(), 1)
202}
203
204func TestMsg_OneOfs(t *testing.T) {
205	t.Parallel()
206
207	m := &msg{}
208	assert.Empty(t, m.OneOfs())
209
210	m.addOneOf(&oneof{})
211	assert.Len(t, m.OneOfs(), 1)
212}
213
214func TestMsg_Extension(t *testing.T) {
215	// cannot be parallel
216	m := &msg{desc: &descriptor.DescriptorProto{}}
217	assert.NotPanics(t, func() { m.Extension(nil, nil) })
218}
219
220func TestMsg_Extensions(t *testing.T) {
221	t.Parallel()
222
223	m := &msg{}
224	assert.Empty(t, m.Extensions())
225
226	ext := &ext{}
227	m.addExtension(ext)
228	assert.Len(t, m.Extensions(), 1)
229}
230
231func TestMsg_DefinedExtensions(t *testing.T) {
232	t.Parallel()
233
234	m := &msg{}
235	assert.Empty(t, m.DefinedExtensions())
236
237	ext := &ext{}
238	m.addDefExtension(ext)
239	assert.Len(t, m.DefinedExtensions(), 1)
240}
241
242func TestMsg_Accept(t *testing.T) {
243	t.Parallel()
244
245	m := &msg{}
246	m.addMessage(&msg{})
247	m.addEnum(&enum{})
248	m.addField(&field{})
249	m.addOneOf(&oneof{})
250	m.addDefExtension(&ext{})
251
252	assert.NoError(t, m.accept(nil))
253
254	v := &mockVisitor{}
255	assert.NoError(t, m.accept(v))
256	assert.Equal(t, 1, v.message)
257	assert.Zero(t, v.enum)
258	assert.Zero(t, v.field)
259	assert.Zero(t, v.oneof)
260	assert.Zero(t, v.extension)
261
262	v.Reset()
263	v.v = v
264	v.err = errors.New("")
265	assert.Error(t, m.accept(v))
266	assert.Equal(t, 1, v.message)
267	assert.Zero(t, v.enum)
268	assert.Zero(t, v.field)
269	assert.Zero(t, v.oneof)
270	assert.Zero(t, v.extension)
271
272	v.Reset()
273	assert.NoError(t, m.accept(v))
274	assert.Equal(t, 2, v.message)
275	assert.Equal(t, 1, v.enum)
276	assert.Equal(t, 1, v.field)
277	assert.Equal(t, 1, v.oneof)
278	assert.Equal(t, 1, v.extension)
279
280	v.Reset()
281	m.addDefExtension(&mockExtension{err: errors.New("")})
282	assert.Error(t, m.accept(v))
283	assert.Equal(t, 2, v.message)
284	assert.Equal(t, 1, v.enum)
285	assert.Equal(t, 1, v.field)
286	assert.Equal(t, 1, v.oneof)
287	assert.Equal(t, 2, v.extension)
288
289	v.Reset()
290	m.addOneOf(&mockOneOf{err: errors.New("")})
291	assert.Error(t, m.accept(v))
292	assert.Equal(t, 2, v.message)
293	assert.Equal(t, 1, v.enum)
294	assert.Equal(t, 1, v.field)
295	assert.Equal(t, 2, v.oneof)
296	assert.Zero(t, v.extension)
297
298	v.Reset()
299	m.addField(&mockField{err: errors.New("")})
300	assert.Error(t, m.accept(v))
301	assert.Equal(t, 2, v.message)
302	assert.Equal(t, 1, v.enum)
303	assert.Equal(t, 2, v.field)
304	assert.Zero(t, v.oneof)
305	assert.Zero(t, v.extension)
306
307	v.Reset()
308	m.addMessage(&mockMessage{err: errors.New("")})
309	assert.Error(t, m.accept(v))
310	assert.Equal(t, 3, v.message)
311	assert.Equal(t, 1, v.enum)
312	assert.Zero(t, v.field)
313	assert.Zero(t, v.oneof)
314	assert.Zero(t, v.extension)
315
316	v.Reset()
317	m.addEnum(&mockEnum{err: errors.New("")})
318	assert.Error(t, m.accept(v))
319	assert.Equal(t, 2, v.enum)
320	assert.Equal(t, 1, v.message)
321	assert.Zero(t, v.field)
322	assert.Zero(t, v.oneof)
323	assert.Zero(t, v.extension)
324}
325
326func TestMsg_Imports(t *testing.T) {
327	t.Parallel()
328
329	m := &msg{}
330	assert.Empty(t, m.Imports())
331
332	m.addField(&mockField{i: []File{&file{}, &file{}}})
333	assert.Len(t, m.Imports(), 1)
334
335	nf := &file{desc: &descriptor.FileDescriptorProto{
336		Name: proto.String("foobar"),
337	}}
338	m.addField(&mockField{i: []File{nf, nf}})
339	assert.Len(t, m.Imports(), 2)
340}
341
342func TestMsg_ChildAtPath(t *testing.T) {
343	t.Parallel()
344
345	m := &msg{}
346	assert.Equal(t, m, m.childAtPath(nil))
347	assert.Nil(t, m.childAtPath([]int32{1}))
348	assert.Nil(t, m.childAtPath([]int32{999, 456}))
349}
350
351func TestMsg_WellKnownType(t *testing.T) {
352	fd, md := desc.ForMessage(&any.Any{})
353	p := &pkg{fd: fd}
354	f := &file{desc: fd}
355	m := &msg{desc: md}
356	f.addMessage(m)
357	p.addFile(f)
358
359	assert.True(t, m.IsWellKnown())
360	assert.Equal(t, AnyWKT, m.WellKnownType())
361
362	m.desc.Name = proto.String("Foobar")
363	assert.False(t, m.IsWellKnown())
364	assert.Equal(t, UnknownWKT, m.WellKnownType())
365
366	m.desc.Name = proto.String("Any")
367	f.desc.Package = proto.String("fizz.buzz")
368	assert.False(t, m.IsWellKnown())
369	assert.Equal(t, UnknownWKT, m.WellKnownType())
370}
371
372type mockMessage struct {
373	Message
374	i   []File
375	p   ParentEntity
376	err error
377}
378
379func (m *mockMessage) Imports() []File { return m.i }
380
381func (m *mockMessage) setParent(p ParentEntity) { m.p = p }
382
383func (m *mockMessage) accept(v Visitor) error {
384	_, err := v.VisitMessage(m)
385	if m.err != nil {
386		return m.err
387	}
388	return err
389}
390
391func dummyMsg() *msg {
392	f := dummyFile()
393
394	m := &msg{
395		desc: &descriptor.DescriptorProto{Name: proto.String("message")},
396	}
397
398	f.addMessage(m)
399	return m
400}
401