2023-12-22 13:20:45 +00:00
|
|
|
package dyn_test
|
2023-12-22 10:38:09 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"testing"
|
|
|
|
|
2023-12-22 13:20:45 +00:00
|
|
|
. "github.com/databricks/cli/libs/dyn"
|
2023-12-22 10:38:09 +00:00
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Return values for specific paths.
|
|
|
|
type walkReturn struct {
|
|
|
|
path Path
|
|
|
|
|
|
|
|
// Return values.
|
|
|
|
fn func(Value) Value
|
|
|
|
err error
|
|
|
|
}
|
|
|
|
|
|
|
|
// Track the calls to the callback.
|
|
|
|
type walkCall struct {
|
|
|
|
path Path
|
|
|
|
value Value
|
|
|
|
}
|
|
|
|
|
|
|
|
// Track the calls to the callback.
|
|
|
|
type walkCallTracker struct {
|
|
|
|
returns []walkReturn
|
|
|
|
calls []walkCall
|
|
|
|
}
|
|
|
|
|
|
|
|
func (w *walkCallTracker) on(path string, fn func(Value) Value, err error) {
|
|
|
|
w.returns = append(w.returns, walkReturn{MustPathFromString(path), fn, err})
|
|
|
|
}
|
|
|
|
|
|
|
|
func (w *walkCallTracker) returnSkip(path string) {
|
|
|
|
w.on(path, func(v Value) Value { return v }, ErrSkip)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (w *walkCallTracker) returnDrop(path string) {
|
|
|
|
w.on(path, func(v Value) Value { return NilValue }, ErrDrop)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (w *walkCallTracker) track(p Path, v Value) (Value, error) {
|
|
|
|
w.calls = append(w.calls, walkCall{p, v})
|
|
|
|
|
|
|
|
// Look for matching return.
|
|
|
|
for _, r := range w.returns {
|
|
|
|
if p.Equal(r.path) {
|
|
|
|
return r.fn(v), r.err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return v, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestWalkEmpty(t *testing.T) {
|
|
|
|
var tracker walkCallTracker
|
|
|
|
|
|
|
|
value := V(nil)
|
|
|
|
out, err := Walk(value, tracker.track)
|
|
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, value, out)
|
|
|
|
|
|
|
|
// The callback should have been called once.
|
|
|
|
assert.Len(t, tracker.calls, 1)
|
|
|
|
|
|
|
|
// The call should have been made with the empty path.
|
|
|
|
assert.Equal(t, EmptyPath, tracker.calls[0].path)
|
|
|
|
|
|
|
|
// The value should be the same as the input.
|
|
|
|
assert.Equal(t, value, tracker.calls[0].value)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestWalkMapSkip(t *testing.T) {
|
|
|
|
var tracker walkCallTracker
|
|
|
|
|
|
|
|
// Skip traversal of the root value.
|
|
|
|
tracker.returnSkip(".")
|
|
|
|
|
|
|
|
value := V(map[string]Value{
|
|
|
|
"key": V("value"),
|
|
|
|
})
|
|
|
|
out, err := Walk(value, tracker.track)
|
|
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(
|
|
|
|
t,
|
|
|
|
V(map[string]Value{
|
|
|
|
"key": V("value"),
|
|
|
|
}),
|
|
|
|
out,
|
|
|
|
)
|
|
|
|
|
|
|
|
// The callback should have been called once.
|
|
|
|
assert.Len(t, tracker.calls, 1)
|
|
|
|
|
|
|
|
// The call should have been made with the empty path.
|
|
|
|
assert.Equal(t, EmptyPath, tracker.calls[0].path)
|
|
|
|
|
|
|
|
// The value should be the same as the input.
|
|
|
|
assert.Equal(t, value, tracker.calls[0].value)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestWalkMapDrop(t *testing.T) {
|
|
|
|
var tracker walkCallTracker
|
|
|
|
|
|
|
|
// Drop the value at key "foo".
|
|
|
|
tracker.returnDrop(".foo")
|
|
|
|
|
|
|
|
value := V(map[string]Value{
|
|
|
|
"foo": V("bar"),
|
|
|
|
"bar": V("baz"),
|
|
|
|
})
|
|
|
|
out, err := Walk(value, tracker.track)
|
|
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(
|
|
|
|
t,
|
|
|
|
V(map[string]Value{
|
|
|
|
"bar": V("baz"),
|
|
|
|
}),
|
|
|
|
out,
|
|
|
|
)
|
|
|
|
|
|
|
|
// The callback should have been called for the root and every key in the map.
|
|
|
|
assert.Len(t, tracker.calls, 3)
|
|
|
|
|
|
|
|
// Calls 2 and 3 have been made for the keys in the map.
|
|
|
|
assert.ElementsMatch(t,
|
|
|
|
[]Path{
|
|
|
|
tracker.calls[1].path,
|
|
|
|
tracker.calls[2].path,
|
|
|
|
}, []Path{
|
|
|
|
MustPathFromString(".foo"),
|
|
|
|
MustPathFromString(".bar"),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestWalkMapError(t *testing.T) {
|
|
|
|
var tracker walkCallTracker
|
|
|
|
|
|
|
|
// Return an error from the callback for key "foo".
|
|
|
|
cerr := errors.New("error!")
|
|
|
|
tracker.on(".foo", func(v Value) Value { return v }, cerr)
|
|
|
|
|
|
|
|
value := V(map[string]Value{
|
|
|
|
"foo": V("bar"),
|
|
|
|
})
|
|
|
|
out, err := Walk(value, tracker.track)
|
|
|
|
assert.Equal(t, cerr, err)
|
|
|
|
assert.Equal(t, NilValue, out)
|
|
|
|
|
|
|
|
// The callback should have been called twice.
|
|
|
|
assert.Len(t, tracker.calls, 2)
|
|
|
|
|
|
|
|
// The second call was for the value at key "foo".
|
|
|
|
assert.Equal(t, MustPathFromString(".foo"), tracker.calls[1].path)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestWalkSequenceSkip(t *testing.T) {
|
|
|
|
var tracker walkCallTracker
|
|
|
|
|
|
|
|
// Skip traversal of the root value.
|
|
|
|
tracker.returnSkip(".")
|
|
|
|
|
|
|
|
value := V([]Value{
|
|
|
|
V("foo"),
|
|
|
|
V("bar"),
|
|
|
|
})
|
|
|
|
out, err := Walk(value, tracker.track)
|
|
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(
|
|
|
|
t,
|
|
|
|
V([]Value{
|
|
|
|
V("foo"),
|
|
|
|
V("bar"),
|
|
|
|
}),
|
|
|
|
out,
|
|
|
|
)
|
|
|
|
|
|
|
|
// The callback should have been called once.
|
|
|
|
assert.Len(t, tracker.calls, 1)
|
|
|
|
|
|
|
|
// The call should have been made with the empty path.
|
|
|
|
assert.Equal(t, EmptyPath, tracker.calls[0].path)
|
|
|
|
|
|
|
|
// The value should be the same as the input.
|
|
|
|
assert.Equal(t, value, tracker.calls[0].value)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestWalkSequenceDrop(t *testing.T) {
|
|
|
|
var tracker walkCallTracker
|
|
|
|
|
|
|
|
// Drop the value at index 1.
|
|
|
|
tracker.returnDrop(".[1]")
|
|
|
|
|
|
|
|
value := V([]Value{
|
|
|
|
V("foo"),
|
|
|
|
V("bar"),
|
|
|
|
V("baz"),
|
|
|
|
})
|
|
|
|
out, err := Walk(value, tracker.track)
|
|
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(
|
|
|
|
t,
|
|
|
|
V([]Value{
|
|
|
|
V("foo"),
|
|
|
|
V("baz"),
|
|
|
|
}),
|
|
|
|
out,
|
|
|
|
)
|
|
|
|
|
|
|
|
// The callback should have been called for the root and every value in the sequence.
|
|
|
|
assert.Len(t, tracker.calls, 4)
|
|
|
|
|
|
|
|
// The second call was for the value at index 0.
|
|
|
|
assert.Equal(t, MustPathFromString(".[0]"), tracker.calls[1].path)
|
|
|
|
assert.Equal(t, V("foo"), tracker.calls[1].value)
|
|
|
|
|
|
|
|
// The third call was for the value at index 1.
|
|
|
|
assert.Equal(t, MustPathFromString(".[1]"), tracker.calls[2].path)
|
|
|
|
assert.Equal(t, V("bar"), tracker.calls[2].value)
|
|
|
|
|
|
|
|
// The fourth call was for the value at index 2.
|
|
|
|
assert.Equal(t, MustPathFromString(".[2]"), tracker.calls[3].path)
|
|
|
|
assert.Equal(t, V("baz"), tracker.calls[3].value)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestWalkSequenceError(t *testing.T) {
|
|
|
|
var tracker walkCallTracker
|
|
|
|
|
|
|
|
// Return an error from the callback for index 1.
|
|
|
|
cerr := errors.New("error!")
|
|
|
|
tracker.on(".[1]", func(v Value) Value { return v }, cerr)
|
|
|
|
|
|
|
|
value := V([]Value{
|
|
|
|
V("foo"),
|
|
|
|
V("bar"),
|
|
|
|
})
|
|
|
|
out, err := Walk(value, tracker.track)
|
|
|
|
assert.Equal(t, cerr, err)
|
|
|
|
assert.Equal(t, NilValue, out)
|
|
|
|
|
|
|
|
// The callback should have been called three times.
|
|
|
|
assert.Len(t, tracker.calls, 3)
|
|
|
|
|
|
|
|
// The second call was for the value at index 0.
|
|
|
|
assert.Equal(t, MustPathFromString(".[0]"), tracker.calls[1].path)
|
|
|
|
assert.Equal(t, V("foo"), tracker.calls[1].value)
|
|
|
|
|
|
|
|
// The third call was for the value at index 1.
|
|
|
|
assert.Equal(t, MustPathFromString(".[1]"), tracker.calls[2].path)
|
|
|
|
assert.Equal(t, V("bar"), tracker.calls[2].value)
|
|
|
|
}
|