Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions src/framework/zcl_mcp_jsonrpc.clas.abap
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,6 @@ CLASS zcl_mcp_jsonrpc IMPLEMENTATION.
result = array_json->stringify( ).
ENDMETHOD.


METHOD serialize_request.
DATA json_obj TYPE REF TO zif_mcp_ajson.

Expand Down Expand Up @@ -312,18 +311,19 @@ CLASS zcl_mcp_jsonrpc IMPLEMENTATION.
json_obj->set_string( iv_path = '/id'
iv_val = request-id ).
ENDIF.
CATCH zcx_mcp_ajson_error.
CATCH cx_sy_conversion_no_number.
" Not a number, use as string
json_obj->set_string( iv_path = '/id'
iv_val = request-id ).
CATCH zcx_mcp_ajson_error.
" Handle JSON operation error
ENDTRY.
ENDIF.

" Convert to string
result = json_obj->stringify( ).
ENDMETHOD.


METHOD serialize_response.
DATA json_obj TYPE REF TO zif_mcp_ajson.

Expand Down Expand Up @@ -362,18 +362,24 @@ CLASS zcl_mcp_jsonrpc IMPLEMENTATION.

" Add ID with correct type
IF response-id IS NOT INITIAL.
" Add ID with correct type if present
TRY.
DATA(number) = CONV i( response-id ).
" Only treat as number if exact string representation matches
IF response-id = |{ number }|.
json_obj->set_integer( iv_path = '/id'
iv_val = number ).
ELSE.
" Not an exact number, treat as string
json_obj->set_string( iv_path = '/id'
iv_val = response-id ).
ENDIF.
CATCH zcx_mcp_ajson_error.
CATCH cx_sy_conversion_no_number.
" Not a number, use as string
json_obj->set_string( iv_path = '/id'
iv_val = response-id ).
CATCH zcx_mcp_ajson_error.
" Handle JSON operation error
ENDTRY.
ELSE.
" Null ID
Expand Down
141 changes: 130 additions & 11 deletions src/framework/zcl_mcp_jsonrpc.clas.testclasses.abap
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,28 @@ CLASS ltcl_mcp_jsonrpc DEFINITION FINAL FOR TESTING
METHODS setup.

" Test methods for core functionality
METHODS create_request FOR TESTING.
METHODS create_notification FOR TESTING.
METHODS create_success_response FOR TESTING RAISING zcx_mcp_ajson_error.
METHODS create_error_response FOR TESTING RAISING zcx_mcp_ajson_error.
METHODS create_request FOR TESTING.
METHODS create_notification FOR TESTING.
METHODS create_success_response FOR TESTING RAISING zcx_mcp_ajson_error.
METHODS create_error_response FOR TESTING RAISING zcx_mcp_ajson_error.

" Test methods for JSON operations
METHODS serialize_request FOR TESTING RAISING zcx_mcp_ajson_error.
METHODS parse_request FOR TESTING RAISING zcx_mcp_ajson_error.
METHODS parse_request_numeric_id FOR TESTING RAISING zcx_mcp_ajson_error.
METHODS serialize_response FOR TESTING RAISING zcx_mcp_ajson_error.
METHODS parse_response FOR TESTING RAISING zcx_mcp_ajson_error.
METHODS serialize_request FOR TESTING RAISING zcx_mcp_ajson_error.
METHODS parse_request FOR TESTING RAISING zcx_mcp_ajson_error.
METHODS parse_request_numeric_id FOR TESTING RAISING zcx_mcp_ajson_error.
METHODS serialize_response FOR TESTING RAISING zcx_mcp_ajson_error.
METHODS parse_response FOR TESTING RAISING zcx_mcp_ajson_error.

" Test methods for batch operations
METHODS parse_batch_request FOR TESTING RAISING zcx_mcp_ajson_error.
METHODS serialize_batch_response FOR TESTING RAISING zcx_mcp_ajson_error.
METHODS parse_batch_request FOR TESTING RAISING zcx_mcp_ajson_error.
METHODS serialize_batch_response FOR TESTING RAISING zcx_mcp_ajson_error.

" Test different ID formats
METHODS parse_request_id_leading_zeros FOR TESTING RAISING zcx_mcp_ajson_error.
METHODS parse_request_alphanumeric_id FOR TESTING RAISING zcx_mcp_ajson_error.
METHODS parse_request_uuid_id FOR TESTING RAISING zcx_mcp_ajson_error.
METHODS serialize_request_id_formats FOR TESTING RAISING zcx_mcp_ajson_error.
METHODS serialize_response_id_formats FOR TESTING RAISING zcx_mcp_ajson_error.

" Helper methods
METHODS assert_json_equals
Expand Down Expand Up @@ -273,4 +280,116 @@ CLASS ltcl_mcp_jsonrpc IMPLEMENTATION.
cl_abap_unit_assert=>assert_equals( exp = normalized_expected
act = normalized_actual ).
ENDMETHOD.

