diff --git a/src/checks/y_check_unit_test_cut_name.clas.abap b/src/checks/y_check_unit_test_cut_name.clas.abap new file mode 100644 index 00000000..3d6d22f4 --- /dev/null +++ b/src/checks/y_check_unit_test_cut_name.clas.abap @@ -0,0 +1,110 @@ +CLASS y_check_unit_test_cut_name DEFINITION PUBLIC INHERITING FROM y_check_base CREATE PUBLIC . + PUBLIC SECTION. + METHODS constructor. + + PROTECTED SECTION. + METHODS inspect_tokens REDEFINITION. + + PRIVATE SECTION. + METHODS is_for_testing IMPORTING statement TYPE sstmnt + RETURNING VALUE(result) TYPE abap_bool. + + METHODS has_cut IMPORTING structure TYPE sstruc + RETURNING VALUE(result) TYPE abap_bool. + +ENDCLASS. + + +CLASS y_check_unit_test_cut_name IMPLEMENTATION. + + + METHOD constructor. + super->constructor( ). + + settings-pseudo_comment = '"#EC UT_CUT' ##NO_TEXT. + settings-disable_threshold_selection = abap_true. + settings-disable_on_testcode_selection = abap_true. + settings-disable_on_prodcode_selection = abap_true. + settings-apply_on_productive_code = abap_false. + settings-apply_on_test_code = abap_true. + settings-threshold = 0. + settings-documentation = |{ c_docs_path-checks }unit_test_cut_name.md|. + relevant_statement_types = VALUE #( ( scan_struc_stmnt_type-method ) ). + relevant_structure_types = VALUE #( ). + + set_check_message( 'Consider naming the class under test to `CUT`' ). + ENDMETHOD. + + + METHOD inspect_tokens. + CHECK get_token_abs( statement-from ) = 'METHOD'. + + IF is_for_testing( statement ) = abap_false + OR has_cut( structure ) = abap_true. + RETURN. + ENDIF. + + DATA(check_configuration) = detect_check_configuration( statement ). + + IF check_configuration IS INITIAL. + RETURN. + ENDIF. + + raise_error( statement_level = statement-level + statement_index = index + statement_from = statement-from + error_priority = check_configuration-prio ). + ENDMETHOD. + + + METHOD is_for_testing. + TRY. + DATA(method_name) = ref_scan_manager->tokens[ statement-from + 1 ]-str. + DATA(method) = ref_scan_manager->structures[ statement-struc ]. + DATA(class_implementation) = ref_scan_manager->structures[ method-back ]. + DATA(class_definition) = ref_scan_manager->structures[ class_implementation-back ]. + CATCH cx_sy_itab_line_not_found. + RETURN. + ENDTRY. + + LOOP AT ref_scan_manager->statements ASSIGNING FIELD-SYMBOL() + FROM class_definition-stmnt_from TO class_definition-stmnt_to. + + IF get_token_abs( -from ) <> 'METHODS' + AND get_token_abs( -from ) <> 'CLASS-METHODS'. + CONTINUE. + ENDIF. + + DATA(statement_abs) = get_statement_abs( ). + + IF statement_abs NP |*{ method_name }*|. + CONTINUE. + ENDIF. + + result = xsdbool( statement_abs CP '*FOR TESTING*' ). + RETURN. + + ENDLOOP. + ENDMETHOD. + + + METHOD has_cut. + LOOP AT ref_scan_manager->statements ASSIGNING FIELD-SYMBOL() + FROM structure-stmnt_from TO structure-stmnt_to + WHERE type <> scan_stmnt_type-comment + AND type <> scan_stmnt_type-pragma. + DATA(statement_abs) = get_statement_abs( ). + + result = xsdbool( statement_abs CP '* CUT *' + OR statement_abs CP '*_CUT *' + OR statement_abs CP '* CLASS_UNDER_TEST *' + OR statement_abs CP '*_CLASS_UNDER_TEST *' ). + + IF result = abap_true. + RETURN. + ENDIF. + ENDLOOP. + ENDMETHOD. + + +ENDCLASS. diff --git a/src/checks/y_check_unit_test_cut_name.clas.testclasses.abap b/src/checks/y_check_unit_test_cut_name.clas.testclasses.abap new file mode 100644 index 00000000..a9de34f3 --- /dev/null +++ b/src/checks/y_check_unit_test_cut_name.clas.testclasses.abap @@ -0,0 +1,206 @@ +CLASS ltc_cut DEFINITION INHERITING FROM y_unit_test_base FOR TESTING RISK LEVEL HARMLESS DURATION SHORT. + PROTECTED SECTION. + METHODS get_cut REDEFINITION. + METHODS get_code_with_issue REDEFINITION. + METHODS get_code_without_issue REDEFINITION. + METHODS get_code_with_exemption REDEFINITION. +ENDCLASS. + +CLASS ltc_cut IMPLEMENTATION. + + METHOD get_cut. + result ?= NEW y_check_unit_test_cut_name( ). + ENDMETHOD. + + METHOD get_code_with_issue. + result = VALUE #( + ( ' REPORT y_example. ' ) + + ( ' CLASS y_example DEFINITION FOR TESTING RISK LEVEL HARMLESS DURATION SHORT. ' ) + ( ' PUBLIC SECTION. ' ) + ( ' METHODS example FOR TESTING. ' ) + ( ' ENDCLASS. ' ) + + ( ' CLASS y_example IMPLEMENTATION. ' ) + ( ' METHOD example. ' ) + ( ' " given ' ) + ( ' DATA demo_failures TYPE REF TO y_demo_failures. ' ) + ( ' " when ' ) + ( ' demo_failures = NEW #( ). ' ) + ( ' " then ' ) + ( ' cl_abap_unit_assert=>assert_bound( demo_failures ). ' ) + ( ' ENDMETHOD. ' ) + ( ' ENDCLASS. ' ) + ). + ENDMETHOD. + + METHOD get_code_without_issue. + result = VALUE #( + ( ' REPORT y_example. ' ) + + ( ' CLASS y_example DEFINITION FOR TESTING RISK LEVEL HARMLESS DURATION SHORT. ' ) + ( ' PUBLIC SECTION. ' ) + ( ' METHODS example FOR TESTING. ' ) + ( ' ENDCLASS. ' ) + + ( ' CLASS y_example IMPLEMENTATION. ' ) + ( ' METHOD example. ' ) + ( ' " given ' ) + ( ' DATA cut TYPE REF TO y_demo_failures. ' ) + ( ' " when ' ) + ( ' cut = NEW #( ). ' ) + ( ' " then ' ) + ( ' cl_abap_unit_assert=>assert_bound( cut ). ' ) + ( ' ENDMETHOD. ' ) + ( ' ENDCLASS. ' ) + ). + ENDMETHOD. + + METHOD get_code_with_exemption. + result = VALUE #( + ( ' REPORT y_example. ' ) + + ( ' CLASS y_example DEFINITION FOR TESTING RISK LEVEL HARMLESS DURATION SHORT. ' ) + ( ' PUBLIC SECTION. ' ) + ( ' METHODS example FOR TESTING. ' ) + ( ' ENDCLASS. ' ) + + ( ' CLASS y_example IMPLEMENTATION. ' ) + ( ' METHOD example. "#EC UT_CUT ' ) + ( ' " given ' ) + ( ' DATA demo_failures TYPE REF TO y_demo_failures. ' ) + ( ' " when ' ) + ( ' demo_failures = NEW #( ). ' ) + ( ' " then ' ) + ( ' cl_abap_unit_assert=>assert_bound( demo_failures ). ' ) + ( ' ENDMETHOD. ' ) + ( ' ENDCLASS. ' ) + ). + ENDMETHOD. + +ENDCLASS. + + +CLASS ltc_class_under_test DEFINITION INHERITING FROM ltc_cut FOR TESTING RISK LEVEL HARMLESS DURATION SHORT. + PROTECTED SECTION. + METHODS get_code_without_issue REDEFINITION. +ENDCLASS. + +CLASS ltc_class_under_test IMPLEMENTATION. + + METHOD get_code_without_issue. + result = VALUE #( + ( ' REPORT y_example. ' ) + + ( ' CLASS y_example DEFINITION FOR TESTING RISK LEVEL HARMLESS DURATION SHORT. ' ) + ( ' PUBLIC SECTION. ' ) + ( ' METHODS example FOR TESTING RAISING cx_static_check. ' ) + ( ' ENDCLASS. ' ) + + ( ' CLASS y_example IMPLEMENTATION. ' ) + ( ' METHOD example. ' ) + ( ' " given ' ) + ( ' DATA class_under_test TYPE REF TO y_demo_failures. ' ) + ( ' " when ' ) + ( ' class_under_test = NEW #( ). ' ) + ( ' " then ' ) + ( ' cl_abap_unit_assert=>assert_bound( class_under_test ). ' ) + ( ' ENDMETHOD. ' ) + ( ' ENDCLASS. ' ) + ). + ENDMETHOD. + +ENDCLASS. + + + +CLASS ltc_prefix DEFINITION INHERITING FROM ltc_cut FOR TESTING RISK LEVEL HARMLESS DURATION SHORT. + PROTECTED SECTION. + METHODS get_code_without_issue REDEFINITION. +ENDCLASS. + +CLASS ltc_prefix IMPLEMENTATION. + + METHOD get_code_without_issue. + result = VALUE #( + ( ' REPORT y_example. ' ) + + ( ' CLASS y_example DEFINITION FOR TESTING RISK LEVEL HARMLESS DURATION SHORT. ' ) + ( ' PUBLIC SECTION. ' ) + ( ' METHODS example FOR TESTING. ' ) + ( ' ENDCLASS. ' ) + + ( ' CLASS y_example IMPLEMENTATION. ' ) + ( ' METHOD example. ' ) + ( ' " given ' ) + ( ' DATA lo_cut TYPE REF TO y_demo_failures. ' ) + ( ' " when ' ) + ( ' lo_cut = NEW #( ). ' ) + ( ' " then ' ) + ( ' cl_abap_unit_assert=>assert_bound( lo_cut ). ' ) + ( ' ENDMETHOD. ' ) + ( ' ENDCLASS. ' ) + ). + ENDMETHOD. + +ENDCLASS. + + + +CLASS ltc_not_for_testing DEFINITION INHERITING FROM ltc_cut FOR TESTING RISK LEVEL HARMLESS DURATION SHORT. + PROTECTED SECTION. + METHODS get_code_without_issue REDEFINITION. +ENDCLASS. + +CLASS ltc_not_for_testing IMPLEMENTATION. + + METHOD get_code_without_issue. + result = VALUE #( + ( ' REPORT y_example. ' ) + + ( ' CLASS y_example DEFINITION FOR TESTING RISK LEVEL HARMLESS DURATION SHORT. ' ) + ( ' PUBLIC SECTION. ' ) + ( ' METHODS example. ' ) + ( ' ENDCLASS. ' ) + + ( ' CLASS y_example IMPLEMENTATION. ' ) + ( ' METHOD example. ' ) + ( ' ENDMETHOD. ' ) + ( ' ENDCLASS. ' ) + ). + ENDMETHOD. + +ENDCLASS. + + + +CLASS ltc_attribute DEFINITION INHERITING FROM ltc_cut FOR TESTING RISK LEVEL HARMLESS DURATION SHORT. + PROTECTED SECTION. + METHODS get_code_without_issue REDEFINITION. +ENDCLASS. + +CLASS ltc_attribute IMPLEMENTATION. + + METHOD get_code_without_issue. + result = VALUE #( + ( ' REPORT y_example. ' ) + + ( ' CLASS y_example DEFINITION FOR TESTING RISK LEVEL HARMLESS DURATION SHORT. ' ) + ( ' PUBLIC SECTION. ' ) + ( ' METHODS example FOR TESTING. ' ) + ( ' PRIVATE SECTION. ' ) + ( ' DATA lo_cut TYPE REF TO y_demo_failures. ' ) + ( ' ENDCLASS. ' ) + + ( ' CLASS y_example IMPLEMENTATION. ' ) + ( ' METHOD example. ' ) + ( ' " when ' ) + ( ' lo_cut = NEW #( ). ' ) + ( ' " then ' ) + ( ' cl_abap_unit_assert=>assert_bound( lo_cut ). ' ) + ( ' ENDMETHOD. ' ) + ( ' ENDCLASS. ' ) + ). + ENDMETHOD. + +ENDCLASS. diff --git a/src/checks/y_check_unit_test_cut_name.clas.xml b/src/checks/y_check_unit_test_cut_name.clas.xml new file mode 100644 index 00000000..8fe1caf7 --- /dev/null +++ b/src/checks/y_check_unit_test_cut_name.clas.xml @@ -0,0 +1,17 @@ + + + + + + Y_CHECK_UNIT_TEST_CUT_NAME + E + Name the Class Under Test to CUT + 1 + X + X + X + X + + + + diff --git a/src/foundation/y_check_base.clas.abap b/src/foundation/y_check_base.clas.abap index 3307562f..9270de05 100644 --- a/src/foundation/y_check_base.clas.abap +++ b/src/foundation/y_check_base.clas.abap @@ -106,6 +106,9 @@ CLASS y_check_base DEFINITION PUBLIC ABSTRACT additional_information TYPE xstring OPTIONAL checksum TYPE int4 OPTIONAL. "#EC OPTL_PARAM + METHODS get_statement_abs IMPORTING statement TYPE sstmnt + RETURNING VALUE(result) TYPE string. + METHODS get_column_abs REDEFINITION. METHODS get_column_rel REDEFINITION. METHODS get_include REDEFINITION. @@ -819,4 +822,16 @@ CLASS Y_CHECK_BASE IMPLEMENTATION. METHOD switch_bool. result = xsdbool( boolean = abap_false ). ENDMETHOD. + + + METHOD get_statement_abs. + LOOP AT ref_scan_manager->tokens ASSIGNING FIELD-SYMBOL() + FROM statement-from TO statement-to. + result = COND #( WHEN result IS INITIAL THEN -str + ELSE |{ result } { -str }| ). + + ENDLOOP. + ENDMETHOD. + + ENDCLASS.