Pipeline controller: plan 2 (hard +, error +50 %), backlog throttle, 2 trajectory workers, stop rules, summaries every 50; budget reserve

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Kral
2026-10-05 13:35:54 +02:00
parent 1c4667a0fc
commit 13360292dd
781 changed files with 50211 additions and 22 deletions

View File

@@ -0,0 +1,87 @@
CLASS {{p}}piano_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_piano_type TYPE c LENGTH 1.
TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2.
TYPES ty_reason TYPE c LENGTH 8.
TYPES:
BEGIN OF ty_charge,
reason TYPE ty_reason,
base_fee TYPE ty_amount,
travel_fee TYPE ty_amount,
extra_fee TYPE ty_amount,
total_fee TYPE ty_amount,
END OF ty_charge.
CONSTANTS:
BEGIN OF c_reason,
ok TYPE ty_reason VALUE 'OK',
unknown TYPE ty_reason VALUE 'UNKNOWN',
distance TYPE ty_reason VALUE 'DISTANCE',
pitch TYPE ty_reason VALUE 'PITCH',
END OF c_reason.
METHODS calculate
IMPORTING iv_piano_type TYPE ty_piano_type
iv_distance_km TYPE i
iv_pitch_cents TYPE i
RETURNING VALUE(rs_charge) TYPE ty_charge.
PRIVATE SECTION.
CONSTANTS c_standard_minutes TYPE i VALUE 45.
METHODS rate_for
IMPORTING iv_piano_type TYPE ty_piano_type
RETURNING VALUE(rs_rate) TYPE {{p}}tune_rates=>ty_rate.
METHODS calc_extra_fee
IMPORTING iv_pitch_cents TYPE i
is_rate TYPE {{p}}tune_rates=>ty_rate
RETURNING VALUE(rv_fee) TYPE ty_amount.
METHODS calc_travel_fee
IMPORTING iv_distance_km TYPE i
RETURNING VALUE(rv_fee) TYPE ty_amount.
ENDCLASS.
CLASS {{p}}piano_pricer IMPLEMENTATION.
METHOD calculate.
DATA(ls_rate) = rate_for( iv_piano_type ).
IF ls_rate IS INITIAL.
rs_charge = VALUE #( reason = c_reason-unknown ).
RETURN.
ENDIF.
IF iv_distance_km < 0.
rs_charge = VALUE #( reason = c_reason-distance ).
RETURN.
ENDIF.
IF iv_pitch_cents < 0.
rs_charge = VALUE #( reason = c_reason-pitch ).
RETURN.
ENDIF.
rs_charge = VALUE #( reason = c_reason-ok
base_fee = ls_rate-base_fee
travel_fee = calc_travel_fee( iv_distance_km )
extra_fee = calc_extra_fee( iv_pitch_cents = iv_pitch_cents
is_rate = ls_rate ) ).
rs_charge-total_fee = rs_charge-base_fee + rs_charge-travel_fee - rs_charge-extra_fee.
ENDMETHOD.
METHOD rate_for.
DATA(lo_rates) = NEW {{p}}tune_rates( ).
DATA(lt_rate) = lo_rates->get_rates( ).
READ TABLE lt_rate WITH KEY piano_type = iv_piano_type INTO rs_rate.
ENDMETHOD.
METHOD calc_extra_fee.
DATA(lv_extra_minutes) = c_standard_minutes + iv_pitch_cents - is_rate-incl_minutes.
IF lv_extra_minutes <= 0.
RETURN.
ENDIF.
rv_fee = lv_extra_minutes * is_rate-minute_fee.
ENDMETHOD.
METHOD calc_travel_fee.
DATA(lv_chargeable_km) = iv_distance_km - {{p}}tune_rates=>c_free_km.
IF lv_chargeable_km <= 0.
RETURN.
ENDIF.
rv_fee = lv_chargeable_km * {{p}}tune_rates=>c_km_fee.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,87 @@
CLASS {{p}}piano_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_piano_type TYPE c LENGTH 1.
TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2.
TYPES ty_reason TYPE c LENGTH 8.
TYPES:
BEGIN OF ty_charge,
reason TYPE ty_reason,
base_fee TYPE ty_amount,
travel_fee TYPE ty_amount,
extra_fee TYPE ty_amount,
total_fee TYPE ty_amount,
END OF ty_charge.
CONSTANTS:
BEGIN OF c_reason,
ok TYPE ty_reason VALUE 'OK',
unknown TYPE ty_reason VALUE 'UNKNOWN',
distance TYPE ty_reason VALUE 'DISTANCE',
pitch TYPE ty_reason VALUE 'PITCH',
END OF c_reason.
METHODS calculate
IMPORTING iv_piano_type TYPE ty_piano_type
iv_distance_km TYPE i
iv_pitch_cents TYPE i
RETURNING VALUE(rs_charge) TYPE ty_charge.
PRIVATE SECTION.
CONSTANTS c_standard_minutes TYPE i VALUE 45.
METHODS rate_for
IMPORTING iv_piano_type TYPE ty_piano_type
RETURNING VALUE(rs_rate) TYPE {{p}}tune_rates=>ty_rate.
METHODS calc_extra_fee
IMPORTING iv_pitch_cents TYPE i
is_rate TYPE {{p}}tune_rates=>ty_rate
RETURNING VALUE(rv_fee) TYPE ty_amount.
METHODS calc_travel_fee
IMPORTING iv_distance_km TYPE i
RETURNING VALUE(rv_fee) TYPE ty_amount.
ENDCLASS.
CLASS {{p}}piano_pricer IMPLEMENTATION.
METHOD calculate.
DATA(ls_rate) = rate_for( iv_piano_type ).
IF ls_rate IS INITIAL.
rs_charge = VALUE #( reason = c_reason-unknown ).
RETURN.
ENDIF.
IF iv_distance_km < 0.
rs_charge = VALUE #( reason = c_reason-distance ).
RETURN.
ENDIF.
IF iv_pitch_cents < 0.
rs_charge = VALUE #( reason = c_reason-pitch ).
RETURN.
ENDIF.
rs_charge = VALUE #( reason = c_reason-ok
base_fee = ls_rate-base_fee
travel_fee = calc_travel_fee( iv_distance_km )
extra_fee = calc_extra_fee( iv_pitch_cents = iv_pitch_cents
is_rate = ls_rate ) ).
rs_charge-total_fee = rs_charge-base_fee + rs_charge-travel_fee + rs_charge-extra_fee.
ENDMETHOD.
METHOD rate_for.
DATA(lo_rates) = NEW {{p}}tune_rates( ).
DATA(lt_rate) = lo_rates->get_rates( ).
READ TABLE lt_rate WITH KEY piano_type = iv_piano_type INTO rs_rate.
ENDMETHOD.
METHOD calc_extra_fee.
DATA(lv_extra_minutes) = c_standard_minutes + iv_pitch_cents - is_rate-incl_minutes.
IF lv_extra_minutes > 0.
RETURN.
ENDIF.
rv_fee = lv_extra_minutes * is_rate-minute_fee.
ENDMETHOD.
METHOD calc_travel_fee.
DATA(lv_chargeable_km) = iv_distance_km - {{p}}tune_rates=>c_free_km.
IF lv_chargeable_km <= 0.
RETURN.
ENDIF.
rv_fee = lv_chargeable_km * {{p}}tune_rates=>c_km_fee.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,87 @@
CLASS {{p}}piano_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_piano_type TYPE c LENGTH 1.
TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2.
TYPES ty_reason TYPE c LENGTH 8.
TYPES:
BEGIN OF ty_charge,
reason TYPE ty_reason,
base_fee TYPE ty_amount,
travel_fee TYPE ty_amount,
extra_fee TYPE ty_amount,
total_fee TYPE ty_amount,
END OF ty_charge.
CONSTANTS:
BEGIN OF c_reason,
ok TYPE ty_reason VALUE 'OK',
unknown TYPE ty_reason VALUE 'UNKNOWN',
distance TYPE ty_reason VALUE 'DISTANCE',
pitch TYPE ty_reason VALUE 'PITCH',
END OF c_reason.
METHODS calculate
IMPORTING iv_piano_type TYPE ty_piano_type
iv_distance_km TYPE i
iv_pitch_cents TYPE i
RETURNING VALUE(rs_charge) TYPE ty_charge.
PRIVATE SECTION.
CONSTANTS c_standard_minutes TYPE i VALUE 45.
METHODS rate_for
IMPORTING iv_piano_type TYPE ty_piano_type
RETURNING VALUE(rs_rate) TYPE {{p}}tune_rates=>ty_rate.
METHODS calc_extra_fee
IMPORTING iv_pitch_cents TYPE i
is_rate TYPE {{p}}tune_rates=>ty_rate
RETURNING VALUE(rv_fee) TYPE ty_amount.
METHODS calc_travel_fee
IMPORTING iv_distance_km TYPE i
RETURNING VALUE(rv_fee) TYPE ty_amount.
ENDCLASS.
CLASS {{p}}piano_pricer IMPLEMENTATION.
METHOD calculate.
DATA(ls_rate) = rate_for( iv_piano_type ).
IF ls_rate IS INITIAL.
rs_charge = VALUE #( reason = c_reason-unknown ).
RETURN.
ENDIF.
IF iv_distance_km < 0.
rs_charge = VALUE #( reason = c_reason-distance ).
RETURN.
ENDIF.
IF iv_pitch_cents < 0.
rs_charge = VALUE #( reason = c_reason-pitch ).
RETURN.
ENDIF.
rs_charge = VALUE #( reason = c_reason-ok
base_fee = ls_rate-base_fee
travel_fee = calc_travel_fee( iv_distance_km )
extra_fee = calc_extra_fee( iv_pitch_cents = iv_pitch_cents
is_rate = ls_rate ) ).
rs_charge-total_fee = rs_charge-base_fee + rs_charge-travel_fee + rs_charge-extra_fee.
ENDMETHOD.
METHOD rate_for.
DATA(lo_rates) = NEW {{p}}tune_rates( ).
DATA(lt_rate) = lo_rates->get_rates( ).
READ TABLE lt_rate WITH KEY piano_type = iv_piano_type INTO rs_rate.
ENDMETHOD.
METHOD calc_extra_fee.
DATA(lv_extra_minutes) = c_standard_minutes + iv_pitch_cents - is_rate-incl_minutes.
IF lv_extra_minutes <= 0.
RETURN.
ENDIF.
rv_fee = lv_extra_minutes / is_rate-minute_fee.
ENDMETHOD.
METHOD calc_travel_fee.
DATA(lv_chargeable_km) = iv_distance_km - {{p}}tune_rates=>c_free_km.
IF lv_chargeable_km <= 0.
RETURN.
ENDIF.
rv_fee = lv_chargeable_km * {{p}}tune_rates=>c_km_fee.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,87 @@
CLASS {{p}}piano_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_piano_type TYPE c LENGTH 1.
TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2.
TYPES ty_reason TYPE c LENGTH 8.
TYPES:
BEGIN OF ty_charge,
reason TYPE ty_reason,
base_fee TYPE ty_amount,
travel_fee TYPE ty_amount,
extra_fee TYPE ty_amount,
total_fee TYPE ty_amount,
END OF ty_charge.
CONSTANTS:
BEGIN OF c_reason,
ok TYPE ty_reason VALUE 'OK',
unknown TYPE ty_reason VALUE 'UNKNOWN',
distance TYPE ty_reason VALUE 'DISTANCE',
pitch TYPE ty_reason VALUE 'PITCH',
END OF c_reason.
METHODS calculate
IMPORTING iv_piano_type TYPE ty_piano_type
iv_distance_km TYPE i
iv_pitch_cents TYPE i
RETURNING VALUE(rs_charge) TYPE ty_charge.
PRIVATE SECTION.
CONSTANTS c_standard_minutes TYPE i VALUE 45.
METHODS rate_for
IMPORTING iv_piano_type TYPE ty_piano_type
RETURNING VALUE(rs_rate) TYPE {{p}}tune_rates=>ty_rate.
METHODS calc_extra_fee
IMPORTING iv_pitch_cents TYPE i
is_rate TYPE {{p}}tune_rates=>ty_rate
RETURNING VALUE(rv_fee) TYPE ty_amount.
METHODS calc_travel_fee
IMPORTING iv_distance_km TYPE i
RETURNING VALUE(rv_fee) TYPE ty_amount.
ENDCLASS.
CLASS {{p}}piano_pricer IMPLEMENTATION.
METHOD calculate.
DATA(ls_rate) = rate_for( iv_piano_type ).
IF ls_rate IS INITIAL.
rs_charge = VALUE #( reason = c_reason-unknown ).
RETURN.
ENDIF.
IF iv_distance_km < 0.
rs_charge = VALUE #( reason = c_reason-distance ).
RETURN.
ENDIF.
IF iv_pitch_cents < 0.
rs_charge = VALUE #( reason = c_reason-pitch ).
RETURN.
ENDIF.
rs_charge = VALUE #( reason = c_reason-ok
base_fee = ls_rate-base_fee
travel_fee = calc_travel_fee( iv_distance_km )
extra_fee = calc_extra_fee( iv_pitch_cents = iv_pitch_cents
is_rate = ls_rate ) ).
rs_charge-total_fee = rs_charge-base_fee + rs_charge-travel_fee + rs_charge-extra_fee.
ENDMETHOD.
METHOD rate_for.
DATA(lo_rates) = NEW {{p}}tune_rates( ).
DATA(lt_rate) = lo_rates->get_rates( ).
READ TABLE lt_rate WITH KEY piano_type = iv_piano_type INTO rs_rate.
ENDMETHOD.
METHOD calc_extra_fee.
DATA(lv_extra_minutes) = c_standard_minutes + iv_pitch_cents - is_rate-incl_minutes.
IF lv_extra_minutes <= 0.
RETURN.
ENDIF.
rv_fee = lv_extra_minutes * is_rate-minute_fee.
ENDMETHOD.
METHOD calc_travel_fee.
DATA(lv_chargeable_km) = iv_distance_km - {{p}}tune_rates=>c_free_km.
IF lv_chargeable_km > 0.
RETURN.
ENDIF.
rv_fee = lv_chargeable_km * {{p}}tune_rates=>c_km_fee.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,87 @@
CLASS {{p}}piano_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_piano_type TYPE c LENGTH 1.
TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2.
TYPES ty_reason TYPE c LENGTH 8.
TYPES:
BEGIN OF ty_charge,
reason TYPE ty_reason,
base_fee TYPE ty_amount,
travel_fee TYPE ty_amount,
extra_fee TYPE ty_amount,
total_fee TYPE ty_amount,
END OF ty_charge.
CONSTANTS:
BEGIN OF c_reason,
ok TYPE ty_reason VALUE 'OK',
unknown TYPE ty_reason VALUE 'UNKNOWN',
distance TYPE ty_reason VALUE 'DISTANCE',
pitch TYPE ty_reason VALUE 'PITCH',
END OF c_reason.
METHODS calculate
IMPORTING iv_piano_type TYPE ty_piano_type
iv_distance_km TYPE i
iv_pitch_cents TYPE i
RETURNING VALUE(rs_charge) TYPE ty_charge.
PRIVATE SECTION.
CONSTANTS c_standard_minutes TYPE i VALUE 45.
METHODS rate_for
IMPORTING iv_piano_type TYPE ty_piano_type
RETURNING VALUE(rs_rate) TYPE {{p}}tune_rates=>ty_rate.
METHODS calc_extra_fee
IMPORTING iv_pitch_cents TYPE i
is_rate TYPE {{p}}tune_rates=>ty_rate
RETURNING VALUE(rv_fee) TYPE ty_amount.
METHODS calc_travel_fee
IMPORTING iv_distance_km TYPE i
RETURNING VALUE(rv_fee) TYPE ty_amount.
ENDCLASS.
CLASS {{p}}piano_pricer IMPLEMENTATION.
METHOD calculate.
DATA(ls_rate) = rate_for( iv_piano_type ).
IF ls_rate IS INITIAL.
rs_charge = VALUE #( reason = c_reason-unknown ).
RETURN.
ENDIF.
IF iv_distance_km < 0.
rs_charge = VALUE #( reason = c_reason-distance ).
RETURN.
ENDIF.
IF iv_pitch_cents < 0.
rs_charge = VALUE #( reason = c_reason-pitch ).
RETURN.
ENDIF.
rs_charge = VALUE #( reason = c_reason-ok
base_fee = ls_rate-base_fee
travel_fee = calc_travel_fee( iv_distance_km )
extra_fee = calc_extra_fee( iv_pitch_cents = iv_pitch_cents
is_rate = ls_rate ) ).
rs_charge-total_fee = rs_charge-base_fee + rs_charge-travel_fee + rs_charge-extra_fee.
ENDMETHOD.
METHOD rate_for.
DATA(lo_rates) = NEW {{p}}tune_rates( ).
DATA(lt_rate) = lo_rates->get_rates( ).
READ TABLE lt_rate WITH KEY piano_type = iv_piano_type INTO rs_rate.
ENDMETHOD.
METHOD calc_extra_fee.
DATA(lv_extra_minutes) = c_standard_minutes + iv_pitch_cents - is_rate-incl_minutes.
IF lv_extra_minutes <= 0.
RETURN.
ENDIF.
rv_fee = lv_extra_minutes * is_rate-minute_fee.
ENDMETHOD.
METHOD calc_travel_fee.
DATA(lv_chargeable_km) = iv_distance_km - {{p}}tune_rates=>c_free_km.
IF lv_chargeable_km <= 0.
RETURN.
ENDIF.
rv_fee = lv_chargeable_km / {{p}}tune_rates=>c_km_fee.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,19 @@
{
"id": "G1037",
"pool": "train",
"object_type": "CLAS",
"category": "F",
"attempts": [
{
"stage": "validate",
"oracle": 100.0,
"null": 0,
"mutation": {
"valid": 5,
"killed": 5,
"ok": true
}
}
],
"accepted": true
}

