File: lazy_normalized_test.go

package info (click to toggle)
golang-google-protobuf 1.36.7-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental, forky, sid
  • size: 14,996 kB
  • sloc: sh: 94; makefile: 4
file content (88 lines) | stat: -rw-r--r-- 3,043 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package impl_test

import (
	"testing"

	"google.golang.org/protobuf/proto"
	"google.golang.org/protobuf/testing/protopack"

	lazytestpb "google.golang.org/protobuf/internal/testprotos/lazy"
)

// Constructs a message encoded in denormalized (non-minimal) wire format, but
// using two levels of nesting: A top-level message with a child message which
// in turn has a grandchild message.
func denormalizedTwoLevel(t *testing.T) ([]byte, *lazytestpb.Top, error) {
	// Construct a message with denormalized (non-minimal) wire format:
	// 1. Encode a top-level message with submessage B (ext) + C (field)
	// 2. Replace the encoding of submessage C (field) with
	//    another instance of submessage B (ext)
	//
	// This modification of the wire format is spec'd in Protobuf:
	// https://github.com/protocolbuffers/protobuf/issues/9257
	grandchild := &lazytestpb.Sub{}
	proto.SetExtension(grandchild, lazytestpb.E_Ext_B, &lazytestpb.Ext{
		SomeFlag: proto.Bool(true),
	})
	expectedMessage := &lazytestpb.Top{
		Child: &lazytestpb.Sub{
			Grandchild: grandchild,
		},
		A: proto.Uint32(2342),
	}

	fullMessage := protopack.Message{
		protopack.Tag{1, protopack.VarintType}, protopack.Varint(2342),
		// Child
		protopack.Tag{2, protopack.BytesType}, protopack.LengthPrefix(protopack.Message{
			// Grandchild
			protopack.Tag{4, protopack.BytesType}, protopack.LengthPrefix(protopack.Message{
				// The first occurrence of B matches expectedMessage:
				protopack.Tag{2, protopack.BytesType}, protopack.LengthPrefix(protopack.Message{
					protopack.Tag{1, protopack.VarintType}, protopack.Varint(1),
				}),
				// This second duplicative occurrence of B is spec'd in Protobuf:
				// https://github.com/protocolbuffers/protobuf/issues/9257
				protopack.Tag{2, protopack.BytesType}, protopack.LengthPrefix(protopack.Message{
					protopack.Tag{1, protopack.VarintType}, protopack.Varint(1),
				}),
			}),
		}),
	}.Marshal()

	return fullMessage, expectedMessage, nil
}

func TestNoInvalidWireFormatWithDeterministicLazy(t *testing.T) {
	fullMessage, _, err := denormalizedTwoLevel(t)
	if err != nil {
		t.Fatal(err)
	}

	top := &lazytestpb.Top{}
	if err := proto.Unmarshal(fullMessage, top); err != nil {
		t.Fatal(err)
	}

	// Requesting deterministic marshaling should result in unmarshaling (and
	// thereby normalizing the non-minimal encoding) when sizing.
	//
	// If the deterministic flag is dropped (like before cl/624951104), the size
	// cache is populated with the non-minimal size. The Marshal call below
	// lazily unmarshals (due to the Deterministic flag), which includes
	// normalization, and will then report a size mismatch error (instead of
	// producing invalid wire format).
	proto.MarshalOptions{Deterministic: true}.Size(top)

	_, err = proto.MarshalOptions{
		Deterministic: true,
		UseCachedSize: true,
	}.Marshal(top)
	if err != nil {
		t.Fatal(err)
	}
}