Skip to content

Commit d5c8469

Browse files
gkorlandCopilot
andcommitted
fix(test): update tests for entity class refactoring
The entity classes (Struct, Class, Function) were removed in commit 19231c7 but the tests were not updated. Also replaced GitPython with pygit2 in test_git_history.py to match the project dependency. Changes: - test_c_analyzer.py: use FalkorDB Node property comparisons - test_py_analyzer.py: use FalkorDB Node property comparisons - test_git_history.py: replace GitPython with pygit2 API - test_graph_ops.py: use add_entity() and Node properties - api/graph.py: fix get_file() to return Node (consistent with other getters; old code called deleted File constructor) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 887b82f commit d5c8469

File tree

5 files changed

+111
-92
lines changed

5 files changed

+111
-92
lines changed

api/graph.py

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -426,22 +426,18 @@ def delete_files(self, files: list[Path]) -> tuple[str, dict, list[int]]:
426426

427427
return None
428428

429-
def get_file(self, path: str, name: str, ext: str) -> Optional[File]:
429+
def get_file(self, path: str, name: str, ext: str) -> Optional[Node]:
430430
"""
431-
Retrieves a File entity from the graph database based on its path, name, and extension.
431+
Retrieves a File node from the graph database based on its path, name,
432+
and extension.
432433
433434
Args:
434435
path (str): The file path.
435436
name (str): The file name.
436437
ext (str): The file extension.
437438
438439
Returns:
439-
Optional[File]: The File object if found, otherwise None.
440-
441-
This method constructs and executes a query to find a file node in the graph
442-
database with the specified path, name, and extension. If the file node is found,
443-
it creates and returns a File object with its properties and ID. If no such node
444-
is found, it returns None.
440+
Optional[Node]: The File node if found, otherwise None.
445441
446442
Example:
447443
file = self.get_file('/path/to/file', 'filename', '.py')
@@ -452,19 +448,10 @@ def get_file(self, path: str, name: str, ext: str) -> Optional[File]:
452448
params = {'path': path, 'name': name, 'ext': ext}
453449

454450
res = self._query(q, params)
455-
if(len(res.result_set) == 0):
451+
if len(res.result_set) == 0:
456452
return None
457453

458-
node = res.result_set[0][0]
459-
460-
ext = node.properties['ext']
461-
path = node.properties['path']
462-
name = node.properties['name']
463-
file = File(path, name, ext)
464-
465-
file.id = node.id
466-
467-
return file
454+
return res.result_set[0][0]
468455

469456
# set file code coverage
470457
# if file coverage is 100% set every defined function coverage to 100% aswell

tests/test_c_analyzer.py

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
import unittest
33
from pathlib import Path
44

5-
from api import SourceAnalyzer, File, Struct, Function, Graph
5+
from api import SourceAnalyzer, Graph
6+
67

78
class Test_C_Analyzer(unittest.TestCase):
89
def test_analyzer(self):
@@ -24,37 +25,44 @@ def test_analyzer(self):
2425
analyzer.analyze_local_folder(path, g)
2526

2627
f = g.get_file('', 'src.c', '.c')
27-
self.assertEqual(File('', 'src.c', '.c'), f)
28+
self.assertIsNotNone(f)
29+
self.assertEqual(f.properties['name'], 'src.c')
30+
self.assertEqual(f.properties['ext'], '.c')
2831

2932
s = g.get_struct_by_name('exp')
30-
expected_s = Struct('src.c', 'exp', '', 9, 13)
31-
expected_s.add_field('i', 'int')
32-
expected_s.add_field('f', 'float')
33-
expected_s.add_field('data', 'char[]')
34-
self.assertEqual(expected_s, s)
33+
self.assertIsNotNone(s)
34+
self.assertEqual(s.properties['name'], 'exp')
35+
self.assertEqual(s.properties['path'], 'src.c')
36+
self.assertEqual(s.properties['src_start'], 9)
37+
self.assertEqual(s.properties['src_end'], 13)
38+
self.assertEqual(s.properties['fields'], [['i', 'int'], ['f', 'float'], ['data', 'char[]']])
3539

3640
add = g.get_function_by_name('add')
37-
38-
expected_add = Function('src.c', 'add', '', 'int', '', 0, 7)
39-
expected_add.add_argument('a', 'int')
40-
expected_add.add_argument('b', 'int')
41-
self.assertEqual(expected_add, add)
42-
self.assertIn('a + b', add.src)
41+
self.assertIsNotNone(add)
42+
self.assertEqual(add.properties['name'], 'add')
43+
self.assertEqual(add.properties['path'], 'src.c')
44+
self.assertEqual(add.properties['ret_type'], 'int')
45+
self.assertEqual(add.properties['src_start'], 0)
46+
self.assertEqual(add.properties['src_end'], 7)
47+
self.assertEqual(add.properties['args'], [['a', 'int'], ['b', 'int']])
48+
self.assertIn('a + b', add.properties['src'])
4349

4450
main = g.get_function_by_name('main')
45-
46-
expected_main = Function('src.c', 'main', '', 'int', '', 15, 18)
47-
expected_main.add_argument('argv', 'const char**')
48-
expected_main.add_argument('argc', 'int')
49-
self.assertEqual(expected_main, main)
50-
self.assertIn('x = add', main.src)
51+
self.assertIsNotNone(main)
52+
self.assertEqual(main.properties['name'], 'main')
53+
self.assertEqual(main.properties['path'], 'src.c')
54+
self.assertEqual(main.properties['ret_type'], 'int')
55+
self.assertEqual(main.properties['src_start'], 15)
56+
self.assertEqual(main.properties['src_end'], 18)
57+
self.assertEqual(main.properties['args'], [['argv', 'const char**'], ['argc', 'int']])
58+
self.assertIn('x = add', main.properties['src'])
5159

5260
callees = g.function_calls(main.id)
5361
self.assertEqual(len(callees), 1)
5462
self.assertEqual(callees[0], add)
5563

5664
callers = g.function_called_by(add.id)
57-
callers = [caller.name for caller in callers]
65+
callers = [caller.properties['name'] for caller in callers]
5866

5967
self.assertEqual(len(callers), 2)
6068
self.assertIn('add', callers)

tests/test_git_history.py

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import os
22
import unittest
3-
from git import Repo
3+
import pygit2
44
from api import (
5-
Graph,
65
Project,
76
switch_commit
87
)
@@ -30,8 +29,8 @@ def setUpClass(cls):
3029
repo_dir = os.path.join(current_dir, 'git_repo')
3130

3231
# Checkout HEAD commit
33-
repo = Repo(repo_dir)
34-
repo.git.checkout("HEAD")
32+
repo = pygit2.Repository(repo_dir)
33+
repo.checkout_head()
3534

3635
proj = Project.from_local_repository(repo_dir)
3736
graph = proj.analyze_sources()
@@ -45,13 +44,13 @@ def assert_file_exists(self, path: str, name: str, ext: str) -> None:
4544
f = graph.get_file(path, name, ext)
4645

4746
self.assertIsNotNone(f)
48-
self.assertEqual(f.ext, ext)
49-
self.assertEqual(f.path, path)
50-
self.assertEqual(f.name, name)
47+
self.assertEqual(f.properties['ext'], ext)
48+
self.assertEqual(f.properties['path'], path)
49+
self.assertEqual(f.properties['name'], name)
5150

5251
def test_git_graph_structure(self):
5352
# validate git graph structure
54-
c = repo.commit("HEAD")
53+
c = repo.revparse_single("HEAD")
5554

5655
while True:
5756
commits = git_graph.get_commits([c.short_id])
@@ -62,13 +61,13 @@ def test_git_graph_structure(self):
6261
self.assertEqual(c.short_id, actual['hash'])
6362
self.assertEqual(c.message, actual['message'])
6463
self.assertEqual(c.author.name, actual['author'])
65-
self.assertEqual(c.committed_date, actual['date'])
64+
self.assertEqual(c.commit_time, actual['date'])
6665

6766
# Advance to previous commit
68-
if len(c.parents) == 0:
67+
if len(c.parent_ids) == 0:
6968
break
7069

71-
c = c.parents[0]
70+
c = repo.get(c.parent_ids[0])
7271

7372
def test_git_transitions(self):
7473
# our test git repo:

tests/test_graph_ops.py

Lines changed: 35 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import unittest
2+
from pathlib import Path
23
from falkordb import FalkorDB
3-
from typing import List, Optional
4-
from api import *
4+
from api import Graph
5+
from api.entities import File
56

67

78
class TestGraphOps(unittest.TestCase):
@@ -11,50 +12,60 @@ def setUp(self):
1112
self.graph = Graph(name='test')
1213

1314
def test_add_function(self):
14-
# Create function
15-
func = Function('/path/to/function', 'func', '', 'int', '', 1, 10)
16-
func.add_argument('x', 'int')
17-
func.add_argument('y', 'float')
18-
19-
self.graph.add_function(func)
20-
self.assertEqual(func, self.graph.get_function(func.id))
15+
func_id = self.graph.add_entity(
16+
'Function', 'func', '', '/path/to/function', 1, 10,
17+
{'ret_type': 'int', 'src': '', 'args': [['x', 'int'], ['y', 'float']]}
18+
)
19+
result = self.graph.get_function(func_id)
20+
self.assertIsNotNone(result)
21+
self.assertEqual(result.properties['name'], 'func')
22+
self.assertEqual(result.properties['ret_type'], 'int')
23+
self.assertEqual(result.properties['args'], [['x', 'int'], ['y', 'float']])
2124

2225
def test_add_file(self):
23-
file = File('/path/to/file', 'file', 'txt')
24-
26+
file = File(Path('/path/to/file.txt'), None)
2527
self.graph.add_file(file)
26-
self.assertEqual(file, self.graph.get_file('/path/to/file', 'file', 'txt'))
28+
result = self.graph.get_file('/path/to/file.txt', 'file.txt', '.txt')
29+
self.assertIsNotNone(result)
30+
self.assertEqual(result.properties['name'], 'file.txt')
31+
self.assertEqual(result.properties['ext'], '.txt')
2732

2833
def test_file_add_function(self):
29-
file = File('/path/to/file', 'file', 'txt')
30-
func = Function('/path/to/function', 'func', '', 'int', '', 1, 10)
31-
34+
file = File(Path('/path/to/file.txt'), None)
3235
self.graph.add_file(file)
33-
self.graph.add_function(func)
3436

35-
self.graph.connect_entities("CONTAINS", file.id, func.id)
37+
func_id = self.graph.add_entity(
38+
'Function', 'func', '', '/path/to/function', 1, 10,
39+
{'ret_type': 'int', 'src': '', 'args': []}
40+
)
41+
42+
self.graph.connect_entities("CONTAINS", file.id, func_id)
3643

3744
query = """MATCH (file:File)-[:CONTAINS]->(func:Function)
3845
WHERE ID(func) = $func_id AND ID(file) = $file_id
3946
RETURN true"""
4047

41-
params = {'file_id': file.id, 'func_id': func.id}
48+
params = {'file_id': file.id, 'func_id': func_id}
4249
res = self.g.query(query, params).result_set
4350
self.assertTrue(res[0][0])
4451

4552
def test_function_calls_function(self):
46-
caller = Function('/path/to/function', 'func_A', '', 'int', '', 1, 10)
47-
callee = Function('/path/to/function', 'func_B', '', 'int', '', 11, 21)
53+
caller_id = self.graph.add_entity(
54+
'Function', 'func_A', '', '/path/to/function', 1, 10,
55+
{'ret_type': 'int', 'src': '', 'args': []}
56+
)
57+
callee_id = self.graph.add_entity(
58+
'Function', 'func_B', '', '/path/to/function', 11, 21,
59+
{'ret_type': 'int', 'src': '', 'args': []}
60+
)
4861

49-
self.graph.add_function(caller)
50-
self.graph.add_function(callee)
51-
self.graph.function_calls_function(caller.id, callee.id, 10)
62+
self.graph.function_calls_function(caller_id, callee_id, 10)
5263

5364
query = """MATCH (caller:Function)-[:CALLS]->(callee:Function)
5465
WHERE ID(caller) = $caller_id AND ID(callee) = $callee_id
5566
RETURN true"""
5667

57-
params = {'caller_id': caller.id, 'callee_id': callee.id}
68+
params = {'caller_id': caller_id, 'callee_id': callee_id}
5869
res = self.g.query(query, params).result_set
5970
self.assertTrue(res[0][0])
6071

tests/test_py_analyzer.py

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
import unittest
33
from pathlib import Path
44

5-
from api import SourceAnalyzer, File, Class, Function, Graph
5+
from api import SourceAnalyzer, Graph
6+
67

78
class Test_PY_Analyzer(unittest.TestCase):
89
def test_analyzer(self):
@@ -15,7 +16,7 @@ def test_analyzer(self):
1516
# Get the directory of the current file
1617
current_dir = os.path.dirname(current_file_path)
1718

18-
# Append 'source_files/c' to the current directory
19+
# Append 'source_files/py' to the current directory
1920
path = os.path.join(current_dir, 'source_files')
2021
path = os.path.join(path, 'py')
2122
path = str(path)
@@ -24,37 +25,50 @@ def test_analyzer(self):
2425
analyzer.analyze_local_folder(path, g)
2526

2627
f = g.get_file('', 'src.py', '.py')
27-
self.assertEqual(File('', 'src.py', '.py'), f)
28+
self.assertIsNotNone(f)
29+
self.assertEqual(f.properties['name'], 'src.py')
30+
self.assertEqual(f.properties['ext'], '.py')
2831

2932
log = g.get_function_by_name('log')
30-
expected_log = Function('src.py', 'log', None, 'None', '', 0, 1)
31-
expected_log.add_argument('msg', 'str')
32-
self.assertEqual(expected_log, log)
33+
self.assertIsNotNone(log)
34+
self.assertEqual(log.properties['name'], 'log')
35+
self.assertEqual(log.properties['path'], 'src.py')
36+
self.assertEqual(log.properties['ret_type'], 'None')
37+
self.assertEqual(log.properties['src_start'], 0)
38+
self.assertEqual(log.properties['src_end'], 1)
39+
self.assertEqual(log.properties['args'], [['msg', 'str']])
3340

3441
abort = g.get_function_by_name('abort')
35-
expected_abort = Function('src.py', 'abort', None, 'Task', '', 9, 11)
36-
expected_abort.add_argument('self', 'Unknown')
37-
expected_abort.add_argument('delay', 'float')
38-
self.assertEqual(expected_abort, abort)
42+
self.assertIsNotNone(abort)
43+
self.assertEqual(abort.properties['name'], 'abort')
44+
self.assertEqual(abort.properties['path'], 'src.py')
45+
self.assertEqual(abort.properties['ret_type'], 'Task')
46+
self.assertEqual(abort.properties['src_start'], 9)
47+
self.assertEqual(abort.properties['src_end'], 11)
48+
self.assertEqual(abort.properties['args'], [['self', 'Unknown'], ['delay', 'float']])
3949

4050
init = g.get_function_by_name('__init__')
41-
expected_init = Function('src.py', '__init__', None, None, '', 4, 7)
42-
expected_init.add_argument('self', 'Unknown')
43-
expected_init.add_argument('name', 'str')
44-
expected_init.add_argument('duration', 'int')
45-
self.assertEqual(expected_init, init)
51+
self.assertIsNotNone(init)
52+
self.assertEqual(init.properties['name'], '__init__')
53+
self.assertEqual(init.properties['path'], 'src.py')
54+
self.assertEqual(init.properties['src_start'], 4)
55+
self.assertEqual(init.properties['src_end'], 7)
56+
self.assertEqual(init.properties['args'], [['self', 'Unknown'], ['name', 'str'], ['duration', 'int']])
4657

4758
task = g.get_class_by_name('Task')
48-
expected_task = Class('src.py', 'Task', None, 3, 11)
49-
self.assertEqual(expected_task, task)
59+
self.assertIsNotNone(task)
60+
self.assertEqual(task.properties['name'], 'Task')
61+
self.assertEqual(task.properties['path'], 'src.py')
62+
self.assertEqual(task.properties['src_start'], 3)
63+
self.assertEqual(task.properties['src_end'], 11)
5064

5165
callees = g.function_calls(abort.id)
5266
self.assertEqual(len(callees), 1)
5367
self.assertEqual(callees[0], log)
5468

5569
print_func = g.get_function_by_name('print')
5670
callers = g.function_called_by(print_func.id)
57-
callers = [caller.name for caller in callers]
71+
callers = [caller.properties['name'] for caller in callers]
5872

5973
self.assertIn('__init__', callers)
6074
self.assertIn('log', callers)

0 commit comments

Comments
 (0)