Files
Viper_VSCode/packages/vipeye-internal/src/tests/viperVpnci.test.ts
T
TermiNexus aef18c2891
Validation / Typecheck (push) Has been cancelled
Validation / Style (push) Has been cancelled
Validation / Test macos-latest (push) Has been cancelled
Validation / Test ubuntu-latest (push) Has been cancelled
Validation / Test windows-latest (push) Has been cancelled
Validation / Build (push) Has been cancelled
Validation / Required (push) Has been cancelled
更新了一些事项,feat(vipeye-internal): builtins.vpi 声明编译器内置 typedef rowptr = t.CPtr;feat(vipeye-internal): None 返回函数仅允许裸 return/return None,return 值为 None 的表达式报错;fix(vipeye-internal): builtins.vp 发现扩展到文件祖先目录与 includes 子目录,修复 uint64 等 typedef 未定义
2026-09-10 16:32:23 +08:00

109 lines
4.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* viperVpnci.test.ts
*
* 验证 Viper 不可编译注解文件 `.vpnci` 与 `.vpi` 配置完全一致:
* - `import MyModule` 可解析到 MyModule.vpnci(不报"导入失败/无法解析")
* - .vpnci 文件被识别为 stub 文件(isStubFile)
* - from 导入其中的声明可正常引用
*
* 运行:npx jest src/tests/viperVpnci.test.ts --runInBand
*/
import assert from 'assert';
import * as path from 'path';
import { ImportResolver } from '../analyzer/importResolver';
import { Program } from '../analyzer/program';
import { ConfigOptions, ExecutionEnvironment } from '../common/configOptions';
import { NullConsole } from '../common/console';
import { RealTempFile, createFromRealFileSystem } from '../common/realFileSystem';
import { createServiceProvider } from '../common/serviceProviderExtensions';
import { UriEx } from '../common/uri/uriUtils';
import { FullAccessHost } from '../common/fullAccessHost';
(global as any).__rootDirectory = path.resolve();
function buildProgram(files: Record<string, string>) {
const tempFile = new RealTempFile();
const serviceProvider = createServiceProvider(createFromRealFileSystem(tempFile), new NullConsole(), tempFile);
const fs = require('fs');
const testRoot = path.join(__dirname, '__vpnci__');
fs.rmSync(testRoot, { recursive: true, force: true });
for (const [relPath, content] of Object.entries(files)) {
const absPath = path.join(testRoot, relPath);
fs.mkdirSync(path.dirname(absPath), { recursive: true });
fs.writeFileSync(absPath, content, 'utf8');
}
const projectRoot = UriEx.file(testRoot);
const configOptions = new ConfigOptions(projectRoot);
configOptions.internalTestMode = true;
configOptions.initializeTypeCheckingMode('standard');
const execEnv = new ExecutionEnvironment(
'python',
projectRoot,
configOptions.diagnosticRuleSet,
configOptions.defaultPythonVersion,
configOptions.defaultPythonPlatform,
[projectRoot],
/* skipNativeLibraries */ false,
/* defaultDialect */ 'viper'
);
configOptions.executionEnvironments = [execEnv];
const importResolver = new ImportResolver(serviceProvider, configOptions, new FullAccessHost(serviceProvider));
const program = new Program(importResolver, configOptions, serviceProvider);
const uris = Object.keys(files).map((relPath) => UriEx.file(path.join(testRoot, relPath)));
const urisMap: Record<string, any> = {};
for (const relPath of Object.keys(files)) {
urisMap[relPath] = UriEx.file(path.join(testRoot, relPath));
}
program.setTrackedFiles(uris);
while (program.analyze()) {
// 循环
}
return { program, configOptions, urisMap, testRoot, serviceProvider };
}
function getDiagnostics(program: Program, configOptions: ConfigOptions, uri: any): string[] {
const sourceFile = program.getSourceFile(uri);
assert(sourceFile, 'source file not found');
return (sourceFile.getDiagnostics(configOptions) || []).map((diag) => {
const line = diag.range ? diag.range.start.line + 1 : -1;
return `[category=${diag.category}][line=${line}] ${diag.message}`;
});
}
test('.vpnci 不可编译注解文件:import 解析成功、识别为 stub、声明可引用', () => {
const { program, configOptions, urisMap, testRoot, serviceProvider } = buildProgram({
'MyModule.vpnci': `def helper() -> int:
...
`,
'main.vp': `from MyModule import helper
import MyModule
def main() -> int:
return helper() + MyModule.helper()
`,
});
// 1. main.vp 中 import/from 均解析成功,无"无法解析"或未定义
const mainDiags = getDiagnostics(program, configOptions, urisMap['main.vp']);
assert(
!mainDiags.some((d) => d.includes('无法解析') || d.includes('could not be resolved') || d.includes('未定义')),
`import MyModule 应解析成功且 helper 可引用,实际: ${JSON.stringify(mainDiags)}`
);
// 2. .vpnci 文件被识别为 stub 文件(与 .vpi 一致)
const stubFile = program.getSourceFile(urisMap['MyModule.vpnci']);
assert(stubFile, 'MyModule.vpnci 应被程序索引');
assert(stubFile.isStubFile(), 'MyModule.vpnci 应被识别为 stub 文件');
program.dispose();
serviceProvider.dispose();
require('fs').rmSync(testRoot, { recursive: true, force: true });
});