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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,56 @@
# 1. Goal
Calculate the overdue fine of a returned library item. The lending desk calls the
calculation before it prints the receipt. The result gives the days overdue, the
chargeable days, and the fine.
# 2. Open questions
None.
# 3. Context
- Package $TMP contains no object for this task.
- The class is new. No other object is necessary.
# 4. Contract
- Create the class {{P}}OVERDUE_FINE in package $TMP.
- The class is public and final. You can create it with NEW {{P}}OVERDUE_FINE( )
without parameters.
- The class has these public types:
- TY_MEDIA: character field, length 8.
- TY_AMOUNT: packed number, length 8, 2 decimal places.
- TY_RESULT: structure with the components DAYS_OVERDUE (type i),
CHARGEABLE_DAYS (type i), and FINE (type TY_AMOUNT).
- The class has one public method:
CALCULATE
IMPORTING iv_due_date TYPE d
iv_return_date TYPE d
iv_media TYPE ty_media
RETURNING VALUE(rs_result) TYPE ty_result.
- Do not add other public methods or public components.
# 5. Business rules
Apply the rules in this sequence.
1. If iv_return_date is earlier than or equal to iv_due_date, return
DAYS_OVERDUE = 0, CHARGEABLE_DAYS = 0, and FINE = 0.00. Stop.
2. DAYS_OVERDUE is the number of calendar days from iv_due_date to iv_return_date.
3. The media code gives the daily rate and the grace days:
- BOOK: daily rate 0.30, grace 7 days
- DVD: daily rate 1.50, grace 2 days
- GAME: daily rate 2.50, grace 0 days
Compare the media code exactly. If the media code is not in this list, return
CHARGEABLE_DAYS = 0 and FINE = 0.00. Keep DAYS_OVERDUE from rule 2. Stop.
4. CHARGEABLE_DAYS is DAYS_OVERDUE minus the grace days. If this value is less
than 0, CHARGEABLE_DAYS is 0.
5. FINE is CHARGEABLE_DAYS multiplied by the daily rate.
6. If DAYS_OVERDUE is greater than 30, add a reminder fee of 5.00 to FINE.
7. If FINE is greater than 25.00, FINE is 25.00.
# 6. Constraints
- Release target: SAP_BASIS 816 (ABAP Platform 2025).
- Coding standards: Clean ABAP. Method length below 40 statements. No global
variables. No comment that restates the code.
- Out of scope: no other object.
# 7. Acceptance
- The class is active and has no syntax error.
- The hidden tests pass.
- Write your own ABAP Unit tests for the class.

View File

@@ -0,0 +1,41 @@
{
"id": "G0103",
"category": "A",
"object_type": "CLAS",
"difficulty": 2,
"release_target": "v816",
"expected_outcome": "implement",
"budget": {
"max_tool_calls": 40,
"max_activations": 10
},
"seed": [],
"contract": [
{
"type": "CLAS",
"name": "{{P}}OVERDUE_FINE"
}
],
"out_of_scope": [],
"hidden_tests": [
{
"type": "CLAS",
"name": "{{P}}T02_HIDDEN",
"file": "hidden/t02_hidden.clas.abap",
"description": "T02 hidden tests for the overdue fine calculation"
}
],
"reference": [
{
"type": "CLAS",
"name": "{{P}}OVERDUE_FINE",
"file": "reference/overdue_fine.clas.abap",
"description": "Overdue fine calculation for a library item",
"testclasses_file": "reference/overdue_fine.testclasses.abap"
}
],
"craft_checks": [
"method_length",
"db_operation_in_loop"
]
}