@@ -11,6 +11,8 @@ import (
1111 "slices"
1212 "strings"
1313 "testing"
14+
15+ "go.opentelemetry.io/otel/attribute/internal/xxhash"
1416)
1517
1618// keyVals is all the KeyValue generators that are used for testing. This is
@@ -38,6 +40,43 @@ var keyVals = []func(string) KeyValue{
3840 func (k string ) KeyValue { return StringSlice (k , []string {"[]i1" }) },
3941 func (k string ) KeyValue { return ByteSlice (k , []byte ("foo" )) },
4042 func (k string ) KeyValue { return ByteSlice (k , []byte ("[]i1" )) },
43+ func (k string ) KeyValue { return Slice (k ) },
44+ func (k string ) KeyValue { return Slice (k , BoolValue (true )) },
45+ func (k string ) KeyValue { return Slice (k , BoolValue (true ), IntValue (42 )) },
46+ func (k string ) KeyValue {
47+ return Slice (k ,
48+ StringValue ("triad" ),
49+ IntValue (3 ),
50+ BoolValue (false ),
51+ )
52+ },
53+ func (k string ) KeyValue {
54+ return Slice (k ,
55+ StringValue ("quad" ),
56+ IntValue (4 ),
57+ BoolValue (false ),
58+ Float64Value (4.25 ),
59+ )
60+ },
61+ func (k string ) KeyValue {
62+ return Slice (k ,
63+ StringValue ("penta" ),
64+ IntValue (5 ),
65+ BoolValue (true ),
66+ Float64Value (5.5 ),
67+ ByteSliceValue ([]byte ("five" )),
68+ )
69+ },
70+ func (k string ) KeyValue {
71+ return Slice (k ,
72+ StringValue ("nested" ),
73+ SliceValue (Float64Value (math .Inf (1 )), ByteSliceValue ([]byte ("bin" ))),
74+ BoolValue (true ),
75+ IntValue (6 ),
76+ StringValue ("tail" ),
77+ StringSliceValue ([]string {"fallback" }),
78+ )
79+ },
4180 func (k string ) KeyValue { return KeyValue {Key : Key (k )} }, // Empty value.
4281}
4382
@@ -129,6 +168,53 @@ func BenchmarkHashKVs(b *testing.B) {
129168 }
130169}
131170
171+ func BenchmarkHashValueSlice (b * testing.B ) {
172+ benches := []struct {
173+ name string
174+ v Value
175+ }{
176+ {
177+ name : "Len2" ,
178+ v : SliceValue (
179+ BoolValue (true ),
180+ StringValue ("two" ),
181+ ),
182+ },
183+ {
184+ name : "Len5" ,
185+ v : SliceValue (
186+ BoolValue (true ),
187+ IntValue (2 ),
188+ StringValue ("three" ),
189+ Float64Value (4.5 ),
190+ ByteSliceValue ([]byte ("five" )),
191+ ),
192+ },
193+ {
194+ name : "Len8Nested" ,
195+ v : SliceValue (
196+ BoolValue (true ),
197+ IntValue (2 ),
198+ StringValue ("three" ),
199+ Float64Value (4.5 ),
200+ ByteSliceValue ([]byte ("five" )),
201+ SliceValue (StringValue ("nested" ), Int64Value (6 )),
202+ BoolSliceValue ([]bool {true , false , true }),
203+ StringSliceValue ([]string {"seven" , "eight" }),
204+ ),
205+ },
206+ }
207+
208+ for _ , bench := range benches {
209+ b .Run (bench .name , func (b * testing.B ) {
210+ b .ReportAllocs ()
211+ for b .Loop () {
212+ hashValue (xxhash .New (), bench .v ).Sum64 ()
213+ }
214+ })
215+ }
216+ }
217+
132218func FuzzHashKVs (f * testing.F ) {
133219 // Add seed inputs to ensure coverage of edge cases.
134220 f .Add ("" , "" , "" , "" , "" , "" , 0 , int64 (0 ), 0.0 , false , uint8 (0 ))
@@ -167,9 +253,9 @@ func FuzzHashKVs(f *testing.F) {
167253 kvs = append (kvs , Bool (k5 , b ))
168254 }
169255
170- // Add slice types based on sliceType parameter
256+ // Add slice types based on sliceType parameter.
171257 if numAttrs > 5 {
172- switch sliceType % 5 {
258+ switch sliceType % 6 {
173259 case 0 :
174260 // Test BoolSlice with variable length.
175261 bools := make ([]bool , len (s )% 5 ) // 0-4 elements
@@ -214,6 +300,21 @@ func FuzzHashKVs(f *testing.F) {
214300 bytes [i ] = byte (i + len (k1 ))
215301 }
216302 kvs = append (kvs , ByteSlice ("bytes" , bytes ))
303+ case 5 :
304+ values := make ([]Value , len (s )% 4 ) // 0-3 elements
305+ for i := range values {
306+ switch i % 4 {
307+ case 0 :
308+ values [i ] = BoolValue ((i + len (k1 ))% 2 == 0 )
309+ case 1 :
310+ values [i ] = IntValue (i + len (k2 ))
311+ case 2 :
312+ values [i ] = StringValue (fmt .Sprintf ("item_%d" , i ))
313+ case 3 :
314+ values [i ] = SliceValue (Float64Value (fVal ), ByteSliceValue ([]byte ("bin" )))
315+ }
316+ }
317+ kvs = append (kvs , Slice ("slice" , values ... ))
217318 }
218319 }
219320
@@ -295,6 +396,22 @@ func FuzzHashKVs(f *testing.F) {
295396 if ! math .IsNaN (val ) && ! math .IsInf (val , 0 ) {
296397 modifiedKvs [0 ] = Float64 (string (modifiedKvs [0 ].Key ), val + 1.0 )
297398 }
399+ case SLICE :
400+ origSlice := modifiedKvs [0 ].Value .AsSlice ()
401+ if len (origSlice ) > 0 {
402+ newSlice := slices .Clone (origSlice )
403+ switch newSlice [0 ].Type () {
404+ case INT64 :
405+ newSlice [0 ] = Int64Value (newSlice [0 ].AsInt64 () + 1 )
406+ case BOOL :
407+ newSlice [0 ] = BoolValue (! newSlice [0 ].AsBool ())
408+ case STRING :
409+ newSlice [0 ] = StringValue (newSlice [0 ].AsString () + "_mod" )
410+ default :
411+ newSlice [0 ] = StringValue ("modified" )
412+ }
413+ modifiedKvs [0 ] = Slice (string (modifiedKvs [0 ].Key ), newSlice ... )
414+ }
298415 case EMPTY :
299416 modifiedKvs [0 ] = String (string (modifiedKvs [0 ].Key ), "not_empty" )
300417 }
0 commit comments