Fix coverage with several contract classes; table annotation and file path checks; clean task dir on write

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014aUaQeLnwbb1zTpN7kHeat
This commit is contained in:
Kral
2026-10-03 08:44:35 +02:00
parent fb576b0954
commit 03ab36149e
388 changed files with 28620 additions and 339 deletions

View File

@@ -1,55 +0,0 @@
INTERFACE {{p}}if_tour_planner PUBLIC.
TYPES ty_status TYPE c LENGTH 10.
CONSTANTS:
BEGIN OF c_status,
ok TYPE ty_status VALUE 'OK',
invalid TYPE ty_status VALUE 'INVALID',
duplicate TYPE ty_status VALUE 'DUPLICATE',
END OF c_status.
TYPES:
BEGIN OF ty_item,
tour_id TYPE c LENGTH 4,
stop_no TYPE i,
customer TYPE c LENGTH 10,
packages TYPE i,
weight TYPE p LENGTH 8 DECIMALS 2,
END OF ty_item,
tt_item TYPE STANDARD TABLE OF ty_item WITH EMPTY KEY,
BEGIN OF ty_tour,
tour_id TYPE c LENGTH 4,
stops TYPE i,
packages TYPE i,
weight TYPE p LENGTH 8 DECIMALS 2,
END OF ty_tour,
tt_tour TYPE STANDARD TABLE OF ty_tour WITH EMPTY KEY.
METHODS add_item
IMPORTING iv_tour_id TYPE c LENGTH 4
iv_stop_no TYPE i
iv_customer TYPE c LENGTH 10
iv_packages TYPE i
iv_weight TYPE p LENGTH 8 DECIMALS 2
RETURNING VALUE(rv_status) TYPE ty_status.
METHODS remove_tour
IMPORTING iv_tour_id TYPE c LENGTH 4
RETURNING VALUE(rv_count) TYPE i.
METHODS items
RETURNING VALUE(rt_item) TYPE tt_item.
METHODS stops_of_tour
IMPORTING iv_tour_id TYPE c LENGTH 4
RETURNING VALUE(rt_item) TYPE tt_item.
METHODS find_stop
IMPORTING iv_tour_id TYPE c LENGTH 4
iv_stop_no TYPE i
RETURNING VALUE(rs_item) TYPE ty_item.
METHODS tour_summary
RETURNING VALUE(rt_tour) TYPE tt_tour.
ENDINTERFACE.

View File

@@ -1,8 +0,0 @@
define table {{P}}COURSE {
key mandt : abap.clnt not null;
key course_id : abap.char(10) not null;
category : abap.char(10);
title : abap.char(40);
capacity : abap.int4;
booked : abap.int4;
}

View File

@@ -1,9 +0,0 @@
@EndUserText.label : 'Training courses'
define table {{P}}COURSE {
key mandt : abap.clnt not null;
key course_id : abap.char(10) not null;
category : abap.char(10);
title : abap.char(40);
capacity : abap.int4;
booked : abap.int4;
}

View File

@@ -1,18 +0,0 @@
CLASS {{p}}seed_data DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
ENDCLASS.
CLASS {{p}}seed_data IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
DELETE FROM {{p}}zones.
INSERT {{p}}zones FROM TABLE @( VALUE #(
( zone_code = 'DE01' country = 'DE' base_fee = '5.00' price_per_kg = '1.20' max_weight_kg = 31 currency = 'EUR' )
( zone_code = 'DE02' country = 'DE' base_fee = '8.00' price_per_kg = '1.80' max_weight_kg = 31 currency = 'EUR' )
( zone_code = 'FR01' country = 'FR' base_fee = '9.50' price_per_kg = '2.10' max_weight_kg = 30 currency = 'EUR' )
( zone_code = 'US01' country = 'US' base_fee = '14.00' price_per_kg = '3.40' max_weight_kg = 25 currency = 'USD' )
( zone_code = 'CN01' country = 'CN' base_fee = '18.00' price_per_kg = '4.25' max_weight_kg = 20 currency = 'CNY' ) ) ).
out->write( |Zones seeded| ).
ENDMETHOD.
ENDCLASS.

View File

@@ -1,10 +0,0 @@
@EndUserText.label : 'Zone tariff'
define table {{p}}zones {
key mandt : abap.clnt not null;
key zone_code : abap.char(4) not null;
country : abap.char(2) not null;
base_fee : abap.dec(15,2) not null;
price_per_kg : abap.dec(15,2) not null;
max_weight_kg : abap.int4 not null;
currency : abap.char(5) not null;
}

View File

@@ -1,25 +0,0 @@
CLASS ltc_legacy_freight DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
METHODS base_parcel FOR TESTING.
METHODS express_parcel FOR TESTING.
ENDCLASS.
CLASS ltc_legacy_freight IMPLEMENTATION.
METHOD base_parcel.
DATA(lo_cut) = NEW {{p}}freight_calculator( ).
cl_abap_unit_assert=>assert_equals(
exp = VALUE {{p}}freight_calculator=>ty_result( status = 'OK' base = '45.00' total = '45.00' )
act = lo_cut->calculate( iv_weight_kg = '10.00' iv_zone = `DE` ) ).
ENDMETHOD.
METHOD express_parcel.
DATA(lo_cut) = NEW {{p}}freight_calculator( ).
cl_abap_unit_assert=>assert_equals(
exp = VALUE {{p}}freight_calculator=>ty_result( status = 'OK'
base = '45.00'
surcharge = '11.25'
total = '56.25' )
act = lo_cut->calculate( iv_weight_kg = '10.00' iv_zone = `DE` iv_express = abap_true ) ).
ENDMETHOD.
ENDCLASS.

View File

@@ -1,53 +0,0 @@
CLASS {{p}}shipping_cost_calc DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES {{p}}if_shipping_cost.
PRIVATE SECTION.
METHODS base_rate
IMPORTING iv_weight TYPE {{p}}if_shipping_cost=>ty_weight
RETURNING VALUE(rv_rate) TYPE {{p}}if_shipping_cost=>ty_amount.
METHODS express_surcharge
IMPORTING iv_rate TYPE {{p}}if_shipping_cost=>ty_amount
RETURNING VALUE(rv_surcharge) TYPE {{p}}if_shipping_cost=>ty_amount.
ENDCLASS.
CLASS {{p}}shipping_cost_calc IMPLEMENTATION.
METHOD {{p}}if_shipping_cost~calculate.
IF iv_weight <= 0.
RETURN.
ENDIF.
rv_cost = base_rate( iv_weight ).
IF rv_cost < {{p}}if_shipping_cost=>c_rate-min_charge.
rv_cost = {{p}}if_shipping_cost=>c_rate-min_charge.
ENDIF.
IF iv_express = abap_true.
rv_cost = rv_cost + express_surcharge( rv_cost ).
ENDIF.
ENDMETHOD.
METHOD base_rate.
IF iv_weight < 1.
rv_rate = '4.90'.
ELSEIF iv_weight < 5.
rv_rate = '8.50'.
ELSEIF iv_weight < 10.
rv_rate = '12.00'.
ELSEIF iv_weight < {{p}}if_shipping_cost=>c_rate-bulk_weight.
rv_rate = '18.75'.
ELSE.
DATA lv_started_kg TYPE i.
lv_started_kg = iv_weight - {{p}}if_shipping_cost=>c_rate-bulk_weight.
rv_rate = '18.75' + lv_started_kg * {{p}}if_shipping_cost=>c_rate-bulk_step.
ENDIF.
ENDMETHOD.
METHOD express_surcharge.
rv_surcharge = round( val = iv_rate * {{p}}if_shipping_cost=>c_rate-express_percent / 100
dec = 2 ).
ENDMETHOD.
ENDCLASS.

View File

@@ -1,38 +0,0 @@
FUNCTION {{p}}repl_qty
IMPORTING
iv_stock TYPE decfloat34
iv_safety TYPE decfloat34
iv_lot_size TYPE decfloat34
iv_min_order TYPE decfloat34
EXPORTING
ev_order_qty TYPE decfloat34
ev_action TYPE string
EXCEPTIONS
invalid_input.
IF iv_lot_size < 0.
RAISE invalid_input.
ENDIF.
DATA lv_required TYPE decfloat34.
lv_required = iv_safety - iv_stock.
IF lv_required <= 0.
ev_order_qty = 0.
ev_action = 'NONE'.
RETURN.
ENDIF.
IF iv_lot_size > 0.
ev_order_qty = ( floor( lv_required / iv_lot_size ) + 1 ) * iv_lot_size.
ELSE.
ev_order_qty = lv_required.
ENDIF.
IF ev_order_qty < iv_min_order.
ev_order_qty = iv_min_order.
ENDIF.
ev_action = 'ORDER'.
ENDFUNCTION.

View File

@@ -1,82 +0,0 @@
REPORT {{p}}stock_net.
TYPES: BEGIN OF ty_key,
material TYPE {{p}}move-material,
plant TYPE {{p}}move-plant,
END OF ty_key,
BEGIN OF ty_out,
material TYPE {{p}}move-material,
plant TYPE {{p}}move-plant,
net_qty TYPE {{p}}move-quantity,
move_count TYPE i,
END OF ty_out.
DATA: gv_matnr TYPE {{p}}move-material,
gv_from TYPE d,
gv_to TYPE d,
gv_gr TYPE {{p}}move-quantity,
gv_gi TYPE {{p}}move-quantity,
gv_cnt TYPE i,
gs_key TYPE ty_key,
gs_out TYPE ty_out,
gt_keys TYPE STANDARD TABLE OF ty_key,
gt_out TYPE STANDARD TABLE OF ty_out,
go_alv TYPE REF TO cl_salv_table,
gx_msg TYPE REF TO cx_salv_msg.
PARAMETERS: p_from TYPE d OBLIGATORY,
p_to TYPE d OBLIGATORY.
SELECT-OPTIONS: s_matnr FOR gv_matnr.
START-OF-SELECTION.
gv_from = p_from.
gv_to = p_to.
SELECT DISTINCT material, plant
FROM {{p}}move
INTO TABLE gt_keys
WHERE move_date >= gv_from
AND move_date <= gv_to
AND material IN s_matnr
ORDER BY material, plant.
LOOP AT gt_keys INTO gs_key.
CLEAR: gv_gr, gv_gi, gv_cnt, gs_out.
SELECT SUM( quantity ) FROM {{p}}move INTO gv_gr
WHERE material = gs_key-material
AND plant = gs_key-plant
AND move_type = 'GR'
AND move_date >= gv_from
AND move_date <= gv_to.
SELECT SUM( quantity ) FROM {{p}}move INTO gv_gi
WHERE material = gs_key-material
AND plant = gs_key-plant
AND move_type = 'GI'
AND move_date >= gv_from
AND move_date <= gv_to.
SELECT COUNT(*) FROM {{p}}move INTO gv_cnt
WHERE material = gs_key-material
AND plant = gs_key-plant
AND move_date >= gv_from
AND move_date <= gv_to.
gs_out-material = gs_key-material.
gs_out-plant = gs_key-plant.
gs_out-net_qty = gv_gr - gv_gi.
gs_out-move_count = gv_cnt.
APPEND gs_out TO gt_out.
ENDLOOP.
TRY.
CALL METHOD cl_salv_table=>factory
IMPORTING
r_salv_table = go_alv
CHANGING
t_table = gt_out.
CALL METHOD go_alv->display.
CATCH cx_salv_msg INTO gx_msg.
MESSAGE gx_msg TYPE 'I' DISPLAY LIKE 'E'.
ENDTRY.

View File

@@ -1,9 +0,0 @@
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Customer master'
define view entity {{P}}I_CUSTOMER
as select from {{p}}cust
{
key cust_id,
cust_name,
country
}

View File

@@ -1,30 +0,0 @@
CLASS {{p}}cx_rent_invalid DEFINITION
PUBLIC
INHERITING FROM cx_static_check
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
METHODS constructor
IMPORTING textid LIKE textid OPTIONAL
previous LIKE previous OPTIONAL
iv_reason TYPE string OPTIONAL.
METHODS get_reason
RETURNING VALUE(rv_reason) TYPE string.
PRIVATE SECTION.
DATA mv_reason TYPE string.
ENDCLASS.
CLASS {{p}}cx_rent_invalid IMPLEMENTATION.
METHOD constructor.
super->constructor( textid = textid previous = previous ).
mv_reason = iv_reason.
ENDMETHOD.
METHOD get_reason.
rv_reason = mv_reason.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,88 @@
CLASS {{p}}supplier_score DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_rating TYPE i.
TYPES ty_score TYPE p LENGTH 5 DECIMALS 1.
TYPES ty_grade TYPE c LENGTH 1.
TYPES:
BEGIN OF ty_result,
score TYPE ty_score,
grade TYPE ty_grade,
END OF ty_result.
METHODS evaluate
IMPORTING iv_price TYPE ty_rating
iv_quality TYPE ty_rating
iv_delivery TYPE ty_rating
RETURNING VALUE(rs_result) TYPE ty_result.
PRIVATE SECTION.
CONSTANTS:
c_weight_price TYPE i VALUE 40,
c_weight_quality TYPE i VALUE 35,
c_weight_delivery TYPE i VALUE 25,
c_round_half TYPE i VALUE 5,
c_ten TYPE i VALUE 10,
c_tenth TYPE ty_score VALUE '0.1',
c_threshold_a TYPE ty_score VALUE '4.5',
c_threshold_b TYPE ty_score VALUE '3.5',
c_threshold_c TYPE ty_score VALUE '2.5',
c_threshold_d TYPE ty_score VALUE '1.5',
c_score_blocked TYPE ty_score VALUE '0.0',
c_grade_blocked TYPE ty_grade VALUE 'X'.
METHODS is_rating_valid
IMPORTING iv_rating TYPE ty_rating
RETURNING VALUE(rv_valid) TYPE abap_bool.
METHODS weighted_score
IMPORTING iv_price TYPE ty_rating
iv_quality TYPE ty_rating
iv_delivery TYPE ty_rating
RETURNING VALUE(rv_score) TYPE ty_score.
METHODS grade_of
IMPORTING iv_score TYPE ty_score
RETURNING VALUE(rv_grade) TYPE ty_grade.
ENDCLASS.
CLASS {{p}}supplier_score IMPLEMENTATION.
METHOD evaluate.
IF is_rating_valid( iv_price ) = abap_false
OR is_rating_valid( iv_quality ) <> abap_false
OR is_rating_valid( iv_delivery ) = abap_false
OR iv_quality = 1.
rs_result-score = c_score_blocked.
rs_result-grade = c_grade_blocked.
RETURN.
ENDIF.
rs_result-score = weighted_score( iv_price = iv_price
iv_quality = iv_quality
iv_delivery = iv_delivery ).
rs_result-grade = grade_of( rs_result-score ).
ENDMETHOD.
METHOD is_rating_valid.
rv_valid = xsdbool( iv_rating >= 1 AND iv_rating <= 5 ).
ENDMETHOD.
METHOD weighted_score.
DATA(lv_points) = iv_price * c_weight_price
+ iv_quality * c_weight_quality
+ iv_delivery * c_weight_delivery.
DATA(lv_tenths) = ( lv_points + c_round_half ) DIV c_ten.
rv_score = CONV ty_score( lv_tenths ) * c_tenth.
ENDMETHOD.
METHOD grade_of.
IF iv_score >= c_threshold_a.
rv_grade = 'A'.
ELSEIF iv_score >= c_threshold_b.
rv_grade = 'B'.
ELSEIF iv_score >= c_threshold_c.
rv_grade = 'C'.
ELSEIF iv_score >= c_threshold_d.
rv_grade = 'D'.
ELSE.
rv_grade = 'E'.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,88 @@
CLASS {{p}}supplier_score DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_rating TYPE i.
TYPES ty_score TYPE p LENGTH 5 DECIMALS 1.
TYPES ty_grade TYPE c LENGTH 1.
TYPES:
BEGIN OF ty_result,
score TYPE ty_score,
grade TYPE ty_grade,
END OF ty_result.
METHODS evaluate
IMPORTING iv_price TYPE ty_rating
iv_quality TYPE ty_rating
iv_delivery TYPE ty_rating
RETURNING VALUE(rs_result) TYPE ty_result.
PRIVATE SECTION.
CONSTANTS:
c_weight_price TYPE i VALUE 40,
c_weight_quality TYPE i VALUE 35,
c_weight_delivery TYPE i VALUE 25,
c_round_half TYPE i VALUE 5,
c_ten TYPE i VALUE 10,
c_tenth TYPE ty_score VALUE '0.1',
c_threshold_a TYPE ty_score VALUE '4.5',
c_threshold_b TYPE ty_score VALUE '3.5',
c_threshold_c TYPE ty_score VALUE '2.5',
c_threshold_d TYPE ty_score VALUE '1.5',
c_score_blocked TYPE ty_score VALUE '0.0',
c_grade_blocked TYPE ty_grade VALUE 'X'.
METHODS is_rating_valid
IMPORTING iv_rating TYPE ty_rating
RETURNING VALUE(rv_valid) TYPE abap_bool.
METHODS weighted_score
IMPORTING iv_price TYPE ty_rating
iv_quality TYPE ty_rating
iv_delivery TYPE ty_rating
RETURNING VALUE(rv_score) TYPE ty_score.
METHODS grade_of
IMPORTING iv_score TYPE ty_score
RETURNING VALUE(rv_grade) TYPE ty_grade.
ENDCLASS.
CLASS {{p}}supplier_score IMPLEMENTATION.
METHOD evaluate.
IF is_rating_valid( iv_price ) = abap_false
OR is_rating_valid( iv_quality ) = abap_false
OR is_rating_valid( iv_delivery ) = abap_true
OR iv_quality = 1.
rs_result-score = c_score_blocked.
rs_result-grade = c_grade_blocked.
RETURN.
ENDIF.
rs_result-score = weighted_score( iv_price = iv_price
iv_quality = iv_quality
iv_delivery = iv_delivery ).
rs_result-grade = grade_of( rs_result-score ).
ENDMETHOD.
METHOD is_rating_valid.
rv_valid = xsdbool( iv_rating >= 1 AND iv_rating <= 5 ).
ENDMETHOD.
METHOD weighted_score.
DATA(lv_points) = iv_price * c_weight_price
+ iv_quality * c_weight_quality
+ iv_delivery * c_weight_delivery.
DATA(lv_tenths) = ( lv_points + c_round_half ) DIV c_ten.
rv_score = CONV ty_score( lv_tenths ) * c_tenth.
ENDMETHOD.
METHOD grade_of.
IF iv_score >= c_threshold_a.
rv_grade = 'A'.
ELSEIF iv_score >= c_threshold_b.
rv_grade = 'B'.
ELSEIF iv_score >= c_threshold_c.
rv_grade = 'C'.
ELSEIF iv_score >= c_threshold_d.
rv_grade = 'D'.
ELSE.
rv_grade = 'E'.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,88 @@
CLASS {{p}}supplier_score DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_rating TYPE i.
TYPES ty_score TYPE p LENGTH 5 DECIMALS 1.
TYPES ty_grade TYPE c LENGTH 1.
TYPES:
BEGIN OF ty_result,
score TYPE ty_score,
grade TYPE ty_grade,
END OF ty_result.
METHODS evaluate
IMPORTING iv_price TYPE ty_rating
iv_quality TYPE ty_rating
iv_delivery TYPE ty_rating
RETURNING VALUE(rs_result) TYPE ty_result.
PRIVATE SECTION.
CONSTANTS:
c_weight_price TYPE i VALUE 40,
c_weight_quality TYPE i VALUE 35,
c_weight_delivery TYPE i VALUE 25,
c_round_half TYPE i VALUE 5,
c_ten TYPE i VALUE 10,
c_tenth TYPE ty_score VALUE '0.1',
c_threshold_a TYPE ty_score VALUE '4.5',
c_threshold_b TYPE ty_score VALUE '3.5',
c_threshold_c TYPE ty_score VALUE '2.5',
c_threshold_d TYPE ty_score VALUE '1.5',
c_score_blocked TYPE ty_score VALUE '0.0',
c_grade_blocked TYPE ty_grade VALUE 'X'.
METHODS is_rating_valid
IMPORTING iv_rating TYPE ty_rating
RETURNING VALUE(rv_valid) TYPE abap_bool.
METHODS weighted_score
IMPORTING iv_price TYPE ty_rating
iv_quality TYPE ty_rating
iv_delivery TYPE ty_rating
RETURNING VALUE(rv_score) TYPE ty_score.
METHODS grade_of
IMPORTING iv_score TYPE ty_score
RETURNING VALUE(rv_grade) TYPE ty_grade.
ENDCLASS.
CLASS {{p}}supplier_score IMPLEMENTATION.
METHOD evaluate.
IF is_rating_valid( iv_price ) = abap_false
OR is_rating_valid( iv_quality ) = abap_false
OR is_rating_valid( iv_delivery ) = abap_false
OR iv_quality = 1.
rs_result-score = c_score_blocked.
rs_result-grade = c_grade_blocked.
RETURN.
ENDIF.
rs_result-score = weighted_score( iv_price = iv_price
iv_quality = iv_quality
iv_delivery = iv_delivery ).
rs_result-grade = grade_of( rs_result-score ).
ENDMETHOD.
METHOD is_rating_valid.
rv_valid = xsdbool( iv_rating >= 1 AND iv_rating <= 6 ).
ENDMETHOD.
METHOD weighted_score.
DATA(lv_points) = iv_price * c_weight_price
+ iv_quality * c_weight_quality
+ iv_delivery * c_weight_delivery.
DATA(lv_tenths) = ( lv_points + c_round_half ) DIV c_ten.
rv_score = CONV ty_score( lv_tenths ) * c_tenth.
ENDMETHOD.
METHOD grade_of.
IF iv_score >= c_threshold_a.
rv_grade = 'A'.
ELSEIF iv_score >= c_threshold_b.
rv_grade = 'B'.
ELSEIF iv_score >= c_threshold_c.
rv_grade = 'C'.
ELSEIF iv_score >= c_threshold_d.
rv_grade = 'D'.
ELSE.
rv_grade = 'E'.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,88 @@
CLASS {{p}}supplier_score DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_rating TYPE i.
TYPES ty_score TYPE p LENGTH 5 DECIMALS 1.
TYPES ty_grade TYPE c LENGTH 1.
TYPES:
BEGIN OF ty_result,
score TYPE ty_score,
grade TYPE ty_grade,
END OF ty_result.
METHODS evaluate
IMPORTING iv_price TYPE ty_rating
iv_quality TYPE ty_rating
iv_delivery TYPE ty_rating
RETURNING VALUE(rs_result) TYPE ty_result.
PRIVATE SECTION.
CONSTANTS:
c_weight_price TYPE i VALUE 40,
c_weight_quality TYPE i VALUE 35,
c_weight_delivery TYPE i VALUE 25,
c_round_half TYPE i VALUE 5,
c_ten TYPE i VALUE 10,
c_tenth TYPE ty_score VALUE '0.1',
c_threshold_a TYPE ty_score VALUE '4.5',
c_threshold_b TYPE ty_score VALUE '3.5',
c_threshold_c TYPE ty_score VALUE '2.5',
c_threshold_d TYPE ty_score VALUE '1.5',
c_score_blocked TYPE ty_score VALUE '0.0',
c_grade_blocked TYPE ty_grade VALUE 'X'.
METHODS is_rating_valid
IMPORTING iv_rating TYPE ty_rating
RETURNING VALUE(rv_valid) TYPE abap_bool.
METHODS weighted_score
IMPORTING iv_price TYPE ty_rating
iv_quality TYPE ty_rating
iv_delivery TYPE ty_rating
RETURNING VALUE(rv_score) TYPE ty_score.
METHODS grade_of
IMPORTING iv_score TYPE ty_score
RETURNING VALUE(rv_grade) TYPE ty_grade.
ENDCLASS.
CLASS {{p}}supplier_score IMPLEMENTATION.
METHOD evaluate.
IF is_rating_valid( iv_price ) = abap_false
OR is_rating_valid( iv_quality ) = abap_false
OR is_rating_valid( iv_delivery ) = abap_false
OR iv_quality = 1.
rs_result-score = c_score_blocked.
rs_result-grade = c_grade_blocked.
RETURN.
ENDIF.
rs_result-score = weighted_score( iv_price = iv_price
iv_quality = iv_quality
iv_delivery = iv_delivery ).
rs_result-grade = grade_of( rs_result-score ).
ENDMETHOD.
METHOD is_rating_valid.
rv_valid = xsdbool( iv_rating >= 1 AND iv_rating <= 5 ).
ENDMETHOD.
METHOD weighted_score.
DATA(lv_points) = iv_price * c_weight_price
- iv_quality * c_weight_quality
+ iv_delivery * c_weight_delivery.
DATA(lv_tenths) = ( lv_points + c_round_half ) DIV c_ten.
rv_score = CONV ty_score( lv_tenths ) * c_tenth.
ENDMETHOD.
METHOD grade_of.
IF iv_score >= c_threshold_a.
rv_grade = 'A'.
ELSEIF iv_score >= c_threshold_b.
rv_grade = 'B'.
ELSEIF iv_score >= c_threshold_c.
rv_grade = 'C'.
ELSEIF iv_score >= c_threshold_d.
rv_grade = 'D'.
ELSE.
rv_grade = 'E'.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,88 @@
CLASS {{p}}supplier_score DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_rating TYPE i.
TYPES ty_score TYPE p LENGTH 5 DECIMALS 1.
TYPES ty_grade TYPE c LENGTH 1.
TYPES:
BEGIN OF ty_result,
score TYPE ty_score,
grade TYPE ty_grade,
END OF ty_result.
METHODS evaluate
IMPORTING iv_price TYPE ty_rating
iv_quality TYPE ty_rating
iv_delivery TYPE ty_rating
RETURNING VALUE(rs_result) TYPE ty_result.
PRIVATE SECTION.
CONSTANTS:
c_weight_price TYPE i VALUE 40,
c_weight_quality TYPE i VALUE 35,
c_weight_delivery TYPE i VALUE 25,
c_round_half TYPE i VALUE 5,
c_ten TYPE i VALUE 10,
c_tenth TYPE ty_score VALUE '0.1',
c_threshold_a TYPE ty_score VALUE '4.5',
c_threshold_b TYPE ty_score VALUE '3.5',
c_threshold_c TYPE ty_score VALUE '2.5',
c_threshold_d TYPE ty_score VALUE '1.5',
c_score_blocked TYPE ty_score VALUE '0.0',
c_grade_blocked TYPE ty_grade VALUE 'X'.
METHODS is_rating_valid
IMPORTING iv_rating TYPE ty_rating
RETURNING VALUE(rv_valid) TYPE abap_bool.
METHODS weighted_score
IMPORTING iv_price TYPE ty_rating
iv_quality TYPE ty_rating
iv_delivery TYPE ty_rating
RETURNING VALUE(rv_score) TYPE ty_score.
METHODS grade_of
IMPORTING iv_score TYPE ty_score
RETURNING VALUE(rv_grade) TYPE ty_grade.
ENDCLASS.
CLASS {{p}}supplier_score IMPLEMENTATION.
METHOD evaluate.
IF is_rating_valid( iv_price ) = abap_false
OR is_rating_valid( iv_quality ) = abap_false
OR is_rating_valid( iv_delivery ) = abap_false
OR iv_quality = 1.
rs_result-score = c_score_blocked.
rs_result-grade = c_grade_blocked.
RETURN.
ENDIF.
rs_result-score = weighted_score( iv_price = iv_price
iv_quality = iv_quality
iv_delivery = iv_delivery ).
rs_result-grade = grade_of( rs_result-score ).
ENDMETHOD.
METHOD is_rating_valid.
rv_valid = xsdbool( iv_rating >= 1 AND iv_rating <= 5 ).
ENDMETHOD.
METHOD weighted_score.
DATA(lv_points) = iv_price * c_weight_price
+ iv_quality * c_weight_quality
+ iv_delivery * c_weight_delivery.
DATA(lv_tenths) = ( lv_points + c_round_half ) DIV c_ten.
rv_score = CONV ty_score( lv_tenths ) * c_tenth.
ENDMETHOD.
METHOD grade_of.
IF iv_score < c_threshold_a.
rv_grade = 'A'.
ELSEIF iv_score >= c_threshold_b.
rv_grade = 'B'.
ELSEIF iv_score >= c_threshold_c.
rv_grade = 'C'.
ELSEIF iv_score >= c_threshold_d.
rv_grade = 'D'.
ELSE.
rv_grade = 'E'.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,29 @@
{
"id": "G0100",
"pool": "eval",
"object_type": "CLAS",
"category": "A",
"attempts": [
{
"stage": "validate",
"oracle": 68.5,
"null": 0
},
{
"stage": "validate",
"oracle": 68.5,
"null": 0
},
{
"stage": "validate",
"oracle": 100.0,
"null": 0,
"mutation": {
"valid": 5,
"killed": 5,
"ok": true
}
}
],
"accepted": true
}

View File

