@@ -484,7 +484,7 @@ func Test_GetDiscussion(t *testing.T) {
484
484
assert .ElementsMatch (t , toolDef .InputSchema .Required , []string {"owner" , "repo" , "discussionNumber" })
485
485
486
486
// 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}}}}"
488
488
489
489
vars := map [string ]interface {}{
490
490
"owner" : "owner" ,
@@ -638,17 +638,33 @@ func Test_GetDiscussionComments(t *testing.T) {
638
638
}
639
639
640
640
func 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
+
641
650
// Use exact string query that matches implementation output
642
651
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}}}"
643
652
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 {}{
646
655
"owner" : "owner" ,
647
656
"repo" : "repo" ,
648
657
"first" : float64 (25 ),
649
658
}
650
659
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 {
652
668
"repository" : map [string ]any {
653
669
"discussionCategories" : map [string ]any {
654
670
"nodes" : []map [string ]any {
@@ -665,37 +681,98 @@ func Test_ListDiscussionCategories(t *testing.T) {
665
681
},
666
682
},
667
683
})
668
- matcher := githubv4mock .NewQueryMatcher (qListCategories , vars , mockResp )
669
- httpClient := githubv4mock .NewMockedHTTPClient (matcher )
670
- gqlClient := githubv4 .NewClient (httpClient )
671
684
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
+ })
678
703
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
+ 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
+ }
682
745
683
- 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 )
684
751
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"`
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
+ })
694
777
}
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" ])
701
778
}
0 commit comments