@@ -131,20 +131,18 @@ describe("loadRuleFiles", () => {
131131 { name : "file2.txt" , isFile : ( ) => true } ,
132132 ] as any )
133133
134- // Simulate file stats
135134 statMock . mockImplementation (
136- ( ) =>
135+ ( path ) =>
137136 ( {
138137 isFile : jest . fn ( ) . mockReturnValue ( true ) ,
139138 } ) as any ,
140139 )
141140
142- // Simulate file reading
143141 readFileMock . mockImplementation ( ( filePath : PathLike ) => {
144- if ( filePath . toString ( ) . includes ( " file1.txt") ) {
142+ if ( filePath . toString ( ) === "/fake/path/.roo/rules/ file1.txt") {
145143 return Promise . resolve ( "content of file1" )
146144 }
147- if ( filePath . toString ( ) . includes ( " file2.txt") ) {
145+ if ( filePath . toString ( ) === "/fake/path/.roo/rules/ file2.txt") {
148146 return Promise . resolve ( "content of file2" )
149147 }
150148 return Promise . reject ( { code : "ENOENT" } )
@@ -156,6 +154,11 @@ describe("loadRuleFiles", () => {
156154 expect ( result ) . toContain ( "content of file1" )
157155 expect ( result ) . toContain ( "# Filename: /fake/path/.roo/rules/file2.txt" )
158156 expect ( result ) . toContain ( "content of file2" )
157+
158+ expect ( statMock ) . toHaveBeenCalledWith ( "/fake/path/.roo/rules/file1.txt" )
159+ expect ( statMock ) . toHaveBeenCalledWith ( "/fake/path/.roo/rules/file2.txt" )
160+ expect ( readFileMock ) . toHaveBeenCalledWith ( "/fake/path/.roo/rules/file1.txt" , "utf-8" )
161+ expect ( readFileMock ) . toHaveBeenCalledWith ( "/fake/path/.roo/rules/file2.txt" , "utf-8" )
159162 } )
160163
161164 it ( "should fall back to .roorules when .roo/rules/ is empty" , async ( ) => {
@@ -323,20 +326,18 @@ describe("addCustomInstructions", () => {
323326 { name : "rule2.txt" , isFile : ( ) => true } ,
324327 ] as any )
325328
326- // Simulate file stats
327329 statMock . mockImplementation (
328- ( ) =>
330+ ( path ) =>
329331 ( {
330332 isFile : jest . fn ( ) . mockReturnValue ( true ) ,
331333 } ) as any ,
332334 )
333335
334- // Simulate file reading
335336 readFileMock . mockImplementation ( ( filePath : PathLike ) => {
336- if ( filePath . toString ( ) . includes ( " rule1.txt") ) {
337+ if ( filePath . toString ( ) === "/fake/path/.roo/rules-test-mode/ rule1.txt") {
337338 return Promise . resolve ( "mode specific rule 1" )
338339 }
339- if ( filePath . toString ( ) . includes ( " rule2.txt") ) {
340+ if ( filePath . toString ( ) === "/fake/path/.roo/rules-test-mode/ rule2.txt") {
340341 return Promise . resolve ( "mode specific rule 2" )
341342 }
342343 return Promise . reject ( { code : "ENOENT" } )
@@ -355,6 +356,11 @@ describe("addCustomInstructions", () => {
355356 expect ( result ) . toContain ( "mode specific rule 1" )
356357 expect ( result ) . toContain ( "# Filename: /fake/path/.roo/rules-test-mode/rule2.txt" )
357358 expect ( result ) . toContain ( "mode specific rule 2" )
359+
360+ expect ( statMock ) . toHaveBeenCalledWith ( "/fake/path/.roo/rules-test-mode/rule1.txt" )
361+ expect ( statMock ) . toHaveBeenCalledWith ( "/fake/path/.roo/rules-test-mode/rule2.txt" )
362+ expect ( readFileMock ) . toHaveBeenCalledWith ( "/fake/path/.roo/rules-test-mode/rule1.txt" , "utf-8" )
363+ expect ( readFileMock ) . toHaveBeenCalledWith ( "/fake/path/.roo/rules-test-mode/rule2.txt" , "utf-8" )
358364 } )
359365
360366 it ( "should fall back to .roorules-test-mode when .roo/rules-test-mode/ does not exist" , async ( ) => {
@@ -418,23 +424,28 @@ describe("addCustomInstructions", () => {
418424
419425 // Simulate directory has files
420426 readdirMock . mockResolvedValueOnce ( [ { name : "rule1.txt" , isFile : ( ) => true } ] as any )
427+ readFileMock . mockReset ( )
421428
422429 // Set up stat mock for checking files
423430 let statCallCount = 0
424- statMock . mockImplementation ( ( ) => {
431+ statMock . mockImplementation ( ( filePath ) => {
425432 statCallCount ++
433+ if ( filePath === "/fake/path/.roo/rules-test-mode/rule1.txt" ) {
434+ return Promise . resolve ( {
435+ isFile : jest . fn ( ) . mockReturnValue ( true ) ,
436+ isDirectory : jest . fn ( ) . mockReturnValue ( false ) ,
437+ } as any )
438+ }
426439 return Promise . resolve ( {
427- isFile : jest . fn ( ) . mockReturnValue ( true ) ,
440+ isFile : jest . fn ( ) . mockReturnValue ( false ) ,
428441 isDirectory : jest . fn ( ) . mockReturnValue ( false ) ,
429442 } as any )
430443 } )
431444
432- // Set up read file mock for both rule files and fallback files
433445 readFileMock . mockImplementation ( ( filePath : PathLike ) => {
434- if ( filePath . toString ( ) . includes ( " rule1.txt") ) {
446+ if ( filePath . toString ( ) === "/fake/path/.roo/rules-test-mode/ rule1.txt") {
435447 return Promise . resolve ( "mode specific rule content" )
436448 }
437- // Make sure we return ENOENT for all other files to test fallback behavior
438449 return Promise . reject ( { code : "ENOENT" } )
439450 } )
440451
@@ -448,6 +459,8 @@ describe("addCustomInstructions", () => {
448459 expect ( result ) . toContain ( "# Rules from /fake/path/.roo/rules-test-mode" )
449460 expect ( result ) . toContain ( "# Filename: /fake/path/.roo/rules-test-mode/rule1.txt" )
450461 expect ( result ) . toContain ( "mode specific rule content" )
462+
463+ expect ( statCallCount ) . toBeGreaterThan ( 0 )
451464 } )
452465} )
453466
@@ -501,44 +514,47 @@ describe("Rules directory reading", () => {
501514 isDirectory : jest . fn ( ) . mockReturnValue ( true ) ,
502515 } as any )
503516
504- // Simulate listing multiple files and a directory
517+ // Simulate listing files
505518 readdirMock . mockResolvedValueOnce ( [
506519 { name : "file1.txt" , isFile : ( ) => true } ,
507520 { name : "file2.txt" , isFile : ( ) => true } ,
508- { name : "subdir " , isFile : ( ) => false } , // This should be filtered out
521+ { name : "file3.txt " , isFile : ( ) => true } ,
509522 ] as any )
510523
511- // Simulate file stats
512524 statMock . mockImplementation ( ( path ) => {
513- if ( path . toString ( ) . includes ( "subdir" ) ) {
514- return Promise . resolve ( {
515- isFile : jest . fn ( ) . mockReturnValue ( false ) ,
516- } as any )
517- }
525+ expect ( [
526+ "/fake/path/.roo/rules/file1.txt" ,
527+ "/fake/path/.roo/rules/file2.txt" ,
528+ "/fake/path/.roo/rules/file3.txt" ,
529+ ] ) . toContain ( path )
530+
518531 return Promise . resolve ( {
519532 isFile : jest . fn ( ) . mockReturnValue ( true ) ,
520- } as any )
533+ } ) as any
521534 } )
522535
523- // Simulate file reading
524536 readFileMock . mockImplementation ( ( filePath : PathLike ) => {
525- if ( filePath . toString ( ) . includes ( " file1.txt") ) {
537+ if ( filePath . toString ( ) === "/fake/path/.roo/rules/ file1.txt") {
526538 return Promise . resolve ( "content of file1" )
527539 }
528- if ( filePath . toString ( ) . includes ( " file2.txt") ) {
540+ if ( filePath . toString ( ) === "/fake/path/.roo/rules/ file2.txt") {
529541 return Promise . resolve ( "content of file2" )
530542 }
543+ if ( filePath . toString ( ) === "/fake/path/.roo/rules/file3.txt" ) {
544+ return Promise . resolve ( "content of file3" )
545+ }
531546 return Promise . reject ( { code : "ENOENT" } )
532547 } )
533548
534549 const result = await loadRuleFiles ( "/fake/path" )
550+
535551 expect ( result ) . toContain ( "# Rules from /fake/path/.roo/rules" )
536552 expect ( result ) . toContain ( "# Filename: /fake/path/.roo/rules/file1.txt" )
537553 expect ( result ) . toContain ( "content of file1" )
538554 expect ( result ) . toContain ( "# Filename: /fake/path/.roo/rules/file2.txt" )
539555 expect ( result ) . toContain ( "content of file2" )
540- // Verify subdirectory was filtered out
541- expect ( result ) . not . toContain ( "subdir " )
556+ expect ( result ) . toContain ( "# Filename: /fake/path/.roo/rules/file3.txt" )
557+ expect ( result ) . toContain ( "content of file3 " )
542558 } )
543559
544560 it ( "should handle empty file list gracefully" , async ( ) => {
@@ -550,7 +566,6 @@ describe("Rules directory reading", () => {
550566 // Simulate empty directory
551567 readdirMock . mockResolvedValueOnce ( [ ] )
552568
553- // For loadRuleFiles to return something for testing
554569 readFileMock . mockResolvedValueOnce ( "fallback content" )
555570
556571 const result = await loadRuleFiles ( "/fake/path" )
0 commit comments