diff --git a/gitnexus/test/integration/resolvers/cpp.test.ts b/gitnexus/test/integration/resolvers/cpp.test.ts index 054779b2e..020366059 100644 --- a/gitnexus/test/integration/resolvers/cpp.test.ts +++ b/gitnexus/test/integration/resolvers/cpp.test.ts @@ -840,8 +840,9 @@ describe('Field type resolution (C++)', () => { it('emits HAS_PROPERTY edges linking fields to classes', () => { const propEdges = getRelationships(result, 'HAS_PROPERTY'); - expect(propEdges.length).toBeGreaterThanOrEqual(2); + expect(propEdges.length).toBe(3); expect(edgeSet(propEdges)).toContain('User → address'); + expect(edgeSet(propEdges)).toContain('User → name'); expect(edgeSet(propEdges)).toContain('Address → city'); }); @@ -952,7 +953,7 @@ describe('Write access tracking (C++)', () => { it('emits ACCESSES write edges for field assignments', () => { const accesses = getRelationships(result, 'ACCESSES'); const writes = accesses.filter(e => e.rel.reason === 'write'); - expect(writes.length).toBeGreaterThanOrEqual(2); + expect(writes.length).toBe(2); const fieldNames = writes.map(e => e.target); expect(fieldNames).toContain('name'); expect(fieldNames).toContain('address'); diff --git a/gitnexus/test/integration/resolvers/csharp.test.ts b/gitnexus/test/integration/resolvers/csharp.test.ts index b2d0a6a48..e603e239d 100644 --- a/gitnexus/test/integration/resolvers/csharp.test.ts +++ b/gitnexus/test/integration/resolvers/csharp.test.ts @@ -1221,7 +1221,7 @@ describe('Field type resolution (C#)', () => { it('emits HAS_PROPERTY edges linking properties to classes', () => { const propEdges = getRelationships(result, 'HAS_PROPERTY'); - expect(propEdges.length).toBeGreaterThanOrEqual(3); + expect(propEdges.length).toBe(3); expect(edgeSet(propEdges)).toContain('User → Address'); expect(edgeSet(propEdges)).toContain('User → Name'); expect(edgeSet(propEdges)).toContain('Address → City'); @@ -1300,7 +1300,7 @@ describe('Write access tracking (C#)', () => { it('emits ACCESSES write edges for field assignments', () => { const accesses = getRelationships(result, 'ACCESSES'); const writes = accesses.filter(e => e.rel.reason === 'write'); - expect(writes.length).toBeGreaterThanOrEqual(2); + expect(writes.length).toBe(2); const fieldNames = writes.map(e => e.target); expect(fieldNames).toContain('Name'); expect(fieldNames).toContain('Address'); diff --git a/gitnexus/test/integration/resolvers/go.test.ts b/gitnexus/test/integration/resolvers/go.test.ts index 8a11e23a0..a1ba00c13 100644 --- a/gitnexus/test/integration/resolvers/go.test.ts +++ b/gitnexus/test/integration/resolvers/go.test.ts @@ -968,7 +968,10 @@ describe('Field type resolution (Go)', () => { it('emits HAS_PROPERTY edges linking struct fields to structs', () => { const propEdges = getRelationships(result, 'HAS_PROPERTY'); - expect(propEdges.length).toBeGreaterThanOrEqual(2); + expect(propEdges.length).toBe(3); + expect(edgeSet(propEdges)).toContain('User → Name'); + expect(edgeSet(propEdges)).toContain('User → Address'); + expect(edgeSet(propEdges)).toContain('Address → City'); }); it('resolves user.Address.Save() → Address#Save via field type', () => { @@ -1008,7 +1011,12 @@ describe('Deep field chain resolution (Go)', () => { it('emits HAS_PROPERTY edges for nested type chain', () => { const propEdges = getRelationships(result, 'HAS_PROPERTY'); - expect(propEdges.length).toBeGreaterThanOrEqual(3); + expect(propEdges.length).toBe(5); + expect(edgeSet(propEdges)).toContain('User → Name'); + expect(edgeSet(propEdges)).toContain('User → Address'); + expect(edgeSet(propEdges)).toContain('Address → City'); + expect(edgeSet(propEdges)).toContain('Address → Street'); + expect(edgeSet(propEdges)).toContain('City → ZipCode'); }); it('resolves 2-level chain: user.Address.Save() → Address#Save', () => { diff --git a/gitnexus/test/integration/resolvers/java.test.ts b/gitnexus/test/integration/resolvers/java.test.ts index a8b82dbcc..b19ca0d63 100644 --- a/gitnexus/test/integration/resolvers/java.test.ts +++ b/gitnexus/test/integration/resolvers/java.test.ts @@ -1096,7 +1096,7 @@ describe('Field type resolution (Java)', () => { it('emits HAS_PROPERTY edges linking properties to classes', () => { const propEdges = getRelationships(result, 'HAS_PROPERTY'); - expect(propEdges.length).toBeGreaterThanOrEqual(3); + expect(propEdges.length).toBe(3); expect(edgeSet(propEdges)).toContain('User → address'); expect(edgeSet(propEdges)).toContain('User → name'); expect(edgeSet(propEdges)).toContain('Address → city'); diff --git a/gitnexus/test/integration/resolvers/javascript.test.ts b/gitnexus/test/integration/resolvers/javascript.test.ts index d99e5e5f8..58bbb54ec 100644 --- a/gitnexus/test/integration/resolvers/javascript.test.ts +++ b/gitnexus/test/integration/resolvers/javascript.test.ts @@ -262,10 +262,11 @@ describe('Field type resolution (JavaScript)', () => { it('emits HAS_PROPERTY edges linking fields to classes', () => { const propEdges = getRelationships(result, 'HAS_PROPERTY'); - expect(propEdges.length).toBeGreaterThanOrEqual(3); + expect(propEdges.length).toBe(4); expect(edgeSet(propEdges)).toContain('User → address'); expect(edgeSet(propEdges)).toContain('User → name'); expect(edgeSet(propEdges)).toContain('Address → city'); + expect(edgeSet(propEdges)).toContain('Config → DEFAULT'); }); }); @@ -285,7 +286,7 @@ describe('Write access tracking (JavaScript)', () => { it('emits ACCESSES write edges for field assignments', () => { const accesses = getRelationships(result, 'ACCESSES'); const writes = accesses.filter(e => e.rel.reason === 'write'); - expect(writes.length).toBeGreaterThanOrEqual(2); + expect(writes.length).toBe(2); const fieldNames = writes.map(e => e.target); expect(fieldNames).toContain('name'); expect(fieldNames).toContain('address'); diff --git a/gitnexus/test/integration/resolvers/kotlin.test.ts b/gitnexus/test/integration/resolvers/kotlin.test.ts index 5b6761dfc..a6866faca 100644 --- a/gitnexus/test/integration/resolvers/kotlin.test.ts +++ b/gitnexus/test/integration/resolvers/kotlin.test.ts @@ -1246,7 +1246,7 @@ describe('Field type resolution (Kotlin)', () => { it('emits HAS_PROPERTY edges linking properties to classes', () => { const propEdges = getRelationships(result, 'HAS_PROPERTY'); - expect(propEdges.length).toBeGreaterThanOrEqual(3); + expect(propEdges.length).toBe(3); expect(edgeSet(propEdges)).toContain('User → address'); expect(edgeSet(propEdges)).toContain('User → name'); expect(edgeSet(propEdges)).toContain('Address → city'); @@ -1367,13 +1367,16 @@ describe('Write access tracking (Kotlin)', () => { it('emits ACCESSES write edges for property assignments', () => { const accesses = getRelationships(result, 'ACCESSES'); const writes = accesses.filter(e => e.rel.reason === 'write'); - expect(writes.length).toBeGreaterThanOrEqual(2); + expect(writes.length).toBe(3); const nameWrite = writes.find(e => e.target === 'name'); const addressWrite = writes.find(e => e.target === 'address'); + const scoreWrite = writes.find(e => e.target === 'score'); expect(nameWrite).toBeDefined(); expect(nameWrite!.source).toBe('updateUser'); expect(addressWrite).toBeDefined(); expect(addressWrite!.source).toBe('updateUser'); + expect(scoreWrite).toBeDefined(); + expect(scoreWrite!.source).toBe('updateUser'); }); it('emits ACCESSES write edge for compound assignment (+=)', () => { diff --git a/gitnexus/test/integration/resolvers/php.test.ts b/gitnexus/test/integration/resolvers/php.test.ts index d4ff15ff7..f8ea5c570 100644 --- a/gitnexus/test/integration/resolvers/php.test.ts +++ b/gitnexus/test/integration/resolvers/php.test.ts @@ -138,7 +138,7 @@ describe('PHP heritage & import resolution', () => { it('emits OVERRIDES edge for User overriding log (inherited from BaseModel)', () => { const overrides = getRelationships(result, 'OVERRIDES'); - expect(overrides.length).toBeGreaterThanOrEqual(1); + expect(overrides.length).toBe(1); const logOverride = overrides.find(e => e.source === 'User' && e.target === 'log'); expect(logOverride).toBeDefined(); }); @@ -1189,7 +1189,7 @@ describe('Field type resolution (PHP)', () => { it('emits HAS_PROPERTY edges linking properties to classes', () => { const propEdges = getRelationships(result, 'HAS_PROPERTY'); - expect(propEdges.length).toBeGreaterThanOrEqual(3); + expect(propEdges.length).toBe(3); }); it('resolves $user->address->save() → Address#save via field type', () => { @@ -1229,7 +1229,12 @@ describe('Deep field chain resolution (PHP)', () => { it('emits HAS_PROPERTY edges for nested type chain', () => { const propEdges = getRelationships(result, 'HAS_PROPERTY'); - expect(propEdges.length).toBeGreaterThanOrEqual(3); + expect(propEdges.length).toBe(5); + expect(edgeSet(propEdges)).toContain('User → name'); + expect(edgeSet(propEdges)).toContain('User → address'); + expect(edgeSet(propEdges)).toContain('Address → city'); + expect(edgeSet(propEdges)).toContain('Address → street'); + expect(edgeSet(propEdges)).toContain('City → zipCode'); }); it('resolves 2-level chain: $user->address->save() → Address#save', () => { @@ -1303,14 +1308,16 @@ describe('Write access tracking (PHP)', () => { it('emits ACCESSES write edges for field assignments', () => { const accesses = getRelationships(result, 'ACCESSES'); const writes = accesses.filter(e => e.rel.reason === 'write'); - // user->name (x2: simple + compound), user->address, User::$count - expect(writes.length).toBeGreaterThanOrEqual(2); + expect(writes.length).toBe(3); const nameWrite = writes.find(e => e.target === 'name'); const addressWrite = writes.find(e => e.target === 'address'); + const countWrite = writes.find(e => e.target === 'count'); expect(nameWrite).toBeDefined(); expect(nameWrite!.source).toBe('updateUser'); expect(addressWrite).toBeDefined(); expect(addressWrite!.source).toBe('updateUser'); + expect(countWrite).toBeDefined(); + expect(countWrite!.source).toBe('updateUser'); }); it('emits ACCESSES write edge for static property assignment', () => { diff --git a/gitnexus/test/integration/resolvers/python.test.ts b/gitnexus/test/integration/resolvers/python.test.ts index 8e20947e7..bdbf58c55 100644 --- a/gitnexus/test/integration/resolvers/python.test.ts +++ b/gitnexus/test/integration/resolvers/python.test.ts @@ -720,10 +720,10 @@ describe('Python static/classmethod class resolution (issue #289)', () => { const hasMethod = getRelationships(result, 'HAS_METHOD'); const userServiceMethods = hasMethod.filter(e => e.source === 'UserService'); - expect(userServiceMethods.length).toBeGreaterThanOrEqual(3); // find_user, create_user, from_config + expect(userServiceMethods.length).toBe(3); // find_user, create_user, from_config const adminServiceMethods = hasMethod.filter(e => e.source === 'AdminService'); - expect(adminServiceMethods.length).toBeGreaterThanOrEqual(2); // find_user, delete_user + expect(adminServiceMethods.length).toBe(2); // find_user, delete_user }); it('resolves unique static method calls (create_user, delete_user, from_config)', () => { @@ -1309,7 +1309,7 @@ describe('Field type resolution (Python)', () => { it('emits HAS_PROPERTY edges linking attributes to classes', () => { const propEdges = getRelationships(result, 'HAS_PROPERTY'); - expect(propEdges.length).toBeGreaterThanOrEqual(3); + expect(propEdges.length).toBe(3); expect(edgeSet(propEdges)).toContain('User → address'); expect(edgeSet(propEdges)).toContain('User → name'); expect(edgeSet(propEdges)).toContain('Address → city'); diff --git a/gitnexus/test/integration/resolvers/ruby.test.ts b/gitnexus/test/integration/resolvers/ruby.test.ts index b94ce48f1..ad6f474f7 100644 --- a/gitnexus/test/integration/resolvers/ruby.test.ts +++ b/gitnexus/test/integration/resolvers/ruby.test.ts @@ -105,7 +105,7 @@ describe('Ruby require_relative, heritage & property resolution', () => { it('emits EXTENDS edge: User → BaseModel', () => { const extends_ = getRelationships(result, 'EXTENDS'); - expect(extends_.length).toBeGreaterThanOrEqual(1); + expect(extends_.length).toBe(1); const edges = edgeSet(extends_); expect(edges).toContain('User → BaseModel'); }); @@ -620,7 +620,7 @@ describe('Ruby return type inference via function call', () => { it('detects save method on both User and Repo (disambiguation required)', () => { const methods = getNodesByLabel(result, 'Method'); // Both classes have save — fuzzy match alone cannot resolve this - expect(methods.filter(m => m === 'save').length).toBeGreaterThanOrEqual(2); + expect(methods.filter(m => m === 'save').length).toBe(2); }); it('resolves user.save to User#save via YARD @return [User] on get_user()', () => { @@ -874,7 +874,7 @@ describe('Field type resolution (Ruby)', () => { it('emits HAS_PROPERTY edges linking properties to classes', () => { const propEdges = getRelationships(result, 'HAS_PROPERTY'); - expect(propEdges.length).toBeGreaterThanOrEqual(3); + expect(propEdges.length).toBe(3); expect(edgeSet(propEdges)).toContain('User → address'); expect(edgeSet(propEdges)).toContain('User → name'); expect(edgeSet(propEdges)).toContain('Address → city'); @@ -938,13 +938,16 @@ describe('Write access tracking (Ruby)', () => { it('emits ACCESSES write edges for setter assignments', () => { const accesses = getRelationships(result, 'ACCESSES'); const writes = accesses.filter(e => e.rel.reason === 'write'); - expect(writes.length).toBeGreaterThanOrEqual(2); + expect(writes.length).toBe(3); const nameWrite = writes.find(e => e.target === 'name'); const addressWrite = writes.find(e => e.target === 'address'); + const scoreWrite = writes.find(e => e.target === 'score'); expect(nameWrite).toBeDefined(); expect(nameWrite!.source).toBe('update_user'); expect(addressWrite).toBeDefined(); expect(addressWrite!.source).toBe('update_user'); + expect(scoreWrite).toBeDefined(); + expect(scoreWrite!.source).toBe('update_user'); }); it('emits ACCESSES write edge for compound assignment (operator_assignment)', () => { diff --git a/gitnexus/test/integration/resolvers/rust.test.ts b/gitnexus/test/integration/resolvers/rust.test.ts index f07cc83ac..e5b0e1d05 100644 --- a/gitnexus/test/integration/resolvers/rust.test.ts +++ b/gitnexus/test/integration/resolvers/rust.test.ts @@ -702,7 +702,7 @@ describe('Rust ::default() constructor resolution', () => { it('detects save methods on both structs', () => { const methods = [...getNodesByLabel(result, 'Function'), ...getNodesByLabel(result, 'Method')]; - expect(methods.filter((m: string) => m === 'save').length).toBeGreaterThanOrEqual(2); + expect(methods.filter((m: string) => m === 'save').length).toBe(2); }); it('resolves user.save() in process_with_new() via User::new() constructor', () => { @@ -774,7 +774,7 @@ describe('Rust async .await constructor binding resolution', () => { it('detects save methods in separate files', () => { const methods = [...getNodesByLabel(result, 'Function'), ...getNodesByLabel(result, 'Method')]; - expect(methods.filter((m: string) => m === 'save').length).toBeGreaterThanOrEqual(2); + expect(methods.filter((m: string) => m === 'save').length).toBe(2); }); it('resolves user.save() after .await to user.rs via return type of get_user()', () => { @@ -1322,7 +1322,10 @@ describe('Field type resolution (Rust)', () => { it('emits HAS_PROPERTY edges linking fields to structs', () => { const propEdges = getRelationships(result, 'HAS_PROPERTY'); - expect(propEdges.length).toBeGreaterThanOrEqual(2); + expect(propEdges.length).toBe(3); + expect(edgeSet(propEdges)).toContain('User → name'); + expect(edgeSet(propEdges)).toContain('User → address'); + expect(edgeSet(propEdges)).toContain('Address → city'); }); it('resolves user.address.save() → Address#save via field type', () => { @@ -1362,7 +1365,12 @@ describe('Deep field chain resolution (Rust)', () => { it('emits HAS_PROPERTY edges for nested type chain', () => { const propEdges = getRelationships(result, 'HAS_PROPERTY'); - expect(propEdges.length).toBeGreaterThanOrEqual(3); + expect(propEdges.length).toBe(5); + expect(edgeSet(propEdges)).toContain('User → name'); + expect(edgeSet(propEdges)).toContain('User → address'); + expect(edgeSet(propEdges)).toContain('Address → city'); + expect(edgeSet(propEdges)).toContain('Address → street'); + expect(edgeSet(propEdges)).toContain('City → zip_code'); }); it('resolves 2-level chain: user.address.save() → Address#save', () => { @@ -1396,10 +1404,11 @@ describe('Write access tracking (Rust)', () => { it('emits ACCESSES write edges for field assignments', () => { const accesses = getRelationships(result, 'ACCESSES'); const writes = accesses.filter(e => e.rel.reason === 'write'); - expect(writes.length).toBeGreaterThanOrEqual(2); + expect(writes.length).toBe(3); const fieldNames = writes.map(e => e.target); expect(fieldNames).toContain('name'); expect(fieldNames).toContain('address'); + expect(fieldNames).toContain('score'); const sources = writes.map(e => e.source); expect(sources).toContain('update_user'); }); diff --git a/gitnexus/test/integration/resolvers/typescript.test.ts b/gitnexus/test/integration/resolvers/typescript.test.ts index 418385ae7..55a19ef76 100644 --- a/gitnexus/test/integration/resolvers/typescript.test.ts +++ b/gitnexus/test/integration/resolvers/typescript.test.ts @@ -1726,10 +1726,11 @@ describe('Field type resolution (TypeScript)', () => { it('emits HAS_PROPERTY edges linking properties to classes', () => { const propEdges = getRelationships(result, 'HAS_PROPERTY'); - expect(propEdges.length).toBeGreaterThanOrEqual(3); + expect(propEdges.length).toBe(4); expect(edgeSet(propEdges)).toContain('User → address'); expect(edgeSet(propEdges)).toContain('User → name'); expect(edgeSet(propEdges)).toContain('Address → city'); + expect(edgeSet(propEdges)).toContain('Config → DEFAULT'); }); it('resolves user.address.save() → Address#save via field type', () => { diff --git a/gitnexus/test/unit/type-env.test.ts b/gitnexus/test/unit/type-env.test.ts index e740818ba..fcbebaba2 100644 --- a/gitnexus/test/unit/type-env.test.ts +++ b/gitnexus/test/unit/type-env.test.ts @@ -554,7 +554,7 @@ class UserService { } findCalls(tree.rootNode); - expect(calls.length).toBeGreaterThanOrEqual(1); + expect(calls.length).toBe(1); // $this should resolve to enclosing class 'UserService' expect(typeEnv.lookup('$this', calls[0])).toBe('UserService'); }); @@ -822,7 +822,7 @@ object AppConfig { } findCalls(tree.rootNode); - expect(calls.length).toBeGreaterThanOrEqual(1); + expect(calls.length).toBe(1); expect(typeEnv.lookup('this', calls[0])).toBe('AppConfig'); }); });