Skip to content

Commit 2f3be25

Browse files
committed
test(extract): guard delegation-receiver recursion false positives
The DeusData#599 receiver-aware narrowing (87091ed) shipped without coverage for the delegation/store bucket reported in DeusData#876: same-named calls whose receiver is a call result (_get_store().get inside get), a module singleton (_default.check inside check), or a loop-local cursor (cur.execute inside execute). All three are clean on current main; this guard pins the bucket so it cannot regress. Refs DeusData#876 Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
1 parent 8c9ac98 commit 2f3be25

1 file changed

Lines changed: 69 additions & 0 deletions

File tree

‎tests/test_extraction.c‎

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3115,6 +3115,74 @@ TEST(complexity_go_method_receiver_self_recursion) {
31153115
PASS();
31163116
}
31173117

3118+
/* #876: the delegation/store bucket left open after #599 — same-named calls
3119+
* whose receiver is a CALL RESULT (_get_store().get), a module singleton
3120+
* (_default.check), or a local cursor inside a loop (cur.execute) are not
3121+
* self-recursion. All three are the reporter's exact v0.8.1 false positives;
3122+
* fixed by the receiver-aware narrowing (87091ed), guarded here so the
3123+
* bucket never regresses. */
3124+
TEST(complexity_delegation_receivers_not_recursive_issue876) {
3125+
/* Store wrapper: _get_store().get() inside get — receiver is the call
3126+
* result, a different object. */
3127+
CBMFileResult *r = extract("def _get_store():\n"
3128+
" return object()\n"
3129+
"\n"
3130+
"def get(collection, record_id):\n"
3131+
" rec = _get_store().get(collection, record_id)\n"
3132+
" return rec\n",
3133+
CBM_LANG_PYTHON, "t", "soil.py");
3134+
ASSERT_NOT_NULL(r);
3135+
ASSERT_FALSE(r->has_error);
3136+
const CBMDefinition *d = find_def(r, "get");
3137+
ASSERT_NOT_NULL(d);
3138+
ASSERT_FALSE(d->is_recursive); /* _get_store() result is not this fn */
3139+
ASSERT_FALSE(d->unguarded_recursion);
3140+
cbm_free_result(r);
3141+
3142+
/* Module-singleton delegation: _default.check() inside check. */
3143+
r = extract("class _Checker:\n"
3144+
" def check(self, app_id, tool_name):\n"
3145+
" return (True, \"ok\")\n"
3146+
"\n"
3147+
"_default = _Checker()\n"
3148+
"\n"
3149+
"def check(app_id, tool_name):\n"
3150+
" return _default.check(app_id, tool_name)\n",
3151+
CBM_LANG_PYTHON, "t", "gleipnir.py");
3152+
ASSERT_NOT_NULL(r);
3153+
ASSERT_FALSE(r->has_error);
3154+
/* The module-level wrapper (not the method) must stay clean. */
3155+
d = NULL;
3156+
for (int i = 0; i < r->defs.count; i++) {
3157+
if (r->defs.items[i].name && strcmp(r->defs.items[i].name, "check") == 0 &&
3158+
strcmp(r->defs.items[i].label, "Function") == 0) {
3159+
d = &r->defs.items[i];
3160+
}
3161+
}
3162+
ASSERT_NOT_NULL(d);
3163+
ASSERT_FALSE(d->is_recursive); /* _default is not this fn */
3164+
ASSERT_FALSE(d->unguarded_recursion);
3165+
cbm_free_result(r);
3166+
3167+
/* Same-named method on a local, called inside a loop (willow.nuke case):
3168+
* neither recursive nor recursion_in_loop. */
3169+
r = extract("def execute(conn, paths):\n"
3170+
" for p in paths:\n"
3171+
" cur = conn.cursor()\n"
3172+
" cur.execute(\"DELETE FROM t WHERE p = %s\", (p,))\n"
3173+
" return True\n",
3174+
CBM_LANG_PYTHON, "t", "nuke.py");
3175+
ASSERT_NOT_NULL(r);
3176+
ASSERT_FALSE(r->has_error);
3177+
d = find_def(r, "execute");
3178+
ASSERT_NOT_NULL(d);
3179+
ASSERT_FALSE(d->is_recursive); /* cur is not this fn */
3180+
ASSERT_FALSE(d->unguarded_recursion);
3181+
ASSERT_FALSE(d->recursion_in_loop);
3182+
cbm_free_result(r);
3183+
PASS();
3184+
}
3185+
31183186
/* Deep chained member access + parameter count structure smells. */
31193187
TEST(complexity_access_depth_and_params) {
31203188
CBMFileResult *r = extract("package p\n"
@@ -3736,6 +3804,7 @@ SUITE(extraction) {
37363804
RUN_TEST(complexity_self_receiver_still_recursive);
37373805
RUN_TEST(complexity_chained_receiver_not_self);
37383806
RUN_TEST(complexity_go_method_receiver_self_recursion);
3807+
RUN_TEST(complexity_delegation_receivers_not_recursive_issue876);
37393808
RUN_TEST(complexity_access_depth_and_params);
37403809
RUN_TEST(walk_defs_no_truncation_over_4096_issue668);
37413810
RUN_TEST(extract_rust_test_attr_marks_is_test_issue855);

0 commit comments

Comments
 (0)