Stage 2 summary at 50 accepted trajectories

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Kral
2026-10-05 18:02:52 +02:00
parent 332fb4601d
commit 5bcd1bf9cd
1230 changed files with 77563 additions and 33 deletions

View File

@@ -0,0 +1,34 @@
{
"id": "G1073",
"pool": "train",
"object_type": "CLAS",
"category": "C",
"attempts": [
{
"stage": "bundle",
"errors": [
"reference/parking_eval.clas.abap line 27: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\"",
"reference/parking_eval.clas.abap line 30: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\""
],
"by_check": {
"abaplint": 2
}
},
{
"stage": "validate",
"oracle": 0,
"null": 0
},
{
"stage": "validate",
"oracle": 0,
"null": 0
},
{
"stage": "validate",
"oracle": 0,
"null": 0
}
],
"accepted": false
}

View File

@@ -0,0 +1,151 @@
CLASS {{p}}t31_hidden DEFINITION
PUBLIC
FINAL
FOR TESTING
RISK LEVEL HARMLESS
DURATION SHORT
CREATE PUBLIC.
PRIVATE SECTION.
CONSTANTS:
c_fee_000 TYPE p LENGTH 8 DECIMALS 2 VALUE '0.00',
c_fee_200 TYPE p LENGTH 8 DECIMALS 2 VALUE '2.00',
c_fee_350 TYPE p LENGTH 8 DECIMALS 2 VALUE '3.50',
c_fee_400 TYPE p LENGTH 8 DECIMALS 2 VALUE '4.00',
c_fee_500 TYPE p LENGTH 8 DECIMALS 2 VALUE '5.00',
c_fee_1000 TYPE p LENGTH 8 DECIMALS 2 VALUE '10.00',
c_fee_1250 TYPE p LENGTH 8 DECIMALS 2 VALUE '12.50',
c_fee_2000 TYPE p LENGTH 8 DECIMALS 2 VALUE '20.00'.
DATA mo_cut TYPE REF TO {{p}}if_park_eval.
METHODS setup.
"! @testing {{p}}parking_eval
METHODS empty_input FOR TESTING.
"! @testing {{p}}parking_eval
METHODS free_minutes FOR TESTING.
"! @testing {{p}}parking_eval
METHODS one_started_hour FOR TESTING.
"! @testing {{p}}parking_eval
METHODS two_started_hours FOR TESTING.
"! @testing {{p}}parking_eval
METHODS rates_per_tariff FOR TESTING.
"! @testing {{p}}parking_eval
METHODS fee_is_capped FOR TESTING.
"! @testing {{p}}parking_eval
METHODS invalid_tariff_ignored FOR TESTING.
"! @testing {{p}}parking_eval
METHODS zero_duration_ignored FOR TESTING.
"! @testing {{p}}parking_eval
METHODS groups_and_sorts_parks FOR TESTING.
"! @testing {{p}}parking_eval
METHODS sums_sessions_of_park FOR TESTING.
ENDCLASS.
CLASS {{p}}t31_hidden IMPLEMENTATION.
METHOD setup.
mo_cut = NEW {{p}}parking_eval( ).
ENDMETHOD.
METHOD empty_input.
DATA(lt_result) = mo_cut->summarize( VALUE {{p}}if_park_eval=>tt_session( ) ).
cl_abap_unit_assert=>assert_equals( exp = 0 act = lines( lt_result ) ).
ENDMETHOD.
METHOD free_minutes.
DATA(lt_result) = mo_cut->summarize( VALUE {{p}}if_park_eval=>tt_session(
( park_id = 'P001' tariff = 'A' duration_min = 20 )
( park_id = 'P001' tariff = 'A' duration_min = 30 ) ) ).
cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_result ) ).
DATA(ls_row) = lt_result[ 1 ].
cl_abap_unit_assert=>assert_equals( exp = 2 act = ls_row-session_cnt ).
cl_abap_unit_assert=>assert_equals( exp = 50 act = ls_row-total_min ).
cl_abap_unit_assert=>assert_equals( exp = c_fee_000 act = ls_row-total_fee ).
ENDMETHOD.
METHOD one_started_hour.
DATA(lt_result) = mo_cut->summarize( VALUE {{p}}if_park_eval=>tt_session(
( park_id = 'P001' tariff = 'A' duration_min = 31 ) ) ).
cl_abap_unit_assert=>assert_equals( exp = c_fee_200 act = lt_result[ 1 ]-total_fee ).
ENDMETHOD.
METHOD two_started_hours.
DATA(lt_result) = mo_cut->summarize( VALUE {{p}}if_park_eval=>tt_session(
( park_id = 'P001' tariff = 'A' duration_min = 91 )
( park_id = 'P002' tariff = 'A' duration_min = 150 ) ) ).
cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_result ) ).
cl_abap_unit_assert=>assert_equals( exp = c_fee_400 act = lt_result[ 1 ]-total_fee ).
cl_abap_unit_assert=>assert_equals( exp = c_fee_400 act = lt_result[ 2 ]-total_fee ).
ENDMETHOD.
METHOD rates_per_tariff.
DATA(lt_result) = mo_cut->summarize( VALUE {{p}}if_park_eval=>tt_session(
( park_id = 'P001' tariff = 'A' duration_min = 90 )
( park_id = 'P002' tariff = 'B' duration_min = 90 )
( park_id = 'P003' tariff = 'C' duration_min = 90 ) ) ).
cl_abap_unit_assert=>assert_equals( exp = 3 act = lines( lt_result ) ).
cl_abap_unit_assert=>assert_equals( exp = c_fee_200 act = lt_result[ 1 ]-total_fee ).
cl_abap_unit_assert=>assert_equals( exp = c_fee_350 act = lt_result[ 2 ]-total_fee ).
cl_abap_unit_assert=>assert_equals( exp = c_fee_500 act = lt_result[ 3 ]-total_fee ).
ENDMETHOD.
METHOD fee_is_capped.
DATA(lt_result) = mo_cut->summarize( VALUE {{p}}if_park_eval=>tt_session(
( park_id = 'P001' tariff = 'C' duration_min = 400 )
( park_id = 'P002' tariff = 'C' duration_min = 150 ) ) ).
cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_result ) ).
cl_abap_unit_assert=>assert_equals( exp = c_fee_2000 act = lt_result[ 1 ]-total_fee ).
cl_abap_unit_assert=>assert_equals( exp = c_fee_1000 act = lt_result[ 2 ]-total_fee ).
ENDMETHOD.
METHOD invalid_tariff_ignored.
DATA(lt_result) = mo_cut->summarize( VALUE {{p}}if_park_eval=>tt_session(
( park_id = 'P001' tariff = 'X' duration_min = 120 )
( park_id = 'P002' tariff = 'A' duration_min = 90 )
( park_id = 'P002' tariff = 'X' duration_min = 200 ) ) ).
cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_result ) ).
DATA(ls_row) = lt_result[ 1 ].
cl_abap_unit_assert=>assert_equals( exp = 'P002' act = ls_row-park_id ).
cl_abap_unit_assert=>assert_equals( exp = 1 act = ls_row-session_cnt ).
cl_abap_unit_assert=>assert_equals( exp = 90 act = ls_row-total_min ).
cl_abap_unit_assert=>assert_equals( exp = c_fee_200 act = ls_row-total_fee ).
ENDMETHOD.
METHOD zero_duration_ignored.
DATA(lt_result) = mo_cut->summarize( VALUE {{p}}if_park_eval=>tt_session(
( park_id = 'P001' tariff = 'A' duration_min = 0 )
( park_id = 'P001' tariff = 'B' duration_min = -5 ) ) ).
cl_abap_unit_assert=>assert_equals( exp = 0 act = lines( lt_result ) ).
ENDMETHOD.
METHOD groups_and_sorts_parks.
DATA(lt_result) = mo_cut->summarize( VALUE {{p}}if_park_eval=>tt_session(
( park_id = 'P003' tariff = 'A' duration_min = 60 )
( park_id = 'P001' tariff = 'B' duration_min = 60 ) ) ).
cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_result ) ).
cl_abap_unit_assert=>assert_equals( exp = 'P001' act = lt_result[ 1 ]-park_id ).
cl_abap_unit_assert=>assert_equals( exp = 'P003' act = lt_result[ 2 ]-park_id ).
ENDMETHOD.
METHOD sums_sessions_of_park.
DATA(lt_result) = mo_cut->summarize( VALUE {{p}}if_park_eval=>tt_session(
( park_id = 'P001' tariff = 'A' duration_min = 45 )
( park_id = 'P001' tariff = 'B' duration_min = 200 )
( park_id = 'P001' tariff = 'A' duration_min = 30 ) ) ).
cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_result ) ).
DATA(ls_row) = lt_result[ 1 ].
cl_abap_unit_assert=>assert_equals( exp = 3 act = ls_row-session_cnt ).
cl_abap_unit_assert=>assert_equals( exp = 275 act = ls_row-total_min ).
cl_abap_unit_assert=>assert_equals( exp = c_fee_1250 act = ls_row-total_fee ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,96 @@
CLASS {{p}}parking_eval DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES {{p}}if_park_eval.
PRIVATE SECTION.
TYPES:
ty_amount TYPE p LENGTH 8 DECIMALS 2,
BEGIN OF ty_total,
park_id TYPE {{p}}if_park_eval=>ty_park_id,
session_cnt TYPE i,
total_min TYPE i,
total_fee TYPE ty_amount,
END OF ty_total,
tt_total TYPE HASHED TABLE OF ty_total WITH UNIQUE KEY park_id.
CONSTANTS:
BEGIN OF c_tariff,
a TYPE {{p}}if_park_eval=>ty_tariff VALUE 'A',
b TYPE {{p}}if_park_eval=>ty_tariff VALUE 'B',
c TYPE {{p}}if_park_eval=>ty_tariff VALUE 'C',
END OF c_tariff.
CONSTANTS:
c_free_min TYPE i VALUE 30,
c_max_fee TYPE ty_amount VALUE '20.00',
c_rate_a TYPE ty_amount VALUE '2.00',
c_rate_b TYPE ty_amount VALUE '3.50',
c_rate_c TYPE ty_amount VALUE '5.00'.
METHODS is_valid
IMPORTING is_session TYPE {{p}}if_park_eval=>ty_session
RETURNING VALUE(rv_valid) TYPE abap_bool.
METHODS fee
IMPORTING is_session TYPE {{p}}if_park_eval=>ty_session
RETURNING VALUE(rv_fee) TYPE ty_amount.
METHODS rate
IMPORTING iv_tariff TYPE {{p}}if_park_eval=>ty_tariff
RETURNING VALUE(rv_rate) TYPE ty_amount.
ENDCLASS.
CLASS {{p}}parking_eval IMPLEMENTATION.
METHOD {{p}}if_park_eval~summarize.
DATA lt_total TYPE tt_total.
LOOP AT it_session INTO DATA(ls_session).
IF is_valid( ls_session ) = abap_false.
CONTINUE.
ENDIF.
READ TABLE lt_total WITH TABLE KEY park_id = ls_session-park_id
ASSIGNING FIELD-SYMBOL(<ls_total>).
IF sy-subrc <> 0.
INSERT INITIAL LINE INTO TABLE lt_total ASSIGNING <ls_total>.
<ls_total>-park_id = ls_session-park_id.
ENDIF.
<ls_total>-session_cnt += 1.
<ls_total>-total_min += ls_session-duration_min.
<ls_total>-total_fee += fee( ls_session ).
ENDLOOP.
rt_summary = CORRESPONDING #( lt_total ).
SORT rt_summary BY park_id.
ENDMETHOD.
METHOD is_valid.
rv_valid = xsdbool( is_session-duration_min > 0 AND rate( is_session-tariff ) > 0 ).
ENDMETHOD.
METHOD fee.
IF is_session-duration_min <= c_free_min.
RETURN.
ENDIF.
DATA(lv_hours) = ( is_session-duration_min - c_free_min + 59 ) DIV 60.
rv_fee = lv_hours * rate( is_session-tariff ).
IF rv_fee > c_max_fee.
rv_fee = c_max_fee.
ENDIF.
ENDMETHOD.
METHOD rate.
CASE iv_tariff.
WHEN c_tariff-a.
rv_rate = c_rate_a.
WHEN c_tariff-b.
rv_rate = c_rate_b.
WHEN c_tariff-c.
rv_rate = c_rate_c.
WHEN OTHERS.
rv_rate = 0.
ENDCASE.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,75 @@
CLASS ltc_parking_eval DEFINITION FINAL FOR TESTING
DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
CONSTANTS:
c_fee_000 TYPE p LENGTH 8 DECIMALS 2 VALUE '0.00',
c_fee_200 TYPE p LENGTH 8 DECIMALS 2 VALUE '2.00',
c_fee_2000 TYPE p LENGTH 8 DECIMALS 2 VALUE '20.00'.
DATA mo_cut TYPE REF TO {{p}}if_park_eval.
METHODS setup.
"! @testing {{p}}parking_eval
METHODS free_minutes_are_free FOR TESTING.
"! @testing {{p}}parking_eval
METHODS one_hour_is_charged FOR TESTING.
"! @testing {{p}}parking_eval
METHODS fee_is_capped FOR TESTING.
"! @testing {{p}}parking_eval
METHODS invalid_tariff_is_ignored FOR TESTING.
"! @testing {{p}}parking_eval
METHODS groups_by_park FOR TESTING.
"! @testing {{p}}parking_eval
METHODS empty_input_gives_no_row FOR TESTING.
ENDCLASS.
CLASS ltc_parking_eval IMPLEMENTATION.
METHOD setup.
mo_cut = NEW {{p}}parking_eval( ).
ENDMETHOD.
METHOD free_minutes_are_free.
DATA(lt_result) = mo_cut->summarize( VALUE {{p}}if_park_eval=>tt_session(
( park_id = 'P001' tariff = 'A' duration_min = 30 ) ) ).
cl_abap_unit_assert=>assert_equals( exp = c_fee_000 act = lt_result[ 1 ]-total_fee ).
ENDMETHOD.
METHOD one_hour_is_charged.
DATA(lt_result) = mo_cut->summarize( VALUE {{p}}if_park_eval=>tt_session(
( park_id = 'P001' tariff = 'A' duration_min = 31 ) ) ).
cl_abap_unit_assert=>assert_equals( exp = c_fee_200 act = lt_result[ 1 ]-total_fee ).
ENDMETHOD.
METHOD fee_is_capped.
DATA(lt_result) = mo_cut->summarize( VALUE {{p}}if_park_eval=>tt_session(
( park_id = 'P001' tariff = 'C' duration_min = 400 ) ) ).
cl_abap_unit_assert=>assert_equals( exp = c_fee_2000 act = lt_result[ 1 ]-total_fee ).
ENDMETHOD.
METHOD invalid_tariff_is_ignored.
DATA(lt_result) = mo_cut->summarize( VALUE {{p}}if_park_eval=>tt_session(
( park_id = 'P001' tariff = 'X' duration_min = 120 ) ) ).
cl_abap_unit_assert=>assert_equals( exp = 0 act = lines( lt_result ) ).
ENDMETHOD.
METHOD groups_by_park.
DATA(lt_result) = mo_cut->summarize( VALUE {{p}}if_park_eval=>tt_session(
( park_id = 'P002' tariff = 'A' duration_min = 60 )
( park_id = 'P001' tariff = 'A' duration_min = 60 ) ) ).
cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_result ) ).
cl_abap_unit_assert=>assert_equals( exp = 'P001' act = lt_result[ 1 ]-park_id ).
cl_abap_unit_assert=>assert_equals( exp = 'P002' act = lt_result[ 2 ]-park_id ).
ENDMETHOD.
METHOD empty_input_gives_no_row.
DATA(lt_result) = mo_cut->summarize( VALUE {{p}}if_park_eval=>tt_session( ) ).
cl_abap_unit_assert=>assert_equals( exp = 0 act = lines( lt_result ) ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,22 @@
INTERFACE {{p}}if_park_eval PUBLIC.
TYPES:
ty_park_id TYPE c LENGTH 4,
ty_tariff TYPE c LENGTH 1,
BEGIN OF ty_session,
park_id TYPE ty_park_id,
tariff TYPE ty_tariff,
duration_min TYPE i,
END OF ty_session,
tt_session TYPE STANDARD TABLE OF ty_session WITH EMPTY KEY,
BEGIN OF ty_summary,
park_id TYPE ty_park_id,
session_cnt TYPE i,
total_min TYPE i,
total_fee TYPE p LENGTH 8 DECIMALS 2,
END OF ty_summary,
tt_summary TYPE STANDARD TABLE OF ty_summary WITH EMPTY KEY.
METHODS summarize
IMPORTING it_session TYPE tt_session
RETURNING VALUE(rt_summary) TYPE tt_summary.
ENDINTERFACE.

View File

@@ -0,0 +1,57 @@
# 1. Goal
Summarise the parking sessions of the car parks of a car park operator. The
operations team calls the class for each day. The class returns one row for each
car park with the number of sessions, the total parking time and the total fee.
# 2. Open questions
None.
# 3. Context
- The interface {{P}}IF_PARK_EVAL exists in package $TMP. It is active.
- The interface has the type TY_PARK_ID (CHAR 4), the type TY_TARIFF (CHAR 1),
the structure TY_SESSION with the components PARK_ID, TARIFF and DURATION_MIN,
the table type TT_SESSION (a standard table of TY_SESSION with an empty key),
the structure TY_SUMMARY with the components PARK_ID, SESSION_CNT, TOTAL_MIN
and TOTAL_FEE, the table type TT_SUMMARY (a standard table of TY_SUMMARY with
an empty key), and one method:
SUMMARIZE IMPORTING it_session TYPE tt_session
RETURNING VALUE(rt_summary) TYPE tt_summary.
- DURATION_MIN is the parking time of one session in minutes.
- The operations program collects the sessions of one day and passes them to the
class.
# 4. Contract
- Create the class {{P}}PARKING_EVAL in package $TMP.
- The class is public and final. It has a public constructor without parameters.
- The class implements {{P}}IF_PARK_EVAL.
- Do not add other public methods.
# 5. Business rules
1. A session is valid when its tariff is A, B or C and its duration is greater
than 0 minutes. Ignore an invalid session completely. Do not count it, do not
add its duration and do not add a fee.
2. The first 30 minutes of a valid session are free.
3. The operator charges each started hour after the first 30 minutes. The first
started hour covers the minutes 31 to 90, the second started hour covers the
minutes 91 to 150, and so on.
4. The price of one started hour depends on the tariff:
A = 2.00 EUR, B = 3.50 EUR, C = 5.00 EUR.
5. The fee of one session is at most 20.00 EUR.
6. The result has one row for each car park with at least one valid session.
7. SESSION_CNT is the number of valid sessions of the car park.
8. TOTAL_MIN is the sum of the durations of the valid sessions of the car park.
9. TOTAL_FEE is the sum of the fees of the valid sessions of the car park.
10. Sort the result in ascending order of PARK_ID.
11. An empty input gives an empty result.
# 6. Constraints
- Release target: SAP_BASIS 816 (ABAP Platform 2025).
- 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_PARK_EVAL. Do not create database tables,
CDS views or other objects.
# 7. Acceptance
- The class is active and has no syntax error.
- The hidden tests pass.
- Write your own ABAP Unit tests for the class.

View File

@@ -0,0 +1,52 @@
{
"id": "G1073",
"category": "C",
"object_type": "CLAS",
"difficulty": 2,
"release_target": "v816",
"expected_outcome": "implement",
"budget": {
"max_tool_calls": 80,
"max_activations": 20
},
"seed": [
{
"type": "INTF",
"name": "{{P}}IF_PARK_EVAL",
"file": "seed/if_park_eval.intf.abap",
"description": "Car park session and summary contract"
}
],
"contract": [
{
"type": "CLAS",
"name": "{{P}}PARKING_EVAL",
"implements": "{{P}}IF_PARK_EVAL"
}
],
"out_of_scope": [
"{{P}}IF_PARK_EVAL"
],
"hidden_tests": [
{
"type": "CLAS",
"name": "{{P}}T31_HIDDEN",
"file": "hidden/t31_hidden.clas.abap",
"description": "T31 hidden tests for the car park summary"
}
],
"reference": [
{
"type": "CLAS",
"name": "{{P}}PARKING_EVAL",
"file": "reference/parking_eval.clas.abap",
"description": "Car park session summary",
"testclasses_file": "reference/parking_eval.testclasses.abap"
}
],
"craft_checks": [
"method_length",
"table_kind",
"access_path"
]
}