package convert import ( "testing" "github.com/databricks/cli/libs/diag" "github.com/databricks/cli/libs/dyn" assert "github.com/databricks/cli/libs/dyn/dynassert" "github.com/stretchr/testify/require" ) func TestNormalizeStruct(t *testing.T) { type Tmp struct { Foo string `json:"foo"` Bar string `json:"bar"` } var typ Tmp vin := dyn.V(map[string]dyn.Value{ "foo": dyn.V("bar"), "bar": dyn.V("baz"), }) vout, diags := Normalize(typ, vin) assert.Empty(t, diags) assert.Equal(t, vin, vout) } func TestNormalizeStructElementDiagnostic(t *testing.T) { type Tmp struct { Foo string `json:"foo"` Bar string `json:"bar"` } var typ Tmp vin := dyn.V(map[string]dyn.Value{ "foo": dyn.V("bar"), "bar": dyn.V(map[string]dyn.Value{"an": dyn.V("error")}), }) vout, diags := Normalize(typ, vin) assert.Len(t, diags, 1) assert.Equal(t, diag.Diagnostic{ Severity: diag.Warning, Summary: `expected string, found map`, Locations: []dyn.Location{{}}, Paths: []dyn.Path{dyn.NewPath(dyn.Key("bar"))}, }, diags[0]) // Elements that encounter an error during normalization are dropped. assert.Equal(t, map[string]any{ "foo": "bar", }, vout.AsAny()) } func TestNormalizeStructUnknownField(t *testing.T) { type Tmp struct { Foo string `json:"foo"` } var typ Tmp m := dyn.NewMapping() err := m.Set(dyn.V("foo"), dyn.V("val-foo")) require.NoError(t, err) // Set the unknown field, with location information. err = m.Set(dyn.NewValue("bar", []dyn.Location{ {File: "hello.yaml", Line: 1, Column: 1}, {File: "world.yaml", Line: 2, Column: 2}, }), dyn.V("var-bar")) require.NoError(t, err) vin := dyn.V(m) vout, diags := Normalize(typ, vin) assert.Len(t, diags, 1) assert.Equal(t, diag.Diagnostic{ Severity: diag.Warning, Summary: `unknown field: bar`, // Assert location of the unknown field is included in the diagnostic. Locations: []dyn.Location{ {File: "hello.yaml", Line: 1, Column: 1}, {File: "world.yaml", Line: 2, Column: 2}, }, Paths: []dyn.Path{dyn.EmptyPath}, }, diags[0]) // The field that can be mapped to the struct field is retained. assert.Equal(t, map[string]any{ "foo": "val-foo", }, vout.AsAny()) } func TestNormalizeStructNil(t *testing.T) { type Tmp struct { Foo string `json:"foo"` } var typ Tmp vin := dyn.NilValue vout, err := Normalize(typ, vin) assert.Empty(t, err) assert.Equal(t, vin, vout) } func TestNormalizeStructError(t *testing.T) { type Tmp struct { Foo string `json:"foo"` } var typ Tmp vin := dyn.V("string") _, err := Normalize(typ, vin) assert.Len(t, err, 1) assert.Equal(t, diag.Diagnostic{ Severity: diag.Warning, Summary: `expected map, found string`, Locations: []dyn.Location{vin.Get("foo").Location()}, Paths: []dyn.Path{dyn.EmptyPath}, }, err[0]) } func TestNormalizeStructNestedError(t *testing.T) { type Nested struct { F1 int `json:"f1"` F2 int `json:"f2"` } type Tmp struct { Foo Nested `json:"foo"` Bar Nested `json:"bar"` } var typ Tmp vin := dyn.V(map[string]dyn.Value{ "foo": dyn.V(map[string]dyn.Value{ "f1": dyn.V("error"), "f2": dyn.V(1), }), "bar": dyn.V(map[string]dyn.Value{ "f1": dyn.V(1), "f2": dyn.V("error"), }), }) vout, err := Normalize(typ, vin) assert.Len(t, err, 2) // Verify that valid fields are retained. assert.Equal(t, dyn.V(map[string]dyn.Value{ "foo": dyn.V(map[string]dyn.Value{ "f2": dyn.V(int64(1)), }), "bar": dyn.V(map[string]dyn.Value{ "f1": dyn.V(int64(1)), }), }), vout, ) } func TestNormalizeStructIncludeMissingFields(t *testing.T) { type Nested struct { String string `json:"string"` } type Tmp struct { // Verify that fields that are already set in the dynamic value are not overridden. Existing string `json:"existing"` // Verify that structs are recursively normalized if not set. Nested Nested `json:"nested"` Ptr *Nested `json:"ptr"` // Verify that containers are also zero-initialized if not set. Map map[string]string `json:"map"` Slice []string `json:"slice"` // Verify that primitive types are zero-initialized if not set. String string `json:"string"` Bool bool `json:"bool"` Int int `json:"int"` Float float64 `json:"float"` } var typ Tmp vin := dyn.V(map[string]dyn.Value{ "existing": dyn.V("already set"), }) vout, err := Normalize(typ, vin, IncludeMissingFields) assert.Empty(t, err) assert.Equal(t, dyn.V(map[string]dyn.Value{ "existing": dyn.V("already set"), "nested": dyn.V(map[string]dyn.Value{ "string": dyn.V(""), }), "ptr": dyn.V(map[string]dyn.Value{ "string": dyn.V(""), }), "map": dyn.V(map[string]dyn.Value{}), "slice": dyn.V([]dyn.Value{}), "string": dyn.V(""), "bool": dyn.V(false), "int": dyn.V(int64(0)), "float": dyn.V(float64(0)), }), vout) } func TestNormalizeStructIncludeMissingFieldsOnRecursiveType(t *testing.T) { type Tmp struct { // Verify that structs are recursively normalized if not set. Ptr *Tmp `json:"ptr"` // Verify that primitive types are zero-initialized if not set. String string `json:"string"` } var typ Tmp vin := dyn.V(map[string]dyn.Value{ "ptr": dyn.V(map[string]dyn.Value{ "ptr": dyn.V(map[string]dyn.Value{ "string": dyn.V("already set"), }), }), }) vout, err := Normalize(typ, vin, IncludeMissingFields) assert.Empty(t, err) assert.Equal(t, dyn.V(map[string]dyn.Value{ "ptr": dyn.V(map[string]dyn.Value{ "ptr": dyn.V(map[string]dyn.Value{ // Note: the ptr field is not zero-initialized because that would recurse. "string": dyn.V("already set"), }), "string": dyn.V(""), }), "string": dyn.V(""), }), vout) } func TestNormalizeStructVariableReference(t *testing.T) { type Tmp struct { Foo string `json:"foo"` } var typ Tmp vin := dyn.NewValue("${var.foo}", []dyn.Location{{File: "file", Line: 1, Column: 1}}) vout, err := Normalize(typ, vin) assert.Empty(t, err) assert.Equal(t, vin, vout) } func TestNormalizeStructRandomStringError(t *testing.T) { type Tmp struct { Foo string `json:"foo"` } var typ Tmp vin := dyn.NewValue("var foo", []dyn.Location{{File: "file", Line: 1, Column: 1}}) _, err := Normalize(typ, vin) assert.Len(t, err, 1) assert.Equal(t, diag.Diagnostic{ Severity: diag.Warning, Summary: `expected map, found string`, Locations: []dyn.Location{vin.Location()}, Paths: []dyn.Path{dyn.EmptyPath}, }, err[0]) } func TestNormalizeStructIntError(t *testing.T) { type Tmp struct { Foo string `json:"foo"` } var typ Tmp vin := dyn.NewValue(1, []dyn.Location{{File: "file", Line: 1, Column: 1}}) _, err := Normalize(typ, vin) assert.Len(t, err, 1) assert.Equal(t, diag.Diagnostic{ Severity: diag.Warning, Summary: `expected map, found int`, Locations: []dyn.Location{vin.Location()}, Paths: []dyn.Path{dyn.EmptyPath}, }, err[0]) } func TestNormalizeMap(t *testing.T) { var typ map[string]string vin := dyn.V(map[string]dyn.Value{ "foo": dyn.V("bar"), "bar": dyn.V("baz"), }) vout, err := Normalize(typ, vin) assert.Empty(t, err) assert.Equal(t, vin, vout) } func TestNormalizeMapElementDiagnostic(t *testing.T) { var typ map[string]string vin := dyn.V(map[string]dyn.Value{ "foo": dyn.V("bar"), "bar": dyn.V(map[string]dyn.Value{"an": dyn.V("error")}), }) vout, err := Normalize(typ, vin) assert.Len(t, err, 1) assert.Equal(t, diag.Diagnostic{ Severity: diag.Warning, Summary: `expected string, found map`, Locations: []dyn.Location{{}}, Paths: []dyn.Path{dyn.NewPath(dyn.Key("bar"))}, }, err[0]) // Elements that encounter an error during normalization are dropped. assert.Equal(t, map[string]any{ "foo": "bar", }, vout.AsAny()) } func TestNormalizeMapNil(t *testing.T) { var typ map[string]string vin := dyn.NilValue vout, err := Normalize(typ, vin) assert.Empty(t, err) assert.Equal(t, vin, vout) } func TestNormalizeMapError(t *testing.T) { var typ map[string]string vin := dyn.V("string") _, err := Normalize(typ, vin) assert.Len(t, err, 1) assert.Equal(t, diag.Diagnostic{ Severity: diag.Warning, Summary: `expected map, found string`, Locations: []dyn.Location{vin.Location()}, Paths: []dyn.Path{dyn.EmptyPath}, }, err[0]) } func TestNormalizeMapNestedError(t *testing.T) { type Nested struct { F1 int `json:"f1"` F2 int `json:"f2"` } var typ map[string]Nested vin := dyn.V(map[string]dyn.Value{ "foo": dyn.V(map[string]dyn.Value{ "f1": dyn.V("error"), "f2": dyn.V(1), }), "bar": dyn.V(map[string]dyn.Value{ "f1": dyn.V(1), "f2": dyn.V("error"), }), }) vout, err := Normalize(typ, vin) assert.Len(t, err, 2) // Verify that valid fields are retained. assert.Equal(t, dyn.V(map[string]dyn.Value{ "foo": dyn.V(map[string]dyn.Value{ "f2": dyn.V(int64(1)), }), "bar": dyn.V(map[string]dyn.Value{ "f1": dyn.V(int64(1)), }), }), vout, ) } func TestNormalizeMapVariableReference(t *testing.T) { var typ map[string]string vin := dyn.NewValue("${var.foo}", []dyn.Location{{File: "file", Line: 1, Column: 1}}) vout, err := Normalize(typ, vin) assert.Empty(t, err) assert.Equal(t, vin, vout) } func TestNormalizeMapRandomStringError(t *testing.T) { var typ map[string]string vin := dyn.NewValue("var foo", []dyn.Location{{File: "file", Line: 1, Column: 1}}) _, err := Normalize(typ, vin) assert.Len(t, err, 1) assert.Equal(t, diag.Diagnostic{ Severity: diag.Warning, Summary: `expected map, found string`, Locations: []dyn.Location{vin.Location()}, Paths: []dyn.Path{dyn.EmptyPath}, }, err[0]) } func TestNormalizeMapIntError(t *testing.T) { var typ map[string]string vin := dyn.NewValue(1, []dyn.Location{{File: "file", Line: 1, Column: 1}}) _, err := Normalize(typ, vin) assert.Len(t, err, 1) assert.Equal(t, diag.Diagnostic{ Severity: diag.Warning, Summary: `expected map, found int`, Locations: []dyn.Location{vin.Location()}, Paths: []dyn.Path{dyn.EmptyPath}, }, err[0]) } func TestNormalizeSlice(t *testing.T) { var typ []string vin := dyn.V([]dyn.Value{ dyn.V("foo"), dyn.V("bar"), }) vout, err := Normalize(typ, vin) assert.Empty(t, err) assert.Equal(t, vin, vout) } func TestNormalizeSliceElementDiagnostic(t *testing.T) { var typ []string vin := dyn.V([]dyn.Value{ dyn.V("foo"), dyn.V("bar"), dyn.V(map[string]dyn.Value{"an": dyn.V("error")}), }) vout, err := Normalize(typ, vin) assert.Len(t, err, 1) assert.Equal(t, diag.Diagnostic{ Severity: diag.Warning, Summary: `expected string, found map`, Locations: []dyn.Location{{}}, Paths: []dyn.Path{dyn.NewPath(dyn.Index(2))}, }, err[0]) // Elements that encounter an error during normalization are dropped. assert.Equal(t, []any{"foo", "bar"}, vout.AsAny()) } func TestNormalizeSliceNil(t *testing.T) { var typ []string vin := dyn.NilValue vout, err := Normalize(typ, vin) assert.Empty(t, err) assert.Equal(t, vin, vout) } func TestNormalizeSliceError(t *testing.T) { var typ []string vin := dyn.V("string") _, err := Normalize(typ, vin) assert.Len(t, err, 1) assert.Equal(t, diag.Diagnostic{ Severity: diag.Warning, Summary: `expected sequence, found string`, Locations: []dyn.Location{vin.Location()}, Paths: []dyn.Path{dyn.EmptyPath}, }, err[0]) } func TestNormalizeSliceNestedError(t *testing.T) { type Nested struct { F1 int `json:"f1"` F2 int `json:"f2"` } var typ []Nested vin := dyn.V([]dyn.Value{ dyn.V(map[string]dyn.Value{ "f1": dyn.V("error"), "f2": dyn.V(1), }), dyn.V(map[string]dyn.Value{ "f1": dyn.V(1), "f2": dyn.V("error"), }), }) vout, err := Normalize(typ, vin) assert.Len(t, err, 2) // Verify that valid fields are retained. assert.Equal(t, dyn.V([]dyn.Value{ dyn.V(map[string]dyn.Value{ "f2": dyn.V(int64(1)), }), dyn.V(map[string]dyn.Value{ "f1": dyn.V(int64(1)), }), }), vout, ) } func TestNormalizeSliceVariableReference(t *testing.T) { var typ []string vin := dyn.NewValue("${var.foo}", []dyn.Location{{File: "file", Line: 1, Column: 1}}) vout, err := Normalize(typ, vin) assert.Empty(t, err) assert.Equal(t, vin, vout) } func TestNormalizeSliceRandomStringError(t *testing.T) { var typ []string vin := dyn.NewValue("var foo", []dyn.Location{{File: "file", Line: 1, Column: 1}}) _, err := Normalize(typ, vin) assert.Len(t, err, 1) assert.Equal(t, diag.Diagnostic{ Severity: diag.Warning, Summary: `expected sequence, found string`, Locations: []dyn.Location{vin.Location()}, Paths: []dyn.Path{dyn.EmptyPath}, }, err[0]) } func TestNormalizeSliceIntError(t *testing.T) { var typ []string vin := dyn.NewValue(1, []dyn.Location{{File: "file", Line: 1, Column: 1}}) _, err := Normalize(typ, vin) assert.Len(t, err, 1) assert.Equal(t, diag.Diagnostic{ Severity: diag.Warning, Summary: `expected sequence, found int`, Locations: []dyn.Location{vin.Location()}, Paths: []dyn.Path{dyn.EmptyPath}, }, err[0]) } func TestNormalizeString(t *testing.T) { var typ string vin := dyn.V("string") vout, err := Normalize(&typ, vin) assert.Empty(t, err) assert.Equal(t, vin, vout) } func TestNormalizeStringNil(t *testing.T) { var typ string vin := dyn.NewValue(nil, []dyn.Location{{File: "file", Line: 1, Column: 1}}) _, err := Normalize(&typ, vin) assert.Len(t, err, 1) assert.Equal(t, diag.Diagnostic{ Severity: diag.Warning, Summary: `expected a string value, found null`, Locations: []dyn.Location{vin.Location()}, Paths: []dyn.Path{dyn.EmptyPath}, }, err[0]) } func TestNormalizeStringFromBool(t *testing.T) { var typ string vin := dyn.NewValue(true, []dyn.Location{{File: "file", Line: 1, Column: 1}}) vout, err := Normalize(&typ, vin) assert.Empty(t, err) assert.Equal(t, dyn.NewValue("true", vin.Locations()), vout) } func TestNormalizeStringFromInt(t *testing.T) { var typ string vin := dyn.NewValue(123, []dyn.Location{{File: "file", Line: 1, Column: 1}}) vout, err := Normalize(&typ, vin) assert.Empty(t, err) assert.Equal(t, dyn.NewValue("123", vin.Locations()), vout) } func TestNormalizeStringFromFloat(t *testing.T) { var typ string vin := dyn.NewValue(1.20, []dyn.Location{{File: "file", Line: 1, Column: 1}}) vout, err := Normalize(&typ, vin) assert.Empty(t, err) assert.Equal(t, dyn.NewValue("1.2", vin.Locations()), vout) } func TestNormalizeStringFromTime(t *testing.T) { var typ string vin := dyn.NewValue(dyn.MustTime("2024-08-29"), []dyn.Location{{File: "file", Line: 1, Column: 1}}) vout, err := Normalize(&typ, vin) assert.Empty(t, err) assert.Equal(t, dyn.NewValue("2024-08-29", vin.Locations()), vout) } func TestNormalizeStringError(t *testing.T) { var typ string vin := dyn.V(map[string]dyn.Value{"an": dyn.V("error")}) _, err := Normalize(&typ, vin) assert.Len(t, err, 1) assert.Equal(t, diag.Diagnostic{ Severity: diag.Warning, Summary: `expected string, found map`, Locations: []dyn.Location{{}}, Paths: []dyn.Path{dyn.EmptyPath}, }, err[0]) } func TestNormalizeBool(t *testing.T) { var typ bool vin := dyn.V(true) vout, err := Normalize(&typ, vin) assert.Empty(t, err) assert.Equal(t, dyn.V(true), vout) } func TestNormalizeBoolNil(t *testing.T) { var typ bool vin := dyn.NewValue(nil, []dyn.Location{{File: "file", Line: 1, Column: 1}}) _, err := Normalize(&typ, vin) assert.Len(t, err, 1) assert.Equal(t, diag.Diagnostic{ Severity: diag.Warning, Summary: `expected a bool value, found null`, Locations: []dyn.Location{vin.Location()}, Paths: []dyn.Path{dyn.EmptyPath}, }, err[0]) } func TestNormalizeBoolFromString(t *testing.T) { var typ bool for _, c := range []struct { Input string Output bool }{ {"true", true}, {"false", false}, {"Y", true}, {"N", false}, {"on", true}, {"off", false}, } { vin := dyn.V(c.Input) vout, err := Normalize(&typ, vin) assert.Empty(t, err) assert.Equal(t, dyn.V(c.Output), vout) } } func TestNormalizeBoolFromStringVariableReference(t *testing.T) { var typ bool vin := dyn.V("${var.foo}") vout, err := Normalize(&typ, vin) assert.Empty(t, err) assert.Equal(t, vin, vout) } func TestNormalizeBoolFromStringError(t *testing.T) { var typ bool vin := dyn.V("abc") _, err := Normalize(&typ, vin) assert.Len(t, err, 1) assert.Equal(t, diag.Diagnostic{ Severity: diag.Warning, Summary: `expected bool, found string`, Locations: []dyn.Location{vin.Location()}, Paths: []dyn.Path{dyn.EmptyPath}, }, err[0]) } func TestNormalizeBoolError(t *testing.T) { var typ bool vin := dyn.V(map[string]dyn.Value{"an": dyn.V("error")}) _, err := Normalize(&typ, vin) assert.Len(t, err, 1) assert.Equal(t, diag.Diagnostic{ Severity: diag.Warning, Summary: `expected bool, found map`, Locations: []dyn.Location{{}}, Paths: []dyn.Path{dyn.EmptyPath}, }, err[0]) } func TestNormalizeInt(t *testing.T) { var typ int vin := dyn.V(123) vout, err := Normalize(&typ, vin) assert.Empty(t, err) assert.Equal(t, dyn.V(int64(123)), vout) } func TestNormalizeIntNil(t *testing.T) { var typ int vin := dyn.NewValue(nil, []dyn.Location{{File: "file", Line: 1, Column: 1}}) _, err := Normalize(&typ, vin) assert.Len(t, err, 1) assert.Equal(t, diag.Diagnostic{ Severity: diag.Warning, Summary: `expected a int value, found null`, Locations: []dyn.Location{vin.Location()}, Paths: []dyn.Path{dyn.EmptyPath}, }, err[0]) } func TestNormalizeIntFromFloat(t *testing.T) { var typ int vin := dyn.V(float64(1.0)) vout, err := Normalize(&typ, vin) assert.Empty(t, err) assert.Equal(t, dyn.V(int64(1)), vout) } func TestNormalizeIntFromFloatError(t *testing.T) { var typ int vin := dyn.V(1.5) _, err := Normalize(&typ, vin) assert.Len(t, err, 1) assert.Equal(t, diag.Diagnostic{ Severity: diag.Warning, Summary: `cannot accurately represent "1.5" as integer due to precision loss`, Locations: []dyn.Location{vin.Location()}, Paths: []dyn.Path{dyn.EmptyPath}, }, err[0]) } func TestNormalizeIntFromString(t *testing.T) { var typ int vin := dyn.V("123") vout, err := Normalize(&typ, vin) assert.Empty(t, err) assert.Equal(t, dyn.V(int64(123)), vout) } func TestNormalizeIntFromStringVariableReference(t *testing.T) { var typ int vin := dyn.V("${var.foo}") vout, err := Normalize(&typ, vin) assert.Empty(t, err) assert.Equal(t, vin, vout) } func TestNormalizeIntFromStringError(t *testing.T) { var typ int vin := dyn.V("abc") _, err := Normalize(&typ, vin) assert.Len(t, err, 1) assert.Equal(t, diag.Diagnostic{ Severity: diag.Warning, Summary: `cannot parse "abc" as an integer`, Locations: []dyn.Location{vin.Location()}, Paths: []dyn.Path{dyn.EmptyPath}, }, err[0]) } func TestNormalizeIntError(t *testing.T) { var typ int vin := dyn.V(map[string]dyn.Value{"an": dyn.V("error")}) _, err := Normalize(&typ, vin) assert.Len(t, err, 1) assert.Equal(t, diag.Diagnostic{ Severity: diag.Warning, Summary: `expected int, found map`, Locations: []dyn.Location{{}}, Paths: []dyn.Path{dyn.EmptyPath}, }, err[0]) } func TestNormalizeFloat(t *testing.T) { var typ float64 vin := dyn.V(1.2) vout, err := Normalize(&typ, vin) assert.Empty(t, err) assert.Equal(t, dyn.V(1.2), vout) } func TestNormalizeFloatNil(t *testing.T) { var typ float64 vin := dyn.NewValue(nil, []dyn.Location{{File: "file", Line: 1, Column: 1}}) _, err := Normalize(&typ, vin) assert.Len(t, err, 1) assert.Equal(t, diag.Diagnostic{ Severity: diag.Warning, Summary: `expected a float value, found null`, Locations: []dyn.Location{vin.Location()}, Paths: []dyn.Path{dyn.EmptyPath}, }, err[0]) } func TestNormalizeFloatFromInt(t *testing.T) { var typ float64 // Maximum safe integer that can be accurately represented as a float. vin := dyn.V(int64(9007199254740992)) vout, err := Normalize(&typ, vin) assert.Empty(t, err) assert.Equal(t, dyn.V(float64(9007199254740992)), vout) } func TestNormalizeFloatFromIntError(t *testing.T) { var typ float64 // Minimum integer that cannot be accurately represented as a float. vin := dyn.V(9007199254740992 + 1) _, err := Normalize(&typ, vin) assert.Len(t, err, 1) assert.Equal(t, diag.Diagnostic{ Severity: diag.Warning, Summary: `cannot accurately represent "9007199254740993" as floating point number due to precision loss`, Locations: []dyn.Location{vin.Location()}, Paths: []dyn.Path{dyn.EmptyPath}, }, err[0]) } func TestNormalizeFloatFromString(t *testing.T) { var typ float64 vin := dyn.V("1.2") vout, err := Normalize(&typ, vin) assert.Empty(t, err) assert.Equal(t, dyn.V(1.2), vout) } func TestNormalizeFloatFromStringVariableReference(t *testing.T) { var typ float64 vin := dyn.V("${var.foo}") vout, err := Normalize(&typ, vin) assert.Empty(t, err) assert.Equal(t, vin, vout) } func TestNormalizeFloatFromStringError(t *testing.T) { var typ float64 vin := dyn.V("abc") _, err := Normalize(&typ, vin) assert.Len(t, err, 1) assert.Equal(t, diag.Diagnostic{ Severity: diag.Warning, Summary: `cannot parse "abc" as a floating point number`, Locations: []dyn.Location{vin.Location()}, Paths: []dyn.Path{dyn.EmptyPath}, }, err[0]) } func TestNormalizeFloatError(t *testing.T) { var typ float64 vin := dyn.V(map[string]dyn.Value{"an": dyn.V("error")}) _, err := Normalize(&typ, vin) assert.Len(t, err, 1) assert.Equal(t, diag.Diagnostic{ Severity: diag.Warning, Summary: `expected float, found map`, Locations: []dyn.Location{{}}, Paths: []dyn.Path{dyn.EmptyPath}, }, err[0]) } func TestNormalizeAnchors(t *testing.T) { type Tmp struct { Foo string `json:"foo"` } var typ Tmp vin := dyn.V(map[string]dyn.Value{ "foo": dyn.V("bar"), "anchor": dyn.V("anchor").MarkAnchor(), }) vout, err := Normalize(typ, vin) assert.Len(t, err, 0) // The field that can be mapped to the struct field is retained. assert.Equal(t, map[string]any{ "foo": "bar", }, vout.AsAny()) } func TestNormalizeAnyFromSlice(t *testing.T) { var typ any v1 := dyn.NewValue(1, []dyn.Location{{File: "file", Line: 1, Column: 1}}) v2 := dyn.NewValue(2, []dyn.Location{{File: "file", Line: 1, Column: 1}}) vin := dyn.NewValue([]dyn.Value{v1, v2}, []dyn.Location{{File: "file", Line: 1, Column: 1}}) vout, err := Normalize(&typ, vin) assert.Len(t, err, 0) assert.Equal(t, dyn.NewValue([]dyn.Value{v1, v2}, []dyn.Location{{File: "file", Line: 1, Column: 1}}), vout) } func TestNormalizeAnyFromString(t *testing.T) { var typ any vin := dyn.NewValue("string", []dyn.Location{{File: "file", Line: 1, Column: 1}}) vout, err := Normalize(&typ, vin) assert.Len(t, err, 0) assert.Equal(t, dyn.NewValue("string", []dyn.Location{{File: "file", Line: 1, Column: 1}}), vout) } func TestNormalizeAnyFromBool(t *testing.T) { var typ any vin := dyn.NewValue(false, []dyn.Location{{File: "file", Line: 1, Column: 1}}) vout, err := Normalize(&typ, vin) assert.Len(t, err, 0) assert.Equal(t, dyn.NewValue(false, []dyn.Location{{File: "file", Line: 1, Column: 1}}), vout) } func TestNormalizeAnyFromInt(t *testing.T) { var typ any vin := dyn.NewValue(10, []dyn.Location{{File: "file", Line: 1, Column: 1}}) vout, err := Normalize(&typ, vin) assert.Len(t, err, 0) assert.Equal(t, dyn.NewValue(10, []dyn.Location{{File: "file", Line: 1, Column: 1}}), vout) } func TestNormalizeAnyFromTime(t *testing.T) { var typ any vin := dyn.NewValue(dyn.MustTime("2024-08-29"), []dyn.Location{{File: "file", Line: 1, Column: 1}}) vout, err := Normalize(&typ, vin) assert.Empty(t, err) assert.Equal(t, dyn.NewValue("2024-08-29", vin.Locations()), vout) }