@@ -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,title,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" ,
@@ -638,17 +638,33 @@ func Test_GetDiscussionComments(t *testing.T) {
638638}
639639
640640func 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+
641650 // Use exact string query that matches implementation output
642651 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}}}"
643652
644- // Variables matching what GraphQL receives after JSON marshaling/unmarshaling
645- vars := map [string ]interface {}{
653+ // Variables for repository-level categories
654+ varsRepo := map [string ]interface {}{
646655 "owner" : "owner" ,
647656 "repo" : "repo" ,
648657 "first" : float64 (25 ),
649658 }
650659
651- 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 {
652668 "repository" : map [string ]any {
653669 "discussionCategories" : map [string ]any {
654670 "nodes" : []map [string ]any {
@@ -665,37 +681,104 @@ func Test_ListDiscussionCategories(t *testing.T) {
665681 },
666682 },
667683 })
668- matcher := githubv4mock .NewQueryMatcher (qListCategories , vars , mockResp )
669- httpClient := githubv4mock .NewMockedHTTPClient (matcher )
670- gqlClient := githubv4 .NewClient (httpClient )
671684
672- tool , handler := ListDiscussionCategories (stubGetGQLClientFn (gqlClient ), translations .NullTranslationHelper )
673- assert .Equal (t , "list_discussion_categories" , tool .Name )
674- assert .NotEmpty (t , tool .Description )
675- assert .Contains (t , tool .InputSchema .Properties , "owner" )
676- assert .Contains (t , tool .InputSchema .Properties , "repo" )
677- 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+ })
678703
679- request := createMCPRequest (map [string ]interface {}{"owner" : "owner" , "repo" : "repo" })
680- result , err := handler (context .Background (), request )
681- 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+ }{
712+ {
713+ name : "list repository-level discussion categories" ,
714+ reqParams : map [string ]interface {}{
715+ "owner" : "owner" ,
716+ "repo" : "repo" ,
717+ },
718+ vars : varsRepo ,
719+ mockResponse : mockRespRepo ,
720+ expectError : false ,
721+ expectedCount : 2 ,
722+ },
723+ {
724+ name : "list org-level discussion categories (no repo provided)" ,
725+ reqParams : map [string ]interface {}{
726+ "owner" : "owner" ,
727+ // repo is not provided, it will default to ".github"
728+ },
729+ vars : varsOrg ,
730+ mockResponse : mockRespOrg ,
731+ expectError : false ,
732+ expectedCount : 3 ,
733+ },
734+ }
735+
736+ for _ , tc := range tests {
737+ t .Run (tc .name , func (t * testing.T ) {
738+ matcher := githubv4mock .NewQueryMatcher (qListCategories , tc .vars , tc .mockResponse )
739+ httpClient := githubv4mock .NewMockedHTTPClient (matcher )
740+ gqlClient := githubv4 .NewClient (httpClient )
682741
683- text := getTextResult ( t , result ). Text
742+ _ , handler := ListDiscussionCategories ( stubGetGQLClientFn ( gqlClient ), translations . NullTranslationHelper )
684743
685- var response struct {
686- Categories []map [string ]string `json:"categories"`
687- PageInfo struct {
688- HasNextPage bool `json:"hasNextPage"`
689- HasPreviousPage bool `json:"hasPreviousPage"`
690- StartCursor string `json:"startCursor"`
691- EndCursor string `json:"endCursor"`
692- } `json:"pageInfo"`
693- TotalCount int `json:"totalCount"`
744+ req := createMCPRequest (tc .reqParams )
745+ res , err := handler (context .Background (), req )
746+ text := getTextResult (t , res ).Text
747+
748+ if tc .expectError {
749+ require .True (t , res .IsError )
750+ return
751+ }
752+ require .NoError (t , err )
753+
754+ var response struct {
755+ Categories []map [string ]string `json:"categories"`
756+ PageInfo struct {
757+ HasNextPage bool `json:"hasNextPage"`
758+ HasPreviousPage bool `json:"hasPreviousPage"`
759+ StartCursor string `json:"startCursor"`
760+ EndCursor string `json:"endCursor"`
761+ } `json:"pageInfo"`
762+ TotalCount int `json:"totalCount"`
763+ }
764+ require .NoError (t , json .Unmarshal ([]byte (text ), & response ))
765+ assert .Len (t , response .Categories , tc .expectedCount )
766+
767+ // Verify specific content based on test case
768+ switch tc .name {
769+ case "list repository-level discussion categories" :
770+ assert .Equal (t , "123" , response .Categories [0 ]["id" ])
771+ assert .Equal (t , "CategoryOne" , response .Categories [0 ]["name" ])
772+ assert .Equal (t , "456" , response .Categories [1 ]["id" ])
773+ assert .Equal (t , "CategoryTwo" , response .Categories [1 ]["name" ])
774+ case "list org-level discussion categories (no repo provided)" :
775+ assert .Equal (t , "789" , response .Categories [0 ]["id" ])
776+ assert .Equal (t , "Announcements" , response .Categories [0 ]["name" ])
777+ assert .Equal (t , "101" , response .Categories [1 ]["id" ])
778+ assert .Equal (t , "General" , response .Categories [1 ]["name" ])
779+ assert .Equal (t , "112" , response .Categories [2 ]["id" ])
780+ assert .Equal (t , "Ideas" , response .Categories [2 ]["name" ])
781+ }
782+ })
694783 }
695- require .NoError (t , json .Unmarshal ([]byte (text ), & response ))
696- assert .Len (t , response .Categories , 2 )
697- assert .Equal (t , "123" , response .Categories [0 ]["id" ])
698- assert .Equal (t , "CategoryOne" , response .Categories [0 ]["name" ])
699- assert .Equal (t , "456" , response .Categories [1 ]["id" ])
700- assert .Equal (t , "CategoryTwo" , response .Categories [1 ]["name" ])
701784}
0 commit comments