Navegador

navegador / tests / test_bash_parser.py
Source Blame History 534 lines
b45288f… lmata 1 """Tests for navegador.ingestion.bash — BashParser internal methods."""
b45288f… lmata 2
b45288f… lmata 3 from unittest.mock import MagicMock, patch
b45288f… lmata 4
b45288f… lmata 5 import pytest
b45288f… lmata 6
b45288f… lmata 7 from navegador.graph.schema import EdgeType, NodeLabel
b45288f… lmata 8
b45288f… lmata 9
b45288f… lmata 10 class MockNode:
b45288f… lmata 11 _id_counter = 0
b45288f… lmata 12
b45288f… lmata 13 def __init__(
b45288f… lmata 14 self,
b45288f… lmata 15 type_: str,
b45288f… lmata 16 text: bytes = b"",
b45288f… lmata 17 children: list = None,
b45288f… lmata 18 start_byte: int = 0,
b45288f… lmata 19 end_byte: int = 0,
b45288f… lmata 20 start_point: tuple = (0, 0),
b45288f… lmata 21 end_point: tuple = (0, 0),
b45288f… lmata 22 parent=None,
b45288f… lmata 23 ):
b45288f… lmata 24 MockNode._id_counter += 1
b45288f… lmata 25 self.id = MockNode._id_counter
b45288f… lmata 26 self.type = type_
b45288f… lmata 27 self._text = text
b45288f… lmata 28 self.children = children or []
b45288f… lmata 29 self.start_byte = start_byte
b45288f… lmata 30 self.end_byte = end_byte
b45288f… lmata 31 self.start_point = start_point
b45288f… lmata 32 self.end_point = end_point
b45288f… lmata 33 self.parent = parent
b45288f… lmata 34 self._fields: dict = {}
b45288f… lmata 35 for child in self.children:
b45288f… lmata 36 child.parent = self
b45288f… lmata 37
b45288f… lmata 38 def child_by_field_name(self, name: str):
b45288f… lmata 39 return self._fields.get(name)
b45288f… lmata 40
b45288f… lmata 41 def set_field(self, name: str, node):
b45288f… lmata 42 self._fields[name] = node
b45288f… lmata 43 node.parent = self
b45288f… lmata 44 return self
b45288f… lmata 45
b45288f… lmata 46
b45288f… lmata 47 def _text_node(text: bytes, type_: str = "identifier") -> MockNode:
b45288f… lmata 48 return MockNode(type_, text, start_byte=0, end_byte=len(text))
b45288f… lmata 49
b45288f… lmata 50
b45288f… lmata 51 def _make_store():
b45288f… lmata 52 store = MagicMock()
b45288f… lmata 53 store.query.return_value = MagicMock(result_set=[])
b45288f… lmata 54 return store
b45288f… lmata 55
b45288f… lmata 56
b45288f… lmata 57 def _make_parser():
b45288f… lmata 58 from navegador.ingestion.bash import BashParser
b45288f… lmata 59
b45288f… lmata 60 parser = BashParser.__new__(BashParser)
b45288f… lmata 61 parser._parser = MagicMock()
b45288f… lmata 62 return parser
b45288f… lmata 63
b45288f… lmata 64
b45288f… lmata 65 class TestBashGetLanguage:
b45288f… lmata 66 def test_raises_when_not_installed(self):
b45288f… lmata 67 from navegador.ingestion.bash import _get_bash_language
b45288f… lmata 68
b45288f… lmata 69 with patch.dict(
b45288f… lmata 70 "sys.modules",
b45288f… lmata 71 {
b45288f… lmata 72 "tree_sitter_bash": None,
b45288f… lmata 73 "tree_sitter": None,
b45288f… lmata 74 },
b45288f… lmata 75 ):
b45288f… lmata 76 with pytest.raises(ImportError, match="tree-sitter-bash"):
b45288f… lmata 77 _get_bash_language()
b45288f… lmata 78
b45288f… lmata 79 def test_returns_language_object(self):
b45288f… lmata 80 from navegador.ingestion.bash import _get_bash_language
b45288f… lmata 81
b45288f… lmata 82 mock_tsbash = MagicMock()
b45288f… lmata 83 mock_ts = MagicMock()
b45288f… lmata 84 with patch.dict(
b45288f… lmata 85 "sys.modules",
b45288f… lmata 86 {
b45288f… lmata 87 "tree_sitter_bash": mock_tsbash,
b45288f… lmata 88 "tree_sitter": mock_ts,
b45288f… lmata 89 },
b45288f… lmata 90 ):
b45288f… lmata 91 result = _get_bash_language()
b45288f… lmata 92 assert result is mock_ts.Language.return_value
b45288f… lmata 93
b45288f… lmata 94
b45288f… lmata 95 class TestBashNodeText:
b45288f… lmata 96 def test_extracts_bytes(self):
b45288f… lmata 97 from navegador.ingestion.bash import _node_text
b45288f… lmata 98
b45288f… lmata 99 source = b"#!/bin/bash\nmy_func() {"
b45288f… lmata 100 node = MockNode(
b45288f… lmata 101 "identifier",
b45288f… lmata 102 start_byte=12,
b45288f… lmata 103 end_byte=19,
b45288f… lmata 104 )
b45288f… lmata 105 assert _node_text(node, source) == "my_func"
b45288f… lmata 106
b45288f… lmata 107
b45288f… lmata 108 class TestBashHandleFunction:
b45288f… lmata 109 def test_creates_function_node(self):
b45288f… lmata 110 parser = _make_parser()
b45288f… lmata 111 store = _make_store()
b45288f… lmata 112 source = b"deploy"
b45288f… lmata 113 name_node = MockNode(
b45288f… lmata 114 "word",
b45288f… lmata 115 start_byte=0,
b45288f… lmata 116 end_byte=6,
b45288f… lmata 117 )
b45288f… lmata 118 node = MockNode(
b45288f… lmata 119 "function_definition",
b45288f… lmata 120 start_point=(0, 0),
b45288f… lmata 121 end_point=(5, 1),
b45288f… lmata 122 )
b45288f… lmata 123 node.set_field("name", name_node)
b45288f… lmata 124 stats = {"functions": 0, "classes": 0, "edges": 0}
b45288f… lmata 125 parser._handle_function(node, source, "deploy.sh", store, stats)
b45288f… lmata 126 assert stats["functions"] == 1
b45288f… lmata 127 assert stats["edges"] == 1
b45288f… lmata 128 label = store.create_node.call_args[0][0]
b45288f… lmata 129 props = store.create_node.call_args[0][1]
b45288f… lmata 130 assert label == NodeLabel.Function
b45288f… lmata 131 assert props["name"] == "deploy"
b45288f… lmata 132 assert props["semantic_type"] == "shell_function"
b45288f… lmata 133
b45288f… lmata 134 def test_skips_if_no_name_node(self):
b45288f… lmata 135 parser = _make_parser()
b45288f… lmata 136 store = _make_store()
b45288f… lmata 137 node = MockNode(
b45288f… lmata 138 "function_definition",
b45288f… lmata 139 start_point=(0, 0),
b45288f… lmata 140 end_point=(0, 5),
b45288f… lmata 141 )
b45288f… lmata 142 stats = {"functions": 0, "classes": 0, "edges": 0}
b45288f… lmata 143 parser._handle_function(node, b"", "test.sh", store, stats)
b45288f… lmata 144 assert stats["functions"] == 0
b45288f… lmata 145 store.create_node.assert_not_called()
b45288f… lmata 146
b45288f… lmata 147 def test_extracts_calls_from_body(self):
b45288f… lmata 148 parser = _make_parser()
b45288f… lmata 149 store = _make_store()
b45288f… lmata 150 source = b"deploy helper"
b45288f… lmata 151 name_node = MockNode(
b45288f… lmata 152 "word",
b45288f… lmata 153 start_byte=0,
b45288f… lmata 154 end_byte=6,
b45288f… lmata 155 )
b45288f… lmata 156 callee_name = MockNode(
b45288f… lmata 157 "word",
b45288f… lmata 158 start_byte=7,
b45288f… lmata 159 end_byte=13,
b45288f… lmata 160 )
b45288f… lmata 161 cmd = MockNode("command")
b45288f… lmata 162 cmd.set_field("name", callee_name)
b45288f… lmata 163 body = MockNode(
b45288f… lmata 164 "compound_statement",
b45288f… lmata 165 children=[cmd],
b45288f… lmata 166 )
b45288f… lmata 167 node = MockNode(
b45288f… lmata 168 "function_definition",
b45288f… lmata 169 start_point=(0, 0),
b45288f… lmata 170 end_point=(5, 1),
b45288f… lmata 171 )
b45288f… lmata 172 node.set_field("name", name_node)
b45288f… lmata 173 node.set_field("body", body)
b45288f… lmata 174 stats = {"functions": 0, "classes": 0, "edges": 0}
b45288f… lmata 175 parser._handle_function(node, source, "deploy.sh", store, stats)
b45288f… lmata 176 # 1 CONTAINS edge + 1 CALLS edge
b45288f… lmata 177 assert stats["edges"] == 2
b45288f… lmata 178
b45288f… lmata 179
b45288f… lmata 180 class TestBashHandleVariable:
b45288f… lmata 181 def test_creates_variable_node_for_top_level(self):
b45288f… lmata 182 parser = _make_parser()
b45288f… lmata 183 store = _make_store()
b45288f… lmata 184 source = b'VERSION="1.0"'
b45288f… lmata 185 name_node = MockNode(
b45288f… lmata 186 "variable_name",
b45288f… lmata 187 start_byte=0,
b45288f… lmata 188 end_byte=7,
b45288f… lmata 189 )
b45288f… lmata 190 value_node = MockNode(
b45288f… lmata 191 "string",
b45288f… lmata 192 start_byte=8,
b45288f… lmata 193 end_byte=13,
b45288f… lmata 194 )
b45288f… lmata 195 program = MockNode("program")
b45288f… lmata 196 node = MockNode(
b45288f… lmata 197 "variable_assignment",
b45288f… lmata 198 start_point=(0, 0),
b45288f… lmata 199 end_point=(0, 13),
b45288f… lmata 200 parent=program,
b45288f… lmata 201 )
b45288f… lmata 202 node.set_field("name", name_node)
b45288f… lmata 203 node.set_field("value", value_node)
b45288f… lmata 204 # Re-set parent after construction since constructor
b45288f… lmata 205 # overwrites it
b45288f… lmata 206 node.parent = program
b45288f… lmata 207 stats = {"functions": 0, "classes": 0, "edges": 0}
b45288f… lmata 208 parser._handle_variable(node, source, "env.sh", store, stats)
b45288f… lmata 209 assert stats["edges"] == 1
b45288f… lmata 210 label = store.create_node.call_args[0][0]
b45288f… lmata 211 props = store.create_node.call_args[0][1]
b45288f… lmata 212 assert label == NodeLabel.Variable
b45288f… lmata 213 assert props["name"] == "VERSION"
b45288f… lmata 214 assert props["semantic_type"] == "shell_variable"
b45288f… lmata 215
b45288f… lmata 216 def test_skips_non_top_level_variable(self):
b45288f… lmata 217 parser = _make_parser()
b45288f… lmata 218 store = _make_store()
b45288f… lmata 219 source = b"x=1"
b45288f… lmata 220 name_node = MockNode(
b45288f… lmata 221 "variable_name",
b45288f… lmata 222 start_byte=0,
b45288f… lmata 223 end_byte=1,
b45288f… lmata 224 )
b45288f… lmata 225 func_parent = MockNode("function_definition")
b45288f… lmata 226 node = MockNode(
b45288f… lmata 227 "variable_assignment",
b45288f… lmata 228 start_point=(0, 0),
b45288f… lmata 229 end_point=(0, 3),
b45288f… lmata 230 parent=func_parent,
b45288f… lmata 231 )
b45288f… lmata 232 node.set_field("name", name_node)
b45288f… lmata 233 node.parent = func_parent
b45288f… lmata 234 stats = {"functions": 0, "classes": 0, "edges": 0}
b45288f… lmata 235 parser._handle_variable(node, source, "test.sh", store, stats)
b45288f… lmata 236 assert stats["edges"] == 0
b45288f… lmata 237 store.create_node.assert_not_called()
b45288f… lmata 238
b45288f… lmata 239 def test_skips_variable_without_name(self):
b45288f… lmata 240 parser = _make_parser()
b45288f… lmata 241 store = _make_store()
b45288f… lmata 242 program = MockNode("program")
b45288f… lmata 243 node = MockNode(
b45288f… lmata 244 "variable_assignment",
b45288f… lmata 245 start_point=(0, 0),
b45288f… lmata 246 end_point=(0, 3),
b45288f… lmata 247 parent=program,
b45288f… lmata 248 )
b45288f… lmata 249 node.parent = program
b45288f… lmata 250 stats = {"functions": 0, "classes": 0, "edges": 0}
b45288f… lmata 251 parser._handle_variable(node, b"", "test.sh", store, stats)
b45288f… lmata 252 store.create_node.assert_not_called()
b45288f… lmata 253
b45288f… lmata 254
b45288f… lmata 255 class TestBashHandleSource:
b45288f… lmata 256 def test_creates_import_for_source_command(self):
b45288f… lmata 257 parser = _make_parser()
b45288f… lmata 258 store = _make_store()
b45288f… lmata 259 source = b"source ./lib.sh"
b45288f… lmata 260 name_node = MockNode(
b45288f… lmata 261 "word",
b45288f… lmata 262 start_byte=0,
b45288f… lmata 263 end_byte=6,
b45288f… lmata 264 )
b45288f… lmata 265 arg_node = MockNode(
b45288f… lmata 266 "word",
b45288f… lmata 267 start_byte=7,
b45288f… lmata 268 end_byte=15,
b45288f… lmata 269 )
b45288f… lmata 270 node = MockNode(
b45288f… lmata 271 "command",
b45288f… lmata 272 children=[name_node, arg_node],
b45288f… lmata 273 start_point=(0, 0),
b45288f… lmata 274 end_point=(0, 15),
b45288f… lmata 275 )
b45288f… lmata 276 node.set_field("name", name_node)
b45288f… lmata 277 stats = {"functions": 0, "classes": 0, "edges": 0}
b45288f… lmata 278 parser._handle_command(node, source, "main.sh", store, stats)
b45288f… lmata 279 assert stats["edges"] == 1
b45288f… lmata 280 label = store.create_node.call_args[0][0]
b45288f… lmata 281 props = store.create_node.call_args[0][1]
b45288f… lmata 282 assert label == NodeLabel.Import
b45288f… lmata 283 assert props["name"] == "./lib.sh"
b45288f… lmata 284 assert props["semantic_type"] == "shell_source"
b45288f… lmata 285
b45288f… lmata 286 def test_creates_import_for_dot_command(self):
b45288f… lmata 287 parser = _make_parser()
b45288f… lmata 288 store = _make_store()
b45288f… lmata 289 source = b". /etc/profile"
b45288f… lmata 290 name_node = MockNode(
b45288f… lmata 291 "word",
b45288f… lmata 292 start_byte=0,
b45288f… lmata 293 end_byte=1,
b45288f… lmata 294 )
b45288f… lmata 295 arg_node = MockNode(
b45288f… lmata 296 "word",
b45288f… lmata 297 start_byte=2,
b45288f… lmata 298 end_byte=14,
b45288f… lmata 299 )
b45288f… lmata 300 node = MockNode(
b45288f… lmata 301 "command",
b45288f… lmata 302 children=[name_node, arg_node],
b45288f… lmata 303 start_point=(0, 0),
b45288f… lmata 304 end_point=(0, 14),
b45288f… lmata 305 )
b45288f… lmata 306 node.set_field("name", name_node)
b45288f… lmata 307 stats = {"functions": 0, "classes": 0, "edges": 0}
b45288f… lmata 308 parser._handle_command(node, source, "main.sh", store, stats)
b45288f… lmata 309 assert stats["edges"] == 1
b45288f… lmata 310 props = store.create_node.call_args[0][1]
b45288f… lmata 311 assert props["name"] == "/etc/profile"
b45288f… lmata 312
b45288f… lmata 313 def test_ignores_non_source_commands(self):
b45288f… lmata 314 parser = _make_parser()
b45288f… lmata 315 store = _make_store()
b45288f… lmata 316 source = b"echo hello"
b45288f… lmata 317 name_node = MockNode(
b45288f… lmata 318 "word",
b45288f… lmata 319 start_byte=0,
b45288f… lmata 320 end_byte=4,
b45288f… lmata 321 )
b45288f… lmata 322 node = MockNode(
b45288f… lmata 323 "command",
b45288f… lmata 324 children=[name_node],
b45288f… lmata 325 start_point=(0, 0),
b45288f… lmata 326 end_point=(0, 10),
b45288f… lmata 327 )
b45288f… lmata 328 node.set_field("name", name_node)
b45288f… lmata 329 stats = {"functions": 0, "classes": 0, "edges": 0}
b45288f… lmata 330 parser._handle_command(node, source, "main.sh", store, stats)
b45288f… lmata 331 assert stats["edges"] == 0
b45288f… lmata 332 store.create_node.assert_not_called()
b45288f… lmata 333
b45288f… lmata 334 def test_skips_source_without_arguments(self):
b45288f… lmata 335 parser = _make_parser()
b45288f… lmata 336 store = _make_store()
b45288f… lmata 337 source = b"source"
b45288f… lmata 338 name_node = MockNode(
b45288f… lmata 339 "word",
b45288f… lmata 340 start_byte=0,
b45288f… lmata 341 end_byte=6,
b45288f… lmata 342 )
b45288f… lmata 343 node = MockNode(
b45288f… lmata 344 "command",
b45288f… lmata 345 children=[name_node],
b45288f… lmata 346 start_point=(0, 0),
b45288f… lmata 347 end_point=(0, 6),
b45288f… lmata 348 )
b45288f… lmata 349 node.set_field("name", name_node)
b45288f… lmata 350 stats = {"functions": 0, "classes": 0, "edges": 0}
b45288f… lmata 351 parser._handle_command(node, source, "main.sh", store, stats)
b45288f… lmata 352 assert stats["edges"] == 0
b45288f… lmata 353 store.create_node.assert_not_called()
b45288f… lmata 354
b45288f… lmata 355
b45288f… lmata 356 class TestBashExtractCalls:
b45288f… lmata 357 def test_finds_command_calls(self):
b45288f… lmata 358 parser = _make_parser()
b45288f… lmata 359 store = _make_store()
b45288f… lmata 360 source = b"build_app"
b45288f… lmata 361 callee = MockNode(
b45288f… lmata 362 "word",
b45288f… lmata 363 start_byte=0,
b45288f… lmata 364 end_byte=9,
b45288f… lmata 365 )
b45288f… lmata 366 cmd = MockNode("command")
b45288f… lmata 367 cmd.set_field("name", callee)
b45288f… lmata 368 body = MockNode(
b45288f… lmata 369 "compound_statement",
b45288f… lmata 370 children=[cmd],
b45288f… lmata 371 )
b45288f… lmata 372 fn_node = MockNode("function_definition")
b45288f… lmata 373 fn_node.set_field("body", body)
b45288f… lmata 374 stats = {"functions": 0, "classes": 0, "edges": 0}
b45288f… lmata 375 parser._extract_calls(fn_node, source, "deploy.sh", "deploy", store, stats)
b45288f… lmata 376 assert stats["edges"] == 1
b45288f… lmata 377 edge_call = store.create_edge.call_args[0]
b45288f… lmata 378 assert edge_call[2] == EdgeType.CALLS
b45288f… lmata 379 assert edge_call[4]["name"] == "build_app"
b45288f… lmata 380
b45288f… lmata 381 def test_skips_builtins(self):
b45288f… lmata 382 parser = _make_parser()
b45288f… lmata 383 store = _make_store()
b45288f… lmata 384 source = b"echo"
b45288f… lmata 385 callee = MockNode(
b45288f… lmata 386 "word",
b45288f… lmata 387 start_byte=0,
b45288f… lmata 388 end_byte=4,
b45288f… lmata 389 )
b45288f… lmata 390 cmd = MockNode("command")
b45288f… lmata 391 cmd.set_field("name", callee)
b45288f… lmata 392 body = MockNode(
b45288f… lmata 393 "compound_statement",
b45288f… lmata 394 children=[cmd],
b45288f… lmata 395 )
b45288f… lmata 396 fn_node = MockNode("function_definition")
b45288f… lmata 397 fn_node.set_field("body", body)
b45288f… lmata 398 stats = {"functions": 0, "classes": 0, "edges": 0}
b45288f… lmata 399 parser._extract_calls(fn_node, source, "test.sh", "myfunc", store, stats)
b45288f… lmata 400 assert stats["edges"] == 0
b45288f… lmata 401
b45288f… lmata 402 def test_no_calls_in_empty_body(self):
b45288f… lmata 403 parser = _make_parser()
b45288f… lmata 404 store = _make_store()
b45288f… lmata 405 fn_node = MockNode("function_definition")
b45288f… lmata 406 fn_node.set_field("body", MockNode("compound_statement"))
b45288f… lmata 407 stats = {"functions": 0, "classes": 0, "edges": 0}
b45288f… lmata 408 parser._extract_calls(fn_node, b"", "test.sh", "myfunc", store, stats)
b45288f… lmata 409 assert stats["edges"] == 0
b45288f… lmata 410
b45288f… lmata 411 def test_no_body_means_no_calls(self):
b45288f… lmata 412 parser = _make_parser()
b45288f… lmata 413 store = _make_store()
b45288f… lmata 414 fn_node = MockNode("function_definition")
b45288f… lmata 415 stats = {"functions": 0, "classes": 0, "edges": 0}
b45288f… lmata 416 parser._extract_calls(fn_node, b"", "test.sh", "myfunc", store, stats)
b45288f… lmata 417 assert stats["edges"] == 0
b45288f… lmata 418
b45288f… lmata 419
b45288f… lmata 420 class TestBashWalkDispatch:
b45288f… lmata 421 def test_walk_handles_function_definition(self):
b45288f… lmata 422 parser = _make_parser()
b45288f… lmata 423 store = _make_store()
b45288f… lmata 424 source = b"deploy"
b45288f… lmata 425 name_node = MockNode(
b45288f… lmata 426 "word",
b45288f… lmata 427 start_byte=0,
b45288f… lmata 428 end_byte=6,
b45288f… lmata 429 )
b45288f… lmata 430 fn = MockNode(
b45288f… lmata 431 "function_definition",
b45288f… lmata 432 start_point=(0, 0),
b45288f… lmata 433 end_point=(5, 1),
b45288f… lmata 434 )
b45288f… lmata 435 fn.set_field("name", name_node)
b45288f… lmata 436 root = MockNode("program", children=[fn])
b45288f… lmata 437 stats = {"functions": 0, "classes": 0, "edges": 0}
b45288f… lmata 438 parser._walk(root, source, "deploy.sh", store, stats)
b45288f… lmata 439 assert stats["functions"] == 1
b45288f… lmata 440
b45288f… lmata 441 def test_walk_handles_variable_assignment(self):
b45288f… lmata 442 parser = _make_parser()
b45288f… lmata 443 store = _make_store()
b45288f… lmata 444 source = b"VERSION"
b45288f… lmata 445 name_node = MockNode(
b45288f… lmata 446 "variable_name",
b45288f… lmata 447 start_byte=0,
b45288f… lmata 448 end_byte=7,
b45288f… lmata 449 )
b45288f… lmata 450 program = MockNode("program")
b45288f… lmata 451 var = MockNode(
b45288f… lmata 452 "variable_assignment",
b45288f… lmata 453 start_point=(0, 0),
b45288f… lmata 454 end_point=(0, 13),
b45288f… lmata 455 )
b45288f… lmata 456 var.set_field("name", name_node)
b45288f… lmata 457 program.children = [var]
b45288f… lmata 458 for child in program.children:
b45288f… lmata 459 child.parent = program
b45288f… lmata 460 stats = {"functions": 0, "classes": 0, "edges": 0}
b45288f… lmata 461 parser._walk(program, source, "env.sh", store, stats)
b45288f… lmata 462 assert stats["edges"] == 1
b45288f… lmata 463
b45288f… lmata 464 def test_walk_handles_source_command(self):
b45288f… lmata 465 parser = _make_parser()
b45288f… lmata 466 store = _make_store()
b45288f… lmata 467 source = b"source ./lib.sh"
b45288f… lmata 468 name_node = MockNode(
b45288f… lmata 469 "word",
b45288f… lmata 470 start_byte=0,
b45288f… lmata 471 end_byte=6,
b45288f… lmata 472 )
b45288f… lmata 473 arg_node = MockNode(
b45288f… lmata 474 "word",
b45288f… lmata 475 start_byte=7,
b45288f… lmata 476 end_byte=15,
b45288f… lmata 477 )
b45288f… lmata 478 cmd = MockNode(
b45288f… lmata 479 "command",
b45288f… lmata 480 children=[name_node, arg_node],
b45288f… lmata 481 start_point=(0, 0),
b45288f… lmata 482 end_point=(0, 15),
b45288f… lmata 483 )
b45288f… lmata 484 cmd.set_field("name", name_node)
b45288f… lmata 485 root = MockNode("program", children=[cmd])
b45288f… lmata 486 stats = {"functions": 0, "classes": 0, "edges": 0}
b45288f… lmata 487 parser._walk(root, source, "main.sh", store, stats)
b45288f… lmata 488 assert stats["edges"] == 1
b45288f… lmata 489
b45288f… lmata 490 def test_walk_recurses_into_children(self):
b45288f… lmata 491 parser = _make_parser()
b45288f… lmata 492 store = _make_store()
b45288f… lmata 493 source = b"deploy"
b45288f… lmata 494 name_node = MockNode(
b45288f… lmata 495 "word",
b45288f… lmata 496 start_byte=0,
b45288f… lmata 497 end_byte=6,
b45288f… lmata 498 )
b45288f… lmata 499 fn = MockNode(
b45288f… lmata 500 "function_definition",
b45288f… lmata 501 start_point=(0, 0),
b45288f… lmata 502 end_point=(5, 1),
b45288f… lmata 503 )
b45288f… lmata 504 fn.set_field("name", name_node)
b45288f… lmata 505 wrapper = MockNode("if_statement", children=[fn])
b45288f… lmata 506 root = MockNode("program", children=[wrapper])
b45288f… lmata 507 stats = {"functions": 0, "classes": 0, "edges": 0}
b45288f… lmata 508 parser._walk(root, source, "deploy.sh", store, stats)
b45288f… lmata 509 assert stats["functions"] == 1
b45288f… lmata 510
b45288f… lmata 511
b45288f… lmata 512 class TestBashParseFile:
b45288f… lmata 513 def test_creates_file_node(self):
b45288f… lmata 514 import tempfile
b45288f… lmata 515 from pathlib import Path
b45288f… lmata 516
b45288f… lmata 517 parser = _make_parser()
b45288f… lmata 518 store = _make_store()
b45288f… lmata 519 mock_tree = MagicMock()
b45288f… lmata 520 mock_tree.root_node.type = "program"
b45288f… lmata 521 mock_tree.root_node.children = []
b45288f… lmata 522 parser._parser.parse.return_value = mock_tree
b45288f… lmata 523 with tempfile.NamedTemporaryFile(suffix=".sh", delete=False) as f:
b45288f… lmata 524 f.write(b"#!/bin/bash\necho hello\n")
b45288f… lmata 525 fpath = Path(f.name)
b45288f… lmata 526 try:
b45288f… lmata 527 parser.parse_file(fpath, fpath.parent, store)
b45288f… lmata 528 store.create_node.assert_called_once()
b45288f… lmata 529 label = store.create_node.call_args[0][0]
b45288f… lmata 530 props = store.create_node.call_args[0][1]
b45288f… lmata 531 assert label == NodeLabel.File
b45288f… lmata 532 assert props["language"] == "bash"
b45288f… lmata 533 finally:
b45288f… lmata 534 fpath.unlink()

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button