Path: blob/main/extensions/copilot/test/inline/review.stest.ts
13388 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*--------------------------------------------------------------------------------------------*/45import assert from 'assert';6import path from 'path';7import { FeedbackGenerator } from '../../src/extension/prompt/node/feedbackGenerator';8import { CHAT_MODEL } from '../../src/platform/configuration/common/configurationService';9import { TextDocumentSnapshot } from '../../src/platform/editing/common/textDocumentSnapshot';10import { ReviewComment } from '../../src/platform/review/common/reviewService';11import { TestingServiceCollection } from '../../src/platform/test/node/services';12import { IInstantiationService } from '../../src/util/vs/platform/instantiation/common/instantiation';13import { CancellationTokenSource, Range } from '../../src/vscodeTypes';14import { ssuite, stest } from '../base/stest';15import { setupSimulationWorkspace, teardownSimulationWorkspace } from '../simulation/inlineChatSimulator';16import { forEachModel, fromFixture } from '../simulation/stestUtil';1718const models = [CHAT_MODEL.GPT41];1920ssuite({ title: '/review', location: 'inline' }, forEachModel(models, model => {2122stest({ description: 'Binary search with incorrect stop condition', language: 'javascript', model }, async (testingServiceCollection) => {23const comments = await generateComments(testingServiceCollection, 'review/binary-search-1.js');24const expectedLine = 4;25const expectedContent = 'left <= right';26const expectedMinRelevance = 10;27const expectedKind = 'bug';28assertComment(comments, expectedLine, expectedContent, expectedMinRelevance, expectedKind);29});3031stest({ description: 'Binary search with correct stop condition', language: 'javascript', model }, async (testingServiceCollection) => {32const comments = await generateComments(testingServiceCollection, 'review/binary-search-2.js');33assertNoHighPriorityCommentOrBug(comments);34});3536stest({ description: 'Bank account with missing lock acquisition', language: 'python', model }, async (testingServiceCollection) => {37const comments = await generateComments(testingServiceCollection, 'review/bank-account-1.py');38const expectedLines = [15, 16, 18, 19];39const expectedContent = 'lock';40const expectedMinRelevance = 5;41const expectedKinds = ['bug', 'consistency'];42assertComment(comments, expectedLines, expectedContent, expectedMinRelevance, expectedKinds);43});4445stest({ description: 'Bank account with lock acquisition', language: 'python', model }, async (testingServiceCollection) => {46const comments = await generateComments(testingServiceCollection, 'review/bank-account-2.py');47const unexpected = comments.filter(c => ['bug', 'consistency'].includes(c.kind) && (typeof c.body === 'string' ? c.body : c.body.value).indexOf('lock') !== -1);48assert.strictEqual(unexpected.length, 0);49});5051stest({ description: 'InstantiationService this scoping bug', language: 'typescript', model }, async (testingServiceCollection) => {52const comments = await generateComments(testingServiceCollection, 'review/nested-services-1.ts');53const expectedLine = 9;54const expectedContent = 'this._parent._children.delete';55const expectedMinRelevance = 5;56const expectedKind = 'bug';57assertComment(comments, expectedLine, expectedContent, expectedMinRelevance, expectedKind);58});5960stest({ description: 'InstantiationService this scoping fixed', language: 'typescript', model }, async (testingServiceCollection) => {61const comments = await generateComments(testingServiceCollection, 'review/nested-services-2.ts');62const unexpected = comments.filter(c => c.kind === 'bug' && c.range.start.line === 10);63assert.strictEqual(unexpected.length, 0);64});65}));6667async function generateComments(testingServiceCollection: TestingServiceCollection, relativeFixturePath: string) {68const workspace = setupSimulationWorkspace(testingServiceCollection, { files: [fromFixture(relativeFixturePath)] });69const accessor = testingServiceCollection.createTestingAccessor();70const instantiationService = accessor.get(IInstantiationService);7172const source = new CancellationTokenSource();73try {74const relativeDocumentPath = path.basename(relativeFixturePath);75const document = TextDocumentSnapshot.create(workspace.getDocument(relativeDocumentPath).document);76const feedbackGenerator = instantiationService.createInstance(FeedbackGenerator);77const result = await feedbackGenerator.generateComments([78{79document,80relativeDocumentPath,81selection: new Range(0, 0, document.lineCount, 0),82}83], source.token);84return result.type === 'success' ? result.comments : [];85} finally {86source.dispose();87await teardownSimulationWorkspace(accessor, workspace);88}89}9091function assertComment(comments: ReviewComment[], expectedLines: number | number[], expectedContent: string, expectedMinRelevance: number, expectedKind: string | string[]) {92const lines = Array.isArray(expectedLines) ? expectedLines : [expectedLines];93const lineComment = comments?.find(d => lines.indexOf(d.range.start.line) !== -1);94assert.ok(lineComment, `Expected comment for line(s) ${lines.join(', ')}.`);95const message = typeof lineComment.body === 'string' ? lineComment.body : lineComment.body.value;96assert.ok(message.includes(expectedContent), `Expected comment for line(s) ${lines.join(', ')} to contain "${expectedContent}"`);97// assert.ok(typeof lineComment.relevance === 'number' && lineComment.relevance >= expectedMinRelevance, `Expected comment to have relevance >= ${expectedMinRelevance}, was: ${lineComment.relevance}`);98const kinds = Array.isArray(expectedKind) ? expectedKind : [expectedKind];99assert.ok(kinds.indexOf(lineComment.kind) !== -1, `Expected ${kinds.join(', ')} comment, was: ${lineComment.kind}`);100}101102function assertNoHighPriorityCommentOrBug(comments: ReviewComment[]) {103// const highPriority = comments.filter(d => d.relevance === 10);104// assert.strictEqual(highPriority.length, 0, `Expected no high priority comment`);105const bugs = comments.filter(d => d.kind === 'bug');106assert.strictEqual(bugs.length, 0, `Expected no bug comment`);107}108109export function logComments(comments: ReviewComment[]) {110console.log(JSON.stringify(comments.map(c => ({111line: c.range.start.line,112content: typeof c.body === 'string' ? c.body : c.body.value,113severity: c.severity,114kind: c.kind115})), null, 2));116}117118119