mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-08-01 18:29:02 -04:00
107 lines
3.2 KiB
Go
107 lines
3.2 KiB
Go
package mapping
|
|
|
|
import (
|
|
"errors"
|
|
"reflect"
|
|
|
|
. "github.com/onsi/ginkgo/v2"
|
|
. "github.com/onsi/gomega"
|
|
)
|
|
|
|
// The walker is shared by both deserializers, so its structural behavior
|
|
// (flattening embedded structs, recursing into nested pointers, joining the
|
|
// prefix, keeping a pointer only when a field was set, fail-soft skipping) is
|
|
// tested here once against a trivial string setter instead of twice through
|
|
// Deserialize and DeserializeStringsAt.
|
|
|
|
// FsEmbVal/FsEmbPtr are exported so their embedded field is exported; an
|
|
// unexported embedded type would be skipped by resolveField.
|
|
type FsEmbVal struct {
|
|
EV string `json:"ev"`
|
|
}
|
|
|
|
type FsEmbPtr struct {
|
|
EP string `json:"ep"`
|
|
}
|
|
|
|
type fsNested struct {
|
|
N string `json:"n"`
|
|
}
|
|
|
|
type fsRoot struct {
|
|
FsEmbVal // embedded value struct: fields promoted
|
|
*FsEmbPtr // embedded pointer struct: allocated on demand
|
|
Leaf string `json:"leaf"`
|
|
Nested *fsNested `json:"nested"` // nested pointer: recursed under "nested."
|
|
}
|
|
|
|
var errBadLeaf = errors.New("bad leaf")
|
|
|
|
// fsSet writes raw into a string field; the "BAD" sentinel simulates a parse
|
|
// failure so the fail-soft path can be exercised.
|
|
func fsSet(v reflect.Value, raw string) error {
|
|
if raw == "BAD" {
|
|
return errBadLeaf
|
|
}
|
|
v.SetString(raw)
|
|
return nil
|
|
}
|
|
|
|
var _ = Describe("fillStruct", func() {
|
|
fill := func(fields map[string]string, prefix string) (fsRoot, bool) {
|
|
var root fsRoot
|
|
touched := fillStruct(reflect.ValueOf(&root).Elem(), fields, prefix, fsSet)
|
|
return root, touched
|
|
}
|
|
|
|
It("flattens embedded and recurses nested", func() {
|
|
root, touched := fill(map[string]string{
|
|
"leaf": "L",
|
|
"ev": "EV",
|
|
"ep": "EP",
|
|
"nested.n": "N",
|
|
}, "")
|
|
Expect(touched).To(BeTrue())
|
|
Expect(root.Leaf).To(Equal("L"))
|
|
Expect(root.EV).To(Equal("EV"), "embedded value not promoted")
|
|
Expect(root.FsEmbPtr).ToNot(BeNil(), "embedded pointer not allocated")
|
|
Expect(root.EP).To(Equal("EP"))
|
|
Expect(root.Nested).ToNot(BeNil(), "nested pointer not populated")
|
|
Expect(root.Nested.N).To(Equal("N"))
|
|
})
|
|
|
|
It("leaves touched false and pointers nil when nothing matches", func() {
|
|
root, touched := fill(map[string]string{"other": "x"}, "")
|
|
Expect(touched).To(BeFalse())
|
|
Expect(root.Nested).To(BeNil(), "Nested should stay nil")
|
|
Expect(root.FsEmbPtr).To(BeNil(), "embedded pointer should stay nil")
|
|
})
|
|
|
|
It("joins the prefix arg with the field name", func() {
|
|
root, touched := fill(map[string]string{
|
|
"pre.leaf": "L",
|
|
"pre.nested.n": "N",
|
|
}, "pre")
|
|
Expect(touched).To(BeTrue())
|
|
Expect(root.Leaf).To(Equal("L"))
|
|
Expect(root.Nested).ToNot(BeNil())
|
|
Expect(root.Nested.N).To(Equal("N"))
|
|
})
|
|
|
|
It("is fail-soft: errored leaf stays zero, walk continues", func() {
|
|
root, touched := fill(map[string]string{
|
|
"leaf": "BAD",
|
|
"ev": "EV",
|
|
}, "")
|
|
Expect(touched).To(BeTrue(), "expected touched because ev was set")
|
|
Expect(root.Leaf).To(BeEmpty(), "errored leaf should stay zero")
|
|
Expect(root.EV).To(Equal("EV"), "walk should continue past the error")
|
|
})
|
|
|
|
It("drops the embedded pointer when its only field errors", func() {
|
|
root, touched := fill(map[string]string{"ep": "BAD"}, "")
|
|
Expect(touched).To(BeFalse())
|
|
Expect(root.FsEmbPtr).To(BeNil(), "embedded pointer should stay nil on error")
|
|
})
|
|
})
|