113 lines
3.3 KiB
Python
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("}")
|