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,124 @@
CLASS {{p}}crane_hire_calc DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES {{p}}if_crane_hire.
PRIVATE SECTION.
CONSTANTS:
c_min_radius TYPE i VALUE 5,
c_max_radius TYPE i VALUE 60,
c_min_load TYPE i VALUE 500,
c_permit_fee TYPE i VALUE 250,
c_min_fee TYPE i VALUE 300,
c_radius_rate TYPE i VALUE 15,
c_load_rate TYPE i VALUE 5.
TYPES:
BEGIN OF ty_band,
radius_max TYPE i,
max_load TYPE i,
END OF ty_band,
tt_band TYPE STANDARD TABLE OF ty_band WITH EMPTY KEY.
METHODS validate
IMPORTING iv_radius_m TYPE i
iv_load_kg TYPE i
iv_ground TYPE string
RETURNING VALUE(rv_reason) TYPE {{p}}if_crane_hire=>ty_reason.
METHODS max_load
IMPORTING iv_radius_m TYPE i
RETURNING VALUE(rv_load) TYPE i.
METHODS load_chart
RETURNING VALUE(rt_band) TYPE tt_band.
METHODS ground_factor
IMPORTING iv_ground TYPE string
RETURNING VALUE(rv_percent) TYPE i.
METHODS normalize_ground
IMPORTING iv_ground TYPE string
RETURNING VALUE(rv_ground) TYPE string.
METHODS apply_percent
IMPORTING iv_value TYPE i
iv_percent TYPE i
RETURNING VALUE(rv_value) TYPE i.
ENDCLASS.
CLASS {{p}}crane_hire_calc IMPLEMENTATION.
METHOD {{p}}if_crane_hire~hire.
DATA(lv_reason) = validate( iv_radius_m = iv_radius_m
iv_load_kg = iv_load_kg
iv_ground = iv_ground ).
IF lv_reason <> {{p}}if_crane_hire=>c_reason-ok.
rs_result = VALUE #( reason = lv_reason fee = 0 ).
RETURN.
ENDIF.
DATA(lv_base) = iv_radius_m * c_radius_rate + ( iv_load_kg DIV 100 ) * c_load_rate.
DATA(lv_fee) = apply_percent( iv_value = lv_base
iv_percent = ground_factor( iv_ground ) ).
IF iv_permit <> abap_true.
lv_fee = lv_fee + c_permit_fee.
ENDIF.
IF lv_fee < c_min_fee.
lv_fee = c_min_fee.
ENDIF.
rs_result = VALUE #( reason = {{p}}if_crane_hire=>c_reason-ok fee = lv_fee ).
ENDMETHOD.
METHOD validate.
IF iv_radius_m < c_min_radius OR iv_radius_m > c_max_radius.
rv_reason = {{p}}if_crane_hire=>c_reason-radius.
RETURN.
ENDIF.
IF iv_load_kg < c_min_load.
rv_reason = {{p}}if_crane_hire=>c_reason-load.
RETURN.
ENDIF.
IF iv_load_kg > max_load( iv_radius_m ).
rv_reason = {{p}}if_crane_hire=>c_reason-capacity.
RETURN.
ENDIF.
IF ground_factor( iv_ground ) = 0.
rv_reason = {{p}}if_crane_hire=>c_reason-ground.
RETURN.
ENDIF.
rv_reason = {{p}}if_crane_hire=>c_reason-ok.
ENDMETHOD.
METHOD max_load.
DATA(lt_band) = load_chart( ).
LOOP AT lt_band INTO DATA(ls_band).
IF iv_radius_m <= ls_band-radius_max.
rv_load = ls_band-max_load.
RETURN.
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD load_chart.
rt_band = VALUE #( ( radius_max = 10 max_load = 12000 )
( radius_max = 20 max_load = 8000 )
( radius_max = 30 max_load = 5000 )
( radius_max = 45 max_load = 3000 )
( radius_max = 60 max_load = 1500 ) ).
ENDMETHOD.
METHOD ground_factor.
CASE normalize_ground( iv_ground ).
WHEN 'ROAD'.
rv_percent = 100.
WHEN 'GRAVEL'.
rv_percent = 115.
WHEN 'SOIL'.
rv_percent = 135.
ENDCASE.
ENDMETHOD.
METHOD normalize_ground.
rv_ground = to_upper( condense( iv_ground ) ).
ENDMETHOD.
METHOD apply_percent.
rv_value = ( iv_value * iv_percent + 50 ) DIV 100.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,124 @@
CLASS {{p}}crane_hire_calc DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES {{p}}if_crane_hire.
PRIVATE SECTION.
CONSTANTS:
c_min_radius TYPE i VALUE 5,
c_max_radius TYPE i VALUE 60,
c_min_load TYPE i VALUE 500,
c_permit_fee TYPE i VALUE 250,
c_min_fee TYPE i VALUE 300,
c_radius_rate TYPE i VALUE 15,
c_load_rate TYPE i VALUE 5.
TYPES:
BEGIN OF ty_band,
radius_max TYPE i,
max_load TYPE i,
END OF ty_band,
tt_band TYPE STANDARD TABLE OF ty_band WITH EMPTY KEY.
METHODS validate
IMPORTING iv_radius_m TYPE i
iv_load_kg TYPE i
iv_ground TYPE string
RETURNING VALUE(rv_reason) TYPE {{p}}if_crane_hire=>ty_reason.
METHODS max_load
IMPORTING iv_radius_m TYPE i
RETURNING VALUE(rv_load) TYPE i.
METHODS load_chart
RETURNING VALUE(rt_band) TYPE tt_band.
METHODS ground_factor
IMPORTING iv_ground TYPE string
RETURNING VALUE(rv_percent) TYPE i.
METHODS normalize_ground
IMPORTING iv_ground TYPE string
RETURNING VALUE(rv_ground) TYPE string.
METHODS apply_percent
IMPORTING iv_value TYPE i
iv_percent TYPE i
RETURNING VALUE(rv_value) TYPE i.
ENDCLASS.
CLASS {{p}}crane_hire_calc IMPLEMENTATION.
METHOD {{p}}if_crane_hire~hire.
DATA(lv_reason) = validate( iv_radius_m = iv_radius_m
iv_load_kg = iv_load_kg
iv_ground = iv_ground ).
IF lv_reason <> {{p}}if_crane_hire=>c_reason-ok.
rs_result = VALUE #( reason = lv_reason fee = 0 ).
RETURN.
ENDIF.
DATA(lv_base) = iv_radius_m * c_radius_rate + ( iv_load_kg DIV 100 ) * c_load_rate.
DATA(lv_fee) = apply_percent( iv_value = lv_base
iv_percent = ground_factor( iv_ground ) ).
IF iv_permit = abap_true.
lv_fee = lv_fee + c_permit_fee.
ENDIF.
IF lv_fee >= c_min_fee.
lv_fee = c_min_fee.
ENDIF.
rs_result = VALUE #( reason = {{p}}if_crane_hire=>c_reason-ok fee = lv_fee ).
ENDMETHOD.
METHOD validate.
IF iv_radius_m < c_min_radius OR iv_radius_m > c_max_radius.
rv_reason = {{p}}if_crane_hire=>c_reason-radius.
RETURN.
ENDIF.
IF iv_load_kg < c_min_load.
rv_reason = {{p}}if_crane_hire=>c_reason-load.
RETURN.
ENDIF.
IF iv_load_kg > max_load( iv_radius_m ).
rv_reason = {{p}}if_crane_hire=>c_reason-capacity.
RETURN.
ENDIF.
IF ground_factor( iv_ground ) = 0.
rv_reason = {{p}}if_crane_hire=>c_reason-ground.
RETURN.
ENDIF.
rv_reason = {{p}}if_crane_hire=>c_reason-ok.
ENDMETHOD.
METHOD max_load.
DATA(lt_band) = load_chart( ).
LOOP AT lt_band INTO DATA(ls_band).
IF iv_radius_m <= ls_band-radius_max.
rv_load = ls_band-max_load.
RETURN.
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD load_chart.
rt_band = VALUE #( ( radius_max = 10 max_load = 12000 )
( radius_max = 20 max_load = 8000 )
( radius_max = 30 max_load = 5000 )
( radius_max = 45 max_load = 3000 )
( radius_max = 60 max_load = 1500 ) ).
ENDMETHOD.
METHOD ground_factor.
CASE normalize_ground( iv_ground ).
WHEN 'ROAD'.
rv_percent = 100.
WHEN 'GRAVEL'.
rv_percent = 115.
WHEN 'SOIL'.
rv_percent = 135.
ENDCASE.
ENDMETHOD.
METHOD normalize_ground.
rv_ground = to_upper( condense( iv_ground ) ).
ENDMETHOD.
METHOD apply_percent.
rv_value = ( iv_value * iv_percent + 50 ) DIV 100.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,124 @@
CLASS {{p}}crane_hire_calc DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES {{p}}if_crane_hire.
PRIVATE SECTION.
CONSTANTS:
c_min_radius TYPE i VALUE 5,
c_max_radius TYPE i VALUE 60,
c_min_load TYPE i VALUE 500,
c_permit_fee TYPE i VALUE 250,
c_min_fee TYPE i VALUE 300,
c_radius_rate TYPE i VALUE 15,
c_load_rate TYPE i VALUE 5.
TYPES:
BEGIN OF ty_band,
radius_max TYPE i,
max_load TYPE i,
END OF ty_band,
tt_band TYPE STANDARD TABLE OF ty_band WITH EMPTY KEY.
METHODS validate
IMPORTING iv_radius_m TYPE i
iv_load_kg TYPE i
iv_ground TYPE string
RETURNING VALUE(rv_reason) TYPE {{p}}if_crane_hire=>ty_reason.
METHODS max_load
IMPORTING iv_radius_m TYPE i
RETURNING VALUE(rv_load) TYPE i.
METHODS load_chart
RETURNING VALUE(rt_band) TYPE tt_band.
METHODS ground_factor
IMPORTING iv_ground TYPE string
RETURNING VALUE(rv_percent) TYPE i.
METHODS normalize_ground
IMPORTING iv_ground TYPE string
RETURNING VALUE(rv_ground) TYPE string.
METHODS apply_percent
IMPORTING iv_value TYPE i
iv_percent TYPE i
RETURNING VALUE(rv_value) TYPE i.
ENDCLASS.
CLASS {{p}}crane_hire_calc IMPLEMENTATION.
METHOD {{p}}if_crane_hire~hire.
DATA(lv_reason) = validate( iv_radius_m = iv_radius_m
iv_load_kg = iv_load_kg
iv_ground = iv_ground ).
IF lv_reason <> {{p}}if_crane_hire=>c_reason-ok.
rs_result = VALUE #( reason = lv_reason fee = 0 ).
RETURN.
ENDIF.
DATA(lv_base) = iv_radius_m * c_radius_rate + ( iv_load_kg DIV 100 ) * c_load_rate.
DATA(lv_fee) = apply_percent( iv_value = lv_base
iv_percent = ground_factor( iv_ground ) ).
IF iv_permit = abap_true.
lv_fee = lv_fee + c_permit_fee.
ENDIF.
IF lv_fee < c_min_fee.
lv_fee = c_min_fee.
ENDIF.
rs_result = VALUE #( reason = {{p}}if_crane_hire=>c_reason-ok fee = lv_fee ).
ENDMETHOD.
METHOD validate.
IF iv_radius_m < c_min_radius AND iv_radius_m > c_max_radius.
rv_reason = {{p}}if_crane_hire=>c_reason-radius.
RETURN.
ENDIF.
IF iv_load_kg < c_min_load.
rv_reason = {{p}}if_crane_hire=>c_reason-load.
RETURN.
ENDIF.
IF iv_load_kg > max_load( iv_radius_m ).
rv_reason = {{p}}if_crane_hire=>c_reason-capacity.
RETURN.
ENDIF.
IF ground_factor( iv_ground ) = 0.
rv_reason = {{p}}if_crane_hire=>c_reason-ground.
RETURN.
ENDIF.
rv_reason = {{p}}if_crane_hire=>c_reason-ok.
ENDMETHOD.
METHOD max_load.
DATA(lt_band) = load_chart( ).
LOOP AT lt_band INTO DATA(ls_band).
IF iv_radius_m <= ls_band-radius_max.
rv_load = ls_band-max_load.
RETURN.
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD load_chart.
rt_band = VALUE #( ( radius_max = 10 max_load = 12000 )
( radius_max = 20 max_load = 8000 )
( radius_max = 30 max_load = 5000 )
( radius_max = 45 max_load = 3000 )
( radius_max = 60 max_load = 1500 ) ).
ENDMETHOD.
METHOD ground_factor.
CASE normalize_ground( iv_ground ).
WHEN 'ROAD'.
rv_percent = 100.
WHEN 'GRAVEL'.
rv_percent = 115.
WHEN 'SOIL'.
rv_percent = 135.
ENDCASE.
ENDMETHOD.
METHOD normalize_ground.
rv_ground = to_upper( condense( iv_ground ) ).
ENDMETHOD.
METHOD apply_percent.
rv_value = ( iv_value * iv_percent + 50 ) DIV 100.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,124 @@
CLASS {{p}}crane_hire_calc DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES {{p}}if_crane_hire.
PRIVATE SECTION.
CONSTANTS:
c_min_radius TYPE i VALUE 5,
c_max_radius TYPE i VALUE 60,
c_min_load TYPE i VALUE 500,
c_permit_fee TYPE i VALUE 250,
c_min_fee TYPE i VALUE 300,
c_radius_rate TYPE i VALUE 15,
c_load_rate TYPE i VALUE 5.
TYPES:
BEGIN OF ty_band,
radius_max TYPE i,
max_load TYPE i,
END OF ty_band,
tt_band TYPE STANDARD TABLE OF ty_band WITH EMPTY KEY.
METHODS validate
IMPORTING iv_radius_m TYPE i
iv_load_kg TYPE i
iv_ground TYPE string
RETURNING VALUE(rv_reason) TYPE {{p}}if_crane_hire=>ty_reason.
METHODS max_load
IMPORTING iv_radius_m TYPE i
RETURNING VALUE(rv_load) TYPE i.
METHODS load_chart
RETURNING VALUE(rt_band) TYPE tt_band.
METHODS ground_factor
IMPORTING iv_ground TYPE string
RETURNING VALUE(rv_percent) TYPE i.
METHODS normalize_ground
IMPORTING iv_ground TYPE string
RETURNING VALUE(rv_ground) TYPE string.
METHODS apply_percent
IMPORTING iv_value TYPE i
iv_percent TYPE i
RETURNING VALUE(rv_value) TYPE i.
ENDCLASS.
CLASS {{p}}crane_hire_calc IMPLEMENTATION.
METHOD {{p}}if_crane_hire~hire.
DATA(lv_reason) = validate( iv_radius_m = iv_radius_m
iv_load_kg = iv_load_kg
iv_ground = iv_ground ).
IF lv_reason <> {{p}}if_crane_hire=>c_reason-ok.
rs_result = VALUE #( reason = lv_reason fee = 0 ).
RETURN.
ENDIF.
DATA(lv_base) = iv_radius_m * c_radius_rate + ( iv_load_kg DIV 100 ) * c_load_rate.
DATA(lv_fee) = apply_percent( iv_value = lv_base
iv_percent = ground_factor( iv_ground ) ).
IF iv_permit = abap_true.
lv_fee = lv_fee + c_permit_fee.
ENDIF.
IF lv_fee < c_min_fee.
lv_fee = c_min_fee.
ENDIF.
rs_result = VALUE #( reason = {{p}}if_crane_hire=>c_reason-ok fee = lv_fee ).
ENDMETHOD.
METHOD validate.
IF iv_radius_m < c_min_radius OR iv_radius_m > c_max_radius.
rv_reason = {{p}}if_crane_hire=>c_reason-radius.
RETURN.
ENDIF.
IF iv_load_kg < c_min_load.
rv_reason = {{p}}if_crane_hire=>c_reason-load.
RETURN.
ENDIF.
IF iv_load_kg > max_load( iv_radius_m ).
rv_reason = {{p}}if_crane_hire=>c_reason-capacity.
RETURN.
ENDIF.
IF ground_factor( iv_ground ) = 0.
rv_reason = {{p}}if_crane_hire=>c_reason-ground.
RETURN.
ENDIF.
rv_reason = {{p}}if_crane_hire=>c_reason-ok.
ENDMETHOD.
METHOD max_load.
DATA(lt_band) = load_chart( ).
LOOP AT lt_band INTO DATA(ls_band).
IF iv_radius_m <= ls_band-radius_max.
rv_load = ls_band-max_load.
RETURN.
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD load_chart.
rt_band = VALUE #( ( radius_max = 10 max_load = 12000 )
( radius_max = 20 max_load = 8000 )
( radius_max = 30 max_load = 5000 )
( radius_max = 45 max_load = 3000 )
( radius_max = 60 max_load = 1500 ) ).
ENDMETHOD.
METHOD ground_factor.
CASE normalize_ground( iv_ground ).
WHEN 'ROAD'.
rv_percent = 100.
WHEN 'GRAVEL'.
rv_percent = 115.
WHEN 'SOIL'.
rv_percent = 135.
ENDCASE.
ENDMETHOD.
METHOD normalize_ground.
rv_ground = to_upper( condense( iv_ground ) ).
ENDMETHOD.
METHOD apply_percent.
rv_value = ( iv_value / iv_percent + 50 ) DIV 100.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,38 @@
{
"id": "G1025",
"pool": "train",
"object_type": "CLAS",
"category": "F",
"attempts": [
{
"stage": "bundle",
"errors": [
"Too close to task G0150 (similarity spec 0.66, rules 0.67, names 0.20). Choose a different business topic and different object names."
],
"by_check": {
"extra": 1
}
},
{
"stage": "bundle",
"errors": [
"reference/crane_hire_calc.clas.abap line 64: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"DATA\"",
"reference/crane_hire_calc.clas.abap line 92: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"IF\""
],
"by_check": {
"abaplint": 2
}
},
{
"stage": "validate",
"oracle": 100.0,
"null": 0,
"mutation": {
"valid": 5,
"killed": 4,
"ok": true
}
}
],
"accepted": true
}