METHOD parse_request_id_leading_zeros.
" Arrange - JSON request with string ID that has leading zeros
DATA(json) = `{"jsonrpc":"2.0","method":"test.method","id":"0123"}`.

" Act - parse the JSON to a request object
DATA(request) = cut->parse_request( json ).

" Assert - check ID is parsed correctly as a string, preserving leading zeros
cl_abap_unit_assert=>assert_equals( exp = '0123'
act = request-id ).

" Serialize and check that it's treated as a string in JSON
DATA(serialized) = cut->serialize_request( request ).
assert_json_equals( actual = serialized
expected = '{"jsonrpc":"2.0","method":"test.method","id":"0123"}' ).
ENDMETHOD.

METHOD parse_request_alphanumeric_id.
" Arrange - JSON request with alphanumeric ID
DATA(json) = `{"jsonrpc":"2.0","method":"test.method","id":"abc123"}`.

" Act - parse the JSON to a request object
DATA(request) = cut->parse_request( json ).

" Assert - check ID is parsed correctly
cl_abap_unit_assert=>assert_equals( exp = 'abc123'
act = request-id ).

" Serialize and check that it's treated as a string in JSON
DATA(serialized) = cut->serialize_request( request ).
assert_json_equals( actual = serialized
expected = '{"jsonrpc":"2.0","method":"test.method","id":"abc123"}' ).
ENDMETHOD.

METHOD parse_request_uuid_id.
" Arrange - JSON request with UUID-style ID
DATA(json) = `{"jsonrpc":"2.0","method":"test.method","id":"550e8400-e29b-41d4-a716-446655440000"}`.

" Act - parse the JSON to a request object
DATA(request) = cut->parse_request( json ).

" Assert - check ID is parsed correctly
cl_abap_unit_assert=>assert_equals( exp = '550e8400-e29b-41d4-a716-446655440000'
act = request-id ).

" Serialize and check that it's treated as a string in JSON
DATA(serialized) = cut->serialize_request( request ).
assert_json_equals(
actual = serialized
expected = '{"jsonrpc":"2.0","method":"test.method","id":"550e8400-e29b-41d4-a716-446655440000"}' ).
ENDMETHOD.

METHOD serialize_request_id_formats.
" Test different ID formats in serialization

" 1. Numeric ID
DATA(request1) = cut->create_request( method = 'test.method'
id = '123' ).
DATA(json1) = cut->serialize_request( request1 ).
assert_json_equals( actual = json1
expected = '{"jsonrpc":"2.0","method":"test.method","id":123}' ).

" 2. ID with leading zeros
DATA(request2) = cut->create_request( method = 'test.method'
id = '0123' ).
DATA(json2) = cut->serialize_request( request2 ).
assert_json_equals( actual = json2
expected = '{"jsonrpc":"2.0","method":"test.method","id":"0123"}' ).

" 3. ID with special formatting (plus sign)
DATA(request3) = cut->create_request( method = 'test.method'
id = '+123' ).
DATA(json3) = cut->serialize_request( request3 ).
assert_json_equals( actual = json3
expected = '{"jsonrpc":"2.0","method":"test.method","id":"+123"}' ).

" 4. Alphanumeric ID
DATA(request4) = cut->create_request( method = 'test.method'
id = 'abc123' ).
DATA(json4) = cut->serialize_request( request4 ).
assert_json_equals( actual = json4
expected = '{"jsonrpc":"2.0","method":"test.method","id":"abc123"}' ).
ENDMETHOD.

METHOD serialize_response_id_formats.
" Setup a simple result for all responses
DATA(result_json) = zcl_mcp_ajson=>create_empty( ).
result_json->set_string( iv_path = '/status'
iv_val = 'success' ).

" 1. Numeric ID
DATA(response1) = cut->create_success_response( id = '123'
result = result_json ).
DATA(json1) = cut->serialize_response( response1 ).
assert_json_equals( actual = json1
expected = '{"jsonrpc":"2.0","result":{"status":"success"},"id":123}' ).

" 2. ID with leading zeros
DATA(response2) = cut->create_success_response( id = '0123'
result = result_json ).
DATA(json2) = cut->serialize_response( response2 ).
assert_json_equals( actual = json2
expected = '{"jsonrpc":"2.0","result":{"status":"success"},"id":"0123"}' ).

" 3. Alphanumeric ID
DATA(response3) = cut->create_success_response( id = 'abc123'
result = result_json ).
DATA(json3) = cut->serialize_response( response3 ).
assert_json_equals( actual = json3
expected = '{"jsonrpc":"2.0","result":{"status":"success"},"id":"abc123"}' ).
ENDMETHOD.
ENDCLASS.