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