View File

@@ -0,0 +1,234 @@
CLASS {{p}}t02_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA mo_cut TYPE REF TO {{p}}if_crane_hire.
METHODS setup.
METHODS base_fee_road FOR TESTING.
METHODS gravel_factor FOR TESTING.
METHODS soil_factor_rounds FOR TESTING.
METHODS permit_surcharge FOR TESTING.
METHODS minimum_fee FOR TESTING.
METHODS radius_out_of_range FOR TESTING.
METHODS load_out_of_range FOR TESTING.
METHODS capacity_exceeded FOR TESTING.
METHODS capacity_band_edges FOR TESTING.
METHODS unknown_ground FOR TESTING.
METHODS ground_case_spaces FOR TESTING.
METHODS validation_order FOR TESTING.
ENDCLASS.
CLASS {{p}}t02_hidden IMPLEMENTATION.
METHOD setup.
mo_cut = NEW {{p}}crane_hire_calc( ).
ENDMETHOD.
METHOD base_fee_road.
DATA(ls_result) = mo_cut->hire( iv_radius_m = 20
iv_load_kg = 5000
iv_ground = `ROAD`
iv_permit = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_crane_hire=>c_reason-ok
act = ls_result-reason ).
cl_abap_unit_assert=>assert_equals( exp = 550
act = ls_result-fee ).
ENDMETHOD.
METHOD gravel_factor.
DATA(ls_result) = mo_cut->hire( iv_radius_m = 30
iv_load_kg = 5000
iv_ground = `GRAVEL`
iv_permit = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_crane_hire=>c_reason-ok
act = ls_result-reason ).
cl_abap_unit_assert=>assert_equals( exp = 805
act = ls_result-fee ).
ENDMETHOD.
METHOD soil_factor_rounds.
DATA(ls_result) = mo_cut->hire( iv_radius_m = 10
iv_load_kg = 12000
iv_ground = `SOIL`
iv_permit = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_crane_hire=>c_reason-ok
act = ls_result-reason ).
cl_abap_unit_assert=>assert_equals( exp = 1013
act = ls_result-fee ).
ENDMETHOD.
METHOD permit_surcharge.
DATA(ls_result) = mo_cut->hire( iv_radius_m = 20
iv_load_kg = 5000
iv_ground = `ROAD`
iv_permit = abap_true ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_crane_hire=>c_reason-ok
act = ls_result-reason ).
cl_abap_unit_assert=>assert_equals( exp = 800
act = ls_result-fee ).
ENDMETHOD.
METHOD minimum_fee.
DATA(ls_result) = mo_cut->hire( iv_radius_m = 5
iv_load_kg = 500
iv_ground = `ROAD`
iv_permit = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = 300
act = ls_result-fee ).
ls_result = mo_cut->hire( iv_radius_m = 5
iv_load_kg = 500
iv_ground = `GRAVEL`
iv_permit = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = 300
act = ls_result-fee ).
ENDMETHOD.
METHOD radius_out_of_range.
DATA(ls_result) = mo_cut->hire( iv_radius_m = 4
iv_load_kg = 5000
iv_ground = `ROAD`
iv_permit = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_crane_hire=>c_reason-radius
act = ls_result-reason ).
cl_abap_unit_assert=>assert_equals( exp = 0
act = ls_result-fee ).
ls_result = mo_cut->hire( iv_radius_m = 61
iv_load_kg = 5000
iv_ground = `ROAD`
iv_permit = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_crane_hire=>c_reason-radius
act = ls_result-reason ).
ls_result = mo_cut->hire( iv_radius_m = 60
iv_load_kg = 1500
iv_ground = `ROAD`
iv_permit = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_crane_hire=>c_reason-ok
act = ls_result-reason ).
cl_abap_unit_assert=>assert_equals( exp = 975
act = ls_result-fee ).
ENDMETHOD.
METHOD load_out_of_range.
DATA(ls_result) = mo_cut->hire( iv_radius_m = 20
iv_load_kg = 499
iv_ground = `ROAD`
iv_permit = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_crane_hire=>c_reason-load
act = ls_result-reason ).
cl_abap_unit_assert=>assert_equals( exp = 0
act = ls_result-fee ).
ls_result = mo_cut->hire( iv_radius_m = 5
iv_load_kg = 500
iv_ground = `ROAD`
iv_permit = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_crane_hire=>c_reason-ok
act = ls_result-reason ).
ENDMETHOD.
METHOD capacity_exceeded.
DATA(ls_result) = mo_cut->hire( iv_radius_m = 25
iv_load_kg = 6000
iv_ground = `ROAD`
iv_permit = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_crane_hire=>c_reason-capacity
act = ls_result-reason ).
cl_abap_unit_assert=>assert_equals( exp = 0
act = ls_result-fee ).
ls_result = mo_cut->hire( iv_radius_m = 60
iv_load_kg = 1501
iv_ground = `ROAD`
iv_permit = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_crane_hire=>c_reason-capacity
act = ls_result-reason ).
ENDMETHOD.
METHOD capacity_band_edges.
DATA(ls_result) = mo_cut->hire( iv_radius_m = 10
iv_load_kg = 12000
iv_ground = `ROAD`
iv_permit = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_crane_hire=>c_reason-ok
act = ls_result-reason ).
cl_abap_unit_assert=>assert_equals( exp = 750
act = ls_result-fee ).
ls_result = mo_cut->hire( iv_radius_m = 11
iv_load_kg = 12000
iv_ground = `ROAD`
iv_permit = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_crane_hire=>c_reason-capacity
act = ls_result-reason ).
ls_result = mo_cut->hire( iv_radius_m = 45
iv_load_kg = 3000
iv_ground = `ROAD`
iv_permit = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_crane_hire=>c_reason-ok
act = ls_result-reason ).
cl_abap_unit_assert=>assert_equals( exp = 825
act = ls_result-fee ).
ls_result = mo_cut->hire( iv_radius_m = 46
iv_load_kg = 3000
iv_ground = `ROAD`
iv_permit = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_crane_hire=>c_reason-capacity
act = ls_result-reason ).
ENDMETHOD.
METHOD unknown_ground.
DATA(ls_result) = mo_cut->hire( iv_radius_m = 20
iv_load_kg = 5000
iv_ground = `FIELD`
iv_permit = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_crane_hire=>c_reason-ground
act = ls_result-reason ).
cl_abap_unit_assert=>assert_equals( exp = 0
act = ls_result-fee ).
ENDMETHOD.
METHOD ground_case_spaces.
DATA(ls_result) = mo_cut->hire( iv_radius_m = 30
iv_load_kg = 5000
iv_ground = ` gravel `
iv_permit = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_crane_hire=>c_reason-ok
act = ls_result-reason ).
cl_abap_unit_assert=>assert_equals( exp = 805
act = ls_result-fee ).
ENDMETHOD.
METHOD validation_order.
DATA(ls_result) = mo_cut->hire( iv_radius_m = 4
iv_load_kg = 100
iv_ground = `FIELD`
iv_permit = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_crane_hire=>c_reason-radius
act = ls_result-reason ).
ls_result = mo_cut->hire( iv_radius_m = 20
iv_load_kg = 100
iv_ground = `FIELD`
iv_permit = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_crane_hire=>c_reason-load
act = ls_result-reason ).
ls_result = mo_cut->hire( iv_radius_m = 25
iv_load_kg = 6000
iv_ground = `FIELD`
iv_permit = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_crane_hire=>c_reason-capacity
act = ls_result-reason ).
ls_result = mo_cut->hire( iv_radius_m = 20
iv_load_kg = 5000
iv_ground = `FIELD`
iv_permit = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_crane_hire=>c_reason-ground
act = ls_result-reason ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,73 @@
{
"task": "G1025",
"mutants": [
{
"object": "{{P}}CRANE_HIRE_CALC",
"mutant": "line 58: = -> <> (eq)",
"status": "killed",
"hidden": "4/12",
"failed_tests": [
"BASE_FEE_ROAD",
"CAPACITY_BAND_EDGES",
"GRAVEL_FACTOR",
"GROUND_CASE_SPACES",
"MINIMUM_FEE",
"PERMIT_SURCHARGE",
"RADIUS_OUT_OF_RANGE",
"SOIL_FACTOR_ROUNDS"
]
},
{
"object": "{{P}}CRANE_HIRE_CALC",
"mutant": "line 61: < -> >= (rel)",
"status": "killed",
"hidden": "4/12",
"failed_tests": [
"BASE_FEE_ROAD",
"CAPACITY_BAND_EDGES",
"GRAVEL_FACTOR",
"GROUND_CASE_SPACES",
"MINIMUM_FEE",
"PERMIT_SURCHARGE",
"RADIUS_OUT_OF_RANGE",
"SOIL_FACTOR_ROUNDS"
]
},
{
"object": "{{P}}CRANE_HIRE_CALC",
"mutant": "line 69: OR -> AND (logic)",
"status": "killed",
"hidden": "10/12",
"failed_tests": [
"RADIUS_OUT_OF_RANGE",
"VALIDATION_ORDER"
]
},
{
"object": "{{P}}CRANE_HIRE_CALC",
"mutant": "line 102: 3000 -> 3001 (const)",
"status": "survived",
"hidden": "12/12",
"failed_tests": []
},
{
"object": "{{P}}CRANE_HIRE_CALC",
"mutant": "line 122: * -> / (arith)",
"status": "killed",
"hidden": "5/12",
"failed_tests": [
"BASE_FEE_ROAD",
"CAPACITY_BAND_EDGES",
"GRAVEL_FACTOR",
"GROUND_CASE_SPACES",
"PERMIT_SURCHARGE",
"RADIUS_OUT_OF_RANGE",
"SOIL_FACTOR_ROUNDS"
]
}
],
"valid": 5,
"killed": 4,
"kill_rate": 0.8,
"ok": true
}

View File

@@ -0,0 +1,124 @@
CLASS {{p}}crane_hire_calc DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES {{p}}if_crane_hire.
PRIVATE SECTION.
CONSTANTS:
c_min_radius TYPE i VALUE 5,
c_max_radius TYPE i VALUE 60,
c_min_load TYPE i VALUE 500,
c_permit_fee TYPE i VALUE 250,
c_min_fee TYPE i VALUE 300,
c_radius_rate TYPE i VALUE 15,
c_load_rate TYPE i VALUE 5.
TYPES:
BEGIN OF ty_band,
radius_max TYPE i,
max_load TYPE i,
END OF ty_band,
tt_band TYPE STANDARD TABLE OF ty_band WITH EMPTY KEY.
METHODS validate
IMPORTING iv_radius_m TYPE i
iv_load_kg TYPE i
iv_ground TYPE string
RETURNING VALUE(rv_reason) TYPE {{p}}if_crane_hire=>ty_reason.
METHODS max_load
IMPORTING iv_radius_m TYPE i
RETURNING VALUE(rv_load) TYPE i.
METHODS load_chart
RETURNING VALUE(rt_band) TYPE tt_band.
METHODS ground_factor
IMPORTING iv_ground TYPE string
RETURNING VALUE(rv_percent) TYPE i.
METHODS normalize_ground
IMPORTING iv_ground TYPE string
RETURNING VALUE(rv_ground) TYPE string.
METHODS apply_percent
IMPORTING iv_value TYPE i
iv_percent TYPE i
RETURNING VALUE(rv_value) TYPE i.
ENDCLASS.
CLASS {{p}}crane_hire_calc IMPLEMENTATION.
METHOD {{p}}if_crane_hire~hire.
DATA(lv_reason) = validate( iv_radius_m = iv_radius_m
iv_load_kg = iv_load_kg
iv_ground = iv_ground ).
IF lv_reason <> {{p}}if_crane_hire=>c_reason-ok.
rs_result = VALUE #( reason = lv_reason fee = 0 ).
RETURN.
ENDIF.
DATA(lv_base) = iv_radius_m * c_radius_rate + ( iv_load_kg DIV 100 ) * c_load_rate.
DATA(lv_fee) = apply_percent( iv_value = lv_base
iv_percent = ground_factor( iv_ground ) ).
IF iv_permit = abap_true.
lv_fee = lv_fee + c_permit_fee.
ENDIF.
IF lv_fee < c_min_fee.
lv_fee = c_min_fee.
ENDIF.
rs_result = VALUE #( reason = {{p}}if_crane_hire=>c_reason-ok fee = lv_fee ).
ENDMETHOD.
METHOD validate.
IF iv_radius_m < c_min_radius OR iv_radius_m > c_max_radius.
rv_reason = {{p}}if_crane_hire=>c_reason-radius.
RETURN.
ENDIF.
IF iv_load_kg < c_min_load.
rv_reason = {{p}}if_crane_hire=>c_reason-load.
RETURN.
ENDIF.
IF iv_load_kg > max_load( iv_radius_m ).
rv_reason = {{p}}if_crane_hire=>c_reason-capacity.
RETURN.
ENDIF.
IF ground_factor( iv_ground ) = 0.
rv_reason = {{p}}if_crane_hire=>c_reason-ground.
RETURN.
ENDIF.
rv_reason = {{p}}if_crane_hire=>c_reason-ok.
ENDMETHOD.
METHOD max_load.
DATA(lt_band) = load_chart( ).
LOOP AT lt_band INTO DATA(ls_band).
IF iv_radius_m <= ls_band-radius_max.
rv_load = ls_band-max_load.
RETURN.
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD load_chart.
rt_band = VALUE #( ( radius_max = 10 max_load = 12000 )
( radius_max = 20 max_load = 8000 )
( radius_max = 30 max_load = 5000 )
( radius_max = 45 max_load = 3000 )
( radius_max = 60 max_load = 1500 ) ).
ENDMETHOD.
METHOD ground_factor.
CASE normalize_ground( iv_ground ).
WHEN 'ROAD'.
rv_percent = 100.
WHEN 'GRAVEL'.
rv_percent = 115.
WHEN 'SOIL'.
rv_percent = 135.
ENDCASE.
ENDMETHOD.
METHOD normalize_ground.
rv_ground = to_upper( condense( iv_ground ) ).
ENDMETHOD.
METHOD apply_percent.
rv_value = ( iv_value * iv_percent + 50 ) DIV 100.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,104 @@
CLASS ltc_crane_hire DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA mo_cut TYPE REF TO {{p}}if_crane_hire.
METHODS setup.
METHODS road_fee FOR TESTING.
METHODS gravel_fee FOR TESTING.
METHODS soil_fee FOR TESTING.
METHODS permit_fee FOR TESTING.
METHODS minimum_fee FOR TESTING.
METHODS invalid_radius FOR TESTING.
METHODS invalid_load FOR TESTING.
METHODS over_capacity FOR TESTING.
METHODS invalid_ground FOR TESTING.
ENDCLASS.
CLASS ltc_crane_hire IMPLEMENTATION.
METHOD setup.
mo_cut = NEW {{p}}crane_hire_calc( ).
ENDMETHOD.
METHOD road_fee.
DATA(ls_result) = mo_cut->hire( iv_radius_m = 20
iv_load_kg = 5000
iv_ground = `ROAD`
iv_permit = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_crane_hire=>c_reason-ok
act = ls_result-reason ).
cl_abap_unit_assert=>assert_equals( exp = 550
act = ls_result-fee ).
ENDMETHOD.
METHOD gravel_fee.
DATA(ls_result) = mo_cut->hire( iv_radius_m = 30
iv_load_kg = 5000
iv_ground = `GRAVEL`
iv_permit = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = 805
act = ls_result-fee ).
ENDMETHOD.
METHOD soil_fee.
DATA(ls_result) = mo_cut->hire( iv_radius_m = 10
iv_load_kg = 12000
iv_ground = `SOIL`
iv_permit = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = 1013
act = ls_result-fee ).
ENDMETHOD.
METHOD permit_fee.
DATA(ls_result) = mo_cut->hire( iv_radius_m = 20
iv_load_kg = 5000
iv_ground = `ROAD`
iv_permit = abap_true ).
cl_abap_unit_assert=>assert_equals( exp = 800
act = ls_result-fee ).
ENDMETHOD.
METHOD minimum_fee.
DATA(ls_result) = mo_cut->hire( iv_radius_m = 5
iv_load_kg = 500
iv_ground = `ROAD`
iv_permit = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = 300
act = ls_result-fee ).
ENDMETHOD.
METHOD invalid_radius.
DATA(ls_result) = mo_cut->hire( iv_radius_m = 61
iv_load_kg = 5000
iv_ground = `ROAD`
iv_permit = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_crane_hire=>c_reason-radius
act = ls_result-reason ).
ENDMETHOD.
METHOD invalid_load.
DATA(ls_result) = mo_cut->hire( iv_radius_m = 20
iv_load_kg = 499
iv_ground = `ROAD`
iv_permit = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_crane_hire=>c_reason-load
act = ls_result-reason ).
ENDMETHOD.
METHOD over_capacity.
DATA(ls_result) = mo_cut->hire( iv_radius_m = 25
iv_load_kg = 6000
iv_ground = `ROAD`
iv_permit = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_crane_hire=>c_reason-capacity
act = ls_result-reason ).
ENDMETHOD.
METHOD invalid_ground.
DATA(ls_result) = mo_cut->hire( iv_radius_m = 20
iv_load_kg = 5000
iv_ground = `FIELD`
iv_permit = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_crane_hire=>c_reason-ground
act = ls_result-reason ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,25 @@
INTERFACE {{p}}if_crane_hire PUBLIC.
TYPES ty_reason TYPE c LENGTH 10.
TYPES:
BEGIN OF ty_result,
reason TYPE ty_reason,
fee TYPE i,
END OF ty_result.
CONSTANTS:
BEGIN OF c_reason,
ok TYPE ty_reason VALUE 'OK',
radius TYPE ty_reason VALUE 'RADIUS',
load TYPE ty_reason VALUE 'LOAD',
capacity TYPE ty_reason VALUE 'CAPACITY',
ground TYPE ty_reason VALUE 'GROUND',
END OF c_reason.
METHODS hire
IMPORTING iv_radius_m TYPE i
iv_load_kg TYPE i
iv_ground TYPE string
iv_permit TYPE abap_bool
RETURNING VALUE(rs_result) TYPE ty_result.
ENDINTERFACE.

View File

@@ -0,0 +1,54 @@
# 1. Goal
Calculate the hire fee of a mobile crane job. A quotation program calls the
calculation before it sends a quote to the customer. The program needs the fee
and one reason code for each request.
# 2. Open questions
None.
# 3. Context
- Interface {{P}}IF_CRANE_HIRE exists in package $TMP. It is active.
- Read the interface. It contains the types, the reason codes and the signature
of the calculation method. Use the names of the interface.
- The method receives the working radius, the load, the ground type and a flag
for a road permit. It returns a reason code and a fee.
# 4. Contract
- Create the class {{P}}CRANE_HIRE_CALC in package $TMP.
- The class is public and final. It has a public constructor without parameters.
- The class implements {{P}}IF_CRANE_HIRE.
- Do not add other public methods.
# 5. Business rules
Apply the rules in this sequence.
1. If the radius is less than 5 or more than 60, return the radius reason and a
fee of 0.
2. If the load is less than 500, return the load reason and a fee of 0.
3. The crane has a load chart. The maximum load depends on the radius:
radius up to 10 m: 12000 kg, up to 20 m: 8000 kg, up to 30 m: 5000 kg,
up to 45 m: 3000 kg, up to 60 m: 1500 kg.
If the load is more than the maximum load for the radius, return the capacity
reason and a fee of 0.
4. Remove the leading and the trailing spaces from the ground type. Convert it
to upper case. The ground type must be ROAD, GRAVEL or SOIL. If not, return
the ground reason and a fee of 0.
5. Calculate the base fee: the radius in metres multiplied by 15, plus the load
in kilograms divided by 100 and rounded down, multiplied by 5.
6. Multiply the base fee by the ground factor and divide the result by 100. The
ground factors are: ROAD 100, GRAVEL 115, SOIL 135.
7. If the road permit is required, add 250 to the fee.
8. If the fee is less than 300, set the fee to 300.
9. Return the OK reason and the fee.
Round each multiplication by a ground factor to the nearest whole euro. Round
halves up. The fee is a whole number of euros.
# 6. Constraints
- Release target: ABAP Platform 2025 (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}}IF_CRANE_HIRE.
# 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,51 @@
{
"id": "G1025",
"category": "F",
"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_CRANE_HIRE",
"file": "seed/if_crane_hire.intf.abap",
"description": "Crane hire contract: types, reason codes and method signature"
}
],
"contract": [
{
"type": "CLAS",
"name": "{{P}}CRANE_HIRE_CALC",
"implements": "{{P}}IF_CRANE_HIRE"
}
],
"out_of_scope": [
"{{P}}IF_CRANE_HIRE"
],
"hidden_tests": [
{
"type": "CLAS",
"name": "{{P}}T02_HIDDEN",
"file": "hidden/t02_hidden.clas.abap",
"description": "T02 hidden tests for the crane hire fee"
}
],
"reference": [
{
"type": "CLAS",
"name": "{{P}}CRANE_HIRE_CALC",
"file": "reference/crane_hire_calc.clas.abap",
"description": "Crane hire fee calculator",
"testclasses_file": "reference/crane_hire_calc.testclasses.abap"
}
],
"craft_checks": [
"method_length",
"cyclomatic_complexity"
]
}