Path: blob/main/src/vs/sessions/contrib/agentFeedback/test/browser/sessionEditorComments.test.ts
13405 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 { URI } from '../../../../../base/common/uri.js';7import { Range } from '../../../../../editor/common/core/range.js';8import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js';9import { getResourceEditorComments, getSessionEditorComments, groupNearbySessionEditorComments, hasAgentFeedbackComments, SessionEditorCommentSource } from '../../browser/sessionEditorComments.js';10import { ICodeReviewState, CodeReviewStateKind, IPRReviewState, PRReviewStateKind } from '../../../codeReview/browser/codeReviewService.js';1112type ICodeReviewResultState = Extract<ICodeReviewState, { kind: CodeReviewStateKind.Result }>;1314suite('SessionEditorComments', () => {15const session = URI.parse('test://session/1');16const fileA = URI.parse('file:///a.ts');17const fileB = URI.parse('file:///b.ts');1819ensureNoDisposablesAreLeakedInTestSuite();2021function reviewState(comments: ICodeReviewResultState['comments']): ICodeReviewState {22return {23kind: CodeReviewStateKind.Result,24version: 'v1',25reviewCount: 1,26comments,27didProduceComments: comments.length > 0,28};29}3031test('merges and sorts feedback and review comments by resource and range', () => {32const comments = getSessionEditorComments(session, [33{ id: 'feedback-b', text: 'feedback b', resourceUri: fileB, range: new Range(8, 1, 8, 1), sessionResource: session },34{ id: 'feedback-a', text: 'feedback a', resourceUri: fileA, range: new Range(12, 1, 12, 1), sessionResource: session },35], reviewState([36{ id: 'review-a', uri: fileA, range: new Range(3, 1, 3, 1), body: 'review a', kind: 'issue', severity: 'warning' },37{ id: 'review-b', uri: fileB, range: new Range(2, 1, 2, 1), body: 'review b', kind: 'issue', severity: 'warning' },38]));3940assert.deepStrictEqual(comments.map(comment => `${comment.resourceUri.path}:${comment.range.startLineNumber}:${comment.source}`), [41'/a.ts:3:codeReview',42'/a.ts:12:agentFeedback',43'/b.ts:2:codeReview',44'/b.ts:8:agentFeedback',45]);46});4748test('groups nearby comments only within the same resource', () => {49const comments = getSessionEditorComments(session, [50{ id: 'feedback-a', text: 'feedback a', resourceUri: fileA, range: new Range(10, 1, 10, 1), sessionResource: session },51], reviewState([52{ id: 'review-a', uri: fileA, range: new Range(13, 1, 13, 1), body: 'review a', kind: 'issue', severity: 'warning' },53{ id: 'review-b', uri: fileB, range: new Range(11, 1, 11, 1), body: 'review b', kind: 'issue', severity: 'warning' },54]));5556const groups = groupNearbySessionEditorComments(comments, 5);57assert.strictEqual(groups.length, 2);58assert.deepStrictEqual(groups[0].map(comment => `${comment.resourceUri.path}:${comment.range.startLineNumber}:${comment.source}`), [59'/a.ts:10:agentFeedback',60'/a.ts:13:codeReview',61]);62assert.deepStrictEqual(groups[1].map(comment => `${comment.resourceUri.path}:${comment.range.startLineNumber}:${comment.source}`), [63'/b.ts:11:codeReview',64]);65});6667test('preserves review suggestion metadata and capability flags', () => {68const comments = getSessionEditorComments(session, [], reviewState([69{70id: 'review-suggestion',71uri: fileA,72range: new Range(7, 1, 7, 1),73body: 'prefer a constant',74kind: 'suggestion',75severity: 'info',76suggestion: {77edits: [{ range: new Range(7, 1, 7, 10), oldText: 'let value', newText: 'const value' }],78},79},80]));8182assert.strictEqual(comments.length, 1);83assert.strictEqual(comments[0].source, SessionEditorCommentSource.CodeReview);84assert.strictEqual(comments[0].canConvertToAgentFeedback, true);85assert.strictEqual(comments[0].suggestion?.edits[0].newText, 'const value');86});8788test('filters resource comments and detects authored feedback presence', () => {89const comments = getSessionEditorComments(session, [90{ id: 'feedback-a', text: 'feedback a', resourceUri: fileA, range: new Range(1, 1, 1, 1), sessionResource: session },91], reviewState([92{ id: 'review-b', uri: fileB, range: new Range(2, 1, 2, 1), body: 'review b', kind: 'issue', severity: 'warning' },93]));9495assert.strictEqual(hasAgentFeedbackComments(comments), true);96assert.deepStrictEqual(getResourceEditorComments(fileA, comments).map(comment => comment.source), [SessionEditorCommentSource.AgentFeedback]);97assert.deepStrictEqual(getResourceEditorComments(fileB, comments).map(comment => comment.source), [SessionEditorCommentSource.CodeReview]);98});99100test('includes PR review comments when prReviewState is loaded', () => {101const prState: IPRReviewState = {102kind: PRReviewStateKind.Loaded,103comments: [104{ id: 'pr-thread-1', uri: fileA, range: new Range(5, 1, 5, 1), body: 'Please fix this', author: 'reviewer' },105{ id: 'pr-thread-2', uri: fileB, range: new Range(1, 1, 1, 1), body: 'Looks wrong', author: 'reviewer' },106],107};108109const comments = getSessionEditorComments(session, [], reviewState([]), prState);110assert.strictEqual(comments.length, 2);111assert.deepStrictEqual(comments.map(c => `${c.resourceUri.path}:${c.range.startLineNumber}:${c.source}`), [112'/a.ts:5:prReview',113'/b.ts:1:prReview',114]);115assert.strictEqual(comments[0].canConvertToAgentFeedback, true);116});117118test('merges PR review comments with other sources sorted correctly', () => {119const prState: IPRReviewState = {120kind: PRReviewStateKind.Loaded,121comments: [122{ id: 'pr-thread-1', uri: fileA, range: new Range(7, 1, 7, 1), body: 'PR comment', author: 'reviewer' },123],124};125126const comments = getSessionEditorComments(session, [127{ id: 'feedback-a', text: 'feedback a', resourceUri: fileA, range: new Range(3, 1, 3, 1), sessionResource: session },128], reviewState([129{ id: 'review-a', uri: fileA, range: new Range(10, 1, 10, 1), body: 'review', kind: 'issue', severity: 'warning' },130]), prState);131132assert.strictEqual(comments.length, 3);133assert.deepStrictEqual(comments.map(c => `${c.range.startLineNumber}:${c.source}`), [134'3:agentFeedback',135'7:prReview',136'10:codeReview',137]);138});139140test('omits PR review comments when prReviewState is not loaded', () => {141const prState: IPRReviewState = { kind: PRReviewStateKind.None };142const comments = getSessionEditorComments(session, [], reviewState([]), prState);143assert.strictEqual(comments.length, 0);144});145});146147148