more ui core decoupling (#6374)

Co-authored-by: Marc Bernard <59966492+mbtools@users.noreply.github.com>
This commit is contained in:
Lars Hvam 2023-08-25 07:14:03 +02:00 committed by GitHub
parent 274f802e8b
commit 55fb0d07a4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 540 additions and 539 deletions

View File

@ -236,6 +236,7 @@
"7bit_ascii": {
"exclude": [
"zcl_abapgit_git_commit.clas.testclasses.abap",
"zcl_abapgit_gui_event.clas.testclasses.abap",
"zcl_abapgit_html_action_utils.clas.testclasses.abap"
]
},

View File

@ -7,6 +7,8 @@ CLASS zcl_abapgit_gui_event DEFINITION
INTERFACES zif_abapgit_gui_event .
CLASS-METHODS class_constructor .
CLASS-METHODS new
IMPORTING
!ii_gui_services TYPE REF TO zif_abapgit_gui_services OPTIONAL
@ -26,6 +28,8 @@ CLASS zcl_abapgit_gui_event DEFINITION
DATA mo_query TYPE REF TO zcl_abapgit_string_map.
DATA mo_form_data TYPE REF TO zcl_abapgit_string_map.
CLASS-DATA gv_non_breaking_space TYPE string .
METHODS fields_to_map
IMPORTING
it_fields TYPE tihttpnvp
@ -34,6 +38,40 @@ CLASS zcl_abapgit_gui_event DEFINITION
RAISING
zcx_abapgit_exception.
CLASS-METHODS parse_post_form_data
IMPORTING
!it_post_data TYPE zif_abapgit_html_viewer=>ty_post_data
!iv_upper_cased TYPE abap_bool DEFAULT abap_false
RETURNING
VALUE(rt_fields) TYPE tihttpnvp .
CLASS-METHODS parse_fields
IMPORTING
!iv_string TYPE clike
!iv_upper_cased TYPE abap_bool DEFAULT abap_false
RETURNING
VALUE(rt_fields) TYPE tihttpnvp .
CLASS-METHODS parse_fields_upper_case_name
IMPORTING
!iv_string TYPE clike
RETURNING
VALUE(rt_fields) TYPE tihttpnvp .
CLASS-METHODS translate_postdata
IMPORTING
!it_postdata TYPE zif_abapgit_html_viewer=>ty_post_data
RETURNING
VALUE(rv_string) TYPE string .
CLASS-METHODS field_keys_to_upper
CHANGING
!ct_fields TYPE tihttpnvp .
CLASS-METHODS unescape
IMPORTING
!iv_string TYPE string
RETURNING
VALUE(rv_string) TYPE string .
ENDCLASS.
@ -81,8 +119,7 @@ CLASS zcl_abapgit_gui_event IMPLEMENTATION.
METHOD zif_abapgit_gui_event~form_data.
IF mo_form_data IS NOT BOUND.
mo_form_data = fields_to_map(
zcl_abapgit_html_action_utils=>parse_post_form_data( zif_abapgit_gui_event~mt_postdata ) ).
mo_form_data = fields_to_map( parse_post_form_data( zif_abapgit_gui_event~mt_postdata ) ).
mo_form_data->freeze( ).
ENDIF.
ro_string_map = mo_form_data.
@ -93,11 +130,142 @@ CLASS zcl_abapgit_gui_event IMPLEMENTATION.
METHOD zif_abapgit_gui_event~query.
IF mo_query IS NOT BOUND.
mo_query = fields_to_map(
zcl_abapgit_html_action_utils=>parse_fields( zif_abapgit_gui_event~mv_getdata ) ).
mo_query = fields_to_map( parse_fields( zif_abapgit_gui_event~mv_getdata ) ).
mo_query->freeze( ).
ENDIF.
ro_string_map = mo_query.
ENDMETHOD.
METHOD parse_fields_upper_case_name.
rt_fields = parse_fields(
iv_string = iv_string
iv_upper_cased = abap_true ).
ENDMETHOD.
METHOD parse_post_form_data.
DATA lv_serialized_post_data TYPE string.
lv_serialized_post_data = translate_postdata( it_post_data ).
IF iv_upper_cased = abap_true.
rt_fields = parse_fields_upper_case_name( lv_serialized_post_data ).
ELSE.
rt_fields = parse_fields( lv_serialized_post_data ).
ENDIF.
ENDMETHOD.
METHOD parse_fields.
DATA:
lt_substrings TYPE string_table,
ls_field LIKE LINE OF rt_fields.
FIELD-SYMBOLS <lv_substring> LIKE LINE OF lt_substrings.
SPLIT iv_string AT '&' INTO TABLE lt_substrings.
LOOP AT lt_substrings ASSIGNING <lv_substring>.
CLEAR ls_field.
" On attempt to change unescaping -> run unit tests to check !
" Unescape name and value separately
ls_field-name = unescape( substring_before(
val = <lv_substring>
sub = '=' ) ).
ls_field-value = unescape( substring_after(
val = <lv_substring>
sub = '=' ) ).
IF ls_field IS INITIAL. " Not a field with proper structure
CONTINUE.
ENDIF.
APPEND ls_field TO rt_fields.
ENDLOOP.
IF iv_upper_cased = abap_true.
field_keys_to_upper( CHANGING ct_fields = rt_fields ).
ENDIF.
ENDMETHOD.
METHOD translate_postdata.
DATA: lt_post_data TYPE zif_abapgit_html_viewer=>ty_post_data,
ls_last_line LIKE LINE OF it_postdata,
lv_last_line_index TYPE i.
IF it_postdata IS INITIAL.
RETURN. "Nothing to do
ENDIF.
lt_post_data = it_postdata.
"Save the last line for separate merge, because we don't need its trailing spaces
WHILE ls_last_line IS INITIAL.
lv_last_line_index = lines( lt_post_data ).
READ TABLE lt_post_data INTO ls_last_line INDEX lv_last_line_index.
"Avoid trailing null values (see isssue #4832)
"todo, keep until SAP GUI for Java is fixed (remove on 2022-12-31)
ls_last_line = replace( val = ls_last_line
sub = zcl_abapgit_git_utils=>get_null( )
with = space
occ = 0 ).
DELETE lt_post_data INDEX lv_last_line_index.
ENDWHILE.
CONCATENATE LINES OF lt_post_data INTO rv_string
IN CHARACTER MODE RESPECTING BLANKS.
CONCATENATE rv_string ls_last_line INTO rv_string
IN CHARACTER MODE.
ENDMETHOD.
METHOD field_keys_to_upper.
FIELD-SYMBOLS <ls_field> LIKE LINE OF ct_fields.
LOOP AT ct_fields ASSIGNING <ls_field>.
<ls_field>-name = to_upper( <ls_field>-name ).
ENDLOOP.
ENDMETHOD.
METHOD unescape.
* do not use cl_http_utility as it does strange things with the encoding
rv_string = iv_string.
* todo, more to be added here
REPLACE ALL OCCURRENCES OF '%3A' IN rv_string WITH ':' IGNORING CASE.
REPLACE ALL OCCURRENCES OF '%3F' IN rv_string WITH '?' IGNORING CASE.
REPLACE ALL OCCURRENCES OF '%3D' IN rv_string WITH '=' IGNORING CASE.
REPLACE ALL OCCURRENCES OF '%2F' IN rv_string WITH '/' IGNORING CASE.
REPLACE ALL OCCURRENCES OF '%25' IN rv_string WITH '%' IGNORING CASE.
REPLACE ALL OCCURRENCES OF '%26' IN rv_string WITH '&' IGNORING CASE.
REPLACE ALL OCCURRENCES OF gv_non_breaking_space IN rv_string WITH ` `.
ENDMETHOD.
METHOD class_constructor.
CONSTANTS lc_nbsp TYPE xstring VALUE 'C2A0'. " &nbsp;
TRY.
gv_non_breaking_space = zcl_abapgit_convert=>xstring_to_string_utf8( lc_nbsp ).
CATCH zcx_abapgit_exception.
ASSERT 0 = 1.
ENDTRY.
ENDMETHOD.
ENDCLASS.

View File

@ -23,7 +23,7 @@ CLASS ltcl_event IMPLEMENTATION.
CREATE OBJECT li_cut TYPE zcl_abapgit_gui_event
EXPORTING
iv_action = 'XXX'
iv_action = 'XXX'
iv_getdata = 'not_a_param'.
lo_map = li_cut->query( ).
@ -56,7 +56,7 @@ CLASS ltcl_event IMPLEMENTATION.
CREATE OBJECT li_cut TYPE zcl_abapgit_gui_event
EXPORTING
iv_action = 'XXX'
iv_action = 'XXX'
iv_getdata = 'a=b&b=c'.
" Cross check just in case
@ -163,3 +163,367 @@ CLASS ltcl_event IMPLEMENTATION.
ENDMETHOD.
ENDCLASS.
CLASS ltcl_html_action_utils DEFINITION FOR TESTING RISK LEVEL HARMLESS
DURATION SHORT FINAL.
PUBLIC SECTION.
CLASS-METHODS class_constructor.
METHODS parse_fields_simple_case FOR TESTING.
METHODS parse_fields_advanced_case FOR TESTING.
METHODS parse_fields_unescape FOR TESTING.
METHODS parse_fields_unescape_nbsp FOR TESTING.
METHODS parse_fields_german_umlauts FOR TESTING.
METHODS parse_fields_wrong_format FOR TESTING.
METHODS parse_post_form_data FOR TESTING.
METHODS parse_fields_webgui FOR TESTING.
METHODS parse_fields_special_chars FOR TESTING.
PRIVATE SECTION.
CONSTANTS: BEGIN OF c_german_umlaut_as_hex,
lower_case_ae TYPE xstring VALUE 'C3A4',
lower_case_oe TYPE xstring VALUE 'C3B6',
lower_case_ue TYPE xstring VALUE 'C3BC',
END OF c_german_umlaut_as_hex.
CLASS-DATA: BEGIN OF gs_german_umlaut_as_char,
lower_case_ae TYPE string,
lower_case_oe TYPE string,
lower_case_ue TYPE string,
END OF gs_german_umlaut_as_char.
DATA mv_given_parse_string TYPE string.
DATA mt_parsed_fields TYPE tihttpnvp.
METHODS _given_string_is
IMPORTING
iv_string TYPE string.
METHODS _when_fields_are_parsed_upper.
METHODS _when_fields_are_parsed.
METHODS _then_fields_should_be
IMPORTING
iv_index TYPE i
iv_name TYPE string
iv_value TYPE string.
METHODS _then_field_count_should_be
IMPORTING
iv_count TYPE i.
CLASS-METHODS _hex_to_char
IMPORTING
iv_x TYPE xstring
RETURNING
VALUE(rv_s) TYPE string.
ENDCLASS.
CLASS zcl_abapgit_gui_event DEFINITION LOCAL FRIENDS ltcl_html_action_utils.
CLASS ltcl_html_action_utils IMPLEMENTATION.
METHOD class_constructor.
gs_german_umlaut_as_char-lower_case_ae = _hex_to_char( c_german_umlaut_as_hex-lower_case_ae ).
gs_german_umlaut_as_char-lower_case_oe = _hex_to_char( c_german_umlaut_as_hex-lower_case_oe ).
gs_german_umlaut_as_char-lower_case_ue = _hex_to_char( c_german_umlaut_as_hex-lower_case_ue ).
ENDMETHOD.
METHOD parse_fields_simple_case.
_given_string_is( `committer_name=Gustav Gans` ).
_when_fields_are_parsed_upper( ).
_then_fields_should_be( iv_index = 1
iv_name = `COMMITTER_NAME`
iv_value = `Gustav Gans` ).
ENDMETHOD.
METHOD parse_fields_advanced_case.
_given_string_is( `committer_name=Albert Schweitzer&`
&& `committer_email=albert.schweitzer@googlemail.com&`
&& `comment=dummy comment&`
&& `body=Message body<<new>><<new>>with line break<<new>>&`
&& `author_name=Karl Klammer&`
&& `author_email=karl@klammer.com` ).
_when_fields_are_parsed_upper( ).
_then_fields_should_be( iv_index = 1
iv_name = `COMMITTER_NAME`
iv_value = `Albert Schweitzer` ).
_then_fields_should_be( iv_index = 2
iv_name = `COMMITTER_EMAIL`
iv_value = `albert.schweitzer@googlemail.com` ).
_then_fields_should_be( iv_index = 3
iv_name = `COMMENT`
iv_value = `dummy comment` ).
_then_fields_should_be( iv_index = 4
iv_name = `BODY`
iv_value = `Message body<<new>><<new>>with line break<<new>>` ).
_then_fields_should_be( iv_index = 5
iv_name = `AUTHOR_NAME`
iv_value = `Karl Klammer` ).
_then_fields_should_be( iv_index = 6
iv_name = `AUTHOR_EMAIL`
iv_value = `karl@klammer.com` ).
ENDMETHOD.
METHOD parse_fields_unescape.
" file status = '?', used in staging page
_given_string_is( '/SRC/ZFOOBAR.PROG.ABAP=%3F' ).
_when_fields_are_parsed_upper( ).
_then_field_count_should_be( 1 ).
_then_fields_should_be(
iv_index = 1
iv_name = '/SRC/ZFOOBAR.PROG.ABAP'
iv_value = '?' ).
ENDMETHOD.
METHOD parse_fields_unescape_nbsp.
" non-breaking space (&nbsp;)
_given_string_is( '/src/ztest_rfc.fugr.xml=%3F&/src/ztest_rfc'
&& zcl_abapgit_gui_event=>gv_non_breaking_space
&& zcl_abapgit_gui_event=>gv_non_breaking_space
&& zcl_abapgit_gui_event=>gv_non_breaking_space
&& 'rf.sush.xml=A' ).
_when_fields_are_parsed( ).
_then_field_count_should_be( 2 ).
_then_fields_should_be(
iv_index = 1
iv_name = '/src/ztest_rfc.fugr.xml'
iv_value = '?' ).
_then_fields_should_be(
iv_index = 2
iv_name = '/src/ztest_rfc rf.sush.xml'
iv_value = 'A' ).
ENDMETHOD.
METHOD parse_fields_german_umlauts.
DATA: lv_ae TYPE string,
lv_oe TYPE string,
lv_ue TYPE string,
lv_ae_oe_ue TYPE string.
lv_ae = gs_german_umlaut_as_char-lower_case_ae.
lv_oe = gs_german_umlaut_as_char-lower_case_oe.
lv_ue = gs_german_umlaut_as_char-lower_case_ue.
lv_ae_oe_ue = lv_ae && lv_oe && lv_ue.
_given_string_is( |committer_name=Christian G{ lv_ue }nter&|
&& |committer_email=guenne@googlemail.com&|
&& |comment={ lv_ae_oe_ue }&|
&& |body=Message body<<new>><<new>>with line break<<new>>and umlauts. { lv_ae_oe_ue }&|
&& |author_name=Gerd Schr{ lv_oe }der&|
&& |author_email=gerd@schroeder.com| ).
_when_fields_are_parsed_upper( ).
_then_fields_should_be( iv_index = 1
iv_name = `COMMITTER_NAME`
iv_value = |Christian G{ lv_ue }nter| ).
_then_fields_should_be( iv_index = 2
iv_name = `COMMITTER_EMAIL`
iv_value = `guenne@googlemail.com` ).
_then_fields_should_be( iv_index = 3
iv_name = `COMMENT`
iv_value = lv_ae_oe_ue ).
_then_fields_should_be( iv_index = 4
iv_name = `BODY`
iv_value = |Message body<<new>><<new>>with line break<<new>>and umlauts. { lv_ae_oe_ue }| ).
_then_fields_should_be( iv_index = 5
iv_name = `AUTHOR_NAME`
iv_value = |Gerd Schr{ lv_oe }der| ).
_then_fields_should_be( iv_index = 6
iv_name = `AUTHOR_EMAIL`
iv_value = `gerd@schroeder.com` ).
ENDMETHOD.
METHOD _given_string_is.
mv_given_parse_string = iv_string.
ENDMETHOD.
METHOD _when_fields_are_parsed_upper.
mt_parsed_fields = zcl_abapgit_gui_event=>parse_fields_upper_case_name( mv_given_parse_string ).
ENDMETHOD.
METHOD _when_fields_are_parsed.
mt_parsed_fields = zcl_abapgit_gui_event=>parse_fields( mv_given_parse_string ).
ENDMETHOD.
METHOD _then_fields_should_be.
FIELD-SYMBOLS: <ls_parsed_field> LIKE LINE OF mt_parsed_fields.
READ TABLE mt_parsed_fields ASSIGNING <ls_parsed_field> INDEX iv_index.
cl_abap_unit_assert=>assert_subrc(
exp = 0
msg = |No parsed field found at index { iv_index }| ).
cl_abap_unit_assert=>assert_equals(
act = <ls_parsed_field>-name
exp = iv_name
msg = |Name at index { iv_index } should be { iv_name }| ).
cl_abap_unit_assert=>assert_equals(
act = <ls_parsed_field>-value
exp = iv_value
msg = |Value at index { iv_index } should be { iv_value }| ).
ENDMETHOD.
METHOD _then_field_count_should_be.
cl_abap_unit_assert=>assert_equals(
act = lines( mt_parsed_fields )
exp = iv_count
msg = |Field count { lines( mt_parsed_fields ) } should be { iv_count }| ).
ENDMETHOD.
METHOD _hex_to_char.
DATA lo_conv TYPE REF TO cl_abap_conv_in_ce.
lo_conv = cl_abap_conv_in_ce=>create( ).
lo_conv->convert( EXPORTING input = iv_x IMPORTING data = rv_s ).
ENDMETHOD.
METHOD parse_fields_wrong_format.
_given_string_is( `some_query_string_without_param_structure` ).
_when_fields_are_parsed_upper( ).
_then_field_count_should_be( 0 ).
_given_string_is( `some_query_string_without_param_structure&a=b` ).
_when_fields_are_parsed_upper( ).
_then_field_count_should_be( 1 ).
_then_fields_should_be(
iv_index = 1
iv_name = 'A'
iv_value = 'b' ).
ENDMETHOD.
METHOD parse_post_form_data.
DATA lt_post_data TYPE zif_abapgit_html_viewer=>ty_post_data.
DATA lv_line LIKE LINE OF lt_post_data.
DATA lv_long_name LIKE LINE OF lt_post_data.
DATA lv_size TYPE i.
DESCRIBE FIELD lv_line LENGTH lv_size IN CHARACTER MODE.
lv_long_name = repeat(
val = 'x'
occ = lv_size - 4 ).
lv_line = 'a=b&' && lv_long_name.
APPEND lv_line TO lt_post_data.
APPEND '=y' TO lt_post_data.
mt_parsed_fields = zcl_abapgit_gui_event=>parse_post_form_data( lt_post_data ).
_then_field_count_should_be( 2 ).
_then_fields_should_be(
iv_index = 1
iv_name = 'a'
iv_value = 'b' ).
_then_fields_should_be(
iv_index = 2
iv_name = |{ lv_long_name }|
iv_value = 'y' ).
mt_parsed_fields = zcl_abapgit_gui_event=>parse_post_form_data(
it_post_data = lt_post_data
iv_upper_cased = abap_true ).
_then_field_count_should_be( 2 ).
_then_fields_should_be(
iv_index = 1
iv_name = 'A'
iv_value = 'b' ).
_then_fields_should_be(
iv_index = 2
iv_name = |{ to_upper( lv_long_name ) }|
iv_value = 'y' ).
ENDMETHOD.
METHOD parse_fields_webgui.
_given_string_is( `KEY=000000000019&PATH=%2fsrc%2f&FILENAME=%2fnsp%2ftest_ddls_bug2.ddls.asddls` ).
_when_fields_are_parsed( ).
_then_field_count_should_be( 3 ).
_then_fields_should_be(
iv_index = 1
iv_name = 'KEY'
iv_value = '000000000019' ).
_then_fields_should_be(
iv_index = 2
iv_name = 'PATH'
iv_value = '/src/' ).
_then_fields_should_be(
iv_index = 3
iv_name = 'FILENAME'
iv_value = '/nsp/test_ddls_bug2.ddls.asddls' ).
ENDMETHOD.
METHOD parse_fields_special_chars.
DATA lv_string TYPE string.
" URL encoded data
lv_string = `TEST=!"#$%25%26'()*+,-./09:;<%3d>?@AZ[\]^_``az{|}~¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿`.
_given_string_is( lv_string ).
_when_fields_are_parsed( ).
_then_field_count_should_be( 1 ).
_then_fields_should_be(
iv_index = 1
iv_name = 'TEST'
iv_value = `!"#$%&'()*+,-./09:;<=>?@AZ[\]^_``az{|}~¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿` ).
ENDMETHOD.
ENDCLASS.

View File

@ -4,18 +4,6 @@ CLASS zcl_abapgit_html_action_utils DEFINITION
PUBLIC SECTION.
CLASS-METHODS parse_post_form_data
IMPORTING
!it_post_data TYPE zif_abapgit_html_viewer=>ty_post_data
!iv_upper_cased TYPE abap_bool DEFAULT abap_false
RETURNING
VALUE(rt_fields) TYPE tihttpnvp .
CLASS-METHODS parse_fields
IMPORTING
!iv_string TYPE clike
!iv_upper_cased TYPE abap_bool DEFAULT abap_false
RETURNING
VALUE(rt_fields) TYPE tihttpnvp .
CLASS-METHODS jump_encode
IMPORTING
!iv_obj_type TYPE tadir-object
@ -40,7 +28,6 @@ CLASS zcl_abapgit_html_action_utils DEFINITION
!ig_object TYPE any
RETURNING
VALUE(rv_string) TYPE string .
CLASS-METHODS class_constructor .
CLASS-METHODS dbkey_encode
IMPORTING
!is_key TYPE zif_abapgit_persistence=>ty_content
@ -49,37 +36,17 @@ CLASS zcl_abapgit_html_action_utils DEFINITION
PROTECTED SECTION.
PRIVATE SECTION.
CLASS-DATA gv_non_breaking_space TYPE string .
CLASS-METHODS parse_fields_upper_case_name
IMPORTING
!iv_string TYPE clike
RETURNING
VALUE(rt_fields) TYPE tihttpnvp .
CLASS-METHODS translate_postdata
IMPORTING
!it_postdata TYPE zif_abapgit_html_viewer=>ty_post_data
RETURNING
VALUE(rv_string) TYPE string .
CLASS-METHODS field_keys_to_upper
CHANGING
!ct_fields TYPE tihttpnvp .
CLASS-METHODS add_field
IMPORTING
!iv_name TYPE string
!ig_field TYPE any
CHANGING
!ct_field TYPE tihttpnvp .
CLASS-METHODS unescape
IMPORTING
!iv_string TYPE string
RETURNING
VALUE(rv_string) TYPE string .
ENDCLASS.
CLASS ZCL_ABAPGIT_HTML_ACTION_UTILS IMPLEMENTATION.
CLASS zcl_abapgit_html_action_utils IMPLEMENTATION.
METHOD add_field.
@ -106,19 +73,6 @@ CLASS ZCL_ABAPGIT_HTML_ACTION_UTILS IMPLEMENTATION.
ENDMETHOD.
METHOD class_constructor.
CONSTANTS lc_nbsp TYPE xstring VALUE 'C2A0'. " &nbsp;
TRY.
gv_non_breaking_space = zcl_abapgit_convert=>xstring_to_string_utf8( lc_nbsp ).
CATCH zcx_abapgit_exception.
ASSERT 0 = 1.
ENDTRY.
ENDMETHOD.
METHOD dbkey_encode.
DATA: lt_fields TYPE tihttpnvp.
@ -143,17 +97,6 @@ CLASS ZCL_ABAPGIT_HTML_ACTION_UTILS IMPLEMENTATION.
ENDMETHOD.
METHOD field_keys_to_upper.
FIELD-SYMBOLS <ls_field> LIKE LINE OF ct_fields.
LOOP AT ct_fields ASSIGNING <ls_field>.
<ls_field>-name = to_upper( <ls_field>-name ).
ENDLOOP.
ENDMETHOD.
METHOD file_encode.
DATA: lt_fields TYPE tihttpnvp.
@ -207,115 +150,4 @@ CLASS ZCL_ABAPGIT_HTML_ACTION_UTILS IMPLEMENTATION.
ENDMETHOD.
METHOD parse_fields.
DATA:
lt_substrings TYPE string_table,
ls_field LIKE LINE OF rt_fields.
FIELD-SYMBOLS <lv_substring> LIKE LINE OF lt_substrings.
SPLIT iv_string AT '&' INTO TABLE lt_substrings.
LOOP AT lt_substrings ASSIGNING <lv_substring>.
CLEAR ls_field.
" On attempt to change unescaping -> run unit tests to check !
" Unescape name and value separately
ls_field-name = unescape( substring_before(
val = <lv_substring>
sub = '=' ) ).
ls_field-value = unescape( substring_after(
val = <lv_substring>
sub = '=' ) ).
IF ls_field IS INITIAL. " Not a field with proper structure
CONTINUE.
ENDIF.
APPEND ls_field TO rt_fields.
ENDLOOP.
IF iv_upper_cased = abap_true.
field_keys_to_upper( CHANGING ct_fields = rt_fields ).
ENDIF.
ENDMETHOD.
METHOD parse_fields_upper_case_name.
rt_fields = parse_fields(
iv_string = iv_string
iv_upper_cased = abap_true ).
ENDMETHOD.
METHOD parse_post_form_data.
DATA lv_serialized_post_data TYPE string.
lv_serialized_post_data = translate_postdata( it_post_data ).
IF iv_upper_cased = abap_true.
rt_fields = parse_fields_upper_case_name( lv_serialized_post_data ).
ELSE.
rt_fields = parse_fields( lv_serialized_post_data ).
ENDIF.
ENDMETHOD.
METHOD translate_postdata.
DATA: lt_post_data TYPE zif_abapgit_html_viewer=>ty_post_data,
ls_last_line LIKE LINE OF it_postdata,
lv_last_line_index TYPE i.
IF it_postdata IS INITIAL.
RETURN. "Nothing to do
ENDIF.
lt_post_data = it_postdata.
"Save the last line for separate merge, because we don't need its trailing spaces
WHILE ls_last_line IS INITIAL.
lv_last_line_index = lines( lt_post_data ).
READ TABLE lt_post_data INTO ls_last_line INDEX lv_last_line_index.
"Avoid trailing null values (see isssue #4832)
"todo, keep until SAP GUI for Java is fixed (remove on 2022-12-31)
ls_last_line = replace( val = ls_last_line
sub = zcl_abapgit_git_utils=>get_null( )
with = space
occ = 0 ).
DELETE lt_post_data INDEX lv_last_line_index.
ENDWHILE.
CONCATENATE LINES OF lt_post_data INTO rv_string
IN CHARACTER MODE RESPECTING BLANKS.
CONCATENATE rv_string ls_last_line INTO rv_string
IN CHARACTER MODE.
ENDMETHOD.
METHOD unescape.
* do not use cl_http_utility as it does strange things with the encoding
rv_string = iv_string.
* todo, more to be added here
REPLACE ALL OCCURRENCES OF '%3A' IN rv_string WITH ':' IGNORING CASE.
REPLACE ALL OCCURRENCES OF '%3F' IN rv_string WITH '?' IGNORING CASE.
REPLACE ALL OCCURRENCES OF '%3D' IN rv_string WITH '=' IGNORING CASE.
REPLACE ALL OCCURRENCES OF '%2F' IN rv_string WITH '/' IGNORING CASE.
REPLACE ALL OCCURRENCES OF '%25' IN rv_string WITH '%' IGNORING CASE.
REPLACE ALL OCCURRENCES OF '%26' IN rv_string WITH '&' IGNORING CASE.
REPLACE ALL OCCURRENCES OF gv_non_breaking_space IN rv_string WITH ` `.
ENDMETHOD.
ENDCLASS.

View File

@ -1,363 +0,0 @@
CLASS ltcl_html_action_utils DEFINITION FOR TESTING RISK LEVEL HARMLESS
DURATION SHORT FINAL.
PUBLIC SECTION.
CLASS-METHODS class_constructor.
METHODS parse_fields_simple_case FOR TESTING.
METHODS parse_fields_advanced_case FOR TESTING.
METHODS parse_fields_unescape FOR TESTING.
METHODS parse_fields_unescape_nbsp FOR TESTING.
METHODS parse_fields_german_umlauts FOR TESTING.
METHODS parse_fields_wrong_format FOR TESTING.
METHODS parse_post_form_data FOR TESTING.
METHODS parse_fields_webgui FOR TESTING.
METHODS parse_fields_special_chars FOR TESTING.
PRIVATE SECTION.
CONSTANTS: BEGIN OF c_german_umlaut_as_hex,
lower_case_ae TYPE xstring VALUE 'C3A4',
lower_case_oe TYPE xstring VALUE 'C3B6',
lower_case_ue TYPE xstring VALUE 'C3BC',
END OF c_german_umlaut_as_hex.
CLASS-DATA: BEGIN OF gs_german_umlaut_as_char,
lower_case_ae TYPE string,
lower_case_oe TYPE string,
lower_case_ue TYPE string,
END OF gs_german_umlaut_as_char.
DATA mv_given_parse_string TYPE string.
DATA mt_parsed_fields TYPE tihttpnvp.
METHODS _given_string_is
IMPORTING
iv_string TYPE string.
METHODS _when_fields_are_parsed_upper.
METHODS _when_fields_are_parsed.
METHODS _then_fields_should_be
IMPORTING
iv_index TYPE i
iv_name TYPE string
iv_value TYPE string.
METHODS _then_field_count_should_be
IMPORTING
iv_count TYPE i.
CLASS-METHODS _hex_to_char
IMPORTING
iv_x TYPE xstring
RETURNING
VALUE(rv_s) TYPE string.
ENDCLASS.
CLASS zcl_abapgit_html_action_utils DEFINITION LOCAL FRIENDS ltcl_html_action_utils.
CLASS ltcl_html_action_utils IMPLEMENTATION.
METHOD class_constructor.
gs_german_umlaut_as_char-lower_case_ae = _hex_to_char( c_german_umlaut_as_hex-lower_case_ae ).
gs_german_umlaut_as_char-lower_case_oe = _hex_to_char( c_german_umlaut_as_hex-lower_case_oe ).
gs_german_umlaut_as_char-lower_case_ue = _hex_to_char( c_german_umlaut_as_hex-lower_case_ue ).
ENDMETHOD.
METHOD parse_fields_simple_case.
_given_string_is( `committer_name=Gustav Gans` ).
_when_fields_are_parsed_upper( ).
_then_fields_should_be( iv_index = 1
iv_name = `COMMITTER_NAME`
iv_value = `Gustav Gans` ).
ENDMETHOD.
METHOD parse_fields_advanced_case.
_given_string_is( `committer_name=Albert Schweitzer&`
&& `committer_email=albert.schweitzer@googlemail.com&`
&& `comment=dummy comment&`
&& `body=Message body<<new>><<new>>with line break<<new>>&`
&& `author_name=Karl Klammer&`
&& `author_email=karl@klammer.com` ).
_when_fields_are_parsed_upper( ).
_then_fields_should_be( iv_index = 1
iv_name = `COMMITTER_NAME`
iv_value = `Albert Schweitzer` ).
_then_fields_should_be( iv_index = 2
iv_name = `COMMITTER_EMAIL`
iv_value = `albert.schweitzer@googlemail.com` ).
_then_fields_should_be( iv_index = 3
iv_name = `COMMENT`
iv_value = `dummy comment` ).
_then_fields_should_be( iv_index = 4
iv_name = `BODY`
iv_value = `Message body<<new>><<new>>with line break<<new>>` ).
_then_fields_should_be( iv_index = 5
iv_name = `AUTHOR_NAME`
iv_value = `Karl Klammer` ).
_then_fields_should_be( iv_index = 6
iv_name = `AUTHOR_EMAIL`
iv_value = `karl@klammer.com` ).
ENDMETHOD.
METHOD parse_fields_unescape.
" file status = '?', used in staging page
_given_string_is( '/SRC/ZFOOBAR.PROG.ABAP=%3F' ).
_when_fields_are_parsed_upper( ).
_then_field_count_should_be( 1 ).
_then_fields_should_be(
iv_index = 1
iv_name = '/SRC/ZFOOBAR.PROG.ABAP'
iv_value = '?' ).
ENDMETHOD.
METHOD parse_fields_unescape_nbsp.
" non-breaking space (&nbsp;)
_given_string_is( '/src/ztest_rfc.fugr.xml=%3F&/src/ztest_rfc'
&& zcl_abapgit_html_action_utils=>gv_non_breaking_space
&& zcl_abapgit_html_action_utils=>gv_non_breaking_space
&& zcl_abapgit_html_action_utils=>gv_non_breaking_space
&& 'rf.sush.xml=A' ).
_when_fields_are_parsed( ).
_then_field_count_should_be( 2 ).
_then_fields_should_be(
iv_index = 1
iv_name = '/src/ztest_rfc.fugr.xml'
iv_value = '?' ).
_then_fields_should_be(
iv_index = 2
iv_name = '/src/ztest_rfc rf.sush.xml'
iv_value = 'A' ).
ENDMETHOD.
METHOD parse_fields_german_umlauts.
DATA: lv_ae TYPE string,
lv_oe TYPE string,
lv_ue TYPE string,
lv_ae_oe_ue TYPE string.
lv_ae = gs_german_umlaut_as_char-lower_case_ae.
lv_oe = gs_german_umlaut_as_char-lower_case_oe.
lv_ue = gs_german_umlaut_as_char-lower_case_ue.
lv_ae_oe_ue = lv_ae && lv_oe && lv_ue.
_given_string_is( |committer_name=Christian G{ lv_ue }nter&|
&& |committer_email=guenne@googlemail.com&|
&& |comment={ lv_ae_oe_ue }&|
&& |body=Message body<<new>><<new>>with line break<<new>>and umlauts. { lv_ae_oe_ue }&|
&& |author_name=Gerd Schr{ lv_oe }der&|
&& |author_email=gerd@schroeder.com| ).
_when_fields_are_parsed_upper( ).
_then_fields_should_be( iv_index = 1
iv_name = `COMMITTER_NAME`
iv_value = |Christian G{ lv_ue }nter| ).
_then_fields_should_be( iv_index = 2
iv_name = `COMMITTER_EMAIL`
iv_value = `guenne@googlemail.com` ).
_then_fields_should_be( iv_index = 3
iv_name = `COMMENT`
iv_value = lv_ae_oe_ue ).
_then_fields_should_be( iv_index = 4
iv_name = `BODY`
iv_value = |Message body<<new>><<new>>with line break<<new>>and umlauts. { lv_ae_oe_ue }| ).
_then_fields_should_be( iv_index = 5
iv_name = `AUTHOR_NAME`
iv_value = |Gerd Schr{ lv_oe }der| ).
_then_fields_should_be( iv_index = 6
iv_name = `AUTHOR_EMAIL`
iv_value = `gerd@schroeder.com` ).
ENDMETHOD.
METHOD _given_string_is.
mv_given_parse_string = iv_string.
ENDMETHOD.
METHOD _when_fields_are_parsed_upper.
mt_parsed_fields = zcl_abapgit_html_action_utils=>parse_fields_upper_case_name( mv_given_parse_string ).
ENDMETHOD.
METHOD _when_fields_are_parsed.
mt_parsed_fields = zcl_abapgit_html_action_utils=>parse_fields( mv_given_parse_string ).
ENDMETHOD.
METHOD _then_fields_should_be.
FIELD-SYMBOLS: <ls_parsed_field> LIKE LINE OF mt_parsed_fields.
READ TABLE mt_parsed_fields ASSIGNING <ls_parsed_field> INDEX iv_index.
cl_abap_unit_assert=>assert_subrc(
exp = 0
msg = |No parsed field found at index { iv_index }| ).
cl_abap_unit_assert=>assert_equals(
act = <ls_parsed_field>-name
exp = iv_name
msg = |Name at index { iv_index } should be { iv_name }| ).
cl_abap_unit_assert=>assert_equals(
act = <ls_parsed_field>-value
exp = iv_value
msg = |Value at index { iv_index } should be { iv_value }| ).
ENDMETHOD.
METHOD _then_field_count_should_be.
cl_abap_unit_assert=>assert_equals(
act = lines( mt_parsed_fields )
exp = iv_count
msg = |Field count { lines( mt_parsed_fields ) } should be { iv_count }| ).
ENDMETHOD.
METHOD _hex_to_char.
DATA lo_conv TYPE REF TO cl_abap_conv_in_ce.
lo_conv = cl_abap_conv_in_ce=>create( ).
lo_conv->convert( EXPORTING input = iv_x IMPORTING data = rv_s ).
ENDMETHOD.
METHOD parse_fields_wrong_format.
_given_string_is( `some_query_string_without_param_structure` ).
_when_fields_are_parsed_upper( ).
_then_field_count_should_be( 0 ).
_given_string_is( `some_query_string_without_param_structure&a=b` ).
_when_fields_are_parsed_upper( ).
_then_field_count_should_be( 1 ).
_then_fields_should_be(
iv_index = 1
iv_name = 'A'
iv_value = 'b' ).
ENDMETHOD.
METHOD parse_post_form_data.
DATA lt_post_data TYPE zif_abapgit_html_viewer=>ty_post_data.
DATA lv_line LIKE LINE OF lt_post_data.
DATA lv_long_name LIKE LINE OF lt_post_data.
DATA lv_size TYPE i.
DESCRIBE FIELD lv_line LENGTH lv_size IN CHARACTER MODE.
lv_long_name = repeat(
val = 'x'
occ = lv_size - 4 ).
lv_line = 'a=b&' && lv_long_name.
APPEND lv_line TO lt_post_data.
APPEND '=y' TO lt_post_data.
mt_parsed_fields = zcl_abapgit_html_action_utils=>parse_post_form_data( lt_post_data ).
_then_field_count_should_be( 2 ).
_then_fields_should_be(
iv_index = 1
iv_name = 'a'
iv_value = 'b' ).
_then_fields_should_be(
iv_index = 2
iv_name = |{ lv_long_name }|
iv_value = 'y' ).
mt_parsed_fields = zcl_abapgit_html_action_utils=>parse_post_form_data(
it_post_data = lt_post_data
iv_upper_cased = abap_true ).
_then_field_count_should_be( 2 ).
_then_fields_should_be(
iv_index = 1
iv_name = 'A'
iv_value = 'b' ).
_then_fields_should_be(
iv_index = 2
iv_name = |{ to_upper( lv_long_name ) }|
iv_value = 'y' ).
ENDMETHOD.
METHOD parse_fields_webgui.
_given_string_is( `KEY=000000000019&PATH=%2fsrc%2f&FILENAME=%2fnsp%2ftest_ddls_bug2.ddls.asddls` ).
_when_fields_are_parsed( ).
_then_field_count_should_be( 3 ).
_then_fields_should_be(
iv_index = 1
iv_name = 'KEY'
iv_value = '000000000019' ).
_then_fields_should_be(
iv_index = 2
iv_name = 'PATH'
iv_value = '/src/' ).
_then_fields_should_be(
iv_index = 3
iv_name = 'FILENAME'
iv_value = '/nsp/test_ddls_bug2.ddls.asddls' ).
ENDMETHOD.
METHOD parse_fields_special_chars.
DATA lv_string TYPE string.
" URL encoded data
lv_string = `TEST=!"#$%25%26'()*+,-./09:;<%3d>?@AZ[\]^_``az{|}~¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿`.
_given_string_is( lv_string ).
_when_fields_are_parsed( ).
_then_field_count_should_be( 1 ).
_then_fields_should_be(
iv_index = 1
iv_name = 'TEST'
iv_value = `!"#$%&'()*+,-./09:;<=>?@AZ[\]^_``az{|}~¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿` ).
ENDMETHOD.
ENDCLASS.

View File

@ -10,7 +10,6 @@
<CLSCCINCL>X</CLSCCINCL>
<FIXPT>X</FIXPT>
<UNICODE>X</UNICODE>
<WITH_UNIT_TESTS>X</WITH_UNIT_TESTS>
</VSEOCLASS>
</asx:values>
</asx:abap>