Pragma and signal validation added
This commit is contained in:
@@ -51,6 +51,7 @@ type ProjectNode struct {
|
|||||||
Parent *ProjectNode
|
Parent *ProjectNode
|
||||||
Metadata map[string]string // Store extra info like Class, Type, Size
|
Metadata map[string]string // Store extra info like Class, Type, Size
|
||||||
Target *ProjectNode // Points to referenced node (for Direct References/Links)
|
Target *ProjectNode // Points to referenced node (for Direct References/Links)
|
||||||
|
Pragmas []string
|
||||||
}
|
}
|
||||||
|
|
||||||
type Fragment struct {
|
type Fragment struct {
|
||||||
@@ -201,6 +202,7 @@ func (pt *ProjectTree) populateNode(node *ProjectNode, file string, config *pars
|
|||||||
|
|
||||||
for _, def := range config.Definitions {
|
for _, def := range config.Definitions {
|
||||||
doc := pt.findDoc(config.Comments, def.Pos())
|
doc := pt.findDoc(config.Comments, def.Pos())
|
||||||
|
pragmas := pt.findPragmas(config.Pragmas, def.Pos())
|
||||||
|
|
||||||
switch d := def.(type) {
|
switch d := def.(type) {
|
||||||
case *parser.Field:
|
case *parser.Field:
|
||||||
@@ -229,7 +231,11 @@ func (pt *ProjectTree) populateNode(node *ProjectNode, file string, config *pars
|
|||||||
child.Doc += doc
|
child.Doc += doc
|
||||||
}
|
}
|
||||||
|
|
||||||
pt.addObjectFragment(child, file, d, doc, config.Comments)
|
if len(pragmas) > 0 {
|
||||||
|
child.Pragmas = append(child.Pragmas, pragmas...)
|
||||||
|
}
|
||||||
|
|
||||||
|
pt.addObjectFragment(child, file, d, doc, config.Comments, config.Pragmas)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -238,7 +244,7 @@ func (pt *ProjectTree) populateNode(node *ProjectNode, file string, config *pars
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pt *ProjectTree) addObjectFragment(node *ProjectNode, file string, obj *parser.ObjectNode, doc string, comments []parser.Comment) {
|
func (pt *ProjectTree) addObjectFragment(node *ProjectNode, file string, obj *parser.ObjectNode, doc string, comments []parser.Comment, pragmas []parser.Pragma) {
|
||||||
frag := &Fragment{
|
frag := &Fragment{
|
||||||
File: file,
|
File: file,
|
||||||
IsObject: true,
|
IsObject: true,
|
||||||
@@ -248,6 +254,7 @@ func (pt *ProjectTree) addObjectFragment(node *ProjectNode, file string, obj *pa
|
|||||||
|
|
||||||
for _, def := range obj.Subnode.Definitions {
|
for _, def := range obj.Subnode.Definitions {
|
||||||
subDoc := pt.findDoc(comments, def.Pos())
|
subDoc := pt.findDoc(comments, def.Pos())
|
||||||
|
subPragmas := pt.findPragmas(pragmas, def.Pos())
|
||||||
|
|
||||||
switch d := def.(type) {
|
switch d := def.(type) {
|
||||||
case *parser.Field:
|
case *parser.Field:
|
||||||
@@ -277,7 +284,11 @@ func (pt *ProjectTree) addObjectFragment(node *ProjectNode, file string, obj *pa
|
|||||||
child.Doc += subDoc
|
child.Doc += subDoc
|
||||||
}
|
}
|
||||||
|
|
||||||
pt.addObjectFragment(child, file, d, subDoc, comments)
|
if len(subPragmas) > 0 {
|
||||||
|
child.Pragmas = append(child.Pragmas, subPragmas...)
|
||||||
|
}
|
||||||
|
|
||||||
|
pt.addObjectFragment(child, file, d, subDoc, comments, pragmas)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -322,6 +333,30 @@ func (pt *ProjectTree) findDoc(comments []parser.Comment, pos parser.Position) s
|
|||||||
return docBuilder.String()
|
return docBuilder.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (pt *ProjectTree) findPragmas(pragmas []parser.Pragma, pos parser.Position) []string {
|
||||||
|
var found []string
|
||||||
|
targetLine := pos.Line - 1
|
||||||
|
|
||||||
|
for i := len(pragmas) - 1; i >= 0; i-- {
|
||||||
|
p := pragmas[i]
|
||||||
|
if p.Position.Line > pos.Line {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if p.Position.Line == pos.Line {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.Position.Line == targetLine {
|
||||||
|
txt := strings.TrimSpace(strings.TrimPrefix(p.Text, "//!"))
|
||||||
|
found = append(found, txt)
|
||||||
|
targetLine--
|
||||||
|
} else if p.Position.Line < targetLine {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return found
|
||||||
|
}
|
||||||
|
|
||||||
func (pt *ProjectTree) indexValue(file string, val parser.Value) {
|
func (pt *ProjectTree) indexValue(file string, val parser.Value) {
|
||||||
switch v := val.(type) {
|
switch v := val.(type) {
|
||||||
case *parser.ReferenceValue:
|
case *parser.ReferenceValue:
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package validator
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/marte-dev/marte-dev-tools/internal/index"
|
"github.com/marte-dev/marte-dev-tools/internal/index"
|
||||||
"github.com/marte-dev/marte-dev-tools/internal/parser"
|
"github.com/marte-dev/marte-dev-tools/internal/parser"
|
||||||
@@ -353,12 +354,22 @@ func (v *Validator) validateGAMSignal(gamNode, signalNode *index.ProjectNode, di
|
|||||||
}
|
}
|
||||||
|
|
||||||
if targetNode == nil {
|
if targetNode == nil {
|
||||||
v.Diagnostics = append(v.Diagnostics, Diagnostic{
|
suppress := false
|
||||||
Level: LevelWarning,
|
for _, p := range signalNode.Pragmas {
|
||||||
Message: fmt.Sprintf("Implicitly Defined Signal: '%s' is defined in GAM '%s' but not in DataSource '%s'", targetSignalName, gamNode.RealName, dsName),
|
if strings.HasPrefix(p, "implicit:") {
|
||||||
Position: v.getNodePosition(signalNode),
|
suppress = true
|
||||||
File: v.getNodeFile(signalNode),
|
break
|
||||||
})
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !suppress {
|
||||||
|
v.Diagnostics = append(v.Diagnostics, Diagnostic{
|
||||||
|
Level: LevelWarning,
|
||||||
|
Message: fmt.Sprintf("Implicitly Defined Signal: '%s' is defined in GAM '%s' but not in DataSource '%s'", targetSignalName, gamNode.RealName, dsName),
|
||||||
|
Position: v.getNodePosition(signalNode),
|
||||||
|
File: v.getNodeFile(signalNode),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if typeFields, ok := fields["Type"]; !ok || len(typeFields) == 0 {
|
if typeFields, ok := fields["Type"]; !ok || len(typeFields) == 0 {
|
||||||
v.Diagnostics = append(v.Diagnostics, Diagnostic{
|
v.Diagnostics = append(v.Diagnostics, Diagnostic{
|
||||||
@@ -367,6 +378,17 @@ func (v *Validator) validateGAMSignal(gamNode, signalNode *index.ProjectNode, di
|
|||||||
Position: v.getNodePosition(signalNode),
|
Position: v.getNodePosition(signalNode),
|
||||||
File: v.getNodeFile(signalNode),
|
File: v.getNodeFile(signalNode),
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
// Check Type validity even for implicit
|
||||||
|
typeVal := v.getFieldValue(typeFields[0])
|
||||||
|
if !isValidType(typeVal) {
|
||||||
|
v.Diagnostics = append(v.Diagnostics, Diagnostic{
|
||||||
|
Level: LevelError,
|
||||||
|
Message: fmt.Sprintf("Invalid Type '%s' for Signal '%s'", typeVal, signalNode.RealName),
|
||||||
|
Position: typeFields[0].Position,
|
||||||
|
File: v.getNodeFile(signalNode),
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
signalNode.Target = targetNode
|
signalNode.Target = targetNode
|
||||||
@@ -376,9 +398,71 @@ func (v *Validator) validateGAMSignal(gamNode, signalNode *index.ProjectNode, di
|
|||||||
v.updateReferenceTarget(v.getNodeFile(signalNode), val.Position, targetNode)
|
v.updateReferenceTarget(v.getNodeFile(signalNode), val.Position, targetNode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Property checks
|
||||||
|
v.checkSignalProperty(signalNode, targetNode, "Type")
|
||||||
|
v.checkSignalProperty(signalNode, targetNode, "NumberOfElements")
|
||||||
|
v.checkSignalProperty(signalNode, targetNode, "NumberOfDimensions")
|
||||||
|
|
||||||
|
// Check Type validity if present
|
||||||
|
if typeFields, ok := fields["Type"]; ok && len(typeFields) > 0 {
|
||||||
|
typeVal := v.getFieldValue(typeFields[0])
|
||||||
|
if !isValidType(typeVal) {
|
||||||
|
v.Diagnostics = append(v.Diagnostics, Diagnostic{
|
||||||
|
Level: LevelError,
|
||||||
|
Message: fmt.Sprintf("Invalid Type '%s' for Signal '%s'", typeVal, signalNode.RealName),
|
||||||
|
Position: typeFields[0].Position,
|
||||||
|
File: v.getNodeFile(signalNode),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *Validator) checkSignalProperty(gamSig, dsSig *index.ProjectNode, prop string) {
|
||||||
|
gamVal := gamSig.Metadata[prop]
|
||||||
|
dsVal := dsSig.Metadata[prop]
|
||||||
|
|
||||||
|
if gamVal == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if dsVal != "" && gamVal != dsVal {
|
||||||
|
if prop == "Type" {
|
||||||
|
if v.checkCastPragma(gamSig, dsVal, gamVal) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
v.Diagnostics = append(v.Diagnostics, Diagnostic{
|
||||||
|
Level: LevelError,
|
||||||
|
Message: fmt.Sprintf("Signal '%s' property '%s' mismatch: defined '%s', referenced '%s'", gamSig.RealName, prop, dsVal, gamVal),
|
||||||
|
Position: v.getNodePosition(gamSig),
|
||||||
|
File: v.getNodeFile(gamSig),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Validator) checkCastPragma(node *index.ProjectNode, defType, curType string) bool {
|
||||||
|
for _, p := range node.Pragmas {
|
||||||
|
if strings.HasPrefix(p, "cast(") {
|
||||||
|
content := strings.TrimPrefix(p, "cast(")
|
||||||
|
if idx := strings.Index(content, ")"); idx != -1 {
|
||||||
|
content = content[:idx]
|
||||||
|
parts := strings.Split(content, ",")
|
||||||
|
if len(parts) == 2 {
|
||||||
|
d := strings.TrimSpace(parts[0])
|
||||||
|
c := strings.TrimSpace(parts[1])
|
||||||
|
if d == defType && c == curType {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (v *Validator) updateReferenceTarget(file string, pos parser.Position, target *index.ProjectNode) {
|
func (v *Validator) updateReferenceTarget(file string, pos parser.Position, target *index.ProjectNode) {
|
||||||
for i := range v.Tree.References {
|
for i := range v.Tree.References {
|
||||||
ref := &v.Tree.References[i]
|
ref := &v.Tree.References[i]
|
||||||
@@ -409,6 +493,10 @@ func (v *Validator) getFieldValue(f *parser.Field) string {
|
|||||||
return val.Value
|
return val.Value
|
||||||
case *parser.ReferenceValue:
|
case *parser.ReferenceValue:
|
||||||
return val.Value
|
return val.Value
|
||||||
|
case *parser.IntValue:
|
||||||
|
return val.Raw
|
||||||
|
case *parser.FloatValue:
|
||||||
|
return val.Raw
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
@@ -533,14 +621,24 @@ func (v *Validator) collectTargetUsage(node *index.ProjectNode, referenced map[*
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v *Validator) checkUnusedRecursive(node *index.ProjectNode, referenced map[*index.ProjectNode]bool) {
|
func (v *Validator) checkUnusedRecursive(node *index.ProjectNode, referenced map[*index.ProjectNode]bool) {
|
||||||
|
// Heuristic for GAM
|
||||||
if isGAM(node) {
|
if isGAM(node) {
|
||||||
if !referenced[node] {
|
if !referenced[node] {
|
||||||
v.Diagnostics = append(v.Diagnostics, Diagnostic{
|
suppress := false
|
||||||
Level: LevelWarning,
|
for _, p := range node.Pragmas {
|
||||||
Message: fmt.Sprintf("Unused GAM: %s is defined but not referenced in any thread or scheduler", node.RealName),
|
if strings.HasPrefix(p, "unused:") {
|
||||||
Position: v.getNodePosition(node),
|
suppress = true
|
||||||
File: v.getNodeFile(node),
|
break
|
||||||
})
|
}
|
||||||
|
}
|
||||||
|
if !suppress {
|
||||||
|
v.Diagnostics = append(v.Diagnostics, Diagnostic{
|
||||||
|
Level: LevelWarning,
|
||||||
|
Message: fmt.Sprintf("Unused GAM: %s is defined but not referenced in any thread or scheduler", node.RealName),
|
||||||
|
Position: v.getNodePosition(node),
|
||||||
|
File: v.getNodeFile(node),
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -549,12 +647,21 @@ func (v *Validator) checkUnusedRecursive(node *index.ProjectNode, referenced map
|
|||||||
if signalsNode, ok := node.Children["Signals"]; ok {
|
if signalsNode, ok := node.Children["Signals"]; ok {
|
||||||
for _, signal := range signalsNode.Children {
|
for _, signal := range signalsNode.Children {
|
||||||
if !referenced[signal] {
|
if !referenced[signal] {
|
||||||
v.Diagnostics = append(v.Diagnostics, Diagnostic{
|
suppress := false
|
||||||
Level: LevelWarning,
|
for _, p := range signal.Pragmas {
|
||||||
Message: fmt.Sprintf("Unused Signal: %s is defined in DataSource %s but never referenced", signal.RealName, node.RealName),
|
if strings.HasPrefix(p, "unused:") {
|
||||||
Position: v.getNodePosition(signal),
|
suppress = true
|
||||||
File: v.getNodeFile(signal),
|
break
|
||||||
})
|
}
|
||||||
|
}
|
||||||
|
if !suppress {
|
||||||
|
v.Diagnostics = append(v.Diagnostics, Diagnostic{
|
||||||
|
Level: LevelWarning,
|
||||||
|
Message: fmt.Sprintf("Unused Signal: %s is defined in DataSource %s but never referenced", signal.RealName, node.RealName),
|
||||||
|
Position: v.getNodePosition(signal),
|
||||||
|
File: v.getNodeFile(signal),
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -602,4 +709,4 @@ func (v *Validator) getNodeFile(node *index.ProjectNode) string {
|
|||||||
return node.Fragments[0].File
|
return node.Fragments[0].File
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
107
test/validator_implicit_signal_test.go
Normal file
107
test/validator_implicit_signal_test.go
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/marte-dev/marte-dev-tools/internal/index"
|
||||||
|
"github.com/marte-dev/marte-dev-tools/internal/parser"
|
||||||
|
"github.com/marte-dev/marte-dev-tools/internal/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestImplicitSignal(t *testing.T) {
|
||||||
|
content := `
|
||||||
|
+Data = {
|
||||||
|
Class = ReferenceContainer
|
||||||
|
+MyDS = {
|
||||||
|
Class = FileReader
|
||||||
|
Filename = "test"
|
||||||
|
Signals = {
|
||||||
|
ExplicitSig = { Type = uint32 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+MyGAM = {
|
||||||
|
Class = IOGAM
|
||||||
|
InputSignals = {
|
||||||
|
ExplicitSig = {
|
||||||
|
DataSource = MyDS
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
ImplicitSig = {
|
||||||
|
DataSource = MyDS
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
p := parser.NewParser(content)
|
||||||
|
config, err := p.Parse()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Parse failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
idx := index.NewProjectTree()
|
||||||
|
idx.AddFile("implicit_signal.marte", config)
|
||||||
|
idx.ResolveReferences()
|
||||||
|
|
||||||
|
v := validator.NewValidator(idx, ".")
|
||||||
|
v.ValidateProject()
|
||||||
|
|
||||||
|
foundWarning := false
|
||||||
|
foundError := false
|
||||||
|
|
||||||
|
for _, d := range v.Diagnostics {
|
||||||
|
if strings.Contains(d.Message, "Implicitly Defined Signal") {
|
||||||
|
if strings.Contains(d.Message, "ImplicitSig") {
|
||||||
|
foundWarning = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if strings.Contains(d.Message, "Signal 'ExplicitSig' not found") {
|
||||||
|
foundError = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !foundWarning || foundError {
|
||||||
|
for _, d := range v.Diagnostics {
|
||||||
|
t.Logf("Diagnostic: %s", d.Message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !foundWarning {
|
||||||
|
t.Error("Expected warning for ImplicitSig")
|
||||||
|
}
|
||||||
|
if foundError {
|
||||||
|
t.Error("Unexpected error for ExplicitSig")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test missing Type for implicit
|
||||||
|
contentMissingType := `
|
||||||
|
+Data = { Class = ReferenceContainer +DS={Class=FileReader Filename="" Signals={}} }
|
||||||
|
+GAM = { Class = IOGAM InputSignals = { Impl = { DataSource = DS } } }
|
||||||
|
`
|
||||||
|
p2 := parser.NewParser(contentMissingType)
|
||||||
|
config2, err2 := p2.Parse()
|
||||||
|
if err2 != nil {
|
||||||
|
t.Fatalf("Parse2 failed: %v", err2)
|
||||||
|
}
|
||||||
|
idx2 := index.NewProjectTree()
|
||||||
|
idx2.AddFile("missing_type.marte", config2)
|
||||||
|
idx2.ResolveReferences()
|
||||||
|
v2 := validator.NewValidator(idx2, ".")
|
||||||
|
v2.ValidateProject()
|
||||||
|
|
||||||
|
foundTypeErr := false
|
||||||
|
for _, d := range v2.Diagnostics {
|
||||||
|
if strings.Contains(d.Message, "Implicit signal 'Impl' must define Type") {
|
||||||
|
foundTypeErr = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !foundTypeErr {
|
||||||
|
for _, d := range v2.Diagnostics {
|
||||||
|
t.Logf("Diagnostic2: %s", d.Message)
|
||||||
|
}
|
||||||
|
t.Error("Expected error for missing Type in implicit signal")
|
||||||
|
}
|
||||||
|
}
|
||||||
69
test/validator_pragma_test.go
Normal file
69
test/validator_pragma_test.go
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/marte-dev/marte-dev-tools/internal/index"
|
||||||
|
"github.com/marte-dev/marte-dev-tools/internal/parser"
|
||||||
|
"github.com/marte-dev/marte-dev-tools/internal/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPragmaSuppression(t *testing.T) {
|
||||||
|
content := `
|
||||||
|
+Data = {
|
||||||
|
Class = ReferenceContainer
|
||||||
|
+MyDS = {
|
||||||
|
Class = FileReader
|
||||||
|
Filename = "test"
|
||||||
|
Signals = {
|
||||||
|
//!unused: Ignore this
|
||||||
|
UnusedSig = { Type = uint32 }
|
||||||
|
UsedSig = { Type = uint32 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+MyGAM = {
|
||||||
|
Class = IOGAM
|
||||||
|
InputSignals = {
|
||||||
|
UsedSig = { DataSource = MyDS Type = uint32 }
|
||||||
|
|
||||||
|
//!implicit: Ignore this implicit
|
||||||
|
ImplicitSig = { DataSource = MyDS Type = uint32 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
p := parser.NewParser(content)
|
||||||
|
config, err := p.Parse()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Parse failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
idx := index.NewProjectTree()
|
||||||
|
idx.AddFile("pragma.marte", config)
|
||||||
|
idx.ResolveReferences()
|
||||||
|
|
||||||
|
v := validator.NewValidator(idx, ".")
|
||||||
|
v.ValidateProject()
|
||||||
|
v.CheckUnused()
|
||||||
|
|
||||||
|
foundUnusedWarning := false
|
||||||
|
foundImplicitWarning := false
|
||||||
|
|
||||||
|
for _, d := range v.Diagnostics {
|
||||||
|
if strings.Contains(d.Message, "Unused Signal") && strings.Contains(d.Message, "UnusedSig") {
|
||||||
|
foundUnusedWarning = true
|
||||||
|
}
|
||||||
|
if strings.Contains(d.Message, "Implicitly Defined Signal") && strings.Contains(d.Message, "ImplicitSig") {
|
||||||
|
foundImplicitWarning = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if foundUnusedWarning {
|
||||||
|
t.Error("Expected warning for UnusedSig to be suppressed")
|
||||||
|
}
|
||||||
|
if foundImplicitWarning {
|
||||||
|
t.Error("Expected warning for ImplicitSig to be suppressed")
|
||||||
|
}
|
||||||
|
}
|
||||||
108
test/validator_signal_properties_test.go
Normal file
108
test/validator_signal_properties_test.go
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/marte-dev/marte-dev-tools/internal/index"
|
||||||
|
"github.com/marte-dev/marte-dev-tools/internal/parser"
|
||||||
|
"github.com/marte-dev/marte-dev-tools/internal/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSignalProperties(t *testing.T) {
|
||||||
|
content := `
|
||||||
|
+Data = {
|
||||||
|
Class = ReferenceContainer
|
||||||
|
+MyDS = {
|
||||||
|
Class = FileReader
|
||||||
|
Filename = "test"
|
||||||
|
Signals = {
|
||||||
|
Correct = { Type = uint32 NumberOfElements = 10 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+MyGAM = {
|
||||||
|
Class = IOGAM
|
||||||
|
InputSignals = {
|
||||||
|
// Correct reference
|
||||||
|
Correct = { DataSource = MyDS Type = uint32 NumberOfElements = 10 }
|
||||||
|
|
||||||
|
// Mismatch Type
|
||||||
|
BadType = {
|
||||||
|
Alias = Correct
|
||||||
|
DataSource = MyDS
|
||||||
|
Type = float32 // Error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mismatch Elements
|
||||||
|
BadElements = {
|
||||||
|
Alias = Correct
|
||||||
|
DataSource = MyDS
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 20 // Error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Valid Cast
|
||||||
|
//!cast(uint32, float32): Cast reason
|
||||||
|
CastSig = {
|
||||||
|
Alias = Correct
|
||||||
|
DataSource = MyDS
|
||||||
|
Type = float32 // OK
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invalid Cast (Wrong definition type in pragma)
|
||||||
|
//!cast(int32, float32): Wrong def type
|
||||||
|
BadCast = {
|
||||||
|
Alias = Correct
|
||||||
|
DataSource = MyDS
|
||||||
|
Type = float32 // Error because pragma mismatch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
p := parser.NewParser(content)
|
||||||
|
config, err := p.Parse()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Parse failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
idx := index.NewProjectTree()
|
||||||
|
idx.AddFile("signal_props.marte", config)
|
||||||
|
idx.ResolveReferences()
|
||||||
|
|
||||||
|
v := validator.NewValidator(idx, ".")
|
||||||
|
v.ValidateProject()
|
||||||
|
|
||||||
|
foundBadType := false
|
||||||
|
foundBadElements := false
|
||||||
|
foundBadCast := false
|
||||||
|
|
||||||
|
for _, d := range v.Diagnostics {
|
||||||
|
if strings.Contains(d.Message, "property 'Type' mismatch") {
|
||||||
|
if strings.Contains(d.Message, "'BadType'") {
|
||||||
|
foundBadType = true
|
||||||
|
}
|
||||||
|
if strings.Contains(d.Message, "'BadCast'") {
|
||||||
|
foundBadCast = true
|
||||||
|
}
|
||||||
|
if strings.Contains(d.Message, "'CastSig'") {
|
||||||
|
t.Error("Unexpected error for CastSig (should be suppressed by pragma)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Contains(d.Message, "property 'NumberOfElements' mismatch") {
|
||||||
|
foundBadElements = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !foundBadType {
|
||||||
|
t.Error("Expected error for BadType")
|
||||||
|
}
|
||||||
|
if !foundBadElements {
|
||||||
|
t.Error("Expected error for BadElements")
|
||||||
|
}
|
||||||
|
if !foundBadCast {
|
||||||
|
t.Error("Expected error for BadCast (pragma mismatch)")
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user