@@ -484,7 +484,7 @@ func Test_GetDiscussion(t *testing.T) {
484484 assert .ElementsMatch (t , toolDef .InputSchema .Required , []string {"owner" , "repo" , "discussionNumber" })
485485
486486 // Use exact string query that matches implementation output
487- qGetDiscussion := "query($discussionNumber:Int!$owner:String!$repo:String!){repository(owner: $owner, name: $repo){discussion(number: $discussionNumber){number,body,createdAt,url,category{name}}}}"
487+ qGetDiscussion := "query($discussionNumber:Int!$owner:String!$repo:String!){repository(owner: $owner, name: $repo){discussion(number: $discussionNumber){number,title, body,createdAt,url,category{name}}}}"
488488
489489 vars := map [string ]interface {}{
490490 "owner" : "owner" ,
@@ -503,6 +503,7 @@ func Test_GetDiscussion(t *testing.T) {
503503 response : githubv4mock .DataResponse (map [string ]any {
504504 "repository" : map [string ]any {"discussion" : map [string ]any {
505505 "number" : 1 ,
506+ "title" : "Test Discussion Title" ,
506507 "body" : "This is a test discussion" ,
507508 "url" : "https://github.com/owner/repo/discussions/1" ,
508509 "createdAt" : "2025-04-25T12:00:00Z" ,
@@ -513,6 +514,7 @@ func Test_GetDiscussion(t *testing.T) {
513514 expected : & github.Discussion {
514515 HTMLURL : github .Ptr ("https://github.com/owner/repo/discussions/1" ),
515516 Number : github .Ptr (1 ),
517+ Title : github .Ptr ("Test Discussion Title" ),
516518 Body : github .Ptr ("This is a test discussion" ),
517519 CreatedAt : & github.Timestamp {Time : time .Date (2025 , 4 , 25 , 12 , 0 , 0 , 0 , time .UTC )},
518520 DiscussionCategory : & github.DiscussionCategory {
@@ -549,6 +551,7 @@ func Test_GetDiscussion(t *testing.T) {
549551 require .NoError (t , json .Unmarshal ([]byte (text ), & out ))
550552 assert .Equal (t , * tc .expected .HTMLURL , * out .HTMLURL )
551553 assert .Equal (t , * tc .expected .Number , * out .Number )
554+ assert .Equal (t , * tc .expected .Title , * out .Title )
552555 assert .Equal (t , * tc .expected .Body , * out .Body )
553556 // Check category label
554557 assert .Equal (t , * tc .expected .DiscussionCategory .Name , * out .DiscussionCategory .Name )
@@ -635,17 +638,33 @@ func Test_GetDiscussionComments(t *testing.T) {
635638}
636639
637640func Test_ListDiscussionCategories (t * testing.T ) {
641+ mockClient := githubv4 .NewClient (nil )
642+ toolDef , _ := ListDiscussionCategories (stubGetGQLClientFn (mockClient ), translations .NullTranslationHelper )
643+ assert .Equal (t , "list_discussion_categories" , toolDef .Name )
644+ assert .NotEmpty (t , toolDef .Description )
645+ assert .Contains (t , toolDef .Description , "or organisation" )
646+ assert .Contains (t , toolDef .InputSchema .Properties , "owner" )
647+ assert .Contains (t , toolDef .InputSchema .Properties , "repo" )
648+ assert .ElementsMatch (t , toolDef .InputSchema .Required , []string {"owner" })
649+
638650 // Use exact string query that matches implementation output
639651 qListCategories := "query($first:Int!$owner:String!$repo:String!){repository(owner: $owner, name: $repo){discussionCategories(first: $first){nodes{id,name},pageInfo{hasNextPage,hasPreviousPage,startCursor,endCursor},totalCount}}}"
640652
641- // Variables matching what GraphQL receives after JSON marshaling/unmarshaling
642- vars := map [string ]interface {}{
653+ // Variables for repository-level categories
654+ varsRepo := map [string ]interface {}{
643655 "owner" : "owner" ,
644656 "repo" : "repo" ,
645657 "first" : float64 (25 ),
646658 }
647659
648- mockResp := githubv4mock .DataResponse (map [string ]any {
660+ // Variables for organization-level categories (using .github repo)
661+ varsOrg := map [string ]interface {}{
662+ "owner" : "owner" ,
663+ "repo" : ".github" ,
664+ "first" : float64 (25 ),
665+ }
666+
667+ mockRespRepo := githubv4mock .DataResponse (map [string ]any {
649668 "repository" : map [string ]any {
650669 "discussionCategories" : map [string ]any {
651670 "nodes" : []map [string ]any {
@@ -662,37 +681,98 @@ func Test_ListDiscussionCategories(t *testing.T) {
662681 },
663682 },
664683 })
665- matcher := githubv4mock .NewQueryMatcher (qListCategories , vars , mockResp )
666- httpClient := githubv4mock .NewMockedHTTPClient (matcher )
667- gqlClient := githubv4 .NewClient (httpClient )
668684
669- tool , handler := ListDiscussionCategories (stubGetGQLClientFn (gqlClient ), translations .NullTranslationHelper )
670- assert .Equal (t , "list_discussion_categories" , tool .Name )
671- assert .NotEmpty (t , tool .Description )
672- assert .Contains (t , tool .InputSchema .Properties , "owner" )
673- assert .Contains (t , tool .InputSchema .Properties , "repo" )
674- assert .ElementsMatch (t , tool .InputSchema .Required , []string {"owner" , "repo" })
685+ mockRespOrg := githubv4mock .DataResponse (map [string ]any {
686+ "repository" : map [string ]any {
687+ "discussionCategories" : map [string ]any {
688+ "nodes" : []map [string ]any {
689+ {"id" : "789" , "name" : "Announcements" },
690+ {"id" : "101" , "name" : "General" },
691+ {"id" : "112" , "name" : "Ideas" },
692+ },
693+ "pageInfo" : map [string ]any {
694+ "hasNextPage" : false ,
695+ "hasPreviousPage" : false ,
696+ "startCursor" : "" ,
697+ "endCursor" : "" ,
698+ },
699+ "totalCount" : 3 ,
700+ },
701+ },
702+ })
675703
676- request := createMCPRequest (map [string ]interface {}{"owner" : "owner" , "repo" : "repo" })
677- result , err := handler (context .Background (), request )
678- require .NoError (t , err )
704+ tests := []struct {
705+ name string
706+ reqParams map [string ]interface {}
707+ vars map [string ]interface {}
708+ mockResponse githubv4mock.GQLResponse
709+ expectError bool
710+ expectedCount int
711+ expectedCategories []map [string ]string
712+ }{
713+ {
714+ name : "list repository-level discussion categories" ,
715+ reqParams : map [string ]interface {}{
716+ "owner" : "owner" ,
717+ "repo" : "repo" ,
718+ },
719+ vars : varsRepo ,
720+ mockResponse : mockRespRepo ,
721+ expectError : false ,
722+ expectedCount : 2 ,
723+ expectedCategories : []map [string ]string {
724+ {"id" : "123" , "name" : "CategoryOne" },
725+ {"id" : "456" , "name" : "CategoryTwo" },
726+ },
727+ },
728+ {
729+ name : "list org-level discussion categories (no repo provided)" ,
730+ reqParams : map [string ]interface {}{
731+ "owner" : "owner" ,
732+ // repo is not provided, it will default to ".github"
733+ },
734+ vars : varsOrg ,
735+ mockResponse : mockRespOrg ,
736+ expectError : false ,
737+ expectedCount : 3 ,
738+ expectedCategories : []map [string ]string {
739+ {"id" : "789" , "name" : "Announcements" },
740+ {"id" : "101" , "name" : "General" },
741+ {"id" : "112" , "name" : "Ideas" },
742+ },
743+ },
744+ }
679745
680- text := getTextResult (t , result ).Text
746+ for _ , tc := range tests {
747+ t .Run (tc .name , func (t * testing.T ) {
748+ matcher := githubv4mock .NewQueryMatcher (qListCategories , tc .vars , tc .mockResponse )
749+ httpClient := githubv4mock .NewMockedHTTPClient (matcher )
750+ gqlClient := githubv4 .NewClient (httpClient )
681751
682- var response struct {
683- Categories []map [string ]string `json:"categories"`
684- PageInfo struct {
685- HasNextPage bool `json:"hasNextPage"`
686- HasPreviousPage bool `json:"hasPreviousPage"`
687- StartCursor string `json:"startCursor"`
688- EndCursor string `json:"endCursor"`
689- } `json:"pageInfo"`
690- TotalCount int `json:"totalCount"`
752+ _ , handler := ListDiscussionCategories (stubGetGQLClientFn (gqlClient ), translations .NullTranslationHelper )
753+
754+ req := createMCPRequest (tc .reqParams )
755+ res , err := handler (context .Background (), req )
756+ text := getTextResult (t , res ).Text
757+
758+ if tc .expectError {
759+ require .True (t , res .IsError )
760+ return
761+ }
762+ require .NoError (t , err )
763+
764+ var response struct {
765+ Categories []map [string ]string `json:"categories"`
766+ PageInfo struct {
767+ HasNextPage bool `json:"hasNextPage"`
768+ HasPreviousPage bool `json:"hasPreviousPage"`
769+ StartCursor string `json:"startCursor"`
770+ EndCursor string `json:"endCursor"`
771+ } `json:"pageInfo"`
772+ TotalCount int `json:"totalCount"`
773+ }
774+ require .NoError (t , json .Unmarshal ([]byte (text ), & response ))
775+ assert .Equal (t , tc .expectedCategories , response .Categories )
776+ })
691777 }
692- require .NoError (t , json .Unmarshal ([]byte (text ), & response ))
693- assert .Len (t , response .Categories , 2 )
694- assert .Equal (t , "123" , response .Categories [0 ]["id" ])
695- assert .Equal (t , "CategoryOne" , response .Categories [0 ]["name" ])
696- assert .Equal (t , "456" , response .Categories [1 ]["id" ])
697- assert .Equal (t , "CategoryTwo" , response .Categories [1 ]["name" ])
698778}
0 commit comments