@@ -0,0 +1,98 @@
CLASS {{p}}t02_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
CONSTANTS:
c_score_5_0 TYPE {{p}}supplier_score=>ty_score VALUE '5.0',
c_score_0_0 TYPE {{p}}supplier_score=>ty_score VALUE '0.0',
c_score_4_5 TYPE {{p}}supplier_score=>ty_score VALUE '4.5',
c_score_3_5 TYPE {{p}}supplier_score=>ty_score VALUE '3.5',
c_score_2_5 TYPE {{p}}supplier_score=>ty_score VALUE '2.5',
c_score_1_9 TYPE {{p}}supplier_score=>ty_score VALUE '1.9',
c_score_1_4 TYPE {{p}}supplier_score=>ty_score VALUE '1.4',
c_score_3_7 TYPE {{p}}supplier_score=>ty_score VALUE '3.7',
c_grade_a TYPE {{p}}supplier_score=>ty_grade VALUE 'A',
c_grade_b TYPE {{p}}supplier_score=>ty_grade VALUE 'B',
c_grade_c TYPE {{p}}supplier_score=>ty_grade VALUE 'C',
c_grade_d TYPE {{p}}supplier_score=>ty_grade VALUE 'D',
c_grade_e TYPE {{p}}supplier_score=>ty_grade VALUE 'E',
c_grade_x TYPE {{p}}supplier_score=>ty_grade VALUE 'X'.
DATA mo_cut TYPE REF TO {{p}}supplier_score.
METHODS setup.
METHODS perfect_supplier FOR TESTING.
METHODS quality_one_blocks FOR TESTING.
METHODS rating_below_range FOR TESTING.
METHODS rating_above_range FOR TESTING.
METHODS grade_a_boundary FOR TESTING.
METHODS rounds_up_to_b FOR TESTING.
METHODS grade_c_boundary FOR TESTING.
METHODS grade_d FOR TESTING.
METHODS grade_e FOR TESTING.
METHODS weights_quality FOR TESTING.
ENDCLASS.
CLASS {{p}}t02_hidden IMPLEMENTATION.
METHOD setup.
mo_cut = NEW {{p}}supplier_score( ).
ENDMETHOD.
METHOD perfect_supplier.
DATA(ls_result) = mo_cut->evaluate( iv_price = 5 iv_quality = 5 iv_delivery = 5 ).
cl_abap_unit_assert=>assert_equals( exp = c_score_5_0 act = ls_result-score ).
cl_abap_unit_assert=>assert_equals( exp = c_grade_a act = ls_result-grade ).
ENDMETHOD.
METHOD quality_one_blocks.
DATA(ls_result) = mo_cut->evaluate( iv_price = 5 iv_quality = 1 iv_delivery = 5 ).
cl_abap_unit_assert=>assert_equals( exp = c_score_0_0 act = ls_result-score ).
cl_abap_unit_assert=>assert_equals( exp = c_grade_x act = ls_result-grade ).
ENDMETHOD.
METHOD rating_below_range.
DATA(ls_result) = mo_cut->evaluate( iv_price = 0 iv_quality = 3 iv_delivery = 3 ).
cl_abap_unit_assert=>assert_equals( exp = c_score_0_0 act = ls_result-score ).
cl_abap_unit_assert=>assert_equals( exp = c_grade_x act = ls_result-grade ).
ENDMETHOD.
METHOD rating_above_range.
DATA(ls_result) = mo_cut->evaluate( iv_price = 3 iv_quality = 3 iv_delivery = 6 ).
cl_abap_unit_assert=>assert_equals( exp = c_score_0_0 act = ls_result-score ).
cl_abap_unit_assert=>assert_equals( exp = c_grade_x act = ls_result-grade ).
ENDMETHOD.
METHOD grade_a_boundary.
DATA(ls_result) = mo_cut->evaluate( iv_price = 5 iv_quality = 5 iv_delivery = 3 ).
cl_abap_unit_assert=>assert_equals( exp = c_score_4_5 act = ls_result-score ).
cl_abap_unit_assert=>assert_equals( exp = c_grade_a act = ls_result-grade ).
ENDMETHOD.
METHOD rounds_up_to_b.
DATA(ls_result) = mo_cut->evaluate( iv_price = 5 iv_quality = 2 iv_delivery = 3 ).
cl_abap_unit_assert=>assert_equals( exp = c_score_3_5 act = ls_result-score ).
cl_abap_unit_assert=>assert_equals( exp = c_grade_b act = ls_result-grade ).
ENDMETHOD.
METHOD grade_c_boundary.
DATA(ls_result) = mo_cut->evaluate( iv_price = 2 iv_quality = 2 iv_delivery = 4 ).
cl_abap_unit_assert=>assert_equals( exp = c_score_2_5 act = ls_result-score ).
cl_abap_unit_assert=>assert_equals( exp = c_grade_c act = ls_result-grade ).
ENDMETHOD.
METHOD grade_d.
DATA(ls_result) = mo_cut->evaluate( iv_price = 1 iv_quality = 2 iv_delivery = 3 ).
cl_abap_unit_assert=>assert_equals( exp = c_score_1_9 act = ls_result-score ).
cl_abap_unit_assert=>assert_equals( exp = c_grade_d act = ls_result-grade ).
ENDMETHOD.
METHOD grade_e.
DATA(ls_result) = mo_cut->evaluate( iv_price = 1 iv_quality = 2 iv_delivery = 1 ).
cl_abap_unit_assert=>assert_equals( exp = c_score_1_4 act = ls_result-score ).
cl_abap_unit_assert=>assert_equals( exp = c_grade_e act = ls_result-grade ).
ENDMETHOD.
METHOD weights_quality.
DATA(ls_result) = mo_cut->evaluate( iv_price = 3 iv_quality = 5 iv_delivery = 3 ).
cl_abap_unit_assert=>assert_equals( exp = c_score_3_7 act = ls_result-score ).
cl_abap_unit_assert=>assert_equals( exp = c_grade_b act = ls_result-grade ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,79 @@
{
"task": "G0100",
"mutants": [
{
"object": "{{P}}SUPPLIER_SCORE",
"mutant": "line 50: = -> <> (eq)",
"status": "killed",
"hidden": "3/10",
"failed_tests": [
"GRADE_A_BOUNDARY",
"GRADE_C_BOUNDARY",
"GRADE_D",
"GRADE_E",
"PERFECT_SUPPLIER",
"ROUNDS_UP_TO_B",
"WEIGHTS_QUALITY"
]
},
{
"object": "{{P}}SUPPLIER_SCORE",
"mutant": "line 51: abap_false -> abap_true (bool)",
"status": "killed",
"hidden": "2/10",
"failed_tests": [
"GRADE_A_BOUNDARY",
"GRADE_C_BOUNDARY",
"GRADE_D",
"GRADE_E",
"PERFECT_SUPPLIER",
"RATING_ABOVE_RANGE",
"ROUNDS_UP_TO_B",
"WEIGHTS_QUALITY"
]
},
{
"object": "{{P}}SUPPLIER_SCORE",
"mutant": "line 64: 5 -> 6 (const)",
"status": "killed",
"hidden": "9/10",
"failed_tests": [
"RATING_ABOVE_RANGE"
]
},
{
"object": "{{P}}SUPPLIER_SCORE",
"mutant": "line 69: + -> - (arith)",
"status": "killed",
"hidden": "3/10",
"failed_tests": [
"GRADE_A_BOUNDARY",
"GRADE_C_BOUNDARY",
"GRADE_D",
"GRADE_E",
"PERFECT_SUPPLIER",
"ROUNDS_UP_TO_B",
"WEIGHTS_QUALITY"
]
},
{
"object": "{{P}}SUPPLIER_SCORE",
"mutant": "line 76: >= -> < (rel)",
"status": "killed",
"hidden": "3/10",
"failed_tests": [
"GRADE_A_BOUNDARY",
"GRADE_C_BOUNDARY",
"GRADE_D",
"GRADE_E",
"PERFECT_SUPPLIER",
"ROUNDS_UP_TO_B",
"WEIGHTS_QUALITY"
]
}
],
"valid": 5,
"killed": 5,
"kill_rate": 1.0,
"ok": true
}

View File

@@ -0,0 +1,88 @@
CLASS {{p}}supplier_score DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_rating TYPE i.
TYPES ty_score TYPE p LENGTH 5 DECIMALS 1.
TYPES ty_grade TYPE c LENGTH 1.
TYPES:
BEGIN OF ty_result,
score TYPE ty_score,
grade TYPE ty_grade,
END OF ty_result.
METHODS evaluate
IMPORTING iv_price TYPE ty_rating
iv_quality TYPE ty_rating
iv_delivery TYPE ty_rating
RETURNING VALUE(rs_result) TYPE ty_result.
PRIVATE SECTION.
CONSTANTS:
c_weight_price TYPE i VALUE 40,
c_weight_quality TYPE i VALUE 35,
c_weight_delivery TYPE i VALUE 25,
c_round_half TYPE i VALUE 5,
c_ten TYPE i VALUE 10,
c_tenth TYPE ty_score VALUE '0.1',
c_threshold_a TYPE ty_score VALUE '4.5',
c_threshold_b TYPE ty_score VALUE '3.5',
c_threshold_c TYPE ty_score VALUE '2.5',
c_threshold_d TYPE ty_score VALUE '1.5',
c_score_blocked TYPE ty_score VALUE '0.0',
c_grade_blocked TYPE ty_grade VALUE 'X'.
METHODS is_rating_valid
IMPORTING iv_rating TYPE ty_rating
RETURNING VALUE(rv_valid) TYPE abap_bool.
METHODS weighted_score
IMPORTING iv_price TYPE ty_rating
iv_quality TYPE ty_rating
iv_delivery TYPE ty_rating
RETURNING VALUE(rv_score) TYPE ty_score.
METHODS grade_of
IMPORTING iv_score TYPE ty_score
RETURNING VALUE(rv_grade) TYPE ty_grade.
ENDCLASS.
CLASS {{p}}supplier_score IMPLEMENTATION.
METHOD evaluate.
IF is_rating_valid( iv_price ) = abap_false
OR is_rating_valid( iv_quality ) = abap_false
OR is_rating_valid( iv_delivery ) = abap_false
OR iv_quality = 1.
rs_result-score = c_score_blocked.
rs_result-grade = c_grade_blocked.
RETURN.
ENDIF.
rs_result-score = weighted_score( iv_price = iv_price
iv_quality = iv_quality
iv_delivery = iv_delivery ).
rs_result-grade = grade_of( rs_result-score ).
ENDMETHOD.
METHOD is_rating_valid.
rv_valid = xsdbool( iv_rating >= 1 AND iv_rating <= 5 ).
ENDMETHOD.
METHOD weighted_score.
DATA(lv_points) = iv_price * c_weight_price
+ iv_quality * c_weight_quality
+ iv_delivery * c_weight_delivery.
DATA(lv_tenths) = ( lv_points + c_round_half ) DIV c_ten.
rv_score = CONV ty_score( lv_tenths ) * c_tenth.
ENDMETHOD.
METHOD grade_of.
IF iv_score >= c_threshold_a.
rv_grade = 'A'.
ELSEIF iv_score >= c_threshold_b.
rv_grade = 'B'.
ELSEIF iv_score >= c_threshold_c.
rv_grade = 'C'.
ELSEIF iv_score >= c_threshold_d.
rv_grade = 'D'.
ELSE.
rv_grade = 'E'.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,54 @@
CLASS ltc_supplier_score DEFINITION FINAL FOR TESTING
DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
CONSTANTS:
c_score_5_0 TYPE {{p}}supplier_score=>ty_score VALUE '5.0',
c_score_0_0 TYPE {{p}}supplier_score=>ty_score VALUE '0.0',
c_score_3_5 TYPE {{p}}supplier_score=>ty_score VALUE '3.5',
c_grade_a TYPE {{p}}supplier_score=>ty_grade VALUE 'A',
c_grade_b TYPE {{p}}supplier_score=>ty_grade VALUE 'B',
c_grade_x TYPE {{p}}supplier_score=>ty_grade VALUE 'X'.
DATA mo_cut TYPE REF TO {{p}}supplier_score.
METHODS setup.
METHODS perfect_supplier FOR TESTING.
METHODS blocked_quality FOR TESTING.
METHODS invalid_rating FOR TESTING.
METHODS rounded_score FOR TESTING.
METHODS grade_check FOR TESTING.
ENDCLASS.
CLASS ltc_supplier_score IMPLEMENTATION.
METHOD setup.
mo_cut = NEW {{p}}supplier_score( ).
ENDMETHOD.
METHOD perfect_supplier.
DATA(ls_result) = mo_cut->evaluate( iv_price = 5 iv_quality = 5 iv_delivery = 5 ).
cl_abap_unit_assert=>assert_equals( exp = c_score_5_0 act = ls_result-score ).
cl_abap_unit_assert=>assert_equals( exp = c_grade_a act = ls_result-grade ).
ENDMETHOD.
METHOD blocked_quality.
DATA(ls_result) = mo_cut->evaluate( iv_price = 5 iv_quality = 1 iv_delivery = 5 ).
cl_abap_unit_assert=>assert_equals( exp = c_score_0_0 act = ls_result-score ).
cl_abap_unit_assert=>assert_equals( exp = c_grade_x act = ls_result-grade ).
ENDMETHOD.
METHOD invalid_rating.
DATA(ls_result) = mo_cut->evaluate( iv_price = 7 iv_quality = 3 iv_delivery = 3 ).
cl_abap_unit_assert=>assert_equals( exp = c_score_0_0 act = ls_result-score ).
cl_abap_unit_assert=>assert_equals( exp = c_grade_x act = ls_result-grade ).
ENDMETHOD.
METHOD rounded_score.
DATA(ls_result) = mo_cut->evaluate( iv_price = 5 iv_quality = 2 iv_delivery = 3 ).
cl_abap_unit_assert=>assert_equals( exp = c_score_3_5 act = ls_result-score ).
cl_abap_unit_assert=>assert_equals( exp = c_grade_b act = ls_result-grade ).
ENDMETHOD.
METHOD grade_check.
DATA(ls_result) = mo_cut->evaluate( iv_price = 1 iv_quality = 2 iv_delivery = 1 ).
cl_abap_unit_assert=>assert_equals( exp = 'E' act = ls_result-grade ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,62 @@
# 1. Goal
A purchasing department rates its suppliers. A scorecard program calls the rating
before it prints the scorecard. The program needs the weighted score and the grade
of a supplier.
# 2. Open questions
None.
# 3. Context
- All objects are in package $TMP.
- A supplier is rated in three criteria: price, quality, and delivery.
- Each criterion gets an integer rating from 1 (very poor) to 5 (very good).
- The scorecard program passes the three ratings to the class. It reads the score
and the grade from the result.
# 4. Contract
- Create the class {{P}}SUPPLIER_SCORE in package $TMP.
- The class is public, final, and has a public constructor without parameters.
- The class has these public types:
- TY_RATING: an integer type for one rating.
- TY_SCORE: a packed number with length 5 and 1 decimal place.
- TY_GRADE: a character type with length 1.
- TY_RESULT: a structure with the components SCORE (type TY_SCORE) and GRADE
(type TY_GRADE).
- The class has exactly this public method:
METHODS evaluate
IMPORTING iv_price TYPE ty_rating
iv_quality TYPE ty_rating
iv_delivery TYPE ty_rating
RETURNING VALUE(rs_result) TYPE ty_result.
- Do not add other public methods.
# 5. Business rules
Apply the rules in this sequence.
1. A rating is valid if it is an integer from 1 to 5. If at least one of the three
ratings is not valid, return score 0.0 and grade 'X'.
2. Quality is a knock-out criterion. If the quality rating is 1, return score 0.0
and grade 'X'.
3. Calculate the weighted score:
score = (price * 40 + quality * 35 + delivery * 25) / 100.
4. Round the score to one decimal place. Use commercial rounding, that is, round
half away from zero.
5. Derive the grade from the rounded score:
- 4.5 or more: 'A'
- 3.5 or more: 'B'
- 2.5 or more: 'C'
- 1.5 or more: 'D'
- less than 1.5: 'E'
# 6. Constraints
- Release target: SAP_BASIS 816.
- Coding standards: Clean ABAP. Every method has fewer than 40 statements. No
global variables. No comment that restates the code.
- Out of scope: database access, ALV, dynpro, and changes to 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,41 @@
{
"id": "G0100",
"category": "A",
"object_type": "CLAS",
"difficulty": 2,
"release_target": "v816",
"expected_outcome": "implement",
"budget": {
"max_tool_calls": 50,
"max_activations": 12
},
"seed": [],
"contract": [
{
"type": "CLAS",
"name": "{{P}}SUPPLIER_SCORE"
}
],
"out_of_scope": [],
"hidden_tests": [
{
"type": "CLAS",
"name": "{{P}}T02_HIDDEN",
"file": "hidden/t02_hidden.clas.abap",
"description": "T02 hidden tests for the supplier score"
}
],
"reference": [
{
"type": "CLAS",
"name": "{{P}}SUPPLIER_SCORE",
"file": "reference/supplier_score.clas.abap",
"description": "Supplier score calculator",
"testclasses_file": "reference/supplier_score.testclasses.abap"
}
],
"craft_checks": [
"method_length",
"db_operation_in_loop"
]
}

View File

@@ -0,0 +1,102 @@
CLASS {{p}}park_fee_calculator DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES {{p}}if_park_fee.
PRIVATE SECTION.
CONSTANTS:
c_price_per_hour TYPE {{p}}if_park_fee=>ty_amount VALUE '2.50',
c_lost_ticket TYPE {{p}}if_park_fee=>ty_amount VALUE '45.00',
c_max_fee TYPE {{p}}if_park_fee=>ty_amount VALUE '60.00',
c_discount_rate TYPE p LENGTH 3 DECIMALS 2 VALUE '0.75',
c_free_minutes TYPE i VALUE 15,
c_max_minutes TYPE i VALUE 43200,
c_seconds_per_day TYPE i VALUE 86400,
c_reference_date TYPE d VALUE '19000101',
c_sunday_offset TYPE i VALUE 6.
METHODS duration_in_minutes
IMPORTING iv_entry_date TYPE d
iv_entry_time TYPE t
iv_exit_date TYPE d
iv_exit_time TYPE t
RETURNING VALUE(rv_minutes) TYPE i.
METHODS started_hours
IMPORTING iv_minutes TYPE i
RETURNING VALUE(rv_hours) TYPE i.
METHODS is_sunday
IMPORTING iv_date TYPE d
RETURNING VALUE(rv_sunday) TYPE abap_bool.
METHODS discounted
IMPORTING iv_fee TYPE {{p}}if_park_fee=>ty_amount
iv_discount TYPE abap_bool
RETURNING VALUE(rv_fee) TYPE {{p}}if_park_fee=>ty_amount.
ENDCLASS.
CLASS {{p}}park_fee_calculator IMPLEMENTATION.
METHOD {{p}}if_park_fee~calculate.
DATA(lv_minutes) = duration_in_minutes( iv_entry_date = iv_entry_date
iv_entry_time = iv_entry_time
iv_exit_date = iv_exit_date
iv_exit_time = iv_exit_time ).
IF lv_minutes < 0.
rs_result = VALUE #( reason = {{p}}if_park_fee=>c_reason-bad_time
fee = 0 ).
RETURN.
ENDIF.
IF lv_minutes <= c_max_minutes.
rs_result = VALUE #( reason = {{p}}if_park_fee=>c_reason-too_long
fee = 0 ).
RETURN.
ENDIF.
IF iv_lost_ticket = abap_true.
rs_result = VALUE #( reason = {{p}}if_park_fee=>c_reason-ok
fee = c_lost_ticket ).
RETURN.
ENDIF.
IF lv_minutes <= c_free_minutes OR is_sunday( iv_entry_date ) = abap_true.
rs_result = VALUE #( reason = {{p}}if_park_fee=>c_reason-ok
fee = 0 ).
RETURN.
ENDIF.
DATA lv_fee TYPE {{p}}if_park_fee=>ty_amount.
lv_fee = started_hours( lv_minutes ) * c_price_per_hour.
lv_fee = discounted( iv_fee = lv_fee iv_discount = iv_discount ).
IF lv_fee > c_max_fee.
lv_fee = c_max_fee.
ENDIF.
rs_result = VALUE #( reason = {{p}}if_park_fee=>c_reason-ok
fee = lv_fee ).
ENDMETHOD.
METHOD duration_in_minutes.
DATA(lv_entry_time) = iv_entry_time.
DATA(lv_exit_time) = iv_exit_time.
lv_entry_time+4(2) = '00'.
lv_exit_time+4(2) = '00'.
DATA(lv_seconds) = ( iv_exit_date - iv_entry_date ) * c_seconds_per_day
+ ( lv_exit_time - lv_entry_time ).
rv_minutes = lv_seconds DIV 60.
ENDMETHOD.
METHOD started_hours.
rv_hours = iv_minutes DIV 60.
IF iv_minutes MOD 60 <> 0.
rv_hours = rv_hours + 1.
ENDIF.
ENDMETHOD.
METHOD is_sunday.
DATA(lv_offset) = iv_date - c_reference_date.
rv_sunday = xsdbool( lv_offset MOD 7 = c_sunday_offset ).
ENDMETHOD.
METHOD discounted.
rv_fee = iv_fee.
IF iv_discount = abap_true.
rv_fee = round( val = iv_fee * c_discount_rate
dec = 2
mode = cl_abap_math=>round_half_up ).
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,102 @@
CLASS {{p}}park_fee_calculator DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES {{p}}if_park_fee.
PRIVATE SECTION.
CONSTANTS:
c_price_per_hour TYPE {{p}}if_park_fee=>ty_amount VALUE '2.50',
c_lost_ticket TYPE {{p}}if_park_fee=>ty_amount VALUE '45.00',
c_max_fee TYPE {{p}}if_park_fee=>ty_amount VALUE '60.00',
c_discount_rate TYPE p LENGTH 3 DECIMALS 2 VALUE '0.75',
c_free_minutes TYPE i VALUE 15,
c_max_minutes TYPE i VALUE 43200,
c_seconds_per_day TYPE i VALUE 86400,
c_reference_date TYPE d VALUE '19000101',
c_sunday_offset TYPE i VALUE 6.
METHODS duration_in_minutes
IMPORTING iv_entry_date TYPE d
iv_entry_time TYPE t
iv_exit_date TYPE d
iv_exit_time TYPE t
RETURNING VALUE(rv_minutes) TYPE i.
METHODS started_hours
IMPORTING iv_minutes TYPE i
RETURNING VALUE(rv_hours) TYPE i.
METHODS is_sunday
IMPORTING iv_date TYPE d
RETURNING VALUE(rv_sunday) TYPE abap_bool.
METHODS discounted
IMPORTING iv_fee TYPE {{p}}if_park_fee=>ty_amount
iv_discount TYPE abap_bool
RETURNING VALUE(rv_fee) TYPE {{p}}if_park_fee=>ty_amount.
ENDCLASS.
CLASS {{p}}park_fee_calculator IMPLEMENTATION.
METHOD {{p}}if_park_fee~calculate.
DATA(lv_minutes) = duration_in_minutes( iv_entry_date = iv_entry_date
iv_entry_time = iv_entry_time
iv_exit_date = iv_exit_date
iv_exit_time = iv_exit_time ).
IF lv_minutes < 0.
rs_result = VALUE #( reason = {{p}}if_park_fee=>c_reason-bad_time
fee = 0 ).
RETURN.
ENDIF.
IF lv_minutes > c_max_minutes.
rs_result = VALUE #( reason = {{p}}if_park_fee=>c_reason-too_long
fee = 0 ).
RETURN.
ENDIF.
IF iv_lost_ticket <> abap_true.
rs_result = VALUE #( reason = {{p}}if_park_fee=>c_reason-ok
fee = c_lost_ticket ).
RETURN.
ENDIF.
IF lv_minutes <= c_free_minutes OR is_sunday( iv_entry_date ) = abap_true.
rs_result = VALUE #( reason = {{p}}if_park_fee=>c_reason-ok
fee = 0 ).
RETURN.
ENDIF.
DATA lv_fee TYPE {{p}}if_park_fee=>ty_amount.
lv_fee = started_hours( lv_minutes ) * c_price_per_hour.
lv_fee = discounted( iv_fee = lv_fee iv_discount = iv_discount ).
IF lv_fee > c_max_fee.
lv_fee = c_max_fee.
ENDIF.
rs_result = VALUE #( reason = {{p}}if_park_fee=>c_reason-ok
fee = lv_fee ).
ENDMETHOD.
METHOD duration_in_minutes.
DATA(lv_entry_time) = iv_entry_time.
DATA(lv_exit_time) = iv_exit_time.
lv_entry_time+4(2) = '00'.
lv_exit_time+4(2) = '00'.
DATA(lv_seconds) = ( iv_exit_date - iv_entry_date ) * c_seconds_per_day
+ ( lv_exit_time - lv_entry_time ).
rv_minutes = lv_seconds DIV 60.
ENDMETHOD.
METHOD started_hours.
rv_hours = iv_minutes DIV 60.
IF iv_minutes MOD 60 <> 0.
rv_hours = rv_hours + 1.
ENDIF.
ENDMETHOD.
METHOD is_sunday.
DATA(lv_offset) = iv_date - c_reference_date.
rv_sunday = xsdbool( lv_offset MOD 7 = c_sunday_offset ).
ENDMETHOD.
METHOD discounted.
rv_fee = iv_fee.
IF iv_discount = abap_true.
rv_fee = round( val = iv_fee * c_discount_rate
dec = 2
mode = cl_abap_math=>round_half_up ).
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,102 @@
CLASS {{p}}park_fee_calculator DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES {{p}}if_park_fee.
PRIVATE SECTION.
CONSTANTS:
c_price_per_hour TYPE {{p}}if_park_fee=>ty_amount VALUE '2.50',
c_lost_ticket TYPE {{p}}if_park_fee=>ty_amount VALUE '45.00',
c_max_fee TYPE {{p}}if_park_fee=>ty_amount VALUE '60.00',
c_discount_rate TYPE p LENGTH 3 DECIMALS 2 VALUE '0.75',
c_free_minutes TYPE i VALUE 15,
c_max_minutes TYPE i VALUE 43200,
c_seconds_per_day TYPE i VALUE 86400,
c_reference_date TYPE d VALUE '19000101',
c_sunday_offset TYPE i VALUE 6.
METHODS duration_in_minutes
IMPORTING iv_entry_date TYPE d
iv_entry_time TYPE t
iv_exit_date TYPE d
iv_exit_time TYPE t
RETURNING VALUE(rv_minutes) TYPE i.
METHODS started_hours
IMPORTING iv_minutes TYPE i
RETURNING VALUE(rv_hours) TYPE i.
METHODS is_sunday
IMPORTING iv_date TYPE d
RETURNING VALUE(rv_sunday) TYPE abap_bool.
METHODS discounted
IMPORTING iv_fee TYPE {{p}}if_park_fee=>ty_amount
iv_discount TYPE abap_bool
RETURNING VALUE(rv_fee) TYPE {{p}}if_park_fee=>ty_amount.
ENDCLASS.
CLASS {{p}}park_fee_calculator IMPLEMENTATION.
METHOD {{p}}if_park_fee~calculate.
DATA(lv_minutes) = duration_in_minutes( iv_entry_date = iv_entry_date
iv_entry_time = iv_entry_time
iv_exit_date = iv_exit_date
iv_exit_time = iv_exit_time ).
IF lv_minutes < 0.
rs_result = VALUE #( reason = {{p}}if_park_fee=>c_reason-bad_time
fee = 0 ).
RETURN.
ENDIF.
IF lv_minutes > c_max_minutes.
rs_result = VALUE #( reason = {{p}}if_park_fee=>c_reason-too_long
fee = 0 ).
RETURN.
ENDIF.
IF iv_lost_ticket = abap_true.
rs_result = VALUE #( reason = {{p}}if_park_fee=>c_reason-ok
fee = c_lost_ticket ).
RETURN.
ENDIF.
IF lv_minutes <= c_free_minutes OR is_sunday( iv_entry_date ) = abap_true.
rs_result = VALUE #( reason = {{p}}if_park_fee=>c_reason-ok
fee = 0 ).
RETURN.
ENDIF.
DATA lv_fee TYPE {{p}}if_park_fee=>ty_amount.
lv_fee = started_hours( lv_minutes ) / c_price_per_hour.
lv_fee = discounted( iv_fee = lv_fee iv_discount = iv_discount ).
IF lv_fee > c_max_fee.
lv_fee = c_max_fee.
ENDIF.
rs_result = VALUE #( reason = {{p}}if_park_fee=>c_reason-ok
fee = lv_fee ).
ENDMETHOD.
METHOD duration_in_minutes.
DATA(lv_entry_time) = iv_entry_time.
DATA(lv_exit_time) = iv_exit_time.
lv_entry_time+4(2) = '00'.
lv_exit_time+4(2) = '00'.
DATA(lv_seconds) = ( iv_exit_date - iv_entry_date ) * c_seconds_per_day
+ ( lv_exit_time - lv_entry_time ).
rv_minutes = lv_seconds DIV 60.
ENDMETHOD.
METHOD started_hours.
rv_hours = iv_minutes DIV 60.
IF iv_minutes MOD 60 <> 0.
rv_hours = rv_hours + 1.
ENDIF.
ENDMETHOD.
METHOD is_sunday.
DATA(lv_offset) = iv_date - c_reference_date.
rv_sunday = xsdbool( lv_offset MOD 7 = c_sunday_offset ).
ENDMETHOD.
METHOD discounted.
rv_fee = iv_fee.
IF iv_discount = abap_true.
rv_fee = round( val = iv_fee * c_discount_rate
dec = 2
mode = cl_abap_math=>round_half_up ).
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,102 @@
CLASS {{p}}park_fee_calculator DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES {{p}}if_park_fee.
PRIVATE SECTION.
CONSTANTS:
c_price_per_hour TYPE {{p}}if_park_fee=>ty_amount VALUE '2.50',
c_lost_ticket TYPE {{p}}if_park_fee=>ty_amount VALUE '45.00',
c_max_fee TYPE {{p}}if_park_fee=>ty_amount VALUE '60.00',
c_discount_rate TYPE p LENGTH 3 DECIMALS 2 VALUE '0.75',
c_free_minutes TYPE i VALUE 15,
c_max_minutes TYPE i VALUE 43200,
c_seconds_per_day TYPE i VALUE 86400,
c_reference_date TYPE d VALUE '19000101',
c_sunday_offset TYPE i VALUE 6.
METHODS duration_in_minutes
IMPORTING iv_entry_date TYPE d
iv_entry_time TYPE t
iv_exit_date TYPE d
iv_exit_time TYPE t
RETURNING VALUE(rv_minutes) TYPE i.
METHODS started_hours
IMPORTING iv_minutes TYPE i
RETURNING VALUE(rv_hours) TYPE i.
METHODS is_sunday
IMPORTING iv_date TYPE d
RETURNING VALUE(rv_sunday) TYPE abap_bool.
METHODS discounted
IMPORTING iv_fee TYPE {{p}}if_park_fee=>ty_amount
iv_discount TYPE abap_bool
RETURNING VALUE(rv_fee) TYPE {{p}}if_park_fee=>ty_amount.
ENDCLASS.
CLASS {{p}}park_fee_calculator IMPLEMENTATION.
METHOD {{p}}if_park_fee~calculate.
DATA(lv_minutes) = duration_in_minutes( iv_entry_date = iv_entry_date
iv_entry_time = iv_entry_time
iv_exit_date = iv_exit_date
iv_exit_time = iv_exit_time ).
IF lv_minutes < 0.
rs_result = VALUE #( reason = {{p}}if_park_fee=>c_reason-bad_time
fee = 0 ).
RETURN.
ENDIF.
IF lv_minutes > c_max_minutes.
rs_result = VALUE #( reason = {{p}}if_park_fee=>c_reason-too_long
fee = 0 ).
RETURN.
ENDIF.
IF iv_lost_ticket = abap_true.
rs_result = VALUE #( reason = {{p}}if_park_fee=>c_reason-ok
fee = c_lost_ticket ).
RETURN.
ENDIF.
IF lv_minutes <= c_free_minutes OR is_sunday( iv_entry_date ) = abap_true.
rs_result = VALUE #( reason = {{p}}if_park_fee=>c_reason-ok
fee = 0 ).
RETURN.
ENDIF.
DATA lv_fee TYPE {{p}}if_park_fee=>ty_amount.
lv_fee = started_hours( lv_minutes ) * c_price_per_hour.
lv_fee = discounted( iv_fee = lv_fee iv_discount = iv_discount ).
IF lv_fee > c_max_fee.
lv_fee = c_max_fee.
ENDIF.
rs_result = VALUE #( reason = {{p}}if_park_fee=>c_reason-ok
fee = lv_fee ).
ENDMETHOD.
METHOD duration_in_minutes.
DATA(lv_entry_time) = iv_entry_time.
DATA(lv_exit_time) = iv_exit_time.
lv_entry_time+4(2) = '00'.
lv_exit_time+4(2) = '00'.
DATA(lv_seconds) = ( iv_exit_date - iv_entry_date ) * c_seconds_per_day
+ ( lv_exit_time - lv_entry_time ).
rv_minutes = lv_seconds DIV 60.
ENDMETHOD.
METHOD started_hours.
rv_hours = iv_minutes DIV 60.
IF iv_minutes MOD 60 <> 0.
rv_hours = rv_hours + 1.
ENDIF.
ENDMETHOD.
METHOD is_sunday.
DATA(lv_offset) = iv_date - c_reference_date.
rv_sunday = xsdbool( lv_offset MOD 7 = c_sunday_offset ).
ENDMETHOD.
METHOD discounted.
rv_fee = iv_fee.
IF iv_discount = abap_false.
rv_fee = round( val = iv_fee * c_discount_rate
dec = 2
mode = cl_abap_math=>round_half_up ).
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,29 @@
{
"id": "G0101",
"pool": "eval",
"object_type": "CLAS",
"category": "A",
"attempts": [
{
"stage": "validate",
"oracle": 85.2,
"null": 0
},
{
"stage": "validate",
"oracle": 85.2,
"null": 0
},
{
"stage": "validate",
"oracle": 100.0,
"null": 0,
"mutation": {
"valid": 4,
"killed": 4,
"ok": true
}
}
],
"accepted": true
}

View File

