mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-09-13 06:09:21 -04:00
- shorten the multi-line doc comments flagged as too verbose - add reconcile_test.go: direct unit tests for Reconcile incl. the persisted-but-errored and classify-error branches (previously only reached indirectly through the engine integration tests) - convert the 11 near-identical Classify It blocks to a DescribeTable
138 lines
4.6 KiB
Go
138 lines
4.6 KiB
Go
package mapping
|
|
|
|
import (
|
|
"encoding/json"
|
|
"slices"
|
|
|
|
. "github.com/onsi/ginkgo/v2"
|
|
. "github.com/onsi/gomega"
|
|
)
|
|
|
|
var _ = Describe("Classify", func() {
|
|
code := `{
|
|
"Name": {"type": "keyword"},
|
|
"Size": {"type": "long"},
|
|
"photo": {"properties": {"cameraMake": {"type": "keyword"}, "cameraModel": {"type": "keyword"}}}
|
|
}`
|
|
|
|
parse := func(s string) map[string]any {
|
|
var m map[string]any
|
|
Expect(json.Unmarshal([]byte(s), &m)).To(Succeed())
|
|
return m
|
|
}
|
|
|
|
hasData := func(fields ...string) func(string) bool {
|
|
return func(path string) bool { return slices.Contains(fields, path) }
|
|
}
|
|
|
|
// setup produces the (stored, code, dataFields) arguments for one case.
|
|
type setup func() (stored, codeSchema map[string]any, dataFields func(string) bool)
|
|
|
|
substrings := func(ss []string) []any {
|
|
out := make([]any, len(ss))
|
|
for i, s := range ss {
|
|
out[i] = ContainSubstring(s)
|
|
}
|
|
return out
|
|
}
|
|
fields := func(ss []string) []any {
|
|
out := make([]any, len(ss))
|
|
for i, s := range ss {
|
|
out[i] = s
|
|
}
|
|
return out
|
|
}
|
|
|
|
// newFields/reasons are asserted only when non-nil; an empty slice asserts
|
|
// "none".
|
|
DescribeTable("verdict",
|
|
func(s setup, verdict Verdict, newFields, reasons []string) {
|
|
stored, codeSchema, dataFields := s()
|
|
|
|
c := Classify(stored, codeSchema, dataFields)
|
|
Expect(c.Verdict).To(Equal(verdict))
|
|
if newFields != nil {
|
|
Expect(c.NewFields).To(ConsistOf(fields(newFields)...))
|
|
}
|
|
if reasons != nil {
|
|
Expect(c.Reasons).To(ConsistOf(substrings(reasons)...))
|
|
}
|
|
},
|
|
Entry("identical schemas are equal",
|
|
setup(func() (map[string]any, map[string]any, func(string) bool) {
|
|
return parse(code), parse(code), nil
|
|
}), VerdictEqual, []string{}, []string{}),
|
|
|
|
Entry("a new top-level field is additive",
|
|
setup(func() (map[string]any, map[string]any, func(string) bool) {
|
|
stored := parse(code)
|
|
delete(stored, "Size")
|
|
return stored, parse(code), nil
|
|
}), VerdictAdditive, []string{"Size"}, nil),
|
|
|
|
Entry("a new nested field is additive",
|
|
setup(func() (map[string]any, map[string]any, func(string) bool) {
|
|
stored := parse(code)
|
|
delete(stored["photo"].(map[string]any)["properties"].(map[string]any), "cameraMake")
|
|
return stored, parse(code), nil
|
|
}), VerdictAdditive, []string{"photo.cameraMake"}, nil),
|
|
|
|
Entry("a new subtree lists every leaf",
|
|
setup(func() (map[string]any, map[string]any, func(string) bool) {
|
|
stored := parse(code)
|
|
delete(stored, "photo")
|
|
return stored, parse(code), nil
|
|
}), VerdictAdditive, []string{"photo.cameraMake", "photo.cameraModel"}, nil),
|
|
|
|
Entry("a new field that already holds data is breaking",
|
|
setup(func() (map[string]any, map[string]any, func(string) bool) {
|
|
stored := parse(code)
|
|
delete(stored, "Size")
|
|
return stored, parse(code), hasData("Size")
|
|
}), VerdictBreaking, nil, []string{"Size"}),
|
|
|
|
Entry("a new nested field that already holds data is breaking",
|
|
setup(func() (map[string]any, map[string]any, func(string) bool) {
|
|
stored := parse(code)
|
|
delete(stored["photo"].(map[string]any)["properties"].(map[string]any), "cameraMake")
|
|
return stored, parse(code), hasData("photo.cameraMake")
|
|
}), VerdictBreaking, nil, []string{"photo.cameraMake"}),
|
|
|
|
Entry("a new subtree with data below it is breaking",
|
|
setup(func() (map[string]any, map[string]any, func(string) bool) {
|
|
stored := parse(code)
|
|
delete(stored, "photo")
|
|
return stored, parse(code), hasData("photo")
|
|
}), VerdictBreaking, nil, []string{"photo"}),
|
|
|
|
Entry("a changed field definition is breaking",
|
|
setup(func() (map[string]any, map[string]any, func(string) bool) {
|
|
stored := parse(code)
|
|
stored["Size"].(map[string]any)["type"] = "keyword"
|
|
return stored, parse(code), nil
|
|
}), VerdictBreaking, nil, []string{"Size"}),
|
|
|
|
Entry("a field removed from the code schema is breaking",
|
|
setup(func() (map[string]any, map[string]any, func(string) bool) {
|
|
reduced := parse(code)
|
|
delete(reduced, "Size")
|
|
return parse(code), reduced, nil
|
|
}), VerdictBreaking, nil, []string{"removed or renamed"}),
|
|
|
|
Entry("a changed object attribute is breaking",
|
|
setup(func() (map[string]any, map[string]any, func(string) bool) {
|
|
stored := parse(code)
|
|
stored["photo"].(map[string]any)["dynamic"] = true
|
|
return stored, parse(code), nil
|
|
}), VerdictBreaking, nil, []string{"dynamic"}),
|
|
|
|
Entry("breaking wins over additive",
|
|
setup(func() (map[string]any, map[string]any, func(string) bool) {
|
|
stored := parse(code)
|
|
delete(stored, "Size")
|
|
stored["Name"].(map[string]any)["type"] = "text"
|
|
return stored, parse(code), nil
|
|
}), VerdictBreaking, []string{"Size"}, []string{"Name"}),
|
|
)
|
|
})
|