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

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

View File

@@ -0,0 +1,109 @@
CLASS {{p}}holiday_checker DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_dest_code TYPE string.
TYPES:
BEGIN OF ty_booking,
dest_code TYPE ty_dest_code,
travellers TYPE i,
nights TYPE i,
departure TYPE d,
END OF ty_booking.
METHODS check
IMPORTING is_booking TYPE ty_booking
iv_today TYPE d
RAISING {{p}}cx_holiday_error.
PRIVATE SECTION.
CONSTANTS:
c_min_travellers TYPE i VALUE 1,
c_min_nights TYPE i VALUE 2,
c_max_nights TYPE i VALUE 28,
c_lead_days TYPE i VALUE 14.
METHODS normalize
IMPORTING iv_code TYPE ty_dest_code
RETURNING VALUE(rv_code) TYPE ty_dest_code.
METHODS max_travellers
IMPORTING iv_code TYPE ty_dest_code
RETURNING VALUE(rv_max) TYPE i
RAISING {{p}}cx_unknown_dest.
METHODS check_travellers
IMPORTING is_booking TYPE ty_booking
iv_max TYPE i
RAISING {{p}}cx_holiday_error.
METHODS check_nights
IMPORTING is_booking TYPE ty_booking
RAISING {{p}}cx_holiday_error.
METHODS check_departure
IMPORTING is_booking TYPE ty_booking
iv_today TYPE d
RAISING {{p}}cx_holiday_error.
ENDCLASS.
CLASS {{p}}holiday_checker IMPLEMENTATION.
METHOD check.
DATA(lv_code) = normalize( is_booking-dest_code ).
DATA(lv_max) = max_travellers( lv_code ).
check_travellers( is_booking = is_booking iv_max = lv_max ).
check_nights( is_booking ).
check_departure( is_booking = is_booking iv_today = iv_today ).
ENDMETHOD.
METHOD normalize.
rv_code = to_upper( replace( val = iv_code sub = ` ` with = `` occ = 0 ) ).
ENDMETHOD.
METHOD max_travellers.
CASE iv_code.
WHEN 'ALPS'.
rv_max = 6.
WHEN 'CRETE'.
rv_max = 4.
WHEN 'KYOTO'.
rv_max = 8.
WHEN 'LAPLAND'.
rv_max = 5.
WHEN 'SAFARI'.
rv_max = 7.
WHEN OTHERS.
RAISE EXCEPTION TYPE {{p}}cx_unknown_dest EXPORTING iv_dest = iv_code.
ENDCASE.
ENDMETHOD.
METHOD check_travellers.
IF is_booking-travellers >= c_min_travellers
OR is_booking-travellers > iv_max.
RAISE EXCEPTION TYPE {{p}}cx_bad_travellers
EXPORTING iv_travellers = is_booking-travellers
iv_max = iv_max.
ENDIF.
ENDMETHOD.
METHOD check_nights.
IF is_booking-nights < c_min_nights OR is_booking-nights > c_max_nights.
RAISE EXCEPTION TYPE {{p}}cx_bad_nights
EXPORTING iv_nights = is_booking-nights.
ENDIF.
ENDMETHOD.
METHOD check_departure.
DATA lv_earliest TYPE d.
lv_earliest = iv_today + c_lead_days.
IF is_booking-departure < lv_earliest.
RAISE EXCEPTION TYPE {{p}}cx_bad_departure
EXPORTING iv_departure = is_booking-departure
iv_earliest = lv_earliest.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,109 @@
CLASS {{p}}holiday_checker DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_dest_code TYPE string.
TYPES:
BEGIN OF ty_booking,
dest_code TYPE ty_dest_code,
travellers TYPE i,
nights TYPE i,
departure TYPE d,
END OF ty_booking.
METHODS check
IMPORTING is_booking TYPE ty_booking
iv_today TYPE d
RAISING {{p}}cx_holiday_error.
PRIVATE SECTION.
CONSTANTS:
c_min_travellers TYPE i VALUE 1,
c_min_nights TYPE i VALUE 2,
c_max_nights TYPE i VALUE 28,
c_lead_days TYPE i VALUE 14.
METHODS normalize
IMPORTING iv_code TYPE ty_dest_code
RETURNING VALUE(rv_code) TYPE ty_dest_code.
METHODS max_travellers
IMPORTING iv_code TYPE ty_dest_code
RETURNING VALUE(rv_max) TYPE i
RAISING {{p}}cx_unknown_dest.
METHODS check_travellers
IMPORTING is_booking TYPE ty_booking
iv_max TYPE i
RAISING {{p}}cx_holiday_error.
METHODS check_nights
IMPORTING is_booking TYPE ty_booking
RAISING {{p}}cx_holiday_error.
METHODS check_departure
IMPORTING is_booking TYPE ty_booking
iv_today TYPE d
RAISING {{p}}cx_holiday_error.
ENDCLASS.
CLASS {{p}}holiday_checker IMPLEMENTATION.
METHOD check.
DATA(lv_code) = normalize( is_booking-dest_code ).
DATA(lv_max) = max_travellers( lv_code ).
check_travellers( is_booking = is_booking iv_max = lv_max ).
check_nights( is_booking ).
check_departure( is_booking = is_booking iv_today = iv_today ).
ENDMETHOD.
METHOD normalize.
rv_code = to_upper( replace( val = iv_code sub = ` ` with = `` occ = 0 ) ).
ENDMETHOD.
METHOD max_travellers.
CASE iv_code.
WHEN 'ALPS'.
rv_max = 6.
WHEN 'CRETE'.
rv_max = 4.
WHEN 'KYOTO'.
rv_max = 8.
WHEN 'LAPLAND'.
rv_max = 5.
WHEN 'SAFARI'.
rv_max = 7.
WHEN OTHERS.
RAISE EXCEPTION TYPE {{p}}cx_unknown_dest EXPORTING iv_dest = iv_code.
ENDCASE.
ENDMETHOD.
METHOD check_travellers.
IF is_booking-travellers < c_min_travellers
AND is_booking-travellers > iv_max.
RAISE EXCEPTION TYPE {{p}}cx_bad_travellers
EXPORTING iv_travellers = is_booking-travellers
iv_max = iv_max.
ENDIF.
ENDMETHOD.
METHOD check_nights.
IF is_booking-nights < c_min_nights OR is_booking-nights > c_max_nights.
RAISE EXCEPTION TYPE {{p}}cx_bad_nights
EXPORTING iv_nights = is_booking-nights.
ENDIF.
ENDMETHOD.
METHOD check_departure.
DATA lv_earliest TYPE d.
lv_earliest = iv_today + c_lead_days.
IF is_booking-departure < lv_earliest.
RAISE EXCEPTION TYPE {{p}}cx_bad_departure
EXPORTING iv_departure = is_booking-departure
iv_earliest = lv_earliest.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,109 @@
CLASS {{p}}holiday_checker DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_dest_code TYPE string.
TYPES:
BEGIN OF ty_booking,
dest_code TYPE ty_dest_code,
travellers TYPE i,
nights TYPE i,
departure TYPE d,
END OF ty_booking.
METHODS check
IMPORTING is_booking TYPE ty_booking
iv_today TYPE d
RAISING {{p}}cx_holiday_error.
PRIVATE SECTION.
CONSTANTS:
c_min_travellers TYPE i VALUE 1,
c_min_nights TYPE i VALUE 2,
c_max_nights TYPE i VALUE 28,
c_lead_days TYPE i VALUE 14.
METHODS normalize
IMPORTING iv_code TYPE ty_dest_code
RETURNING VALUE(rv_code) TYPE ty_dest_code.
METHODS max_travellers
IMPORTING iv_code TYPE ty_dest_code
RETURNING VALUE(rv_max) TYPE i
RAISING {{p}}cx_unknown_dest.
METHODS check_travellers
IMPORTING is_booking TYPE ty_booking
iv_max TYPE i
RAISING {{p}}cx_holiday_error.
METHODS check_nights
IMPORTING is_booking TYPE ty_booking
RAISING {{p}}cx_holiday_error.
METHODS check_departure
IMPORTING is_booking TYPE ty_booking
iv_today TYPE d
RAISING {{p}}cx_holiday_error.
ENDCLASS.
CLASS {{p}}holiday_checker IMPLEMENTATION.
METHOD check.
DATA(lv_code) = normalize( is_booking-dest_code ).
DATA(lv_max) = max_travellers( lv_code ).
check_travellers( is_booking = is_booking iv_max = lv_max ).
check_nights( is_booking ).
check_departure( is_booking = is_booking iv_today = iv_today ).
ENDMETHOD.
METHOD normalize.
rv_code = to_upper( replace( val = iv_code sub = ` ` with = `` occ = 0 ) ).
ENDMETHOD.
METHOD max_travellers.
CASE iv_code.
WHEN 'ALPS'.
rv_max = 6.
WHEN 'CRETE'.
rv_max = 4.
WHEN 'KYOTO'.
rv_max = 8.
WHEN 'LAPLAND'.
rv_max = 5.
WHEN 'SAFARI'.
rv_max = 7.
WHEN OTHERS.
RAISE EXCEPTION TYPE {{p}}cx_unknown_dest EXPORTING iv_dest = iv_code.
ENDCASE.
ENDMETHOD.
METHOD check_travellers.
IF is_booking-travellers < c_min_travellers
OR is_booking-travellers > iv_max.
RAISE EXCEPTION TYPE {{p}}cx_bad_travellers
EXPORTING iv_travellers = is_booking-travellers
iv_max = iv_max.
ENDIF.
ENDMETHOD.
METHOD check_nights.
IF is_booking-nights >= c_min_nights OR is_booking-nights > c_max_nights.
RAISE EXCEPTION TYPE {{p}}cx_bad_nights
EXPORTING iv_nights = is_booking-nights.
ENDIF.
ENDMETHOD.
METHOD check_departure.
DATA lv_earliest TYPE d.
lv_earliest = iv_today + c_lead_days.
IF is_booking-departure < lv_earliest.
RAISE EXCEPTION TYPE {{p}}cx_bad_departure
EXPORTING iv_departure = is_booking-departure
iv_earliest = lv_earliest.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,109 @@
CLASS {{p}}holiday_checker DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_dest_code TYPE string.
TYPES:
BEGIN OF ty_booking,
dest_code TYPE ty_dest_code,
travellers TYPE i,
nights TYPE i,
departure TYPE d,
END OF ty_booking.
METHODS check
IMPORTING is_booking TYPE ty_booking
iv_today TYPE d
RAISING {{p}}cx_holiday_error.
PRIVATE SECTION.
CONSTANTS:
c_min_travellers TYPE i VALUE 1,
c_min_nights TYPE i VALUE 2,
c_max_nights TYPE i VALUE 28,
c_lead_days TYPE i VALUE 14.
METHODS normalize
IMPORTING iv_code TYPE ty_dest_code
RETURNING VALUE(rv_code) TYPE ty_dest_code.
METHODS max_travellers
IMPORTING iv_code TYPE ty_dest_code
RETURNING VALUE(rv_max) TYPE i
RAISING {{p}}cx_unknown_dest.
METHODS check_travellers
IMPORTING is_booking TYPE ty_booking
iv_max TYPE i
RAISING {{p}}cx_holiday_error.
METHODS check_nights
IMPORTING is_booking TYPE ty_booking
RAISING {{p}}cx_holiday_error.
METHODS check_departure
IMPORTING is_booking TYPE ty_booking
iv_today TYPE d
RAISING {{p}}cx_holiday_error.
ENDCLASS.
CLASS {{p}}holiday_checker IMPLEMENTATION.
METHOD check.
DATA(lv_code) = normalize( is_booking-dest_code ).
DATA(lv_max) = max_travellers( lv_code ).
check_travellers( is_booking = is_booking iv_max = lv_max ).
check_nights( is_booking ).
check_departure( is_booking = is_booking iv_today = iv_today ).
ENDMETHOD.
METHOD normalize.
rv_code = to_upper( replace( val = iv_code sub = ` ` with = `` occ = 0 ) ).
ENDMETHOD.
METHOD max_travellers.
CASE iv_code.
WHEN 'ALPS'.
rv_max = 6.
WHEN 'CRETE'.
rv_max = 4.
WHEN 'KYOTO'.
rv_max = 8.
WHEN 'LAPLAND'.
rv_max = 5.
WHEN 'SAFARI'.
rv_max = 7.
WHEN OTHERS.
RAISE EXCEPTION TYPE {{p}}cx_unknown_dest EXPORTING iv_dest = iv_code.
ENDCASE.
ENDMETHOD.
METHOD check_travellers.
IF is_booking-travellers < c_min_travellers
OR is_booking-travellers > iv_max.
RAISE EXCEPTION TYPE {{p}}cx_bad_travellers
EXPORTING iv_travellers = is_booking-travellers
iv_max = iv_max.
ENDIF.
ENDMETHOD.
METHOD check_nights.
IF is_booking-nights < c_min_nights OR is_booking-nights <= c_max_nights.
RAISE EXCEPTION TYPE {{p}}cx_bad_nights
EXPORTING iv_nights = is_booking-nights.
ENDIF.
ENDMETHOD.
METHOD check_departure.
DATA lv_earliest TYPE d.
lv_earliest = iv_today + c_lead_days.
IF is_booking-departure < lv_earliest.
RAISE EXCEPTION TYPE {{p}}cx_bad_departure
EXPORTING iv_departure = is_booking-departure
iv_earliest = lv_earliest.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,109 @@
CLASS {{p}}holiday_checker DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_dest_code TYPE string.
TYPES:
BEGIN OF ty_booking,
dest_code TYPE ty_dest_code,
travellers TYPE i,
nights TYPE i,
departure TYPE d,
END OF ty_booking.
METHODS check
IMPORTING is_booking TYPE ty_booking
iv_today TYPE d
RAISING {{p}}cx_holiday_error.
PRIVATE SECTION.
CONSTANTS:
c_min_travellers TYPE i VALUE 1,
c_min_nights TYPE i VALUE 2,
c_max_nights TYPE i VALUE 28,
c_lead_days TYPE i VALUE 14.
METHODS normalize
IMPORTING iv_code TYPE ty_dest_code
RETURNING VALUE(rv_code) TYPE ty_dest_code.
METHODS max_travellers
IMPORTING iv_code TYPE ty_dest_code
RETURNING VALUE(rv_max) TYPE i
RAISING {{p}}cx_unknown_dest.
METHODS check_travellers
IMPORTING is_booking TYPE ty_booking
iv_max TYPE i
RAISING {{p}}cx_holiday_error.
METHODS check_nights
IMPORTING is_booking TYPE ty_booking
RAISING {{p}}cx_holiday_error.
METHODS check_departure
IMPORTING is_booking TYPE ty_booking
iv_today TYPE d
RAISING {{p}}cx_holiday_error.
ENDCLASS.
CLASS {{p}}holiday_checker IMPLEMENTATION.
METHOD check.
DATA(lv_code) = normalize( is_booking-dest_code ).
DATA(lv_max) = max_travellers( lv_code ).
check_travellers( is_booking = is_booking iv_max = lv_max ).
check_nights( is_booking ).
check_departure( is_booking = is_booking iv_today = iv_today ).
ENDMETHOD.
METHOD normalize.
rv_code = to_upper( replace( val = iv_code sub = ` ` with = `` occ = 0 ) ).
ENDMETHOD.
METHOD max_travellers.
CASE iv_code.
WHEN 'ALPS'.
rv_max = 6.
WHEN 'CRETE'.
rv_max = 4.
WHEN 'KYOTO'.
rv_max = 8.
WHEN 'LAPLAND'.
rv_max = 5.
WHEN 'SAFARI'.
rv_max = 7.
WHEN OTHERS.
RAISE EXCEPTION TYPE {{p}}cx_unknown_dest EXPORTING iv_dest = iv_code.
ENDCASE.
ENDMETHOD.
METHOD check_travellers.
IF is_booking-travellers < c_min_travellers
OR is_booking-travellers > iv_max.
RAISE EXCEPTION TYPE {{p}}cx_bad_travellers
EXPORTING iv_travellers = is_booking-travellers
iv_max = iv_max.
ENDIF.
ENDMETHOD.
METHOD check_nights.
IF is_booking-nights < c_min_nights OR is_booking-nights > c_max_nights.
RAISE EXCEPTION TYPE {{p}}cx_bad_nights
EXPORTING iv_nights = is_booking-nights.
ENDIF.
ENDMETHOD.
METHOD check_departure.
DATA lv_earliest TYPE d.
lv_earliest = iv_today - c_lead_days.
IF is_booking-departure < lv_earliest.
RAISE EXCEPTION TYPE {{p}}cx_bad_departure
EXPORTING iv_departure = is_booking-departure
iv_earliest = lv_earliest.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,24 @@
{
"id": "G1024",
"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,184 @@
CLASS {{p}}holiday_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
CONSTANTS c_today TYPE d VALUE '20260101'.
DATA mo_cut TYPE REF TO {{p}}holiday_checker.
METHODS setup.
METHODS valid_booking FOR TESTING.
METHODS minimum_values FOR TESTING.
METHODS lower_case_code FOR TESTING.
METHODS unknown_destination FOR TESTING.
METHODS too_many_travellers FOR TESTING.
METHODS zero_travellers FOR TESTING.
METHODS bad_nights FOR TESTING.
METHODS too_early_departure FOR TESTING.
METHODS dest_rule_comes_first FOR TESTING.
METHODS nights_rule_comes_first FOR TESTING.
ENDCLASS.
CLASS {{p}}holiday_hidden IMPLEMENTATION.
METHOD setup.
mo_cut = NEW {{p}}holiday_checker( ).
ENDMETHOD.
METHOD valid_booking.
DATA(lv_done) = abap_false.
TRY.
mo_cut->check( is_booking = VALUE #( dest_code = 'ALPS'
travellers = 6
nights = 7
departure = '20260201' )
iv_today = c_today ).
lv_done = abap_true.
CATCH {{p}}cx_holiday_error INTO DATA(lx).
cl_abap_unit_assert=>fail( |Unexpected exception: { lx->mv_message }| ).
ENDTRY.
cl_abap_unit_assert=>assert_equals( exp = abap_true act = lv_done ).
ENDMETHOD.
METHOD minimum_values.
DATA(lv_done) = abap_false.
TRY.
mo_cut->check( is_booking = VALUE #( dest_code = 'LAPLAND'
travellers = 1
nights = 2
departure = '20260115' )
iv_today = c_today ).
lv_done = abap_true.
CATCH {{p}}cx_holiday_error INTO DATA(lx).
cl_abap_unit_assert=>fail( |Unexpected exception: { lx->mv_message }| ).
ENDTRY.
cl_abap_unit_assert=>assert_equals( exp = abap_true act = lv_done ).
ENDMETHOD.
METHOD lower_case_code.
DATA(lv_done) = abap_false.
TRY.
mo_cut->check( is_booking = VALUE #( dest_code = ' kyoto '
travellers = 8
nights = 14
departure = '20260301' )
iv_today = c_today ).
lv_done = abap_true.
CATCH {{p}}cx_holiday_error INTO DATA(lx).
cl_abap_unit_assert=>fail( |Unexpected exception: { lx->mv_message }| ).
ENDTRY.
cl_abap_unit_assert=>assert_equals( exp = abap_true act = lv_done ).
ENDMETHOD.
METHOD unknown_destination.
TRY.
mo_cut->check( is_booking = VALUE #( dest_code = 'MARS'
travellers = 2
nights = 7
departure = '20260201' )
iv_today = c_today ).
cl_abap_unit_assert=>fail( 'CX_UNKNOWN_DEST expected' ).
CATCH {{p}}cx_unknown_dest INTO DATA(lx).
cl_abap_unit_assert=>assert_equals( exp = `MARS` act = lx->mv_dest ).
cl_abap_unit_assert=>assert_equals( exp = `Destination is not offered`
act = lx->mv_message ).
CATCH {{p}}cx_holiday_error.
cl_abap_unit_assert=>fail( 'Wrong exception type' ).
ENDTRY.
ENDMETHOD.
METHOD too_many_travellers.
TRY.
mo_cut->check( is_booking = VALUE #( dest_code = 'CRETE'
travellers = 5
nights = 7
departure = '20260201' )
iv_today = c_today ).
cl_abap_unit_assert=>fail( 'CX_BAD_TRAVELLERS expected' ).
CATCH {{p}}cx_bad_travellers INTO DATA(lx).
cl_abap_unit_assert=>assert_equals( exp = 5 act = lx->mv_travellers ).
cl_abap_unit_assert=>assert_equals( exp = 4 act = lx->mv_max ).
CATCH {{p}}cx_holiday_error.
cl_abap_unit_assert=>fail( 'Wrong exception type' ).
ENDTRY.
ENDMETHOD.
METHOD zero_travellers.
TRY.
mo_cut->check( is_booking = VALUE #( dest_code = 'ALPS'
travellers = 0
nights = 7
departure = '20260201' )
iv_today = c_today ).
cl_abap_unit_assert=>fail( 'CX_BAD_TRAVELLERS expected' ).
CATCH {{p}}cx_bad_travellers INTO DATA(lx).
cl_abap_unit_assert=>assert_equals( exp = 0 act = lx->mv_travellers ).
cl_abap_unit_assert=>assert_equals( exp = 6 act = lx->mv_max ).
CATCH {{p}}cx_holiday_error.
cl_abap_unit_assert=>fail( 'Wrong exception type' ).
ENDTRY.
ENDMETHOD.
METHOD bad_nights.
TRY.
mo_cut->check( is_booking = VALUE #( dest_code = 'ALPS'
travellers = 2
nights = 29
departure = '20260201' )
iv_today = c_today ).
cl_abap_unit_assert=>fail( 'CX_BAD_NIGHTS expected' ).
CATCH {{p}}cx_bad_nights INTO DATA(lx).
cl_abap_unit_assert=>assert_equals( exp = 29 act = lx->mv_nights ).
CATCH {{p}}cx_holiday_error.
cl_abap_unit_assert=>fail( 'Wrong exception type' ).
ENDTRY.
ENDMETHOD.
METHOD too_early_departure.
TRY.
mo_cut->check( is_booking = VALUE #( dest_code = 'SAFARI'
travellers = 3
nights = 7
departure = '20260114' )
iv_today = c_today ).
cl_abap_unit_assert=>fail( 'CX_BAD_DEPARTURE expected' ).
CATCH {{p}}cx_bad_departure INTO DATA(lx).
cl_abap_unit_assert=>assert_equals( exp = CONV d( '20260114' )
act = lx->mv_departure ).
cl_abap_unit_assert=>assert_equals( exp = CONV d( '20260115' )
act = lx->mv_earliest ).
cl_abap_unit_assert=>assert_equals( exp = `Departure date is too early`
act = lx->mv_message ).
CATCH {{p}}cx_holiday_error.
cl_abap_unit_assert=>fail( 'Wrong exception type' ).
ENDTRY.
ENDMETHOD.
METHOD dest_rule_comes_first.
TRY.
mo_cut->check( is_booking = VALUE #( dest_code = 'MARS'
travellers = 99
nights = 99
departure = '20200101' )
iv_today = c_today ).
cl_abap_unit_assert=>fail( 'CX_UNKNOWN_DEST expected' ).
CATCH {{p}}cx_unknown_dest.
CATCH {{p}}cx_holiday_error.
cl_abap_unit_assert=>fail( 'Wrong exception type' ).
ENDTRY.
ENDMETHOD.
METHOD nights_rule_comes_first.
TRY.
mo_cut->check( is_booking = VALUE #( dest_code = 'ALPS'
travellers = 2
nights = 99
departure = '20200101' )
iv_today = c_today ).
cl_abap_unit_assert=>fail( 'CX_BAD_NIGHTS expected' ).
CATCH {{p}}cx_bad_nights.
CATCH {{p}}cx_holiday_error.
cl_abap_unit_assert=>fail( 'Wrong exception type' ).
ENDTRY.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,69 @@
{
"task": "G1024",
"mutants": [
{
"object": "{{P}}HOLIDAY_CHECKER",
"mutant": "line 85: < -> >= (rel)",
"status": "killed",
"hidden": "3/10",
"failed_tests": [
"BAD_NIGHTS",
"LOWER_CASE_CODE",
"MINIMUM_VALUES",
"NIGHTS_RULE_COMES_FIRST",
"TOO_EARLY_DEPARTURE",
"VALID_BOOKING",
"ZERO_TRAVELLERS"
]
},
{
"object": "{{P}}HOLIDAY_CHECKER",
"mutant": "line 86: OR -> AND (logic)",
"status": "killed",
"hidden": "8/10",
"failed_tests": [
"TOO_MANY_TRAVELLERS",
"ZERO_TRAVELLERS"
]
},
{
"object": "{{P}}HOLIDAY_CHECKER",
"mutant": "line 94: < -> >= (rel)",
"status": "killed",
"hidden": "6/10",
"failed_tests": [
"LOWER_CASE_CODE",
"MINIMUM_VALUES",
"TOO_EARLY_DEPARTURE",
"VALID_BOOKING"
]
},
{
"object": "{{P}}HOLIDAY_CHECKER",
"mutant": "line 94: > -> <= (rel)",
"status": "killed",
"hidden": "4/10",
"failed_tests": [
"BAD_NIGHTS",
"LOWER_CASE_CODE",
"MINIMUM_VALUES",
"NIGHTS_RULE_COMES_FIRST",
"TOO_EARLY_DEPARTURE",
"VALID_BOOKING"
]
},
{
"object": "{{P}}HOLIDAY_CHECKER",
"mutant": "line 102: + -> - (arith)",
"status": "killed",
"hidden": "9/10",
"failed_tests": [
"TOO_EARLY_DEPARTURE"
]
}
],
"valid": 5,
"killed": 5,
"kill_rate": 1.0,
"ok": true
}

