Path: blob/main/extensions/copilot/test/simulation/nesExternalTests.ts
13389 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/456import * as fs from 'fs';7import * as path from 'path';8import { serializeSingleEdit } from '../../src/platform/inlineEdits/common/dataTypes/editUtils';9import { assert } from '../../src/util/vs/base/common/assert';10import { SimulationOptions } from '../base/simulationOptions';11import { Configuration, ISimulationTestRuntime, SimulationSuite, SimulationTest } from '../base/stest';12import { loadFile } from './inlineEdit/fileLoading';13import { EditNotScoredError, InlineEditTester } from './inlineEdit/inlineEditTester';14import { nesOptionsToConfigurations } from './nesOptionsToConfigurations';1516const RECORDING_BASENAME = 'recording.w.json';17const RECORDING_FILE_SUFFIX = '.recording.w.json';1819async function discoverRecordingFiles(rootPath: string) {20const recordings: fs.Dirent<string>[] = [];2122async function dfs(root: string) {23const contents = await fs.promises.readdir(root, { withFileTypes: true });2425await Promise.all(contents.map(entry => {26if (entry.isFile() && entry.name.includes(RECORDING_BASENAME)) {27recordings.push(entry);28return;29}30if (entry.isDirectory()) {31return dfs(path.join(entry.parentPath, entry.name));32}33}));34}3536await dfs(rootPath);3738return recordings;39}4041export async function discoverNesTests(rootFolder: string, options: SimulationOptions) {42const recordingFiles = await discoverRecordingFiles(rootFolder);4344const tester = new InlineEditTester();4546const configurations = nesOptionsToConfigurations(options);4748const rootSuite = new SimulationSuite({ title: 'NES', location: 'external' });4950let tests = recordingFiles.map((file) => generateExternalStestFromRecording(file, rootSuite, tester, configurations));5152tests = tests.sort((a, b) => a.fullName.localeCompare(b.fullName));5354rootSuite.tests.push(...tests);5556return rootSuite;57}5859function generateExternalStestFromRecording(file: fs.Dirent<string>, containingSuite: SimulationSuite, tester: InlineEditTester, configurations: Configuration<unknown>[]): SimulationTest {60const fileDir = file.parentPath;61const basename = file.name;6263const testName = computeTestNameFromFile(file);6465const stest = new SimulationTest({ description: testName, configurations }, {}, containingSuite, async (collection) => {66const accessor = collection.createTestingAccessor();6768const { isScored, result, scoredEditsFilePath } = await tester.runAndScoreFromRecording(accessor, loadFile({ filePath: path.join(fileDir, basename) }));6970accessor.get(ISimulationTestRuntime).writeFile(`${testName}.textAfterAiEdit.txt`, result.textAfterAiEdit?.value ?? '<NO AI EDIT>', 'textAfterAiEdit');71accessor.get(ISimulationTestRuntime).writeFile(`${testName}.aiEdit.json`, result.nextEdit === undefined ? '<NO AI EDIT>' : JSON.stringify(result.nextEdit ? serializeSingleEdit(result.nextEdit) : undefined), 'nextEdit');7273if (!isScored) {74throw new EditNotScoredError(scoredEditsFilePath);75}76});7778return stest;79}8081function computeTestNameFromFile(file: fs.Dirent<string>): string {82const basename = file.name;8384// if ends with recording file suffix, remove suffix85if (basename.endsWith(RECORDING_FILE_SUFFIX)) {86return basename.slice(0, -RECORDING_FILE_SUFFIX.length);87}8889// if basename is just the recording file name, use parent directory name as test name90if (basename === RECORDING_BASENAME) {91const fileDir = file.parentPath;92const pathChunks = fileDir.split(path.sep);93const parentBasename = pathChunks.at(-1);94assert(parentBasename !== undefined, `Expected recording's ${path.join(file.parentPath, file.name)} parent directory name to be defined`);9596if (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`97return `[${pathChunks.at(-2)}] ${parentBasename}`;98}99100return parentBasename;101}102103throw new Error('Unexpected file name format');104}105106107