Skip to content

Commit 971eaa5

Browse files
authored
fix: proper path handling for additional context (aws#2129)
* fix: proper pathing for additonal context * fix: update existing tests to also mock path.join()
1 parent 0bf825e commit 971eaa5

File tree

2 files changed

+118
-1
lines changed

2 files changed

+118
-1
lines changed

server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/additionalContextProvider.test.ts

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,12 @@ describe('AdditionalContextProvider', () => {
174174
workspaceFolder: mockWorkspaceFolder,
175175
}
176176

177+
// Mock path.join to simulate Unix behavior
178+
sinon.stub(path, 'join').callsFake((...args) => {
179+
// Simulate Unix path.join behavior
180+
return args.join('/').replace(/\\/g, '/')
181+
})
182+
177183
const explicitContext = [
178184
{
179185
id: 'explicit-file',
@@ -208,6 +214,9 @@ describe('AdditionalContextProvider', () => {
208214
assert.strictEqual(result.length, 1)
209215
assert.strictEqual(result[0].name, 'Explicit File')
210216
assert.strictEqual(result[0].pinned, false)
217+
218+
// Restore original path.join
219+
;(path.join as sinon.SinonStub).restore()
211220
})
212221

213222
it('should avoid duplicates between explicit and pinned context', async () => {
@@ -220,6 +229,12 @@ describe('AdditionalContextProvider', () => {
220229
workspaceFolder: mockWorkspaceFolder,
221230
}
222231

232+
// Mock path.join to simulate Unix behavior
233+
sinon.stub(path, 'join').callsFake((...args) => {
234+
// Simulate Unix path.join behavior
235+
return args.join('/').replace(/\\/g, '/')
236+
})
237+
223238
const sharedContext = {
224239
id: 'shared-file',
225240
command: 'Shared File',
@@ -255,6 +270,9 @@ describe('AdditionalContextProvider', () => {
255270
assert.strictEqual(result.length, 1)
256271
assert.strictEqual(result[0].name, 'Shared File')
257272
assert.strictEqual(result[0].pinned, false) // Should be marked as explicit, not pinned
273+
274+
// Restore original path.join
275+
;(path.join as sinon.SinonStub).restore()
258276
})
259277

260278
it('should handle Active File context correctly', async () => {
@@ -358,6 +376,105 @@ describe('AdditionalContextProvider', () => {
358376
assert.strictEqual(triggerContext.contextInfo?.pinnedContextCount.codeContextCount, 1)
359377
assert.strictEqual(triggerContext.contextInfo?.pinnedContextCount.promptContextCount, 1)
360378
})
379+
380+
it('should handle Unix path separators correctly', async () => {
381+
const mockWorkspaceFolder = { uri: URI.file('/workspace').toString(), name: 'test' }
382+
sinon.stub(workspaceUtils, 'getWorkspaceFolderPaths').returns(['/workspace'])
383+
384+
// Mock path.join to simulate Unix behavior
385+
sinon.stub(path, 'join').callsFake((...args) => {
386+
// Simulate Unix path.join behavior
387+
return args.join('/').replace(/\\/g, '/')
388+
})
389+
390+
const explicitContext = [
391+
{
392+
id: 'unix-prompt',
393+
command: 'Unix Prompt',
394+
label: 'file' as any,
395+
route: ['/Users/test/.aws/amazonq/prompts', 'hello.md'],
396+
},
397+
]
398+
399+
fsExistsStub.callsFake((path: string) => path.includes('.amazonq/rules'))
400+
fsReadDirStub.resolves([])
401+
402+
// Reset stub - return data for first call (explicit context), empty for second call (pinned context)
403+
getContextCommandPromptStub.reset()
404+
getContextCommandPromptStub.onFirstCall().resolves([
405+
{
406+
// promptContextCommands - explicit context
407+
name: 'Unix Prompt',
408+
content: 'content',
409+
filePath: '/Users/test/.aws/amazonq/prompts/hello.md', // Proper Unix path
410+
relativePath: 'hello.md',
411+
startLine: 1,
412+
endLine: 10,
413+
},
414+
])
415+
getContextCommandPromptStub.onSecondCall().resolves([]) // pinnedContextCommands - empty
416+
417+
const result = await provider.getAdditionalContext(
418+
{ workspaceFolder: mockWorkspaceFolder },
419+
'tab1',
420+
explicitContext
421+
)
422+
assert.strictEqual(result.length, 1)
423+
assert.strictEqual(result[0].name, 'Unix Prompt')
424+
425+
// Restore original path.join
426+
;(path.join as sinon.SinonStub).restore()
427+
})
428+
429+
it('should handle Windows path separators correctly', async () => {
430+
const mockWorkspaceFolder = { uri: URI.file('/workspace').toString(), name: 'test' }
431+
sinon.stub(workspaceUtils, 'getWorkspaceFolderPaths').returns(['/workspace'])
432+
433+
// Mock path.join to simulate Windows behavior
434+
const originalPathJoin = path.join
435+
sinon.stub(path, 'join').callsFake((...args) => {
436+
// Simulate Windows path.join behavior
437+
return args.join('\\').replace(/\//g, '\\')
438+
})
439+
440+
const explicitContext = [
441+
{
442+
id: 'windows-prompt',
443+
command: 'Windows Prompt',
444+
label: 'file' as any,
445+
route: ['C:\\Users\\test\\.aws\\amazonq\\prompts', 'hello.md'],
446+
},
447+
]
448+
449+
fsExistsStub.callsFake((path: string) => path.includes('.amazonq/rules'))
450+
fsReadDirStub.resolves([])
451+
452+
// Reset stub - return data for first call (explicit context), empty for second call (pinned context)
453+
getContextCommandPromptStub.reset()
454+
getContextCommandPromptStub.onFirstCall().resolves([
455+
{
456+
// promptContextCommands - explicit context
457+
name: 'Windows Prompt',
458+
content: 'content',
459+
filePath: 'C:\\Users\\test\\.aws\\amazonq\\prompts\\hello.md', // Proper Windows path
460+
relativePath: 'hello.md',
461+
startLine: 1,
462+
endLine: 10,
463+
},
464+
])
465+
getContextCommandPromptStub.onSecondCall().resolves([]) // pinnedContextCommands - empty
466+
467+
const result = await provider.getAdditionalContext(
468+
{ workspaceFolder: mockWorkspaceFolder },
469+
'tab1',
470+
explicitContext
471+
)
472+
assert.strictEqual(result.length, 1)
473+
assert.strictEqual(result[0].name, 'Windows Prompt')
474+
475+
// Restore original path.join
476+
;(path.join as sinon.SinonStub).restore()
477+
})
361478
})
362479

363480
describe('getFileListFromContext', () => {

server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/additionalContextProvider.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,7 @@ export class AdditionalContextProvider {
406406
const image = imageMap.get(item.description)
407407
if (image) ordered.push(image)
408408
} else {
409-
const doc = item.route ? docMap.get(item.route.join('/')) : undefined
409+
const doc = item.route ? docMap.get(path.join(...item.route)) : undefined
410410
if (doc) ordered.push(doc)
411411
}
412412
}

0 commit comments

Comments
 (0)