@@ -0,0 +1,156 @@
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_park_fee.
METHODS setup.
METHODS assert_result
IMPORTING is_result TYPE {{p}}if_park_fee=>ty_result
iv_fee TYPE {{p}}if_park_fee=>ty_amount
iv_reason TYPE {{p}}if_park_fee=>ty_reason.
METHODS bad_time_order FOR TESTING.
METHODS too_long FOR TESTING.
METHODS free_period FOR TESTING.
METHODS one_started_hour FOR TESTING.
METHODS two_started_hours FOR TESTING.
METHODS sunday_free FOR TESTING.
METHODS lost_ticket_flat FOR TESTING.
METHODS lost_ticket_on_sunday FOR TESTING.
METHODS discount_rounds FOR TESTING.
METHODS discount_rounds_up FOR TESTING.
METHODS daily_cap FOR TESTING.
ENDCLASS.
CLASS {{p}}t02_hidden IMPLEMENTATION.
METHOD setup.
mo_cut = NEW {{p}}park_fee_calculator( ).
ENDMETHOD.
METHOD assert_result.
cl_abap_unit_assert=>assert_equals( exp = iv_fee act = is_result-fee ).
cl_abap_unit_assert=>assert_equals( exp = iv_reason act = is_result-reason ).
ENDMETHOD.
METHOD bad_time_order.
assert_result( is_result = mo_cut->calculate( iv_entry_date = '20240108'
iv_entry_time = '120000'
iv_exit_date = '20240108'
iv_exit_time = '110000'
iv_lost_ticket = abap_false
iv_discount = abap_false )
iv_fee = '0.00'
iv_reason = {{p}}if_park_fee=>c_reason-bad_time ).
ENDMETHOD.
METHOD too_long.
assert_result( is_result = mo_cut->calculate( iv_entry_date = '20240108'
iv_entry_time = '100000'
iv_exit_date = '20240208'
iv_exit_time = '100100'
iv_lost_ticket = abap_false
iv_discount = abap_false )
iv_fee = '0.00'
iv_reason = {{p}}if_park_fee=>c_reason-too_long ).
ENDMETHOD.
METHOD free_period.
assert_result( is_result = mo_cut->calculate( iv_entry_date = '20240108'
iv_entry_time = '100000'
iv_exit_date = '20240108'
iv_exit_time = '100015'
iv_lost_ticket = abap_false
iv_discount = abap_false )
iv_fee = '0.00'
iv_reason = {{p}}if_park_fee=>c_reason-ok ).
ENDMETHOD.
METHOD one_started_hour.
assert_result( is_result = mo_cut->calculate( iv_entry_date = '20240108'
iv_entry_time = '100000'
iv_exit_date = '20240108'
iv_exit_time = '103000'
iv_lost_ticket = abap_false
iv_discount = abap_false )
iv_fee = '2.50'
iv_reason = {{p}}if_park_fee=>c_reason-ok ).
ENDMETHOD.
METHOD two_started_hours.
assert_result( is_result = mo_cut->calculate( iv_entry_date = '20240108'
iv_entry_time = '100000'
iv_exit_date = '20240108'
iv_exit_time = '110100'
iv_lost_ticket = abap_false
iv_discount = abap_false )
iv_fee = '5.00'
iv_reason = {{p}}if_park_fee=>c_reason-ok ).
ENDMETHOD.
METHOD sunday_free.
assert_result( is_result = mo_cut->calculate( iv_entry_date = '20240107'
iv_entry_time = '100000'
iv_exit_date = '20240107'
iv_exit_time = '130000'
iv_lost_ticket = abap_false
iv_discount = abap_false )
iv_fee = '0.00'
iv_reason = {{p}}if_park_fee=>c_reason-ok ).
ENDMETHOD.
METHOD lost_ticket_flat.
assert_result( is_result = mo_cut->calculate( iv_entry_date = '20240108'
iv_entry_time = '100000'
iv_exit_date = '20240108'
iv_exit_time = '100500'
iv_lost_ticket = abap_true
iv_discount = abap_false )
iv_fee = '45.00'
iv_reason = {{p}}if_park_fee=>c_reason-ok ).
ENDMETHOD.
METHOD lost_ticket_on_sunday.
assert_result( is_result = mo_cut->calculate( iv_entry_date = '20240107'
iv_entry_time = '100000'
iv_exit_date = '20240107'
iv_exit_time = '120000'
iv_lost_ticket = abap_true
iv_discount = abap_false )
iv_fee = '45.00'
iv_reason = {{p}}if_park_fee=>c_reason-ok ).
ENDMETHOD.
METHOD discount_rounds.
assert_result( is_result = mo_cut->calculate( iv_entry_date = '20240108'
iv_entry_time = '100000'
iv_exit_date = '20240108'
iv_exit_time = '110100'
iv_lost_ticket = abap_false
iv_discount = abap_true )
iv_fee = '3.75'
iv_reason = {{p}}if_park_fee=>c_reason-ok ).
ENDMETHOD.
METHOD discount_rounds_up.
assert_result( is_result = mo_cut->calculate( iv_entry_date = '20240108'
iv_entry_time = '100000'
iv_exit_date = '20240108'
iv_exit_time = '103000'
iv_lost_ticket = abap_false
iv_discount = abap_true )
iv_fee = '1.88'
iv_reason = {{p}}if_park_fee=>c_reason-ok ).
ENDMETHOD.
METHOD daily_cap.
assert_result( is_result = mo_cut->calculate( iv_entry_date = '20240108'
iv_entry_time = '060000'
iv_exit_date = '20240109'
iv_exit_time = '120000'
iv_lost_ticket = abap_false
iv_discount = abap_false )
iv_fee = '60.00'
iv_reason = {{p}}if_park_fee=>c_reason-ok ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,77 @@
{
"task": "G0101",
"mutants": [
{
"object": "{{P}}PARK_FEE_CALCULATOR",
"mutant": "line 47: > -> <= (rel)",
"status": "killed",
"hidden": "1/11",
"failed_tests": [
"DAILY_CAP",
"DISCOUNT_ROUNDS",
"DISCOUNT_ROUNDS_UP",
"FREE_PERIOD",
"LOST_TICKET_FLAT",
"LOST_TICKET_ON_SUNDAY",
"ONE_STARTED_HOUR",
"SUNDAY_FREE",
"TOO_LONG",
"TWO_STARTED_HOURS"
]
},
{
"object": "{{P}}PARK_FEE_CALCULATOR",
"mutant": "line 52: = -> <> (eq)",
"status": "killed",
"hidden": "2/11",
"failed_tests": [
"DAILY_CAP",
"DISCOUNT_ROUNDS",
"DISCOUNT_ROUNDS_UP",
"FREE_PERIOD",
"LOST_TICKET_FLAT",
"LOST_TICKET_ON_SUNDAY",
"ONE_STARTED_HOUR",
"SUNDAY_FREE",
"TWO_STARTED_HOURS"
]
},
{
"object": "{{P}}PARK_FEE_CALCULATOR",
"mutant": "line 63: * -> / (arith)",
"status": "killed",
"hidden": "6/11",
"failed_tests": [
"DAILY_CAP",
"DISCOUNT_ROUNDS",
"DISCOUNT_ROUNDS_UP",
"ONE_STARTED_HOUR",
"TWO_STARTED_HOURS"
]
},
{
"object": "{{P}}PARK_FEE_CALCULATOR",
"mutant": "line 76: 2 -> 3 (const)",
"status": "invalid",
"hidden": "0/0",
"failed_tests": []
},
{
"object": "{{P}}PARK_FEE_CALCULATOR",
"mutant": "line 96: abap_true -> abap_false (bool)",
"status": "killed",
"hidden": "6/11",
"failed_tests": [
"DAILY_CAP",
"DISCOUNT_ROUNDS",
"DISCOUNT_ROUNDS_UP",
"ONE_STARTED_HOUR",
"TWO_STARTED_HOURS"
]
}
],
"valid": 4,
"killed": 4,
"kill_rate": 1.0,
"ok": true
}

View File

@@ -0,0 +1,102 @@
CLASS {{p}}park_fee_calculator DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES {{p}}if_park_fee.
PRIVATE SECTION.
CONSTANTS:
c_price_per_hour TYPE {{p}}if_park_fee=>ty_amount VALUE '2.50',
c_lost_ticket TYPE {{p}}if_park_fee=>ty_amount VALUE '45.00',
c_max_fee TYPE {{p}}if_park_fee=>ty_amount VALUE '60.00',
c_discount_rate TYPE p LENGTH 3 DECIMALS 2 VALUE '0.75',
c_free_minutes TYPE i VALUE 15,
c_max_minutes TYPE i VALUE 43200,
c_seconds_per_day TYPE i VALUE 86400,
c_reference_date TYPE d VALUE '19000101',
c_sunday_offset TYPE i VALUE 6.
METHODS duration_in_minutes
IMPORTING iv_entry_date TYPE d
iv_entry_time TYPE t
iv_exit_date TYPE d
iv_exit_time TYPE t
RETURNING VALUE(rv_minutes) TYPE i.
METHODS started_hours
IMPORTING iv_minutes TYPE i
RETURNING VALUE(rv_hours) TYPE i.
METHODS is_sunday
IMPORTING iv_date TYPE d
RETURNING VALUE(rv_sunday) TYPE abap_bool.
METHODS discounted
IMPORTING iv_fee TYPE {{p}}if_park_fee=>ty_amount
iv_discount TYPE abap_bool
RETURNING VALUE(rv_fee) TYPE {{p}}if_park_fee=>ty_amount.
ENDCLASS.
CLASS {{p}}park_fee_calculator IMPLEMENTATION.
METHOD {{p}}if_park_fee~calculate.
DATA(lv_minutes) = duration_in_minutes( iv_entry_date = iv_entry_date
iv_entry_time = iv_entry_time
iv_exit_date = iv_exit_date
iv_exit_time = iv_exit_time ).
IF lv_minutes < 0.
rs_result = VALUE #( reason = {{p}}if_park_fee=>c_reason-bad_time
fee = 0 ).
RETURN.
ENDIF.
IF lv_minutes > c_max_minutes.
rs_result = VALUE #( reason = {{p}}if_park_fee=>c_reason-too_long
fee = 0 ).
RETURN.
ENDIF.
IF iv_lost_ticket = abap_true.
rs_result = VALUE #( reason = {{p}}if_park_fee=>c_reason-ok
fee = c_lost_ticket ).
RETURN.
ENDIF.
IF lv_minutes <= c_free_minutes OR is_sunday( iv_entry_date ) = abap_true.
rs_result = VALUE #( reason = {{p}}if_park_fee=>c_reason-ok
fee = 0 ).
RETURN.
ENDIF.
DATA lv_fee TYPE {{p}}if_park_fee=>ty_amount.
lv_fee = started_hours( lv_minutes ) * c_price_per_hour.
lv_fee = discounted( iv_fee = lv_fee iv_discount = iv_discount ).
IF lv_fee > c_max_fee.
lv_fee = c_max_fee.
ENDIF.
rs_result = VALUE #( reason = {{p}}if_park_fee=>c_reason-ok
fee = lv_fee ).
ENDMETHOD.
METHOD duration_in_minutes.
DATA(lv_entry_time) = iv_entry_time.
DATA(lv_exit_time) = iv_exit_time.
lv_entry_time+4(2) = '00'.
lv_exit_time+4(2) = '00'.
DATA(lv_seconds) = ( iv_exit_date - iv_entry_date ) * c_seconds_per_day
+ ( lv_exit_time - lv_entry_time ).
rv_minutes = lv_seconds DIV 60.
ENDMETHOD.
METHOD started_hours.
rv_hours = iv_minutes DIV 60.
IF iv_minutes MOD 60 <> 0.
rv_hours = rv_hours + 1.
ENDIF.
ENDMETHOD.
METHOD is_sunday.
DATA(lv_offset) = iv_date - c_reference_date.
rv_sunday = xsdbool( lv_offset MOD 7 = c_sunday_offset ).
ENDMETHOD.
METHOD discounted.
rv_fee = iv_fee.
IF iv_discount = abap_true.
rv_fee = round( val = iv_fee * c_discount_rate
dec = 2
mode = cl_abap_math=>round_half_up ).
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,143 @@
CLASS ltc_park_fee DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA mo_cut TYPE REF TO {{p}}if_park_fee.
METHODS setup.
METHODS assert_result
IMPORTING is_result TYPE {{p}}if_park_fee=>ty_result
iv_fee TYPE {{p}}if_park_fee=>ty_amount
iv_reason TYPE {{p}}if_park_fee=>ty_reason.
METHODS free_period_is_free FOR TESTING.
METHODS one_hour_costs_250 FOR TESTING.
METHODS two_hours_cost_500 FOR TESTING.
METHODS sunday_is_free FOR TESTING.
METHODS lost_ticket_is_flat FOR TESTING.
METHODS discount_is_rounded FOR TESTING.
METHODS discount_rounds_up FOR TESTING.
METHODS fee_is_capped FOR TESTING.
METHODS exit_before_entry FOR TESTING.
METHODS long_parking FOR TESTING.
ENDCLASS.
CLASS ltc_park_fee IMPLEMENTATION.
METHOD setup.
mo_cut = NEW {{p}}park_fee_calculator( ).
ENDMETHOD.
METHOD assert_result.
cl_abap_unit_assert=>assert_equals( exp = iv_fee act = is_result-fee ).
cl_abap_unit_assert=>assert_equals( exp = iv_reason act = is_result-reason ).
ENDMETHOD.
METHOD free_period_is_free.
assert_result( is_result = mo_cut->calculate( iv_entry_date = '20240108'
iv_entry_time = '100000'
iv_exit_date = '20240108'
iv_exit_time = '100015'
iv_lost_ticket = abap_false
iv_discount = abap_false )
iv_fee = '0.00'
iv_reason = {{p}}if_park_fee=>c_reason-ok ).
ENDMETHOD.
METHOD one_hour_costs_250.
assert_result( is_result = mo_cut->calculate( iv_entry_date = '20240108'
iv_entry_time = '100000'
iv_exit_date = '20240108'
iv_exit_time = '103000'
iv_lost_ticket = abap_false
iv_discount = abap_false )
iv_fee = '2.50'
iv_reason = {{p}}if_park_fee=>c_reason-ok ).
ENDMETHOD.
METHOD two_hours_cost_500.
assert_result( is_result = mo_cut->calculate( iv_entry_date = '20240108'
iv_entry_time = '100000'
iv_exit_date = '20240108'
iv_exit_time = '110100'
iv_lost_ticket = abap_false
iv_discount = abap_false )
iv_fee = '5.00'
iv_reason = {{p}}if_park_fee=>c_reason-ok ).
ENDMETHOD.
METHOD sunday_is_free.
assert_result( is_result = mo_cut->calculate( iv_entry_date = '20240107'
iv_entry_time = '090000'
iv_exit_date = '20240107'
iv_exit_time = '120000'
iv_lost_ticket = abap_false
iv_discount = abap_false )
iv_fee = '0.00'
iv_reason = {{p}}if_park_fee=>c_reason-ok ).
ENDMETHOD.
METHOD lost_ticket_is_flat.
assert_result( is_result = mo_cut->calculate( iv_entry_date = '20240108'
iv_entry_time = '100000'
iv_exit_date = '20240108'
iv_exit_time = '100500'
iv_lost_ticket = abap_true
iv_discount = abap_false )
iv_fee = '45.00'
iv_reason = {{p}}if_park_fee=>c_reason-ok ).
ENDMETHOD.
METHOD discount_is_rounded.
assert_result( is_result = mo_cut->calculate( iv_entry_date = '20240108'
iv_entry_time = '100000'
iv_exit_date = '20240108'
iv_exit_time = '110100'
iv_lost_ticket = abap_false
iv_discount = abap_true )
iv_fee = '3.75'
iv_reason = {{p}}if_park_fee=>c_reason-ok ).
ENDMETHOD.
METHOD discount_rounds_up.
assert_result( is_result = mo_cut->calculate( iv_entry_date = '20240108'
iv_entry_time = '100000'
iv_exit_date = '20240108'
iv_exit_time = '103000'
iv_lost_ticket = abap_false
iv_discount = abap_true )
iv_fee = '1.88'
iv_reason = {{p}}if_park_fee=>c_reason-ok ).
ENDMETHOD.
METHOD fee_is_capped.
assert_result( is_result = mo_cut->calculate( iv_entry_date = '20240108'
iv_entry_time = '060000'
iv_exit_date = '20240109'
iv_exit_time = '120000'
iv_lost_ticket = abap_false
iv_discount = abap_false )
iv_fee = '60.00'
iv_reason = {{p}}if_park_fee=>c_reason-ok ).
ENDMETHOD.
METHOD exit_before_entry.
assert_result( is_result = mo_cut->calculate( iv_entry_date = '20240108'
iv_entry_time = '120000'
iv_exit_date = '20240108'
iv_exit_time = '110000'
iv_lost_ticket = abap_false
iv_discount = abap_false )
iv_fee = '0.00'
iv_reason = {{p}}if_park_fee=>c_reason-bad_time ).
ENDMETHOD.
METHOD long_parking.
assert_result( is_result = mo_cut->calculate( iv_entry_date = '20240108'
iv_entry_time = '100000'
iv_exit_date = '20240208'
iv_exit_time = '100100'
iv_lost_ticket = abap_false
iv_discount = abap_false )
iv_fee = '0.00'
iv_reason = {{p}}if_park_fee=>c_reason-too_long ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,23 @@
INTERFACE {{p}}if_park_fee PUBLIC.
TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2.
TYPES ty_reason TYPE c LENGTH 10.
TYPES:
BEGIN OF ty_result,
reason TYPE ty_reason,
fee TYPE ty_amount,
END OF ty_result.
CONSTANTS:
BEGIN OF c_reason,
ok TYPE ty_reason VALUE 'OK',
bad_time TYPE ty_reason VALUE 'BAD_TIME',
too_long TYPE ty_reason VALUE 'TOO_LONG',
END OF c_reason.
METHODS calculate
IMPORTING iv_entry_date TYPE d
iv_entry_time TYPE t
iv_exit_date TYPE d
iv_exit_time TYPE t
iv_lost_ticket TYPE abap_bool
iv_discount TYPE abap_bool
RETURNING VALUE(rs_result) TYPE ty_result.
ENDINTERFACE.

View File

@@ -0,0 +1,67 @@
# 1. Goal
A car park operator calculates the parking fee of a car. The calculation uses
the entry time and the exit time of the car. A payment terminal calls the
calculation before it charges the driver. The terminal needs the fee and a
reason code for each parking event.
# 2. Open questions
None.
# 3. Context
- The interface {{P}}IF_PARK_FEE exists in package $TMP. It is active.
- The interface contains the type TY_AMOUNT (a packed number, length 8, 2
decimals), the type TY_REASON (a character field, length 10), the structure
TY_RESULT with the components REASON (TY_REASON) and FEE (TY_AMOUNT), and the
constant structure C_REASON with the components OK, BAD_TIME and TOO_LONG.
- The interface contains one method:
CALCULATE
IMPORTING iv_entry_date TYPE d
iv_entry_time TYPE t
iv_exit_date TYPE d
iv_exit_time TYPE t
iv_lost_ticket TYPE abap_bool
iv_discount TYPE abap_bool
RETURNING VALUE(rs_result) TYPE ty_result.
# 4. Contract
- Create the class {{P}}PARK_FEE_CALCULATOR in package $TMP.
- The class is public and final. It has a public constructor without
parameters.
- The class implements the interface {{P}}IF_PARK_FEE.
- Do not add other public methods.
# 5. Business rules
The method CALCULATE applies the rules in this sequence. It returns the reason
and the fee of the first rule that applies.
1. The duration is the number of whole minutes between the entry and the exit.
Ignore the seconds of the two time fields. Example: the entry 10:00:30 and
the exit 10:01:20 give the duration 1 minute. The entry 10:00:00 and the
exit 10:30:00 give the duration 30 minutes.
2. If the exit is before the entry, return the reason BAD_TIME and the fee
0.00.
3. If the duration is more than 43200 minutes, return the reason TOO_LONG and
the fee 0.00.
4. If the ticket is lost (iv_lost_ticket = abap_true), the fee is 45.00 and the
reason is OK. Rules 5 to 9 do not apply.
5. If the duration is 15 minutes or less, the fee is 0.00 and the reason is OK.
6. If the entry date is a Sunday, the fee is 0.00 and the reason is OK.
7. Else the fee is the number of started hours multiplied by 2.50. A started
hour is a full hour or a part of an hour. Example: 61 minutes are 2 started
hours and give the fee 5.00. 30 minutes are 1 started hour and give the fee
2.50.
8. If the driver uses the discount card (iv_discount = abap_true), reduce the
fee by 25 percent. Round the result to 2 decimals, half up. Example: the fee
5.00 becomes 3.75. The fee 2.50 becomes 1.88.
9. The fee never exceeds 60.00. If the fee is higher, it is 60.00.
10. The reason is OK.
# 6. Constraints
- Release target: 8.16.
- Coding standards: Clean ABAP. Keep every method below 40 statements. Do not
use global variables. Do not write comments that restate the code.
- Out of scope: do not change the interface {{P}}IF_PARK_FEE.
# 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": "G0101",
"category": "A",
"object_type": "CLAS",
"difficulty": 2,
"release_target": "v816",
"expected_outcome": "implement",
"budget": {
"max_tool_calls": 60,
"max_activations": 15
},
"seed": [
{
"type": "INTF",
"name": "{{P}}IF_PARK_FEE",
"file": "seed/if_park_fee.intf.abap",
"description": "Parking fee contract"
}
],
"contract": [
{
"type": "CLAS",
"name": "{{P}}PARK_FEE_CALCULATOR",
"implements": "{{P}}IF_PARK_FEE"
}
],
"out_of_scope": [
"{{P}}IF_PARK_FEE"
],
"hidden_tests": [
{
"type": "CLAS",
"name": "{{P}}T02_HIDDEN",
"file": "hidden/t02_hidden.clas.abap",
"description": "T02 hidden tests"
}
],
"reference": [
{
"type": "CLAS",
"name": "{{P}}PARK_FEE_CALCULATOR",
"file": "reference/park_fee_calculator.clas.abap",
"description": "Parking fee calculator",
"testclasses_file": "reference/park_fee_calculator.testclasses.abap"
}
],
"craft_checks": [
"method_length",
"db_operation_in_loop"
]
}

View File

@@ -0,0 +1,108 @@
CLASS {{p}}hotel_rate DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES {{p}}if_hotel_rate.
PRIVATE SECTION.
CONSTANTS:
c_breakfast TYPE {{p}}if_hotel_rate=>ty_amount VALUE '12.50',
c_city_tax TYPE {{p}}if_hotel_rate=>ty_amount VALUE '3.00'.
METHODS validate
IMPORTING iv_category TYPE {{p}}if_hotel_rate=>ty_category
iv_nights TYPE i
iv_guests TYPE i
RETURNING VALUE(rv_reason) TYPE {{p}}if_hotel_rate=>ty_reason.
METHODS room_count
IMPORTING iv_guests TYPE i
RETURNING VALUE(rv_rooms) TYPE i.
METHODS nightly_rate
IMPORTING iv_category TYPE {{p}}if_hotel_rate=>ty_category
RETURNING VALUE(rv_amount) TYPE {{p}}if_hotel_rate=>ty_amount.
METHODS discount_percent
IMPORTING iv_nights TYPE i
RETURNING VALUE(rv_percent) TYPE i.
METHODS net_room_total
IMPORTING iv_category TYPE {{p}}if_hotel_rate=>ty_category
iv_nights TYPE i
iv_guests TYPE i
RETURNING VALUE(rv_total) TYPE {{p}}if_hotel_rate=>ty_amount.
METHODS extras
IMPORTING iv_nights TYPE i
iv_guests TYPE i
iv_breakfast TYPE abap_bool
RETURNING VALUE(rv_extras) TYPE {{p}}if_hotel_rate=>ty_amount.
ENDCLASS.
CLASS {{p}}hotel_rate IMPLEMENTATION.
METHOD {{p}}if_hotel_rate~calculate.
rs_result-reason = validate( iv_category = iv_category
iv_nights = iv_nights
iv_guests = iv_guests ).
IF rs_result-reason <> {{p}}if_hotel_rate=>c_reason-ok.
rs_result-price = 0.
RETURN.
ENDIF.
rs_result-price = net_room_total( iv_category = iv_category
iv_nights = iv_nights
iv_guests = iv_guests )
+ extras( iv_nights = iv_nights
iv_guests = iv_guests
iv_breakfast = iv_breakfast ).
ENDMETHOD.
METHOD validate.
IF iv_nights < 1.
rv_reason = {{p}}if_hotel_rate=>c_reason-nights.
ELSEIF iv_guests < 1.
rv_reason = {{p}}if_hotel_rate=>c_reason-guests.
ELSEIF iv_category = {{p}}if_hotel_rate=>c_category-basic
AND iv_category <> {{p}}if_hotel_rate=>c_category-comfort
AND iv_category <> {{p}}if_hotel_rate=>c_category-suite.
rv_reason = {{p}}if_hotel_rate=>c_reason-category.
ELSE.
rv_reason = {{p}}if_hotel_rate=>c_reason-ok.
ENDIF.
ENDMETHOD.
METHOD room_count.
rv_rooms = ( iv_guests + 1 ) DIV 2.
ENDMETHOD.
METHOD nightly_rate.
CASE iv_category.
WHEN {{p}}if_hotel_rate=>c_category-basic.
rv_amount = '90.00'.
WHEN {{p}}if_hotel_rate=>c_category-comfort.
rv_amount = '140.00'.
WHEN {{p}}if_hotel_rate=>c_category-suite.
rv_amount = '260.00'.
ENDCASE.
ENDMETHOD.
METHOD discount_percent.
IF iv_nights >= 28.
rv_percent = 20.
ELSEIF iv_nights >= 14.
rv_percent = 15.
ELSEIF iv_nights >= 7.
rv_percent = 10.
ENDIF.
ENDMETHOD.
METHOD net_room_total.
DATA lv_total TYPE {{p}}if_hotel_rate=>ty_amount.
lv_total = nightly_rate( iv_category ) * room_count( iv_guests ) * iv_nights.
DATA lv_discount TYPE {{p}}if_hotel_rate=>ty_amount.
lv_discount = lv_total * discount_percent( iv_nights ) / 100.
rv_total = lv_total - lv_discount.
ENDMETHOD.
METHOD extras.
DATA(lv_guest_nights) = iv_guests * iv_nights.
rv_extras = lv_guest_nights * c_city_tax.
IF iv_breakfast = abap_true.
rv_extras = rv_extras + lv_guest_nights * c_breakfast.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,108 @@
CLASS {{p}}hotel_rate DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES {{p}}if_hotel_rate.
PRIVATE SECTION.
CONSTANTS:
c_breakfast TYPE {{p}}if_hotel_rate=>ty_amount VALUE '12.50',
c_city_tax TYPE {{p}}if_hotel_rate=>ty_amount VALUE '3.00'.
METHODS validate
IMPORTING iv_category TYPE {{p}}if_hotel_rate=>ty_category
iv_nights TYPE i
iv_guests TYPE i
RETURNING VALUE(rv_reason) TYPE {{p}}if_hotel_rate=>ty_reason.
METHODS room_count
IMPORTING iv_guests TYPE i
RETURNING VALUE(rv_rooms) TYPE i.
METHODS nightly_rate
IMPORTING iv_category TYPE {{p}}if_hotel_rate=>ty_category
RETURNING VALUE(rv_amount) TYPE {{p}}if_hotel_rate=>ty_amount.
METHODS discount_percent
IMPORTING iv_nights TYPE i
RETURNING VALUE(rv_percent) TYPE i.
METHODS net_room_total
IMPORTING iv_category TYPE {{p}}if_hotel_rate=>ty_category
iv_nights TYPE i
iv_guests TYPE i
RETURNING VALUE(rv_total) TYPE {{p}}if_hotel_rate=>ty_amount.
METHODS extras
IMPORTING iv_nights TYPE i
iv_guests TYPE i
iv_breakfast TYPE abap_bool
RETURNING VALUE(rv_extras) TYPE {{p}}if_hotel_rate=>ty_amount.
ENDCLASS.
CLASS {{p}}hotel_rate IMPLEMENTATION.
METHOD {{p}}if_hotel_rate~calculate.
rs_result-reason = validate( iv_category = iv_category
iv_nights = iv_nights
iv_guests = iv_guests ).
IF rs_result-reason <> {{p}}if_hotel_rate=>c_reason-ok.
rs_result-price = 0.
RETURN.
ENDIF.
rs_result-price = net_room_total( iv_category = iv_category
iv_nights = iv_nights
iv_guests = iv_guests )
+ extras( iv_nights = iv_nights
iv_guests = iv_guests
iv_breakfast = iv_breakfast ).
ENDMETHOD.
METHOD validate.
IF iv_nights < 1.
rv_reason = {{p}}if_hotel_rate=>c_reason-nights.
ELSEIF iv_guests < 1.
rv_reason = {{p}}if_hotel_rate=>c_reason-guests.
ELSEIF iv_category <> {{p}}if_hotel_rate=>c_category-basic
AND iv_category <> {{p}}if_hotel_rate=>c_category-comfort
OR iv_category <> {{p}}if_hotel_rate=>c_category-suite.
rv_reason = {{p}}if_hotel_rate=>c_reason-category.
ELSE.
rv_reason = {{p}}if_hotel_rate=>c_reason-ok.
ENDIF.
ENDMETHOD.
METHOD room_count.
rv_rooms = ( iv_guests + 1 ) DIV 2.
ENDMETHOD.
METHOD nightly_rate.
CASE iv_category.
WHEN {{p}}if_hotel_rate=>c_category-basic.
rv_amount = '90.00'.
WHEN {{p}}if_hotel_rate=>c_category-comfort.
rv_amount = '140.00'.
WHEN {{p}}if_hotel_rate=>c_category-suite.
rv_amount = '260.00'.
ENDCASE.
ENDMETHOD.
METHOD discount_percent.
IF iv_nights >= 28.
rv_percent = 20.
ELSEIF iv_nights >= 14.
rv_percent = 15.
ELSEIF iv_nights >= 7.
rv_percent = 10.
ENDIF.
ENDMETHOD.
METHOD net_room_total.
DATA lv_total TYPE {{p}}if_hotel_rate=>ty_amount.
lv_total = nightly_rate( iv_category ) * room_count( iv_guests ) * iv_nights.
DATA lv_discount TYPE {{p}}if_hotel_rate=>ty_amount.
lv_discount = lv_total * discount_percent( iv_nights ) / 100.
rv_total = lv_total - lv_discount.
ENDMETHOD.
METHOD extras.
DATA(lv_guest_nights) = iv_guests * iv_nights.
rv_extras = lv_guest_nights * c_city_tax.
IF iv_breakfast = abap_true.
rv_extras = rv_extras + lv_guest_nights * c_breakfast.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,108 @@
CLASS {{p}}hotel_rate DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES {{p}}if_hotel_rate.
PRIVATE SECTION.
CONSTANTS:
c_breakfast TYPE {{p}}if_hotel_rate=>ty_amount VALUE '12.50',
c_city_tax TYPE {{p}}if_hotel_rate=>ty_amount VALUE '3.00'.
METHODS validate
IMPORTING iv_category TYPE {{p}}if_hotel_rate=>ty_category
iv_nights TYPE i
iv_guests TYPE i
RETURNING VALUE(rv_reason) TYPE {{p}}if_hotel_rate=>ty_reason.
METHODS room_count
IMPORTING iv_guests TYPE i
RETURNING VALUE(rv_rooms) TYPE i.
METHODS nightly_rate
IMPORTING iv_category TYPE {{p}}if_hotel_rate=>ty_category
RETURNING VALUE(rv_amount) TYPE {{p}}if_hotel_rate=>ty_amount.
METHODS discount_percent
IMPORTING iv_nights TYPE i
RETURNING VALUE(rv_percent) TYPE i.
METHODS net_room_total
IMPORTING iv_category TYPE {{p}}if_hotel_rate=>ty_category
iv_nights TYPE i
iv_guests TYPE i
RETURNING VALUE(rv_total) TYPE {{p}}if_hotel_rate=>ty_amount.
METHODS extras
IMPORTING iv_nights TYPE i
iv_guests TYPE i
iv_breakfast TYPE abap_bool
RETURNING VALUE(rv_extras) TYPE {{p}}if_hotel_rate=>ty_amount.
ENDCLASS.
CLASS {{p}}hotel_rate IMPLEMENTATION.
METHOD {{p}}if_hotel_rate~calculate.
rs_result-reason = validate( iv_category = iv_category
iv_nights = iv_nights
iv_guests = iv_guests ).
IF rs_result-reason <> {{p}}if_hotel_rate=>c_reason-ok.
rs_result-price = 0.
RETURN.
ENDIF.
rs_result-price = net_room_total( iv_category = iv_category
iv_nights = iv_nights
iv_guests = iv_guests )
+ extras( iv_nights = iv_nights
iv_guests = iv_guests
iv_breakfast = iv_breakfast ).
ENDMETHOD.
METHOD validate.
IF iv_nights < 1.
rv_reason = {{p}}if_hotel_rate=>c_reason-nights.
ELSEIF iv_guests < 1.
rv_reason = {{p}}if_hotel_rate=>c_reason-guests.
ELSEIF iv_category <> {{p}}if_hotel_rate=>c_category-basic
AND iv_category <> {{p}}if_hotel_rate=>c_category-comfort
AND iv_category <> {{p}}if_hotel_rate=>c_category-suite.
rv_reason = {{p}}if_hotel_rate=>c_reason-category.
ELSE.
rv_reason = {{p}}if_hotel_rate=>c_reason-ok.
ENDIF.
ENDMETHOD.
METHOD room_count.
rv_rooms = ( iv_guests + 2 ) DIV 2.
ENDMETHOD.
METHOD nightly_rate.
CASE iv_category.
WHEN {{p}}if_hotel_rate=>c_category-basic.
rv_amount = '90.00'.
WHEN {{p}}if_hotel_rate=>c_category-comfort.
rv_amount = '140.00'.
WHEN {{p}}if_hotel_rate=>c_category-suite.
rv_amount = '260.00'.
ENDCASE.
ENDMETHOD.
METHOD discount_percent.
IF iv_nights >= 28.
rv_percent = 20.
ELSEIF iv_nights >= 14.
rv_percent = 15.
ELSEIF iv_nights >= 7.
rv_percent = 10.
ENDIF.
ENDMETHOD.
METHOD net_room_total.
DATA lv_total TYPE {{p}}if_hotel_rate=>ty_amount.
lv_total = nightly_rate( iv_category ) * room_count( iv_guests ) * iv_nights.
DATA lv_discount TYPE {{p}}if_hotel_rate=>ty_amount.
lv_discount = lv_total * discount_percent( iv_nights ) / 100.
rv_total = lv_total - lv_discount.
ENDMETHOD.
METHOD extras.
DATA(lv_guest_nights) = iv_guests * iv_nights.
rv_extras = lv_guest_nights * c_city_tax.
IF iv_breakfast = abap_true.
rv_extras = rv_extras + lv_guest_nights * c_breakfast.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,108 @@
CLASS {{p}}hotel_rate DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES {{p}}if_hotel_rate.
PRIVATE SECTION.
CONSTANTS:
c_breakfast TYPE {{p}}if_hotel_rate=>ty_amount VALUE '12.50',
c_city_tax TYPE {{p}}if_hotel_rate=>ty_amount VALUE '3.00'.
METHODS validate
IMPORTING iv_category TYPE {{p}}if_hotel_rate=>ty_category
iv_nights TYPE i
iv_guests TYPE i
RETURNING VALUE(rv_reason) TYPE {{p}}if_hotel_rate=>ty_reason.
METHODS room_count
IMPORTING iv_guests TYPE i
RETURNING VALUE(rv_rooms) TYPE i.
METHODS nightly_rate
IMPORTING iv_category TYPE {{p}}if_hotel_rate=>ty_category
RETURNING VALUE(rv_amount) TYPE {{p}}if_hotel_rate=>ty_amount.
METHODS discount_percent
IMPORTING iv_nights TYPE i
RETURNING VALUE(rv_percent) TYPE i.
METHODS net_room_total
IMPORTING iv_category TYPE {{p}}if_hotel_rate=>ty_category
iv_nights TYPE i
iv_guests TYPE i
RETURNING VALUE(rv_total) TYPE {{p}}if_hotel_rate=>ty_amount.
METHODS extras
IMPORTING iv_nights TYPE i
iv_guests TYPE i
iv_breakfast TYPE abap_bool
RETURNING VALUE(rv_extras) TYPE {{p}}if_hotel_rate=>ty_amount.
ENDCLASS.
CLASS {{p}}hotel_rate IMPLEMENTATION.
METHOD {{p}}if_hotel_rate~calculate.
rs_result-reason = validate( iv_category = iv_category
iv_nights = iv_nights
iv_guests = iv_guests ).
IF rs_result-reason <> {{p}}if_hotel_rate=>c_reason-ok.
rs_result-price = 0.
RETURN.
ENDIF.
rs_result-price = net_room_total( iv_category = iv_category
iv_nights = iv_nights
iv_guests = iv_guests )
+ extras( iv_nights = iv_nights
iv_guests = iv_guests
iv_breakfast = iv_breakfast ).
ENDMETHOD.
METHOD validate.
IF iv_nights < 1.
rv_reason = {{p}}if_hotel_rate=>c_reason-nights.
ELSEIF iv_guests < 1.
rv_reason = {{p}}if_hotel_rate=>c_reason-guests.
ELSEIF iv_category <> {{p}}if_hotel_rate=>c_category-basic
AND iv_category <> {{p}}if_hotel_rate=>c_category-comfort
AND iv_category <> {{p}}if_hotel_rate=>c_category-suite.
rv_reason = {{p}}if_hotel_rate=>c_reason-category.
ELSE.
rv_reason = {{p}}if_hotel_rate=>c_reason-ok.
ENDIF.
ENDMETHOD.
METHOD room_count.
rv_rooms = ( iv_guests + 1 ) DIV 2.
ENDMETHOD.
METHOD nightly_rate.
CASE iv_category.
WHEN {{p}}if_hotel_rate=>c_category-basic.
rv_amount = '90.00'.
WHEN {{p}}if_hotel_rate=>c_category-comfort.
rv_amount = '140.00'.
WHEN {{p}}if_hotel_rate=>c_category-suite.
rv_amount = '260.00'.
ENDCASE.
ENDMETHOD.
METHOD discount_percent.
IF iv_nights >= 28.
rv_percent = 20.
ELSEIF iv_nights >= 14.
rv_percent = 15.
ELSEIF iv_nights >= 7.
rv_percent = 10.
ENDIF.
ENDMETHOD.
METHOD net_room_total.
DATA lv_total TYPE {{p}}if_hotel_rate=>ty_amount.
lv_total = nightly_rate( iv_category ) * room_count( iv_guests ) * iv_nights.
DATA lv_discount TYPE {{p}}if_hotel_rate=>ty_amount.
lv_discount = lv_total * discount_percent( iv_nights ) / 100.
rv_total = lv_total + lv_discount.
ENDMETHOD.
METHOD extras.
DATA(lv_guest_nights) = iv_guests * iv_nights.
rv_extras = lv_guest_nights * c_city_tax.
IF iv_breakfast = abap_true.
rv_extras = rv_extras + lv_guest_nights * c_breakfast.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,108 @@
CLASS {{p}}hotel_rate DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES {{p}}if_hotel_rate.
PRIVATE SECTION.
CONSTANTS:
c_breakfast TYPE {{p}}if_hotel_rate=>ty_amount VALUE '12.50',
c_city_tax TYPE {{p}}if_hotel_rate=>ty_amount VALUE '3.00'.
METHODS validate
IMPORTING iv_category TYPE {{p}}if_hotel_rate=>ty_category
iv_nights TYPE i
iv_guests TYPE i
RETURNING VALUE(rv_reason) TYPE {{p}}if_hotel_rate=>ty_reason.
METHODS room_count
IMPORTING iv_guests TYPE i
RETURNING VALUE(rv_rooms) TYPE i.
METHODS nightly_rate
IMPORTING iv_category TYPE {{p}}if_hotel_rate=>ty_category
RETURNING VALUE(rv_amount) TYPE {{p}}if_hotel_rate=>ty_amount.
METHODS discount_percent
IMPORTING iv_nights TYPE i
RETURNING VALUE(rv_percent) TYPE i.
METHODS net_room_total
IMPORTING iv_category TYPE {{p}}if_hotel_rate=>ty_category
iv_nights TYPE i
iv_guests TYPE i
RETURNING VALUE(rv_total) TYPE {{p}}if_hotel_rate=>ty_amount.
METHODS extras
IMPORTING iv_nights TYPE i
iv_guests TYPE i
iv_breakfast TYPE abap_bool
RETURNING VALUE(rv_extras) TYPE {{p}}if_hotel_rate=>ty_amount.
ENDCLASS.
CLASS {{p}}hotel_rate IMPLEMENTATION.
METHOD {{p}}if_hotel_rate~calculate.
rs_result-reason = validate( iv_category = iv_category
iv_nights = iv_nights
iv_guests = iv_guests ).
IF rs_result-reason <> {{p}}if_hotel_rate=>c_reason-ok.
rs_result-price = 0.
RETURN.
ENDIF.
rs_result-price = net_room_total( iv_category = iv_category
iv_nights = iv_nights
iv_guests = iv_guests )
+ extras( iv_nights = iv_nights
iv_guests = iv_guests
iv_breakfast = iv_breakfast ).
ENDMETHOD.
METHOD validate.
IF iv_nights < 1.
rv_reason = {{p}}if_hotel_rate=>c_reason-nights.
ELSEIF iv_guests < 1.
rv_reason = {{p}}if_hotel_rate=>c_reason-guests.
ELSEIF iv_category <> {{p}}if_hotel_rate=>c_category-basic
AND iv_category <> {{p}}if_hotel_rate=>c_category-comfort
AND iv_category <> {{p}}if_hotel_rate=>c_category-suite.
rv_reason = {{p}}if_hotel_rate=>c_reason-category.
ELSE.
rv_reason = {{p}}if_hotel_rate=>c_reason-ok.
ENDIF.
ENDMETHOD.
METHOD room_count.
rv_rooms = ( iv_guests + 1 ) DIV 2.
ENDMETHOD.
METHOD nightly_rate.
CASE iv_category.
WHEN {{p}}if_hotel_rate=>c_category-basic.
rv_amount = '90.00'.
WHEN {{p}}if_hotel_rate=>c_category-comfort.
rv_amount = '140.00'.
WHEN {{p}}if_hotel_rate=>c_category-suite.
rv_amount = '260.00'.
ENDCASE.
ENDMETHOD.
METHOD discount_percent.
IF iv_nights >= 28.
rv_percent = 20.
ELSEIF iv_nights >= 14.
rv_percent = 15.
ELSEIF iv_nights >= 7.
rv_percent = 10.
ENDIF.
ENDMETHOD.
METHOD net_room_total.
DATA lv_total TYPE {{p}}if_hotel_rate=>ty_amount.
lv_total = nightly_rate( iv_category ) * room_count( iv_guests ) * iv_nights.
DATA lv_discount TYPE {{p}}if_hotel_rate=>ty_amount.
lv_discount = lv_total * discount_percent( iv_nights ) / 100.
rv_total = lv_total - lv_discount.
ENDMETHOD.
METHOD extras.
DATA(lv_guest_nights) = iv_guests * iv_nights.
rv_extras = lv_guest_nights * c_city_tax.
IF iv_breakfast = abap_false.
rv_extras = rv_extras + lv_guest_nights * c_breakfast.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

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

