@@ -192,6 +192,34 @@ describe('LiveWatchTreeDataProvider', () => {
192192 await ( liveWatchTreeDataProvider as any ) . rename ( node , 'node-1-renamed' ) ;
193193 expect ( node . expression ) . toBe ( 'node-1-renamed' ) ;
194194 } ) ;
195+
196+ it ( 'copy copies node expression to clipboard' , async ( ) => {
197+ const node = makeNode ( 'node-to-copy' , { result : '1' , variablesReference : 0 } , 1 ) ;
198+ ( liveWatchTreeDataProvider as any ) . roots = [ node ] ;
199+ await ( liveWatchTreeDataProvider as any ) . handleCopyCommand ( node ) ;
200+ expect ( vscode . env . clipboard . writeText ) . toHaveBeenCalledWith ( 'node-to-copy' ) ;
201+ } ) ;
202+
203+ it ( 'AddFromSelection adds selected text as new live watch expression to roots' , async ( ) => {
204+ jest . spyOn ( liveWatchTreeDataProvider as any , 'evaluate' ) . mockResolvedValue ( { result : '5678' , variablesReference : 0 } ) ;
205+ // Mock the active text editor with a selection whose active position returns a word range
206+ const fakeRange = { start : { line : 0 , character : 0 } , end : { line : 0 , character : 10 } } ;
207+ const mockEditor : any = {
208+ document : {
209+ getWordRangeAtPosition : jest . fn ( ) . mockReturnValue ( fakeRange ) ,
210+ getText : jest . fn ( ) . mockReturnValue ( 'selected-expression' )
211+ } ,
212+ selection : { active : { line : 0 , character : 5 } }
213+ } ;
214+ ( vscode . window as any ) . activeTextEditor = mockEditor ;
215+ await ( liveWatchTreeDataProvider as any ) . handleAddFromSelectionCommand ( ) ;
216+ const roots = ( liveWatchTreeDataProvider as any ) . roots ;
217+ expect ( mockEditor . document . getWordRangeAtPosition ) . toHaveBeenCalledWith ( mockEditor . selection . active ) ;
218+ expect ( mockEditor . document . getText ) . toHaveBeenCalledWith ( fakeRange ) ;
219+ expect ( roots . length ) . toBe ( 1 ) ;
220+ expect ( roots [ 0 ] . expression ) . toBe ( 'selected-expression' ) ;
221+ expect ( roots [ 0 ] . value . result ) . toBe ( '5678' ) ;
222+ } ) ;
195223 } ) ;
196224
197225 describe ( 'refresh' , ( ) => {
@@ -247,7 +275,12 @@ describe('LiveWatchTreeDataProvider', () => {
247275 'vscode-cmsis-debugger.liveWatch.deleteAll' ,
248276 'vscode-cmsis-debugger.liveWatch.delete' ,
249277 'vscode-cmsis-debugger.liveWatch.refresh' ,
250- 'vscode-cmsis-debugger.liveWatch.modify'
278+ 'vscode-cmsis-debugger.liveWatch.modify' ,
279+ 'vscode-cmsis-debugger.liveWatch.copy' ,
280+ 'vscode-cmsis-debugger.liveWatch.addToLiveWatchFromTextEditor' ,
281+ 'vscode-cmsis-debugger.liveWatch.addToLiveWatchFromWatchWindow' ,
282+ 'vscode-cmsis-debugger.liveWatch.addToLiveWatchFromVariablesView' ,
283+ 'vscode-cmsis-debugger.liveWatch.showInMemoryInspector'
251284 ] ) ) ;
252285 } ) ;
253286
@@ -324,6 +357,79 @@ describe('LiveWatchTreeDataProvider', () => {
324357 await handler ( ) ;
325358 expect ( refreshSpy ) . toHaveBeenCalled ( ) ;
326359 } ) ;
360+
361+ it ( 'watch window command adds variable name root' , async ( ) => {
362+ jest . spyOn ( liveWatchTreeDataProvider as any , 'evaluate' ) . mockResolvedValue ( { result : 'value' , variablesReference : 0 } ) ;
363+ liveWatchTreeDataProvider . activate ( tracker ) ;
364+ const handler = getRegisteredHandler ( 'vscode-cmsis-debugger.liveWatch.addToLiveWatchFromWatchWindow' ) ;
365+ expect ( handler ) . toBeDefined ( ) ;
366+ await handler ( { variable : { name : 'myWatchVariable' } } ) ;
367+ const roots = ( liveWatchTreeDataProvider as any ) . roots ;
368+ expect ( roots . length ) . toBe ( 1 ) ;
369+ expect ( roots [ 0 ] . expression ) . toBe ( 'myWatchVariable' ) ;
370+ } ) ;
371+
372+ it ( 'watch window command does nothing with falsy payload' , async ( ) => {
373+ liveWatchTreeDataProvider . activate ( tracker ) ;
374+ const handler = getRegisteredHandler ( 'vscode-cmsis-debugger.liveWatch.addToLiveWatchFromWatchWindow' ) ;
375+ await handler ( undefined ) ;
376+ expect ( ( liveWatchTreeDataProvider as any ) . roots . length ) . toBe ( 0 ) ;
377+ } ) ;
378+
379+ it ( 'variables view command adds variable name root' , async ( ) => {
380+ jest . spyOn ( liveWatchTreeDataProvider as any , 'evaluate' ) . mockResolvedValue ( { result : '12345' , variablesReference : 0 } ) ;
381+ liveWatchTreeDataProvider . activate ( tracker ) ;
382+ const handler = getRegisteredHandler ( 'vscode-cmsis-debugger.liveWatch.addToLiveWatchFromVariablesView' ) ;
383+ expect ( handler ) . toBeDefined ( ) ;
384+ const payload = { container : { name : 'local' } , variable : { name : 'localVariable' } } ;
385+ await handler ( payload ) ;
386+ const roots = ( liveWatchTreeDataProvider as any ) . roots ;
387+ expect ( roots . length ) . toBe ( 1 ) ;
388+ expect ( roots [ 0 ] . expression ) . toBe ( 'localVariable' ) ;
389+ } ) ;
390+
391+ it ( 'variables view command does nothing when variable missing' , async ( ) => {
392+ liveWatchTreeDataProvider . activate ( tracker ) ;
393+ const handler = getRegisteredHandler ( 'vscode-cmsis-debugger.liveWatch.addToLiveWatchFromVariablesView' ) ;
394+ await handler ( { container : { name : 'local' } } ) ;
395+ expect ( ( liveWatchTreeDataProvider as any ) . roots . length ) . toBe ( 0 ) ;
396+ } ) ;
397+
398+ it ( 'showInMemoryInspector command does nothing when node is undefined' , async ( ) => {
399+ liveWatchTreeDataProvider . activate ( tracker ) ;
400+ const handler = getRegisteredHandler ( 'vscode-cmsis-debugger.liveWatch.showInMemoryInspector' ) ;
401+ expect ( handler ) . toBeDefined ( ) ;
402+ await handler ( undefined ) ;
403+ expect ( vscode . commands . executeCommand ) . not . toHaveBeenCalledWith ( 'memory-inspector.show-variable' , expect . anything ( ) ) ;
404+ } ) ;
405+
406+ it ( 'showInMemoryInspector shows error if extension is missing' , async ( ) => {
407+ ( vscode . extensions . getExtension as jest . Mock ) . mockReturnValue ( undefined ) ;
408+ ( vscode . window . showErrorMessage as jest . Mock ) . mockClear ( ) ;
409+ liveWatchTreeDataProvider . activate ( tracker ) ;
410+ const handler = getRegisteredHandler ( 'vscode-cmsis-debugger.liveWatch.showInMemoryInspector' ) ;
411+ const node = makeNode ( 'node' , { result : '0x1234' , variablesReference : 77 } , 1 ) ;
412+ await handler ( node ) ;
413+ expect ( vscode . window . showErrorMessage ) . toHaveBeenCalledWith ( expect . stringContaining ( 'Memory Inspector extension is not installed' ) ) ;
414+ expect ( vscode . commands . executeCommand ) . not . toHaveBeenCalledWith ( 'memory-inspector.show-variable' , expect . anything ( ) ) ;
415+ } ) ;
416+
417+ it ( 'showInMemoryInspector executes command with proper args when extension is present' , async ( ) => {
418+ ( vscode . extensions . getExtension as jest . Mock ) . mockReturnValue ( { id : 'eclipse-cdt.memory-inspector' } ) ;
419+ ( vscode . commands . executeCommand as jest . Mock ) . mockResolvedValue ( 'ok' ) ;
420+ liveWatchTreeDataProvider . activate ( tracker ) ;
421+ ( liveWatchTreeDataProvider as any ) . _activeSession = { session : { id : 'session-1' } } ;
422+ const handler = getRegisteredHandler ( 'vscode-cmsis-debugger.liveWatch.showInMemoryInspector' ) ;
423+ const node = makeNode ( 'node' , { result : '0x1234' , variablesReference : 0 } , 1 ) ;
424+ await handler ( node ) ;
425+ const lastCall = ( vscode . commands . executeCommand as jest . Mock ) . mock . calls . pop ( ) ;
426+ expect ( lastCall [ 0 ] ) . toBe ( 'memory-inspector.show-variable' ) ;
427+ const args = lastCall [ 1 ] ;
428+ expect ( args . sessionId ) . toBe ( 'session-1' ) ;
429+ expect ( args . container . name ) . toBe ( 'node' ) ;
430+ expect ( args . variable . name ) . toBe ( 'node' ) ;
431+ expect ( args . variable . memoryReference ) . toBe ( '&(node)' ) ;
432+ } ) ;
327433 } ) ;
328434
329435 describe ( 'evaluate' , ( ) => {
0 commit comments