View File

@@ -0,0 +1,25 @@
CLASS {{p}}cx_bad_departure DEFINITION
PUBLIC
FINAL
INHERITING FROM {{p}}cx_holiday_error
CREATE PUBLIC.
PUBLIC SECTION.
DATA mv_departure TYPE d READ-ONLY.
DATA mv_earliest TYPE d READ-ONLY.
METHODS constructor
IMPORTING iv_departure TYPE d
iv_earliest TYPE d.
PRIVATE SECTION.
ENDCLASS.
CLASS {{p}}cx_bad_departure IMPLEMENTATION.
METHOD constructor.
super->constructor( iv_message = 'Departure date is too early' ).
mv_departure = iv_departure.
mv_earliest = iv_earliest.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,22 @@
CLASS {{p}}cx_bad_nights DEFINITION
PUBLIC
FINAL
INHERITING FROM {{p}}cx_holiday_error
CREATE PUBLIC.
PUBLIC SECTION.
DATA mv_nights TYPE i READ-ONLY.
METHODS constructor
IMPORTING iv_nights TYPE i.
PRIVATE SECTION.
ENDCLASS.
CLASS {{p}}cx_bad_nights IMPLEMENTATION.
METHOD constructor.
super->constructor( iv_message = 'Number of nights is not allowed' ).
mv_nights = iv_nights.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,25 @@
CLASS {{p}}cx_bad_travellers DEFINITION
PUBLIC
FINAL
INHERITING FROM {{p}}cx_holiday_error
CREATE PUBLIC.
PUBLIC SECTION.
DATA mv_travellers TYPE i READ-ONLY.
DATA mv_max TYPE i READ-ONLY.
METHODS constructor
IMPORTING iv_travellers TYPE i
iv_max TYPE i.
PRIVATE SECTION.
ENDCLASS.
CLASS {{p}}cx_bad_travellers IMPLEMENTATION.
METHOD constructor.
super->constructor( iv_message = 'Number of travellers is not allowed' ).
mv_travellers = iv_travellers.
mv_max = iv_max.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,22 @@
CLASS {{p}}cx_unknown_dest DEFINITION
PUBLIC
FINAL
INHERITING FROM {{p}}cx_holiday_error
CREATE PUBLIC.
PUBLIC SECTION.
DATA mv_dest TYPE string READ-ONLY.
METHODS constructor
IMPORTING iv_dest TYPE string.
PRIVATE SECTION.
ENDCLASS.
CLASS {{p}}cx_unknown_dest IMPLEMENTATION.
METHOD constructor.
super->constructor( iv_message = 'Destination is not offered' ).
mv_dest = iv_dest.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,109 @@
CLASS {{p}}holiday_checker DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_dest_code TYPE string.
TYPES:
BEGIN OF ty_booking,
dest_code TYPE ty_dest_code,
travellers TYPE i,
nights TYPE i,
departure TYPE d,
END OF ty_booking.
METHODS check
IMPORTING is_booking TYPE ty_booking
iv_today TYPE d
RAISING {{p}}cx_holiday_error.
PRIVATE SECTION.
CONSTANTS:
c_min_travellers TYPE i VALUE 1,
c_min_nights TYPE i VALUE 2,
c_max_nights TYPE i VALUE 28,
c_lead_days TYPE i VALUE 14.
METHODS normalize
IMPORTING iv_code TYPE ty_dest_code
RETURNING VALUE(rv_code) TYPE ty_dest_code.
METHODS max_travellers
IMPORTING iv_code TYPE ty_dest_code
RETURNING VALUE(rv_max) TYPE i
RAISING {{p}}cx_unknown_dest.
METHODS check_travellers
IMPORTING is_booking TYPE ty_booking
iv_max TYPE i
RAISING {{p}}cx_holiday_error.
METHODS check_nights
IMPORTING is_booking TYPE ty_booking
RAISING {{p}}cx_holiday_error.
METHODS check_departure
IMPORTING is_booking TYPE ty_booking
iv_today TYPE d
RAISING {{p}}cx_holiday_error.
ENDCLASS.
CLASS {{p}}holiday_checker IMPLEMENTATION.
METHOD check.
DATA(lv_code) = normalize( is_booking-dest_code ).
DATA(lv_max) = max_travellers( lv_code ).
check_travellers( is_booking = is_booking iv_max = lv_max ).
check_nights( is_booking ).
check_departure( is_booking = is_booking iv_today = iv_today ).
ENDMETHOD.
METHOD normalize.
rv_code = to_upper( replace( val = iv_code sub = ` ` with = `` occ = 0 ) ).
ENDMETHOD.
METHOD max_travellers.
CASE iv_code.
WHEN 'ALPS'.
rv_max = 6.
WHEN 'CRETE'.
rv_max = 4.
WHEN 'KYOTO'.
rv_max = 8.
WHEN 'LAPLAND'.
rv_max = 5.
WHEN 'SAFARI'.
rv_max = 7.
WHEN OTHERS.
RAISE EXCEPTION TYPE {{p}}cx_unknown_dest EXPORTING iv_dest = iv_code.
ENDCASE.
ENDMETHOD.
METHOD check_travellers.
IF is_booking-travellers < c_min_travellers
OR is_booking-travellers > iv_max.
RAISE EXCEPTION TYPE {{p}}cx_bad_travellers
EXPORTING iv_travellers = is_booking-travellers
iv_max = iv_max.
ENDIF.
ENDMETHOD.
METHOD check_nights.
IF is_booking-nights < c_min_nights OR is_booking-nights > c_max_nights.
RAISE EXCEPTION TYPE {{p}}cx_bad_nights
EXPORTING iv_nights = is_booking-nights.
ENDIF.
ENDMETHOD.
METHOD check_departure.
DATA lv_earliest TYPE d.
lv_earliest = iv_today + c_lead_days.
IF is_booking-departure < lv_earliest.
RAISE EXCEPTION TYPE {{p}}cx_bad_departure
EXPORTING iv_departure = is_booking-departure
iv_earliest = lv_earliest.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,115 @@
CLASS ltc_holiday_checker DEFINITION FINAL FOR TESTING
DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
CONSTANTS c_today TYPE d VALUE '20260101'.
DATA mo_cut TYPE REF TO {{p}}holiday_checker.
METHODS setup.
METHODS valid_booking FOR TESTING.
METHODS minimum_values FOR TESTING.
METHODS unknown_destination FOR TESTING.
METHODS too_many_travellers FOR TESTING.
METHODS bad_nights FOR TESTING.
METHODS early_departure FOR TESTING.
ENDCLASS.
CLASS ltc_holiday_checker IMPLEMENTATION.
METHOD setup.
mo_cut = NEW {{p}}holiday_checker( ).
ENDMETHOD.
METHOD valid_booking.
DATA(lv_done) = abap_false.
TRY.
mo_cut->check( is_booking = VALUE #( dest_code = 'KYOTO'
travellers = 8
nights = 10
departure = '20260301' )
iv_today = c_today ).
lv_done = abap_true.
CATCH {{p}}cx_holiday_error INTO DATA(lx).
cl_abap_unit_assert=>fail( |Unexpected exception: { lx->mv_message }| ).
ENDTRY.
cl_abap_unit_assert=>assert_equals( exp = abap_true act = lv_done ).
ENDMETHOD.
METHOD minimum_values.
DATA(lv_done) = abap_false.
TRY.
mo_cut->check( is_booking = VALUE #( dest_code = 'LAPLAND'
travellers = 1
nights = 2
departure = '20260115' )
iv_today = c_today ).
lv_done = abap_true.
CATCH {{p}}cx_holiday_error INTO DATA(lx).
cl_abap_unit_assert=>fail( |Unexpected exception: { lx->mv_message }| ).
ENDTRY.
cl_abap_unit_assert=>assert_equals( exp = abap_true act = lv_done ).
ENDMETHOD.
METHOD unknown_destination.
TRY.
mo_cut->check( is_booking = VALUE #( dest_code = 'MARS'
travellers = 2
nights = 7
departure = '20260301' )
iv_today = c_today ).
cl_abap_unit_assert=>fail( 'CX_UNKNOWN_DEST expected' ).
CATCH {{p}}cx_unknown_dest INTO DATA(lx).
cl_abap_unit_assert=>assert_equals( exp = `MARS` act = lx->mv_dest ).
CATCH {{p}}cx_holiday_error.
cl_abap_unit_assert=>fail( 'Wrong exception type' ).
ENDTRY.
ENDMETHOD.
METHOD too_many_travellers.
TRY.
mo_cut->check( is_booking = VALUE #( dest_code = 'SAFARI'
travellers = 8
nights = 7
departure = '20260301' )
iv_today = c_today ).
cl_abap_unit_assert=>fail( 'CX_BAD_TRAVELLERS expected' ).
CATCH {{p}}cx_bad_travellers INTO DATA(lx).
cl_abap_unit_assert=>assert_equals( exp = 8 act = lx->mv_travellers ).
cl_abap_unit_assert=>assert_equals( exp = 7 act = lx->mv_max ).
CATCH {{p}}cx_holiday_error.
cl_abap_unit_assert=>fail( 'Wrong exception type' ).
ENDTRY.
ENDMETHOD.
METHOD bad_nights.
TRY.
mo_cut->check( is_booking = VALUE #( dest_code = 'ALPS'
travellers = 2
nights = 30
departure = '20260301' )
iv_today = c_today ).
cl_abap_unit_assert=>fail( 'CX_BAD_NIGHTS expected' ).
CATCH {{p}}cx_bad_nights INTO DATA(lx).
cl_abap_unit_assert=>assert_equals( exp = 30 act = lx->mv_nights ).
CATCH {{p}}cx_holiday_error.
cl_abap_unit_assert=>fail( 'Wrong exception type' ).
ENDTRY.
ENDMETHOD.
METHOD early_departure.
TRY.
mo_cut->check( is_booking = VALUE #( dest_code = 'CRETE'
travellers = 2
nights = 7
departure = '20260110' )
iv_today = c_today ).
cl_abap_unit_assert=>fail( 'CX_BAD_DEPARTURE expected' ).
CATCH {{p}}cx_bad_departure INTO DATA(lx).
cl_abap_unit_assert=>assert_equals( exp = CONV d( '20260115' )
act = lx->mv_earliest ).
CATCH {{p}}cx_holiday_error.
cl_abap_unit_assert=>fail( 'Wrong exception type' ).
ENDTRY.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,22 @@
CLASS {{p}}cx_holiday_error DEFINITION
PUBLIC
ABSTRACT
INHERITING FROM cx_static_check
CREATE PUBLIC.
PUBLIC SECTION.
DATA mv_message TYPE string READ-ONLY.
METHODS constructor
IMPORTING iv_message TYPE string.
PRIVATE SECTION.
ENDCLASS.
CLASS {{p}}cx_holiday_error IMPLEMENTATION.
METHOD constructor.
super->constructor( ).
mv_message = iv_message.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,97 @@
# 1. Goal
A tour operator checks a holiday booking before it confirms the booking. The
booking desk calls one check method for each booking. The check method reports
each problem as a class-based exception. Each exception carries a message and
the values that caused the problem.
# 2. Open questions
None.
# 3. Context
- Class {{P}}CX_HOLIDAY_ERROR exists in package $TMP. It is active. It is
abstract and inherits from cx_static_check. It has the public read-only
attribute mv_message TYPE string and a public constructor with the importing
parameter iv_message TYPE string. The constructor sets mv_message.
- The tour operator offers five destinations. The destination code and the
maximum number of travellers of each destination are:
ALPS 6, CRETE 4, KYOTO 8, LAPLAND 5, SAFARI 7.
- The booking desk passes the booking and the current date to the check method.
- A booking has a destination code, a number of travellers, a number of nights,
and a departure date.
# 4. Contract
Create these five classes in package $TMP. Do not change {{P}}CX_HOLIDAY_ERROR.
1. Class {{P}}HOLIDAY_CHECKER
- The class is public and final. It has a public constructor without
parameters.
- Public type ty_dest_code, type string.
- Public type ty_booking, a structure with these components:
dest_code TYPE ty_dest_code, travellers TYPE i, nights TYPE i,
departure TYPE d.
- Public method check with this signature:
IMPORTING is_booking TYPE ty_booking
iv_today TYPE d
RAISING {{P}}CX_HOLIDAY_ERROR
- Do not add other public methods.
2. Class {{P}}CX_UNKNOWN_DEST
- The class is final and inherits from {{P}}CX_HOLIDAY_ERROR.
- Public read-only attribute mv_dest TYPE string.
- Public constructor with the importing parameter iv_dest TYPE string.
- mv_message is 'Destination is not offered'.
- mv_dest holds the normalized destination code. The value has no leading or
trailing blanks.
3. Class {{P}}CX_BAD_TRAVELLERS
- The class is final and inherits from {{P}}CX_HOLIDAY_ERROR.
- Public read-only attributes mv_travellers TYPE i and mv_max TYPE i.
- Public constructor with the importing parameters iv_travellers TYPE i and
iv_max TYPE i.
- mv_message is 'Number of travellers is not allowed'.
4. Class {{P}}CX_BAD_NIGHTS
- The class is final and inherits from {{P}}CX_HOLIDAY_ERROR.
- Public read-only attribute mv_nights TYPE i.
- Public constructor with the importing parameter iv_nights TYPE i.
- mv_message is 'Number of nights is not allowed'.
5. Class {{P}}CX_BAD_DEPARTURE
- The class is final and inherits from {{P}}CX_HOLIDAY_ERROR.
- Public read-only attributes mv_departure TYPE d and mv_earliest TYPE d.
- Public constructor with the importing parameters iv_departure TYPE d and
iv_earliest TYPE d.
- mv_message is 'Departure date is too early'.
# 5. Business rules
The method check applies these rules in this sequence. The method raises the
exception of the first rule that fails. If no rule fails, the method returns
without an exception.
1. Normalize the destination code: remove all spaces and convert all letters to
upper case.
2. The normalized code must be ALPS, CRETE, KYOTO, LAPLAND, or SAFARI. If it is
not, raise {{P}}CX_UNKNOWN_DEST. Pass the normalized code in iv_dest.
3. The number of travellers must be 1 or more. It must not be more than the
maximum number of travellers of the destination. If a value is not correct,
raise {{P}}CX_BAD_TRAVELLERS. Pass the number of travellers in iv_travellers
and the maximum of the destination in iv_max.
4. The number of nights must be 2 or more. It must not be more than 28. If a
value is not correct, raise {{P}}CX_BAD_NIGHTS. Pass the number of nights in
iv_nights.
5. The departure date must be at least 14 days after iv_today. If it is not,
raise {{P}}CX_BAD_DEPARTURE. Pass the departure date in iv_departure and the
earliest possible date (iv_today plus 14 days) in iv_earliest.
# 6. Constraints
- Release target: SAP_BASIS 816 (ABAP Platform 2025).
- Coding standards: Clean ABAP. Methods below 40 statements. No global
variables. No comment that restates the code.
- Out of scope: do not change {{P}}CX_HOLIDAY_ERROR. Do not create a database
table, a CDS view entity, a function module, or a report. Do not change the
signature of check.
# 7. Acceptance
- All five classes are active and have no syntax error.
- The hidden tests pass.
- Write your own ABAP Unit tests for {{P}}HOLIDAY_CHECKER.

