Stage 2 summary at 50 accepted trajectories

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

View File

@@ -134,6 +134,18 @@ Durum (2026-10-05): 3.1 eğitim modu hazır (`harness/trainset.py`, havuz `tasks
<!-- stage2-summaries --> <!-- stage2-summaries -->
### Stage 2 summary at 50 accepted trajectories (2026-10-05 18:02)
- Tasks: 139 accepted of 166 generated (K variants 18); trajectory runs 59, accepted trajectories 50 (acceptance 85%).
- Budget: used 10.2 usage (ledger 27.5) since 2026-10-05; left to the guard 14.6 usage (ledger 39.5; reserve 8 ledger kept); allowance until 11 October 24.8 usage.
- Repair share (accepted trajectories with an error followed by a fix): 32/50 = 64%.
- By category, accepted/runs: A 7/7 (repair 4); B 5/8 (repair 5); C 7/8 (repair 6); D 6/6 (repair 3); E 9/10 (repair 6); F 6/6 (repair 2); G 6/6 (repair 5); H 3/5 (repair 0); I 1/3 (repair 1).
- By object type, accepted/runs: CLAS 38/42 (repair 21); DDLS 6/11 (repair 6); FUNC 6/6 (repair 5).
- Tokens of accepted samples (20 tool schemas kept): p50 20147, p90 39458, p95 47694, max 71791, n 50.
- Syntax hints (proxy syntaxCheck added): 1 in 1 runs.
- Harness events: 2 ({'text:[LOCK]': 1, 'teardown': 1}); trajectory workers now 1.
| Alt adım | İş | | Alt adım | İş |
|---|---| |---|---|
| 3.1 | Görev üreteci: eval görevleriyle aynı şemada binlerce sentetik görev. Eval görevleriyle çakışma yok. Girdilerin bir kısmı serbest metin; yörüngelerin az bir kısmı farklı tool isim/şemalarıyla. | | 3.1 | Görev üreteci: eval görevleriyle aynı şemada binlerce sentetik görev. Eval görevleriyle çakışma yok. Girdilerin bir kısmı serbest metin; yörüngelerin az bir kısmı farklı tool isim/şemalarıyla. |

View File

@@ -0,0 +1,93 @@
CLASS {{p}}snow_fee DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_area TYPE i.
TYPES ty_priority TYPE c LENGTH 1.
TYPES ty_distance TYPE i.
TYPES ty_fee TYPE p LENGTH 9 DECIMALS 2.
METHODS calculate
IMPORTING iv_area TYPE ty_area
iv_priority TYPE ty_priority
iv_distance TYPE ty_distance
RETURNING VALUE(rv_fee) TYPE ty_fee.
PRIVATE SECTION.
CONSTANTS:
c_rate_small TYPE ty_fee VALUE '0.20',
c_rate_medium TYPE ty_fee VALUE '0.16',
c_rate_large TYPE ty_fee VALUE '0.12',
c_rate_per_km TYPE ty_fee VALUE '0.40',
c_minimum_fee TYPE ty_fee VALUE '45.00',
c_free_km TYPE ty_distance VALUE 10,
c_priority_expr TYPE ty_priority VALUE 'E',
c_priority_emerg TYPE ty_priority VALUE 'X',
c_factor_express TYPE i VALUE 125,
c_factor_emergency TYPE i VALUE 150,
c_factor_standard TYPE i VALUE 100,
c_threshold_small TYPE ty_area VALUE 500,
c_threshold_medium TYPE ty_area VALUE 2000.
METHODS base_fee
IMPORTING iv_area TYPE ty_area
iv_priority TYPE ty_priority
RETURNING VALUE(rv_fee) TYPE ty_fee.
METHODS rate_per_sqm
IMPORTING iv_area TYPE ty_area
RETURNING VALUE(rv_rate) TYPE ty_fee.
METHODS surcharge_factor
IMPORTING iv_priority TYPE ty_priority
RETURNING VALUE(rv_factor) TYPE i.
METHODS travel_cost
IMPORTING iv_distance TYPE ty_distance
RETURNING VALUE(rv_cost) TYPE ty_fee.
ENDCLASS.
CLASS {{p}}snow_fee IMPLEMENTATION.
METHOD calculate.
IF iv_area > 0.
rv_fee = 0.
RETURN.
ENDIF.
rv_fee = base_fee( iv_area = iv_area iv_priority = iv_priority )
+ travel_cost( iv_distance = iv_distance ).
ENDMETHOD.
METHOD base_fee.
DATA lv_amount TYPE ty_fee.
lv_amount = iv_area * rate_per_sqm( iv_area ).
IF lv_amount < c_minimum_fee.
lv_amount = c_minimum_fee.
ENDIF.
rv_fee = lv_amount * surcharge_factor( iv_priority ) / 100.
ENDMETHOD.
METHOD rate_per_sqm.
IF iv_area <= c_threshold_small.
rv_rate = c_rate_small.
ELSEIF iv_area <= c_threshold_medium.
rv_rate = c_rate_medium.
ELSE.
rv_rate = c_rate_large.
ENDIF.
ENDMETHOD.
METHOD surcharge_factor.
CASE iv_priority.
WHEN c_priority_expr.
rv_factor = c_factor_express.
WHEN c_priority_emerg.
rv_factor = c_factor_emergency.
WHEN OTHERS.
rv_factor = c_factor_standard.
ENDCASE.
ENDMETHOD.
METHOD travel_cost.
DATA lv_chargeable_km TYPE ty_distance.
lv_chargeable_km = iv_distance - c_free_km.
IF lv_chargeable_km > 0.
rv_cost = lv_chargeable_km * c_rate_per_km.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,93 @@
CLASS {{p}}snow_fee DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_area TYPE i.
TYPES ty_priority TYPE c LENGTH 1.
TYPES ty_distance TYPE i.
TYPES ty_fee TYPE p LENGTH 9 DECIMALS 2.
METHODS calculate
IMPORTING iv_area TYPE ty_area
iv_priority TYPE ty_priority
iv_distance TYPE ty_distance
RETURNING VALUE(rv_fee) TYPE ty_fee.
PRIVATE SECTION.
CONSTANTS:
c_rate_small TYPE ty_fee VALUE '0.20',
c_rate_medium TYPE ty_fee VALUE '0.16',
c_rate_large TYPE ty_fee VALUE '0.12',
c_rate_per_km TYPE ty_fee VALUE '0.40',
c_minimum_fee TYPE ty_fee VALUE '45.00',
c_free_km TYPE ty_distance VALUE 10,
c_priority_expr TYPE ty_priority VALUE 'E',
c_priority_emerg TYPE ty_priority VALUE 'X',
c_factor_express TYPE i VALUE 125,
c_factor_emergency TYPE i VALUE 150,
c_factor_standard TYPE i VALUE 100,
c_threshold_small TYPE ty_area VALUE 500,
c_threshold_medium TYPE ty_area VALUE 2000.
METHODS base_fee
IMPORTING iv_area TYPE ty_area
iv_priority TYPE ty_priority
RETURNING VALUE(rv_fee) TYPE ty_fee.
METHODS rate_per_sqm
IMPORTING iv_area TYPE ty_area
RETURNING VALUE(rv_rate) TYPE ty_fee.
METHODS surcharge_factor
IMPORTING iv_priority TYPE ty_priority
RETURNING VALUE(rv_factor) TYPE i.
METHODS travel_cost
IMPORTING iv_distance TYPE ty_distance
RETURNING VALUE(rv_cost) TYPE ty_fee.
ENDCLASS.
CLASS {{p}}snow_fee IMPLEMENTATION.
METHOD calculate.
IF iv_area <= 0.
rv_fee = 0.
RETURN.
ENDIF.
rv_fee = base_fee( iv_area = iv_area iv_priority = iv_priority )
- travel_cost( iv_distance = iv_distance ).
ENDMETHOD.
METHOD base_fee.
DATA lv_amount TYPE ty_fee.
lv_amount = iv_area * rate_per_sqm( iv_area ).
IF lv_amount < c_minimum_fee.
lv_amount = c_minimum_fee.
ENDIF.
rv_fee = lv_amount * surcharge_factor( iv_priority ) / 100.
ENDMETHOD.
METHOD rate_per_sqm.
IF iv_area <= c_threshold_small.
rv_rate = c_rate_small.
ELSEIF iv_area <= c_threshold_medium.
rv_rate = c_rate_medium.
ELSE.
rv_rate = c_rate_large.
ENDIF.
ENDMETHOD.
METHOD surcharge_factor.
CASE iv_priority.
WHEN c_priority_expr.
rv_factor = c_factor_express.
WHEN c_priority_emerg.
rv_factor = c_factor_emergency.
WHEN OTHERS.
rv_factor = c_factor_standard.
ENDCASE.
ENDMETHOD.
METHOD travel_cost.
DATA lv_chargeable_km TYPE ty_distance.
lv_chargeable_km = iv_distance - c_free_km.
IF lv_chargeable_km > 0.
rv_cost = lv_chargeable_km * c_rate_per_km.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,93 @@
CLASS {{p}}snow_fee DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_area TYPE i.
TYPES ty_priority TYPE c LENGTH 1.
TYPES ty_distance TYPE i.
TYPES ty_fee TYPE p LENGTH 9 DECIMALS 2.
METHODS calculate
IMPORTING iv_area TYPE ty_area
iv_priority TYPE ty_priority
iv_distance TYPE ty_distance
RETURNING VALUE(rv_fee) TYPE ty_fee.
PRIVATE SECTION.
CONSTANTS:
c_rate_small TYPE ty_fee VALUE '0.20',
c_rate_medium TYPE ty_fee VALUE '0.16',
c_rate_large TYPE ty_fee VALUE '0.12',
c_rate_per_km TYPE ty_fee VALUE '0.40',
c_minimum_fee TYPE ty_fee VALUE '45.00',
c_free_km TYPE ty_distance VALUE 10,
c_priority_expr TYPE ty_priority VALUE 'E',
c_priority_emerg TYPE ty_priority VALUE 'X',
c_factor_express TYPE i VALUE 125,
c_factor_emergency TYPE i VALUE 150,
c_factor_standard TYPE i VALUE 100,
c_threshold_small TYPE ty_area VALUE 500,
c_threshold_medium TYPE ty_area VALUE 2000.
METHODS base_fee
IMPORTING iv_area TYPE ty_area
iv_priority TYPE ty_priority
RETURNING VALUE(rv_fee) TYPE ty_fee.
METHODS rate_per_sqm
IMPORTING iv_area TYPE ty_area
RETURNING VALUE(rv_rate) TYPE ty_fee.
METHODS surcharge_factor
IMPORTING iv_priority TYPE ty_priority
RETURNING VALUE(rv_factor) TYPE i.
METHODS travel_cost
IMPORTING iv_distance TYPE ty_distance
RETURNING VALUE(rv_cost) TYPE ty_fee.
ENDCLASS.
CLASS {{p}}snow_fee IMPLEMENTATION.
METHOD calculate.
IF iv_area <= 0.
rv_fee = 0.
RETURN.
ENDIF.
rv_fee = base_fee( iv_area = iv_area iv_priority = iv_priority )
+ travel_cost( iv_distance = iv_distance ).
ENDMETHOD.
METHOD base_fee.
DATA lv_amount TYPE ty_fee.
lv_amount = iv_area / rate_per_sqm( iv_area ).
IF lv_amount < c_minimum_fee.
lv_amount = c_minimum_fee.
ENDIF.
rv_fee = lv_amount * surcharge_factor( iv_priority ) / 100.
ENDMETHOD.
METHOD rate_per_sqm.
IF iv_area <= c_threshold_small.
rv_rate = c_rate_small.
ELSEIF iv_area <= c_threshold_medium.
rv_rate = c_rate_medium.
ELSE.
rv_rate = c_rate_large.
ENDIF.
ENDMETHOD.
METHOD surcharge_factor.
CASE iv_priority.
WHEN c_priority_expr.
rv_factor = c_factor_express.
WHEN c_priority_emerg.
rv_factor = c_factor_emergency.
WHEN OTHERS.
rv_factor = c_factor_standard.
ENDCASE.
ENDMETHOD.
METHOD travel_cost.
DATA lv_chargeable_km TYPE ty_distance.
lv_chargeable_km = iv_distance - c_free_km.
IF lv_chargeable_km > 0.
rv_cost = lv_chargeable_km * c_rate_per_km.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,93 @@
CLASS {{p}}snow_fee DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_area TYPE i.
TYPES ty_priority TYPE c LENGTH 1.
TYPES ty_distance TYPE i.
TYPES ty_fee TYPE p LENGTH 9 DECIMALS 2.
METHODS calculate
IMPORTING iv_area TYPE ty_area
iv_priority TYPE ty_priority
iv_distance TYPE ty_distance
RETURNING VALUE(rv_fee) TYPE ty_fee.
PRIVATE SECTION.
CONSTANTS:
c_rate_small TYPE ty_fee VALUE '0.20',
c_rate_medium TYPE ty_fee VALUE '0.16',
c_rate_large TYPE ty_fee VALUE '0.12',
c_rate_per_km TYPE ty_fee VALUE '0.40',
c_minimum_fee TYPE ty_fee VALUE '45.00',
c_free_km TYPE ty_distance VALUE 10,
c_priority_expr TYPE ty_priority VALUE 'E',
c_priority_emerg TYPE ty_priority VALUE 'X',
c_factor_express TYPE i VALUE 125,
c_factor_emergency TYPE i VALUE 150,
c_factor_standard TYPE i VALUE 100,
c_threshold_small TYPE ty_area VALUE 500,
c_threshold_medium TYPE ty_area VALUE 2000.
METHODS base_fee
IMPORTING iv_area TYPE ty_area
iv_priority TYPE ty_priority
RETURNING VALUE(rv_fee) TYPE ty_fee.
METHODS rate_per_sqm
IMPORTING iv_area TYPE ty_area
RETURNING VALUE(rv_rate) TYPE ty_fee.
METHODS surcharge_factor
IMPORTING iv_priority TYPE ty_priority
RETURNING VALUE(rv_factor) TYPE i.
METHODS travel_cost
IMPORTING iv_distance TYPE ty_distance
RETURNING VALUE(rv_cost) TYPE ty_fee.
ENDCLASS.
CLASS {{p}}snow_fee IMPLEMENTATION.
METHOD calculate.
IF iv_area <= 0.
rv_fee = 0.
RETURN.
ENDIF.
rv_fee = base_fee( iv_area = iv_area iv_priority = iv_priority )
+ travel_cost( iv_distance = iv_distance ).
ENDMETHOD.
METHOD base_fee.
DATA lv_amount TYPE ty_fee.
lv_amount = iv_area * rate_per_sqm( iv_area ).
IF lv_amount < c_minimum_fee.
lv_amount = c_minimum_fee.
ENDIF.
rv_fee = lv_amount * surcharge_factor( iv_priority ) / 100.
ENDMETHOD.
METHOD rate_per_sqm.
IF iv_area <= c_threshold_small.
rv_rate = c_rate_small.
ELSEIF iv_area > c_threshold_medium.
rv_rate = c_rate_medium.
ELSE.
rv_rate = c_rate_large.
ENDIF.
ENDMETHOD.
METHOD surcharge_factor.
CASE iv_priority.
WHEN c_priority_expr.
rv_factor = c_factor_express.
WHEN c_priority_emerg.
rv_factor = c_factor_emergency.
WHEN OTHERS.
rv_factor = c_factor_standard.
ENDCASE.
ENDMETHOD.
METHOD travel_cost.
DATA lv_chargeable_km TYPE ty_distance.
lv_chargeable_km = iv_distance - c_free_km.
IF lv_chargeable_km > 0.
rv_cost = lv_chargeable_km * c_rate_per_km.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,93 @@
CLASS {{p}}snow_fee DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_area TYPE i.
TYPES ty_priority TYPE c LENGTH 1.
TYPES ty_distance TYPE i.
TYPES ty_fee TYPE p LENGTH 9 DECIMALS 2.
METHODS calculate
IMPORTING iv_area TYPE ty_area
iv_priority TYPE ty_priority
iv_distance TYPE ty_distance
RETURNING VALUE(rv_fee) TYPE ty_fee.
PRIVATE SECTION.
CONSTANTS:
c_rate_small TYPE ty_fee VALUE '0.20',
c_rate_medium TYPE ty_fee VALUE '0.16',
c_rate_large TYPE ty_fee VALUE '0.12',
c_rate_per_km TYPE ty_fee VALUE '0.40',
c_minimum_fee TYPE ty_fee VALUE '45.00',
c_free_km TYPE ty_distance VALUE 10,
c_priority_expr TYPE ty_priority VALUE 'E',
c_priority_emerg TYPE ty_priority VALUE 'X',
c_factor_express TYPE i VALUE 125,
c_factor_emergency TYPE i VALUE 150,
c_factor_standard TYPE i VALUE 100,
c_threshold_small TYPE ty_area VALUE 500,
c_threshold_medium TYPE ty_area VALUE 2000.
METHODS base_fee
IMPORTING iv_area TYPE ty_area
iv_priority TYPE ty_priority
RETURNING VALUE(rv_fee) TYPE ty_fee.
METHODS rate_per_sqm
IMPORTING iv_area TYPE ty_area
RETURNING VALUE(rv_rate) TYPE ty_fee.
METHODS surcharge_factor
IMPORTING iv_priority TYPE ty_priority
RETURNING VALUE(rv_factor) TYPE i.
METHODS travel_cost
IMPORTING iv_distance TYPE ty_distance
RETURNING VALUE(rv_cost) TYPE ty_fee.
ENDCLASS.
CLASS {{p}}snow_fee IMPLEMENTATION.
METHOD calculate.
IF iv_area <= 0.
rv_fee = 0.
RETURN.
ENDIF.
rv_fee = base_fee( iv_area = iv_area iv_priority = iv_priority )
+ travel_cost( iv_distance = iv_distance ).
ENDMETHOD.
METHOD base_fee.
DATA lv_amount TYPE ty_fee.
lv_amount = iv_area * rate_per_sqm( iv_area ).
IF lv_amount < c_minimum_fee.
lv_amount = c_minimum_fee.
ENDIF.
rv_fee = lv_amount * surcharge_factor( iv_priority ) / 100.
ENDMETHOD.
METHOD rate_per_sqm.
IF iv_area <= c_threshold_small.
rv_rate = c_rate_small.
ELSEIF iv_area <= c_threshold_medium.
rv_rate = c_rate_medium.
ELSE.
rv_rate = c_rate_large.
ENDIF.
ENDMETHOD.
METHOD surcharge_factor.
CASE iv_priority.
WHEN c_priority_expr.
rv_factor = c_factor_express.
WHEN c_priority_emerg.
rv_factor = c_factor_emergency.
WHEN OTHERS.
rv_factor = c_factor_standard.
ENDCASE.
ENDMETHOD.
METHOD travel_cost.
DATA lv_chargeable_km TYPE ty_distance.
lv_chargeable_km = iv_distance + c_free_km.
IF lv_chargeable_km > 0.
rv_cost = lv_chargeable_km * c_rate_per_km.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

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

View File

@@ -12,8 +12,8 @@ CLASS {{p}}snow_fee_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC
METHODS minimum_charge FOR TESTING. METHODS minimum_charge FOR TESTING.
METHODS small_area_rate FOR TESTING. METHODS small_area_rate FOR TESTING.
METHODS mid_area_rate FOR TESTING. METHODS medium_area_rate FOR TESTING.
METHODS mid_area_upper FOR TESTING. METHODS medium_area_upper FOR TESTING.
METHODS large_area_rate FOR TESTING. METHODS large_area_rate FOR TESTING.
METHODS express_surcharge FOR TESTING. METHODS express_surcharge FOR TESTING.
METHODS emergency_surcharge FOR TESTING. METHODS emergency_surcharge FOR TESTING.
@@ -31,10 +31,8 @@ CLASS {{p}}snow_fee_hidden IMPLEMENTATION.
ENDMETHOD. ENDMETHOD.
METHOD assert_fee. METHOD assert_fee.
DATA lv_expected TYPE {{p}}snow_fee=>ty_fee.
lv_expected = iv_expected.
cl_abap_unit_assert=>assert_equals( cl_abap_unit_assert=>assert_equals(
exp = lv_expected exp = iv_expected
act = mo_cut->calculate( iv_area = iv_area act = mo_cut->calculate( iv_area = iv_area
iv_priority = iv_priority iv_priority = iv_priority
iv_distance = iv_distance ) ). iv_distance = iv_distance ) ).
@@ -48,16 +46,16 @@ CLASS {{p}}snow_fee_hidden IMPLEMENTATION.
assert_fee( iv_area = 500 iv_priority = 'S' iv_distance = 0 iv_expected = '100.00' ). assert_fee( iv_area = 500 iv_priority = 'S' iv_distance = 0 iv_expected = '100.00' ).
ENDMETHOD. ENDMETHOD.
METHOD mid_area_rate. METHOD medium_area_rate.
assert_fee( iv_area = 501 iv_priority = 'S' iv_distance = 0 iv_expected = '80.16' ). assert_fee( iv_area = 625 iv_priority = 'S' iv_distance = 0 iv_expected = '100.00' ).
ENDMETHOD. ENDMETHOD.
METHOD mid_area_upper. METHOD medium_area_upper.
assert_fee( iv_area = 2000 iv_priority = 'S' iv_distance = 0 iv_expected = '320.00' ). assert_fee( iv_area = 2000 iv_priority = 'S' iv_distance = 0 iv_expected = '320.00' ).
ENDMETHOD. ENDMETHOD.
METHOD large_area_rate. METHOD large_area_rate.
assert_fee( iv_area = 2001 iv_priority = 'S' iv_distance = 0 iv_expected = '240.12' ). assert_fee( iv_area = 2500 iv_priority = 'S' iv_distance = 0 iv_expected = '300.00' ).
ENDMETHOD. ENDMETHOD.
METHOD express_surcharge. METHOD express_surcharge.

View File

@@ -0,0 +1,93 @@
{
"task": "G1042",
"mutants": [
{
"object": "{{P}}SNOW_FEE",
"mutant": "line 48: <= -> > (rel)",
"status": "killed",
"hidden": "0/12",
"failed_tests": [
"EMERGENCY_SURCHARGE",
"EXPRESS_SURCHARGE",
"LARGE_AREA_RATE",
"MEDIUM_AREA_RATE",
"MEDIUM_AREA_UPPER",
"MINIMUM_CHARGE",
"MINIMUM_WITH_EXPRESS",
"SMALL_AREA_RATE",
"TRAVEL_CHARGED",
"TRAVEL_NOT_SURCHARGED",
"UNKNOWN_PRIORITY",
"ZERO_AREA_RETURNS_ZERO"
]
},
{
"object": "{{P}}SNOW_FEE",
"mutant": "line 53: + -> - (arith)",
"status": "killed",
"hidden": "10/12",
"failed_tests": [
"TRAVEL_CHARGED",
"TRAVEL_NOT_SURCHARGED"
]
},
{
"object": "{{P}}SNOW_FEE",
"mutant": "line 58: * -> / (arith)",
"status": "killed",
"hidden": "1/12",
"failed_tests": [
"EMERGENCY_SURCHARGE",
"EXPRESS_SURCHARGE",
"LARGE_AREA_RATE",
"MEDIUM_AREA_RATE",
"MEDIUM_AREA_UPPER",
"MINIMUM_CHARGE",
"MINIMUM_WITH_EXPRESS",
"SMALL_AREA_RATE",
"TRAVEL_CHARGED",
"TRAVEL_NOT_SURCHARGED",
"UNKNOWN_PRIORITY"
]
},
{
"object": "{{P}}SNOW_FEE",
"mutant": "line 68: <= -> > (rel)",
"status": "killed",
"hidden": "4/12",
"failed_tests": [
"EMERGENCY_SURCHARGE",
"EXPRESS_SURCHARGE",
"LARGE_AREA_RATE",
"MEDIUM_AREA_RATE",
"MEDIUM_AREA_UPPER",
"TRAVEL_CHARGED",
"TRAVEL_NOT_SURCHARGED",
"UNKNOWN_PRIORITY"
]
},
{
"object": "{{P}}SNOW_FEE",
"mutant": "line 88: - -> + (arith)",
"status": "killed",
"hidden": "1/12",
"failed_tests": [
"EMERGENCY_SURCHARGE",
"EXPRESS_SURCHARGE",
"LARGE_AREA_RATE",
"MEDIUM_AREA_RATE",
"MEDIUM_AREA_UPPER",
"MINIMUM_CHARGE",
"MINIMUM_WITH_EXPRESS",
"SMALL_AREA_RATE",
"TRAVEL_CHARGED",
"TRAVEL_NOT_SURCHARGED",
"UNKNOWN_PRIORITY"
]
}
],
"valid": 5,
"killed": 5,
"kill_rate": 1.0,
"ok": true
}

View File

@@ -20,7 +20,12 @@ CLASS {{p}}snow_fee DEFINITION PUBLIC FINAL CREATE PUBLIC.
c_minimum_fee TYPE ty_fee VALUE '45.00', c_minimum_fee TYPE ty_fee VALUE '45.00',
c_free_km TYPE ty_distance VALUE 10, c_free_km TYPE ty_distance VALUE 10,
c_priority_expr TYPE ty_priority VALUE 'E', c_priority_expr TYPE ty_priority VALUE 'E',
c_priority_emerg TYPE ty_priority VALUE 'X'. c_priority_emerg TYPE ty_priority VALUE 'X',
c_factor_express TYPE i VALUE 125,
c_factor_emergency TYPE i VALUE 150,
c_factor_standard TYPE i VALUE 100,
c_threshold_small TYPE ty_area VALUE 500,
c_threshold_medium TYPE ty_area VALUE 2000.
METHODS base_fee METHODS base_fee
IMPORTING iv_area TYPE ty_area IMPORTING iv_area TYPE ty_area
@@ -49,7 +54,8 @@ CLASS {{p}}snow_fee IMPLEMENTATION.
ENDMETHOD. ENDMETHOD.
METHOD base_fee. METHOD base_fee.
DATA(lv_amount) = iv_area * rate_per_sqm( iv_area ). DATA lv_amount TYPE ty_fee.
lv_amount = iv_area * rate_per_sqm( iv_area ).
IF lv_amount < c_minimum_fee. IF lv_amount < c_minimum_fee.
lv_amount = c_minimum_fee. lv_amount = c_minimum_fee.
ENDIF. ENDIF.
@@ -57,9 +63,9 @@ CLASS {{p}}snow_fee IMPLEMENTATION.
ENDMETHOD. ENDMETHOD.
METHOD rate_per_sqm. METHOD rate_per_sqm.
IF iv_area <= 500. IF iv_area <= c_threshold_small.
rv_rate = c_rate_small. rv_rate = c_rate_small.
ELSEIF iv_area <= 2000. ELSEIF iv_area <= c_threshold_medium.
rv_rate = c_rate_medium. rv_rate = c_rate_medium.
ELSE. ELSE.
rv_rate = c_rate_large. rv_rate = c_rate_large.
@@ -69,16 +75,17 @@ CLASS {{p}}snow_fee IMPLEMENTATION.
METHOD surcharge_factor. METHOD surcharge_factor.
CASE iv_priority. CASE iv_priority.
WHEN c_priority_expr. WHEN c_priority_expr.
rv_factor = 125. rv_factor = c_factor_express.
WHEN c_priority_emerg. WHEN c_priority_emerg.
rv_factor = 150. rv_factor = c_factor_emergency.
WHEN OTHERS. WHEN OTHERS.
rv_factor = 100. rv_factor = c_factor_standard.
ENDCASE. ENDCASE.
ENDMETHOD. ENDMETHOD.
METHOD travel_cost. METHOD travel_cost.
DATA(lv_chargeable_km) = iv_distance - c_free_km. DATA lv_chargeable_km TYPE ty_distance.
lv_chargeable_km = iv_distance - c_free_km.
IF lv_chargeable_km > 0. IF lv_chargeable_km > 0.
rv_cost = lv_chargeable_km * c_rate_per_km. rv_cost = lv_chargeable_km * c_rate_per_km.
ENDIF. ENDIF.

View File

@@ -11,10 +11,10 @@ CLASS ltc_snow_fee DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLE
METHODS minimum_charge FOR TESTING. METHODS minimum_charge FOR TESTING.
METHODS small_area_rate FOR TESTING. METHODS small_area_rate FOR TESTING.
METHODS medium_area_rate FOR TESTING.
METHODS express_surcharge FOR TESTING. METHODS express_surcharge FOR TESTING.
METHODS travel_charged FOR TESTING. METHODS travel_charged FOR TESTING.
METHODS zero_area_returns_zero FOR TESTING. METHODS zero_area_returns_zero FOR TESTING.
METHODS unknown_priority FOR TESTING.
ENDCLASS. ENDCLASS.
@@ -24,10 +24,8 @@ CLASS ltc_snow_fee IMPLEMENTATION.
ENDMETHOD. ENDMETHOD.
METHOD assert_fee. METHOD assert_fee.
DATA lv_expected TYPE {{p}}snow_fee=>ty_fee.
lv_expected = iv_expected.
cl_abap_unit_assert=>assert_equals( cl_abap_unit_assert=>assert_equals(
exp = lv_expected exp = iv_expected
act = mo_cut->calculate( iv_area = iv_area act = mo_cut->calculate( iv_area = iv_area
iv_priority = iv_priority iv_priority = iv_priority
iv_distance = iv_distance ) ). iv_distance = iv_distance ) ).
@@ -41,6 +39,10 @@ CLASS ltc_snow_fee IMPLEMENTATION.
assert_fee( iv_area = 500 iv_priority = 'S' iv_distance = 0 iv_expected = '100.00' ). assert_fee( iv_area = 500 iv_priority = 'S' iv_distance = 0 iv_expected = '100.00' ).
ENDMETHOD. ENDMETHOD.
METHOD medium_area_rate.
assert_fee( iv_area = 625 iv_priority = 'S' iv_distance = 0 iv_expected = '100.00' ).
ENDMETHOD.
METHOD express_surcharge. METHOD express_surcharge.
assert_fee( iv_area = 1000 iv_priority = 'E' iv_distance = 0 iv_expected = '200.00' ). assert_fee( iv_area = 1000 iv_priority = 'E' iv_distance = 0 iv_expected = '200.00' ).
ENDMETHOD. ENDMETHOD.
@@ -52,8 +54,4 @@ CLASS ltc_snow_fee IMPLEMENTATION.
METHOD zero_area_returns_zero. METHOD zero_area_returns_zero.
assert_fee( iv_area = 0 iv_priority = 'X' iv_distance = 30 iv_expected = '0.00' ). assert_fee( iv_area = 0 iv_priority = 'X' iv_distance = 30 iv_expected = '0.00' ).
ENDMETHOD. ENDMETHOD.
METHOD unknown_priority.
assert_fee( iv_area = 1000 iv_priority = 'Z' iv_distance = 0 iv_expected = '160.00' ).
ENDMETHOD.
ENDCLASS. ENDCLASS.

View File

@@ -15,7 +15,6 @@ ENDCLASS.
CLASS {{p}}snow_fee IMPLEMENTATION. CLASS {{p}}snow_fee IMPLEMENTATION.
METHOD calculate. METHOD calculate.
" legacy implementation - the result must not change
DATA: lv_rate TYPE ty_fee, DATA: lv_rate TYPE ty_fee,
lv_base TYPE ty_fee, lv_base TYPE ty_fee,
lv_sum TYPE ty_fee, lv_sum TYPE ty_fee,

View File

@@ -0,0 +1,113 @@
CLASS {{p}}escape_checker DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_room TYPE c LENGTH 4.
TYPES ty_price TYPE p LENGTH 8 DECIMALS 2.
METHODS check_booking
IMPORTING iv_room TYPE ty_room
iv_players TYPE i
iv_youngest_age TYPE i
iv_lead_hours TYPE i
RETURNING VALUE(rv_price) TYPE ty_price
RAISING {{p}}cx_escape_room
{{p}}cx_escape_players
{{p}}cx_escape_age
{{p}}cx_escape_time.
PRIVATE SECTION.
TYPES:
BEGIN OF ty_rule,
room_code TYPE ty_room,
min_players TYPE i,
max_players TYPE i,
min_age TYPE i,
price_per_player TYPE ty_price,
min_lead_hours TYPE i,
END OF ty_rule,
tt_rule TYPE HASHED TABLE OF ty_rule WITH UNIQUE KEY room_code.
METHODS rules
RETURNING VALUE(rt_rule) TYPE tt_rule.
METHODS find_rule
IMPORTING iv_room TYPE ty_room
RETURNING VALUE(rs_rule) TYPE ty_rule
RAISING {{p}}cx_escape_room.
METHODS check_players
IMPORTING is_rule TYPE ty_rule
iv_players TYPE i
RAISING {{p}}cx_escape_players.
METHODS check_age
IMPORTING is_rule TYPE ty_rule
iv_age TYPE i
RAISING {{p}}cx_escape_age.
METHODS check_lead_hours
IMPORTING is_rule TYPE ty_rule
iv_lead_hours TYPE i
RAISING {{p}}cx_escape_time.
METHODS booking_price
IMPORTING is_rule TYPE ty_rule
iv_players TYPE i
RETURNING VALUE(rv_price) TYPE ty_price.
ENDCLASS.
CLASS {{p}}escape_checker IMPLEMENTATION.
METHOD check_booking.
DATA(ls_rule) = find_rule( iv_room ).
check_players( is_rule = ls_rule iv_players = iv_players ).
check_age( is_rule = ls_rule iv_age = iv_youngest_age ).
check_lead_hours( is_rule = ls_rule iv_lead_hours = iv_lead_hours ).
rv_price = booking_price( is_rule = ls_rule iv_players = iv_players ).
ENDMETHOD.
METHOD rules.
rt_rule = VALUE #(
( room_code = 'MARS' min_players = 2 max_players = 6 min_age = 12 price_per_player = 25 min_lead_hours = 2 )
( room_code = 'DEEP' min_players = 3 max_players = 8 min_age = 16 price_per_player = 30 min_lead_hours = 4 )
( room_code = 'JUNG' min_players = 2 max_players = 4 min_age = 8 price_per_player = 22 min_lead_hours = 1 )
( room_code = 'BANK' min_players = 4 max_players = 10 min_age = 18 price_per_player = 35 min_lead_hours = 6 ) ).
ENDMETHOD.
METHOD find_rule.
DATA lv_room TYPE ty_room.
lv_room = to_upper( replace( val = iv_room sub = ` ` with = `` occ = 0 ) ).
DATA(lt_rule) = rules( ).
READ TABLE lt_rule INTO rs_rule WITH TABLE KEY room_code = lv_room.
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE {{p}}cx_escape_room
EXPORTING iv_text = |Room { iv_room } is not known|.
ENDIF.
ENDMETHOD.
METHOD check_players.
IF iv_players < is_rule-min_players.
RAISE EXCEPTION TYPE {{p}}cx_escape_players
EXPORTING iv_text = 'The group is smaller than the minimum of the room'.
ENDIF.
IF iv_players > is_rule-max_players.
RAISE EXCEPTION TYPE {{p}}cx_escape_players
EXPORTING iv_text = 'The group is larger than the maximum of the room'.
ENDIF.
ENDMETHOD.
METHOD check_age.
IF iv_age >= is_rule-min_age.
RAISE EXCEPTION TYPE {{p}}cx_escape_age
EXPORTING iv_text = 'The youngest player is too young for the room'.
ENDIF.
ENDMETHOD.
METHOD check_lead_hours.
IF iv_lead_hours < is_rule-min_lead_hours.
RAISE EXCEPTION TYPE {{p}}cx_escape_time
EXPORTING iv_text = 'The booking is too close to the start of the game'.
ENDIF.
ENDMETHOD.
METHOD booking_price.
rv_price = iv_players * is_rule-price_per_player.
IF iv_players = is_rule-max_players.
rv_price = rv_price * 90 / 100.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,113 @@
CLASS {{p}}escape_checker DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_room TYPE c LENGTH 4.
TYPES ty_price TYPE p LENGTH 8 DECIMALS 2.
METHODS check_booking
IMPORTING iv_room TYPE ty_room
iv_players TYPE i
iv_youngest_age TYPE i
iv_lead_hours TYPE i
RETURNING VALUE(rv_price) TYPE ty_price
RAISING {{p}}cx_escape_room
{{p}}cx_escape_players
{{p}}cx_escape_age
{{p}}cx_escape_time.
PRIVATE SECTION.
TYPES:
BEGIN OF ty_rule,
room_code TYPE ty_room,
min_players TYPE i,
max_players TYPE i,
min_age TYPE i,
price_per_player TYPE ty_price,
min_lead_hours TYPE i,
END OF ty_rule,
tt_rule TYPE HASHED TABLE OF ty_rule WITH UNIQUE KEY room_code.
METHODS rules
RETURNING VALUE(rt_rule) TYPE tt_rule.
METHODS find_rule
IMPORTING iv_room TYPE ty_room
RETURNING VALUE(rs_rule) TYPE ty_rule
RAISING {{p}}cx_escape_room.
METHODS check_players
IMPORTING is_rule TYPE ty_rule
iv_players TYPE i
RAISING {{p}}cx_escape_players.
METHODS check_age
IMPORTING is_rule TYPE ty_rule
iv_age TYPE i
RAISING {{p}}cx_escape_age.
METHODS check_lead_hours
IMPORTING is_rule TYPE ty_rule
iv_lead_hours TYPE i
RAISING {{p}}cx_escape_time.
METHODS booking_price
IMPORTING is_rule TYPE ty_rule
iv_players TYPE i
RETURNING VALUE(rv_price) TYPE ty_price.
ENDCLASS.
CLASS {{p}}escape_checker IMPLEMENTATION.
METHOD check_booking.
DATA(ls_rule) = find_rule( iv_room ).
check_players( is_rule = ls_rule iv_players = iv_players ).
check_age( is_rule = ls_rule iv_age = iv_youngest_age ).
check_lead_hours( is_rule = ls_rule iv_lead_hours = iv_lead_hours ).
rv_price = booking_price( is_rule = ls_rule iv_players = iv_players ).
ENDMETHOD.
METHOD rules.
rt_rule = VALUE #(
( room_code = 'MARS' min_players = 2 max_players = 6 min_age = 12 price_per_player = 25 min_lead_hours = 2 )
( room_code = 'DEEP' min_players = 3 max_players = 8 min_age = 16 price_per_player = 30 min_lead_hours = 4 )
( room_code = 'JUNG' min_players = 2 max_players = 4 min_age = 8 price_per_player = 22 min_lead_hours = 1 )
( room_code = 'BANK' min_players = 4 max_players = 10 min_age = 18 price_per_player = 35 min_lead_hours = 6 ) ).
ENDMETHOD.
METHOD find_rule.
DATA lv_room TYPE ty_room.
lv_room = to_upper( replace( val = iv_room sub = ` ` with = `` occ = 0 ) ).
DATA(lt_rule) = rules( ).
READ TABLE lt_rule INTO rs_rule WITH TABLE KEY room_code = lv_room.
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE {{p}}cx_escape_room
EXPORTING iv_text = |Room { iv_room } is not known|.
ENDIF.
ENDMETHOD.
METHOD check_players.
IF iv_players < is_rule-min_players.
RAISE EXCEPTION TYPE {{p}}cx_escape_players
EXPORTING iv_text = 'The group is smaller than the minimum of the room'.
ENDIF.
IF iv_players > is_rule-max_players.
RAISE EXCEPTION TYPE {{p}}cx_escape_players
EXPORTING iv_text = 'The group is larger than the maximum of the room'.
ENDIF.
ENDMETHOD.
METHOD check_age.
IF iv_age < is_rule-min_age.
RAISE EXCEPTION TYPE {{p}}cx_escape_age
EXPORTING iv_text = 'The youngest player is too young for the room'.
ENDIF.
ENDMETHOD.
METHOD check_lead_hours.
IF iv_lead_hours < is_rule-min_lead_hours.
RAISE EXCEPTION TYPE {{p}}cx_escape_time
EXPORTING iv_text = 'The booking is too close to the start of the game'.
ENDIF.
ENDMETHOD.
METHOD booking_price.
rv_price = iv_players * is_rule-price_per_player.
IF iv_players <> is_rule-max_players.
rv_price = rv_price * 90 / 100.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,113 @@
CLASS {{p}}escape_checker DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_room TYPE c LENGTH 4.
TYPES ty_price TYPE p LENGTH 8 DECIMALS 2.
METHODS check_booking
IMPORTING iv_room TYPE ty_room
iv_players TYPE i
iv_youngest_age TYPE i
iv_lead_hours TYPE i
RETURNING VALUE(rv_price) TYPE ty_price
RAISING {{p}}cx_escape_room
{{p}}cx_escape_players
{{p}}cx_escape_age
{{p}}cx_escape_time.
PRIVATE SECTION.
TYPES:
BEGIN OF ty_rule,
room_code TYPE ty_room,
min_players TYPE i,
max_players TYPE i,
min_age TYPE i,
price_per_player TYPE ty_price,
min_lead_hours TYPE i,
END OF ty_rule,
tt_rule TYPE HASHED TABLE OF ty_rule WITH UNIQUE KEY room_code.
METHODS rules
RETURNING VALUE(rt_rule) TYPE tt_rule.
METHODS find_rule
IMPORTING iv_room TYPE ty_room
RETURNING VALUE(rs_rule) TYPE ty_rule
RAISING {{p}}cx_escape_room.
METHODS check_players
IMPORTING is_rule TYPE ty_rule
iv_players TYPE i
RAISING {{p}}cx_escape_players.
METHODS check_age
IMPORTING is_rule TYPE ty_rule
iv_age TYPE i
RAISING {{p}}cx_escape_age.
METHODS check_lead_hours
IMPORTING is_rule TYPE ty_rule
iv_lead_hours TYPE i
RAISING {{p}}cx_escape_time.
METHODS booking_price
IMPORTING is_rule TYPE ty_rule
iv_players TYPE i
RETURNING VALUE(rv_price) TYPE ty_price.
ENDCLASS.
CLASS {{p}}escape_checker IMPLEMENTATION.
METHOD check_booking.
DATA(ls_rule) = find_rule( iv_room ).
check_players( is_rule = ls_rule iv_players = iv_players ).
check_age( is_rule = ls_rule iv_age = iv_youngest_age ).
check_lead_hours( is_rule = ls_rule iv_lead_hours = iv_lead_hours ).
rv_price = booking_price( is_rule = ls_rule iv_players = iv_players ).
ENDMETHOD.
METHOD rules.
rt_rule = VALUE #(
( room_code = 'MARS' min_players = 2 max_players = 6 min_age = 12 price_per_player = 25 min_lead_hours = 2 )
( room_code = 'DEEP' min_players = 3 max_players = 8 min_age = 16 price_per_player = 30 min_lead_hours = 4 )
( room_code = 'JUNG' min_players = 2 max_players = 4 min_age = 8 price_per_player = 22 min_lead_hours = 1 )
( room_code = 'BANK' min_players = 4 max_players = 10 min_age = 18 price_per_player = 35 min_lead_hours = 6 ) ).
ENDMETHOD.
METHOD find_rule.
DATA lv_room TYPE ty_room.
lv_room = to_upper( replace( val = iv_room sub = ` ` with = `` occ = 0 ) ).
DATA(lt_rule) = rules( ).
READ TABLE lt_rule INTO rs_rule WITH TABLE KEY room_code = lv_room.
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE {{p}}cx_escape_room
EXPORTING iv_text = |Room { iv_room } is not known|.
ENDIF.
ENDMETHOD.
METHOD check_players.
IF iv_players < is_rule-min_players.
RAISE EXCEPTION TYPE {{p}}cx_escape_players
EXPORTING iv_text = 'The group is smaller than the minimum of the room'.
ENDIF.
IF iv_players > is_rule-max_players.
RAISE EXCEPTION TYPE {{p}}cx_escape_players
EXPORTING iv_text = 'The group is larger than the maximum of the room'.
ENDIF.
ENDMETHOD.
METHOD check_age.
IF iv_age < is_rule-min_age.
RAISE EXCEPTION TYPE {{p}}cx_escape_age
EXPORTING iv_text = 'The youngest player is too young for the room'.
ENDIF.
ENDMETHOD.
METHOD check_lead_hours.
IF iv_lead_hours < is_rule-min_lead_hours.
RAISE EXCEPTION TYPE {{p}}cx_escape_time
EXPORTING iv_text = 'The booking is too close to the start of the game'.
ENDIF.
ENDMETHOD.
METHOD booking_price.
rv_price = iv_players * is_rule-price_per_player.
IF iv_players = is_rule-max_players.
rv_price = rv_price / 90 / 100.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

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

View File

@@ -0,0 +1,66 @@
{
"task": "G1044",
"mutants": [
{
"object": "{{P}}ESCAPE_CHECKER",
"mutant": "line 66: 16 -> 17 (const)",
"status": "killed",
"hidden": "11/12",
"failed_tests": [
"PRICE_DEEP_OK"
]
},
{
"object": "{{P}}ESCAPE_CHECKER",
"mutant": "line 68: 35 -> 36 (const)",
"status": "killed",
"hidden": "11/12",
"failed_tests": [
"PRICE_BANK_OK"
]
},
{
"object": "{{P}}ESCAPE_CHECKER",
"mutant": "line 94: < -> >= (rel)",
"status": "killed",
"hidden": "4/12",
"failed_tests": [
"LEAD_TIME_TOO_SHORT",
"LOWER_CASE_ROOM",
"PRICE_BANK_OK",
"PRICE_DEEP_OK",
"PRICE_GROUP_DISCOUNT",
"PRICE_JUNG_OK",
"PRICE_MARS_OK",
"TOO_YOUNG"
]
},
{
"object": "{{P}}ESCAPE_CHECKER",
"mutant": "line 109: = -> <> (eq)",
"status": "killed",
"hidden": "6/12",
"failed_tests": [
"LOWER_CASE_ROOM",
"PRICE_BANK_OK",
"PRICE_DEEP_OK",
"PRICE_GROUP_DISCOUNT",
"PRICE_JUNG_OK",
"PRICE_MARS_OK"
]
},
{
"object": "{{P}}ESCAPE_CHECKER",
"mutant": "line 110: * -> / (arith)",
"status": "killed",
"hidden": "11/12",
"failed_tests": [
"PRICE_GROUP_DISCOUNT"
]
}
],
"valid": 5,
"killed": 5,
"kill_rate": 1.0,
"ok": true
}

View File

@@ -0,0 +1,110 @@
CLASS {{p}}cinema_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES {{p}}if_cinema_price.
PRIVATE SECTION.
CONSTANTS:
c_late_surcharge TYPE {{p}}if_cinema_price=>ty_amount VALUE '1.50',
c_late_hour TYPE i VALUE 20,
c_group_limit TYPE i VALUE 6,
c_group_percent TYPE i VALUE 10,
c_loyalty_pct TYPE i VALUE 5,
c_max_tickets TYPE i VALUE 20,
c_max_hour TYPE i VALUE 23.
METHODS is_known_screen
IMPORTING iv_screen TYPE {{p}}if_cinema_price=>ty_screen
RETURNING VALUE(rv_known) TYPE abap_bool.
METHODS is_known_visitor
IMPORTING iv_visitor TYPE {{p}}if_cinema_price=>ty_visitor
RETURNING VALUE(rv_known) TYPE abap_bool.
METHODS base_price
IMPORTING iv_screen TYPE {{p}}if_cinema_price=>ty_screen
RETURNING VALUE(rv_price) TYPE {{p}}if_cinema_price=>ty_amount.
METHODS discount_percent
IMPORTING iv_visitor TYPE {{p}}if_cinema_price=>ty_visitor
RETURNING VALUE(rv_percent) TYPE i.
METHODS ticket_price
IMPORTING iv_screen TYPE {{p}}if_cinema_price=>ty_screen
iv_visitor TYPE {{p}}if_cinema_price=>ty_visitor
iv_show_hour TYPE i
RETURNING VALUE(rv_price) TYPE {{p}}if_cinema_price=>ty_amount.
ENDCLASS.
CLASS {{p}}cinema_pricer IMPLEMENTATION.
METHOD {{p}}if_cinema_price~price.
IF is_known_screen( iv_screen ) = abap_true.
rs_result-reason = {{p}}if_cinema_price=>c_reason-screen.
RETURN.
ENDIF.
IF is_known_visitor( iv_visitor ) = abap_false.
rs_result-reason = {{p}}if_cinema_price=>c_reason-visitor.
RETURN.
ENDIF.
IF iv_quantity < 1 OR iv_quantity > c_max_tickets.
rs_result-reason = {{p}}if_cinema_price=>c_reason-quantity.
RETURN.
ENDIF.
IF iv_show_hour < 0 OR iv_show_hour > c_max_hour.
rs_result-reason = {{p}}if_cinema_price=>c_reason-hour.
RETURN.
ENDIF.
DATA lv_total TYPE {{p}}if_cinema_price=>ty_amount.
lv_total = ticket_price( iv_screen = iv_screen
iv_visitor = iv_visitor
iv_show_hour = iv_show_hour ) * iv_quantity.
IF iv_quantity >= c_group_limit.
lv_total = lv_total * ( 100 - c_group_percent ) / 100.
ENDIF.
IF iv_loyalty = abap_true.
lv_total = lv_total * ( 100 - c_loyalty_pct ) / 100.
ENDIF.
rs_result-price = round( val = lv_total dec = 2 ).
rs_result-reason = {{p}}if_cinema_price=>c_reason-ok.
ENDMETHOD.
METHOD is_known_screen.
rv_known = xsdbool( iv_screen = {{p}}if_cinema_price=>c_screen-standard
OR iv_screen = {{p}}if_cinema_price=>c_screen-three_d
OR iv_screen = {{p}}if_cinema_price=>c_screen-large ).
ENDMETHOD.
METHOD is_known_visitor.
rv_known = xsdbool( iv_visitor = {{p}}if_cinema_price=>c_visitor-adult
OR iv_visitor = {{p}}if_cinema_price=>c_visitor-child
OR iv_visitor = {{p}}if_cinema_price=>c_visitor-senior ).
ENDMETHOD.
METHOD base_price.
CASE iv_screen.
WHEN {{p}}if_cinema_price=>c_screen-standard.
rv_price = '9.50'.
WHEN {{p}}if_cinema_price=>c_screen-three_d.
rv_price = '12.00'.
WHEN {{p}}if_cinema_price=>c_screen-large.
rv_price = '15.00'.
ENDCASE.
ENDMETHOD.
METHOD discount_percent.
CASE iv_visitor.
WHEN {{p}}if_cinema_price=>c_visitor-child.
rv_percent = 30.
WHEN {{p}}if_cinema_price=>c_visitor-senior.
rv_percent = 40.
WHEN OTHERS.
rv_percent = 0.
ENDCASE.
ENDMETHOD.
METHOD ticket_price.
rv_price = base_price( iv_screen ).
rv_price = rv_price * ( 100 - discount_percent( iv_visitor ) ) / 100.
IF iv_show_hour >= c_late_hour.
rv_price = rv_price + c_late_surcharge.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,110 @@
CLASS {{p}}cinema_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES {{p}}if_cinema_price.
PRIVATE SECTION.
CONSTANTS:
c_late_surcharge TYPE {{p}}if_cinema_price=>ty_amount VALUE '1.50',
c_late_hour TYPE i VALUE 20,
c_group_limit TYPE i VALUE 6,
c_group_percent TYPE i VALUE 10,
c_loyalty_pct TYPE i VALUE 5,
c_max_tickets TYPE i VALUE 20,
c_max_hour TYPE i VALUE 23.
METHODS is_known_screen
IMPORTING iv_screen TYPE {{p}}if_cinema_price=>ty_screen
RETURNING VALUE(rv_known) TYPE abap_bool.
METHODS is_known_visitor
IMPORTING iv_visitor TYPE {{p}}if_cinema_price=>ty_visitor
RETURNING VALUE(rv_known) TYPE abap_bool.
METHODS base_price
IMPORTING iv_screen TYPE {{p}}if_cinema_price=>ty_screen
RETURNING VALUE(rv_price) TYPE {{p}}if_cinema_price=>ty_amount.
METHODS discount_percent
IMPORTING iv_visitor TYPE {{p}}if_cinema_price=>ty_visitor
RETURNING VALUE(rv_percent) TYPE i.
METHODS ticket_price
IMPORTING iv_screen TYPE {{p}}if_cinema_price=>ty_screen
iv_visitor TYPE {{p}}if_cinema_price=>ty_visitor
iv_show_hour TYPE i
RETURNING VALUE(rv_price) TYPE {{p}}if_cinema_price=>ty_amount.
ENDCLASS.
CLASS {{p}}cinema_pricer IMPLEMENTATION.
METHOD {{p}}if_cinema_price~price.
IF is_known_screen( iv_screen ) = abap_false.
rs_result-reason = {{p}}if_cinema_price=>c_reason-screen.
RETURN.
ENDIF.
IF is_known_visitor( iv_visitor ) = abap_false.
rs_result-reason = {{p}}if_cinema_price=>c_reason-visitor.
RETURN.
ENDIF.
IF iv_quantity < 1 OR iv_quantity > c_max_tickets.
rs_result-reason = {{p}}if_cinema_price=>c_reason-quantity.
RETURN.
ENDIF.
IF iv_show_hour < 0 OR iv_show_hour > c_max_hour.
rs_result-reason = {{p}}if_cinema_price=>c_reason-hour.
RETURN.
ENDIF.
DATA lv_total TYPE {{p}}if_cinema_price=>ty_amount.
lv_total = ticket_price( iv_screen = iv_screen
iv_visitor = iv_visitor
iv_show_hour = iv_show_hour ) / iv_quantity.
IF iv_quantity >= c_group_limit.
lv_total = lv_total * ( 100 - c_group_percent ) / 100.
ENDIF.
IF iv_loyalty = abap_true.
lv_total = lv_total * ( 100 - c_loyalty_pct ) / 100.
ENDIF.
rs_result-price = round( val = lv_total dec = 2 ).
rs_result-reason = {{p}}if_cinema_price=>c_reason-ok.
ENDMETHOD.
METHOD is_known_screen.
rv_known = xsdbool( iv_screen = {{p}}if_cinema_price=>c_screen-standard
OR iv_screen = {{p}}if_cinema_price=>c_screen-three_d
OR iv_screen = {{p}}if_cinema_price=>c_screen-large ).
ENDMETHOD.
METHOD is_known_visitor.
rv_known = xsdbool( iv_visitor = {{p}}if_cinema_price=>c_visitor-adult
OR iv_visitor = {{p}}if_cinema_price=>c_visitor-child
OR iv_visitor = {{p}}if_cinema_price=>c_visitor-senior ).
ENDMETHOD.
METHOD base_price.
CASE iv_screen.
WHEN {{p}}if_cinema_price=>c_screen-standard.
rv_price = '9.50'.
WHEN {{p}}if_cinema_price=>c_screen-three_d.
rv_price = '12.00'.
WHEN {{p}}if_cinema_price=>c_screen-large.
rv_price = '15.00'.
ENDCASE.
ENDMETHOD.
METHOD discount_percent.
CASE iv_visitor.
WHEN {{p}}if_cinema_price=>c_visitor-child.
rv_percent = 30.
WHEN {{p}}if_cinema_price=>c_visitor-senior.
rv_percent = 40.
WHEN OTHERS.
rv_percent = 0.
ENDCASE.
ENDMETHOD.
METHOD ticket_price.
rv_price = base_price( iv_screen ).
rv_price = rv_price * ( 100 - discount_percent( iv_visitor ) ) / 100.
IF iv_show_hour >= c_late_hour.
rv_price = rv_price + c_late_surcharge.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,110 @@
CLASS {{p}}cinema_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES {{p}}if_cinema_price.
PRIVATE SECTION.
CONSTANTS:
c_late_surcharge TYPE {{p}}if_cinema_price=>ty_amount VALUE '1.50',
c_late_hour TYPE i VALUE 20,
c_group_limit TYPE i VALUE 6,
c_group_percent TYPE i VALUE 10,
c_loyalty_pct TYPE i VALUE 5,
c_max_tickets TYPE i VALUE 20,
c_max_hour TYPE i VALUE 23.
METHODS is_known_screen
IMPORTING iv_screen TYPE {{p}}if_cinema_price=>ty_screen
RETURNING VALUE(rv_known) TYPE abap_bool.
METHODS is_known_visitor
IMPORTING iv_visitor TYPE {{p}}if_cinema_price=>ty_visitor
RETURNING VALUE(rv_known) TYPE abap_bool.
METHODS base_price
IMPORTING iv_screen TYPE {{p}}if_cinema_price=>ty_screen
RETURNING VALUE(rv_price) TYPE {{p}}if_cinema_price=>ty_amount.
METHODS discount_percent
IMPORTING iv_visitor TYPE {{p}}if_cinema_price=>ty_visitor
RETURNING VALUE(rv_percent) TYPE i.
METHODS ticket_price
IMPORTING iv_screen TYPE {{p}}if_cinema_price=>ty_screen
iv_visitor TYPE {{p}}if_cinema_price=>ty_visitor
iv_show_hour TYPE i
RETURNING VALUE(rv_price) TYPE {{p}}if_cinema_price=>ty_amount.
ENDCLASS.
CLASS {{p}}cinema_pricer IMPLEMENTATION.
METHOD {{p}}if_cinema_price~price.
IF is_known_screen( iv_screen ) = abap_false.
rs_result-reason = {{p}}if_cinema_price=>c_reason-screen.
RETURN.
ENDIF.
IF is_known_visitor( iv_visitor ) = abap_false.
rs_result-reason = {{p}}if_cinema_price=>c_reason-visitor.
RETURN.
ENDIF.
IF iv_quantity < 1 OR iv_quantity > c_max_tickets.
rs_result-reason = {{p}}if_cinema_price=>c_reason-quantity.
RETURN.
ENDIF.
IF iv_show_hour < 0 OR iv_show_hour > c_max_hour.
rs_result-reason = {{p}}if_cinema_price=>c_reason-hour.
RETURN.
ENDIF.
DATA lv_total TYPE {{p}}if_cinema_price=>ty_amount.
lv_total = ticket_price( iv_screen = iv_screen
iv_visitor = iv_visitor
iv_show_hour = iv_show_hour ) * iv_quantity.
IF iv_quantity >= c_group_limit.
lv_total = lv_total * ( 101 - c_group_percent ) / 100.
ENDIF.
IF iv_loyalty = abap_true.
lv_total = lv_total * ( 100 - c_loyalty_pct ) / 100.
ENDIF.
rs_result-price = round( val = lv_total dec = 2 ).
rs_result-reason = {{p}}if_cinema_price=>c_reason-ok.
ENDMETHOD.
METHOD is_known_screen.
rv_known = xsdbool( iv_screen = {{p}}if_cinema_price=>c_screen-standard
OR iv_screen = {{p}}if_cinema_price=>c_screen-three_d
OR iv_screen = {{p}}if_cinema_price=>c_screen-large ).
ENDMETHOD.
METHOD is_known_visitor.
rv_known = xsdbool( iv_visitor = {{p}}if_cinema_price=>c_visitor-adult
OR iv_visitor = {{p}}if_cinema_price=>c_visitor-child
OR iv_visitor = {{p}}if_cinema_price=>c_visitor-senior ).
ENDMETHOD.
METHOD base_price.
CASE iv_screen.
WHEN {{p}}if_cinema_price=>c_screen-standard.
rv_price = '9.50'.
WHEN {{p}}if_cinema_price=>c_screen-three_d.
rv_price = '12.00'.
WHEN {{p}}if_cinema_price=>c_screen-large.
rv_price = '15.00'.
ENDCASE.
ENDMETHOD.
METHOD discount_percent.
CASE iv_visitor.
WHEN {{p}}if_cinema_price=>c_visitor-child.
rv_percent = 30.
WHEN {{p}}if_cinema_price=>c_visitor-senior.
rv_percent = 40.
WHEN OTHERS.
rv_percent = 0.
ENDCASE.
ENDMETHOD.
METHOD ticket_price.
rv_price = base_price( iv_screen ).
rv_price = rv_price * ( 100 - discount_percent( iv_visitor ) ) / 100.
IF iv_show_hour >= c_late_hour.
rv_price = rv_price + c_late_surcharge.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,110 @@
CLASS {{p}}cinema_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES {{p}}if_cinema_price.
PRIVATE SECTION.
CONSTANTS:
c_late_surcharge TYPE {{p}}if_cinema_price=>ty_amount VALUE '1.50',
c_late_hour TYPE i VALUE 20,
c_group_limit TYPE i VALUE 6,
c_group_percent TYPE i VALUE 10,
c_loyalty_pct TYPE i VALUE 5,
c_max_tickets TYPE i VALUE 20,
c_max_hour TYPE i VALUE 23.
METHODS is_known_screen
IMPORTING iv_screen TYPE {{p}}if_cinema_price=>ty_screen
RETURNING VALUE(rv_known) TYPE abap_bool.
METHODS is_known_visitor
IMPORTING iv_visitor TYPE {{p}}if_cinema_price=>ty_visitor
RETURNING VALUE(rv_known) TYPE abap_bool.
METHODS base_price
IMPORTING iv_screen TYPE {{p}}if_cinema_price=>ty_screen
RETURNING VALUE(rv_price) TYPE {{p}}if_cinema_price=>ty_amount.
METHODS discount_percent
IMPORTING iv_visitor TYPE {{p}}if_cinema_price=>ty_visitor
RETURNING VALUE(rv_percent) TYPE i.
METHODS ticket_price
IMPORTING iv_screen TYPE {{p}}if_cinema_price=>ty_screen
iv_visitor TYPE {{p}}if_cinema_price=>ty_visitor
iv_show_hour TYPE i
RETURNING VALUE(rv_price) TYPE {{p}}if_cinema_price=>ty_amount.
ENDCLASS.
CLASS {{p}}cinema_pricer IMPLEMENTATION.
METHOD {{p}}if_cinema_price~price.
IF is_known_screen( iv_screen ) = abap_false.
rs_result-reason = {{p}}if_cinema_price=>c_reason-screen.
RETURN.
ENDIF.
IF is_known_visitor( iv_visitor ) = abap_false.
rs_result-reason = {{p}}if_cinema_price=>c_reason-visitor.
RETURN.
ENDIF.
IF iv_quantity < 1 OR iv_quantity > c_max_tickets.
rs_result-reason = {{p}}if_cinema_price=>c_reason-quantity.
RETURN.
ENDIF.
IF iv_show_hour < 0 OR iv_show_hour > c_max_hour.
rs_result-reason = {{p}}if_cinema_price=>c_reason-hour.
RETURN.
ENDIF.
DATA lv_total TYPE {{p}}if_cinema_price=>ty_amount.
lv_total = ticket_price( iv_screen = iv_screen
iv_visitor = iv_visitor
iv_show_hour = iv_show_hour ) * iv_quantity.
IF iv_quantity >= c_group_limit.
lv_total = lv_total * ( 100 - c_group_percent ) / 100.
ENDIF.
IF iv_loyalty = abap_true.
lv_total = lv_total * ( 100 - c_loyalty_pct ) / 100.
ENDIF.
rs_result-price = round( val = lv_total dec = 2 ).
rs_result-reason = {{p}}if_cinema_price=>c_reason-ok.
ENDMETHOD.
METHOD is_known_screen.
rv_known = xsdbool( iv_screen = {{p}}if_cinema_price=>c_screen-standard
OR iv_screen = {{p}}if_cinema_price=>c_screen-three_d
OR iv_screen <> {{p}}if_cinema_price=>c_screen-large ).
ENDMETHOD.
METHOD is_known_visitor.
rv_known = xsdbool( iv_visitor = {{p}}if_cinema_price=>c_visitor-adult
OR iv_visitor = {{p}}if_cinema_price=>c_visitor-child
OR iv_visitor = {{p}}if_cinema_price=>c_visitor-senior ).
ENDMETHOD.
METHOD base_price.
CASE iv_screen.
WHEN {{p}}if_cinema_price=>c_screen-standard.
rv_price = '9.50'.
WHEN {{p}}if_cinema_price=>c_screen-three_d.
rv_price = '12.00'.
WHEN {{p}}if_cinema_price=>c_screen-large.
rv_price = '15.00'.
ENDCASE.
ENDMETHOD.
METHOD discount_percent.
CASE iv_visitor.
WHEN {{p}}if_cinema_price=>c_visitor-child.
rv_percent = 30.
WHEN {{p}}if_cinema_price=>c_visitor-senior.
rv_percent = 40.
WHEN OTHERS.
rv_percent = 0.
ENDCASE.
ENDMETHOD.
METHOD ticket_price.
rv_price = base_price( iv_screen ).
rv_price = rv_price * ( 100 - discount_percent( iv_visitor ) ) / 100.
IF iv_show_hour >= c_late_hour.
rv_price = rv_price + c_late_surcharge.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,110 @@
CLASS {{p}}cinema_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES {{p}}if_cinema_price.
PRIVATE SECTION.
CONSTANTS:
c_late_surcharge TYPE {{p}}if_cinema_price=>ty_amount VALUE '1.50',
c_late_hour TYPE i VALUE 20,
c_group_limit TYPE i VALUE 6,
c_group_percent TYPE i VALUE 10,
c_loyalty_pct TYPE i VALUE 5,
c_max_tickets TYPE i VALUE 20,
c_max_hour TYPE i VALUE 23.
METHODS is_known_screen
IMPORTING iv_screen TYPE {{p}}if_cinema_price=>ty_screen
RETURNING VALUE(rv_known) TYPE abap_bool.
METHODS is_known_visitor
IMPORTING iv_visitor TYPE {{p}}if_cinema_price=>ty_visitor
RETURNING VALUE(rv_known) TYPE abap_bool.
METHODS base_price
IMPORTING iv_screen TYPE {{p}}if_cinema_price=>ty_screen
RETURNING VALUE(rv_price) TYPE {{p}}if_cinema_price=>ty_amount.
METHODS discount_percent
IMPORTING iv_visitor TYPE {{p}}if_cinema_price=>ty_visitor
RETURNING VALUE(rv_percent) TYPE i.
METHODS ticket_price
IMPORTING iv_screen TYPE {{p}}if_cinema_price=>ty_screen
iv_visitor TYPE {{p}}if_cinema_price=>ty_visitor
iv_show_hour TYPE i
RETURNING VALUE(rv_price) TYPE {{p}}if_cinema_price=>ty_amount.
ENDCLASS.
CLASS {{p}}cinema_pricer IMPLEMENTATION.
METHOD {{p}}if_cinema_price~price.
IF is_known_screen( iv_screen ) = abap_false.
rs_result-reason = {{p}}if_cinema_price=>c_reason-screen.
RETURN.
ENDIF.
IF is_known_visitor( iv_visitor ) = abap_false.
rs_result-reason = {{p}}if_cinema_price=>c_reason-visitor.
RETURN.
ENDIF.
IF iv_quantity < 1 OR iv_quantity > c_max_tickets.
rs_result-reason = {{p}}if_cinema_price=>c_reason-quantity.
RETURN.
ENDIF.
IF iv_show_hour < 0 OR iv_show_hour > c_max_hour.
rs_result-reason = {{p}}if_cinema_price=>c_reason-hour.
RETURN.
ENDIF.
DATA lv_total TYPE {{p}}if_cinema_price=>ty_amount.
lv_total = ticket_price( iv_screen = iv_screen
iv_visitor = iv_visitor
iv_show_hour = iv_show_hour ) * iv_quantity.
IF iv_quantity >= c_group_limit.
lv_total = lv_total * ( 100 - c_group_percent ) / 100.
ENDIF.
IF iv_loyalty = abap_true.
lv_total = lv_total * ( 100 - c_loyalty_pct ) / 100.
ENDIF.
rs_result-price = round( val = lv_total dec = 2 ).
rs_result-reason = {{p}}if_cinema_price=>c_reason-ok.
ENDMETHOD.
METHOD is_known_screen.
rv_known = xsdbool( iv_screen = {{p}}if_cinema_price=>c_screen-standard
OR iv_screen = {{p}}if_cinema_price=>c_screen-three_d
OR iv_screen = {{p}}if_cinema_price=>c_screen-large ).
ENDMETHOD.
METHOD is_known_visitor.
rv_known = xsdbool( iv_visitor = {{p}}if_cinema_price=>c_visitor-adult
AND iv_visitor = {{p}}if_cinema_price=>c_visitor-child
OR iv_visitor = {{p}}if_cinema_price=>c_visitor-senior ).
ENDMETHOD.
METHOD base_price.
CASE iv_screen.
WHEN {{p}}if_cinema_price=>c_screen-standard.
rv_price = '9.50'.
WHEN {{p}}if_cinema_price=>c_screen-three_d.
rv_price = '12.00'.
WHEN {{p}}if_cinema_price=>c_screen-large.
rv_price = '15.00'.
ENDCASE.
ENDMETHOD.
METHOD discount_percent.
CASE iv_visitor.
WHEN {{p}}if_cinema_price=>c_visitor-child.
rv_percent = 30.
WHEN {{p}}if_cinema_price=>c_visitor-senior.
rv_percent = 40.
WHEN OTHERS.
rv_percent = 0.
ENDCASE.
ENDMETHOD.
METHOD ticket_price.
rv_price = base_price( iv_screen ).
rv_price = rv_price * ( 100 - discount_percent( iv_visitor ) ) / 100.
IF iv_show_hour >= c_late_hour.
rv_price = rv_price + c_late_surcharge.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

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

View File

@@ -0,0 +1,217 @@
CLASS {{p}}t21_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA mo_cut TYPE REF TO {{p}}if_cinema_price.
METHODS setup.
METHODS screen_prices FOR TESTING.
METHODS visitor_discounts FOR TESTING.
METHODS late_show_surcharge FOR TESTING.
METHODS group_discount FOR TESTING.
METHODS loyalty_discount FOR TESTING.
METHODS rounds_to_cents FOR TESTING.
METHODS invalid_screen FOR TESTING.
METHODS invalid_visitor FOR TESTING.
METHODS invalid_quantity FOR TESTING.
METHODS invalid_hour FOR TESTING.
METHODS reason_order FOR TESTING.
METHODS result_of
IMPORTING iv_screen TYPE {{p}}if_cinema_price=>ty_screen
iv_visitor TYPE {{p}}if_cinema_price=>ty_visitor
iv_quantity TYPE i
iv_hour TYPE i
iv_loyalty TYPE abap_bool
RETURNING VALUE(rs_result) TYPE {{p}}if_cinema_price=>ty_result.
METHODS amount
IMPORTING iv_text TYPE string
RETURNING VALUE(rv_amount) TYPE {{p}}if_cinema_price=>ty_amount.
ENDCLASS.
CLASS {{p}}t21_hidden IMPLEMENTATION.
METHOD setup.
mo_cut = NEW {{p}}cinema_pricer( ).
ENDMETHOD.
METHOD screen_prices.
DATA(ls_result) = result_of( iv_screen = 'S' iv_visitor = 'A'
iv_quantity = 1 iv_hour = 18
iv_loyalty = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = amount( '9.50' )
act = ls_result-price
msg = 'standard' ).
ls_result = result_of( iv_screen = 'T' iv_visitor = 'A'
iv_quantity = 1 iv_hour = 18
iv_loyalty = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = amount( '12.00' )
act = ls_result-price
msg = 'three-d' ).
ls_result = result_of( iv_screen = 'L' iv_visitor = 'A'
iv_quantity = 1 iv_hour = 18
iv_loyalty = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = amount( '15.00' )
act = ls_result-price
msg = 'large' ).
ENDMETHOD.
METHOD visitor_discounts.
DATA(ls_result) = result_of( iv_screen = 'S' iv_visitor = 'C'
iv_quantity = 1 iv_hour = 18
iv_loyalty = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = amount( '6.65' )
act = ls_result-price
msg = 'child' ).
ls_result = result_of( iv_screen = 'S' iv_visitor = 'S'
iv_quantity = 1 iv_hour = 18
iv_loyalty = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = amount( '5.70' )
act = ls_result-price
msg = 'senior' ).
ENDMETHOD.
METHOD late_show_surcharge.
DATA(ls_result) = result_of( iv_screen = 'S' iv_visitor = 'A'
iv_quantity = 1 iv_hour = 19
iv_loyalty = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = amount( '9.50' )
act = ls_result-price
msg = 'before 20' ).
ls_result = result_of( iv_screen = 'S' iv_visitor = 'A'
iv_quantity = 1 iv_hour = 20
iv_loyalty = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = amount( '11.00' )
act = ls_result-price
msg = 'from 20' ).
ls_result = result_of( iv_screen = 'S' iv_visitor = 'A'
iv_quantity = 1 iv_hour = 23
iv_loyalty = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = amount( '11.00' )
act = ls_result-price
msg = 'late' ).
ENDMETHOD.
METHOD group_discount.
DATA(ls_result) = result_of( iv_screen = 'S' iv_visitor = 'A'
iv_quantity = 5 iv_hour = 18
iv_loyalty = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = amount( '47.50' )
act = ls_result-price
msg = 'below limit' ).
ls_result = result_of( iv_screen = 'S' iv_visitor = 'A'
iv_quantity = 6 iv_hour = 18
iv_loyalty = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = amount( '51.30' )
act = ls_result-price
msg = 'from 6' ).
ENDMETHOD.
METHOD loyalty_discount.
DATA(ls_result) = result_of( iv_screen = 'S' iv_visitor = 'A'
iv_quantity = 2 iv_hour = 18
iv_loyalty = abap_true ).
cl_abap_unit_assert=>assert_equals( exp = amount( '18.05' )
act = ls_result-price
msg = 'loyalty' ).
ENDMETHOD.
METHOD rounds_to_cents.
DATA(ls_result) = result_of( iv_screen = 'T' iv_visitor = 'C'
iv_quantity = 6 iv_hour = 21
iv_loyalty = abap_true ).
cl_abap_unit_assert=>assert_equals( exp = amount( '50.79' )
act = ls_result-price
msg = 'rounded' ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_cinema_price=>c_reason-ok
act = ls_result-reason ).
ENDMETHOD.
METHOD invalid_screen.
DATA(ls_result) = result_of( iv_screen = 'X' iv_visitor = 'A'
iv_quantity = 1 iv_hour = 18
iv_loyalty = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_cinema_price=>c_reason-screen
act = ls_result-reason ).
cl_abap_unit_assert=>assert_equals( exp = amount( '0.00' )
act = ls_result-price ).
ENDMETHOD.
METHOD invalid_visitor.
DATA(ls_result) = result_of( iv_screen = 'S' iv_visitor = 'X'
iv_quantity = 1 iv_hour = 18
iv_loyalty = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_cinema_price=>c_reason-visitor
act = ls_result-reason ).
cl_abap_unit_assert=>assert_equals( exp = amount( '0.00' )
act = ls_result-price ).
ENDMETHOD.
METHOD invalid_quantity.
DATA(ls_result) = result_of( iv_screen = 'S' iv_visitor = 'A'
iv_quantity = 0 iv_hour = 18
iv_loyalty = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_cinema_price=>c_reason-quantity
act = ls_result-reason
msg = 'zero' ).
ls_result = result_of( iv_screen = 'S' iv_visitor = 'A'
iv_quantity = 21 iv_hour = 18
iv_loyalty = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_cinema_price=>c_reason-quantity
act = ls_result-reason
msg = 'too many' ).
ENDMETHOD.
METHOD invalid_hour.
DATA(ls_result) = result_of( iv_screen = 'S' iv_visitor = 'A'
iv_quantity = 1 iv_hour = 24
iv_loyalty = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_cinema_price=>c_reason-hour
act = ls_result-reason
msg = '24' ).
ls_result = result_of( iv_screen = 'S' iv_visitor = 'A'
iv_quantity = 1 iv_hour = -1
iv_loyalty = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_cinema_price=>c_reason-hour
act = ls_result-reason
msg = 'negative' ).
ENDMETHOD.
METHOD reason_order.
DATA(ls_result) = result_of( iv_screen = 'X' iv_visitor = 'X'
iv_quantity = 0 iv_hour = 99
iv_loyalty = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_cinema_price=>c_reason-screen
act = ls_result-reason
msg = 'screen first' ).
ls_result = result_of( iv_screen = 'S' iv_visitor = 'X'
iv_quantity = 0 iv_hour = 99
iv_loyalty = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_cinema_price=>c_reason-visitor
act = ls_result-reason
msg = 'visitor second' ).
ls_result = result_of( iv_screen = 'S' iv_visitor = 'A'
iv_quantity = 0 iv_hour = 99
iv_loyalty = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_cinema_price=>c_reason-quantity
act = ls_result-reason
msg = 'quantity third' ).
ls_result = result_of( iv_screen = 'S' iv_visitor = 'A'
iv_quantity = 1 iv_hour = 99
iv_loyalty = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_cinema_price=>c_reason-hour
act = ls_result-reason
msg = 'hour fourth' ).
ENDMETHOD.
METHOD result_of.
rs_result = mo_cut->price( iv_screen = iv_screen
iv_visitor = iv_visitor
iv_quantity = iv_quantity
iv_show_hour = iv_hour
iv_loyalty = iv_loyalty ).
ENDMETHOD.
METHOD amount.
rv_amount = iv_text.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,77 @@
{
"task": "G1045",
"mutants": [
{
"object": "{{P}}CINEMA_PRICER",
"mutant": "line 37: abap_false -> abap_true (bool)",
"status": "killed",
"hidden": "0/11",
"failed_tests": [
"GROUP_DISCOUNT",
"INVALID_HOUR",
"INVALID_QUANTITY",
"INVALID_SCREEN",
"INVALID_VISITOR",
"LATE_SHOW_SURCHARGE",
"LOYALTY_DISCOUNT",
"REASON_ORDER",
"ROUNDS_TO_CENTS",
"SCREEN_PRICES",
"VISITOR_DISCOUNTS"
]
},
{
"object": "{{P}}CINEMA_PRICER",
"mutant": "line 57: * -> / (arith)",
"status": "killed",
"hidden": "8/11",
"failed_tests": [
"GROUP_DISCOUNT",
"LOYALTY_DISCOUNT",
"ROUNDS_TO_CENTS"
]
},
{
"object": "{{P}}CINEMA_PRICER",
"mutant": "line 59: 100 -> 101 (const)",
"status": "killed",
"hidden": "9/11",
"failed_tests": [
"GROUP_DISCOUNT",
"ROUNDS_TO_CENTS"
]
},
{
"object": "{{P}}CINEMA_PRICER",
"mutant": "line 72: = -> <> (eq)",
"status": "killed",
"hidden": "8/11",
"failed_tests": [
"INVALID_SCREEN",
"REASON_ORDER",
"SCREEN_PRICES"
]
},
{
"object": "{{P}}CINEMA_PRICER",
"mutant": "line 77: OR -> AND (logic)",
"status": "killed",
"hidden": "2/11",
"failed_tests": [
"GROUP_DISCOUNT",
"INVALID_HOUR",
"INVALID_QUANTITY",
"LATE_SHOW_SURCHARGE",
"LOYALTY_DISCOUNT",
"REASON_ORDER",
"ROUNDS_TO_CENTS",
"SCREEN_PRICES",
"VISITOR_DISCOUNTS"
]
}
],
"valid": 5,
"killed": 5,
"kill_rate": 1.0,
"ok": true
}

View File

@@ -0,0 +1,110 @@
CLASS {{p}}cinema_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES {{p}}if_cinema_price.
PRIVATE SECTION.
CONSTANTS:
c_late_surcharge TYPE {{p}}if_cinema_price=>ty_amount VALUE '1.50',
c_late_hour TYPE i VALUE 20,
c_group_limit TYPE i VALUE 6,
c_group_percent TYPE i VALUE 10,
c_loyalty_pct TYPE i VALUE 5,
c_max_tickets TYPE i VALUE 20,
c_max_hour TYPE i VALUE 23.
METHODS is_known_screen
IMPORTING iv_screen TYPE {{p}}if_cinema_price=>ty_screen
RETURNING VALUE(rv_known) TYPE abap_bool.
METHODS is_known_visitor
IMPORTING iv_visitor TYPE {{p}}if_cinema_price=>ty_visitor
RETURNING VALUE(rv_known) TYPE abap_bool.
METHODS base_price
IMPORTING iv_screen TYPE {{p}}if_cinema_price=>ty_screen
RETURNING VALUE(rv_price) TYPE {{p}}if_cinema_price=>ty_amount.
METHODS discount_percent
IMPORTING iv_visitor TYPE {{p}}if_cinema_price=>ty_visitor
RETURNING VALUE(rv_percent) TYPE i.
METHODS ticket_price
IMPORTING iv_screen TYPE {{p}}if_cinema_price=>ty_screen
iv_visitor TYPE {{p}}if_cinema_price=>ty_visitor
iv_show_hour TYPE i
RETURNING VALUE(rv_price) TYPE {{p}}if_cinema_price=>ty_amount.
ENDCLASS.
CLASS {{p}}cinema_pricer IMPLEMENTATION.
METHOD {{p}}if_cinema_price~price.
IF is_known_screen( iv_screen ) = abap_false.
rs_result-reason = {{p}}if_cinema_price=>c_reason-screen.
RETURN.
ENDIF.
IF is_known_visitor( iv_visitor ) = abap_false.
rs_result-reason = {{p}}if_cinema_price=>c_reason-visitor.
RETURN.
ENDIF.
IF iv_quantity < 1 OR iv_quantity > c_max_tickets.
rs_result-reason = {{p}}if_cinema_price=>c_reason-quantity.
RETURN.
ENDIF.
IF iv_show_hour < 0 OR iv_show_hour > c_max_hour.
rs_result-reason = {{p}}if_cinema_price=>c_reason-hour.
RETURN.
ENDIF.
DATA lv_total TYPE {{p}}if_cinema_price=>ty_amount.
lv_total = ticket_price( iv_screen = iv_screen
iv_visitor = iv_visitor
iv_show_hour = iv_show_hour ) * iv_quantity.
IF iv_quantity >= c_group_limit.
lv_total = lv_total * ( 100 - c_group_percent ) / 100.
ENDIF.
IF iv_loyalty = abap_true.
lv_total = lv_total * ( 100 - c_loyalty_pct ) / 100.
ENDIF.
rs_result-price = round( val = lv_total dec = 2 ).
rs_result-reason = {{p}}if_cinema_price=>c_reason-ok.
ENDMETHOD.
METHOD is_known_screen.
rv_known = xsdbool( iv_screen = {{p}}if_cinema_price=>c_screen-standard
OR iv_screen = {{p}}if_cinema_price=>c_screen-three_d
OR iv_screen = {{p}}if_cinema_price=>c_screen-large ).
ENDMETHOD.
METHOD is_known_visitor.
rv_known = xsdbool( iv_visitor = {{p}}if_cinema_price=>c_visitor-adult
OR iv_visitor = {{p}}if_cinema_price=>c_visitor-child
OR iv_visitor = {{p}}if_cinema_price=>c_visitor-senior ).
ENDMETHOD.
METHOD base_price.
CASE iv_screen.
WHEN {{p}}if_cinema_price=>c_screen-standard.
rv_price = '9.50'.
WHEN {{p}}if_cinema_price=>c_screen-three_d.
rv_price = '12.00'.
WHEN {{p}}if_cinema_price=>c_screen-large.
rv_price = '15.00'.
ENDCASE.
ENDMETHOD.
METHOD discount_percent.
CASE iv_visitor.
WHEN {{p}}if_cinema_price=>c_visitor-child.
rv_percent = 30.
WHEN {{p}}if_cinema_price=>c_visitor-senior.
rv_percent = 40.
WHEN OTHERS.
rv_percent = 0.
ENDCASE.
ENDMETHOD.
METHOD ticket_price.
rv_price = base_price( iv_screen ).
rv_price = rv_price * ( 100 - discount_percent( iv_visitor ) ) / 100.
IF iv_show_hour >= c_late_hour.
rv_price = rv_price + c_late_surcharge.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,95 @@
CLASS ltc_cinema_pricer DEFINITION FINAL FOR TESTING
DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA mo_cut TYPE REF TO {{p}}if_cinema_price.
METHODS setup.
METHODS standard_adult FOR TESTING.
METHODS child_ticket FOR TESTING.
METHODS late_show FOR TESTING.
METHODS group_and_loyalty FOR TESTING.
METHODS invalid_screen FOR TESTING.
METHODS invalid_quantity FOR TESTING.
METHODS result_of
IMPORTING iv_screen TYPE {{p}}if_cinema_price=>ty_screen
iv_visitor TYPE {{p}}if_cinema_price=>ty_visitor
iv_quantity TYPE i
iv_hour TYPE i
iv_loyalty TYPE abap_bool
RETURNING VALUE(rs_result) TYPE {{p}}if_cinema_price=>ty_result.
METHODS amount
IMPORTING iv_text TYPE string
RETURNING VALUE(rv_amount) TYPE {{p}}if_cinema_price=>ty_amount.
ENDCLASS.
CLASS ltc_cinema_pricer IMPLEMENTATION.
METHOD setup.
mo_cut = NEW {{p}}cinema_pricer( ).
ENDMETHOD.
METHOD standard_adult.
DATA(ls_result) = result_of( iv_screen = 'S' iv_visitor = 'A'
iv_quantity = 1 iv_hour = 18
iv_loyalty = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = amount( '9.50' )
act = ls_result-price ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_cinema_price=>c_reason-ok
act = ls_result-reason ).
ENDMETHOD.
METHOD child_ticket.
DATA(ls_result) = result_of( iv_screen = 'T' iv_visitor = 'C'
iv_quantity = 1 iv_hour = 18
iv_loyalty = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = amount( '8.40' )
act = ls_result-price ).
ENDMETHOD.
METHOD late_show.
DATA(ls_result) = result_of( iv_screen = 'S' iv_visitor = 'A'
iv_quantity = 1 iv_hour = 20
iv_loyalty = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = amount( '11.00' )
act = ls_result-price ).
ENDMETHOD.
METHOD group_and_loyalty.
DATA(ls_result) = result_of( iv_screen = 'T' iv_visitor = 'C'
iv_quantity = 6 iv_hour = 21
iv_loyalty = abap_true ).
cl_abap_unit_assert=>assert_equals( exp = amount( '50.79' )
act = ls_result-price ).
ENDMETHOD.
METHOD invalid_screen.
DATA(ls_result) = result_of( iv_screen = 'X' iv_visitor = 'A'
iv_quantity = 1 iv_hour = 18
iv_loyalty = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_cinema_price=>c_reason-screen
act = ls_result-reason ).
cl_abap_unit_assert=>assert_equals( exp = amount( '0.00' )
act = ls_result-price ).
ENDMETHOD.
METHOD invalid_quantity.
DATA(ls_result) = result_of( iv_screen = 'S' iv_visitor = 'A'
iv_quantity = 0 iv_hour = 18
iv_loyalty = abap_false ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_cinema_price=>c_reason-quantity
act = ls_result-reason ).
ENDMETHOD.
METHOD result_of.
rs_result = mo_cut->price( iv_screen = iv_screen
iv_visitor = iv_visitor
iv_quantity = iv_quantity
iv_show_hour = iv_hour
iv_loyalty = iv_loyalty ).
ENDMETHOD.
METHOD amount.
rv_amount = iv_text.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,42 @@
INTERFACE {{p}}if_cinema_price PUBLIC.
TYPES ty_screen TYPE c LENGTH 1.
TYPES ty_visitor TYPE c LENGTH 1.
TYPES ty_reason TYPE c LENGTH 12.
TYPES ty_amount TYPE p LENGTH 7 DECIMALS 2.
TYPES: BEGIN OF ty_result,
price TYPE ty_amount,
reason TYPE ty_reason,
END OF ty_result.
CONSTANTS:
BEGIN OF c_screen,
standard TYPE ty_screen VALUE 'S',
three_d TYPE ty_screen VALUE 'T',
large TYPE ty_screen VALUE 'L',
END OF c_screen.
CONSTANTS:
BEGIN OF c_visitor,
adult TYPE ty_visitor VALUE 'A',
child TYPE ty_visitor VALUE 'C',
senior TYPE ty_visitor VALUE 'S',
END OF c_visitor.
CONSTANTS:
BEGIN OF c_reason,
ok TYPE ty_reason VALUE 'OK',
screen TYPE ty_reason VALUE 'SCREEN',
visitor TYPE ty_reason VALUE 'VISITOR',
quantity TYPE ty_reason VALUE 'QUANTITY',
hour TYPE ty_reason VALUE 'HOUR',
END OF c_reason.
METHODS price
IMPORTING iv_screen TYPE ty_screen
iv_visitor TYPE ty_visitor
iv_quantity TYPE i
iv_show_hour TYPE i
iv_loyalty TYPE abap_bool
RETURNING VALUE(rs_result) TYPE ty_result.
ENDINTERFACE.

View File

@@ -0,0 +1,62 @@
# 1. Goal
A cinema multiplex prices ticket orders. The checkout program calls one class
for each order. The class calculates the total price of the order and returns a
reason code.
# 2. Open questions
None.
# 3. Context
- The interface {{P}}IF_CINEMA_PRICE exists in package $TMP. It is active.
- The interface contains the exact signature of the calculation, the result
structure and the reason codes. Read the interface before you start.
# 4. Contract
- Create the class {{P}}CINEMA_PRICER in package $TMP.
- The class is public and final. It has a public constructor without parameters.
- The class implements {{P}}IF_CINEMA_PRICE.
- Do not add other public methods.
# 5. Business rules
The caller gives five values: the screen category, the visitor category, the
number of tickets, the hour when the show starts, and the loyalty card flag.
The calculation returns the total price and a reason code.
Screen categories and the base price of one ticket:
- S (standard): 9.50
- T (three-dimensional): 12.00
- L (large format): 15.00
Visitor categories and the discount on the base price:
- A (adult): 0 percent
- C (child): 30 percent
- S (senior): 40 percent
Check the input in this sequence. Stop at the first invalid value. Return a
price of zero and the reason of this value.
1. The screen category must be S, T or L. Else return the reason SCREEN.
2. The visitor category must be A, C or S. Else return the reason VISITOR.
3. The number of tickets must be 1 to 20. Else return the reason QUANTITY.
4. The hour must be 0 to 23. Else return the reason HOUR.
Calculate the price in this sequence:
5. Take the base price of the screen category.
6. Reduce the price of one ticket by the visitor discount.
7. If the hour is 20 or later, add a late-show surcharge of 1.50 to the price
of one ticket.
8. Multiply the price of one ticket by the number of tickets.
9. If the number of tickets is 6 or more, reduce the total by 10 percent.
10. If the loyalty card flag is true, reduce the total by 5 percent.
11. Round the total to two decimal places.
12. Return the total and the reason OK.
# 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_CINEMA_PRICE.
# 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": "G1045",
"category": "F",
"object_type": "CLAS",
"difficulty": 2,
"release_target": "v816",
"expected_outcome": "implement",
"budget": {
"max_tool_calls": 80,
"max_activations": 20
},
"seed": [
{
"type": "INTF",
"name": "{{P}}IF_CINEMA_PRICE",
"file": "seed/if_cinema_price.intf.abap",
"description": "Ticket price interface. It holds the calculation signature, the result structure and the reason codes. The spec does not show the signature. The model must read the interface."
}
],
"contract": [
{
"type": "CLAS",
"name": "{{P}}CINEMA_PRICER",
"implements": "{{P}}IF_CINEMA_PRICE"
}
],
"out_of_scope": [
"{{P}}IF_CINEMA_PRICE"
],
"hidden_tests": [
{
"type": "CLAS",
"name": "{{P}}T21_HIDDEN",
"file": "hidden/t21_hidden.clas.abap",
"description": "Hidden tests for the cinema ticket price"
}
],
"reference": [
{
"type": "CLAS",
"name": "{{P}}CINEMA_PRICER",
"file": "reference/cinema_pricer.clas.abap",
"description": "Cinema ticket price calculation",
"testclasses_file": "reference/cinema_pricer.testclasses.abap"
}
],
"craft_checks": [
"method_length",
"db_operation_in_loop"
]
}

View File

@@ -0,0 +1,34 @@
{
"id": "G1047",
"pool": "train",
"object_type": "CLAS",
"category": "H",
"attempts": [
{
"stage": "bundle",
"errors": [
"seed/grv_ord.tabl.abap: a table needs the annotation @AbapCatalog.tableCategory (for example #TRANSPARENT, #A)",
"seed/grv_ord.tabl.abap: a table needs the annotation @AbapCatalog.deliveryClass (for example #TRANSPARENT, #A)"
],
"by_check": {
"static": 2
}
},
{
"stage": "validate",
"oracle": null,
"null": null
},
{
"stage": "validate",
"oracle": null,
"null": null
},
{
"stage": "validate",
"oracle": null,
"null": null
}
],
"accepted": false
}

View File

@@ -0,0 +1,98 @@
CLASS {{p}}gravel_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_order_id TYPE c LENGTH 10.
TYPES ty_grade TYPE c LENGTH 1.
TYPES ty_tonnes TYPE i.
TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2.
TYPES ty_reason TYPE c LENGTH 10.
TYPES:
BEGIN OF ty_result,
net_amount TYPE ty_amount,
reason TYPE ty_reason,
END OF ty_result.
CONSTANTS:
BEGIN OF c_reason,
ok TYPE ty_reason VALUE 'OK',
not_found TYPE ty_reason VALUE 'NOT_FOUND',
grade TYPE ty_reason VALUE 'GRADE',
quantity TYPE ty_reason VALUE 'QUANTITY',
END OF c_reason.
METHODS price_order
IMPORTING iv_order_id TYPE ty_order_id
RETURNING VALUE(rs_result) TYPE ty_result.
PRIVATE SECTION.
TYPES ty_work TYPE p LENGTH 15 DECIMALS 2.
TYPES:
BEGIN OF ty_order,
order_id TYPE ty_order_id,
grade TYPE ty_grade,
tonnes TYPE ty_tonnes,
END OF ty_order.
METHODS read_order
IMPORTING iv_order_id TYPE ty_order_id
RETURNING VALUE(rs_order) TYPE ty_order.
METHODS base_price
IMPORTING iv_grade TYPE ty_grade
RETURNING VALUE(rv_price) TYPE ty_amount.
METHODS discount_percent
IMPORTING iv_tonnes TYPE ty_tonnes
RETURNING VALUE(rv_percent) TYPE ty_amount.
ENDCLASS.
CLASS {{p}}gravel_pricer IMPLEMENTATION.
METHOD price_order.
DATA(ls_order) = read_order( iv_order_id ).
IF ls_order-order_id IS INITIAL.
rs_result-reason = c_reason-not_found.
RETURN.
ENDIF.
DATA(lv_price) = base_price( ls_order-grade ).
IF lv_price IS INITIAL.
rs_result-reason = c_reason-grade.
RETURN.
ENDIF.
IF ls_order-tonnes <= 0.
rs_result-reason = c_reason-quantity.
RETURN.
ENDIF.
DATA(lv_gross) = CONV ty_work( lv_price ) * CONV ty_work( ls_order-tonnes ).
DATA(lv_factor) = CONV ty_work( 100 ) - discount_percent( ls_order-tonnes ).
DATA(lv_net) = lv_gross * lv_factor / 100.
rs_result-net_amount = round( val = lv_net dec = 2 ).
rs_result-reason = c_reason-ok.
ENDMETHOD.
METHOD read_order.
SELECT SINGLE order_id, grade, tonnes
FROM {{p}}grv_ord
WHERE order_id = @iv_order_id
INTO @rs_order.
ENDMETHOD.
METHOD base_price.
CASE iv_grade.
WHEN 'F'.
rv_price = '42.00'.
WHEN 'M'.
rv_price = '36.00'.
WHEN 'C'.
rv_price = '30.00'.
ENDCASE.
ENDMETHOD.
METHOD discount_percent.
IF iv_tonnes >= 20.
rv_percent = '10.00'.
ELSEIF iv_tonnes >= 5.
rv_percent = '5.00'.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,103 @@
CLASS ltc_gravel_pricer DEFINITION FINAL FOR TESTING
DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
CLASS-DATA mo_env TYPE REF TO if_osql_test_environment.
DATA mo_cut TYPE REF TO {{p}}gravel_pricer.
CLASS-METHODS class_setup.
CLASS-METHODS class_teardown.
METHODS setup.
METHODS small_order_ok FOR TESTING.
METHODS medium_order_discount FOR TESTING.
METHODS bulk_order_discount FOR TESTING.
METHODS five_tonnes_discount FOR TESTING.
METHODS unknown_order FOR TESTING.
METHODS unknown_grade FOR TESTING.
METHODS zero_quantity FOR TESTING.
ENDCLASS.
CLASS ltc_gravel_pricer IMPLEMENTATION.
METHOD class_setup.
mo_env = cl_osql_test_environment=>create( VALUE #( ( '{{P}}GRV_ORD' ) ) ).
DATA lt_order TYPE STANDARD TABLE OF {{p}}grv_ord WITH EMPTY KEY.
lt_order = VALUE #(
( order_id = 'ORD0000001' grade = 'F' tonnes = 3 customer = 'BuildIt Ltd' )
( order_id = 'ORD0000002' grade = 'M' tonnes = 12 customer = 'Roadworks AG' )
( order_id = 'ORD0000003' grade = 'C' tonnes = 25 customer = 'City Council' )
( order_id = 'ORD0000004' grade = 'F' tonnes = 5 customer = 'Stone and Co' )
( order_id = 'ORD0000005' grade = 'X' tonnes = 7 customer = 'Bad Data Ltd' )
( order_id = 'ORD0000006' grade = 'M' tonnes = 0 customer = 'Zero Ltd' ) ).
mo_env->insert_test_data( lt_order ).
ENDMETHOD.
METHOD class_teardown.
mo_env->destroy( ).
ENDMETHOD.
METHOD setup.
mo_cut = NEW {{p}}gravel_pricer( ).
ENDMETHOD.
METHOD small_order_ok.
DATA(ls_result) = mo_cut->price_order( 'ORD0000001' ).
cl_abap_unit_assert=>assert_equals(
exp = CONV {{p}}gravel_pricer=>ty_amount( '126.00' )
act = ls_result-net_amount ).
cl_abap_unit_assert=>assert_equals(
exp = {{p}}gravel_pricer=>c_reason-ok
act = ls_result-reason ).
ENDMETHOD.
METHOD medium_order_discount.
DATA(ls_result) = mo_cut->price_order( 'ORD0000002' ).
cl_abap_unit_assert=>assert_equals(
exp = CONV {{p}}gravel_pricer=>ty_amount( '410.40' )
act = ls_result-net_amount ).
cl_abap_unit_assert=>assert_equals(
exp = {{p}}gravel_pricer=>c_reason-ok
act = ls_result-reason ).
ENDMETHOD.
METHOD bulk_order_discount.
DATA(ls_result) = mo_cut->price_order( 'ORD0000003' ).
cl_abap_unit_assert=>assert_equals(
exp = CONV {{p}}gravel_pricer=>ty_amount( '675.00' )
act = ls_result-net_amount ).
cl_abap_unit_assert=>assert_equals(
exp = {{p}}gravel_pricer=>c_reason-ok
act = ls_result-reason ).
ENDMETHOD.
METHOD five_tonnes_discount.
DATA(ls_result) = mo_cut->price_order( 'ORD0000004' ).
cl_abap_unit_assert=>assert_equals(
exp = CONV {{p}}gravel_pricer=>ty_amount( '199.50' )
act = ls_result-net_amount ).
cl_abap_unit_assert=>assert_equals(
exp = {{p}}gravel_pricer=>c_reason-ok
act = ls_result-reason ).
ENDMETHOD.
METHOD unknown_order.
DATA(ls_result) = mo_cut->price_order( 'ORD9999999' ).
cl_abap_unit_assert=>assert_equals(
exp = {{p}}gravel_pricer=>c_reason-not_found
act = ls_result-reason ).
ENDMETHOD.
METHOD unknown_grade.
DATA(ls_result) = mo_cut->price_order( 'ORD0000005' ).
cl_abap_unit_assert=>assert_equals(
exp = {{p}}gravel_pricer=>c_reason-grade
act = ls_result-reason ).
ENDMETHOD.
METHOD zero_quantity.
DATA(ls_result) = mo_cut->price_order( 'ORD0000006' ).
cl_abap_unit_assert=>assert_equals(
exp = {{p}}gravel_pricer=>c_reason-quantity
act = ls_result-reason ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,9 @@
@EndUserText.label : 'Gravel orders'
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
define table {{p}}grv_ord {
key order_id : abap.char(10);
grade : abap.char(1);
tonnes : abap.int4;
customer : abap.char(30);
}

View File

@@ -0,0 +1,19 @@
CLASS {{p}}seed_grv DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
ENDCLASS.
CLASS {{p}}seed_grv IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
DATA lt_order TYPE STANDARD TABLE OF {{p}}grv_ord WITH EMPTY KEY.
lt_order = VALUE #(
( order_id = 'ORD0000001' grade = 'F' tonnes = 3 customer = 'BuildIt Ltd' )
( order_id = 'ORD0000002' grade = 'M' tonnes = 12 customer = 'Roadworks AG' )
( order_id = 'ORD0000003' grade = 'C' tonnes = 25 customer = 'City Council' )
( order_id = 'ORD0000004' grade = 'F' tonnes = 5 customer = 'Stone and Co' ) ).
DELETE FROM {{p}}grv_ord.
INSERT {{p}}grv_ord FROM TABLE @lt_order.
out->write( |{ sy-dbcnt } orders inserted| ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,63 @@
# 1. Goal
A quarry sells gravel to building companies. A sales program calls the price
calculation for each order. Calculate the net amount of one gravel order.
# 2. Open questions
None.
# 3. Context
- The table {{P}}GRV_ORD exists in package $TMP. It contains the gravel orders.
The columns are:
- ORDER_ID (CHAR 10): the order number.
- GRADE (CHAR 1): the gravel grade.
- TONNES (INT4): the order quantity in whole tonnes.
- CUSTOMER (CHAR 30): the name of the customer.
- The seed class {{P}}SEED_GRV fills the table with test data.
# 4. Contract
- Create the class {{P}}GRAVEL_PRICER in package $TMP.
- The class is public, final, and has a public constructor without parameters.
- Define these public types:
- TY_ORDER_ID TYPE c LENGTH 10.
- TY_GRADE TYPE c LENGTH 1.
- TY_TONNES TYPE i.
- TY_AMOUNT TYPE p LENGTH 8 DECIMALS 2.
- TY_REASON TYPE c LENGTH 10.
- TY_RESULT: a structure with the components NET_AMOUNT (TYPE ty_amount) and
REASON (TYPE ty_reason).
- Define the public constant structure C_REASON with these components of type
TY_REASON: OK, NOT_FOUND, GRADE, QUANTITY.
- Define one public method:
PRICE_ORDER
IMPORTING iv_order_id TYPE ty_order_id
RETURNING VALUE(rs_result) TYPE ty_result.
- Do not add other public methods.
# 5. Business rules
Apply the rules in this sequence. Return the reason of the first rule that fails.
1. Read the order with the number iv_order_id from the table {{P}}GRV_ORD. If
the table has no order with this number, return NOT_FOUND.
2. The grade must be F (fine), M (medium) or C (coarse). If the grade is not
one of these three letters, return GRADE.
3. The quantity must be greater than zero. If the quantity is zero or negative,
return QUANTITY.
4. The base price of one tonne is 42.00 EUR for grade F, 36.00 EUR for grade M
and 30.00 EUR for grade C.
5. The discount depends on the order quantity:
- An order of up to 4 tonnes gets no discount.
- An order of 6 to 19 tonnes gets a discount of 5 percent.
- An order of 20 tonnes or more gets a discount of 10 percent.
6. The net amount is the base price multiplied by the quantity, less the
discount. Round the net amount to 2 decimals. Return OK.
# 6. Constraints
- Release target: SAP_BASIS 816.
- Coding standards: Clean ABAP. Method length below 40 statements. No global
variables. No comment that restates the code.
- Out of scope: do not change the table {{P}}GRV_ORD and the seed class
{{P}}SEED_GRV.
# 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,68 @@
{
"id": "G1047",
"category": "H",
"object_type": "CLAS",
"difficulty": 2,
"release_target": "v816",
"expected_outcome": "stop",
"expected_gap": {
"description": "The business rules do not state the discount for an order of exactly 5 tonnes, so the net amount of such an order cannot be calculated.",
"keywords": [
[
"discount",
"tonnes"
],
[
"5",
"tonnes"
],
[
"5",
"discount"
]
]
},
"budget": {
"max_tool_calls": 60,
"max_activations": 15
},
"seed": [
{
"type": "TABL",
"name": "{{P}}GRV_ORD",
"file": "seed/grv_ord.tabl.abap",
"description": "Gravel orders of the quarry"
},
{
"type": "CLAS",
"name": "{{P}}SEED_GRV",
"file": "seed/seed_grv.clas.abap",
"description": "Fills the gravel order table with test data",
"run": true
}
],
"contract": [
{
"type": "CLAS",
"name": "{{P}}GRAVEL_PRICER"
}
],
"out_of_scope": [
"{{P}}GRV_ORD",
"{{P}}SEED_GRV"
],
"hidden_tests": [],
"reference": [
{
"type": "CLAS",
"name": "{{P}}GRAVEL_PRICER",
"file": "reference/gravel_pricer.clas.abap",
"description": "Calculates the net amount of one gravel order",
"testclasses_file": "reference/gravel_pricer.testclasses.abap"
}
],
"craft_checks": [
"method_length",
"db_operation_in_loop"
]
}

View File

@@ -0,0 +1,14 @@
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Truck with depot'
define view entity {{P}}I_TRUCK
as select from {{p}}truck as truck
left outer join {{p}}depot as depot on depot.depot_id = truck.depot_id
association [0..1] to {{p}}depot as _Depot on truck.depot_id = _Depot.depot_id
{
key truck.truck_id as truck_id,
truck.depot_id as depot_id,
truck.capacity_kg as capacity_kg,
truck.truck_type as truck_type,
_Depot
}
where truck.capacity_kg > 0

View File

@@ -0,0 +1,14 @@
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Truck with depot'
define view entity {{P}}I_TRUCK
as select from {{p}}truck as truck
inner join {{p}}depot as depot on depot.depot_id <> truck.depot_id
association [0..1] to {{p}}depot as _Depot on truck.depot_id = _Depot.depot_id
{
key truck.truck_id as truck_id,
truck.depot_id as depot_id,
truck.capacity_kg as capacity_kg,
truck.truck_type as truck_type,
_Depot
}
where truck.capacity_kg > 0

View File

@@ -0,0 +1,14 @@
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Truck with depot'
define view entity {{P}}I_TRUCK
as select from {{p}}truck as truck
inner join {{p}}depot as depot on depot.depot_id = truck.depot_id
association [0..1] to {{p}}depot as _Depot on truck.depot_id <> _Depot.depot_id
{
key truck.truck_id as truck_id,
truck.depot_id as depot_id,
truck.capacity_kg as capacity_kg,
truck.truck_type as truck_type,
_Depot
}
where truck.capacity_kg > 0

View File

@@ -0,0 +1,14 @@
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Truck with depot'
define view entity {{P}}I_TRUCK
as select from {{p}}truck as truck
inner join {{p}}depot as depot on depot.depot_id = truck.depot_id
association [0..1] to {{p}}depot as _Depot on truck.depot_id = _Depot.depot_id
{
key truck.truck_id as truck_id,
truck.depot_id as depot_id,
truck.capacity_kg as capacity_kg,
truck.truck_type as truck_type,
_Depot
}
where truck.capacity_kg <= 0

View File

@@ -0,0 +1,29 @@
{
"id": "G1048",
"pool": "train",
"object_type": "DDLS",
"category": "B",
"attempts": [
{
"stage": "validate",
"oracle": 0,
"null": 0
},
{
"stage": "validate",
"oracle": 85.0,
"null": 0
},
{
"stage": "validate",
"oracle": 100.0,
"null": 0,
"mutation": {
"valid": 4,
"killed": 4,
"ok": true
}
}
],
"accepted": true
}

View File

@@ -0,0 +1,95 @@
CLASS {{p}}t21_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
CLASS-DATA go_env TYPE REF TO if_cds_test_environment.
CLASS-METHODS class_setup.
CLASS-METHODS class_teardown.
METHODS setup.
METHODS one_row_per_truck FOR TESTING.
METHODS depot_name_via_path FOR TESTING.
METHODS city_via_path FOR TESTING.
METHODS depot_names_of_all FOR TESTING.
METHODS zero_capacity_hidden FOR TESTING.
METHODS unknown_depot_hidden FOR TESTING.
METHODS truck_type_shown FOR TESTING.
METHODS capacity_shown FOR TESTING.
ENDCLASS.
CLASS {{p}}t21_hidden IMPLEMENTATION.
METHOD class_setup.
go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_TRUCK' ).
ENDMETHOD.
METHOD class_teardown.
go_env->destroy( ).
ENDMETHOD.
METHOD setup.
DATA lt_depot TYPE STANDARD TABLE OF {{p}}depot WITH EMPTY KEY.
DATA lt_truck TYPE STANDARD TABLE OF {{p}}truck WITH EMPTY KEY.
go_env->clear_doubles( ).
lt_depot = VALUE #(
( client = sy-mandt depot_id = 'D1' depot_name = 'North Depot' city = 'HAMBURG' )
( client = sy-mandt depot_id = 'D2' depot_name = 'South Depot' city = 'MUNICH' ) ).
lt_truck = VALUE #(
( client = sy-mandt truck_id = 'T1' depot_id = 'D1' capacity_kg = 12000 truck_type = 'BOX' )
( client = sy-mandt truck_id = 'T2' depot_id = 'D1' capacity_kg = 7500 truck_type = 'FLAT' )
( client = sy-mandt truck_id = 'T3' depot_id = 'D2' capacity_kg = 20000 truck_type = 'BOX' )
( client = sy-mandt truck_id = 'T4' depot_id = 'D2' capacity_kg = 0 truck_type = 'BOX' )
( client = sy-mandt truck_id = 'T5' depot_id = 'D9' capacity_kg = 5000 truck_type = 'BOX' ) ).
go_env->insert_test_data( lt_depot ).
go_env->insert_test_data( lt_truck ).
ENDMETHOD.
METHOD one_row_per_truck.
SELECT COUNT(*) FROM {{p}}i_truck INTO @DATA(lv_rows).
cl_abap_unit_assert=>assert_equals( exp = 3 act = lv_rows ).
ENDMETHOD.
METHOD depot_name_via_path.
SELECT SINGLE t~\_depot-depot_name FROM {{p}}i_truck AS t
WHERE t~truck_id = 'T1' INTO @DATA(lv_name).
cl_abap_unit_assert=>assert_equals( exp = 'North Depot' act = lv_name ).
ENDMETHOD.
METHOD city_via_path.
SELECT SINGLE t~\_depot-city FROM {{p}}i_truck AS t
WHERE t~truck_id = 'T3' INTO @DATA(lv_city).
cl_abap_unit_assert=>assert_equals( exp = 'MUNICH' act = lv_city ).
ENDMETHOD.
METHOD depot_names_of_all.
SELECT t~truck_id, t~\_depot-depot_name AS depot_name
FROM {{p}}i_truck AS t INTO TABLE @DATA(lt_rows).
cl_abap_unit_assert=>assert_equals( exp = 3 act = lines( lt_rows ) ).
READ TABLE lt_rows INTO DATA(ls_row) WITH KEY truck_id = 'T3'.
cl_abap_unit_assert=>assert_equals( exp = 'South Depot' act = ls_row-depot_name ).
ENDMETHOD.
METHOD zero_capacity_hidden.
SELECT SINGLE t~truck_id FROM {{p}}i_truck AS t
WHERE t~truck_id = 'T4' INTO @DATA(lv_id).
cl_abap_unit_assert=>assert_equals( exp = 4 act = sy-subrc ).
cl_abap_unit_assert=>assert_initial( act = lv_id ).
ENDMETHOD.
METHOD unknown_depot_hidden.
SELECT SINGLE t~truck_id FROM {{p}}i_truck AS t
WHERE t~truck_id = 'T5' INTO @DATA(lv_id).
cl_abap_unit_assert=>assert_equals( exp = 4 act = sy-subrc ).
cl_abap_unit_assert=>assert_initial( act = lv_id ).
ENDMETHOD.
METHOD truck_type_shown.
SELECT SINGLE t~truck_type FROM {{p}}i_truck AS t
WHERE t~truck_id = 'T2' INTO @DATA(lv_type).
cl_abap_unit_assert=>assert_equals( exp = 'FLAT' act = lv_type ).
ENDMETHOD.
METHOD capacity_shown.
SELECT SINGLE t~capacity_kg FROM {{p}}i_truck AS t
WHERE t~truck_id = 'T3' INTO @DATA(lv_capacity).
cl_abap_unit_assert=>assert_equals( exp = 20000 act = lv_capacity ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,57 @@
{
"task": "G1048",
"mutants": [
{
"object": "{{P}}I_TRUCK",
"mutant": "line 5: inner join -> left outer join (join)",
"status": "killed",
"hidden": "5/8",
"failed_tests": [
"DEPOT_NAMES_OF_ALL",
"ONE_ROW_PER_TRUCK",
"UNKNOWN_DEPOT_HIDDEN"
]
},
{
"object": "{{P}}I_TRUCK",
"mutant": "line 5: = -> <> (eq)",
"status": "killed",
"hidden": "5/8",
"failed_tests": [
"DEPOT_NAMES_OF_ALL",
"ONE_ROW_PER_TRUCK",
"UNKNOWN_DEPOT_HIDDEN"
]
},
{
"object": "{{P}}I_TRUCK",
"mutant": "line 6: = -> <> (eq)",
"status": "killed",
"hidden": "5/8",
"failed_tests": [
"CITY_VIA_PATH",
"DEPOT_NAMES_OF_ALL",
"DEPOT_NAME_VIA_PATH"
]
},
{
"object": "{{P}}I_TRUCK",
"mutant": "line 14: > -> <= (rel)",
"status": "killed",
"hidden": "1/8",
"failed_tests": [
"CAPACITY_SHOWN",
"CITY_VIA_PATH",
"DEPOT_NAMES_OF_ALL",
"DEPOT_NAME_VIA_PATH",
"ONE_ROW_PER_TRUCK",
"TRUCK_TYPE_SHOWN",
"ZERO_CAPACITY_HIDDEN"
]
}
],
"valid": 4,
"killed": 4,
"kill_rate": 1.0,
"ok": true
}

View File

@@ -0,0 +1,14 @@
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Truck with depot'
define view entity {{P}}I_TRUCK
as select from {{p}}truck as truck
inner join {{p}}depot as depot on depot.depot_id = truck.depot_id
association [0..1] to {{p}}depot as _Depot on truck.depot_id = _Depot.depot_id
{
key truck.truck_id as truck_id,
truck.depot_id as depot_id,
truck.capacity_kg as capacity_kg,
truck.truck_type as truck_type,
_Depot
}
where truck.capacity_kg > 0

View File

@@ -0,0 +1,51 @@
CLASS {{p}}t21_test DEFINITION PUBLIC FINAL CREATE PUBLIC
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
CLASS-DATA go_env TYPE REF TO if_cds_test_environment.
CLASS-METHODS class_setup.
CLASS-METHODS class_teardown.
METHODS setup.
METHODS depot_of_truck FOR TESTING.
METHODS zero_capacity_absent FOR TESTING.
ENDCLASS.
CLASS {{p}}t21_test IMPLEMENTATION.
METHOD class_setup.
go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_TRUCK' ).
ENDMETHOD.
METHOD class_teardown.
go_env->destroy( ).
ENDMETHOD.
METHOD setup.
DATA lt_depot TYPE STANDARD TABLE OF {{p}}depot WITH EMPTY KEY.
DATA lt_truck TYPE STANDARD TABLE OF {{p}}truck WITH EMPTY KEY.
go_env->clear_doubles( ).
lt_depot = VALUE #(
( client = sy-mandt depot_id = 'D1' depot_name = 'North Depot' city = 'HAMBURG' )
( client = sy-mandt depot_id = 'D2' depot_name = 'South Depot' city = 'MUNICH' ) ).
lt_truck = VALUE #(
( client = sy-mandt truck_id = 'T1' depot_id = 'D1' capacity_kg = 12000 truck_type = 'BOX' )
( client = sy-mandt truck_id = 'T2' depot_id = 'D1' capacity_kg = 7500 truck_type = 'FLAT' )
( client = sy-mandt truck_id = 'T3' depot_id = 'D2' capacity_kg = 20000 truck_type = 'BOX' )
( client = sy-mandt truck_id = 'T4' depot_id = 'D2' capacity_kg = 0 truck_type = 'BOX' )
( client = sy-mandt truck_id = 'T5' depot_id = 'D9' capacity_kg = 5000 truck_type = 'BOX' ) ).
go_env->insert_test_data( lt_depot ).
go_env->insert_test_data( lt_truck ).
ENDMETHOD.
METHOD depot_of_truck.
SELECT SINGLE t~\_depot-city FROM {{p}}i_truck AS t
WHERE t~truck_id = 'T1' INTO @DATA(lv_city).
cl_abap_unit_assert=>assert_equals( exp = 'HAMBURG' act = lv_city ).
ENDMETHOD.
METHOD zero_capacity_absent.
SELECT SINGLE t~truck_id FROM {{p}}i_truck AS t
WHERE t~truck_id = 'T4' INTO @DATA(lv_id).
cl_abap_unit_assert=>assert_equals( exp = 4 act = sy-subrc ).
cl_abap_unit_assert=>assert_initial( act = lv_id ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,11 @@
@EndUserText.label : 'Depot'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table {{p}}depot {
key client : abap.clnt not null;
key depot_id : abap.char(10) not null;
depot_name : abap.char(30);
city : abap.char(20);
}

View File

@@ -0,0 +1,25 @@
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}}truck.
DELETE FROM {{p}}depot.
INSERT {{p}}depot FROM TABLE @( VALUE #(
( client = sy-mandt depot_id = 'D1' depot_name = 'North Depot' city = 'HAMBURG' )
( client = sy-mandt depot_id = 'D2' depot_name = 'South Depot' city = 'MUNICH' ) ) ).
INSERT {{p}}truck FROM TABLE @( VALUE #(
( client = sy-mandt truck_id = 'T1' depot_id = 'D1' capacity_kg = 12000 truck_type = 'BOX' )
( client = sy-mandt truck_id = 'T2' depot_id = 'D1' capacity_kg = 7500 truck_type = 'FLAT' )
( client = sy-mandt truck_id = 'T3' depot_id = 'D2' capacity_kg = 20000 truck_type = 'BOX' )
( client = sy-mandt truck_id = 'T4' depot_id = 'D2' capacity_kg = 0 truck_type = 'BOX' )
( client = sy-mandt truck_id = 'T5' depot_id = 'D9' capacity_kg = 5000 truck_type = 'BOX' ) ) ).
out->write( 'Seed data written' ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,12 @@
@EndUserText.label : 'Truck'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table {{p}}truck {
key client : abap.clnt not null;
key truck_id : abap.char(10) not null;
depot_id : abap.char(10);
capacity_kg : abap.int4;
truck_type : abap.char(4);
}

View File

@@ -0,0 +1,53 @@
# 1. Goal
Show each truck of the fleet together with the depot that it belongs to. A
planning program and an OData service read the data. The join must be in the
database, in a CDS view. The consumers read the depot data with a path
expression over the association of the view.
# 2. Open questions
None.
# 3. Context
- Table {{P}}DEPOT (depot), package $TMP. Key: DEPOT_ID (CHAR 10).
Fields: DEPOT_NAME (CHAR 30), CITY (CHAR 20).
- Table {{P}}TRUCK (truck), package $TMP. Key: TRUCK_ID (CHAR 10).
Fields: DEPOT_ID (CHAR 10), CAPACITY_KG (INT4, payload in kilograms),
TRUCK_TYPE (CHAR 4).
- A truck belongs to one depot. The depot is in {{P}}DEPOT.
# 4. Contract
- Create the CDS view entity {{P}}I_TRUCK in package $TMP.
- Elements, with these names: TRUCK_ID (key), DEPOT_ID, CAPACITY_KG,
TRUCK_TYPE.
- The view exposes the association `_Depot` to {{P}}DEPOT. The association is
an element of the view and its name is `_Depot`.
- An ABAP SQL consumer reads the depot with the path expression
`\_Depot-DEPOT_NAME` and `\_Depot-CITY`.
- The authorization check is not required (#NOT_REQUIRED).
# 5. Business rules
1. The view has one row for each truck with a CAPACITY_KG greater than zero.
A truck with a capacity of zero or less is not in the view.
2. The view has one row for each truck whose depot exists in {{P}}DEPOT.
A truck with a DEPOT_ID that is not in {{P}}DEPOT is not in the view.
3. TRUCK_ID, DEPOT_ID, CAPACITY_KG and TRUCK_TYPE are the values of the
truck.
4. The association `_Depot` points from a truck to the depot with the same
DEPOT_ID. The cardinality is to-one.
# 6. Constraints
- Release target: ABAP Platform 2025, SAP_BASIS 816.
- Coding standards: Clean ABAP. No ATC findings of priority 1 or 2.
- Out of scope: do not change {{P}}DEPOT and {{P}}TRUCK.
# 7. Acceptance
- The view is active and has no syntax error.
- The hidden tests pass.
- Write ABAP Unit tests with CL_CDS_TEST_ENVIRONMENT in a global test class.

View File

@@ -0,0 +1,72 @@
{
"id": "G1048",
"category": "B",
"object_type": "DDLS",
"difficulty": 2,
"release_target": "v816",
"expected_outcome": "implement",
"budget": {
"max_tool_calls": 60,
"max_activations": 15
},
"seed": [
{
"type": "TABL",
"name": "{{P}}DEPOT",
"file": "seed/depot.tabl.asabap",
"description": "Depot"
},
{
"type": "TABL",
"name": "{{P}}TRUCK",
"file": "seed/truck.tabl.asabap",
"description": "Truck"
},
{
"type": "CLAS",
"name": "{{P}}SEED_DATA",
"file": "seed/seed_data.clas.abap",
"description": "Seed data for depot and truck",
"run": true
}
],
"contract": [
{
"type": "DDLS",
"name": "{{P}}I_TRUCK",
"fields": [
"TRUCK_ID",
"DEPOT_ID",
"CAPACITY_KG",
"TRUCK_TYPE"
]
}
],
"out_of_scope": [
"{{P}}DEPOT",
"{{P}}TRUCK"
],
"hidden_tests": [
{
"type": "CLAS",
"name": "{{P}}T21_HIDDEN",
"file": "hidden/t21_hidden.clas.abap",
"description": "T21 hidden tests"
}
],
"reference": [
{
"type": "DDLS",
"name": "{{P}}I_TRUCK",
"file": "reference/i_truck.ddls.asddls",
"description": "Truck with exposed depot association"
},
{
"type": "CLAS",
"name": "{{P}}T21_TEST",
"file": "reference/t21_test.clas.abap",
"description": "T21 own tests"
}
],
"craft_checks": []
}

View File

@@ -0,0 +1,126 @@
CLASS {{p}}tailor_pricer DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_garment TYPE c LENGTH 10.
TYPES ty_service TYPE c LENGTH 10.
TYPES ty_price TYPE p LENGTH 8 DECIMALS 2.
METHODS calculate_price
IMPORTING iv_garment TYPE ty_garment
iv_service TYPE ty_service
iv_quantity TYPE i
iv_express TYPE abap_bool
RETURNING VALUE(rv_price) TYPE ty_price.
PRIVATE SECTION.
CONSTANTS:
c_express_fee TYPE ty_price VALUE '6.00',
c_minimum_price TYPE ty_price VALUE '15.00',
c_discount_low TYPE ty_price VALUE '10.00',
c_discount_high TYPE ty_price VALUE '20.00',
c_qty_low TYPE i VALUE 3,
c_qty_high TYPE i VALUE 5,
c_percent_base TYPE i VALUE 100.
METHODS service_base
IMPORTING iv_service TYPE ty_service
RETURNING VALUE(rv_base) TYPE ty_price.
METHODS garment_factor
IMPORTING iv_garment TYPE ty_garment
RETURNING VALUE(rv_factor) TYPE ty_price.
METHODS discount_percent
IMPORTING iv_quantity TYPE i
RETURNING VALUE(rv_percent) TYPE ty_price.
ENDCLASS.
CLASS {{p}}tailor_pricer IMPLEMENTATION.
METHOD calculate_price.
DATA lv_base TYPE ty_price.
DATA lv_factor TYPE ty_price.
DATA lv_unit TYPE ty_price.
DATA lv_total TYPE ty_price.
DATA lv_discount TYPE ty_price.
IF iv_quantity <= 0.
RETURN.
ENDIF.
lv_base = service_base( iv_service ).
lv_factor = garment_factor( iv_garment ).
IF lv_base <= 0 AND lv_factor <= 0.
RETURN.
ENDIF.
lv_unit = lv_base * lv_factor.
IF iv_express = abap_true.
lv_unit = lv_unit + c_express_fee.
ENDIF.
lv_total = lv_unit * iv_quantity.
lv_discount = discount_percent( iv_quantity ).
lv_total = lv_total - lv_total * lv_discount / c_percent_base.
IF lv_total < c_minimum_price.
rv_price = c_minimum_price.
ELSE.
rv_price = lv_total.
ENDIF.
ENDMETHOD.
METHOD service_base.
CASE iv_service.
WHEN 'HEM'.
rv_base = '8.00'.
WHEN 'TAKE_IN'.
rv_base = '15.00'.
WHEN 'ZIP'.
rv_base = '12.00'.
WHEN 'SLEEVE'.
rv_base = '10.00'.
WHEN 'LINING'.
rv_base = '25.00'.
WHEN OTHERS.
rv_base = 0.
ENDCASE.
ENDMETHOD.
METHOD garment_factor.
CASE iv_garment.
WHEN 'TROUSERS'.
rv_factor = '1.00'.
WHEN 'SKIRT'.
rv_factor = '1.00'.
WHEN 'JACKET'.
rv_factor = '1.50'.
WHEN 'DRESS'.
rv_factor = '1.50'.
WHEN 'COAT'.
rv_factor = '2.00'.
WHEN OTHERS.
rv_factor = 0.
ENDCASE.
ENDMETHOD.
METHOD discount_percent.
IF iv_quantity >= c_qty_high.
rv_percent = c_discount_high.
ELSEIF iv_quantity >= c_qty_low.
rv_percent = c_discount_low.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,126 @@
CLASS {{p}}tailor_pricer DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_garment TYPE c LENGTH 10.
TYPES ty_service TYPE c LENGTH 10.
TYPES ty_price TYPE p LENGTH 8 DECIMALS 2.
METHODS calculate_price
IMPORTING iv_garment TYPE ty_garment
iv_service TYPE ty_service
iv_quantity TYPE i
iv_express TYPE abap_bool
RETURNING VALUE(rv_price) TYPE ty_price.
PRIVATE SECTION.
CONSTANTS:
c_express_fee TYPE ty_price VALUE '6.00',
c_minimum_price TYPE ty_price VALUE '15.00',
c_discount_low TYPE ty_price VALUE '10.00',
c_discount_high TYPE ty_price VALUE '20.00',
c_qty_low TYPE i VALUE 3,
c_qty_high TYPE i VALUE 5,
c_percent_base TYPE i VALUE 100.
METHODS service_base
IMPORTING iv_service TYPE ty_service
RETURNING VALUE(rv_base) TYPE ty_price.
METHODS garment_factor
IMPORTING iv_garment TYPE ty_garment
RETURNING VALUE(rv_factor) TYPE ty_price.
METHODS discount_percent
IMPORTING iv_quantity TYPE i
RETURNING VALUE(rv_percent) TYPE ty_price.
ENDCLASS.
CLASS {{p}}tailor_pricer IMPLEMENTATION.
METHOD calculate_price.
DATA lv_base TYPE ty_price.
DATA lv_factor TYPE ty_price.
DATA lv_unit TYPE ty_price.
DATA lv_total TYPE ty_price.
DATA lv_discount TYPE ty_price.
IF iv_quantity <= 0.
RETURN.
ENDIF.
lv_base = service_base( iv_service ).
lv_factor = garment_factor( iv_garment ).
IF lv_base <= 0 OR lv_factor <= 0.
RETURN.
ENDIF.
lv_unit = lv_base * lv_factor.
IF iv_express <> abap_true.
lv_unit = lv_unit + c_express_fee.
ENDIF.
lv_total = lv_unit * iv_quantity.
lv_discount = discount_percent( iv_quantity ).
lv_total = lv_total - lv_total * lv_discount / c_percent_base.
IF lv_total < c_minimum_price.
rv_price = c_minimum_price.
ELSE.
rv_price = lv_total.
ENDIF.
ENDMETHOD.
METHOD service_base.
CASE iv_service.
WHEN 'HEM'.
rv_base = '8.00'.
WHEN 'TAKE_IN'.
rv_base = '15.00'.
WHEN 'ZIP'.
rv_base = '12.00'.
WHEN 'SLEEVE'.
rv_base = '10.00'.
WHEN 'LINING'.
rv_base = '25.00'.
WHEN OTHERS.
rv_base = 0.
ENDCASE.
ENDMETHOD.
METHOD garment_factor.
CASE iv_garment.
WHEN 'TROUSERS'.
rv_factor = '1.00'.
WHEN 'SKIRT'.
rv_factor = '1.00'.
WHEN 'JACKET'.
rv_factor = '1.50'.
WHEN 'DRESS'.
rv_factor = '1.50'.
WHEN 'COAT'.
rv_factor = '2.00'.
WHEN OTHERS.
rv_factor = 0.
ENDCASE.
ENDMETHOD.
METHOD discount_percent.
IF iv_quantity >= c_qty_high.
rv_percent = c_discount_high.
ELSEIF iv_quantity >= c_qty_low.
rv_percent = c_discount_low.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,126 @@
CLASS {{p}}tailor_pricer DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_garment TYPE c LENGTH 10.
TYPES ty_service TYPE c LENGTH 10.
TYPES ty_price TYPE p LENGTH 8 DECIMALS 2.
METHODS calculate_price
IMPORTING iv_garment TYPE ty_garment
iv_service TYPE ty_service
iv_quantity TYPE i
iv_express TYPE abap_bool
RETURNING VALUE(rv_price) TYPE ty_price.
PRIVATE SECTION.
CONSTANTS:
c_express_fee TYPE ty_price VALUE '6.00',
c_minimum_price TYPE ty_price VALUE '15.00',
c_discount_low TYPE ty_price VALUE '10.00',
c_discount_high TYPE ty_price VALUE '20.00',
c_qty_low TYPE i VALUE 3,
c_qty_high TYPE i VALUE 5,
c_percent_base TYPE i VALUE 100.
METHODS service_base
IMPORTING iv_service TYPE ty_service
RETURNING VALUE(rv_base) TYPE ty_price.
METHODS garment_factor
IMPORTING iv_garment TYPE ty_garment
RETURNING VALUE(rv_factor) TYPE ty_price.
METHODS discount_percent
IMPORTING iv_quantity TYPE i
RETURNING VALUE(rv_percent) TYPE ty_price.
ENDCLASS.
CLASS {{p}}tailor_pricer IMPLEMENTATION.
METHOD calculate_price.
DATA lv_base TYPE ty_price.
DATA lv_factor TYPE ty_price.
DATA lv_unit TYPE ty_price.
DATA lv_total TYPE ty_price.
DATA lv_discount TYPE ty_price.
IF iv_quantity <= 0.
RETURN.
ENDIF.
lv_base = service_base( iv_service ).
lv_factor = garment_factor( iv_garment ).
IF lv_base <= 0 OR lv_factor <= 0.
RETURN.
ENDIF.
lv_unit = lv_base * lv_factor.
IF iv_express = abap_true.
lv_unit = lv_unit - c_express_fee.
ENDIF.
lv_total = lv_unit * iv_quantity.
lv_discount = discount_percent( iv_quantity ).
lv_total = lv_total - lv_total * lv_discount / c_percent_base.
IF lv_total < c_minimum_price.
rv_price = c_minimum_price.
ELSE.
rv_price = lv_total.
ENDIF.
ENDMETHOD.
METHOD service_base.
CASE iv_service.
WHEN 'HEM'.
rv_base = '8.00'.
WHEN 'TAKE_IN'.
rv_base = '15.00'.
WHEN 'ZIP'.
rv_base = '12.00'.
WHEN 'SLEEVE'.
rv_base = '10.00'.
WHEN 'LINING'.
rv_base = '25.00'.
WHEN OTHERS.
rv_base = 0.
ENDCASE.
ENDMETHOD.
METHOD garment_factor.
CASE iv_garment.
WHEN 'TROUSERS'.
rv_factor = '1.00'.
WHEN 'SKIRT'.
rv_factor = '1.00'.
WHEN 'JACKET'.
rv_factor = '1.50'.
WHEN 'DRESS'.
rv_factor = '1.50'.
WHEN 'COAT'.
rv_factor = '2.00'.
WHEN OTHERS.
rv_factor = 0.
ENDCASE.
ENDMETHOD.
METHOD discount_percent.
IF iv_quantity >= c_qty_high.
rv_percent = c_discount_high.
ELSEIF iv_quantity >= c_qty_low.
rv_percent = c_discount_low.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,126 @@
CLASS {{p}}tailor_pricer DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_garment TYPE c LENGTH 10.
TYPES ty_service TYPE c LENGTH 10.
TYPES ty_price TYPE p LENGTH 8 DECIMALS 2.
METHODS calculate_price
IMPORTING iv_garment TYPE ty_garment
iv_service TYPE ty_service
iv_quantity TYPE i
iv_express TYPE abap_bool
RETURNING VALUE(rv_price) TYPE ty_price.
PRIVATE SECTION.
CONSTANTS:
c_express_fee TYPE ty_price VALUE '6.00',
c_minimum_price TYPE ty_price VALUE '15.00',
c_discount_low TYPE ty_price VALUE '10.00',
c_discount_high TYPE ty_price VALUE '20.00',
c_qty_low TYPE i VALUE 3,
c_qty_high TYPE i VALUE 5,
c_percent_base TYPE i VALUE 100.
METHODS service_base
IMPORTING iv_service TYPE ty_service
RETURNING VALUE(rv_base) TYPE ty_price.
METHODS garment_factor
IMPORTING iv_garment TYPE ty_garment
RETURNING VALUE(rv_factor) TYPE ty_price.
METHODS discount_percent
IMPORTING iv_quantity TYPE i
RETURNING VALUE(rv_percent) TYPE ty_price.
ENDCLASS.
CLASS {{p}}tailor_pricer IMPLEMENTATION.
METHOD calculate_price.
DATA lv_base TYPE ty_price.
DATA lv_factor TYPE ty_price.
DATA lv_unit TYPE ty_price.
DATA lv_total TYPE ty_price.
DATA lv_discount TYPE ty_price.
IF iv_quantity <= 0.
RETURN.
ENDIF.
lv_base = service_base( iv_service ).
lv_factor = garment_factor( iv_garment ).
IF lv_base <= 0 OR lv_factor <= 0.
RETURN.
ENDIF.
lv_unit = lv_base * lv_factor.
IF iv_express = abap_true.
lv_unit = lv_unit + c_express_fee.
ENDIF.
lv_total = lv_unit * iv_quantity.
lv_discount = discount_percent( iv_quantity ).
lv_total = lv_total - lv_total * lv_discount / c_percent_base.
IF lv_total >= c_minimum_price.
rv_price = c_minimum_price.
ELSE.
rv_price = lv_total.
ENDIF.
ENDMETHOD.
METHOD service_base.
CASE iv_service.
WHEN 'HEM'.
rv_base = '8.00'.
WHEN 'TAKE_IN'.
rv_base = '15.00'.
WHEN 'ZIP'.
rv_base = '12.00'.
WHEN 'SLEEVE'.
rv_base = '10.00'.
WHEN 'LINING'.
rv_base = '25.00'.
WHEN OTHERS.
rv_base = 0.
ENDCASE.
ENDMETHOD.
METHOD garment_factor.
CASE iv_garment.
WHEN 'TROUSERS'.
rv_factor = '1.00'.
WHEN 'SKIRT'.
rv_factor = '1.00'.
WHEN 'JACKET'.
rv_factor = '1.50'.
WHEN 'DRESS'.
rv_factor = '1.50'.
WHEN 'COAT'.
rv_factor = '2.00'.
WHEN OTHERS.
rv_factor = 0.
ENDCASE.
ENDMETHOD.
METHOD discount_percent.
IF iv_quantity >= c_qty_high.
rv_percent = c_discount_high.
ELSEIF iv_quantity >= c_qty_low.
rv_percent = c_discount_low.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,126 @@
CLASS {{p}}tailor_pricer DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_garment TYPE c LENGTH 10.
TYPES ty_service TYPE c LENGTH 10.
TYPES ty_price TYPE p LENGTH 8 DECIMALS 2.
METHODS calculate_price
IMPORTING iv_garment TYPE ty_garment
iv_service TYPE ty_service
iv_quantity TYPE i
iv_express TYPE abap_bool
RETURNING VALUE(rv_price) TYPE ty_price.
PRIVATE SECTION.
CONSTANTS:
c_express_fee TYPE ty_price VALUE '6.00',
c_minimum_price TYPE ty_price VALUE '15.00',
c_discount_low TYPE ty_price VALUE '10.00',
c_discount_high TYPE ty_price VALUE '20.00',
c_qty_low TYPE i VALUE 3,
c_qty_high TYPE i VALUE 5,
c_percent_base TYPE i VALUE 100.
METHODS service_base
IMPORTING iv_service TYPE ty_service
RETURNING VALUE(rv_base) TYPE ty_price.
METHODS garment_factor
IMPORTING iv_garment TYPE ty_garment
RETURNING VALUE(rv_factor) TYPE ty_price.
METHODS discount_percent
IMPORTING iv_quantity TYPE i
RETURNING VALUE(rv_percent) TYPE ty_price.
ENDCLASS.
CLASS {{p}}tailor_pricer IMPLEMENTATION.
METHOD calculate_price.
DATA lv_base TYPE ty_price.
DATA lv_factor TYPE ty_price.
DATA lv_unit TYPE ty_price.
DATA lv_total TYPE ty_price.
DATA lv_discount TYPE ty_price.
IF iv_quantity <= 0.
RETURN.
ENDIF.
lv_base = service_base( iv_service ).
lv_factor = garment_factor( iv_garment ).
IF lv_base <= 0 OR lv_factor <= 0.
RETURN.
ENDIF.
lv_unit = lv_base * lv_factor.
IF iv_express = abap_true.
lv_unit = lv_unit + c_express_fee.
ENDIF.
lv_total = lv_unit * iv_quantity.
lv_discount = discount_percent( iv_quantity ).
lv_total = lv_total - lv_total * lv_discount / c_percent_base.
IF lv_total < c_minimum_price.
rv_price = c_minimum_price.
ELSE.
rv_price = lv_total.
ENDIF.
ENDMETHOD.
METHOD service_base.
CASE iv_service.
WHEN 'HEM'.
rv_base = '8.00'.
WHEN 'TAKE_IN'.
rv_base = '15.00'.
WHEN 'ZIP'.
rv_base = '12.00'.
WHEN 'SLEEVE'.
rv_base = '10.00'.
WHEN 'LINING'.
rv_base = '25.00'.
WHEN OTHERS.
rv_base = 0.
ENDCASE.
ENDMETHOD.
METHOD garment_factor.
CASE iv_garment.
WHEN 'TROUSERS'.
rv_factor = '1.00'.
WHEN 'SKIRT'.
rv_factor = '1.00'.
WHEN 'JACKET'.
rv_factor = '1.50'.
WHEN 'DRESS'.
rv_factor = '1.50'.
WHEN 'COAT'.
rv_factor = '2.00'.
WHEN OTHERS.
rv_factor = 0.
ENDCASE.
ENDMETHOD.
METHOD discount_percent.
IF iv_quantity < c_qty_high.
rv_percent = c_discount_high.
ELSEIF iv_quantity >= c_qty_low.
rv_percent = c_discount_low.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,44 @@
{
"id": "G1050",
"pool": "train",
"object_type": "CLAS",
"category": "E",
"attempts": [
{
"stage": "bundle",
"errors": [
"reference/tailor_pricer.clas.abap line 100: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"rt_factor\"",
"reference/tailor_pricer.clas.abap line 102: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"5\"",
"reference/tailor_pricer.clas.abap line 103: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"5\""
],
"by_check": {
"abaplint": 3
}
},
{
"stage": "validate",
"oracle": 88.9,
"null": 0
},
{
"stage": "bundle",
"errors": [
"invalid JSON: Unterminated string starting at: line 1 column 5615 (char 5614)"
],
"by_check": {
"json": 1
}
},
{
"stage": "validate",
"oracle": 100.0,
"null": 0,
"mutation": {
"valid": 5,
"killed": 5,
"ok": true
}
}
],
"accepted": true
}

View File

@@ -0,0 +1,131 @@
CLASS {{p}}tailor_hidden DEFINITION
PUBLIC
FINAL
CREATE PUBLIC
FOR TESTING
DURATION SHORT
RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA mo_cut TYPE REF TO {{p}}tailor_pricer.
METHODS setup.
METHODS minimum_price FOR TESTING.
METHODS ten_percent_discount FOR TESTING.
METHODS twenty_percent_discount FOR TESTING.
METHODS express_fee FOR TESTING.
METHODS express_hits_minimum FOR TESTING.
METHODS coat_lining FOR TESTING.
METHODS unknown_service FOR TESTING.
METHODS unknown_garment FOR TESTING.
METHODS zero_quantity FOR TESTING.
METHODS negative_quantity FOR TESTING.
METHODS plain_price FOR TESTING.
ENDCLASS.
CLASS {{p}}tailor_hidden IMPLEMENTATION.
METHOD setup.
mo_cut = NEW {{p}}tailor_pricer( ).
ENDMETHOD.
METHOD minimum_price.
cl_abap_unit_assert=>assert_equals(
exp = CONV {{p}}tailor_pricer=>ty_price( '15.00' )
act = mo_cut->calculate_price( iv_garment = 'TROUSERS'
iv_service = 'HEM'
iv_quantity = 1
iv_express = abap_false ) ).
ENDMETHOD.
METHOD ten_percent_discount.
cl_abap_unit_assert=>assert_equals(
exp = CONV {{p}}tailor_pricer=>ty_price( '32.40' )
act = mo_cut->calculate_price( iv_garment = 'SKIRT'
iv_service = 'ZIP'
iv_quantity = 3
iv_express = abap_false ) ).
ENDMETHOD.
METHOD twenty_percent_discount.
cl_abap_unit_assert=>assert_equals(
exp = CONV {{p}}tailor_pricer=>ty_price( '32.00' )
act = mo_cut->calculate_price( iv_garment = 'TROUSERS'
iv_service = 'HEM'
iv_quantity = 5
iv_express = abap_false ) ).
ENDMETHOD.
METHOD express_fee.
cl_abap_unit_assert=>assert_equals(
exp = CONV {{p}}tailor_pricer=>ty_price( '57.00' )
act = mo_cut->calculate_price( iv_garment = 'JACKET'
iv_service = 'TAKE_IN'
iv_quantity = 2
iv_express = abap_true ) ).
ENDMETHOD.
METHOD express_hits_minimum.
cl_abap_unit_assert=>assert_equals(
exp = CONV {{p}}tailor_pricer=>ty_price( '15.00' )
act = mo_cut->calculate_price( iv_garment = 'TROUSERS'
iv_service = 'HEM'
iv_quantity = 1
iv_express = abap_true ) ).
ENDMETHOD.
METHOD coat_lining.
cl_abap_unit_assert=>assert_equals(
exp = CONV {{p}}tailor_pricer=>ty_price( '135.00' )
act = mo_cut->calculate_price( iv_garment = 'COAT'
iv_service = 'LINING'
iv_quantity = 3
iv_express = abap_false ) ).
ENDMETHOD.
METHOD unknown_service.
cl_abap_unit_assert=>assert_equals(
exp = CONV {{p}}tailor_pricer=>ty_price( '0.00' )
act = mo_cut->calculate_price( iv_garment = 'TROUSERS'
iv_service = 'PATCH'
iv_quantity = 2
iv_express = abap_false ) ).
ENDMETHOD.
METHOD unknown_garment.
cl_abap_unit_assert=>assert_equals(
exp = CONV {{p}}tailor_pricer=>ty_price( '0.00' )
act = mo_cut->calculate_price( iv_garment = 'SHIRT'
iv_service = 'HEM'
iv_quantity = 2
iv_express = abap_false ) ).
ENDMETHOD.
METHOD zero_quantity.
cl_abap_unit_assert=>assert_equals(
exp = CONV {{p}}tailor_pricer=>ty_price( '0.00' )
act = mo_cut->calculate_price( iv_garment = 'TROUSERS'
iv_service = 'HEM'
iv_quantity = 0
iv_express = abap_false ) ).
ENDMETHOD.
METHOD negative_quantity.
cl_abap_unit_assert=>assert_equals(
exp = CONV {{p}}tailor_pricer=>ty_price( '0.00' )
act = mo_cut->calculate_price( iv_garment = 'TROUSERS'
iv_service = 'HEM'
iv_quantity = -2
iv_express = abap_false ) ).
ENDMETHOD.
METHOD plain_price.
cl_abap_unit_assert=>assert_equals(
exp = CONV {{p}}tailor_pricer=>ty_price( '18.00' )
act = mo_cut->calculate_price( iv_garment = 'JACKET'
iv_service = 'ZIP'
iv_quantity = 1
iv_express = abap_false ) ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,69 @@
{
"task": "G1050",
"mutants": [
{
"object": "{{P}}TAILOR_PRICER",
"mutant": "line 60: OR -> AND (logic)",
"status": "killed",
"hidden": "9/11",
"failed_tests": [
"UNKNOWN_GARMENT",
"UNKNOWN_SERVICE"
]
},
{
"object": "{{P}}TAILOR_PRICER",
"mutant": "line 65: = -> <> (eq)",
"status": "killed",
"hidden": "6/11",
"failed_tests": [
"COAT_LINING",
"EXPRESS_FEE",
"PLAIN_PRICE",
"TEN_PERCENT_DISCOUNT",
"TWENTY_PERCENT_DISCOUNT"
]
},
{
"object": "{{P}}TAILOR_PRICER",
"mutant": "line 66: + -> - (arith)",
"status": "killed",
"hidden": "10/11",
"failed_tests": [
"EXPRESS_FEE"
]
},
{
"object": "{{P}}TAILOR_PRICER",
"mutant": "line 73: < -> >= (rel)",
"status": "killed",
"hidden": "4/11",
"failed_tests": [
"COAT_LINING",
"EXPRESS_FEE",
"EXPRESS_HITS_MINIMUM",
"MINIMUM_PRICE",
"PLAIN_PRICE",
"TEN_PERCENT_DISCOUNT",
"TWENTY_PERCENT_DISCOUNT"
]
},
{
"object": "{{P}}TAILOR_PRICER",
"mutant": "line 119: >= -> < (rel)",
"status": "killed",
"hidden": "6/11",
"failed_tests": [
"COAT_LINING",
"EXPRESS_FEE",
"PLAIN_PRICE",
"TEN_PERCENT_DISCOUNT",
"TWENTY_PERCENT_DISCOUNT"
]
}
],
"valid": 5,
"killed": 5,
"kill_rate": 1.0,
"ok": true
}

View File

@@ -0,0 +1,126 @@
CLASS {{p}}tailor_pricer DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_garment TYPE c LENGTH 10.
TYPES ty_service TYPE c LENGTH 10.
TYPES ty_price TYPE p LENGTH 8 DECIMALS 2.
METHODS calculate_price
IMPORTING iv_garment TYPE ty_garment
iv_service TYPE ty_service
iv_quantity TYPE i
iv_express TYPE abap_bool
RETURNING VALUE(rv_price) TYPE ty_price.
PRIVATE SECTION.
CONSTANTS:
c_express_fee TYPE ty_price VALUE '6.00',
c_minimum_price TYPE ty_price VALUE '15.00',
c_discount_low TYPE ty_price VALUE '10.00',
c_discount_high TYPE ty_price VALUE '20.00',
c_qty_low TYPE i VALUE 3,
c_qty_high TYPE i VALUE 5,
c_percent_base TYPE i VALUE 100.
METHODS service_base
IMPORTING iv_service TYPE ty_service
RETURNING VALUE(rv_base) TYPE ty_price.
METHODS garment_factor
IMPORTING iv_garment TYPE ty_garment
RETURNING VALUE(rv_factor) TYPE ty_price.
METHODS discount_percent
IMPORTING iv_quantity TYPE i
RETURNING VALUE(rv_percent) TYPE ty_price.
ENDCLASS.
CLASS {{p}}tailor_pricer IMPLEMENTATION.
METHOD calculate_price.
DATA lv_base TYPE ty_price.
DATA lv_factor TYPE ty_price.
DATA lv_unit TYPE ty_price.
DATA lv_total TYPE ty_price.
DATA lv_discount TYPE ty_price.
IF iv_quantity <= 0.
RETURN.
ENDIF.
lv_base = service_base( iv_service ).
lv_factor = garment_factor( iv_garment ).
IF lv_base <= 0 OR lv_factor <= 0.
RETURN.
ENDIF.
lv_unit = lv_base * lv_factor.
IF iv_express = abap_true.
lv_unit = lv_unit + c_express_fee.
ENDIF.
lv_total = lv_unit * iv_quantity.
lv_discount = discount_percent( iv_quantity ).
lv_total = lv_total - lv_total * lv_discount / c_percent_base.
IF lv_total < c_minimum_price.
rv_price = c_minimum_price.
ELSE.
rv_price = lv_total.
ENDIF.
ENDMETHOD.
METHOD service_base.
CASE iv_service.
WHEN 'HEM'.
rv_base = '8.00'.
WHEN 'TAKE_IN'.
rv_base = '15.00'.
WHEN 'ZIP'.
rv_base = '12.00'.
WHEN 'SLEEVE'.
rv_base = '10.00'.
WHEN 'LINING'.
rv_base = '25.00'.
WHEN OTHERS.
rv_base = 0.
ENDCASE.
ENDMETHOD.
METHOD garment_factor.
CASE iv_garment.
WHEN 'TROUSERS'.
rv_factor = '1.00'.
WHEN 'SKIRT'.
rv_factor = '1.00'.
WHEN 'JACKET'.
rv_factor = '1.50'.
WHEN 'DRESS'.
rv_factor = '1.50'.
WHEN 'COAT'.
rv_factor = '2.00'.
WHEN OTHERS.
rv_factor = 0.
ENDCASE.
ENDMETHOD.
METHOD discount_percent.
IF iv_quantity >= c_qty_high.
rv_percent = c_discount_high.
ELSEIF iv_quantity >= c_qty_low.
rv_percent = c_discount_low.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,70 @@
CLASS ltc_tailor_pricer DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA mo_cut TYPE REF TO {{p}}tailor_pricer.
METHODS setup.
METHODS minimum_price FOR TESTING.
METHODS ten_percent_discount FOR TESTING.
METHODS twenty_percent_discount FOR TESTING.
METHODS express_fee FOR TESTING.
METHODS unknown_service FOR TESTING.
METHODS unknown_garment FOR TESTING.
METHODS no_quantity FOR TESTING.
ENDCLASS.
CLASS ltc_tailor_pricer IMPLEMENTATION.
METHOD setup.
mo_cut = NEW {{p}}tailor_pricer( ).
ENDMETHOD.
METHOD minimum_price.
cl_abap_unit_assert=>assert_equals(
exp = CONV {{p}}tailor_pricer=>ty_price( '15.00' )
act = mo_cut->calculate_price( iv_garment = 'TROUSERS' iv_service = 'HEM'
iv_quantity = 1 iv_express = abap_false ) ).
ENDMETHOD.
METHOD ten_percent_discount.
cl_abap_unit_assert=>assert_equals(
exp = CONV {{p}}tailor_pricer=>ty_price( '32.40' )
act = mo_cut->calculate_price( iv_garment = 'SKIRT' iv_service = 'ZIP'
iv_quantity = 3 iv_express = abap_false ) ).
ENDMETHOD.
METHOD twenty_percent_discount.
cl_abap_unit_assert=>assert_equals(
exp = CONV {{p}}tailor_pricer=>ty_price( '32.00' )
act = mo_cut->calculate_price( iv_garment = 'TROUSERS' iv_service = 'HEM'
iv_quantity = 5 iv_express = abap_false ) ).
ENDMETHOD.
METHOD express_fee.
cl_abap_unit_assert=>assert_equals(
exp = CONV {{p}}tailor_pricer=>ty_price( '57.00' )
act = mo_cut->calculate_price( iv_garment = 'JACKET' iv_service = 'TAKE_IN'
iv_quantity = 2 iv_express = abap_true ) ).
ENDMETHOD.
METHOD unknown_service.
cl_abap_unit_assert=>assert_equals(
exp = CONV {{p}}tailor_pricer=>ty_price( '0.00' )
act = mo_cut->calculate_price( iv_garment = 'TROUSERS' iv_service = 'PATCH'
iv_quantity = 2 iv_express = abap_false ) ).
ENDMETHOD.
METHOD unknown_garment.
cl_abap_unit_assert=>assert_equals(
exp = CONV {{p}}tailor_pricer=>ty_price( '0.00' )
act = mo_cut->calculate_price( iv_garment = 'SHIRT' iv_service = 'HEM'
iv_quantity = 2 iv_express = abap_false ) ).
ENDMETHOD.
METHOD no_quantity.
cl_abap_unit_assert=>assert_equals(
exp = CONV {{p}}tailor_pricer=>ty_price( '0.00' )
act = mo_cut->calculate_price( iv_garment = 'TROUSERS' iv_service = 'HEM'
iv_quantity = 0 iv_express = abap_false ) ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,104 @@
CLASS {{p}}tailor_pricer DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_garment TYPE c LENGTH 10.
TYPES ty_service TYPE c LENGTH 10.
TYPES ty_price TYPE p LENGTH 8 DECIMALS 2.
METHODS calculate_price
IMPORTING iv_garment TYPE ty_garment
iv_service TYPE ty_service
iv_quantity TYPE i
iv_express TYPE abap_bool
RETURNING VALUE(rv_price) TYPE ty_price.
ENDCLASS.
CLASS {{p}}tailor_pricer IMPLEMENTATION.
METHOD calculate_price.
DATA lv_base TYPE ty_price.
DATA lv_factor TYPE ty_price.
DATA lv_total TYPE ty_price.
DATA lv_disc TYPE ty_price.
rv_price = 0.
" a job needs at least one garment
IF iv_quantity > 0.
" base price of the service
IF iv_service = 'HEM'.
lv_base = '8.00'.
ELSEIF iv_service = 'TAKE_IN'.
lv_base = '15.00'.
ELSEIF iv_service = 'ZIP'.
lv_base = '12.00'.
ELSEIF iv_service = 'SLEEVE'.
lv_base = '10.00'.
ELSEIF iv_service = 'LINING'.
lv_base = '25.00'.
ELSE.
lv_base = '0.00'.
ENDIF.
" factor of the garment
IF iv_garment = 'TROUSERS'.
lv_factor = '1.00'.
ELSEIF iv_garment = 'SKIRT'.
lv_factor = '1.00'.
ELSEIF iv_garment = 'JACKET'.
lv_factor = '1.50'.
ELSEIF iv_garment = 'DRESS'.
lv_factor = '1.50'.
ELSEIF iv_garment = 'COAT'.
lv_factor = '2.00'.
ELSE.
lv_factor = '0.00'.
ENDIF.
IF lv_base > '0.00' AND lv_factor > '0.00'.
" price of one garment
lv_total = lv_base * lv_factor.
" express service costs more
IF iv_express = 'X'.
lv_total = lv_total + '6.00'.
ENDIF.
" price of all garments
lv_total = lv_total * iv_quantity.
" discount for many garments
IF iv_quantity >= 5.
lv_disc = '20.00'.
ELSEIF iv_quantity >= 3.
lv_disc = '10.00'.
ELSE.
lv_disc = '0.00'.
ENDIF.
lv_total = lv_total - lv_total * lv_disc / 100.
" the shop has a minimum order value
IF lv_total < '15.00'.
lv_total = '15.00'.
ENDIF.
rv_price = lv_total.
ENDIF.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,47 @@
# 1. Goal
Refactor the legacy class {{P}}TAILOR_PRICER in package $TMP. The class calculates
the price of an alteration job in a tailor shop. The shop terminal calls the class
for each job. The behavior of the class must stay the same.
# 2. Open questions
None.
# 3. Context
- The class {{P}}TAILOR_PRICER exists in package $TMP. It is active.
- The class is public and final. The public constructor has no parameters.
- The shop terminal calls the public method CALCULATE_PRICE for each job.
- The legacy implementation is correct. It is also long, deeply nested, and full of
magic numbers. It is hard to read and hard to change.
- The customers do not accept different prices. The same input must give the same
result as before.
# 4. Contract
- The class {{P}}TAILOR_PRICER stays in package $TMP. Do not rename it.
- The class stays public and final. The public constructor stays without parameters.
- The public types ty_garment, ty_service, and ty_price stay unchanged.
- The public method stays unchanged:
calculate_price
IMPORTING iv_garment TYPE ty_garment
iv_service TYPE ty_service
iv_quantity TYPE i
iv_express TYPE abap_bool
RETURNING VALUE(rv_price) TYPE ty_price.
- Do not add other public methods, public attributes, or public types.
# 5. Business rules
The legacy implementation of {{P}}TAILOR_PRICER defines the price rules. Read the
legacy code in the seed object. Keep every rule, the sequence of the rules, and all
special cases. The behavior stays the same for every input combination.
# 6. Constraints
- Release target: SAP_BASIS 816.
- Coding standards: Clean ABAP. Methods below 40 statements. Maximum nesting depth
of 3. No magic numbers, use constants. No global variables. No comment that
restates the code.
- Out of scope: do not change the public interface. Do not change the class name.
Do not add public members. Do not change the price rules.
# 7. Acceptance
- The class is active and has no syntax error.
- The hidden tests pass.
- Write your own ABAP Unit tests as local test classes in the class.

View File

@@ -0,0 +1,48 @@
{
"id": "G1050",
"category": "E",
"object_type": "CLAS",
"difficulty": 2,
"release_target": "v816",
"expected_outcome": "implement",
"budget": {
"max_tool_calls": 60,
"max_activations": 15
},
"seed": [
{
"type": "CLAS",
"name": "{{P}}TAILOR_PRICER",
"file": "seed/tailor_pricer.clas.abap",
"description": "Legacy tailor alteration price calculation"
}
],
"contract": [
{
"type": "CLAS",
"name": "{{P}}TAILOR_PRICER"
}
],
"out_of_scope": [],
"hidden_tests": [
{
"type": "CLAS",
"name": "{{P}}TAILOR_HIDDEN",
"file": "hidden/tailor_pricer_hidden.clas.abap",
"description": "Hidden tests for the refactored tailor pricer"
}
],
"reference": [
{
"type": "CLAS",
"name": "{{P}}TAILOR_PRICER",
"file": "reference/tailor_pricer.clas.abap",
"description": "Refactored tailor pricer",
"testclasses_file": "reference/tailor_pricer.testclasses.abap"
}
],
"craft_checks": [
"method_length",
"cyclomatic_complexity"
]
}

View File

@@ -0,0 +1,21 @@
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Melt output'
define view entity {{P}}I_MELT_OUT
as select from {{p}}casting as part
inner join {{p}}melt as head
on part.furnace_id <> head.furnace_id
and part.melt_date = head.melt_date
and part.melt_no = head.melt_no
{
key head.furnace_id as furnace_id,
key head.melt_date as melt_date,
key head.melt_no as melt_no,
head.alloy as alloy,
count( * ) as pieces,
sum( part.weight ) as net_weight
}
group by
head.furnace_id,
head.melt_date,
head.melt_no,
head.alloy

View File

@@ -0,0 +1,21 @@
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Melt output'
define view entity {{P}}I_MELT_OUT
as select from {{p}}casting as part
inner join {{p}}melt as head
on part.furnace_id = head.furnace_id
or part.melt_date = head.melt_date
and part.melt_no = head.melt_no
{
key head.furnace_id as furnace_id,
key head.melt_date as melt_date,
key head.melt_no as melt_no,
head.alloy as alloy,
count( * ) as pieces,
sum( part.weight ) as net_weight
}
group by
head.furnace_id,
head.melt_date,
head.melt_no,
head.alloy

View File

@@ -0,0 +1,21 @@
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Melt output'
define view entity {{P}}I_MELT_OUT
as select from {{p}}casting as part
inner join {{p}}melt as head
on part.furnace_id = head.furnace_id
and part.melt_date <> head.melt_date
and part.melt_no = head.melt_no
{
key head.furnace_id as furnace_id,
key head.melt_date as melt_date,
key head.melt_no as melt_no,
head.alloy as alloy,
count( * ) as pieces,
sum( part.weight ) as net_weight
}
group by
head.furnace_id,
head.melt_date,
head.melt_no,
head.alloy

View File

@@ -0,0 +1,21 @@
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Melt output'
define view entity {{P}}I_MELT_OUT
as select from {{p}}casting as part
inner join {{p}}melt as head
on part.furnace_id = head.furnace_id
and part.melt_date = head.melt_date
and part.melt_no = head.melt_no
{
key head.furnace_id as furnace_id,
key head.melt_date as melt_date,
key head.melt_no as melt_no,
head.alloy as alloy,
count( * ) as pieces,
max( part.weight ) as net_weight
}
group by
head.furnace_id,
head.melt_date,
head.melt_no,
head.alloy

View File

@@ -0,0 +1,29 @@
{
"id": "G1051",
"pool": "train",
"object_type": "DDLS",
"category": "I",
"attempts": [
{
"stage": "bundle",
"errors": [
"Too close to task T15 (similarity spec 0.84, rules 0.79, names 0.00). Choose a different business topic and different object names.",
"Too close to task T15 (similarity spec 0.84, rules 0.79, names 0.00). Choose a different business topic and different object names."
],
"by_check": {
"extra": 2
}
},
{
"stage": "validate",
"oracle": 100.0,
"null": 0,
"mutation": {
"valid": 5,
"killed": 4,
"ok": true
}
}
],
"accepted": true
}

View File

@@ -0,0 +1,115 @@
CLASS {{p}}melt_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
CLASS-DATA go_env TYPE REF TO if_cds_test_environment.
CLASS-METHODS class_setup.
CLASS-METHODS class_teardown.
METHODS setup.
METHODS melt_f1_1010 FOR TESTING.
METHODS melt_f2_1010 FOR TESTING.
METHODS melt_f1_1011 FOR TESTING.
METHODS melt_f2_0002 FOR TESTING.
METHODS melt_f2_0009 FOR TESTING.
METHODS empty_melt_absent FOR TESTING.
METHODS row_count FOR TESTING.
METHODS alloy_kept FOR TESTING.
ENDCLASS.
CLASS {{p}}melt_hidden IMPLEMENTATION.
METHOD class_setup.
go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_MELT_OUT' ).
ENDMETHOD.
METHOD class_teardown.
go_env->destroy( ).
ENDMETHOD.
METHOD setup.
DATA lt_melt TYPE STANDARD TABLE OF {{p}}melt WITH EMPTY KEY.
DATA lt_cast TYPE STANDARD TABLE OF {{p}}casting WITH EMPTY KEY.
go_env->clear_doubles( ).
lt_melt = VALUE #(
( furnace_id = 'F1' melt_date = '20240110' melt_no = '0001' alloy = 'GJL' crew = 'A' )
( furnace_id = 'F2' melt_date = '20240110' melt_no = '0001' alloy = 'GJS' crew = 'B' )
( furnace_id = 'F1' melt_date = '20240111' melt_no = '0001' alloy = 'GJL' crew = 'A' )
( furnace_id = 'F2' melt_date = '20240110' melt_no = '0002' alloy = 'GJS' crew = 'B' )
( furnace_id = 'F1' melt_date = '20240112' melt_no = '0009' alloy = 'GJL' crew = 'C' )
( furnace_id = 'F2' melt_date = '20240115' melt_no = '0009' alloy = 'GJS' crew = 'D' ) ).
lt_cast = VALUE #(
( furnace_id = 'F1' melt_date = '20240110' melt_no = '0001' part_no = 1 part_name = 'WHEEL' weight = '12.50' )
( furnace_id = 'F1' melt_date = '20240110' melt_no = '0001' part_no = 2 part_name = 'HUB' weight = '7.50' )
( furnace_id = 'F2' melt_date = '20240110' melt_no = '0001' part_no = 1 part_name = 'GEAR' weight = '20.00' )
( furnace_id = 'F1' melt_date = '20240111' melt_no = '0001' part_no = 1 part_name = 'WHEEL' weight = '12.50' )
( furnace_id = 'F2' melt_date = '20240110' melt_no = '0002' part_no = 1 part_name = 'GEAR' weight = '20.00' )
( furnace_id = 'F2' melt_date = '20240110' melt_no = '0002' part_no = 2 part_name = 'HUB' weight = '7.45' )
( furnace_id = 'F2' melt_date = '20240110' melt_no = '0002' part_no = 3 part_name = 'SHAFT' weight = '5.05' )
( furnace_id = 'F2' melt_date = '20240115' melt_no = '0009' part_no = 1 part_name = 'GEAR' weight = '20.00' ) ).
go_env->insert_test_data( lt_melt ).
go_env->insert_test_data( lt_cast ).
ENDMETHOD.
METHOD melt_f1_1010.
SELECT SINGLE pieces, net_weight FROM {{p}}i_melt_out
WHERE furnace_id = 'F1' AND melt_date = '20240110' AND melt_no = '0001'
INTO @DATA(ls_row).
cl_abap_unit_assert=>assert_equals( exp = 2 act = ls_row-pieces ).
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '20.00' )
act = CONV decfloat34( ls_row-net_weight ) ).
ENDMETHOD.
METHOD melt_f2_1010.
SELECT SINGLE pieces, net_weight FROM {{p}}i_melt_out
WHERE furnace_id = 'F2' AND melt_date = '20240110' AND melt_no = '0001'
INTO @DATA(ls_row).
cl_abap_unit_assert=>assert_equals( exp = 1 act = ls_row-pieces ).
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '20.00' )
act = CONV decfloat34( ls_row-net_weight ) ).
ENDMETHOD.
METHOD melt_f1_1011.
SELECT SINGLE pieces, net_weight FROM {{p}}i_melt_out
WHERE furnace_id = 'F1' AND melt_date = '20240111' AND melt_no = '0001'
INTO @DATA(ls_row).
cl_abap_unit_assert=>assert_equals( exp = 1 act = ls_row-pieces ).
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '12.50' )
act = CONV decfloat34( ls_row-net_weight ) ).
ENDMETHOD.
METHOD melt_f2_0002.
SELECT SINGLE pieces, net_weight FROM {{p}}i_melt_out
WHERE furnace_id = 'F2' AND melt_date = '20240110' AND melt_no = '0002'
INTO @DATA(ls_row).
cl_abap_unit_assert=>assert_equals( exp = 3 act = ls_row-pieces ).
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '32.50' )
act = CONV decfloat34( ls_row-net_weight ) ).
ENDMETHOD.
METHOD melt_f2_0009.
SELECT SINGLE pieces, net_weight FROM {{p}}i_melt_out
WHERE furnace_id = 'F2' AND melt_date = '20240115' AND melt_no = '0009'
INTO @DATA(ls_row).
cl_abap_unit_assert=>assert_equals( exp = 1 act = ls_row-pieces ).
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '20.00' )
act = CONV decfloat34( ls_row-net_weight ) ).
ENDMETHOD.
METHOD empty_melt_absent.
SELECT COUNT(*) FROM {{p}}i_melt_out
WHERE furnace_id = 'F1' AND melt_date = '20240112' AND melt_no = '0009'
INTO @DATA(lv_rows).
cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_rows ).
ENDMETHOD.
METHOD row_count.
SELECT COUNT(*) FROM {{p}}i_melt_out INTO @DATA(lv_rows).
cl_abap_unit_assert=>assert_equals( exp = 5 act = lv_rows ).
ENDMETHOD.
METHOD alloy_kept.
SELECT SINGLE alloy FROM {{p}}i_melt_out
WHERE furnace_id = 'F2' AND melt_date = '20240110' AND melt_no = '0001'
INTO @DATA(lv_alloy).
cl_abap_unit_assert=>assert_equals( exp = 'GJS' act = lv_alloy ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,70 @@
{
"task": "G1051",
"mutants": [
{
"object": "{{P}}I_MELT_OUT",
"mutant": "line 5: inner join -> left outer join (join)",
"status": "survived",
"hidden": "8/8",
"failed_tests": []
},
{
"object": "{{P}}I_MELT_OUT",
"mutant": "line 6: = -> <> (eq)",
"status": "killed",
"hidden": "2/8",
"failed_tests": [
"MELT_F1_1010",
"MELT_F1_1011",
"MELT_F2_0002",
"MELT_F2_0009",
"MELT_F2_1010",
"ROW_COUNT"
]
},
{
"object": "{{P}}I_MELT_OUT",
"mutant": "line 7: and -> or (logic)",
"status": "killed",
"hidden": "1/8",
"failed_tests": [
"EMPTY_MELT_ABSENT",
"MELT_F1_1010",
"MELT_F1_1011",
"MELT_F2_0002",
"MELT_F2_0009",
"MELT_F2_1010",
"ROW_COUNT"
]
},
{
"object": "{{P}}I_MELT_OUT",
"mutant": "line 7: = -> <> (eq)",
"status": "killed",
"hidden": "1/8",
"failed_tests": [
"ALLOY_KEPT",
"MELT_F1_1010",
"MELT_F1_1011",
"MELT_F2_0002",
"MELT_F2_0009",
"MELT_F2_1010",
"ROW_COUNT"
]
},
{
"object": "{{P}}I_MELT_OUT",
"mutant": "line 15: sum( -> max( (agg)",
"status": "killed",
"hidden": "6/8",
"failed_tests": [
"MELT_F1_1010",
"MELT_F2_0002"
]
}
],
"valid": 5,
"killed": 4,
"kill_rate": 0.8,
"ok": true
}

View File

@@ -0,0 +1,21 @@
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Melt output'
define view entity {{P}}I_MELT_OUT
as select from {{p}}casting as part
inner join {{p}}melt as head
on part.furnace_id = head.furnace_id
and part.melt_date = head.melt_date
and part.melt_no = head.melt_no
{
key head.furnace_id as furnace_id,
key head.melt_date as melt_date,
key head.melt_no as melt_no,
head.alloy as alloy,
count( * ) as pieces,
sum( part.weight ) as net_weight
}
group by
head.furnace_id,
head.melt_date,
head.melt_no,
head.alloy

View File

@@ -0,0 +1,53 @@
CLASS {{p}}melt_test DEFINITION PUBLIC FINAL CREATE PUBLIC
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
CLASS-DATA go_env TYPE REF TO if_cds_test_environment.
CLASS-METHODS class_setup.
CLASS-METHODS class_teardown.
METHODS setup.
METHODS same_no_other_furnace FOR TESTING.
METHODS melt_without_castings FOR TESTING.
ENDCLASS.
CLASS {{p}}melt_test IMPLEMENTATION.
METHOD class_setup.
go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_MELT_OUT' ).
ENDMETHOD.
METHOD class_teardown.
go_env->destroy( ).
ENDMETHOD.
METHOD setup.
go_env->clear_doubles( ).
ENDMETHOD.
METHOD same_no_other_furnace.
DATA lt_melt TYPE STANDARD TABLE OF {{p}}melt WITH EMPTY KEY.
DATA lt_cast TYPE STANDARD TABLE OF {{p}}casting WITH EMPTY KEY.
lt_melt = VALUE #(
( furnace_id = 'F1' melt_date = '20240110' melt_no = '0001' alloy = 'GJL' crew = 'A' )
( furnace_id = 'F2' melt_date = '20240110' melt_no = '0001' alloy = 'GJS' crew = 'B' ) ).
lt_cast = VALUE #(
( furnace_id = 'F1' melt_date = '20240110' melt_no = '0001' part_no = 1 part_name = 'WHEEL' weight = '12.50' )
( furnace_id = 'F2' melt_date = '20240110' melt_no = '0001' part_no = 1 part_name = 'GEAR' weight = '20.00' ) ).
go_env->insert_test_data( lt_melt ).
go_env->insert_test_data( lt_cast ).
SELECT SINGLE pieces, net_weight FROM {{p}}i_melt_out
WHERE furnace_id = 'F1' AND melt_date = '20240110' AND melt_no = '0001'
INTO @DATA(ls_row).
cl_abap_unit_assert=>assert_equals( exp = 1 act = ls_row-pieces ).
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '12.50' )
act = CONV decfloat34( ls_row-net_weight ) ).
ENDMETHOD.
METHOD melt_without_castings.
DATA lt_melt TYPE STANDARD TABLE OF {{p}}melt WITH EMPTY KEY.
lt_melt = VALUE #(
( furnace_id = 'F1' melt_date = '20240112' melt_no = '0009' alloy = 'GJL' crew = 'C' ) ).
go_env->insert_test_data( lt_melt ).
SELECT COUNT(*) FROM {{p}}i_melt_out INTO @DATA(lv_rows).
cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_rows ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,14 @@
@EndUserText.label : 'Foundry casting'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table {{p}}casting {
key client : abap.clnt not null;
key furnace_id : abap.char(4) not null;
key melt_date : abap.dats not null;
key melt_no : abap.numc(4) not null;
key part_no : abap.int4 not null;
part_name : abap.char(10);
weight : abap.dec(15,2);
}

View File

@@ -0,0 +1,18 @@
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Melt output'
define view entity {{P}}I_MELT_OUT
as select from {{p}}casting as part
inner join {{p}}melt as head on part.melt_no = head.melt_no
{
key head.furnace_id as furnace_id,
key head.melt_date as melt_date,
key head.melt_no as melt_no,
head.alloy as alloy,
count( * ) as pieces,
sum( part.weight ) as net_weight
}
group by
head.furnace_id,
head.melt_date,
head.melt_no,
head.alloy

View File

@@ -0,0 +1,13 @@
@EndUserText.label : 'Foundry melt'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table {{p}}melt {
key client : abap.clnt not null;
key furnace_id : abap.char(4) not null;
key melt_date : abap.dats not null;
key melt_no : abap.numc(4) not null;
alloy : abap.char(10);
crew : abap.char(10);
}

View File

@@ -0,0 +1,51 @@
# 1. Goal
Fix the CDS view entity {{P}}I_MELT_OUT in package $TMP. The view reports the
output of the casting melts of a foundry. The production team says that the
figures in the view are wrong for many melts.
# 2. Open questions
None.
# 3. Context
- Table {{P}}MELT (melt header), package $TMP. Key: FURNACE_ID (CHAR 4),
MELT_DATE (DATS), MELT_NO (NUMC 4). Fields: ALLOY (CHAR 10), CREW (CHAR 10).
- Table {{P}}CASTING (casting), package $TMP. Key: FURNACE_ID (CHAR 4),
MELT_DATE (DATS), MELT_NO (NUMC 4), PART_NO (INT4). Fields: PART_NAME
(CHAR 10), WEIGHT (DEC 15,2, the weight of one casting in kilograms).
- A melt number is not unique in the foundry. The same melt number occurs in
other furnaces and on other dates.
- The CDS view entity {{P}}I_MELT_OUT already exists in package $TMP.
The production team reports these symptoms:
- The pieces and the net weight of a melt are too high when the melt number of
the melt also occurs in another furnace or on another date.
- The view shows melts that have no castings.
# 4. Contract
- Fix the CDS view entity {{P}}I_MELT_OUT in package $TMP. The name stays the
same.
- Elements, with these names: FURNACE_ID (key), MELT_DATE (key), MELT_NO (key),
ALLOY, PIECES, NET_WEIGHT.
- No authorization check (#NOT_REQUIRED).
# 5. Business rules
1. The view shows one row for each melt that has castings. A melt without
castings must not appear in the view.
2. PIECES is the number of castings of the melt.
3. NET_WEIGHT is the sum of the weights of the castings of the melt, in
kilograms with 2 decimals.
4. A casting belongs to the melt of its own furnace, its own date and its own
melt number. Castings of another furnace, of another date or of another melt
number must not contribute to the figures of a melt.
5. All other behavior of the view stays the same.
# 6. Constraints
- Release target: ABAP Platform 2025 (SAP_BASIS 816).
- Coding standard: Clean ABAP.
- Out of scope: do not change {{P}}MELT and {{P}}CASTING. Do not change the
element names or the data types of the view.
# 7. Acceptance
- The view is active and has no syntax error.
- The hidden tests pass.
- Write ABAP Unit tests with CL_CDS_TEST_ENVIRONMENT in a global test class.

View File

@@ -0,0 +1,73 @@
{
"id": "G1051",
"category": "I",
"object_type": "DDLS",
"difficulty": 2,
"release_target": "v816",
"expected_outcome": "implement",
"budget": {
"max_tool_calls": 60,
"max_activations": 15
},
"seed": [
{
"type": "TABL",
"name": "{{P}}MELT",
"file": "seed/melt.tabl.asabap",
"description": "Foundry melt header"
},
{
"type": "TABL",
"name": "{{P}}CASTING",
"file": "seed/casting.tabl.asabap",
"description": "Foundry casting"
},
{
"type": "DDLS",
"name": "{{P}}I_MELT_OUT",
"file": "seed/i_melt_out.ddls.asddls",
"description": "Melt output view (faulty)"
}
],
"contract": [
{
"type": "DDLS",
"name": "{{P}}I_MELT_OUT",
"fields": [
"FURNACE_ID",
"MELT_DATE",
"MELT_NO",
"ALLOY",
"PIECES",
"NET_WEIGHT"
]
}
],
"out_of_scope": [
"{{P}}MELT",
"{{P}}CASTING"
],
"hidden_tests": [
{
"type": "CLAS",
"name": "{{P}}MELT_HIDDEN",
"file": "hidden/melt_hidden.clas.abap",
"description": "Hidden tests for the melt output view"
}
],
"reference": [
{
"type": "DDLS",
"name": "{{P}}I_MELT_OUT",
"file": "reference/i_melt_out.ddls.asddls",
"description": "Fixed melt output view"
},
{
"type": "CLAS",
"name": "{{P}}MELT_TEST",
"file": "reference/melt_test.clas.abap",
"description": "Own tests for the melt output view"
}
],
"craft_checks": []
}

View File

@@ -0,0 +1,116 @@
CLASS {{p}}rack_billing DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_size TYPE c LENGTH 1.
TYPES ty_power TYPE c LENGTH 1.
TYPES ty_customer TYPE c LENGTH 10.
TYPES ty_fee TYPE p LENGTH 8 DECIMALS 2.
TYPES:
BEGIN OF ty_rack,
rack_id TYPE c LENGTH 10,
customer TYPE ty_customer,
size_class TYPE ty_size,
power_class TYPE ty_power,
END OF ty_rack.
TYPES tt_racks TYPE STANDARD TABLE OF ty_rack WITH EMPTY KEY.
TYPES:
BEGIN OF ty_bill,
customer TYPE ty_customer,
rack_count TYPE i,
total_fee TYPE ty_fee,
END OF ty_bill.
TYPES tt_bills TYPE STANDARD TABLE OF ty_bill WITH EMPTY KEY.
METHODS calculate
IMPORTING it_racks TYPE tt_racks
RETURNING VALUE(rt_bills) TYPE tt_bills.
PRIVATE SECTION.
TYPES:
BEGIN OF ty_price,
size_class TYPE ty_size,
power_class TYPE ty_power,
fee TYPE ty_fee,
END OF ty_price.
TYPES tt_prices TYPE HASHED TABLE OF ty_price WITH UNIQUE KEY size_class power_class.
TYPES tt_seen TYPE HASHED TABLE OF ty_rack WITH UNIQUE KEY rack_id.
TYPES tt_bill_hash TYPE HASHED TABLE OF ty_bill WITH UNIQUE KEY customer.
METHODS price_list
RETURNING VALUE(rt_prices) TYPE tt_prices.
METHODS rack_fee
IMPORTING is_rack TYPE ty_rack
it_prices TYPE tt_prices
RETURNING VALUE(rv_fee) TYPE ty_fee.
METHODS discount_percent
IMPORTING iv_count TYPE i
RETURNING VALUE(rv_percent) TYPE i.
ENDCLASS.
CLASS {{p}}rack_billing IMPLEMENTATION.
METHOD calculate.
DATA(lt_prices) = price_list( ).
DATA lt_seen TYPE tt_seen.
DATA lt_bills TYPE tt_bill_hash.
LOOP AT it_racks INTO DATA(ls_rack).
INSERT ls_rack INTO TABLE lt_seen.
IF sy-subrc <> 0.
CONTINUE.
ENDIF.
DATA(lv_fee) = rack_fee( is_rack = ls_rack it_prices = lt_prices ).
IF lv_fee IS INITIAL.
CONTINUE.
ENDIF.
ASSIGN lt_bills[ customer = ls_rack-customer ] TO FIELD-SYMBOL(<ls_bill>).
IF sy-subrc <> 0.
INSERT VALUE #( customer = ls_rack-customer ) INTO TABLE lt_bills ASSIGNING <ls_bill>.
ENDIF.
<ls_bill>-rack_count = <ls_bill>-rack_count + 1.
<ls_bill>-total_fee = <ls_bill>-total_fee - lv_fee.
ENDLOOP.
LOOP AT lt_bills ASSIGNING <ls_bill>.
DATA(lv_percent) = discount_percent( <ls_bill>-rack_count ).
<ls_bill>-total_fee = <ls_bill>-total_fee * ( 100 - lv_percent ) / 100.
INSERT VALUE #( customer = <ls_bill>-customer
rack_count = <ls_bill>-rack_count
total_fee = <ls_bill>-total_fee ) INTO TABLE rt_bills.
ENDLOOP.
SORT rt_bills BY customer.
ENDMETHOD.
METHOD price_list.
rt_prices = VALUE #(
( size_class = 'S' power_class = 'A' fee = '50.00' )
( size_class = 'S' power_class = 'B' fee = '80.00' )
( size_class = 'S' power_class = 'C' fee = '120.00' )
( size_class = 'M' power_class = 'A' fee = '120.00' )
( size_class = 'M' power_class = 'B' fee = '150.00' )
( size_class = 'M' power_class = 'C' fee = '190.00' )
( size_class = 'L' power_class = 'A' fee = '250.00' )
( size_class = 'L' power_class = 'B' fee = '280.00' )
( size_class = 'L' power_class = 'C' fee = '320.00' ) ).
ENDMETHOD.
METHOD rack_fee.
ASSIGN it_prices[ size_class = is_rack-size_class power_class = is_rack-power_class ]
TO FIELD-SYMBOL(<ls_price>).
IF sy-subrc = 0.
rv_fee = <ls_price>-fee.
ENDIF.
ENDMETHOD.
METHOD discount_percent.
IF iv_count >= 20.
rv_percent = 20.
ELSEIF iv_count >= 10.
rv_percent = 10.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,116 @@
CLASS {{p}}rack_billing DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_size TYPE c LENGTH 1.
TYPES ty_power TYPE c LENGTH 1.
TYPES ty_customer TYPE c LENGTH 10.
TYPES ty_fee TYPE p LENGTH 8 DECIMALS 2.
TYPES:
BEGIN OF ty_rack,
rack_id TYPE c LENGTH 10,
customer TYPE ty_customer,
size_class TYPE ty_size,
power_class TYPE ty_power,
END OF ty_rack.
TYPES tt_racks TYPE STANDARD TABLE OF ty_rack WITH EMPTY KEY.
TYPES:
BEGIN OF ty_bill,
customer TYPE ty_customer,
rack_count TYPE i,
total_fee TYPE ty_fee,
END OF ty_bill.
TYPES tt_bills TYPE STANDARD TABLE OF ty_bill WITH EMPTY KEY.
METHODS calculate
IMPORTING it_racks TYPE tt_racks
RETURNING VALUE(rt_bills) TYPE tt_bills.
PRIVATE SECTION.
TYPES:
BEGIN OF ty_price,
size_class TYPE ty_size,
power_class TYPE ty_power,
fee TYPE ty_fee,
END OF ty_price.
TYPES tt_prices TYPE HASHED TABLE OF ty_price WITH UNIQUE KEY size_class power_class.
TYPES tt_seen TYPE HASHED TABLE OF ty_rack WITH UNIQUE KEY rack_id.
TYPES tt_bill_hash TYPE HASHED TABLE OF ty_bill WITH UNIQUE KEY customer.
METHODS price_list
RETURNING VALUE(rt_prices) TYPE tt_prices.
METHODS rack_fee
IMPORTING is_rack TYPE ty_rack
it_prices TYPE tt_prices
RETURNING VALUE(rv_fee) TYPE ty_fee.
METHODS discount_percent
IMPORTING iv_count TYPE i
RETURNING VALUE(rv_percent) TYPE i.
ENDCLASS.
CLASS {{p}}rack_billing IMPLEMENTATION.
METHOD calculate.
DATA(lt_prices) = price_list( ).
DATA lt_seen TYPE tt_seen.
DATA lt_bills TYPE tt_bill_hash.
LOOP AT it_racks INTO DATA(ls_rack).
INSERT ls_rack INTO TABLE lt_seen.
IF sy-subrc <> 0.
CONTINUE.
ENDIF.
DATA(lv_fee) = rack_fee( is_rack = ls_rack it_prices = lt_prices ).
IF lv_fee IS INITIAL.
CONTINUE.
ENDIF.
ASSIGN lt_bills[ customer = ls_rack-customer ] TO FIELD-SYMBOL(<ls_bill>).
IF sy-subrc <> 0.
INSERT VALUE #( customer = ls_rack-customer ) INTO TABLE lt_bills ASSIGNING <ls_bill>.
ENDIF.
<ls_bill>-rack_count = <ls_bill>-rack_count + 1.
<ls_bill>-total_fee = <ls_bill>-total_fee + lv_fee.
ENDLOOP.
LOOP AT lt_bills ASSIGNING <ls_bill>.
DATA(lv_percent) = discount_percent( <ls_bill>-rack_count ).
<ls_bill>-total_fee = <ls_bill>-total_fee / ( 100 - lv_percent ) / 100.
INSERT VALUE #( customer = <ls_bill>-customer
rack_count = <ls_bill>-rack_count
total_fee = <ls_bill>-total_fee ) INTO TABLE rt_bills.
ENDLOOP.
SORT rt_bills BY customer.
ENDMETHOD.
METHOD price_list.
rt_prices = VALUE #(
( size_class = 'S' power_class = 'A' fee = '50.00' )
( size_class = 'S' power_class = 'B' fee = '80.00' )
( size_class = 'S' power_class = 'C' fee = '120.00' )
( size_class = 'M' power_class = 'A' fee = '120.00' )
( size_class = 'M' power_class = 'B' fee = '150.00' )
( size_class = 'M' power_class = 'C' fee = '190.00' )
( size_class = 'L' power_class = 'A' fee = '250.00' )
( size_class = 'L' power_class = 'B' fee = '280.00' )
( size_class = 'L' power_class = 'C' fee = '320.00' ) ).
ENDMETHOD.
METHOD rack_fee.
ASSIGN it_prices[ size_class = is_rack-size_class power_class = is_rack-power_class ]
TO FIELD-SYMBOL(<ls_price>).
IF sy-subrc = 0.
rv_fee = <ls_price>-fee.
ENDIF.
ENDMETHOD.
METHOD discount_percent.
IF iv_count >= 20.
rv_percent = 20.
ELSEIF iv_count >= 10.
rv_percent = 10.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,116 @@
CLASS {{p}}rack_billing DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_size TYPE c LENGTH 1.
TYPES ty_power TYPE c LENGTH 1.
TYPES ty_customer TYPE c LENGTH 10.
TYPES ty_fee TYPE p LENGTH 8 DECIMALS 2.
TYPES:
BEGIN OF ty_rack,
rack_id TYPE c LENGTH 10,
customer TYPE ty_customer,
size_class TYPE ty_size,
power_class TYPE ty_power,
END OF ty_rack.
TYPES tt_racks TYPE STANDARD TABLE OF ty_rack WITH EMPTY KEY.
TYPES:
BEGIN OF ty_bill,
customer TYPE ty_customer,
rack_count TYPE i,
total_fee TYPE ty_fee,
END OF ty_bill.
TYPES tt_bills TYPE STANDARD TABLE OF ty_bill WITH EMPTY KEY.
METHODS calculate
IMPORTING it_racks TYPE tt_racks
RETURNING VALUE(rt_bills) TYPE tt_bills.
PRIVATE SECTION.
TYPES:
BEGIN OF ty_price,
size_class TYPE ty_size,
power_class TYPE ty_power,
fee TYPE ty_fee,
END OF ty_price.
TYPES tt_prices TYPE HASHED TABLE OF ty_price WITH UNIQUE KEY size_class power_class.
TYPES tt_seen TYPE HASHED TABLE OF ty_rack WITH UNIQUE KEY rack_id.
TYPES tt_bill_hash TYPE HASHED TABLE OF ty_bill WITH UNIQUE KEY customer.
METHODS price_list
RETURNING VALUE(rt_prices) TYPE tt_prices.
METHODS rack_fee
IMPORTING is_rack TYPE ty_rack
it_prices TYPE tt_prices
RETURNING VALUE(rv_fee) TYPE ty_fee.
METHODS discount_percent
IMPORTING iv_count TYPE i
RETURNING VALUE(rv_percent) TYPE i.
ENDCLASS.
CLASS {{p}}rack_billing IMPLEMENTATION.
METHOD calculate.
DATA(lt_prices) = price_list( ).
DATA lt_seen TYPE tt_seen.
DATA lt_bills TYPE tt_bill_hash.
LOOP AT it_racks INTO DATA(ls_rack).
INSERT ls_rack INTO TABLE lt_seen.
IF sy-subrc <> 0.
CONTINUE.
ENDIF.
DATA(lv_fee) = rack_fee( is_rack = ls_rack it_prices = lt_prices ).
IF lv_fee IS INITIAL.
CONTINUE.
ENDIF.
ASSIGN lt_bills[ customer = ls_rack-customer ] TO FIELD-SYMBOL(<ls_bill>).
IF sy-subrc <> 0.
INSERT VALUE #( customer = ls_rack-customer ) INTO TABLE lt_bills ASSIGNING <ls_bill>.
ENDIF.
<ls_bill>-rack_count = <ls_bill>-rack_count + 1.
<ls_bill>-total_fee = <ls_bill>-total_fee + lv_fee.
ENDLOOP.
LOOP AT lt_bills ASSIGNING <ls_bill>.
DATA(lv_percent) = discount_percent( <ls_bill>-rack_count ).
<ls_bill>-total_fee = <ls_bill>-total_fee * ( 101 - lv_percent ) / 100.
INSERT VALUE #( customer = <ls_bill>-customer
rack_count = <ls_bill>-rack_count
total_fee = <ls_bill>-total_fee ) INTO TABLE rt_bills.
ENDLOOP.
SORT rt_bills BY customer.
ENDMETHOD.
METHOD price_list.
rt_prices = VALUE #(
( size_class = 'S' power_class = 'A' fee = '50.00' )
( size_class = 'S' power_class = 'B' fee = '80.00' )
( size_class = 'S' power_class = 'C' fee = '120.00' )
( size_class = 'M' power_class = 'A' fee = '120.00' )
( size_class = 'M' power_class = 'B' fee = '150.00' )
( size_class = 'M' power_class = 'C' fee = '190.00' )
( size_class = 'L' power_class = 'A' fee = '250.00' )
( size_class = 'L' power_class = 'B' fee = '280.00' )
( size_class = 'L' power_class = 'C' fee = '320.00' ) ).
ENDMETHOD.
METHOD rack_fee.
ASSIGN it_prices[ size_class = is_rack-size_class power_class = is_rack-power_class ]
TO FIELD-SYMBOL(<ls_price>).
IF sy-subrc = 0.
rv_fee = <ls_price>-fee.
ENDIF.
ENDMETHOD.
METHOD discount_percent.
IF iv_count >= 20.
rv_percent = 20.
ELSEIF iv_count >= 10.
rv_percent = 10.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,116 @@
CLASS {{p}}rack_billing DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_size TYPE c LENGTH 1.
TYPES ty_power TYPE c LENGTH 1.
TYPES ty_customer TYPE c LENGTH 10.
TYPES ty_fee TYPE p LENGTH 8 DECIMALS 2.
TYPES:
BEGIN OF ty_rack,
rack_id TYPE c LENGTH 10,
customer TYPE ty_customer,
size_class TYPE ty_size,
power_class TYPE ty_power,
END OF ty_rack.
TYPES tt_racks TYPE STANDARD TABLE OF ty_rack WITH EMPTY KEY.
TYPES:
BEGIN OF ty_bill,
customer TYPE ty_customer,
rack_count TYPE i,
total_fee TYPE ty_fee,
END OF ty_bill.
TYPES tt_bills TYPE STANDARD TABLE OF ty_bill WITH EMPTY KEY.
METHODS calculate
IMPORTING it_racks TYPE tt_racks
RETURNING VALUE(rt_bills) TYPE tt_bills.
PRIVATE SECTION.
TYPES:
BEGIN OF ty_price,
size_class TYPE ty_size,
power_class TYPE ty_power,
fee TYPE ty_fee,
END OF ty_price.
TYPES tt_prices TYPE HASHED TABLE OF ty_price WITH UNIQUE KEY size_class power_class.
TYPES tt_seen TYPE HASHED TABLE OF ty_rack WITH UNIQUE KEY rack_id.
TYPES tt_bill_hash TYPE HASHED TABLE OF ty_bill WITH UNIQUE KEY customer.
METHODS price_list
RETURNING VALUE(rt_prices) TYPE tt_prices.
METHODS rack_fee
IMPORTING is_rack TYPE ty_rack
it_prices TYPE tt_prices
RETURNING VALUE(rv_fee) TYPE ty_fee.
METHODS discount_percent
IMPORTING iv_count TYPE i
RETURNING VALUE(rv_percent) TYPE i.
ENDCLASS.
CLASS {{p}}rack_billing IMPLEMENTATION.
METHOD calculate.
DATA(lt_prices) = price_list( ).
DATA lt_seen TYPE tt_seen.
DATA lt_bills TYPE tt_bill_hash.
LOOP AT it_racks INTO DATA(ls_rack).
INSERT ls_rack INTO TABLE lt_seen.
IF sy-subrc <> 0.
CONTINUE.
ENDIF.
DATA(lv_fee) = rack_fee( is_rack = ls_rack it_prices = lt_prices ).
IF lv_fee IS INITIAL.
CONTINUE.
ENDIF.
ASSIGN lt_bills[ customer = ls_rack-customer ] TO FIELD-SYMBOL(<ls_bill>).
IF sy-subrc <> 0.
INSERT VALUE #( customer = ls_rack-customer ) INTO TABLE lt_bills ASSIGNING <ls_bill>.
ENDIF.
<ls_bill>-rack_count = <ls_bill>-rack_count + 1.
<ls_bill>-total_fee = <ls_bill>-total_fee + lv_fee.
ENDLOOP.
LOOP AT lt_bills ASSIGNING <ls_bill>.
DATA(lv_percent) = discount_percent( <ls_bill>-rack_count ).
<ls_bill>-total_fee = <ls_bill>-total_fee * ( 100 - lv_percent ) / 100.
INSERT VALUE #( customer = <ls_bill>-customer
rack_count = <ls_bill>-rack_count
total_fee = <ls_bill>-total_fee ) INTO TABLE rt_bills.
ENDLOOP.
SORT rt_bills BY customer.
ENDMETHOD.
METHOD price_list.
rt_prices = VALUE #(
( size_class = 'S' power_class = 'A' fee = '50.00' )
( size_class = 'S' power_class = 'B' fee = '80.00' )
( size_class = 'S' power_class = 'C' fee = '120.00' )
( size_class = 'M' power_class = 'A' fee = '120.00' )
( size_class = 'M' power_class = 'B' fee = '150.00' )
( size_class = 'M' power_class = 'C' fee = '190.00' )
( size_class = 'L' power_class = 'A' fee = '250.00' )
( size_class = 'L' power_class = 'B' fee = '280.00' )
( size_class = 'L' power_class = 'C' fee = '320.00' ) ).
ENDMETHOD.
METHOD rack_fee.
ASSIGN it_prices[ size_class = is_rack-size_class power_class = is_rack-power_class ]
TO FIELD-SYMBOL(<ls_price>).
IF sy-subrc = 0.
rv_fee = <ls_price>-fee.
ENDIF.
ENDMETHOD.
METHOD discount_percent.
IF iv_count < 20.
rv_percent = 20.
ELSEIF iv_count >= 10.
rv_percent = 10.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,116 @@
CLASS {{p}}rack_billing DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_size TYPE c LENGTH 1.
TYPES ty_power TYPE c LENGTH 1.
TYPES ty_customer TYPE c LENGTH 10.
TYPES ty_fee TYPE p LENGTH 8 DECIMALS 2.
TYPES:
BEGIN OF ty_rack,
rack_id TYPE c LENGTH 10,
customer TYPE ty_customer,
size_class TYPE ty_size,
power_class TYPE ty_power,
END OF ty_rack.
TYPES tt_racks TYPE STANDARD TABLE OF ty_rack WITH EMPTY KEY.
TYPES:
BEGIN OF ty_bill,
customer TYPE ty_customer,
rack_count TYPE i,
total_fee TYPE ty_fee,
END OF ty_bill.
TYPES tt_bills TYPE STANDARD TABLE OF ty_bill WITH EMPTY KEY.
METHODS calculate
IMPORTING it_racks TYPE tt_racks
RETURNING VALUE(rt_bills) TYPE tt_bills.
PRIVATE SECTION.
TYPES:
BEGIN OF ty_price,
size_class TYPE ty_size,
power_class TYPE ty_power,
fee TYPE ty_fee,
END OF ty_price.
TYPES tt_prices TYPE HASHED TABLE OF ty_price WITH UNIQUE KEY size_class power_class.
TYPES tt_seen TYPE HASHED TABLE OF ty_rack WITH UNIQUE KEY rack_id.
TYPES tt_bill_hash TYPE HASHED TABLE OF ty_bill WITH UNIQUE KEY customer.
METHODS price_list
RETURNING VALUE(rt_prices) TYPE tt_prices.
METHODS rack_fee
IMPORTING is_rack TYPE ty_rack
it_prices TYPE tt_prices
RETURNING VALUE(rv_fee) TYPE ty_fee.
METHODS discount_percent
IMPORTING iv_count TYPE i
RETURNING VALUE(rv_percent) TYPE i.
ENDCLASS.
CLASS {{p}}rack_billing IMPLEMENTATION.
METHOD calculate.
DATA(lt_prices) = price_list( ).
DATA lt_seen TYPE tt_seen.
DATA lt_bills TYPE tt_bill_hash.
LOOP AT it_racks INTO DATA(ls_rack).
INSERT ls_rack INTO TABLE lt_seen.
IF sy-subrc <> 0.
CONTINUE.
ENDIF.
DATA(lv_fee) = rack_fee( is_rack = ls_rack it_prices = lt_prices ).
IF lv_fee IS INITIAL.
CONTINUE.
ENDIF.
ASSIGN lt_bills[ customer = ls_rack-customer ] TO FIELD-SYMBOL(<ls_bill>).
IF sy-subrc <> 0.
INSERT VALUE #( customer = ls_rack-customer ) INTO TABLE lt_bills ASSIGNING <ls_bill>.
ENDIF.
<ls_bill>-rack_count = <ls_bill>-rack_count + 1.
<ls_bill>-total_fee = <ls_bill>-total_fee + lv_fee.
ENDLOOP.
LOOP AT lt_bills ASSIGNING <ls_bill>.
DATA(lv_percent) = discount_percent( <ls_bill>-rack_count ).
<ls_bill>-total_fee = <ls_bill>-total_fee * ( 100 - lv_percent ) / 100.
INSERT VALUE #( customer = <ls_bill>-customer
rack_count = <ls_bill>-rack_count
total_fee = <ls_bill>-total_fee ) INTO TABLE rt_bills.
ENDLOOP.
SORT rt_bills BY customer.
ENDMETHOD.
METHOD price_list.
rt_prices = VALUE #(
( size_class = 'S' power_class = 'A' fee = '50.00' )
( size_class = 'S' power_class = 'B' fee = '80.00' )
( size_class = 'S' power_class = 'C' fee = '120.00' )
( size_class = 'M' power_class = 'A' fee = '120.00' )
( size_class = 'M' power_class = 'B' fee = '150.00' )
( size_class = 'M' power_class = 'C' fee = '190.00' )
( size_class = 'L' power_class = 'A' fee = '250.00' )
( size_class = 'L' power_class = 'B' fee = '280.00' )
( size_class = 'L' power_class = 'C' fee = '320.00' ) ).
ENDMETHOD.
METHOD rack_fee.
ASSIGN it_prices[ size_class = is_rack-size_class power_class = is_rack-power_class ]
TO FIELD-SYMBOL(<ls_price>).
IF sy-subrc = 0.
rv_fee = <ls_price>-fee.
ENDIF.
ENDMETHOD.
METHOD discount_percent.
IF iv_count >= 20.
rv_percent = 20.
ELSEIF iv_count < 10.
rv_percent = 10.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,29 @@
{
"id": "G1053",
"pool": "train",
"object_type": "CLAS",
"category": "C",
"attempts": [
{
"stage": "bundle",
"errors": [
"hidden/t02_hidden.clas.abap line 7: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\"",
"reference/rack_billing.testclasses.abap line 6: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\""
],
"by_check": {
"abaplint": 2
}
},
{
"stage": "validate",
"oracle": 100.0,
"null": 0,
"mutation": {
"valid": 5,
"killed": 5,
"ok": true
}
}
],
"accepted": true
}

View File

@@ -0,0 +1,157 @@
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}}rack_billing.
METHODS setup.
METHODS assert_amount
IMPORTING iv_expected TYPE {{p}}rack_billing=>ty_fee
iv_actual TYPE {{p}}rack_billing=>ty_fee.
METHODS one_rack FOR TESTING.
METHODS sums_per_customer FOR TESTING.
METHODS sorted_by_customer FOR TESTING.
METHODS ten_racks_discount FOR TESTING.
METHODS twenty_racks_discount FOR TESTING.
METHODS nine_racks_no_discount FOR TESTING.
METHODS ignores_unknown_size FOR TESTING.
METHODS ignores_unknown_power FOR TESTING.
METHODS ignores_second_rack_id FOR TESTING.
METHODS empty_input FOR TESTING.
METHODS all_classes FOR TESTING.
ENDCLASS.
CLASS {{p}}t02_hidden IMPLEMENTATION.
METHOD setup.
mo_cut = NEW {{p}}rack_billing( ).
ENDMETHOD.
METHOD assert_amount.
cl_abap_unit_assert=>assert_equals( exp = iv_expected act = iv_actual ).
ENDMETHOD.
METHOD one_rack.
DATA(lt_bills) = mo_cut->calculate( VALUE #( ( rack_id = 'R001' customer = 'ALPHA'
size_class = 'M' power_class = 'B' ) ) ).
cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_bills ) ).
cl_abap_unit_assert=>assert_equals( exp = 'ALPHA' act = lt_bills[ 1 ]-customer ).
cl_abap_unit_assert=>assert_equals( exp = 1 act = lt_bills[ 1 ]-rack_count ).
assert_amount( iv_expected = '150.00' iv_actual = lt_bills[ 1 ]-total_fee ).
ENDMETHOD.
METHOD sums_per_customer.
DATA lt_racks TYPE {{p}}rack_billing=>tt_racks.
lt_racks = VALUE #(
( rack_id = 'R001' customer = 'ALPHA' size_class = 'S' power_class = 'A' )
( rack_id = 'R002' customer = 'ALPHA' size_class = 'S' power_class = 'B' )
( rack_id = 'R003' customer = 'ALPHA' size_class = 'M' power_class = 'A' )
( rack_id = 'R004' customer = 'BETA' size_class = 'L' power_class = 'C' ) ).
DATA(lt_bills) = mo_cut->calculate( lt_racks ).
cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_bills ) ).
cl_abap_unit_assert=>assert_equals( exp = 'ALPHA' act = lt_bills[ 1 ]-customer ).
cl_abap_unit_assert=>assert_equals( exp = 3 act = lt_bills[ 1 ]-rack_count ).
assert_amount( iv_expected = '250.00' iv_actual = lt_bills[ 1 ]-total_fee ).
cl_abap_unit_assert=>assert_equals( exp = 'BETA' act = lt_bills[ 2 ]-customer ).
cl_abap_unit_assert=>assert_equals( exp = 1 act = lt_bills[ 2 ]-rack_count ).
assert_amount( iv_expected = '320.00' iv_actual = lt_bills[ 2 ]-total_fee ).
ENDMETHOD.
METHOD sorted_by_customer.
DATA lt_racks TYPE {{p}}rack_billing=>tt_racks.
lt_racks = VALUE #(
( rack_id = 'R001' customer = 'ZULU' size_class = 'S' power_class = 'A' )
( rack_id = 'R002' customer = 'ALPHA' size_class = 'S' power_class = 'A' )
( rack_id = 'R003' customer = 'MIKE' size_class = 'S' power_class = 'A' ) ).
DATA(lt_bills) = mo_cut->calculate( lt_racks ).
cl_abap_unit_assert=>assert_equals( exp = 3 act = lines( lt_bills ) ).
cl_abap_unit_assert=>assert_equals( exp = 'ALPHA' act = lt_bills[ 1 ]-customer ).
cl_abap_unit_assert=>assert_equals( exp = 'MIKE' act = lt_bills[ 2 ]-customer ).
cl_abap_unit_assert=>assert_equals( exp = 'ZULU' act = lt_bills[ 3 ]-customer ).
ENDMETHOD.
METHOD ten_racks_discount.
DATA lt_racks TYPE {{p}}rack_billing=>tt_racks.
DO 10 TIMES.
INSERT VALUE #( rack_id = |R{ sy-index }| customer = 'ALPHA'
size_class = 'S' power_class = 'A' ) INTO TABLE lt_racks.
ENDDO.
DATA(lt_bills) = mo_cut->calculate( lt_racks ).
cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_bills ) ).
cl_abap_unit_assert=>assert_equals( exp = 10 act = lt_bills[ 1 ]-rack_count ).
assert_amount( iv_expected = '450.00' iv_actual = lt_bills[ 1 ]-total_fee ).
ENDMETHOD.
METHOD twenty_racks_discount.
DATA lt_racks TYPE {{p}}rack_billing=>tt_racks.
DO 20 TIMES.
INSERT VALUE #( rack_id = |R{ sy-index }| customer = 'ALPHA'
size_class = 'S' power_class = 'A' ) INTO TABLE lt_racks.
ENDDO.
DATA(lt_bills) = mo_cut->calculate( lt_racks ).
cl_abap_unit_assert=>assert_equals( exp = 20 act = lt_bills[ 1 ]-rack_count ).
assert_amount( iv_expected = '800.00' iv_actual = lt_bills[ 1 ]-total_fee ).
ENDMETHOD.
METHOD nine_racks_no_discount.
DATA lt_racks TYPE {{p}}rack_billing=>tt_racks.
DO 9 TIMES.
INSERT VALUE #( rack_id = |R{ sy-index }| customer = 'ALPHA'
size_class = 'S' power_class = 'A' ) INTO TABLE lt_racks.
ENDDO.
DATA(lt_bills) = mo_cut->calculate( lt_racks ).
cl_abap_unit_assert=>assert_equals( exp = 9 act = lt_bills[ 1 ]-rack_count ).
assert_amount( iv_expected = '450.00' iv_actual = lt_bills[ 1 ]-total_fee ).
ENDMETHOD.
METHOD ignores_unknown_size.
DATA lt_racks TYPE {{p}}rack_billing=>tt_racks.
lt_racks = VALUE #(
( rack_id = 'R001' customer = 'ALPHA' size_class = 'X' power_class = 'A' )
( rack_id = 'R002' customer = 'ALPHA' size_class = 'S' power_class = 'A' ) ).
DATA(lt_bills) = mo_cut->calculate( lt_racks ).
cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_bills ) ).
cl_abap_unit_assert=>assert_equals( exp = 1 act = lt_bills[ 1 ]-rack_count ).
assert_amount( iv_expected = '50.00' iv_actual = lt_bills[ 1 ]-total_fee ).
ENDMETHOD.
METHOD ignores_unknown_power.
DATA lt_racks TYPE {{p}}rack_billing=>tt_racks.
lt_racks = VALUE #(
( rack_id = 'R001' customer = 'ALPHA' size_class = 'L' power_class = 'Z' )
( rack_id = 'R002' customer = 'ALPHA' size_class = 'L' power_class = 'B' ) ).
DATA(lt_bills) = mo_cut->calculate( lt_racks ).
cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_bills ) ).
cl_abap_unit_assert=>assert_equals( exp = 1 act = lt_bills[ 1 ]-rack_count ).
assert_amount( iv_expected = '280.00' iv_actual = lt_bills[ 1 ]-total_fee ).
ENDMETHOD.
METHOD ignores_second_rack_id.
DATA lt_racks TYPE {{p}}rack_billing=>tt_racks.
lt_racks = VALUE #(
( rack_id = 'R001' customer = 'ALPHA' size_class = 'M' power_class = 'A' )
( rack_id = 'R001' customer = 'BETA' size_class = 'L' power_class = 'C' ) ).
DATA(lt_bills) = mo_cut->calculate( lt_racks ).
cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_bills ) ).
cl_abap_unit_assert=>assert_equals( exp = 'ALPHA' act = lt_bills[ 1 ]-customer ).
cl_abap_unit_assert=>assert_equals( exp = 1 act = lt_bills[ 1 ]-rack_count ).
assert_amount( iv_expected = '120.00' iv_actual = lt_bills[ 1 ]-total_fee ).
ENDMETHOD.
METHOD empty_input.
DATA lt_racks TYPE {{p}}rack_billing=>tt_racks.
DATA(lt_bills) = mo_cut->calculate( lt_racks ).
cl_abap_unit_assert=>assert_initial( lt_bills ).
ENDMETHOD.
METHOD all_classes.
DATA lt_racks TYPE {{p}}rack_billing=>tt_racks.
lt_racks = VALUE #(
( rack_id = 'R001' customer = 'ALPHA' size_class = 'S' power_class = 'C' )
( rack_id = 'R002' customer = 'ALPHA' size_class = 'M' power_class = 'C' )
( rack_id = 'R003' customer = 'ALPHA' size_class = 'L' power_class = 'C' ) ).
DATA(lt_bills) = mo_cut->calculate( lt_racks ).
cl_abap_unit_assert=>assert_equals( exp = 3 act = lt_bills[ 1 ]-rack_count ).
assert_amount( iv_expected = '630.00' iv_actual = lt_bills[ 1 ]-total_fee ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,93 @@
{
"task": "G1053",
"mutants": [
{
"object": "{{P}}RACK_BILLING",
"mutant": "line 74: + -> - (arith)",
"status": "killed",
"hidden": "2/11",
"failed_tests": [
"ALL_CLASSES",
"IGNORES_SECOND_RACK_ID",
"IGNORES_UNKNOWN_POWER",
"IGNORES_UNKNOWN_SIZE",
"NINE_RACKS_NO_DISCOUNT",
"ONE_RACK",
"SUMS_PER_CUSTOMER",
"TEN_RACKS_DISCOUNT",
"TWENTY_RACKS_DISCOUNT"
]
},
{
"object": "{{P}}RACK_BILLING",
"mutant": "line 79: * -> / (arith)",
"status": "killed",
"hidden": "2/11",
"failed_tests": [
"ALL_CLASSES",
"IGNORES_SECOND_RACK_ID",
"IGNORES_UNKNOWN_POWER",
"IGNORES_UNKNOWN_SIZE",
"NINE_RACKS_NO_DISCOUNT",
"ONE_RACK",
"SUMS_PER_CUSTOMER",
"TEN_RACKS_DISCOUNT",
"TWENTY_RACKS_DISCOUNT"
]
},
{
"object": "{{P}}RACK_BILLING",
"mutant": "line 79: 100 -> 101 (const)",
"status": "killed",
"hidden": "2/11",
"failed_tests": [
"ALL_CLASSES",
"IGNORES_SECOND_RACK_ID",
"IGNORES_UNKNOWN_POWER",
"IGNORES_UNKNOWN_SIZE",
"NINE_RACKS_NO_DISCOUNT",
"ONE_RACK",
"SUMS_PER_CUSTOMER",
"TEN_RACKS_DISCOUNT",
"TWENTY_RACKS_DISCOUNT"
]
},
{
"object": "{{P}}RACK_BILLING",
"mutant": "line 110: >= -> < (rel)",
"status": "killed",
"hidden": "2/11",
"failed_tests": [
"ALL_CLASSES",
"IGNORES_SECOND_RACK_ID",
"IGNORES_UNKNOWN_POWER",
"IGNORES_UNKNOWN_SIZE",
"NINE_RACKS_NO_DISCOUNT",
"ONE_RACK",
"SUMS_PER_CUSTOMER",
"TEN_RACKS_DISCOUNT",
"TWENTY_RACKS_DISCOUNT"
]
},
{
"object": "{{P}}RACK_BILLING",
"mutant": "line 112: >= -> < (rel)",
"status": "killed",
"hidden": "3/11",
"failed_tests": [
"ALL_CLASSES",
"IGNORES_SECOND_RACK_ID",
"IGNORES_UNKNOWN_POWER",
"IGNORES_UNKNOWN_SIZE",
"NINE_RACKS_NO_DISCOUNT",
"ONE_RACK",
"SUMS_PER_CUSTOMER",
"TEN_RACKS_DISCOUNT"
]
}
],
"valid": 5,
"killed": 5,
"kill_rate": 1.0,
"ok": true
}

View File

@@ -0,0 +1,116 @@
CLASS {{p}}rack_billing DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_size TYPE c LENGTH 1.
TYPES ty_power TYPE c LENGTH 1.
TYPES ty_customer TYPE c LENGTH 10.
TYPES ty_fee TYPE p LENGTH 8 DECIMALS 2.
TYPES:
BEGIN OF ty_rack,
rack_id TYPE c LENGTH 10,
customer TYPE ty_customer,
size_class TYPE ty_size,
power_class TYPE ty_power,
END OF ty_rack.
TYPES tt_racks TYPE STANDARD TABLE OF ty_rack WITH EMPTY KEY.
TYPES:
BEGIN OF ty_bill,
customer TYPE ty_customer,
rack_count TYPE i,
total_fee TYPE ty_fee,
END OF ty_bill.
TYPES tt_bills TYPE STANDARD TABLE OF ty_bill WITH EMPTY KEY.
METHODS calculate
IMPORTING it_racks TYPE tt_racks
RETURNING VALUE(rt_bills) TYPE tt_bills.
PRIVATE SECTION.
TYPES:
BEGIN OF ty_price,
size_class TYPE ty_size,
power_class TYPE ty_power,
fee TYPE ty_fee,
END OF ty_price.
TYPES tt_prices TYPE HASHED TABLE OF ty_price WITH UNIQUE KEY size_class power_class.
TYPES tt_seen TYPE HASHED TABLE OF ty_rack WITH UNIQUE KEY rack_id.
TYPES tt_bill_hash TYPE HASHED TABLE OF ty_bill WITH UNIQUE KEY customer.
METHODS price_list
RETURNING VALUE(rt_prices) TYPE tt_prices.
METHODS rack_fee
IMPORTING is_rack TYPE ty_rack
it_prices TYPE tt_prices
RETURNING VALUE(rv_fee) TYPE ty_fee.
METHODS discount_percent
IMPORTING iv_count TYPE i
RETURNING VALUE(rv_percent) TYPE i.
ENDCLASS.
CLASS {{p}}rack_billing IMPLEMENTATION.
METHOD calculate.
DATA(lt_prices) = price_list( ).
DATA lt_seen TYPE tt_seen.
DATA lt_bills TYPE tt_bill_hash.
LOOP AT it_racks INTO DATA(ls_rack).
INSERT ls_rack INTO TABLE lt_seen.
IF sy-subrc <> 0.
CONTINUE.
ENDIF.
DATA(lv_fee) = rack_fee( is_rack = ls_rack it_prices = lt_prices ).
IF lv_fee IS INITIAL.
CONTINUE.
ENDIF.
ASSIGN lt_bills[ customer = ls_rack-customer ] TO FIELD-SYMBOL(<ls_bill>).
IF sy-subrc <> 0.
INSERT VALUE #( customer = ls_rack-customer ) INTO TABLE lt_bills ASSIGNING <ls_bill>.
ENDIF.
<ls_bill>-rack_count = <ls_bill>-rack_count + 1.
<ls_bill>-total_fee = <ls_bill>-total_fee + lv_fee.
ENDLOOP.
LOOP AT lt_bills ASSIGNING <ls_bill>.
DATA(lv_percent) = discount_percent( <ls_bill>-rack_count ).
<ls_bill>-total_fee = <ls_bill>-total_fee * ( 100 - lv_percent ) / 100.
INSERT VALUE #( customer = <ls_bill>-customer
rack_count = <ls_bill>-rack_count
total_fee = <ls_bill>-total_fee ) INTO TABLE rt_bills.
ENDLOOP.
SORT rt_bills BY customer.
ENDMETHOD.
METHOD price_list.
rt_prices = VALUE #(
( size_class = 'S' power_class = 'A' fee = '50.00' )
( size_class = 'S' power_class = 'B' fee = '80.00' )
( size_class = 'S' power_class = 'C' fee = '120.00' )
( size_class = 'M' power_class = 'A' fee = '120.00' )
( size_class = 'M' power_class = 'B' fee = '150.00' )
( size_class = 'M' power_class = 'C' fee = '190.00' )
( size_class = 'L' power_class = 'A' fee = '250.00' )
( size_class = 'L' power_class = 'B' fee = '280.00' )
( size_class = 'L' power_class = 'C' fee = '320.00' ) ).
ENDMETHOD.
METHOD rack_fee.
ASSIGN it_prices[ size_class = is_rack-size_class power_class = is_rack-power_class ]
TO FIELD-SYMBOL(<ls_price>).
IF sy-subrc = 0.
rv_fee = <ls_price>-fee.
ENDIF.
ENDMETHOD.
METHOD discount_percent.
IF iv_count >= 20.
rv_percent = 20.
ELSEIF iv_count >= 10.
rv_percent = 10.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,88 @@
CLASS ltc_rack_billing DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA mo_cut TYPE REF TO {{p}}rack_billing.
METHODS setup.
METHODS assert_amount
IMPORTING iv_expected TYPE {{p}}rack_billing=>ty_fee
iv_actual TYPE {{p}}rack_billing=>ty_fee.
METHODS one_rack FOR TESTING.
METHODS groups_by_customer FOR TESTING.
METHODS applies_discount FOR TESTING.
METHODS ignores_invalid_rack FOR TESTING.
METHODS ignores_duplicate_rack FOR TESTING.
METHODS empty_input FOR TESTING.
ENDCLASS.
CLASS ltc_rack_billing IMPLEMENTATION.
METHOD setup.
mo_cut = NEW {{p}}rack_billing( ).
ENDMETHOD.
METHOD assert_amount.
cl_abap_unit_assert=>assert_equals( exp = iv_expected act = iv_actual ).
ENDMETHOD.
METHOD one_rack.
DATA lt_racks TYPE {{p}}rack_billing=>tt_racks.
lt_racks = VALUE #( ( rack_id = 'R001' customer = 'ALPHA'
size_class = 'M' power_class = 'B' ) ).
DATA(lt_bills) = mo_cut->calculate( lt_racks ).
cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_bills ) ).
cl_abap_unit_assert=>assert_equals( exp = 1 act = lt_bills[ 1 ]-rack_count ).
assert_amount( iv_expected = '150.00' iv_actual = lt_bills[ 1 ]-total_fee ).
ENDMETHOD.
METHOD groups_by_customer.
DATA lt_racks TYPE {{p}}rack_billing=>tt_racks.
lt_racks = VALUE #(
( rack_id = 'R001' customer = 'ALPHA' size_class = 'S' power_class = 'C' )
( rack_id = 'R002' customer = 'ALPHA' size_class = 'L' power_class = 'A' )
( rack_id = 'R003' customer = 'BETA' size_class = 'M' power_class = 'B' ) ).
DATA(lt_bills) = mo_cut->calculate( lt_racks ).
cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_bills ) ).
cl_abap_unit_assert=>assert_equals( exp = 'ALPHA' act = lt_bills[ 1 ]-customer ).
cl_abap_unit_assert=>assert_equals( exp = 2 act = lt_bills[ 1 ]-rack_count ).
assert_amount( iv_expected = '370.00' iv_actual = lt_bills[ 1 ]-total_fee ).
assert_amount( iv_expected = '150.00' iv_actual = lt_bills[ 2 ]-total_fee ).
ENDMETHOD.
METHOD applies_discount.
DATA lt_racks TYPE {{p}}rack_billing=>tt_racks.
DO 10 TIMES.
INSERT VALUE #( rack_id = |R{ sy-index }| customer = 'ALPHA'
size_class = 'M' power_class = 'B' ) INTO TABLE lt_racks.
ENDDO.
DATA(lt_bills) = mo_cut->calculate( lt_racks ).
cl_abap_unit_assert=>assert_equals( exp = 10 act = lt_bills[ 1 ]-rack_count ).
assert_amount( iv_expected = '1350.00' iv_actual = lt_bills[ 1 ]-total_fee ).
ENDMETHOD.
METHOD ignores_invalid_rack.
DATA lt_racks TYPE {{p}}rack_billing=>tt_racks.
lt_racks = VALUE #(
( rack_id = 'R001' customer = 'ALPHA' size_class = 'S' power_class = 'D' )
( rack_id = 'R002' customer = 'ALPHA' size_class = 'M' power_class = 'A' ) ).
DATA(lt_bills) = mo_cut->calculate( lt_racks ).
cl_abap_unit_assert=>assert_equals( exp = 1 act = lt_bills[ 1 ]-rack_count ).
assert_amount( iv_expected = '120.00' iv_actual = lt_bills[ 1 ]-total_fee ).
ENDMETHOD.
METHOD ignores_duplicate_rack.
DATA lt_racks TYPE {{p}}rack_billing=>tt_racks.
lt_racks = VALUE #(
( rack_id = 'R001' customer = 'ALPHA' size_class = 'S' power_class = 'A' )
( rack_id = 'R001' customer = 'ALPHA' size_class = 'L' power_class = 'C' ) ).
DATA(lt_bills) = mo_cut->calculate( lt_racks ).
cl_abap_unit_assert=>assert_equals( exp = 1 act = lt_bills[ 1 ]-rack_count ).
assert_amount( iv_expected = '50.00' iv_actual = lt_bills[ 1 ]-total_fee ).
ENDMETHOD.
METHOD empty_input.
DATA lt_racks TYPE {{p}}rack_billing=>tt_racks.
DATA(lt_bills) = mo_cut->calculate( lt_racks ).
cl_abap_unit_assert=>assert_initial( lt_bills ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,76 @@
# 1. Goal
A data centre operator bills its customers for the server racks that they rent.
A billing program calls one class for each billing run. The class returns one
row per customer with the number of racks and the monthly fee.
# 2. Open questions
None.
# 3. Context
- There are no seed objects. Create the class in package $TMP.
- A rack has a rack ID, a customer, a size class and a power class.
- The billing input can contain the same rack more than once.
- The class is the only object of this task.
# 4. Contract
Create the class {{P}}RACK_BILLING in package $TMP.
- The class is public and final. It has a public constructor without parameters.
- Public types:
TYPES ty_size TYPE c LENGTH 1.
TYPES ty_power TYPE c LENGTH 1.
TYPES ty_customer TYPE c LENGTH 10.
TYPES ty_fee TYPE p LENGTH 8 DECIMALS 2.
TYPES: BEGIN OF ty_rack,
rack_id TYPE c LENGTH 10,
customer TYPE ty_customer,
size_class TYPE ty_size,
power_class TYPE ty_power,
END OF ty_rack.
TYPES tt_racks TYPE STANDARD TABLE OF ty_rack WITH EMPTY KEY.
TYPES: BEGIN OF ty_bill,
customer TYPE ty_customer,
rack_count TYPE i,
total_fee TYPE ty_fee,
END OF ty_bill.
TYPES tt_bills TYPE STANDARD TABLE OF ty_bill WITH EMPTY KEY.
- Public method:
METHODS calculate
IMPORTING it_racks TYPE tt_racks
RETURNING VALUE(rt_bills) TYPE tt_bills.
- Do not add other public methods.
# 5. Business rules
A rack is valid when its size class is S, M or L and its power class is A, B
or C.
1. Read it_racks in the given order.
2. A rack ID identifies one rack. If a rack ID was already read, skip the rack.
Remember the rack ID of every rack that you read, also when the rack is not
valid.
3. If the size class is not S, M or L, or the power class is not A, B or C,
skip the rack.
4. The monthly fee of a valid rack is the base fee of its size class plus the
surcharge of its power class:
- base fee: S = 50.00, M = 120.00, L = 250.00
- power surcharge: A = 0.00, B = 30.00, C = 70.00
5. Add the fee of the rack to the total fee of its customer. Increase the rack
count of the customer by 1.
6. After all racks, apply a volume discount to the total fee of each customer:
- 20 or more racks: 20 percent
- 10 or more racks: 10 percent
- less than 10 racks: no discount
7. The result has one row for each customer with at least one valid rack. The
row contains the customer, the number of valid racks and the total fee after
the discount.
8. Sort the result by customer in ascending order.
9. If it_racks is empty, return an empty table.
# 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: 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,42 @@
{
"id": "G1053",
"category": "C",
"object_type": "CLAS",
"difficulty": 2,
"release_target": "v816",
"expected_outcome": "implement",
"budget": {
"max_tool_calls": 70,
"max_activations": 18
},
"seed": [],
"contract": [
{
"type": "CLAS",
"name": "{{P}}RACK_BILLING"
}
],
"out_of_scope": [],
"hidden_tests": [
{
"type": "CLAS",
"name": "{{P}}T02_HIDDEN",
"file": "hidden/t02_hidden.clas.abap",
"description": "T02 hidden tests for the rack billing class"
}
],
"reference": [
{
"type": "CLAS",
"name": "{{P}}RACK_BILLING",
"file": "reference/rack_billing.clas.abap",
"description": "Rack billing with price lookup, customer grouping and volume discount",
"testclasses_file": "reference/rack_billing.testclasses.abap"
}
],
"craft_checks": [
"method_length",
"table_kind",
"key_access"
]
}

View File

@@ -0,0 +1,105 @@
CLASS {{p}}pest_fee DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_pest TYPE c LENGTH 4.
TYPES ty_fee TYPE p LENGTH 8 DECIMALS 2.
METHODS calculate_fee
IMPORTING iv_pest_type TYPE ty_pest
iv_area TYPE i
iv_urgent TYPE abap_bool
iv_contract TYPE abap_bool
RETURNING VALUE(rv_fee) TYPE ty_fee.
PRIVATE SECTION.
CONSTANTS:
c_minimum_fee TYPE ty_fee VALUE '50.00',
c_urgent_fee TYPE ty_fee VALUE '45.00',
c_area_free TYPE i VALUE 100,
c_area_step TYPE i VALUE 50,
c_area_step_fee TYPE i VALUE 15,
c_discount_pct TYPE i VALUE 10.
METHODS base_fee
IMPORTING iv_pest_type TYPE ty_pest
RETURNING VALUE(rv_fee) TYPE ty_fee.
METHODS area_surcharge
IMPORTING iv_area TYPE i
RETURNING VALUE(rv_fee) TYPE ty_fee.
METHODS urgent_surcharge
IMPORTING iv_urgent TYPE abap_bool
RETURNING VALUE(rv_fee) TYPE ty_fee.
METHODS contract_discount
IMPORTING iv_base TYPE ty_fee
iv_area_fee TYPE ty_fee
iv_contract TYPE abap_bool
RETURNING VALUE(rv_fee) TYPE ty_fee.
ENDCLASS.
CLASS {{p}}pest_fee IMPLEMENTATION.
METHOD calculate_fee.
DATA(lv_base) = base_fee( iv_pest_type ).
IF lv_base = 0.
CLEAR rv_fee.
RETURN.
ENDIF.
DATA(lv_area_fee) = area_surcharge( iv_area ).
DATA(lv_gross) = lv_base + lv_area_fee + urgent_surcharge( iv_urgent ).
DATA(lv_discount) = contract_discount( iv_base = lv_base
iv_area_fee = lv_area_fee
iv_contract = iv_contract ).
rv_fee = lv_gross + lv_discount.
IF rv_fee < c_minimum_fee.
rv_fee = c_minimum_fee.
ENDIF.
ENDMETHOD.
METHOD base_fee.
CASE iv_pest_type.
WHEN 'RATS'.
rv_fee = 120.
WHEN 'MICE'.
rv_fee = 55.
WHEN 'WASP'.
rv_fee = 150.
WHEN 'ANTS'.
rv_fee = 80.
WHEN OTHERS.
CLEAR rv_fee.
ENDCASE.
ENDMETHOD.
METHOD area_surcharge.
DATA(lv_billable) = iv_area - c_area_free.
IF lv_billable <= 0.
RETURN.
ENDIF.
DATA(lv_steps) = ( lv_billable + c_area_step - 1 ) DIV c_area_step.
rv_fee = lv_steps * c_area_step_fee.
ENDMETHOD.
METHOD urgent_surcharge.
IF iv_urgent = abap_true.
rv_fee = c_urgent_fee.
ENDIF.
ENDMETHOD.
METHOD contract_discount.
IF iv_contract = abap_false.
RETURN.
ENDIF.
DATA(lv_discountable) = iv_base + iv_area_fee.
rv_fee = lv_discountable * c_discount_pct / 100.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,105 @@
CLASS {{p}}pest_fee DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_pest TYPE c LENGTH 4.
TYPES ty_fee TYPE p LENGTH 8 DECIMALS 2.
METHODS calculate_fee
IMPORTING iv_pest_type TYPE ty_pest
iv_area TYPE i
iv_urgent TYPE abap_bool
iv_contract TYPE abap_bool
RETURNING VALUE(rv_fee) TYPE ty_fee.
PRIVATE SECTION.
CONSTANTS:
c_minimum_fee TYPE ty_fee VALUE '50.00',
c_urgent_fee TYPE ty_fee VALUE '45.00',
c_area_free TYPE i VALUE 100,
c_area_step TYPE i VALUE 50,
c_area_step_fee TYPE i VALUE 15,
c_discount_pct TYPE i VALUE 10.
METHODS base_fee
IMPORTING iv_pest_type TYPE ty_pest
RETURNING VALUE(rv_fee) TYPE ty_fee.
METHODS area_surcharge
IMPORTING iv_area TYPE i
RETURNING VALUE(rv_fee) TYPE ty_fee.
METHODS urgent_surcharge
IMPORTING iv_urgent TYPE abap_bool
RETURNING VALUE(rv_fee) TYPE ty_fee.
METHODS contract_discount
IMPORTING iv_base TYPE ty_fee
iv_area_fee TYPE ty_fee
iv_contract TYPE abap_bool
RETURNING VALUE(rv_fee) TYPE ty_fee.
ENDCLASS.
CLASS {{p}}pest_fee IMPLEMENTATION.
METHOD calculate_fee.
DATA(lv_base) = base_fee( iv_pest_type ).
IF lv_base = 0.
CLEAR rv_fee.
RETURN.
ENDIF.
DATA(lv_area_fee) = area_surcharge( iv_area ).
DATA(lv_gross) = lv_base + lv_area_fee + urgent_surcharge( iv_urgent ).
DATA(lv_discount) = contract_discount( iv_base = lv_base
iv_area_fee = lv_area_fee
iv_contract = iv_contract ).
rv_fee = lv_gross - lv_discount.
IF rv_fee >= c_minimum_fee.
rv_fee = c_minimum_fee.
ENDIF.
ENDMETHOD.
METHOD base_fee.
CASE iv_pest_type.
WHEN 'RATS'.
rv_fee = 120.
WHEN 'MICE'.
rv_fee = 55.
WHEN 'WASP'.
rv_fee = 150.
WHEN 'ANTS'.
rv_fee = 80.
WHEN OTHERS.
CLEAR rv_fee.
ENDCASE.
ENDMETHOD.
METHOD area_surcharge.
DATA(lv_billable) = iv_area - c_area_free.
IF lv_billable <= 0.
RETURN.
ENDIF.
DATA(lv_steps) = ( lv_billable + c_area_step - 1 ) DIV c_area_step.
rv_fee = lv_steps * c_area_step_fee.
ENDMETHOD.
METHOD urgent_surcharge.
IF iv_urgent = abap_true.
rv_fee = c_urgent_fee.
ENDIF.
ENDMETHOD.
METHOD contract_discount.
IF iv_contract = abap_false.
RETURN.
ENDIF.
DATA(lv_discountable) = iv_base + iv_area_fee.
rv_fee = lv_discountable * c_discount_pct / 100.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,105 @@
CLASS {{p}}pest_fee DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_pest TYPE c LENGTH 4.
TYPES ty_fee TYPE p LENGTH 8 DECIMALS 2.
METHODS calculate_fee
IMPORTING iv_pest_type TYPE ty_pest
iv_area TYPE i
iv_urgent TYPE abap_bool
iv_contract TYPE abap_bool
RETURNING VALUE(rv_fee) TYPE ty_fee.
PRIVATE SECTION.
CONSTANTS:
c_minimum_fee TYPE ty_fee VALUE '50.00',
c_urgent_fee TYPE ty_fee VALUE '45.00',
c_area_free TYPE i VALUE 100,
c_area_step TYPE i VALUE 50,
c_area_step_fee TYPE i VALUE 15,
c_discount_pct TYPE i VALUE 10.
METHODS base_fee
IMPORTING iv_pest_type TYPE ty_pest
RETURNING VALUE(rv_fee) TYPE ty_fee.
METHODS area_surcharge
IMPORTING iv_area TYPE i
RETURNING VALUE(rv_fee) TYPE ty_fee.
METHODS urgent_surcharge
IMPORTING iv_urgent TYPE abap_bool
RETURNING VALUE(rv_fee) TYPE ty_fee.
METHODS contract_discount
IMPORTING iv_base TYPE ty_fee
iv_area_fee TYPE ty_fee
iv_contract TYPE abap_bool
RETURNING VALUE(rv_fee) TYPE ty_fee.
ENDCLASS.
CLASS {{p}}pest_fee IMPLEMENTATION.
METHOD calculate_fee.
DATA(lv_base) = base_fee( iv_pest_type ).
IF lv_base = 0.
CLEAR rv_fee.
RETURN.
ENDIF.
DATA(lv_area_fee) = area_surcharge( iv_area ).
DATA(lv_gross) = lv_base + lv_area_fee + urgent_surcharge( iv_urgent ).
DATA(lv_discount) = contract_discount( iv_base = lv_base
iv_area_fee = lv_area_fee
iv_contract = iv_contract ).
rv_fee = lv_gross - lv_discount.
IF rv_fee < c_minimum_fee.
rv_fee = c_minimum_fee.
ENDIF.
ENDMETHOD.
METHOD base_fee.
CASE iv_pest_type.
WHEN 'RATS'.
rv_fee = 120.
WHEN 'MICE'.
rv_fee = 55.
WHEN 'WASP'.
rv_fee = 150.
WHEN 'ANTS'.
rv_fee = 80.
WHEN OTHERS.
CLEAR rv_fee.
ENDCASE.
ENDMETHOD.
METHOD area_surcharge.
DATA(lv_billable) = iv_area - c_area_free.
IF lv_billable <= 0.
RETURN.
ENDIF.
DATA(lv_steps) = ( lv_billable + c_area_step - 1 ) DIV c_area_step.
rv_fee = lv_steps / c_area_step_fee.
ENDMETHOD.
METHOD urgent_surcharge.
IF iv_urgent = abap_true.
rv_fee = c_urgent_fee.
ENDIF.
ENDMETHOD.
METHOD contract_discount.
IF iv_contract = abap_false.
RETURN.
ENDIF.
DATA(lv_discountable) = iv_base + iv_area_fee.
rv_fee = lv_discountable * c_discount_pct / 100.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,105 @@
CLASS {{p}}pest_fee DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_pest TYPE c LENGTH 4.
TYPES ty_fee TYPE p LENGTH 8 DECIMALS 2.
METHODS calculate_fee
IMPORTING iv_pest_type TYPE ty_pest
iv_area TYPE i
iv_urgent TYPE abap_bool
iv_contract TYPE abap_bool
RETURNING VALUE(rv_fee) TYPE ty_fee.
PRIVATE SECTION.
CONSTANTS:
c_minimum_fee TYPE ty_fee VALUE '50.00',
c_urgent_fee TYPE ty_fee VALUE '45.00',
c_area_free TYPE i VALUE 100,
c_area_step TYPE i VALUE 50,
c_area_step_fee TYPE i VALUE 15,
c_discount_pct TYPE i VALUE 10.
METHODS base_fee
IMPORTING iv_pest_type TYPE ty_pest
RETURNING VALUE(rv_fee) TYPE ty_fee.
METHODS area_surcharge
IMPORTING iv_area TYPE i
RETURNING VALUE(rv_fee) TYPE ty_fee.
METHODS urgent_surcharge
IMPORTING iv_urgent TYPE abap_bool
RETURNING VALUE(rv_fee) TYPE ty_fee.
METHODS contract_discount
IMPORTING iv_base TYPE ty_fee
iv_area_fee TYPE ty_fee
iv_contract TYPE abap_bool
RETURNING VALUE(rv_fee) TYPE ty_fee.
ENDCLASS.
CLASS {{p}}pest_fee IMPLEMENTATION.
METHOD calculate_fee.
DATA(lv_base) = base_fee( iv_pest_type ).
IF lv_base = 0.
CLEAR rv_fee.
RETURN.
ENDIF.
DATA(lv_area_fee) = area_surcharge( iv_area ).
DATA(lv_gross) = lv_base + lv_area_fee + urgent_surcharge( iv_urgent ).
DATA(lv_discount) = contract_discount( iv_base = lv_base
iv_area_fee = lv_area_fee
iv_contract = iv_contract ).
rv_fee = lv_gross - lv_discount.
IF rv_fee < c_minimum_fee.
rv_fee = c_minimum_fee.
ENDIF.
ENDMETHOD.
METHOD base_fee.
CASE iv_pest_type.
WHEN 'RATS'.
rv_fee = 120.
WHEN 'MICE'.
rv_fee = 55.
WHEN 'WASP'.
rv_fee = 150.
WHEN 'ANTS'.
rv_fee = 80.
WHEN OTHERS.
CLEAR rv_fee.
ENDCASE.
ENDMETHOD.
METHOD area_surcharge.
DATA(lv_billable) = iv_area - c_area_free.
IF lv_billable <= 0.
RETURN.
ENDIF.
DATA(lv_steps) = ( lv_billable + c_area_step - 1 ) DIV c_area_step.
rv_fee = lv_steps * c_area_step_fee.
ENDMETHOD.
METHOD urgent_surcharge.
IF iv_urgent <> abap_true.
rv_fee = c_urgent_fee.
ENDIF.
ENDMETHOD.
METHOD contract_discount.
IF iv_contract = abap_false.
RETURN.
ENDIF.
DATA(lv_discountable) = iv_base + iv_area_fee.
rv_fee = lv_discountable * c_discount_pct / 100.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,105 @@
CLASS {{p}}pest_fee DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_pest TYPE c LENGTH 4.
TYPES ty_fee TYPE p LENGTH 8 DECIMALS 2.
METHODS calculate_fee
IMPORTING iv_pest_type TYPE ty_pest
iv_area TYPE i
iv_urgent TYPE abap_bool
iv_contract TYPE abap_bool
RETURNING VALUE(rv_fee) TYPE ty_fee.
PRIVATE SECTION.
CONSTANTS:
c_minimum_fee TYPE ty_fee VALUE '50.00',
c_urgent_fee TYPE ty_fee VALUE '45.00',
c_area_free TYPE i VALUE 100,
c_area_step TYPE i VALUE 50,
c_area_step_fee TYPE i VALUE 15,
c_discount_pct TYPE i VALUE 10.
METHODS base_fee
IMPORTING iv_pest_type TYPE ty_pest
RETURNING VALUE(rv_fee) TYPE ty_fee.
METHODS area_surcharge
IMPORTING iv_area TYPE i
RETURNING VALUE(rv_fee) TYPE ty_fee.
METHODS urgent_surcharge
IMPORTING iv_urgent TYPE abap_bool
RETURNING VALUE(rv_fee) TYPE ty_fee.
METHODS contract_discount
IMPORTING iv_base TYPE ty_fee
iv_area_fee TYPE ty_fee
iv_contract TYPE abap_bool
RETURNING VALUE(rv_fee) TYPE ty_fee.
ENDCLASS.
CLASS {{p}}pest_fee IMPLEMENTATION.
METHOD calculate_fee.
DATA(lv_base) = base_fee( iv_pest_type ).
IF lv_base = 0.
CLEAR rv_fee.
RETURN.
ENDIF.
DATA(lv_area_fee) = area_surcharge( iv_area ).
DATA(lv_gross) = lv_base + lv_area_fee + urgent_surcharge( iv_urgent ).
DATA(lv_discount) = contract_discount( iv_base = lv_base
iv_area_fee = lv_area_fee
iv_contract = iv_contract ).
rv_fee = lv_gross - lv_discount.
IF rv_fee < c_minimum_fee.
rv_fee = c_minimum_fee.
ENDIF.
ENDMETHOD.
METHOD base_fee.
CASE iv_pest_type.
WHEN 'RATS'.
rv_fee = 120.
WHEN 'MICE'.
rv_fee = 55.
WHEN 'WASP'.
rv_fee = 150.
WHEN 'ANTS'.
rv_fee = 80.
WHEN OTHERS.
CLEAR rv_fee.
ENDCASE.
ENDMETHOD.
METHOD area_surcharge.
DATA(lv_billable) = iv_area - c_area_free.
IF lv_billable <= 0.
RETURN.
ENDIF.
DATA(lv_steps) = ( lv_billable + c_area_step - 1 ) DIV c_area_step.
rv_fee = lv_steps * c_area_step_fee.
ENDMETHOD.
METHOD urgent_surcharge.
IF iv_urgent = abap_true.
rv_fee = c_urgent_fee.
ENDIF.
ENDMETHOD.
METHOD contract_discount.
IF iv_contract = abap_true.
RETURN.
ENDIF.
DATA(lv_discountable) = iv_base + iv_area_fee.
rv_fee = lv_discountable * c_discount_pct / 100.
ENDMETHOD.
ENDCLASS.

View File

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

View File

@@ -0,0 +1,141 @@
CLASS {{p}}pest_test_hidden DEFINITION
PUBLIC
FINAL
CREATE PUBLIC
FOR TESTING
DURATION SHORT
RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA mo_cut TYPE REF TO {{p}}pest_fee.
METHODS setup.
METHODS expect_fee
IMPORTING iv_expected TYPE {{p}}pest_fee=>ty_fee
iv_actual TYPE {{p}}pest_fee=>ty_fee
iv_case TYPE string.
METHODS rats_base_fee FOR TESTING.
METHODS mice_base_fee FOR TESTING.
METHODS wasp_base_fee FOR TESTING.
METHODS unknown_pest_zero FOR TESTING.
METHODS area_surcharge_step FOR TESTING.
METHODS area_surcharge_rounds FOR TESTING.
METHODS no_surcharge_at_100 FOR TESTING.
METHODS urgent_surcharge FOR TESTING.
METHODS contract_discount FOR TESTING.
METHODS discount_excludes_urgent FOR TESTING.
METHODS minimum_fee FOR TESTING.
ENDCLASS.
CLASS {{p}}pest_test_hidden IMPLEMENTATION.
METHOD setup.
mo_cut = NEW {{p}}pest_fee( ).
ENDMETHOD.
METHOD expect_fee.
cl_abap_unit_assert=>assert_equals( exp = iv_expected
act = iv_actual
msg = iv_case ).
ENDMETHOD.
METHOD rats_base_fee.
expect_fee( iv_expected = 120
iv_actual = mo_cut->calculate_fee( iv_pest_type = 'RATS'
iv_area = 50
iv_urgent = abap_false
iv_contract = abap_false )
iv_case = 'RATS base fee' ).
ENDMETHOD.
METHOD mice_base_fee.
expect_fee( iv_expected = 55
iv_actual = mo_cut->calculate_fee( iv_pest_type = 'MICE'
iv_area = 0
iv_urgent = abap_false
iv_contract = abap_false )
iv_case = 'MICE base fee' ).
ENDMETHOD.
METHOD wasp_base_fee.
expect_fee( iv_expected = 150
iv_actual = mo_cut->calculate_fee( iv_pest_type = 'WASP'
iv_area = 100
iv_urgent = abap_false
iv_contract = abap_false )
iv_case = 'WASP base fee' ).
ENDMETHOD.
METHOD unknown_pest_zero.
expect_fee( iv_expected = 0
iv_actual = mo_cut->calculate_fee( iv_pest_type = 'BIRD'
iv_area = 300
iv_urgent = abap_true
iv_contract = abap_true )
iv_case = 'unknown pest type' ).
ENDMETHOD.
METHOD area_surcharge_step.
expect_fee( iv_expected = 135
iv_actual = mo_cut->calculate_fee( iv_pest_type = 'RATS'
iv_area = 101
iv_urgent = abap_false
iv_contract = abap_false )
iv_case = 'one started area step' ).
ENDMETHOD.
METHOD area_surcharge_rounds.
expect_fee( iv_expected = 165
iv_actual = mo_cut->calculate_fee( iv_pest_type = 'RATS'
iv_area = 250
iv_urgent = abap_false
iv_contract = abap_false )
iv_case = 'three started area steps' ).
ENDMETHOD.
METHOD no_surcharge_at_100.
expect_fee( iv_expected = 80
iv_actual = mo_cut->calculate_fee( iv_pest_type = 'ANTS'
iv_area = 100
iv_urgent = abap_false
iv_contract = abap_false )
iv_case = 'no area surcharge at 100' ).
ENDMETHOD.
METHOD urgent_surcharge.
expect_fee( iv_expected = 125
iv_actual = mo_cut->calculate_fee( iv_pest_type = 'ANTS'
iv_area = 100
iv_urgent = abap_true
iv_contract = abap_false )
iv_case = 'urgent surcharge' ).
ENDMETHOD.
METHOD contract_discount.
expect_fee( iv_expected = 135
iv_actual = mo_cut->calculate_fee( iv_pest_type = 'RATS'
iv_area = 200
iv_urgent = abap_false
iv_contract = abap_true )
iv_case = 'contract discount' ).
ENDMETHOD.
METHOD discount_excludes_urgent.
expect_fee( iv_expected = 153
iv_actual = mo_cut->calculate_fee( iv_pest_type = 'RATS'
iv_area = 0
iv_urgent = abap_true
iv_contract = abap_true )
iv_case = 'discount without urgent surcharge' ).
ENDMETHOD.
METHOD minimum_fee.
expect_fee( iv_expected = 50
iv_actual = mo_cut->calculate_fee( iv_pest_type = 'MICE'
iv_area = 0
iv_urgent = abap_false
iv_contract = abap_true )
iv_case = 'minimum fee' ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,85 @@
{
"task": "G1054",
"mutants": [
{
"object": "{{P}}PEST_FEE",
"mutant": "line 60: - -> + (arith)",
"status": "killed",
"hidden": "8/11",
"failed_tests": [
"CONTRACT_DISCOUNT",
"DISCOUNT_EXCLUDES_URGENT",
"MINIMUM_FEE"
]
},
{
"object": "{{P}}PEST_FEE",
"mutant": "line 61: < -> >= (rel)",
"status": "killed",
"hidden": "1/11",
"failed_tests": [
"AREA_SURCHARGE_ROUNDS",
"AREA_SURCHARGE_STEP",
"CONTRACT_DISCOUNT",
"DISCOUNT_EXCLUDES_URGENT",
"MICE_BASE_FEE",
"MINIMUM_FEE",
"NO_SURCHARGE_AT_100",
"RATS_BASE_FEE",
"URGENT_SURCHARGE",
"WASP_BASE_FEE"
]
},
{
"object": "{{P}}PEST_FEE",
"mutant": "line 88: * -> / (arith)",
"status": "killed",
"hidden": "8/11",
"failed_tests": [
"AREA_SURCHARGE_ROUNDS",
"AREA_SURCHARGE_STEP",
"CONTRACT_DISCOUNT"
]
},
{
"object": "{{P}}PEST_FEE",
"mutant": "line 92: = -> <> (eq)",
"status": "killed",
"hidden": "1/11",
"failed_tests": [
"AREA_SURCHARGE_ROUNDS",
"AREA_SURCHARGE_STEP",
"CONTRACT_DISCOUNT",
"DISCOUNT_EXCLUDES_URGENT",
"MICE_BASE_FEE",
"MINIMUM_FEE",
"NO_SURCHARGE_AT_100",
"RATS_BASE_FEE",
"URGENT_SURCHARGE",
"WASP_BASE_FEE"
]
},
{
"object": "{{P}}PEST_FEE",
"mutant": "line 98: abap_false -> abap_true (bool)",
"status": "killed",
"hidden": "1/11",
"failed_tests": [
"AREA_SURCHARGE_ROUNDS",
"AREA_SURCHARGE_STEP",
"CONTRACT_DISCOUNT",
"DISCOUNT_EXCLUDES_URGENT",
"MICE_BASE_FEE",
"MINIMUM_FEE",
"NO_SURCHARGE_AT_100",
"RATS_BASE_FEE",
"URGENT_SURCHARGE",
"WASP_BASE_FEE"
]
}
],
"valid": 5,
"killed": 5,
"kill_rate": 1.0,
"ok": true
}

View File

@@ -0,0 +1,105 @@
CLASS {{p}}pest_fee DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_pest TYPE c LENGTH 4.
TYPES ty_fee TYPE p LENGTH 8 DECIMALS 2.
METHODS calculate_fee
IMPORTING iv_pest_type TYPE ty_pest
iv_area TYPE i
iv_urgent TYPE abap_bool
iv_contract TYPE abap_bool
RETURNING VALUE(rv_fee) TYPE ty_fee.
PRIVATE SECTION.
CONSTANTS:
c_minimum_fee TYPE ty_fee VALUE '50.00',
c_urgent_fee TYPE ty_fee VALUE '45.00',
c_area_free TYPE i VALUE 100,
c_area_step TYPE i VALUE 50,
c_area_step_fee TYPE i VALUE 15,
c_discount_pct TYPE i VALUE 10.
METHODS base_fee
IMPORTING iv_pest_type TYPE ty_pest
RETURNING VALUE(rv_fee) TYPE ty_fee.
METHODS area_surcharge
IMPORTING iv_area TYPE i
RETURNING VALUE(rv_fee) TYPE ty_fee.
METHODS urgent_surcharge
IMPORTING iv_urgent TYPE abap_bool
RETURNING VALUE(rv_fee) TYPE ty_fee.
METHODS contract_discount
IMPORTING iv_base TYPE ty_fee
iv_area_fee TYPE ty_fee
iv_contract TYPE abap_bool
RETURNING VALUE(rv_fee) TYPE ty_fee.
ENDCLASS.
CLASS {{p}}pest_fee IMPLEMENTATION.
METHOD calculate_fee.
DATA(lv_base) = base_fee( iv_pest_type ).
IF lv_base = 0.
CLEAR rv_fee.
RETURN.
ENDIF.
DATA(lv_area_fee) = area_surcharge( iv_area ).
DATA(lv_gross) = lv_base + lv_area_fee + urgent_surcharge( iv_urgent ).
DATA(lv_discount) = contract_discount( iv_base = lv_base
iv_area_fee = lv_area_fee
iv_contract = iv_contract ).
rv_fee = lv_gross - lv_discount.
IF rv_fee < c_minimum_fee.
rv_fee = c_minimum_fee.
ENDIF.
ENDMETHOD.
METHOD base_fee.
CASE iv_pest_type.
WHEN 'RATS'.
rv_fee = 120.
WHEN 'MICE'.
rv_fee = 55.
WHEN 'WASP'.
rv_fee = 150.
WHEN 'ANTS'.
rv_fee = 80.
WHEN OTHERS.
CLEAR rv_fee.
ENDCASE.
ENDMETHOD.
METHOD area_surcharge.
DATA(lv_billable) = iv_area - c_area_free.
IF lv_billable <= 0.
RETURN.
ENDIF.
DATA(lv_steps) = ( lv_billable + c_area_step - 1 ) DIV c_area_step.
rv_fee = lv_steps * c_area_step_fee.
ENDMETHOD.
METHOD urgent_surcharge.
IF iv_urgent = abap_true.
rv_fee = c_urgent_fee.
ENDIF.
ENDMETHOD.
METHOD contract_discount.
IF iv_contract = abap_false.
RETURN.
ENDIF.
DATA(lv_discountable) = iv_base + iv_area_fee.
rv_fee = lv_discountable * c_discount_pct / 100.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,73 @@
CLASS ltc_pest_fee DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA mo_cut TYPE REF TO {{p}}pest_fee.
METHODS setup.
METHODS rats_with_area FOR TESTING.
METHODS mice_base_fee FOR TESTING.
METHODS unknown_pest_is_free FOR TESTING.
METHODS urgent_job FOR TESTING.
METHODS contract_discount FOR TESTING.
METHODS minimum_fee FOR TESTING.
ENDCLASS.
CLASS ltc_pest_fee IMPLEMENTATION.
METHOD setup.
mo_cut = NEW {{p}}pest_fee( ).
ENDMETHOD.
METHOD rats_with_area.
DATA lv_exp TYPE {{p}}pest_fee=>ty_fee.
lv_exp = 135.
cl_abap_unit_assert=>assert_equals(
exp = lv_exp
act = mo_cut->calculate_fee( iv_pest_type = 'RATS' iv_area = 101
iv_urgent = abap_false iv_contract = abap_false ) ).
ENDMETHOD.
METHOD mice_base_fee.
DATA lv_exp TYPE {{p}}pest_fee=>ty_fee.
lv_exp = 55.
cl_abap_unit_assert=>assert_equals(
exp = lv_exp
act = mo_cut->calculate_fee( iv_pest_type = 'MICE' iv_area = 0
iv_urgent = abap_false iv_contract = abap_false ) ).
ENDMETHOD.
METHOD unknown_pest_is_free.
DATA lv_exp TYPE {{p}}pest_fee=>ty_fee.
lv_exp = 0.
cl_abap_unit_assert=>assert_equals(
exp = lv_exp
act = mo_cut->calculate_fee( iv_pest_type = 'BIRD' iv_area = 500
iv_urgent = abap_true iv_contract = abap_true ) ).
ENDMETHOD.
METHOD urgent_job.
DATA lv_exp TYPE {{p}}pest_fee=>ty_fee.
lv_exp = 125.
cl_abap_unit_assert=>assert_equals(
exp = lv_exp
act = mo_cut->calculate_fee( iv_pest_type = 'ANTS' iv_area = 100
iv_urgent = abap_true iv_contract = abap_false ) ).
ENDMETHOD.
METHOD contract_discount.
DATA lv_exp TYPE {{p}}pest_fee=>ty_fee.
lv_exp = 153.
cl_abap_unit_assert=>assert_equals(
exp = lv_exp
act = mo_cut->calculate_fee( iv_pest_type = 'RATS' iv_area = 0
iv_urgent = abap_true iv_contract = abap_true ) ).
ENDMETHOD.
METHOD minimum_fee.
DATA lv_exp TYPE {{p}}pest_fee=>ty_fee.
lv_exp = 50.
cl_abap_unit_assert=>assert_equals(
exp = lv_exp
act = mo_cut->calculate_fee( iv_pest_type = 'MICE' iv_area = 0
iv_urgent = abap_false iv_contract = abap_true ) ).
ENDMETHOD.
ENDCLASS.

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