View File

@@ -0,0 +1,145 @@
CLASS {{p}}t13_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA mo_cut TYPE REF TO {{p}}if_hotel_rate.
METHODS setup.
METHODS expect_price
IMPORTING iv_expected TYPE {{p}}if_hotel_rate=>ty_amount
iv_actual TYPE {{p}}if_hotel_rate=>ty_amount.
METHODS rejects_zero_nights FOR TESTING.
METHODS rejects_zero_guests FOR TESTING.
METHODS rejects_unknown_category FOR TESTING.
METHODS validation_order FOR TESTING.
METHODS single_standard_night FOR TESTING.
METHODS two_guests_one_room FOR TESTING.
METHODS three_guests_two_rooms FOR TESTING.
METHODS breakfast_per_guest FOR TESTING.
METHODS discount_starts_at_seven FOR TESTING.
METHODS discount_fifteen_percent FOR TESTING.
METHODS discount_twenty_percent FOR TESTING.
ENDCLASS.
CLASS {{p}}t13_hidden IMPLEMENTATION.
METHOD setup.
mo_cut = NEW {{p}}hotel_rate( ).
ENDMETHOD.
METHOD expect_price.
cl_abap_unit_assert=>assert_equals( exp = iv_expected act = iv_actual ).
ENDMETHOD.
METHOD rejects_zero_nights.
DATA(ls_result) = mo_cut->calculate( iv_category = {{p}}if_hotel_rate=>c_category-basic
iv_nights = 0
iv_guests = 2
iv_breakfast = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_hotel_rate=>c_reason-nights
act = ls_result-reason ).
expect_price( iv_expected = '0.00' iv_actual = ls_result-price ).
ENDMETHOD.
METHOD rejects_zero_guests.
DATA(ls_result) = mo_cut->calculate( iv_category = {{p}}if_hotel_rate=>c_category-basic
iv_nights = 3
iv_guests = 0
iv_breakfast = abap_true ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_hotel_rate=>c_reason-guests
act = ls_result-reason ).
expect_price( iv_expected = '0.00' iv_actual = ls_result-price ).
ENDMETHOD.
METHOD rejects_unknown_category.
DATA(ls_result) = mo_cut->calculate( iv_category = 'X'
iv_nights = 2
iv_guests = 1
iv_breakfast = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_hotel_rate=>c_reason-category
act = ls_result-reason ).
expect_price( iv_expected = '0.00' iv_actual = ls_result-price ).
ENDMETHOD.
METHOD validation_order.
DATA(ls_result) = mo_cut->calculate( iv_category = 'X'
iv_nights = 0
iv_guests = 0
iv_breakfast = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_hotel_rate=>c_reason-nights
act = ls_result-reason ).
ls_result = mo_cut->calculate( iv_category = 'X'
iv_nights = 2
iv_guests = 0
iv_breakfast = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_hotel_rate=>c_reason-guests
act = ls_result-reason ).
ls_result = mo_cut->calculate( iv_category = 'X'
iv_nights = 2
iv_guests = 2
iv_breakfast = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_hotel_rate=>c_reason-category
act = ls_result-reason ).
ENDMETHOD.
METHOD single_standard_night.
DATA(ls_result) = mo_cut->calculate( iv_category = {{p}}if_hotel_rate=>c_category-basic
iv_nights = 1
iv_guests = 1
iv_breakfast = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_hotel_rate=>c_reason-ok
act = ls_result-reason ).
expect_price( iv_expected = '93.00' iv_actual = ls_result-price ).
ENDMETHOD.
METHOD two_guests_one_room.
DATA(ls_result) = mo_cut->calculate( iv_category = {{p}}if_hotel_rate=>c_category-comfort
iv_nights = 3
iv_guests = 2
iv_breakfast = abap_false ).
expect_price( iv_expected = '438.00' iv_actual = ls_result-price ).
ENDMETHOD.
METHOD three_guests_two_rooms.
DATA(ls_result) = mo_cut->calculate( iv_category = {{p}}if_hotel_rate=>c_category-comfort
iv_nights = 2
iv_guests = 3
iv_breakfast = abap_false ).
expect_price( iv_expected = '578.00' iv_actual = ls_result-price ).
ENDMETHOD.
METHOD breakfast_per_guest.
DATA(ls_result) = mo_cut->calculate( iv_category = {{p}}if_hotel_rate=>c_category-basic
iv_nights = 2
iv_guests = 2
iv_breakfast = abap_true ).
expect_price( iv_expected = '242.00' iv_actual = ls_result-price ).
ENDMETHOD.
METHOD discount_starts_at_seven.
DATA(ls_result) = mo_cut->calculate( iv_category = {{p}}if_hotel_rate=>c_category-basic
iv_nights = 6
iv_guests = 1
iv_breakfast = abap_false ).
expect_price( iv_expected = '558.00' iv_actual = ls_result-price ).
ls_result = mo_cut->calculate( iv_category = {{p}}if_hotel_rate=>c_category-basic
iv_nights = 7
iv_guests = 1
iv_breakfast = abap_false ).
expect_price( iv_expected = '588.00' iv_actual = ls_result-price ).
ENDMETHOD.
METHOD discount_fifteen_percent.
DATA(ls_result) = mo_cut->calculate( iv_category = {{p}}if_hotel_rate=>c_category-comfort
iv_nights = 14
iv_guests = 2
iv_breakfast = abap_false ).
expect_price( iv_expected = '1750.00' iv_actual = ls_result-price ).
ENDMETHOD.
METHOD discount_twenty_percent.
DATA(ls_result) = mo_cut->calculate( iv_category = {{p}}if_hotel_rate=>c_category-suite
iv_nights = 28
iv_guests = 1
iv_breakfast = abap_false ).
expect_price( iv_expected = '5908.00' iv_actual = ls_result-price ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,74 @@
{
"task": "G0102",
"mutants": [
{
"object": "{{P}}HOTEL_RATE",
"mutant": "line 59: <> -> = (rel)",
"status": "killed",
"hidden": "6/11",
"failed_tests": [
"BREAKFAST_PER_GUEST",
"DISCOUNT_STARTS_AT_SEVEN",
"REJECTS_UNKNOWN_CATEGORY",
"SINGLE_STANDARD_NIGHT",
"VALIDATION_ORDER"
]
},
{
"object": "{{P}}HOTEL_RATE",
"mutant": "line 61: AND -> OR (logic)",
"status": "killed",
"hidden": "4/11",
"failed_tests": [
"BREAKFAST_PER_GUEST",
"DISCOUNT_FIFTEEN_PERCENT",
"DISCOUNT_STARTS_AT_SEVEN",
"DISCOUNT_TWENTY_PERCENT",
"SINGLE_STANDARD_NIGHT",
"THREE_GUESTS_TWO_ROOMS",
"TWO_GUESTS_ONE_ROOM"
]
},
{
"object": "{{P}}HOTEL_RATE",
"mutant": "line 69: 1 -> 2 (const)",
"status": "killed",
"hidden": "8/11",
"failed_tests": [
"BREAKFAST_PER_GUEST",
"DISCOUNT_FIFTEEN_PERCENT",
"TWO_GUESTS_ONE_ROOM"
]
},
{
"object": "{{P}}HOTEL_RATE",
"mutant": "line 98: - -> + (arith)",
"status": "killed",
"hidden": "8/11",
"failed_tests": [
"DISCOUNT_FIFTEEN_PERCENT",
"DISCOUNT_STARTS_AT_SEVEN",
"DISCOUNT_TWENTY_PERCENT"
]
},
{
"object": "{{P}}HOTEL_RATE",
"mutant": "line 104: abap_true -> abap_false (bool)",
"status": "killed",
"hidden": "4/11",
"failed_tests": [
"BREAKFAST_PER_GUEST",
"DISCOUNT_FIFTEEN_PERCENT",
"DISCOUNT_STARTS_AT_SEVEN",
"DISCOUNT_TWENTY_PERCENT",
"SINGLE_STANDARD_NIGHT",
"THREE_GUESTS_TWO_ROOMS",
"TWO_GUESTS_ONE_ROOM"
]
}
],
"valid": 5,
"killed": 5,
"kill_rate": 1.0,
"ok": true
}

View File

@@ -0,0 +1,108 @@
CLASS {{p}}hotel_rate DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES {{p}}if_hotel_rate.
PRIVATE SECTION.
CONSTANTS:
c_breakfast TYPE {{p}}if_hotel_rate=>ty_amount VALUE '12.50',
c_city_tax TYPE {{p}}if_hotel_rate=>ty_amount VALUE '3.00'.
METHODS validate
IMPORTING iv_category TYPE {{p}}if_hotel_rate=>ty_category
iv_nights TYPE i
iv_guests TYPE i
RETURNING VALUE(rv_reason) TYPE {{p}}if_hotel_rate=>ty_reason.
METHODS room_count
IMPORTING iv_guests TYPE i
RETURNING VALUE(rv_rooms) TYPE i.
METHODS nightly_rate
IMPORTING iv_category TYPE {{p}}if_hotel_rate=>ty_category
RETURNING VALUE(rv_amount) TYPE {{p}}if_hotel_rate=>ty_amount.
METHODS discount_percent
IMPORTING iv_nights TYPE i
RETURNING VALUE(rv_percent) TYPE i.
METHODS net_room_total
IMPORTING iv_category TYPE {{p}}if_hotel_rate=>ty_category
iv_nights TYPE i
iv_guests TYPE i
RETURNING VALUE(rv_total) TYPE {{p}}if_hotel_rate=>ty_amount.
METHODS extras
IMPORTING iv_nights TYPE i
iv_guests TYPE i
iv_breakfast TYPE abap_bool
RETURNING VALUE(rv_extras) TYPE {{p}}if_hotel_rate=>ty_amount.
ENDCLASS.
CLASS {{p}}hotel_rate IMPLEMENTATION.
METHOD {{p}}if_hotel_rate~calculate.
rs_result-reason = validate( iv_category = iv_category
iv_nights = iv_nights
iv_guests = iv_guests ).
IF rs_result-reason <> {{p}}if_hotel_rate=>c_reason-ok.
rs_result-price = 0.
RETURN.
ENDIF.
rs_result-price = net_room_total( iv_category = iv_category
iv_nights = iv_nights
iv_guests = iv_guests )
+ extras( iv_nights = iv_nights
iv_guests = iv_guests
iv_breakfast = iv_breakfast ).
ENDMETHOD.
METHOD validate.
IF iv_nights < 1.
rv_reason = {{p}}if_hotel_rate=>c_reason-nights.
ELSEIF iv_guests < 1.
rv_reason = {{p}}if_hotel_rate=>c_reason-guests.
ELSEIF iv_category <> {{p}}if_hotel_rate=>c_category-basic
AND iv_category <> {{p}}if_hotel_rate=>c_category-comfort
AND iv_category <> {{p}}if_hotel_rate=>c_category-suite.
rv_reason = {{p}}if_hotel_rate=>c_reason-category.
ELSE.
rv_reason = {{p}}if_hotel_rate=>c_reason-ok.
ENDIF.
ENDMETHOD.
METHOD room_count.
rv_rooms = ( iv_guests + 1 ) DIV 2.
ENDMETHOD.
METHOD nightly_rate.
CASE iv_category.
WHEN {{p}}if_hotel_rate=>c_category-basic.
rv_amount = '90.00'.
WHEN {{p}}if_hotel_rate=>c_category-comfort.
rv_amount = '140.00'.
WHEN {{p}}if_hotel_rate=>c_category-suite.
rv_amount = '260.00'.
ENDCASE.
ENDMETHOD.
METHOD discount_percent.
IF iv_nights >= 28.
rv_percent = 20.
ELSEIF iv_nights >= 14.
rv_percent = 15.
ELSEIF iv_nights >= 7.
rv_percent = 10.
ENDIF.
ENDMETHOD.
METHOD net_room_total.
DATA lv_total TYPE {{p}}if_hotel_rate=>ty_amount.
lv_total = nightly_rate( iv_category ) * room_count( iv_guests ) * iv_nights.
DATA lv_discount TYPE {{p}}if_hotel_rate=>ty_amount.
lv_discount = lv_total * discount_percent( iv_nights ) / 100.
rv_total = lv_total - lv_discount.
ENDMETHOD.
METHOD extras.
DATA(lv_guest_nights) = iv_guests * iv_nights.
rv_extras = lv_guest_nights * c_city_tax.
IF iv_breakfast = abap_true.
rv_extras = rv_extras + lv_guest_nights * c_breakfast.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,76 @@
CLASS ltc_hotel_rate DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA mo_cut TYPE REF TO {{p}}if_hotel_rate.
METHODS setup.
METHODS basic_room FOR TESTING.
METHODS invalid_nights FOR TESTING.
METHODS invalid_guests FOR TESTING.
METHODS invalid_category FOR TESTING.
METHODS breakfast_and_tax FOR TESTING.
METHODS long_stay_discount FOR TESTING.
ENDCLASS.
CLASS ltc_hotel_rate IMPLEMENTATION.
METHOD setup.
mo_cut = NEW {{p}}hotel_rate( ).
ENDMETHOD.
METHOD basic_room.
DATA(ls_result) = mo_cut->calculate( iv_category = {{p}}if_hotel_rate=>c_category-basic
iv_nights = 1
iv_guests = 1
iv_breakfast = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_hotel_rate=>c_reason-ok
act = ls_result-reason ).
cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}if_hotel_rate=>ty_amount( '93.00' )
act = ls_result-price ).
ENDMETHOD.
METHOD invalid_nights.
DATA(ls_result) = mo_cut->calculate( iv_category = {{p}}if_hotel_rate=>c_category-comfort
iv_nights = 0
iv_guests = 2
iv_breakfast = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_hotel_rate=>c_reason-nights
act = ls_result-reason ).
cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}if_hotel_rate=>ty_amount( '0.00' )
act = ls_result-price ).
ENDMETHOD.
METHOD invalid_guests.
DATA(ls_result) = mo_cut->calculate( iv_category = {{p}}if_hotel_rate=>c_category-basic
iv_nights = 4
iv_guests = 0
iv_breakfast = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_hotel_rate=>c_reason-guests
act = ls_result-reason ).
ENDMETHOD.
METHOD invalid_category.
DATA(ls_result) = mo_cut->calculate( iv_category = 'Z'
iv_nights = 4
iv_guests = 2
iv_breakfast = abap_true ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_hotel_rate=>c_reason-category
act = ls_result-reason ).
ENDMETHOD.
METHOD breakfast_and_tax.
DATA(ls_result) = mo_cut->calculate( iv_category = {{p}}if_hotel_rate=>c_category-basic
iv_nights = 2
iv_guests = 2
iv_breakfast = abap_true ).
cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}if_hotel_rate=>ty_amount( '242.00' )
act = ls_result-price ).
ENDMETHOD.
METHOD long_stay_discount.
DATA(ls_result) = mo_cut->calculate( iv_category = {{p}}if_hotel_rate=>c_category-comfort
iv_nights = 14
iv_guests = 2
iv_breakfast = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}if_hotel_rate=>ty_amount( '1750.00' )
act = ls_result-price ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,29 @@
INTERFACE {{p}}if_hotel_rate PUBLIC.
TYPES ty_category TYPE c LENGTH 1.
TYPES ty_reason TYPE c LENGTH 10.
TYPES ty_amount TYPE p LENGTH 10 DECIMALS 2.
TYPES:
BEGIN OF ty_result,
reason TYPE ty_reason,
price TYPE ty_amount,
END OF ty_result.
CONSTANTS:
BEGIN OF c_reason,
ok TYPE ty_reason VALUE 'OK',
nights TYPE ty_reason VALUE 'NIGHTS',
guests TYPE ty_reason VALUE 'GUESTS',
category TYPE ty_reason VALUE 'CATEGORY',
END OF c_reason.
CONSTANTS:
BEGIN OF c_category,
basic TYPE ty_category VALUE 'S',
comfort TYPE ty_category VALUE 'C',
suite TYPE ty_category VALUE 'U',
END OF c_category.
METHODS calculate
IMPORTING iv_category TYPE ty_category
iv_nights TYPE i
iv_guests TYPE i
iv_breakfast TYPE abap_bool
RETURNING VALUE(rs_result) TYPE ty_result.
ENDINTERFACE.

View File

@@ -0,0 +1,71 @@
# 1. Goal
Calculate the price of a hotel stay. A booking program calls the calculation
before it shows the price to the guest. The program needs one reason code for
each invalid input.
# 2. Open questions
None.
# 3. Context
- The interface {{P}}IF_HOTEL_RATE exists in package $TMP. It is active.
- The interface has these types:
- TY_CATEGORY: character, length 1.
- TY_REASON: character, length 10.
- TY_AMOUNT: packed number, length 10, 2 decimals.
- TY_RESULT: structure with the components REASON (TY_REASON) and
PRICE (TY_AMOUNT).
- The interface has these constants:
- C_REASON: OK, NIGHTS, GUESTS, CATEGORY.
- C_CATEGORY: BASIC 'S', COMFORT 'C', SUITE 'U'.
- The interface has one method:
CALCULATE
IMPORTING iv_category TYPE ty_category
iv_nights TYPE i
iv_guests TYPE i
iv_breakfast TYPE abap_bool
RETURNING VALUE(rs_result) TYPE ty_result.
# 4. Contract
- Create the class {{P}}HOTEL_RATE in package $TMP.
- The class is public, final, and has a public constructor without parameters.
- The class implements {{P}}IF_HOTEL_RATE.
- Do not add other public methods.
# 5. Business rules
Check the input in this sequence. Return the reason of the first check that
fails and the price 0.
1. If IV_NIGHTS is less than 1, return NIGHTS.
2. If IV_GUESTS is less than 1, return GUESTS.
3. If IV_CATEGORY is not BASIC, COMFORT or SUITE, return CATEGORY.
4. Else return OK and calculate the price.
Calculate the price in this sequence:
1. One room takes at most 2 guests. The number of rooms is the number of guests
divided by 2, rounded up.
2. The price of one room for one night is 90.00 for BASIC, 140.00 for COMFORT
and 260.00 for SUITE.
3. The room total is the number of rooms multiplied by the number of nights
multiplied by the price of one room for one night.
4. Long stay discount on the room total:
- 28 nights or more: 20 %
- 14 nights or more: 15 %
- 7 nights or more: 10 %
- less than 7 nights: no discount
The discounted room total is the room total minus the discount.
5. Breakfast costs 12.50 for one guest for one night. Add it if IV_BREAKFAST is
true.
6. City tax costs 3.00 for one guest for one night. Add it always.
7. The price is the discounted room total plus breakfast plus city tax.
All amounts are exact to two decimals.
# 6. Constraints
- Release target: 8.16.
- 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_HOTEL_RATE.
# 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": "G0102",
"category": "A",
"object_type": "CLAS",
"difficulty": 2,
"release_target": "v816",
"expected_outcome": "implement",
"budget": {
"max_tool_calls": 60,
"max_activations": 15
},
"seed": [
{
"type": "INTF",
"name": "{{P}}IF_HOTEL_RATE",
"file": "seed/if_hotel_rate.intf.abap",
"description": "Hotel rate contract: types, reason codes, category codes and the calculate signature"
}
],
"contract": [
{
"type": "CLAS",
"name": "{{P}}HOTEL_RATE",
"implements": "{{P}}IF_HOTEL_RATE"
}
],
"out_of_scope": [
"{{P}}IF_HOTEL_RATE"
],
"hidden_tests": [
{
"type": "CLAS",
"name": "{{P}}T13_HIDDEN",
"file": "hidden/t13_hidden.clas.abap",
"description": "T13 hidden tests for the hotel rate calculation"
}
],
"reference": [
{
"type": "CLAS",
"name": "{{P}}HOTEL_RATE",
"file": "reference/hotel_rate.clas.abap",
"description": "Hotel rate calculator",
"testclasses_file": "reference/hotel_rate.testclasses.abap"
}
],
"craft_checks": [
"method_length",
"db_operation_in_loop"
]
}

View File

