@@ -359,90 +359,273 @@ void builder_arrayTypes() {
359359 }
360360
361361 @ Test
362- void builder_valueTypes () {
363- // Test Value type attributes with various Value kinds
364- // Note: simple Value types (string, long, double, boolean) are coerced to their
365- // corresponding primitive AttributeTypes for consistent storage
366-
367- // These Value types should be coerced to primitive types
368- AttributeKey <Value <?>> stringValueKey = valueKey ("stringValue" );
369- AttributeKey <Value <?>> longValueKey = valueKey ("longValue" );
370- AttributeKey <Value <?>> doubleValueKey = valueKey ("doubleValue" );
371- AttributeKey <Value <?>> booleanValueKey = valueKey ("booleanValue" );
372-
373- // These Value types cannot be coerced and remain as VALUE type
374- AttributeKey <Value <?>> bytesValueKey = valueKey ("bytesValue" );
375- AttributeKey <Value <?>> kvListValueKey = valueKey ("kvListValue" );
376- AttributeKey <Value <?>> heterogeneousArrayKey = valueKey ("heterogeneousArray" );
377- AttributeKey <Value <?>> emptyValueKey = valueKey ("emptyValue" );
362+ void valueStoredAsString () {
363+ // When putting a VALUE attribute with a string Value, it should be stored as STRING type
364+ Attributes attributes = Attributes .builder ().put (valueKey ("key" ), Value .of ("test" )).build ();
378365
366+ // Should be stored as STRING type internally
367+ assertThat (attributes .get (stringKey ("key" ))).isEqualTo ("test" );
368+ assertThat (attributes .get (valueKey ("key" ))).isEqualTo (Value .of ("test" ));
369+
370+ // forEach should show STRING type
371+ Map <AttributeKey , Object > entriesSeen = new HashMap <>();
372+ attributes .forEach (entriesSeen ::put );
373+ assertThat (entriesSeen ).containsExactly (entry (stringKey ("key" ), "test" ));
374+
375+ // asMap should show STRING type
376+ assertThat (attributes .asMap ()).containsExactly (entry (stringKey ("key" ), "test" ));
377+ }
378+
379+ @ Test
380+ void valueStoredAsLong () {
381+ // When putting a VALUE attribute with a long Value, it should be stored as LONG type
382+ Attributes attributes = Attributes .builder ().put (valueKey ("key" ), Value .of (123L )).build ();
383+
384+ // Should be stored as LONG type internally
385+ assertThat (attributes .get (longKey ("key" ))).isEqualTo (123L );
386+ assertThat (attributes .get (valueKey ("key" ))).isEqualTo (Value .of (123L ));
387+
388+ // forEach should show LONG type
389+ Map <AttributeKey , Object > entriesSeen = new HashMap <>();
390+ attributes .forEach (entriesSeen ::put );
391+ assertThat (entriesSeen ).containsExactly (entry (longKey ("key" ), 123L ));
392+
393+ // asMap should show LONG type
394+ assertThat (attributes .asMap ()).containsExactly (entry (longKey ("key" ), 123L ));
395+ }
396+
397+ @ Test
398+ void valueStoredAsDouble () {
399+ // When putting a VALUE attribute with a double Value, it should be stored as DOUBLE type
400+ Attributes attributes = Attributes .builder ().put (valueKey ("key" ), Value .of (1.23 )).build ();
401+
402+ // Should be stored as DOUBLE type internally
403+ assertThat (attributes .get (doubleKey ("key" ))).isEqualTo (1.23 );
404+ assertThat (attributes .get (valueKey ("key" ))).isEqualTo (Value .of (1.23 ));
405+
406+ // forEach should show DOUBLE type
407+ Map <AttributeKey , Object > entriesSeen = new HashMap <>();
408+ attributes .forEach (entriesSeen ::put );
409+ assertThat (entriesSeen ).containsExactly (entry (doubleKey ("key" ), 1.23 ));
410+
411+ // asMap should show DOUBLE type
412+ assertThat (attributes .asMap ()).containsExactly (entry (doubleKey ("key" ), 1.23 ));
413+ }
414+
415+ @ Test
416+ void valueStoredAsBoolean () {
417+ // When putting a VALUE attribute with a boolean Value, it should be stored as BOOLEAN type
418+ Attributes attributes = Attributes .builder ().put (valueKey ("key" ), Value .of (true )).build ();
419+
420+ // Should be stored as BOOLEAN type internally
421+ assertThat (attributes .get (booleanKey ("key" ))).isEqualTo (true );
422+ assertThat (attributes .get (valueKey ("key" ))).isEqualTo (Value .of (true ));
423+
424+ // forEach should show BOOLEAN type
425+ Map <AttributeKey , Object > entriesSeen = new HashMap <>();
426+ attributes .forEach (entriesSeen ::put );
427+ assertThat (entriesSeen ).containsExactly (entry (booleanKey ("key" ), true ));
428+
429+ // asMap should show BOOLEAN type
430+ assertThat (attributes .asMap ()).containsExactly (entry (booleanKey ("key" ), true ));
431+ }
432+
433+ @ Test
434+ void valueStoredAsStringArray () {
435+ // When putting a VALUE attribute with a homogeneous string array, it should be stored as
436+ // STRING_ARRAY type
379437 Attributes attributes =
380438 Attributes .builder ()
381- .put (stringValueKey , Value .of ("stringVal" ))
382- .put (longValueKey , Value .of (100L ))
383- .put (doubleValueKey , Value .of (3.14 ))
384- .put (booleanValueKey , Value .of (true ))
385- .put (bytesValueKey , Value .of (new byte [] {1 , 2 , 3 }))
386- .put (kvListValueKey , Value .of (KeyValue .of ("nested" , Value .of ("value" ))))
387- .put (heterogeneousArrayKey , Value .of (Value .of ("elem1" ), Value .of (42L )))
388- .put (emptyValueKey , Value .empty ())
439+ .put (valueKey ("key" ), Value .of (Arrays .asList (Value .of ("a" ), Value .of ("b" ))))
389440 .build ();
390441
391- // Verify coerced values can be retrieved with primitive keys
392- assertThat (attributes .get (stringKey ("stringValue" ))).isEqualTo ("stringVal" );
393- assertThat (attributes .get (longKey ("longValue" ))).isEqualTo (100L );
394- assertThat (attributes .get (doubleKey ("doubleValue" ))).isEqualTo (3.14 );
395- assertThat (attributes .get (booleanKey ("booleanValue" ))).isEqualTo (true );
442+ // Should be stored as STRING_ARRAY type internally
443+ assertThat (attributes .get (stringArrayKey ("key" ))).containsExactly ("a" , "b" );
444+ assertThat (attributes .get (valueKey ("key" )))
445+ .isEqualTo (Value .of (Arrays .asList (Value .of ("a" ), Value .of ("b" ))));
396446
397- // Verify complex Value types that remain as VALUE type
398- assertThat (attributes .get (bytesValueKey )).isNotNull ();
399- assertThat (attributes .get (bytesValueKey ).getType ()).isEqualTo (ValueType .BYTES );
447+ // forEach should show STRING_ARRAY type
448+ Map <AttributeKey , Object > entriesSeen = new HashMap <>();
449+ attributes .forEach (entriesSeen ::put );
450+ assertThat (entriesSeen ).containsExactly (entry (stringArrayKey ("key" ), Arrays .asList ("a" , "b" )));
400451
401- assertThat (attributes .get (kvListValueKey )).isNotNull ();
402- assertThat (attributes .get (kvListValueKey ).getType ()).isEqualTo (ValueType .KEY_VALUE_LIST );
452+ // asMap should show STRING_ARRAY type
453+ assertThat (attributes .asMap ())
454+ .containsExactly (entry (stringArrayKey ("key" ), Arrays .asList ("a" , "b" )));
455+ }
403456
404- assertThat (attributes .get (heterogeneousArrayKey )).isNotNull ();
405- assertThat (attributes .get (heterogeneousArrayKey ).getType ()).isEqualTo (ValueType .ARRAY );
457+ @ Test
458+ void valueStoredAsLongArray () {
459+ // When putting a VALUE attribute with a homogeneous long array, it should be stored as
460+ // LONG_ARRAY type
461+ Attributes attributes =
462+ Attributes .builder ()
463+ .put (valueKey ("key" ), Value .of (Arrays .asList (Value .of (1L ), Value .of (2L ))))
464+ .build ();
406465
407- assertThat (attributes .get (emptyValueKey )).isNotNull ();
408- assertThat (attributes .get (emptyValueKey ).getType ()).isEqualTo (ValueType .EMPTY );
409- assertThat (attributes .get (emptyValueKey ).getValue ()).isNull ();
466+ // Should be stored as LONG_ARRAY type internally
467+ assertThat (attributes .get (longArrayKey ("key" ))).containsExactly (1L , 2L );
468+ assertThat (attributes .get (valueKey ("key" )))
469+ .isEqualTo (Value .of (Arrays .asList (Value .of (1L ), Value .of (2L ))));
410470
411- // Verify the total size
412- assertThat (attributes .size ()).isEqualTo (8 );
471+ // forEach should show LONG_ARRAY type
472+ Map <AttributeKey , Object > entriesSeen = new HashMap <>();
473+ attributes .forEach (entriesSeen ::put );
474+ assertThat (entriesSeen ).containsExactly (entry (longArrayKey ("key" ), Arrays .asList (1L , 2L )));
413475
414- // Verify forEach sees the correct types
415- Map <AttributeKey , Object > entriesSeen = new LinkedHashMap <>();
476+ // asMap should show LONG_ARRAY type
477+ assertThat (attributes .asMap ())
478+ .containsExactly (entry (longArrayKey ("key" ), Arrays .asList (1L , 2L )));
479+ }
480+
481+ @ Test
482+ void valueStoredAsDoubleArray () {
483+ // When putting a VALUE attribute with a homogeneous double array, it should be stored as
484+ // DOUBLE_ARRAY type
485+ Attributes attributes =
486+ Attributes .builder ()
487+ .put (valueKey ("key" ), Value .of (Arrays .asList (Value .of (1.1 ), Value .of (2.2 ))))
488+ .build ();
489+
490+ // Should be stored as DOUBLE_ARRAY type internally
491+ assertThat (attributes .get (doubleArrayKey ("key" ))).containsExactly (1.1 , 2.2 );
492+ assertThat (attributes .get (valueKey ("key" )))
493+ .isEqualTo (Value .of (Arrays .asList (Value .of (1.1 ), Value .of (2.2 ))));
494+
495+ // forEach should show DOUBLE_ARRAY type
496+ Map <AttributeKey , Object > entriesSeen = new HashMap <>();
497+ attributes .forEach (entriesSeen ::put );
498+ assertThat (entriesSeen ).containsExactly (entry (doubleArrayKey ("key" ), Arrays .asList (1.1 , 2.2 )));
499+
500+ // asMap should show DOUBLE_ARRAY type
501+ assertThat (attributes .asMap ())
502+ .containsExactly (entry (doubleArrayKey ("key" ), Arrays .asList (1.1 , 2.2 )));
503+ }
504+
505+ @ Test
506+ void valueStoredAsBooleanArray () {
507+ // When putting a VALUE attribute with a homogeneous boolean array, it should be stored as
508+ // BOOLEAN_ARRAY type
509+ Attributes attributes =
510+ Attributes .builder ()
511+ .put (valueKey ("key" ), Value .of (Arrays .asList (Value .of (true ), Value .of (false ))))
512+ .build ();
513+
514+ // Should be stored as BOOLEAN_ARRAY type internally
515+ assertThat (attributes .get (booleanArrayKey ("key" ))).containsExactly (true , false );
516+ assertThat (attributes .get (valueKey ("key" )))
517+ .isEqualTo (Value .of (Arrays .asList (Value .of (true ), Value .of (false ))));
518+
519+ // forEach should show BOOLEAN_ARRAY type
520+ Map <AttributeKey , Object > entriesSeen = new HashMap <>();
521+ attributes .forEach (entriesSeen ::put );
522+ assertThat (entriesSeen )
523+ .containsExactly (entry (booleanArrayKey ("key" ), Arrays .asList (true , false )));
524+
525+ // asMap should show BOOLEAN_ARRAY type
526+ assertThat (attributes .asMap ())
527+ .containsExactly (entry (booleanArrayKey ("key" ), Arrays .asList (true , false )));
528+ }
529+
530+ @ Test
531+ void simpleAttributeRetrievedAsValue () {
532+ Attributes attributes =
533+ Attributes .builder ()
534+ .put ("string" , "test" )
535+ .put ("long" , 123L )
536+ .put ("double" , 1.23 )
537+ .put ("boolean" , true )
538+ .put ("stringArray" , "a" , "b" )
539+ .put ("longArray" , 1L , 2L )
540+ .put ("doubleArray" , 1.1 , 2.2 )
541+ .put ("booleanArray" , true , false )
542+ .build ();
543+ assertThat (attributes .get (valueKey ("string" ))).isEqualTo (Value .of ("test" ));
544+ assertThat (attributes .get (valueKey ("long" ))).isEqualTo (Value .of (123L ));
545+ assertThat (attributes .get (valueKey ("double" ))).isEqualTo (Value .of (1.23 ));
546+ assertThat (attributes .get (valueKey ("boolean" ))).isEqualTo (Value .of (true ));
547+ assertThat (attributes .get (valueKey ("stringArray" )))
548+ .isEqualTo (Value .of (Arrays .asList (Value .of ("a" ), Value .of ("b" ))));
549+ assertThat (attributes .get (valueKey ("longArray" )))
550+ .isEqualTo (Value .of (Arrays .asList (Value .of (1L ), Value .of (2L ))));
551+ assertThat (attributes .get (valueKey ("doubleArray" )))
552+ .isEqualTo (Value .of (Arrays .asList (Value .of (1.1 ), Value .of (2.2 ))));
553+ assertThat (attributes .get (valueKey ("booleanArray" )))
554+ .isEqualTo (Value .of (Arrays .asList (Value .of (true ), Value .of (false ))));
555+ }
556+
557+ @ Test
558+ void emptyValueArrayRetrievedAsAnyArrayType () {
559+ Attributes attributes =
560+ Attributes .builder ().put (valueKey ("key" ), Value .of (Collections .emptyList ())).build ();
561+ assertThat (attributes .get (stringArrayKey ("key" ))).isEmpty ();
562+ assertThat (attributes .get (longArrayKey ("key" ))).isEmpty ();
563+ assertThat (attributes .get (doubleArrayKey ("key" ))).isEmpty ();
564+ assertThat (attributes .get (booleanArrayKey ("key" ))).isEmpty ();
565+ }
566+
567+ @ Test
568+ void valueWithKeyValueList () {
569+ // KEY_VALUE_LIST should be kept as VALUE type
570+ Value <?> kvListValue = Value .of (Collections .emptyMap ());
571+ Attributes attributes = Attributes .builder ().put (valueKey ("key" ), kvListValue ).build ();
572+
573+ // Should be stored as VALUE type
574+ assertThat (attributes .get (valueKey ("key" ))).isEqualTo (kvListValue );
575+
576+ // forEach should show VALUE type
577+ Map <AttributeKey , Object > entriesSeen = new HashMap <>();
578+ attributes .forEach (entriesSeen ::put );
579+ assertThat (entriesSeen ).containsExactly (entry (valueKey ("key" ), kvListValue ));
580+ }
581+
582+ @ Test
583+ void valueWithBytes () {
584+ // BYTES should be kept as VALUE type
585+ Value <?> bytesValue = Value .of (new byte [] {1 , 2 , 3 });
586+ Attributes attributes = Attributes .builder ().put (valueKey ("key" ), bytesValue ).build ();
587+
588+ // Should be stored as VALUE type
589+ assertThat (attributes .get (valueKey ("key" ))).isEqualTo (bytesValue );
590+
591+ // forEach should show VALUE type
592+ Map <AttributeKey , Object > entriesSeen = new HashMap <>();
593+ attributes .forEach (entriesSeen ::put );
594+ assertThat (entriesSeen ).containsExactly (entry (valueKey ("key" ), bytesValue ));
595+ }
596+
597+ @ Test
598+ void valueWithNonHomogeneousArray () {
599+ // Non-homogeneous array should be kept as VALUE type
600+ Value <?> mixedArray = Value .of (Arrays .asList (Value .of ("string" ), Value .of (123L )));
601+ Attributes attributes = Attributes .builder ().put (valueKey ("key" ), mixedArray ).build ();
602+
603+ // Should be stored as VALUE type
604+ assertThat (attributes .get (valueKey ("key" ))).isEqualTo (mixedArray );
605+
606+ // forEach should show VALUE type
607+ Map <AttributeKey , Object > entriesSeen = new HashMap <>();
608+ attributes .forEach (entriesSeen ::put );
609+ assertThat (entriesSeen ).containsExactly (entry (valueKey ("key" ), mixedArray ));
610+ }
611+
612+ @ Test
613+ void valueWithNestedArray () {
614+ // Array containing arrays should be kept as VALUE type
615+ Value <?> nestedArray =
616+ Value .of (
617+ Arrays .asList (
618+ Value .of (Arrays .asList (Value .of ("a" ), Value .of ("b" ))),
619+ Value .of (Arrays .asList (Value .of ("c" ), Value .of ("d" )))));
620+ Attributes attributes = Attributes .builder ().put (valueKey ("key" ), nestedArray ).build ();
621+
622+ // Should be stored as VALUE type
623+ assertThat (attributes .get (valueKey ("key" ))).isEqualTo (nestedArray );
624+
625+ // forEach should show VALUE type
626+ Map <AttributeKey , Object > entriesSeen = new HashMap <>();
416627 attributes .forEach (entriesSeen ::put );
417- assertThat (entriesSeen ).hasSize (8 );
418-
419- // Verify coerced keys have primitive types
420- assertThat (entriesSeen .keySet ())
421- .filteredOn (key -> key .getKey ().equals ("stringValue" ))
422- .allMatch (key -> key .getType () == AttributeType .STRING );
423- assertThat (entriesSeen .keySet ())
424- .filteredOn (key -> key .getKey ().equals ("longValue" ))
425- .allMatch (key -> key .getType () == AttributeType .LONG );
426- assertThat (entriesSeen .keySet ())
427- .filteredOn (key -> key .getKey ().equals ("doubleValue" ))
428- .allMatch (key -> key .getType () == AttributeType .DOUBLE );
429- assertThat (entriesSeen .keySet ())
430- .filteredOn (key -> key .getKey ().equals ("booleanValue" ))
431- .allMatch (key -> key .getType () == AttributeType .BOOLEAN );
432-
433- // Verify complex types remain as VALUE type
434- assertThat (entriesSeen .keySet ())
435- .filteredOn (key -> key .getKey ().equals ("bytesValue" ))
436- .allMatch (key -> key .getType () == AttributeType .VALUE );
437- assertThat (entriesSeen .keySet ())
438- .filteredOn (key -> key .getKey ().equals ("kvListValue" ))
439- .allMatch (key -> key .getType () == AttributeType .VALUE );
440- assertThat (entriesSeen .keySet ())
441- .filteredOn (key -> key .getKey ().equals ("heterogeneousArray" ))
442- .allMatch (key -> key .getType () == AttributeType .VALUE );
443- assertThat (entriesSeen .keySet ())
444- .filteredOn (key -> key .getKey ().equals ("emptyValue" ))
445- .allMatch (key -> key .getType () == AttributeType .VALUE );
628+ assertThat (entriesSeen ).containsExactly (entry (valueKey ("key" ), nestedArray ));
446629 }
447630
448631 @ Test
0 commit comments