@@ -126,6 +126,188 @@ func Test_GetPullRequest(t *testing.T) {
126
126
}
127
127
}
128
128
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
+
129
311
func Test_ListPullRequests (t * testing.T ) {
130
312
// Verify tool definition once
131
313
mockClient := github .NewClient (nil )
0 commit comments