Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/test/simulation/nesExternalTests.ts
13389 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
7
import * as fs from 'fs';
8
import * as path from 'path';
9
import { serializeSingleEdit } from '../../src/platform/inlineEdits/common/dataTypes/editUtils';
10
import { assert } from '../../src/util/vs/base/common/assert';
11
import { SimulationOptions } from '../base/simulationOptions';
12
import { Configuration, ISimulationTestRuntime, SimulationSuite, SimulationTest } from '../base/stest';
13
import { loadFile } from './inlineEdit/fileLoading';
14
import { EditNotScoredError, InlineEditTester } from './inlineEdit/inlineEditTester';
15
import { nesOptionsToConfigurations } from './nesOptionsToConfigurations';
16
17
const RECORDING_BASENAME = 'recording.w.json';
18
const RECORDING_FILE_SUFFIX = '.recording.w.json';
19
20
async function discoverRecordingFiles(rootPath: string) {
21
const recordings: fs.Dirent<string>[] = [];
22
23
async function dfs(root: string) {
24
const contents = await fs.promises.readdir(root, { withFileTypes: true });
25
26
await Promise.all(contents.map(entry => {
27
if (entry.isFile() && entry.name.includes(RECORDING_BASENAME)) {
28
recordings.push(entry);
29
return;
30
}
31
if (entry.isDirectory()) {
32
return dfs(path.join(entry.parentPath, entry.name));
33
}
34
}));
35
}
36
37
await dfs(rootPath);
38
39
return recordings;
40
}
41
42
export async function discoverNesTests(rootFolder: string, options: SimulationOptions) {
43
const recordingFiles = await discoverRecordingFiles(rootFolder);
44
45
const tester = new InlineEditTester();
46
47
const configurations = nesOptionsToConfigurations(options);
48
49
const rootSuite = new SimulationSuite({ title: 'NES', location: 'external' });
50
51
let tests = recordingFiles.map((file) => generateExternalStestFromRecording(file, rootSuite, tester, configurations));
52
53
tests = tests.sort((a, b) => a.fullName.localeCompare(b.fullName));
54
55
rootSuite.tests.push(...tests);
56
57
return rootSuite;
58
}
59
60
function generateExternalStestFromRecording(file: fs.Dirent<string>, containingSuite: SimulationSuite, tester: InlineEditTester, configurations: Configuration<unknown>[]): SimulationTest {
61
const fileDir = file.parentPath;
62
const basename = file.name;
63
64
const testName = computeTestNameFromFile(file);
65
66
const stest = new SimulationTest({ description: testName, configurations }, {}, containingSuite, async (collection) => {
67
const accessor = collection.createTestingAccessor();
68
69
const { isScored, result, scoredEditsFilePath } = await tester.runAndScoreFromRecording(accessor, loadFile({ filePath: path.join(fileDir, basename) }));
70
71
accessor.get(ISimulationTestRuntime).writeFile(`${testName}.textAfterAiEdit.txt`, result.textAfterAiEdit?.value ?? '<NO AI EDIT>', 'textAfterAiEdit');
72
accessor.get(ISimulationTestRuntime).writeFile(`${testName}.aiEdit.json`, result.nextEdit === undefined ? '<NO AI EDIT>' : JSON.stringify(result.nextEdit ? serializeSingleEdit(result.nextEdit) : undefined), 'nextEdit');
73
74
if (!isScored) {
75
throw new EditNotScoredError(scoredEditsFilePath);
76
}
77
});
78
79
return stest;
80
}
81
82
function computeTestNameFromFile(file: fs.Dirent<string>): string {
83
const basename = file.name;
84
85
// if ends with recording file suffix, remove suffix
86
if (basename.endsWith(RECORDING_FILE_SUFFIX)) {
87
return basename.slice(0, -RECORDING_FILE_SUFFIX.length);
88
}
89
90
// if basename is just the recording file name, use parent directory name as test name
91
if (basename === RECORDING_BASENAME) {
92
const fileDir = file.parentPath;
93
const pathChunks = fileDir.split(path.sep);
94
const parentBasename = pathChunks.at(-1);
95
assert(parentBasename !== undefined, `Expected recording's ${path.join(file.parentPath, file.name)} parent directory name to be defined`);
96
97
if (pathChunks.at(-2)?.[0].match(/^[A-Z]/)) { // if the recording is at `path/to/MustHave/MyAwesomeTest/recording.w.json` - test name should be `[MustHave] MyAwesomeTest`
98
return `[${pathChunks.at(-2)}] ${parentBasename}`;
99
}
100
101
return parentBasename;
102
}
103
104
throw new Error('Unexpected file name format');
105
}
106
107