Adjust diff algorithm (#5251)

* Adjust diff algorithm

This implements a workaround for the kernel issue when determining diffs (see https://github.com/abapGit/abapGit/issues/4395 for background). 

Here's an example of the change.

Before:

After:

* Lint + check

* Add test

* Ignore new tests

Co-authored-by: Lars Hvam <larshp@hotmail.com>
This commit is contained in:
Marc Bernard 2022-01-11 07:22:46 +01:00 committed by GitHub
parent e74076c0bb
commit 269c7cb1e6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 201 additions and 3 deletions

View File

@ -78,6 +78,7 @@ CLASS zcl_abapgit_diff DEFINITION
RETURNING
VALUE(rt_diff) TYPE zif_abapgit_definitions=>ty_diffs_tt.
METHODS calculate_stats.
METHODS adjust_diff.
ENDCLASS.
@ -85,6 +86,85 @@ ENDCLASS.
CLASS zcl_abapgit_diff IMPLEMENTATION.
METHOD adjust_diff.
" ABAP kernel diff traverses files from bottom up which leads to odd display of diffs
" SAP won't adjust this kernel service so we will do it here
" https://github.com/abapGit/abapGit/issues/4395
TYPES:
BEGIN OF ty_diff_block,
start TYPE i,
len TYPE i,
END OF ty_diff_block.
DATA:
lv_block_begin TYPE i,
lv_block_end TYPE i,
ls_diff_block TYPE ty_diff_block,
lt_diff_block TYPE STANDARD TABLE OF ty_diff_block WITH DEFAULT KEY.
FIELD-SYMBOLS:
<ls_diff> LIKE LINE OF mt_diff,
<ls_diff_begin> LIKE LINE OF mt_diff,
<ls_diff_end> LIKE LINE OF mt_diff.
" Determine start and length of diff blocks
LOOP AT mt_diff ASSIGNING <ls_diff>.
IF <ls_diff>-result = zif_abapgit_definitions=>c_diff-insert OR
<ls_diff>-result = zif_abapgit_definitions=>c_diff-delete.
IF ls_diff_block IS INITIAL.
ls_diff_block-start = sy-tabix.
ENDIF.
ls_diff_block-len = ls_diff_block-len + 1.
ELSEIF ls_diff_block-start IS NOT INITIAL.
APPEND ls_diff_block TO lt_diff_block.
CLEAR ls_diff_block.
ENDIF.
ENDLOOP.
" For each diff block, check if beginning is same as end of block
" If yes, move diff block down
LOOP AT lt_diff_block INTO ls_diff_block.
DO ls_diff_block-len TIMES.
lv_block_begin = ls_diff_block-start + sy-index - 1.
READ TABLE mt_diff ASSIGNING <ls_diff_begin> INDEX lv_block_begin.
IF sy-subrc <> 0.
EXIT.
ENDIF.
lv_block_end = ls_diff_block-start + ls_diff_block-len + sy-index - 1.
READ TABLE mt_diff ASSIGNING <ls_diff_end> INDEX lv_block_end.
IF sy-subrc <> 0.
EXIT.
ENDIF.
CASE <ls_diff_begin>-result.
WHEN zif_abapgit_definitions=>c_diff-insert.
IF <ls_diff_begin>-new = <ls_diff_end>-new.
<ls_diff_begin>-old_num = <ls_diff_end>-old_num.
<ls_diff_begin>-old = <ls_diff_end>-old.
<ls_diff_end>-result = <ls_diff_begin>-result.
CLEAR: <ls_diff_begin>-result, <ls_diff_end>-old_num, <ls_diff_end>-old.
ELSE.
EXIT.
ENDIF.
WHEN zif_abapgit_definitions=>c_diff-delete.
IF <ls_diff_begin>-old = <ls_diff_end>-old.
<ls_diff_begin>-new_num = <ls_diff_end>-new_num.
<ls_diff_begin>-new = <ls_diff_end>-new.
<ls_diff_end>-result = <ls_diff_begin>-result.
CLEAR: <ls_diff_begin>-result, <ls_diff_end>-new_num, <ls_diff_end>-new.
ELSE.
EXIT.
ENDIF.
WHEN OTHERS.
EXIT.
ENDCASE.
ENDDO.
ENDLOOP.
ENDMETHOD.
METHOD calculate_stats.
FIELD-SYMBOLS: <ls_diff> LIKE LINE OF mt_diff.
@ -197,6 +277,8 @@ CLASS zcl_abapgit_diff IMPLEMENTATION.
mt_diff = compute_and_render( it_new = lt_new
it_old = lt_old ).
adjust_diff( ).
calculate_stats( ).
map_beacons( ).
shortlist( ).

View File

@ -15,7 +15,9 @@ CLASS ltcl_diff DEFINITION FOR TESTING
iv_new TYPE zif_abapgit_definitions=>ty_diff-new
iv_result TYPE zif_abapgit_definitions=>ty_diff-result
iv_old_num TYPE zif_abapgit_definitions=>ty_diff-old_num
iv_old TYPE zif_abapgit_definitions=>ty_diff-old.
iv_old TYPE zif_abapgit_definitions=>ty_diff-old
iv_beacon TYPE zif_abapgit_definitions=>ty_diff-beacon
DEFAULT zcl_abapgit_diff=>co_starting_beacon.
METHODS: setup.
@ -36,7 +38,9 @@ CLASS ltcl_diff DEFINITION FOR TESTING
diff08 FOR TESTING,
diff09 FOR TESTING,
diff10 FOR TESTING,
diff11 FOR TESTING.
diff11 FOR TESTING,
diff12 FOR TESTING,
diff13 FOR TESTING.
ENDCLASS.
@ -65,7 +69,7 @@ CLASS ltcl_diff IMPLEMENTATION.
ls_expected-result = iv_result.
ls_expected-old_num = iv_old_num.
ls_expected-old = iv_old.
ls_expected-beacon = zcl_abapgit_diff=>co_starting_beacon.
ls_expected-beacon = iv_beacon.
APPEND ls_expected TO mt_expected.
ENDMETHOD.
@ -394,4 +398,114 @@ CLASS ltcl_diff IMPLEMENTATION.
ENDMETHOD.
METHOD diff12.
" adjusted diffs for insert (workaround for kernel issue)
add_new( iv_new = `REPORT zprog_diff.` ).
add_new( iv_new = `*` ).
add_new( iv_new = `FORM t_1.` ).
add_new( iv_new = `ENDFORM.` ).
add_new( iv_new = `FORM t_2.` ).
add_new( iv_new = `ENDFORM.` ).
add_old( iv_old = `REPORT zprog_diff.` ).
add_old( iv_old = `FORM t_1.` ).
add_old( iv_old = `ENDFORM.` ).
add_expected( iv_new_num = ' 1'
iv_new = `REPORT zprog_diff.`
iv_result = '' " no diff!
iv_old_num = ' 1'
iv_old = `REPORT zprog_diff.`
iv_beacon = 1 ).
add_expected( iv_new_num = ' 2'
iv_new = `*`
iv_result = 'I'
iv_old_num = ' '
iv_old = ``
iv_beacon = 1 ).
add_expected( iv_new_num = ' 3'
iv_new = `FORM t_1.`
iv_result = '' " no diff!
iv_old_num = ' 2'
iv_old = `FORM t_1.`
iv_beacon = 2 ).
add_expected( iv_new_num = ' 4'
iv_new = `ENDFORM.`
iv_result = '' " no diff!
iv_old_num = ' 3'
iv_old = `ENDFORM.`
iv_beacon = 2 ).
add_expected( iv_new_num = ' 5'
iv_new = `FORM t_2.`
iv_result = 'I'
iv_old_num = ' '
iv_old = ``
iv_beacon = 3 ).
add_expected( iv_new_num = ' 6'
iv_new = `ENDFORM.`
iv_result = 'I'
iv_old_num = ' '
iv_old = ``
iv_beacon = 3 ).
test( ).
ENDMETHOD.
METHOD diff13.
" adjusted diffs for delete (workaround for kernel issue)
add_old( iv_old = `REPORT zprog_diff.` ).
add_old( iv_old = `*` ).
add_old( iv_old = `FORM t_1.` ).
add_old( iv_old = `ENDFORM.` ).
add_old( iv_old = `FORM t_2.` ).
add_old( iv_old = `ENDFORM.` ).
add_new( iv_new = `REPORT zprog_diff.` ).
add_new( iv_new = `FORM t_1.` ).
add_new( iv_new = `ENDFORM.` ).
add_expected( iv_old_num = ' 1'
iv_old = `REPORT zprog_diff.`
iv_result = '' " no diff!
iv_new_num = ' 1'
iv_new = `REPORT zprog_diff.`
iv_beacon = 1 ).
add_expected( iv_old_num = ' 2'
iv_old = `*`
iv_result = 'D'
iv_new_num = ' '
iv_new = ``
iv_beacon = 1 ).
add_expected( iv_old_num = ' 3'
iv_old = `FORM t_1.`
iv_result = '' " no diff!
iv_new_num = ' 2'
iv_new = `FORM t_1.`
iv_beacon = 2 ).
add_expected( iv_old_num = ' 4'
iv_old = `ENDFORM.`
iv_result = '' " no diff!
iv_new_num = ' 3'
iv_new = `ENDFORM.`
iv_beacon = 2 ).
add_expected( iv_old_num = ' 5'
iv_old = `FORM t_2.`
iv_result = 'D'
iv_new_num = ' '
iv_new = ``
iv_beacon = 2 ).
add_expected( iv_old_num = ' 6'
iv_old = `ENDFORM.`
iv_result = 'D'
iv_new_num = ' '
iv_new = ``
iv_beacon = 2 ).
test( ).
ENDMETHOD.
ENDCLASS.

View File

@ -239,6 +239,8 @@
{"object": "ZCL_ABAPGIT_DIFF", "class": "ltcl_diff", "method": "diff09", "note": "fm RS_CMP_COMPUTE_DELTA + Void type: RSWSOURCET"},
{"object": "ZCL_ABAPGIT_DIFF", "class": "ltcl_diff", "method": "diff10", "note": "fm RS_CMP_COMPUTE_DELTA + Void type: RSWSOURCET"},
{"object": "ZCL_ABAPGIT_DIFF", "class": "ltcl_diff", "method": "diff11", "note": "fm RS_CMP_COMPUTE_DELTA + Void type: RSWSOURCET"},
{"object": "ZCL_ABAPGIT_DIFF", "class": "ltcl_diff", "method": "diff12", "note": "fm RS_CMP_COMPUTE_DELTA + Void type: RSWSOURCET"},
{"object": "ZCL_ABAPGIT_DIFF", "class": "ltcl_diff", "method": "diff13", "note": "fm RS_CMP_COMPUTE_DELTA + Void type: RSWSOURCET"},
{"object": "ZCL_ABAPGIT_USER_RECORD", "class": "ltcl_user_record", "method": "test_invalid_user", "note": "Void type: BAPIADDR3"},
{"object": "ZCL_ABAPGIT_SERVICES_BASIS", "class": "ltcl_create_package", "method": "raise_error_if_package_exists", "note": "Void type: SCOMPKDTLN"},
{"object": "ZCL_ABAPGIT_SERVICES_BASIS", "class": "ltcl_create_package", "method": "package_given_in_popup", "note": "Void type: SCOMPKDTLN"},