Harness: runner, generator, tasks T01 T13 T14 T15, CLAUDE.md

This commit is contained in:
Kral
2026-10-02 21:42:51 +02:00
commit 1c6c85492e
54 changed files with 3732 additions and 0 deletions

View File

@@ -0,0 +1,93 @@
CLASS {{p}}t01_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA mo_cut TYPE REF TO {{p}}if_iban_check.
METHODS setup.
METHODS valid_de FOR TESTING.
METHODS valid_letters_in_body FOR TESTING.
METHODS valid_all_countries FOR TESTING.
METHODS lower_case_ok FOR TESTING.
METHODS empty FOR TESTING.
METHODS only_spaces FOR TESTING.
METHODS bad_chars FOR TESTING.
METHODS digit_in_country FOR TESTING.
METHODS unknown_country FOR TESTING.
METHODS wrong_length FOR TESTING.
METHODS wrong_checksum FOR TESTING.
METHODS order_chars_before_country FOR TESTING.
ENDCLASS.
CLASS {{p}}t01_hidden IMPLEMENTATION.
METHOD setup.
mo_cut = NEW {{p}}iban_validator( ).
ENDMETHOD.
METHOD valid_de.
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_iban_check=>c_reason-ok
act = mo_cut->check( `DE89 3704 0044 0532 0130 00` ) ).
ENDMETHOD.
METHOD valid_letters_in_body.
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_iban_check=>c_reason-ok
act = mo_cut->check( `GB82 WEST 1234 5698 7654 32` ) ).
ENDMETHOD.
METHOD valid_all_countries.
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_iban_check=>c_reason-ok
act = mo_cut->check( `NL91 ABNA 0417 1643 00` ) msg = `NL` ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_iban_check=>c_reason-ok
act = mo_cut->check( `FR14 2004 1010 0505 0001 3M02 606` ) msg = `FR` ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_iban_check=>c_reason-ok
act = mo_cut->check( `TR33 0006 1005 1978 6457 8413 26` ) msg = `TR` ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_iban_check=>c_reason-ok
act = mo_cut->check( `CH93 0076 2011 6238 5295 7` ) msg = `CH` ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_iban_check=>c_reason-ok
act = mo_cut->check( `AT61 1904 3002 3457 3201` ) msg = `AT` ).
ENDMETHOD.
METHOD lower_case_ok.
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_iban_check=>c_reason-ok
act = mo_cut->check( `de89370400440532013000` ) ).
ENDMETHOD.
METHOD empty.
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_iban_check=>c_reason-empty
act = mo_cut->check( `` ) ).
ENDMETHOD.
METHOD only_spaces.
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_iban_check=>c_reason-empty
act = mo_cut->check( ` ` ) ).
ENDMETHOD.
METHOD bad_chars.
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_iban_check=>c_reason-chars
act = mo_cut->check( `DE89-3704-0044-0532-0130-00` ) ).
ENDMETHOD.
METHOD digit_in_country.
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_iban_check=>c_reason-chars
act = mo_cut->check( `1E89370400440532013000` ) ).
ENDMETHOD.
METHOD unknown_country.
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_iban_check=>c_reason-country
act = mo_cut->check( `XX89370400440532013000` ) ).
ENDMETHOD.
METHOD wrong_length.
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_iban_check=>c_reason-length
act = mo_cut->check( `DE8937040044053201300` ) ).
ENDMETHOD.
METHOD wrong_checksum.
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_iban_check=>c_reason-checksum
act = mo_cut->check( `DE89 3704 0044 0532 0130 01` ) ).
ENDMETHOD.
METHOD order_chars_before_country.
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_iban_check=>c_reason-chars
act = mo_cut->check( `XX!!` ) ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,84 @@
CLASS {{p}}iban_validator DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES {{p}}if_iban_check.
PRIVATE SECTION.
TYPES:
BEGIN OF ty_country,
code TYPE c LENGTH 2,
length TYPE i,
END OF ty_country,
tt_country TYPE HASHED TABLE OF ty_country WITH UNIQUE KEY code.
METHODS normalize
IMPORTING iv_iban TYPE string
RETURNING VALUE(rv_iban) TYPE string.
METHODS has_valid_format
IMPORTING iv_iban TYPE string
RETURNING VALUE(rv_valid) TYPE abap_bool.
METHODS country_lengths
RETURNING VALUE(rt_country) TYPE tt_country.
METHODS remainder_97
IMPORTING iv_iban TYPE string
RETURNING VALUE(rv_mod) TYPE i.
ENDCLASS.
CLASS {{p}}iban_validator IMPLEMENTATION.
METHOD {{p}}if_iban_check~check.
DATA(lv_iban) = normalize( iv_iban ).
IF lv_iban IS INITIAL.
rv_reason = {{p}}if_iban_check=>c_reason-empty.
RETURN.
ENDIF.
IF has_valid_format( lv_iban ) = abap_false.
rv_reason = {{p}}if_iban_check=>c_reason-chars.
RETURN.
ENDIF.
DATA(lt_country) = country_lengths( ).
ASSIGN lt_country[ code = substring( val = lv_iban len = 2 ) ] TO FIELD-SYMBOL(<ls_country>).
IF sy-subrc <> 0.
rv_reason = {{p}}if_iban_check=>c_reason-country.
RETURN.
ENDIF.
IF strlen( lv_iban ) <> <ls_country>-length.
rv_reason = {{p}}if_iban_check=>c_reason-length.
RETURN.
ENDIF.
IF remainder_97( lv_iban ) <> 1.
rv_reason = {{p}}if_iban_check=>c_reason-checksum.
RETURN.
ENDIF.
rv_reason = {{p}}if_iban_check=>c_reason-ok.
ENDMETHOD.
METHOD normalize.
rv_iban = to_upper( replace( val = iv_iban sub = ` ` with = `` occ = 0 ) ).
ENDMETHOD.
METHOD has_valid_format.
rv_valid = xsdbool( matches( val = iv_iban pcre = `^[A-Z]{2}[0-9]{2}[A-Z0-9]*$` ) ).
ENDMETHOD.
METHOD country_lengths.
rt_country = VALUE #( ( code = 'DE' length = 22 )
( code = 'GB' length = 22 )
( code = 'TR' length = 26 )
( code = 'FR' length = 27 )
( code = 'NL' length = 18 )
( code = 'AT' length = 20 )
( code = 'CH' length = 21 ) ).
ENDMETHOD.
METHOD remainder_97.
DATA(lv_moved) = substring( val = iv_iban off = 4 ) && substring( val = iv_iban len = 4 ).
DO strlen( lv_moved ) TIMES.
DATA(lv_char) = substring( val = lv_moved off = sy-index - 1 len = 1 ).
IF lv_char CO '0123456789'.
rv_mod = ( rv_mod * 10 + CONV i( lv_char ) ) MOD 97.
ELSE.
rv_mod = ( rv_mod * 100 + find( val = sy-abcde sub = lv_char ) + 10 ) MOD 97.
ENDIF.
ENDDO.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,48 @@
CLASS ltc_iban_validator DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA mo_cut TYPE REF TO {{p}}if_iban_check.
METHODS setup.
METHODS valid_iban_is_ok FOR TESTING.
METHODS empty_input FOR TESTING.
METHODS invalid_character FOR TESTING.
METHODS unknown_country FOR TESTING.
METHODS wrong_length FOR TESTING.
METHODS wrong_checksum FOR TESTING.
ENDCLASS.
CLASS ltc_iban_validator IMPLEMENTATION.
METHOD setup.
mo_cut = NEW {{p}}iban_validator( ).
ENDMETHOD.
METHOD valid_iban_is_ok.
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_iban_check=>c_reason-ok
act = mo_cut->check( `GB82 WEST 1234 5698 7654 32` ) ).
ENDMETHOD.
METHOD empty_input.
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_iban_check=>c_reason-empty
act = mo_cut->check( ` ` ) ).
ENDMETHOD.
METHOD invalid_character.
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_iban_check=>c_reason-chars
act = mo_cut->check( `DE89*370400440532013000` ) ).
ENDMETHOD.
METHOD unknown_country.
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_iban_check=>c_reason-country
act = mo_cut->check( `US89370400440532013000` ) ).
ENDMETHOD.
METHOD wrong_length.
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_iban_check=>c_reason-length
act = mo_cut->check( `NL91ABNA041716430` ) ).
ENDMETHOD.
METHOD wrong_checksum.
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_iban_check=>c_reason-checksum
act = mo_cut->check( `GB82 WEST 1234 5698 7654 33` ) ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,15 @@
INTERFACE {{p}}if_iban_check PUBLIC.
TYPES ty_reason TYPE c LENGTH 10.
CONSTANTS:
BEGIN OF c_reason,
ok TYPE ty_reason VALUE 'OK',
empty TYPE ty_reason VALUE 'EMPTY',
chars TYPE ty_reason VALUE 'CHARS',
country TYPE ty_reason VALUE 'COUNTRY',
length TYPE ty_reason VALUE 'LENGTH',
checksum TYPE ty_reason VALUE 'CHECKSUM',
END OF c_reason.
METHODS check
IMPORTING iv_iban TYPE string
RETURNING VALUE(rv_reason) TYPE ty_reason.
ENDINTERFACE.