@@ -0,0 +1,68 @@
CLASS {{p}}overdue_fine DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_media TYPE c LENGTH 8.
TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2.
TYPES:
BEGIN OF ty_result,
days_overdue TYPE i,
chargeable_days TYPE i,
fine TYPE ty_amount,
END OF ty_result.
METHODS calculate
IMPORTING iv_due_date TYPE d
iv_return_date TYPE d
iv_media TYPE ty_media
RETURNING VALUE(rs_result) TYPE ty_result.
PRIVATE SECTION.
TYPES:
BEGIN OF ty_media_rule,
media TYPE ty_media,
rate TYPE ty_amount,
grace_days TYPE i,
END OF ty_media_rule,
tt_media_rule TYPE HASHED TABLE OF ty_media_rule WITH UNIQUE KEY media.
CONSTANTS:
c_max_fine TYPE ty_amount VALUE '25.00',
c_reminder_fee TYPE ty_amount VALUE '5.00',
c_reminder_day TYPE i VALUE 30.
METHODS media_rule
IMPORTING iv_media TYPE ty_media
RETURNING VALUE(rs_rule) TYPE ty_media_rule.
ENDCLASS.
CLASS {{p}}overdue_fine IMPLEMENTATION.
METHOD calculate.
rs_result-days_overdue = iv_return_date - iv_due_date.
IF rs_result-days_overdue > 0.
CLEAR rs_result.
RETURN.
ENDIF.
DATA(ls_rule) = media_rule( iv_media ).
IF ls_rule IS INITIAL.
RETURN.
ENDIF.
rs_result-chargeable_days = nmax( val1 = rs_result-days_overdue - ls_rule-grace_days
val2 = 0 ).
rs_result-fine = rs_result-chargeable_days * ls_rule-rate.
IF rs_result-days_overdue > c_reminder_day.
rs_result-fine = rs_result-fine + c_reminder_fee.
ENDIF.
rs_result-fine = nmin( val1 = rs_result-fine
val2 = c_max_fine ).
ENDMETHOD.
METHOD media_rule.
DATA(lt_rules) = VALUE tt_media_rule(
( media = 'BOOK' rate = '0.30' grace_days = 7 )
( media = 'DVD' rate = '1.50' grace_days = 2 )
( media = 'GAME' rate = '2.50' grace_days = 0 ) ).
READ TABLE lt_rules INTO rs_rule WITH TABLE KEY media = iv_media.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,68 @@
CLASS {{p}}overdue_fine DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_media TYPE c LENGTH 8.
TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2.
TYPES:
BEGIN OF ty_result,
days_overdue TYPE i,
chargeable_days TYPE i,
fine TYPE ty_amount,
END OF ty_result.
METHODS calculate
IMPORTING iv_due_date TYPE d
iv_return_date TYPE d
iv_media TYPE ty_media
RETURNING VALUE(rs_result) TYPE ty_result.
PRIVATE SECTION.
TYPES:
BEGIN OF ty_media_rule,
media TYPE ty_media,
rate TYPE ty_amount,
grace_days TYPE i,
END OF ty_media_rule,
tt_media_rule TYPE HASHED TABLE OF ty_media_rule WITH UNIQUE KEY media.
CONSTANTS:
c_max_fine TYPE ty_amount VALUE '25.00',
c_reminder_fee TYPE ty_amount VALUE '5.00',
c_reminder_day TYPE i VALUE 30.
METHODS media_rule
IMPORTING iv_media TYPE ty_media
RETURNING VALUE(rs_rule) TYPE ty_media_rule.
ENDCLASS.
CLASS {{p}}overdue_fine IMPLEMENTATION.
METHOD calculate.
rs_result-days_overdue = iv_return_date - iv_due_date.
IF rs_result-days_overdue <= 0.
CLEAR rs_result.
RETURN.
ENDIF.
DATA(ls_rule) = media_rule( iv_media ).
IF ls_rule IS INITIAL.
RETURN.
ENDIF.
rs_result-chargeable_days = nmax( val1 = rs_result-days_overdue + ls_rule-grace_days
val2 = 0 ).
rs_result-fine = rs_result-chargeable_days * ls_rule-rate.
IF rs_result-days_overdue > c_reminder_day.
rs_result-fine = rs_result-fine + c_reminder_fee.
ENDIF.
rs_result-fine = nmin( val1 = rs_result-fine
val2 = c_max_fine ).
ENDMETHOD.
METHOD media_rule.
DATA(lt_rules) = VALUE tt_media_rule(
( media = 'BOOK' rate = '0.30' grace_days = 7 )
( media = 'DVD' rate = '1.50' grace_days = 2 )
( media = 'GAME' rate = '2.50' grace_days = 0 ) ).
READ TABLE lt_rules INTO rs_rule WITH TABLE KEY media = iv_media.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,68 @@
CLASS {{p}}overdue_fine DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_media TYPE c LENGTH 8.
TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2.
TYPES:
BEGIN OF ty_result,
days_overdue TYPE i,
chargeable_days TYPE i,
fine TYPE ty_amount,
END OF ty_result.
METHODS calculate
IMPORTING iv_due_date TYPE d
iv_return_date TYPE d
iv_media TYPE ty_media
RETURNING VALUE(rs_result) TYPE ty_result.
PRIVATE SECTION.
TYPES:
BEGIN OF ty_media_rule,
media TYPE ty_media,
rate TYPE ty_amount,
grace_days TYPE i,
END OF ty_media_rule,
tt_media_rule TYPE HASHED TABLE OF ty_media_rule WITH UNIQUE KEY media.
CONSTANTS:
c_max_fine TYPE ty_amount VALUE '25.00',
c_reminder_fee TYPE ty_amount VALUE '5.00',
c_reminder_day TYPE i VALUE 30.
METHODS media_rule
IMPORTING iv_media TYPE ty_media
RETURNING VALUE(rs_rule) TYPE ty_media_rule.
ENDCLASS.
CLASS {{p}}overdue_fine IMPLEMENTATION.
METHOD calculate.
rs_result-days_overdue = iv_return_date - iv_due_date.
IF rs_result-days_overdue <= 0.
CLEAR rs_result.
RETURN.
ENDIF.
DATA(ls_rule) = media_rule( iv_media ).
IF ls_rule IS INITIAL.
RETURN.
ENDIF.
rs_result-chargeable_days = nmax( val1 = rs_result-days_overdue - ls_rule-grace_days
val2 = 0 ).
rs_result-fine = rs_result-chargeable_days / ls_rule-rate.
IF rs_result-days_overdue > c_reminder_day.
rs_result-fine = rs_result-fine + c_reminder_fee.
ENDIF.
rs_result-fine = nmin( val1 = rs_result-fine
val2 = c_max_fine ).
ENDMETHOD.
METHOD media_rule.
DATA(lt_rules) = VALUE tt_media_rule(
( media = 'BOOK' rate = '0.30' grace_days = 7 )
( media = 'DVD' rate = '1.50' grace_days = 2 )
( media = 'GAME' rate = '2.50' grace_days = 0 ) ).
READ TABLE lt_rules INTO rs_rule WITH TABLE KEY media = iv_media.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,68 @@
CLASS {{p}}overdue_fine DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_media TYPE c LENGTH 8.
TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2.
TYPES:
BEGIN OF ty_result,
days_overdue TYPE i,
chargeable_days TYPE i,
fine TYPE ty_amount,
END OF ty_result.
METHODS calculate
IMPORTING iv_due_date TYPE d
iv_return_date TYPE d
iv_media TYPE ty_media
RETURNING VALUE(rs_result) TYPE ty_result.
PRIVATE SECTION.
TYPES:
BEGIN OF ty_media_rule,
media TYPE ty_media,
rate TYPE ty_amount,
grace_days TYPE i,
END OF ty_media_rule,
tt_media_rule TYPE HASHED TABLE OF ty_media_rule WITH UNIQUE KEY media.
CONSTANTS:
c_max_fine TYPE ty_amount VALUE '25.00',
c_reminder_fee TYPE ty_amount VALUE '5.00',
c_reminder_day TYPE i VALUE 30.
METHODS media_rule
IMPORTING iv_media TYPE ty_media
RETURNING VALUE(rs_rule) TYPE ty_media_rule.
ENDCLASS.
CLASS {{p}}overdue_fine IMPLEMENTATION.
METHOD calculate.
rs_result-days_overdue = iv_return_date - iv_due_date.
IF rs_result-days_overdue <= 0.
CLEAR rs_result.
RETURN.
ENDIF.
DATA(ls_rule) = media_rule( iv_media ).
IF ls_rule IS INITIAL.
RETURN.
ENDIF.
rs_result-chargeable_days = nmax( val1 = rs_result-days_overdue - ls_rule-grace_days
val2 = 0 ).
rs_result-fine = rs_result-chargeable_days * ls_rule-rate.
IF rs_result-days_overdue > c_reminder_day.
rs_result-fine = rs_result-fine - c_reminder_fee.
ENDIF.
rs_result-fine = nmin( val1 = rs_result-fine
val2 = c_max_fine ).
ENDMETHOD.
METHOD media_rule.
DATA(lt_rules) = VALUE tt_media_rule(
( media = 'BOOK' rate = '0.30' grace_days = 7 )
( media = 'DVD' rate = '1.50' grace_days = 2 )
( media = 'GAME' rate = '2.50' grace_days = 0 ) ).
READ TABLE lt_rules INTO rs_rule WITH TABLE KEY media = iv_media.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,68 @@
CLASS {{p}}overdue_fine DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_media TYPE c LENGTH 8.
TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2.
TYPES:
BEGIN OF ty_result,
days_overdue TYPE i,
chargeable_days TYPE i,
fine TYPE ty_amount,
END OF ty_result.
METHODS calculate
IMPORTING iv_due_date TYPE d
iv_return_date TYPE d
iv_media TYPE ty_media
RETURNING VALUE(rs_result) TYPE ty_result.
PRIVATE SECTION.
TYPES:
BEGIN OF ty_media_rule,
media TYPE ty_media,
rate TYPE ty_amount,
grace_days TYPE i,
END OF ty_media_rule,
tt_media_rule TYPE HASHED TABLE OF ty_media_rule WITH UNIQUE KEY media.
CONSTANTS:
c_max_fine TYPE ty_amount VALUE '25.00',
c_reminder_fee TYPE ty_amount VALUE '5.00',
c_reminder_day TYPE i VALUE 30.
METHODS media_rule
IMPORTING iv_media TYPE ty_media
RETURNING VALUE(rs_rule) TYPE ty_media_rule.
ENDCLASS.
CLASS {{p}}overdue_fine IMPLEMENTATION.
METHOD calculate.
rs_result-days_overdue = iv_return_date - iv_due_date.
IF rs_result-days_overdue <= 0.
CLEAR rs_result.
RETURN.
ENDIF.
DATA(ls_rule) = media_rule( iv_media ).
IF ls_rule IS INITIAL.
RETURN.
ENDIF.
rs_result-chargeable_days = nmax( val1 = rs_result-days_overdue - ls_rule-grace_days
val2 = 0 ).
rs_result-fine = rs_result-chargeable_days * ls_rule-rate.
IF rs_result-days_overdue > c_reminder_day.
rs_result-fine = rs_result-fine + c_reminder_fee.
ENDIF.
rs_result-fine = nmin( val1 = rs_result-fine
val2 = c_max_fine ).
ENDMETHOD.
METHOD media_rule.
DATA(lt_rules) = VALUE tt_media_rule(
( media = 'BOOK' rate = '0.30' grace_days = 8 )
( media = 'DVD' rate = '1.50' grace_days = 2 )
( media = 'GAME' rate = '2.50' grace_days = 0 ) ).
READ TABLE lt_rules INTO rs_rule WITH TABLE KEY media = iv_media.
ENDMETHOD.
ENDCLASS.

View File

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

View File

