@@ -126,6 +126,188 @@ func Test_GetPullRequest(t *testing.T) {
126126 }
127127}
128128
129+ func Test_UpdatePullRequest (t * testing.T ) {
130+ // Verify tool definition once
131+ mockClient := github .NewClient (nil )
132+ tool , _ := updatePullRequest (mockClient , translations .NullTranslationHelper )
133+
134+ assert .Equal (t , "update_pull_request" , tool .Name )
135+ assert .NotEmpty (t , tool .Description )
136+ assert .Contains (t , tool .InputSchema .Properties , "owner" )
137+ assert .Contains (t , tool .InputSchema .Properties , "repo" )
138+ assert .Contains (t , tool .InputSchema .Properties , "pullNumber" )
139+ assert .Contains (t , tool .InputSchema .Properties , "title" )
140+ assert .Contains (t , tool .InputSchema .Properties , "body" )
141+ assert .Contains (t , tool .InputSchema .Properties , "state" )
142+ assert .Contains (t , tool .InputSchema .Properties , "base" )
143+ assert .Contains (t , tool .InputSchema .Properties , "maintainer_can_modify" )
144+ assert .ElementsMatch (t , tool .InputSchema .Required , []string {"owner" , "repo" , "pullNumber" })
145+
146+ // Setup mock PR for success case
147+ mockUpdatedPR := & github.PullRequest {
148+ Number : github .Ptr (42 ),
149+ Title : github .Ptr ("Updated Test PR Title" ),
150+ State : github .Ptr ("open" ),
151+ HTMLURL : github .Ptr ("https://github.com/owner/repo/pull/42" ),
152+ Body : github .Ptr ("Updated test PR body." ),
153+ MaintainerCanModify : github .Ptr (false ),
154+ Base : & github.PullRequestBranch {
155+ Ref : github .Ptr ("develop" ),
156+ },
157+ }
158+
159+ mockClosedPR := & github.PullRequest {
160+ Number : github .Ptr (42 ),
161+ Title : github .Ptr ("Test PR" ),
162+ State : github .Ptr ("closed" ), // State updated
163+ }
164+
165+ tests := []struct {
166+ name string
167+ mockedClient * http.Client
168+ requestArgs map [string ]interface {}
169+ expectError bool
170+ expectedPR * github.PullRequest
171+ expectedErrMsg string
172+ }{
173+ {
174+ name : "successful PR update (title, body, base, maintainer_can_modify)" ,
175+ mockedClient : mock .NewMockedHTTPClient (
176+ mock .WithRequestMatchHandler (
177+ mock .PatchReposPullsByOwnerByRepoByPullNumber ,
178+ // Expect the flat string based on previous test failure output and API docs
179+ expectRequestBody (t , map [string ]interface {}{
180+ "title" : "Updated Test PR Title" ,
181+ "body" : "Updated test PR body." ,
182+ "base" : "develop" ,
183+ "maintainer_can_modify" : false ,
184+ }).andThen (
185+ mockResponse (t , http .StatusOK , mockUpdatedPR ),
186+ ),
187+ ),
188+ ),
189+ requestArgs : map [string ]interface {}{
190+ "owner" : "owner" ,
191+ "repo" : "repo" ,
192+ "pullNumber" : float64 (42 ),
193+ "title" : "Updated Test PR Title" ,
194+ "body" : "Updated test PR body." ,
195+ "base" : "develop" ,
196+ "maintainer_can_modify" : false ,
197+ },
198+ expectError : false ,
199+ expectedPR : mockUpdatedPR ,
200+ },
201+ {
202+ name : "successful PR update (state)" ,
203+ mockedClient : mock .NewMockedHTTPClient (
204+ mock .WithRequestMatchHandler (
205+ mock .PatchReposPullsByOwnerByRepoByPullNumber ,
206+ expectRequestBody (t , map [string ]interface {}{
207+ "state" : "closed" ,
208+ }).andThen (
209+ mockResponse (t , http .StatusOK , mockClosedPR ),
210+ ),
211+ ),
212+ ),
213+ requestArgs : map [string ]interface {}{
214+ "owner" : "owner" ,
215+ "repo" : "repo" ,
216+ "pullNumber" : float64 (42 ),
217+ "state" : "closed" ,
218+ },
219+ expectError : false ,
220+ expectedPR : mockClosedPR ,
221+ },
222+ {
223+ name : "no update parameters provided" ,
224+ mockedClient : mock .NewMockedHTTPClient (), // No API call expected
225+ requestArgs : map [string ]interface {}{
226+ "owner" : "owner" ,
227+ "repo" : "repo" ,
228+ "pullNumber" : float64 (42 ),
229+ // No update fields
230+ },
231+ expectError : false , // Error is returned in the result, not as Go error
232+ expectedErrMsg : "No update parameters provided" ,
233+ },
234+ {
235+ name : "PR update fails (API error)" ,
236+ mockedClient : mock .NewMockedHTTPClient (
237+ mock .WithRequestMatchHandler (
238+ mock .PatchReposPullsByOwnerByRepoByPullNumber ,
239+ http .HandlerFunc (func (w http.ResponseWriter , _ * http.Request ) {
240+ w .WriteHeader (http .StatusUnprocessableEntity )
241+ _ , _ = w .Write ([]byte (`{"message": "Validation Failed"}` ))
242+ }),
243+ ),
244+ ),
245+ requestArgs : map [string ]interface {}{
246+ "owner" : "owner" ,
247+ "repo" : "repo" ,
248+ "pullNumber" : float64 (42 ),
249+ "title" : "Invalid Title Causing Error" ,
250+ },
251+ expectError : true ,
252+ expectedErrMsg : "failed to update pull request" ,
253+ },
254+ }
255+
256+ for _ , tc := range tests {
257+ t .Run (tc .name , func (t * testing.T ) {
258+ // Setup client with mock
259+ client := github .NewClient (tc .mockedClient )
260+ _ , handler := updatePullRequest (client , translations .NullTranslationHelper )
261+
262+ // Create call request
263+ request := createMCPRequest (tc .requestArgs )
264+
265+ // Call handler
266+ result , err := handler (context .Background (), request )
267+
268+ // Verify results
269+ if tc .expectError {
270+ require .Error (t , err )
271+ assert .Contains (t , err .Error (), tc .expectedErrMsg )
272+ return
273+ }
274+
275+ require .NoError (t , err )
276+
277+ // Parse the result and get the text content
278+ textContent := getTextResult (t , result )
279+
280+ // Check for expected error message within the result text
281+ if tc .expectedErrMsg != "" {
282+ assert .Contains (t , textContent .Text , tc .expectedErrMsg )
283+ return
284+ }
285+
286+ // Unmarshal and verify the successful result
287+ var returnedPR github.PullRequest
288+ err = json .Unmarshal ([]byte (textContent .Text ), & returnedPR )
289+ require .NoError (t , err )
290+ assert .Equal (t , * tc .expectedPR .Number , * returnedPR .Number )
291+ if tc .expectedPR .Title != nil {
292+ assert .Equal (t , * tc .expectedPR .Title , * returnedPR .Title )
293+ }
294+ if tc .expectedPR .Body != nil {
295+ assert .Equal (t , * tc .expectedPR .Body , * returnedPR .Body )
296+ }
297+ if tc .expectedPR .State != nil {
298+ assert .Equal (t , * tc .expectedPR .State , * returnedPR .State )
299+ }
300+ if tc .expectedPR .Base != nil && tc .expectedPR .Base .Ref != nil {
301+ assert .NotNil (t , returnedPR .Base )
302+ assert .Equal (t , * tc .expectedPR .Base .Ref , * returnedPR .Base .Ref )
303+ }
304+ if tc .expectedPR .MaintainerCanModify != nil {
305+ assert .Equal (t , * tc .expectedPR .MaintainerCanModify , * returnedPR .MaintainerCanModify )
306+ }
307+ })
308+ }
309+ }
310+
129311func Test_ListPullRequests (t * testing.T ) {
130312 // Verify tool definition once
131313 mockClient := github .NewClient (nil )
0 commit comments