@@ -3,7 +3,6 @@ package mcp_test
33import (
44 "context"
55 "testing"
6- "time"
76
87 "github.com/DATA-DOG/go-sqlmock"
98 "github.com/golang/mock/gomock"
@@ -15,26 +14,38 @@ import (
1514 "github.com/ft-t/go-money/pkg/testingutils"
1615)
1716
18- func TestServer_HandleSetTransactionCategory_Success (t * testing.T ) {
17+ func TestServer_HandleBulkSetTransactionCategory_Success (t * testing.T ) {
1918 type tc struct {
20- name string
21- txID float64
22- categoryID any
23- expected string
19+ name string
20+ assignments []map [string ]any
2421 }
2522
2623 cases := []tc {
2724 {
28- name : "set category" ,
29- txID : 1 ,
30- categoryID : float64 (5 ) ,
31- expected : "Transaction 1 category set to 5" ,
25+ name : "set single category" ,
26+ assignments : [] map [ string ] any {
27+ { "transaction_id" : float64 (1 ), "category_id" : float64 ( 5 )} ,
28+ } ,
3229 },
3330 {
34- name : "clear category with nil" ,
35- txID : 2 ,
36- categoryID : nil ,
37- expected : "Transaction 2 category cleared" ,
31+ name : "set multiple categories" ,
32+ assignments : []map [string ]any {
33+ {"transaction_id" : float64 (1 ), "category_id" : float64 (5 )},
34+ {"transaction_id" : float64 (2 ), "category_id" : float64 (10 )},
35+ },
36+ },
37+ {
38+ name : "clear category" ,
39+ assignments : []map [string ]any {
40+ {"transaction_id" : float64 (1 ), "category_id" : nil },
41+ },
42+ },
43+ {
44+ name : "mixed set and clear" ,
45+ assignments : []map [string ]any {
46+ {"transaction_id" : float64 (1 ), "category_id" : float64 (5 )},
47+ {"transaction_id" : float64 (2 ), "category_id" : nil },
48+ },
3849 },
3950 }
4051
@@ -44,114 +55,102 @@ func TestServer_HandleSetTransactionCategory_Success(t *testing.T) {
4455 gormDB , mockDB , mock := testingutils .GormMock ()
4556 defer func () { _ = mockDB .Close () }()
4657
47- selectRows := sqlmock .NewRows ([]string {
48- "id" , "source_amount" , "source_currency" , "destination_amount" ,
49- "destination_currency" , "source_account_id" , "destination_account_id" ,
50- "category_id" , "transaction_type" , "created_at" , "updated_at" ,
51- }).AddRow (
52- int64 (c .txID ), nil , "USD" , nil , "USD" , 1 , 2 , nil , 3 ,
53- time .Now (), time .Now (),
54- )
55- mock .ExpectQuery ("SELECT \\ * FROM \" transactions\" " ).WillReturnRows (selectRows )
56- mock .ExpectBegin ()
57- mock .ExpectExec ("UPDATE \" transactions\" " ).WillReturnResult (sqlmock .NewResult (0 , 1 ))
58- mock .ExpectCommit ()
59-
60- catSvc := NewMockCategoryService (ctrl )
61- rulesSvc := NewMockRulesService (ctrl )
62- dryRunSvc := NewMockDryRunService (ctrl )
58+ for range c .assignments {
59+ mock .ExpectBegin ()
60+ mock .ExpectExec ("UPDATE \" transactions\" " ).WillReturnResult (sqlmock .NewResult (0 , 1 ))
61+ mock .ExpectCommit ()
62+ }
6363
6464 server := gomcp .NewServer (& gomcp.ServerConfig {
6565 DB : gormDB ,
6666 Docs : "test docs" ,
67- CategorySvc : catSvc ,
68- RulesSvc : rulesSvc ,
69- DryRunSvc : dryRunSvc ,
67+ CategorySvc : NewMockCategoryService ( ctrl ) ,
68+ RulesSvc : NewMockRulesService ( ctrl ) ,
69+ DryRunSvc : NewMockDryRunService ( ctrl ) ,
7070 })
7171
72- mcpServer := server .MCPServer ()
73- tool := mcpServer .GetTool ("set_transaction_category" )
72+ tool := server .MCPServer ().GetTool ("bulk_set_transaction_category" )
7473 require .NotNil (t , tool )
7574
76- args := map [ string ]any { "transaction_id" : c . txID }
77- if c . categoryID != nil {
78- args [ "category_id" ] = c . categoryID
75+ assignmentsAny := make ([ ]any , len ( c . assignments ))
76+ for i , a := range c . assignments {
77+ assignmentsAny [ i ] = a
7978 }
8079
8180 result , err := tool .Handler (context .Background (), mcp.CallToolRequest {
8281 Params : mcp.CallToolParams {
83- Name : "set_transaction_category " ,
84- Arguments : args ,
82+ Name : "bulk_set_transaction_category " ,
83+ Arguments : map [ string ] any { "assignments" : assignmentsAny } ,
8584 },
8685 })
8786
8887 require .NoError (t , err )
8988 require .NotNil (t , result )
9089 assert .False (t , result .IsError )
91- assert .Contains (t , result .Content [0 ].(mcp.TextContent ).Text , c . expected )
90+ assert .Contains (t , result .Content [0 ].(mcp.TextContent ).Text , "Updated" )
9291 })
9392 }
9493}
9594
96- func TestServer_HandleSetTransactionCategory_Failure (t * testing.T ) {
95+ func TestServer_HandleBulkSetTransactionCategory_Failure (t * testing.T ) {
9796 type tc struct {
9897 name string
9998 args map [string ]any
100- setupMock func (sqlmock.Sqlmock )
10199 expectedError string
102100 }
103101
104102 cases := []tc {
105103 {
106- name : "missing transaction_id " ,
104+ name : "missing assignments " ,
107105 args : map [string ]any {},
108- setupMock : func (m sqlmock.Sqlmock ) {},
109- expectedError : "transaction_id parameter is required" ,
106+ expectedError : "assignments parameter is required" ,
110107 },
111108 {
112- name : "invalid category_id type" ,
113- args : map [string ]any {"transaction_id" : float64 (1 ), "category_id" : "invalid" },
114- setupMock : func (m sqlmock.Sqlmock ) {},
115- expectedError : "category_id must be a number or null" ,
109+ name : "empty assignments" ,
110+ args : map [string ]any {"assignments" : []any {}},
111+ expectedError : "assignments parameter is required and must be a non-empty array" ,
116112 },
117113 {
118- name : "transaction not found" ,
119- args : map [string ]any {"transaction_id" : float64 (999 )},
120- setupMock : func (m sqlmock.Sqlmock ) {
121- m .ExpectQuery ("SELECT \\ * FROM \" transactions\" " ).
122- WillReturnRows (sqlmock .NewRows ([]string {"id" }))
123- },
124- expectedError : "transaction not found" ,
114+ name : "invalid assignment type" ,
115+ args : map [string ]any {"assignments" : []any {"not an object" }},
116+ expectedError : "assignment[0] must be an object" ,
117+ },
118+ {
119+ name : "missing transaction_id" ,
120+ args : map [string ]any {"assignments" : []any {
121+ map [string ]any {"category_id" : float64 (5 )},
122+ }},
123+ expectedError : "assignment[0].transaction_id is required" ,
124+ },
125+ {
126+ name : "invalid category_id type" ,
127+ args : map [string ]any {"assignments" : []any {
128+ map [string ]any {"transaction_id" : float64 (1 ), "category_id" : "invalid" },
129+ }},
130+ expectedError : "assignment[0].category_id must be a number or null" ,
125131 },
126132 }
127133
128134 for _ , c := range cases {
129135 t .Run (c .name , func (t * testing.T ) {
130136 ctrl := gomock .NewController (t )
131- gormDB , mockDB , mock := testingutils .GormMock ()
137+ gormDB , mockDB , _ := testingutils .GormMock ()
132138 defer func () { _ = mockDB .Close () }()
133139
134- c .setupMock (mock )
135-
136- catSvc := NewMockCategoryService (ctrl )
137- rulesSvc := NewMockRulesService (ctrl )
138- dryRunSvc := NewMockDryRunService (ctrl )
139-
140140 server := gomcp .NewServer (& gomcp.ServerConfig {
141141 DB : gormDB ,
142142 Docs : "test docs" ,
143- CategorySvc : catSvc ,
144- RulesSvc : rulesSvc ,
145- DryRunSvc : dryRunSvc ,
143+ CategorySvc : NewMockCategoryService ( ctrl ) ,
144+ RulesSvc : NewMockRulesService ( ctrl ) ,
145+ DryRunSvc : NewMockDryRunService ( ctrl ) ,
146146 })
147147
148- mcpServer := server .MCPServer ()
149- tool := mcpServer .GetTool ("set_transaction_category" )
148+ tool := server .MCPServer ().GetTool ("bulk_set_transaction_category" )
150149 require .NotNil (t , tool )
151150
152151 result , err := tool .Handler (context .Background (), mcp.CallToolRequest {
153152 Params : mcp.CallToolParams {
154- Name : "set_transaction_category " ,
153+ Name : "bulk_set_transaction_category " ,
155154 Arguments : c .args ,
156155 },
157156 })
0 commit comments