|  | // 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 proto_test | 
|  |  | 
|  | import ( | 
|  | "fmt" | 
|  | "reflect" | 
|  | "testing" | 
|  | "unsafe" | 
|  |  | 
|  | "google.golang.org/protobuf/internal/impl" | 
|  | testhybridpb "google.golang.org/protobuf/internal/testprotos/testeditions/testeditions_hybrid" | 
|  | testopaquepb "google.golang.org/protobuf/internal/testprotos/testeditions/testeditions_opaque" | 
|  | "google.golang.org/protobuf/proto" | 
|  | ) | 
|  |  | 
|  | func TestOpenSetRepeatedNilReceiver(t *testing.T) { | 
|  | var x *testhybridpb.TestAllTypes | 
|  | expectPanic(t, func() { | 
|  | x.SetRepeatedUint32(nil) | 
|  | }, "Setting repeated field on nil receiver did not panic.") | 
|  | } | 
|  |  | 
|  | func TestOpenSetRepeated(t *testing.T) { | 
|  | x := &testhybridpb.TestAllTypes{} | 
|  |  | 
|  | tab := []struct { | 
|  | fName  string     // Field name (in proto) | 
|  | set    func()     // Set the field to empty slice | 
|  | setNil func()     // Set the field to nil | 
|  | len    func() int // length of field, -1 if nil | 
|  | }{ | 
|  | { | 
|  | fName:  "repeated_int32", | 
|  | set:    func() { x.SetRepeatedInt32([]int32{}) }, | 
|  | setNil: func() { x.SetRepeatedInt32(nil) }, | 
|  | len: func() int { | 
|  | if x.GetRepeatedInt32() == nil { | 
|  | return -1 | 
|  | } | 
|  | return len(x.GetRepeatedInt32()) | 
|  | }, | 
|  | }, | 
|  | { | 
|  | fName:  "repeated_int64", | 
|  | set:    func() { x.SetRepeatedInt64([]int64{}) }, | 
|  | setNil: func() { x.SetRepeatedInt64(nil) }, | 
|  | len: func() int { | 
|  | if x.GetRepeatedInt64() == nil { | 
|  | return -1 | 
|  | } | 
|  | return len(x.GetRepeatedInt64()) | 
|  | }, | 
|  | }, | 
|  | { | 
|  | fName:  "repeated_uint32", | 
|  | set:    func() { x.SetRepeatedUint32([]uint32{}) }, | 
|  | setNil: func() { x.SetRepeatedUint32(nil) }, | 
|  | len: func() int { | 
|  | if x.GetRepeatedUint32() == nil { | 
|  | return -1 | 
|  | } | 
|  | return len(x.GetRepeatedUint32()) | 
|  | }, | 
|  | }, | 
|  | { | 
|  | fName:  "repeated_uint64", | 
|  | set:    func() { x.SetRepeatedUint64([]uint64{}) }, | 
|  | setNil: func() { x.SetRepeatedUint64(nil) }, | 
|  | len: func() int { | 
|  | if x.GetRepeatedUint64() == nil { | 
|  | return -1 | 
|  | } | 
|  | return len(x.GetRepeatedUint64()) | 
|  | }, | 
|  | }, | 
|  | { | 
|  | fName:  "repeated_sint32", | 
|  | set:    func() { x.SetRepeatedSint32([]int32{}) }, | 
|  | setNil: func() { x.SetRepeatedSint32(nil) }, | 
|  | len: func() int { | 
|  | if x.GetRepeatedSint32() == nil { | 
|  | return -1 | 
|  | } | 
|  | return len(x.GetRepeatedSint32()) | 
|  | }, | 
|  | }, | 
|  | { | 
|  | fName:  "repeated_sint64", | 
|  | set:    func() { x.SetRepeatedSint64([]int64{}) }, | 
|  | setNil: func() { x.SetRepeatedSint64(nil) }, | 
|  | len: func() int { | 
|  | if x.GetRepeatedSint64() == nil { | 
|  | return -1 | 
|  | } | 
|  | return len(x.GetRepeatedSint64()) | 
|  | }, | 
|  | }, | 
|  | { | 
|  | fName:  "repeated_fixed32", | 
|  | set:    func() { x.SetRepeatedFixed32([]uint32{}) }, | 
|  | setNil: func() { x.SetRepeatedFixed32(nil) }, | 
|  | len: func() int { | 
|  | if x.GetRepeatedFixed32() == nil { | 
|  | return -1 | 
|  | } | 
|  | return len(x.GetRepeatedFixed32()) | 
|  | }, | 
|  | }, | 
|  | { | 
|  | fName:  "repeated_fixed64", | 
|  | set:    func() { x.SetRepeatedFixed64([]uint64{}) }, | 
|  | setNil: func() { x.SetRepeatedFixed64(nil) }, | 
|  | len: func() int { | 
|  | if x.GetRepeatedFixed64() == nil { | 
|  | return -1 | 
|  | } | 
|  | return len(x.GetRepeatedFixed64()) | 
|  | }, | 
|  | }, | 
|  | { | 
|  | fName:  "repeated_sfixed32", | 
|  | set:    func() { x.SetRepeatedSfixed32([]int32{}) }, | 
|  | setNil: func() { x.SetRepeatedSfixed32(nil) }, | 
|  | len: func() int { | 
|  | if x.GetRepeatedSfixed32() == nil { | 
|  | return -1 | 
|  | } | 
|  | return len(x.GetRepeatedSfixed32()) | 
|  | }, | 
|  | }, | 
|  | { | 
|  | fName:  "repeated_sfixed64", | 
|  | set:    func() { x.SetRepeatedSfixed64([]int64{}) }, | 
|  | setNil: func() { x.SetRepeatedSfixed64(nil) }, | 
|  | len: func() int { | 
|  | if x.GetRepeatedSfixed64() == nil { | 
|  | return -1 | 
|  | } | 
|  | return len(x.GetRepeatedSfixed64()) | 
|  | }, | 
|  | }, | 
|  | { | 
|  | fName:  "repeated_float", | 
|  | set:    func() { x.SetRepeatedFloat([]float32{}) }, | 
|  | setNil: func() { x.SetRepeatedFloat(nil) }, | 
|  | len: func() int { | 
|  | if x.GetRepeatedFloat() == nil { | 
|  | return -1 | 
|  | } | 
|  | return len(x.GetRepeatedFloat()) | 
|  | }, | 
|  | }, | 
|  | { | 
|  | fName:  "repeated_double", | 
|  | set:    func() { x.SetRepeatedDouble([]float64{}) }, | 
|  | setNil: func() { x.SetRepeatedDouble(nil) }, | 
|  | len: func() int { | 
|  | if x.GetRepeatedDouble() == nil { | 
|  | return -1 | 
|  | } | 
|  | return len(x.GetRepeatedDouble()) | 
|  | }, | 
|  | }, | 
|  | { | 
|  | fName:  "repeated_bool", | 
|  | set:    func() { x.SetRepeatedBool([]bool{}) }, | 
|  | setNil: func() { x.SetRepeatedBool(nil) }, | 
|  | len: func() int { | 
|  | if x.GetRepeatedBool() == nil { | 
|  | return -1 | 
|  | } | 
|  | return len(x.GetRepeatedBool()) | 
|  | }, | 
|  | }, | 
|  | { | 
|  | fName:  "repeated_string", | 
|  | set:    func() { x.SetRepeatedString([]string{}) }, | 
|  | setNil: func() { x.SetRepeatedString(nil) }, | 
|  | len: func() int { | 
|  | if x.GetRepeatedString() == nil { | 
|  | return -1 | 
|  | } | 
|  | return len(x.GetRepeatedString()) | 
|  | }, | 
|  | }, | 
|  | { | 
|  | fName:  "repeated_bytes", | 
|  | set:    func() { x.SetRepeatedBytes([][]byte{}) }, | 
|  | setNil: func() { x.SetRepeatedBytes(nil) }, | 
|  | len: func() int { | 
|  | if x.GetRepeatedBytes() == nil { | 
|  | return -1 | 
|  | } | 
|  | return len(x.GetRepeatedBytes()) | 
|  | }, | 
|  | }, | 
|  | { | 
|  | fName:  "RepeatedGroup", | 
|  | set:    func() { x.SetRepeatedgroup([]*testhybridpb.TestAllTypes_RepeatedGroup{}) }, | 
|  | setNil: func() { x.SetRepeatedgroup(nil) }, | 
|  | len: func() int { | 
|  | if x.GetRepeatedgroup() == nil { | 
|  | return -1 | 
|  | } | 
|  | return len(x.GetRepeatedgroup()) | 
|  | }, | 
|  | }, | 
|  | { | 
|  | fName:  "repeated_nested_message", | 
|  | set:    func() { x.SetRepeatedNestedMessage([]*testhybridpb.TestAllTypes_NestedMessage{}) }, | 
|  | setNil: func() { x.SetRepeatedNestedMessage(nil) }, | 
|  | len: func() int { | 
|  | if x.GetRepeatedNestedMessage() == nil { | 
|  | return -1 | 
|  | } | 
|  | return len(x.GetRepeatedNestedMessage()) | 
|  | }, | 
|  | }, | 
|  | { | 
|  | fName:  "repeated_nested_enum", | 
|  | set:    func() { x.SetRepeatedNestedEnum([]testhybridpb.TestAllTypes_NestedEnum{}) }, | 
|  | setNil: func() { x.SetRepeatedNestedEnum(nil) }, | 
|  | len: func() int { | 
|  | if x.GetRepeatedNestedEnum() == nil { | 
|  | return -1 | 
|  | } | 
|  | return len(x.GetRepeatedNestedEnum()) | 
|  | }, | 
|  | }, | 
|  | } | 
|  |  | 
|  | for _, mv := range tab { | 
|  | if mv.len() != -1 { | 
|  | t.Errorf("Repeated field %s was not nil to start with ", mv.fName) | 
|  | } | 
|  | mv.set() | 
|  | if mv.len() != 0 { | 
|  | t.Errorf("Repeated field %s did not retain empty slice ", mv.fName) | 
|  | } | 
|  | b, err := proto.Marshal(x) | 
|  | if err != nil { | 
|  | t.Fatalf("Failed to marshal message, err = %v", err) | 
|  | } | 
|  | proto.Unmarshal(b, x) | 
|  | if mv.len() != -1 { | 
|  | t.Errorf("Repeated field %s was not nil to start with ", mv.fName) | 
|  | } | 
|  | mv.set() | 
|  | mv.setNil() | 
|  | if mv.len() != -1 { | 
|  | t.Errorf("Repeated field %s was not nil event though we set it to ", mv.fName) | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | // Check that we actually retain the same slice | 
|  | s := make([]testhybridpb.TestAllTypes_NestedEnum, 0, 455) | 
|  | x.SetRepeatedNestedEnum(s) | 
|  | if got, want := cap(x.GetRepeatedNestedEnum()), 455; got != want { | 
|  | t.Errorf("cap(x.GetRepeatedNestedEnum()) returned %v, expected %v", got, want) | 
|  | } | 
|  | // Do this for a message too | 
|  | s2 := make([]*testhybridpb.TestAllTypes_NestedMessage, 0, 544) | 
|  | x.SetRepeatedNestedMessage(s2) | 
|  | if got, want := cap(x.GetRepeatedNestedMessage()), 544; got != want { | 
|  | t.Errorf("cap(x.GetRepeatedNestedMessage()) returned %v, expected %v", got, want) | 
|  | } | 
|  | // Check special bytes behavior | 
|  | x.SetOptionalBytes(nil) | 
|  | if got, want := x.HasOptionalBytes(), true; got != want { | 
|  | t.Errorf("HasOptionalBytes after setting to nil returned %v, expected %v", got, want) | 
|  | } | 
|  | if got := x.GetOptionalBytes(); got == nil || len(got) != 0 { | 
|  | t.Errorf("GetOptionalBytes after setting to nil returned %v, expected %v", got, []byte{}) | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | func TestOpaqueSetRepeatedNilReceiver(t *testing.T) { | 
|  | var x *testopaquepb.TestAllTypes | 
|  | expectPanic(t, func() { | 
|  | x.SetRepeatedUint32(nil) | 
|  | }, "Setting repeated field on nil receiver did not panic.") | 
|  | } | 
|  |  | 
|  | func TestOpaqueSetRepeated(t *testing.T) { | 
|  | for _, mode := range []bool{true, false} { | 
|  | impl.EnableLazyUnmarshal(mode) | 
|  | t.Run(fmt.Sprintf("LazyUnmarshal_%t", mode), testOpaqueSetRepeatedSub) | 
|  | } | 
|  | } | 
|  |  | 
|  | func testOpaqueSetRepeatedSub(t *testing.T) { | 
|  | x := &testopaquepb.TestAllTypes{} | 
|  |  | 
|  | tab := []struct { | 
|  | fName  string     // Field name (in proto) | 
|  | set    func()     // Set the field to empty slice | 
|  | setNil func()     // Set the field to nil | 
|  | len    func() int // length of field, -1 if nil | 
|  | }{ | 
|  | { | 
|  | fName:  "repeated_int32", | 
|  | set:    func() { x.SetRepeatedInt32([]int32{}) }, | 
|  | setNil: func() { x.SetRepeatedInt32(nil) }, | 
|  | len: func() int { | 
|  | if x.GetRepeatedInt32() == nil { | 
|  | return -1 | 
|  | } | 
|  | return len(x.GetRepeatedInt32()) | 
|  | }, | 
|  | }, | 
|  | { | 
|  | fName:  "repeated_int64", | 
|  | set:    func() { x.SetRepeatedInt64([]int64{}) }, | 
|  | setNil: func() { x.SetRepeatedInt64(nil) }, | 
|  | len: func() int { | 
|  | if x.GetRepeatedInt64() == nil { | 
|  | return -1 | 
|  | } | 
|  | return len(x.GetRepeatedInt64()) | 
|  | }, | 
|  | }, | 
|  | { | 
|  | fName:  "repeated_uint32", | 
|  | set:    func() { x.SetRepeatedUint32([]uint32{}) }, | 
|  | setNil: func() { x.SetRepeatedUint32(nil) }, | 
|  | len: func() int { | 
|  | if x.GetRepeatedUint32() == nil { | 
|  | return -1 | 
|  | } | 
|  | return len(x.GetRepeatedUint32()) | 
|  | }, | 
|  | }, | 
|  | { | 
|  | fName:  "repeated_uint64", | 
|  | set:    func() { x.SetRepeatedUint64([]uint64{}) }, | 
|  | setNil: func() { x.SetRepeatedUint64(nil) }, | 
|  | len: func() int { | 
|  | if x.GetRepeatedUint64() == nil { | 
|  | return -1 | 
|  | } | 
|  | return len(x.GetRepeatedUint64()) | 
|  | }, | 
|  | }, | 
|  | { | 
|  | fName:  "repeated_sint32", | 
|  | set:    func() { x.SetRepeatedSint32([]int32{}) }, | 
|  | setNil: func() { x.SetRepeatedSint32(nil) }, | 
|  | len: func() int { | 
|  | if x.GetRepeatedSint32() == nil { | 
|  | return -1 | 
|  | } | 
|  | return len(x.GetRepeatedSint32()) | 
|  | }, | 
|  | }, | 
|  | { | 
|  | fName:  "repeated_sint64", | 
|  | set:    func() { x.SetRepeatedSint64([]int64{}) }, | 
|  | setNil: func() { x.SetRepeatedSint64(nil) }, | 
|  | len: func() int { | 
|  | if x.GetRepeatedSint64() == nil { | 
|  | return -1 | 
|  | } | 
|  | return len(x.GetRepeatedSint64()) | 
|  | }, | 
|  | }, | 
|  | { | 
|  | fName:  "repeated_fixed32", | 
|  | set:    func() { x.SetRepeatedFixed32([]uint32{}) }, | 
|  | setNil: func() { x.SetRepeatedFixed32(nil) }, | 
|  | len: func() int { | 
|  | if x.GetRepeatedFixed32() == nil { | 
|  | return -1 | 
|  | } | 
|  | return len(x.GetRepeatedFixed32()) | 
|  | }, | 
|  | }, | 
|  | { | 
|  | fName:  "repeated_fixed64", | 
|  | set:    func() { x.SetRepeatedFixed64([]uint64{}) }, | 
|  | setNil: func() { x.SetRepeatedFixed64(nil) }, | 
|  | len: func() int { | 
|  | if x.GetRepeatedFixed64() == nil { | 
|  | return -1 | 
|  | } | 
|  | return len(x.GetRepeatedFixed64()) | 
|  | }, | 
|  | }, | 
|  | { | 
|  | fName:  "repeated_sfixed32", | 
|  | set:    func() { x.SetRepeatedSfixed32([]int32{}) }, | 
|  | setNil: func() { x.SetRepeatedSfixed32(nil) }, | 
|  | len: func() int { | 
|  | if x.GetRepeatedSfixed32() == nil { | 
|  | return -1 | 
|  | } | 
|  | return len(x.GetRepeatedSfixed32()) | 
|  | }, | 
|  | }, | 
|  | { | 
|  | fName:  "repeated_sfixed64", | 
|  | set:    func() { x.SetRepeatedSfixed64([]int64{}) }, | 
|  | setNil: func() { x.SetRepeatedSfixed64(nil) }, | 
|  | len: func() int { | 
|  | if x.GetRepeatedSfixed64() == nil { | 
|  | return -1 | 
|  | } | 
|  | return len(x.GetRepeatedSfixed64()) | 
|  | }, | 
|  | }, | 
|  | { | 
|  | fName:  "repeated_float", | 
|  | set:    func() { x.SetRepeatedFloat([]float32{}) }, | 
|  | setNil: func() { x.SetRepeatedFloat(nil) }, | 
|  | len: func() int { | 
|  | if x.GetRepeatedFloat() == nil { | 
|  | return -1 | 
|  | } | 
|  | return len(x.GetRepeatedFloat()) | 
|  | }, | 
|  | }, | 
|  | { | 
|  | fName:  "repeated_double", | 
|  | set:    func() { x.SetRepeatedDouble([]float64{}) }, | 
|  | setNil: func() { x.SetRepeatedDouble(nil) }, | 
|  | len: func() int { | 
|  | if x.GetRepeatedDouble() == nil { | 
|  | return -1 | 
|  | } | 
|  | return len(x.GetRepeatedDouble()) | 
|  | }, | 
|  | }, | 
|  | { | 
|  | fName:  "repeated_bool", | 
|  | set:    func() { x.SetRepeatedBool([]bool{}) }, | 
|  | setNil: func() { x.SetRepeatedBool(nil) }, | 
|  | len: func() int { | 
|  | if x.GetRepeatedBool() == nil { | 
|  | return -1 | 
|  | } | 
|  | return len(x.GetRepeatedBool()) | 
|  | }, | 
|  | }, | 
|  | { | 
|  | fName:  "repeated_string", | 
|  | set:    func() { x.SetRepeatedString([]string{}) }, | 
|  | setNil: func() { x.SetRepeatedString(nil) }, | 
|  | len: func() int { | 
|  | if x.GetRepeatedString() == nil { | 
|  | return -1 | 
|  | } | 
|  | return len(x.GetRepeatedString()) | 
|  | }, | 
|  | }, | 
|  | { | 
|  | fName:  "repeated_bytes", | 
|  | set:    func() { x.SetRepeatedBytes([][]byte{}) }, | 
|  | setNil: func() { x.SetRepeatedBytes(nil) }, | 
|  | len: func() int { | 
|  | if x.GetRepeatedBytes() == nil { | 
|  | return -1 | 
|  | } | 
|  | return len(x.GetRepeatedBytes()) | 
|  | }, | 
|  | }, | 
|  | { | 
|  | fName:  "RepeatedGroup", | 
|  | set:    func() { x.SetRepeatedgroup([]*testopaquepb.TestAllTypes_RepeatedGroup{}) }, | 
|  | setNil: func() { x.SetRepeatedgroup(nil) }, | 
|  | len: func() int { | 
|  | if x.GetRepeatedgroup() == nil { | 
|  | return -1 | 
|  | } | 
|  | return len(x.GetRepeatedgroup()) | 
|  | }, | 
|  | }, | 
|  | { | 
|  | fName:  "repeated_nested_message", | 
|  | set:    func() { x.SetRepeatedNestedMessage([]*testopaquepb.TestAllTypes_NestedMessage{}) }, | 
|  | setNil: func() { x.SetRepeatedNestedMessage(nil) }, | 
|  | len: func() int { | 
|  | if x.GetRepeatedNestedMessage() == nil { | 
|  | return -1 | 
|  | } | 
|  | return len(x.GetRepeatedNestedMessage()) | 
|  | }, | 
|  | }, | 
|  | { | 
|  | fName:  "repeated_nested_enum", | 
|  | set:    func() { x.SetRepeatedNestedEnum([]testopaquepb.TestAllTypes_NestedEnum{}) }, | 
|  | setNil: func() { x.SetRepeatedNestedEnum(nil) }, | 
|  | len: func() int { | 
|  | if x.GetRepeatedNestedEnum() == nil { | 
|  | return -1 | 
|  | } | 
|  | return len(x.GetRepeatedNestedEnum()) | 
|  | }, | 
|  | }, | 
|  | } | 
|  |  | 
|  | for _, mv := range tab { | 
|  | if mv.len() != -1 { | 
|  | t.Errorf("Repeated field %s was not nil to start with ", mv.fName) | 
|  | } | 
|  | mv.set() | 
|  | if mv.len() != 0 { | 
|  | t.Errorf("Repeated field %s did not retain empty slice ", mv.fName) | 
|  | } | 
|  | b, err := proto.Marshal(x) | 
|  | if err != nil { | 
|  | t.Fatalf("Failed to marshal message, err = %v", err) | 
|  | } | 
|  | proto.Unmarshal(b, x) | 
|  | if mv.len() != -1 { | 
|  | t.Errorf("Repeated field %s was not nil to start with ", mv.fName) | 
|  | } | 
|  | mv.set() | 
|  | mv.setNil() | 
|  | if mv.len() != -1 { | 
|  | t.Errorf("Repeated field %s was not nil event though we set it to ", mv.fName) | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | // Check that we actually retain the same slice | 
|  | s := make([]testopaquepb.TestAllTypes_NestedEnum, 0, 455) | 
|  | x.SetRepeatedNestedEnum(s) | 
|  | if got, want := cap(x.GetRepeatedNestedEnum()), 455; got != want { | 
|  | t.Errorf("cap(x.GetRepeatedNestedEnum()) returned %v, expected %v", got, want) | 
|  | } | 
|  | // Do this for a message too | 
|  | s2 := make([]*testopaquepb.TestAllTypes_NestedMessage, 0, 544) | 
|  | x.SetRepeatedNestedMessage(s2) | 
|  | if got, want := cap(x.GetRepeatedNestedMessage()), 544; got != want { | 
|  | t.Errorf("cap(x.GetRepeatedNestedMessage()) returned %v, expected %v", got, want) | 
|  | t.Errorf("present: %v, isNilen: %v", checkPresent(x, 34), x.GetRepeatedNestedMessage()) | 
|  | } | 
|  | // Check special bytes behavior | 
|  | x.SetOptionalBytes(nil) | 
|  | if got, want := x.HasOptionalBytes(), true; got != want { | 
|  | t.Errorf("HasOptionalBytes after setting to nil returned %v, expected %v", got, want) | 
|  | } | 
|  | if got := x.GetOptionalBytes(); got == nil || len(got) != 0 { | 
|  | t.Errorf("GetOptionalBytes after setting to nil returned %v, expected %v", got, []byte{}) | 
|  | } | 
|  | } | 
|  |  | 
|  | func checkPresent(m proto.Message, fn uint32) bool { | 
|  | vv := reflect.ValueOf(m).Elem() | 
|  | rf := vv.FieldByName("XXX_presence") | 
|  | rf = reflect.NewAt(rf.Type(), unsafe.Pointer(rf.UnsafeAddr())).Elem() | 
|  | ai := int(fn) / 32 | 
|  | bit := fn % 32 | 
|  | ptr := rf.Index(ai).Addr().Interface().(*uint32) | 
|  | return (*ptr & (1 << bit)) > 0 | 
|  | } |