Files
trivy/pkg/iac/terraform/context/context_test.go
2024-08-08 22:09:36 +00:00

276 lines
7.1 KiB
Go

package context
import (
"testing"
"github.com/hashicorp/hcl/v2"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/gocty"
)
func Test_ContextVariables(t *testing.T) {
underlying := &hcl.EvalContext{}
ctx := NewContext(underlying, nil)
val, err := gocty.ToCtyValue("hello", cty.String)
if err != nil {
t.Fatal(err)
}
ctx.Set(val, "my", "value")
value := underlying.Variables["my"].AsValueMap()["value"]
assert.Equal(t, "hello", value.AsString())
}
func Test_ContextVariablesPreservation(t *testing.T) {
underlying := &hcl.EvalContext{}
underlying.Variables = make(map[string]cty.Value)
underlying.Variables["x"], _ = gocty.ToCtyValue("does it work?", cty.String)
str, _ := gocty.ToCtyValue("something", cty.String)
underlying.Variables["my"] = cty.ObjectVal(map[string]cty.Value{
"other": str,
"obj": cty.ObjectVal(map[string]cty.Value{
"another": str,
}),
})
ctx := NewContext(underlying, nil)
val, err := gocty.ToCtyValue("hello", cty.String)
if err != nil {
t.Fatal(err)
}
ctx.Set(val, "my", "value")
assert.Equal(t, "hello", underlying.Variables["my"].AsValueMap()["value"].AsString())
assert.Equal(t, "something", underlying.Variables["my"].AsValueMap()["other"].AsString())
assert.Equal(t, "something", underlying.Variables["my"].AsValueMap()["obj"].AsValueMap()["another"].AsString())
assert.Equal(t, "does it work?", underlying.Variables["x"].AsString())
}
func Test_SetWithMerge(t *testing.T) {
hctx := hcl.EvalContext{
Variables: map[string]cty.Value{
"my": cty.ObjectVal(map[string]cty.Value{
"someValue": cty.ObjectVal(map[string]cty.Value{
"foo": cty.StringVal("test"),
"bar": cty.ObjectVal(map[string]cty.Value{
"foo": cty.StringVal("test"),
}),
}),
}),
},
}
ctx := NewContext(&hctx, nil)
val := cty.ObjectVal(map[string]cty.Value{
"foo2": cty.StringVal("test2"),
"bar": cty.ObjectVal(map[string]cty.Value{
"foo2": cty.StringVal("test2"),
}),
})
ctx.Set(val, "my", "someValue")
got := ctx.Get("my", "someValue")
expected := cty.ObjectVal(map[string]cty.Value{
"foo": cty.StringVal("test"),
"foo2": cty.StringVal("test2"),
"bar": cty.ObjectVal(map[string]cty.Value{
"foo": cty.StringVal("test"),
"foo2": cty.StringVal("test2"),
}),
})
assert.Equal(t, expected, got)
}
func Test_ContextVariablesPreservationByDot(t *testing.T) {
underlying := &hcl.EvalContext{}
underlying.Variables = make(map[string]cty.Value)
underlying.Variables["x"], _ = gocty.ToCtyValue("does it work?", cty.String)
str, _ := gocty.ToCtyValue("something", cty.String)
underlying.Variables["my"] = cty.ObjectVal(map[string]cty.Value{
"other": str,
"obj": cty.ObjectVal(map[string]cty.Value{
"another": str,
}),
})
ctx := NewContext(underlying, nil)
val, err := gocty.ToCtyValue("hello", cty.String)
if err != nil {
t.Fatal(err)
}
ctx.SetByDot(val, "my.something.value")
assert.Equal(t, "hello", underlying.Variables["my"].AsValueMap()["something"].AsValueMap()["value"].AsString())
assert.Equal(t, "something", underlying.Variables["my"].AsValueMap()["other"].AsString())
assert.Equal(t, "something", underlying.Variables["my"].AsValueMap()["obj"].AsValueMap()["another"].AsString())
assert.Equal(t, "does it work?", underlying.Variables["x"].AsString())
}
func Test_ContextSetThenImmediateGet(t *testing.T) {
underlying := &hcl.EvalContext{}
ctx := NewContext(underlying, nil)
ctx.Set(cty.ObjectVal(map[string]cty.Value{
"mod_result": cty.StringVal("ok"),
}), "module", "modulename")
val := ctx.Get("module", "modulename", "mod_result")
assert.Equal(t, "ok", val.AsString())
}
func Test_ContextSetThenImmediateGetWithChild(t *testing.T) {
underlying := &hcl.EvalContext{}
ctx := NewContext(underlying, nil)
childCtx := ctx.NewChild()
childCtx.Root().Set(cty.ObjectVal(map[string]cty.Value{
"mod_result": cty.StringVal("ok"),
}), "module", "modulename")
val := ctx.Get("module", "modulename", "mod_result")
assert.Equal(t, "ok", val.AsString())
}
func Test_MergeObjects(t *testing.T) {
tests := []struct {
name string
oldVal cty.Value
newVal cty.Value
expected cty.Value
}{
{
name: "happy",
oldVal: cty.ObjectVal(map[string]cty.Value{
"this": cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("some_id"),
"arn": cty.StringVal("some_arn"),
}),
}),
newVal: cty.ObjectVal(map[string]cty.Value{
"this": cty.ObjectVal(map[string]cty.Value{
"arn": cty.StringVal("some_new_arn"),
"bucket": cty.StringVal("test"),
}),
}),
expected: cty.ObjectVal(map[string]cty.Value{
"this": cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("some_id"),
"arn": cty.StringVal("some_new_arn"),
"bucket": cty.StringVal("test"),
}),
}),
},
{
name: "old value is empty",
oldVal: cty.EmptyObjectVal,
newVal: cty.ObjectVal(map[string]cty.Value{
"this": cty.ObjectVal(map[string]cty.Value{
"bucket": cty.StringVal("test"),
}),
}),
expected: cty.ObjectVal(map[string]cty.Value{
"this": cty.ObjectVal(map[string]cty.Value{
"bucket": cty.StringVal("test"),
}),
}),
},
{
name: "new value is empty",
oldVal: cty.ObjectVal(map[string]cty.Value{
"this": cty.ObjectVal(map[string]cty.Value{
"bucket": cty.StringVal("test"),
}),
}),
newVal: cty.EmptyObjectVal,
expected: cty.ObjectVal(map[string]cty.Value{
"this": cty.ObjectVal(map[string]cty.Value{
"bucket": cty.StringVal("test"),
}),
}),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.expected, mergeObjects(tt.oldVal, tt.newVal))
})
}
}
func Test_IsNotEmptyObject(t *testing.T) {
tests := []struct {
name string
val cty.Value
expected bool
}{
{
name: "happy",
val: cty.ObjectVal(map[string]cty.Value{
"field": cty.NilVal,
}),
expected: true,
},
{
name: "empty object",
val: cty.EmptyObjectVal,
expected: false,
},
{
name: "nil value",
val: cty.NilVal,
expected: false,
},
{
name: "dynamic value",
val: cty.DynamicVal,
expected: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.expected, isNotEmptyObject(tt.val))
})
}
}
func TestReplace(t *testing.T) {
t.Run("replacement of an existing value", func(t *testing.T) {
underlying := &hcl.EvalContext{}
ctx := NewContext(underlying, nil)
ctx.SetByDot(cty.StringVal("some-value"), "my.value")
require.NotEqual(t, cty.NilVal, ctx.GetByDot("my.value"))
ctx.Replace(cty.NumberIntVal(-1), "my.value")
assert.Equal(t, cty.NumberIntVal(-1), ctx.GetByDot("my.value"))
})
t.Run("replacement of a non-existing value", func(t *testing.T) {
underlying := &hcl.EvalContext{}
ctx := NewContext(underlying, nil)
ctx.Replace(cty.NumberIntVal(-1), "my.value")
assert.Equal(t, cty.NumberIntVal(-1), ctx.GetByDot("my.value"))
})
t.Run("empty path", func(t *testing.T) {
underlying := &hcl.EvalContext{}
ctx := NewContext(underlying, nil)
ctx.Replace(cty.NumberIntVal(-1), "")
})
}