@@ -565,6 +565,162 @@ func Test_MergePullRequest(t *testing.T) {
565565 }
566566}
567567
568+ func Test_SearchPullRequests (t * testing.T ) {
569+ mockClient := github .NewClient (nil )
570+ tool , _ := SearchPullRequests (stubGetClientFn (mockClient ), translations .NullTranslationHelper )
571+ require .NoError (t , toolsnaps .Test (tool .Name , tool ))
572+
573+ assert .Equal (t , "search_pull_requests" , tool .Name )
574+ assert .NotEmpty (t , tool .Description )
575+ assert .Contains (t , tool .InputSchema .Properties , "q" )
576+ assert .Contains (t , tool .InputSchema .Properties , "sort" )
577+ assert .Contains (t , tool .InputSchema .Properties , "order" )
578+ assert .Contains (t , tool .InputSchema .Properties , "perPage" )
579+ assert .Contains (t , tool .InputSchema .Properties , "page" )
580+ assert .ElementsMatch (t , tool .InputSchema .Required , []string {"q" })
581+
582+ mockSearchResult := & github.IssuesSearchResult {
583+ Total : github .Ptr (2 ),
584+ IncompleteResults : github .Ptr (false ),
585+ Issues : []* github.Issue {
586+ {
587+ Number : github .Ptr (42 ),
588+ Title : github .Ptr ("Test PR 1" ),
589+ Body : github .Ptr ("Updated tests." ),
590+ State : github .Ptr ("open" ),
591+ HTMLURL : github .Ptr ("https://github.com/owner/repo/pull/1" ),
592+ Comments : github .Ptr (5 ),
593+ User : & github.User {
594+ Login : github .Ptr ("user1" ),
595+ },
596+ },
597+ {
598+ Number : github .Ptr (43 ),
599+ Title : github .Ptr ("Test PR 2" ),
600+ Body : github .Ptr ("Updated build scripts." ),
601+ State : github .Ptr ("open" ),
602+ HTMLURL : github .Ptr ("https://github.com/owner/repo/pull/2" ),
603+ Comments : github .Ptr (3 ),
604+ User : & github.User {
605+ Login : github .Ptr ("user2" ),
606+ },
607+ },
608+ },
609+ }
610+
611+ tests := []struct {
612+ name string
613+ mockedClient * http.Client
614+ requestArgs map [string ]interface {}
615+ expectError bool
616+ expectedResult * github.IssuesSearchResult
617+ expectedErrMsg string
618+ }{
619+ {
620+ name : "successful pull request search with all parameters" ,
621+ mockedClient : mock .NewMockedHTTPClient (
622+ mock .WithRequestMatchHandler (
623+ mock .GetSearchIssues ,
624+ expectQueryParams (
625+ t ,
626+ map [string ]string {
627+ "q" : "repo:owner/repo is:pr is:open" ,
628+ "sort" : "created" ,
629+ "order" : "desc" ,
630+ "page" : "1" ,
631+ "per_page" : "30" ,
632+ },
633+ ).andThen (
634+ mockResponse (t , http .StatusOK , mockSearchResult ),
635+ ),
636+ ),
637+ ),
638+ requestArgs : map [string ]interface {}{
639+ "q" : "repo:owner/repo is:pr is:open" ,
640+ "sort" : "created" ,
641+ "order" : "desc" ,
642+ "page" : float64 (1 ),
643+ "perPage" : float64 (30 ),
644+ },
645+ expectError : false ,
646+ expectedResult : mockSearchResult ,
647+ },
648+ {
649+ name : "pull request search with minimal parameters" ,
650+ mockedClient : mock .NewMockedHTTPClient (
651+ mock .WithRequestMatch (
652+ mock .GetSearchIssues ,
653+ mockSearchResult ,
654+ ),
655+ ),
656+ requestArgs : map [string ]interface {}{
657+ "q" : "repo:owner/repo is:pr is:open" ,
658+ },
659+ expectError : false ,
660+ expectedResult : mockSearchResult ,
661+ },
662+ {
663+ name : "search pull requests fails" ,
664+ mockedClient : mock .NewMockedHTTPClient (
665+ mock .WithRequestMatchHandler (
666+ mock .GetSearchIssues ,
667+ http .HandlerFunc (func (w http.ResponseWriter , _ * http.Request ) {
668+ w .WriteHeader (http .StatusBadRequest )
669+ _ , _ = w .Write ([]byte (`{"message": "Validation Failed"}` ))
670+ }),
671+ ),
672+ ),
673+ requestArgs : map [string ]interface {}{
674+ "q" : "invalid:query" ,
675+ },
676+ expectError : true ,
677+ expectedErrMsg : "failed to search issues" ,
678+ },
679+ }
680+
681+ for _ , tc := range tests {
682+ t .Run (tc .name , func (t * testing.T ) {
683+ // Setup client with mock
684+ client := github .NewClient (tc .mockedClient )
685+ _ , handler := SearchIssues (stubGetClientFn (client ), translations .NullTranslationHelper )
686+
687+ // Create call request
688+ request := createMCPRequest (tc .requestArgs )
689+
690+ // Call handler
691+ result , err := handler (context .Background (), request )
692+
693+ // Verify results
694+ if tc .expectError {
695+ require .Error (t , err )
696+ assert .Contains (t , err .Error (), tc .expectedErrMsg )
697+ return
698+ }
699+
700+ require .NoError (t , err )
701+
702+ // Parse the result and get the text content if no error
703+ textContent := getTextResult (t , result )
704+
705+ // Unmarshal and verify the result
706+ var returnedResult github.IssuesSearchResult
707+ err = json .Unmarshal ([]byte (textContent .Text ), & returnedResult )
708+ require .NoError (t , err )
709+ assert .Equal (t , * tc .expectedResult .Total , * returnedResult .Total )
710+ assert .Equal (t , * tc .expectedResult .IncompleteResults , * returnedResult .IncompleteResults )
711+ assert .Len (t , returnedResult .Issues , len (tc .expectedResult .Issues ))
712+ for i , issue := range returnedResult .Issues {
713+ assert .Equal (t , * tc .expectedResult .Issues [i ].Number , * issue .Number )
714+ assert .Equal (t , * tc .expectedResult .Issues [i ].Title , * issue .Title )
715+ assert .Equal (t , * tc .expectedResult .Issues [i ].State , * issue .State )
716+ assert .Equal (t , * tc .expectedResult .Issues [i ].HTMLURL , * issue .HTMLURL )
717+ assert .Equal (t , * tc .expectedResult .Issues [i ].User .Login , * issue .User .Login )
718+ }
719+ })
720+ }
721+
722+ }
723+
568724func Test_GetPullRequestFiles (t * testing.T ) {
569725 // Verify tool definition once
570726 mockClient := github .NewClient (nil )
0 commit comments