@@ -1389,3 +1389,170 @@ func TestKeyLoaderEndToEnd(t *testing.T) {
13891389 }
13901390 }
13911391}
1392+
1393+ func TestIssue5225 (t * testing.T ) {
1394+ type CustomType struct {
1395+ ID []byte `datastore:"custom_identifier"`
1396+ Name string `datastore:"name"`
1397+ }
1398+
1399+ // Case 1: Struct has []byte, but Property has string (e.g. from projection)
1400+ t .Run ("String To []byte" , func (t * testing.T ) {
1401+ x := & CustomType {}
1402+ ps := []Property {
1403+ {Name : "custom_identifier" , Value : "some-id" },
1404+ }
1405+ err := LoadStruct (x , ps )
1406+ if err != nil {
1407+ t .Errorf ("LoadStruct failed: %v" , err )
1408+ }
1409+ if string (x .ID ) != "some-id" {
1410+ t .Errorf ("got x.ID = %q, want %q" , string (x .ID ), "some-id" )
1411+ }
1412+ })
1413+
1414+ // Case 2: Struct has string, but Property has []byte (e.g. from projection)
1415+ t .Run ("[]byte To String" , func (t * testing.T ) {
1416+ x := & CustomType {}
1417+ ps := []Property {
1418+ {Name : "name" , Value : []byte ("some-name" )},
1419+ }
1420+ err := LoadStruct (x , ps )
1421+ if err != nil {
1422+ t .Errorf ("LoadStruct failed: %v" , err )
1423+ }
1424+ if x .Name != "some-name" {
1425+ t .Errorf ("got x.Name = %q, want %q" , x .Name , "some-name" )
1426+ }
1427+ })
1428+
1429+ // Case 3: Pointer to string, but Property has []byte
1430+ t .Run ("[]byte To *String" , func (t * testing.T ) {
1431+ type PtrType struct {
1432+ Name * string `datastore:"name"`
1433+ }
1434+ x := & PtrType {}
1435+ ps := []Property {
1436+ {Name : "name" , Value : []byte ("some-name" )},
1437+ }
1438+ err := LoadStruct (x , ps )
1439+ if err != nil {
1440+ t .Errorf ("LoadStruct failed: %v" , err )
1441+ }
1442+ if x .Name == nil || * x .Name != "some-name" {
1443+ got := "nil"
1444+ if x .Name != nil {
1445+ got = * x .Name
1446+ }
1447+ t .Errorf ("got x.Name = %q, want %q" , got , "some-name" )
1448+ }
1449+ })
1450+
1451+ // Case 4: time.Time, but Property has int64 (micros)
1452+ t .Run ("int64 To time.Time" , func (t * testing.T ) {
1453+ type TimeType struct {
1454+ T time.Time `datastore:"t"`
1455+ }
1456+ x := & TimeType {}
1457+ // 1639728000123456 is 2021-12-17 08:00:00.123456 UTC
1458+ ps := []Property {
1459+ {Name : "t" , Value : int64 (1639728000123456 )},
1460+ }
1461+ err := LoadStruct (x , ps )
1462+ if err != nil {
1463+ t .Errorf ("LoadStruct failed: %v" , err )
1464+ }
1465+ want := time .Unix (1639728000 , 123456000 ).In (time .UTC )
1466+ if ! x .T .Equal (want ) {
1467+ t .Errorf ("got x.T = %v, want %v" , x .T , want )
1468+ }
1469+ })
1470+
1471+ // Case 5: *time.Time, but Property has int64 (micros)
1472+ t .Run ("int64 To *time.Time" , func (t * testing.T ) {
1473+ type TimePtrType struct {
1474+ T * time.Time `datastore:"t"`
1475+ }
1476+ x := & TimePtrType {}
1477+ ps := []Property {
1478+ {Name : "t" , Value : int64 (1639728000123456 )},
1479+ }
1480+ err := LoadStruct (x , ps )
1481+ if err != nil {
1482+ t .Errorf ("LoadStruct failed: %v" , err )
1483+ }
1484+ want := time .Unix (1639728000 , 123456000 ).In (time .UTC )
1485+ if x .T == nil || ! x .T .Equal (want ) {
1486+ t .Errorf ("got x.T = %v, want %v" , x .T , want )
1487+ }
1488+ })
1489+
1490+ // Case 6: *[]byte, but Property has string
1491+ t .Run ("String To *[]byte" , func (t * testing.T ) {
1492+ type PtrSliceType struct {
1493+ ID * []byte `datastore:"id"`
1494+ }
1495+ x := & PtrSliceType {}
1496+ ps := []Property {
1497+ {Name : "id" , Value : "some-id" },
1498+ }
1499+ err := LoadStruct (x , ps )
1500+ if err != nil {
1501+ t .Errorf ("LoadStruct failed: %v" , err )
1502+ }
1503+ if x .ID == nil || string (* x .ID ) != "some-id" {
1504+ got := "nil"
1505+ if x .ID != nil {
1506+ got = string (* x .ID )
1507+ }
1508+ t .Errorf ("got x.ID = %q, want %q" , got , "some-id" )
1509+ }
1510+ })
1511+
1512+ // Case 7: *[]byte, but Property has []byte
1513+ t .Run ("[]byte To *[]byte" , func (t * testing.T ) {
1514+ type PtrSliceType struct {
1515+ ID * []byte `datastore:"id"`
1516+ }
1517+ x := & PtrSliceType {}
1518+ ps := []Property {
1519+ {Name : "id" , Value : []byte ("some-id" )},
1520+ }
1521+ err := LoadStruct (x , ps )
1522+ if err != nil {
1523+ t .Errorf ("LoadStruct failed: %v" , err )
1524+ }
1525+ if x .ID == nil || string (* x .ID ) != "some-id" {
1526+ got := "nil"
1527+ if x .ID != nil {
1528+ got = string (* x .ID )
1529+ }
1530+ t .Errorf ("got x.ID = %q, want %q" , got , "some-id" )
1531+ }
1532+ })
1533+
1534+ // Case 8: Saving *[]byte
1535+ t .Run ("Save *[]byte" , func (t * testing.T ) {
1536+ type PtrSliceType struct {
1537+ ID * []byte `datastore:"id"`
1538+ }
1539+ data := []byte ("some-id" )
1540+ x := & PtrSliceType {ID : & data }
1541+ props , err := SaveStruct (x )
1542+ if err != nil {
1543+ t .Errorf ("SaveStruct failed: %v" , err )
1544+ }
1545+ found := false
1546+ for _ , p := range props {
1547+ if p .Name == "id" {
1548+ found = true
1549+ if string (p .Value .([]byte )) != "some-id" {
1550+ t .Errorf ("got p.Value = %q, want %q" , string (p .Value .([]byte )), "some-id" )
1551+ }
1552+ }
1553+ }
1554+ if ! found {
1555+ t .Errorf ("property 'id' not found in %v" , props )
1556+ }
1557+ })
1558+ }
0 commit comments