diff --git a/decoder/attribute_candidates_test.go b/decoder/attribute_candidates_test.go index cf4a0829..54bbd519 100644 --- a/decoder/attribute_candidates_test.go +++ b/decoder/attribute_candidates_test.go @@ -1,20 +1,24 @@ 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", @@ -22,7 +26,22 @@ func TestSnippetForAttribute(t *testing.T) { &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", @@ -30,9 +49,24 @@ func TestSnippetForAttribute(t *testing.T) { &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", @@ -40,9 +74,24 @@ func TestSnippetForAttribute(t *testing.T) { &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", @@ -50,7 +99,22 @@ func TestSnippetForAttribute(t *testing.T) { &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", @@ -61,10 +125,25 @@ 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", @@ -72,7 +151,22 @@ func TestSnippetForAttribute(t *testing.T) { &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", @@ -84,11 +178,26 @@ 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", @@ -96,7 +205,22 @@ func TestSnippetForAttribute(t *testing.T) { &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", @@ -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) } }) }