diff --git a/hcltest/mock.go b/hcltest/mock.go index 9e3a746..5f5e82c 100644 --- a/hcltest/mock.go +++ b/hcltest/mock.go @@ -166,6 +166,24 @@ func (e mockExprLiteral) ExprList() []hcl.Expression { return nil } +// Implementation for hcl.ExprMap +func (e mockExprLiteral) ExprMap() []hcl.KeyValuePair { + v := e.V + ty := v.Type() + if v.IsKnown() && !v.IsNull() && (ty.IsObjectType() || ty.IsMapType()) { + ret := make([]hcl.KeyValuePair, 0, v.LengthInt()) + for it := v.ElementIterator(); it.Next(); { + k, v := it.Element() + ret = append(ret, hcl.KeyValuePair{ + Key: MockExprLiteral(k), + Value: MockExprLiteral(v), + }) + } + return ret + } + return nil +} + // MockExprVariable returns a hcl.Expression that evaluates to the value of // the variable with the given name. func MockExprVariable(name string) hcl.Expression { diff --git a/hcltest/mock_test.go b/hcltest/mock_test.go index 6d823f9..5b01d02 100644 --- a/hcltest/mock_test.go +++ b/hcltest/mock_test.go @@ -1,6 +1,7 @@ package hcltest import ( + "strings" "testing" "reflect" @@ -266,3 +267,129 @@ func TestMockBodyPartialContent(t *testing.T) { }) } } + +func TestExprList(t *testing.T) { + tests := map[string]struct { + In hcl.Expression + Want []hcl.Expression + Diags string + }{ + "as list": { + In: MockExprLiteral(cty.ListVal([]cty.Value{ + cty.StringVal("foo"), + cty.StringVal("bar"), + })), + Want: []hcl.Expression{ + MockExprLiteral(cty.StringVal("foo")), + MockExprLiteral(cty.StringVal("bar")), + }, + }, + "as tuple": { + In: MockExprLiteral(cty.TupleVal([]cty.Value{ + cty.StringVal("foo"), + cty.StringVal("bar"), + })), + Want: []hcl.Expression{ + MockExprLiteral(cty.StringVal("foo")), + MockExprLiteral(cty.StringVal("bar")), + }, + }, + "not list": { + In: MockExprLiteral(cty.ObjectVal(map[string]cty.Value{ + "a": cty.StringVal("foo"), + "b": cty.StringVal("bar"), + })), + Want: nil, + Diags: "list expression is required", + }, + } + + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + got, diags := hcl.ExprList(tc.In) + if tc.Diags != "" { + if diags.HasErrors() && !strings.Contains(diags.Error(), tc.Diags) { + t.Errorf("expected error %q, got %q", tc.Diags, diags) + } + if !diags.HasErrors() { + t.Errorf("expected diagnostic message %q", tc.Diags) + } + } else if diags.HasErrors() { + t.Error(diags) + } + + if !reflect.DeepEqual(got, tc.Want) { + t.Errorf("incorrect expression,\ngot: %#v\nwant: %#v", got, tc.Want) + } + }) + } +} + +func TestExprMap(t *testing.T) { + tests := map[string]struct { + In hcl.Expression + Want []hcl.KeyValuePair + Diags string + }{ + "as object": { + In: MockExprLiteral(cty.ObjectVal(map[string]cty.Value{ + "name": cty.StringVal("test"), + "count": cty.NumberIntVal(2), + })), + Want: []hcl.KeyValuePair{ + { + Key: MockExprLiteral(cty.StringVal("count")), + Value: MockExprLiteral(cty.NumberIntVal(2)), + }, + { + Key: MockExprLiteral(cty.StringVal("name")), + Value: MockExprLiteral(cty.StringVal("test")), + }, + }, + }, + "as map": { + In: MockExprLiteral(cty.MapVal(map[string]cty.Value{ + "name": cty.StringVal("test"), + "version": cty.StringVal("2.0.0"), + })), + Want: []hcl.KeyValuePair{ + { + Key: MockExprLiteral(cty.StringVal("name")), + Value: MockExprLiteral(cty.StringVal("test")), + }, + { + Key: MockExprLiteral(cty.StringVal("version")), + Value: MockExprLiteral(cty.StringVal("2.0.0")), + }, + }, + }, + "not map": { + In: MockExprLiteral(cty.ListVal([]cty.Value{ + cty.StringVal("foo"), + cty.StringVal("bar"), + })), + Want: nil, + Diags: "map expression is required", + }, + } + + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + got, diags := hcl.ExprMap(tc.In) + if tc.Diags != "" { + if diags.HasErrors() && !strings.Contains(diags.Error(), tc.Diags) { + t.Errorf("expected error %q, got %q", tc.Diags, diags) + } + if !diags.HasErrors() { + t.Errorf("expected diagnostic message %q", tc.Diags) + } + } else if diags.HasErrors() { + t.Error(diags) + } + + if !reflect.DeepEqual(got, tc.Want) { + t.Errorf("incorrect expression,\ngot: %#v\nwant: %#v", got, tc.Want) + } + }) + } +}