mirror of
https://github.com/hanzoai/numscript.git
synced 2026-10-30 18:26:57 +00:00
* feat: emit warning when asset is inferred to be a fixed value * address coderabbit's suggestions
202 lines
3.8 KiB
Go
202 lines
3.8 KiB
Go
package lsp_test
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/formancehq/numscript/internal/analysis"
|
|
lsp "github.com/formancehq/numscript/internal/lsp"
|
|
"github.com/formancehq/numscript/internal/parser"
|
|
"github.com/stretchr/testify/require"
|
|
"go.lsp.dev/protocol"
|
|
)
|
|
|
|
func performAction(t *testing.T,
|
|
initial string,
|
|
expected string,
|
|
toEdit func(kind analysis.DiagnosticKind, program parser.Program) protocol.TextEdit,
|
|
) {
|
|
res := analysis.CheckSource(initial)
|
|
|
|
first := res.Diagnostics[0]
|
|
|
|
finalStr := performEdit(initial, toEdit(first.Kind, res.Program))
|
|
|
|
require.Equal(t, expected, finalStr)
|
|
}
|
|
|
|
func TestCreateVarWhenNoVarsBlock(t *testing.T) {
|
|
initial := `send [USD/2 100] (
|
|
source = max $example from @a
|
|
destination = @b
|
|
)
|
|
`
|
|
|
|
final := `vars {
|
|
monetary $example
|
|
}
|
|
|
|
send [USD/2 100] (
|
|
source = max $example from @a
|
|
destination = @b
|
|
)
|
|
`
|
|
|
|
performAction(t, initial, final, func(kind analysis.DiagnosticKind, program parser.Program) protocol.TextEdit {
|
|
return lsp.CreateVar(kind.(analysis.UnboundVariable), program)
|
|
})
|
|
|
|
}
|
|
|
|
func TestCreateVarWhenAlreadyExistingVars(t *testing.T) {
|
|
initial := `vars {
|
|
monetary $example
|
|
}
|
|
|
|
send [USD/2 100] (
|
|
source = max $example from $account
|
|
destination = @b
|
|
)
|
|
`
|
|
|
|
final := `vars {
|
|
monetary $example
|
|
account $account
|
|
}
|
|
|
|
send [USD/2 100] (
|
|
source = max $example from $account
|
|
destination = @b
|
|
)
|
|
`
|
|
|
|
performAction(t, initial, final, func(kind analysis.DiagnosticKind, program parser.Program) protocol.TextEdit {
|
|
return lsp.CreateVar(kind.(analysis.UnboundVariable), program)
|
|
})
|
|
|
|
}
|
|
|
|
func TestCreateVarWhenAlreadyExistingVarsSameLine(t *testing.T) {
|
|
initial := `vars { account $account }
|
|
|
|
send [USD/2 100] (
|
|
source = max $example from $account
|
|
destination = @b
|
|
)
|
|
`
|
|
|
|
final := `vars { account $account
|
|
monetary $example
|
|
}
|
|
|
|
send [USD/2 100] (
|
|
source = max $example from $account
|
|
destination = @b
|
|
)
|
|
`
|
|
|
|
performAction(t, initial, final, func(kind analysis.DiagnosticKind, program parser.Program) protocol.TextEdit {
|
|
return lsp.CreateVar(kind.(analysis.UnboundVariable), program)
|
|
})
|
|
|
|
}
|
|
|
|
func TestCreateVarWhenEmptyVarsBlock(t *testing.T) {
|
|
initial := `vars {
|
|
}
|
|
|
|
send [USD/2 100] (
|
|
source = max [USD/2 100] from $account
|
|
destination = @b
|
|
)
|
|
`
|
|
|
|
final := `vars {
|
|
account $account
|
|
}
|
|
|
|
send [USD/2 100] (
|
|
source = max [USD/2 100] from $account
|
|
destination = @b
|
|
)
|
|
`
|
|
|
|
performAction(t, initial, final, func(kind analysis.DiagnosticKind, program parser.Program) protocol.TextEdit {
|
|
return lsp.CreateVar(kind.(analysis.UnboundVariable), program)
|
|
})
|
|
|
|
}
|
|
|
|
func TestPositionToOffset(t *testing.T) {
|
|
str := `abc
|
|
def
|
|
ghi`
|
|
|
|
require.Equal(t, positionToOffset(strings.Split(str, "\n"), protocol.Position{
|
|
Line: 1,
|
|
Character: 1,
|
|
}), 5)
|
|
|
|
}
|
|
|
|
func TestPerformEdit(t *testing.T) {
|
|
initial := `a
|
|
ins<>here
|
|
c
|
|
`
|
|
|
|
require.Equal(t, `a
|
|
ins___here
|
|
c
|
|
`, performEdit(initial, protocol.TextEdit{
|
|
Range: protocol.Range{
|
|
Start: protocol.Position{Line: 1, Character: 3},
|
|
End: protocol.Position{Line: 1, Character: 5},
|
|
},
|
|
NewText: "___",
|
|
}))
|
|
|
|
}
|
|
|
|
func TestPerformEdit2(t *testing.T) {
|
|
initial := `abc`
|
|
|
|
require.Equal(t, `LINE1
|
|
LINE2
|
|
|
|
abc`, performEdit(initial, protocol.TextEdit{
|
|
// Empty range
|
|
NewText: `LINE1
|
|
LINE2
|
|
|
|
`,
|
|
}))
|
|
|
|
}
|
|
|
|
func positionToOffset(lines []string, position protocol.Position) int {
|
|
// TODO: check indexes are 0-based
|
|
|
|
offset := 0
|
|
for _, line := range lines[0:position.Line] {
|
|
// +1 for the newline which was trimmed in lines
|
|
offset += len(line) + 1
|
|
}
|
|
|
|
offset += int(position.Character)
|
|
|
|
return offset
|
|
}
|
|
|
|
func performEdit(initial string, textEdit protocol.TextEdit) string {
|
|
lines := strings.Split(initial, "\n")
|
|
|
|
startOffset := positionToOffset(lines, textEdit.Range.Start)
|
|
endOffset := positionToOffset(lines, textEdit.Range.End)
|
|
|
|
before := initial[0:startOffset]
|
|
after := initial[endOffset:]
|
|
|
|
return before + textEdit.NewText + after
|
|
}
|