Skip to content

Commit

Permalink
🍺 supported AssertStmt statement (#179)
Browse files Browse the repository at this point in the history
  • Loading branch information
shivasurya authored Nov 6, 2024
1 parent 6ba07a3 commit db8d91e
Show file tree
Hide file tree
Showing 7 changed files with 173 additions and 0 deletions.
16 changes: 16 additions & 0 deletions sourcecode-parser/graph/construct.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ type Node struct {
BreakStmt *model.BreakStmt
ContinueStmt *model.ContinueStmt
YieldStmt *model.YieldStmt
AssertStmt *model.AssertStmt
}

type Edge struct {
Expand Down Expand Up @@ -181,6 +182,21 @@ func parseJavadocTags(commentContent string) *model.Javadoc {
func buildGraphFromAST(node *sitter.Node, sourceCode []byte, graph *CodeGraph, currentContext *Node, file string) {
isJavaSourceFile := isJavaSourceFile(file)
switch node.Type() {
case "assert_statement":
assertNode := javalang.ParseAssertStatement(node, sourceCode)
uniqueAssertID := fmt.Sprintf("assert_%d_%d_%s", node.StartPoint().Row+1, node.StartPoint().Column+1, file)
assertStmtNode := &Node{
ID: GenerateSha256(uniqueAssertID),
Type: "AssertStmt",
LineNumber: node.StartPoint().Row + 1,
Name: "AssertStmt",
IsExternal: true,
CodeSnippet: node.Content(sourceCode),
File: file,
isJavaSourceFile: isJavaSourceFile,
AssertStmt: assertNode,
}
graph.AddNode(assertStmtNode)
case "yield_statement":
yieldNode := javalang.ParseYieldStatement(node, sourceCode)
uniqueyieldID := fmt.Sprintf("yield_%d_%d_%s", node.StartPoint().Row+1, node.StartPoint().Column+1, file)
Expand Down
9 changes: 9 additions & 0 deletions sourcecode-parser/graph/java/parse_statement.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,12 @@ func ParseYieldStatement(node *sitter.Node, sourcecode []byte) *model.YieldStmt
yieldStmt.Value = yieldStmtExpr
return yieldStmt
}

func ParseAssertStatement(node *sitter.Node, sourcecode []byte) *model.AssertStmt {
assertStmt := &model.AssertStmt{}
assertStmt.Expr = &model.Expr{NodeString: node.Child(1).Content(sourcecode)}
if node.Child(3) != nil && node.Child(3).Type() == "string_literal" {
assertStmt.Message = &model.Expr{NodeString: node.Child(3).Content(sourcecode)}
}
return assertStmt
}
61 changes: 61 additions & 0 deletions sourcecode-parser/graph/java/parse_statement_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,3 +136,64 @@ func TestParseYieldStatement(t *testing.T) {
})
}
}

func TestParseAssertStatement(t *testing.T) {
tests := []struct {
name string
input string
expected *model.AssertStmt
}{
{
name: "Simple assert statement without message",
input: "assert x > 0;",
expected: &model.AssertStmt{
Expr: &model.Expr{NodeString: "x > 0"},
Message: nil,
},
},
{
name: "Assert statement with message",
input: "assert condition : \"Value must be positive\";",
expected: &model.AssertStmt{
Expr: &model.Expr{NodeString: "condition"},
Message: &model.Expr{NodeString: "\"Value must be positive\""},
},
},
{
name: "Assert statement with boolean literal",
input: "assert true;",
expected: &model.AssertStmt{
Expr: &model.Expr{NodeString: "true"},
Message: nil,
},
},
{
name: "Assert statement with complex expression",
input: "assert x != null && x.isValid();",
expected: &model.AssertStmt{
Expr: &model.Expr{NodeString: "x != null && x.isValid()"},
Message: nil,
},
},
{
name: "Assert statement with method call and message",
input: "assert obj.validate() : \"Validation failed\";",
expected: &model.AssertStmt{
Expr: &model.Expr{NodeString: "obj.validate()"},
Message: &model.Expr{NodeString: "\"Validation failed\""},
},
},
}

parser := sitter.NewParser()
parser.SetLanguage(java.GetLanguage())

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tree := parser.Parse(nil, []byte(tt.input))
node := tree.RootNode().Child(0)
result := ParseAssertStatement(node, []byte(tt.input))
assert.Equal(t, tt.expected, result)
})
}
}
11 changes: 11 additions & 0 deletions sourcecode-parser/graph/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,10 @@ func (env *Env) GetYieldStmt() *model.YieldStmt {
return env.Node.YieldStmt
}

