AtlatestRepositorysigil-mcp
1
(import (sigil test)2
(sigil mcp protocol)3
(sigil json))5
;; ============================================================6
;; parse-message7
;; ============================================================9
(test-group "parse-message"10
(test "request with id+method+params"11
(let* ((json (json-decode "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"ping\",\"params\":{}}"))12
(msg (parse-message json)))13
(assert-true (jsonrpc-request? msg))14
(assert-equal 1 (jsonrpc-request-id msg))15
(assert-equal "ping" (jsonrpc-request-method msg))))17
(test "notification (no id)"18
(let* ((json (json-decode "{\"jsonrpc\":\"2.0\",\"method\":\"notify\",\"params\":{}}"))19
(msg (parse-message json)))20
(assert-true (jsonrpc-notification? msg))21
(assert-equal "notify" (jsonrpc-notification-method msg))))23
(test "missing jsonrpc field returns #f"24
(let* ((json (json-decode "{\"id\":1,\"method\":\"test\"}"))25
(msg (parse-message json)))26
(assert-false msg)))28
(test "wrong version returns #f"29
(let* ((json (json-decode "{\"jsonrpc\":\"1.0\",\"id\":1,\"method\":\"test\"}"))30
(msg (parse-message json)))31
(assert-false msg)))33
(test "missing method returns #f"34
(let* ((json (json-decode "{\"jsonrpc\":\"2.0\",\"id\":1}"))35
(msg (parse-message json)))36
(assert-false msg)))38
(test "non-dict returns #f"39
(assert-false (parse-message "not a dict")))41
(test "successful response"42
(let ((msg (parse-message-string43
"{\"jsonrpc\":\"2.0\",\"id\":0,\"result\":{\"ok\":true}}")))44
(assert-true (jsonrpc-response? msg))45
(assert-equal 0 (jsonrpc-response-id msg))46
(assert-true (dict-ref (jsonrpc-response-result msg) ok:))))48
(test "successful response preserves a false result"49
(let ((msg (parse-message-string50
"{\"jsonrpc\":\"2.0\",\"id\":0,\"result\":false}")))51
(assert-true (jsonrpc-response? msg))52
(assert-equal 0 (jsonrpc-response-id msg))53
(assert-false (jsonrpc-response-result msg))))55
(test "error response"56
(let ((msg (parse-message-string57
"{\"jsonrpc\":\"2.0\",\"id\":7,\"error\":{\"code\":-32001,\"message\":\"refused\",\"data\":{\"kind\":\"policy\"}}}")))58
(assert-true (jsonrpc-error-response? msg))59
(assert-equal 7 (jsonrpc-error-response-id msg))60
(assert-equal -32001 (jsonrpc-error-response-code msg))61
(assert-equal "refused" (jsonrpc-error-response-message msg)))))63
;; ============================================================64
;; parse-message-string65
;; ============================================================67
(test-group "parse-message-string"68
(test "JSON string roundtrip"69
(let ((msg (parse-message-string "{\"jsonrpc\":\"2.0\",\"id\":42,\"method\":\"tools/list\",\"params\":{}}")))70
(assert-true (jsonrpc-request? msg))71
(assert-equal 42 (jsonrpc-request-id msg))72
(assert-equal "tools/list" (jsonrpc-request-method msg)))))74
;; ============================================================75
;; Serialization76
;; ============================================================78
(test-group "serialization"79
(test "response->json produces valid JSON"80
(let* ((resp (make-response 1 "ok"))81
(json-str (response->json resp))82
(parsed (json-decode json-str)))83
(assert-true (dict? parsed))84
(assert-equal "2.0" (dict-ref parsed jsonrpc:))85
(assert-equal 1 (dict-ref parsed id:))86
(assert-equal "ok" (dict-ref parsed result:))))88
(test "error-response->json includes error"89
(let* ((resp (make-error-response 1 -32600 "Invalid Request"))90
(json-str (error-response->json resp))91
(parsed (json-decode json-str)))92
(assert-true (dict? parsed))93
(assert-equal 1 (dict-ref parsed id:))94
(let ((err (dict-ref parsed error:)))95
(assert-true (dict? err))96
(assert-equal -32600 (dict-ref err code:))97
(assert-equal "Invalid Request" (dict-ref err message:)))))99
(test "notification->json omits id"100
(let* ((notif (make-notification "update"))101
(json-str (notification->json notif))102
(parsed (json-decode json-str)))103
(assert-equal "2.0" (dict-ref parsed jsonrpc:))104
(assert-equal "update" (dict-ref parsed method:))105
(assert-false (dict-ref parsed id: #f))))107
(test "request->json includes all fields"108
(let* ((req (jsonrpc-request id: 5 method: "test" params: (dict)))109
(json-str (request->json req))110
(parsed (json-decode json-str)))111
(assert-equal 5 (dict-ref parsed id:))112
(assert-equal "test" (dict-ref parsed method:)))))114
;; ============================================================115
;; Helper constructors116
;; ============================================================118
(test-group "helper constructors"119
(test "make-response"120
(let ((r (make-response 1 "data")))121
(assert-true (jsonrpc-response? r))122
(assert-equal 1 (jsonrpc-response-id r))123
(assert-equal "data" (jsonrpc-response-result r))))125
(test "make-error-response without data"126
(let ((r (make-error-response 2 -32700 "Parse error")))127
(assert-true (jsonrpc-error-response? r))128
(assert-equal 2 (jsonrpc-error-response-id r))129
(assert-equal -32700 (jsonrpc-error-response-code r))130
(assert-equal "Parse error" (jsonrpc-error-response-message r))))132
(test "make-notification"133
(let ((n (make-notification "event")))134
(assert-true (jsonrpc-notification? n))135
(assert-equal "event" (jsonrpc-notification-method n)))))137
;; ============================================================138
;; Error codes139
;; ============================================================141
(test-group "error codes"142
(test "error-parse"143
(assert-equal -32700 error-parse))145
(test "error-invalid-request"146
(assert-equal -32600 error-invalid-request))148
(test "error-method-not-found"149
(assert-equal -32601 error-method-not-found))151
(test "error-invalid-params"152
(assert-equal -32602 error-invalid-params))154
(test "error-internal"155
(assert-equal -32603 error-internal)))157
(run-tests)