2017-09-11 23:00:31 +00:00
|
|
|
package hcltest
|
2017-07-27 22:59:32 +00:00
|
|
|
|
|
|
|
import (
|
2021-02-08 14:17:28 +00:00
|
|
|
"strings"
|
2017-07-27 22:59:32 +00:00
|
|
|
"testing"
|
|
|
|
|
|
|
|
"reflect"
|
|
|
|
|
2019-09-09 23:08:19 +00:00
|
|
|
"github.com/hashicorp/hcl/v2"
|
2017-07-27 22:59:32 +00:00
|
|
|
"github.com/zclconf/go-cty/cty"
|
|
|
|
)
|
|
|
|
|
2017-09-11 23:40:37 +00:00
|
|
|
var mockBodyIsBody hcl.Body = mockBody{}
|
|
|
|
var mockExprLiteralIsExpr hcl.Expression = mockExprLiteral{}
|
|
|
|
var mockExprVariableIsExpr hcl.Expression = mockExprVariable("")
|
2017-07-27 22:59:32 +00:00
|
|
|
|
|
|
|
func TestMockBodyPartialContent(t *testing.T) {
|
|
|
|
tests := map[string]struct {
|
2017-09-11 23:40:37 +00:00
|
|
|
In *hcl.BodyContent
|
|
|
|
Schema *hcl.BodySchema
|
|
|
|
Want *hcl.BodyContent
|
|
|
|
Remain *hcl.BodyContent
|
2017-07-27 22:59:32 +00:00
|
|
|
DiagCount int
|
|
|
|
}{
|
|
|
|
"empty": {
|
2017-09-11 23:40:37 +00:00
|
|
|
&hcl.BodyContent{},
|
|
|
|
&hcl.BodySchema{},
|
|
|
|
&hcl.BodyContent{
|
|
|
|
Attributes: hcl.Attributes{},
|
|
|
|
Blocks: hcl.Blocks{},
|
2017-07-27 22:59:32 +00:00
|
|
|
},
|
2017-09-11 23:40:37 +00:00
|
|
|
&hcl.BodyContent{
|
|
|
|
Attributes: hcl.Attributes{},
|
|
|
|
Blocks: hcl.Blocks{},
|
2017-07-27 22:59:32 +00:00
|
|
|
},
|
|
|
|
0,
|
|
|
|
},
|
|
|
|
"attribute requested": {
|
2017-09-11 23:40:37 +00:00
|
|
|
&hcl.BodyContent{
|
|
|
|
Attributes: MockAttrs(map[string]hcl.Expression{
|
2017-07-27 22:59:32 +00:00
|
|
|
"name": MockExprLiteral(cty.StringVal("Ermintrude")),
|
|
|
|
}),
|
|
|
|
},
|
2017-09-11 23:40:37 +00:00
|
|
|
&hcl.BodySchema{
|
|
|
|
Attributes: []hcl.AttributeSchema{
|
2017-07-27 22:59:32 +00:00
|
|
|
{
|
|
|
|
Name: "name",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2017-09-11 23:40:37 +00:00
|
|
|
&hcl.BodyContent{
|
|
|
|
Attributes: MockAttrs(map[string]hcl.Expression{
|
2017-07-27 22:59:32 +00:00
|
|
|
"name": MockExprLiteral(cty.StringVal("Ermintrude")),
|
|
|
|
}),
|
2017-09-11 23:40:37 +00:00
|
|
|
Blocks: hcl.Blocks{},
|
2017-07-27 22:59:32 +00:00
|
|
|
},
|
2017-09-11 23:40:37 +00:00
|
|
|
&hcl.BodyContent{
|
|
|
|
Attributes: hcl.Attributes{},
|
|
|
|
Blocks: hcl.Blocks{},
|
2017-07-27 22:59:32 +00:00
|
|
|
},
|
|
|
|
0,
|
|
|
|
},
|
|
|
|
"attribute remains": {
|
2017-09-11 23:40:37 +00:00
|
|
|
&hcl.BodyContent{
|
|
|
|
Attributes: MockAttrs(map[string]hcl.Expression{
|
2017-07-27 22:59:32 +00:00
|
|
|
"name": MockExprLiteral(cty.StringVal("Ermintrude")),
|
|
|
|
}),
|
|
|
|
},
|
2017-09-11 23:40:37 +00:00
|
|
|
&hcl.BodySchema{},
|
|
|
|
&hcl.BodyContent{
|
|
|
|
Attributes: hcl.Attributes{},
|
|
|
|
Blocks: hcl.Blocks{},
|
2017-07-27 22:59:32 +00:00
|
|
|
},
|
2017-09-11 23:40:37 +00:00
|
|
|
&hcl.BodyContent{
|
|
|
|
Attributes: MockAttrs(map[string]hcl.Expression{
|
2017-07-27 22:59:32 +00:00
|
|
|
"name": MockExprLiteral(cty.StringVal("Ermintrude")),
|
|
|
|
}),
|
2017-09-11 23:40:37 +00:00
|
|
|
Blocks: hcl.Blocks{},
|
2017-07-27 22:59:32 +00:00
|
|
|
},
|
|
|
|
0,
|
|
|
|
},
|
|
|
|
"attribute missing": {
|
2017-09-11 23:40:37 +00:00
|
|
|
&hcl.BodyContent{
|
|
|
|
Attributes: hcl.Attributes{},
|
2017-07-27 22:59:32 +00:00
|
|
|
},
|
2017-09-11 23:40:37 +00:00
|
|
|
&hcl.BodySchema{
|
|
|
|
Attributes: []hcl.AttributeSchema{
|
2017-07-27 22:59:32 +00:00
|
|
|
{
|
|
|
|
Name: "name",
|
|
|
|
Required: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2017-09-11 23:40:37 +00:00
|
|
|
&hcl.BodyContent{
|
|
|
|
Attributes: hcl.Attributes{},
|
|
|
|
Blocks: hcl.Blocks{},
|
2017-07-27 22:59:32 +00:00
|
|
|
},
|
2017-09-11 23:40:37 +00:00
|
|
|
&hcl.BodyContent{
|
|
|
|
Attributes: hcl.Attributes{},
|
|
|
|
Blocks: hcl.Blocks{},
|
2017-07-27 22:59:32 +00:00
|
|
|
},
|
|
|
|
1, // missing attribute "name"
|
|
|
|
},
|
|
|
|
"block requested, no labels": {
|
2017-09-11 23:40:37 +00:00
|
|
|
&hcl.BodyContent{
|
|
|
|
Blocks: hcl.Blocks{
|
2017-07-27 22:59:32 +00:00
|
|
|
{
|
|
|
|
Type: "baz",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2017-09-11 23:40:37 +00:00
|
|
|
&hcl.BodySchema{
|
|
|
|
Blocks: []hcl.BlockHeaderSchema{
|
2017-07-27 22:59:32 +00:00
|
|
|
{
|
|
|
|
Type: "baz",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2017-09-11 23:40:37 +00:00
|
|
|
&hcl.BodyContent{
|
|
|
|
Attributes: hcl.Attributes{},
|
|
|
|
Blocks: hcl.Blocks{
|
2017-07-27 22:59:32 +00:00
|
|
|
{
|
|
|
|
Type: "baz",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2017-09-11 23:40:37 +00:00
|
|
|
&hcl.BodyContent{
|
|
|
|
Attributes: hcl.Attributes{},
|
|
|
|
Blocks: hcl.Blocks{},
|
2017-07-27 22:59:32 +00:00
|
|
|
},
|
|
|
|
0,
|
|
|
|
},
|
|
|
|
"block requested, wrong labels": {
|
2017-09-11 23:40:37 +00:00
|
|
|
&hcl.BodyContent{
|
|
|
|
Blocks: hcl.Blocks{
|
2017-07-27 22:59:32 +00:00
|
|
|
{
|
|
|
|
Type: "baz",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2017-09-11 23:40:37 +00:00
|
|
|
&hcl.BodySchema{
|
|
|
|
Blocks: []hcl.BlockHeaderSchema{
|
2017-07-27 22:59:32 +00:00
|
|
|
{
|
|
|
|
Type: "baz",
|
|
|
|
LabelNames: []string{"foo"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2017-09-11 23:40:37 +00:00
|
|
|
&hcl.BodyContent{
|
|
|
|
Attributes: hcl.Attributes{},
|
|
|
|
Blocks: hcl.Blocks{
|
2017-07-27 22:59:32 +00:00
|
|
|
{
|
|
|
|
Type: "baz",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2017-09-11 23:40:37 +00:00
|
|
|
&hcl.BodyContent{
|
|
|
|
Attributes: hcl.Attributes{},
|
|
|
|
Blocks: hcl.Blocks{},
|
2017-07-27 22:59:32 +00:00
|
|
|
},
|
|
|
|
1, // "baz" requires 1 label
|
|
|
|
},
|
|
|
|
"block remains": {
|
2017-09-11 23:40:37 +00:00
|
|
|
&hcl.BodyContent{
|
|
|
|
Blocks: hcl.Blocks{
|
2017-07-27 22:59:32 +00:00
|
|
|
{
|
|
|
|
Type: "baz",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2017-09-11 23:40:37 +00:00
|
|
|
&hcl.BodySchema{},
|
|
|
|
&hcl.BodyContent{
|
|
|
|
Attributes: hcl.Attributes{},
|
|
|
|
Blocks: hcl.Blocks{},
|
2017-07-27 22:59:32 +00:00
|
|
|
},
|
2017-09-11 23:40:37 +00:00
|
|
|
&hcl.BodyContent{
|
|
|
|
Attributes: hcl.Attributes{},
|
|
|
|
Blocks: hcl.Blocks{
|
2017-07-27 22:59:32 +00:00
|
|
|
{
|
|
|
|
Type: "baz",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
0,
|
|
|
|
},
|
|
|
|
"various": {
|
2017-09-11 23:40:37 +00:00
|
|
|
&hcl.BodyContent{
|
|
|
|
Attributes: MockAttrs(map[string]hcl.Expression{
|
2017-07-27 22:59:32 +00:00
|
|
|
"name": MockExprLiteral(cty.StringVal("Ermintrude")),
|
|
|
|
"age": MockExprLiteral(cty.NumberIntVal(32)),
|
|
|
|
}),
|
2017-09-11 23:40:37 +00:00
|
|
|
Blocks: hcl.Blocks{
|
2017-07-27 22:59:32 +00:00
|
|
|
{
|
|
|
|
Type: "baz",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Type: "bar",
|
|
|
|
Labels: []string{"foo1"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Type: "bar",
|
|
|
|
Labels: []string{"foo2"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2017-09-11 23:40:37 +00:00
|
|
|
&hcl.BodySchema{
|
|
|
|
Attributes: []hcl.AttributeSchema{
|
2017-07-27 22:59:32 +00:00
|
|
|
{
|
|
|
|
Name: "name",
|
|
|
|
},
|
|
|
|
},
|
2017-09-11 23:40:37 +00:00
|
|
|
Blocks: []hcl.BlockHeaderSchema{
|
2017-07-27 22:59:32 +00:00
|
|
|
{
|
|
|
|
Type: "bar",
|
|
|
|
LabelNames: []string{"name"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2017-09-11 23:40:37 +00:00
|
|
|
&hcl.BodyContent{
|
|
|
|
Attributes: MockAttrs(map[string]hcl.Expression{
|
2017-07-27 22:59:32 +00:00
|
|
|
"name": MockExprLiteral(cty.StringVal("Ermintrude")),
|
|
|
|
}),
|
2017-09-11 23:40:37 +00:00
|
|
|
Blocks: hcl.Blocks{
|
2017-07-27 22:59:32 +00:00
|
|
|
{
|
|
|
|
Type: "bar",
|
|
|
|
Labels: []string{"foo1"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Type: "bar",
|
|
|
|
Labels: []string{"foo2"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2017-09-11 23:40:37 +00:00
|
|
|
&hcl.BodyContent{
|
|
|
|
Attributes: MockAttrs(map[string]hcl.Expression{
|
2017-07-27 22:59:32 +00:00
|
|
|
"age": MockExprLiteral(cty.NumberIntVal(32)),
|
|
|
|
}),
|
2017-09-11 23:40:37 +00:00
|
|
|
Blocks: hcl.Blocks{
|
2017-07-27 22:59:32 +00:00
|
|
|
{
|
|
|
|
Type: "baz",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
0,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for name, test := range tests {
|
|
|
|
t.Run(name, func(t *testing.T) {
|
|
|
|
inBody := MockBody(test.In)
|
|
|
|
got, remainBody, diags := inBody.PartialContent(test.Schema)
|
|
|
|
if len(diags) != test.DiagCount {
|
|
|
|
t.Errorf("wrong number of diagnostics %d; want %d", len(diags), test.DiagCount)
|
|
|
|
for _, diag := range diags {
|
|
|
|
t.Logf("- %s", diag)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if !reflect.DeepEqual(got, test.Want) {
|
|
|
|
t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want)
|
|
|
|
}
|
|
|
|
|
|
|
|
gotRemain := remainBody.(mockBody).C
|
|
|
|
if !reflect.DeepEqual(gotRemain, test.Remain) {
|
|
|
|
t.Errorf("wrong remain\ngot: %#v\nwant: %#v", gotRemain, test.Remain)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2021-02-08 14:17:28 +00:00
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|