View File

@@ -0,0 +1,94 @@
{
"id": "G1024",
"category": "D",
"object_type": "CLAS",
"difficulty": 2,
"release_target": "v816",
"expected_outcome": "implement",
"budget": {
"max_tool_calls": 80,
"max_activations": 20
},
"seed": [
{
"type": "CLAS",
"name": "{{P}}CX_HOLIDAY_ERROR",
"file": "seed/cx_holiday_error.clas.abap",
"description": "Abstract base exception that carries a message"
}
],
"contract": [
{
"type": "CLAS",
"name": "{{P}}HOLIDAY_CHECKER"
},
{
"type": "CLAS",
"name": "{{P}}CX_UNKNOWN_DEST"
},
{
"type": "CLAS",
"name": "{{P}}CX_BAD_TRAVELLERS"
},
{
"type": "CLAS",
"name": "{{P}}CX_BAD_NIGHTS"
},
{
"type": "CLAS",
"name": "{{P}}CX_BAD_DEPARTURE"
}
],
"out_of_scope": [
"{{P}}CX_HOLIDAY_ERROR",
"database tables",
"CDS view entities",
"function modules",
"reports"
],
"hidden_tests": [
{
"type": "CLAS",
"name": "{{P}}HOLIDAY_HIDDEN",
"file": "hidden/holiday_hidden.clas.abap",
"description": "T07 hidden tests"
}
],
"reference": [
{
"type": "CLAS",
"name": "{{P}}CX_UNKNOWN_DEST",
"file": "reference/cx_unknown_dest.clas.abap",
"description": "Unknown destination exception"
},
{
"type": "CLAS",
"name": "{{P}}CX_BAD_TRAVELLERS",
"file": "reference/cx_bad_travellers.clas.abap",
"description": "Bad traveller count exception"
},
{
"type": "CLAS",
"name": "{{P}}CX_BAD_NIGHTS",
"file": "reference/cx_bad_nights.clas.abap",
"description": "Bad night count exception"
},
{
"type": "CLAS",
"name": "{{P}}CX_BAD_DEPARTURE",
"file": "reference/cx_bad_departure.clas.abap",
"description": "Departure date too early exception"
},
{
"type": "CLAS",
"name": "{{P}}HOLIDAY_CHECKER",
"file": "reference/holiday_checker.clas.abap",
"description": "Holiday booking checker",
"testclasses_file": "reference/holiday_checker.testclasses.abap"
}
],
"craft_checks": [
"method_length",
"db_operation_in_loop"
]
}