1
+ /* eslint-disable max-lines-per-function */
2
+ /* lint is not useful for test classes */
1
3
import { jest } from "@jest/globals" ;
2
4
import { execSync } from "node:child_process" ;
3
5
import fs from "node:fs" ;
@@ -14,8 +16,11 @@ import {
14
16
} from "../test/testDir.js" ;
15
17
import { getIndexSqlitePath } from "../util/paths.js" ;
16
18
19
+ import { ConfigResult } from "@continuedev/config-yaml" ;
20
+ import CodebaseContextProvider from "../context/providers/CodebaseContextProvider.js" ;
21
+ import { ContinueConfig } from "../index.js" ;
17
22
import { localPathToUri } from "../util/pathToUri.js" ;
18
- import { CodebaseIndexer , PauseToken } from "./CodebaseIndexer.js" ;
23
+ import { CodebaseIndexer } from "./CodebaseIndexer.js" ;
19
24
import { getComputeDeleteAddRemove } from "./refreshIndex.js" ;
20
25
import { TestCodebaseIndex } from "./TestCodebaseIndex.js" ;
21
26
import { CodebaseIndex } from "./types.js" ;
@@ -57,6 +62,17 @@ class TestCodebaseIndexer extends CodebaseIndexer {
57
62
protected async getIndexesToBuild ( ) : Promise < CodebaseIndex [ ] > {
58
63
return [ new TestCodebaseIndex ( ) ] ;
59
64
}
65
+
66
+ // Add public methods to test private methods
67
+ public testHasCodebaseContextProvider ( ) {
68
+ return ( this as any ) . hasCodebaseContextProvider ( ) ;
69
+ }
70
+
71
+ public async testHandleConfigUpdate (
72
+ configResult : ConfigResult < ContinueConfig > ,
73
+ ) {
74
+ return ( this as any ) . handleConfigUpdate ( { config : configResult . config } ) ;
75
+ }
60
76
}
61
77
62
78
// Create a mock messenger type that doesn't require actual protocol imports
@@ -71,8 +87,6 @@ type MockMessengerType = {
71
87
// These are more like integration tests, whereas we should separately test
72
88
// the individual CodebaseIndex classes
73
89
describe ( "CodebaseIndexer" , ( ) => {
74
- const pauseToken = new PauseToken ( false ) ;
75
-
76
90
// Replace mockProgressReporter with mockMessenger
77
91
const mockMessenger : MockMessengerType = {
78
92
send : jest . fn ( ) ,
@@ -82,13 +96,8 @@ describe("CodebaseIndexer", () => {
82
96
onError : jest . fn ( ) ,
83
97
} ;
84
98
85
- const codebaseIndexer = new TestCodebaseIndexer (
86
- testConfigHandler ,
87
- testIde ,
88
- mockMessenger as any ,
89
- false ,
90
- ) ;
91
- const testIndex = new TestCodebaseIndex ( ) ;
99
+ let codebaseIndexer : TestCodebaseIndexer ;
100
+ let testIndex : TestCodebaseIndex ;
92
101
93
102
beforeAll ( async ( ) => {
94
103
tearDownTestDir ( ) ;
@@ -99,6 +108,15 @@ describe("CodebaseIndexer", () => {
99
108
cwd : TEST_DIR_PATH ,
100
109
} ) ;
101
110
execSync ( 'git config user.name "Test"' , { cwd : TEST_DIR_PATH } ) ;
111
+
112
+ codebaseIndexer = new TestCodebaseIndexer (
113
+ testConfigHandler ,
114
+ testIde ,
115
+ mockMessenger as any ,
116
+ false ,
117
+ ) ;
118
+ await codebaseIndexer . initPromise ;
119
+ testIndex = new TestCodebaseIndex ( ) ;
102
120
} ) ;
103
121
104
122
afterAll ( async ( ) => {
@@ -161,6 +179,7 @@ describe("CodebaseIndexer", () => {
161
179
}
162
180
163
181
test ( "should index test folder without problem" , async ( ) => {
182
+ walkDirCache . invalidate ( ) ;
164
183
addToTestDir ( [
165
184
[ "test.ts" , TEST_TS ] ,
166
185
[ "py/main.py" , TEST_PY ] ,
@@ -403,4 +422,270 @@ describe("CodebaseIndexer", () => {
403
422
expect ( codebaseIndexer . currentIndexingState ) . toEqual ( testState ) ;
404
423
} ) ;
405
424
} ) ;
425
+
426
+ // New describe block for testing handleConfigUpdate functionality
427
+ describe ( "handleConfigUpdate functionality" , ( ) => {
428
+ let testIndexer : TestCodebaseIndexer ;
429
+ let mockRefreshCodebaseIndex : jest . MockedFunction < any > ;
430
+ let mockGetWorkspaceDirs : jest . MockedFunction < any > ;
431
+
432
+ beforeEach ( ( ) => {
433
+ testIndexer = new TestCodebaseIndexer (
434
+ testConfigHandler ,
435
+ testIde ,
436
+ mockMessenger as any ,
437
+ false ,
438
+ ) ;
439
+
440
+ // Mock the refreshCodebaseIndex method to avoid actual indexing
441
+ mockRefreshCodebaseIndex = jest
442
+ . spyOn ( testIndexer , "refreshCodebaseIndex" )
443
+ . mockImplementation ( async ( ) => { } ) ;
444
+
445
+ // Mock getWorkspaceDirs to return test directories
446
+ mockGetWorkspaceDirs = jest
447
+ . spyOn ( testIde , "getWorkspaceDirs" )
448
+ . mockResolvedValue ( [ "/test/workspace" ] ) ;
449
+ } ) ;
450
+
451
+ afterEach ( ( ) => {
452
+ jest . clearAllMocks ( ) ;
453
+ } ) ;
454
+
455
+ describe ( "hasCodebaseContextProvider" , ( ) => {
456
+ test ( "should return true when codebase context provider is present" , ( ) => {
457
+ // Set up config with codebase context provider
458
+ ( testIndexer as any ) . config = {
459
+ contextProviders : [
460
+ {
461
+ description : {
462
+ title : CodebaseContextProvider . description . title ,
463
+ } ,
464
+ } ,
465
+ ] ,
466
+ } ;
467
+
468
+ const result = testIndexer . testHasCodebaseContextProvider ( ) ;
469
+ expect ( result ) . toBe ( true ) ;
470
+ } ) ;
471
+
472
+ test ( "should return false when no context providers are configured" , ( ) => {
473
+ ( testIndexer as any ) . config = {
474
+ contextProviders : undefined ,
475
+ } ;
476
+
477
+ const result = testIndexer . testHasCodebaseContextProvider ( ) ;
478
+ expect ( result ) . toBe ( false ) ;
479
+ } ) ;
480
+
481
+ test ( "should return false when context providers exist but no codebase provider" , ( ) => {
482
+ ( testIndexer as any ) . config = {
483
+ contextProviders : [
484
+ {
485
+ description : {
486
+ title : "SomeOtherProvider" ,
487
+ } ,
488
+ } ,
489
+ ] ,
490
+ } ;
491
+
492
+ const result = testIndexer . testHasCodebaseContextProvider ( ) ;
493
+ expect ( result ) . toBe ( false ) ;
494
+ } ) ;
495
+
496
+ test ( "should return false when context providers is empty array" , ( ) => {
497
+ ( testIndexer as any ) . config = {
498
+ contextProviders : [ ] ,
499
+ } ;
500
+
501
+ const result = testIndexer . testHasCodebaseContextProvider ( ) ;
502
+ expect ( result ) . toBe ( false ) ;
503
+ } ) ;
504
+ } ) ;
505
+
506
+ describe ( "handleConfigUpdate" , ( ) => {
507
+ test ( "should return early when newConfig is null" , async ( ) => {
508
+ const configResult : ConfigResult < ContinueConfig > = {
509
+ config : null as any ,
510
+ errors : [ ] ,
511
+ configLoadInterrupted : false ,
512
+ } ;
513
+
514
+ await testIndexer . testHandleConfigUpdate ( configResult ) ;
515
+
516
+ // These get called once on init, so we want them to not get called again
517
+ expect ( mockRefreshCodebaseIndex ) . toHaveBeenCalledTimes ( 1 ) ;
518
+ expect ( mockGetWorkspaceDirs ) . toHaveBeenCalledTimes ( 1 ) ;
519
+ } ) ;
520
+
521
+ test ( "should return early when newConfig is undefined" , async ( ) => {
522
+ const configResult : ConfigResult < ContinueConfig > = {
523
+ config : undefined as any ,
524
+ errors : [ ] ,
525
+ configLoadInterrupted : false ,
526
+ } ;
527
+
528
+ await testIndexer . testHandleConfigUpdate ( configResult ) ;
529
+
530
+ // These get called once on init, so we want them to not get called again
531
+ expect ( mockRefreshCodebaseIndex ) . toHaveBeenCalledTimes ( 1 ) ;
532
+ expect ( mockGetWorkspaceDirs ) . toHaveBeenCalledTimes ( 1 ) ;
533
+ } ) ;
534
+
535
+ test ( "should return early when no codebase context provider is present" , async ( ) => {
536
+ const configResult : ConfigResult < ContinueConfig > = {
537
+ config : {
538
+ contextProviders : [
539
+ {
540
+ description : {
541
+ title : "SomeOtherProvider" ,
542
+ } ,
543
+ } ,
544
+ ] ,
545
+ selectedModelByRole : {
546
+ embed : {
547
+ model : "test-model" ,
548
+ provider : "test-provider" ,
549
+ } ,
550
+ } ,
551
+ } as unknown as ContinueConfig ,
552
+ errors : [ ] ,
553
+ configLoadInterrupted : false ,
554
+ } ;
555
+
556
+ await testIndexer . testHandleConfigUpdate ( configResult ) ;
557
+
558
+ // These get called once on init, so we want them to not get called again
559
+ expect ( mockRefreshCodebaseIndex ) . toHaveBeenCalledTimes ( 1 ) ;
560
+ expect ( mockGetWorkspaceDirs ) . toHaveBeenCalledTimes ( 1 ) ;
561
+ } ) ;
562
+
563
+ test ( "should return early when no embed model is configured" , async ( ) => {
564
+ const configResult : ConfigResult < ContinueConfig > = {
565
+ config : {
566
+ contextProviders : [
567
+ {
568
+ description : {
569
+ title : CodebaseContextProvider . description . title ,
570
+ } ,
571
+ } ,
572
+ ] ,
573
+ selectedModelByRole : {
574
+ embed : undefined ,
575
+ } ,
576
+ } as unknown as ContinueConfig ,
577
+ errors : [ ] ,
578
+ configLoadInterrupted : false ,
579
+ } ;
580
+
581
+ await testIndexer . testHandleConfigUpdate ( configResult ) ;
582
+
583
+ // These get called once on init, so we want them to not get called again
584
+ expect ( mockRefreshCodebaseIndex ) . toHaveBeenCalledTimes ( 1 ) ;
585
+ expect ( mockGetWorkspaceDirs ) . toHaveBeenCalledTimes ( 1 ) ;
586
+ } ) ;
587
+
588
+ test ( "should call refreshCodebaseIndex when all conditions are met" , async ( ) => {
589
+ const configResult : ConfigResult < ContinueConfig > = {
590
+ config : {
591
+ contextProviders : [
592
+ {
593
+ description : {
594
+ title : CodebaseContextProvider . description . title ,
595
+ } ,
596
+ } ,
597
+ ] ,
598
+ selectedModelByRole : {
599
+ embed : {
600
+ model : "test-model" ,
601
+ provider : "test-provider" ,
602
+ } ,
603
+ } ,
604
+ } as unknown as ContinueConfig ,
605
+ errors : [ ] ,
606
+ configLoadInterrupted : false ,
607
+ } ;
608
+
609
+ await testIndexer . testHandleConfigUpdate ( configResult ) ;
610
+
611
+ // These get called once on init, and we want them to get called again
612
+ expect ( mockGetWorkspaceDirs ) . toHaveBeenCalledTimes ( 2 ) ;
613
+ expect ( mockRefreshCodebaseIndex ) . toHaveBeenCalledTimes ( 2 ) ;
614
+ expect ( mockRefreshCodebaseIndex ) . toHaveBeenCalledWith ( [
615
+ "/test/workspace" ,
616
+ ] ) ;
617
+ } ) ;
618
+
619
+ test ( "should set config property before checking conditions" , async ( ) => {
620
+ const testConfig = {
621
+ contextProviders : [
622
+ {
623
+ description : {
624
+ title : CodebaseContextProvider . description . title ,
625
+ } ,
626
+ } ,
627
+ ] ,
628
+ selectedModelByRole : {
629
+ embed : {
630
+ model : "test-model" ,
631
+ provider : "test-provider" ,
632
+ } ,
633
+ } ,
634
+ } as unknown as ContinueConfig ;
635
+
636
+ const configResult : ConfigResult < ContinueConfig > = {
637
+ config : testConfig ,
638
+ errors : [ ] ,
639
+ configLoadInterrupted : false ,
640
+ } ;
641
+
642
+ await testIndexer . testHandleConfigUpdate ( configResult ) ;
643
+
644
+ // Verify that the config was set
645
+ expect ( ( testIndexer as any ) . config ) . toBe ( testConfig ) ;
646
+ // These get called once on init, and we want them to get called again
647
+ expect ( mockRefreshCodebaseIndex ) . toHaveBeenCalledTimes ( 2 ) ;
648
+ } ) ;
649
+
650
+ test ( "should handle multiple context providers correctly" , async ( ) => {
651
+ const configResult : ConfigResult < ContinueConfig > = {
652
+ config : {
653
+ contextProviders : [
654
+ {
655
+ description : {
656
+ title : "SomeOtherProvider" ,
657
+ } ,
658
+ } ,
659
+ {
660
+ description : {
661
+ title : CodebaseContextProvider . description . title ,
662
+ } ,
663
+ } ,
664
+ {
665
+ description : {
666
+ title : "AnotherProvider" ,
667
+ } ,
668
+ } ,
669
+ ] ,
670
+ selectedModelByRole : {
671
+ embed : {
672
+ model : "test-model" ,
673
+ provider : "test-provider" ,
674
+ } ,
675
+ } ,
676
+ } as unknown as ContinueConfig ,
677
+ errors : [ ] ,
678
+ configLoadInterrupted : false ,
679
+ } ;
680
+
681
+ await testIndexer . testHandleConfigUpdate ( configResult ) ;
682
+
683
+ // These get called once on init, and we want them to get called again
684
+ expect ( mockRefreshCodebaseIndex ) . toHaveBeenCalledTimes ( 2 ) ;
685
+ expect ( mockRefreshCodebaseIndex ) . toHaveBeenCalledWith ( [
686
+ "/test/workspace" ,
687
+ ] ) ;
688
+ } ) ;
689
+ } ) ;
690
+ } ) ;
406
691
} ) ;
0 commit comments