func (env *Env) GetAssertStmt() *model.AssertStmt {
return env.Node.AssertStmt
}

func QueryEntities(graph *CodeGraph, query parser.Query) (nodes [][]*Node, output [][]interface{}) {
result := make([][]*Node, 0)

Expand Down Expand Up @@ -325,6 +329,7 @@ func generateProxyEnv(node *Node, query parser.Query) map[string]interface{} {
breakStmt := "BreakStmt"
continueStmt := "ContinueStmt"
yieldStmt := "YieldStmt"
assertStmt := "AssertStmt"

// print query select list
for _, entity := range query.SelectList {
Expand Down Expand Up @@ -387,6 +392,8 @@ func generateProxyEnv(node *Node, query parser.Query) map[string]interface{} {
continueStmt = entity.Alias
case "YieldStmt":
yieldStmt = entity.Alias
case "AssertStmt":
assertStmt = entity.Alias
}
}
env := map[string]interface{}{
Expand Down Expand Up @@ -545,6 +552,10 @@ func generateProxyEnv(node *Node, query parser.Query) map[string]interface{} {
"toString": proxyenv.ToString,
"getYieldStmt": proxyenv.GetYieldStmt,
},
assertStmt: map[string]interface{}{
"toString": proxyenv.ToString,
"getAssertStmt": proxyenv.GetAssertStmt,
},
}
return env
}
Expand Down
40 changes: 40 additions & 0 deletions sourcecode-parser/model/stmt.go
Original file line number Diff line number Diff line change
Expand Up @@ -301,3 +301,43 @@ func (yieldStmt *YieldStmt) ToString() string {
func (yieldStmt *YieldStmt) GetValue() *Expr {
return yieldStmt.Value
}

type AssertStmt struct {
Stmt
Expr *Expr
Message *Expr
}

type IAssertStmt interface {
GetAPrimaryQlClass() string
GetHalsteadID() int
GetPP() string
ToString() string
GetMessage() *Expr
GetExpr() *Expr
}

func (assertStmt *AssertStmt) GetAPrimaryQlClass() string {
return "AssertStmt"
}

func (assertStmt *AssertStmt) GetHalsteadID() int {
// TODO: Implement Halstead ID calculation for AssertStmt
return 0
}

func (assertStmt *AssertStmt) GetPP() string {
return fmt.Sprintf("assert %s", assertStmt.Expr.NodeString)
}

func (assertStmt *AssertStmt) ToString() string {
return fmt.Sprintf("assert %s", assertStmt.Expr.NodeString)
}

func (assertStmt *AssertStmt) GetMessage() *Expr {
return assertStmt.Message
}

func (assertStmt *AssertStmt) GetExpr() *Expr {
return assertStmt.Expr
}
35 changes: 35 additions & 0 deletions sourcecode-parser/model/stmt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -349,3 +349,38 @@ func TestYieldStmt_GetPP(t *testing.T) {
assert.Equal(t, "yield \"test string\"", yieldStmt.GetPP())
})
}

func TestAssertStmt_GetMessage(t *testing.T) {
t.Run("GetMessage with non-nil message", func(t *testing.T) {
message := &Expr{NodeString: "Expected value to be positive"}
assertStmt := &AssertStmt{
Message: message,
}
assert.Equal(t, message, assertStmt.GetMessage())
})

t.Run("GetMessage with nil message", func(t *testing.T) {
assertStmt := &AssertStmt{
Message: nil,
}
assert.Nil(t, assertStmt.GetMessage())
})

t.Run("GetMessage with complex expression", func(t *testing.T) {
message := &Expr{NodeString: "String.format(\"Value %d should be greater than zero\", value)"}
assertStmt := &AssertStmt{
Message: message,
}
assert.Equal(t, message, assertStmt.GetMessage())
})

t.Run("GetMessage preserves expression reference", func(t *testing.T) {
message := &Expr{NodeString: "Initial message"}
assertStmt := &AssertStmt{
Message: message,
}
retrievedMessage := assertStmt.GetMessage()
message.NodeString = "Modified message"
assert.Equal(t, "Modified message", retrievedMessage.NodeString)
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ public void onBackPressed() {
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
assert id > 0 : "Invalid item id";
if (id == android.R.id.home) {
onBackPressed();
return true;
Expand Down

0 comments on commit db8d91e

Please sign in to comment.