Skip to content

cut as default #399

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 14 commits into from
5 changes: 5 additions & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ Upgrade Note
------------------
Whenever you upgrade code pal for ABAP, it is highly recommended to execute the Y_CI_CHECK_REGISTRATION report to activate/reactivate the Checks (SE38 transaction) and regenerate the respective Code Inspector Variant (SCI transaction)

2021-05-XX v.1.15.0
------------------
+ Name the code under test to CUT (#369)
* CALL METHOD Usage does not check if the method call is dynamic (#396)

2021-05-03 v.1.14.1
------------------
+ Assert Classes (#378)
Expand Down
1 change: 1 addition & 0 deletions docs/check_documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
- [Comment Type](checks/comment-type.md)
- [Comment Usage](checks/comment-usage.md)
- [Constants Interface](checks/constants-interface.md)
- [`cut` as Default](checks/cut-as-default.md)
- [Cyclomatic Complexity](checks/cyclomatic-complexity.md)
- [CX_ROOT Usage](checks/cx-root-usage.md)
- [Database Access in Unit-Test](checks/db-access-in-ut.md)
Expand Down
64 changes: 64 additions & 0 deletions docs/checks/cut-as-default.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
[code pal for ABAP](../../README.md) > [Documentation](../check_documentation.md) > [`cut` as Default](cut-as-default.md)

## `cut` as Default

### What is the Intent of the Check?

In a test class, the code under the test can be represented using a meaningful name, or `cut` as a default.
If you decide to follow `cut` as a default, this Check reports test methods that do not follow the pattern.

### How does the check work?

For each `for testing` method, it searches for the `cut` on it, and also on its `class definition`.

### How to solve the issue?

Name the code under the test to `cut`.

### What to do in case of exception?

If you found a meaningful name, you can suppress this finding by using the pseudo comment `"#EC CUT_AS_DEFAULT` which has to be placed after the method implementation statement:

```abap
METHOD test. "#EC CUT_AS_DEFAULT
" given
DATA demo_failures TYPE REF TO y_demo_failures.
" when
demo_failures = NEW #( ).
" then
cl_abap_unit_assert=>assert_bound( demo_failures ).
ENDMETHOD.
```

### Example

Before the check:


```abap
METHOD test.
DATA class_abc TYPE REF TO ...
DATA class_123 TYPE REF TO ...
DATA class_qwe TYPE REF TO ...
...
cl_abap_unit_assert=>assert_bound( class_qwe ).
ENDMETHOD.
```

After the check:

```abap
METHOD test.
DATA class_abc TYPE REF TO ...
DATA class_123 TYPE REF TO ...
DATA cut TYPE REF TO ...
...
cl_abap_unit_assert=>assert_bound( cut ).
ENDMETHOD.
```

### Further Readings & Knowledge

* [Clean ABAP: Name the code under test meaningfully, or default to CUT](https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#name-the-code-under-test-meaningfully-or-default-to-cut)


3 changes: 2 additions & 1 deletion src/checks/y_check_call_method_usage.clas.abap
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ CLASS y_check_call_method_usage IMPLEMENTATION.
DATA(is_dynamic) = xsdbool( token CP '*->(*)*'
OR token CP '*=>(*)*'
OR token CP '*)=>(*)*'
OR token CP '*)=>*' ).
OR token CP '*)=>*'
OR token CP '(*)' ).

DATA(check_configuration) = detect_check_configuration( statement ).

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ CLASS ltc_class IMPLEMENTATION.
( ' PUBLIC SECTION. ' )
( ' METHODS class_method. ' )
( ' CLASS-METHODS execute. ' )
( ' PROTECTED SECTION. ' )
( 'ENDCLASS. ' )

( 'CLASS lcl_classname IMPLEMENTATION. ' )
Expand All @@ -41,12 +40,12 @@ CLASS ltc_class IMPLEMENTATION.
( ' PUBLIC SECTION. ' )
( ' METHODS class_method. ' )
( ' CLASS-METHODS execute. ' )
( ' PROTECTED SECTION. ' )
( 'ENDCLASS. ' )

( 'CLASS lcl_classname IMPLEMENTATION. ' )
( ' METHOD class_method. ' )
( ' lcl_classname=>execute( ). ' )
( | CALL METHOD ('execute'). | )
( ' ENDMETHOD. ' )
( ' METHOD execute. ' )
( ' ENDMETHOD. ' )
Expand All @@ -62,7 +61,6 @@ CLASS ltc_class IMPLEMENTATION.
( ' PUBLIC SECTION. ' )
( ' METHODS class_method. ' )
( ' CLASS-METHODS execute. ' )
( ' PROTECTED SECTION. ' )
( 'ENDCLASS. ' )

( 'CLASS lcl_classname IMPLEMENTATION. ' )
Expand Down Expand Up @@ -98,7 +96,6 @@ CLASS ltc_report IMPLEMENTATION.
( 'CLASS lcl_classname DEFINITION. ' )
( ' PUBLIC SECTION. ' )
( ' CLASS-METHODS execute. ' )
( ' PROTECTED SECTION. ' )
( 'ENDCLASS. ' )

( 'CLASS lcl_classname IMPLEMENTATION. ' )
Expand All @@ -120,7 +117,6 @@ CLASS ltc_report IMPLEMENTATION.
( 'CLASS lcl_classname DEFINITION. ' )
( ' PUBLIC SECTION. ' )
( ' CLASS-METHODS execute. ' )
( ' PROTECTED SECTION. ' )
( 'ENDCLASS. ' )

( 'CLASS lcl_classname IMPLEMENTATION. ' )
Expand Down
119 changes: 119 additions & 0 deletions src/checks/y_check_cut_as_default.clas.abap
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
CLASS y_check_cut_as_default 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 method_name TYPE string
class_definition TYPE sstruc
RETURNING VALUE(result) TYPE abap_bool.

METHODS has_cut IMPORTING structure TYPE sstruc
RETURNING VALUE(result) TYPE abap_bool.

METHODS get_class_definition IMPORTING structure TYPE sstruc
RETURNING VALUE(result) TYPE sstruc
RAISING cx_sy_itab_line_not_found.

ENDCLASS.


CLASS y_check_cut_as_default IMPLEMENTATION.


METHOD constructor.
super->constructor( ).

settings-pseudo_comment = '"#EC CUT_AS_DEFAULT' ##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 }cut-as-default.md|.
relevant_statement_types = VALUE #( ( scan_struc_stmnt_type-method ) ).
relevant_structure_types = VALUE #( ).

set_check_message( 'Name the code under test to `cut`' ).
ENDMETHOD.


METHOD inspect_tokens.
CHECK get_token_abs( statement-from ) = 'METHOD'.

DATA(class_definition) = get_class_definition( structure ).

DATA(for_testing) = is_for_testing( method_name = get_token_abs( statement-from + 1 )
class_definition = class_definition ).

IF for_testing = abap_false.
RETURN.
ENDIF.

IF has_cut( structure ) = abap_true
OR has_cut( class_definition ) = 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.
LOOP AT ref_scan_manager->statements ASSIGNING FIELD-SYMBOL(<statement>)
FROM class_definition-stmnt_from TO class_definition-stmnt_to.

IF get_token_abs( <statement>-from ) <> 'METHODS'
AND get_token_abs( <statement>-from ) <> 'CLASS-METHODS'.
CONTINUE.
ENDIF.

DATA(statement_abs) = get_statement_abs( <statement> ).

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(<statement>)
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( <statement> ).

result = xsdbool( statement_abs CP '* CUT *'
OR statement_abs CP '*_CUT *' ).

IF result = abap_true.
RETURN.
ENDIF.
ENDLOOP.
ENDMETHOD.


METHOD get_class_definition.
DATA(class_implementation) = ref_scan_manager->structures[ structure-back ].
result = ref_scan_manager->structures[ class_implementation-back ].
ENDMETHOD.


ENDCLASS.
Loading