Files
raycast-api/tests/test_ast_parse.py
T

113 lines
3.3 KiB
Python

"""Tests for `raycast_api.discovery.ast_parse`."""
from __future__ import annotations
from raycast_api.discovery.ast_parse import (
collect_numeric_literals,
find_calls,
find_function_by_shape,
has_string_literal,
iter_function_declarations,
)
def test_finds_declarations_and_skips_decoys(mock_bundle_source: str) -> None:
fns = list(iter_function_declarations(mock_bundle_source))
names = [f.name for f in fns]
assert {
"RotXform",
"RotXform2",
"SignReq",
"decoyOneParam",
"decoyHmac",
"noiseFn",
} <= set(names)
def test_param_count_filter(mock_bundle_source: str) -> None:
fns = list(iter_function_declarations(mock_bundle_source))
one_param = {f.name for f in find_function_by_shape(fns, param_count=1)}
assert "RotXform" in one_param
assert "decoyOneParam" in one_param
four_param = {
f.name for f in find_function_by_shape(fns, is_async=True, param_count=4)
}
assert "SignReq" in four_param
assert "decoyHmac" in four_param
def test_body_contains_excludes_decoys(mock_bundle_source: str) -> None:
fns = list(iter_function_declarations(mock_bundle_source))
signing_like = find_function_by_shape(
fns,
is_async=True,
param_count=4,
body_contains_all=["HMAC", "SHA-256", "importKey"],
)
assert {f.name for f in signing_like} == {"SignReq", "decoyHmac"}
def test_find_calls_locates_map_calls(mock_bundle_source: str) -> None:
fns = list(iter_function_declarations(mock_bundle_source))
sign = next(f for f in fns if f.name == "SignReq")
map_calls = find_calls(sign, "map")
assert len(map_calls) == 3
def test_has_string_literal(mock_bundle_source: str) -> None:
fns = list(iter_function_declarations(mock_bundle_source))
sign = next(f for f in fns if f.name == "SignReq")
assert has_string_literal(sign, "HMAC")
assert has_string_literal(sign, "SHA-256")
assert not has_string_literal(sign, "MD5")
def test_collect_numeric_literals(mock_bundle_source: str) -> None:
fns = list(iter_function_declarations(mock_bundle_source))
rot = next(f for f in fns if f.name == "RotXform")
nums = collect_numeric_literals(rot)
assert {65, 90, 13, 26, 97, 122, 48, 57, 5, 10} <= nums
def test_regex_literal_with_brace_does_not_truncate_function() -> None:
"""The brace matcher must skip braces inside regex literals."""
src = """
function tricky(s) {
let re = /\\}/;
if (s.match(re)) { return true }
return false;
}
"""
fns = list(iter_function_declarations(src))
assert len(fns) == 1
assert fns[0].name == "tricky"
assert "return true" in fns[0].body_source
assert fns[0].body_source.endswith("}")
def test_template_literal_with_interpolation() -> None:
src = r"""
function templating(x) {
let nested = `prefix-${x.toString()}-${`inner-${x}`}-end`;
if (x) { return nested }
return "";
}
"""
fns = list(iter_function_declarations(src))
assert len(fns) == 1
assert fns[0].name == "templating"
assert "return nested" in fns[0].body_source
def test_strings_with_braces_dont_confuse_matcher() -> None:
src = """
function strs() {
let a = "{ not real }";
let b = '} also not };';
return a + b;
}
"""
fns = list(iter_function_declarations(src))
assert len(fns) == 1
assert fns[0].body_source.endswith("}")