Improved test
This commit is contained in:
56
test/builder_merge_test.go
Normal file
56
test/builder_merge_test.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/marte-community/marte-dev-tools/internal/builder"
|
||||
)
|
||||
|
||||
func TestBuilderMergeNodes(t *testing.T) {
|
||||
// Two files without package, defining SAME root node +App.
|
||||
// This triggers merging logic in Builder.
|
||||
|
||||
content1 := `
|
||||
+App = {
|
||||
Field1 = 10
|
||||
+Sub = { Val = 1 }
|
||||
}
|
||||
`
|
||||
content2 := `
|
||||
+App = {
|
||||
Field2 = 20
|
||||
+Sub = { Val2 = 2 }
|
||||
}
|
||||
`
|
||||
f1, _ := os.CreateTemp("", "merge1.marte")
|
||||
f1.WriteString(content1)
|
||||
f1.Close()
|
||||
defer os.Remove(f1.Name())
|
||||
|
||||
f2, _ := os.CreateTemp("", "merge2.marte")
|
||||
f2.WriteString(content2)
|
||||
f2.Close()
|
||||
defer os.Remove(f2.Name())
|
||||
|
||||
b := builder.NewBuilder([]string{f1.Name(), f2.Name()}, nil)
|
||||
|
||||
outF, _ := os.CreateTemp("", "out_merge.marte")
|
||||
defer os.Remove(outF.Name())
|
||||
|
||||
err := b.Build(outF)
|
||||
if err != nil {
|
||||
t.Fatalf("Build failed: %v", err)
|
||||
}
|
||||
outF.Close()
|
||||
|
||||
outContent, _ := os.ReadFile(outF.Name())
|
||||
outStr := string(outContent)
|
||||
|
||||
if !strings.Contains(outStr, "Field1 = 10") { t.Error("Missing Field1") }
|
||||
if !strings.Contains(outStr, "Field2 = 20") { t.Error("Missing Field2") }
|
||||
if !strings.Contains(outStr, "+Sub = {") { t.Error("Missing Sub") }
|
||||
if !strings.Contains(outStr, "Val = 1") { t.Error("Missing Sub.Val") }
|
||||
if !strings.Contains(outStr, "Val2 = 2") { t.Error("Missing Sub.Val2") }
|
||||
}
|
||||
55
test/formatter_coverage_test.go
Normal file
55
test/formatter_coverage_test.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/marte-community/marte-dev-tools/internal/formatter"
|
||||
"github.com/marte-community/marte-dev-tools/internal/parser"
|
||||
)
|
||||
|
||||
func TestFormatterCoverage(t *testing.T) {
|
||||
content := `
|
||||
// Head comment
|
||||
#package Pkg
|
||||
|
||||
//# Doc for A
|
||||
+A = {
|
||||
Field = 10 // Trailing
|
||||
Bool = true
|
||||
Float = 1.23
|
||||
Ref = SomeObj
|
||||
Array = { 1 2 3 }
|
||||
Expr = 1 + 2
|
||||
|
||||
// Inner
|
||||
+B = {
|
||||
Val = "Str"
|
||||
}
|
||||
}
|
||||
|
||||
// Final
|
||||
`
|
||||
p := parser.NewParser(content)
|
||||
cfg, err := p.Parse()
|
||||
if err != nil {
|
||||
t.Fatalf("Parse failed: %v", err)
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
formatter.Format(cfg, &buf)
|
||||
|
||||
out := buf.String()
|
||||
if !strings.Contains(out, "Field = 10") {
|
||||
t.Error("Formatting failed")
|
||||
}
|
||||
|
||||
// Check comments
|
||||
if !strings.Contains(out, "// Head comment") {
|
||||
t.Error("Head comment missing")
|
||||
}
|
||||
if !strings.Contains(out, "//# Doc for A") {
|
||||
t.Error("Doc missing")
|
||||
}
|
||||
}
|
||||
45
test/lexer_coverage_test.go
Normal file
45
test/lexer_coverage_test.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/marte-community/marte-dev-tools/internal/parser"
|
||||
)
|
||||
|
||||
func TestLexerCoverage(t *testing.T) {
|
||||
// 1. Comments
|
||||
input := `
|
||||
// Line comment
|
||||
/* Block comment */
|
||||
//# Docstring
|
||||
//! Pragma
|
||||
/* Unclosed block
|
||||
`
|
||||
l := parser.NewLexer(input)
|
||||
for {
|
||||
tok := l.NextToken()
|
||||
if tok.Type == parser.TokenEOF {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Numbers
|
||||
inputNum := `123 12.34 1.2e3 1.2E-3 0xFF`
|
||||
lNum := parser.NewLexer(inputNum)
|
||||
for {
|
||||
tok := lNum.NextToken()
|
||||
if tok.Type == parser.TokenEOF {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Identifiers
|
||||
inputID := `Valid ID with-hyphen _under`
|
||||
lID := parser.NewLexer(inputID)
|
||||
for {
|
||||
tok := lID.NextToken()
|
||||
if tok.Type == parser.TokenEOF {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,9 @@ import (
|
||||
)
|
||||
|
||||
func TestLoggerPrint(t *testing.T) {
|
||||
// Direct call for coverage
|
||||
logger.Println("Coverage check")
|
||||
|
||||
if os.Getenv("TEST_LOGGER_PRINT") == "1" {
|
||||
logger.Printf("Test Printf %d", 123)
|
||||
logger.Println("Test Println")
|
||||
|
||||
@@ -8,7 +8,9 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/marte-community/marte-dev-tools/internal/index"
|
||||
"github.com/marte-community/marte-dev-tools/internal/lsp"
|
||||
"github.com/marte-community/marte-dev-tools/internal/parser"
|
||||
)
|
||||
|
||||
func TestLSPIncrementalSync(t *testing.T) {
|
||||
@@ -108,3 +110,82 @@ func TestLSPMalformedParams(t *testing.T) {
|
||||
t.Errorf("Expected nil result for malformed params, got: %s", output)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLSPDispatch(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
lsp.Output = &buf
|
||||
|
||||
// Initialize
|
||||
msgInit := &lsp.JsonRpcMessage{Method: "initialize", ID: 1, Params: json.RawMessage(`{}`)}
|
||||
lsp.HandleMessage(msgInit)
|
||||
|
||||
// DidOpen
|
||||
msgOpen := &lsp.JsonRpcMessage{Method: "textDocument/didOpen", Params: json.RawMessage(`{"textDocument":{"uri":"file://d.marte","text":""}}`)}
|
||||
lsp.HandleMessage(msgOpen)
|
||||
|
||||
// DidChange
|
||||
msgChange := &lsp.JsonRpcMessage{Method: "textDocument/didChange", Params: json.RawMessage(`{"textDocument":{"uri":"file://d.marte","version":2},"contentChanges":[{"text":"A"}]}`)}
|
||||
lsp.HandleMessage(msgChange)
|
||||
|
||||
// Hover
|
||||
msgHover := &lsp.JsonRpcMessage{Method: "textDocument/hover", ID: 2, Params: json.RawMessage(`{"textDocument":{"uri":"file://d.marte"},"position":{"line":0,"character":0}}`)}
|
||||
lsp.HandleMessage(msgHover)
|
||||
|
||||
// Definition
|
||||
msgDef := &lsp.JsonRpcMessage{Method: "textDocument/definition", ID: 3, Params: json.RawMessage(`{"textDocument":{"uri":"file://d.marte"},"position":{"line":0,"character":0}}`)}
|
||||
lsp.HandleMessage(msgDef)
|
||||
|
||||
// References
|
||||
msgRef := &lsp.JsonRpcMessage{Method: "textDocument/references", ID: 4, Params: json.RawMessage(`{"textDocument":{"uri":"file://d.marte"},"position":{"line":0,"character":0},"context":{"includeDeclaration":true}}`)}
|
||||
lsp.HandleMessage(msgRef)
|
||||
|
||||
// Completion
|
||||
msgComp := &lsp.JsonRpcMessage{Method: "textDocument/completion", ID: 5, Params: json.RawMessage(`{"textDocument":{"uri":"file://d.marte"},"position":{"line":0,"character":0}}`)}
|
||||
lsp.HandleMessage(msgComp)
|
||||
|
||||
// Formatting
|
||||
msgFmt := &lsp.JsonRpcMessage{Method: "textDocument/formatting", ID: 6, Params: json.RawMessage(`{"textDocument":{"uri":"file://d.marte"},"options":{"tabSize":4,"insertSpaces":true}}`)}
|
||||
lsp.HandleMessage(msgFmt)
|
||||
|
||||
// Rename
|
||||
msgRename := &lsp.JsonRpcMessage{Method: "textDocument/rename", ID: 7, Params: json.RawMessage(`{"textDocument":{"uri":"file://d.marte"},"position":{"line":0,"character":0},"newName":"B"}`)}
|
||||
lsp.HandleMessage(msgRename)
|
||||
}
|
||||
|
||||
func TestLSPVariableDefinition(t *testing.T) {
|
||||
lsp.Tree = index.NewProjectTree()
|
||||
lsp.Documents = make(map[string]string)
|
||||
|
||||
content := `
|
||||
#var MyVar: int = 10
|
||||
+Obj = {
|
||||
Field = @MyVar
|
||||
}
|
||||
`
|
||||
uri := "file://var_def.marte"
|
||||
lsp.Documents[uri] = content
|
||||
|
||||
p := parser.NewParser(content)
|
||||
cfg, _ := p.Parse()
|
||||
lsp.Tree.AddFile("var_def.marte", cfg)
|
||||
lsp.Tree.ResolveReferences()
|
||||
|
||||
params := lsp.DefinitionParams{
|
||||
TextDocument: lsp.TextDocumentIdentifier{URI: uri},
|
||||
Position: lsp.Position{Line: 3, Character: 13},
|
||||
}
|
||||
|
||||
res := lsp.HandleDefinition(params)
|
||||
if res == nil {
|
||||
t.Fatal("Definition not found for variable")
|
||||
}
|
||||
|
||||
locs, ok := res.([]lsp.Location)
|
||||
if !ok || len(locs) == 0 {
|
||||
t.Fatal("Expected location list")
|
||||
}
|
||||
|
||||
if locs[0].Range.Start.Line != 1 {
|
||||
t.Errorf("Expected line 1, got %d", locs[0].Range.Start.Line)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,11 +15,23 @@ func TestOperators(t *testing.T) {
|
||||
#var B: int = 20
|
||||
#var S1: string = "Hello"
|
||||
#var S2: string = "World"
|
||||
#var FA: float = 1.5
|
||||
#var FB: float = 2.0
|
||||
|
||||
+Obj = {
|
||||
Math = @A + @B
|
||||
Precedence = @A + @B * 2
|
||||
Concat = @S1 .. " " .. @S2
|
||||
FloatMath = @FA + @FB
|
||||
Mix = @A + @FA
|
||||
ConcatNum = "Num: " .. @A
|
||||
ConcatFloat = "F: " .. @FA
|
||||
ConcatArr = "A: " .. { 1 }
|
||||
BoolVal = true
|
||||
RefVal = Obj
|
||||
ArrVal = { 1 2 }
|
||||
Unres = @Unknown
|
||||
InvalidMath = "A" + 1
|
||||
}
|
||||
`
|
||||
// Check Parser
|
||||
@@ -55,4 +67,26 @@ func TestOperators(t *testing.T) {
|
||||
if !strings.Contains(outStr, "Concat = \"Hello World\"") {
|
||||
t.Errorf("Concat failed. Got:\n%s", outStr)
|
||||
}
|
||||
}
|
||||
if !strings.Contains(outStr, "FloatMath = 3.5") {
|
||||
t.Errorf("FloatMath failed. Got:\n%s", outStr)
|
||||
}
|
||||
// 10 + 1.5 = 11.5
|
||||
if !strings.Contains(outStr, "Mix = 11.5") {
|
||||
t.Errorf("Mix failed. Got:\n%s", outStr)
|
||||
}
|
||||
if !strings.Contains(outStr, "ConcatNum = \"Num: 10\"") {
|
||||
t.Errorf("ConcatNum failed. Got:\n%s", outStr)
|
||||
}
|
||||
if !strings.Contains(outStr, "BoolVal = true") {
|
||||
t.Errorf("BoolVal failed. Got:\n%s", outStr)
|
||||
}
|
||||
if !strings.Contains(outStr, "RefVal = Obj") {
|
||||
t.Errorf("RefVal failed. Got:\n%s", outStr)
|
||||
}
|
||||
if !strings.Contains(outStr, "ArrVal = { 1 2 }") {
|
||||
t.Errorf("ArrVal failed. Got:\n%s", outStr)
|
||||
}
|
||||
if !strings.Contains(outStr, "Unres = @Unknown") {
|
||||
t.Errorf("Unres failed. Got:\n%s", outStr)
|
||||
}
|
||||
}
|
||||
84
test/validator_expression_test.go
Normal file
84
test/validator_expression_test.go
Normal file
@@ -0,0 +1,84 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/marte-community/marte-dev-tools/internal/index"
|
||||
"github.com/marte-community/marte-dev-tools/internal/parser"
|
||||
"github.com/marte-community/marte-dev-tools/internal/schema"
|
||||
"github.com/marte-community/marte-dev-tools/internal/validator"
|
||||
)
|
||||
|
||||
func TestValidatorExpressionCoverage(t *testing.T) {
|
||||
content := `
|
||||
#var A: int = 10
|
||||
#var B: int = 5
|
||||
#var S1: string = "Hello"
|
||||
#var S2: string = "World"
|
||||
|
||||
// Valid cases (execution hits evaluateBinary)
|
||||
#var Sum: int = @A + @B // 15
|
||||
#var Sub: int = @A - @B // 5
|
||||
#var Mul: int = @A * @B // 50
|
||||
#var Div: int = @A / @B // 2
|
||||
#var Mod: int = @A % 3 // 1
|
||||
#var Concat: string = @S1 .. " " .. @S2 // "Hello World"
|
||||
#var Unary: int = -@A // -10
|
||||
#var BitAnd: int = 10 & 5
|
||||
#var BitOr: int = 10 | 5
|
||||
#var BitXor: int = 10 ^ 5
|
||||
|
||||
#var FA: float = 1.5
|
||||
#var FB: float = 2.0
|
||||
#var FSum: float = @FA + @FB // 3.5
|
||||
#var FSub: float = @FB - @FA // 0.5
|
||||
#var FMul: float = @FA * @FB // 3.0
|
||||
#var FDiv: float = @FB / @FA // 1.333...
|
||||
|
||||
#var BT: bool = true
|
||||
#var BF: bool = !@BT
|
||||
|
||||
// Invalid cases (should error)
|
||||
#var BadSum: int & > 20 = @A + @B // 15, should fail
|
||||
#var BadUnary: bool = !10 // Should fail type check (nil result from evaluateUnary)
|
||||
#var StrVar: string = "DS"
|
||||
|
||||
+InvalidDS = {
|
||||
Class = IOGAM
|
||||
InputSignals = {
|
||||
S = { DataSource = 10 } // Int coverage
|
||||
S2 = { DataSource = 1.5 } // Float coverage
|
||||
S3 = { DataSource = true } // Bool coverage
|
||||
S4 = { DataSource = @StrVar } // VarRef coverage -> String
|
||||
S5 = { DataSource = { 1 } } // Array coverage (default case)
|
||||
}
|
||||
OutputSignals = {}
|
||||
}
|
||||
`
|
||||
pt := index.NewProjectTree()
|
||||
p := parser.NewParser(content)
|
||||
cfg, err := p.Parse()
|
||||
if err != nil {
|
||||
t.Fatalf("Parse failed: %v", err)
|
||||
}
|
||||
pt.AddFile("expr.marte", cfg)
|
||||
pt.ResolveReferences()
|
||||
|
||||
v := validator.NewValidator(pt, ".")
|
||||
// Use NewSchema to ensure basic types
|
||||
v.Schema = schema.NewSchema()
|
||||
|
||||
v.CheckVariables()
|
||||
|
||||
// Check for expected errors
|
||||
foundBadSum := false
|
||||
for _, diag := range v.Diagnostics {
|
||||
if strings.Contains(diag.Message, "BadSum") && strings.Contains(diag.Message, "value mismatch") {
|
||||
foundBadSum = true
|
||||
}
|
||||
}
|
||||
if !foundBadSum {
|
||||
t.Error("Expected error for BadSum")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user