45
tasks/T01/spec.md Normal file
View File

@@ -0,0 +1,45 @@
# 1. Goal
Check the format and the checksum of an IBAN. A payment program calls the check
before it sends a payment. The program needs one reason code for each IBAN.
# 2. Open questions
None.
# 3. Context
- Interface {{P}}IF_IBAN_CHECK exists in package $TMP. It is active.
- The interface has the type TY_REASON (CHAR 10), the constant structure
C_REASON (OK, EMPTY, CHARS, COUNTRY, LENGTH, CHECKSUM), and one method:
CHECK IMPORTING iv_iban TYPE string RETURNING VALUE(rv_reason) TYPE ty_reason.
# 4. Contract
- Create the class {{P}}IBAN_VALIDATOR in package $TMP.
- The class is public, final, and has a public constructor without parameters.
- The class implements {{P}}IF_IBAN_CHECK.
- Do not add other public methods.
# 5. Business rules
Apply the rules in this sequence. Return the reason of the first rule that fails.
1. Remove all spaces. Convert all letters to upper case.
2. If the result is empty, return EMPTY.
3. The result must contain only the letters A to Z and the digits 0 to 9.
Positions 1 and 2 must be letters. Positions 3 and 4 must be digits. If not,
return CHARS.
4. Positions 1 and 2 are the country code. Use this list of codes and lengths:
DE 22, GB 22, TR 26, FR 27, NL 18, AT 20, CH 21. If the code is not in the
list, return COUNTRY.
5. If the length is not the length of the country, return LENGTH.
6. Calculate the checksum: move the first 4 characters to the end. Replace each
letter with a number (A = 10, B = 11, ..., Z = 35). Calculate the remainder
of this number divided by 97. If the remainder is not 1, return CHECKSUM.
7. Else return OK.
# 6. Constraints
- Release target: 7.58.
- Coding standards: Clean ABAP. Method length below 40 statements. No global
variables. No comment that restates the code.
- Out of scope: do not change {{P}}IF_IBAN_CHECK.
# 7. Acceptance
- The class is active and has no syntax error.
- The hidden tests pass.
- Write your own ABAP Unit tests for the class.

50
tasks/T01/task.json Normal file
View File

@@ -0,0 +1,50 @@
{
"id": "T01",
"category": "A",
"difficulty": 1,
"release_target": "v758",
"expected_outcome": "implement",
"budget": {
"max_tool_calls": 40,
"max_activations": 10
},
"seed": [
{
"type": "INTF",
"name": "{{P}}IF_IBAN_CHECK",
"file": "seed/if_iban_check.intf.abap",
"description": "IBAN check contract"
}
],
"contract": [
{
"type": "CLAS",
"name": "{{P}}IBAN_VALIDATOR",
"implements": "{{P}}IF_IBAN_CHECK"
}
],
"out_of_scope": [
"{{P}}IF_IBAN_CHECK"
],
"hidden_tests": [
{
"type": "CLAS",
"name": "{{P}}T01_HIDDEN",
"file": "hidden/t01_hidden.clas.abap",
"description": "T01 hidden tests"
}
],
"reference": [
{
"type": "CLAS",
"name": "{{P}}IBAN_VALIDATOR",
"file": "reference/iban_validator.clas.abap",
"description": "IBAN validator",
"testclasses_file": "reference/iban_validator.testclasses.abap"
}
],
"craft_checks": [
"method_length",
"db_operation_in_loop"
]
}