Skip to content

Commit

Permalink
decoder: Rewrite existing expression completion tests
Browse files Browse the repository at this point in the history
Previously the tests were testing internal API, this change makes the tests less brittle and easier to reuse when implementation changes.
  • Loading branch information
radeksimko committed Jan 5, 2023
1 parent 5b41891 commit 812d0f9
Showing 1 changed file with 172 additions and 16 deletions.
188 changes: 172 additions & 16 deletions decoder/attribute_candidates_test.go
Original file line number Diff line number Diff line change
@@ -1,56 +1,120 @@
package decoder

import (
"context"
"fmt"
"testing"

"github.com/google/go-cmp/cmp"
"github.com/hashicorp/hcl-lang/lang"
"github.com/hashicorp/hcl-lang/schema"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclsyntax"
"github.com/zclconf/go-cty/cty"
)

func TestSnippetForAttribute(t *testing.T) {
testCases := []struct {
testName string
attrName string
attrSchema *schema.AttributeSchema
expectedSnippet string
testName string
attrName string
attrSchema *schema.AttributeSchema
expectedCandidates lang.Candidates
}{
{
"primitive type",
"primitive",
&schema.AttributeSchema{
Expr: schema.LiteralTypeOnly(cty.String),
},
`primitive = "${1:value}"`,
lang.CompleteCandidates([]lang.Candidate{
{
Label: "primitive",
Detail: "string",
TextEdit: lang.TextEdit{
Range: hcl.Range{
Filename: "test.tf",
Start: hcl.InitialPos,
End: hcl.InitialPos,
},
NewText: "primitive",
Snippet: `primitive = "${1:value}"`,
},
Kind: lang.AttributeCandidateKind,
},
}),
},
{
"map of strings",
"mymap",
&schema.AttributeSchema{
Expr: schema.LiteralTypeOnly(cty.Map(cty.String)),
},
`mymap = {
lang.CompleteCandidates([]lang.Candidate{
{
Label: "mymap",
Detail: "map of string",
TextEdit: lang.TextEdit{
Range: hcl.Range{
Filename: "test.tf",
Start: hcl.InitialPos,
End: hcl.InitialPos,
},
NewText: "mymap",
Snippet: `mymap = {
"${1:key}" = "${2:value}"
}`,
},
Kind: lang.AttributeCandidateKind,
},
}),
},
{
"map of numbers",
"mymap",
&schema.AttributeSchema{
Expr: schema.LiteralTypeOnly(cty.Map(cty.Number)),
},
`mymap = {
lang.CompleteCandidates([]lang.Candidate{
{
Label: "mymap",
Detail: "map of number",
TextEdit: lang.TextEdit{
Range: hcl.Range{
Filename: "test.tf",
Start: hcl.InitialPos,
End: hcl.InitialPos,
},
NewText: "mymap",
Snippet: `mymap = {
"${1:key}" = ${2:1}
}`,
},
Kind: lang.AttributeCandidateKind,
},
}),
},
{
"list of numbers",
"mylist",
&schema.AttributeSchema{
Expr: schema.LiteralTypeOnly(cty.List(cty.Number)),
},
`mylist = [ ${1:1} ]`,
lang.CompleteCandidates([]lang.Candidate{
{
Label: "mylist",
Detail: "list of number",
TextEdit: lang.TextEdit{
Range: hcl.Range{
Filename: "test.tf",
Start: hcl.InitialPos,
End: hcl.InitialPos,
},
NewText: "mylist",
Snippet: `mylist = [ ${1:1} ]`,
},
Kind: lang.AttributeCandidateKind,
},
}),
},
{
"list of objects",
Expand All @@ -61,18 +125,48 @@ func TestSnippetForAttribute(t *testing.T) {
"second": cty.Number,
}))),
},
`mylistobj = [ {
lang.CompleteCandidates([]lang.Candidate{
{
Label: "mylistobj",
Detail: "list of object",
TextEdit: lang.TextEdit{
Range: hcl.Range{
Filename: "test.tf",
Start: hcl.InitialPos,
End: hcl.InitialPos,
},
NewText: "mylistobj",
Snippet: `mylistobj = [ {
first = "${1:value}"
second = ${2:1}
} ]`,
},
Kind: lang.AttributeCandidateKind,
},
}),
},
{
"set of numbers",
"myset",
&schema.AttributeSchema{
Expr: schema.LiteralTypeOnly(cty.Set(cty.Number)),
},
`myset = [ ${1:1} ]`,
lang.CompleteCandidates([]lang.Candidate{
{
Label: "myset",
Detail: "set of number",
TextEdit: lang.TextEdit{
Range: hcl.Range{
Filename: "test.tf",
Start: hcl.InitialPos,
End: hcl.InitialPos,
},
NewText: "myset",
Snippet: `myset = [ ${1:1} ]`,
},
Kind: lang.AttributeCandidateKind,
},
}),
},
{
"object",
Expand All @@ -84,19 +178,49 @@ func TestSnippetForAttribute(t *testing.T) {
"keybool": cty.Bool,
})),
},
`myobj = {
lang.CompleteCandidates([]lang.Candidate{
{
Label: "myobj",
Detail: "object",
TextEdit: lang.TextEdit{
Range: hcl.Range{
Filename: "test.tf",
Start: hcl.InitialPos,
End: hcl.InitialPos,
},
NewText: "myobj",
Snippet: `myobj = {
keybool = ${1:false}
keynum = ${2:1}
keystr = "${3:value}"
}`,
},
Kind: lang.AttributeCandidateKind,
},
}),
},
{
"unknown type",
"mynil",
&schema.AttributeSchema{
Expr: schema.LiteralTypeOnly(cty.DynamicPseudoType),
},
`mynil = ${1}`,
lang.CompleteCandidates([]lang.Candidate{
{
Label: "mynil",
Detail: "any type",
TextEdit: lang.TextEdit{
Range: hcl.Range{
Filename: "test.tf",
Start: hcl.InitialPos,
End: hcl.InitialPos,
},
NewText: "mynil",
Snippet: `mynil = ${1}`,
},
Kind: lang.AttributeCandidateKind,
},
}),
},
{
"nested object",
Expand All @@ -110,21 +234,53 @@ func TestSnippetForAttribute(t *testing.T) {
}),
})),
},
`myobj = {
lang.CompleteCandidates([]lang.Candidate{
{
Label: "myobj",
Detail: "object",
TextEdit: lang.TextEdit{
Range: hcl.Range{
Filename: "test.tf",
Start: hcl.InitialPos,
End: hcl.InitialPos,
},
NewText: "myobj",
Snippet: `myobj = {
another = {
nested_number = ${1:1}
nestedstr = "${2:value}"
}
keystr = "${3:value}"
}`,
},
Kind: lang.AttributeCandidateKind,
},
}),
},
}

for i, tc := range testCases {
t.Run(fmt.Sprintf("%d-%s", i, tc.testName), func(t *testing.T) {
snippet := snippetForAttribute(tc.attrName, tc.attrSchema)
if diff := cmp.Diff(tc.expectedSnippet, snippet); diff != "" {
t.Fatalf("unexpected snippet: %s", diff)
f, _ := hclsyntax.ParseConfig([]byte("\n"), "test.tf", hcl.InitialPos)
d := testPathDecoder(t, &PathContext{
Schema: &schema.BodySchema{
Attributes: map[string]*schema.AttributeSchema{
tc.attrName: tc.attrSchema,
},
},
Files: map[string]*hcl.File{
"test.tf": f,
},
})

ctx := context.Background()
candidates, err := d.CandidatesAtPos(ctx, "test.tf", hcl.InitialPos)
if err != nil {
t.Fatal(err)
}

if diff := cmp.Diff(tc.expectedCandidates, candidates); diff != "" {
t.Fatalf("unexpected candidates: %s", diff)
}
})
}
Expand Down

0 comments on commit 812d0f9

Please sign in to comment.