1- import 'dart:convert' ;
2-
3- import 'package:test/test.dart' ;
41import 'package:mcp_dart/mcp_dart.dart' ;
2+ import 'package:test/test.dart' ;
53
64void main () {
75 group ('JsonRpcMessage Tests' , () {
@@ -29,6 +27,20 @@ void main() {
2927 equals (latestProtocolVersion));
3028 });
3129
30+ test ('JsonRpcResponse serialization' , () {
31+ final response = JsonRpcResponse (
32+ id: 1 ,
33+ result: {'key' : 'value' },
34+ meta: {'metaKey' : 'metaValue' },
35+ );
36+
37+ final json = response.toJson ();
38+ expect (json['jsonrpc' ], equals (jsonRpcVersion));
39+ expect (json['id' ], equals (1 ));
40+ expect (json['result' ]['key' ], equals ('value' ));
41+ expect (json['result' ]['_meta' ]['metaKey' ], equals ('metaValue' ));
42+ });
43+
3244 test ('JsonRpcError serialization and deserialization' , () {
3345 final error = JsonRpcError (
3446 id: 1 ,
@@ -43,10 +55,15 @@ void main() {
4355 expect (json['jsonrpc' ], equals (jsonRpcVersion));
4456 expect (json['error' ]['code' ], equals (ErrorCode .invalidRequest.value));
4557 expect (json['error' ]['message' ], equals ('Invalid request' ));
58+ expect (
59+ json['error' ]['data' ]['details' ], equals ('Missing required field' ));
4660
4761 final deserialized = JsonRpcError .fromJson (json);
4862 expect (deserialized.id, equals (error.id));
4963 expect (deserialized.error.code, equals (ErrorCode .invalidRequest.value));
64+ expect (deserialized.error.message, equals ('Invalid request' ));
65+ expect (
66+ deserialized.error.data['details' ], equals ('Missing required field' ));
5067 });
5168 });
5269
@@ -112,6 +129,19 @@ void main() {
112129 expect (deserialized.data, equals ('base64data' ));
113130 expect (deserialized.mimeType, equals ('image/png' ));
114131 });
132+
133+ test ('UnknownContent serialization and deserialization' , () {
134+ final content = UnknownContent (
135+ type: 'unknown' , additionalProperties: {'key' : 'value' });
136+ final json = content.toJson ();
137+ expect (json['type' ], equals ('unknown' ));
138+ expect (json['key' ], equals ('value' ));
139+
140+ final deserialized =
141+ UnknownContent (type: 'unknown' , additionalProperties: json);
142+ expect (deserialized.type, equals ('unknown' ));
143+ expect (deserialized.additionalProperties['key' ], equals ('value' ));
144+ });
115145 });
116146
117147 group ('Resource Tests' , () {
@@ -151,6 +181,24 @@ void main() {
151181 expect (deserialized.uri, equals ('file://example.txt' ));
152182 expect (deserialized.text, equals ('Sample text content' ));
153183 });
184+
185+ test ('BlobResourceContents serialization and deserialization' , () {
186+ final contents = BlobResourceContents (
187+ uri: 'file://example.bin' ,
188+ blob: 'base64data' ,
189+ mimeType: 'application/octet-stream' ,
190+ );
191+
192+ final json = contents.toJson ();
193+ expect (json['uri' ], equals ('file://example.bin' ));
194+ expect (json['blob' ], equals ('base64data' ));
195+ expect (json['mimeType' ], equals ('application/octet-stream' ));
196+
197+ final deserialized =
198+ ResourceContents .fromJson (json) as BlobResourceContents ;
199+ expect (deserialized.uri, equals ('file://example.bin' ));
200+ expect (deserialized.blob, equals ('base64data' ));
201+ });
154202 });
155203
156204 group ('Prompt Tests' , () {
@@ -173,5 +221,169 @@ void main() {
173221 expect (deserialized.name, equals ('example-prompt' ));
174222 expect (deserialized.arguments? .first.name, equals ('arg1' ));
175223 });
224+
225+ test ('PromptArgument serialization and deserialization' , () {
226+ final argument = PromptArgument (
227+ name: 'arg1' ,
228+ description: 'Argument 1' ,
229+ required : true ,
230+ );
231+
232+ final json = argument.toJson ();
233+ expect (json['name' ], equals ('arg1' ));
234+ expect (json['description' ], equals ('Argument 1' ));
235+ expect (json['required' ], equals (true ));
236+
237+ final deserialized = PromptArgument .fromJson (json);
238+ expect (deserialized.name, equals ('arg1' ));
239+ expect (deserialized.description, equals ('Argument 1' ));
240+ expect (deserialized.required , equals (true ));
241+ });
242+ });
243+ group ('CreateMessageResult Tests' , () {
244+ test ('CreateMessageResult serialization and deserialization' , () {
245+ final result = CreateMessageResult (
246+ model: 'gpt-4' ,
247+ stopReason: StopReason .maxTokens,
248+ role: SamplingMessageRole .assistant,
249+ content: SamplingTextContent (text: 'Hello, world!' ),
250+ meta: {'key' : 'value' },
251+ );
252+
253+ final json = result.toJson ();
254+ expect (json['model' ], equals ('gpt-4' ));
255+ expect (json['stopReason' ], equals (StopReason .maxTokens.toString ()));
256+ expect (json['role' ], equals ('assistant' ));
257+ expect (json['content' ]['type' ], equals ('text' ));
258+ expect (json['content' ]['text' ], equals ('Hello, world!' ));
259+ expect (json['_meta' ], isNull); // `_meta` is not included in `toJson`
260+
261+ final deserialized = CreateMessageResult .fromJson ({
262+ 'model' : 'gpt-4' ,
263+ 'stopReason' : 'maxTokens' ,
264+ 'role' : 'assistant' ,
265+ 'content' : {'type' : 'text' , 'text' : 'Hello, world!' },
266+ '_meta' : {'key' : 'value' },
267+ });
268+
269+ expect (deserialized.model, equals ('gpt-4' ));
270+ expect (deserialized.stopReason, equals (StopReason .maxTokens));
271+ expect (deserialized.role, equals (SamplingMessageRole .assistant));
272+ expect (deserialized.content, isA <SamplingTextContent >());
273+ expect ((deserialized.content as SamplingTextContent ).text,
274+ equals ('Hello, world!' ));
275+ expect (deserialized.meta, equals ({'key' : 'value' }));
276+ });
277+
278+ test ('CreateMessageResult handles custom stopReason' , () {
279+ final result = CreateMessageResult (
280+ model: 'gpt-4' ,
281+ stopReason: 'customReason' ,
282+ role: SamplingMessageRole .assistant,
283+ content: SamplingTextContent (text: 'Custom reason test' ),
284+ );
285+
286+ final json = result.toJson ();
287+ expect (json['stopReason' ], equals ('customReason' ));
288+
289+ final deserialized = CreateMessageResult .fromJson ({
290+ 'model' : 'gpt-4' ,
291+ 'stopReason' : 'customReason' ,
292+ 'role' : 'assistant' ,
293+ 'content' : {'type' : 'text' , 'text' : 'Custom reason test' },
294+ });
295+
296+ expect (deserialized.stopReason, equals ('customReason' ));
297+ });
298+
299+ test ('CreateMessageResult handles invalid stopReason gracefully' , () {
300+ final deserialized = CreateMessageResult .fromJson ({
301+ 'model' : 'gpt-4' ,
302+ 'stopReason' : 'invalidReason' ,
303+ 'role' : 'assistant' ,
304+ 'content' : {'type' : 'text' , 'text' : 'Invalid reason test' },
305+ });
306+
307+ expect (deserialized.stopReason, equals ('invalidReason' ));
308+ });
309+ });
310+
311+ group ('JsonRpcMessage.fromJson Tests' , () {
312+ test ('Parses valid request with method and id' , () {
313+ final json = {
314+ 'jsonrpc' : '2.0' ,
315+ 'id' : 1 ,
316+ 'method' : 'ping' ,
317+ };
318+ final message = JsonRpcMessage .fromJson (json);
319+ expect (message, isA <JsonRpcPingRequest >());
320+ expect ((message as JsonRpcPingRequest ).id, equals (1 ));
321+ });
322+
323+ test ('Parses valid notification without id' , () {
324+ final json = {
325+ 'jsonrpc' : '2.0' ,
326+ 'method' : 'notifications/initialized' ,
327+ };
328+ final message = JsonRpcMessage .fromJson (json);
329+ expect (message, isA <JsonRpcInitializedNotification >());
330+ });
331+
332+ test ('Parses valid response with result and meta' , () {
333+ final json = {
334+ 'jsonrpc' : '2.0' ,
335+ 'id' : 1 ,
336+ 'result' : {
337+ 'key' : 'value' ,
338+ '_meta' : {'metaKey' : 'metaValue' }
339+ },
340+ };
341+ final message = JsonRpcMessage .fromJson (json);
342+ expect (message, isA <JsonRpcResponse >());
343+ final response = message as JsonRpcResponse ;
344+ expect (response.id, equals (1 ));
345+ expect (response.result, equals ({'key' : 'value' }));
346+ expect (response.meta, equals ({'metaKey' : 'metaValue' }));
347+ });
348+
349+ test ('Parses valid error response' , () {
350+ final json = {
351+ 'jsonrpc' : '2.0' ,
352+ 'id' : 1 ,
353+ 'error' : {'code' : - 32601 , 'message' : 'Method not found' },
354+ };
355+ final message = JsonRpcMessage .fromJson (json);
356+ expect (message, isA <JsonRpcError >());
357+ final error = message as JsonRpcError ;
358+ expect (error.id, equals (1 ));
359+ expect (error.error.code, equals (- 32601 ));
360+ expect (error.error.message, equals ('Method not found' ));
361+ });
362+
363+ test ('Throws FormatException for invalid JSON-RPC version' , () {
364+ final json = {
365+ 'jsonrpc' : '1.0' ,
366+ 'id' : 1 ,
367+ 'method' : 'ping' ,
368+ };
369+ expect (() => JsonRpcMessage .fromJson (json), throwsFormatException);
370+ });
371+
372+ test ('Throws UnimplementedError for unknown method' , () {
373+ final json = {
374+ 'jsonrpc' : '2.0' ,
375+ 'id' : 1 ,
376+ 'method' : 'unknownMethod' ,
377+ };
378+ expect (() => JsonRpcMessage .fromJson (json), throwsUnimplementedError);
379+ });
380+
381+ test ('Throws FormatException for invalid message format' , () {
382+ final json = {
383+ 'jsonrpc' : '2.0' ,
384+ 'id' : 1 ,
385+ };
386+ expect (() => JsonRpcMessage .fromJson (json), throwsFormatException);
387+ });
176388 });
177389}
0 commit comments