mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-10-16 04:28:11 +00:00
173 lines
6.8 KiB
TypeScript
173 lines
6.8 KiB
TypeScript
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
|
|
import fs from 'node:fs';
|
|
import os from 'node:os';
|
|
import path from 'node:path';
|
|
import {
|
|
getRelationships,
|
|
runPipelineFromRepo,
|
|
writeFixtureRepo,
|
|
type PipelineResult,
|
|
} from './helpers.js';
|
|
|
|
describe('C++ lexical using declarations and directives', () => {
|
|
let repoDir: string;
|
|
let result: PipelineResult;
|
|
|
|
beforeAll(async () => {
|
|
repoDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gitnexus-cpp-local-using-'));
|
|
writeFixtureRepo(repoDir, {
|
|
'alpha.hpp': `namespace alpha {
|
|
int work() { return 1; }
|
|
int collision() { return 1; }
|
|
struct Worker { int run() { return 1; } };
|
|
namespace detail { int nested_work() { return 1; } }
|
|
}
|
|
int included_helper() { return 1; }
|
|
`,
|
|
'beta.hpp': `namespace beta {
|
|
int work() { return 2; }
|
|
struct Worker { int run() { return 2; } };
|
|
namespace detail { int nested_work() { return 2; } }
|
|
}
|
|
`,
|
|
'decoy.cpp': 'int work() { return 9; }\n',
|
|
'main.cpp': `#include "alpha.hpp"
|
|
#include "beta.hpp"
|
|
int collision() { return 0; }
|
|
int named_alpha() { using alpha::work; return work(); }
|
|
int named_beta() { using beta::work; return work(); }
|
|
int before_named() { return work(); using alpha::work; }
|
|
int unresolved_named() { using missing::work; return work(); }
|
|
int missing_member() { using alpha::absent; return absent(); }
|
|
int directive_alpha() { using namespace alpha; return work(); }
|
|
int directive_beta() { using namespace beta; return work(); }
|
|
int before_directive() { return work(); using namespace alpha; }
|
|
int sibling() { return work(); }
|
|
int nested_block() { { using alpha::work; work(); } return 0; }
|
|
int outside_block() { { using alpha::work; } return work(); }
|
|
int ambiguous_directives() { using namespace alpha; using namespace beta; return work(); }
|
|
int type_alpha() { using alpha::Worker; Worker worker; return worker.run(); }
|
|
int type_beta() { using beta::Worker; Worker worker; return worker.run(); }
|
|
int directive_type() { using namespace alpha; Worker worker; return worker.run(); }
|
|
int before_type() { Worker worker; using alpha::Worker; return worker.run(); }
|
|
int value_shadow() { using namespace alpha; { int work = 0; return work(); } }
|
|
int ancestor_value_shadow() { int work = 0; { using namespace alpha; return work(); } }
|
|
int global_collision() { using namespace alpha; return collision(); }
|
|
int directive_before_value() { using namespace alpha; work(); int work = 0; return 0; }
|
|
int prototype_parameter() { using namespace alpha; void unused(int work); return work(); }
|
|
int function_pointer_parameter(void (*callback)(int work)) { using namespace alpha; return work(); }
|
|
int actual_parameter(int work) { using namespace alpha; return work(); }
|
|
int nested_alpha() { using alpha::detail::nested_work; return nested_work(); }
|
|
int nested_beta() { using beta::detail::nested_work; return nested_work(); }
|
|
struct InlineCaller { int inline_method() { using alpha::work; return work(); } };
|
|
int header_control() { return included_helper(); }
|
|
`,
|
|
'overloads.hpp': 'namespace imported { int choose(int value) { return value; } }\n',
|
|
'overloads.cpp': `#include "overloads.hpp"
|
|
int choose(double value) { return 1; }
|
|
int before_using() { return choose(1.0); }
|
|
using imported::choose;
|
|
int local_overload() { return choose(1.0); }
|
|
int imported_overload() { return choose(1); }
|
|
int block_hides_outer() { using imported::choose; return choose(1.0); }
|
|
`,
|
|
'nested-overloads.cpp': `#include "overloads.hpp"
|
|
namespace nested {
|
|
int choose(double value) { return 2; }
|
|
using imported::choose;
|
|
int nested_local() { return choose(1.0); }
|
|
int nested_imported() { return choose(1); }
|
|
}
|
|
`,
|
|
'absent.cpp': 'int absent() { return 0; }\n',
|
|
});
|
|
result = await runPipelineFromRepo(repoDir, () => {});
|
|
}, 60_000);
|
|
|
|
afterAll(() => {
|
|
if (repoDir !== undefined) fs.rmSync(repoDir, { recursive: true, force: true });
|
|
});
|
|
|
|
it.each([
|
|
['named_alpha', 'alpha.hpp'],
|
|
['named_beta', 'beta.hpp'],
|
|
['directive_alpha', 'alpha.hpp'],
|
|
['directive_beta', 'beta.hpp'],
|
|
['nested_block', 'alpha.hpp'],
|
|
['inline_method', 'alpha.hpp'],
|
|
['directive_before_value', 'alpha.hpp'],
|
|
['prototype_parameter', 'alpha.hpp'],
|
|
['function_pointer_parameter', 'alpha.hpp'],
|
|
])('resolves %s to its exact namespace member', (caller, targetFile) => {
|
|
const calls = getRelationships(result, 'CALLS').filter(
|
|
(edge) => edge.source === caller && edge.target === 'work',
|
|
);
|
|
expect(calls.map((edge) => edge.targetFilePath)).toEqual([targetFile]);
|
|
});
|
|
|
|
it.each([
|
|
['nested_alpha', 'alpha.hpp'],
|
|
['nested_beta', 'beta.hpp'],
|
|
])('preserves the full namespace path in %s', (caller, targetFile) => {
|
|
const calls = getRelationships(result, 'CALLS').filter(
|
|
(edge) => edge.source === caller && edge.target === 'nested_work',
|
|
);
|
|
expect(calls.map((edge) => edge.targetFilePath)).toEqual([targetFile]);
|
|
});
|
|
|
|
it.each(['before_named', 'before_directive', 'sibling', 'outside_block'])(
|
|
'does not leak a namespace using into %s',
|
|
(caller) => {
|
|
const calls = getRelationships(result, 'CALLS').filter(
|
|
(edge) => edge.source === caller && edge.target === 'work',
|
|
);
|
|
expect(calls.some((edge) => edge.targetFilePath === 'alpha.hpp')).toBe(false);
|
|
expect(calls.some((edge) => edge.targetFilePath === 'beta.hpp')).toBe(false);
|
|
},
|
|
);
|
|
|
|
it.each([
|
|
'unresolved_named',
|
|
'missing_member',
|
|
'ambiguous_directives',
|
|
'value_shadow',
|
|
'ancestor_value_shadow',
|
|
'actual_parameter',
|
|
'global_collision',
|
|
'before_type',
|
|
])('does not guess an unrelated target for %s', (caller) => {
|
|
expect(getRelationships(result, 'CALLS').filter((edge) => edge.source === caller)).toEqual([]);
|
|
});
|
|
|
|
it.each([
|
|
['type_alpha', 'alpha.hpp'],
|
|
['type_beta', 'beta.hpp'],
|
|
['directive_type', 'alpha.hpp'],
|
|
])('uses the namespace type identity in %s', (caller, targetFile) => {
|
|
const calls = getRelationships(result, 'CALLS').filter(
|
|
(edge) => edge.source === caller && edge.target === 'run',
|
|
);
|
|
expect(calls.map((edge) => edge.targetFilePath)).toEqual([targetFile]);
|
|
});
|
|
|
|
it('preserves compilation-unit include bindings', () => {
|
|
const calls = getRelationships(result, 'CALLS').filter(
|
|
(edge) => edge.source === 'header_control' && edge.target === 'included_helper',
|
|
);
|
|
expect(calls.map((edge) => edge.targetFilePath)).toEqual(['alpha.hpp']);
|
|
});
|
|
|
|
it.each([
|
|
['before_using', 'overloads.cpp'],
|
|
['local_overload', 'overloads.cpp'],
|
|
['imported_overload', 'overloads.hpp'],
|
|
['nested_local', 'nested-overloads.cpp'],
|
|
['nested_imported', 'overloads.hpp'],
|
|
['block_hides_outer', 'overloads.hpp'],
|
|
])('preserves the exact overload selected by %s', (caller, targetFile) => {
|
|
const calls = getRelationships(result, 'CALLS').filter(
|
|
(edge) => edge.source === caller && edge.target === 'choose',
|
|
);
|
|
expect(calls.map((edge) => edge.targetFilePath)).toEqual([targetFile]);
|
|
});
|
|
});
|