From 5f12ffccf2c9afd666308e4635a96fe260d210ab Mon Sep 17 00:00:00 2001 From: Gergo Magyar Date: Mon, 16 Mar 2026 23:13:05 +0000 Subject: [PATCH] test: add assertion bodies to known limitation skip tests Convert empty skip test stubs to proper tests with parse/buildTypeEnv/expect assertions following the codebase convention (e.g., call-processor.test.ts:319). Each skip test now documents the exact expected behavior, so removing .skip will cause a meaningful failure when the limitation is eventually fixed. Also clarify Python integration skip tests as call-extraction issues (not type-env) and Swift integration skips as build-dep issues (self/super resolution code already exists in type-env.ts). --- .../test/integration/resolvers/python.test.ts | 7 +- .../test/integration/resolvers/swift.test.ts | 6 +- gitnexus/test/unit/type-env.test.ts | 68 +++++++++++++++++-- 3 files changed, 70 insertions(+), 11 deletions(-) diff --git a/gitnexus/test/integration/resolvers/python.test.ts b/gitnexus/test/integration/resolvers/python.test.ts index 19d7851e3..77186edd1 100644 --- a/gitnexus/test/integration/resolvers/python.test.ts +++ b/gitnexus/test/integration/resolvers/python.test.ts @@ -986,9 +986,10 @@ describe('Python match/case as-pattern type binding', () => { expect(true).toBe(true); }); - // Skip: tree-sitter-python match_statement call extraction needs query updates - // Type-env binding works (unit test passes), but calls inside case_clause blocks - // are not captured by the current call extraction queries. + // Skip: call extraction issue, NOT a type-env limitation. + // Type-env binding works correctly (unit test passes). The root cause is likely + // in call-processor's findEnclosingFunction scope resolution within match_statement + // blocks, not the tree-sitter query patterns (which descend recursively by default). it.skip('resolves u.save() to User#save via match/case as-pattern binding', () => { const calls = getRelationships(result, 'CALLS'); const userSave = calls.find(c => diff --git a/gitnexus/test/integration/resolvers/swift.test.ts b/gitnexus/test/integration/resolvers/swift.test.ts index 6ab8c28b6..773323044 100644 --- a/gitnexus/test/integration/resolvers/swift.test.ts +++ b/gitnexus/test/integration/resolvers/swift.test.ts @@ -57,7 +57,8 @@ describe.skipIf(!swiftAvailable)('Swift constructor-inferred type resolution', ( // --------------------------------------------------------------------------- // self.save() resolves to enclosing class's own save method -// Known issue: tree-sitter-swift has build issues on Node 22 +// Build-dep issue (NOT a feature gap): tree-sitter-swift has build issues on Node 22. +// The self/super resolution code already exists in type-env.ts lookupInEnv (lines 56-66). // --------------------------------------------------------------------------- describe.skip('Swift self resolution', () => { @@ -86,7 +87,8 @@ describe.skip('Swift self resolution', () => { // --------------------------------------------------------------------------- // Parent class resolution: EXTENDS + protocol conformance -// Known issue: tree-sitter-swift has build issues on Node 22 +// Build-dep issue (NOT a feature gap): tree-sitter-swift has build issues on Node 22. +// findEnclosingParentClassName in type-env.ts already has Swift inheritance_specifier handler. // --------------------------------------------------------------------------- describe.skip('Swift parent resolution', () => { diff --git a/gitnexus/test/unit/type-env.test.ts b/gitnexus/test/unit/type-env.test.ts index 67390e8be..40a86e9dc 100644 --- a/gitnexus/test/unit/type-env.test.ts +++ b/gitnexus/test/unit/type-env.test.ts @@ -2928,25 +2928,81 @@ class Foo { }); }); + // These tests document capabilities we intentionally do not support yet. + // Each skip test has assertions that should pass once the feature is implemented. + // When a skip test starts passing, remove .skip and update the corresponding issue. describe('known limitations (documented skip tests)', () => { it.skip('TS destructured for-of: for (const [k, v] of entries) — requires tuple destructuring', () => { - // extractVarName returns undefined for array_pattern + // extractVarName returns undefined for array_pattern; also needs + // resolveIterableElementType to return tuple types and ForLoopExtractor + // type signature to support multi-variable binding + const tree = parse(` +function process(entries: Map) { + for (const [key, user] of entries) { + user.save(); + } +} + `, TypeScript); + const { env } = buildTypeEnv(tree, 'typescript'); + expect(flatGet(env, 'user')).toBe('User'); }); - it.skip('Python tuple unpacking: for key, value in dict.items() — requires pattern_list', () => { - // left is pattern_list, not identifier + it.skip('Python tuple unpacking: for key, value in dict.items() — requires pattern_list + method call iterable', () => { + // Left side is pattern_list, not identifier (needs Group A: tuple destructuring). + // Right side is call_expression .items() (needs Group C: method call iterable resolution). + const tree = parse(` +def process(data: dict[str, User]): + for key, user in data.items(): + user.save() + `, Python); + const { env } = buildTypeEnv(tree, 'python'); + expect(flatGet(env, 'user')).toBe('User'); }); it.skip('TS instanceof narrowing: if (x instanceof User) { x.save() } — needs block-level scoping', () => { - // Narrows existing variable, does not introduce new one + // Narrows existing variable within a block, does not introduce a new one. + // Requires scope stack infrastructure (push/pop on block entry/exit) and + // type guard recognition. TS parses instanceof as binary_expression, not + // a dedicated node type. + const tree = parse(` +function process(x: unknown) { + if (x instanceof User) { + x.save(); + } +} + `, TypeScript); + const { env } = buildTypeEnv(tree, 'typescript'); + // x should be narrowed to User inside the if-block + expect(flatGet(env, 'x')).toBe('User'); }); it.skip('Rust for with .iter(): for user in users.iter() — needs method call iterable resolution', () => { - // Iterable is a call_expression, not an identifier + // Iterable is a call_expression, not an identifier. In idiomatic Rust, + // .iter()/.into_iter()/.iter_mut() is the dominant iteration pattern — + // the plain identifier form (which IS supported) is less common. + const tree = parse(` +fn process(users: Vec) { + for user in users.iter() { + user.save(); + } +} + `, Rust); + const { env } = buildTypeEnv(tree, 'rust'); + expect(flatGet(env, 'user')).toBe('User'); }); it.skip('Ruby block parameter: users.each { |user| } — closure param inference, different feature', () => { - // Not a for-loop; requires block/closure parameter inference + // Not a for-loop; .each { |user| } is a method call with a block. + // Requires closure parameter inference — a different feature category + // applicable to Ruby, Swift closures, Kotlin lambdas, and Java lambdas. + // Depends on method call resolution (Group C) as prerequisite. + const tree = parse(` +def process(users) + users.each { |user| user.save } +end + `, Ruby); + const { env } = buildTypeEnv(tree, 'ruby'); + expect(flatGet(env, 'user')).toBe('User'); }); });