initial tests for callgraph

This commit is contained in:
ehrenb 2024-01-01 20:55:33 -05:00
parent 3f1bd97c43
commit a35c241a4b

101
tests/test_callgraph.py Normal file
View File

@ -0,0 +1,101 @@
from androguard.misc import AnalyzeAPK
from androguard.core.analysis.analysis import ExternalMethod
import os
import unittest
test_dir = os.path.dirname(os.path.abspath(__file__))
class TestCallgraph(unittest.TestCase):
@classmethod
def setUpClass(cls):
test_apk_path = os.path.join(test_dir, 'data/APK/TestActivity.apk')
cls.a, cls.d, cls.dx = AnalyzeAPK(test_apk_path)
def _get_num_nodes(self, callgraph):
num_external = 0
num_internal = 0
for n in callgraph:
if isinstance(n, ExternalMethod):
num_external+=1
else:
num_internal+=1
return callgraph.number_of_nodes(), num_external, num_internal
def testCallgraphTotalNodesEdges(self):
"""test callgraph generated with default parameter values"""
callgraph = self.dx.get_call_graph()
total_nodes, total_external_nodes, total_internal_nodes = self._get_num_nodes(callgraph)
# ensure total of internal and external nodes equals the total nodes
self.assertEqual(total_nodes, total_external_nodes + total_internal_nodes)
# total num nodes
self.assertEqual(total_nodes, 3600)
# num external nodes
self.assertEqual(total_external_nodes, 1000)
# num external nodes
self.assertEqual(total_internal_nodes, 2600)
# total num edges
self.assertEqual(callgraph.number_of_edges(), 4490)
def testCallgraphFilterClassname(self):
"""test callgraph with classname filter parameter"""
callgraph = self.dx.get_call_graph(classname='Ltests/androguard/*')
total_nodes, total_external_nodes, total_internal_nodes = self._get_num_nodes(callgraph)
self.assertEqual(total_nodes, 165)
self.assertEqual(total_external_nodes, 41)
self.assertEqual(total_internal_nodes, 124)
self.assertEqual(callgraph.number_of_edges(), 197)
def testCallgraphFilterMethodname(self):
"""test callgraph with methodname filter parameter"""
callgraph = self.dx.get_call_graph(methodname='Test*')
total_nodes, total_external_nodes, total_internal_nodes = self._get_num_nodes(callgraph)
self.assertEqual(total_nodes, 36)
self.assertEqual(total_external_nodes, 12)
self.assertEqual(total_internal_nodes, 24)
self.assertEqual(callgraph.number_of_edges(), 42)
def testCallgraphFilterDescriptor(self):
"""test callgraph with descriptor filter parameter"""
callgraph = self.dx.get_call_graph(descriptor='\(LTestDefaultPackage;\sI\sI\sLTestDefaultPackage\$TestInnerClass;\)V')
total_nodes, total_external_nodes, total_internal_nodes = self._get_num_nodes(callgraph)
self.assertEqual(total_nodes, 2)
self.assertEqual(total_external_nodes, 0)
self.assertEqual(total_internal_nodes, 2)
self.assertEqual(callgraph.number_of_edges(), 1)
# since this is a small graph, let's check some additional values
# get the source and destination node of the only edge
src_node, dst_node = list(callgraph.edges)[0]
# check source node
self.assertEqual(src_node.get_class_name(), 'LTestDefaultPackage$TestInnerClass;')
self.assertEqual(src_node.get_name(), '<init>')
self.assertEqual(src_node.get_access_flags_string(), 'synthetic constructor')
self.assertEqual(src_node.get_descriptor(), '(LTestDefaultPackage; I I LTestDefaultPackage$TestInnerClass;)V')
# check dest node
self.assertEqual(dst_node.get_class_name(), 'LTestDefaultPackage$TestInnerClass;')
self.assertEqual(dst_node.get_name(), '<init>')
self.assertEqual(dst_node.get_access_flags_string(), 'private constructor')
self.assertEqual(dst_node.get_descriptor(), '(LTestDefaultPackage; I I)V')
if __name__ == '__main__':
unittest.main()