d2/d2lsp/completion_test.go

455 lines
9.2 KiB
Go
Raw Normal View History

package d2lsp
import (
"testing"
)
func TestGetCompletionItems(t *testing.T) {
tests := []struct {
name string
text string
line int
column int
want []CompletionItem
wantErr bool
}{
{
name: "style dot suggestions",
text: "a.style.",
line: 0,
column: 8,
want: getStyleCompletions(),
},
{
name: "style map suggestions",
text: `a: {
style.
}
`,
line: 1,
column: 8,
want: getStyleCompletions(),
},
2025-01-02 04:00:45 +00:00
{
name: "classes shapes",
text: `classes: {
goal: {
shape:
}
}
`,
line: 2,
column: 10,
want: getShapeCompletions(),
},
2025-01-02 03:35:06 +00:00
{
name: "nested style map suggestions",
text: `a: {
style: {
3d:
}
}
`,
line: 2,
column: 7,
want: getBooleanCompletions(),
},
{
name: "3d style map suggestions",
text: `a.style: {
3d:
}
`,
line: 1,
column: 5,
want: getBooleanCompletions(),
},
{
name: "fill pattern style map suggestions",
text: `a.style: {
fill-pattern:
}
`,
line: 1,
column: 15,
want: getFillPatternCompletions(),
},
{
name: "opacity style map suggestions",
text: `a.style: {
opacity:
}
`,
line: 1,
column: 10,
want: getValueCompletions("opacity"),
},
{
name: "width dot",
text: `a.width:`,
line: 0,
column: 8,
want: getValueCompletions("width"),
},
{
name: "layer shape",
text: `a
layers: {
hey: {
go: {
shape:
}
}
}
`,
line: 5,
column: 12,
want: getShapeCompletions(),
},
{
name: "stroke width value",
text: `a.style.stroke-width: 1`,
line: 0,
column: 23,
want: nil,
},
{
name: "no style suggestions",
text: `a.style:
`,
line: 0,
column: 8,
want: nil,
},
{
name: "style property suggestions",
text: "a -> b: { style. }",
line: 0,
column: 16,
want: getStyleCompletions(),
},
{
name: "style.opacity value hint",
text: "a -> b: { style.opacity: }",
line: 0,
column: 24,
want: getValueCompletions("opacity"),
},
{
name: "fill pattern completions",
text: "a -> b: { style.fill-pattern: }",
line: 0,
column: 29,
want: getFillPatternCompletions(),
},
{
name: "text transform completions",
text: "a -> b: { style.text-transform: }",
line: 0,
column: 31,
want: getTextTransformCompletions(),
},
{
name: "boolean property completions",
text: "a -> b: { style.shadow: }",
line: 0,
column: 23,
want: getBooleanCompletions(),
},
{
name: "near position completions",
text: "a -> b: { label.near: }",
line: 0,
column: 21,
want: getNearCompletions(),
},
{
name: "direction completions",
text: "a -> b: { direction: }",
line: 0,
column: 20,
want: getDirectionCompletions(),
},
{
name: "icon url completions",
text: "a -> b: { icon: }",
line: 0,
column: 15,
want: getIconCompletions(),
},
{
name: "icon dot url completions",
text: "a.icon:",
line: 0,
column: 7,
want: getIconCompletions(),
},
{
name: "icon near completions",
text: "a -> b: { icon.near: }",
line: 0,
column: 20,
want: getNearCompletions(),
},
{
name: "icon map",
text: `a.icon: {
# here
}`,
line: 1,
column: 2,
want: nil,
},
{
name: "icon flat dot",
text: `a.icon.`,
line: 0,
column: 7,
want: getLabelCompletions(),
},
{
name: "label flat dot",
text: `a.label.`,
line: 0,
column: 8,
want: getLabelCompletions(),
},
{
name: "arrowhead completions - dot syntax",
text: "a -> b: { source-arrowhead. }",
line: 0,
column: 27,
want: getArrowheadCompletions(),
},
{
name: "arrowhead completions - colon syntax",
text: "a -> b: { source-arrowhead: }",
line: 0,
column: 27,
want: nil,
},
{
name: "arrowhead completions - map syntax",
text: `a -> b: {
source-arrowhead: {
# here
}
}`,
line: 2,
column: 4,
want: getArrowheadCompletions(),
},
{
name: "arrowhead shape completions - flat dot syntax",
text: "(a -> b)[0].source-arrowhead.shape:",
line: 0,
column: 35,
want: getArrowheadShapeCompletions(),
},
{
name: "arrowhead shape completions - dot syntax",
text: "a -> b: { source-arrowhead.shape: }",
line: 0,
column: 33,
want: getArrowheadShapeCompletions(),
},
{
name: "arrowhead shape completions - map syntax",
text: "a -> b: { source-arrowhead: { shape: } }",
line: 0,
column: 36,
want: getArrowheadShapeCompletions(),
},
{
name: "width value hint",
text: "a -> b: { width: }",
line: 0,
column: 16,
want: getValueCompletions("width"),
},
{
name: "height value hint",
text: "a -> b: { height: }",
line: 0,
column: 17,
want: getValueCompletions("height"),
},
{
name: "tooltip markdown template",
text: "a -> b: { tooltip: }",
line: 0,
column: 18,
want: getTooltipCompletions(),
},
{
name: "tooltip dot markdown template",
text: "a.tooltip:",
line: 0,
column: 10,
want: getTooltipCompletions(),
},
{
name: "shape dot suggestions",
text: "a.shape:",
line: 0,
column: 8,
want: getShapeCompletions(),
},
{
name: "shape suggestions",
text: "a -> b: { shape: }",
line: 0,
column: 16,
want: getShapeCompletions(),
},
2025-01-02 04:00:45 +00:00
{
name: "shape 2 suggestions",
text: `a: {
shape:
}`,
line: 1,
column: 8,
want: getShapeCompletions(),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := GetCompletionItems(tt.text, tt.line, tt.column)
if (err != nil) != tt.wantErr {
t.Errorf("GetCompletionItems() error = %v, wantErr %v", err, tt.wantErr)
return
}
if len(got) != len(tt.want) {
t.Errorf("GetCompletionItems() got %d completions, want %d", len(got), len(tt.want))
return
}
// Create maps for easy comparison
gotMap := make(map[string]CompletionItem)
wantMap := make(map[string]CompletionItem)
for _, item := range got {
gotMap[item.Label] = item
}
for _, item := range tt.want {
wantMap[item.Label] = item
}
// Check that each completion exists and has correct properties
for label, wantItem := range wantMap {
gotItem, exists := gotMap[label]
if !exists {
t.Errorf("missing completion for %q", label)
continue
}
if gotItem.Kind != wantItem.Kind {
t.Errorf("completion %q Kind = %v, want %v", label, gotItem.Kind, wantItem.Kind)
}
if gotItem.Detail != wantItem.Detail {
t.Errorf("completion %q Detail = %v, want %v", label, gotItem.Detail, wantItem.Detail)
}
if gotItem.InsertText != wantItem.InsertText {
t.Errorf("completion %q InsertText = %v, want %v", label, gotItem.InsertText, wantItem.InsertText)
}
}
})
}
}
// Helper function to compare CompletionItem slices
func equalCompletions(a, b []CompletionItem) bool {
if len(a) != len(b) {
return false
}
for i := range a {
if a[i].Label != b[i].Label ||
a[i].Kind != b[i].Kind ||
a[i].Detail != b[i].Detail ||
a[i].InsertText != b[i].InsertText {
return false
}
}
return true
}
func TestGetArrowheadShapeCompletions(t *testing.T) {
got := getArrowheadShapeCompletions()
expectedLabels := []string{
"triangle", "arrow", "diamond", "circle",
"cf-one", "cf-one-required",
"cf-many", "cf-many-required",
}
if len(got) != len(expectedLabels) {
t.Errorf("getArrowheadShapeCompletions() returned %d items, want %d", len(got), len(expectedLabels))
return
}
for i, label := range expectedLabels {
if got[i].Label != label {
t.Errorf("completion[%d].Label = %v, want %v", i, got[i].Label, label)
}
if got[i].Kind != ShapeCompletion {
t.Errorf("completion[%d].Kind = %v, want ShapeCompletion", i, got[i].Kind)
}
if got[i].InsertText != label {
t.Errorf("completion[%d].InsertText = %v, want %v", i, got[i].InsertText, label)
}
}
}
func TestGetValueCompletions(t *testing.T) {
tests := []struct {
property string
wantLabel string
wantDetail string
}{
{
property: "opacity",
wantLabel: "(number between 0.0 and 1.0)",
wantDetail: "e.g. 0.4",
},
{
property: "stroke-width",
wantLabel: "(number between 0 and 15)",
wantDetail: "e.g. 2",
},
{
property: "font-size",
wantLabel: "(number between 8 and 100)",
wantDetail: "e.g. 14",
},
{
property: "width",
wantLabel: "(pixels)",
wantDetail: "e.g. 400",
},
{
property: "stroke",
wantLabel: "(color name or hex code)",
wantDetail: "e.g. blue, #ff0000",
},
}
for _, tt := range tests {
t.Run(tt.property, func(t *testing.T) {
got := getValueCompletions(tt.property)
if len(got) != 1 {
t.Fatalf("getValueCompletions(%s) returned %d items, want 1", tt.property, len(got))
}
if got[0].Label != tt.wantLabel {
t.Errorf("completion.Label = %v, want %v", got[0].Label, tt.wantLabel)
}
if got[0].Detail != tt.wantDetail {
t.Errorf("completion.Detail = %v, want %v", got[0].Detail, tt.wantDetail)
}
if got[0].InsertText != "" {
t.Errorf("completion.InsertText = %v, want empty string", got[0].InsertText)
}
})
}
}