Exemplo
google.golang.org/protobuf v1.36.12: Merge, clone, equality, and reset semantics for Protocol Buffers messages across presence types, repeated slices, maps, and floating-point values
Amostra verificada para golang google.golang.org/protobuf v1.36.12: Merge, clone, equality, and reset semantics for Protocol Buffers messages across presence…
sha256:45bb69bf251a6f037374e5373c90a8b7ada4e709ed3c0558a13a7f718836d1ed
Esta rede oferece uma coisa: uma amostra que compila. Ela a executou em um sandbox e guardou o recibo assinado. Não classifica nem garante nada — se o mesmo código compila onde você está, ela não mediu.
Quantas chaves de assinatura distintas enviaram um recibo de contrato aprovado. Uma é só o autor; mais de uma significa que outra pessoa também o compilou. Uma chave é gerada por conta própria e não tem identidade registrada por trás, então conta chaves, não pessoas.
MIT-0
Evidência de execução
O ambiente declarado e as execuções assinadas ficam separados, para você ver exatamente o que esta amostra executou e onde.
- Base da evidência
- Contrato assinado aprovado
- Recibos de verificação
- 2
- Chaves de assinatura que o compilaram
- 2
Ambiente declarado
go linux x64 go go go
Ambientes das execuções de verificação
| Ambiente | Contrato | Etapas | Execução |
|---|---|---|---|
| go 1.26 · linux alpine/x64 · docker ed25519:d91480838ac982c9 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · golang@1 |
2026-08-17 |
| go 1.26 · linux alpine/x64 · docker ed25519:2175b912ea1c23b1 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · golang@1 |
2026-08-18 |
Caso
HOW- Objetivo
- Merge, clone, equality, and reset semantics for Protocol Buffers messages across presence types, repeated slices, maps, and floating-point values
- Símbolos
-
- google.golang.org/protobuf/proto.Merge
- google.golang.org/protobuf/proto.Equal
- google.golang.org/protobuf/proto.Clone
- google.golang.org/protobuf/proto.Reset
- google.golang.org/protobuf/reflect/protoreflect.Message.Has
- Ambiente
- go
- Criado
- 2026-08-17T19:33:38Z
Contrato
- proto.Merge appends repeated slice elements rather than replacing them, leaves destination scalars untouched when source holds implicit zero values, overwrites destination when source explicitly sets proto3 optional zero values, and recursively merges nested message fields.
- proto.Merge replaces matching map entry values with the source message rather than recursively merging nested submessages within the map.
- proto.Clone creates an isolated deep copy where mutating cloned slices, maps, or nested messages does not affect the original message, and proto.Clone(nil) returns nil.
- proto.Equal correctly evaluates semantic message equality including IEEE 754 NaN == NaN for float/double fields, whereas reflect.DeepEqual fails on NaN and internal message state.
- protoreflect.Message.Has distinguishes between implicit-presence scalars (reporting false for default zero) and proto3 optional scalars (reporting true even when explicitly set to zero).
- proto.Reset clears all message fields in-place back to their default unpopulated state without reallocating the message struct.
Arquivos
- NOTES.md
- csx.json
- go.mod
- go.sum
- proto_test.go
Código-fonte
# Protocol Buffers Core Operations and Presence Behavior
A known-solution search for `google.golang.org/protobuf` identified existing samples for JSON formatting and parsing (`protojson.MarshalOptions` / `UnmarshalOptions` in sample sha256:b4eaaa06b9ceab6e52f7e4023b4e801213a60c5d5835efcfda2490e38d021c6c) and duplicate registration conflict configuration (`GOLANG_PROTOBUF_REGISTRATION_CONFLICT` in sample sha256:483581752059a6c7b423f8e927bd877e782e82da6eb0bffd094f66af376e53b7). A specific query for `proto.Merge`, `proto.Clone`, `proto.Equal`, `proto.Reset`, and presence handling returned no safe match.
This sample tests and verifies core message manipulation behaviors in `google.golang.org/protobuf` pinned to release `v1.36.12`.
## Observed Behavior
1. **Repeated Field Merging (`proto.Merge`)**:
`proto.Merge(dst, src)` appends all elements from `src` repeated fields into `dst`. It does not replace, overwrite, or deduplicate existing list elements. Naive callers expecting `Merge` to replace slices will silently retain stale elements alongside newly appended entries.
2. **Scalar Field Presence in `proto.Merge`**:
- For proto3 scalar fields with implicit presence (standard integers, strings, booleans, enums without `optional`), an unpopulated/zero-valued field (`0`, `""`, `false`) in `src` does not overwrite an existing non-zero value in `dst`.
- For proto3 scalar fields with explicit presence (`proto3_optional`), an explicitly set zero value in `src` (`retries = 0`) has presence and correctly overwrites the corresponding field in `dst`. Unset optional fields in `src` leave `dst` unchanged.
3. **Singular Message vs. Map Merging**:
- Singular nested message fields are recursively merged: fields set in `src` update `dst`'s child message, while fields unset in `src` remain intact in `dst`.
- For protobuf map fields (`map<string, Message>`), matching keys in `src` replace the entire entry value in `dst`, rather than recursively merging child messages within the map.
4. **Deep Copy Isolation (`proto.Clone`)**:
`proto.Clone` produces an independent deep copy of the message structure. Appending to repeated lists, mutating child submessages, or altering map entries on the cloned message does not mutate the source message. `proto.Clone(nil)` returns `nil`.
5. **Semantic Equality vs. `reflect.DeepEqual` (`proto.Equal`)**:
`proto.Equal` performs descriptor-aware semantic comparison of protobuf messages. In accordance with the Protocol Buffers specification, float/double fields containing IEEE 754 `NaN` values are evaluated as equal (`NaN == NaN`). In contrast, Go's standard `reflect.DeepEqual` evaluates `NaN` comparisons as unequal and fails on unexported internal runtime metadata.
6. **Reflection Presence Inspection (`protoreflect.Message.Has`)**:
`protoreflect.Message.Has` distinguishes between fields with and without explicit presence:
- For implicit-presence scalars, `Has` returns `true` only when the field holds a non-default (non-zero) value; setting the zero value leaves `Has` as `false`.
- For `proto3_optional` scalars, `Has` returns `true` as long as the field was explicitly populated, even if set to the default zero value.
- For repeated fields, `Has` reports `true` if and only if the list length is greater than zero.
7. **In-Place Reset (`proto.Reset`)**:
`proto.Reset` clears all fields in-place back to their default unpopulated state without reallocating the underlying struct pointer.
{"case":{"believed":"proto.Merge replaces repeated slice fields with the source list and ignores explicit zero values for optional fields, while reflect.DeepEqual can safely compare protobuf messages.","caseId":"case:sha256:988e3294aff95cd3dd469e7849e27717a36c15570e1e4bdce39b16a358008aeb","contract":["proto.Merge appends repeated slice elements rather than replacing them, leaves destination scalars untouched when source holds implicit zero values, overwrites destination when source explicitly sets proto3 optional zero values, and recursively merges nested message fields.","proto.Merge replaces matching map entry values with the source message rather than recursively merging nested submessages within the map.","proto.Clone creates an isolated deep copy where mutating cloned slices, maps, or nested messages does not affect the original message, and proto.Clone(nil) returns nil.","proto.Equal correctly evaluates semantic message equality including IEEE 754 NaN == NaN for float/double fields, whereas reflect.DeepEqual fails on NaN and internal message state.","protoreflect.Message.Has distinguishes between implicit-presence scalars (reporting false for default zero) and proto3 optional scalars (reporting true even when explicitly set to zero).","proto.Reset clears all message fields in-place back to their default unpopulated state without reallocating the message struct."],"goal":"Merge, clone, equality, and reset semantics for Protocol Buffers messages across presence types, repeated slices, maps, and floating-point values","kind":"HOW","packages":["pkg:golang/google.golang.org/protobuf@v1.36.12"],"schemaVersion":1,"symbols":["google.golang.org/protobuf/proto.Merge","google.golang.org/protobuf/proto.Equal","google.golang.org/protobuf/proto.Clone","google.golang.org/protobuf/proto.Reset","google.golang.org/protobuf/reflect/protoreflect.Message.Has"]},"contractCommand":["go","test","./..."],"environment":{"arch":"x64","ecosystem":"golang","executionContext":"go","language":"go","os":"linux","packageManager":"go","runtime":"go","schemaVersion":1},"license":"MIT-0","packages":["pkg:golang/google.golang.org/protobuf@v1.36.12"],"schemaVersion":1,"symbols":["google.golang.org/protobuf/proto.Merge","google.golang.org/protobuf/proto.Equal","google.golang.org/protobuf/proto.Clone","google.golang.org/protobuf/proto.Reset","google.golang.org/protobuf/reflect/protoreflect.Message.Has"],"verifierAdapter":"golang@1"}
module example.com/protocore
go 1.26.5
require google.golang.org/protobuf v1.36.12
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
google.golang.org/protobuf v1.36.12 h1:pJOKDDOyeXErUroCihFAd5LQuwXBSpVnKGrj5o/fwxc=
google.golang.org/protobuf v1.36.12/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
package protocore_test
import (
"math"
"reflect"
"testing"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protodesc"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
"google.golang.org/protobuf/types/descriptorpb"
"google.golang.org/protobuf/types/dynamicpb"
)
func buildSchema(t *testing.T) (*descriptorpb.FileDescriptorProto, protoreflect.MessageDescriptor, protoreflect.MessageDescriptor) {
t.Helper()
fd := &descriptorpb.FileDescriptorProto{
Name: proto.String("service_config.proto"),
Package: proto.String("example.config"),
Syntax: proto.String("proto3"),
MessageType: []*descriptorpb.DescriptorProto{
{
Name: proto.String("Endpoint"),
Field: []*descriptorpb.FieldDescriptorProto{
{
Name: proto.String("host"),
Number: proto.Int32(1),
Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
JsonName: proto.String("host"),
},
{
Name: proto.String("port"),
Number: proto.Int32(2),
Type: descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(),
JsonName: proto.String("port"),
},
},
},
{
Name: proto.String("ServiceConfig"),
Field: []*descriptorpb.FieldDescriptorProto{
{
Name: proto.String("timeout_ms"),
Number: proto.Int32(1),
Type: descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(),
JsonName: proto.String("timeoutMs"),
},
{
Name: proto.String("retries"),
Number: proto.Int32(2),
Type: descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(),
JsonName: proto.String("retries"),
Proto3Optional: proto.Bool(true),
OneofIndex: proto.Int32(0),
},
{
Name: proto.String("tags"),
Number: proto.Int32(3),
Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
Label: descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
JsonName: proto.String("tags"),
},
{
Name: proto.String("endpoint"),
Number: proto.Int32(4),
Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
TypeName: proto.String(".example.config.Endpoint"),
JsonName: proto.String("endpoint"),
},
{
Name: proto.String("ratio"),
Number: proto.Int32(5),
Type: descriptorpb.FieldDescriptorProto_TYPE_DOUBLE.Enum(),
JsonName: proto.String("ratio"),
},
{
Name: proto.String("metadata"),
Number: proto.Int32(6),
Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
TypeName: proto.String(".example.config.ServiceConfig.MetadataEntry"),
Label: descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
JsonName: proto.String("metadata"),
},
},
NestedType: []*descriptorpb.DescriptorProto{
{
Name: proto.String("MetadataEntry"),
Field: []*descriptorpb.FieldDescriptorProto{
{
Name: proto.String("key"),
Number: proto.Int32(1),
Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
JsonName: proto.String("key"),
},
{
Name: proto.String("value"),
Number: proto.Int32(2),
Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
TypeName: proto.String(".example.config.Endpoint"),
JsonName: proto.String("value"),
},
},
Options: &descriptorpb.MessageOptions{
MapEntry: proto.Bool(true),
},
},
},
OneofDecl: []*descriptorpb.OneofDescriptorProto{
{
Name: proto.String("_retries"),
},
},
},
},
}
fileDesc, err := protodesc.NewFile(fd, protoregistry.GlobalFiles)
if err != nil {
t.Fatalf("protodesc.NewFile failed: %v", err)
}
svcDesc := fileDesc.Messages().ByName("ServiceConfig")
endpointDesc := fileDesc.Messages().ByName("Endpoint")
if svcDesc == nil || endpointDesc == nil {
t.Fatalf("failed to resolve message descriptors")
}
return fd, svcDesc, endpointDesc
}
func TestProtoMergeRepeatedAndScalars(t *testing.T) {
_, svcDesc, endpointDesc := buildSchema(t)
timeoutField := svcDesc.Fields().ByName("timeout_ms")
retriesField := svcDesc.Fields().ByName("retries")
tagsField := svcDesc.Fields().ByName("tags")
endpointField := svcDesc.Fields().ByName("endpoint")
hostField := endpointDesc.Fields().ByName("host")
portField := endpointDesc.Fields().ByName("port")
// Destination message
dst := dynamicpb.NewMessage(svcDesc)
dst.Set(timeoutField, protoreflect.ValueOfInt32(5000))
dst.Set(retriesField, protoreflect.ValueOfInt32(3))
dstTags := dst.Mutable(tagsField).List()
dstTags.Append(protoreflect.ValueOfString("us-east"))
dstTags.Append(protoreflect.ValueOfString("prod"))
dstEndpoint := dst.Mutable(endpointField).Message()
dstEndpoint.Set(hostField, protoreflect.ValueOfString("primary.example.com"))
dstEndpoint.Set(portField, protoreflect.ValueOfInt32(8080))
// Source message
src := dynamicpb.NewMessage(svcDesc)
// timeout_ms is left 0 (zero-value, implicit presence in proto3)
// retries is explicitly set to 0 (proto3_optional explicit presence)
src.Set(retriesField, protoreflect.ValueOfInt32(0))
srcTags := src.Mutable(tagsField).List()
srcTags.Append(protoreflect.ValueOfString("canary"))
srcEndpoint := src.Mutable(endpointField).Message()
// host is left unset in srcEndpoint, only port is updated
srcEndpoint.Set(portField, protoreflect.ValueOfInt32(9090))
// Merge src into dst
proto.Merge(dst, src)
// 1. Implicit presence scalar in src with 0 does NOT overwrite non-zero dst value
if got := dst.Get(timeoutField).Int(); got != 5000 {
t.Fatalf("expected timeout_ms to remain 5000, got %d", got)
}
// 2. Explicit presence (proto3_optional) scalar in src with 0 DOES overwrite dst value
if got := dst.Get(retriesField).Int(); got != 0 {
t.Fatalf("expected retries to be overwritten to 0, got %d", got)
}
// 3. Repeated fields are APPENDED, not overwritten
resTags := dst.Get(tagsField).List()
if resTags.Len() != 3 {
t.Fatalf("expected tags length to be 3 (appended), got %d", resTags.Len())
}
expectedTags := []string{"us-east", "prod", "canary"}
for i, exp := range expectedTags {
if resTags.Get(i).String() != exp {
t.Errorf("tags[%d] = %q, expected %q", i, resTags.Get(i).String(), exp)
}
}
// 4. Singular submessage fields are recursively merged
resEndpoint := dst.Get(endpointField).Message()
if resEndpoint.Get(hostField).String() != "primary.example.com" {
t.Fatalf("expected host to be retained as primary.example.com, got %q", resEndpoint.Get(hostField).String())
}
if resEndpoint.Get(portField).Int() != 9090 {
t.Fatalf("expected port to be updated to 9090, got %d", resEndpoint.Get(portField).Int())
}
}
func TestProtoMergeMapFieldReplacement(t *testing.T) {
_, svcDesc, endpointDesc := buildSchema(t)
metadataField := svcDesc.Fields().ByName("metadata")
hostField := endpointDesc.Fields().ByName("host")
portField := endpointDesc.Fields().ByName("port")
// Destination message with map entry "svc1"
dst := dynamicpb.NewMessage(svcDesc)
dstMeta := dst.Mutable(metadataField).Map()
ep1Dst := dynamicpb.NewMessage(endpointDesc)
ep1Dst.Set(hostField, protoreflect.ValueOfString("meta1.example.com"))
ep1Dst.Set(portField, protoreflect.ValueOfInt32(7000))
dstMeta.Set(protoreflect.ValueOfString("svc1").MapKey(), protoreflect.ValueOfMessage(ep1Dst))
// Source message with updated "svc1" (host unset) and new entry "svc2"
src := dynamicpb.NewMessage(svcDesc)
srcMeta := src.Mutable(metadataField).Map()
ep1Src := dynamicpb.NewMessage(endpointDesc)
ep1Src.Set(portField, protoreflect.ValueOfInt32(7001))
srcMeta.Set(protoreflect.ValueOfString("svc1").MapKey(), protoreflect.ValueOfMessage(ep1Src))
ep2Src := dynamicpb.NewMessage(endpointDesc)
ep2Src.Set(hostField, protoreflect.ValueOfString("meta2.example.com"))
ep2Src.Set(portField, protoreflect.ValueOfInt32(8000))
srcMeta.Set(protoreflect.ValueOfString("svc2").MapKey(), protoreflect.ValueOfMessage(ep2Src))
// Merge src into dst
proto.Merge(dst, src)
// For map fields, matching keys in src REPLACE dst map entry values rather than recursively merging them
resMeta := dst.Get(metadataField).Map()
if resMeta.Len() != 2 {
t.Fatalf("expected metadata map length to be 2, got %d", resMeta.Len())
}
svc1Val := resMeta.Get(protoreflect.ValueOfString("svc1").MapKey()).Message()
// In protobuf merge semantics, the entire map value is replaced by the source entry
if svc1Val.Get(hostField).String() != "" {
t.Fatalf("expected host to be replaced by empty string from src, got %q", svc1Val.Get(hostField).String())
}
if svc1Val.Get(portField).Int() != 7001 {
t.Fatalf("expected port to be 7001, got %d", svc1Val.Get(portField).Int())
}
svc2Val := resMeta.Get(protoreflect.ValueOfString("svc2").MapKey()).Message()
if svc2Val.Get(hostField).String() != "meta2.example.com" || svc2Val.Get(portField).Int() != 8000 {
t.Fatalf("expected svc2 entry to be copied from src")
}
}
func TestProtoCloneIsolation(t *testing.T) {
_, svcDesc, endpointDesc := buildSchema(t)
tagsField := svcDesc.Fields().ByName("tags")
endpointField := svcDesc.Fields().ByName("endpoint")
metadataField := svcDesc.Fields().ByName("metadata")
hostField := endpointDesc.Fields().ByName("host")
portField := endpointDesc.Fields().ByName("port")
ratioField := svcDesc.Fields().ByName("ratio")
orig := dynamicpb.NewMessage(svcDesc)
orig.Set(ratioField, protoreflect.ValueOfFloat64(math.NaN()))
origTags := orig.Mutable(tagsField).List()
origTags.Append(protoreflect.ValueOfString("alpha"))
origEndpoint := orig.Mutable(endpointField).Message()
origEndpoint.Set(hostField, protoreflect.ValueOfString("cluster.example.com"))
origMeta := orig.Mutable(metadataField).Map()
ep := dynamicpb.NewMessage(endpointDesc)
ep.Set(portField, protoreflect.ValueOfInt32(5000))
origMeta.Set(protoreflect.ValueOfString("app").MapKey(), protoreflect.ValueOfMessage(ep))
// proto.Clone creates a deep copy
cloned := proto.Clone(orig)
clonedMsg, ok := cloned.(*dynamicpb.Message)
if !ok {
t.Fatalf("cloned message is not *dynamicpb.Message")
}
// Mutating the clone's list, child message, and map does not mutate original
clonedTags := clonedMsg.Mutable(tagsField).List()
clonedTags.Append(protoreflect.ValueOfString("beta"))
clonedEndpoint := clonedMsg.Mutable(endpointField).Message()
clonedEndpoint.Set(hostField, protoreflect.ValueOfString("mutated.example.com"))
clonedMeta := clonedMsg.Mutable(metadataField).Map()
clonedMeta.Clear(protoreflect.ValueOfString("app").MapKey())
if orig.Get(tagsField).List().Len() != 1 {
t.Fatalf("mutating clone list modified original list")
}
if orig.Get(endpointField).Message().Get(hostField).String() != "cluster.example.com" {
t.Fatalf("mutating clone child message modified original child message")
}
if orig.Get(metadataField).Map().Len() != 1 {
t.Fatalf("clearing clone map entry modified original map")
}
// proto.Clone(nil) returns nil
var nilMsg proto.Message
if proto.Clone(nilMsg) != nil {
t.Fatalf("proto.Clone(nil) must return nil")
}
}
func TestProtoEqualSemantics(t *testing.T) {
_, svcDesc, endpointDesc := buildSchema(t)
tagsField := svcDesc.Fields().ByName("tags")
endpointField := svcDesc.Fields().ByName("endpoint")
hostField := endpointDesc.Fields().ByName("host")
ratioField := svcDesc.Fields().ByName("ratio")
// Message 1 with NaN float
msg1 := dynamicpb.NewMessage(svcDesc)
msg1.Set(ratioField, protoreflect.ValueOfFloat64(math.NaN()))
msg1.Mutable(tagsField).List().Append(protoreflect.ValueOfString("v1"))
msg1.Mutable(endpointField).Message().Set(hostField, protoreflect.ValueOfString("equal.example.com"))
// Message 2 constructed independently with identical values
msg2 := dynamicpb.NewMessage(svcDesc)
msg2.Set(ratioField, protoreflect.ValueOfFloat64(math.NaN()))
msg2.Mutable(tagsField).List().Append(protoreflect.ValueOfString("v1"))
msg2.Mutable(endpointField).Message().Set(hostField, protoreflect.ValueOfString("equal.example.com"))
// 1. proto.Equal treats NaN == NaN as equal according to protobuf specifications
if !proto.Equal(msg1, msg2) {
t.Fatalf("expected proto.Equal(msg1, msg2) to be true")
}
// 2. reflect.DeepEqual fails because Go float NaN != NaN and internal runtime metadata differs
if reflect.DeepEqual(msg1, msg2) {
t.Fatalf("expected reflect.DeepEqual to evaluate to false due to NaN comparison")
}
// 3. Nil comparisons
if !proto.Equal(nil, nil) {
t.Fatalf("proto.Equal(nil, nil) must be true")
}
if proto.Equal(msg1, nil) {
t.Fatalf("proto.Equal(msg1, nil) must be false")
}
if proto.Equal(nil, msg1) {
t.Fatalf("proto.Equal(nil, msg1) must be false")
}
}
func TestProtoReflectHasPresence(t *testing.T) {
_, svcDesc, endpointDesc := buildSchema(t)
timeoutField := svcDesc.Fields().ByName("timeout_ms")
retriesField := svcDesc.Fields().ByName("retries")
tagsField := svcDesc.Fields().ByName("tags")
endpointField := svcDesc.Fields().ByName("endpoint")
msg := dynamicpb.NewMessage(svcDesc)
// 1. Proto3 scalar without optional has implicit presence (HasPresence() == false)
if timeoutField.HasPresence() {
t.Fatalf("expected proto3 scalar without optional to have HasPresence() == false")
}
// Has() returns false when value is 0 (default) and true when non-zero
if msg.ProtoReflect().Has(timeoutField) {
t.Fatalf("expected unpopulated implicit-presence scalar to report Has() == false")
}
msg.Set(timeoutField, protoreflect.ValueOfInt32(0))
if msg.ProtoReflect().Has(timeoutField) {
t.Fatalf("setting default 0 on implicit-presence scalar must still report Has() == false")
}
msg.Set(timeoutField, protoreflect.ValueOfInt32(42))
if !msg.ProtoReflect().Has(timeoutField) {
t.Fatalf("setting non-zero 42 on implicit-presence scalar must report Has() == true")
}
// 2. Proto3 scalar with proto3_optional has explicit presence (HasPresence() == true)
if !retriesField.HasPresence() {
t.Fatalf("expected proto3_optional scalar to have HasPresence() == true")
}
if msg.ProtoReflect().Has(retriesField) {
t.Fatalf("expected unpopulated proto3_optional scalar to report Has() == false")
}
msg.Set(retriesField, protoreflect.ValueOfInt32(0))
if !msg.ProtoReflect().Has(retriesField) {
t.Fatalf("setting explicit 0 on proto3_optional scalar must report Has() == true")
}
// 3. Repeated fields report Has() == true only when non-empty
if tagsField.HasPresence() {
t.Fatalf("expected repeated field to have HasPresence() == false")
}
if msg.ProtoReflect().Has(tagsField) {
t.Fatalf("empty repeated field must report Has() == false")
}
msg.Mutable(tagsField).List().Append(protoreflect.ValueOfString("tag1"))
if !msg.ProtoReflect().Has(tagsField) {
t.Fatalf("non-empty repeated field must report Has() == true")
}
// 4. Message fields have explicit presence
if !endpointField.HasPresence() {
t.Fatalf("expected message field to have HasPresence() == true")
}
if msg.ProtoReflect().Has(endpointField) {
t.Fatalf("unset message field must report Has() == false")
}
ep := dynamicpb.NewMessage(endpointDesc)
msg.Set(endpointField, protoreflect.ValueOfMessage(ep))
if !msg.ProtoReflect().Has(endpointField) {
t.Fatalf("populated message field must report Has() == true")
}
}
func TestProtoReset(t *testing.T) {
_, svcDesc, endpointDesc := buildSchema(t)
timeoutField := svcDesc.Fields().ByName("timeout_ms")
tagsField := svcDesc.Fields().ByName("tags")
endpointField := svcDesc.Fields().ByName("endpoint")
hostField := endpointDesc.Fields().ByName("host")
msg := dynamicpb.NewMessage(svcDesc)
msg.Set(timeoutField, protoreflect.ValueOfInt32(999))
msg.Mutable(tagsField).List().Append(protoreflect.ValueOfString("prod"))
msg.Mutable(endpointField).Message().Set(hostField, protoreflect.ValueOfString("reset.example.com"))
// Reset in-place
proto.Reset(msg)
if msg.Get(timeoutField).Int() != 0 {
t.Fatalf("expected timeout_ms to be reset to 0, got %d", msg.Get(timeoutField).Int())
}
if msg.Get(tagsField).List().Len() != 0 {
t.Fatalf("expected tags list to be cleared to length 0, got %d", msg.Get(tagsField).List().Len())
}
if msg.ProtoReflect().Has(endpointField) {
t.Fatalf("expected endpoint message field to be cleared after Reset")
}
}