Rename libs/config -> libs/dyn (#1086)

## Changes

The name "dynamic value", or "dyn" for short, is more descriptive than
the opaque "config". Also, it conveniently does not alias with other
packages in the repository, or (popular ones) elsewhere.

(discussed with @andrewnester)

## Tests

n/a
This commit is contained in:
Pieter Noordhuis 2023-12-22 14:20:45 +01:00 committed by GitHub
parent a1297d71fd
commit 938eb1600c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
45 changed files with 600 additions and 600 deletions

View File

@ -1,76 +0,0 @@
package config_test
import (
"testing"
"github.com/databricks/cli/libs/config"
"github.com/stretchr/testify/assert"
)
func TestPathAppend(t *testing.T) {
p := config.NewPath(config.Key("foo"))
// Single arg.
p1 := p.Append(config.Key("bar"))
assert.True(t, p1.Equal(config.NewPath(config.Key("foo"), config.Key("bar"))))
// Multiple args.
p2 := p.Append(config.Key("bar"), config.Index(1))
assert.True(t, p2.Equal(config.NewPath(config.Key("foo"), config.Key("bar"), config.Index(1))))
}
func TestPathJoin(t *testing.T) {
p := config.NewPath(config.Key("foo"))
// Single arg.
p1 := p.Join(config.NewPath(config.Key("bar")))
assert.True(t, p1.Equal(config.NewPath(config.Key("foo"), config.Key("bar"))))
// Multiple args.
p2 := p.Join(config.NewPath(config.Key("bar")), config.NewPath(config.Index(1)))
assert.True(t, p2.Equal(config.NewPath(config.Key("foo"), config.Key("bar"), config.Index(1))))
}
func TestPathEqualEmpty(t *testing.T) {
assert.True(t, config.EmptyPath.Equal(config.EmptyPath))
}
func TestPathEqual(t *testing.T) {
p1 := config.NewPath(config.Key("foo"), config.Index(1))
p2 := config.NewPath(config.Key("bar"), config.Index(2))
assert.False(t, p1.Equal(p2), "expected %q to not equal %q", p1, p2)
p3 := config.NewPath(config.Key("foo"), config.Index(1))
assert.True(t, p1.Equal(p3), "expected %q to equal %q", p1, p3)
p4 := config.NewPath(config.Key("foo"), config.Index(1), config.Key("bar"), config.Index(2))
assert.False(t, p1.Equal(p4), "expected %q to not equal %q", p1, p4)
}
func TestPathHasPrefixEmpty(t *testing.T) {
empty := config.EmptyPath
nonEmpty := config.NewPath(config.Key("foo"))
assert.True(t, empty.HasPrefix(empty))
assert.True(t, nonEmpty.HasPrefix(empty))
assert.False(t, empty.HasPrefix(nonEmpty))
}
func TestPathHasPrefix(t *testing.T) {
p1 := config.NewPath(config.Key("foo"), config.Index(1))
p2 := config.NewPath(config.Key("bar"), config.Index(2))
assert.False(t, p1.HasPrefix(p2), "expected %q to not have prefix %q", p1, p2)
p3 := config.NewPath(config.Key("foo"))
assert.True(t, p1.HasPrefix(p3), "expected %q to have prefix %q", p1, p3)
}
func TestPathString(t *testing.T) {
p1 := config.NewPath(config.Key("foo"), config.Index(1))
assert.Equal(t, "foo[1]", p1.String())
p2 := config.NewPath(config.Key("bar"), config.Index(2), config.Key("baz"))
assert.Equal(t, "bar[2].baz", p2.String())
p3 := config.NewPath(config.Key("foo"), config.Index(1), config.Key("bar"), config.Index(2), config.Key("baz"))
assert.Equal(t, "foo[1].bar[2].baz", p3.String())
}

View File

@ -3,7 +3,7 @@ package diag
import (
"fmt"
"github.com/databricks/cli/libs/config"
"github.com/databricks/cli/libs/dyn"
)
type Diagnostic struct {
@ -19,7 +19,7 @@ type Diagnostic struct {
// Location is a source code location associated with the diagnostic message.
// It may be zero if there is no associated location.
Location config.Location
Location dyn.Location
}
// Errorf creates a new error diagnostic.

View File

@ -3,13 +3,13 @@ package convert
import (
"testing"
"github.com/databricks/cli/libs/config"
"github.com/databricks/cli/libs/dyn"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func assertFromTypedToTypedEqual[T any](t *testing.T, src T) {
nv, err := FromTyped(src, config.NilValue)
nv, err := FromTyped(src, dyn.NilValue)
require.NoError(t, err)
var dst T

View File

@ -3,11 +3,11 @@ package convert
import (
"fmt"
"github.com/databricks/cli/libs/config"
"github.com/databricks/cli/libs/dyn"
)
type TypeError struct {
value config.Value
value dyn.Value
msg string
}

View File

@ -4,18 +4,18 @@ import (
"fmt"
"reflect"
"github.com/databricks/cli/libs/config"
"github.com/databricks/cli/libs/dyn"
)
// FromTyped converts changes made in the typed structure w.r.t. the configuration value
// back to the configuration value, retaining existing location information where possible.
func FromTyped(src any, ref config.Value) (config.Value, error) {
func FromTyped(src any, ref dyn.Value) (dyn.Value, error) {
srcv := reflect.ValueOf(src)
// Dereference pointer if necessary
for srcv.Kind() == reflect.Pointer {
if srcv.IsNil() {
return config.NilValue, nil
return dyn.NilValue, nil
}
srcv = srcv.Elem()
}
@ -37,53 +37,53 @@ func FromTyped(src any, ref config.Value) (config.Value, error) {
return fromTypedFloat(srcv, ref)
}
return config.NilValue, fmt.Errorf("unsupported type: %s", srcv.Kind())
return dyn.NilValue, fmt.Errorf("unsupported type: %s", srcv.Kind())
}
func fromTypedStruct(src reflect.Value, ref config.Value) (config.Value, error) {
func fromTypedStruct(src reflect.Value, ref dyn.Value) (dyn.Value, error) {
// Check that the reference value is compatible or nil.
switch ref.Kind() {
case config.KindMap, config.KindNil:
case dyn.KindMap, dyn.KindNil:
default:
return config.Value{}, fmt.Errorf("unhandled type: %s", ref.Kind())
return dyn.Value{}, fmt.Errorf("unhandled type: %s", ref.Kind())
}
out := make(map[string]config.Value)
out := make(map[string]dyn.Value)
info := getStructInfo(src.Type())
for k, v := range info.FieldValues(src) {
// Convert the field taking into account the reference value (may be equal to config.NilValue).
nv, err := FromTyped(v.Interface(), ref.Get(k))
if err != nil {
return config.Value{}, err
return dyn.Value{}, err
}
if nv != config.NilValue {
if nv != dyn.NilValue {
out[k] = nv
}
}
// If the struct was equal to its zero value, emit a nil.
if len(out) == 0 {
return config.NilValue, nil
return dyn.NilValue, nil
}
return config.NewValue(out, ref.Location()), nil
return dyn.NewValue(out, ref.Location()), nil
}
func fromTypedMap(src reflect.Value, ref config.Value) (config.Value, error) {
func fromTypedMap(src reflect.Value, ref dyn.Value) (dyn.Value, error) {
// Check that the reference value is compatible or nil.
switch ref.Kind() {
case config.KindMap, config.KindNil:
case dyn.KindMap, dyn.KindNil:
default:
return config.Value{}, fmt.Errorf("unhandled type: %s", ref.Kind())
return dyn.Value{}, fmt.Errorf("unhandled type: %s", ref.Kind())
}
// Return nil if the map is nil.
if src.IsNil() {
return config.NilValue, nil
return dyn.NilValue, nil
}
out := make(map[string]config.Value)
out := make(map[string]dyn.Value)
iter := src.MapRange()
for iter.Next() {
k := iter.Key().String()
@ -92,7 +92,7 @@ func fromTypedMap(src reflect.Value, ref config.Value) (config.Value, error) {
// Convert entry taking into account the reference value (may be equal to config.NilValue).
nv, err := FromTyped(v.Interface(), ref.Get(k))
if err != nil {
return config.Value{}, err
return dyn.Value{}, err
}
// Every entry is represented, even if it is a nil.
@ -100,115 +100,115 @@ func fromTypedMap(src reflect.Value, ref config.Value) (config.Value, error) {
out[k] = nv
}
return config.NewValue(out, ref.Location()), nil
return dyn.NewValue(out, ref.Location()), nil
}
func fromTypedSlice(src reflect.Value, ref config.Value) (config.Value, error) {
func fromTypedSlice(src reflect.Value, ref dyn.Value) (dyn.Value, error) {
// Check that the reference value is compatible or nil.
switch ref.Kind() {
case config.KindSequence, config.KindNil:
case dyn.KindSequence, dyn.KindNil:
default:
return config.Value{}, fmt.Errorf("unhandled type: %s", ref.Kind())
return dyn.Value{}, fmt.Errorf("unhandled type: %s", ref.Kind())
}
// Return nil if the slice is nil.
if src.IsNil() {
return config.NilValue, nil
return dyn.NilValue, nil
}
out := make([]config.Value, src.Len())
out := make([]dyn.Value, src.Len())
for i := 0; i < src.Len(); i++ {
v := src.Index(i)
// Convert entry taking into account the reference value (may be equal to config.NilValue).
nv, err := FromTyped(v.Interface(), ref.Index(i))
if err != nil {
return config.Value{}, err
return dyn.Value{}, err
}
out[i] = nv
}
return config.NewValue(out, ref.Location()), nil
return dyn.NewValue(out, ref.Location()), nil
}
func fromTypedString(src reflect.Value, ref config.Value) (config.Value, error) {
func fromTypedString(src reflect.Value, ref dyn.Value) (dyn.Value, error) {
switch ref.Kind() {
case config.KindString:
case dyn.KindString:
value := src.String()
if value == ref.MustString() {
return ref, nil
}
return config.V(value), nil
case config.KindNil:
return dyn.V(value), nil
case dyn.KindNil:
// This field is not set in the reference, so we only include it if it has a non-zero value.
// Otherwise, we would always include all zero valued fields.
if src.IsZero() {
return config.NilValue, nil
return dyn.NilValue, nil
}
return config.V(src.String()), nil
return dyn.V(src.String()), nil
}
return config.Value{}, fmt.Errorf("unhandled type: %s", ref.Kind())
return dyn.Value{}, fmt.Errorf("unhandled type: %s", ref.Kind())
}
func fromTypedBool(src reflect.Value, ref config.Value) (config.Value, error) {
func fromTypedBool(src reflect.Value, ref dyn.Value) (dyn.Value, error) {
switch ref.Kind() {
case config.KindBool:
case dyn.KindBool:
value := src.Bool()
if value == ref.MustBool() {
return ref, nil
}
return config.V(value), nil
case config.KindNil:
return dyn.V(value), nil
case dyn.KindNil:
// This field is not set in the reference, so we only include it if it has a non-zero value.
// Otherwise, we would always include all zero valued fields.
if src.IsZero() {
return config.NilValue, nil
return dyn.NilValue, nil
}
return config.V(src.Bool()), nil
return dyn.V(src.Bool()), nil
}
return config.Value{}, fmt.Errorf("unhandled type: %s", ref.Kind())
return dyn.Value{}, fmt.Errorf("unhandled type: %s", ref.Kind())
}
func fromTypedInt(src reflect.Value, ref config.Value) (config.Value, error) {
func fromTypedInt(src reflect.Value, ref dyn.Value) (dyn.Value, error) {
switch ref.Kind() {
case config.KindInt:
case dyn.KindInt:
value := src.Int()
if value == ref.MustInt() {
return ref, nil
}
return config.V(value), nil
case config.KindNil:
return dyn.V(value), nil
case dyn.KindNil:
// This field is not set in the reference, so we only include it if it has a non-zero value.
// Otherwise, we would always include all zero valued fields.
if src.IsZero() {
return config.NilValue, nil
return dyn.NilValue, nil
}
return config.V(src.Int()), nil
return dyn.V(src.Int()), nil
}
return config.Value{}, fmt.Errorf("unhandled type: %s", ref.Kind())
return dyn.Value{}, fmt.Errorf("unhandled type: %s", ref.Kind())
}
func fromTypedFloat(src reflect.Value, ref config.Value) (config.Value, error) {
func fromTypedFloat(src reflect.Value, ref dyn.Value) (dyn.Value, error) {
switch ref.Kind() {
case config.KindFloat:
case dyn.KindFloat:
value := src.Float()
if value == ref.MustFloat() {
return ref, nil
}
return config.V(value), nil
case config.KindNil:
return dyn.V(value), nil
case dyn.KindNil:
// This field is not set in the reference, so we only include it if it has a non-zero value.
// Otherwise, we would always include all zero valued fields.
if src.IsZero() {
return config.NilValue, nil
return dyn.NilValue, nil
}
return config.V(src.Float()), nil
return dyn.V(src.Float()), nil
}
return config.Value{}, fmt.Errorf("unhandled type: %s", ref.Kind())
return dyn.Value{}, fmt.Errorf("unhandled type: %s", ref.Kind())
}

View File

@ -3,7 +3,7 @@ package convert
import (
"testing"
"github.com/databricks/cli/libs/config"
"github.com/databricks/cli/libs/dyn"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@ -15,11 +15,11 @@ func TestFromTypedStructZeroFields(t *testing.T) {
}
src := Tmp{}
ref := config.NilValue
ref := dyn.NilValue
nv, err := FromTyped(src, ref)
require.NoError(t, err)
assert.Equal(t, config.NilValue, nv)
assert.Equal(t, dyn.NilValue, nv)
}
func TestFromTypedStructSetFields(t *testing.T) {
@ -33,12 +33,12 @@ func TestFromTypedStructSetFields(t *testing.T) {
Bar: "bar",
}
ref := config.NilValue
ref := dyn.NilValue
nv, err := FromTyped(src, ref)
require.NoError(t, err)
assert.Equal(t, config.V(map[string]config.Value{
"foo": config.V("foo"),
"bar": config.V("bar"),
assert.Equal(t, dyn.V(map[string]dyn.Value{
"foo": dyn.V("foo"),
"bar": dyn.V("bar"),
}), nv)
}
@ -53,45 +53,45 @@ func TestFromTypedStructSetFieldsRetainLocationIfUnchanged(t *testing.T) {
Bar: "qux",
}
ref := config.V(map[string]config.Value{
"foo": config.NewValue("bar", config.Location{File: "foo"}),
"bar": config.NewValue("baz", config.Location{File: "bar"}),
ref := dyn.V(map[string]dyn.Value{
"foo": dyn.NewValue("bar", dyn.Location{File: "foo"}),
"bar": dyn.NewValue("baz", dyn.Location{File: "bar"}),
})
nv, err := FromTyped(src, ref)
require.NoError(t, err)
// Assert foo has retained its location.
assert.Equal(t, config.NewValue("bar", config.Location{File: "foo"}), nv.Get("foo"))
assert.Equal(t, dyn.NewValue("bar", dyn.Location{File: "foo"}), nv.Get("foo"))
// Assert bar lost its location (because it was overwritten).
assert.Equal(t, config.NewValue("qux", config.Location{}), nv.Get("bar"))
assert.Equal(t, dyn.NewValue("qux", dyn.Location{}), nv.Get("bar"))
}
func TestFromTypedMapNil(t *testing.T) {
var src map[string]string = nil
ref := config.V(map[string]config.Value{
"foo": config.V("bar"),
"bar": config.V("baz"),
ref := dyn.V(map[string]dyn.Value{
"foo": dyn.V("bar"),
"bar": dyn.V("baz"),
})
nv, err := FromTyped(src, ref)
require.NoError(t, err)
assert.Equal(t, config.NilValue, nv)
assert.Equal(t, dyn.NilValue, nv)
}
func TestFromTypedMapEmpty(t *testing.T) {
var src = map[string]string{}
ref := config.V(map[string]config.Value{
"foo": config.V("bar"),
"bar": config.V("baz"),
ref := dyn.V(map[string]dyn.Value{
"foo": dyn.V("bar"),
"bar": dyn.V("baz"),
})
nv, err := FromTyped(src, ref)
require.NoError(t, err)
assert.Equal(t, config.V(map[string]config.Value{}), nv)
assert.Equal(t, dyn.V(map[string]dyn.Value{}), nv)
}
func TestFromTypedMapNonEmpty(t *testing.T) {
@ -100,12 +100,12 @@ func TestFromTypedMapNonEmpty(t *testing.T) {
"bar": "bar",
}
ref := config.NilValue
ref := dyn.NilValue
nv, err := FromTyped(src, ref)
require.NoError(t, err)
assert.Equal(t, config.V(map[string]config.Value{
"foo": config.V("foo"),
"bar": config.V("bar"),
assert.Equal(t, dyn.V(map[string]dyn.Value{
"foo": dyn.V("foo"),
"bar": dyn.V("bar"),
}), nv)
}
@ -115,19 +115,19 @@ func TestFromTypedMapNonEmptyRetainLocationIfUnchanged(t *testing.T) {
"bar": "qux",
}
ref := config.V(map[string]config.Value{
"foo": config.NewValue("bar", config.Location{File: "foo"}),
"bar": config.NewValue("baz", config.Location{File: "bar"}),
ref := dyn.V(map[string]dyn.Value{
"foo": dyn.NewValue("bar", dyn.Location{File: "foo"}),
"bar": dyn.NewValue("baz", dyn.Location{File: "bar"}),
})
nv, err := FromTyped(src, ref)
require.NoError(t, err)
// Assert foo has retained its location.
assert.Equal(t, config.NewValue("bar", config.Location{File: "foo"}), nv.Get("foo"))
assert.Equal(t, dyn.NewValue("bar", dyn.Location{File: "foo"}), nv.Get("foo"))
// Assert bar lost its location (because it was overwritten).
assert.Equal(t, config.NewValue("qux", config.Location{}), nv.Get("bar"))
assert.Equal(t, dyn.NewValue("qux", dyn.Location{}), nv.Get("bar"))
}
func TestFromTypedMapFieldWithZeroValue(t *testing.T) {
@ -135,38 +135,38 @@ func TestFromTypedMapFieldWithZeroValue(t *testing.T) {
"foo": "",
}
ref := config.NilValue
ref := dyn.NilValue
nv, err := FromTyped(src, ref)
require.NoError(t, err)
assert.Equal(t, config.V(map[string]config.Value{
"foo": config.NilValue,
assert.Equal(t, dyn.V(map[string]dyn.Value{
"foo": dyn.NilValue,
}), nv)
}
func TestFromTypedSliceNil(t *testing.T) {
var src []string = nil
ref := config.V([]config.Value{
config.V("bar"),
config.V("baz"),
ref := dyn.V([]dyn.Value{
dyn.V("bar"),
dyn.V("baz"),
})
nv, err := FromTyped(src, ref)
require.NoError(t, err)
assert.Equal(t, config.NilValue, nv)
assert.Equal(t, dyn.NilValue, nv)
}
func TestFromTypedSliceEmpty(t *testing.T) {
var src = []string{}
ref := config.V([]config.Value{
config.V("bar"),
config.V("baz"),
ref := dyn.V([]dyn.Value{
dyn.V("bar"),
dyn.V("baz"),
})
nv, err := FromTyped(src, ref)
require.NoError(t, err)
assert.Equal(t, config.V([]config.Value{}), nv)
assert.Equal(t, dyn.V([]dyn.Value{}), nv)
}
func TestFromTypedSliceNonEmpty(t *testing.T) {
@ -175,12 +175,12 @@ func TestFromTypedSliceNonEmpty(t *testing.T) {
"bar",
}
ref := config.NilValue
ref := dyn.NilValue
nv, err := FromTyped(src, ref)
require.NoError(t, err)
assert.Equal(t, config.V([]config.Value{
config.V("foo"),
config.V("bar"),
assert.Equal(t, dyn.V([]dyn.Value{
dyn.V("foo"),
dyn.V("bar"),
}), nv)
}
@ -190,205 +190,205 @@ func TestFromTypedSliceNonEmptyRetainLocationIfUnchanged(t *testing.T) {
"bar",
}
ref := config.V([]config.Value{
config.NewValue("foo", config.Location{File: "foo"}),
config.NewValue("baz", config.Location{File: "baz"}),
ref := dyn.V([]dyn.Value{
dyn.NewValue("foo", dyn.Location{File: "foo"}),
dyn.NewValue("baz", dyn.Location{File: "baz"}),
})
nv, err := FromTyped(src, ref)
require.NoError(t, err)
// Assert foo has retained its location.
assert.Equal(t, config.NewValue("foo", config.Location{File: "foo"}), nv.Index(0))
assert.Equal(t, dyn.NewValue("foo", dyn.Location{File: "foo"}), nv.Index(0))
// Assert bar lost its location (because it was overwritten).
assert.Equal(t, config.NewValue("bar", config.Location{}), nv.Index(1))
assert.Equal(t, dyn.NewValue("bar", dyn.Location{}), nv.Index(1))
}
func TestFromTypedStringEmpty(t *testing.T) {
var src string
var ref = config.NilValue
var ref = dyn.NilValue
nv, err := FromTyped(src, ref)
require.NoError(t, err)
assert.Equal(t, config.NilValue, nv)
assert.Equal(t, dyn.NilValue, nv)
}
func TestFromTypedStringEmptyOverwrite(t *testing.T) {
var src string
var ref = config.V("old")
var ref = dyn.V("old")
nv, err := FromTyped(src, ref)
require.NoError(t, err)
assert.Equal(t, config.V(""), nv)
assert.Equal(t, dyn.V(""), nv)
}
func TestFromTypedStringNonEmpty(t *testing.T) {
var src string = "new"
var ref = config.NilValue
var ref = dyn.NilValue
nv, err := FromTyped(src, ref)
require.NoError(t, err)
assert.Equal(t, config.V("new"), nv)
assert.Equal(t, dyn.V("new"), nv)
}
func TestFromTypedStringNonEmptyOverwrite(t *testing.T) {
var src string = "new"
var ref = config.V("old")
var ref = dyn.V("old")
nv, err := FromTyped(src, ref)
require.NoError(t, err)
assert.Equal(t, config.V("new"), nv)
assert.Equal(t, dyn.V("new"), nv)
}
func TestFromTypedStringRetainsLocationsIfUnchanged(t *testing.T) {
var src string = "foo"
var ref = config.NewValue("foo", config.Location{File: "foo"})
var ref = dyn.NewValue("foo", dyn.Location{File: "foo"})
nv, err := FromTyped(src, ref)
require.NoError(t, err)
assert.Equal(t, config.NewValue("foo", config.Location{File: "foo"}), nv)
assert.Equal(t, dyn.NewValue("foo", dyn.Location{File: "foo"}), nv)
}
func TestFromTypedStringTypeError(t *testing.T) {
var src string = "foo"
var ref = config.V(1234)
var ref = dyn.V(1234)
_, err := FromTyped(src, ref)
require.Error(t, err)
}
func TestFromTypedBoolEmpty(t *testing.T) {
var src bool
var ref = config.NilValue
var ref = dyn.NilValue
nv, err := FromTyped(src, ref)
require.NoError(t, err)
assert.Equal(t, config.NilValue, nv)
assert.Equal(t, dyn.NilValue, nv)
}
func TestFromTypedBoolEmptyOverwrite(t *testing.T) {
var src bool
var ref = config.V(true)
var ref = dyn.V(true)
nv, err := FromTyped(src, ref)
require.NoError(t, err)
assert.Equal(t, config.V(false), nv)
assert.Equal(t, dyn.V(false), nv)
}
func TestFromTypedBoolNonEmpty(t *testing.T) {
var src bool = true
var ref = config.NilValue
var ref = dyn.NilValue
nv, err := FromTyped(src, ref)
require.NoError(t, err)
assert.Equal(t, config.V(true), nv)
assert.Equal(t, dyn.V(true), nv)
}
func TestFromTypedBoolNonEmptyOverwrite(t *testing.T) {
var src bool = true
var ref = config.V(false)
var ref = dyn.V(false)
nv, err := FromTyped(src, ref)
require.NoError(t, err)
assert.Equal(t, config.V(true), nv)
assert.Equal(t, dyn.V(true), nv)
}
func TestFromTypedBoolRetainsLocationsIfUnchanged(t *testing.T) {
var src bool = true
var ref = config.NewValue(true, config.Location{File: "foo"})
var ref = dyn.NewValue(true, dyn.Location{File: "foo"})
nv, err := FromTyped(src, ref)
require.NoError(t, err)
assert.Equal(t, config.NewValue(true, config.Location{File: "foo"}), nv)
assert.Equal(t, dyn.NewValue(true, dyn.Location{File: "foo"}), nv)
}
func TestFromTypedBoolTypeError(t *testing.T) {
var src bool = true
var ref = config.V("string")
var ref = dyn.V("string")
_, err := FromTyped(src, ref)
require.Error(t, err)
}
func TestFromTypedIntEmpty(t *testing.T) {
var src int
var ref = config.NilValue
var ref = dyn.NilValue
nv, err := FromTyped(src, ref)
require.NoError(t, err)
assert.Equal(t, config.NilValue, nv)
assert.Equal(t, dyn.NilValue, nv)
}
func TestFromTypedIntEmptyOverwrite(t *testing.T) {
var src int
var ref = config.V(1234)
var ref = dyn.V(1234)
nv, err := FromTyped(src, ref)
require.NoError(t, err)
assert.Equal(t, config.V(int64(0)), nv)
assert.Equal(t, dyn.V(int64(0)), nv)
}
func TestFromTypedIntNonEmpty(t *testing.T) {
var src int = 1234
var ref = config.NilValue
var ref = dyn.NilValue
nv, err := FromTyped(src, ref)
require.NoError(t, err)
assert.Equal(t, config.V(int64(1234)), nv)
assert.Equal(t, dyn.V(int64(1234)), nv)
}
func TestFromTypedIntNonEmptyOverwrite(t *testing.T) {
var src int = 1234
var ref = config.V(1233)
var ref = dyn.V(1233)
nv, err := FromTyped(src, ref)
require.NoError(t, err)
assert.Equal(t, config.V(int64(1234)), nv)
assert.Equal(t, dyn.V(int64(1234)), nv)
}
func TestFromTypedIntRetainsLocationsIfUnchanged(t *testing.T) {
var src int = 1234
var ref = config.NewValue(1234, config.Location{File: "foo"})
var ref = dyn.NewValue(1234, dyn.Location{File: "foo"})
nv, err := FromTyped(src, ref)
require.NoError(t, err)
assert.Equal(t, config.NewValue(1234, config.Location{File: "foo"}), nv)
assert.Equal(t, dyn.NewValue(1234, dyn.Location{File: "foo"}), nv)
}
func TestFromTypedIntTypeError(t *testing.T) {
var src int = 1234
var ref = config.V("string")
var ref = dyn.V("string")
_, err := FromTyped(src, ref)
require.Error(t, err)
}
func TestFromTypedFloatEmpty(t *testing.T) {
var src float64
var ref = config.NilValue
var ref = dyn.NilValue
nv, err := FromTyped(src, ref)
require.NoError(t, err)
assert.Equal(t, config.NilValue, nv)
assert.Equal(t, dyn.NilValue, nv)
}
func TestFromTypedFloatEmptyOverwrite(t *testing.T) {
var src float64
var ref = config.V(1.23)
var ref = dyn.V(1.23)
nv, err := FromTyped(src, ref)
require.NoError(t, err)
assert.Equal(t, config.V(0.0), nv)
assert.Equal(t, dyn.V(0.0), nv)
}
func TestFromTypedFloatNonEmpty(t *testing.T) {
var src float64 = 1.23
var ref = config.NilValue
var ref = dyn.NilValue
nv, err := FromTyped(src, ref)
require.NoError(t, err)
assert.Equal(t, config.V(1.23), nv)
assert.Equal(t, dyn.V(1.23), nv)
}
func TestFromTypedFloatNonEmptyOverwrite(t *testing.T) {
var src float64 = 1.23
var ref = config.V(1.24)
var ref = dyn.V(1.24)
nv, err := FromTyped(src, ref)
require.NoError(t, err)
assert.Equal(t, config.V(1.23), nv)
assert.Equal(t, dyn.V(1.23), nv)
}
func TestFromTypedFloatRetainsLocationsIfUnchanged(t *testing.T) {
var src float64 = 1.23
var ref = config.NewValue(1.23, config.Location{File: "foo"})
var ref = dyn.NewValue(1.23, dyn.Location{File: "foo"})
nv, err := FromTyped(src, ref)
require.NoError(t, err)
assert.Equal(t, config.NewValue(1.23, config.Location{File: "foo"}), nv)
assert.Equal(t, dyn.NewValue(1.23, dyn.Location{File: "foo"}), nv)
}
func TestFromTypedFloatTypeError(t *testing.T) {
var src float64 = 1.23
var ref = config.V("string")
var ref = dyn.V("string")
_, err := FromTyped(src, ref)
require.Error(t, err)
}

View File

@ -5,15 +5,15 @@ import (
"reflect"
"strconv"
"github.com/databricks/cli/libs/config"
"github.com/databricks/cli/libs/diag"
"github.com/databricks/cli/libs/dyn"
)
func Normalize(dst any, src config.Value) (config.Value, diag.Diagnostics) {
func Normalize(dst any, src dyn.Value) (dyn.Value, diag.Diagnostics) {
return normalizeType(reflect.TypeOf(dst), src)
}
func normalizeType(typ reflect.Type, src config.Value) (config.Value, diag.Diagnostics) {
func normalizeType(typ reflect.Type, src dyn.Value) (dyn.Value, diag.Diagnostics) {
for typ.Kind() == reflect.Pointer {
typ = typ.Elem()
}
@ -35,10 +35,10 @@ func normalizeType(typ reflect.Type, src config.Value) (config.Value, diag.Diagn
return normalizeFloat(typ, src)
}
return config.NilValue, diag.Errorf("unsupported type: %s", typ.Kind())
return dyn.NilValue, diag.Errorf("unsupported type: %s", typ.Kind())
}
func typeMismatch(expected config.Kind, src config.Value) diag.Diagnostic {
func typeMismatch(expected dyn.Kind, src dyn.Value) diag.Diagnostic {
return diag.Diagnostic{
Severity: diag.Error,
Summary: fmt.Sprintf("expected %s, found %s", expected, src.Kind()),
@ -46,12 +46,12 @@ func typeMismatch(expected config.Kind, src config.Value) diag.Diagnostic {
}
}
func normalizeStruct(typ reflect.Type, src config.Value) (config.Value, diag.Diagnostics) {
func normalizeStruct(typ reflect.Type, src dyn.Value) (dyn.Value, diag.Diagnostics) {
var diags diag.Diagnostics
switch src.Kind() {
case config.KindMap:
out := make(map[string]config.Value)
case dyn.KindMap:
out := make(map[string]dyn.Value)
info := getStructInfo(typ)
for k, v := range src.MustMap() {
index, ok := info.Fields[k]
@ -77,20 +77,20 @@ func normalizeStruct(typ reflect.Type, src config.Value) (config.Value, diag.Dia
out[k] = v
}
return config.NewValue(out, src.Location()), diags
case config.KindNil:
return dyn.NewValue(out, src.Location()), diags
case dyn.KindNil:
return src, diags
}
return config.NilValue, diags.Append(typeMismatch(config.KindMap, src))
return dyn.NilValue, diags.Append(typeMismatch(dyn.KindMap, src))
}
func normalizeMap(typ reflect.Type, src config.Value) (config.Value, diag.Diagnostics) {
func normalizeMap(typ reflect.Type, src dyn.Value) (dyn.Value, diag.Diagnostics) {
var diags diag.Diagnostics
switch src.Kind() {
case config.KindMap:
out := make(map[string]config.Value)
case dyn.KindMap:
out := make(map[string]dyn.Value)
for k, v := range src.MustMap() {
// Normalize the value according to the map element type.
v, err := normalizeType(typ.Elem(), v)
@ -105,20 +105,20 @@ func normalizeMap(typ reflect.Type, src config.Value) (config.Value, diag.Diagno
out[k] = v
}
return config.NewValue(out, src.Location()), diags
case config.KindNil:
return dyn.NewValue(out, src.Location()), diags
case dyn.KindNil:
return src, diags
}
return config.NilValue, diags.Append(typeMismatch(config.KindMap, src))
return dyn.NilValue, diags.Append(typeMismatch(dyn.KindMap, src))
}
func normalizeSlice(typ reflect.Type, src config.Value) (config.Value, diag.Diagnostics) {
func normalizeSlice(typ reflect.Type, src dyn.Value) (dyn.Value, diag.Diagnostics) {
var diags diag.Diagnostics
switch src.Kind() {
case config.KindSequence:
out := make([]config.Value, 0, len(src.MustSequence()))
case dyn.KindSequence:
out := make([]dyn.Value, 0, len(src.MustSequence()))
for _, v := range src.MustSequence() {
// Normalize the value according to the slice element type.
v, err := normalizeType(typ.Elem(), v)
@ -133,42 +133,42 @@ func normalizeSlice(typ reflect.Type, src config.Value) (config.Value, diag.Diag
out = append(out, v)
}
return config.NewValue(out, src.Location()), diags
case config.KindNil:
return dyn.NewValue(out, src.Location()), diags
case dyn.KindNil:
return src, diags
}
return config.NilValue, diags.Append(typeMismatch(config.KindSequence, src))
return dyn.NilValue, diags.Append(typeMismatch(dyn.KindSequence, src))
}
func normalizeString(typ reflect.Type, src config.Value) (config.Value, diag.Diagnostics) {
func normalizeString(typ reflect.Type, src dyn.Value) (dyn.Value, diag.Diagnostics) {
var diags diag.Diagnostics
var out string
switch src.Kind() {
case config.KindString:
case dyn.KindString:
out = src.MustString()
case config.KindBool:
case dyn.KindBool:
out = strconv.FormatBool(src.MustBool())
case config.KindInt:
case dyn.KindInt:
out = strconv.FormatInt(src.MustInt(), 10)
case config.KindFloat:
case dyn.KindFloat:
out = strconv.FormatFloat(src.MustFloat(), 'f', -1, 64)
default:
return config.NilValue, diags.Append(typeMismatch(config.KindString, src))
return dyn.NilValue, diags.Append(typeMismatch(dyn.KindString, src))
}
return config.NewValue(out, src.Location()), diags
return dyn.NewValue(out, src.Location()), diags
}
func normalizeBool(typ reflect.Type, src config.Value) (config.Value, diag.Diagnostics) {
func normalizeBool(typ reflect.Type, src dyn.Value) (dyn.Value, diag.Diagnostics) {
var diags diag.Diagnostics
var out bool
switch src.Kind() {
case config.KindBool:
case dyn.KindBool:
out = src.MustBool()
case config.KindString:
case dyn.KindString:
// See https://github.com/go-yaml/yaml/blob/f6f7691b1fdeb513f56608cd2c32c51f8194bf51/decode.go#L684-L693.
switch src.MustString() {
case "true", "y", "Y", "yes", "Yes", "YES", "on", "On", "ON":
@ -177,59 +177,59 @@ func normalizeBool(typ reflect.Type, src config.Value) (config.Value, diag.Diagn
out = false
default:
// Cannot interpret as a boolean.
return config.NilValue, diags.Append(typeMismatch(config.KindBool, src))
return dyn.NilValue, diags.Append(typeMismatch(dyn.KindBool, src))
}
default:
return config.NilValue, diags.Append(typeMismatch(config.KindBool, src))
return dyn.NilValue, diags.Append(typeMismatch(dyn.KindBool, src))
}
return config.NewValue(out, src.Location()), diags
return dyn.NewValue(out, src.Location()), diags
}
func normalizeInt(typ reflect.Type, src config.Value) (config.Value, diag.Diagnostics) {
func normalizeInt(typ reflect.Type, src dyn.Value) (dyn.Value, diag.Diagnostics) {
var diags diag.Diagnostics
var out int64
switch src.Kind() {
case config.KindInt:
case dyn.KindInt:
out = src.MustInt()
case config.KindString:
case dyn.KindString:
var err error
out, err = strconv.ParseInt(src.MustString(), 10, 64)
if err != nil {
return config.NilValue, diags.Append(diag.Diagnostic{
return dyn.NilValue, diags.Append(diag.Diagnostic{
Severity: diag.Error,
Summary: fmt.Sprintf("cannot parse %q as an integer", src.MustString()),
Location: src.Location(),
})
}
default:
return config.NilValue, diags.Append(typeMismatch(config.KindInt, src))
return dyn.NilValue, diags.Append(typeMismatch(dyn.KindInt, src))
}
return config.NewValue(out, src.Location()), diags
return dyn.NewValue(out, src.Location()), diags
}
func normalizeFloat(typ reflect.Type, src config.Value) (config.Value, diag.Diagnostics) {
func normalizeFloat(typ reflect.Type, src dyn.Value) (dyn.Value, diag.Diagnostics) {
var diags diag.Diagnostics
var out float64
switch src.Kind() {
case config.KindFloat:
case dyn.KindFloat:
out = src.MustFloat()
case config.KindString:
case dyn.KindString:
var err error
out, err = strconv.ParseFloat(src.MustString(), 64)
if err != nil {
return config.NilValue, diags.Append(diag.Diagnostic{
return dyn.NilValue, diags.Append(diag.Diagnostic{
Severity: diag.Error,
Summary: fmt.Sprintf("cannot parse %q as a floating point number", src.MustString()),
Location: src.Location(),
})
}
default:
return config.NilValue, diags.Append(typeMismatch(config.KindFloat, src))
return dyn.NilValue, diags.Append(typeMismatch(dyn.KindFloat, src))
}
return config.NewValue(out, src.Location()), diags
return dyn.NewValue(out, src.Location()), diags
}

View File

@ -3,8 +3,8 @@ package convert
import (
"testing"
"github.com/databricks/cli/libs/config"
"github.com/databricks/cli/libs/diag"
"github.com/databricks/cli/libs/dyn"
"github.com/stretchr/testify/assert"
)
@ -15,9 +15,9 @@ func TestNormalizeStruct(t *testing.T) {
}
var typ Tmp
vin := config.V(map[string]config.Value{
"foo": config.V("bar"),
"bar": config.V("baz"),
vin := dyn.V(map[string]dyn.Value{
"foo": dyn.V("bar"),
"bar": dyn.V("baz"),
})
vout, err := Normalize(typ, vin)
@ -32,9 +32,9 @@ func TestNormalizeStructElementDiagnostic(t *testing.T) {
}
var typ Tmp
vin := config.V(map[string]config.Value{
"foo": config.V("bar"),
"bar": config.V(map[string]config.Value{"an": config.V("error")}),
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)
@ -42,7 +42,7 @@ func TestNormalizeStructElementDiagnostic(t *testing.T) {
assert.Equal(t, diag.Diagnostic{
Severity: diag.Error,
Summary: `expected string, found map`,
Location: config.Location{},
Location: dyn.Location{},
}, err[0])
// Elements that encounter an error during normalization are dropped.
@ -57,9 +57,9 @@ func TestNormalizeStructUnknownField(t *testing.T) {
}
var typ Tmp
vin := config.V(map[string]config.Value{
"foo": config.V("bar"),
"bar": config.V("baz"),
vin := dyn.V(map[string]dyn.Value{
"foo": dyn.V("bar"),
"bar": dyn.V("baz"),
})
vout, err := Normalize(typ, vin)
@ -82,7 +82,7 @@ func TestNormalizeStructNil(t *testing.T) {
}
var typ Tmp
vin := config.NilValue
vin := dyn.NilValue
vout, err := Normalize(typ, vin)
assert.Empty(t, err)
assert.Equal(t, vin, vout)
@ -94,7 +94,7 @@ func TestNormalizeStructError(t *testing.T) {
}
var typ Tmp
vin := config.V("string")
vin := dyn.V("string")
_, err := Normalize(typ, vin)
assert.Len(t, err, 1)
assert.Equal(t, diag.Diagnostic{
@ -106,9 +106,9 @@ func TestNormalizeStructError(t *testing.T) {
func TestNormalizeMap(t *testing.T) {
var typ map[string]string
vin := config.V(map[string]config.Value{
"foo": config.V("bar"),
"bar": config.V("baz"),
vin := dyn.V(map[string]dyn.Value{
"foo": dyn.V("bar"),
"bar": dyn.V("baz"),
})
vout, err := Normalize(typ, vin)
@ -118,9 +118,9 @@ func TestNormalizeMap(t *testing.T) {
func TestNormalizeMapElementDiagnostic(t *testing.T) {
var typ map[string]string
vin := config.V(map[string]config.Value{
"foo": config.V("bar"),
"bar": config.V(map[string]config.Value{"an": config.V("error")}),
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)
@ -128,7 +128,7 @@ func TestNormalizeMapElementDiagnostic(t *testing.T) {
assert.Equal(t, diag.Diagnostic{
Severity: diag.Error,
Summary: `expected string, found map`,
Location: config.Location{},
Location: dyn.Location{},
}, err[0])
// Elements that encounter an error during normalization are dropped.
@ -139,7 +139,7 @@ func TestNormalizeMapElementDiagnostic(t *testing.T) {
func TestNormalizeMapNil(t *testing.T) {
var typ map[string]string
vin := config.NilValue
vin := dyn.NilValue
vout, err := Normalize(typ, vin)
assert.Empty(t, err)
assert.Equal(t, vin, vout)
@ -147,7 +147,7 @@ func TestNormalizeMapNil(t *testing.T) {
func TestNormalizeMapError(t *testing.T) {
var typ map[string]string
vin := config.V("string")
vin := dyn.V("string")
_, err := Normalize(typ, vin)
assert.Len(t, err, 1)
assert.Equal(t, diag.Diagnostic{
@ -159,9 +159,9 @@ func TestNormalizeMapError(t *testing.T) {
func TestNormalizeSlice(t *testing.T) {
var typ []string
vin := config.V([]config.Value{
config.V("foo"),
config.V("bar"),
vin := dyn.V([]dyn.Value{
dyn.V("foo"),
dyn.V("bar"),
})
vout, err := Normalize(typ, vin)
@ -171,10 +171,10 @@ func TestNormalizeSlice(t *testing.T) {
func TestNormalizeSliceElementDiagnostic(t *testing.T) {
var typ []string
vin := config.V([]config.Value{
config.V("foo"),
config.V("bar"),
config.V(map[string]config.Value{"an": config.V("error")}),
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)
@ -182,7 +182,7 @@ func TestNormalizeSliceElementDiagnostic(t *testing.T) {
assert.Equal(t, diag.Diagnostic{
Severity: diag.Error,
Summary: `expected string, found map`,
Location: config.Location{},
Location: dyn.Location{},
}, err[0])
// Elements that encounter an error during normalization are dropped.
@ -191,7 +191,7 @@ func TestNormalizeSliceElementDiagnostic(t *testing.T) {
func TestNormalizeSliceNil(t *testing.T) {
var typ []string
vin := config.NilValue
vin := dyn.NilValue
vout, err := Normalize(typ, vin)
assert.Empty(t, err)
assert.Equal(t, vin, vout)
@ -199,7 +199,7 @@ func TestNormalizeSliceNil(t *testing.T) {
func TestNormalizeSliceError(t *testing.T) {
var typ []string
vin := config.V("string")
vin := dyn.V("string")
_, err := Normalize(typ, vin)
assert.Len(t, err, 1)
assert.Equal(t, diag.Diagnostic{
@ -211,7 +211,7 @@ func TestNormalizeSliceError(t *testing.T) {
func TestNormalizeString(t *testing.T) {
var typ string
vin := config.V("string")
vin := dyn.V("string")
vout, err := Normalize(&typ, vin)
assert.Empty(t, err)
assert.Equal(t, vin, vout)
@ -219,7 +219,7 @@ func TestNormalizeString(t *testing.T) {
func TestNormalizeStringNil(t *testing.T) {
var typ string
vin := config.NewValue(nil, config.Location{File: "file", Line: 1, Column: 1})
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{
@ -231,51 +231,51 @@ func TestNormalizeStringNil(t *testing.T) {
func TestNormalizeStringFromBool(t *testing.T) {
var typ string
vin := config.NewValue(true, config.Location{File: "file", Line: 1, Column: 1})
vin := dyn.NewValue(true, dyn.Location{File: "file", Line: 1, Column: 1})
vout, err := Normalize(&typ, vin)
assert.Empty(t, err)
assert.Equal(t, config.NewValue("true", vin.Location()), vout)
assert.Equal(t, dyn.NewValue("true", vin.Location()), vout)
}
func TestNormalizeStringFromInt(t *testing.T) {
var typ string
vin := config.NewValue(123, config.Location{File: "file", Line: 1, Column: 1})
vin := dyn.NewValue(123, dyn.Location{File: "file", Line: 1, Column: 1})
vout, err := Normalize(&typ, vin)
assert.Empty(t, err)
assert.Equal(t, config.NewValue("123", vin.Location()), vout)
assert.Equal(t, dyn.NewValue("123", vin.Location()), vout)
}
func TestNormalizeStringFromFloat(t *testing.T) {
var typ string
vin := config.NewValue(1.20, config.Location{File: "file", Line: 1, Column: 1})
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, config.NewValue("1.2", vin.Location()), vout)
assert.Equal(t, dyn.NewValue("1.2", vin.Location()), vout)
}
func TestNormalizeStringError(t *testing.T) {
var typ string
vin := config.V(map[string]config.Value{"an": config.V("error")})
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.Error,
Summary: `expected string, found map`,
Location: config.Location{},
Location: dyn.Location{},
}, err[0])
}
func TestNormalizeBool(t *testing.T) {
var typ bool
vin := config.V(true)
vin := dyn.V(true)
vout, err := Normalize(&typ, vin)
assert.Empty(t, err)
assert.Equal(t, config.V(true), vout)
assert.Equal(t, dyn.V(true), vout)
}
func TestNormalizeBoolNil(t *testing.T) {
var typ bool
vin := config.NewValue(nil, config.Location{File: "file", Line: 1, Column: 1})
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{
@ -299,16 +299,16 @@ func TestNormalizeBoolFromString(t *testing.T) {
{"on", true},
{"off", false},
} {
vin := config.V(c.Input)
vin := dyn.V(c.Input)
vout, err := Normalize(&typ, vin)
assert.Empty(t, err)
assert.Equal(t, config.V(c.Output), vout)
assert.Equal(t, dyn.V(c.Output), vout)
}
}
func TestNormalizeBoolFromStringError(t *testing.T) {
var typ bool
vin := config.V("abc")
vin := dyn.V("abc")
_, err := Normalize(&typ, vin)
assert.Len(t, err, 1)
assert.Equal(t, diag.Diagnostic{
@ -320,27 +320,27 @@ func TestNormalizeBoolFromStringError(t *testing.T) {
func TestNormalizeBoolError(t *testing.T) {
var typ bool
vin := config.V(map[string]config.Value{"an": config.V("error")})
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.Error,
Summary: `expected bool, found map`,
Location: config.Location{},
Location: dyn.Location{},
}, err[0])
}
func TestNormalizeInt(t *testing.T) {
var typ int
vin := config.V(123)
vin := dyn.V(123)
vout, err := Normalize(&typ, vin)
assert.Empty(t, err)
assert.Equal(t, config.V(int64(123)), vout)
assert.Equal(t, dyn.V(int64(123)), vout)
}
func TestNormalizeIntNil(t *testing.T) {
var typ int
vin := config.NewValue(nil, config.Location{File: "file", Line: 1, Column: 1})
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{
@ -352,15 +352,15 @@ func TestNormalizeIntNil(t *testing.T) {
func TestNormalizeIntFromString(t *testing.T) {
var typ int
vin := config.V("123")
vin := dyn.V("123")
vout, err := Normalize(&typ, vin)
assert.Empty(t, err)
assert.Equal(t, config.V(int64(123)), vout)
assert.Equal(t, dyn.V(int64(123)), vout)
}
func TestNormalizeIntFromStringError(t *testing.T) {
var typ int
vin := config.V("abc")
vin := dyn.V("abc")
_, err := Normalize(&typ, vin)
assert.Len(t, err, 1)
assert.Equal(t, diag.Diagnostic{
@ -372,27 +372,27 @@ func TestNormalizeIntFromStringError(t *testing.T) {
func TestNormalizeIntError(t *testing.T) {
var typ int
vin := config.V(map[string]config.Value{"an": config.V("error")})
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.Error,
Summary: `expected int, found map`,
Location: config.Location{},
Location: dyn.Location{},
}, err[0])
}
func TestNormalizeFloat(t *testing.T) {
var typ float64
vin := config.V(1.2)
vin := dyn.V(1.2)
vout, err := Normalize(&typ, vin)
assert.Empty(t, err)
assert.Equal(t, config.V(1.2), vout)
assert.Equal(t, dyn.V(1.2), vout)
}
func TestNormalizeFloatNil(t *testing.T) {
var typ float64
vin := config.NewValue(nil, config.Location{File: "file", Line: 1, Column: 1})
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{
@ -404,15 +404,15 @@ func TestNormalizeFloatNil(t *testing.T) {
func TestNormalizeFloatFromString(t *testing.T) {
var typ float64
vin := config.V("1.2")
vin := dyn.V("1.2")
vout, err := Normalize(&typ, vin)
assert.Empty(t, err)
assert.Equal(t, config.V(1.2), vout)
assert.Equal(t, dyn.V(1.2), vout)
}
func TestNormalizeFloatFromStringError(t *testing.T) {
var typ float64
vin := config.V("abc")
vin := dyn.V("abc")
_, err := Normalize(&typ, vin)
assert.Len(t, err, 1)
assert.Equal(t, diag.Diagnostic{
@ -424,12 +424,12 @@ func TestNormalizeFloatFromStringError(t *testing.T) {
func TestNormalizeFloatError(t *testing.T) {
var typ float64
vin := config.V(map[string]config.Value{"an": config.V("error")})
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.Error,
Summary: `expected float, found map`,
Location: config.Location{},
Location: dyn.Location{},
}, err[0])
}

View File

@ -5,16 +5,16 @@ import (
"strings"
"sync"
"github.com/databricks/cli/libs/config"
"github.com/databricks/cli/libs/dyn"
)
// structInfo holds the type information we need to efficiently
// convert data from a [config.Value] to a Go struct.
// convert data from a [dyn.Value] to a Go struct.
type structInfo struct {
// Fields maps the JSON-name of the field to the field's index for use with [FieldByIndex].
Fields map[string][]int
// ValueField maps to the field with a [config.Value].
// ValueField maps to the field with a [dyn.Value].
// The underlying type is expected to only have one of these.
ValueField []int
}
@ -74,10 +74,10 @@ func buildStructInfo(typ reflect.Type) structInfo {
continue
}
// If this field has type [config.Value], we populate it with the source [config.Value] from [ToTyped].
// If this field has type [dyn.Value], we populate it with the source [dyn.Value] from [ToTyped].
if sf.IsExported() && sf.Type == configValueType {
if out.ValueField != nil {
panic("multiple config.Value fields")
panic("multiple dyn.Value fields")
}
out.ValueField = append(prefix, sf.Index...)
continue
@ -129,5 +129,5 @@ func (s *structInfo) FieldValues(v reflect.Value) map[string]reflect.Value {
return out
}
// Type of [config.Value].
var configValueType = reflect.TypeOf((*config.Value)(nil)).Elem()
// Type of [dyn.Value].
var configValueType = reflect.TypeOf((*dyn.Value)(nil)).Elem()

View File

@ -4,7 +4,7 @@ import (
"reflect"
"testing"
"github.com/databricks/cli/libs/config"
"github.com/databricks/cli/libs/dyn"
"github.com/stretchr/testify/assert"
)
@ -207,7 +207,7 @@ func TestStructInfoValueFieldAbsent(t *testing.T) {
func TestStructInfoValueFieldPresent(t *testing.T) {
type Tmp struct {
Foo config.Value
Foo dyn.Value
}
si := getStructInfo(reflect.TypeOf(Tmp{}))
@ -216,8 +216,8 @@ func TestStructInfoValueFieldPresent(t *testing.T) {
func TestStructInfoValueFieldMultiple(t *testing.T) {
type Tmp struct {
Foo config.Value
Bar config.Value
Foo dyn.Value
Bar dyn.Value
}
assert.Panics(t, func() {

View File

@ -5,17 +5,17 @@ import (
"reflect"
"strconv"
"github.com/databricks/cli/libs/config"
"github.com/databricks/cli/libs/dyn"
)
func ToTyped(dst any, src config.Value) error {
func ToTyped(dst any, src dyn.Value) error {
dstv := reflect.ValueOf(dst)
// Dereference pointer if necessary
for dstv.Kind() == reflect.Pointer {
// If the source value is nil and the destination is a settable pointer,
// set the destination to nil. Also see `end_to_end_test.go`.
if dstv.CanSet() && src == config.NilValue {
if dstv.CanSet() && src == dyn.NilValue {
dstv.SetZero()
return nil
}
@ -50,9 +50,9 @@ func ToTyped(dst any, src config.Value) error {
return fmt.Errorf("unsupported type: %s", dstv.Kind())
}
func toTypedStruct(dst reflect.Value, src config.Value) error {
func toTypedStruct(dst reflect.Value, src dyn.Value) error {
switch src.Kind() {
case config.KindMap:
case dyn.KindMap:
info := getStructInfo(dst.Type())
for k, v := range src.MustMap() {
index, ok := info.Fields[k]
@ -83,14 +83,14 @@ func toTypedStruct(dst reflect.Value, src config.Value) error {
}
}
// Populate field(s) for [config.Value], if any.
// Populate field(s) for [dyn.Value], if any.
if info.ValueField != nil {
vv := dst.FieldByIndex(info.ValueField)
vv.Set(reflect.ValueOf(src))
}
return nil
case config.KindNil:
case dyn.KindNil:
dst.SetZero()
return nil
}
@ -101,9 +101,9 @@ func toTypedStruct(dst reflect.Value, src config.Value) error {
}
}
func toTypedMap(dst reflect.Value, src config.Value) error {
func toTypedMap(dst reflect.Value, src dyn.Value) error {
switch src.Kind() {
case config.KindMap:
case dyn.KindMap:
m := src.MustMap()
// Always overwrite.
@ -118,7 +118,7 @@ func toTypedMap(dst reflect.Value, src config.Value) error {
dst.SetMapIndex(kv, vv.Elem())
}
return nil
case config.KindNil:
case dyn.KindNil:
dst.SetZero()
return nil
}
@ -129,9 +129,9 @@ func toTypedMap(dst reflect.Value, src config.Value) error {
}
}
func toTypedSlice(dst reflect.Value, src config.Value) error {
func toTypedSlice(dst reflect.Value, src dyn.Value) error {
switch src.Kind() {
case config.KindSequence:
case dyn.KindSequence:
seq := src.MustSequence()
// Always overwrite.
@ -143,7 +143,7 @@ func toTypedSlice(dst reflect.Value, src config.Value) error {
}
}
return nil
case config.KindNil:
case dyn.KindNil:
dst.SetZero()
return nil
}
@ -154,18 +154,18 @@ func toTypedSlice(dst reflect.Value, src config.Value) error {
}
}
func toTypedString(dst reflect.Value, src config.Value) error {
func toTypedString(dst reflect.Value, src dyn.Value) error {
switch src.Kind() {
case config.KindString:
case dyn.KindString:
dst.SetString(src.MustString())
return nil
case config.KindBool:
case dyn.KindBool:
dst.SetString(strconv.FormatBool(src.MustBool()))
return nil
case config.KindInt:
case dyn.KindInt:
dst.SetString(strconv.FormatInt(src.MustInt(), 10))
return nil
case config.KindFloat:
case dyn.KindFloat:
dst.SetString(strconv.FormatFloat(src.MustFloat(), 'f', -1, 64))
return nil
}
@ -176,12 +176,12 @@ func toTypedString(dst reflect.Value, src config.Value) error {
}
}
func toTypedBool(dst reflect.Value, src config.Value) error {
func toTypedBool(dst reflect.Value, src dyn.Value) error {
switch src.Kind() {
case config.KindBool:
case dyn.KindBool:
dst.SetBool(src.MustBool())
return nil
case config.KindString:
case dyn.KindString:
// See https://github.com/go-yaml/yaml/blob/f6f7691b1fdeb513f56608cd2c32c51f8194bf51/decode.go#L684-L693.
switch src.MustString() {
case "y", "Y", "yes", "Yes", "YES", "on", "On", "ON":
@ -199,12 +199,12 @@ func toTypedBool(dst reflect.Value, src config.Value) error {
}
}
func toTypedInt(dst reflect.Value, src config.Value) error {
func toTypedInt(dst reflect.Value, src dyn.Value) error {
switch src.Kind() {
case config.KindInt:
case dyn.KindInt:
dst.SetInt(src.MustInt())
return nil
case config.KindString:
case dyn.KindString:
if i64, err := strconv.ParseInt(src.MustString(), 10, 64); err == nil {
dst.SetInt(i64)
return nil
@ -217,12 +217,12 @@ func toTypedInt(dst reflect.Value, src config.Value) error {
}
}
func toTypedFloat(dst reflect.Value, src config.Value) error {
func toTypedFloat(dst reflect.Value, src dyn.Value) error {
switch src.Kind() {
case config.KindFloat:
case dyn.KindFloat:
dst.SetFloat(src.MustFloat())
return nil
case config.KindString:
case dyn.KindString:
if f64, err := strconv.ParseFloat(src.MustString(), 64); err == nil {
dst.SetFloat(f64)
return nil

View File

@ -3,7 +3,7 @@ package convert
import (
"testing"
"github.com/databricks/cli/libs/config"
"github.com/databricks/cli/libs/dyn"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@ -21,9 +21,9 @@ func TestToTypedStruct(t *testing.T) {
}
var out Tmp
v := config.V(map[string]config.Value{
"foo": config.V("bar"),
"bar": config.V("baz"),
v := dyn.V(map[string]dyn.Value{
"foo": dyn.V("bar"),
"bar": dyn.V("baz"),
})
err := ToTyped(&out, v)
@ -48,9 +48,9 @@ func TestToTypedStructOverwrite(t *testing.T) {
Foo: "baz",
Bar: "qux",
}
v := config.V(map[string]config.Value{
"foo": config.V("bar"),
"bar": config.V("baz"),
v := dyn.V(map[string]dyn.Value{
"foo": dyn.V("bar"),
"bar": dyn.V("baz"),
})
err := ToTyped(&out, v)
@ -74,9 +74,9 @@ func TestToTypedStructAnonymousByValue(t *testing.T) {
}
var out Tmp
v := config.V(map[string]config.Value{
"foo": config.V("bar"),
"bar": config.V("baz"),
v := dyn.V(map[string]dyn.Value{
"foo": dyn.V("bar"),
"bar": dyn.V("baz"),
})
err := ToTyped(&out, v)
@ -100,9 +100,9 @@ func TestToTypedStructAnonymousByPointer(t *testing.T) {
}
var out Tmp
v := config.V(map[string]config.Value{
"foo": config.V("bar"),
"bar": config.V("baz"),
v := dyn.V(map[string]dyn.Value{
"foo": dyn.V("bar"),
"bar": dyn.V("baz"),
})
err := ToTyped(&out, v)
@ -117,7 +117,7 @@ func TestToTypedStructNil(t *testing.T) {
}
var out = Tmp{}
err := ToTyped(&out, config.NilValue)
err := ToTyped(&out, dyn.NilValue)
require.NoError(t, err)
assert.Equal(t, Tmp{}, out)
}
@ -128,7 +128,7 @@ func TestToTypedStructNilOverwrite(t *testing.T) {
}
var out = Tmp{"bar"}
err := ToTyped(&out, config.NilValue)
err := ToTyped(&out, dyn.NilValue)
require.NoError(t, err)
assert.Equal(t, Tmp{}, out)
}
@ -137,12 +137,12 @@ func TestToTypedStructWithValueField(t *testing.T) {
type Tmp struct {
Foo string `json:"foo"`
ConfigValue config.Value
ConfigValue dyn.Value
}
var out Tmp
v := config.V(map[string]config.Value{
"foo": config.V("bar"),
v := dyn.V(map[string]dyn.Value{
"foo": dyn.V("bar"),
})
err := ToTyped(&out, v)
@ -154,8 +154,8 @@ func TestToTypedStructWithValueField(t *testing.T) {
func TestToTypedMap(t *testing.T) {
var out = map[string]string{}
v := config.V(map[string]config.Value{
"key": config.V("value"),
v := dyn.V(map[string]dyn.Value{
"key": dyn.V("value"),
})
err := ToTyped(&out, v)
@ -169,8 +169,8 @@ func TestToTypedMapOverwrite(t *testing.T) {
"foo": "bar",
}
v := config.V(map[string]config.Value{
"bar": config.V("qux"),
v := dyn.V(map[string]dyn.Value{
"bar": dyn.V("qux"),
})
err := ToTyped(&out, v)
@ -182,8 +182,8 @@ func TestToTypedMapOverwrite(t *testing.T) {
func TestToTypedMapWithPointerElement(t *testing.T) {
var out map[string]*string
v := config.V(map[string]config.Value{
"key": config.V("value"),
v := dyn.V(map[string]dyn.Value{
"key": dyn.V("value"),
})
err := ToTyped(&out, v)
@ -194,7 +194,7 @@ func TestToTypedMapWithPointerElement(t *testing.T) {
func TestToTypedMapNil(t *testing.T) {
var out = map[string]string{}
err := ToTyped(&out, config.NilValue)
err := ToTyped(&out, dyn.NilValue)
require.NoError(t, err)
assert.Nil(t, out)
}
@ -203,7 +203,7 @@ func TestToTypedMapNilOverwrite(t *testing.T) {
var out = map[string]string{
"foo": "bar",
}
err := ToTyped(&out, config.NilValue)
err := ToTyped(&out, dyn.NilValue)
require.NoError(t, err)
assert.Nil(t, out)
}
@ -211,9 +211,9 @@ func TestToTypedMapNilOverwrite(t *testing.T) {
func TestToTypedSlice(t *testing.T) {
var out []string
v := config.V([]config.Value{
config.V("foo"),
config.V("bar"),
v := dyn.V([]dyn.Value{
dyn.V("foo"),
dyn.V("bar"),
})
err := ToTyped(&out, v)
@ -226,9 +226,9 @@ func TestToTypedSlice(t *testing.T) {
func TestToTypedSliceOverwrite(t *testing.T) {
var out = []string{"qux"}
v := config.V([]config.Value{
config.V("foo"),
config.V("bar"),
v := dyn.V([]dyn.Value{
dyn.V("foo"),
dyn.V("bar"),
})
err := ToTyped(&out, v)
@ -241,9 +241,9 @@ func TestToTypedSliceOverwrite(t *testing.T) {
func TestToTypedSliceWithPointerElement(t *testing.T) {
var out []*string
v := config.V([]config.Value{
config.V("foo"),
config.V("bar"),
v := dyn.V([]dyn.Value{
dyn.V("foo"),
dyn.V("bar"),
})
err := ToTyped(&out, v)
@ -255,63 +255,63 @@ func TestToTypedSliceWithPointerElement(t *testing.T) {
func TestToTypedSliceNil(t *testing.T) {
var out []string
err := ToTyped(&out, config.NilValue)
err := ToTyped(&out, dyn.NilValue)
require.NoError(t, err)
assert.Nil(t, out)
}
func TestToTypedSliceNilOverwrite(t *testing.T) {
var out = []string{"foo"}
err := ToTyped(&out, config.NilValue)
err := ToTyped(&out, dyn.NilValue)
require.NoError(t, err)
assert.Nil(t, out)
}
func TestToTypedString(t *testing.T) {
var out string
err := ToTyped(&out, config.V("foo"))
err := ToTyped(&out, dyn.V("foo"))
require.NoError(t, err)
assert.Equal(t, "foo", out)
}
func TestToTypedStringOverwrite(t *testing.T) {
var out string = "bar"
err := ToTyped(&out, config.V("foo"))
err := ToTyped(&out, dyn.V("foo"))
require.NoError(t, err)
assert.Equal(t, "foo", out)
}
func TestToTypedStringFromBool(t *testing.T) {
var out string
err := ToTyped(&out, config.V(true))
err := ToTyped(&out, dyn.V(true))
require.NoError(t, err)
assert.Equal(t, "true", out)
}
func TestToTypedStringFromInt(t *testing.T) {
var out string
err := ToTyped(&out, config.V(123))
err := ToTyped(&out, dyn.V(123))
require.NoError(t, err)
assert.Equal(t, "123", out)
}
func TestToTypedStringFromFloat(t *testing.T) {
var out string
err := ToTyped(&out, config.V(1.2))
err := ToTyped(&out, dyn.V(1.2))
require.NoError(t, err)
assert.Equal(t, "1.2", out)
}
func TestToTypedBool(t *testing.T) {
var out bool
err := ToTyped(&out, config.V(true))
err := ToTyped(&out, dyn.V(true))
require.NoError(t, err)
assert.Equal(t, true, out)
}
func TestToTypedBoolOverwrite(t *testing.T) {
var out bool = true
err := ToTyped(&out, config.V(false))
err := ToTyped(&out, dyn.V(false))
require.NoError(t, err)
assert.Equal(t, false, out)
}
@ -321,128 +321,128 @@ func TestToTypedBoolFromString(t *testing.T) {
// True-ish
for _, v := range []string{"y", "yes", "on"} {
err := ToTyped(&out, config.V(v))
err := ToTyped(&out, dyn.V(v))
require.NoError(t, err)
assert.Equal(t, true, out)
}
// False-ish
for _, v := range []string{"n", "no", "off"} {
err := ToTyped(&out, config.V(v))
err := ToTyped(&out, dyn.V(v))
require.NoError(t, err)
assert.Equal(t, false, out)
}
// Other
err := ToTyped(&out, config.V("${var.foo}"))
err := ToTyped(&out, dyn.V("${var.foo}"))
require.Error(t, err)
}
func TestToTypedInt(t *testing.T) {
var out int
err := ToTyped(&out, config.V(1234))
err := ToTyped(&out, dyn.V(1234))
require.NoError(t, err)
assert.Equal(t, int(1234), out)
}
func TestToTypedInt32(t *testing.T) {
var out32 int32
err := ToTyped(&out32, config.V(1235))
err := ToTyped(&out32, dyn.V(1235))
require.NoError(t, err)
assert.Equal(t, int32(1235), out32)
}
func TestToTypedInt64(t *testing.T) {
var out64 int64
err := ToTyped(&out64, config.V(1236))
err := ToTyped(&out64, dyn.V(1236))
require.NoError(t, err)
assert.Equal(t, int64(1236), out64)
}
func TestToTypedIntOverwrite(t *testing.T) {
var out int = 123
err := ToTyped(&out, config.V(1234))
err := ToTyped(&out, dyn.V(1234))
require.NoError(t, err)
assert.Equal(t, int(1234), out)
}
func TestToTypedInt32Overwrite(t *testing.T) {
var out32 int32 = 123
err := ToTyped(&out32, config.V(1234))
err := ToTyped(&out32, dyn.V(1234))
require.NoError(t, err)
assert.Equal(t, int32(1234), out32)
}
func TestToTypedInt64Overwrite(t *testing.T) {
var out64 int64 = 123
err := ToTyped(&out64, config.V(1234))
err := ToTyped(&out64, dyn.V(1234))
require.NoError(t, err)
assert.Equal(t, int64(1234), out64)
}
func TestToTypedIntFromStringError(t *testing.T) {
var out int
err := ToTyped(&out, config.V("abc"))
err := ToTyped(&out, dyn.V("abc"))
require.Error(t, err)
}
func TestToTypedIntFromStringInt(t *testing.T) {
var out int
err := ToTyped(&out, config.V("123"))
err := ToTyped(&out, dyn.V("123"))
require.NoError(t, err)
assert.Equal(t, int(123), out)
}
func TestToTypedFloat32(t *testing.T) {
var out float32
err := ToTyped(&out, config.V(float32(1.0)))
err := ToTyped(&out, dyn.V(float32(1.0)))
require.NoError(t, err)
assert.Equal(t, float32(1.0), out)
}
func TestToTypedFloat64(t *testing.T) {
var out float64
err := ToTyped(&out, config.V(float64(1.0)))
err := ToTyped(&out, dyn.V(float64(1.0)))
require.NoError(t, err)
assert.Equal(t, float64(1.0), out)
}
func TestToTypedFloat32Overwrite(t *testing.T) {
var out float32 = 1.0
err := ToTyped(&out, config.V(float32(2.0)))
err := ToTyped(&out, dyn.V(float32(2.0)))
require.NoError(t, err)
assert.Equal(t, float32(2.0), out)
}
func TestToTypedFloat64Overwrite(t *testing.T) {
var out float64 = 1.0
err := ToTyped(&out, config.V(float64(2.0)))
err := ToTyped(&out, dyn.V(float64(2.0)))
require.NoError(t, err)
assert.Equal(t, float64(2.0), out)
}
func TestToTypedFloat32FromStringError(t *testing.T) {
var out float32
err := ToTyped(&out, config.V("abc"))
err := ToTyped(&out, dyn.V("abc"))
require.Error(t, err)
}
func TestToTypedFloat64FromStringError(t *testing.T) {
var out float64
err := ToTyped(&out, config.V("abc"))
err := ToTyped(&out, dyn.V("abc"))
require.Error(t, err)
}
func TestToTypedFloat32FromString(t *testing.T) {
var out float32
err := ToTyped(&out, config.V("1.2"))
err := ToTyped(&out, dyn.V("1.2"))
require.NoError(t, err)
assert.Equal(t, float32(1.2), out)
}
func TestToTypedFloat64FromString(t *testing.T) {
var out float64
err := ToTyped(&out, config.V("1.2"))
err := ToTyped(&out, dyn.V("1.2"))
require.NoError(t, err)
assert.Equal(t, float64(1.2), out)
}

View File

@ -1,4 +1,4 @@
package config
package dyn
import "time"

View File

@ -1,4 +1,4 @@
package config
package dyn
import "fmt"

View File

@ -1,13 +1,13 @@
package config_test
package dyn_test
import (
"testing"
"github.com/databricks/cli/libs/config"
"github.com/databricks/cli/libs/dyn"
"github.com/stretchr/testify/assert"
)
func TestLocation(t *testing.T) {
loc := config.Location{File: "file", Line: 1, Column: 2}
loc := dyn.Location{File: "file", Line: 1, Column: 2}
assert.Equal(t, "file:1:2", loc.String())
}

View File

@ -3,7 +3,7 @@ package merge
import (
"fmt"
"github.com/databricks/cli/libs/config"
"github.com/databricks/cli/libs/dyn"
)
// Merge recursively merges the specified values.
@ -12,46 +12,46 @@ import (
// * Merging x with nil or nil with x always yields x.
// * Merging maps a and b means entries from map b take precedence.
// * Merging sequences a and b means concatenating them.
func Merge(a, b config.Value) (config.Value, error) {
func Merge(a, b dyn.Value) (dyn.Value, error) {
return merge(a, b)
}
func merge(a, b config.Value) (config.Value, error) {
func merge(a, b dyn.Value) (dyn.Value, error) {
ak := a.Kind()
bk := b.Kind()
// If a is nil, return b.
if ak == config.KindNil {
if ak == dyn.KindNil {
return b, nil
}
// If b is nil, return a.
if bk == config.KindNil {
if bk == dyn.KindNil {
return a, nil
}
// Call the appropriate merge function based on the kind of a and b.
switch ak {
case config.KindMap:
if bk != config.KindMap {
return config.NilValue, fmt.Errorf("cannot merge map with %s", bk)
case dyn.KindMap:
if bk != dyn.KindMap {
return dyn.NilValue, fmt.Errorf("cannot merge map with %s", bk)
}
return mergeMap(a, b)
case config.KindSequence:
if bk != config.KindSequence {
return config.NilValue, fmt.Errorf("cannot merge sequence with %s", bk)
case dyn.KindSequence:
if bk != dyn.KindSequence {
return dyn.NilValue, fmt.Errorf("cannot merge sequence with %s", bk)
}
return mergeSequence(a, b)
default:
if ak != bk {
return config.NilValue, fmt.Errorf("cannot merge %s with %s", ak, bk)
return dyn.NilValue, fmt.Errorf("cannot merge %s with %s", ak, bk)
}
return mergePrimitive(a, b)
}
}
func mergeMap(a, b config.Value) (config.Value, error) {
out := make(map[string]config.Value)
func mergeMap(a, b dyn.Value) (dyn.Value, error) {
out := make(map[string]dyn.Value)
am := a.MustMap()
bm := b.MustMap()
@ -66,7 +66,7 @@ func mergeMap(a, b config.Value) (config.Value, error) {
// If the key already exists, merge the values.
merged, err := merge(out[k], v)
if err != nil {
return config.NilValue, err
return dyn.NilValue, err
}
out[k] = merged
} else {
@ -76,23 +76,23 @@ func mergeMap(a, b config.Value) (config.Value, error) {
}
// Preserve the location of the first value.
return config.NewValue(out, a.Location()), nil
return dyn.NewValue(out, a.Location()), nil
}
func mergeSequence(a, b config.Value) (config.Value, error) {
func mergeSequence(a, b dyn.Value) (dyn.Value, error) {
as := a.MustSequence()
bs := b.MustSequence()
// Merging sequences means concatenating them.
out := make([]config.Value, len(as)+len(bs))
out := make([]dyn.Value, len(as)+len(bs))
copy(out[:], as)
copy(out[len(as):], bs)
// Preserve the location of the first value.
return config.NewValue(out, a.Location()), nil
return dyn.NewValue(out, a.Location()), nil
}
func mergePrimitive(a, b config.Value) (config.Value, error) {
func mergePrimitive(a, b dyn.Value) (dyn.Value, error) {
// Merging primitive values means using the incoming value.
return b, nil
}

View File

@ -3,19 +3,19 @@ package merge
import (
"testing"
"github.com/databricks/cli/libs/config"
"github.com/databricks/cli/libs/dyn"
"github.com/stretchr/testify/assert"
)
func TestMergeMaps(t *testing.T) {
v1 := config.V(map[string]config.Value{
"foo": config.V("bar"),
"bar": config.V("baz"),
v1 := dyn.V(map[string]dyn.Value{
"foo": dyn.V("bar"),
"bar": dyn.V("baz"),
})
v2 := config.V(map[string]config.Value{
"bar": config.V("qux"),
"qux": config.V("foo"),
v2 := dyn.V(map[string]dyn.Value{
"bar": dyn.V("qux"),
"qux": dyn.V("foo"),
})
// Merge v2 into v1.
@ -42,13 +42,13 @@ func TestMergeMaps(t *testing.T) {
}
func TestMergeMapsNil(t *testing.T) {
v := config.V(map[string]config.Value{
"foo": config.V("bar"),
v := dyn.V(map[string]dyn.Value{
"foo": dyn.V("bar"),
})
// Merge nil into v.
{
out, err := Merge(v, config.NilValue)
out, err := Merge(v, dyn.NilValue)
assert.NoError(t, err)
assert.Equal(t, map[string]any{
"foo": "bar",
@ -57,7 +57,7 @@ func TestMergeMapsNil(t *testing.T) {
// Merge v into nil.
{
out, err := Merge(config.NilValue, v)
out, err := Merge(dyn.NilValue, v)
assert.NoError(t, err)
assert.Equal(t, map[string]any{
"foo": "bar",
@ -66,29 +66,29 @@ func TestMergeMapsNil(t *testing.T) {
}
func TestMergeMapsError(t *testing.T) {
v := config.V(map[string]config.Value{
"foo": config.V("bar"),
v := dyn.V(map[string]dyn.Value{
"foo": dyn.V("bar"),
})
other := config.V("string")
other := dyn.V("string")
// Merge a string into v.
{
out, err := Merge(v, other)
assert.EqualError(t, err, "cannot merge map with string")
assert.Equal(t, config.NilValue, out)
assert.Equal(t, dyn.NilValue, out)
}
}
func TestMergeSequences(t *testing.T) {
v1 := config.V([]config.Value{
config.V("bar"),
config.V("baz"),
v1 := dyn.V([]dyn.Value{
dyn.V("bar"),
dyn.V("baz"),
})
v2 := config.V([]config.Value{
config.V("qux"),
config.V("foo"),
v2 := dyn.V([]dyn.Value{
dyn.V("qux"),
dyn.V("foo"),
})
// Merge v2 into v1.
@ -117,13 +117,13 @@ func TestMergeSequences(t *testing.T) {
}
func TestMergeSequencesNil(t *testing.T) {
v := config.V([]config.Value{
config.V("bar"),
v := dyn.V([]dyn.Value{
dyn.V("bar"),
})
// Merge nil into v.
{
out, err := Merge(v, config.NilValue)
out, err := Merge(v, dyn.NilValue)
assert.NoError(t, err)
assert.Equal(t, []any{
"bar",
@ -132,7 +132,7 @@ func TestMergeSequencesNil(t *testing.T) {
// Merge v into nil.
{
out, err := Merge(config.NilValue, v)
out, err := Merge(dyn.NilValue, v)
assert.NoError(t, err)
assert.Equal(t, []any{
"bar",
@ -141,23 +141,23 @@ func TestMergeSequencesNil(t *testing.T) {
}
func TestMergeSequencesError(t *testing.T) {
v := config.V([]config.Value{
config.V("bar"),
v := dyn.V([]dyn.Value{
dyn.V("bar"),
})
other := config.V("string")
other := dyn.V("string")
// Merge a string into v.
{
out, err := Merge(v, other)
assert.EqualError(t, err, "cannot merge sequence with string")
assert.Equal(t, config.NilValue, out)
assert.Equal(t, dyn.NilValue, out)
}
}
func TestMergePrimitives(t *testing.T) {
v1 := config.V("bar")
v2 := config.V("baz")
v1 := dyn.V("bar")
v2 := dyn.V("baz")
// Merge v2 into v1.
{
@ -175,33 +175,33 @@ func TestMergePrimitives(t *testing.T) {
}
func TestMergePrimitivesNil(t *testing.T) {
v := config.V("bar")
v := dyn.V("bar")
// Merge nil into v.
{
out, err := Merge(v, config.NilValue)
out, err := Merge(v, dyn.NilValue)
assert.NoError(t, err)
assert.Equal(t, "bar", out.AsAny())
}
// Merge v into nil.
{
out, err := Merge(config.NilValue, v)
out, err := Merge(dyn.NilValue, v)
assert.NoError(t, err)
assert.Equal(t, "bar", out.AsAny())
}
}
func TestMergePrimitivesError(t *testing.T) {
v := config.V("bar")
other := config.V(map[string]config.Value{
"foo": config.V("bar"),
v := dyn.V("bar")
other := dyn.V(map[string]dyn.Value{
"foo": dyn.V("bar"),
})
// Merge a map into v.
{
out, err := Merge(v, other)
assert.EqualError(t, err, "cannot merge string with map")
assert.Equal(t, config.NilValue, out)
assert.Equal(t, dyn.NilValue, out)
}
}

View File

@ -1,4 +1,4 @@
package config
package dyn
import (
"bytes"

View File

@ -1,4 +1,4 @@
package config
package dyn
import (
"fmt"

View File

@ -1,10 +1,10 @@
package config_test
package dyn_test
import (
"fmt"
"testing"
. "github.com/databricks/cli/libs/config"
. "github.com/databricks/cli/libs/dyn"
"github.com/stretchr/testify/assert"
)

76
libs/dyn/path_test.go Normal file
View File

@ -0,0 +1,76 @@
package dyn_test
import (
"testing"
"github.com/databricks/cli/libs/dyn"
"github.com/stretchr/testify/assert"
)
func TestPathAppend(t *testing.T) {
p := dyn.NewPath(dyn.Key("foo"))
// Single arg.
p1 := p.Append(dyn.Key("bar"))
assert.True(t, p1.Equal(dyn.NewPath(dyn.Key("foo"), dyn.Key("bar"))))
// Multiple args.
p2 := p.Append(dyn.Key("bar"), dyn.Index(1))
assert.True(t, p2.Equal(dyn.NewPath(dyn.Key("foo"), dyn.Key("bar"), dyn.Index(1))))
}
func TestPathJoin(t *testing.T) {
p := dyn.NewPath(dyn.Key("foo"))
// Single arg.
p1 := p.Join(dyn.NewPath(dyn.Key("bar")))
assert.True(t, p1.Equal(dyn.NewPath(dyn.Key("foo"), dyn.Key("bar"))))
// Multiple args.
p2 := p.Join(dyn.NewPath(dyn.Key("bar")), dyn.NewPath(dyn.Index(1)))
assert.True(t, p2.Equal(dyn.NewPath(dyn.Key("foo"), dyn.Key("bar"), dyn.Index(1))))
}
func TestPathEqualEmpty(t *testing.T) {
assert.True(t, dyn.EmptyPath.Equal(dyn.EmptyPath))
}
func TestPathEqual(t *testing.T) {
p1 := dyn.NewPath(dyn.Key("foo"), dyn.Index(1))
p2 := dyn.NewPath(dyn.Key("bar"), dyn.Index(2))
assert.False(t, p1.Equal(p2), "expected %q to not equal %q", p1, p2)
p3 := dyn.NewPath(dyn.Key("foo"), dyn.Index(1))
assert.True(t, p1.Equal(p3), "expected %q to equal %q", p1, p3)
p4 := dyn.NewPath(dyn.Key("foo"), dyn.Index(1), dyn.Key("bar"), dyn.Index(2))
assert.False(t, p1.Equal(p4), "expected %q to not equal %q", p1, p4)
}
func TestPathHasPrefixEmpty(t *testing.T) {
empty := dyn.EmptyPath
nonEmpty := dyn.NewPath(dyn.Key("foo"))
assert.True(t, empty.HasPrefix(empty))
assert.True(t, nonEmpty.HasPrefix(empty))
assert.False(t, empty.HasPrefix(nonEmpty))
}
func TestPathHasPrefix(t *testing.T) {
p1 := dyn.NewPath(dyn.Key("foo"), dyn.Index(1))
p2 := dyn.NewPath(dyn.Key("bar"), dyn.Index(2))
assert.False(t, p1.HasPrefix(p2), "expected %q to not have prefix %q", p1, p2)
p3 := dyn.NewPath(dyn.Key("foo"))
assert.True(t, p1.HasPrefix(p3), "expected %q to have prefix %q", p1, p3)
}
func TestPathString(t *testing.T) {
p1 := dyn.NewPath(dyn.Key("foo"), dyn.Index(1))
assert.Equal(t, "foo[1]", p1.String())
p2 := dyn.NewPath(dyn.Key("bar"), dyn.Index(2), dyn.Key("baz"))
assert.Equal(t, "bar[2].baz", p2.String())
p3 := dyn.NewPath(dyn.Key("foo"), dyn.Index(1), dyn.Key("bar"), dyn.Index(2), dyn.Key("baz"))
assert.Equal(t, "foo[1].bar[2].baz", p3.String())
}

View File

@ -1,4 +1,4 @@
package config
package dyn
import (
"fmt"

View File

@ -1,35 +1,35 @@
package config_test
package dyn_test
import (
"testing"
"github.com/databricks/cli/libs/config"
"github.com/databricks/cli/libs/dyn"
"github.com/stretchr/testify/assert"
)
func TestValueIsAnchor(t *testing.T) {
var zero config.Value
var zero dyn.Value
assert.False(t, zero.IsAnchor())
mark := zero.MarkAnchor()
assert.True(t, mark.IsAnchor())
}
func TestValueAsMap(t *testing.T) {
var zeroValue config.Value
var zeroValue dyn.Value
m, ok := zeroValue.AsMap()
assert.False(t, ok)
assert.Nil(t, m)
var intValue = config.NewValue(1, config.Location{})
var intValue = dyn.NewValue(1, dyn.Location{})
m, ok = intValue.AsMap()
assert.False(t, ok)
assert.Nil(t, m)
var mapValue = config.NewValue(
map[string]config.Value{
"key": config.NewValue("value", config.Location{File: "file", Line: 1, Column: 2}),
var mapValue = dyn.NewValue(
map[string]dyn.Value{
"key": dyn.NewValue("value", dyn.Location{File: "file", Line: 1, Column: 2}),
},
config.Location{File: "file", Line: 1, Column: 2},
dyn.Location{File: "file", Line: 1, Column: 2},
)
m, ok = mapValue.AsMap()
assert.True(t, ok)
@ -37,8 +37,8 @@ func TestValueAsMap(t *testing.T) {
}
func TestValueIsValid(t *testing.T) {
var zeroValue config.Value
var zeroValue dyn.Value
assert.False(t, zeroValue.IsValid())
var intValue = config.NewValue(1, config.Location{})
var intValue = dyn.NewValue(1, dyn.Location{})
assert.True(t, intValue.IsValid())
}

View File

@ -1,4 +1,4 @@
package config
package dyn
import "errors"

View File

@ -1,10 +1,10 @@
package config_test
package dyn_test
import (
"errors"
"testing"
. "github.com/databricks/cli/libs/config"
. "github.com/databricks/cli/libs/dyn"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

View File

@ -7,7 +7,7 @@ import (
"strings"
"time"
"github.com/databricks/cli/libs/config"
"github.com/databricks/cli/libs/dyn"
"gopkg.in/yaml.v3"
)
@ -15,7 +15,7 @@ type loader struct {
path string
}
func errorf(loc config.Location, format string, args ...interface{}) error {
func errorf(loc dyn.Location, format string, args ...interface{}) error {
return fmt.Errorf("yaml (%s): %s", loc, fmt.Sprintf(format, args...))
}
@ -25,22 +25,22 @@ func newLoader(path string) *loader {
}
}
func (d *loader) location(node *yaml.Node) config.Location {
return config.Location{
func (d *loader) location(node *yaml.Node) dyn.Location {
return dyn.Location{
File: d.path,
Line: node.Line,
Column: node.Column,
}
}
func (d *loader) load(node *yaml.Node) (config.Value, error) {
loc := config.Location{
func (d *loader) load(node *yaml.Node) (dyn.Value, error) {
loc := dyn.Location{
File: d.path,
Line: node.Line,
Column: node.Column,
}
var value config.Value
var value dyn.Value
var err error
switch node.Kind {
@ -55,7 +55,7 @@ func (d *loader) load(node *yaml.Node) (config.Value, error) {
case yaml.AliasNode:
value, err = d.loadAlias(node, loc)
default:
return config.NilValue, errorf(loc, "unknown node kind: %v", node.Kind)
return dyn.NilValue, errorf(loc, "unknown node kind: %v", node.Kind)
}
if err != nil {
@ -71,35 +71,35 @@ func (d *loader) load(node *yaml.Node) (config.Value, error) {
return value, nil
}
func (d *loader) loadDocument(node *yaml.Node, loc config.Location) (config.Value, error) {
func (d *loader) loadDocument(node *yaml.Node, loc dyn.Location) (dyn.Value, error) {
return d.load(node.Content[0])
}
func (d *loader) loadSequence(node *yaml.Node, loc config.Location) (config.Value, error) {
acc := make([]config.Value, len(node.Content))
func (d *loader) loadSequence(node *yaml.Node, loc dyn.Location) (dyn.Value, error) {
acc := make([]dyn.Value, len(node.Content))
for i, n := range node.Content {
v, err := d.load(n)
if err != nil {
return config.NilValue, err
return dyn.NilValue, err
}
acc[i] = v
}
return config.NewValue(acc, loc), nil
return dyn.NewValue(acc, loc), nil
}
func (d *loader) loadMapping(node *yaml.Node, loc config.Location) (config.Value, error) {
func (d *loader) loadMapping(node *yaml.Node, loc dyn.Location) (dyn.Value, error) {
var merge *yaml.Node
acc := make(map[string]config.Value)
acc := make(map[string]dyn.Value)
for i := 0; i < len(node.Content); i += 2 {
key := node.Content[i]
val := node.Content[i+1]
// Assert that keys are strings
if key.Kind != yaml.ScalarNode {
return config.NilValue, errorf(loc, "key is not a scalar")
return dyn.NilValue, errorf(loc, "key is not a scalar")
}
st := key.ShortTag()
@ -113,19 +113,19 @@ func (d *loader) loadMapping(node *yaml.Node, loc config.Location) (config.Value
merge = val
continue
default:
return config.NilValue, errorf(loc, "invalid key tag: %v", st)
return dyn.NilValue, errorf(loc, "invalid key tag: %v", st)
}
v, err := d.load(val)
if err != nil {
return config.NilValue, err
return dyn.NilValue, err
}
acc[key.Value] = v
}
if merge == nil {
return config.NewValue(acc, loc), nil
return dyn.NewValue(acc, loc), nil
}
// Build location for the merge node.
@ -141,68 +141,68 @@ func (d *loader) loadMapping(node *yaml.Node, loc config.Location) (config.Value
case yaml.AliasNode:
mnodes = []*yaml.Node{merge}
default:
return config.NilValue, merr
return dyn.NilValue, merr
}
// Build a sequence of values to merge.
// The entries that we already accumulated have precedence.
var seq []map[string]config.Value
var seq []map[string]dyn.Value
for _, n := range mnodes {
v, err := d.load(n)
if err != nil {
return config.NilValue, err
return dyn.NilValue, err
}
m, ok := v.AsMap()
if !ok {
return config.NilValue, merr
return dyn.NilValue, merr
}
seq = append(seq, m)
}
// Append the accumulated entries to the sequence.
seq = append(seq, acc)
out := make(map[string]config.Value)
out := make(map[string]dyn.Value)
for _, m := range seq {
for k, v := range m {
out[k] = v
}
}
return config.NewValue(out, loc), nil
return dyn.NewValue(out, loc), nil
}
func (d *loader) loadScalar(node *yaml.Node, loc config.Location) (config.Value, error) {
func (d *loader) loadScalar(node *yaml.Node, loc dyn.Location) (dyn.Value, error) {
st := node.ShortTag()
switch st {
case "!!str":
return config.NewValue(node.Value, loc), nil
return dyn.NewValue(node.Value, loc), nil
case "!!bool":
switch strings.ToLower(node.Value) {
case "true":
return config.NewValue(true, loc), nil
return dyn.NewValue(true, loc), nil
case "false":
return config.NewValue(false, loc), nil
return dyn.NewValue(false, loc), nil
default:
return config.NilValue, errorf(loc, "invalid bool value: %v", node.Value)
return dyn.NilValue, errorf(loc, "invalid bool value: %v", node.Value)
}
case "!!int":
i64, err := strconv.ParseInt(node.Value, 10, 64)
if err != nil {
return config.NilValue, errorf(loc, "invalid int value: %v", node.Value)
return dyn.NilValue, errorf(loc, "invalid int value: %v", node.Value)
}
// Use regular int type instead of int64 if possible.
if i64 >= math.MinInt32 && i64 <= math.MaxInt32 {
return config.NewValue(int(i64), loc), nil
return dyn.NewValue(int(i64), loc), nil
}
return config.NewValue(i64, loc), nil
return dyn.NewValue(i64, loc), nil
case "!!float":
f64, err := strconv.ParseFloat(node.Value, 64)
if err != nil {
return config.NilValue, errorf(loc, "invalid float value: %v", node.Value)
return dyn.NilValue, errorf(loc, "invalid float value: %v", node.Value)
}
return config.NewValue(f64, loc), nil
return dyn.NewValue(f64, loc), nil
case "!!null":
return config.NewValue(nil, loc), nil
return dyn.NewValue(nil, loc), nil
case "!!timestamp":
// Try a couple of layouts
for _, layout := range []string{
@ -213,15 +213,15 @@ func (d *loader) loadScalar(node *yaml.Node, loc config.Location) (config.Value,
} {
t, terr := time.Parse(layout, node.Value)
if terr == nil {
return config.NewValue(t, loc), nil
return dyn.NewValue(t, loc), nil
}
}
return config.NilValue, errorf(loc, "invalid timestamp value: %v", node.Value)
return dyn.NilValue, errorf(loc, "invalid timestamp value: %v", node.Value)
default:
return config.NilValue, errorf(loc, "unknown tag: %v", st)
return dyn.NilValue, errorf(loc, "unknown tag: %v", st)
}
}
func (d *loader) loadAlias(node *yaml.Node, loc config.Location) (config.Value, error) {
func (d *loader) loadAlias(node *yaml.Node, loc dyn.Location) (dyn.Value, error) {
return d.load(node.Alias)
}

View File

@ -3,19 +3,19 @@ package yamlloader
import (
"io"
"github.com/databricks/cli/libs/config"
"github.com/databricks/cli/libs/dyn"
"gopkg.in/yaml.v3"
)
func LoadYAML(path string, r io.Reader) (config.Value, error) {
func LoadYAML(path string, r io.Reader) (dyn.Value, error) {
var node yaml.Node
dec := yaml.NewDecoder(r)
err := dec.Decode(&node)
if err != nil {
if err == io.EOF {
return config.NilValue, nil
return dyn.NilValue, nil
}
return config.NilValue, err
return dyn.NilValue, err
}
return newLoader(path).load(&node)

View File

@ -3,14 +3,14 @@ package yamlloader_test
import (
"testing"
"github.com/databricks/cli/libs/config"
"github.com/databricks/cli/libs/dyn"
"github.com/stretchr/testify/assert"
)
func TestYAMLAnchor01(t *testing.T) {
file := "testdata/anchor_01.yml"
self := loadYAML(t, file)
assert.NotEqual(t, config.NilValue, self)
assert.NotEqual(t, dyn.NilValue, self)
assert.True(t, self.Get("defaults").IsAnchor())
assert.False(t, self.Get("shirt1").IsAnchor())
@ -18,31 +18,31 @@ func TestYAMLAnchor01(t *testing.T) {
pattern := self.Get("shirt1").Get("pattern")
assert.Equal(t, "striped", pattern.AsAny())
assert.Equal(t, config.Location{File: file, Line: 8, Column: 12}, pattern.Location())
assert.Equal(t, dyn.Location{File: file, Line: 8, Column: 12}, pattern.Location())
}
func TestYAMLAnchor02(t *testing.T) {
file := "testdata/anchor_02.yml"
self := loadYAML(t, file)
assert.NotEqual(t, config.NilValue, self)
assert.NotEqual(t, dyn.NilValue, self)
color := self.Get("shirt").Get("color")
assert.Equal(t, "red", color.AsAny())
assert.Equal(t, config.Location{File: file, Line: 4, Column: 10}, color.Location())
assert.Equal(t, dyn.Location{File: file, Line: 4, Column: 10}, color.Location())
primary := self.Get("shirt").Get("primary")
assert.Equal(t, "cotton", primary.AsAny())
assert.Equal(t, config.Location{File: file, Line: 8, Column: 12}, primary.Location())
assert.Equal(t, dyn.Location{File: file, Line: 8, Column: 12}, primary.Location())
pattern := self.Get("shirt").Get("pattern")
assert.Equal(t, "striped", pattern.AsAny())
assert.Equal(t, config.Location{File: file, Line: 13, Column: 12}, pattern.Location())
assert.Equal(t, dyn.Location{File: file, Line: 13, Column: 12}, pattern.Location())
}
func TestYAMLAnchor03(t *testing.T) {
file := "testdata/anchor_03.yml"
self := loadYAML(t, file)
assert.NotEqual(t, config.NilValue, self)
assert.NotEqual(t, dyn.NilValue, self)
// Assert the override took place.
blue := self.Get("shirt").Get("color")
@ -55,63 +55,63 @@ func TestYAMLAnchor03(t *testing.T) {
func TestYAMLAnchor04(t *testing.T) {
file := "testdata/anchor_04.yml"
self := loadYAML(t, file)
assert.NotEqual(t, config.NilValue, self)
assert.NotEqual(t, dyn.NilValue, self)
p1 := self.Get("person1").Get("address").Get("city")
assert.Equal(t, "San Francisco", p1.AsAny())
assert.Equal(t, config.Location{File: file, Line: 4, Column: 9}, p1.Location())
assert.Equal(t, dyn.Location{File: file, Line: 4, Column: 9}, p1.Location())
p2 := self.Get("person2").Get("address").Get("city")
assert.Equal(t, "Los Angeles", p2.AsAny())
assert.Equal(t, config.Location{File: file, Line: 16, Column: 11}, p2.Location())
assert.Equal(t, dyn.Location{File: file, Line: 16, Column: 11}, p2.Location())
}
func TestYAMLAnchor05(t *testing.T) {
file := "testdata/anchor_05.yml"
self := loadYAML(t, file)
assert.NotEqual(t, config.NilValue, self)
assert.NotEqual(t, dyn.NilValue, self)
features := self.Get("phone1").Get("features")
assert.Equal(t, "wifi", features.Index(0).AsAny())
assert.Equal(t, config.Location{File: file, Line: 4, Column: 5}, features.Index(0).Location())
assert.Equal(t, dyn.Location{File: file, Line: 4, Column: 5}, features.Index(0).Location())
assert.Equal(t, "bluetooth", features.Index(1).AsAny())
assert.Equal(t, config.Location{File: file, Line: 5, Column: 5}, features.Index(1).Location())
assert.Equal(t, dyn.Location{File: file, Line: 5, Column: 5}, features.Index(1).Location())
}
func TestYAMLAnchor06(t *testing.T) {
file := "testdata/anchor_06.yml"
self := loadYAML(t, file)
assert.NotEqual(t, config.NilValue, self)
assert.NotEqual(t, dyn.NilValue, self)
greeting := self.Get("greeting1")
assert.Equal(t, "Hello, World!", greeting.AsAny())
assert.Equal(t, config.Location{File: file, Line: 2, Column: 16}, greeting.Location())
assert.Equal(t, dyn.Location{File: file, Line: 2, Column: 16}, greeting.Location())
}
func TestYAMLAnchor07(t *testing.T) {
file := "testdata/anchor_07.yml"
self := loadYAML(t, file)
assert.NotEqual(t, config.NilValue, self)
assert.NotEqual(t, dyn.NilValue, self)
name := self.Get("person1").Get("name")
assert.Equal(t, "Alice", name.AsAny())
assert.Equal(t, config.Location{File: file, Line: 5, Column: 9}, name.Location())
assert.Equal(t, dyn.Location{File: file, Line: 5, Column: 9}, name.Location())
age := self.Get("person1").Get("age")
assert.Equal(t, 25, age.AsAny())
assert.Equal(t, config.Location{File: file, Line: 2, Column: 13}, age.Location())
assert.Equal(t, dyn.Location{File: file, Line: 2, Column: 13}, age.Location())
}
func TestYAMLAnchor08(t *testing.T) {
file := "testdata/anchor_08.yml"
self := loadYAML(t, file)
assert.NotEqual(t, config.NilValue, self)
assert.NotEqual(t, dyn.NilValue, self)
username := self.Get("user1").Get("username")
assert.Equal(t, "user1", username.AsAny())
assert.Equal(t, config.Location{File: file, Line: 5, Column: 13}, username.Location())
assert.Equal(t, dyn.Location{File: file, Line: 5, Column: 13}, username.Location())
active := self.Get("user1").Get("active")
assert.Equal(t, true, active.AsAny())
assert.Equal(t, config.Location{File: file, Line: 2, Column: 11}, active.Location())
assert.Equal(t, dyn.Location{File: file, Line: 2, Column: 11}, active.Location())
}

View File

@ -5,7 +5,7 @@ import (
"os"
"testing"
"github.com/databricks/cli/libs/config/yamlloader"
"github.com/databricks/cli/libs/dyn/yamlloader"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gopkg.in/yaml.v3"

View File

@ -3,14 +3,14 @@ package yamlloader_test
import (
"testing"
"github.com/databricks/cli/libs/config"
"github.com/databricks/cli/libs/dyn"
"github.com/stretchr/testify/assert"
)
func TestYAMLMix01(t *testing.T) {
file := "testdata/mix_01.yml"
self := loadYAML(t, file)
assert.NotEqual(t, config.NilValue, self)
assert.NotEqual(t, dyn.NilValue, self)
assert.True(t, self.Get("base_address").IsAnchor())
assert.False(t, self.Get("office_address").IsAnchor())
@ -19,7 +19,7 @@ func TestYAMLMix01(t *testing.T) {
func TestYAMLMix02(t *testing.T) {
file := "testdata/mix_02.yml"
self := loadYAML(t, file)
assert.NotEqual(t, config.NilValue, self)
assert.NotEqual(t, dyn.NilValue, self)
assert.True(t, self.Get("base_colors").IsAnchor())
assert.False(t, self.Get("theme").IsAnchor())

View File

@ -5,14 +5,14 @@ import (
"os"
"testing"
"github.com/databricks/cli/libs/config"
"github.com/databricks/cli/libs/config/yamlloader"
"github.com/databricks/cli/libs/dyn"
"github.com/databricks/cli/libs/dyn/yamlloader"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gopkg.in/yaml.v3"
)
func loadYAML(t *testing.T, path string) config.Value {
func loadYAML(t *testing.T, path string) dyn.Value {
input, err := os.ReadFile(path)
require.NoError(t, err)
@ -31,5 +31,5 @@ func loadYAML(t *testing.T, path string) config.Value {
func TestYAMLEmpty(t *testing.T) {
self := loadYAML(t, "testdata/empty.yml")
assert.Equal(t, config.NilValue, self)
assert.Equal(t, dyn.NilValue, self)
}