From df6a409ad0a7c56e4e71f5727713b66dfeba6391 Mon Sep 17 00:00:00 2001 From: mann1x <20623405+mann1x@users.noreply.github.com> Date: Sun, 26 Apr 2026 13:49:32 +0200 Subject: [PATCH] test(csharp): companion fixture for #1066 frozen-bucket regression The csharp-large-cache-miss-resolution fixture added in #1082 reproduces the freeze contract failure via tree-sitter cache-miss reparse on >32 KB files. This adds a complementary trigger for the same root cause that does not depend on file size: a small-file pair where the importer locally declares a class with the same simple name as a sibling reached through `using`. Pre-#1082 path: scope-extractor pre-populates (and freezes) `User` in the importer's Module bindings, then populateCsharpNamespaceSiblings' namespace-import loop calls push() on the frozen array and throws "Cannot add property N, object is not extensible", aborting the whole scopeResolution phase. Post-#1082 the augmentation channel keeps both bindings visible; the local `Collision.App.User` shadows the namespace-imported one per origin precedence, so `Program.Run -> new User()` resolves to the local class. Three assertions: - scopeResolution completes (no throw on the colliding bucket). - both `User` declarations are detected across the two namespaces. - `Program.Run -> User` constructor edge points at App/Program.cs (not Models/User.cs), verifying origin:local shadows origin:namespace. Verified: full csharp.test.ts suite green (207/207). tsc --noEmit clean. Refs: #1066, #1082, #1083 (closed as superseded). --- .../App/Program.cs | 18 +++++++ .../CsharpFrozenBindingCollision.csproj | 6 +++ .../Models/User.cs | 7 +++ .../test/integration/resolvers/csharp.test.ts | 47 +++++++++++++++++++ 4 files changed, 78 insertions(+) create mode 100644 gitnexus/test/fixtures/lang-resolution/csharp-frozen-binding-collision/App/Program.cs create mode 100644 gitnexus/test/fixtures/lang-resolution/csharp-frozen-binding-collision/CsharpFrozenBindingCollision.csproj create mode 100644 gitnexus/test/fixtures/lang-resolution/csharp-frozen-binding-collision/Models/User.cs diff --git a/gitnexus/test/fixtures/lang-resolution/csharp-frozen-binding-collision/App/Program.cs b/gitnexus/test/fixtures/lang-resolution/csharp-frozen-binding-collision/App/Program.cs new file mode 100644 index 0000000000..4e71ec93a7 --- /dev/null +++ b/gitnexus/test/fixtures/lang-resolution/csharp-frozen-binding-collision/App/Program.cs @@ -0,0 +1,18 @@ +using Collision.Models; + +namespace Collision.App +{ + public class User + { + public string GetName() { return "app"; } + } + + public class Program + { + public void Run() + { + var u = new User(); + u.GetName(); + } + } +} diff --git a/gitnexus/test/fixtures/lang-resolution/csharp-frozen-binding-collision/CsharpFrozenBindingCollision.csproj b/gitnexus/test/fixtures/lang-resolution/csharp-frozen-binding-collision/CsharpFrozenBindingCollision.csproj new file mode 100644 index 0000000000..4cefc0dfae --- /dev/null +++ b/gitnexus/test/fixtures/lang-resolution/csharp-frozen-binding-collision/CsharpFrozenBindingCollision.csproj @@ -0,0 +1,6 @@ + + + net8.0 + Collision + + diff --git a/gitnexus/test/fixtures/lang-resolution/csharp-frozen-binding-collision/Models/User.cs b/gitnexus/test/fixtures/lang-resolution/csharp-frozen-binding-collision/Models/User.cs new file mode 100644 index 0000000000..a02beb6722 --- /dev/null +++ b/gitnexus/test/fixtures/lang-resolution/csharp-frozen-binding-collision/Models/User.cs @@ -0,0 +1,7 @@ +namespace Collision.Models +{ + public class User + { + public string GetName() { return "models"; } + } +} diff --git a/gitnexus/test/integration/resolvers/csharp.test.ts b/gitnexus/test/integration/resolvers/csharp.test.ts index b412ecc9a7..1d41bb1708 100644 --- a/gitnexus/test/integration/resolvers/csharp.test.ts +++ b/gitnexus/test/integration/resolvers/csharp.test.ts @@ -2485,3 +2485,50 @@ describe('C# large-file + frozen-bucket regression (issue #1066)', () => { expect(['import-resolved', 'global']).toContain(save!.rel.reason); }); }); + +// --------------------------------------------------------------------------- +// Issue #1066 companion regression: small-file trigger for the same +// frozen-bucket failure. Where csharp-large-cache-miss-resolution exercises +// the path through tree-sitter cache-miss reparse on >32 KB files, this +// fixture trips the same `Object.freeze` contract on the populator's +// namespace-import loop in a single small file pair: the importer locally +// declares a class with the same simple name as a sibling reachable through +// `using`, so the extractor pre-populates (and freezes) `User` in the +// importer's Module bindings before populateNamespaceSiblings tries to +// append the cross-file `Collision.Models.User`. Pre-#1082 the populator +// pushed onto the frozen array → "Cannot add property N, object is not +// extensible" → whole scopeResolution phase aborted. Post-#1082 the +// augmentation channel keeps both bindings visible to readers, with the +// local `Collision.App.User` taking precedence per origin ordering. +// --------------------------------------------------------------------------- + +describe('C# frozen-binding collision via using-import (issue #1066 companion)', () => { + let result: PipelineResult; + + beforeAll(async () => { + result = await runPipelineFromRepo( + path.join(FIXTURES, 'csharp-frozen-binding-collision'), + () => {}, + ); + }, 60000); + + it('completes scopeResolution without throwing on the colliding bucket', () => { + expect(getNodesByLabel(result, 'Class')).toEqual(expect.arrayContaining(['User', 'Program'])); + }); + + it('detects both User declarations across the two namespaces', () => { + const users = getNodesByLabelFull(result, 'Class').filter((n) => n.name === 'User'); + expect(users.length).toBe(2); + const paths = users.map((u) => u.properties.filePath).sort(); + expect(paths).toEqual(['App/Program.cs', 'Models/User.cs']); + }); + + it('resolves Program.Run -> local Collision.App.User constructor (origin:local shadows namespace)', () => { + const calls = getRelationships(result, 'CALLS'); + const ctor = calls.find( + (c) => c.source === 'Run' && c.target === 'User' && c.targetLabel === 'Class', + ); + expect(ctor).toBeDefined(); + expect(ctor!.targetFilePath).toBe('App/Program.cs'); + }); +});