View File

@@ -0,0 +1,140 @@
CLASS {{p}}t42_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA mo_cut TYPE REF TO {{p}}piano_pricer.
METHODS setup.
METHODS assert_charge
IMPORTING is_charge TYPE {{p}}piano_pricer=>ty_charge
iv_reason TYPE {{p}}piano_pricer=>ty_reason
iv_base TYPE {{p}}piano_pricer=>ty_amount
iv_travel TYPE {{p}}piano_pricer=>ty_amount
iv_extra TYPE {{p}}piano_pricer=>ty_amount
iv_total TYPE {{p}}piano_pricer=>ty_amount.
METHODS upright_basic FOR TESTING.
METHODS grand_pitch_raise FOR TESTING.
METHODS travel_beyond_free FOR TESTING.
METHODS digital_piano FOR TESTING.
METHODS studio_piano FOR TESTING.
METHODS concert_grand FOR TESTING.
METHODS unknown_type FOR TESTING.
METHODS negative_distance FOR TESTING.
METHODS negative_pitch FOR TESTING.
METHODS unknown_wins FOR TESTING.
METHODS exact_limits FOR TESTING.
ENDCLASS.
CLASS {{p}}t42_hidden IMPLEMENTATION.
METHOD setup.
mo_cut = NEW {{p}}piano_pricer( ).
ENDMETHOD.
METHOD assert_charge.
cl_abap_unit_assert=>assert_equals( exp = iv_reason act = is_charge-reason msg = 'reason' ).
cl_abap_unit_assert=>assert_equals( exp = iv_base act = is_charge-base_fee msg = 'base_fee' ).
cl_abap_unit_assert=>assert_equals( exp = iv_travel act = is_charge-travel_fee msg = 'travel_fee' ).
cl_abap_unit_assert=>assert_equals( exp = iv_extra act = is_charge-extra_fee msg = 'extra_fee' ).
cl_abap_unit_assert=>assert_equals( exp = iv_total act = is_charge-total_fee msg = 'total_fee' ).
ENDMETHOD.
METHOD upright_basic.
DATA(ls_charge) = mo_cut->calculate( iv_piano_type = 'U'
iv_distance_km = 5
iv_pitch_cents = 0 ).
assert_charge( is_charge = ls_charge
iv_reason = 'OK' iv_base = '89.00' iv_travel = '0.00'
iv_extra = '0.00' iv_total = '89.00' ).
ENDMETHOD.
METHOD grand_pitch_raise.
DATA(ls_charge) = mo_cut->calculate( iv_piano_type = 'G'
iv_distance_km = 0
iv_pitch_cents = 40 ).
assert_charge( is_charge = ls_charge
iv_reason = 'OK' iv_base = '129.00' iv_travel = '0.00'
iv_extra = '15.00' iv_total = '144.00' ).
ENDMETHOD.
METHOD travel_beyond_free.
DATA(ls_charge) = mo_cut->calculate( iv_piano_type = 'U'
iv_distance_km = 25
iv_pitch_cents = 0 ).
assert_charge( is_charge = ls_charge
iv_reason = 'OK' iv_base = '89.00' iv_travel = '12.00'
iv_extra = '0.00' iv_total = '101.00' ).
ENDMETHOD.
METHOD digital_piano.
DATA(ls_charge) = mo_cut->calculate( iv_piano_type = 'D'
iv_distance_km = 10
iv_pitch_cents = 10 ).
assert_charge( is_charge = ls_charge
iv_reason = 'OK' iv_base = '69.00' iv_travel = '0.00'
iv_extra = '10.00' iv_total = '79.00' ).
ENDMETHOD.
METHOD studio_piano.
DATA(ls_charge) = mo_cut->calculate( iv_piano_type = 'S'
iv_distance_km = 12
iv_pitch_cents = 20 ).
assert_charge( is_charge = ls_charge
iv_reason = 'OK' iv_base = '99.00' iv_travel = '1.60'
iv_extra = '6.50' iv_total = '107.10' ).
ENDMETHOD.
METHOD concert_grand.
DATA(ls_charge) = mo_cut->calculate( iv_piano_type = 'C'
iv_distance_km = 40
iv_pitch_cents = 60 ).
assert_charge( is_charge = ls_charge
iv_reason = 'OK' iv_base = '149.00' iv_travel = '24.00'
iv_extra = '27.00' iv_total = '200.00' ).
ENDMETHOD.
METHOD unknown_type.
DATA(ls_charge) = mo_cut->calculate( iv_piano_type = 'Z'
iv_distance_km = 5
iv_pitch_cents = 0 ).
assert_charge( is_charge = ls_charge
iv_reason = 'UNKNOWN' iv_base = '0.00' iv_travel = '0.00'
iv_extra = '0.00' iv_total = '0.00' ).
ENDMETHOD.
METHOD negative_distance.
DATA(ls_charge) = mo_cut->calculate( iv_piano_type = 'U'
iv_distance_km = -1
iv_pitch_cents = 0 ).
assert_charge( is_charge = ls_charge
iv_reason = 'DISTANCE' iv_base = '0.00' iv_travel = '0.00'
iv_extra = '0.00' iv_total = '0.00' ).
ENDMETHOD.
METHOD negative_pitch.
DATA(ls_charge) = mo_cut->calculate( iv_piano_type = 'U'
iv_distance_km = 5
iv_pitch_cents = -1 ).
assert_charge( is_charge = ls_charge
iv_reason = 'PITCH' iv_base = '0.00' iv_travel = '0.00'
iv_extra = '0.00' iv_total = '0.00' ).
ENDMETHOD.
METHOD unknown_wins.
DATA(ls_charge) = mo_cut->calculate( iv_piano_type = 'Z'
iv_distance_km = -5
iv_pitch_cents = -5 ).
assert_charge( is_charge = ls_charge
iv_reason = 'UNKNOWN' iv_base = '0.00' iv_travel = '0.00'
iv_extra = '0.00' iv_total = '0.00' ).
ENDMETHOD.
METHOD exact_limits.
DATA(ls_charge) = mo_cut->calculate( iv_piano_type = 'U'
iv_distance_km = 10
iv_pitch_cents = 15 ).
assert_charge( is_charge = ls_charge
iv_reason = 'OK' iv_base = '89.00' iv_travel = '0.00'
iv_extra = '0.00' iv_total = '89.00' ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,70 @@
{
"task": "G1037",
"mutants": [
{
"object": "{{P}}PIANO_PRICER",
"mutant": "line 63: + -> - (arith)",
"status": "killed",
"hidden": "7/11",
"failed_tests": [
"CONCERT_GRAND",
"DIGITAL_PIANO",
"GRAND_PITCH_RAISE",
"STUDIO_PIANO"
]
},
{
"object": "{{P}}PIANO_PRICER",
"mutant": "line 74: <= -> > (rel)",
"status": "killed",
"hidden": "5/11",
"failed_tests": [
"CONCERT_GRAND",
"DIGITAL_PIANO",
"GRAND_PITCH_RAISE",
"STUDIO_PIANO",
"TRAVEL_BEYOND_FREE",
"UPRIGHT_BASIC"
]
},
{
"object": "{{P}}PIANO_PRICER",
"mutant": "line 77: * -> / (arith)",
"status": "killed",
"hidden": "8/11",
"failed_tests": [
"CONCERT_GRAND",
"GRAND_PITCH_RAISE",
"STUDIO_PIANO"
]
},
{
"object": "{{P}}PIANO_PRICER",
"mutant": "line 82: <= -> > (rel)",
"status": "killed",
"hidden": "6/11",
"failed_tests": [
"CONCERT_GRAND",
"GRAND_PITCH_RAISE",
"STUDIO_PIANO",
"TRAVEL_BEYOND_FREE",
"UPRIGHT_BASIC"
]
},
{
"object": "{{P}}PIANO_PRICER",
"mutant": "line 85: * -> / (arith)",
"status": "killed",
"hidden": "8/11",
"failed_tests": [
"CONCERT_GRAND",
"STUDIO_PIANO",
"TRAVEL_BEYOND_FREE"
]
}
],
"valid": 5,
"killed": 5,
"kill_rate": 1.0,
"ok": true
}

View File

@@ -0,0 +1,87 @@
CLASS {{p}}piano_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_piano_type TYPE c LENGTH 1.
TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2.
TYPES ty_reason TYPE c LENGTH 8.
TYPES:
BEGIN OF ty_charge,
reason TYPE ty_reason,
base_fee TYPE ty_amount,
travel_fee TYPE ty_amount,
extra_fee TYPE ty_amount,
total_fee TYPE ty_amount,
END OF ty_charge.
CONSTANTS:
BEGIN OF c_reason,
ok TYPE ty_reason VALUE 'OK',
unknown TYPE ty_reason VALUE 'UNKNOWN',
distance TYPE ty_reason VALUE 'DISTANCE',
pitch TYPE ty_reason VALUE 'PITCH',
END OF c_reason.
METHODS calculate
IMPORTING iv_piano_type TYPE ty_piano_type
iv_distance_km TYPE i
iv_pitch_cents TYPE i
RETURNING VALUE(rs_charge) TYPE ty_charge.
PRIVATE SECTION.
CONSTANTS c_standard_minutes TYPE i VALUE 45.
METHODS rate_for
IMPORTING iv_piano_type TYPE ty_piano_type
RETURNING VALUE(rs_rate) TYPE {{p}}tune_rates=>ty_rate.
METHODS calc_extra_fee
IMPORTING iv_pitch_cents TYPE i
is_rate TYPE {{p}}tune_rates=>ty_rate
RETURNING VALUE(rv_fee) TYPE ty_amount.
METHODS calc_travel_fee
IMPORTING iv_distance_km TYPE i
RETURNING VALUE(rv_fee) TYPE ty_amount.
ENDCLASS.
CLASS {{p}}piano_pricer IMPLEMENTATION.
METHOD calculate.
DATA(ls_rate) = rate_for( iv_piano_type ).
IF ls_rate IS INITIAL.
rs_charge = VALUE #( reason = c_reason-unknown ).
RETURN.
ENDIF.
IF iv_distance_km < 0.
rs_charge = VALUE #( reason = c_reason-distance ).
RETURN.
ENDIF.
IF iv_pitch_cents < 0.
rs_charge = VALUE #( reason = c_reason-pitch ).
RETURN.
ENDIF.
rs_charge = VALUE #( reason = c_reason-ok
base_fee = ls_rate-base_fee
travel_fee = calc_travel_fee( iv_distance_km )
extra_fee = calc_extra_fee( iv_pitch_cents = iv_pitch_cents
is_rate = ls_rate ) ).
rs_charge-total_fee = rs_charge-base_fee + rs_charge-travel_fee + rs_charge-extra_fee.
ENDMETHOD.
METHOD rate_for.
DATA(lo_rates) = NEW {{p}}tune_rates( ).
DATA(lt_rate) = lo_rates->get_rates( ).
READ TABLE lt_rate WITH KEY piano_type = iv_piano_type INTO rs_rate.
ENDMETHOD.
METHOD calc_extra_fee.
DATA(lv_extra_minutes) = c_standard_minutes + iv_pitch_cents - is_rate-incl_minutes.
IF lv_extra_minutes <= 0.
RETURN.
ENDIF.
rv_fee = lv_extra_minutes * is_rate-minute_fee.
ENDMETHOD.
METHOD calc_travel_fee.
DATA(lv_chargeable_km) = iv_distance_km - {{p}}tune_rates=>c_free_km.
IF lv_chargeable_km <= 0.
RETURN.
ENDIF.
rv_fee = lv_chargeable_km * {{p}}tune_rates=>c_km_fee.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,84 @@
CLASS ltc_piano_pricer DEFINITION FINAL FOR TESTING
DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA mo_cut TYPE REF TO {{p}}piano_pricer.
METHODS setup.
METHODS assert_charge
IMPORTING is_charge TYPE {{p}}piano_pricer=>ty_charge
iv_reason TYPE {{p}}piano_pricer=>ty_reason
iv_base TYPE {{p}}piano_pricer=>ty_amount
iv_travel TYPE {{p}}piano_pricer=>ty_amount
iv_extra TYPE {{p}}piano_pricer=>ty_amount
iv_total TYPE {{p}}piano_pricer=>ty_amount.
METHODS upright_visit FOR TESTING.
METHODS pitch_raise FOR TESTING.
METHODS far_visit FOR TESTING.
METHODS unknown_piano FOR TESTING.
METHODS invalid_distance FOR TESTING.
METHODS invalid_pitch FOR TESTING.
ENDCLASS.
CLASS ltc_piano_pricer IMPLEMENTATION.
METHOD setup.
mo_cut = NEW {{p}}piano_pricer( ).
ENDMETHOD.
METHOD assert_charge.
cl_abap_unit_assert=>assert_equals( exp = iv_reason act = is_charge-reason ).
cl_abap_unit_assert=>assert_equals( exp = iv_base act = is_charge-base_fee ).
cl_abap_unit_assert=>assert_equals( exp = iv_travel act = is_charge-travel_fee ).
cl_abap_unit_assert=>assert_equals( exp = iv_extra act = is_charge-extra_fee ).
cl_abap_unit_assert=>assert_equals( exp = iv_total act = is_charge-total_fee ).
ENDMETHOD.
METHOD upright_visit.
DATA(ls_charge) = mo_cut->calculate( iv_piano_type = 'U'
iv_distance_km = 3
iv_pitch_cents = 0 ).
assert_charge( is_charge = ls_charge iv_reason = 'OK' iv_base = '89.00'
iv_travel = '0.00' iv_extra = '0.00' iv_total = '89.00' ).
ENDMETHOD.
METHOD pitch_raise.
DATA(ls_charge) = mo_cut->calculate( iv_piano_type = 'G'
iv_distance_km = 0
iv_pitch_cents = 40 ).
assert_charge( is_charge = ls_charge iv_reason = 'OK' iv_base = '129.00'
iv_travel = '0.00' iv_extra = '15.00' iv_total = '144.00' ).
ENDMETHOD.
METHOD far_visit.
DATA(ls_charge) = mo_cut->calculate( iv_piano_type = 'U'
iv_distance_km = 25
iv_pitch_cents = 0 ).
assert_charge( is_charge = ls_charge iv_reason = 'OK' iv_base = '89.00'
iv_travel = '12.00' iv_extra = '0.00' iv_total = '101.00' ).
ENDMETHOD.
METHOD unknown_piano.
DATA(ls_charge) = mo_cut->calculate( iv_piano_type = 'Z'
iv_distance_km = 0
iv_pitch_cents = 0 ).
assert_charge( is_charge = ls_charge iv_reason = 'UNKNOWN' iv_base = '0.00'
iv_travel = '0.00' iv_extra = '0.00' iv_total = '0.00' ).
ENDMETHOD.
METHOD invalid_distance.
DATA(ls_charge) = mo_cut->calculate( iv_piano_type = 'U'
iv_distance_km = -1
iv_pitch_cents = 0 ).
assert_charge( is_charge = ls_charge iv_reason = 'DISTANCE' iv_base = '0.00'
iv_travel = '0.00' iv_extra = '0.00' iv_total = '0.00' ).
ENDMETHOD.
METHOD invalid_pitch.
DATA(ls_charge) = mo_cut->calculate( iv_piano_type = 'U'
iv_distance_km = 0
iv_pitch_cents = -1 ).
assert_charge( is_charge = ls_charge iv_reason = 'PITCH' iv_base = '0.00'
iv_travel = '0.00' iv_extra = '0.00' iv_total = '0.00' ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,30 @@
CLASS {{p}}tune_rates DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2.
TYPES:
BEGIN OF ty_rate,
piano_type TYPE c LENGTH 1,
base_fee TYPE ty_amount,
incl_minutes TYPE i,
minute_fee TYPE ty_amount,
END OF ty_rate.
TYPES tt_rate TYPE STANDARD TABLE OF ty_rate WITH EMPTY KEY.
CONSTANTS:
c_free_km TYPE i VALUE 10,
c_km_fee TYPE ty_amount VALUE '0.80'.
METHODS get_rates
RETURNING VALUE(rt_rate) TYPE tt_rate.
ENDCLASS.
CLASS {{p}}tune_rates IMPLEMENTATION.
METHOD get_rates.
" U = upright, G = grand, D = digital, C = concert grand, S = studio
rt_rate = VALUE #(
( piano_type = 'U' base_fee = '89.00' incl_minutes = 60 minute_fee = '1.20' )
( piano_type = 'G' base_fee = '129.00' incl_minutes = 75 minute_fee = '1.50' )
( piano_type = 'D' base_fee = '69.00' incl_minutes = 45 minute_fee = '1.00' )
( piano_type = 'C' base_fee = '149.00' incl_minutes = 90 minute_fee = '1.80' )
( piano_type = 'S' base_fee = '99.00' incl_minutes = 60 minute_fee = '1.30' ) ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,68 @@
# 1. Goal
Calculate the charge of a piano tuning visit. A booking program calls the
calculation before it confirms the appointment. The program needs the fee parts
and the total fee of the visit.
# 2. Open questions
None.
# 3. Context
- The class {{P}}TUNE_RATES is in package $TMP. It is active. It holds the
price list of the tuning service and the travel constants. Read this class.
Its interface is not written in this document.
- {{P}}TUNE_RATES is out of scope. Do not change it.
# 4. Contract
- Create the class {{P}}PIANO_PRICER in package $TMP.
- The class is public, final, and has a public constructor without parameters.
- Define these public types in the class:
- ty_piano_type: character, length 1.
- ty_amount: packed number, length 8, 2 decimals.
- ty_reason: character, length 8.
- ty_charge: structure with the components reason (TYPE ty_reason), base_fee,
travel_fee, extra_fee and total_fee (all TYPE ty_amount).
- Define the public constant structure c_reason with the components ok = 'OK',
unknown = 'UNKNOWN', distance = 'DISTANCE' and pitch = 'PITCH'. All
components have the type ty_reason.
- The class has one public method:
calculate
IMPORTING iv_piano_type TYPE ty_piano_type
iv_distance_km TYPE i
iv_pitch_cents TYPE i
RETURNING VALUE(rs_charge) TYPE ty_charge.
- Do not add other public methods.
# 5. Business rules
Apply the rules in this sequence.
1. Read the price list of {{P}}TUNE_RATES. If iv_piano_type is not a piano type
of the price list, return a charge with the reason UNKNOWN. All fee
components of this charge are 0.
2. If iv_distance_km is smaller than 0, return a charge with the reason
DISTANCE. All fee components of this charge are 0.
3. If iv_pitch_cents is smaller than 0, return a charge with the reason PITCH.
All fee components of this charge are 0.
4. The base fee is the base fee of the piano type in the price list.
5. A tuning takes 45 minutes. Each cent of pitch deviation adds one minute of
work.
6. The piano type has a number of included minutes and a fee for each minute.
The extra fee is the number of work minutes above the included minutes
multiplied by the minute fee. If the work minutes are not above the included
minutes, the extra fee is 0.
7. The travel is free up to the free distance of {{P}}TUNE_RATES. Each
kilometre above the free distance costs the kilometre fee of
{{P}}TUNE_RATES. The travel fee is this cost. If the distance is not above
the free distance, the travel fee is 0.
8. The total fee is the base fee plus the travel fee plus the extra fee.
9. Else return a charge with the reason OK and the fee components of rules 4,
6 and 7.
# 6. Constraints
- Release target: 8.16 (SAP_BASIS 816).
- 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}}TUNE_RATES.
# 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,50 @@
{
"id": "G1037",
"category": "F",
"object_type": "CLAS",
"difficulty": 2,
"release_target": "v816",
"expected_outcome": "implement",
"budget": {
"max_tool_calls": 60,
"max_activations": 15
},
"seed": [
{
"type": "CLAS",
"name": "{{P}}TUNE_RATES",
"file": "seed/tune_rates.clas.abap",
"description": "Price list of the tuning service and the travel constants. The spec does not give its signature."
}
],
"contract": [
{
"type": "CLAS",
"name": "{{P}}PIANO_PRICER"
}
],
"out_of_scope": [
"{{P}}TUNE_RATES"
],
"hidden_tests": [
{
"type": "CLAS",
"name": "{{P}}T42_HIDDEN",
"file": "hidden/t42_hidden.clas.abap",
"description": "T42 hidden tests for the piano tuning charge"
}
],
"reference": [
{
"type": "CLAS",
"name": "{{P}}PIANO_PRICER",
"file": "reference/piano_pricer.clas.abap",
"description": "Piano tuning charge calculator",
"testclasses_file": "reference/piano_pricer.testclasses.abap"
}
],
"craft_checks": [
"method_length",
"db_operation_in_loop"
]
}