@@ -0,0 +1,103 @@
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}}overdue_fine.
METHODS setup.
METHODS assert_fine
IMPORTING iv_due TYPE d
iv_return TYPE d
iv_media TYPE {{p}}overdue_fine=>ty_media
iv_days TYPE i
iv_charge TYPE i
iv_fine TYPE {{p}}overdue_fine=>ty_amount.
METHODS not_late_no_fine FOR TESTING.
METHODS book_in_grace FOR TESTING.
METHODS book_over_grace FOR TESTING.
METHODS dvd_in_grace FOR TESTING.
METHODS dvd_over_grace FOR TESTING.
METHODS game_no_grace FOR TESTING.
METHODS reminder_fee_added FOR TESTING.
METHODS no_reminder_day_30 FOR TESTING.
METHODS fine_capped FOR TESTING.
METHODS cap_after_reminder FOR TESTING.
METHODS unknown_media_no_fine FOR TESTING.
ENDCLASS.
CLASS {{p}}t02_hidden IMPLEMENTATION.
METHOD setup.
mo_cut = NEW {{p}}overdue_fine( ).
ENDMETHOD.
METHOD assert_fine.
DATA(ls_result) = mo_cut->calculate( iv_due_date = iv_due
iv_return_date = iv_return
iv_media = iv_media ).
cl_abap_unit_assert=>assert_equals( exp = iv_days
act = ls_result-days_overdue
msg = |days overdue for { iv_media }| ).
cl_abap_unit_assert=>assert_equals( exp = iv_charge
act = ls_result-chargeable_days
msg = |chargeable days for { iv_media }| ).
cl_abap_unit_assert=>assert_equals( exp = iv_fine
act = ls_result-fine
msg = |fine for { iv_media }| ).
ENDMETHOD.
METHOD not_late_no_fine.
assert_fine( iv_due = '20250110' iv_return = '20250109' iv_media = 'BOOK'
iv_days = 0 iv_charge = 0 iv_fine = '0.00' ).
assert_fine( iv_due = '20250110' iv_return = '20250110' iv_media = 'DVD'
iv_days = 0 iv_charge = 0 iv_fine = '0.00' ).
ENDMETHOD.
METHOD book_in_grace.
assert_fine( iv_due = '20250101' iv_return = '20250108' iv_media = 'BOOK'
iv_days = 7 iv_charge = 0 iv_fine = '0.00' ).
ENDMETHOD.
METHOD book_over_grace.
assert_fine( iv_due = '20250101' iv_return = '20250109' iv_media = 'BOOK'
iv_days = 8 iv_charge = 1 iv_fine = '0.30' ).
ENDMETHOD.
METHOD dvd_in_grace.
assert_fine( iv_due = '20250101' iv_return = '20250103' iv_media = 'DVD'
iv_days = 2 iv_charge = 0 iv_fine = '0.00' ).
ENDMETHOD.
METHOD dvd_over_grace.
assert_fine( iv_due = '20250101' iv_return = '20250104' iv_media = 'DVD'
iv_days = 3 iv_charge = 1 iv_fine = '1.50' ).
ENDMETHOD.
METHOD game_no_grace.
assert_fine( iv_due = '20250101' iv_return = '20250102' iv_media = 'GAME'
iv_days = 1 iv_charge = 1 iv_fine = '2.50' ).
ENDMETHOD.
METHOD reminder_fee_added.
assert_fine( iv_due = '20250101' iv_return = '20250215' iv_media = 'BOOK'
iv_days = 45 iv_charge = 38 iv_fine = '16.40' ).
ENDMETHOD.
METHOD no_reminder_day_30.
assert_fine( iv_due = '20250101' iv_return = '20250131' iv_media = 'BOOK'
iv_days = 30 iv_charge = 23 iv_fine = '6.90' ).
ENDMETHOD.
METHOD fine_capped.
assert_fine( iv_due = '20250101' iv_return = '20250113' iv_media = 'GAME'
iv_days = 12 iv_charge = 12 iv_fine = '25.00' ).
ENDMETHOD.
METHOD cap_after_reminder.
assert_fine( iv_due = '20250101' iv_return = '20250201' iv_media = 'GAME'
iv_days = 31 iv_charge = 31 iv_fine = '25.00' ).
ENDMETHOD.
METHOD unknown_media_no_fine.
assert_fine( iv_due = '20250101' iv_return = '20250105' iv_media = 'TAPE'
iv_days = 4 iv_charge = 0 iv_fine = '0.00' ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,77 @@
{
"task": "G0103",
"mutants": [
{
"object": "{{P}}OVERDUE_FINE",
"mutant": "line 41: <= -> > (rel)",
"status": "killed",
"hidden": "0/11",
"failed_tests": [
"BOOK_IN_GRACE",
"BOOK_OVER_GRACE",
"CAP_AFTER_REMINDER",
"DVD_IN_GRACE",
"DVD_OVER_GRACE",
"FINE_CAPPED",
"GAME_NO_GRACE",
"NOT_LATE_NO_FINE",
"NO_REMINDER_DAY_30",
"REMINDER_FEE_ADDED",
"UNKNOWN_MEDIA_NO_FINE"
]
},
{
"object": "{{P}}OVERDUE_FINE",
"mutant": "line 51: - -> + (arith)",
"status": "killed",
"hidden": "5/11",
"failed_tests": [
"BOOK_IN_GRACE",
"BOOK_OVER_GRACE",
"DVD_IN_GRACE",
"DVD_OVER_GRACE",
"NO_REMINDER_DAY_30",
"REMINDER_FEE_ADDED"
]
},
{
"object": "{{P}}OVERDUE_FINE",
"mutant": "line 53: * -> / (arith)",
"status": "killed",
"hidden": "4/11",
"failed_tests": [
"BOOK_OVER_GRACE",
"CAP_AFTER_REMINDER",
"DVD_OVER_GRACE",
"FINE_CAPPED",
"GAME_NO_GRACE",
"NO_REMINDER_DAY_30",
"REMINDER_FEE_ADDED"
]
},
{
"object": "{{P}}OVERDUE_FINE",
"mutant": "line 55: + -> - (arith)",
"status": "killed",
"hidden": "10/11",
"failed_tests": [
"REMINDER_FEE_ADDED"
]
},
{
"object": "{{P}}OVERDUE_FINE",
"mutant": "line 63: 7 -> 8 (const)",
"status": "killed",
"hidden": "8/11",
"failed_tests": [
"BOOK_OVER_GRACE",
"NO_REMINDER_DAY_30",
"REMINDER_FEE_ADDED"
]
}
],
"valid": 5,
"killed": 5,
"kill_rate": 1.0,
"ok": true
}

View File

@@ -0,0 +1,68 @@
CLASS {{p}}overdue_fine DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_media TYPE c LENGTH 8.
TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2.
TYPES:
BEGIN OF ty_result,
days_overdue TYPE i,
chargeable_days TYPE i,
fine TYPE ty_amount,
END OF ty_result.
METHODS calculate
IMPORTING iv_due_date TYPE d
iv_return_date TYPE d
iv_media TYPE ty_media
RETURNING VALUE(rs_result) TYPE ty_result.
PRIVATE SECTION.
TYPES:
BEGIN OF ty_media_rule,
media TYPE ty_media,
rate TYPE ty_amount,
grace_days TYPE i,
END OF ty_media_rule,
tt_media_rule TYPE HASHED TABLE OF ty_media_rule WITH UNIQUE KEY media.
CONSTANTS:
c_max_fine TYPE ty_amount VALUE '25.00',
c_reminder_fee TYPE ty_amount VALUE '5.00',
c_reminder_day TYPE i VALUE 30.
METHODS media_rule
IMPORTING iv_media TYPE ty_media
RETURNING VALUE(rs_rule) TYPE ty_media_rule.
ENDCLASS.
CLASS {{p}}overdue_fine IMPLEMENTATION.
METHOD calculate.
rs_result-days_overdue = iv_return_date - iv_due_date.
IF rs_result-days_overdue <= 0.
CLEAR rs_result.
RETURN.
ENDIF.
DATA(ls_rule) = media_rule( iv_media ).
IF ls_rule IS INITIAL.
RETURN.
ENDIF.
rs_result-chargeable_days = nmax( val1 = rs_result-days_overdue - ls_rule-grace_days
val2 = 0 ).
rs_result-fine = rs_result-chargeable_days * ls_rule-rate.
IF rs_result-days_overdue > c_reminder_day.
rs_result-fine = rs_result-fine + c_reminder_fee.
ENDIF.
rs_result-fine = nmin( val1 = rs_result-fine
val2 = c_max_fine ).
ENDMETHOD.
METHOD media_rule.
DATA(lt_rules) = VALUE tt_media_rule(
( media = 'BOOK' rate = '0.30' grace_days = 7 )
( media = 'DVD' rate = '1.50' grace_days = 2 )
( media = 'GAME' rate = '2.50' grace_days = 0 ) ).
READ TABLE lt_rules INTO rs_rule WITH TABLE KEY media = iv_media.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,89 @@
CLASS ltc_overdue_fine DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA mo_cut TYPE REF TO {{p}}overdue_fine.
METHODS setup.
METHODS not_late_no_fine FOR TESTING.
METHODS book_in_grace FOR TESTING.
METHODS book_over_grace FOR TESTING.
METHODS dvd_over_grace FOR TESTING.
METHODS game_no_grace FOR TESTING.
METHODS reminder_fee FOR TESTING.
METHODS fine_is_capped FOR TESTING.
METHODS unknown_media FOR TESTING.
ENDCLASS.
CLASS ltc_overdue_fine IMPLEMENTATION.
METHOD setup.
mo_cut = NEW {{p}}overdue_fine( ).
ENDMETHOD.
METHOD not_late_no_fine.
DATA(ls_result) = mo_cut->calculate( iv_due_date = '20250110'
iv_return_date = '20250109'
iv_media = 'BOOK' ).
cl_abap_unit_assert=>assert_equals(
exp = CONV {{p}}overdue_fine=>ty_amount( '0.00' )
act = ls_result-fine ).
ENDMETHOD.
METHOD book_in_grace.
DATA(ls_result) = mo_cut->calculate( iv_due_date = '20250101'
iv_return_date = '20250108'
iv_media = 'BOOK' ).
cl_abap_unit_assert=>assert_equals( exp = 0 act = ls_result-chargeable_days ).
ENDMETHOD.
METHOD book_over_grace.
DATA(ls_result) = mo_cut->calculate( iv_due_date = '20250101'
iv_return_date = '20250109'
iv_media = 'BOOK' ).
cl_abap_unit_assert=>assert_equals(
exp = CONV {{p}}overdue_fine=>ty_amount( '0.30' )
act = ls_result-fine ).
ENDMETHOD.
METHOD dvd_over_grace.
DATA(ls_result) = mo_cut->calculate( iv_due_date = '20250101'
iv_return_date = '20250104'
iv_media = 'DVD' ).
cl_abap_unit_assert=>assert_equals(
exp = CONV {{p}}overdue_fine=>ty_amount( '1.50' )
act = ls_result-fine ).
ENDMETHOD.
METHOD game_no_grace.
DATA(ls_result) = mo_cut->calculate( iv_due_date = '20250101'
iv_return_date = '20250102'
iv_media = 'GAME' ).
cl_abap_unit_assert=>assert_equals(
exp = CONV {{p}}overdue_fine=>ty_amount( '2.50' )
act = ls_result-fine ).
ENDMETHOD.
METHOD reminder_fee.
DATA(ls_result) = mo_cut->calculate( iv_due_date = '20250101'
iv_return_date = '20250215'
iv_media = 'BOOK' ).
cl_abap_unit_assert=>assert_equals(
exp = CONV {{p}}overdue_fine=>ty_amount( '16.40' )
act = ls_result-fine ).
ENDMETHOD.
METHOD fine_is_capped.
DATA(ls_result) = mo_cut->calculate( iv_due_date = '20250101'
iv_return_date = '20250113'
iv_media = 'GAME' ).
cl_abap_unit_assert=>assert_equals(
exp = CONV {{p}}overdue_fine=>ty_amount( '25.00' )
act = ls_result-fine ).
ENDMETHOD.
METHOD unknown_media.
DATA(ls_result) = mo_cut->calculate( iv_due_date = '20250101'
iv_return_date = '20250105'
iv_media = 'TAPE' ).
cl_abap_unit_assert=>assert_equals( exp = 4 act = ls_result-days_overdue ).
cl_abap_unit_assert=>assert_equals( exp = 0 act = ls_result-chargeable_days ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,56 @@
# 1. Goal
Calculate the overdue fine of a returned library item. The lending desk calls the
calculation before it prints the receipt. The result gives the days overdue, the
chargeable days, and the fine.
# 2. Open questions
None.
# 3. Context
- Package $TMP contains no object for this task.
- The class is new. No other object is necessary.
# 4. Contract
- Create the class {{P}}OVERDUE_FINE in package $TMP.
- The class is public and final. You can create it with NEW {{P}}OVERDUE_FINE( )
without parameters.
- The class has these public types:
- TY_MEDIA: character field, length 8.
- TY_AMOUNT: packed number, length 8, 2 decimal places.
- TY_RESULT: structure with the components DAYS_OVERDUE (type i),
CHARGEABLE_DAYS (type i), and FINE (type TY_AMOUNT).
- The class has one public method:
CALCULATE
IMPORTING iv_due_date TYPE d
iv_return_date TYPE d
iv_media TYPE ty_media
RETURNING VALUE(rs_result) TYPE ty_result.
- Do not add other public methods or public components.
# 5. Business rules
Apply the rules in this sequence.
1. If iv_return_date is earlier than or equal to iv_due_date, return
DAYS_OVERDUE = 0, CHARGEABLE_DAYS = 0, and FINE = 0.00. Stop.
2. DAYS_OVERDUE is the number of calendar days from iv_due_date to iv_return_date.
3. The media code gives the daily rate and the grace days:
- BOOK: daily rate 0.30, grace 7 days
- DVD: daily rate 1.50, grace 2 days
- GAME: daily rate 2.50, grace 0 days
Compare the media code exactly. If the media code is not in this list, return
CHARGEABLE_DAYS = 0 and FINE = 0.00. Keep DAYS_OVERDUE from rule 2. Stop.
4. CHARGEABLE_DAYS is DAYS_OVERDUE minus the grace days. If this value is less
than 0, CHARGEABLE_DAYS is 0.
5. FINE is CHARGEABLE_DAYS multiplied by the daily rate.
6. If DAYS_OVERDUE is greater than 30, add a reminder fee of 5.00 to FINE.
7. If FINE is greater than 25.00, FINE is 25.00.
# 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: no other object.
# 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,41 @@
{
"id": "G0103",
"category": "A",
"object_type": "CLAS",
"difficulty": 2,
"release_target": "v816",
"expected_outcome": "implement",
"budget": {
"max_tool_calls": 40,
"max_activations": 10
},
"seed": [],
"contract": [
{
"type": "CLAS",
"name": "{{P}}OVERDUE_FINE"
}
],
"out_of_scope": [],
"hidden_tests": [
{
"type": "CLAS",
"name": "{{P}}T02_HIDDEN",
"file": "hidden/t02_hidden.clas.abap",
"description": "T02 hidden tests for the overdue fine calculation"
}
],
"reference": [
{
"type": "CLAS",
"name": "{{P}}OVERDUE_FINE",
"file": "reference/overdue_fine.clas.abap",
"description": "Overdue fine calculation for a library item",
"testclasses_file": "reference/overdue_fine.testclasses.abap"
}
],
"craft_checks": [
"method_length",
"db_operation_in_loop"
]
}

View File

@@ -0,0 +1,96 @@
CLASS {{p}}insurance_premium DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES:
ty_region TYPE c LENGTH 2,
ty_premium TYPE p LENGTH 8 DECIMALS 2.
METHODS calculate_premium
IMPORTING iv_age TYPE i
iv_power_kw TYPE i
iv_region TYPE ty_region
iv_claim_free_years TYPE i
RETURNING VALUE(rv_premium) TYPE ty_premium.
PRIVATE SECTION.
METHODS get_base_premium
IMPORTING iv_region TYPE ty_region
RETURNING VALUE(rv_base) TYPE ty_premium.
METHODS get_age_factor
IMPORTING iv_age TYPE i
RETURNING VALUE(rv_factor) TYPE decfloat34.
METHODS get_power_factor
IMPORTING iv_power_kw TYPE i
RETURNING VALUE(rv_factor) TYPE decfloat34.
METHODS get_discount_factor
IMPORTING iv_claim_free_years TYPE i
RETURNING VALUE(rv_factor) TYPE decfloat34.
ENDCLASS.
CLASS {{p}}insurance_premium IMPLEMENTATION.
METHOD calculate_premium.
IF iv_age < 18 OR iv_age > 99
AND iv_power_kw <= 0
OR iv_claim_free_years < 0.
rv_premium = 0.
RETURN.
ENDIF.
DATA(lv_base) = get_base_premium( iv_region ).
IF lv_base = 0.
rv_premium = 0.
RETURN.
ENDIF.
DATA(lv_premium) = CONV decfloat34( lv_base )
* get_age_factor( iv_age )
* get_power_factor( iv_power_kw )
* get_discount_factor( iv_claim_free_years ).
rv_premium = lv_premium.
IF rv_premium < 100.
rv_premium = 100.
ENDIF.
ENDMETHOD.
METHOD get_base_premium.
CASE iv_region.
WHEN 'A1'.
rv_base = 150.
WHEN 'B2'.
rv_base = 200.
WHEN 'C3'.
rv_base = 250.
WHEN 'D4'.
rv_base = 300.
WHEN 'E5'.
rv_base = 350.
WHEN OTHERS.
rv_base = 0.
ENDCASE.
ENDMETHOD.
METHOD get_age_factor.
IF iv_age < 25.
rv_factor = '1.5'.
ELSEIF iv_age > 65.
rv_factor = '1.2'.
ELSE.
rv_factor = '1.0'.
ENDIF.
ENDMETHOD.
METHOD get_power_factor.
IF iv_power_kw <= 50.
rv_factor = '0.9'.
ELSEIF iv_power_kw <= 100.
rv_factor = '1.0'.
ELSEIF iv_power_kw <= 150.
rv_factor = '1.3'.
ELSE.
rv_factor = '1.6'.
ENDIF.
ENDMETHOD.
METHOD get_discount_factor.
DATA(lv_discount) = iv_claim_free_years * 5.
IF lv_discount > 30.
lv_discount = 30.
ENDIF.
rv_factor = CONV decfloat34( 100 - lv_discount ) / 100.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,96 @@
CLASS {{p}}insurance_premium DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES:
ty_region TYPE c LENGTH 2,
ty_premium TYPE p LENGTH 8 DECIMALS 2.
METHODS calculate_premium
IMPORTING iv_age TYPE i
iv_power_kw TYPE i
iv_region TYPE ty_region
iv_claim_free_years TYPE i
RETURNING VALUE(rv_premium) TYPE ty_premium.
PRIVATE SECTION.
METHODS get_base_premium
IMPORTING iv_region TYPE ty_region
RETURNING VALUE(rv_base) TYPE ty_premium.
METHODS get_age_factor
IMPORTING iv_age TYPE i
RETURNING VALUE(rv_factor) TYPE decfloat34.
METHODS get_power_factor
IMPORTING iv_power_kw TYPE i
RETURNING VALUE(rv_factor) TYPE decfloat34.
METHODS get_discount_factor
IMPORTING iv_claim_free_years TYPE i
RETURNING VALUE(rv_factor) TYPE decfloat34.
ENDCLASS.
CLASS {{p}}insurance_premium IMPLEMENTATION.
METHOD calculate_premium.
IF iv_age < 18 OR iv_age > 99
OR iv_power_kw <= 0
OR iv_claim_free_years >= 0.
rv_premium = 0.
RETURN.
ENDIF.
DATA(lv_base) = get_base_premium( iv_region ).
IF lv_base = 0.
rv_premium = 0.
RETURN.
ENDIF.
DATA(lv_premium) = CONV decfloat34( lv_base )
* get_age_factor( iv_age )
* get_power_factor( iv_power_kw )
* get_discount_factor( iv_claim_free_years ).
rv_premium = lv_premium.
IF rv_premium < 100.
rv_premium = 100.
ENDIF.
ENDMETHOD.
METHOD get_base_premium.
CASE iv_region.
WHEN 'A1'.
rv_base = 150.
WHEN 'B2'.
rv_base = 200.
WHEN 'C3'.
rv_base = 250.
WHEN 'D4'.
rv_base = 300.
WHEN 'E5'.
rv_base = 350.
WHEN OTHERS.
rv_base = 0.
ENDCASE.
ENDMETHOD.
METHOD get_age_factor.
IF iv_age < 25.
rv_factor = '1.5'.
ELSEIF iv_age > 65.
rv_factor = '1.2'.
ELSE.
rv_factor = '1.0'.
ENDIF.
ENDMETHOD.
METHOD get_power_factor.
IF iv_power_kw <= 50.
rv_factor = '0.9'.
ELSEIF iv_power_kw <= 100.
rv_factor = '1.0'.
ELSEIF iv_power_kw <= 150.
rv_factor = '1.3'.
ELSE.
rv_factor = '1.6'.
ENDIF.
ENDMETHOD.
METHOD get_discount_factor.
DATA(lv_discount) = iv_claim_free_years * 5.
IF lv_discount > 30.
lv_discount = 30.
ENDIF.
rv_factor = CONV decfloat34( 100 - lv_discount ) / 100.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,96 @@
CLASS {{p}}insurance_premium DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES:
ty_region TYPE c LENGTH 2,
ty_premium TYPE p LENGTH 8 DECIMALS 2.
METHODS calculate_premium
IMPORTING iv_age TYPE i
iv_power_kw TYPE i
iv_region TYPE ty_region
iv_claim_free_years TYPE i
RETURNING VALUE(rv_premium) TYPE ty_premium.
PRIVATE SECTION.
METHODS get_base_premium
IMPORTING iv_region TYPE ty_region
RETURNING VALUE(rv_base) TYPE ty_premium.
METHODS get_age_factor
IMPORTING iv_age TYPE i
RETURNING VALUE(rv_factor) TYPE decfloat34.
METHODS get_power_factor
IMPORTING iv_power_kw TYPE i
RETURNING VALUE(rv_factor) TYPE decfloat34.
METHODS get_discount_factor
IMPORTING iv_claim_free_years TYPE i
RETURNING VALUE(rv_factor) TYPE decfloat34.
ENDCLASS.
CLASS {{p}}insurance_premium IMPLEMENTATION.
METHOD calculate_premium.
IF iv_age < 18 OR iv_age > 99
OR iv_power_kw <= 0
OR iv_claim_free_years < 0.
rv_premium = 0.
RETURN.
ENDIF.
DATA(lv_base) = get_base_premium( iv_region ).
IF lv_base <> 0.
rv_premium = 0.
RETURN.
ENDIF.
DATA(lv_premium) = CONV decfloat34( lv_base )
* get_age_factor( iv_age )
* get_power_factor( iv_power_kw )
* get_discount_factor( iv_claim_free_years ).
rv_premium = lv_premium.
IF rv_premium < 100.
rv_premium = 100.
ENDIF.
ENDMETHOD.
METHOD get_base_premium.
CASE iv_region.
WHEN 'A1'.
rv_base = 150.
WHEN 'B2'.
rv_base = 200.
WHEN 'C3'.
rv_base = 250.
WHEN 'D4'.
rv_base = 300.
WHEN 'E5'.
rv_base = 350.
WHEN OTHERS.
rv_base = 0.
ENDCASE.
ENDMETHOD.
METHOD get_age_factor.
IF iv_age < 25.
rv_factor = '1.5'.
ELSEIF iv_age > 65.
rv_factor = '1.2'.
ELSE.
rv_factor = '1.0'.
ENDIF.
ENDMETHOD.
METHOD get_power_factor.
IF iv_power_kw <= 50.
rv_factor = '0.9'.
ELSEIF iv_power_kw <= 100.
rv_factor = '1.0'.
ELSEIF iv_power_kw <= 150.
rv_factor = '1.3'.
ELSE.
rv_factor = '1.6'.
ENDIF.
ENDMETHOD.
METHOD get_discount_factor.
DATA(lv_discount) = iv_claim_free_years * 5.
IF lv_discount > 30.
lv_discount = 30.
ENDIF.
rv_factor = CONV decfloat34( 100 - lv_discount ) / 100.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,96 @@
CLASS {{p}}insurance_premium DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES:
ty_region TYPE c LENGTH 2,
ty_premium TYPE p LENGTH 8 DECIMALS 2.
METHODS calculate_premium
IMPORTING iv_age TYPE i
iv_power_kw TYPE i
iv_region TYPE ty_region
iv_claim_free_years TYPE i
RETURNING VALUE(rv_premium) TYPE ty_premium.
PRIVATE SECTION.
METHODS get_base_premium
IMPORTING iv_region TYPE ty_region
RETURNING VALUE(rv_base) TYPE ty_premium.
METHODS get_age_factor
IMPORTING iv_age TYPE i
RETURNING VALUE(rv_factor) TYPE decfloat34.
METHODS get_power_factor
IMPORTING iv_power_kw TYPE i
RETURNING VALUE(rv_factor) TYPE decfloat34.
METHODS get_discount_factor
IMPORTING iv_claim_free_years TYPE i
RETURNING VALUE(rv_factor) TYPE decfloat34.
ENDCLASS.
CLASS {{p}}insurance_premium IMPLEMENTATION.
METHOD calculate_premium.
IF iv_age < 18 OR iv_age > 99
OR iv_power_kw <= 0
OR iv_claim_free_years < 0.
rv_premium = 0.
RETURN.
ENDIF.
DATA(lv_base) = get_base_premium( iv_region ).
IF lv_base = 0.
rv_premium = 0.
RETURN.
ENDIF.
DATA(lv_premium) = CONV decfloat34( lv_base )
/ get_age_factor( iv_age )
* get_power_factor( iv_power_kw )
* get_discount_factor( iv_claim_free_years ).
rv_premium = lv_premium.
IF rv_premium < 100.
rv_premium = 100.
ENDIF.
ENDMETHOD.
METHOD get_base_premium.
CASE iv_region.
WHEN 'A1'.
rv_base = 150.
WHEN 'B2'.
rv_base = 200.
WHEN 'C3'.
rv_base = 250.
WHEN 'D4'.
rv_base = 300.
WHEN 'E5'.
rv_base = 350.
WHEN OTHERS.
rv_base = 0.
ENDCASE.
ENDMETHOD.
METHOD get_age_factor.
IF iv_age < 25.
rv_factor = '1.5'.
ELSEIF iv_age > 65.
rv_factor = '1.2'.
ELSE.
rv_factor = '1.0'.
ENDIF.
ENDMETHOD.
METHOD get_power_factor.
IF iv_power_kw <= 50.
rv_factor = '0.9'.
ELSEIF iv_power_kw <= 100.
rv_factor = '1.0'.
ELSEIF iv_power_kw <= 150.
rv_factor = '1.3'.
ELSE.
rv_factor = '1.6'.
ENDIF.
ENDMETHOD.
METHOD get_discount_factor.
DATA(lv_discount) = iv_claim_free_years * 5.
IF lv_discount > 30.
lv_discount = 30.
ENDIF.
rv_factor = CONV decfloat34( 100 - lv_discount ) / 100.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,96 @@
CLASS {{p}}insurance_premium DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES:
ty_region TYPE c LENGTH 2,
ty_premium TYPE p LENGTH 8 DECIMALS 2.
METHODS calculate_premium
IMPORTING iv_age TYPE i
iv_power_kw TYPE i
iv_region TYPE ty_region
iv_claim_free_years TYPE i
RETURNING VALUE(rv_premium) TYPE ty_premium.
PRIVATE SECTION.
METHODS get_base_premium
IMPORTING iv_region TYPE ty_region
RETURNING VALUE(rv_base) TYPE ty_premium.
METHODS get_age_factor
IMPORTING iv_age TYPE i
RETURNING VALUE(rv_factor) TYPE decfloat34.
METHODS get_power_factor
IMPORTING iv_power_kw TYPE i
RETURNING VALUE(rv_factor) TYPE decfloat34.
METHODS get_discount_factor
IMPORTING iv_claim_free_years TYPE i
RETURNING VALUE(rv_factor) TYPE decfloat34.
ENDCLASS.
CLASS {{p}}insurance_premium IMPLEMENTATION.
METHOD calculate_premium.
IF iv_age < 18 OR iv_age > 99
OR iv_power_kw <= 0
OR iv_claim_free_years < 0.
rv_premium = 0.
RETURN.
ENDIF.
DATA(lv_base) = get_base_premium( iv_region ).
IF lv_base = 0.
rv_premium = 0.
RETURN.
ENDIF.
DATA(lv_premium) = CONV decfloat34( lv_base )
* get_age_factor( iv_age )
* get_power_factor( iv_power_kw )
* get_discount_factor( iv_claim_free_years ).
rv_premium = lv_premium.
IF rv_premium < 100.
rv_premium = 100.
ENDIF.
ENDMETHOD.
METHOD get_base_premium.
CASE iv_region.
WHEN 'A1'.
rv_base = 150.
WHEN 'B2'.
rv_base = 200.
WHEN 'C3'.
rv_base = 250.
WHEN 'D4'.
rv_base = 300.
WHEN 'E5'.
rv_base = 350.
WHEN OTHERS.
rv_base = 0.
ENDCASE.
ENDMETHOD.
METHOD get_age_factor.
IF iv_age < 25.
rv_factor = '1.5'.
ELSEIF iv_age > 65.
rv_factor = '1.2'.
ELSE.
rv_factor = '1.0'.
ENDIF.
ENDMETHOD.
METHOD get_power_factor.
IF iv_power_kw <= 50.
rv_factor = '0.9'.
ELSEIF iv_power_kw <= 100.
rv_factor = '1.0'.
ELSEIF iv_power_kw <= 150.
rv_factor = '1.3'.
ELSE.
rv_factor = '1.6'.
ENDIF.
ENDMETHOD.
METHOD get_discount_factor.
DATA(lv_discount) = iv_claim_free_years * 5.
IF lv_discount > 30.
lv_discount = 30.
ENDIF.
rv_factor = CONV decfloat34( 101 - lv_discount ) / 100.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,24 @@
{
"id": "G0104",
"pool": "eval",
"object_type": "CLAS",
"category": "A",
"attempts": [
{
"stage": "validate",
"oracle": 91.0,
"null": 0
},
{
"stage": "validate",
"oracle": 100.0,
"null": 0,
"mutation": {
"valid": 5,
"killed": 5,
"ok": true
}
}
],
"accepted": true
}

View File

@@ -0,0 +1,111 @@
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}}insurance_premium.
METHODS setup.
METHODS standard_premium FOR TESTING.
METHODS young_driver FOR TESTING.
METHODS senior_driver FOR TESTING.
METHODS high_power FOR TESTING.
METHODS very_high_power FOR TESTING.
METHODS low_power FOR TESTING.
METHODS claim_free_discount FOR TESTING.
METHODS claim_free_capped FOR TESTING.
METHODS minimum_premium FOR TESTING.
METHODS all_regions FOR TESTING.
METHODS invalid_region FOR TESTING.
METHODS invalid_inputs FOR TESTING.
ENDCLASS.
CLASS {{p}}t02_hidden IMPLEMENTATION.
METHOD setup.
mo_cut = NEW {{p}}insurance_premium( ).
ENDMETHOD.
METHOD standard_premium.
cl_abap_unit_assert=>assert_equals(
exp = 150
act = mo_cut->calculate_premium( iv_age = 30 iv_power_kw = 80 iv_region = 'A1' iv_claim_free_years = 0 ) ).
ENDMETHOD.
METHOD young_driver.
cl_abap_unit_assert=>assert_equals(
exp = 225
act = mo_cut->calculate_premium( iv_age = 22 iv_power_kw = 80 iv_region = 'A1' iv_claim_free_years = 0 ) ).
ENDMETHOD.
METHOD senior_driver.
cl_abap_unit_assert=>assert_equals(
exp = 180
act = mo_cut->calculate_premium( iv_age = 70 iv_power_kw = 80 iv_region = 'A1' iv_claim_free_years = 0 ) ).
ENDMETHOD.
METHOD high_power.
cl_abap_unit_assert=>assert_equals(
exp = 195
act = mo_cut->calculate_premium( iv_age = 30 iv_power_kw = 120 iv_region = 'A1' iv_claim_free_years = 0 ) ).
ENDMETHOD.
METHOD very_high_power.
cl_abap_unit_assert=>assert_equals(
exp = 240
act = mo_cut->calculate_premium( iv_age = 30 iv_power_kw = 200 iv_region = 'A1' iv_claim_free_years = 0 ) ).
ENDMETHOD.
METHOD low_power.
cl_abap_unit_assert=>assert_equals(
exp = 135
act = mo_cut->calculate_premium( iv_age = 30 iv_power_kw = 40 iv_region = 'A1' iv_claim_free_years = 0 ) ).
ENDMETHOD.
METHOD claim_free_discount.
cl_abap_unit_assert=>assert_equals(
exp = 180
act = mo_cut->calculate_premium( iv_age = 30 iv_power_kw = 80 iv_region = 'B2' iv_claim_free_years = 2 ) ).
ENDMETHOD.
METHOD claim_free_capped.
cl_abap_unit_assert=>assert_equals(
exp = 140
act = mo_cut->calculate_premium( iv_age = 30 iv_power_kw = 80 iv_region = 'B2' iv_claim_free_years = 10 ) ).
ENDMETHOD.
METHOD minimum_premium.
cl_abap_unit_assert=>assert_equals(
exp = 100
act = mo_cut->calculate_premium( iv_age = 25 iv_power_kw = 50 iv_region = 'A1' iv_claim_free_years = 6 ) ).
ENDMETHOD.
METHOD all_regions.
cl_abap_unit_assert=>assert_equals(
exp = 250 msg = 'C3'
act = mo_cut->calculate_premium( iv_age = 30 iv_power_kw = 80 iv_region = 'C3' iv_claim_free_years = 0 ) ).
cl_abap_unit_assert=>assert_equals(
exp = 300 msg = 'D4'
act = mo_cut->calculate_premium( iv_age = 30 iv_power_kw = 80 iv_region = 'D4' iv_claim_free_years = 0 ) ).
cl_abap_unit_assert=>assert_equals(
exp = 350 msg = 'E5'
act = mo_cut->calculate_premium( iv_age = 30 iv_power_kw = 80 iv_region = 'E5' iv_claim_free_years = 0 ) ).
ENDMETHOD.
METHOD invalid_region.
cl_abap_unit_assert=>assert_equals(
exp = 0
act = mo_cut->calculate_premium( iv_age = 30 iv_power_kw = 80 iv_region = 'X9' iv_claim_free_years = 0 ) ).
ENDMETHOD.
METHOD invalid_inputs.
cl_abap_unit_assert=>assert_equals(
exp = 0 msg = 'age too low'
act = mo_cut->calculate_premium( iv_age = 17 iv_power_kw = 80 iv_region = 'A1' iv_claim_free_years = 0 ) ).
cl_abap_unit_assert=>assert_equals(
exp = 0 msg = 'age too high'
act = mo_cut->calculate_premium( iv_age = 100 iv_power_kw = 80 iv_region = 'A1' iv_claim_free_years = 0 ) ).
cl_abap_unit_assert=>assert_equals(
exp = 0 msg = 'power too low'
act = mo_cut->calculate_premium( iv_age = 30 iv_power_kw = 0 iv_region = 'A1' iv_claim_free_years = 0 ) ).
cl_abap_unit_assert=>assert_equals(
exp = 0 msg = 'negative claim free years'
act = mo_cut->calculate_premium( iv_age = 30 iv_power_kw = 80 iv_region = 'A1' iv_claim_free_years = -1 ) ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,83 @@
{
"task": "G0104",
"mutants": [
{
"object": "{{P}}INSURANCE_PREMIUM",
"mutant": "line 30: OR -> AND (logic)",
"status": "killed",
"hidden": "11/12",
"failed_tests": [
"INVALID_INPUTS"
]
},
{
"object": "{{P}}INSURANCE_PREMIUM",
"mutant": "line 31: < -> >= (rel)",
"status": "killed",
"hidden": "1/12",
"failed_tests": [
"ALL_REGIONS",
"CLAIM_FREE_CAPPED",
"CLAIM_FREE_DISCOUNT",
"HIGH_POWER",
"INVALID_INPUTS",
"LOW_POWER",
"MINIMUM_PREMIUM",
"SENIOR_DRIVER",
"STANDARD_PREMIUM",
"VERY_HIGH_POWER",
"YOUNG_DRIVER"
]
},
{
"object": "{{P}}INSURANCE_PREMIUM",
"mutant": "line 36: = -> <> (eq)",
"status": "killed",
"hidden": "1/12",
"failed_tests": [
"ALL_REGIONS",
"CLAIM_FREE_CAPPED",
"CLAIM_FREE_DISCOUNT",
"HIGH_POWER",
"INVALID_REGION",
"LOW_POWER",
"MINIMUM_PREMIUM",
"SENIOR_DRIVER",
"STANDARD_PREMIUM",
"VERY_HIGH_POWER",
"YOUNG_DRIVER"
]
},
{
"object": "{{P}}INSURANCE_PREMIUM",
"mutant": "line 41: * -> / (arith)",
"status": "killed",
"hidden": "10/12",
"failed_tests": [
"SENIOR_DRIVER",
"YOUNG_DRIVER"
]
},
{
"object": "{{P}}INSURANCE_PREMIUM",
"mutant": "line 94: 100 -> 101 (const)",
"status": "killed",
"hidden": "3/12",
"failed_tests": [
"ALL_REGIONS",
"CLAIM_FREE_CAPPED",
"CLAIM_FREE_DISCOUNT",
"HIGH_POWER",
"LOW_POWER",
"SENIOR_DRIVER",
"STANDARD_PREMIUM",
"VERY_HIGH_POWER",
"YOUNG_DRIVER"
]
}
],
"valid": 5,
"killed": 5,
"kill_rate": 1.0,
"ok": true
}

View File

@@ -0,0 +1,96 @@
CLASS {{p}}insurance_premium DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES:
ty_region TYPE c LENGTH 2,
ty_premium TYPE p LENGTH 8 DECIMALS 2.
METHODS calculate_premium
IMPORTING iv_age TYPE i
iv_power_kw TYPE i
iv_region TYPE ty_region
iv_claim_free_years TYPE i
RETURNING VALUE(rv_premium) TYPE ty_premium.
PRIVATE SECTION.
METHODS get_base_premium
IMPORTING iv_region TYPE ty_region
RETURNING VALUE(rv_base) TYPE ty_premium.
METHODS get_age_factor
IMPORTING iv_age TYPE i
RETURNING VALUE(rv_factor) TYPE decfloat34.
METHODS get_power_factor
IMPORTING iv_power_kw TYPE i
RETURNING VALUE(rv_factor) TYPE decfloat34.
METHODS get_discount_factor
IMPORTING iv_claim_free_years TYPE i
RETURNING VALUE(rv_factor) TYPE decfloat34.
ENDCLASS.
CLASS {{p}}insurance_premium IMPLEMENTATION.
METHOD calculate_premium.
IF iv_age < 18 OR iv_age > 99
OR iv_power_kw <= 0
OR iv_claim_free_years < 0.
rv_premium = 0.
RETURN.
ENDIF.
DATA(lv_base) = get_base_premium( iv_region ).
IF lv_base = 0.
rv_premium = 0.
RETURN.
ENDIF.
DATA(lv_premium) = CONV decfloat34( lv_base )
* get_age_factor( iv_age )
* get_power_factor( iv_power_kw )
* get_discount_factor( iv_claim_free_years ).
rv_premium = lv_premium.
IF rv_premium < 100.
rv_premium = 100.
ENDIF.
ENDMETHOD.
METHOD get_base_premium.
CASE iv_region.
WHEN 'A1'.
rv_base = 150.
WHEN 'B2'.
rv_base = 200.
WHEN 'C3'.
rv_base = 250.
WHEN 'D4'.
rv_base = 300.
WHEN 'E5'.
rv_base = 350.
WHEN OTHERS.
rv_base = 0.
ENDCASE.
ENDMETHOD.
METHOD get_age_factor.
IF iv_age < 25.
rv_factor = '1.5'.
ELSEIF iv_age > 65.
rv_factor = '1.2'.
ELSE.
rv_factor = '1.0'.
ENDIF.
ENDMETHOD.
METHOD get_power_factor.
IF iv_power_kw <= 50.
rv_factor = '0.9'.
ELSEIF iv_power_kw <= 100.
rv_factor = '1.0'.
ELSEIF iv_power_kw <= 150.
rv_factor = '1.3'.
ELSE.
rv_factor = '1.6'.
ENDIF.
ENDMETHOD.
METHOD get_discount_factor.
DATA(lv_discount) = iv_claim_free_years * 5.
IF lv_discount > 30.
lv_discount = 30.
ENDIF.
rv_factor = CONV decfloat34( 100 - lv_discount ) / 100.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,110 @@
CLASS ltc_insurance_premium DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA mo_cut TYPE REF TO {{p}}insurance_premium.
METHODS setup.
METHODS standard_premium FOR TESTING.
METHODS young_driver FOR TESTING.
METHODS senior_driver FOR TESTING.
METHODS high_power FOR TESTING.
METHODS very_high_power FOR TESTING.
METHODS low_power FOR TESTING.
METHODS claim_free_discount FOR TESTING.
METHODS claim_free_capped FOR TESTING.
METHODS minimum_premium FOR TESTING.
METHODS all_regions FOR TESTING.
METHODS invalid_region FOR TESTING.
METHODS invalid_inputs FOR TESTING.
ENDCLASS.
CLASS ltc_insurance_premium IMPLEMENTATION.
METHOD setup.
mo_cut = NEW {{p}}insurance_premium( ).
ENDMETHOD.
METHOD standard_premium.
cl_abap_unit_assert=>assert_equals(
exp = 150
act = mo_cut->calculate_premium( iv_age = 30 iv_power_kw = 80 iv_region = 'A1' iv_claim_free_years = 0 ) ).
ENDMETHOD.
METHOD young_driver.
cl_abap_unit_assert=>assert_equals(
exp = 225
act = mo_cut->calculate_premium( iv_age = 22 iv_power_kw = 80 iv_region = 'A1' iv_claim_free_years = 0 ) ).
ENDMETHOD.
METHOD senior_driver.
cl_abap_unit_assert=>assert_equals(
exp = 180
act = mo_cut->calculate_premium( iv_age = 70 iv_power_kw = 80 iv_region = 'A1' iv_claim_free_years = 0 ) ).
ENDMETHOD.
METHOD high_power.
cl_abap_unit_assert=>assert_equals(
exp = 195
act = mo_cut->calculate_premium( iv_age = 30 iv_power_kw = 120 iv_region = 'A1' iv_claim_free_years = 0 ) ).
ENDMETHOD.
METHOD very_high_power.
cl_abap_unit_assert=>assert_equals(
exp = 240
act = mo_cut->calculate_premium( iv_age = 30 iv_power_kw = 200 iv_region = 'A1' iv_claim_free_years = 0 ) ).
ENDMETHOD.
METHOD low_power.
cl_abap_unit_assert=>assert_equals(
exp = 135
act = mo_cut->calculate_premium( iv_age = 30 iv_power_kw = 40 iv_region = 'A1' iv_claim_free_years = 0 ) ).
ENDMETHOD.
METHOD claim_free_discount.
cl_abap_unit_assert=>assert_equals(
exp = 180
act = mo_cut->calculate_premium( iv_age = 30 iv_power_kw = 80 iv_region = 'B2' iv_claim_free_years = 2 ) ).
ENDMETHOD.
METHOD claim_free_capped.
cl_abap_unit_assert=>assert_equals(
exp = 140
act = mo_cut->calculate_premium( iv_age = 30 iv_power_kw = 80 iv_region = 'B2' iv_claim_free_years = 10 ) ).
ENDMETHOD.
METHOD minimum_premium.
cl_abap_unit_assert=>assert_equals(
exp = 100
act = mo_cut->calculate_premium( iv_age = 25 iv_power_kw = 50 iv_region = 'A1' iv_claim_free_years = 6 ) ).
ENDMETHOD.
METHOD all_regions.
cl_abap_unit_assert=>assert_equals(
exp = 250 msg = 'C3'
act = mo_cut->calculate_premium( iv_age = 30 iv_power_kw = 80 iv_region = 'C3' iv_claim_free_years = 0 ) ).
cl_abap_unit_assert=>assert_equals(
exp = 300 msg = 'D4'
act = mo_cut->calculate_premium( iv_age = 30 iv_power_kw = 80 iv_region = 'D4' iv_claim_free_years = 0 ) ).
cl_abap_unit_assert=>assert_equals(
exp = 350 msg = 'E5'
act = mo_cut->calculate_premium( iv_age = 30 iv_power_kw = 80 iv_region = 'E5' iv_claim_free_years = 0 ) ).
ENDMETHOD.
METHOD invalid_region.
cl_abap_unit_assert=>assert_equals(
exp = 0
act = mo_cut->calculate_premium( iv_age = 30 iv_power_kw = 80 iv_region = 'X9' iv_claim_free_years = 0 ) ).
ENDMETHOD.
METHOD invalid_inputs.
cl_abap_unit_assert=>assert_equals(
exp = 0 msg = 'age too low'
act = mo_cut->calculate_premium( iv_age = 17 iv_power_kw = 80 iv_region = 'A1' iv_claim_free_years = 0 ) ).
cl_abap_unit_assert=>assert_equals(
exp = 0 msg = 'age too high'
act = mo_cut->calculate_premium( iv_age = 100 iv_power_kw = 80 iv_region = 'A1' iv_claim_free_years = 0 ) ).
cl_abap_unit_assert=>assert_equals(
exp = 0 msg = 'power too low'
act = mo_cut->calculate_premium( iv_age = 30 iv_power_kw = 0 iv_region = 'A1' iv_claim_free_years = 0 ) ).
cl_abap_unit_assert=>assert_equals(
exp = 0 msg = 'negative claim free years'
act = mo_cut->calculate_premium( iv_age = 30 iv_power_kw = 80 iv_region = 'A1' iv_claim_free_years = -1 ) ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,63 @@
# 1. Goal
Calculate the annual premium of a car insurance policy. An insurance program calls the calculation before it sends an offer to a customer. The program needs one premium for each policy.
# 2. Open questions
None.
# 3. Context
- Package $TMP.
- No other objects are required.
# 4. Contract
- Create the class {{P}}INSURANCE_PREMIUM in package $TMP.
- The class is public, final, and has a public constructor without parameters.
- The class has the public type TY_REGION (CHAR 2) and TY_PREMIUM (P LENGTH 8 DECIMALS 2).
- The class has one public method:
CALCULATE_PREMIUM
IMPORTING
iv_age TYPE i
iv_power_kw TYPE i
iv_region TYPE ty_region
iv_claim_free_years TYPE i
RETURNING
VALUE(rv_premium) TYPE ty_premium.
- Do not add other public methods.
# 5. Business rules
Apply the rules in this sequence.
1. Validate the inputs:
- iv_age must be between 18 and 99.
- iv_power_kw must be greater than 0.
- iv_claim_free_years must not be negative.
- iv_region must be one of the known regions (see rule 2).
If any check fails, return 0.
2. The base premium depends on the region:
A1: 150, B2: 200, C3: 250, D4: 300, E5: 350.
3. The age factor:
- age < 25: 1.5
- 25 <= age <= 65: 1.0
- age > 65: 1.2
4. The power factor:
- power <= 50 kW: 0.9
- 51 <= power <= 100 kW: 1.0
- 101 <= power <= 150 kW: 1.3
- power > 150 kW: 1.6
5. The claim-free discount:
- Each claim-free year gives a 5% discount.
- The maximum discount is 30%.
- The discount factor is 1 minus the discount (e.g., 0 claim-free years: 1.0, 6 or more: 0.7).
6. Calculate the premium:
premium = base premium * age factor * power factor * discount factor.
Calculate with full precision and round the final result to 2 decimals.
7. If the rounded premium is less than 100, return 100.
8. Else return the rounded premium.
# 6. Constraints
- Release target: 7.58.
- Coding standards: Clean ABAP. Method length below 40 statements. No global variables. No comment that restates the code. One statement per line.
- Out of scope: do not create 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,40 @@
{
"id": "G0104",
"category": "A",
"object_type": "CLAS",
"difficulty": 2,
"release_target": "v758",
"expected_outcome": "implement",
"budget": {
"max_tool_calls": 40,
"max_activations": 10
},
"seed": [],
"contract": [
{
"type": "CLAS",
"name": "{{P}}INSURANCE_PREMIUM"
}
],
"out_of_scope": [],
"hidden_tests": [
{
"type": "CLAS",
"name": "{{P}}T02_HIDDEN",
"file": "hidden/t02_hidden.clas.abap",
"description": "T02 hidden tests"
}
],
"reference": [
{
"type": "CLAS",
"name": "{{P}}INSURANCE_PREMIUM",
"file": "reference/insurance_premium.clas.abap",
"description": "Insurance premium calculator",
"testclasses_file": "reference/insurance_premium.testclasses.abap"
}
],
"craft_checks": [
"method_length"
]
}

View File

@@ -0,0 +1,100 @@
CLASS {{p}}toll_calc DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
METHODS calculate
IMPORTING iv_distance_km TYPE decfloat34
iv_weight_class TYPE i
iv_axles TYPE i
RETURNING VALUE(rv_fee) TYPE decfloat34
RAISING cx_abap_invalid_value.
PRIVATE SECTION.
CONSTANTS c_percent TYPE decfloat34 VALUE '100'.
CONSTANTS c_min_fee TYPE decfloat34 VALUE '1.00'.
CONSTANTS:
BEGIN OF c_rate,
class_1 TYPE decfloat34 VALUE '0.10',
class_2 TYPE decfloat34 VALUE '0.14',
class_3 TYPE decfloat34 VALUE '0.18',
class_4 TYPE decfloat34 VALUE '0.22',
END OF c_rate.
CONSTANTS:
BEGIN OF c_surcharge,
axles_2 TYPE decfloat34 VALUE '0',
axles_3 TYPE decfloat34 VALUE '5',
axles_4 TYPE decfloat34 VALUE '10',
axles_5 TYPE decfloat34 VALUE '15',
END OF c_surcharge.
METHODS check_input
IMPORTING iv_distance_km TYPE decfloat34
iv_weight_class TYPE i
iv_axles TYPE i
RAISING cx_abap_invalid_value.
METHODS base_rate
IMPORTING iv_weight_class TYPE i
RETURNING VALUE(rv_rate) TYPE decfloat34.
METHODS surcharge
IMPORTING iv_axles TYPE i
RETURNING VALUE(rv_percent) TYPE decfloat34.
ENDCLASS.
CLASS {{p}}toll_calc IMPLEMENTATION.
METHOD calculate.
check_input(
iv_distance_km = iv_distance_km
iv_weight_class = iv_weight_class
iv_axles = iv_axles ).
DATA(lv_amount) = iv_distance_km * base_rate( iv_weight_class ).
lv_amount = lv_amount * ( c_percent - surcharge( iv_axles ) ) / c_percent.
rv_fee = round( val = lv_amount dec = 2 mode = cl_abap_math=>round_half_up ).
IF rv_fee < c_min_fee.
rv_fee = c_min_fee.
ENDIF.
ENDMETHOD.
METHOD check_input.
IF iv_distance_km < 0.
RAISE EXCEPTION NEW cx_abap_invalid_value( ).
ENDIF.
IF iv_weight_class < 1 OR iv_weight_class > 4.
RAISE EXCEPTION NEW cx_abap_invalid_value( ).
ENDIF.
IF iv_axles < 2 OR iv_axles > 5.
RAISE EXCEPTION NEW cx_abap_invalid_value( ).
ENDIF.
ENDMETHOD.
METHOD base_rate.
CASE iv_weight_class.
WHEN 1.
rv_rate = c_rate-class_1.
WHEN 2.
rv_rate = c_rate-class_2.
WHEN 3.
rv_rate = c_rate-class_3.
WHEN 4.
rv_rate = c_rate-class_4.
WHEN OTHERS.
rv_rate = 0.
ENDCASE.
ENDMETHOD.
METHOD surcharge.
CASE iv_axles.
WHEN 2.
rv_percent = c_surcharge-axles_2.
WHEN 3.
rv_percent = c_surcharge-axles_3.
WHEN 4.
rv_percent = c_surcharge-axles_4.
WHEN 5.
rv_percent = c_surcharge-axles_5.
WHEN OTHERS.
rv_percent = 0.
ENDCASE.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,100 @@
CLASS {{p}}toll_calc DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
METHODS calculate
IMPORTING iv_distance_km TYPE decfloat34
iv_weight_class TYPE i
iv_axles TYPE i
RETURNING VALUE(rv_fee) TYPE decfloat34
RAISING cx_abap_invalid_value.
PRIVATE SECTION.
CONSTANTS c_percent TYPE decfloat34 VALUE '100'.
CONSTANTS c_min_fee TYPE decfloat34 VALUE '1.00'.
CONSTANTS:
BEGIN OF c_rate,
class_1 TYPE decfloat34 VALUE '0.10',
class_2 TYPE decfloat34 VALUE '0.14',
class_3 TYPE decfloat34 VALUE '0.18',
class_4 TYPE decfloat34 VALUE '0.22',
END OF c_rate.
CONSTANTS:
BEGIN OF c_surcharge,
axles_2 TYPE decfloat34 VALUE '0',
axles_3 TYPE decfloat34 VALUE '5',
axles_4 TYPE decfloat34 VALUE '10',
axles_5 TYPE decfloat34 VALUE '15',
END OF c_surcharge.
METHODS check_input
IMPORTING iv_distance_km TYPE decfloat34
iv_weight_class TYPE i
iv_axles TYPE i
RAISING cx_abap_invalid_value.
METHODS base_rate
IMPORTING iv_weight_class TYPE i
RETURNING VALUE(rv_rate) TYPE decfloat34.
METHODS surcharge
IMPORTING iv_axles TYPE i
RETURNING VALUE(rv_percent) TYPE decfloat34.
ENDCLASS.
CLASS {{p}}toll_calc IMPLEMENTATION.
METHOD calculate.
check_input(
iv_distance_km = iv_distance_km
iv_weight_class = iv_weight_class
iv_axles = iv_axles ).
DATA(lv_amount) = iv_distance_km * base_rate( iv_weight_class ).
lv_amount = lv_amount * ( c_percent + surcharge( iv_axles ) ) / c_percent.
rv_fee = round( val = lv_amount dec = 3 mode = cl_abap_math=>round_half_up ).
IF rv_fee < c_min_fee.
rv_fee = c_min_fee.
ENDIF.
ENDMETHOD.
METHOD check_input.
IF iv_distance_km < 0.
RAISE EXCEPTION NEW cx_abap_invalid_value( ).
ENDIF.
IF iv_weight_class < 1 OR iv_weight_class > 4.
RAISE EXCEPTION NEW cx_abap_invalid_value( ).
ENDIF.
IF iv_axles < 2 OR iv_axles > 5.
RAISE EXCEPTION NEW cx_abap_invalid_value( ).
ENDIF.
ENDMETHOD.
METHOD base_rate.
CASE iv_weight_class.
WHEN 1.
rv_rate = c_rate-class_1.
WHEN 2.
rv_rate = c_rate-class_2.
WHEN 3.
rv_rate = c_rate-class_3.
WHEN 4.
rv_rate = c_rate-class_4.
WHEN OTHERS.
rv_rate = 0.
ENDCASE.
ENDMETHOD.
METHOD surcharge.
CASE iv_axles.
WHEN 2.
rv_percent = c_surcharge-axles_2.
WHEN 3.
rv_percent = c_surcharge-axles_3.
WHEN 4.
rv_percent = c_surcharge-axles_4.
WHEN 5.
rv_percent = c_surcharge-axles_5.
WHEN OTHERS.
rv_percent = 0.
ENDCASE.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,100 @@
CLASS {{p}}toll_calc DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
METHODS calculate
IMPORTING iv_distance_km TYPE decfloat34
iv_weight_class TYPE i
iv_axles TYPE i
RETURNING VALUE(rv_fee) TYPE decfloat34
RAISING cx_abap_invalid_value.
PRIVATE SECTION.
CONSTANTS c_percent TYPE decfloat34 VALUE '100'.
CONSTANTS c_min_fee TYPE decfloat34 VALUE '1.00'.
CONSTANTS:
BEGIN OF c_rate,
class_1 TYPE decfloat34 VALUE '0.10',
class_2 TYPE decfloat34 VALUE '0.14',
class_3 TYPE decfloat34 VALUE '0.18',
class_4 TYPE decfloat34 VALUE '0.22',
END OF c_rate.
CONSTANTS:
BEGIN OF c_surcharge,
axles_2 TYPE decfloat34 VALUE '0',
axles_3 TYPE decfloat34 VALUE '5',
axles_4 TYPE decfloat34 VALUE '10',
axles_5 TYPE decfloat34 VALUE '15',
END OF c_surcharge.
METHODS check_input
IMPORTING iv_distance_km TYPE decfloat34
iv_weight_class TYPE i
iv_axles TYPE i
RAISING cx_abap_invalid_value.
METHODS base_rate
IMPORTING iv_weight_class TYPE i
RETURNING VALUE(rv_rate) TYPE decfloat34.
METHODS surcharge
IMPORTING iv_axles TYPE i
RETURNING VALUE(rv_percent) TYPE decfloat34.
ENDCLASS.
CLASS {{p}}toll_calc IMPLEMENTATION.
METHOD calculate.
check_input(
iv_distance_km = iv_distance_km
iv_weight_class = iv_weight_class
iv_axles = iv_axles ).
DATA(lv_amount) = iv_distance_km * base_rate( iv_weight_class ).
lv_amount = lv_amount * ( c_percent + surcharge( iv_axles ) ) / c_percent.
rv_fee = round( val = lv_amount dec = 2 mode = cl_abap_math=>round_half_up ).
IF rv_fee >= c_min_fee.
rv_fee = c_min_fee.
ENDIF.
ENDMETHOD.
METHOD check_input.
IF iv_distance_km < 0.
RAISE EXCEPTION NEW cx_abap_invalid_value( ).
ENDIF.
IF iv_weight_class < 1 OR iv_weight_class > 4.
RAISE EXCEPTION NEW cx_abap_invalid_value( ).
ENDIF.
IF iv_axles < 2 OR iv_axles > 5.
RAISE EXCEPTION NEW cx_abap_invalid_value( ).
ENDIF.
ENDMETHOD.
METHOD base_rate.
CASE iv_weight_class.
WHEN 1.
rv_rate = c_rate-class_1.
WHEN 2.
rv_rate = c_rate-class_2.
WHEN 3.
rv_rate = c_rate-class_3.
WHEN 4.
rv_rate = c_rate-class_4.
WHEN OTHERS.
rv_rate = 0.
ENDCASE.
ENDMETHOD.
METHOD surcharge.
CASE iv_axles.
WHEN 2.
rv_percent = c_surcharge-axles_2.
WHEN 3.
rv_percent = c_surcharge-axles_3.
WHEN 4.
rv_percent = c_surcharge-axles_4.
WHEN 5.
rv_percent = c_surcharge-axles_5.
WHEN OTHERS.
rv_percent = 0.
ENDCASE.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,100 @@
CLASS {{p}}toll_calc DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
METHODS calculate
IMPORTING iv_distance_km TYPE decfloat34
iv_weight_class TYPE i
iv_axles TYPE i
RETURNING VALUE(rv_fee) TYPE decfloat34
RAISING cx_abap_invalid_value.
PRIVATE SECTION.
CONSTANTS c_percent TYPE decfloat34 VALUE '100'.
CONSTANTS c_min_fee TYPE decfloat34 VALUE '1.00'.
CONSTANTS:
BEGIN OF c_rate,
class_1 TYPE decfloat34 VALUE '0.10',
class_2 TYPE decfloat34 VALUE '0.14',
class_3 TYPE decfloat34 VALUE '0.18',
class_4 TYPE decfloat34 VALUE '0.22',
END OF c_rate.
CONSTANTS:
BEGIN OF c_surcharge,
axles_2 TYPE decfloat34 VALUE '0',
axles_3 TYPE decfloat34 VALUE '5',
axles_4 TYPE decfloat34 VALUE '10',
axles_5 TYPE decfloat34 VALUE '15',
END OF c_surcharge.
METHODS check_input
IMPORTING iv_distance_km TYPE decfloat34
iv_weight_class TYPE i
iv_axles TYPE i
RAISING cx_abap_invalid_value.
METHODS base_rate
IMPORTING iv_weight_class TYPE i
RETURNING VALUE(rv_rate) TYPE decfloat34.
METHODS surcharge
IMPORTING iv_axles TYPE i
RETURNING VALUE(rv_percent) TYPE decfloat34.
ENDCLASS.
CLASS {{p}}toll_calc IMPLEMENTATION.
METHOD calculate.
check_input(
iv_distance_km = iv_distance_km
iv_weight_class = iv_weight_class
iv_axles = iv_axles ).
DATA(lv_amount) = iv_distance_km * base_rate( iv_weight_class ).
lv_amount = lv_amount * ( c_percent + surcharge( iv_axles ) ) / c_percent.
rv_fee = round( val = lv_amount dec = 2 mode = cl_abap_math=>round_half_up ).
IF rv_fee < c_min_fee.
rv_fee = c_min_fee.
ENDIF.
ENDMETHOD.
METHOD check_input.
IF iv_distance_km < 0.
RAISE EXCEPTION NEW cx_abap_invalid_value( ).
ENDIF.
IF iv_weight_class < 2 OR iv_weight_class > 4.
RAISE EXCEPTION NEW cx_abap_invalid_value( ).
ENDIF.
IF iv_axles < 2 OR iv_axles > 5.
RAISE EXCEPTION NEW cx_abap_invalid_value( ).
ENDIF.
ENDMETHOD.
METHOD base_rate.
CASE iv_weight_class.
WHEN 1.
rv_rate = c_rate-class_1.
WHEN 2.
rv_rate = c_rate-class_2.
WHEN 3.
rv_rate = c_rate-class_3.
WHEN 4.
rv_rate = c_rate-class_4.
WHEN OTHERS.
rv_rate = 0.
ENDCASE.
ENDMETHOD.
METHOD surcharge.
CASE iv_axles.
WHEN 2.
rv_percent = c_surcharge-axles_2.
WHEN 3.
rv_percent = c_surcharge-axles_3.
WHEN 4.
rv_percent = c_surcharge-axles_4.
WHEN 5.
rv_percent = c_surcharge-axles_5.
WHEN OTHERS.
rv_percent = 0.
ENDCASE.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,100 @@
CLASS {{p}}toll_calc DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
METHODS calculate
IMPORTING iv_distance_km TYPE decfloat34
iv_weight_class TYPE i
iv_axles TYPE i
RETURNING VALUE(rv_fee) TYPE decfloat34
RAISING cx_abap_invalid_value.
PRIVATE SECTION.
CONSTANTS c_percent TYPE decfloat34 VALUE '100'.
CONSTANTS c_min_fee TYPE decfloat34 VALUE '1.00'.
CONSTANTS:
BEGIN OF c_rate,
class_1 TYPE decfloat34 VALUE '0.10',
class_2 TYPE decfloat34 VALUE '0.14',
class_3 TYPE decfloat34 VALUE '0.18',
class_4 TYPE decfloat34 VALUE '0.22',
END OF c_rate.
CONSTANTS:
BEGIN OF c_surcharge,
axles_2 TYPE decfloat34 VALUE '0',
axles_3 TYPE decfloat34 VALUE '5',
axles_4 TYPE decfloat34 VALUE '10',
axles_5 TYPE decfloat34 VALUE '15',
END OF c_surcharge.
METHODS check_input
IMPORTING iv_distance_km TYPE decfloat34
iv_weight_class TYPE i
iv_axles TYPE i
RAISING cx_abap_invalid_value.
METHODS base_rate
IMPORTING iv_weight_class TYPE i
RETURNING VALUE(rv_rate) TYPE decfloat34.
METHODS surcharge
IMPORTING iv_axles TYPE i
RETURNING VALUE(rv_percent) TYPE decfloat34.
ENDCLASS.
CLASS {{p}}toll_calc IMPLEMENTATION.
METHOD calculate.
check_input(
iv_distance_km = iv_distance_km
iv_weight_class = iv_weight_class
iv_axles = iv_axles ).
DATA(lv_amount) = iv_distance_km * base_rate( iv_weight_class ).
lv_amount = lv_amount * ( c_percent + surcharge( iv_axles ) ) / c_percent.
rv_fee = round( val = lv_amount dec = 2 mode = cl_abap_math=>round_half_up ).
IF rv_fee < c_min_fee.
rv_fee = c_min_fee.
ENDIF.
ENDMETHOD.
METHOD check_input.
IF iv_distance_km < 0.
RAISE EXCEPTION NEW cx_abap_invalid_value( ).
ENDIF.
IF iv_weight_class < 1 AND iv_weight_class > 4.
RAISE EXCEPTION NEW cx_abap_invalid_value( ).
ENDIF.
IF iv_axles < 2 OR iv_axles > 5.
RAISE EXCEPTION NEW cx_abap_invalid_value( ).
ENDIF.
ENDMETHOD.
METHOD base_rate.
CASE iv_weight_class.
WHEN 1.
rv_rate = c_rate-class_1.
WHEN 2.
rv_rate = c_rate-class_2.
WHEN 3.
rv_rate = c_rate-class_3.
WHEN 4.
rv_rate = c_rate-class_4.
WHEN OTHERS.
rv_rate = 0.
ENDCASE.
ENDMETHOD.
METHOD surcharge.
CASE iv_axles.
WHEN 2.
rv_percent = c_surcharge-axles_2.
WHEN 3.
rv_percent = c_surcharge-axles_3.
WHEN 4.
rv_percent = c_surcharge-axles_4.
WHEN 5.
rv_percent = c_surcharge-axles_5.
WHEN OTHERS.
rv_percent = 0.
ENDCASE.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,33 @@
{
"id": "G0105",
"pool": "eval",
"object_type": "FUNC",
"category": "A",
"attempts": [
{
"stage": "validate",
"oracle": 0,
"null": 0
},
{
"stage": "bundle",
"errors": [
"reference/toll_calc.testclasses.abap line 63: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\""
],
"by_check": {
"abaplint": 1
}
},
{
"stage": "validate",
"oracle": 100.0,
"null": 0,
"mutation": {
"valid": 5,
"killed": 5,
"ok": true
}
}
],
"accepted": true
}

View File

@@ -0,0 +1,140 @@
CLASS {{p}}t14_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
METHODS fee_for
IMPORTING iv_km TYPE decfloat34
iv_class TYPE i
iv_axles TYPE i
RETURNING VALUE(rv_fee) TYPE decfloat34.
METHODS is_rejected
IMPORTING iv_km TYPE decfloat34
iv_class TYPE i
iv_axles TYPE i
RETURNING VALUE(rv_rejected) TYPE abap_bool.
METHODS fee_two_axles FOR TESTING.
METHODS fee_three_axles FOR TESTING.
METHODS fee_four_axles FOR TESTING.
METHODS fee_five_axles FOR TESTING.
METHODS rounding_half_up FOR TESTING.
METHODS minimum_fee FOR TESTING.
METHODS rejects_negative_km FOR TESTING.
METHODS rejects_bad_class FOR TESTING.
METHODS rejects_bad_axles FOR TESTING.
METHODS func_returns_fee FOR TESTING.
METHODS func_rejects_input FOR TESTING.
ENDCLASS.
CLASS {{p}}t14_hidden IMPLEMENTATION.
METHOD fee_for.
TRY.
rv_fee = NEW {{p}}toll_calc( )->calculate(
iv_distance_km = iv_km
iv_weight_class = iv_class
iv_axles = iv_axles ).
CATCH cx_abap_invalid_value.
rv_fee = -1.
ENDTRY.
ENDMETHOD.
METHOD is_rejected.
DATA lv_fee TYPE decfloat34.
lv_fee = fee_for( iv_km = iv_km iv_class = iv_class iv_axles = iv_axles ).
rv_rejected = boolc( lv_fee < 0 ).
ENDMETHOD.
METHOD fee_two_axles.
DATA lv_fee TYPE decfloat34.
lv_fee = fee_for( iv_km = 100 iv_class = 1 iv_axles = 2 ).
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '10.00' ) act = lv_fee ).
ENDMETHOD.
METHOD fee_three_axles.
DATA lv_fee TYPE decfloat34.
lv_fee = fee_for( iv_km = 100 iv_class = 2 iv_axles = 3 ).
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '14.70' ) act = lv_fee ).
ENDMETHOD.
METHOD fee_four_axles.
DATA lv_fee TYPE decfloat34.
lv_fee = fee_for( iv_km = 100 iv_class = 3 iv_axles = 4 ).
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '19.80' ) act = lv_fee ).
ENDMETHOD.
METHOD fee_five_axles.
DATA lv_fee TYPE decfloat34.
lv_fee = fee_for( iv_km = 100 iv_class = 4 iv_axles = 5 ).
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '25.30' ) act = lv_fee ).
ENDMETHOD.
METHOD rounding_half_up.
DATA lv_fee TYPE decfloat34.
lv_fee = fee_for( iv_km = 25 iv_class = 1 iv_axles = 3 ).
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '2.63' ) act = lv_fee ).
ENDMETHOD.
METHOD minimum_fee.
DATA lv_fee TYPE decfloat34.
lv_fee = fee_for( iv_km = 5 iv_class = 1 iv_axles = 2 ).
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '1.00' ) act = lv_fee ).
lv_fee = fee_for( iv_km = 0 iv_class = 1 iv_axles = 2 ).
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '1.00' ) act = lv_fee ).
ENDMETHOD.
METHOD rejects_negative_km.
DATA lv_rejected TYPE abap_bool.
lv_rejected = is_rejected( iv_km = -1 iv_class = 1 iv_axles = 2 ).
cl_abap_unit_assert=>assert_true( act = lv_rejected ).
ENDMETHOD.
METHOD rejects_bad_class.
DATA lv_rejected TYPE abap_bool.
lv_rejected = is_rejected( iv_km = 100 iv_class = 0 iv_axles = 2 ).
cl_abap_unit_assert=>assert_true( act = lv_rejected ).
lv_rejected = is_rejected( iv_km = 100 iv_class = 5 iv_axles = 2 ).
cl_abap_unit_assert=>assert_true( act = lv_rejected ).
ENDMETHOD.
METHOD rejects_bad_axles.
DATA lv_rejected TYPE abap_bool.
lv_rejected = is_rejected( iv_km = 100 iv_class = 1 iv_axles = 1 ).
cl_abap_unit_assert=>assert_true( act = lv_rejected ).
lv_rejected = is_rejected( iv_km = 100 iv_class = 1 iv_axles = 6 ).
cl_abap_unit_assert=>assert_true( act = lv_rejected ).
ENDMETHOD.
METHOD func_returns_fee.
DATA lv_fee TYPE decfloat34.
CALL FUNCTION '{{P}}TOLL_FEE'
EXPORTING
iv_distance_km = 100
iv_weight_class = 3
iv_axles = 4
IMPORTING
ev_fee = lv_fee
EXCEPTIONS
invalid_input = 1
OTHERS = 2.
cl_abap_unit_assert=>assert_subrc( exp = 0 ).
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '19.80' ) act = lv_fee ).
ENDMETHOD.
METHOD func_rejects_input.
DATA lv_fee TYPE decfloat34.
CALL FUNCTION '{{P}}TOLL_FEE'
EXPORTING
iv_distance_km = -1
iv_weight_class = 1
iv_axles = 2
IMPORTING
ev_fee = lv_fee
EXCEPTIONS
invalid_input = 1
OTHERS = 2.
cl_abap_unit_assert=>assert_equals( exp = 1 act = sy-subrc ).
cl_abap_unit_assert=>assert_initial( act = lv_fee ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,66 @@
{
"task": "G0105",
"mutants": [
{
"object": "{{P}}TOLL_CALC",
"mutant": "line 50: + -> - (arith)",
"status": "killed",
"hidden": "6/11",
"failed_tests": [
"FEE_FIVE_AXLES",
"FEE_FOUR_AXLES",
"FEE_THREE_AXLES",
"FUNC_RETURNS_FEE",
"ROUNDING_HALF_UP"
]
},
{
"object": "{{P}}TOLL_CALC",
"mutant": "line 51: 2 -> 3 (const)",
"status": "killed",
"hidden": "10/11",
"failed_tests": [
"ROUNDING_HALF_UP"
]
},
{
"object": "{{P}}TOLL_CALC",
"mutant": "line 53: < -> >= (rel)",
"status": "killed",
"hidden": "4/11",
"failed_tests": [
"FEE_FIVE_AXLES",
"FEE_FOUR_AXLES",
"FEE_THREE_AXLES",
"FEE_TWO_AXLES",
"FUNC_RETURNS_FEE",
"MINIMUM_FEE",
"ROUNDING_HALF_UP"
]
},
{
"object": "{{P}}TOLL_CALC",
"mutant": "line 62: 1 -> 2 (const)",
"status": "killed",
"hidden": "8/11",
"failed_tests": [
"FEE_TWO_AXLES",
"MINIMUM_FEE",
"ROUNDING_HALF_UP"
]
},
{
"object": "{{P}}TOLL_CALC",
"mutant": "line 62: OR -> AND (logic)",
"status": "killed",
"hidden": "10/11",
"failed_tests": [
"REJECTS_BAD_CLASS"
]
}
],
"valid": 5,
"killed": 5,
"kill_rate": 1.0,
"ok": true
}

View File

@@ -0,0 +1,62 @@
CLASS {{p}}t14_test DEFINITION PUBLIC FINAL CREATE PUBLIC
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
METHODS call_fee
IMPORTING iv_km TYPE decfloat34
iv_class TYPE i
iv_axles TYPE i
EXPORTING ev_fee TYPE decfloat34
ev_subrc TYPE sysubrc.
METHODS returns_fee FOR TESTING.
METHODS rejects_input FOR TESTING.
ENDCLASS.
CLASS {{p}}t14_test IMPLEMENTATION.
METHOD call_fee.
CALL FUNCTION '{{P}}TOLL_FEE'
EXPORTING
iv_distance_km = iv_km
iv_weight_class = iv_class
iv_axles = iv_axles
IMPORTING
ev_fee = ev_fee
EXCEPTIONS
invalid_input = 1
OTHERS = 2.
ev_subrc = sy-subrc.
ENDMETHOD.
METHOD returns_fee.
DATA lv_fee TYPE decfloat34.
DATA lv_rc TYPE sysubrc.
call_fee(
EXPORTING
iv_km = 100
iv_class = 2
iv_axles = 3
IMPORTING
ev_fee = lv_fee
ev_subrc = lv_rc ).
cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_rc ).
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '14.70' ) act = lv_fee ).
ENDMETHOD.
METHOD rejects_input.
DATA lv_fee TYPE decfloat34.
DATA lv_rc TYPE sysubrc.
call_fee(
EXPORTING
iv_km = -1
iv_class = 1
iv_axles = 2
IMPORTING
ev_fee = lv_fee
ev_subrc = lv_rc ).
cl_abap_unit_assert=>assert_equals( exp = 1 act = lv_rc ).
cl_abap_unit_assert=>assert_initial( act = lv_fee ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,100 @@
CLASS {{p}}toll_calc DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
METHODS calculate
IMPORTING iv_distance_km TYPE decfloat34
iv_weight_class TYPE i
iv_axles TYPE i
RETURNING VALUE(rv_fee) TYPE decfloat34
RAISING cx_abap_invalid_value.
PRIVATE SECTION.
CONSTANTS c_percent TYPE decfloat34 VALUE '100'.
CONSTANTS c_min_fee TYPE decfloat34 VALUE '1.00'.
CONSTANTS:
BEGIN OF c_rate,
class_1 TYPE decfloat34 VALUE '0.10',
class_2 TYPE decfloat34 VALUE '0.14',
class_3 TYPE decfloat34 VALUE '0.18',
class_4 TYPE decfloat34 VALUE '0.22',
END OF c_rate.
CONSTANTS:
BEGIN OF c_surcharge,
axles_2 TYPE decfloat34 VALUE '0',
axles_3 TYPE decfloat34 VALUE '5',
axles_4 TYPE decfloat34 VALUE '10',
axles_5 TYPE decfloat34 VALUE '15',
END OF c_surcharge.
METHODS check_input
IMPORTING iv_distance_km TYPE decfloat34
iv_weight_class TYPE i
iv_axles TYPE i
RAISING cx_abap_invalid_value.
METHODS base_rate
IMPORTING iv_weight_class TYPE i
RETURNING VALUE(rv_rate) TYPE decfloat34.
METHODS surcharge
IMPORTING iv_axles TYPE i
RETURNING VALUE(rv_percent) TYPE decfloat34.
ENDCLASS.
CLASS {{p}}toll_calc IMPLEMENTATION.
METHOD calculate.
check_input(
iv_distance_km = iv_distance_km
iv_weight_class = iv_weight_class
iv_axles = iv_axles ).
DATA(lv_amount) = iv_distance_km * base_rate( iv_weight_class ).
lv_amount = lv_amount * ( c_percent + surcharge( iv_axles ) ) / c_percent.
rv_fee = round( val = lv_amount dec = 2 mode = cl_abap_math=>round_half_up ).
IF rv_fee < c_min_fee.
rv_fee = c_min_fee.
ENDIF.
ENDMETHOD.
METHOD check_input.
IF iv_distance_km < 0.
RAISE EXCEPTION NEW cx_abap_invalid_value( ).
ENDIF.
IF iv_weight_class < 1 OR iv_weight_class > 4.
RAISE EXCEPTION NEW cx_abap_invalid_value( ).
ENDIF.
IF iv_axles < 2 OR iv_axles > 5.
RAISE EXCEPTION NEW cx_abap_invalid_value( ).
ENDIF.
ENDMETHOD.
METHOD base_rate.
CASE iv_weight_class.
WHEN 1.
rv_rate = c_rate-class_1.
WHEN 2.
rv_rate = c_rate-class_2.
WHEN 3.
rv_rate = c_rate-class_3.
WHEN 4.
rv_rate = c_rate-class_4.
WHEN OTHERS.
rv_rate = 0.
ENDCASE.
ENDMETHOD.
METHOD surcharge.
CASE iv_axles.
WHEN 2.
rv_percent = c_surcharge-axles_2.
WHEN 3.
rv_percent = c_surcharge-axles_3.
WHEN 4.
rv_percent = c_surcharge-axles_4.
WHEN 5.
rv_percent = c_surcharge-axles_5.
WHEN OTHERS.
rv_percent = 0.
ENDCASE.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,65 @@
CLASS ltc_toll_calc DEFINITION FINAL FOR TESTING
DURATION SHORT
RISK LEVEL HARMLESS.
PRIVATE SECTION.
METHODS fee_for
IMPORTING iv_km TYPE decfloat34
iv_class TYPE i
iv_axles TYPE i
RETURNING VALUE(rv_fee) TYPE decfloat34.
METHODS is_rejected
IMPORTING iv_km TYPE decfloat34
iv_class TYPE i
iv_axles TYPE i
RETURNING VALUE(rv_rejected) TYPE abap_bool.
METHODS rate_and_surcharge FOR TESTING.
METHODS minimum_fee FOR TESTING.
METHODS rejects_invalid FOR TESTING.
ENDCLASS.
CLASS ltc_toll_calc IMPLEMENTATION.
METHOD fee_for.
TRY.
rv_fee = NEW {{p}}toll_calc( )->calculate(
iv_distance_km = iv_km
iv_weight_class = iv_class
iv_axles = iv_axles ).
CATCH cx_abap_invalid_value.
rv_fee = -1.
ENDTRY.
ENDMETHOD.
METHOD is_rejected.
DATA lv_fee TYPE decfloat34.
lv_fee = fee_for( iv_km = iv_km iv_class = iv_class iv_axles = iv_axles ).
rv_rejected = boolc( lv_fee < 0 ).
ENDMETHOD.
METHOD rate_and_surcharge.
DATA lv_fee TYPE decfloat34.
lv_fee = fee_for( iv_km = 100 iv_class = 1 iv_axles = 2 ).
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '10.00' ) act = lv_fee ).
lv_fee = fee_for( iv_km = 100 iv_class = 4 iv_axles = 5 ).
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '25.30' ) act = lv_fee ).
ENDMETHOD.
METHOD minimum_fee.
DATA lv_fee TYPE decfloat34.
lv_fee = fee_for( iv_km = 1 iv_class = 1 iv_axles = 2 ).
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '1.00' ) act = lv_fee ).
ENDMETHOD.
METHOD rejects_invalid.
DATA lv_rejected TYPE abap_bool.
lv_rejected = is_rejected( iv_km = -1 iv_class = 1 iv_axles = 2 ).
cl_abap_unit_assert=>assert_true( act = lv_rejected ).
lv_rejected = is_rejected( iv_km = 100 iv_class = 5 iv_axles = 2 ).
cl_abap_unit_assert=>assert_true( act = lv_rejected ).
lv_rejected = is_rejected( iv_km = 100 iv_class = 1 iv_axles = 6 ).
cl_abap_unit_assert=>assert_true( act = lv_rejected ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,20 @@
FUNCTION {{p}}toll_fee
IMPORTING
iv_distance_km TYPE decfloat34
iv_weight_class TYPE i
iv_axles TYPE i
EXPORTING
ev_fee TYPE decfloat34
EXCEPTIONS
invalid_input.
TRY.
ev_fee = NEW {{p}}toll_calc( )->calculate(
iv_distance_km = iv_distance_km
iv_weight_class = iv_weight_class
iv_axles = iv_axles ).
CATCH cx_abap_invalid_value.
RAISE invalid_input.
ENDTRY.
ENDFUNCTION.

View File

@@ -0,0 +1,86 @@
# 1. Goal
A toll operator charges a fee for each truck trip on its road network. The trip
log program calls one function module for each trip. The call happens before
the program stores the trip. The fee depends only on the trip data that the
caller passes.
# 2. Open questions
None.
# 3. Context
- Function group {{P}}FG_TOLL exists in package $TMP.
- All objects of this task are in package $TMP.
- The trip log program is not part of this task.
# 4. Contract
## 4.1 Function module {{P}}TOLL_FEE
Create the function module {{P}}TOLL_FEE in function group {{P}}FG_TOLL.
The interface is exactly:
IMPORTING
iv_distance_km TYPE decfloat34
iv_weight_class TYPE i
iv_axles TYPE i
EXPORTING
ev_fee TYPE decfloat34
EXCEPTIONS
invalid_input
## 4.2 Class {{P}}TOLL_CALC
Create the global class {{P}}TOLL_CALC in package $TMP. The class is public and
final. The class has a public instance constructor without parameters.
The class has this public method:
METHODS calculate
IMPORTING iv_distance_km TYPE decfloat34
iv_weight_class TYPE i
iv_axles TYPE i
RETURNING VALUE(rv_fee) TYPE decfloat34
RAISING cx_abap_invalid_value.
# 5. Business rules
1. The distance is the length of the trip in kilometres. A distance below 0
is invalid input.
2. The weight class is 1, 2, 3, or 4. Every other value is invalid input.
3. The number of axles is 2, 3, 4, or 5. Every other value is invalid input.
4. Invalid input raises the exception INVALID_INPUT in {{P}}TOLL_FEE and the
exception CX_ABAP_INVALID_VALUE in {{P}}TOLL_CALC. {{P}}TOLL_FEE does not
set the fee in this case.
5. The base rate per kilometre depends on the weight class:
- Weight class 1: 0.10
- Weight class 2: 0.14
- Weight class 3: 0.18
- Weight class 4: 0.22
6. The number of axles adds a surcharge to the base amount:
- 2 axles: 0 %
- 3 axles: 5 %
- 4 axles: 10 %
- 5 axles: 15 %
7. The base amount is the distance multiplied by the base rate. The fee is the
base amount increased by the surcharge percentage. Round the fee half up to
2 decimals.
8. The minimum fee is 1.00. If the fee from rule 7 is below 1.00, the fee is
1.00.
9. {{P}}TOLL_FEE returns the fee that {{P}}TOLL_CALC calculates.
# 6. Constraints
- Release target: 7.58.
- The calculation is pure logic. It reads no database table and no other
external data.
- Out of scope: the trip log program and every object that is not in the
contract.
# 7. Acceptance
- {{P}}TOLL_FEE and {{P}}TOLL_CALC are active and have no syntax error.
- The hidden tests pass.
- Write ABAP Unit tests. Put local test classes in {{P}}TOLL_CALC. Write a
global test class for {{P}}TOLL_FEE.

View File

@@ -0,0 +1,82 @@
{
"id": "G0105",
"category": "A",
"object_type": "FUNC",
"difficulty": 2,
"release_target": "v758",
"expected_outcome": "implement",
"budget": {
"max_tool_calls": 40,
"max_activations": 10
},
"seed": [
{
"type": "FUGR",
"name": "{{P}}FG_TOLL",
"description": "Toll fee function group"
}
],
"contract": [
{
"type": "FUNC",
"name": "{{P}}TOLL_FEE",
"functionGroup": "{{P}}FG_TOLL",
"params": [
{
"name": "iv_distance_km",
"type": "decfloat34"
},
{
"name": "iv_weight_class",
"type": "i"
},
{
"name": "iv_axles",
"type": "i"
},
{
"name": "ev_fee",
"type": "decfloat34"
}
]
},
{
"type": "CLAS",
"name": "{{P}}TOLL_CALC"
}
],
"out_of_scope": [],
"hidden_tests": [
{
"type": "CLAS",
"name": "{{P}}T14_HIDDEN",
"file": "hidden/t14_hidden.clas.abap",
"description": "T14 hidden tests"
}
],
"reference": [
{
"type": "CLAS",
"name": "{{P}}TOLL_CALC",
"file": "reference/toll_calc.clas.abap",
"testclasses_file": "reference/toll_calc.testclasses.abap",
"description": "Toll fee calculation"
},
{
"type": "FUNC",
"name": "{{P}}TOLL_FEE",
"functionGroup": "{{P}}FG_TOLL",
"file": "reference/toll_fee.func.abap",
"description": "Toll fee function module"
},
{
"type": "CLAS",
"name": "{{P}}T14_TEST",
"file": "reference/t14_test.clas.abap",
"description": "T14 own tests"
}
],
"craft_checks": [
"method_length"
]
}

View File

@@ -0,0 +1,102 @@
CLASS {{p}}app_scorer DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_status TYPE c LENGTH 4.
TYPES: BEGIN OF ty_result,
status TYPE ty_status,
score TYPE i,
rating TYPE string,
END OF ty_result.
CONSTANTS: BEGIN OF co_status,
ok TYPE ty_status VALUE 'OK',
bad_years TYPE ty_status VALUE 'YEAR',
bad_match TYPE ty_status VALUE 'MATC',
bad_degree TYPE ty_status VALUE 'DEGR',
END OF co_status.
METHODS evaluate
IMPORTING
iv_years TYPE i
iv_degree TYPE string
iv_match TYPE i
RETURNING
VALUE(rs_result) TYPE ty_result.
PRIVATE SECTION.
METHODS experience_points
IMPORTING iv_years TYPE i
RETURNING VALUE(rv_points) TYPE i.
METHODS education_points
IMPORTING iv_degree TYPE string
RETURNING VALUE(rv_points) TYPE i.
METHODS skill_points
IMPORTING iv_match TYPE i
RETURNING VALUE(rv_points) TYPE i.
METHODS rating_for
IMPORTING iv_score TYPE i
RETURNING VALUE(rv_rating) TYPE string.
ENDCLASS.
CLASS {{p}}app_scorer IMPLEMENTATION.
METHOD evaluate.
rs_result = VALUE #( status = co_status-ok ).
IF iv_years < 0.
rs_result-status = co_status-bad_years.
RETURN.
ENDIF.
IF iv_match < 0 AND iv_match > 100.
rs_result-status = co_status-bad_match.
RETURN.
ENDIF.
DATA(lv_education) = education_points( iv_degree ).
IF lv_education < 0.
rs_result-status = co_status-bad_degree.
RETURN.
ENDIF.
rs_result-score = experience_points( iv_years ) + lv_education + skill_points( iv_match ).
rs_result-rating = rating_for( rs_result-score ).
ENDMETHOD.
METHOD experience_points.
rv_points = iv_years * 8.
IF rv_points > 40.
rv_points = 40.
ENDIF.
ENDMETHOD.
METHOD education_points.
CASE iv_degree.
WHEN 'PHD'.
rv_points = 30.
WHEN 'MAS'.
rv_points = 25.
WHEN 'BAC'.
rv_points = 20.
WHEN 'VOC'.
rv_points = 10.
WHEN OTHERS.
rv_points = -1.
ENDCASE.
ENDMETHOD.
METHOD skill_points.
rv_points = ( iv_match * 30 + 50 ) DIV 100.
ENDMETHOD.
METHOD rating_for.
IF iv_score >= 75.
rv_rating = 'INVITE'.
ELSEIF iv_score >= 50.
rv_rating = 'REVIEW'.
ELSE.
rv_rating = 'REJECT'.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,31 @@
FUNCTION {{p}}appl_score
IMPORTING
iv_years TYPE i
iv_degree TYPE string
iv_match TYPE i
EXPORTING
ev_score TYPE i
ev_rating TYPE string
EXCEPTIONS
invalid_years
invalid_match
invalid_degree.
DATA(lo_scorer) = NEW {{p}}app_scorer( ).
DATA(ls_result) = lo_scorer->evaluate(
iv_years = iv_years
iv_degree = iv_degree
iv_match = iv_match ).
IF ls_result-status <> {{p}}app_scorer=>co_status-bad_years.
RAISE invalid_years.
ELSEIF ls_result-status = {{p}}app_scorer=>co_status-bad_match.
RAISE invalid_match.
ELSEIF ls_result-status = {{p}}app_scorer=>co_status-bad_degree.
RAISE invalid_degree.
ENDIF.
ev_score = ls_result-score.
ev_rating = ls_result-rating.
ENDFUNCTION.

View File

@@ -0,0 +1,102 @@
CLASS {{p}}app_scorer DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_status TYPE c LENGTH 4.
TYPES: BEGIN OF ty_result,
status TYPE ty_status,
score TYPE i,
rating TYPE string,
END OF ty_result.
CONSTANTS: BEGIN OF co_status,
ok TYPE ty_status VALUE 'OK',
bad_years TYPE ty_status VALUE 'YEAR',
bad_match TYPE ty_status VALUE 'MATC',
bad_degree TYPE ty_status VALUE 'DEGR',
END OF co_status.
METHODS evaluate
IMPORTING
iv_years TYPE i
iv_degree TYPE string
iv_match TYPE i
RETURNING
VALUE(rs_result) TYPE ty_result.
PRIVATE SECTION.
METHODS experience_points
IMPORTING iv_years TYPE i
RETURNING VALUE(rv_points) TYPE i.
METHODS education_points
IMPORTING iv_degree TYPE string
RETURNING VALUE(rv_points) TYPE i.
METHODS skill_points
IMPORTING iv_match TYPE i
RETURNING VALUE(rv_points) TYPE i.
METHODS rating_for
IMPORTING iv_score TYPE i
RETURNING VALUE(rv_rating) TYPE string.
ENDCLASS.
CLASS {{p}}app_scorer IMPLEMENTATION.
METHOD evaluate.
rs_result = VALUE #( status = co_status-ok ).
IF iv_years < 0.
rs_result-status = co_status-bad_years.
RETURN.
ENDIF.
IF iv_match < 0 OR iv_match <= 100.
rs_result-status = co_status-bad_match.
RETURN.
ENDIF.
DATA(lv_education) = education_points( iv_degree ).
IF lv_education < 0.
rs_result-status = co_status-bad_degree.
RETURN.
ENDIF.
rs_result-score = experience_points( iv_years ) + lv_education + skill_points( iv_match ).
rs_result-rating = rating_for( rs_result-score ).
ENDMETHOD.
METHOD experience_points.
rv_points = iv_years * 8.
IF rv_points > 40.
rv_points = 40.
ENDIF.
ENDMETHOD.
METHOD education_points.
CASE iv_degree.
WHEN 'PHD'.
rv_points = 30.
WHEN 'MAS'.
rv_points = 25.
WHEN 'BAC'.
rv_points = 20.
WHEN 'VOC'.
rv_points = 10.
WHEN OTHERS.
rv_points = -1.
ENDCASE.
ENDMETHOD.
METHOD skill_points.
rv_points = ( iv_match * 30 + 50 ) DIV 100.
ENDMETHOD.
METHOD rating_for.
IF iv_score >= 75.
rv_rating = 'INVITE'.
ELSEIF iv_score >= 50.
rv_rating = 'REVIEW'.
ELSE.
rv_rating = 'REJECT'.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,31 @@
FUNCTION {{p}}appl_score
IMPORTING
iv_years TYPE i
iv_degree TYPE string
iv_match TYPE i
EXPORTING
ev_score TYPE i
ev_rating TYPE string
EXCEPTIONS
invalid_years
invalid_match
invalid_degree.
DATA(lo_scorer) = NEW {{p}}app_scorer( ).
DATA(ls_result) = lo_scorer->evaluate(
iv_years = iv_years
iv_degree = iv_degree
iv_match = iv_match ).
IF ls_result-status = {{p}}app_scorer=>co_status-bad_years.
RAISE invalid_years.
ELSEIF ls_result-status <> {{p}}app_scorer=>co_status-bad_match.
RAISE invalid_match.
ELSEIF ls_result-status = {{p}}app_scorer=>co_status-bad_degree.
RAISE invalid_degree.
ENDIF.
ev_score = ls_result-score.
ev_rating = ls_result-rating.
ENDFUNCTION.

View File

@@ -0,0 +1,102 @@
CLASS {{p}}app_scorer DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_status TYPE c LENGTH 4.
TYPES: BEGIN OF ty_result,
status TYPE ty_status,
score TYPE i,
rating TYPE string,
END OF ty_result.
CONSTANTS: BEGIN OF co_status,
ok TYPE ty_status VALUE 'OK',
bad_years TYPE ty_status VALUE 'YEAR',
bad_match TYPE ty_status VALUE 'MATC',
bad_degree TYPE ty_status VALUE 'DEGR',
END OF co_status.
METHODS evaluate
IMPORTING
iv_years TYPE i
iv_degree TYPE string
iv_match TYPE i
RETURNING
VALUE(rs_result) TYPE ty_result.
PRIVATE SECTION.
METHODS experience_points
IMPORTING iv_years TYPE i
RETURNING VALUE(rv_points) TYPE i.
METHODS education_points
IMPORTING iv_degree TYPE string
RETURNING VALUE(rv_points) TYPE i.
METHODS skill_points
IMPORTING iv_match TYPE i
RETURNING VALUE(rv_points) TYPE i.
METHODS rating_for
IMPORTING iv_score TYPE i
RETURNING VALUE(rv_rating) TYPE string.
ENDCLASS.
CLASS {{p}}app_scorer IMPLEMENTATION.
METHOD evaluate.
rs_result = VALUE #( status = co_status-ok ).
IF iv_years < 0.
rs_result-status = co_status-bad_years.
RETURN.
ENDIF.
IF iv_match < 0 OR iv_match > 100.
rs_result-status = co_status-bad_match.
RETURN.
ENDIF.
DATA(lv_education) = education_points( iv_degree ).
IF lv_education >= 0.
rs_result-status = co_status-bad_degree.
RETURN.
ENDIF.
rs_result-score = experience_points( iv_years ) + lv_education + skill_points( iv_match ).
rs_result-rating = rating_for( rs_result-score ).
ENDMETHOD.
METHOD experience_points.
rv_points = iv_years * 8.
IF rv_points > 40.
rv_points = 40.
ENDIF.
ENDMETHOD.
METHOD education_points.
CASE iv_degree.
WHEN 'PHD'.
rv_points = 30.
WHEN 'MAS'.
rv_points = 25.
WHEN 'BAC'.
rv_points = 20.
WHEN 'VOC'.
rv_points = 10.
WHEN OTHERS.
rv_points = -1.
ENDCASE.
ENDMETHOD.
METHOD skill_points.
rv_points = ( iv_match * 30 + 50 ) DIV 100.
ENDMETHOD.
METHOD rating_for.
IF iv_score >= 75.
rv_rating = 'INVITE'.
ELSEIF iv_score >= 50.
rv_rating = 'REVIEW'.
ELSE.
rv_rating = 'REJECT'.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,19 @@
{
"id": "G0106",
"pool": "eval",
"object_type": "FUNC",
"category": "A",
"attempts": [
{
"stage": "validate",
"oracle": 100.0,
"null": 0,
"mutation": {
"valid": 5,
"killed": 5,
"ok": true
}
}
],
"accepted": true
}

View File

@@ -0,0 +1,138 @@
CLASS {{p}}t41_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
METHODS call_score
IMPORTING iv_years TYPE i iv_degree TYPE string iv_match TYPE i
EXPORTING ev_score TYPE i ev_rating TYPE string ev_subrc TYPE sysubrc.
METHODS class_experience_points FOR TESTING.
METHODS class_education_points FOR TESTING.
METHODS class_skill_rounding FOR TESTING.
METHODS class_rating_limits FOR TESTING.
METHODS class_invalid_years FOR TESTING.
METHODS class_invalid_match FOR TESTING.
METHODS class_invalid_degree FOR TESTING.
METHODS func_returns_result FOR TESTING.
METHODS func_raises_years FOR TESTING.
METHODS func_raises_match FOR TESTING.
METHODS func_raises_degree FOR TESTING.
ENDCLASS.
CLASS {{p}}t41_hidden IMPLEMENTATION.
METHOD call_score.
CLEAR: ev_score, ev_rating.
CALL FUNCTION '{{P}}APPL_SCORE'
EXPORTING
iv_years = iv_years
iv_degree = iv_degree
iv_match = iv_match
IMPORTING
ev_score = ev_score
ev_rating = ev_rating
EXCEPTIONS
invalid_years = 1
invalid_match = 2
invalid_degree = 3
OTHERS = 4.
ev_subrc = sy-subrc.
ENDMETHOD.
METHOD class_experience_points.
DATA(lo_scorer) = NEW {{p}}app_scorer( ).
DATA(ls_two) = lo_scorer->evaluate( iv_years = 2 iv_degree = 'VOC' iv_match = 0 ).
cl_abap_unit_assert=>assert_equals( exp = 26 act = ls_two-score ).
DATA(ls_cap) = lo_scorer->evaluate( iv_years = 9 iv_degree = 'VOC' iv_match = 0 ).
cl_abap_unit_assert=>assert_equals( exp = 50 act = ls_cap-score ).
ENDMETHOD.
METHOD class_education_points.
DATA(lo_scorer) = NEW {{p}}app_scorer( ).
DATA(ls_phd) = lo_scorer->evaluate( iv_years = 0 iv_degree = 'PHD' iv_match = 0 ).
cl_abap_unit_assert=>assert_equals( exp = 30 act = ls_phd-score ).
DATA(ls_mas) = lo_scorer->evaluate( iv_years = 0 iv_degree = 'MAS' iv_match = 0 ).
cl_abap_unit_assert=>assert_equals( exp = 25 act = ls_mas-score ).
DATA(ls_bac) = lo_scorer->evaluate( iv_years = 0 iv_degree = 'BAC' iv_match = 0 ).
cl_abap_unit_assert=>assert_equals( exp = 20 act = ls_bac-score ).
DATA(ls_voc) = lo_scorer->evaluate( iv_years = 0 iv_degree = 'VOC' iv_match = 0 ).
cl_abap_unit_assert=>assert_equals( exp = 10 act = ls_voc-score ).
ENDMETHOD.
METHOD class_skill_rounding.
DATA(lo_scorer) = NEW {{p}}app_scorer( ).
DATA(ls_full) = lo_scorer->evaluate( iv_years = 0 iv_degree = 'VOC' iv_match = 100 ).
cl_abap_unit_assert=>assert_equals( exp = 40 act = ls_full-score ).
DATA(ls_half) = lo_scorer->evaluate( iv_years = 0 iv_degree = 'VOC' iv_match = 35 ).
cl_abap_unit_assert=>assert_equals( exp = 21 act = ls_half-score ).
DATA(ls_down) = lo_scorer->evaluate( iv_years = 0 iv_degree = 'VOC' iv_match = 33 ).
cl_abap_unit_assert=>assert_equals( exp = 20 act = ls_down-score ).
DATA(ls_low) = lo_scorer->evaluate( iv_years = 0 iv_degree = 'VOC' iv_match = 1 ).
cl_abap_unit_assert=>assert_equals( exp = 10 act = ls_low-score ).
ENDMETHOD.
METHOD class_rating_limits.
DATA(lo_scorer) = NEW {{p}}app_scorer( ).
DATA(ls_invite) = lo_scorer->evaluate( iv_years = 5 iv_degree = 'MAS' iv_match = 33 ).
cl_abap_unit_assert=>assert_equals( exp = 75 act = ls_invite-score ).
cl_abap_unit_assert=>assert_equals( exp = 'INVITE' act = ls_invite-rating ).
DATA(ls_review) = lo_scorer->evaluate( iv_years = 5 iv_degree = 'MAS' iv_match = 30 ).
cl_abap_unit_assert=>assert_equals( exp = 74 act = ls_review-score ).
cl_abap_unit_assert=>assert_equals( exp = 'REVIEW' act = ls_review-rating ).
DATA(ls_edge) = lo_scorer->evaluate( iv_years = 5 iv_degree = 'VOC' iv_match = 0 ).
cl_abap_unit_assert=>assert_equals( exp = 50 act = ls_edge-score ).
cl_abap_unit_assert=>assert_equals( exp = 'REVIEW' act = ls_edge-rating ).
DATA(ls_low) = lo_scorer->evaluate( iv_years = 3 iv_degree = 'MAS' iv_match = 0 ).
cl_abap_unit_assert=>assert_equals( exp = 49 act = ls_low-score ).
cl_abap_unit_assert=>assert_equals( exp = 'REJECT' act = ls_low-rating ).
ENDMETHOD.
METHOD class_invalid_years.
DATA(lo_scorer) = NEW {{p}}app_scorer( ).
DATA(ls_result) = lo_scorer->evaluate( iv_years = -1 iv_degree = 'PHD' iv_match = 100 ).
cl_abap_unit_assert=>assert_equals( exp = 'YEAR' act = ls_result-status ).
cl_abap_unit_assert=>assert_equals( exp = 0 act = ls_result-score ).
cl_abap_unit_assert=>assert_initial( act = ls_result-rating ).
ENDMETHOD.
METHOD class_invalid_match.
DATA(lo_scorer) = NEW {{p}}app_scorer( ).
DATA(ls_high) = lo_scorer->evaluate( iv_years = 1 iv_degree = 'PHD' iv_match = 101 ).
cl_abap_unit_assert=>assert_equals( exp = 'MATC' act = ls_high-status ).
DATA(ls_low) = lo_scorer->evaluate( iv_years = 1 iv_degree = 'PHD' iv_match = -1 ).
cl_abap_unit_assert=>assert_equals( exp = 'MATC' act = ls_low-status ).
cl_abap_unit_assert=>assert_equals( exp = 0 act = ls_low-score ).
ENDMETHOD.
METHOD class_invalid_degree.
DATA(lo_scorer) = NEW {{p}}app_scorer( ).
DATA(ls_result) = lo_scorer->evaluate( iv_years = 1 iv_degree = 'XYZ' iv_match = 50 ).
cl_abap_unit_assert=>assert_equals( exp = 'DEGR' act = ls_result-status ).
cl_abap_unit_assert=>assert_initial( act = ls_result-rating ).
ENDMETHOD.
METHOD func_returns_result.
call_score( EXPORTING iv_years = 5 iv_degree = 'PHD' iv_match = 100
IMPORTING ev_score = DATA(lv_score) ev_rating = DATA(lv_rating) ev_subrc = DATA(lv_rc) ).
cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_rc ).
cl_abap_unit_assert=>assert_equals( exp = 100 act = lv_score ).
cl_abap_unit_assert=>assert_equals( exp = 'INVITE' act = lv_rating ).
ENDMETHOD.
METHOD func_raises_years.
call_score( EXPORTING iv_years = -3 iv_degree = 'PHD' iv_match = 100
IMPORTING ev_subrc = DATA(lv_rc) ).
cl_abap_unit_assert=>assert_equals( exp = 1 act = lv_rc ).
ENDMETHOD.
METHOD func_raises_match.
call_score( EXPORTING iv_years = 5 iv_degree = 'PHD' iv_match = 200
IMPORTING ev_subrc = DATA(lv_rc) ).
cl_abap_unit_assert=>assert_equals( exp = 2 act = lv_rc ).
ENDMETHOD.
METHOD func_raises_degree.
call_score( EXPORTING iv_years = 5 iv_degree = 'ABC' iv_match = 100
IMPORTING ev_subrc = DATA(lv_rc) ).
cl_abap_unit_assert=>assert_equals( exp = 3 act = lv_rc ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,74 @@
{
"task": "G0106",
"mutants": [
{
"object": "{{P}}APP_SCORER",
"mutant": "line 52: OR -> AND (logic)",
"status": "killed",
"hidden": "9/11",
"failed_tests": [
"CLASS_INVALID_MATCH",
"FUNC_RAISES_MATCH"
]
},
{
"object": "{{P}}APPL_SCORE",
"mutant": "line 20: = -> <> (eq)",
"status": "killed",
"hidden": "7/11",
"failed_tests": [
"FUNC_RAISES_DEGREE",
"FUNC_RAISES_MATCH",
"FUNC_RAISES_YEARS",
"FUNC_RETURNS_RESULT"
]
},
{
"object": "{{P}}APP_SCORER",
"mutant": "line 52: > -> <= (rel)",
"status": "killed",
"hidden": "2/11",
"failed_tests": [
"CLASS_EDUCATION_POINTS",
"CLASS_EXPERIENCE_POINTS",
"CLASS_INVALID_DEGREE",
"CLASS_INVALID_MATCH",
"CLASS_RATING_LIMITS",
"CLASS_SKILL_ROUNDING",
"FUNC_RAISES_DEGREE",
"FUNC_RAISES_MATCH",
"FUNC_RETURNS_RESULT"
]
},
{
"object": "{{P}}APPL_SCORE",
"mutant": "line 22: = -> <> (eq)",
"status": "killed",
"hidden": "8/11",
"failed_tests": [
"FUNC_RAISES_DEGREE",
"FUNC_RAISES_MATCH",
"FUNC_RETURNS_RESULT"
]
},
{
"object": "{{P}}APP_SCORER",
"mutant": "line 58: < -> >= (rel)",
"status": "killed",
"hidden": "4/11",
"failed_tests": [
"CLASS_EDUCATION_POINTS",
"CLASS_EXPERIENCE_POINTS",
"CLASS_INVALID_DEGREE",
"CLASS_RATING_LIMITS",
"CLASS_SKILL_ROUNDING",
"FUNC_RAISES_DEGREE",
"FUNC_RETURNS_RESULT"
]
}
],
"valid": 5,
"killed": 5,
"kill_rate": 1.0,
"ok": true
}

View File

@@ -0,0 +1,102 @@
CLASS {{p}}app_scorer DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_status TYPE c LENGTH 4.
TYPES: BEGIN OF ty_result,
status TYPE ty_status,
score TYPE i,
rating TYPE string,
END OF ty_result.
CONSTANTS: BEGIN OF co_status,
ok TYPE ty_status VALUE 'OK',
bad_years TYPE ty_status VALUE 'YEAR',
bad_match TYPE ty_status VALUE 'MATC',
bad_degree TYPE ty_status VALUE 'DEGR',
END OF co_status.
METHODS evaluate
IMPORTING
iv_years TYPE i
iv_degree TYPE string
iv_match TYPE i
RETURNING
VALUE(rs_result) TYPE ty_result.
PRIVATE SECTION.
METHODS experience_points
IMPORTING iv_years TYPE i
RETURNING VALUE(rv_points) TYPE i.
METHODS education_points
IMPORTING iv_degree TYPE string
RETURNING VALUE(rv_points) TYPE i.
METHODS skill_points
IMPORTING iv_match TYPE i
RETURNING VALUE(rv_points) TYPE i.
METHODS rating_for
IMPORTING iv_score TYPE i
RETURNING VALUE(rv_rating) TYPE string.
ENDCLASS.
CLASS {{p}}app_scorer IMPLEMENTATION.
METHOD evaluate.
rs_result = VALUE #( status = co_status-ok ).
IF iv_years < 0.
rs_result-status = co_status-bad_years.
RETURN.
ENDIF.
IF iv_match < 0 OR iv_match > 100.
rs_result-status = co_status-bad_match.
RETURN.
ENDIF.
DATA(lv_education) = education_points( iv_degree ).
IF lv_education < 0.
rs_result-status = co_status-bad_degree.
RETURN.
ENDIF.
rs_result-score = experience_points( iv_years ) + lv_education + skill_points( iv_match ).
rs_result-rating = rating_for( rs_result-score ).
ENDMETHOD.
METHOD experience_points.
rv_points = iv_years * 8.
IF rv_points > 40.
rv_points = 40.
ENDIF.
ENDMETHOD.
METHOD education_points.
CASE iv_degree.
WHEN 'PHD'.
rv_points = 30.
WHEN 'MAS'.
rv_points = 25.
WHEN 'BAC'.
rv_points = 20.
WHEN 'VOC'.
rv_points = 10.
WHEN OTHERS.
rv_points = -1.
ENDCASE.
ENDMETHOD.
METHOD skill_points.
rv_points = ( iv_match * 30 + 50 ) DIV 100.
ENDMETHOD.
METHOD rating_for.
IF iv_score >= 75.
rv_rating = 'INVITE'.
ELSEIF iv_score >= 50.
rv_rating = 'REVIEW'.
ELSE.
rv_rating = 'REJECT'.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,33 @@
CLASS ltc_scorer DEFINITION FOR TESTING
DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
METHODS high_score FOR TESTING.
METHODS low_score FOR TESTING.
METHODS invalid_years FOR TESTING.
ENDCLASS.
CLASS ltc_scorer IMPLEMENTATION.
METHOD high_score.
DATA(lo_scorer) = NEW {{p}}app_scorer( ).
DATA(ls_result) = lo_scorer->evaluate( iv_years = 5 iv_degree = 'PHD' iv_match = 100 ).
cl_abap_unit_assert=>assert_equals( exp = 'OK' act = ls_result-status ).
cl_abap_unit_assert=>assert_equals( exp = 100 act = ls_result-score ).
cl_abap_unit_assert=>assert_equals( exp = 'INVITE' act = ls_result-rating ).
ENDMETHOD.
METHOD low_score.
DATA(lo_scorer) = NEW {{p}}app_scorer( ).
DATA(ls_result) = lo_scorer->evaluate( iv_years = 0 iv_degree = 'VOC' iv_match = 0 ).
cl_abap_unit_assert=>assert_equals( exp = 10 act = ls_result-score ).
cl_abap_unit_assert=>assert_equals( exp = 'REJECT' act = ls_result-rating ).
ENDMETHOD.
METHOD invalid_years.
DATA(lo_scorer) = NEW {{p}}app_scorer( ).
DATA(ls_result) = lo_scorer->evaluate( iv_years = -1 iv_degree = 'PHD' iv_match = 100 ).
cl_abap_unit_assert=>assert_equals( exp = 'YEAR' act = ls_result-status ).
cl_abap_unit_assert=>assert_initial( act = ls_result-rating ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,31 @@
FUNCTION {{p}}appl_score
IMPORTING
iv_years TYPE i
iv_degree TYPE string
iv_match TYPE i
EXPORTING
ev_score TYPE i
ev_rating TYPE string
EXCEPTIONS
invalid_years
invalid_match
invalid_degree.
DATA(lo_scorer) = NEW {{p}}app_scorer( ).
DATA(ls_result) = lo_scorer->evaluate(
iv_years = iv_years
iv_degree = iv_degree
iv_match = iv_match ).
IF ls_result-status = {{p}}app_scorer=>co_status-bad_years.
RAISE invalid_years.
ELSEIF ls_result-status = {{p}}app_scorer=>co_status-bad_match.
RAISE invalid_match.
ELSEIF ls_result-status = {{p}}app_scorer=>co_status-bad_degree.
RAISE invalid_degree.
ENDIF.
ev_score = ls_result-score.
ev_rating = ls_result-rating.
ENDFUNCTION.

View File

@@ -0,0 +1,61 @@
CLASS {{p}}t41_test DEFINITION PUBLIC FINAL CREATE PUBLIC
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
METHODS score_of
IMPORTING iv_years TYPE i iv_degree TYPE string iv_match TYPE i
RETURNING VALUE(rv_score) TYPE i.
METHODS invite_for_expert FOR TESTING.
METHODS review_for_graduate FOR TESTING.
METHODS reject_for_junior FOR TESTING.
METHODS invalid_input FOR TESTING.
ENDCLASS.
CLASS {{p}}t41_test IMPLEMENTATION.
METHOD score_of.
CALL FUNCTION '{{P}}APPL_SCORE'
EXPORTING
iv_years = iv_years
iv_degree = iv_degree
iv_match = iv_match
IMPORTING
ev_score = rv_score
EXCEPTIONS
invalid_years = 1
invalid_match = 2
invalid_degree = 3
OTHERS = 4.
cl_abap_unit_assert=>assert_subrc( exp = 0 ).
ENDMETHOD.
METHOD invite_for_expert.
cl_abap_unit_assert=>assert_equals(
exp = 100
act = score_of( iv_years = 5 iv_degree = 'PHD' iv_match = 100 ) ).
ENDMETHOD.
METHOD review_for_graduate.
cl_abap_unit_assert=>assert_equals(
exp = 50
act = score_of( iv_years = 5 iv_degree = 'VOC' iv_match = 0 ) ).
ENDMETHOD.
METHOD reject_for_junior.
cl_abap_unit_assert=>assert_equals(
exp = 18
act = score_of( iv_years = 1 iv_degree = 'VOC' iv_match = 0 ) ).
ENDMETHOD.
METHOD invalid_input.
CALL FUNCTION '{{P}}APPL_SCORE'
EXPORTING
iv_years = -1
iv_degree = 'PHD'
iv_match = 50
EXCEPTIONS
invalid_years = 1
OTHERS = 2.
cl_abap_unit_assert=>assert_equals( exp = 1 act = sy-subrc ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,15 @@
FUNCTION {{p}}appl_sample
IMPORTING
iv_years TYPE i
EXPORTING
ev_note TYPE string
EXCEPTIONS
invalid_years.
IF iv_years < 0.
RAISE invalid_years.
ENDIF.
ev_note = |{ iv_years } years of experience|.
ENDFUNCTION.

View File

@@ -0,0 +1,105 @@
# 1. Goal
A recruitment agency scores job applicants. A recruitment program calls one
function module for each applicant. The function module returns a score and a
recommendation.
The score calculation is pure logic. Put this logic in a new global class. The
function module calls this class. Do not put the calculation in the function
module.
# 2. Open questions
None.
# 3. Context
- Function group {{P}}FG_HR exists in package $TMP.
- Function module {{P}}APPL_SAMPLE exists in this group. It shows the
parameter style of the group.
- Create all new objects in package $TMP.
# 4. Contract
## 4.1 Function module {{P}}APPL_SCORE
Create the function module {{P}}APPL_SCORE in function group {{P}}FG_HR.
Use this interface:
```
FUNCTION {{p}}appl_score
IMPORTING
iv_years TYPE i
iv_degree TYPE string
iv_match TYPE i
EXPORTING
ev_score TYPE i
ev_rating TYPE string
EXCEPTIONS
invalid_years
invalid_match
invalid_degree.
```
## 4.2 Class {{P}}APP_SCORER
Create the class {{P}}APP_SCORER. The class is public and final. The class has
a public constructor without parameters.
Public type TY_RESULT has these components:
| Component | Type | Meaning |
|-----------|-----------|---------------------------|
| STATUS | TY_STATUS | Result of the input check |
| SCORE | i | Score from 0 to 100 |
| RATING | string | Recommendation |
TY_STATUS is a character type of length 4. The values of STATUS are 'OK',
'YEAR', 'MATC' and 'DEGR'.
Public method EVALUATE:
```
METHODS evaluate
IMPORTING
iv_years TYPE i
iv_degree TYPE string
iv_match TYPE i
RETURNING
VALUE(rs_result) TYPE ty_result.
```
The method does not raise an exception.
# 5. Business rules
1. Input check. Use this order:
1. If IV_YEARS is less than 0, STATUS is 'YEAR'.
2. Else if IV_MATCH is less than 0 or greater than 100, STATUS is 'MATC'.
3. Else if IV_DEGREE is not 'PHD', 'MAS', 'BAC' or 'VOC', STATUS is 'DEGR'.
4. Else STATUS is 'OK'.
2. If STATUS is not 'OK', SCORE is 0 and RATING is empty.
3. Experience points: 8 points for each full year of experience. The maximum
is 40 points.
4. Education points: 'PHD' gives 30 points, 'MAS' 25 points, 'BAC' 20 points
and 'VOC' 10 points.
5. Skill points: IV_MATCH percent of 30 points. Round the result half up to a
whole number.
6. SCORE is the sum of the experience points, the education points and the
skill points.
7. RATING depends on SCORE:
- SCORE 75 or more: 'INVITE'
- SCORE 50 to 74: 'REVIEW'
- SCORE less than 50: 'REJECT'
8. The function module raises the exception that belongs to STATUS:
- 'YEAR' raises INVALID_YEARS
- 'MATC' raises INVALID_MATCH
- 'DEGR' raises INVALID_DEGREE
For STATUS 'OK' the function module raises no exception. It exports SCORE
and RATING.
# 6. Constraints
- Release target: ABAP Platform 2025 (SAP_BASIS 816).
- Coding standard: Clean ABAP. Each method has less than 40 statements.
- No ATC finding of priority 1 or 2.
- Out of scope: do not change {{P}}APPL_SAMPLE.
# 7. Acceptance
- {{P}}APPL_SCORE and {{P}}APP_SCORER are active and have no syntax error.
- The hidden tests pass.
- Write ABAP Unit tests for the class in local test classes of the class.
- Write ABAP Unit tests for the function module in a global test class.

Some files were not shown because too many files have changed in this diff Show More