Snapshot: new training tasks (balanced generation), docs

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Kral
2026-10-05 22:08:59 +02:00
parent eb13453097
commit 6984fc7917
572 changed files with 30024 additions and 0 deletions

View File

@@ -0,0 +1,19 @@
@EndUserText.label : 'Cider pressing batch'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table {{p}}cider {
key client : abap.clnt not null;
batch_id : abap.char(10) not null;
orchard_id : abap.char(6) not null;
apple_variety : abap.char(20);
pressed_on : abap.dats;
bin_count : abap.int4;
apple_kg : abap.dec(13,3);
juice_l : abap.dec(13,3);
@Semantics.amount.currencyCode : '{{p}}cider.currency_code'
press_fee : abap.curr(15,2);
currency_code : abap.cuky;
grade : abap.char(2);
}

View File

@@ -0,0 +1,19 @@
@EndUserText.label : 'Cider pressing batch'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table {{p}}cider {
key client : abap.clnt not null;
key batch_id : abap.char(10) not null;
orchard_id : abap.numc(6) not null;
apple_variety : abap.char(20);
pressed_on : abap.dats;
bin_count : abap.int4;
apple_kg : abap.dec(13,3);
juice_l : abap.dec(13,3);
@Semantics.amount.currencyCode : '{{p}}cider.currency_code'
press_fee : abap.curr(15,2);
currency_code : abap.cuky;
grade : abap.char(2);
}

View File

@@ -0,0 +1,19 @@
@EndUserText.label : 'Cider pressing batch'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table {{p}}cider {
key client : abap.clnt not null;
key batch_id : abap.char(10) not null;
orchard_id : abap.char(5) not null;
apple_variety : abap.char(20);
pressed_on : abap.dats;
bin_count : abap.int4;
apple_kg : abap.dec(13,3);
juice_l : abap.dec(13,3);
@Semantics.amount.currencyCode : '{{p}}cider.currency_code'
press_fee : abap.curr(15,2);
currency_code : abap.cuky;
grade : abap.char(2);
}

View File

@@ -0,0 +1,19 @@
@EndUserText.label : 'Cider pressing batch'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table {{p}}cider {
key client : abap.clnt not null;
key batch_id : abap.char(10) not null;
orchard_id : abap.char(6) not null;
apple_variety : abap.char(19);
pressed_on : abap.dats;
bin_count : abap.int4;
apple_kg : abap.dec(13,3);
juice_l : abap.dec(13,3);
@Semantics.amount.currencyCode : '{{p}}cider.currency_code'
press_fee : abap.curr(15,2);
currency_code : abap.cuky;
grade : abap.char(2);
}

View File

@@ -0,0 +1,19 @@
@EndUserText.label : 'Cider pressing batch'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table {{p}}cider {
key client : abap.clnt not null;
key batch_id : abap.char(10) not null;
orchard_id : abap.char(6) not null;
apple_variety : abap.char(20);
pressed_on : abap.dats;
bin_count : abap.int4;
apple_kg : abap.dec(13,3);
juice_l : abap.dec(13,3);
@Semantics.amount.currencyCode : '{{p}}cider.currency_code'
press_fee : abap.curr(15,3);
currency_code : abap.cuky;
grade : abap.char(2);
}

View File

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

View File

@@ -0,0 +1,157 @@
CLASS {{p}}cider_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
TYPES ty_name TYPE c LENGTH 30.
CLASS-DATA go_env TYPE REF TO if_osql_test_environment.
CLASS-METHODS class_setup.
CLASS-METHODS class_teardown.
METHODS setup.
METHODS field_of
IMPORTING iv_name TYPE ty_name
RETURNING VALUE(rs_field) TYPE dfies.
METHODS field_names FOR TESTING.
METHODS key_fields FOR TESTING.
METHODS not_null_fields FOR TESTING.
METHODS char_lengths FOR TESTING.
METHODS numeric_types FOR TESTING.
METHODS decimals FOR TESTING.
METHODS insert_and_read FOR TESTING.
METHODS duplicate_key FOR TESTING.
ENDCLASS.
CLASS {{p}}cider_hidden IMPLEMENTATION.
METHOD class_setup.
go_env = cl_osql_test_environment=>create(
i_dependency_list = VALUE #( ( '{{P}}CIDER' ) ) ).
ENDMETHOD.
METHOD class_teardown.
go_env->destroy( ).
ENDMETHOD.
METHOD setup.
go_env->clear_doubles( ).
ENDMETHOD.
METHOD field_of.
DATA(lo_struct) = CAST cl_abap_structdescr(
cl_abap_typedescr=>describe_by_name( '{{P}}CIDER' ) ).
DATA(lt_fields) = lo_struct->get_ddic_field_list( ).
READ TABLE lt_fields INTO rs_field WITH KEY fieldname = iv_name.
cl_abap_unit_assert=>assert_subrc( exp = 0 act = sy-subrc
msg = |Field { iv_name } is missing| ).
ENDMETHOD.
METHOD field_names.
DATA(lo_struct) = CAST cl_abap_structdescr(
cl_abap_typedescr=>describe_by_name( '{{P}}CIDER' ) ).
DATA(lt_fields) = lo_struct->get_ddic_field_list( ).
cl_abap_unit_assert=>assert_equals( exp = 11 act = lines( lt_fields ) ).
DATA lt_expected TYPE STANDARD TABLE OF ty_name WITH EMPTY KEY.
lt_expected = VALUE #(
( 'CLIENT' ) ( 'BATCH_ID' ) ( 'ORCHARD_ID' ) ( 'APPLE_VARIETY' )
( 'PRESSED_ON' ) ( 'BIN_COUNT' ) ( 'APPLE_KG' ) ( 'JUICE_L' )
( 'PRESS_FEE' ) ( 'CURRENCY_CODE' ) ( 'GRADE' ) ).
LOOP AT lt_expected INTO DATA(lv_name).
READ TABLE lt_fields TRANSPORTING NO FIELDS WITH KEY fieldname = lv_name.
cl_abap_unit_assert=>assert_subrc( exp = 0 act = sy-subrc
msg = |Field { lv_name } is missing| ).
ENDLOOP.
ENDMETHOD.
METHOD key_fields.
cl_abap_unit_assert=>assert_equals( exp = 'X' act = field_of( 'CLIENT' )-keyflag ).
cl_abap_unit_assert=>assert_equals( exp = 'X' act = field_of( 'BATCH_ID' )-keyflag ).
cl_abap_unit_assert=>assert_equals( exp = ' ' act = field_of( 'ORCHARD_ID' )-keyflag ).
cl_abap_unit_assert=>assert_equals( exp = ' ' act = field_of( 'PRESS_FEE' )-keyflag ).
ENDMETHOD.
METHOD not_null_fields.
DATA lt_expected TYPE STANDARD TABLE OF ty_name WITH EMPTY KEY.
lt_expected = VALUE #( ( 'CLIENT' ) ( 'BATCH_ID' ) ( 'ORCHARD_ID' ) ).
LOOP AT lt_expected INTO DATA(lv_name).
DATA(ls_field) = field_of( lv_name ).
ASSIGN COMPONENT 'NOT_NULL' OF STRUCTURE ls_field TO FIELD-SYMBOL(<lv_flag>).
IF sy-subrc = 0.
cl_abap_unit_assert=>assert_equals( exp = 'X' act = <lv_flag>
msg = |Field { lv_name } must be not null| ).
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD char_lengths.
cl_abap_unit_assert=>assert_equals( exp = 3 act = CONV i( field_of( 'CLIENT' )-leng ) ).
cl_abap_unit_assert=>assert_equals( exp = 10 act = CONV i( field_of( 'BATCH_ID' )-leng ) ).
cl_abap_unit_assert=>assert_equals( exp = 6 act = CONV i( field_of( 'ORCHARD_ID' )-leng ) ).
cl_abap_unit_assert=>assert_equals( exp = 20 act = CONV i( field_of( 'APPLE_VARIETY' )-leng ) ).
cl_abap_unit_assert=>assert_equals( exp = 5 act = CONV i( field_of( 'CURRENCY_CODE' )-leng ) ).
cl_abap_unit_assert=>assert_equals( exp = 2 act = CONV i( field_of( 'GRADE' )-leng ) ).
ENDMETHOD.
METHOD numeric_types.
cl_abap_unit_assert=>assert_equals( exp = 'CLNT' act = field_of( 'CLIENT' )-datatype ).
cl_abap_unit_assert=>assert_equals( exp = 'CHAR' act = field_of( 'BATCH_ID' )-datatype ).
cl_abap_unit_assert=>assert_equals( exp = 'DATS' act = field_of( 'PRESSED_ON' )-datatype ).
cl_abap_unit_assert=>assert_equals( exp = 'INT4' act = field_of( 'BIN_COUNT' )-datatype ).
cl_abap_unit_assert=>assert_equals( exp = 'CURR' act = field_of( 'PRESS_FEE' )-datatype ).
cl_abap_unit_assert=>assert_equals( exp = 'CUKY' act = field_of( 'CURRENCY_CODE' )-datatype ).
ENDMETHOD.
METHOD decimals.
cl_abap_unit_assert=>assert_equals( exp = 13 act = CONV i( field_of( 'APPLE_KG' )-leng ) ).
cl_abap_unit_assert=>assert_equals( exp = 3 act = CONV i( field_of( 'APPLE_KG' )-decimals ) ).
cl_abap_unit_assert=>assert_equals( exp = 13 act = CONV i( field_of( 'JUICE_L' )-leng ) ).
cl_abap_unit_assert=>assert_equals( exp = 3 act = CONV i( field_of( 'JUICE_L' )-decimals ) ).
cl_abap_unit_assert=>assert_equals( exp = 15 act = CONV i( field_of( 'PRESS_FEE' )-leng ) ).
cl_abap_unit_assert=>assert_equals( exp = 2 act = CONV i( field_of( 'PRESS_FEE' )-decimals ) ).
ENDMETHOD.
METHOD insert_and_read.
DATA lt_batch TYPE STANDARD TABLE OF {{p}}cider WITH EMPTY KEY.
lt_batch = VALUE #(
( batch_id = 'B000000001' orchard_id = 'OR0001' apple_variety = 'ELSTAR'
pressed_on = '20250801' bin_count = 12 apple_kg = '480.500'
juice_l = '320.250' press_fee = '125.50' currency_code = 'EUR'
grade = 'A1' )
( batch_id = 'B000000002' orchard_id = 'OR0002' apple_variety = 'GALA'
pressed_on = '20250802' bin_count = 8 apple_kg = '310.000'
juice_l = '205.000' press_fee = '80.00' currency_code = 'EUR'
grade = 'B2' ) ).
INSERT {{p}}cider FROM TABLE @lt_batch.
cl_abap_unit_assert=>assert_subrc( exp = 0 ).
SELECT SINGLE orchard_id, bin_count, apple_kg, press_fee, currency_code, grade
FROM {{p}}cider
WHERE batch_id = 'B000000001'
INTO @DATA(ls_row).
cl_abap_unit_assert=>assert_subrc( exp = 0 ).
cl_abap_unit_assert=>assert_equals( exp = 'OR0001' act = ls_row-orchard_id ).
cl_abap_unit_assert=>assert_equals( exp = 12 act = ls_row-bin_count ).
cl_abap_unit_assert=>assert_equals(
exp = CONV decfloat34( '480.5' ) act = CONV decfloat34( ls_row-apple_kg ) ).
cl_abap_unit_assert=>assert_equals(
exp = CONV decfloat34( '125.50' ) act = CONV decfloat34( ls_row-press_fee ) ).
cl_abap_unit_assert=>assert_equals( exp = 'EUR' act = ls_row-currency_code ).
cl_abap_unit_assert=>assert_equals( exp = 'A1' act = ls_row-grade ).
ENDMETHOD.
METHOD duplicate_key.
DATA ls_batch TYPE {{p}}cider.
ls_batch-batch_id = 'B000000009'.
ls_batch-orchard_id = 'OR0009'.
INSERT {{p}}cider FROM @ls_batch.
cl_abap_unit_assert=>assert_subrc( exp = 0 ).
INSERT {{p}}cider FROM @ls_batch.
cl_abap_unit_assert=>assert_equals( exp = 4 act = sy-subrc ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,56 @@
{
"task": "G1910",
"mutants": [
{
"object": "{{P}}CIDER",
"mutant": "line 8: key batch_id : -> batch_id : (key)",
"status": "killed",
"hidden": "6/8",
"failed_tests": [
"INSERT_AND_READ",
"KEY_FIELDS"
]
},
{
"object": "{{P}}CIDER",
"mutant": "line 9: abap.char(6) -> abap.numc(6) (type)",
"status": "killed",
"hidden": "7/8",
"failed_tests": [
"INSERT_AND_READ"
]
},
{
"object": "{{P}}CIDER",
"mutant": "line 9: abap.char(6) -> abap.char(5) (length)",
"status": "killed",
"hidden": "6/8",
"failed_tests": [
"CHAR_LENGTHS",
"INSERT_AND_READ"
]
},
{
"object": "{{P}}CIDER",
"mutant": "line 10: abap.char(20) -> abap.char(19) (length)",
"status": "killed",
"hidden": "7/8",
"failed_tests": [
"CHAR_LENGTHS"
]
},
{
"object": "{{P}}CIDER",
"mutant": "line 16: abap.curr(15,2) -> abap.curr(15,3) (decimals)",
"status": "killed",
"hidden": "7/8",
"failed_tests": [
"DECIMALS"
]
}
],
"valid": 5,
"killed": 5,
"kill_rate": 1.0,
"ok": true
}

View File

@@ -0,0 +1,19 @@
@EndUserText.label : 'Cider pressing batch'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table {{p}}cider {
key client : abap.clnt not null;
key batch_id : abap.char(10) not null;
orchard_id : abap.char(6) not null;
apple_variety : abap.char(20);
pressed_on : abap.dats;
bin_count : abap.int4;
apple_kg : abap.dec(13,3);
juice_l : abap.dec(13,3);
@Semantics.amount.currencyCode : '{{p}}cider.currency_code'
press_fee : abap.curr(15,2);
currency_code : abap.cuky;
grade : abap.char(2);
}

View File

@@ -0,0 +1,58 @@
CLASS {{p}}cider_test DEFINITION PUBLIC FINAL CREATE PUBLIC
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
CLASS-DATA go_env TYPE REF TO if_osql_test_environment.
CLASS-METHODS class_setup.
CLASS-METHODS class_teardown.
METHODS setup.
METHODS stores_batch FOR TESTING.
METHODS rejects_duplicate FOR TESTING.
ENDCLASS.
CLASS {{p}}cider_test IMPLEMENTATION.
METHOD class_setup.
go_env = cl_osql_test_environment=>create(
i_dependency_list = VALUE #( ( '{{P}}CIDER' ) ) ).
ENDMETHOD.
METHOD class_teardown.
go_env->destroy( ).
ENDMETHOD.
METHOD setup.
go_env->clear_doubles( ).
ENDMETHOD.
METHOD stores_batch.
DATA ls_batch TYPE {{p}}cider.
ls_batch-batch_id = 'B000000001'.
ls_batch-orchard_id = 'OR0001'.
ls_batch-apple_kg = '480.500'.
ls_batch-press_fee = '125.50'.
ls_batch-currency_code = 'EUR'.
INSERT {{p}}cider FROM @ls_batch.
cl_abap_unit_assert=>assert_subrc( exp = 0 ).
SELECT SINGLE orchard_id, apple_kg FROM {{p}}cider
WHERE batch_id = 'B000000001'
INTO @DATA(ls_read).
cl_abap_unit_assert=>assert_subrc( exp = 0 ).
cl_abap_unit_assert=>assert_equals( exp = 'OR0001' act = ls_read-orchard_id ).
cl_abap_unit_assert=>assert_equals(
exp = CONV decfloat34( '480.5' ) act = CONV decfloat34( ls_read-apple_kg ) ).
ENDMETHOD.
METHOD rejects_duplicate.
DATA ls_batch TYPE {{p}}cider.
ls_batch-batch_id = 'B000000002'.
INSERT {{p}}cider FROM @ls_batch.
cl_abap_unit_assert=>assert_subrc( exp = 0 ).
INSERT {{p}}cider FROM @ls_batch.
cl_abap_unit_assert=>assert_equals( exp = 4 act = sy-subrc ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,51 @@
# 1. Goal
The cider press house of a fruit cooperative records each pressing batch of
apple deliveries. Create the database table that stores these batches. A press
terminal writes the batches and a reporting tool reads them. The field names,
the data types and the key must be exactly as agreed.
# 2. Open questions
None.
# 3. Context
- The table is in package $TMP.
- The press house receives apples from the member orchards.
- One pressing batch comes from one orchard.
- The press house charges a fee for each pressing. The fee is money.
# 4. Contract
- Create the transparent database table {{P}}CIDER in package $TMP as a DDL
source.
- The table has these fields, with these names: CLIENT, BATCH_ID, ORCHARD_ID,
APPLE_VARIETY, PRESSED_ON, BIN_COUNT, APPLE_KG, JUICE_L, PRESS_FEE,
CURRENCY_CODE, GRADE.
- The table has no other fields.
- The key of the table is CLIENT and BATCH_ID.
# 5. Business rules
1. CLIENT is the client field of the table (CLNT, 3 characters). It is a key
field. It is not null.
2. BATCH_ID is the number of the pressing batch (CHAR 10). It is a key field.
It is not null.
3. ORCHARD_ID is the number of the orchard that delivered the apples (CHAR 6).
It is not null.
4. APPLE_VARIETY is the name of the apple variety (CHAR 20).
5. PRESSED_ON is the date of the pressing (DATS, 8 characters).
6. BIN_COUNT is the number of apple bins of the batch (INT4).
7. APPLE_KG is the weight of the apples in kilograms (DEC 13,3).
8. JUICE_L is the volume of the juice in litres (DEC 13,3).
9. PRESS_FEE is the fee of the pressing (CURR 15,2). It is an amount in the
currency that CURRENCY_CODE gives.
10. CURRENCY_CODE is the currency key (CUKY, 5 characters).
11. GRADE is the quality grade of the juice (CHAR 2).
# 6. Constraints
- Release target: 8.16 (SAP_BASIS 816).
- Coding standards: Clean ABAP.
- Out of scope: do not create other tables, views, classes or programs. Create
only the table and your own test class.
# 7. Acceptance
- The table is active and has no syntax error.
- The hidden tests pass.
- Write ABAP Unit tests with CL_OSQL_TEST_ENVIRONMENT in a global test class.

View File

@@ -0,0 +1,56 @@
{
"id": "G1910",
"category": "B",
"object_type": "TABL",
"difficulty": 2,
"release_target": "v816",
"expected_outcome": "implement",
"budget": {
"max_tool_calls": 60,
"max_activations": 15
},
"seed": [],
"contract": [
{
"type": "TABL",
"name": "{{P}}CIDER",
"fields": [
"client",
"batch_id",
"orchard_id",
"apple_variety",
"pressed_on",
"bin_count",
"apple_kg",
"juice_l",
"press_fee",
"currency_code",
"grade"
]
}
],
"out_of_scope": [],
"hidden_tests": [
{
"type": "CLAS",
"name": "{{P}}CIDER_HIDDEN",
"file": "hidden/cider_hidden.clas.abap",
"description": "Hidden tests for the cider pressing batch table"
}
],
"reference": [
{
"type": "TABL",
"name": "{{P}}CIDER",
"file": "reference/cider.tabl.asabap",
"description": "Cider pressing batch table"
},
{
"type": "CLAS",
"name": "{{P}}CIDER_TEST",
"file": "reference/cider_test.clas.abap",
"description": "Own tests for the table"
}
],
"craft_checks": []
}

View File

@@ -0,0 +1,19 @@
@EndUserText.label : 'Beach item hire'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table {{p}}hire {
key client : abap.clnt not null;
hire_id : abap.numc(10) not null;
kiosk_id : abap.char(6) not null;
hire_date : abap.dats not null;
item_type : abap.char(4);
item_count : abap.int4;
hire_days : abap.int4;
@Semantics.amount.currencyCode : '{{p}}hire.currency_code'
daily_rate : abap.dec(13,2);
currency_code : abap.cuky;
customer_name : abap.char(30);
is_returned : abap.char(1);
}

View File

@@ -0,0 +1,19 @@
@EndUserText.label : 'Beach item hire'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table {{p}}hire {
key client : abap.clnt not null;
key hire_id : abap.numc(10) not null;
kiosk_id : abap.char(5) not null;
hire_date : abap.dats not null;
item_type : abap.char(4);
item_count : abap.int4;
hire_days : abap.int4;
@Semantics.amount.currencyCode : '{{p}}hire.currency_code'
daily_rate : abap.dec(13,2);
currency_code : abap.cuky;
customer_name : abap.char(30);
is_returned : abap.char(1);
}

View File

@@ -0,0 +1,19 @@
@EndUserText.label : 'Beach item hire'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table {{p}}hire {
key client : abap.clnt not null;
key hire_id : abap.numc(10) not null;
kiosk_id : abap.char(6) not null;
hire_date : abap.dats not null;
item_type : abap.char(4);
item_count : abap.int8;
hire_days : abap.int4;
@Semantics.amount.currencyCode : '{{p}}hire.currency_code'
daily_rate : abap.dec(13,2);
currency_code : abap.cuky;
customer_name : abap.char(30);
is_returned : abap.char(1);
}

View File

@@ -0,0 +1,19 @@
@EndUserText.label : 'Beach item hire'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table {{p}}hire {
key client : abap.clnt not null;
key hire_id : abap.numc(10) not null;
kiosk_id : abap.char(6) not null;
hire_date : abap.dats not null;
item_type : abap.char(4);
item_count : abap.int4;
hire_days : abap.int4;
@Semantics.amount.currencyCode : '{{p}}hire.currency_code'
daily_rate : abap.dec(13,3);
currency_code : abap.cuky;
customer_name : abap.char(30);
is_returned : abap.char(1);
}

View File

@@ -0,0 +1,19 @@
@EndUserText.label : 'Beach item hire'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table {{p}}hire {
key client : abap.clnt not null;
key hire_id : abap.numc(10) not null;
kiosk_id : abap.char(6) not null;
hire_date : abap.dats not null;
item_type : abap.char(4);
item_count : abap.int4;
hire_days : abap.int4;
@Semantics.amount.currencyCode : '{{p}}hire.currency_code'
daily_rate : abap.dec(13,2);
currency_code : abap.cuky;
customer_name : abap.numc(30);
is_returned : abap.char(1);
}

View File

@@ -0,0 +1,24 @@
{
"id": "G1911",
"pool": "train",
"object_type": "TABL",
"category": "B",
"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,231 @@
CLASS {{p}}hire_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
CLASS-DATA go_env TYPE REF TO if_osql_test_environment.
CLASS-METHODS class_setup.
CLASS-METHODS class_teardown.
METHODS setup.
METHODS get_fields RETURNING VALUE(rt_fields) TYPE dfies_table.
METHODS field_of
IMPORTING iv_name TYPE fieldname
RETURNING VALUE(rs_field) TYPE dfies.
METHODS is_key
IMPORTING iv_name TYPE fieldname
RETURNING VALUE(rv_is_key) TYPE abap_bool.
METHODS is_not_null
IMPORTING iv_name TYPE fieldname
RETURNING VALUE(rv_not_null) TYPE abap_bool.
METHODS fields_exist FOR TESTING.
METHODS key_fields FOR TESTING.
METHODS not_null_fields FOR TESTING.
METHODS lengths_in_chars FOR TESTING.
METHODS decimals_of_rate FOR TESTING.
METHODS field_types FOR TESTING.
METHODS insert_and_read FOR TESTING.
METHODS duplicate_key FOR TESTING.
METHODS select_by_kiosk FOR TESTING.
ENDCLASS.
CLASS {{p}}hire_hidden IMPLEMENTATION.
METHOD class_setup.
go_env = cl_osql_test_environment=>create(
i_dependency_list = VALUE #( ( '{{P}}HIRE' ) ) ).
ENDMETHOD.
METHOD class_teardown.
go_env->destroy( ).
ENDMETHOD.
METHOD setup.
go_env->clear_doubles( ).
ENDMETHOD.
METHOD get_fields.
DATA(lo_struct) = CAST cl_abap_structdescr(
cl_abap_typedescr=>describe_by_name( '{{P}}HIRE' ) ).
rt_fields = lo_struct->get_ddic_field_list( ).
ENDMETHOD.
METHOD field_of.
DATA(lt_fields) = get_fields( ).
READ TABLE lt_fields INTO rs_field WITH KEY fieldname = iv_name.
IF sy-subrc <> 0.
cl_abap_unit_assert=>fail( msg = |The field { iv_name } is missing| ).
ENDIF.
ENDMETHOD.
METHOD is_key.
DATA(ls_field) = field_of( iv_name ).
IF ls_field-keyflag = 'X'.
rv_is_key = abap_true.
ENDIF.
ENDMETHOD.
METHOD is_not_null.
DATA(ls_field) = field_of( iv_name ).
ASSIGN COMPONENT 'NOTNULL' OF STRUCTURE ls_field TO FIELD-SYMBOL(<lv_flag>).
IF sy-subrc <> 0.
ASSIGN COMPONENT 'NOT_NULL' OF STRUCTURE ls_field TO <lv_flag>.
ENDIF.
IF sy-subrc = 0.
IF <lv_flag> = 'X'.
rv_not_null = abap_true.
ENDIF.
ENDIF.
ENDMETHOD.
METHOD fields_exist.
DATA(lt_fields) = get_fields( ).
cl_abap_unit_assert=>assert_equals( exp = 11 act = lines( lt_fields ) ).
DATA lt_names TYPE STANDARD TABLE OF fieldname WITH EMPTY KEY.
lt_names = VALUE #( ( 'CLIENT' ) ( 'HIRE_ID' ) ( 'KIOSK_ID' )
( 'HIRE_DATE' ) ( 'ITEM_TYPE' ) ( 'ITEM_COUNT' )
( 'HIRE_DAYS' ) ( 'DAILY_RATE' ) ( 'CURRENCY_CODE' )
( 'CUSTOMER_NAME' ) ( 'IS_RETURNED' ) ).
LOOP AT lt_names INTO DATA(lv_name).
READ TABLE lt_fields TRANSPORTING NO FIELDS WITH KEY fieldname = lv_name.
cl_abap_unit_assert=>assert_equals(
exp = 0 act = sy-subrc msg = |The field { lv_name } is missing| ).
ENDLOOP.
ENDMETHOD.
METHOD key_fields.
cl_abap_unit_assert=>assert_equals( exp = abap_true act = is_key( 'CLIENT' ) ).
cl_abap_unit_assert=>assert_equals( exp = abap_true act = is_key( 'HIRE_ID' ) ).
cl_abap_unit_assert=>assert_equals( exp = abap_false act = is_key( 'KIOSK_ID' ) ).
cl_abap_unit_assert=>assert_equals( exp = abap_false act = is_key( 'HIRE_DATE' ) ).
cl_abap_unit_assert=>assert_equals( exp = abap_false act = is_key( 'DAILY_RATE' ) ).
ENDMETHOD.
METHOD not_null_fields.
DATA(ls_field) = field_of( 'KIOSK_ID' ).
ASSIGN COMPONENT 'NOTNULL' OF STRUCTURE ls_field TO FIELD-SYMBOL(<lv_flag>).
IF sy-subrc <> 0.
RETURN.
ENDIF.
cl_abap_unit_assert=>assert_equals( exp = 'X' act = <lv_flag> ).
cl_abap_unit_assert=>assert_equals( exp = abap_true act = is_not_null( 'HIRE_ID' ) ).
cl_abap_unit_assert=>assert_equals( exp = abap_true act = is_not_null( 'HIRE_DATE' ) ).
cl_abap_unit_assert=>assert_equals( exp = abap_false act = is_not_null( 'ITEM_TYPE' ) ).
cl_abap_unit_assert=>assert_equals( exp = abap_false act = is_not_null( 'DAILY_RATE' ) ).
cl_abap_unit_assert=>assert_equals( exp = abap_false act = is_not_null( 'CUSTOMER_NAME' ) ).
ENDMETHOD.
METHOD lengths_in_chars.
DATA(ls_field) = field_of( 'CLIENT' ).
cl_abap_unit_assert=>assert_equals( exp = 3 act = CONV i( ls_field-leng ) ).
ls_field = field_of( 'HIRE_ID' ).
cl_abap_unit_assert=>assert_equals( exp = 10 act = CONV i( ls_field-leng ) ).
ls_field = field_of( 'KIOSK_ID' ).
cl_abap_unit_assert=>assert_equals( exp = 6 act = CONV i( ls_field-leng ) ).
ls_field = field_of( 'HIRE_DATE' ).
cl_abap_unit_assert=>assert_equals( exp = 8 act = CONV i( ls_field-leng ) ).
ls_field = field_of( 'ITEM_TYPE' ).
cl_abap_unit_assert=>assert_equals( exp = 4 act = CONV i( ls_field-leng ) ).
ls_field = field_of( 'ITEM_COUNT' ).
cl_abap_unit_assert=>assert_equals( exp = 10 act = CONV i( ls_field-leng ) ).
ls_field = field_of( 'HIRE_DAYS' ).
cl_abap_unit_assert=>assert_equals( exp = 10 act = CONV i( ls_field-leng ) ).
ls_field = field_of( 'DAILY_RATE' ).
cl_abap_unit_assert=>assert_equals( exp = 13 act = CONV i( ls_field-leng ) ).
ls_field = field_of( 'CURRENCY_CODE' ).
cl_abap_unit_assert=>assert_equals( exp = 5 act = CONV i( ls_field-leng ) ).
ls_field = field_of( 'CUSTOMER_NAME' ).
cl_abap_unit_assert=>assert_equals( exp = 30 act = CONV i( ls_field-leng ) ).
ls_field = field_of( 'IS_RETURNED' ).
cl_abap_unit_assert=>assert_equals( exp = 1 act = CONV i( ls_field-leng ) ).
ENDMETHOD.
METHOD decimals_of_rate.
DATA(ls_field) = field_of( 'DAILY_RATE' ).
cl_abap_unit_assert=>assert_equals( exp = 2 act = CONV i( ls_field-decimals ) ).
ls_field = field_of( 'ITEM_COUNT' ).
cl_abap_unit_assert=>assert_equals( exp = 0 act = CONV i( ls_field-decimals ) ).
ls_field = field_of( 'HIRE_DAYS' ).
cl_abap_unit_assert=>assert_equals( exp = 0 act = CONV i( ls_field-decimals ) ).
ENDMETHOD.
METHOD field_types.
DATA(ls_field) = field_of( 'CLIENT' ).
cl_abap_unit_assert=>assert_equals( exp = 'CLNT' act = ls_field-datatype ).
ls_field = field_of( 'HIRE_ID' ).
cl_abap_unit_assert=>assert_equals( exp = 'NUMC' act = ls_field-datatype ).
ls_field = field_of( 'KIOSK_ID' ).
cl_abap_unit_assert=>assert_equals( exp = 'CHAR' act = ls_field-datatype ).
ls_field = field_of( 'HIRE_DATE' ).
cl_abap_unit_assert=>assert_equals( exp = 'DATS' act = ls_field-datatype ).
ls_field = field_of( 'ITEM_TYPE' ).
cl_abap_unit_assert=>assert_equals( exp = 'CHAR' act = ls_field-datatype ).
ls_field = field_of( 'ITEM_COUNT' ).
cl_abap_unit_assert=>assert_equals( exp = 'INT4' act = ls_field-datatype ).
ls_field = field_of( 'HIRE_DAYS' ).
cl_abap_unit_assert=>assert_equals( exp = 'INT4' act = ls_field-datatype ).
ls_field = field_of( 'DAILY_RATE' ).
cl_abap_unit_assert=>assert_equals( exp = 'DEC' act = ls_field-datatype(3) ).
ls_field = field_of( 'CURRENCY_CODE' ).
cl_abap_unit_assert=>assert_equals( exp = 'CUKY' act = ls_field-datatype ).
ls_field = field_of( 'CUSTOMER_NAME' ).
cl_abap_unit_assert=>assert_equals( exp = 'CHAR' act = ls_field-datatype ).
ls_field = field_of( 'IS_RETURNED' ).
cl_abap_unit_assert=>assert_equals( exp = 'CHAR' act = ls_field-datatype ).
ENDMETHOD.
METHOD insert_and_read.
DATA lt_hire TYPE STANDARD TABLE OF {{p}}hire WITH EMPTY KEY.
DATA lv_date TYPE d.
DATA lv_curr TYPE c LENGTH 5.
lv_date = '20250701'.
lv_curr = 'EUR'.
lt_hire = VALUE #(
( hire_id = '0000000001' kiosk_id = 'K1' hire_date = '20250701'
item_type = 'CHAI' item_count = 2 hire_days = 3
daily_rate = '4.50' currency_code = 'EUR'
customer_name = 'SMITH' is_returned = 'X' )
( hire_id = '0000000002' kiosk_id = 'K2' hire_date = '20250702'
item_type = 'PARA' item_count = 1 hire_days = 1
daily_rate = '6.00' currency_code = 'EUR'
customer_name = 'JONES' is_returned = ' ' ) ).
go_env->insert_test_data( lt_hire ).
SELECT SINGLE hire_id, kiosk_id, hire_date, item_type, item_count,
hire_days, daily_rate, currency_code, customer_name,
is_returned
FROM {{p}}hire
WHERE hire_id = '0000000001'
INTO @DATA(ls_hire).
cl_abap_unit_assert=>assert_equals( exp = '0000000001' act = ls_hire-hire_id ).
cl_abap_unit_assert=>assert_equals( exp = 'K1' act = ls_hire-kiosk_id ).
cl_abap_unit_assert=>assert_equals( exp = lv_date act = ls_hire-hire_date ).
cl_abap_unit_assert=>assert_equals( exp = 'CHAI' act = ls_hire-item_type ).
cl_abap_unit_assert=>assert_equals( exp = 2 act = ls_hire-item_count ).
cl_abap_unit_assert=>assert_equals( exp = 3 act = ls_hire-hire_days ).
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '4.50' )
act = CONV decfloat34( ls_hire-daily_rate ) ).
cl_abap_unit_assert=>assert_equals( exp = lv_curr act = ls_hire-currency_code ).
cl_abap_unit_assert=>assert_equals( exp = 'SMITH' act = ls_hire-customer_name ).
cl_abap_unit_assert=>assert_equals( exp = 'X' act = ls_hire-is_returned ).
ENDMETHOD.
METHOD duplicate_key.
DATA ls_hire TYPE {{p}}hire.
ls_hire-hire_id = '0000000009'.
ls_hire-kiosk_id = 'K9'.
ls_hire-hire_date = '20250703'.
INSERT {{p}}hire FROM @ls_hire.
INSERT {{p}}hire FROM @ls_hire.
cl_abap_unit_assert=>assert_equals( exp = 4 act = sy-subrc ).
ENDMETHOD.
METHOD select_by_kiosk.
DATA lt_hire TYPE STANDARD TABLE OF {{p}}hire WITH EMPTY KEY.
lt_hire = VALUE #(
( hire_id = '0000000011' kiosk_id = 'K1' hire_date = '20250704' )
( hire_id = '0000000012' kiosk_id = 'K1' hire_date = '20250704' )
( hire_id = '0000000013' kiosk_id = 'K2' hire_date = '20250704' ) ).
go_env->insert_test_data( lt_hire ).
SELECT COUNT(*) FROM {{p}}hire WHERE kiosk_id = 'K1' INTO @DATA(lv_count).
cl_abap_unit_assert=>assert_equals( exp = 2 act = lv_count ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,58 @@
{
"task": "G1911",
"mutants": [
{
"object": "{{P}}HIRE",
"mutant": "line 8: key hire_id : -> hire_id : (key)",
"status": "killed",
"hidden": "6/9",
"failed_tests": [
"INSERT_AND_READ",
"KEY_FIELDS",
"SELECT_BY_KIOSK"
]
},
{
"object": "{{P}}HIRE",
"mutant": "line 9: abap.char(6) -> abap.char(5) (length)",
"status": "killed",
"hidden": "8/9",
"failed_tests": [
"LENGTHS_IN_CHARS"
]
},
{
"object": "{{P}}HIRE",
"mutant": "line 12: abap.int4 -> abap.int8 (type)",
"status": "killed",
"hidden": "7/9",
"failed_tests": [
"FIELD_TYPES",
"LENGTHS_IN_CHARS"
]
},
{
"object": "{{P}}HIRE",
"mutant": "line 15: abap.dec(13,2) -> abap.dec(13,3) (decimals)",
"status": "killed",
"hidden": "8/9",
"failed_tests": [
"DECIMALS_OF_RATE"
]
},
{
"object": "{{P}}HIRE",
"mutant": "line 17: abap.char(30) -> abap.numc(30) (type)",
"status": "killed",
"hidden": "7/9",
"failed_tests": [
"FIELD_TYPES",
"INSERT_AND_READ"
]
}
],
"valid": 5,
"killed": 5,
"kill_rate": 1.0,
"ok": true
}

View File

@@ -0,0 +1,19 @@
@EndUserText.label : 'Beach item hire'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table {{p}}hire {
key client : abap.clnt not null;
key hire_id : abap.numc(10) not null;
kiosk_id : abap.char(6) not null;
hire_date : abap.dats not null;
item_type : abap.char(4);
item_count : abap.int4;
hire_days : abap.int4;
@Semantics.amount.currencyCode : '{{p}}hire.currency_code'
daily_rate : abap.dec(13,2);
currency_code : abap.cuky;
customer_name : abap.char(30);
is_returned : abap.char(1);
}

View File

@@ -0,0 +1,76 @@
CLASS {{p}}hire_test DEFINITION PUBLIC FINAL CREATE PUBLIC
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
CLASS-DATA go_env TYPE REF TO if_osql_test_environment.
CLASS-METHODS class_setup.
CLASS-METHODS class_teardown.
METHODS setup.
METHODS structure_ok FOR TESTING.
METHODS stores_and_reads FOR TESTING.
METHODS duplicate_is_rejected FOR TESTING.
ENDCLASS.
CLASS {{p}}hire_test IMPLEMENTATION.
METHOD class_setup.
go_env = cl_osql_test_environment=>create(
i_dependency_list = VALUE #( ( '{{P}}HIRE' ) ) ).
ENDMETHOD.
METHOD class_teardown.
go_env->destroy( ).
ENDMETHOD.
METHOD setup.
go_env->clear_doubles( ).
ENDMETHOD.
METHOD structure_ok.
DATA(lo_struct) = CAST cl_abap_structdescr(
cl_abap_typedescr=>describe_by_name( '{{P}}HIRE' ) ).
DATA(lt_fields) = lo_struct->get_ddic_field_list( ).
cl_abap_unit_assert=>assert_equals( exp = 11 act = lines( lt_fields ) ).
READ TABLE lt_fields INTO DATA(ls_field) WITH KEY fieldname = 'HIRE_ID'.
cl_abap_unit_assert=>assert_equals( exp = 'X' act = ls_field-keyflag ).
cl_abap_unit_assert=>assert_equals( exp = 10 act = CONV i( ls_field-leng ) ).
ENDMETHOD.
METHOD stores_and_reads.
DATA ls_hire TYPE {{p}}hire.
DATA lt_hire TYPE STANDARD TABLE OF {{p}}hire WITH EMPTY KEY.
ls_hire-hire_id = '0000000001'.
ls_hire-kiosk_id = 'K1'.
ls_hire-hire_date = '20250701'.
ls_hire-item_type = 'CHAI'.
ls_hire-item_count = 2.
ls_hire-hire_days = 3.
ls_hire-daily_rate = '4.50'.
ls_hire-currency_code = 'EUR'.
ls_hire-customer_name = 'SMITH'.
ls_hire-is_returned = 'X'.
APPEND ls_hire TO lt_hire.
go_env->insert_test_data( lt_hire ).
SELECT SINGLE kiosk_id, item_count, hire_days, daily_rate, is_returned
FROM {{p}}hire
WHERE hire_id = '0000000001'
INTO @DATA(ls_read).
cl_abap_unit_assert=>assert_equals( exp = 'K1' act = ls_read-kiosk_id ).
cl_abap_unit_assert=>assert_equals( exp = 2 act = ls_read-item_count ).
cl_abap_unit_assert=>assert_equals( exp = 3 act = ls_read-hire_days ).
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '4.50' )
act = CONV decfloat34( ls_read-daily_rate ) ).
cl_abap_unit_assert=>assert_equals( exp = 'X' act = ls_read-is_returned ).
ENDMETHOD.
METHOD duplicate_is_rejected.
DATA ls_hire TYPE {{p}}hire.
ls_hire-hire_id = '0000000002'.
ls_hire-kiosk_id = 'K2'.
ls_hire-hire_date = '20250702'.
INSERT {{p}}hire FROM @ls_hire.
INSERT {{p}}hire FROM @ls_hire.
cl_abap_unit_assert=>assert_equals( exp = 4 act = sy-subrc ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,78 @@
# 1. Goal
A beach kiosk hires out beach chairs and parasols to holidaymakers. The kiosk
needs one database table that stores every hire. A report and an OData service
will read this table later, so the table is the only object of this task.
# 2. Open questions
None.
# 3. Context
- The table is new. It has no data and no other object uses it yet.
- One hire is one row of the table.
- hire_id is the number of the hire receipt.
- kiosk_id identifies the kiosk that made the hire.
- hire_date is the day of the hire.
- item_type is the code of the hired item: 'CHAI' is a beach chair and 'PARA'
is a parasol.
- item_count is the number of hired items.
- hire_days is the number of days of the hire.
- daily_rate is the price of one item for one day, in the currency
currency_code.
- customer_name is the name of the customer.
- is_returned is 'X' when the customer returned the items and ' ' when the
items are still out.
- All objects are in package $TMP.
# 4. Contract
- Create the transparent database table {{P}}HIRE in package $TMP.
- The table has these 11 fields, with these names (lower case): client,
hire_id, kiosk_id, hire_date, item_type, item_count, hire_days, daily_rate,
currency_code, customer_name, is_returned.
- The data types, the key fields and the not-null fields are fixed by rule 1
of section 5.
# 5. Business rules
1. The table has exactly these fields, in this order:
| Field | Type and length | Key | Not null |
|---------------|-----------------|-----|----------|
| client | abap.clnt | yes | yes |
| hire_id | abap.numc(10) | yes | yes |
| kiosk_id | abap.char(6) | no | yes |
| hire_date | abap.dats | no | yes |
| item_type | abap.char(4) | no | no |
| item_count | abap.int4 | no | no |
| hire_days | abap.int4 | no | no |
| daily_rate | abap.dec(13,2) | no | no |
| currency_code | abap.cuky | no | no |
| customer_name | abap.char(30) | no | no |
| is_returned | abap.char(1) | no | no |
2. client and hire_id are the key of the table. Two rows with the same client
and the same hire_id are not allowed.
3. client, hire_id, kiosk_id and hire_date are not null. All other fields can
be empty.
4. daily_rate is an amount with 2 decimals in the currency currency_code.
item_count and hire_days are whole numbers.
5. A row that was inserted can be read again with the same field values.
6. Rows can be selected by kiosk_id.
# 6. Constraints
- Release target: SAP_BASIS 816 (ABAP Platform 2025), client 001.
- Coding standards: Clean ABAP. Create the table as a DDL source with
"define table ..." and the annotations @EndUserText.label,
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE,
@AbapCatalog.tableCategory : #TRANSPARENT,
@AbapCatalog.deliveryClass : #A and
@AbapCatalog.dataMaintenance : #RESTRICTED.
- daily_rate is an amount in the currency currency_code, so it needs the
currency reference to currency_code.
- Out of scope: no CDS view, no report, no function module, no class other
than the test class for your own ABAP Unit tests.
# 7. Acceptance
- The table {{P}}HIRE is active and has no syntax error.
- The hidden tests pass.
- Write ABAP Unit tests in a global test class in package $TMP. Check the
structure of the table with cl_abap_typedescr and the data access with
cl_osql_test_environment.

View File

@@ -0,0 +1,56 @@
{
"id": "G1911",
"category": "B",
"object_type": "TABL",
"difficulty": 2,
"release_target": "v816",
"expected_outcome": "implement",
"budget": {
"max_tool_calls": 60,
"max_activations": 15
},
"seed": [],
"contract": [
{
"type": "TABL",
"name": "{{P}}HIRE",
"fields": [
"client",
"hire_id",
"kiosk_id",
"hire_date",
"item_type",
"item_count",
"hire_days",
"daily_rate",
"currency_code",
"customer_name",
"is_returned"
]
}
],
"out_of_scope": [],
"hidden_tests": [
{
"type": "CLAS",
"name": "{{P}}HIRE_HIDDEN",
"file": "hidden/hire_hidden.clas.abap",
"description": "Structure (RTTI) and data access (OSQL test double) tests for the table"
}
],
"reference": [
{
"type": "TABL",
"name": "{{P}}HIRE",
"file": "reference/hire.tabl.asabap",
"description": "Beach item hire table"
},
{
"type": "CLAS",
"name": "{{P}}HIRE_TEST",
"file": "reference/hire_test.clas.abap",
"description": "Own ABAP Unit tests for the table"
}
],
"craft_checks": []
}

View File

@@ -0,0 +1,16 @@
@EndUserText.label : 'Service job'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table {{p}}svcjob {
key client : abap.clnt not null;
job_id : abap.char(10) not null;
work_hours : abap.dec(5,2) not null;
calc_mode : abap.char(2) not null;
order_no : abap.char(10) not null;
job_date : abap.dats not null;
part_count : abap.int4 not null;
job_group : abap.char(4) not null;
job_value : abap.dec(15,2) not null;
}

View File

@@ -0,0 +1,16 @@
@EndUserText.label : 'Service job'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table {{p}}svcjob {
key client : abap.clnt not null;
key job_id : abap.char(10) not null;
work_hours : abap.dec(5,3) not null;
calc_mode : abap.char(2) not null;
order_no : abap.char(10) not null;
job_date : abap.dats not null;
part_count : abap.int4 not null;
job_group : abap.char(4) not null;
job_value : abap.dec(15,2) not null;
}

View File

@@ -0,0 +1,16 @@
@EndUserText.label : 'Service job'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table {{p}}svcjob {
key client : abap.clnt not null;
key job_id : abap.char(10) not null;
work_hours : abap.dec(5,2) not null;
calc_mode : abap.char(1) not null;
order_no : abap.char(10) not null;
job_date : abap.dats not null;
part_count : abap.int4 not null;
job_group : abap.char(4) not null;
job_value : abap.dec(15,2) not null;
}

View File

@@ -0,0 +1,16 @@
@EndUserText.label : 'Service job'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table {{p}}svcjob {
key client : abap.clnt not null;
key job_id : abap.char(10) not null;
work_hours : abap.dec(5,2) not null;
calc_mode : abap.char(2) not null;
order_no : abap.char(10) not null;
job_date : abap.tims not null;
part_count : abap.int4 not null;
job_group : abap.char(4) not null;
job_value : abap.dec(15,2) not null;
}

View File

@@ -0,0 +1,16 @@
@EndUserText.label : 'Service job'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table {{p}}svcjob {
key client : abap.clnt not null;
key job_id : abap.char(10) not null;
work_hours : abap.dec(5,2) not null;
calc_mode : abap.char(2) not null;
order_no : abap.char(10) not null;
job_date : abap.dats not null;
part_count : abap.int4 not null;
job_group : abap.char(4) not null;
job_value : abap.dec(15,3) not null;
}

View File

@@ -0,0 +1,29 @@
{
"id": "G1912",
"pool": "train",
"object_type": "TABL",
"category": "B",
"attempts": [
{
"stage": "validate",
"oracle": 0,
"null": 0
},
{
"stage": "validate",
"oracle": 58.3,
"null": 0
},
{
"stage": "validate",
"oracle": 100.0,
"null": 0,
"mutation": {
"valid": 5,
"killed": 5,
"ok": true
}
}
],
"accepted": true
}

View File

@@ -0,0 +1,175 @@
CLASS {{p}}svcjob_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
TYPES ty_typekind TYPE c LENGTH 1.
CLASS-DATA go_env TYPE REF TO if_osql_test_environment.
CLASS-METHODS class_setup.
CLASS-METHODS class_teardown.
METHODS setup.
METHODS field_names FOR TESTING.
METHODS key_fields FOR TESTING.
METHODS key_field_types FOR TESTING.
METHODS work_hours_field FOR TESTING.
METHODS calc_mode_field FOR TESTING.
METHODS order_no_field FOR TESTING.
METHODS job_date_field FOR TESTING.
METHODS part_count_field FOR TESTING.
METHODS job_group_field FOR TESTING.
METHODS job_value_field FOR TESTING.
METHODS insert_and_select FOR TESTING.
METHODS duplicate_key FOR TESTING.
METHODS get_ddic_fields RETURNING VALUE(rt_fields) TYPE ddfields.
METHODS check_type IMPORTING iv_name TYPE fieldname
iv_inttype TYPE ty_typekind
iv_leng TYPE i
iv_decimals TYPE i.
ENDCLASS.
CLASS {{p}}svcjob_hidden IMPLEMENTATION.
METHOD class_setup.
go_env = cl_osql_test_environment=>create( i_dependency_list = VALUE #( ( '{{P}}SVCJOB' ) ) ).
ENDMETHOD.
METHOD class_teardown.
go_env->destroy( ).
ENDMETHOD.
METHOD setup.
go_env->clear_doubles( ).
ENDMETHOD.
METHOD get_ddic_fields.
DATA lt_fields TYPE ddfields.
CALL FUNCTION 'DDIF_FIELDINFO_GET'
EXPORTING
tabname = '{{P}}SVCJOB'
langu = 'E'
TABLES
dfies_tab = lt_fields
EXCEPTIONS
not_found = 1
OTHERS = 2.
IF sy-subrc <> 0.
cl_abap_unit_assert=>fail( msg = 'DDIC field information is not available' ).
ENDIF.
rt_fields = lt_fields.
ENDMETHOD.
METHOD check_type.
DATA lt_fields TYPE ddfields.
lt_fields = get_ddic_fields( ).
READ TABLE lt_fields INTO DATA(ls_field) WITH KEY fieldname = iv_name.
IF sy-subrc <> 0.
cl_abap_unit_assert=>fail( msg = |Field { iv_name } is missing| ).
ENDIF.
cl_abap_unit_assert=>assert_equals( exp = iv_inttype act = ls_field-inttype
msg = |Internal type of { iv_name }| ).
cl_abap_unit_assert=>assert_equals( exp = iv_leng act = CONV i( ls_field-leng )
msg = |Length of { iv_name }| ).
cl_abap_unit_assert=>assert_equals( exp = iv_decimals act = CONV i( ls_field-decimals )
msg = |Decimals of { iv_name }| ).
ENDMETHOD.
METHOD field_names.
DATA lt_fields TYPE ddfields.
DATA lt_expected TYPE STANDARD TABLE OF fieldname WITH EMPTY KEY.
lt_expected = VALUE #( ( 'CLIENT' ) ( 'JOB_ID' ) ( 'WORK_HOURS' )
( 'CALC_MODE' ) ( 'ORDER_NO' ) ( 'JOB_DATE' )
( 'PART_COUNT' ) ( 'JOB_GROUP' ) ( 'JOB_VALUE' ) ).
lt_fields = get_ddic_fields( ).
cl_abap_unit_assert=>assert_equals( exp = lines( lt_expected ) act = lines( lt_fields ) ).
LOOP AT lt_expected INTO DATA(lv_name).
READ TABLE lt_fields TRANSPORTING NO FIELDS WITH KEY fieldname = lv_name.
cl_abap_unit_assert=>assert_subrc( exp = 0 msg = |Field { lv_name } is missing| ).
ENDLOOP.
ENDMETHOD.
METHOD key_fields.
DATA lt_fields TYPE ddfields.
lt_fields = get_ddic_fields( ).
LOOP AT lt_fields INTO DATA(ls_field).
IF ls_field-fieldname = 'CLIENT' OR ls_field-fieldname = 'JOB_ID'.
cl_abap_unit_assert=>assert_equals( exp = 'X' act = ls_field-keyflag
msg = |Key flag of { ls_field-fieldname }| ).
ELSE.
cl_abap_unit_assert=>assert_initial( act = ls_field-keyflag
msg = |Key flag of { ls_field-fieldname }| ).
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD key_field_types.
check_type( iv_name = 'CLIENT' iv_inttype = 'C' iv_leng = 3 iv_decimals = 0 ).
check_type( iv_name = 'JOB_ID' iv_inttype = 'C' iv_leng = 10 iv_decimals = 0 ).
ENDMETHOD.
METHOD work_hours_field.
check_type( iv_name = 'WORK_HOURS' iv_inttype = 'P' iv_leng = 5 iv_decimals = 2 ).
ENDMETHOD.
METHOD calc_mode_field.
check_type( iv_name = 'CALC_MODE' iv_inttype = 'C' iv_leng = 2 iv_decimals = 0 ).
ENDMETHOD.
METHOD order_no_field.
check_type( iv_name = 'ORDER_NO' iv_inttype = 'C' iv_leng = 10 iv_decimals = 0 ).
ENDMETHOD.
METHOD job_date_field.
check_type( iv_name = 'JOB_DATE' iv_inttype = 'D' iv_leng = 8 iv_decimals = 0 ).
ENDMETHOD.
METHOD part_count_field.
check_type( iv_name = 'PART_COUNT' iv_inttype = 'I' iv_leng = 10 iv_decimals = 0 ).
ENDMETHOD.
METHOD job_group_field.
check_type( iv_name = 'JOB_GROUP' iv_inttype = 'C' iv_leng = 4 iv_decimals = 0 ).
ENDMETHOD.
METHOD job_value_field.
check_type( iv_name = 'JOB_VALUE' iv_inttype = 'P' iv_leng = 15 iv_decimals = 2 ).
ENDMETHOD.
METHOD insert_and_select.
DATA ls_job TYPE {{p}}svcjob.
ls_job-client = sy-mandt.
ls_job-job_id = 'J001'.
ls_job-work_hours = '12.50'.
ls_job-calc_mode = 'A1'.
ls_job-order_no = 'ORD123'.
ls_job-job_date = '20250101'.
ls_job-part_count = 5.
ls_job-job_group = 'GR01'.
ls_job-job_value = '1000.00'.
INSERT {{p}}svcjob FROM ls_job.
cl_abap_unit_assert=>assert_subrc( exp = 0 ).
SELECT SINGLE * FROM {{p}}svcjob WHERE job_id = 'J001' INTO @DATA(ls_read).
cl_abap_unit_assert=>assert_subrc( exp = 0 ).
cl_abap_unit_assert=>assert_equals( exp = ls_job-work_hours act = ls_read-work_hours ).
cl_abap_unit_assert=>assert_equals( exp = ls_job-calc_mode act = ls_read-calc_mode ).
cl_abap_unit_assert=>assert_equals( exp = ls_job-order_no act = ls_read-order_no ).
cl_abap_unit_assert=>assert_equals( exp = ls_job-job_date act = ls_read-job_date ).
cl_abap_unit_assert=>assert_equals( exp = ls_job-part_count act = ls_read-part_count ).
cl_abap_unit_assert=>assert_equals( exp = ls_job-job_group act = ls_read-job_group ).
cl_abap_unit_assert=>assert_equals( exp = ls_job-job_value act = ls_read-job_value ).
ENDMETHOD.
METHOD duplicate_key.
DATA ls_job TYPE {{p}}svcjob.
ls_job-client = sy-mandt.
ls_job-job_id = 'J002'.
ls_job-work_hours = '1.00'.
ls_job-calc_mode = 'B2'.
ls_job-order_no = 'ORD456'.
ls_job-job_date = '20250102'.
ls_job-part_count = 1.
ls_job-job_group = 'GR02'.
ls_job-job_value = '50.00'.
INSERT {{p}}svcjob FROM ls_job.
cl_abap_unit_assert=>assert_subrc( exp = 0 ).
INSERT {{p}}svcjob FROM ls_job.
cl_abap_unit_assert=>assert_equals( exp = 4 act = sy-subrc ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,54 @@
{
"task": "G1912",
"mutants": [
{
"object": "{{P}}SVCJOB",
"mutant": "line 8: key job_id : -> job_id : (key)",
"status": "killed",
"hidden": "11/12",
"failed_tests": [
"KEY_FIELDS"
]
},
{
"object": "{{P}}SVCJOB",
"mutant": "line 9: abap.dec(5,2) -> abap.dec(5,3) (decimals)",
"status": "killed",
"hidden": "11/12",
"failed_tests": [
"WORK_HOURS_FIELD"
]
},
{
"object": "{{P}}SVCJOB",
"mutant": "line 10: abap.char(2) -> abap.char(1) (length)",
"status": "killed",
"hidden": "11/12",
"failed_tests": [
"CALC_MODE_FIELD"
]
},
{
"object": "{{P}}SVCJOB",
"mutant": "line 12: abap.dats -> abap.tims (type)",
"status": "killed",
"hidden": "11/12",
"failed_tests": [
"JOB_DATE_FIELD"
]
},
{
"object": "{{P}}SVCJOB",
"mutant": "line 15: abap.dec(15,2) -> abap.dec(15,3) (decimals)",
"status": "killed",
"hidden": "11/12",
"failed_tests": [
"JOB_VALUE_FIELD"
]
}
],
"valid": 5,
"killed": 5,
"kill_rate": 1.0,
"ok": true
}

View File

@@ -0,0 +1,16 @@
@EndUserText.label : 'Service job'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table {{p}}svcjob {
key client : abap.clnt not null;
key job_id : abap.char(10) not null;
work_hours : abap.dec(5,2) not null;
calc_mode : abap.char(2) not null;
order_no : abap.char(10) not null;
job_date : abap.dats not null;
part_count : abap.int4 not null;
job_group : abap.char(4) not null;
job_value : abap.dec(15,2) not null;
}

View File

@@ -0,0 +1,139 @@
CLASS {{p}}svcjob_test DEFINITION PUBLIC FINAL CREATE PUBLIC
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
TYPES ty_typekind TYPE c LENGTH 1.
CLASS-DATA go_env TYPE REF TO if_osql_test_environment.
CLASS-METHODS class_setup.
CLASS-METHODS class_teardown.
METHODS setup.
METHODS field_names FOR TESTING.
METHODS key_fields FOR TESTING.
METHODS field_types FOR TESTING.
METHODS insert_and_select FOR TESTING.
METHODS duplicate_key FOR TESTING.
METHODS get_ddic_fields RETURNING VALUE(rt_fields) TYPE ddfields.
METHODS check_type IMPORTING iv_name TYPE fieldname
iv_inttype TYPE ty_typekind
iv_leng TYPE i
iv_decimals TYPE i.
ENDCLASS.
CLASS {{p}}svcjob_test IMPLEMENTATION.
METHOD class_setup.
go_env = cl_osql_test_environment=>create( i_dependency_list = VALUE #( ( '{{P}}SVCJOB' ) ) ).
ENDMETHOD.
METHOD class_teardown.
go_env->destroy( ).
ENDMETHOD.
METHOD setup.
go_env->clear_doubles( ).
ENDMETHOD.
METHOD get_ddic_fields.
DATA lt_fields TYPE ddfields.
CALL FUNCTION 'DDIF_FIELDINFO_GET'
EXPORTING
tabname = '{{P}}SVCJOB'
langu = 'E'
TABLES
dfies_tab = lt_fields
EXCEPTIONS
not_found = 1
OTHERS = 2.
IF sy-subrc <> 0.
cl_abap_unit_assert=>fail( msg = 'DDIC field information is not available' ).
ENDIF.
rt_fields = lt_fields.
ENDMETHOD.
METHOD check_type.
DATA lt_fields TYPE ddfields.
lt_fields = get_ddic_fields( ).
READ TABLE lt_fields INTO DATA(ls_field) WITH KEY fieldname = iv_name.
IF sy-subrc <> 0.
cl_abap_unit_assert=>fail( msg = |Field { iv_name } is missing| ).
ENDIF.
cl_abap_unit_assert=>assert_equals( exp = iv_inttype act = ls_field-inttype ).
cl_abap_unit_assert=>assert_equals( exp = iv_leng act = CONV i( ls_field-leng ) ).
cl_abap_unit_assert=>assert_equals( exp = iv_decimals act = CONV i( ls_field-decimals ) ).
ENDMETHOD.
METHOD field_names.
DATA lt_fields TYPE ddfields.
DATA lt_expected TYPE STANDARD TABLE OF fieldname WITH EMPTY KEY.
lt_expected = VALUE #( ( 'CLIENT' ) ( 'JOB_ID' ) ( 'WORK_HOURS' )
( 'CALC_MODE' ) ( 'ORDER_NO' ) ( 'JOB_DATE' )
( 'PART_COUNT' ) ( 'JOB_GROUP' ) ( 'JOB_VALUE' ) ).
lt_fields = get_ddic_fields( ).
cl_abap_unit_assert=>assert_equals( exp = lines( lt_expected ) act = lines( lt_fields ) ).
LOOP AT lt_expected INTO DATA(lv_name).
READ TABLE lt_fields TRANSPORTING NO FIELDS WITH KEY fieldname = lv_name.
cl_abap_unit_assert=>assert_subrc( exp = 0 msg = |Field { lv_name } is missing| ).
ENDLOOP.
ENDMETHOD.
METHOD key_fields.
DATA lt_fields TYPE ddfields.
lt_fields = get_ddic_fields( ).
LOOP AT lt_fields INTO DATA(ls_field).
IF ls_field-fieldname = 'CLIENT' OR ls_field-fieldname = 'JOB_ID'.
cl_abap_unit_assert=>assert_equals( exp = 'X' act = ls_field-keyflag
msg = |Key flag of { ls_field-fieldname }| ).
ELSE.
cl_abap_unit_assert=>assert_initial( act = ls_field-keyflag
msg = |Key flag of { ls_field-fieldname }| ).
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD field_types.
check_type( iv_name = 'CLIENT' iv_inttype = 'C' iv_leng = 3 iv_decimals = 0 ).
check_type( iv_name = 'JOB_ID' iv_inttype = 'C' iv_leng = 10 iv_decimals = 0 ).
check_type( iv_name = 'WORK_HOURS' iv_inttype = 'P' iv_leng = 5 iv_decimals = 2 ).
check_type( iv_name = 'CALC_MODE' iv_inttype = 'C' iv_leng = 2 iv_decimals = 0 ).
check_type( iv_name = 'ORDER_NO' iv_inttype = 'C' iv_leng = 10 iv_decimals = 0 ).
check_type( iv_name = 'JOB_DATE' iv_inttype = 'D' iv_leng = 8 iv_decimals = 0 ).
check_type( iv_name = 'PART_COUNT' iv_inttype = 'I' iv_leng = 10 iv_decimals = 0 ).
check_type( iv_name = 'JOB_GROUP' iv_inttype = 'C' iv_leng = 4 iv_decimals = 0 ).
check_type( iv_name = 'JOB_VALUE' iv_inttype = 'P' iv_leng = 15 iv_decimals = 2 ).
ENDMETHOD.
METHOD insert_and_select.
DATA ls_job TYPE {{p}}svcjob.
ls_job-client = sy-mandt.
ls_job-job_id = 'J001'.
ls_job-work_hours = '12.50'.
ls_job-calc_mode = 'A1'.
ls_job-order_no = 'ORD123'.
ls_job-job_date = '20250101'.
ls_job-part_count = 5.
ls_job-job_group = 'GR01'.
ls_job-job_value = '1000.00'.
INSERT {{p}}svcjob FROM ls_job.
cl_abap_unit_assert=>assert_subrc( exp = 0 ).
SELECT SINGLE * FROM {{p}}svcjob WHERE job_id = 'J001' INTO @DATA(ls_read).
cl_abap_unit_assert=>assert_subrc( exp = 0 ).
cl_abap_unit_assert=>assert_equals( exp = ls_job-work_hours act = ls_read-work_hours ).
cl_abap_unit_assert=>assert_equals( exp = ls_job-job_value act = ls_read-job_value ).
ENDMETHOD.
METHOD duplicate_key.
DATA ls_job TYPE {{p}}svcjob.
ls_job-client = sy-mandt.
ls_job-job_id = 'J002'.
ls_job-work_hours = '1.00'.
ls_job-calc_mode = 'B2'.
ls_job-order_no = 'ORD456'.
ls_job-job_date = '20250102'.
ls_job-part_count = 1.
ls_job-job_group = 'GR02'.
ls_job-job_value = '50.00'.
INSERT {{p}}svcjob FROM ls_job.
cl_abap_unit_assert=>assert_subrc( exp = 0 ).
INSERT {{p}}svcjob FROM ls_job.
cl_abap_unit_assert=>assert_equals( exp = 4 act = sy-subrc ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,47 @@
# 1. Goal
Store the service jobs of a service company. The company records the work hours,
the calculation mode, the order number, the date, the part count, the group, and
the value of each job. The business domain uses concepts that collide with
reserved or SQL words. The contract therefore uses safe field names.
# 2. Open questions
None.
# 3. Context
- The table is in package $TMP.
- The table stores service jobs of the service company.
- The table has a client field as the first key field.
# 4. Contract
Create the database table {{P}}SVCJOB with these fields:
| Field name | Data type | Length | Decimals | Key |
|------------|-----------|--------|----------|-----|
| client | abap.clnt | 3 | 0 | X |
| job_id | abap.char | 10 | 0 | X |
| work_hours | abap.dec | 5 | 2 | |
| calc_mode | abap.char | 2 | 0 | |
| order_no | abap.char | 10 | 0 | |
| job_date | abap.dats | 8 | 0 | |
| part_count | abap.int4 | 10 | 0 | |
| job_group | abap.char | 4 | 0 | |
| job_value | abap.dec | 15 | 2 | |
# 5. Business rules
1. Use the field names exactly as given in the contract. Use lower case field
names in the table definition.
2. Do not use reserved words as field names. Reserved words include HOURS, MODE,
ORDER, DATE, COUNT, GROUP, and VALUE.
3. The key fields are client and job_id. No other field is a key field.
4. Use only built-in data types. Do not use data elements or domains.
5. The table must be active.
# 6. Constraints
- Release target: 8.16.
- Out of scope: none.
- Do not create other objects.
# 7. Acceptance
- The table is active and has no syntax error.
- The hidden tests pass.
- Write ABAP Unit tests for the table in a global test class.

View File

@@ -0,0 +1,54 @@
{
"id": "G1912",
"category": "B",
"object_type": "TABL",
"difficulty": 2,
"release_target": "v816",
"expected_outcome": "implement",
"budget": {
"max_tool_calls": 60,
"max_activations": 15
},
"seed": [],
"contract": [
{
"type": "TABL",
"name": "{{P}}SVCJOB",
"fields": [
"client",
"job_id",
"work_hours",
"calc_mode",
"order_no",
"job_date",
"part_count",
"job_group",
"job_value"
]
}
],
"out_of_scope": [],
"hidden_tests": [
{
"type": "CLAS",
"name": "{{P}}SVCJOB_HIDDEN",
"file": "hidden/svcjob_hidden.clas.abap",
"description": "Hidden tests for table {{P}}SVCJOB"
}
],
"reference": [
{
"type": "TABL",
"name": "{{P}}SVCJOB",
"file": "reference/svcjob.tabl.asabap",
"description": "Service job table"
},
{
"type": "CLAS",
"name": "{{P}}SVCJOB_TEST",
"file": "reference/svcjob_test.clas.abap",
"description": "Own tests for table {{P}}SVCJOB"
}
],
"craft_checks": []
}

View File

@@ -0,0 +1,84 @@
INTERFACE {{p}}if_laundry_fee PUBLIC.
TYPES ty_item TYPE c LENGTH 7.
TYPES ty_service TYPE c LENGTH 4.
TYPES ty_reason TYPE c LENGTH 10.
TYPES ty_quantity TYPE i.
TYPES ty_amount TYPE p LENGTH 7 DECIMALS 2.
TYPES ty_flag TYPE abap_bool.
TYPES:
BEGIN OF ty_order_line,
item TYPE ty_item,
service TYPE ty_service,
quantity TYPE ty_quantity,
express TYPE ty_flag,
END OF ty_order_line.
TYPES tt_order_line TYPE STANDARD TABLE OF ty_order_line WITH EMPTY KEY.
CONSTANTS:
BEGIN OF c_reason,
ok TYPE ty_reason VALUE 'OK',
item TYPE ty_reason VALUE 'ITEM',
service TYPE ty_reason VALUE 'SERVICE',
qty TYPE ty_reason VALUE 'QTY',
END OF c_reason.
CONSTANTS:
BEGIN OF c_item,
shirt TYPE ty_item VALUE 'SHIRT',
trousers TYPE ty_item VALUE 'TROUS',
suit TYPE ty_item VALUE 'SUIT',
coat TYPE ty_item VALUE 'COAT',
dress TYPE ty_item VALUE 'DRESS',
curtain TYPE ty_item VALUE 'CURTAIN',
END OF c_item.
CONSTANTS:
BEGIN OF c_service,
wash TYPE ty_service VALUE 'WASH',
dryc TYPE ty_service VALUE 'DRYC',
iron TYPE ty_service VALUE 'IRON',
mend TYPE ty_service VALUE 'MEND',
END OF c_service.
CONSTANTS:
BEGIN OF c_price,
shirt TYPE ty_amount VALUE '3.50',
trousers TYPE ty_amount VALUE '5.00',
suit TYPE ty_amount VALUE '12.00',
coat TYPE ty_amount VALUE '14.50',
dress TYPE ty_amount VALUE '8.00',
curtain TYPE ty_amount VALUE '9.50',
END OF c_price.
CONSTANTS:
BEGIN OF c_factor,
wash TYPE i VALUE 100,
dryc TYPE i VALUE 180,
iron TYPE i VALUE 40,
mend TYPE i VALUE 220,
END OF c_factor.
CONSTANTS c_max_qty TYPE ty_quantity VALUE 99.
CONSTANTS c_bulk_min_qty TYPE ty_quantity VALUE 10.
CONSTANTS c_bulk_discount TYPE i VALUE 10.
CONSTANTS c_express_surcharge TYPE i VALUE 25.
CONSTANTS c_min_fee TYPE ty_amount VALUE '5.00'.
METHODS check_item
IMPORTING iv_item TYPE ty_item
iv_service TYPE ty_service
iv_quantity TYPE ty_quantity
RETURNING VALUE(rv_reason) TYPE ty_reason.
METHODS calculate_fee
IMPORTING iv_item TYPE ty_item
iv_service TYPE ty_service
iv_quantity TYPE ty_quantity
iv_express TYPE ty_flag
RETURNING VALUE(rv_fee) TYPE ty_amount.
METHODS calculate_order
IMPORTING it_lines TYPE tt_order_line
RETURNING VALUE(rv_total) TYPE ty_amount.
ENDINTERFACE.

View File

@@ -0,0 +1,84 @@
INTERFACE {{p}}if_laundry_fee PUBLIC.
TYPES ty_item TYPE c LENGTH 7.
TYPES ty_service TYPE c LENGTH 4.
TYPES ty_reason TYPE c LENGTH 10.
TYPES ty_quantity TYPE i.
TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2.
TYPES ty_flag TYPE abap_bool.
TYPES:
BEGIN OF ty_order_line,
item TYPE ty_item,
service TYPE ty_service,
quantity TYPE ty_quantity,
express TYPE ty_flag,
END OF ty_order_line.
TYPES tt_order_line TYPE STANDARD TABLE OF ty_order_line WITH EMPTY KEY.
CONSTANTS:
BEGIN OF c_reason,
ok TYPE ty_reason VALUE 'ZK',
item TYPE ty_reason VALUE 'ITEM',
service TYPE ty_reason VALUE 'SERVICE',
qty TYPE ty_reason VALUE 'QTY',
END OF c_reason.
CONSTANTS:
BEGIN OF c_item,
shirt TYPE ty_item VALUE 'SHIRT',
trousers TYPE ty_item VALUE 'TROUS',
suit TYPE ty_item VALUE 'SUIT',
coat TYPE ty_item VALUE 'COAT',
dress TYPE ty_item VALUE 'DRESS',
curtain TYPE ty_item VALUE 'CURTAIN',
END OF c_item.
CONSTANTS:
BEGIN OF c_service,
wash TYPE ty_service VALUE 'WASH',
dryc TYPE ty_service VALUE 'DRYC',
iron TYPE ty_service VALUE 'IRON',
mend TYPE ty_service VALUE 'MEND',
END OF c_service.
CONSTANTS:
BEGIN OF c_price,
shirt TYPE ty_amount VALUE '3.50',
trousers TYPE ty_amount VALUE '5.00',
suit TYPE ty_amount VALUE '12.00',
coat TYPE ty_amount VALUE '14.50',
dress TYPE ty_amount VALUE '8.00',
curtain TYPE ty_amount VALUE '9.50',
END OF c_price.
CONSTANTS:
BEGIN OF c_factor,
wash TYPE i VALUE 100,
dryc TYPE i VALUE 180,
iron TYPE i VALUE 40,
mend TYPE i VALUE 220,
END OF c_factor.
CONSTANTS c_max_qty TYPE ty_quantity VALUE 99.
CONSTANTS c_bulk_min_qty TYPE ty_quantity VALUE 10.
CONSTANTS c_bulk_discount TYPE i VALUE 10.
CONSTANTS c_express_surcharge TYPE i VALUE 25.
CONSTANTS c_min_fee TYPE ty_amount VALUE '5.00'.
METHODS check_item
IMPORTING iv_item TYPE ty_item
iv_service TYPE ty_service
iv_quantity TYPE ty_quantity
RETURNING VALUE(rv_reason) TYPE ty_reason.
METHODS calculate_fee
IMPORTING iv_item TYPE ty_item
iv_service TYPE ty_service
iv_quantity TYPE ty_quantity
iv_express TYPE ty_flag
RETURNING VALUE(rv_fee) TYPE ty_amount.
METHODS calculate_order
IMPORTING it_lines TYPE tt_order_line
RETURNING VALUE(rv_total) TYPE ty_amount.
ENDINTERFACE.

View File

@@ -0,0 +1,84 @@
INTERFACE {{p}}if_laundry_fee PUBLIC.
TYPES ty_item TYPE c LENGTH 7.
TYPES ty_service TYPE c LENGTH 4.
TYPES ty_reason TYPE c LENGTH 10.
TYPES ty_quantity TYPE i.
TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2.
TYPES ty_flag TYPE abap_bool.
TYPES:
BEGIN OF ty_order_line,
item TYPE ty_item,
service TYPE ty_service,
quantity TYPE ty_quantity,
express TYPE ty_flag,
END OF ty_order_line.
TYPES tt_order_line TYPE STANDARD TABLE OF ty_order_line WITH EMPTY KEY.
CONSTANTS:
BEGIN OF c_reason,
ok TYPE ty_reason VALUE 'OK',
item TYPE ty_reason VALUE 'ITEM',
service TYPE ty_reason VALUE 'SERVICE',
qty TYPE ty_reason VALUE 'ZTY',
END OF c_reason.
CONSTANTS:
BEGIN OF c_item,
shirt TYPE ty_item VALUE 'SHIRT',
trousers TYPE ty_item VALUE 'TROUS',
suit TYPE ty_item VALUE 'SUIT',
coat TYPE ty_item VALUE 'COAT',
dress TYPE ty_item VALUE 'DRESS',
curtain TYPE ty_item VALUE 'CURTAIN',
END OF c_item.
CONSTANTS:
BEGIN OF c_service,
wash TYPE ty_service VALUE 'WASH',
dryc TYPE ty_service VALUE 'DRYC',
iron TYPE ty_service VALUE 'IRON',
mend TYPE ty_service VALUE 'MEND',
END OF c_service.
CONSTANTS:
BEGIN OF c_price,
shirt TYPE ty_amount VALUE '3.50',
trousers TYPE ty_amount VALUE '5.00',
suit TYPE ty_amount VALUE '12.00',
coat TYPE ty_amount VALUE '14.50',
dress TYPE ty_amount VALUE '8.00',
curtain TYPE ty_amount VALUE '9.50',
END OF c_price.
CONSTANTS:
BEGIN OF c_factor,
wash TYPE i VALUE 100,
dryc TYPE i VALUE 180,
iron TYPE i VALUE 40,
mend TYPE i VALUE 220,
END OF c_factor.
CONSTANTS c_max_qty TYPE ty_quantity VALUE 99.
CONSTANTS c_bulk_min_qty TYPE ty_quantity VALUE 10.
CONSTANTS c_bulk_discount TYPE i VALUE 10.
CONSTANTS c_express_surcharge TYPE i VALUE 25.
CONSTANTS c_min_fee TYPE ty_amount VALUE '5.00'.
METHODS check_item
IMPORTING iv_item TYPE ty_item
iv_service TYPE ty_service
iv_quantity TYPE ty_quantity
RETURNING VALUE(rv_reason) TYPE ty_reason.
METHODS calculate_fee
IMPORTING iv_item TYPE ty_item
iv_service TYPE ty_service
iv_quantity TYPE ty_quantity
iv_express TYPE ty_flag
RETURNING VALUE(rv_fee) TYPE ty_amount.
METHODS calculate_order
IMPORTING it_lines TYPE tt_order_line
RETURNING VALUE(rv_total) TYPE ty_amount.
ENDINTERFACE.

View File

@@ -0,0 +1,84 @@
INTERFACE {{p}}if_laundry_fee PUBLIC.
TYPES ty_item TYPE c LENGTH 7.
TYPES ty_service TYPE c LENGTH 4.
TYPES ty_reason TYPE c LENGTH 10.
TYPES ty_quantity TYPE i.
TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2.
TYPES ty_flag TYPE abap_bool.
TYPES:
BEGIN OF ty_order_line,
item TYPE ty_item,
service TYPE ty_service,
quantity TYPE ty_quantity,
express TYPE ty_flag,
END OF ty_order_line.
TYPES tt_order_line TYPE STANDARD TABLE OF ty_order_line WITH EMPTY KEY.
CONSTANTS:
BEGIN OF c_reason,
ok TYPE ty_reason VALUE 'OK',
item TYPE ty_reason VALUE 'ITEM',
service TYPE ty_reason VALUE 'SERVICE',
qty TYPE ty_reason VALUE 'QTY',
END OF c_reason.
CONSTANTS:
BEGIN OF c_item,
shirt TYPE ty_item VALUE 'SHIRT',
trousers TYPE ty_item VALUE 'TROUS',
suit TYPE ty_item VALUE 'SUIT',
coat TYPE ty_item VALUE 'COAT',
dress TYPE ty_item VALUE 'DRESS',
curtain TYPE ty_item VALUE 'CURTAIN',
END OF c_item.
CONSTANTS:
BEGIN OF c_service,
wash TYPE ty_service VALUE 'WASH',
dryc TYPE ty_service VALUE 'DRYC',
iron TYPE ty_service VALUE 'ZRON',
mend TYPE ty_service VALUE 'MEND',
END OF c_service.
CONSTANTS:
BEGIN OF c_price,
shirt TYPE ty_amount VALUE '3.50',
trousers TYPE ty_amount VALUE '5.00',
suit TYPE ty_amount VALUE '12.00',
coat TYPE ty_amount VALUE '14.50',
dress TYPE ty_amount VALUE '8.00',
curtain TYPE ty_amount VALUE '9.50',
END OF c_price.
CONSTANTS:
BEGIN OF c_factor,
wash TYPE i VALUE 100,
dryc TYPE i VALUE 180,
iron TYPE i VALUE 40,
mend TYPE i VALUE 220,
END OF c_factor.
CONSTANTS c_max_qty TYPE ty_quantity VALUE 99.
CONSTANTS c_bulk_min_qty TYPE ty_quantity VALUE 10.
CONSTANTS c_bulk_discount TYPE i VALUE 10.
CONSTANTS c_express_surcharge TYPE i VALUE 25.
CONSTANTS c_min_fee TYPE ty_amount VALUE '5.00'.
METHODS check_item
IMPORTING iv_item TYPE ty_item
iv_service TYPE ty_service
iv_quantity TYPE ty_quantity
RETURNING VALUE(rv_reason) TYPE ty_reason.
METHODS calculate_fee
IMPORTING iv_item TYPE ty_item
iv_service TYPE ty_service
iv_quantity TYPE ty_quantity
iv_express TYPE ty_flag
RETURNING VALUE(rv_fee) TYPE ty_amount.
METHODS calculate_order
IMPORTING it_lines TYPE tt_order_line
RETURNING VALUE(rv_total) TYPE ty_amount.
ENDINTERFACE.

View File

@@ -0,0 +1,84 @@
INTERFACE {{p}}if_laundry_fee PUBLIC.
TYPES ty_item TYPE c LENGTH 7.
TYPES ty_service TYPE c LENGTH 4.
TYPES ty_reason TYPE c LENGTH 10.
TYPES ty_quantity TYPE i.
TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2.
TYPES ty_flag TYPE abap_bool.
TYPES:
BEGIN OF ty_order_line,
item TYPE ty_item,
service TYPE ty_service,
quantity TYPE ty_quantity,
express TYPE ty_flag,
END OF ty_order_line.
TYPES tt_order_line TYPE STANDARD TABLE OF ty_order_line WITH EMPTY KEY.
CONSTANTS:
BEGIN OF c_reason,
ok TYPE ty_reason VALUE 'OK',
item TYPE ty_reason VALUE 'ITEM',
service TYPE ty_reason VALUE 'SERVICE',
qty TYPE ty_reason VALUE 'QTY',
END OF c_reason.
CONSTANTS:
BEGIN OF c_item,
shirt TYPE ty_item VALUE 'SHIRT',
trousers TYPE ty_item VALUE 'TROUS',
suit TYPE ty_item VALUE 'SUIT',
coat TYPE ty_item VALUE 'COAT',
dress TYPE ty_item VALUE 'DRESS',
curtain TYPE ty_item VALUE 'CURTAIN',
END OF c_item.
CONSTANTS:
BEGIN OF c_service,
wash TYPE ty_service VALUE 'WASH',
dryc TYPE ty_service VALUE 'DRYC',
iron TYPE ty_service VALUE 'IRON',
mend TYPE ty_service VALUE 'MEND',
END OF c_service.
CONSTANTS:
BEGIN OF c_price,
shirt TYPE ty_amount VALUE '3.50',
trousers TYPE ty_amount VALUE '5.00',
suit TYPE ty_amount VALUE '12.00',
coat TYPE ty_amount VALUE '14.50',
dress TYPE ty_amount VALUE '8.00',
curtain TYPE ty_amount VALUE '9.50',
END OF c_price.
CONSTANTS:
BEGIN OF c_factor,
wash TYPE i VALUE 100,
dryc TYPE i VALUE 180,
iron TYPE i VALUE 40,
mend TYPE i VALUE 220,
END OF c_factor.
CONSTANTS c_max_qty TYPE ty_quantity VALUE 99.
CONSTANTS c_bulk_min_qty TYPE ty_quantity VALUE 10.
CONSTANTS c_bulk_discount TYPE i VALUE 10.
CONSTANTS c_express_surcharge TYPE i VALUE 26.
CONSTANTS c_min_fee TYPE ty_amount VALUE '5.00'.
METHODS check_item
IMPORTING iv_item TYPE ty_item
iv_service TYPE ty_service
iv_quantity TYPE ty_quantity
RETURNING VALUE(rv_reason) TYPE ty_reason.
METHODS calculate_fee
IMPORTING iv_item TYPE ty_item
iv_service TYPE ty_service
iv_quantity TYPE ty_quantity
iv_express TYPE ty_flag
RETURNING VALUE(rv_fee) TYPE ty_amount.
METHODS calculate_order
IMPORTING it_lines TYPE tt_order_line
RETURNING VALUE(rv_total) TYPE ty_amount.
ENDINTERFACE.

View File

@@ -0,0 +1,38 @@
{
"id": "G1913",
"pool": "train",
"object_type": "INTF",
"category": "A",
"attempts": [
{
"stage": "bundle",
"errors": [
"invalid JSON: Unterminated string starting at: line 1 column 905 (char 904)"
],
"by_check": {
"json": 1
}
},
{
"stage": "validate",
"oracle": 0,
"null": 0
},
{
"stage": "validate",
"oracle": 81.0,
"null": 0
},
{
"stage": "validate",
"oracle": 100.0,
"null": 0,
"mutation": {
"valid": 5,
"killed": 5,
"ok": true
}
}
],
"accepted": true
}

View File

@@ -0,0 +1,197 @@
CLASS {{p}}laundry_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PUBLIC SECTION.
INTERFACES {{p}}if_laundry_fee.
PRIVATE SECTION.
METHODS reason_codes FOR TESTING.
METHODS item_codes FOR TESTING.
METHODS service_codes FOR TESTING.
METHODS price_table FOR TESTING.
METHODS factor_table FOR TESTING.
METHODS limit_values FOR TESTING.
METHODS char_type_lengths FOR TESTING.
METHODS amount_type FOR TESTING.
METHODS order_line_type FOR TESTING.
METHODS methods_callable FOR TESTING.
ENDCLASS.
CLASS {{p}}laundry_hidden IMPLEMENTATION.
METHOD {{p}}if_laundry_fee~check_item.
rv_reason = {{p}}if_laundry_fee=>c_reason-ok.
ENDMETHOD.
METHOD {{p}}if_laundry_fee~calculate_fee.
rv_fee = {{p}}if_laundry_fee=>c_min_fee.
ENDMETHOD.
METHOD {{p}}if_laundry_fee~calculate_order.
rv_total = {{p}}if_laundry_fee=>c_min_fee.
ENDMETHOD.
METHOD reason_codes.
DATA lv_reason TYPE {{p}}if_laundry_fee=>ty_reason.
lv_reason = 'OK'.
cl_abap_unit_assert=>assert_equals( exp = lv_reason act = {{p}}if_laundry_fee=>c_reason-ok ).
lv_reason = 'ITEM'.
cl_abap_unit_assert=>assert_equals( exp = lv_reason act = {{p}}if_laundry_fee=>c_reason-item ).
lv_reason = 'SERVICE'.
cl_abap_unit_assert=>assert_equals( exp = lv_reason act = {{p}}if_laundry_fee=>c_reason-service ).
lv_reason = 'QTY'.
cl_abap_unit_assert=>assert_equals( exp = lv_reason act = {{p}}if_laundry_fee=>c_reason-qty ).
ENDMETHOD.
METHOD item_codes.
DATA lv_item TYPE {{p}}if_laundry_fee=>ty_item.
lv_item = 'SHIRT'.
cl_abap_unit_assert=>assert_equals( exp = lv_item act = {{p}}if_laundry_fee=>c_item-shirt ).
lv_item = 'TROUS'.
cl_abap_unit_assert=>assert_equals( exp = lv_item act = {{p}}if_laundry_fee=>c_item-trousers ).
lv_item = 'SUIT'.
cl_abap_unit_assert=>assert_equals( exp = lv_item act = {{p}}if_laundry_fee=>c_item-suit ).
lv_item = 'COAT'.
cl_abap_unit_assert=>assert_equals( exp = lv_item act = {{p}}if_laundry_fee=>c_item-coat ).
lv_item = 'DRESS'.
cl_abap_unit_assert=>assert_equals( exp = lv_item act = {{p}}if_laundry_fee=>c_item-dress ).
lv_item = 'CURTAIN'.
cl_abap_unit_assert=>assert_equals( exp = lv_item act = {{p}}if_laundry_fee=>c_item-curtain ).
ENDMETHOD.
METHOD service_codes.
DATA lv_service TYPE {{p}}if_laundry_fee=>ty_service.
lv_service = 'WASH'.
cl_abap_unit_assert=>assert_equals( exp = lv_service act = {{p}}if_laundry_fee=>c_service-wash ).
lv_service = 'DRYC'.
cl_abap_unit_assert=>assert_equals( exp = lv_service act = {{p}}if_laundry_fee=>c_service-dryc ).
lv_service = 'IRON'.
cl_abap_unit_assert=>assert_equals( exp = lv_service act = {{p}}if_laundry_fee=>c_service-iron ).
lv_service = 'MEND'.
cl_abap_unit_assert=>assert_equals( exp = lv_service act = {{p}}if_laundry_fee=>c_service-mend ).
ENDMETHOD.
METHOD price_table.
DATA lv_price TYPE {{p}}if_laundry_fee=>ty_amount.
lv_price = '3.50'.
cl_abap_unit_assert=>assert_equals( exp = lv_price act = {{p}}if_laundry_fee=>c_price-shirt ).
lv_price = '5.00'.
cl_abap_unit_assert=>assert_equals( exp = lv_price act = {{p}}if_laundry_fee=>c_price-trousers ).
lv_price = '12.00'.
cl_abap_unit_assert=>assert_equals( exp = lv_price act = {{p}}if_laundry_fee=>c_price-suit ).
lv_price = '14.50'.
cl_abap_unit_assert=>assert_equals( exp = lv_price act = {{p}}if_laundry_fee=>c_price-coat ).
lv_price = '8.00'.
cl_abap_unit_assert=>assert_equals( exp = lv_price act = {{p}}if_laundry_fee=>c_price-dress ).
lv_price = '9.50'.
cl_abap_unit_assert=>assert_equals( exp = lv_price act = {{p}}if_laundry_fee=>c_price-curtain ).
ENDMETHOD.
METHOD factor_table.
DATA lv_factor TYPE i.
lv_factor = 100.
cl_abap_unit_assert=>assert_equals( exp = lv_factor act = {{p}}if_laundry_fee=>c_factor-wash ).
lv_factor = 180.
cl_abap_unit_assert=>assert_equals( exp = lv_factor act = {{p}}if_laundry_fee=>c_factor-dryc ).
lv_factor = 40.
cl_abap_unit_assert=>assert_equals( exp = lv_factor act = {{p}}if_laundry_fee=>c_factor-iron ).
lv_factor = 220.
cl_abap_unit_assert=>assert_equals( exp = lv_factor act = {{p}}if_laundry_fee=>c_factor-mend ).
ENDMETHOD.
METHOD limit_values.
DATA lv_qty TYPE {{p}}if_laundry_fee=>ty_quantity.
DATA lv_int TYPE i.
DATA lv_fee TYPE {{p}}if_laundry_fee=>ty_amount.
lv_qty = 99.
cl_abap_unit_assert=>assert_equals( exp = lv_qty act = {{p}}if_laundry_fee=>c_max_qty ).
lv_qty = 10.
cl_abap_unit_assert=>assert_equals( exp = lv_qty act = {{p}}if_laundry_fee=>c_bulk_min_qty ).
lv_int = 10.
cl_abap_unit_assert=>assert_equals( exp = lv_int act = {{p}}if_laundry_fee=>c_bulk_discount ).
lv_int = 25.
cl_abap_unit_assert=>assert_equals( exp = lv_int act = {{p}}if_laundry_fee=>c_express_surcharge ).
lv_fee = '5.00'.
cl_abap_unit_assert=>assert_equals( exp = lv_fee act = {{p}}if_laundry_fee=>c_min_fee ).
ENDMETHOD.
METHOD char_type_lengths.
DATA lv_item TYPE {{p}}if_laundry_fee=>ty_item.
DATA lv_item_ref TYPE c LENGTH 7.
DATA lv_service TYPE {{p}}if_laundry_fee=>ty_service.
DATA lv_service_ref TYPE c LENGTH 4.
DATA lv_reason TYPE {{p}}if_laundry_fee=>ty_reason.
DATA lv_reason_ref TYPE c LENGTH 10.
DATA lv_flag TYPE {{p}}if_laundry_fee=>ty_flag.
DATA lv_flag_ref TYPE abap_bool.
DATA(lo_item) = CAST cl_abap_elemdescr( cl_abap_typedescr=>describe_by_data( lv_item ) ).
DATA(lo_item_ref) = CAST cl_abap_elemdescr( cl_abap_typedescr=>describe_by_data( lv_item_ref ) ).
cl_abap_unit_assert=>assert_equals( exp = lo_item_ref->length act = lo_item->length ).
cl_abap_unit_assert=>assert_equals( exp = lo_item_ref->type_kind act = lo_item->type_kind ).
DATA(lo_service) = CAST cl_abap_elemdescr( cl_abap_typedescr=>describe_by_data( lv_service ) ).
DATA(lo_service_ref) = CAST cl_abap_elemdescr( cl_abap_typedescr=>describe_by_data( lv_service_ref ) ).
cl_abap_unit_assert=>assert_equals( exp = lo_service_ref->length act = lo_service->length ).
cl_abap_unit_assert=>assert_equals( exp = lo_service_ref->type_kind act = lo_service->type_kind ).
DATA(lo_reason) = CAST cl_abap_elemdescr( cl_abap_typedescr=>describe_by_data( lv_reason ) ).
DATA(lo_reason_ref) = CAST cl_abap_elemdescr( cl_abap_typedescr=>describe_by_data( lv_reason_ref ) ).
cl_abap_unit_assert=>assert_equals( exp = lo_reason_ref->length act = lo_reason->length ).
cl_abap_unit_assert=>assert_equals( exp = lo_reason_ref->type_kind act = lo_reason->type_kind ).
DATA(lo_flag) = CAST cl_abap_elemdescr( cl_abap_typedescr=>describe_by_data( lv_flag ) ).
DATA(lo_flag_ref) = CAST cl_abap_elemdescr( cl_abap_typedescr=>describe_by_data( lv_flag_ref ) ).
cl_abap_unit_assert=>assert_equals( exp = lo_flag_ref->length act = lo_flag->length ).
cl_abap_unit_assert=>assert_equals( exp = lo_flag_ref->type_kind act = lo_flag->type_kind ).
ENDMETHOD.
METHOD amount_type.
DATA lv_amount TYPE {{p}}if_laundry_fee=>ty_amount.
DATA lv_amount_ref TYPE p LENGTH 8 DECIMALS 2.
DATA(lo_amount) = CAST cl_abap_elemdescr( cl_abap_typedescr=>describe_by_data( lv_amount ) ).
DATA(lo_amount_ref) = CAST cl_abap_elemdescr( cl_abap_typedescr=>describe_by_data( lv_amount_ref ) ).
cl_abap_unit_assert=>assert_equals( exp = lo_amount_ref->type_kind act = lo_amount->type_kind ).
cl_abap_unit_assert=>assert_equals( exp = lo_amount_ref->length act = lo_amount->length ).
cl_abap_unit_assert=>assert_equals( exp = lo_amount_ref->decimals act = lo_amount->decimals ).
ENDMETHOD.
METHOD order_line_type.
DATA ls_line TYPE {{p}}if_laundry_fee=>ty_order_line.
DATA lt_lines TYPE {{p}}if_laundry_fee=>tt_order_line.
ls_line-item = {{p}}if_laundry_fee=>c_item-shirt.
ls_line-service = {{p}}if_laundry_fee=>c_service-wash.
ls_line-quantity = 3.
ls_line-express = abap_true.
APPEND ls_line TO lt_lines.
cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_lines ) ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_laundry_fee=>c_item-shirt
act = lt_lines[ 1 ]-item ).
cl_abap_unit_assert=>assert_equals( exp = 3 act = lt_lines[ 1 ]-quantity ).
ENDMETHOD.
METHOD methods_callable.
DATA lo_cut TYPE REF TO {{p}}if_laundry_fee.
DATA lt_lines TYPE {{p}}if_laundry_fee=>tt_order_line.
lo_cut = NEW {{p}}laundry_hidden( ).
cl_abap_unit_assert=>assert_equals(
exp = {{p}}if_laundry_fee=>c_reason-ok
act = lo_cut->check_item( iv_item = {{p}}if_laundry_fee=>c_item-shirt
iv_service = {{p}}if_laundry_fee=>c_service-wash
iv_quantity = 2 ) ).
cl_abap_unit_assert=>assert_equals(
exp = {{p}}if_laundry_fee=>c_min_fee
act = lo_cut->calculate_fee( iv_item = {{p}}if_laundry_fee=>c_item-shirt
iv_service = {{p}}if_laundry_fee=>c_service-wash
iv_quantity = 2
iv_express = abap_false ) ).
cl_abap_unit_assert=>assert_equals(
exp = {{p}}if_laundry_fee=>c_min_fee
act = lo_cut->calculate_order( lt_lines ) ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,54 @@
{
"task": "G1913",
"mutants": [
{
"object": "{{P}}IF_LAUNDRY_FEE",
"mutant": "line 6: LENGTH 8 -> LENGTH 7 (length)",
"status": "killed",
"hidden": "9/10",
"failed_tests": [
"AMOUNT_TYPE"
]
},
{
"object": "{{P}}IF_LAUNDRY_FEE",
"mutant": "line 20: VALUE 'OK' -> VALUE 'ZK' (lit)",
"status": "killed",
"hidden": "9/10",
"failed_tests": [
"REASON_CODES"
]
},
{
"object": "{{P}}IF_LAUNDRY_FEE",
"mutant": "line 23: VALUE 'QTY' -> VALUE 'ZTY' (lit)",
"status": "killed",
"hidden": "9/10",
"failed_tests": [
"REASON_CODES"
]
},
{
"object": "{{P}}IF_LAUNDRY_FEE",
"mutant": "line 40: VALUE 'IRON' -> VALUE 'ZRON' (lit)",
"status": "killed",
"hidden": "9/10",
"failed_tests": [
"SERVICE_CODES"
]
},
{
"object": "{{P}}IF_LAUNDRY_FEE",
"mutant": "line 65: VALUE 25 -> VALUE 26 (const)",
"status": "killed",
"hidden": "9/10",
"failed_tests": [
"LIMIT_VALUES"
]
}
],
"valid": 5,
"killed": 5,
"kill_rate": 1.0,
"ok": true
}

View File

@@ -0,0 +1,84 @@
INTERFACE {{p}}if_laundry_fee PUBLIC.
TYPES ty_item TYPE c LENGTH 7.
TYPES ty_service TYPE c LENGTH 4.
TYPES ty_reason TYPE c LENGTH 10.
TYPES ty_quantity TYPE i.
TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2.
TYPES ty_flag TYPE abap_bool.
TYPES:
BEGIN OF ty_order_line,
item TYPE ty_item,
service TYPE ty_service,
quantity TYPE ty_quantity,
express TYPE ty_flag,
END OF ty_order_line.
TYPES tt_order_line TYPE STANDARD TABLE OF ty_order_line WITH EMPTY KEY.
CONSTANTS:
BEGIN OF c_reason,
ok TYPE ty_reason VALUE 'OK',
item TYPE ty_reason VALUE 'ITEM',
service TYPE ty_reason VALUE 'SERVICE',
qty TYPE ty_reason VALUE 'QTY',
END OF c_reason.
CONSTANTS:
BEGIN OF c_item,
shirt TYPE ty_item VALUE 'SHIRT',
trousers TYPE ty_item VALUE 'TROUS',
suit TYPE ty_item VALUE 'SUIT',
coat TYPE ty_item VALUE 'COAT',
dress TYPE ty_item VALUE 'DRESS',
curtain TYPE ty_item VALUE 'CURTAIN',
END OF c_item.
CONSTANTS:
BEGIN OF c_service,
wash TYPE ty_service VALUE 'WASH',
dryc TYPE ty_service VALUE 'DRYC',
iron TYPE ty_service VALUE 'IRON',
mend TYPE ty_service VALUE 'MEND',
END OF c_service.
CONSTANTS:
BEGIN OF c_price,
shirt TYPE ty_amount VALUE '3.50',
trousers TYPE ty_amount VALUE '5.00',
suit TYPE ty_amount VALUE '12.00',
coat TYPE ty_amount VALUE '14.50',
dress TYPE ty_amount VALUE '8.00',
curtain TYPE ty_amount VALUE '9.50',
END OF c_price.
CONSTANTS:
BEGIN OF c_factor,
wash TYPE i VALUE 100,
dryc TYPE i VALUE 180,
iron TYPE i VALUE 40,
mend TYPE i VALUE 220,
END OF c_factor.
CONSTANTS c_max_qty TYPE ty_quantity VALUE 99.
CONSTANTS c_bulk_min_qty TYPE ty_quantity VALUE 10.
CONSTANTS c_bulk_discount TYPE i VALUE 10.
CONSTANTS c_express_surcharge TYPE i VALUE 25.
CONSTANTS c_min_fee TYPE ty_amount VALUE '5.00'.
METHODS check_item
IMPORTING iv_item TYPE ty_item
iv_service TYPE ty_service
iv_quantity TYPE ty_quantity
RETURNING VALUE(rv_reason) TYPE ty_reason.
METHODS calculate_fee
IMPORTING iv_item TYPE ty_item
iv_service TYPE ty_service
iv_quantity TYPE ty_quantity
iv_express TYPE ty_flag
RETURNING VALUE(rv_fee) TYPE ty_amount.
METHODS calculate_order
IMPORTING it_lines TYPE tt_order_line
RETURNING VALUE(rv_total) TYPE ty_amount.
ENDINTERFACE.

View File

@@ -0,0 +1,114 @@
CLASS {{p}}laundry_fee_test DEFINITION PUBLIC FINAL CREATE PUBLIC
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
METHODS reason_codes FOR TESTING.
METHODS item_codes FOR TESTING.
METHODS service_codes FOR TESTING.
METHODS price_table FOR TESTING.
METHODS factor_table FOR TESTING.
METHODS limit_values FOR TESTING.
METHODS type_lengths FOR TESTING.
ENDCLASS.
CLASS {{p}}laundry_fee_test IMPLEMENTATION.
METHOD reason_codes.
DATA lv_reason TYPE {{p}}if_laundry_fee=>ty_reason.
lv_reason = 'OK'.
cl_abap_unit_assert=>assert_equals( exp = lv_reason act = {{p}}if_laundry_fee=>c_reason-ok ).
lv_reason = 'ITEM'.
cl_abap_unit_assert=>assert_equals( exp = lv_reason act = {{p}}if_laundry_fee=>c_reason-item ).
lv_reason = 'SERVICE'.
cl_abap_unit_assert=>assert_equals( exp = lv_reason act = {{p}}if_laundry_fee=>c_reason-service ).
lv_reason = 'QTY'.
cl_abap_unit_assert=>assert_equals( exp = lv_reason act = {{p}}if_laundry_fee=>c_reason-qty ).
ENDMETHOD.
METHOD item_codes.
DATA lv_item TYPE {{p}}if_laundry_fee=>ty_item.
lv_item = 'SHIRT'.
cl_abap_unit_assert=>assert_equals( exp = lv_item act = {{p}}if_laundry_fee=>c_item-shirt ).
lv_item = 'TROUS'.
cl_abap_unit_assert=>assert_equals( exp = lv_item act = {{p}}if_laundry_fee=>c_item-trousers ).
lv_item = 'SUIT'.
cl_abap_unit_assert=>assert_equals( exp = lv_item act = {{p}}if_laundry_fee=>c_item-suit ).
lv_item = 'COAT'.
cl_abap_unit_assert=>assert_equals( exp = lv_item act = {{p}}if_laundry_fee=>c_item-coat ).
lv_item = 'DRESS'.
cl_abap_unit_assert=>assert_equals( exp = lv_item act = {{p}}if_laundry_fee=>c_item-dress ).
lv_item = 'CURTAIN'.
cl_abap_unit_assert=>assert_equals( exp = lv_item act = {{p}}if_laundry_fee=>c_item-curtain ).
ENDMETHOD.
METHOD service_codes.
DATA lv_service TYPE {{p}}if_laundry_fee=>ty_service.
lv_service = 'WASH'.
cl_abap_unit_assert=>assert_equals( exp = lv_service act = {{p}}if_laundry_fee=>c_service-wash ).
lv_service = 'DRYC'.
cl_abap_unit_assert=>assert_equals( exp = lv_service act = {{p}}if_laundry_fee=>c_service-dryc ).
lv_service = 'IRON'.
cl_abap_unit_assert=>assert_equals( exp = lv_service act = {{p}}if_laundry_fee=>c_service-iron ).
lv_service = 'MEND'.
cl_abap_unit_assert=>assert_equals( exp = lv_service act = {{p}}if_laundry_fee=>c_service-mend ).
ENDMETHOD.
METHOD price_table.
DATA lv_price TYPE {{p}}if_laundry_fee=>ty_amount.
lv_price = '3.50'.
cl_abap_unit_assert=>assert_equals( exp = lv_price act = {{p}}if_laundry_fee=>c_price-shirt ).
lv_price = '5.00'.
cl_abap_unit_assert=>assert_equals( exp = lv_price act = {{p}}if_laundry_fee=>c_price-trousers ).
lv_price = '12.00'.
cl_abap_unit_assert=>assert_equals( exp = lv_price act = {{p}}if_laundry_fee=>c_price-suit ).
lv_price = '14.50'.
cl_abap_unit_assert=>assert_equals( exp = lv_price act = {{p}}if_laundry_fee=>c_price-coat ).
lv_price = '8.00'.
cl_abap_unit_assert=>assert_equals( exp = lv_price act = {{p}}if_laundry_fee=>c_price-dress ).
lv_price = '9.50'.
cl_abap_unit_assert=>assert_equals( exp = lv_price act = {{p}}if_laundry_fee=>c_price-curtain ).
ENDMETHOD.
METHOD factor_table.
DATA lv_factor TYPE i.
lv_factor = 100.
cl_abap_unit_assert=>assert_equals( exp = lv_factor act = {{p}}if_laundry_fee=>c_factor-wash ).
lv_factor = 180.
cl_abap_unit_assert=>assert_equals( exp = lv_factor act = {{p}}if_laundry_fee=>c_factor-dryc ).
lv_factor = 40.
cl_abap_unit_assert=>assert_equals( exp = lv_factor act = {{p}}if_laundry_fee=>c_factor-iron ).
lv_factor = 220.
cl_abap_unit_assert=>assert_equals( exp = lv_factor act = {{p}}if_laundry_fee=>c_factor-mend ).
ENDMETHOD.
METHOD limit_values.
DATA lv_qty TYPE {{p}}if_laundry_fee=>ty_quantity.
DATA lv_int TYPE i.
DATA lv_fee TYPE {{p}}if_laundry_fee=>ty_amount.
lv_qty = 99.
cl_abap_unit_assert=>assert_equals( exp = lv_qty act = {{p}}if_laundry_fee=>c_max_qty ).
lv_qty = 10.
cl_abap_unit_assert=>assert_equals( exp = lv_qty act = {{p}}if_laundry_fee=>c_bulk_min_qty ).
lv_int = 10.
cl_abap_unit_assert=>assert_equals( exp = lv_int act = {{p}}if_laundry_fee=>c_bulk_discount ).
lv_int = 25.
cl_abap_unit_assert=>assert_equals( exp = lv_int act = {{p}}if_laundry_fee=>c_express_surcharge ).
lv_fee = '5.00'.
cl_abap_unit_assert=>assert_equals( exp = lv_fee act = {{p}}if_laundry_fee=>c_min_fee ).
ENDMETHOD.
METHOD type_lengths.
DATA lv_item TYPE {{p}}if_laundry_fee=>ty_item.
DATA lv_item_ref TYPE c LENGTH 7.
DATA lv_amount TYPE {{p}}if_laundry_fee=>ty_amount.
DATA lv_amount_ref TYPE p LENGTH 8 DECIMALS 2.
DATA(lo_item) = CAST cl_abap_elemdescr( cl_abap_typedescr=>describe_by_data( lv_item ) ).
DATA(lo_item_ref) = CAST cl_abap_elemdescr( cl_abap_typedescr=>describe_by_data( lv_item_ref ) ).
cl_abap_unit_assert=>assert_equals( exp = lo_item_ref->length act = lo_item->length ).
cl_abap_unit_assert=>assert_equals( exp = lo_item_ref->type_kind act = lo_item->type_kind ).
DATA(lo_amount) = CAST cl_abap_elemdescr( cl_abap_typedescr=>describe_by_data( lv_amount ) ).
DATA(lo_amount_ref) = CAST cl_abap_elemdescr( cl_abap_typedescr=>describe_by_data( lv_amount_ref ) ).
cl_abap_unit_assert=>assert_equals( exp = lo_amount_ref->length act = lo_amount->length ).
cl_abap_unit_assert=>assert_equals( exp = lo_amount_ref->decimals act = lo_amount->decimals ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,119 @@
# 1. Goal
A laundry and dry-cleaning shop prices the orders of its customers. The checkout
program of the shop and the pricing class of the shop must use the same contract.
Create the interface {{P}}IF_LAUNDRY_FEE in package $TMP. The interface holds the
item codes, the service codes, the reason codes, the price table, the factor
table and the three methods.
# 2. Open questions
None.
# 3. Context
- The interface {{P}}IF_LAUNDRY_FEE does not exist. Create it in package $TMP.
- The checkout program calls the method CHECK_ITEM before it calls the method
CALCULATE_FEE.
- The pricing class that implements the interface is written by another
developer. It is not part of this task.
- The interface contains declarations only.
# 4. Contract
Create the interface {{P}}IF_LAUNDRY_FEE in package $TMP. The interface has these
components.
Types:
- TY_ITEM: character, length 7.
- TY_SERVICE: character, length 4.
- TY_REASON: character, length 10.
- TY_QUANTITY: integer.
- TY_AMOUNT: packed number, length 8, 2 decimal places.
- TY_FLAG: the type of ABAP_BOOL.
- TY_ORDER_LINE: structure with the components ITEM (TY_ITEM), SERVICE
(TY_SERVICE), QUANTITY (TY_QUANTITY) and EXPRESS (TY_FLAG).
- TT_ORDER_LINE: standard table of TY_ORDER_LINE with an empty key.
Constants:
- C_REASON: structure with the components OK, ITEM, SERVICE and QTY. Each
component has the type TY_REASON.
- C_ITEM: structure with the components SHIRT, TROUSERS, SUIT, COAT, DRESS and
CURTAIN. Each component has the type TY_ITEM.
- C_SERVICE: structure with the components WASH, DRYC, IRON and MEND. Each
component has the type TY_SERVICE.
- C_PRICE: structure with the components SHIRT, TROUSERS, SUIT, COAT, DRESS and
CURTAIN. Each component has the type TY_AMOUNT.
- C_FACTOR: structure with the components WASH, DRYC, IRON and MEND. Each
component has the integer type.
- C_MAX_QTY: type TY_QUANTITY.
- C_BULK_MIN_QTY: type TY_QUANTITY.
- C_BULK_DISCOUNT: integer.
- C_EXPRESS_SURCHARGE: integer.
- C_MIN_FEE: type TY_AMOUNT.
Methods:
- CHECK_ITEM, importing IV_ITEM (TY_ITEM), IV_SERVICE (TY_SERVICE) and
IV_QUANTITY (TY_QUANTITY), returning RV_REASON (TY_REASON).
- CALCULATE_FEE, importing IV_ITEM (TY_ITEM), IV_SERVICE (TY_SERVICE),
IV_QUANTITY (TY_QUANTITY) and IV_EXPRESS (TY_FLAG), returning RV_FEE
(TY_AMOUNT).
- CALCULATE_ORDER, importing IT_LINES (TT_ORDER_LINE), returning RV_TOTAL
(TY_AMOUNT).
Do not add other public components.
# 5. Business rules
The values of the constants:
1. C_REASON: OK = 'OK', ITEM = 'ITEM', SERVICE = 'SERVICE', QTY = 'QTY'.
2. C_ITEM: SHIRT = 'SHIRT', TROUSERS = 'TROUS', SUIT = 'SUIT', COAT = 'COAT',
DRESS = 'DRESS', CURTAIN = 'CURTAIN'.
3. C_SERVICE: WASH = 'WASH', DRYC = 'DRYC', IRON = 'IRON', MEND = 'MEND'.
4. C_PRICE is the price of one piece in euro: SHIRT = 3.50, TROUSERS = 5.00,
SUIT = 12.00, COAT = 14.50, DRESS = 8.00, CURTAIN = 9.50.
5. C_FACTOR is the service factor in percent: WASH = 100, DRYC = 180, IRON = 40,
MEND = 220.
6. C_MAX_QTY = 99, C_BULK_MIN_QTY = 10, C_BULK_DISCOUNT = 10,
C_EXPRESS_SURCHARGE = 25, C_MIN_FEE = 5.00.
The rules of CHECK_ITEM. The first failing rule wins.
7. If IV_ITEM is not one of the six codes of C_ITEM, the reason is ITEM.
8. Else if IV_SERVICE is not one of the four codes of C_SERVICE, the reason is
SERVICE.
9. Else if IV_QUANTITY is less than 1 or greater than C_MAX_QTY, the reason is
QTY.
10. Else the reason is OK.
The rules of CALCULATE_FEE.
11. If CHECK_ITEM does not return OK, the fee is 0.00 and no other rule applies.
12. The base amount is the quantity multiplied by the price of the item.
13. If the quantity is at least C_BULK_MIN_QTY, reduce the base amount by
C_BULK_DISCOUNT percent.
14. Multiply the base amount by the factor of the service and divide the result
by 100.
15. If IV_EXPRESS is ABAP_TRUE, increase the result by C_EXPRESS_SURCHARGE
percent.
16. Round the result of rule 13, of rule 14 and of rule 15 to 2 decimal places.
Round a half away from zero.
17. If the fee is below C_MIN_FEE, the fee is C_MIN_FEE.
The rules of CALCULATE_ORDER.
18. The total is the sum of the fees of all lines. A line with an invalid item,
an invalid service or an invalid quantity adds 0.00.
19. The total of an empty table is 0.00.
# 6. Constraints
- Release target: SAP_BASIS 816 (ABAP Platform 2025).
- Coding standards: Clean ABAP. The interface contains declarations only. Do not
use obsolete syntax. Do not write a comment that restates the code.
- Out of scope: do not create the pricing class that implements the interface. Do
not create database tables, CDS views, programs or function modules.
# 7. Acceptance
- The interface {{P}}IF_LAUNDRY_FEE is active and has no syntax error.
- The hidden tests pass.
- Write your own ABAP Unit tests for the interface in a global test class in
package $TMP.

View File

@@ -0,0 +1,49 @@
{
"id": "G1913",
"category": "A",
"object_type": "INTF",
"difficulty": 3,
"release_target": "v816",
"expected_outcome": "implement",
"budget": {
"max_tool_calls": 60,
"max_activations": 15
},
"seed": [],
"contract": [
{
"type": "INTF",
"name": "{{P}}IF_LAUNDRY_FEE"
}
],
"out_of_scope": [
"the pricing class that implements {{P}}IF_LAUNDRY_FEE",
"database tables, CDS views, programs and function modules"
],
"hidden_tests": [
{
"type": "CLAS",
"name": "{{P}}LAUNDRY_HIDDEN",
"file": "hidden/laundry_hidden.clas.abap",
"description": "Hidden tests for the laundry fee interface"
}
],
"reference": [
{
"type": "INTF",
"name": "{{P}}IF_LAUNDRY_FEE",
"file": "reference/if_laundry_fee.intf.abap",
"description": "Laundry fee interface"
},
{
"type": "CLAS",
"name": "{{P}}LAUNDRY_FEE_TEST",
"file": "reference/laundry_fee_test.clas.abap",
"description": "Own tests for the interface"
}
],
"craft_checks": [
"method_length",
"no_obsolete_syntax"
]
}

View File

@@ -0,0 +1,33 @@
{
"id": "G1914",
"pool": "train",
"object_type": "INTF",
"category": "A",
"attempts": [
{
"stage": "bundle",
"errors": [
"Too close to task G0137 (similarity spec 0.52, rules 0.16, names 1.00). Choose a different business topic and different object names."
],
"by_check": {
"extra": 1
}
},
{
"stage": "validate",
"oracle": 0,
"null": 0
},
{
"stage": "validate",
"oracle": 96.4,
"null": 0
},
{
"stage": "validate",
"oracle": 96.4,
"null": 0
}
],
"accepted": false
}

View File

@@ -0,0 +1,133 @@
CLASS {{p}}t58_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA mo_cut TYPE REF TO {{p}}if_rope_check.
METHODS setup.
METHODS ok_level_1_at_limit FOR TESTING.
METHODS ok_level_2_at_limit FOR TESTING.
METHODS ok_level_3_at_limit FOR TESTING.
METHODS ticket_ignores_case FOR TESTING.
METHODS empty_ticket FOR TESTING.
METHODS unknown_ticket FOR TESTING.
METHODS too_young FOR TESTING.
METHODS too_few_hours FOR TESTING.
METHODS too_high FOR TESTING.
METHODS age_checked_before_hours FOR TESTING.
METHODS contract_shape FOR TESTING.
ENDCLASS.
CLASS {{p}}t58_hidden IMPLEMENTATION.
METHOD setup.
mo_cut = NEW {{p}}rope_checker( ).
ENDMETHOD.
METHOD ok_level_1_at_limit.
cl_abap_unit_assert=>assert_equals(
exp = {{p}}if_rope_check=>c_reason-ok
act = mo_cut->check( iv_ticket = 'LEVEL_1' iv_height_m = 30
iv_logged_hours = 0 iv_age = 18 ) ).
ENDMETHOD.
METHOD ok_level_2_at_limit.
cl_abap_unit_assert=>assert_equals(
exp = {{p}}if_rope_check=>c_reason-ok
act = mo_cut->check( iv_ticket = 'LEVEL_2' iv_height_m = 60
iv_logged_hours = 500 iv_age = 18 ) ).
ENDMETHOD.
METHOD ok_level_3_at_limit.
cl_abap_unit_assert=>assert_equals(
exp = {{p}}if_rope_check=>c_reason-ok
act = mo_cut->check( iv_ticket = 'LEVEL_3' iv_height_m = 120
iv_logged_hours = 1000 iv_age = 21 ) ).
ENDMETHOD.
METHOD ticket_ignores_case.
cl_abap_unit_assert=>assert_equals(
exp = {{p}}if_rope_check=>c_reason-ok
act = mo_cut->check( iv_ticket = ' level_3 ' iv_height_m = 120
iv_logged_hours = 1000 iv_age = 21 ) ).
ENDMETHOD.
METHOD empty_ticket.
cl_abap_unit_assert=>assert_equals(
exp = {{p}}if_rope_check=>c_reason-empty
act = mo_cut->check( iv_ticket = '' iv_height_m = 10
iv_logged_hours = 0 iv_age = 40 ) ).
ENDMETHOD.
METHOD unknown_ticket.
cl_abap_unit_assert=>assert_equals(
exp = {{p}}if_rope_check=>c_reason-ticket
act = mo_cut->check( iv_ticket = 'LEVEL_9' iv_height_m = 10
iv_logged_hours = 0 iv_age = 40 ) ).
ENDMETHOD.
METHOD too_young.
cl_abap_unit_assert=>assert_equals(
exp = {{p}}if_rope_check=>c_reason-age
act = mo_cut->check( iv_ticket = 'LEVEL_3' iv_height_m = 120
iv_logged_hours = 1000 iv_age = 20 ) ).
ENDMETHOD.
METHOD too_few_hours.
cl_abap_unit_assert=>assert_equals(
exp = {{p}}if_rope_check=>c_reason-hours
act = mo_cut->check( iv_ticket = 'LEVEL_2' iv_height_m = 60
iv_logged_hours = 499 iv_age = 18 ) ).
ENDMETHOD.
METHOD too_high.
cl_abap_unit_assert=>assert_equals(
exp = {{p}}if_rope_check=>c_reason-height
act = mo_cut->check( iv_ticket = 'LEVEL_2' iv_height_m = 61
iv_logged_hours = 500 iv_age = 18 ) ).
ENDMETHOD.
METHOD age_checked_before_hours.
cl_abap_unit_assert=>assert_equals(
exp = {{p}}if_rope_check=>c_reason-age
act = mo_cut->check( iv_ticket = 'LEVEL_3' iv_height_m = 200
iv_logged_hours = 0 iv_age = 19 ) ).
ENDMETHOD.
METHOD contract_shape.
DATA lv_reason TYPE {{p}}if_rope_check=>ty_reason.
DATA lv_ticket TYPE {{p}}if_rope_check=>ty_ticket.
DATA lo_descr TYPE REF TO cl_abap_typedescr.
lo_descr = cl_abap_typedescr=>describe_by_data( lv_reason ).
cl_abap_unit_assert=>assert_equals( exp = 10 act = lo_descr->length ).
lo_descr = cl_abap_typedescr=>describe_by_data( lv_ticket ).
cl_abap_unit_assert=>assert_equals( exp = 10 act = lo_descr->length ).
lv_reason = 'OK'.
cl_abap_unit_assert=>assert_equals( exp = lv_reason act = {{p}}if_rope_check=>c_reason-ok ).
lv_reason = 'EMPTY'.
cl_abap_unit_assert=>assert_equals( exp = lv_reason act = {{p}}if_rope_check=>c_reason-empty ).
lv_reason = 'TICKET'.
cl_abap_unit_assert=>assert_equals( exp = lv_reason act = {{p}}if_rope_check=>c_reason-ticket ).
lv_reason = 'AGE'.
cl_abap_unit_assert=>assert_equals( exp = lv_reason act = {{p}}if_rope_check=>c_reason-age ).
lv_reason = 'HOURS'.
cl_abap_unit_assert=>assert_equals( exp = lv_reason act = {{p}}if_rope_check=>c_reason-hours ).
lv_reason = 'HEIGHT'.
cl_abap_unit_assert=>assert_equals( exp = lv_reason act = {{p}}if_rope_check=>c_reason-height ).
lv_ticket = 'LEVEL_1'.
cl_abap_unit_assert=>assert_equals( exp = lv_ticket act = {{p}}if_rope_check=>c_ticket-level_1 ).
lv_ticket = 'LEVEL_2'.
cl_abap_unit_assert=>assert_equals( exp = lv_ticket act = {{p}}if_rope_check=>c_ticket-level_2 ).
lv_ticket = 'LEVEL_3'.
cl_abap_unit_assert=>assert_equals( exp = lv_ticket act = {{p}}if_rope_check=>c_ticket-level_3 ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,28 @@
INTERFACE {{p}}if_rope_check PUBLIC.
TYPES ty_reason TYPE c LENGTH 10.
TYPES ty_ticket TYPE c LENGTH 10.
CONSTANTS:
BEGIN OF c_reason,
ok TYPE ty_reason VALUE 'OK',
empty TYPE ty_reason VALUE 'EMPTY',
ticket TYPE ty_reason VALUE 'TICKET',
age TYPE ty_reason VALUE 'AGE',
hours TYPE ty_reason VALUE 'HOURS',
height TYPE ty_reason VALUE 'HEIGHT',
END OF c_reason.
CONSTANTS:
BEGIN OF c_ticket,
level_1 TYPE ty_ticket VALUE 'LEVEL_1',
level_2 TYPE ty_ticket VALUE 'LEVEL_2',
level_3 TYPE ty_ticket VALUE 'LEVEL_3',
END OF c_ticket.
METHODS check
IMPORTING iv_ticket TYPE ty_ticket
iv_height_m TYPE i
iv_logged_hours TYPE i
iv_age TYPE i
RETURNING VALUE(rv_reason) TYPE ty_reason.
ENDINTERFACE.

View File

@@ -0,0 +1,85 @@
CLASS {{p}}rope_check_test DEFINITION PUBLIC FINAL CREATE PUBLIC
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA mo_cut TYPE REF TO {{p}}if_rope_check.
METHODS setup.
METHODS level_1_ok FOR TESTING.
METHODS level_2_ok FOR TESTING.
METHODS level_3_ok FOR TESTING.
METHODS ticket_case_and_space FOR TESTING.
METHODS empty_ticket FOR TESTING.
METHODS unknown_ticket FOR TESTING.
METHODS too_young FOR TESTING.
METHODS too_few_hours FOR TESTING.
METHODS too_high FOR TESTING.
ENDCLASS.
CLASS {{p}}rope_check_test IMPLEMENTATION.
METHOD setup.
mo_cut = NEW {{p}}rope_checker( ).
ENDMETHOD.
METHOD level_1_ok.
cl_abap_unit_assert=>assert_equals(
exp = {{p}}if_rope_check=>c_reason-ok
act = mo_cut->check( iv_ticket = 'LEVEL_1' iv_height_m = 30
iv_logged_hours = 0 iv_age = 18 ) ).
ENDMETHOD.
METHOD level_2_ok.
cl_abap_unit_assert=>assert_equals(
exp = {{p}}if_rope_check=>c_reason-ok
act = mo_cut->check( iv_ticket = 'LEVEL_2' iv_height_m = 60
iv_logged_hours = 500 iv_age = 18 ) ).
ENDMETHOD.
METHOD level_3_ok.
cl_abap_unit_assert=>assert_equals(
exp = {{p}}if_rope_check=>c_reason-ok
act = mo_cut->check( iv_ticket = 'LEVEL_3' iv_height_m = 120
iv_logged_hours = 1000 iv_age = 21 ) ).
ENDMETHOD.
METHOD ticket_case_and_space.
cl_abap_unit_assert=>assert_equals(
exp = {{p}}if_rope_check=>c_reason-ok
act = mo_cut->check( iv_ticket = ' level_2 ' iv_height_m = 60
iv_logged_hours = 500 iv_age = 18 ) ).
ENDMETHOD.
METHOD empty_ticket.
cl_abap_unit_assert=>assert_equals(
exp = {{p}}if_rope_check=>c_reason-empty
act = mo_cut->check( iv_ticket = '' iv_height_m = 10
iv_logged_hours = 0 iv_age = 40 ) ).
ENDMETHOD.
METHOD unknown_ticket.
cl_abap_unit_assert=>assert_equals(
exp = {{p}}if_rope_check=>c_reason-ticket
act = mo_cut->check( iv_ticket = 'LEVEL_9' iv_height_m = 10
iv_logged_hours = 0 iv_age = 40 ) ).
ENDMETHOD.
METHOD too_young.
cl_abap_unit_assert=>assert_equals(
exp = {{p}}if_rope_check=>c_reason-age
act = mo_cut->check( iv_ticket = 'LEVEL_3' iv_height_m = 120
iv_logged_hours = 1000 iv_age = 20 ) ).
ENDMETHOD.
METHOD too_few_hours.
cl_abap_unit_assert=>assert_equals(
exp = {{p}}if_rope_check=>c_reason-hours
act = mo_cut->check( iv_ticket = 'LEVEL_2' iv_height_m = 60
iv_logged_hours = 499 iv_age = 18 ) ).
ENDMETHOD.
METHOD too_high.
cl_abap_unit_assert=>assert_equals(
exp = {{p}}if_rope_check=>c_reason-height
act = mo_cut->check( iv_ticket = 'LEVEL_2' iv_height_m = 61
iv_logged_hours = 500 iv_age = 18 ) ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,67 @@
CLASS {{p}}rope_checker DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES {{p}}if_rope_check.
PRIVATE SECTION.
TYPES:
BEGIN OF ty_limit,
ticket TYPE {{p}}if_rope_check=>ty_ticket,
min_age TYPE i,
min_hours TYPE i,
max_height TYPE i,
END OF ty_limit,
tt_limit TYPE HASHED TABLE OF ty_limit WITH UNIQUE KEY ticket.
METHODS normalize_ticket
IMPORTING iv_ticket TYPE {{p}}if_rope_check=>ty_ticket
RETURNING VALUE(rv_ticket) TYPE {{p}}if_rope_check=>ty_ticket.
METHODS limits
RETURNING VALUE(rt_limit) TYPE tt_limit.
ENDCLASS.
CLASS {{p}}rope_checker IMPLEMENTATION.
METHOD {{p}}if_rope_check~check.
DATA(lv_ticket) = normalize_ticket( iv_ticket ).
IF lv_ticket IS INITIAL.
rv_reason = {{p}}if_rope_check=>c_reason-empty.
RETURN.
ENDIF.
DATA(lt_limit) = limits( ).
ASSIGN lt_limit[ ticket = lv_ticket ] TO FIELD-SYMBOL(<ls_limit>).
IF sy-subrc <> 0.
rv_reason = {{p}}if_rope_check=>c_reason-ticket.
RETURN.
ENDIF.
IF iv_age < <ls_limit>-min_age.
rv_reason = {{p}}if_rope_check=>c_reason-age.
RETURN.
ENDIF.
IF iv_logged_hours < <ls_limit>-min_hours.
rv_reason = {{p}}if_rope_check=>c_reason-hours.
RETURN.
ENDIF.
IF iv_height_m > <ls_limit>-max_height.
rv_reason = {{p}}if_rope_check=>c_reason-height.
RETURN.
ENDIF.
rv_reason = {{p}}if_rope_check=>c_reason-ok.
ENDMETHOD.
METHOD normalize_ticket.
rv_ticket = to_upper( replace( val = iv_ticket sub = ` ` with = `` occ = 0 ) ).
ENDMETHOD.
METHOD limits.
rt_limit = VALUE #(
( ticket = {{p}}if_rope_check=>c_ticket-level_1 min_age = 18 min_hours = 0 max_height = 30 )
( ticket = {{p}}if_rope_check=>c_ticket-level_2 min_age = 18 min_hours = 500 max_height = 60 )
( ticket = {{p}}if_rope_check=>c_ticket-level_3 min_age = 21 min_hours = 1000 max_height = 120 ) ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,76 @@
CLASS ltc_rope_checker DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA mo_cut TYPE REF TO {{p}}if_rope_check.
METHODS setup.
METHODS level_1_ok FOR TESTING.
METHODS level_3_ok FOR TESTING.
METHODS ticket_case_and_space FOR TESTING.
METHODS empty_ticket FOR TESTING.
METHODS unknown_ticket FOR TESTING.
METHODS too_young FOR TESTING.
METHODS too_few_hours FOR TESTING.
METHODS too_high FOR TESTING.
ENDCLASS.
CLASS ltc_rope_checker IMPLEMENTATION.
METHOD setup.
mo_cut = NEW {{p}}rope_checker( ).
ENDMETHOD.
METHOD level_1_ok.
cl_abap_unit_assert=>assert_equals(
exp = {{p}}if_rope_check=>c_reason-ok
act = mo_cut->check( iv_ticket = 'LEVEL_1' iv_height_m = 30
iv_logged_hours = 0 iv_age = 18 ) ).
ENDMETHOD.
METHOD level_3_ok.
cl_abap_unit_assert=>assert_equals(
exp = {{p}}if_rope_check=>c_reason-ok
act = mo_cut->check( iv_ticket = 'LEVEL_3' iv_height_m = 120
iv_logged_hours = 1000 iv_age = 21 ) ).
ENDMETHOD.
METHOD ticket_case_and_space.
cl_abap_unit_assert=>assert_equals(
exp = {{p}}if_rope_check=>c_reason-ok
act = mo_cut->check( iv_ticket = ' level_2 ' iv_height_m = 60
iv_logged_hours = 500 iv_age = 18 ) ).
ENDMETHOD.
METHOD empty_ticket.
cl_abap_unit_assert=>assert_equals(
exp = {{p}}if_rope_check=>c_reason-empty
act = mo_cut->check( iv_ticket = '' iv_height_m = 10
iv_logged_hours = 0 iv_age = 40 ) ).
ENDMETHOD.
METHOD unknown_ticket.
cl_abap_unit_assert=>assert_equals(
exp = {{p}}if_rope_check=>c_reason-ticket
act = mo_cut->check( iv_ticket = 'LEVEL_9' iv_height_m = 10
iv_logged_hours = 0 iv_age = 40 ) ).
ENDMETHOD.
METHOD too_young.
cl_abap_unit_assert=>assert_equals(
exp = {{p}}if_rope_check=>c_reason-age
act = mo_cut->check( iv_ticket = 'LEVEL_3' iv_height_m = 120
iv_logged_hours = 1000 iv_age = 20 ) ).
ENDMETHOD.
METHOD too_few_hours.
cl_abap_unit_assert=>assert_equals(
exp = {{p}}if_rope_check=>c_reason-hours
act = mo_cut->check( iv_ticket = 'LEVEL_2' iv_height_m = 60
iv_logged_hours = 499 iv_age = 18 ) ).
ENDMETHOD.
METHOD too_high.
cl_abap_unit_assert=>assert_equals(
exp = {{p}}if_rope_check=>c_reason-height
act = mo_cut->check( iv_ticket = 'LEVEL_2' iv_height_m = 61
iv_logged_hours = 500 iv_age = 18 ) ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,63 @@
# 1. Goal
A rope access company checks a work permit before a technician starts a job on a
building. The permit desk calls one check for each job. The check returns one
reason code for each job.
# 2. Open questions
None.
# 3. Context
- All objects are in package $TMP.
- The interface {{P}}IF_ROPE_CHECK does not exist yet. You create it.
- The interface contains the type TY_REASON (character, length 10), the type
TY_TICKET (character, length 10), the constant structure C_REASON with the
components OK, EMPTY, TICKET, AGE, HOURS and HEIGHT, the constant structure
C_TICKET with the components LEVEL_1, LEVEL_2 and LEVEL_3, and one method:
CHECK IMPORTING iv_ticket TYPE ty_ticket iv_height_m TYPE i
iv_logged_hours TYPE i iv_age TYPE i
RETURNING VALUE(rv_reason) TYPE ty_reason.
# 4. Contract
- Create the interface {{P}}IF_ROPE_CHECK in package $TMP with the types, the
constants and the method of section 3.
- Create the class {{P}}ROPE_CHECKER in package $TMP.
- The class is public and final. It has a public constructor without parameters.
- The class implements {{P}}IF_ROPE_CHECK.
- Do not add other public methods to the class.
- The values of the constants:
C_REASON-OK = 'OK'. C_REASON-EMPTY = 'EMPTY'. C_REASON-TICKET = 'TICKET'.
C_REASON-AGE = 'AGE'. C_REASON-HOURS = 'HOURS'.
C_REASON-HEIGHT = 'HEIGHT'.
C_TICKET-LEVEL_1 = 'LEVEL_1'. C_TICKET-LEVEL_2 = 'LEVEL_2'.
C_TICKET-LEVEL_3 = 'LEVEL_3'.
# 5. Business rules
Apply the rules in this sequence. Return the reason code of the first rule that
fails.
1. Remove all spaces from iv_ticket. Convert all letters to upper case. The
result is the ticket.
2. If the ticket is empty, return EMPTY.
3. The ticket must be the value of one component of C_TICKET. If not, return
TICKET.
4. The tickets have these limits:
LEVEL_1: minimum age 18, minimum logged hours 0, maximum height 30.
LEVEL_2: minimum age 18, minimum logged hours 500, maximum height 60.
LEVEL_3: minimum age 21, minimum logged hours 1000, maximum height 120.
If iv_age is less than the minimum age of the ticket, return AGE.
5. If iv_logged_hours is less than the minimum logged hours of the ticket,
return HOURS.
6. If iv_height_m is greater than the maximum height of the ticket, return
HEIGHT.
7. Else return OK.
# 6. Constraints
- Release target: SAP_BASIS 816 (ABAP Platform 2025).
- Coding standards: Clean ABAP. A method has less than 40 statements. No global
variables. No comment that restates the code. Pass large parameters by
reference.
- Out of scope: do not change objects that are not in the contract.
# 7. Acceptance
- The interface and the class are active and have no syntax error.
- The hidden tests pass.
- Write your own ABAP Unit tests for the class.

View File

@@ -0,0 +1,61 @@
{
"id": "G1914",
"category": "A",
"object_type": "INTF",
"difficulty": 2,
"release_target": "v816",
"expected_outcome": "implement",
"budget": {
"max_tool_calls": 60,
"max_activations": 15
},
"seed": [],
"contract": [
{
"type": "INTF",
"name": "{{P}}IF_ROPE_CHECK"
},
{
"type": "CLAS",
"name": "{{P}}ROPE_CHECKER",
"implements": "{{P}}IF_ROPE_CHECK"
}
],
"out_of_scope": [
"No other object than {{P}}IF_ROPE_CHECK and {{P}}ROPE_CHECKER.",
"No database tables, no reports, no function modules, no CDS views."
],
"hidden_tests": [
{
"type": "CLAS",
"name": "{{P}}T58_HIDDEN",
"file": "hidden/t58_hidden.clas.abap",
"description": "T58 hidden tests for the rope access permit check"
}
],
"reference": [
{
"type": "INTF",
"name": "{{P}}IF_ROPE_CHECK",
"file": "reference/if_rope_check.intf.abap",
"description": "Rope access permit check contract"
},
{
"type": "CLAS",
"name": "{{P}}ROPE_CHECKER",
"file": "reference/rope_checker.clas.abap",
"description": "Rope access permit check implementation",
"testclasses_file": "reference/rope_checker.testclasses.abap"
},
{
"type": "CLAS",
"name": "{{P}}ROPE_CHECK_TEST",
"file": "reference/rope_check_test.clas.abap",
"description": "Global own tests for the interface and the class"
}
],
"craft_checks": [
"method_length",
"db_operation_in_loop"
]
}

View File

@@ -0,0 +1,16 @@
@EndUserText.label : 'Grape harvest record'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table {{p}}grh {
key client : abap.clnt not null;
harvest_id : abap.char(10) not null;
vineyard_id : abap.char(8) not null;
grape : abap.char(12);
harvest_date : abap.dats;
crates : abap.int4;
weight_kg : abap.dec(13,3);
grade : abap.char(2);
organic : abap.char(1);
}

View File

@@ -0,0 +1,16 @@
@EndUserText.label : 'Grape harvest record'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table {{p}}grh {
key client : abap.clnt not null;
key harvest_id : abap.char(9) not null;
vineyard_id : abap.char(8) not null;
grape : abap.char(12);
harvest_date : abap.dats;
crates : abap.int4;
weight_kg : abap.dec(13,3);
grade : abap.char(2);
organic : abap.char(1);
}

View File

@@ -0,0 +1,16 @@
@EndUserText.label : 'Grape harvest record'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table {{p}}grh {
key client : abap.clnt not null;
key harvest_id : abap.char(10) not null;
vineyard_id : abap.char(8) not null;
grape : abap.numc(12);
harvest_date : abap.dats;
crates : abap.int4;
weight_kg : abap.dec(13,3);
grade : abap.char(2);
organic : abap.char(1);
}

View File

@@ -0,0 +1,16 @@
@EndUserText.label : 'Grape harvest record'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table {{p}}grh {
key client : abap.clnt not null;
key harvest_id : abap.char(10) not null;
vineyard_id : abap.char(8) not null;
grape : abap.char(12);
harvest_date : abap.tims;
crates : abap.int4;
weight_kg : abap.dec(13,3);
grade : abap.char(2);
organic : abap.char(1);
}

View File

@@ -0,0 +1,16 @@
@EndUserText.label : 'Grape harvest record'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table {{p}}grh {
key client : abap.clnt not null;
key harvest_id : abap.char(10) not null;
vineyard_id : abap.char(8) not null;
grape : abap.char(12);
harvest_date : abap.dats;
crates : abap.int4;
weight_kg : abap.dec(13,4);
grade : abap.char(2);
organic : abap.char(1);
}

View File

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

View File

@@ -0,0 +1,146 @@
CLASS {{p}}grh_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
TYPES ty_field_name TYPE dfies-fieldname.
CLASS-DATA go_env TYPE REF TO if_osql_test_environment.
CLASS-METHODS class_setup.
CLASS-METHODS class_teardown.
METHODS setup.
METHODS get_descr RETURNING VALUE(ro_descr) TYPE REF TO cl_abap_structdescr.
METHODS assert_field_exists IMPORTING iv_name TYPE ty_field_name.
METHODS field_of IMPORTING iv_name TYPE ty_field_name
RETURNING VALUE(rs_field) TYPE dfies.
METHODS field_names FOR TESTING.
METHODS key_fields FOR TESTING.
METHODS text_lengths FOR TESTING.
METHODS date_and_number_types FOR TESTING.
METHODS decimal_places FOR TESTING.
METHODS client_field FOR TESTING.
METHODS stores_and_reads_a_record FOR TESTING.
METHODS rejects_duplicate_key FOR TESTING.
ENDCLASS.
CLASS {{p}}grh_hidden IMPLEMENTATION.
METHOD class_setup.
go_env = cl_osql_test_environment=>create( i_dependency_list = VALUE #( ( '{{P}}GRH' ) ) ).
ENDMETHOD.
METHOD class_teardown.
go_env->destroy( ).
ENDMETHOD.
METHOD setup.
go_env->clear_doubles( ).
ENDMETHOD.
METHOD get_descr.
ro_descr = CAST cl_abap_structdescr( cl_abap_typedescr=>describe_by_name( '{{P}}GRH' ) ).
ENDMETHOD.
METHOD assert_field_exists.
DATA(lt_fields) = get_descr( )->get_ddic_field_list( ).
READ TABLE lt_fields TRANSPORTING NO FIELDS WITH KEY fieldname = iv_name.
cl_abap_unit_assert=>assert_subrc( exp = 0 act = sy-subrc
msg = |Field { iv_name } is missing in table {{P}}GRH| ).
ENDMETHOD.
METHOD field_of.
DATA(lt_fields) = get_descr( )->get_ddic_field_list( ).
READ TABLE lt_fields INTO rs_field WITH KEY fieldname = iv_name.
cl_abap_unit_assert=>assert_subrc( exp = 0 act = sy-subrc
msg = |Field { iv_name } is missing in table {{P}}GRH| ).
ENDMETHOD.
METHOD field_names.
DATA(lt_fields) = get_descr( )->get_ddic_field_list( ).
cl_abap_unit_assert=>assert_equals( exp = 9 act = lines( lt_fields ) ).
assert_field_exists( 'CLIENT' ).
assert_field_exists( 'HARVEST_ID' ).
assert_field_exists( 'VINEYARD_ID' ).
assert_field_exists( 'GRAPE' ).
assert_field_exists( 'HARVEST_DATE' ).
assert_field_exists( 'CRATES' ).
assert_field_exists( 'WEIGHT_KG' ).
assert_field_exists( 'GRADE' ).
assert_field_exists( 'ORGANIC' ).
ENDMETHOD.
METHOD key_fields.
cl_abap_unit_assert=>assert_equals( exp = 'X' act = field_of( 'CLIENT' )-keyflag ).
cl_abap_unit_assert=>assert_equals( exp = 'X' act = field_of( 'HARVEST_ID' )-keyflag ).
cl_abap_unit_assert=>assert_equals( exp = ' ' act = field_of( 'VINEYARD_ID' )-keyflag ).
cl_abap_unit_assert=>assert_equals( exp = ' ' act = field_of( 'GRAPE' )-keyflag ).
cl_abap_unit_assert=>assert_equals( exp = ' ' act = field_of( 'HARVEST_DATE' )-keyflag ).
cl_abap_unit_assert=>assert_equals( exp = ' ' act = field_of( 'CRATES' )-keyflag ).
cl_abap_unit_assert=>assert_equals( exp = ' ' act = field_of( 'WEIGHT_KG' )-keyflag ).
cl_abap_unit_assert=>assert_equals( exp = ' ' act = field_of( 'GRADE' )-keyflag ).
cl_abap_unit_assert=>assert_equals( exp = ' ' act = field_of( 'ORGANIC' )-keyflag ).
ENDMETHOD.
METHOD text_lengths.
cl_abap_unit_assert=>assert_equals( exp = 10 act = CONV i( field_of( 'HARVEST_ID' )-leng ) ).
cl_abap_unit_assert=>assert_equals( exp = 8 act = CONV i( field_of( 'VINEYARD_ID' )-leng ) ).
cl_abap_unit_assert=>assert_equals( exp = 12 act = CONV i( field_of( 'GRAPE' )-leng ) ).
cl_abap_unit_assert=>assert_equals( exp = 2 act = CONV i( field_of( 'GRADE' )-leng ) ).
cl_abap_unit_assert=>assert_equals( exp = 1 act = CONV i( field_of( 'ORGANIC' )-leng ) ).
ENDMETHOD.
METHOD date_and_number_types.
cl_abap_unit_assert=>assert_equals( exp = 'D' act = field_of( 'HARVEST_DATE' )-inttype ).
cl_abap_unit_assert=>assert_equals( exp = 8 act = CONV i( field_of( 'HARVEST_DATE' )-leng ) ).
cl_abap_unit_assert=>assert_equals( exp = 'I' act = field_of( 'CRATES' )-inttype ).
cl_abap_unit_assert=>assert_equals( exp = 10 act = CONV i( field_of( 'CRATES' )-leng ) ).
ENDMETHOD.
METHOD decimal_places.
cl_abap_unit_assert=>assert_equals( exp = 'P' act = field_of( 'WEIGHT_KG' )-inttype ).
cl_abap_unit_assert=>assert_equals( exp = 13 act = CONV i( field_of( 'WEIGHT_KG' )-leng ) ).
cl_abap_unit_assert=>assert_equals( exp = 3 act = CONV i( field_of( 'WEIGHT_KG' )-decimals ) ).
ENDMETHOD.
METHOD client_field.
cl_abap_unit_assert=>assert_equals( exp = 'C' act = field_of( 'CLIENT' )-inttype ).
cl_abap_unit_assert=>assert_equals( exp = 3 act = CONV i( field_of( 'CLIENT' )-leng ) ).
ENDMETHOD.
METHOD stores_and_reads_a_record.
DATA lt_grh TYPE STANDARD TABLE OF {{p}}grh WITH EMPTY KEY.
lt_grh = VALUE #( ( client = sy-mandt harvest_id = 'H1' vineyard_id = 'VINE01'
grape = 'RIESLING' harvest_date = '20240901'
crates = 14 weight_kg = '212.500' grade = 'A' organic = 'X' ) ).
INSERT {{p}}grh FROM TABLE @lt_grh.
cl_abap_unit_assert=>assert_subrc( exp = 0 ).
SELECT SINGLE vineyard_id, grape, harvest_date, crates, weight_kg, grade, organic
FROM {{p}}grh WHERE harvest_id = 'H1' INTO @DATA(ls_grh).
cl_abap_unit_assert=>assert_subrc( exp = 0 ).
cl_abap_unit_assert=>assert_equals( exp = 'VINE01' act = ls_grh-vineyard_id ).
cl_abap_unit_assert=>assert_equals( exp = 'RIESLING' act = ls_grh-grape ).
cl_abap_unit_assert=>assert_equals( exp = '20240901' act = ls_grh-harvest_date ).
cl_abap_unit_assert=>assert_equals( exp = 14 act = ls_grh-crates ).
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '212.5' )
act = CONV decfloat34( ls_grh-weight_kg ) ).
cl_abap_unit_assert=>assert_equals( exp = 'A' act = ls_grh-grade ).
cl_abap_unit_assert=>assert_equals( exp = 'X' act = ls_grh-organic ).
ENDMETHOD.
METHOD rejects_duplicate_key.
DATA lt_grh TYPE STANDARD TABLE OF {{p}}grh WITH EMPTY KEY.
lt_grh = VALUE #( ( client = sy-mandt harvest_id = 'D1' vineyard_id = 'VINE02' ) ).
INSERT {{p}}grh FROM TABLE @lt_grh.
cl_abap_unit_assert=>assert_subrc( exp = 0 ).
TRY.
INSERT {{p}}grh FROM TABLE @lt_grh.
cl_abap_unit_assert=>fail( msg = 'A duplicate key must not be accepted' ).
CATCH cx_sy_open_sql_db.
" expected: client and harvest_id are the unique key
ENDTRY.
SELECT COUNT(*) FROM {{p}}grh WHERE harvest_id = 'D1' INTO @DATA(lv_count).
cl_abap_unit_assert=>assert_equals( exp = 1 act = lv_count ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,55 @@
{
"task": "G1915",
"mutants": [
{
"object": "{{P}}GRH",
"mutant": "line 8: key harvest_id : -> harvest_id : (key)",
"status": "killed",
"hidden": "7/8",
"failed_tests": [
"KEY_FIELDS"
]
},
{
"object": "{{P}}GRH",
"mutant": "line 8: abap.char(10) -> abap.char(9) (length)",
"status": "killed",
"hidden": "7/8",
"failed_tests": [
"TEXT_LENGTHS"
]
},
{
"object": "{{P}}GRH",
"mutant": "line 10: abap.char(12) -> abap.numc(12) (type)",
"status": "killed",
"hidden": "7/8",
"failed_tests": [
"STORES_AND_READS_A_RECORD"
]
},
{
"object": "{{P}}GRH",
"mutant": "line 11: abap.dats -> abap.tims (type)",
"status": "killed",
"hidden": "6/8",
"failed_tests": [
"DATE_AND_NUMBER_TYPES",
"STORES_AND_READS_A_RECORD"
]
},
{
"object": "{{P}}GRH",
"mutant": "line 13: abap.dec(13,3) -> abap.dec(13,4) (decimals)",
"status": "killed",
"hidden": "7/8",
"failed_tests": [
"DECIMAL_PLACES"
]
}
],
"valid": 5,
"killed": 5,
"kill_rate": 1.0,
"ok": true
}

View File

@@ -0,0 +1,16 @@
@EndUserText.label : 'Grape harvest record'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table {{p}}grh {
key client : abap.clnt not null;
key harvest_id : abap.char(10) not null;
vineyard_id : abap.char(8) not null;
grape : abap.char(12);
harvest_date : abap.dats;
crates : abap.int4;
weight_kg : abap.dec(13,3);
grade : abap.char(2);
organic : abap.char(1);
}

View File

@@ -0,0 +1,64 @@
CLASS {{p}}grh_test DEFINITION PUBLIC FINAL CREATE PUBLIC
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
CLASS-DATA go_env TYPE REF TO if_osql_test_environment.
CLASS-METHODS class_setup.
CLASS-METHODS class_teardown.
METHODS setup.
METHODS stores_all_values FOR TESTING.
METHODS rejects_duplicate_key FOR TESTING.
METHODS has_expected_fields FOR TESTING.
ENDCLASS.
CLASS {{p}}grh_test IMPLEMENTATION.
METHOD class_setup.
go_env = cl_osql_test_environment=>create( i_dependency_list = VALUE #( ( '{{P}}GRH' ) ) ).
ENDMETHOD.
METHOD class_teardown.
go_env->destroy( ).
ENDMETHOD.
METHOD setup.
go_env->clear_doubles( ).
ENDMETHOD.
METHOD stores_all_values.
DATA lt_grh TYPE STANDARD TABLE OF {{p}}grh WITH EMPTY KEY.
lt_grh = VALUE #( ( client = sy-mandt harvest_id = 'H1' vineyard_id = 'VINE01'
grape = 'RIESLING' harvest_date = '20240901'
crates = 14 weight_kg = '212.500' grade = 'A' organic = 'X' ) ).
INSERT {{p}}grh FROM TABLE @lt_grh.
cl_abap_unit_assert=>assert_subrc( exp = 0 ).
SELECT SINGLE vineyard_id, crates FROM {{p}}grh WHERE harvest_id = 'H1'
INTO @DATA(ls_grh).
cl_abap_unit_assert=>assert_subrc( exp = 0 ).
cl_abap_unit_assert=>assert_equals( exp = 'VINE01' act = ls_grh-vineyard_id ).
cl_abap_unit_assert=>assert_equals( exp = 14 act = ls_grh-crates ).
ENDMETHOD.
METHOD rejects_duplicate_key.
DATA lt_grh TYPE STANDARD TABLE OF {{p}}grh WITH EMPTY KEY.
lt_grh = VALUE #( ( client = sy-mandt harvest_id = 'D1' vineyard_id = 'VINE02' ) ).
INSERT {{p}}grh FROM TABLE @lt_grh.
cl_abap_unit_assert=>assert_subrc( exp = 0 ).
TRY.
INSERT {{p}}grh FROM TABLE @lt_grh.
cl_abap_unit_assert=>fail( msg = 'A duplicate key must not be accepted' ).
CATCH cx_sy_open_sql_db.
" expected: the key is unique
ENDTRY.
SELECT COUNT(*) FROM {{p}}grh WHERE harvest_id = 'D1' INTO @DATA(lv_count).
cl_abap_unit_assert=>assert_equals( exp = 1 act = lv_count ).
ENDMETHOD.
METHOD has_expected_fields.
DATA(lo_descr) = CAST cl_abap_structdescr( cl_abap_typedescr=>describe_by_name( '{{P}}GRH' ) ).
DATA(lt_fields) = lo_descr->get_ddic_field_list( ).
cl_abap_unit_assert=>assert_equals( exp = 9 act = lines( lt_fields ) ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,63 @@
# 1. Goal
A winery records the grape harvest of each picking. The cellar team needs one
database table for these records. The table stores the vineyard, the grape
variety, the picking date, the number of crates, the weight and the quality
grade of each picking.
# 2. Open questions
None.
# 3. Context
- Package: $TMP.
- The table is a new object. No other object exists.
- One harvest record belongs to exactly one vineyard and one grape variety.
- The winery stores the weight of a picking in kilograms.
# 4. Contract
- Create the transparent database table {{P}}GRH in package $TMP.
- Field names, in this order: client, harvest_id, vineyard_id, grape,
harvest_date, crates, weight_kg, grade, organic.
- Key fields: client and harvest_id.
# 5. Business rules
1. client is the client field (abap.clnt, length 3). It is a key field. It must
not be null.
2. harvest_id identifies one picking (abap.char, length 10). It is a key field.
It must not be null.
3. vineyard_id identifies the vineyard (abap.char, length 8). It is not a key
field. It must not be null.
4. grape holds the name of the grape variety (abap.char, length 12). It is not
a key field.
5. harvest_date holds the date of the picking (abap.dats). It is not a key
field.
6. crates holds the number of crates that the picking filled (abap.int4). It is
not a key field.
7. weight_kg holds the weight of the picking in kilograms (abap.dec, length 13,
3 decimal places). It is not a key field.
8. grade holds the quality grade of the picking (abap.char, length 2). It is
not a key field.
9. organic holds 'X' when the vineyard is organic (abap.char, length 1). It is
not a key field.
10. The table stores one record for each value pair of client and harvest_id. A
second record with the same client and the same harvest_id must not be
stored. The database rejects the second record: the statement that stores
it raises an exception of the class CX_SY_OPEN_SQL_DB, and the first record
stays in the table.
11. A stored record can be read again with all its values.
# 6. Constraints
- Release target: ABAP Platform 2025 (SAP_BASIS 816).
- The table is transparent. Create it as a DDL source in package $TMP with the
annotations @EndUserText.label, @AbapCatalog.enhancement.category :
#NOT_EXTENSIBLE, @AbapCatalog.tableCategory : #TRANSPARENT,
@AbapCatalog.deliveryClass : #A and @AbapCatalog.dataMaintenance :
#RESTRICTED.
- Coding standards: Clean ABAP.
- Out of scope: do not create any other object. Do not create a CDS view, a
report or a class other than the test class.
# 7. Acceptance
- The table is active.
- The hidden tests pass.
- Write ABAP Unit tests in a global test class. The tests use
CL_OSQL_TEST_ENVIRONMENT.

View File

@@ -0,0 +1,54 @@
{
"id": "G1915",
"category": "B",
"object_type": "TABL",
"difficulty": 2,
"release_target": "v816",
"expected_outcome": "implement",
"budget": {
"max_tool_calls": 60,
"max_activations": 15
},
"seed": [],
"contract": [
{
"type": "TABL",
"name": "{{P}}GRH",
"fields": [
"client",
"harvest_id",
"vineyard_id",
"grape",
"harvest_date",
"crates",
"weight_kg",
"grade",
"organic"
]
}
],
"out_of_scope": [],
"hidden_tests": [
{
"type": "CLAS",
"name": "{{P}}GRH_HIDDEN",
"file": "hidden/grh_hidden.clas.abap",
"description": "Hidden tests: DDIC field list of the table and Open SQL test doubles"
}
],
"reference": [
{
"type": "TABL",
"name": "{{P}}GRH",
"file": "reference/grh.tabl.asabap",
"description": "Grape harvest records"
},
{
"type": "CLAS",
"name": "{{P}}GRH_TEST",
"file": "reference/grh_test.clas.abap",
"description": "Own tests for the table"
}
],
"craft_checks": []
}

View File

@@ -0,0 +1,33 @@
{
"id": "G1916",
"pool": "train",
"object_type": "INTF",
"category": "A",
"attempts": [
{
"stage": "validate",
"oracle": 0,
"null": 0
},
{
"stage": "bundle",
"errors": [
"hidden/solar_check_hidden.clas.abap line 174: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"DATA\""
],
"by_check": {
"abaplint": 1
}
},
{
"stage": "validate",
"oracle": 0,
"null": 0
},
{
"stage": "validate",
"oracle": 0,
"null": 0
}
],
"accepted": false
}

View File

@@ -0,0 +1,179 @@
CLASS {{p}}solar_check_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PUBLIC SECTION.
INTERFACES {{p}}if_solar_check.
PRIVATE SECTION.
METHODS assert_reason
IMPORTING iv_exp TYPE {{p}}if_solar_check=>ty_reason
iv_act TYPE {{p}}if_solar_check=>ty_reason.
METHODS assert_roof
IMPORTING iv_exp TYPE {{p}}if_solar_check=>ty_roof
iv_act TYPE {{p}}if_solar_check=>ty_roof.
METHODS reason_codes FOR TESTING.
METHODS roof_codes FOR TESTING.
METHODS limit_values FOR TESTING.
METHODS reason_length FOR TESTING.
METHODS roof_length FOR TESTING.
METHODS request_structure FOR TESTING.
METHODS request_table FOR TESTING.
METHODS reason_table FOR TESTING.
METHODS check_via_interface FOR TESTING.
METHODS check_many_via_interface FOR TESTING.
ENDCLASS.
CLASS {{p}}solar_check_hidden IMPLEMENTATION.
METHOD {{p}}if_solar_check~check.
rv_reason = {{p}}if_solar_check=>c_reason-ok.
IF is_request-panel_count < {{p}}if_solar_check=>c_min_panels.
rv_reason = {{p}}if_solar_check=>c_reason-panels.
ENDIF.
ENDMETHOD.
METHOD {{p}}if_solar_check~check_many.
DATA ls_request TYPE {{p}}if_solar_check=>ty_request.
LOOP AT it_request INTO ls_request.
IF ls_request-tilt_angle < 0.
APPEND {{p}}if_solar_check=>c_reason-tilt TO rt_reason.
ELSE.
APPEND {{p}}if_solar_check=>c_reason-ok TO rt_reason.
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD assert_reason.
cl_abap_unit_assert=>assert_equals( exp = iv_exp act = iv_act ).
ENDMETHOD.
METHOD assert_roof.
cl_abap_unit_assert=>assert_equals( exp = iv_exp act = iv_act ).
ENDMETHOD.
METHOD reason_codes.
assert_reason( iv_exp = 'OK' iv_act = {{p}}if_solar_check=>c_reason-ok ).
assert_reason( iv_exp = 'EMPTY' iv_act = {{p}}if_solar_check=>c_reason-empty_input ).
assert_reason( iv_exp = 'ROOF' iv_act = {{p}}if_solar_check=>c_reason-roof_type ).
assert_reason( iv_exp = 'SIZE' iv_act = {{p}}if_solar_check=>c_reason-roof_size ).
assert_reason( iv_exp = 'PANELS' iv_act = {{p}}if_solar_check=>c_reason-panels ).
assert_reason( iv_exp = 'TILT' iv_act = {{p}}if_solar_check=>c_reason-tilt ).
assert_reason( iv_exp = 'BATTERY' iv_act = {{p}}if_solar_check=>c_reason-battery ).
ENDMETHOD.
METHOD roof_codes.
assert_roof( iv_exp = 'TILE' iv_act = {{p}}if_solar_check=>c_roof_tile ).
assert_roof( iv_exp = 'SLAT' iv_act = {{p}}if_solar_check=>c_roof_slate ).
assert_roof( iv_exp = 'FLAT' iv_act = {{p}}if_solar_check=>c_roof_flat ).
ENDMETHOD.
METHOD limit_values.
cl_abap_unit_assert=>assert_equals( exp = 4 act = {{p}}if_solar_check=>c_min_panels ).
cl_abap_unit_assert=>assert_equals( exp = 60 act = {{p}}if_solar_check=>c_max_panels ).
cl_abap_unit_assert=>assert_equals( exp = 5 act = {{p}}if_solar_check=>c_min_tilt ).
cl_abap_unit_assert=>assert_equals( exp = 60 act = {{p}}if_solar_check=>c_max_tilt ).
cl_abap_unit_assert=>assert_equals( exp = 20 act = {{p}}if_solar_check=>c_max_battery ).
ENDMETHOD.
METHOD reason_length.
DATA lv_reason TYPE {{p}}if_solar_check=>ty_reason.
DATA(lo_descr) = cl_abap_typedescr=>describe_by_data( lv_reason ).
cl_abap_unit_assert=>assert_equals( exp = 10 act = lo_descr->length ).
cl_abap_unit_assert=>assert_equals( exp = cl_abap_typedescr=>typekind_char
act = lo_descr->type_kind ).
ENDMETHOD.
METHOD roof_length.
DATA lv_roof TYPE {{p}}if_solar_check=>ty_roof.
DATA(lo_descr) = cl_abap_typedescr=>describe_by_data( lv_roof ).
cl_abap_unit_assert=>assert_equals( exp = 4 act = lo_descr->length ).
cl_abap_unit_assert=>assert_equals( exp = cl_abap_typedescr=>typekind_char
act = lo_descr->type_kind ).
ENDMETHOD.
METHOD request_structure.
DATA ls_request TYPE {{p}}if_solar_check=>ty_request.
ls_request = VALUE #( roof_type = {{p}}if_solar_check=>c_roof_tile
roof_size = 80
panel_count = 20
tilt_angle = 30
battery_kwh = 10 ).
DATA(lo_descr) = cl_abap_typedescr=>describe_by_data( ls_request ).
DATA(lo_struct) = CAST cl_abap_structdescr( lo_descr ).
DATA(lt_comp) = lo_struct->get_components( ).
cl_abap_unit_assert=>assert_equals( exp = 5 act = lines( lt_comp ) ).
cl_abap_unit_assert=>assert_equals( exp = 'ROOF_TYPE' act = lt_comp[ 1 ]-name ).
cl_abap_unit_assert=>assert_equals( exp = 'ROOF_SIZE' act = lt_comp[ 2 ]-name ).
cl_abap_unit_assert=>assert_equals( exp = 'PANEL_COUNT' act = lt_comp[ 3 ]-name ).
cl_abap_unit_assert=>assert_equals( exp = 'TILT_ANGLE' act = lt_comp[ 4 ]-name ).
cl_abap_unit_assert=>assert_equals( exp = 'BATTERY_KWH' act = lt_comp[ 5 ]-name ).
cl_abap_unit_assert=>assert_equals( exp = cl_abap_typedescr=>typekind_char
act = lt_comp[ 1 ]-type_kind ).
cl_abap_unit_assert=>assert_equals( exp = 4 act = lt_comp[ 1 ]-length ).
cl_abap_unit_assert=>assert_equals( exp = cl_abap_typedescr=>typekind_int
act = lt_comp[ 2 ]-type_kind ).
cl_abap_unit_assert=>assert_equals( exp = 4 act = lt_comp[ 2 ]-length ).
cl_abap_unit_assert=>assert_equals( exp = cl_abap_typedescr=>typekind_int
act = lt_comp[ 3 ]-type_kind ).
cl_abap_unit_assert=>assert_equals( exp = 4 act = lt_comp[ 3 ]-length ).
cl_abap_unit_assert=>assert_equals( exp = cl_abap_typedescr=>typekind_int
act = lt_comp[ 4 ]-type_kind ).
cl_abap_unit_assert=>assert_equals( exp = 4 act = lt_comp[ 4 ]-length ).
cl_abap_unit_assert=>assert_equals( exp = cl_abap_typedescr=>typekind_int
act = lt_comp[ 5 ]-type_kind ).
cl_abap_unit_assert=>assert_equals( exp = 4 act = lt_comp[ 5 ]-length ).
ENDMETHOD.
METHOD request_table.
DATA lv_kind TYPE c LENGTH 1.
DATA lt_request TYPE {{p}}if_solar_check=>tt_request.
lt_request = VALUE #( ( roof_type = {{p}}if_solar_check=>c_roof_flat
roof_size = 120
panel_count = 30
tilt_angle = 15
battery_kwh = 10 ) ).
cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_request ) ).
DESCRIBE TABLE lt_request KIND lv_kind.
cl_abap_unit_assert=>assert_equals( exp = 'T' act = lv_kind ).
ENDMETHOD.
METHOD reason_table.
DATA lv_kind TYPE c LENGTH 1.
DATA lt_reason TYPE {{p}}if_solar_check=>tt_reason.
lt_reason = VALUE #( ( {{p}}if_solar_check=>c_reason-ok ) ).
cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_reason ) ).
DESCRIBE TABLE lt_reason KIND lv_kind.
cl_abap_unit_assert=>assert_equals( exp = 'T' act = lv_kind ).
ENDMETHOD.
METHOD check_via_interface.
DATA lo_cut TYPE REF TO {{p}}if_solar_check.
DATA ls_request TYPE {{p}}if_solar_check=>ty_request.
lo_cut = me.
ls_request = VALUE #( roof_type = {{p}}if_solar_check=>c_roof_flat
roof_size = 120
panel_count = 30
tilt_angle = 15
battery_kwh = 10 ).
assert_reason( iv_exp = {{p}}if_solar_check=>c_reason-ok
iv_act = lo_cut->check( ls_request ) ).
ENDMETHOD.
METHOD check_many_via_interface.
DATA lo_cut TYPE REF TO {{p}}if_solar_check.
DATA lt_request TYPE {{p}}if_solar_check=>tt_request.
DATA lt_reason TYPE {{p}}if_solar_check=>tt_reason.
lo_cut = me.
lt_request = VALUE #( ( roof_type = {{p}}if_solar_check=>c_roof_tile
roof_size = 80
panel_count = 20
tilt_angle = 30
battery_kwh = 0 ) ).
lt_reason = lo_cut->check_many( lt_request ).
cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_reason ) ).
assert_reason( iv_exp = {{p}}if_solar_check=>c_reason-ok
iv_act = lt_reason[ 1 ] ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,41 @@
INTERFACE {{p}}if_solar_check PUBLIC.
TYPES:
ty_reason TYPE c LENGTH 10,
ty_roof TYPE c LENGTH 4,
BEGIN OF ty_request,
roof_type TYPE ty_roof,
roof_size TYPE i,
panel_count TYPE i,
tilt_angle TYPE i,
battery_kwh TYPE i,
END OF ty_request,
tt_request TYPE STANDARD TABLE OF ty_request WITH EMPTY KEY,
tt_reason TYPE STANDARD TABLE OF ty_reason WITH EMPTY KEY.
CONSTANTS:
BEGIN OF c_reason,
ok TYPE ty_reason VALUE 'OK',
empty_input TYPE ty_reason VALUE 'EMPTY',
roof_type TYPE ty_reason VALUE 'ROOF',
roof_size TYPE ty_reason VALUE 'SIZE',
panels TYPE ty_reason VALUE 'PANELS',
tilt TYPE ty_reason VALUE 'TILT',
battery TYPE ty_reason VALUE 'BATTERY',
END OF c_reason,
c_roof_tile TYPE ty_roof VALUE 'TILE',
c_roof_slate TYPE ty_roof VALUE 'SLAT',
c_roof_flat TYPE ty_roof VALUE 'FLAT',
c_min_panels TYPE i VALUE 4,
c_max_panels TYPE i VALUE 60,
c_min_tilt TYPE i VALUE 5,
c_max_tilt TYPE i VALUE 60,
c_max_battery TYPE i VALUE 20.
METHODS check
IMPORTING is_request TYPE ty_request
RETURNING VALUE(rv_reason) TYPE ty_reason.
METHODS check_many
IMPORTING it_request TYPE tt_request
RETURNING VALUE(rt_reason) TYPE tt_reason.
ENDINTERFACE.

View File

@@ -0,0 +1,114 @@
CLASS {{p}}solar_check_test DEFINITION PUBLIC FINAL CREATE PUBLIC
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PUBLIC SECTION.
INTERFACES {{p}}if_solar_check.
PRIVATE SECTION.
METHODS assert_reason
IMPORTING iv_exp TYPE {{p}}if_solar_check=>ty_reason
iv_act TYPE {{p}}if_solar_check=>ty_reason.
METHODS assert_roof
IMPORTING iv_exp TYPE {{p}}if_solar_check=>ty_roof
iv_act TYPE {{p}}if_solar_check=>ty_roof.
METHODS reason_codes FOR TESTING.
METHODS roof_codes FOR TESTING.
METHODS limit_values FOR TESTING.
METHODS reason_length FOR TESTING.
METHODS request_structure FOR TESTING.
METHODS check_via_interface FOR TESTING.
ENDCLASS.
CLASS {{p}}solar_check_test IMPLEMENTATION.
METHOD {{p}}if_solar_check~check.
rv_reason = {{p}}if_solar_check=>c_reason-ok.
IF is_request-panel_count < {{p}}if_solar_check=>c_min_panels.
rv_reason = {{p}}if_solar_check=>c_reason-panels.
ENDIF.
ENDMETHOD.
METHOD {{p}}if_solar_check~check_many.
DATA ls_request TYPE {{p}}if_solar_check=>ty_request.
LOOP AT it_request INTO ls_request.
IF ls_request-tilt_angle < 0.
APPEND {{p}}if_solar_check=>c_reason-tilt TO rt_reason.
ELSE.
APPEND {{p}}if_solar_check=>c_reason-ok TO rt_reason.
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD assert_reason.
cl_abap_unit_assert=>assert_equals( exp = iv_exp act = iv_act ).
ENDMETHOD.
METHOD assert_roof.
cl_abap_unit_assert=>assert_equals( exp = iv_exp act = iv_act ).
ENDMETHOD.
METHOD reason_codes.
assert_reason( iv_exp = 'OK' iv_act = {{p}}if_solar_check=>c_reason-ok ).
assert_reason( iv_exp = 'EMPTY' iv_act = {{p}}if_solar_check=>c_reason-empty_input ).
assert_reason( iv_exp = 'ROOF' iv_act = {{p}}if_solar_check=>c_reason-roof_type ).
assert_reason( iv_exp = 'SIZE' iv_act = {{p}}if_solar_check=>c_reason-roof_size ).
assert_reason( iv_exp = 'PANELS' iv_act = {{p}}if_solar_check=>c_reason-panels ).
assert_reason( iv_exp = 'TILT' iv_act = {{p}}if_solar_check=>c_reason-tilt ).
assert_reason( iv_exp = 'BATTERY' iv_act = {{p}}if_solar_check=>c_reason-battery ).
ENDMETHOD.
METHOD roof_codes.
assert_roof( iv_exp = 'TILE' iv_act = {{p}}if_solar_check=>c_roof_tile ).
assert_roof( iv_exp = 'SLAT' iv_act = {{p}}if_solar_check=>c_roof_slate ).
assert_roof( iv_exp = 'FLAT' iv_act = {{p}}if_solar_check=>c_roof_flat ).
ENDMETHOD.
METHOD limit_values.
cl_abap_unit_assert=>assert_equals( exp = 4 act = {{p}}if_solar_check=>c_min_panels ).
cl_abap_unit_assert=>assert_equals( exp = 60 act = {{p}}if_solar_check=>c_max_panels ).
cl_abap_unit_assert=>assert_equals( exp = 5 act = {{p}}if_solar_check=>c_min_tilt ).
cl_abap_unit_assert=>assert_equals( exp = 60 act = {{p}}if_solar_check=>c_max_tilt ).
cl_abap_unit_assert=>assert_equals( exp = 20 act = {{p}}if_solar_check=>c_max_battery ).
ENDMETHOD.
METHOD reason_length.
DATA lv_reason TYPE {{p}}if_solar_check=>ty_reason.
DATA(lo_descr) = cl_abap_typedescr=>describe_by_data( lv_reason ).
cl_abap_unit_assert=>assert_equals( exp = 10 act = lo_descr->length ).
cl_abap_unit_assert=>assert_equals( exp = cl_abap_typedescr=>typekind_char
act = lo_descr->type_kind ).
ENDMETHOD.
METHOD request_structure.
DATA ls_request TYPE {{p}}if_solar_check=>ty_request.
ls_request = VALUE #( roof_type = {{p}}if_solar_check=>c_roof_tile
roof_size = 80
panel_count = 20
tilt_angle = 30
battery_kwh = 10 ).
DATA(lo_descr) = cl_abap_typedescr=>describe_by_data( ls_request ).
DATA(lo_struct) = CAST cl_abap_structdescr( lo_descr ).
DATA(lt_comp) = lo_struct->get_components( ).
cl_abap_unit_assert=>assert_equals( exp = 5 act = lines( lt_comp ) ).
cl_abap_unit_assert=>assert_equals( exp = 'ROOF_TYPE' act = lt_comp[ 1 ]-name ).
cl_abap_unit_assert=>assert_equals( exp = 'ROOF_SIZE' act = lt_comp[ 2 ]-name ).
cl_abap_unit_assert=>assert_equals( exp = 'PANEL_COUNT' act = lt_comp[ 3 ]-name ).
cl_abap_unit_assert=>assert_equals( exp = 'TILT_ANGLE' act = lt_comp[ 4 ]-name ).
cl_abap_unit_assert=>assert_equals( exp = 'BATTERY_KWH' act = lt_comp[ 5 ]-name ).
ENDMETHOD.
METHOD check_via_interface.
DATA lo_cut TYPE REF TO {{p}}if_solar_check.
DATA ls_request TYPE {{p}}if_solar_check=>ty_request.
lo_cut = me.
ls_request = VALUE #( roof_type = {{p}}if_solar_check=>c_roof_flat
roof_size = 120
panel_count = 30
tilt_angle = 15
battery_kwh = 10 ).
assert_reason( iv_exp = {{p}}if_solar_check=>c_reason-ok
iv_act = lo_cut->check( ls_request ) ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,87 @@
# 1. Goal
A rooftop solar installer checks a planned photovoltaic system before it sends a
quotation. The quotation program works against one interface. The interface
carries the request type, the reason codes, the limits and the check methods.
# 2. Open questions
None.
# 3. Context
- Package $TMP. The interface does not exist yet.
- The quotation program fills a request, calls the check through the interface
{{P}}IF_SOLAR_CHECK and reads the reason code.
- The interface is the only object of this task.
# 4. Contract
- Create the interface {{P}}IF_SOLAR_CHECK in package $TMP.
- The interface is global and public.
- The interface contains exactly the types, the constants and the methods of
section 5. Do not add other components.
# 5. Business rules
## 5.1 Types
1. TY_REASON is a character type of length 10. It carries one reason code.
2. TY_ROOF is a character type of length 4. It carries one roof type.
3. TY_REQUEST is a structure type with exactly these five components in this
order:
| component | type | meaning |
| ----------- | ------- | ------------------------------ |
| roof_type | ty_roof | the kind of the roof |
| roof_size | i | the roof size in square metres |
| panel_count | i | the number of planned panels |
| tilt_angle | i | the roof pitch in degrees |
| battery_kwh | i | the battery capacity in kWh |
4. TT_REQUEST is a standard table of TY_REQUEST.
5. TT_REASON is a standard table of TY_REASON.
## 5.2 Constants
6. C_REASON is a constant structure. Each component has the type TY_REASON and
this value:
| component | value |
| ----------- | ------- |
| ok | OK |
| empty_input | EMPTY |
| roof_type | ROOF |
| roof_size | SIZE |
| panels | PANELS |
| tilt | TILT |
| battery | BATTERY |
7. C_ROOF_TILE is a constant of type TY_ROOF with the value TILE.
8. C_ROOF_SLATE is a constant of type TY_ROOF with the value SLAT.
9. C_ROOF_FLAT is a constant of type TY_ROOF with the value FLAT.
10. C_MIN_PANELS is a constant of type i with the value 4.
11. C_MAX_PANELS is a constant of type i with the value 60.
12. C_MIN_TILT is a constant of type i with the value 5.
13. C_MAX_TILT is a constant of type i with the value 60.
14. C_MAX_BATTERY is a constant of type i with the value 20.
## 5.3 Methods
15. The method CHECK has the importing parameter IS_REQUEST of the type
TY_REQUEST and the returning parameter RV_REASON of the type TY_REASON.
16. The method CHECK_MANY has the importing parameter IT_REQUEST of the type
TT_REQUEST and the returning parameter RT_REASON of the type TT_REASON.
# 6. Constraints
- Release target: ABAP Platform 2025 (SAP_BASIS 816).
- Coding standards: Clean ABAP. No comment that restates the code.
- Out of scope: do not create a class, a report, a function module or a
database table for this task.
# 7. Acceptance
- The interface {{P}}IF_SOLAR_CHECK is active and has no syntax error.
- The hidden tests pass.
- Write your own ABAP Unit tests for the interface in a global test class.

View File

@@ -0,0 +1,46 @@
{
"id": "G1916",
"category": "A",
"object_type": "INTF",
"difficulty": 3,
"release_target": "v816",
"expected_outcome": "implement",
"budget": {
"max_tool_calls": 60,
"max_activations": 15
},
"seed": [],
"contract": [
{
"type": "INTF",
"name": "{{P}}IF_SOLAR_CHECK"
}
],
"out_of_scope": [],
"hidden_tests": [
{
"type": "CLAS",
"name": "{{P}}SOLAR_CHECK_HIDDEN",
"file": "hidden/solar_check_hidden.clas.abap",
"description": "Hidden tests for the interface {{P}}IF_SOLAR_CHECK"
}
],
"reference": [
{
"type": "INTF",
"name": "{{P}}IF_SOLAR_CHECK",
"file": "reference/if_solar_check.intf.abap",
"description": "Solar check contract"
},
{
"type": "CLAS",
"name": "{{P}}SOLAR_CHECK_TEST",
"file": "reference/solar_check_test.clas.abap",
"description": "Own ABAP Unit tests for the interface"
}
],
"craft_checks": [
"method_length",
"db_operation_in_loop"
]
}

View File

@@ -0,0 +1,41 @@
INTERFACE {{p}}if_bouquet_check PUBLIC.
TYPES ty_band TYPE c LENGTH 1.
TYPES ty_reason TYPE c LENGTH 9.
TYPES:
BEGIN OF ty_result,
band TYPE ty_band,
reason TYPE ty_reason,
END OF ty_result.
CONSTANTS:
BEGIN OF c_band,
small TYPE ty_band VALUE 'S',
medium TYPE ty_band VALUE 'M',
large TYPE ty_band VALUE 'L',
END OF c_band.
CONSTANTS:
BEGIN OF c_reason,
ok TYPE ty_reason VALUE 'OK',
invalid TYPE ty_reason VALUE 'INVALID',
short TYPE ty_reason VALUE 'SHORT',
weight TYPE ty_reason VALUE 'WEIGHT',
stems TYPE ty_reason VALUE 'STEMS',
END OF c_reason.
CONSTANTS:
BEGIN OF c_limit,
max_stems_small TYPE i VALUE 20,
max_stems_medium TYPE i VALUE 40,
max_stems_large TYPE i VALUE 60,
max_weight_g TYPE i VALUE 3000,
min_stem_cm TYPE i VALUE 40,
END OF c_limit.
METHODS check_order
IMPORTING iv_stems TYPE i
iv_weight_g TYPE i
iv_stem_cm TYPE i
RETURNING VALUE(rs_result) TYPE ty_result.
ENDINTERFACE.

View File

@@ -0,0 +1,41 @@
INTERFACE {{p}}if_bouquet_check PUBLIC.
TYPES ty_band TYPE c LENGTH 1.
TYPES ty_reason TYPE c LENGTH 10.
TYPES:
BEGIN OF ty_result,
band TYPE ty_band,
reason TYPE ty_reason,
END OF ty_result.
CONSTANTS:
BEGIN OF c_band,
small TYPE ty_band VALUE 'S',
medium TYPE ty_band VALUE 'M',
large TYPE ty_band VALUE 'L',
END OF c_band.
CONSTANTS:
BEGIN OF c_reason,
ok TYPE ty_reason VALUE 'ZK',
invalid TYPE ty_reason VALUE 'INVALID',
short TYPE ty_reason VALUE 'SHORT',
weight TYPE ty_reason VALUE 'WEIGHT',
stems TYPE ty_reason VALUE 'STEMS',
END OF c_reason.
CONSTANTS:
BEGIN OF c_limit,
max_stems_small TYPE i VALUE 20,
max_stems_medium TYPE i VALUE 40,
max_stems_large TYPE i VALUE 60,
max_weight_g TYPE i VALUE 3000,
min_stem_cm TYPE i VALUE 40,
END OF c_limit.
METHODS check_order
IMPORTING iv_stems TYPE i
iv_weight_g TYPE i
iv_stem_cm TYPE i
RETURNING VALUE(rs_result) TYPE ty_result.
ENDINTERFACE.

View File

@@ -0,0 +1,41 @@
INTERFACE {{p}}if_bouquet_check PUBLIC.
TYPES ty_band TYPE c LENGTH 1.
TYPES ty_reason TYPE c LENGTH 10.
TYPES:
BEGIN OF ty_result,
band TYPE ty_band,
reason TYPE ty_reason,
END OF ty_result.
CONSTANTS:
BEGIN OF c_band,
small TYPE ty_band VALUE 'S',
medium TYPE ty_band VALUE 'M',
large TYPE ty_band VALUE 'L',
END OF c_band.
CONSTANTS:
BEGIN OF c_reason,
ok TYPE ty_reason VALUE 'OK',
invalid TYPE ty_reason VALUE 'ZNVALID',
short TYPE ty_reason VALUE 'SHORT',
weight TYPE ty_reason VALUE 'WEIGHT',
stems TYPE ty_reason VALUE 'STEMS',
END OF c_reason.
CONSTANTS:
BEGIN OF c_limit,
max_stems_small TYPE i VALUE 20,
max_stems_medium TYPE i VALUE 40,
max_stems_large TYPE i VALUE 60,
max_weight_g TYPE i VALUE 3000,
min_stem_cm TYPE i VALUE 40,
END OF c_limit.
METHODS check_order
IMPORTING iv_stems TYPE i
iv_weight_g TYPE i
iv_stem_cm TYPE i
RETURNING VALUE(rs_result) TYPE ty_result.
ENDINTERFACE.

View File

@@ -0,0 +1,41 @@
INTERFACE {{p}}if_bouquet_check PUBLIC.
TYPES ty_band TYPE c LENGTH 1.
TYPES ty_reason TYPE c LENGTH 10.
TYPES:
BEGIN OF ty_result,
band TYPE ty_band,
reason TYPE ty_reason,
END OF ty_result.
CONSTANTS:
BEGIN OF c_band,
small TYPE ty_band VALUE 'S',
medium TYPE ty_band VALUE 'M',
large TYPE ty_band VALUE 'L',
END OF c_band.
CONSTANTS:
BEGIN OF c_reason,
ok TYPE ty_reason VALUE 'OK',
invalid TYPE ty_reason VALUE 'INVALID',
short TYPE ty_reason VALUE 'ZHORT',
weight TYPE ty_reason VALUE 'WEIGHT',
stems TYPE ty_reason VALUE 'STEMS',
END OF c_reason.
CONSTANTS:
BEGIN OF c_limit,
max_stems_small TYPE i VALUE 20,
max_stems_medium TYPE i VALUE 40,
max_stems_large TYPE i VALUE 60,
max_weight_g TYPE i VALUE 3000,
min_stem_cm TYPE i VALUE 40,
END OF c_limit.
METHODS check_order
IMPORTING iv_stems TYPE i
iv_weight_g TYPE i
iv_stem_cm TYPE i
RETURNING VALUE(rs_result) TYPE ty_result.
ENDINTERFACE.

View File

@@ -0,0 +1,41 @@
INTERFACE {{p}}if_bouquet_check PUBLIC.
TYPES ty_band TYPE c LENGTH 1.
TYPES ty_reason TYPE c LENGTH 10.
TYPES:
BEGIN OF ty_result,
band TYPE ty_band,
reason TYPE ty_reason,
END OF ty_result.
CONSTANTS:
BEGIN OF c_band,
small TYPE ty_band VALUE 'S',
medium TYPE ty_band VALUE 'M',
large TYPE ty_band VALUE 'L',
END OF c_band.
CONSTANTS:
BEGIN OF c_reason,
ok TYPE ty_reason VALUE 'OK',
invalid TYPE ty_reason VALUE 'INVALID',
short TYPE ty_reason VALUE 'SHORT',
weight TYPE ty_reason VALUE 'ZEIGHT',
stems TYPE ty_reason VALUE 'STEMS',
END OF c_reason.
CONSTANTS:
BEGIN OF c_limit,
max_stems_small TYPE i VALUE 20,
max_stems_medium TYPE i VALUE 40,
max_stems_large TYPE i VALUE 60,
max_weight_g TYPE i VALUE 3000,
min_stem_cm TYPE i VALUE 40,
END OF c_limit.
METHODS check_order
IMPORTING iv_stems TYPE i
iv_weight_g TYPE i
iv_stem_cm TYPE i
RETURNING VALUE(rs_result) TYPE ty_result.
ENDINTERFACE.

View File

@@ -0,0 +1,38 @@
{
"id": "G1917",
"pool": "train",
"object_type": "INTF",
"category": "A",
"attempts": [
{
"stage": "bundle",
"errors": [
"Too close to task G1900 (similarity spec 0.58, rules 0.61, names 0.33). Choose a different business topic and different object names."
],
"by_check": {
"extra": 1
}
},
{
"stage": "validate",
"oracle": 0,
"null": 0
},
{
"stage": "validate",
"oracle": 73.6,
"null": 0
},
{
"stage": "validate",
"oracle": 100.0,
"null": 0,
"mutation": {
"valid": 5,
"killed": 5,
"ok": true
}
}
],
"accepted": true
}

View File

@@ -0,0 +1,126 @@
CLASS {{p}}bouquet_check_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PUBLIC SECTION.
INTERFACES {{p}}if_bouquet_check.
PRIVATE SECTION.
METHODS band_values FOR TESTING.
METHODS reason_values FOR TESTING.
METHODS limit_values FOR TESTING.
METHODS band_is_one_char FOR TESTING.
METHODS reason_is_ten_chars FOR TESTING.
METHODS result_structure FOR TESTING.
METHODS call_returns_result FOR TESTING.
METHODS call_with_variables FOR TESTING.
ENDCLASS.
CLASS {{p}}bouquet_check_hidden IMPLEMENTATION.
METHOD {{p}}if_bouquet_check~check_order.
rs_result = VALUE #( band = {{p}}if_bouquet_check=>c_band-large
reason = {{p}}if_bouquet_check=>c_reason-ok ).
ENDMETHOD.
METHOD band_values.
DATA lv_band TYPE {{p}}if_bouquet_check=>ty_band.
lv_band = {{p}}if_bouquet_check=>c_band-small.
cl_abap_unit_assert=>assert_equals( exp = 'S' act = lv_band msg = `SMALL` ).
lv_band = {{p}}if_bouquet_check=>c_band-medium.
cl_abap_unit_assert=>assert_equals( exp = 'M' act = lv_band msg = `MEDIUM` ).
lv_band = {{p}}if_bouquet_check=>c_band-large.
cl_abap_unit_assert=>assert_equals( exp = 'L' act = lv_band msg = `LARGE` ).
ENDMETHOD.
METHOD reason_values.
DATA lv_exp TYPE {{p}}if_bouquet_check=>ty_reason.
DATA lv_act TYPE {{p}}if_bouquet_check=>ty_reason.
lv_exp = 'OK'.
lv_act = {{p}}if_bouquet_check=>c_reason-ok.
cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_act msg = `OK` ).
lv_exp = 'INVALID'.
lv_act = {{p}}if_bouquet_check=>c_reason-invalid.
cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_act msg = `INVALID` ).
lv_exp = 'SHORT'.
lv_act = {{p}}if_bouquet_check=>c_reason-short.
cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_act msg = `SHORT` ).
lv_exp = 'WEIGHT'.
lv_act = {{p}}if_bouquet_check=>c_reason-weight.
cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_act msg = `WEIGHT` ).
lv_exp = 'STEMS'.
lv_act = {{p}}if_bouquet_check=>c_reason-stems.
cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_act msg = `STEMS` ).
ENDMETHOD.
METHOD limit_values.
DATA lv_limit TYPE i.
lv_limit = {{p}}if_bouquet_check=>c_limit-max_stems_small.
cl_abap_unit_assert=>assert_equals( exp = 20 act = lv_limit msg = `SMALL` ).
lv_limit = {{p}}if_bouquet_check=>c_limit-max_stems_medium.
cl_abap_unit_assert=>assert_equals( exp = 40 act = lv_limit msg = `MEDIUM` ).
lv_limit = {{p}}if_bouquet_check=>c_limit-max_stems_large.
cl_abap_unit_assert=>assert_equals( exp = 60 act = lv_limit msg = `LARGE` ).
lv_limit = {{p}}if_bouquet_check=>c_limit-max_weight_g.
cl_abap_unit_assert=>assert_equals( exp = 3000 act = lv_limit msg = `WEIGHT` ).
lv_limit = {{p}}if_bouquet_check=>c_limit-min_stem_cm.
cl_abap_unit_assert=>assert_equals( exp = 40 act = lv_limit msg = `STEM` ).
ENDMETHOD.
METHOD band_is_one_char.
DATA lv_band TYPE {{p}}if_bouquet_check=>ty_band.
lv_band = 'XY'.
cl_abap_unit_assert=>assert_equals( exp = 'X' act = lv_band
msg = `band is one character` ).
ENDMETHOD.
METHOD reason_is_ten_chars.
DATA lv_reason TYPE {{p}}if_bouquet_check=>ty_reason.
lv_reason = 'ABCDEFGHIJKL'.
cl_abap_unit_assert=>assert_equals( exp = 'ABCDEFGHIJ' act = lv_reason
msg = `reason is ten characters` ).
ENDMETHOD.
METHOD result_structure.
DATA ls_result TYPE {{p}}if_bouquet_check=>ty_result.
DATA(lo_struct) = CAST cl_abap_structdescr(
cl_abap_typedescr=>describe_by_data( ls_result ) ).
DATA(lt_comp) = lo_struct->get_components( ).
cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_comp ) ).
cl_abap_unit_assert=>assert_equals( exp = 'BAND'
act = to_upper( lt_comp[ 1 ]-name ) ).
cl_abap_unit_assert=>assert_equals( exp = 'REASON'
act = to_upper( lt_comp[ 2 ]-name ) ).
ls_result-band = 'XY'.
cl_abap_unit_assert=>assert_equals( exp = 'X' act = ls_result-band ).
ls_result-reason = 'ABCDEFGHIJKL'.
cl_abap_unit_assert=>assert_equals( exp = 'ABCDEFGHIJ'
act = ls_result-reason ).
ENDMETHOD.
METHOD call_returns_result.
DATA mo_cut TYPE REF TO {{p}}if_bouquet_check.
mo_cut = NEW {{p}}bouquet_check_hidden( ).
DATA(ls_result) = mo_cut->check_order( iv_stems = 30
iv_weight_g = 1200
iv_stem_cm = 50 ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_bouquet_check=>c_band-large
act = ls_result-band ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_bouquet_check=>c_reason-ok
act = ls_result-reason ).
ENDMETHOD.
METHOD call_with_variables.
DATA lv_stems TYPE i VALUE 5.
DATA lv_weight TYPE i VALUE 900.
DATA lv_stem TYPE i VALUE 45.
DATA mo_cut TYPE REF TO {{p}}if_bouquet_check.
mo_cut = NEW {{p}}bouquet_check_hidden( ).
DATA(ls_result) = mo_cut->check_order( iv_stems = lv_stems
iv_weight_g = lv_weight
iv_stem_cm = lv_stem ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_bouquet_check=>c_band-large
act = ls_result-band ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_bouquet_check=>c_reason-ok
act = ls_result-reason ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,55 @@
{
"task": "G1917",
"mutants": [
{
"object": "{{P}}IF_BOUQUET_CHECK",
"mutant": "line 3: LENGTH 10 -> LENGTH 9 (length)",
"status": "killed",
"hidden": "6/8",
"failed_tests": [
"REASON_IS_TEN_CHARS",
"RESULT_STRUCTURE"
]
},
{
"object": "{{P}}IF_BOUQUET_CHECK",
"mutant": "line 20: VALUE 'OK' -> VALUE 'ZK' (lit)",
"status": "killed",
"hidden": "7/8",
"failed_tests": [
"REASON_VALUES"
]
},
{
"object": "{{P}}IF_BOUQUET_CHECK",
"mutant": "line 21: VALUE 'INVALID' -> VALUE 'ZNVALID' (lit)",
"status": "killed",
"hidden": "7/8",
"failed_tests": [
"REASON_VALUES"
]
},
{
"object": "{{P}}IF_BOUQUET_CHECK",
"mutant": "line 22: VALUE 'SHORT' -> VALUE 'ZHORT' (lit)",
"status": "killed",
"hidden": "7/8",
"failed_tests": [
"REASON_VALUES"
]
},
{
"object": "{{P}}IF_BOUQUET_CHECK",
"mutant": "line 23: VALUE 'WEIGHT' -> VALUE 'ZEIGHT' (lit)",
"status": "killed",
"hidden": "7/8",
"failed_tests": [
"REASON_VALUES"
]
}
],
"valid": 5,
"killed": 5,
"kill_rate": 1.0,
"ok": true
}

View File

@@ -0,0 +1,108 @@
CLASS {{p}}bouquet_check_test DEFINITION PUBLIC FINAL CREATE PUBLIC
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PUBLIC SECTION.
INTERFACES {{p}}if_bouquet_check.
PRIVATE SECTION.
METHODS bands FOR TESTING.
METHODS reasons FOR TESTING.
METHODS limits FOR TESTING.
METHODS band_is_one_char FOR TESTING.
METHODS reason_is_ten_chars FOR TESTING.
METHODS result_parts FOR TESTING.
METHODS order_contract FOR TESTING.
ENDCLASS.
CLASS {{p}}bouquet_check_test IMPLEMENTATION.
METHOD {{p}}if_bouquet_check~check_order.
rs_result = VALUE #( band = {{p}}if_bouquet_check=>c_band-small
reason = {{p}}if_bouquet_check=>c_reason-ok ).
ENDMETHOD.
METHOD bands.
DATA lv_band TYPE {{p}}if_bouquet_check=>ty_band.
lv_band = {{p}}if_bouquet_check=>c_band-small.
cl_abap_unit_assert=>assert_equals( exp = 'S' act = lv_band ).
lv_band = {{p}}if_bouquet_check=>c_band-medium.
cl_abap_unit_assert=>assert_equals( exp = 'M' act = lv_band ).
lv_band = {{p}}if_bouquet_check=>c_band-large.
cl_abap_unit_assert=>assert_equals( exp = 'L' act = lv_band ).
ENDMETHOD.
METHOD reasons.
DATA lv_exp TYPE {{p}}if_bouquet_check=>ty_reason.
DATA lv_act TYPE {{p}}if_bouquet_check=>ty_reason.
lv_exp = 'OK'.
lv_act = {{p}}if_bouquet_check=>c_reason-ok.
cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_act ).
lv_exp = 'INVALID'.
lv_act = {{p}}if_bouquet_check=>c_reason-invalid.
cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_act ).
lv_exp = 'SHORT'.
lv_act = {{p}}if_bouquet_check=>c_reason-short.
cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_act ).
lv_exp = 'WEIGHT'.
lv_act = {{p}}if_bouquet_check=>c_reason-weight.
cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_act ).
lv_exp = 'STEMS'.
lv_act = {{p}}if_bouquet_check=>c_reason-stems.
cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_act ).
ENDMETHOD.
METHOD limits.
DATA lv_limit TYPE i.
lv_limit = {{p}}if_bouquet_check=>c_limit-max_stems_small.
cl_abap_unit_assert=>assert_equals( exp = 20 act = lv_limit ).
lv_limit = {{p}}if_bouquet_check=>c_limit-max_stems_medium.
cl_abap_unit_assert=>assert_equals( exp = 40 act = lv_limit ).
lv_limit = {{p}}if_bouquet_check=>c_limit-max_stems_large.
cl_abap_unit_assert=>assert_equals( exp = 60 act = lv_limit ).
lv_limit = {{p}}if_bouquet_check=>c_limit-max_weight_g.
cl_abap_unit_assert=>assert_equals( exp = 3000 act = lv_limit ).
lv_limit = {{p}}if_bouquet_check=>c_limit-min_stem_cm.
cl_abap_unit_assert=>assert_equals( exp = 40 act = lv_limit ).
ENDMETHOD.
METHOD band_is_one_char.
DATA lv_band TYPE {{p}}if_bouquet_check=>ty_band.
lv_band = 'XY'.
cl_abap_unit_assert=>assert_equals( exp = 'X' act = lv_band ).
ENDMETHOD.
METHOD reason_is_ten_chars.
DATA lv_reason TYPE {{p}}if_bouquet_check=>ty_reason.
lv_reason = 'ABCDEFGHIJKL'.
cl_abap_unit_assert=>assert_equals( exp = 'ABCDEFGHIJ' act = lv_reason ).
ENDMETHOD.
METHOD result_parts.
DATA ls_result TYPE {{p}}if_bouquet_check=>ty_result.
DATA(lo_struct) = CAST cl_abap_structdescr(
cl_abap_typedescr=>describe_by_data( ls_result ) ).
DATA(lt_comp) = lo_struct->get_components( ).
cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_comp ) ).
cl_abap_unit_assert=>assert_equals( exp = 'BAND'
act = to_upper( lt_comp[ 1 ]-name ) ).
cl_abap_unit_assert=>assert_equals( exp = 'REASON'
act = to_upper( lt_comp[ 2 ]-name ) ).
ls_result-band = 'XY'.
cl_abap_unit_assert=>assert_equals( exp = 'X' act = ls_result-band ).
ls_result-reason = 'ABCDEFGHIJKL'.
cl_abap_unit_assert=>assert_equals( exp = 'ABCDEFGHIJ'
act = ls_result-reason ).
ENDMETHOD.
METHOD order_contract.
DATA mo_cut TYPE REF TO {{p}}if_bouquet_check.
mo_cut = NEW {{p}}bouquet_check_test( ).
DATA(ls_result) = mo_cut->check_order( iv_stems = 25
iv_weight_g = 1200
iv_stem_cm = 45 ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_bouquet_check=>c_band-small
act = ls_result-band ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_bouquet_check=>c_reason-ok
act = ls_result-reason ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,41 @@
INTERFACE {{p}}if_bouquet_check PUBLIC.
TYPES ty_band TYPE c LENGTH 1.
TYPES ty_reason TYPE c LENGTH 10.
TYPES:
BEGIN OF ty_result,
band TYPE ty_band,
reason TYPE ty_reason,
END OF ty_result.
CONSTANTS:
BEGIN OF c_band,
small TYPE ty_band VALUE 'S',
medium TYPE ty_band VALUE 'M',
large TYPE ty_band VALUE 'L',
END OF c_band.
CONSTANTS:
BEGIN OF c_reason,
ok TYPE ty_reason VALUE 'OK',
invalid TYPE ty_reason VALUE 'INVALID',
short TYPE ty_reason VALUE 'SHORT',
weight TYPE ty_reason VALUE 'WEIGHT',
stems TYPE ty_reason VALUE 'STEMS',
END OF c_reason.
CONSTANTS:
BEGIN OF c_limit,
max_stems_small TYPE i VALUE 20,
max_stems_medium TYPE i VALUE 40,
max_stems_large TYPE i VALUE 60,
max_weight_g TYPE i VALUE 3000,
min_stem_cm TYPE i VALUE 40,
END OF c_limit.
METHODS check_order
IMPORTING iv_stems TYPE i
iv_weight_g TYPE i
iv_stem_cm TYPE i
RETURNING VALUE(rs_result) TYPE ty_result.
ENDINTERFACE.

View File

@@ -0,0 +1,66 @@
# 1. Goal
A florist's order desk checks a bouquet order before the workshop starts the
work. The order desk software needs one interface for this check. The interface
defines the bouquet bands, the reason codes and the limits of the workshop.
Create this interface.
# 2. Open questions
None.
# 3. Context
- Package $TMP.
- A bouquet order has a number of stems, a total weight in grams and the length
of a stem in centimetres.
- The workshop uses three bouquet bands: S, M and L.
- The result of the check is a structure with the band and a reason code.
- The reason OK means that the order is correct. INVALID means that a value is
not positive. SHORT means that the stem is shorter than the workshop allows.
WEIGHT means that the bouquet is heavier than the workshop allows. STEMS means
that the order has more stems than the workshop allows.
- The workshop accepts at most 3000 g and a stem of at least 40 cm. The bands
S, M and L take at most 20, 40 and 60 stems.
# 4. Contract
- Create the interface {{P}}IF_BOUQUET_CHECK in package $TMP.
- The interface is public. It contains the types, the constants and the method
of the business rules and no other components.
- Do not create other repository objects.
# 5. Business rules
1. Type TY_BAND is a character type of length 1.
2. Type TY_REASON is a character type of length 10.
3. Type TY_RESULT is a structure with exactly two components in this sequence:
BAND of type TY_BAND, then REASON of type TY_REASON.
4. Constant structure C_BAND has exactly three components of type TY_BAND:
SMALL with the value 'S', MEDIUM with the value 'M' and LARGE with the value
'L'.
5. Constant structure C_REASON has exactly five components of type TY_REASON:
OK with the value 'OK', INVALID with the value 'INVALID', SHORT with the
value 'SHORT', WEIGHT with the value 'WEIGHT' and STEMS with the value
'STEMS'.
6. Constant structure C_LIMIT has exactly five components of type I:
MAX_STEMS_SMALL with the value 20, MAX_STEMS_MEDIUM with the value 40,
MAX_STEMS_LARGE with the value 60, MAX_WEIGHT_G with the value 3000 and
MIN_STEM_CM with the value 40.
7. The interface has the method CHECK_ORDER with the importing parameters
IV_STEMS of type I, IV_WEIGHT_G of type I and IV_STEM_CM of type I, and the
returning parameter RS_RESULT of type TY_RESULT.
8. The band of the result is SMALL if IV_STEMS is at most MAX_STEMS_SMALL,
MEDIUM if IV_STEMS is at most MAX_STEMS_MEDIUM, and LARGE in all other
cases.
9. The reason of the result is the reason of the first rule that fails, in this
sequence: INVALID if IV_STEMS, IV_WEIGHT_G or IV_STEM_CM is less than 1;
SHORT if IV_STEM_CM is less than MIN_STEM_CM; WEIGHT if IV_WEIGHT_G is
greater than MAX_WEIGHT_G; STEMS if IV_STEMS is greater than
MAX_STEMS_LARGE. If no rule fails, the reason is OK.
# 6. Constraints
- Release target: ABAP Platform 2025 (SAP_BASIS 816).
- Coding standards: Clean ABAP. An interface has no implementation.
- Out of scope: no class that implements the interface, no database table, no
CDS view entity.
# 7. Acceptance
- The interface {{P}}IF_BOUQUET_CHECK is active and has no syntax error.
- The hidden tests pass.
- Write your own ABAP Unit tests for the interface.

View File

@@ -0,0 +1,52 @@
{
"id": "G1917",
"category": "A",
"object_type": "INTF",
"difficulty": 2,
"release_target": "v816",
"expected_outcome": "implement",
"budget": {
"max_tool_calls": 60,
"max_activations": 15
},
"seed": [],
"contract": [
{
"type": "INTF",
"name": "{{P}}IF_BOUQUET_CHECK"
}
],
"out_of_scope": [
"No class that implements the interface",
"No database table",
"No CDS view entity",
"No function module",
"No report"
],
"hidden_tests": [
{
"type": "CLAS",
"name": "{{P}}BOUQUET_CHECK_HIDDEN",
"file": "hidden/bouquet_check_hidden.clas.abap",
"description": "Contract tests for {{P}}IF_BOUQUET_CHECK: the test class implements the interface, reads the constants, checks the type lengths, the result structure and calls the method through the interface"
}
],
"reference": [
{
"type": "INTF",
"name": "{{P}}IF_BOUQUET_CHECK",
"file": "reference/if_bouquet_check.intf.abap",
"description": "Bouquet order check contract"
},
{
"type": "CLAS",
"name": "{{P}}BOUQUET_CHECK_TEST",
"file": "reference/bouquet_check_test.clas.abap",
"description": "Own ABAP Unit tests for the interface"
}
],
"craft_checks": [
"method_length",
"db_operation_in_loop"
]
}

View File

@@ -0,0 +1,61 @@
INTERFACE {{p}}if_bouquet_pricing PUBLIC.
TYPES:
ty_size TYPE c LENGTH 1,
ty_zone TYPE c LENGTH 1,
ty_reason TYPE c LENGTH 12,
ty_amount TYPE p LENGTH 8 DECIMALS 2,
ty_stems TYPE i.
CONSTANTS:
BEGIN OF c_size,
small TYPE ty_size VALUE 'S',
medium TYPE ty_size VALUE 'M',
large TYPE ty_size VALUE 'L',
END OF c_size.
CONSTANTS:
BEGIN OF c_zone,
town TYPE ty_zone VALUE 'T1',
nearby TYPE ty_zone VALUE 'N1',
far TYPE ty_zone VALUE 'F1',
END OF c_zone.
CONSTANTS:
BEGIN OF c_reason,
ok TYPE ty_reason VALUE 'OK',
no_stems TYPE ty_reason VALUE 'NO_STEMS',
too_many TYPE ty_reason VALUE 'TOO_MANY',
bad_size TYPE ty_reason VALUE 'BAD_SIZE',
bad_zone TYPE ty_reason VALUE 'BAD_ZONE',
END OF c_reason.
CONSTANTS:
BEGIN OF c_limit,
min_stems TYPE ty_stems VALUE 5,
max_stems TYPE ty_stems VALUE 60,
END OF c_limit.
CONSTANTS:
BEGIN OF c_fee,
vase TYPE ty_amount VALUE '4.50',
town TYPE ty_amount VALUE '0.00',
nearby TYPE ty_amount VALUE '6.00',
far TYPE ty_amount VALUE '12.00',
END OF c_fee.
METHODS check_order
IMPORTING iv_size TYPE ty_size
iv_stems TYPE ty_stems
iv_zone TYPE ty_zone
RETURNING VALUE(rv_reason) TYPE ty_reason.
METHODS delivery_fee
IMPORTING iv_zone TYPE ty_zone
RETURNING VALUE(rv_fee) TYPE ty_amount.
METHODS bouquet_price
IMPORTING iv_size TYPE ty_size
iv_stems TYPE ty_stems
iv_vase TYPE abap_bool
RETURNING VALUE(rv_price) TYPE ty_amount.
ENDINTERFACE.

View File

@@ -0,0 +1,61 @@
INTERFACE {{p}}if_bouquet_pricing PUBLIC.
TYPES:
ty_size TYPE c LENGTH 1,
ty_zone TYPE c LENGTH 2,
ty_reason TYPE c LENGTH 12,
ty_amount TYPE p LENGTH 8 DECIMALS 2,
ty_stems TYPE i.
CONSTANTS:
BEGIN OF c_size,
small TYPE ty_size VALUE 'S',
medium TYPE ty_size VALUE 'M',
large TYPE ty_size VALUE 'L',
END OF c_size.
CONSTANTS:
BEGIN OF c_zone,
town TYPE ty_zone VALUE 'T1',
nearby TYPE ty_zone VALUE 'N1',
far TYPE ty_zone VALUE 'Z1',
END OF c_zone.
CONSTANTS:
BEGIN OF c_reason,
ok TYPE ty_reason VALUE 'OK',
no_stems TYPE ty_reason VALUE 'NO_STEMS',
too_many TYPE ty_reason VALUE 'TOO_MANY',
bad_size TYPE ty_reason VALUE 'BAD_SIZE',
bad_zone TYPE ty_reason VALUE 'BAD_ZONE',
END OF c_reason.
CONSTANTS:
BEGIN OF c_limit,
min_stems TYPE ty_stems VALUE 5,
max_stems TYPE ty_stems VALUE 60,
END OF c_limit.
CONSTANTS:
BEGIN OF c_fee,
vase TYPE ty_amount VALUE '4.50',
town TYPE ty_amount VALUE '0.00',
nearby TYPE ty_amount VALUE '6.00',
far TYPE ty_amount VALUE '12.00',
END OF c_fee.
METHODS check_order
IMPORTING iv_size TYPE ty_size
iv_stems TYPE ty_stems
iv_zone TYPE ty_zone
RETURNING VALUE(rv_reason) TYPE ty_reason.
METHODS delivery_fee
IMPORTING iv_zone TYPE ty_zone
RETURNING VALUE(rv_fee) TYPE ty_amount.
METHODS bouquet_price
IMPORTING iv_size TYPE ty_size
iv_stems TYPE ty_stems
iv_vase TYPE abap_bool
RETURNING VALUE(rv_price) TYPE ty_amount.
ENDINTERFACE.

View File

@@ -0,0 +1,61 @@
INTERFACE {{p}}if_bouquet_pricing PUBLIC.
TYPES:
ty_size TYPE c LENGTH 1,
ty_zone TYPE c LENGTH 2,
ty_reason TYPE c LENGTH 12,
ty_amount TYPE p LENGTH 8 DECIMALS 2,
ty_stems TYPE i.
CONSTANTS:
BEGIN OF c_size,
small TYPE ty_size VALUE 'S',
medium TYPE ty_size VALUE 'M',
large TYPE ty_size VALUE 'L',
END OF c_size.
CONSTANTS:
BEGIN OF c_zone,
town TYPE ty_zone VALUE 'T1',
nearby TYPE ty_zone VALUE 'N1',
far TYPE ty_zone VALUE 'F1',
END OF c_zone.
CONSTANTS:
BEGIN OF c_reason,
ok TYPE ty_reason VALUE 'ZK',
no_stems TYPE ty_reason VALUE 'NO_STEMS',
too_many TYPE ty_reason VALUE 'TOO_MANY',
bad_size TYPE ty_reason VALUE 'BAD_SIZE',
bad_zone TYPE ty_reason VALUE 'BAD_ZONE',
END OF c_reason.
CONSTANTS:
BEGIN OF c_limit,
min_stems TYPE ty_stems VALUE 5,
max_stems TYPE ty_stems VALUE 60,
END OF c_limit.
CONSTANTS:
BEGIN OF c_fee,
vase TYPE ty_amount VALUE '4.50',
town TYPE ty_amount VALUE '0.00',
nearby TYPE ty_amount VALUE '6.00',
far TYPE ty_amount VALUE '12.00',
END OF c_fee.
METHODS check_order
IMPORTING iv_size TYPE ty_size
iv_stems TYPE ty_stems
iv_zone TYPE ty_zone
RETURNING VALUE(rv_reason) TYPE ty_reason.
METHODS delivery_fee
IMPORTING iv_zone TYPE ty_zone
RETURNING VALUE(rv_fee) TYPE ty_amount.
METHODS bouquet_price
IMPORTING iv_size TYPE ty_size
iv_stems TYPE ty_stems
iv_vase TYPE abap_bool
RETURNING VALUE(rv_price) TYPE ty_amount.
ENDINTERFACE.

View File

@@ -0,0 +1,61 @@
INTERFACE {{p}}if_bouquet_pricing PUBLIC.
TYPES:
ty_size TYPE c LENGTH 1,
ty_zone TYPE c LENGTH 2,
ty_reason TYPE c LENGTH 12,
ty_amount TYPE p LENGTH 8 DECIMALS 2,
ty_stems TYPE i.
CONSTANTS:
BEGIN OF c_size,
small TYPE ty_size VALUE 'S',
medium TYPE ty_size VALUE 'M',
large TYPE ty_size VALUE 'L',
END OF c_size.
CONSTANTS:
BEGIN OF c_zone,
town TYPE ty_zone VALUE 'T1',
nearby TYPE ty_zone VALUE 'N1',
far TYPE ty_zone VALUE 'F1',
END OF c_zone.
CONSTANTS:
BEGIN OF c_reason,
ok TYPE ty_reason VALUE 'OK',
no_stems TYPE ty_reason VALUE 'NO_STEMS',
too_many TYPE ty_reason VALUE 'ZOO_MANY',
bad_size TYPE ty_reason VALUE 'BAD_SIZE',
bad_zone TYPE ty_reason VALUE 'BAD_ZONE',
END OF c_reason.
CONSTANTS:
BEGIN OF c_limit,
min_stems TYPE ty_stems VALUE 5,
max_stems TYPE ty_stems VALUE 60,
END OF c_limit.
CONSTANTS:
BEGIN OF c_fee,
vase TYPE ty_amount VALUE '4.50',
town TYPE ty_amount VALUE '0.00',
nearby TYPE ty_amount VALUE '6.00',
far TYPE ty_amount VALUE '12.00',
END OF c_fee.
METHODS check_order
IMPORTING iv_size TYPE ty_size
iv_stems TYPE ty_stems
iv_zone TYPE ty_zone
RETURNING VALUE(rv_reason) TYPE ty_reason.
METHODS delivery_fee
IMPORTING iv_zone TYPE ty_zone
RETURNING VALUE(rv_fee) TYPE ty_amount.
METHODS bouquet_price
IMPORTING iv_size TYPE ty_size
iv_stems TYPE ty_stems
iv_vase TYPE abap_bool
RETURNING VALUE(rv_price) TYPE ty_amount.
ENDINTERFACE.

View File

@@ -0,0 +1,39 @@
{
"id": "G1918",
"pool": "train",
"object_type": "INTF",
"category": "A",
"attempts": [
{
"stage": "bundle",
"errors": [
"hidden/t02_hidden.clas.abap line 62: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"5\"",
"reference/bouquet_if_test.clas.abap line 59: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"5\""
],
"by_check": {
"abaplint": 2
}
},
{
"stage": "validate",
"oracle": 0,
"null": 0
},
{
"stage": "validate",
"oracle": 80.6,
"null": 0
},
{
"stage": "validate",
"oracle": 100.0,
"null": 0,
"mutation": {
"valid": 4,
"killed": 4,
"ok": true
}
}
],
"accepted": true
}

View File

@@ -0,0 +1,173 @@
CLASS {{p}}t02_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PUBLIC SECTION.
INTERFACES {{p}}if_bouquet_pricing.
PRIVATE SECTION.
METHODS size_constants FOR TESTING.
METHODS zone_constants FOR TESTING.
METHODS reason_constants FOR TESTING.
METHODS limit_constants FOR TESTING.
METHODS fee_constants FOR TESTING.
METHODS type_lengths FOR TESTING.
METHODS check_order_contract FOR TESTING.
METHODS delivery_fee_contract FOR TESTING.
METHODS bouquet_price_contract FOR TESTING.
ENDCLASS.
CLASS {{p}}t02_hidden IMPLEMENTATION.
METHOD {{p}}if_bouquet_pricing~check_order.
rv_reason = {{p}}if_bouquet_pricing=>c_reason-ok.
ENDMETHOD.
METHOD {{p}}if_bouquet_pricing~delivery_fee.
rv_fee = {{p}}if_bouquet_pricing=>c_fee-nearby.
ENDMETHOD.
METHOD {{p}}if_bouquet_pricing~bouquet_price.
rv_price = {{p}}if_bouquet_pricing=>c_fee-vase.
ENDMETHOD.
METHOD size_constants.
DATA lv_exp TYPE {{p}}if_bouquet_pricing=>ty_size.
lv_exp = 'S'.
cl_abap_unit_assert=>assert_equals( exp = lv_exp
act = {{p}}if_bouquet_pricing=>c_size-small ).
lv_exp = 'M'.
cl_abap_unit_assert=>assert_equals( exp = lv_exp
act = {{p}}if_bouquet_pricing=>c_size-medium ).
lv_exp = 'L'.
cl_abap_unit_assert=>assert_equals( exp = lv_exp
act = {{p}}if_bouquet_pricing=>c_size-large ).
ENDMETHOD.
METHOD zone_constants.
DATA lv_exp TYPE {{p}}if_bouquet_pricing=>ty_zone.
lv_exp = 'T1'.
cl_abap_unit_assert=>assert_equals( exp = lv_exp
act = {{p}}if_bouquet_pricing=>c_zone-town ).
lv_exp = 'N1'.
cl_abap_unit_assert=>assert_equals( exp = lv_exp
act = {{p}}if_bouquet_pricing=>c_zone-nearby ).
lv_exp = 'F1'.
cl_abap_unit_assert=>assert_equals( exp = lv_exp
act = {{p}}if_bouquet_pricing=>c_zone-far ).
ENDMETHOD.
METHOD reason_constants.
DATA lv_exp TYPE {{p}}if_bouquet_pricing=>ty_reason.
lv_exp = 'OK'.
cl_abap_unit_assert=>assert_equals( exp = lv_exp
act = {{p}}if_bouquet_pricing=>c_reason-ok ).
lv_exp = 'NO_STEMS'.
cl_abap_unit_assert=>assert_equals( exp = lv_exp
act = {{p}}if_bouquet_pricing=>c_reason-no_stems ).
lv_exp = 'TOO_MANY'.
cl_abap_unit_assert=>assert_equals( exp = lv_exp
act = {{p}}if_bouquet_pricing=>c_reason-too_many ).
lv_exp = 'BAD_SIZE'.
cl_abap_unit_assert=>assert_equals( exp = lv_exp
act = {{p}}if_bouquet_pricing=>c_reason-bad_size ).
lv_exp = 'BAD_ZONE'.
cl_abap_unit_assert=>assert_equals( exp = lv_exp
act = {{p}}if_bouquet_pricing=>c_reason-bad_zone ).
ENDMETHOD.
METHOD limit_constants.
DATA lv_exp TYPE {{p}}if_bouquet_pricing=>ty_stems.
lv_exp = 5.
cl_abap_unit_assert=>assert_equals( exp = lv_exp
act = {{p}}if_bouquet_pricing=>c_limit-min_stems ).
lv_exp = 60.
cl_abap_unit_assert=>assert_equals( exp = lv_exp
act = {{p}}if_bouquet_pricing=>c_limit-max_stems ).
ENDMETHOD.
METHOD fee_constants.
DATA lv_exp TYPE {{p}}if_bouquet_pricing=>ty_amount.
lv_exp = '4.50'.
cl_abap_unit_assert=>assert_equals( exp = lv_exp
act = {{p}}if_bouquet_pricing=>c_fee-vase ).
lv_exp = '0.00'.
cl_abap_unit_assert=>assert_equals( exp = lv_exp
act = {{p}}if_bouquet_pricing=>c_fee-town ).
lv_exp = '6.00'.
cl_abap_unit_assert=>assert_equals( exp = lv_exp
act = {{p}}if_bouquet_pricing=>c_fee-nearby ).
lv_exp = '12.00'.
cl_abap_unit_assert=>assert_equals( exp = lv_exp
act = {{p}}if_bouquet_pricing=>c_fee-far ).
ENDMETHOD.
METHOD type_lengths.
DATA lv_size TYPE {{p}}if_bouquet_pricing=>ty_size.
DATA lv_zone TYPE {{p}}if_bouquet_pricing=>ty_zone.
DATA lv_reason TYPE {{p}}if_bouquet_pricing=>ty_reason.
DATA lv_amount TYPE {{p}}if_bouquet_pricing=>ty_amount.
DATA lv_stems TYPE {{p}}if_bouquet_pricing=>ty_stems.
DATA lv_ref_size TYPE c LENGTH 1.
DATA lv_ref_zone TYPE c LENGTH 2.
DATA lv_ref_reason TYPE c LENGTH 12.
DATA lv_ref_amount TYPE p LENGTH 8 DECIMALS 2.
DATA lv_ref_stems TYPE i.
DATA(lo_size) = cl_abap_typedescr=>describe_by_data( lv_size ).
DATA(lo_zone) = cl_abap_typedescr=>describe_by_data( lv_zone ).
DATA(lo_reason) = cl_abap_typedescr=>describe_by_data( lv_reason ).
DATA(lo_amount) = cl_abap_typedescr=>describe_by_data( lv_amount ).
DATA(lo_stems) = cl_abap_typedescr=>describe_by_data( lv_stems ).
cl_abap_unit_assert=>assert_equals( exp = 'C' act = lo_size->type_kind ).
cl_abap_unit_assert=>assert_equals( exp = 'C' act = lo_zone->type_kind ).
cl_abap_unit_assert=>assert_equals( exp = 'C' act = lo_reason->type_kind ).
cl_abap_unit_assert=>assert_equals( exp = 'P' act = lo_amount->type_kind ).
cl_abap_unit_assert=>assert_equals( exp = 'I' act = lo_stems->type_kind ).
cl_abap_unit_assert=>assert_equals( exp = 2 act = lo_amount->decimals ).
cl_abap_unit_assert=>assert_equals(
exp = cl_abap_typedescr=>describe_by_data( lv_ref_size )->length
act = lo_size->length ).
cl_abap_unit_assert=>assert_equals(
exp = cl_abap_typedescr=>describe_by_data( lv_ref_zone )->length
act = lo_zone->length ).
cl_abap_unit_assert=>assert_equals(
exp = cl_abap_typedescr=>describe_by_data( lv_ref_reason )->length
act = lo_reason->length ).
cl_abap_unit_assert=>assert_equals(
exp = cl_abap_typedescr=>describe_by_data( lv_ref_amount )->length
act = lo_amount->length ).
cl_abap_unit_assert=>assert_equals(
exp = cl_abap_typedescr=>describe_by_data( lv_ref_stems )->length
act = lo_stems->length ).
ENDMETHOD.
METHOD check_order_contract.
DATA lo_cut TYPE REF TO {{p}}if_bouquet_pricing.
lo_cut = me.
DATA(lv_reason) = lo_cut->check_order( iv_size = {{p}}if_bouquet_pricing=>c_size-medium
iv_stems = 20
iv_zone = {{p}}if_bouquet_pricing=>c_zone-town ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_bouquet_pricing=>c_reason-ok
act = lv_reason ).
ENDMETHOD.
METHOD delivery_fee_contract.
DATA lo_cut TYPE REF TO {{p}}if_bouquet_pricing.
lo_cut = me.
DATA(lv_fee) = lo_cut->delivery_fee( iv_zone = {{p}}if_bouquet_pricing=>c_zone-nearby ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_bouquet_pricing=>c_fee-nearby
act = lv_fee ).
ENDMETHOD.
METHOD bouquet_price_contract.
DATA lo_cut TYPE REF TO {{p}}if_bouquet_pricing.
lo_cut = me.
DATA(lv_price) = lo_cut->bouquet_price( iv_size = {{p}}if_bouquet_pricing=>c_size-large
iv_stems = 40
iv_vase = abap_true ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_bouquet_pricing=>c_fee-vase
act = lv_price ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,52 @@
{
"task": "G1918",
"mutants": [
{
"object": "{{P}}IF_BOUQUET_PRICING",
"mutant": "line 4: LENGTH 2 -> LENGTH 1 (length)",
"status": "killed",
"hidden": "8/9",
"failed_tests": [
"TYPE_LENGTHS"
]
},
{
"object": "{{P}}IF_BOUQUET_PRICING",
"mutant": "line 20: VALUE 'F1' -> VALUE 'Z1' (lit)",
"status": "killed",
"hidden": "8/9",
"failed_tests": [
"ZONE_CONSTANTS"
]
},
{
"object": "{{P}}IF_BOUQUET_PRICING",
"mutant": "line 25: VALUE 'OK' -> VALUE 'ZK' (lit)",
"status": "killed",
"hidden": "8/9",
"failed_tests": [
"REASON_CONSTANTS"
]
},
{
"object": "{{P}}IF_BOUQUET_PRICING",
"mutant": "line 27: VALUE 'TOO_MANY' -> VALUE 'ZOO_MANY' (lit)",
"status": "killed",
"hidden": "8/9",
"failed_tests": [
"REASON_CONSTANTS"
]
},
{
"object": "{{P}}IF_BOUQUET_PRICING",
"mutant": "line 41: VALUE '0.00' -> VALUE 'Z.00' (lit)",
"status": "invalid",
"hidden": "0/0",
"failed_tests": []
}
],
"valid": 4,
"killed": 4,
"kill_rate": 1.0,
"ok": true
}

View File

@@ -0,0 +1,142 @@
CLASS {{p}}bouquet_if_test DEFINITION PUBLIC FINAL CREATE PUBLIC
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PUBLIC SECTION.
INTERFACES {{p}}if_bouquet_pricing.
PRIVATE SECTION.
METHODS size_values FOR TESTING.
METHODS zone_values FOR TESTING.
METHODS reason_values FOR TESTING.
METHODS limit_values FOR TESTING.
METHODS fee_values FOR TESTING.
METHODS types_are_correct FOR TESTING.
ENDCLASS.
CLASS {{p}}bouquet_if_test IMPLEMENTATION.
METHOD {{p}}if_bouquet_pricing~check_order.
rv_reason = {{p}}if_bouquet_pricing=>c_reason-ok.
ENDMETHOD.
METHOD {{p}}if_bouquet_pricing~delivery_fee.
rv_fee = {{p}}if_bouquet_pricing=>c_fee-town.
ENDMETHOD.
METHOD {{p}}if_bouquet_pricing~bouquet_price.
rv_price = {{p}}if_bouquet_pricing=>c_fee-vase.
ENDMETHOD.
METHOD size_values.
DATA lv_exp TYPE {{p}}if_bouquet_pricing=>ty_size.
lv_exp = 'S'.
cl_abap_unit_assert=>assert_equals( exp = lv_exp
act = {{p}}if_bouquet_pricing=>c_size-small ).
lv_exp = 'M'.
cl_abap_unit_assert=>assert_equals( exp = lv_exp
act = {{p}}if_bouquet_pricing=>c_size-medium ).
lv_exp = 'L'.
cl_abap_unit_assert=>assert_equals( exp = lv_exp
act = {{p}}if_bouquet_pricing=>c_size-large ).
ENDMETHOD.
METHOD zone_values.
DATA lv_exp TYPE {{p}}if_bouquet_pricing=>ty_zone.
lv_exp = 'T1'.
cl_abap_unit_assert=>assert_equals( exp = lv_exp
act = {{p}}if_bouquet_pricing=>c_zone-town ).
lv_exp = 'N1'.
cl_abap_unit_assert=>assert_equals( exp = lv_exp
act = {{p}}if_bouquet_pricing=>c_zone-nearby ).
lv_exp = 'F1'.
cl_abap_unit_assert=>assert_equals( exp = lv_exp
act = {{p}}if_bouquet_pricing=>c_zone-far ).
ENDMETHOD.
METHOD reason_values.
DATA lv_exp TYPE {{p}}if_bouquet_pricing=>ty_reason.
lv_exp = 'OK'.
cl_abap_unit_assert=>assert_equals( exp = lv_exp
act = {{p}}if_bouquet_pricing=>c_reason-ok ).
lv_exp = 'NO_STEMS'.
cl_abap_unit_assert=>assert_equals( exp = lv_exp
act = {{p}}if_bouquet_pricing=>c_reason-no_stems ).
lv_exp = 'TOO_MANY'.
cl_abap_unit_assert=>assert_equals( exp = lv_exp
act = {{p}}if_bouquet_pricing=>c_reason-too_many ).
lv_exp = 'BAD_SIZE'.
cl_abap_unit_assert=>assert_equals( exp = lv_exp
act = {{p}}if_bouquet_pricing=>c_reason-bad_size ).
lv_exp = 'BAD_ZONE'.
cl_abap_unit_assert=>assert_equals( exp = lv_exp
act = {{p}}if_bouquet_pricing=>c_reason-bad_zone ).
ENDMETHOD.
METHOD limit_values.
DATA lv_exp TYPE {{p}}if_bouquet_pricing=>ty_stems.
lv_exp = 5.
cl_abap_unit_assert=>assert_equals( exp = lv_exp
act = {{p}}if_bouquet_pricing=>c_limit-min_stems ).
lv_exp = 60.
cl_abap_unit_assert=>assert_equals( exp = lv_exp
act = {{p}}if_bouquet_pricing=>c_limit-max_stems ).
ENDMETHOD.
METHOD fee_values.
DATA lv_exp TYPE {{p}}if_bouquet_pricing=>ty_amount.
lv_exp = '4.50'.
cl_abap_unit_assert=>assert_equals( exp = lv_exp
act = {{p}}if_bouquet_pricing=>c_fee-vase ).
lv_exp = '0.00'.
cl_abap_unit_assert=>assert_equals( exp = lv_exp
act = {{p}}if_bouquet_pricing=>c_fee-town ).
lv_exp = '6.00'.
cl_abap_unit_assert=>assert_equals( exp = lv_exp
act = {{p}}if_bouquet_pricing=>c_fee-nearby ).
lv_exp = '12.00'.
cl_abap_unit_assert=>assert_equals( exp = lv_exp
act = {{p}}if_bouquet_pricing=>c_fee-far ).
ENDMETHOD.
METHOD types_are_correct.
DATA lv_size TYPE {{p}}if_bouquet_pricing=>ty_size.
DATA lv_zone TYPE {{p}}if_bouquet_pricing=>ty_zone.
DATA lv_reason TYPE {{p}}if_bouquet_pricing=>ty_reason.
DATA lv_amount TYPE {{p}}if_bouquet_pricing=>ty_amount.
DATA lv_stems TYPE {{p}}if_bouquet_pricing=>ty_stems.
DATA lv_ref_size TYPE c LENGTH 1.
DATA lv_ref_zone TYPE c LENGTH 2.
DATA lv_ref_reason TYPE c LENGTH 12.
DATA lv_ref_amount TYPE p LENGTH 8 DECIMALS 2.
DATA lv_ref_stems TYPE i.
DATA(lo_size) = cl_abap_typedescr=>describe_by_data( lv_size ).
DATA(lo_zone) = cl_abap_typedescr=>describe_by_data( lv_zone ).
DATA(lo_reason) = cl_abap_typedescr=>describe_by_data( lv_reason ).
DATA(lo_amount) = cl_abap_typedescr=>describe_by_data( lv_amount ).
DATA(lo_stems) = cl_abap_typedescr=>describe_by_data( lv_stems ).
cl_abap_unit_assert=>assert_equals( exp = 'C' act = lo_size->type_kind ).
cl_abap_unit_assert=>assert_equals( exp = 'C' act = lo_zone->type_kind ).
cl_abap_unit_assert=>assert_equals( exp = 'C' act = lo_reason->type_kind ).
cl_abap_unit_assert=>assert_equals( exp = 'P' act = lo_amount->type_kind ).
cl_abap_unit_assert=>assert_equals( exp = 'I' act = lo_stems->type_kind ).
cl_abap_unit_assert=>assert_equals( exp = 2 act = lo_amount->decimals ).
cl_abap_unit_assert=>assert_equals(
exp = cl_abap_typedescr=>describe_by_data( lv_ref_size )->length
act = lo_size->length ).
cl_abap_unit_assert=>assert_equals(
exp = cl_abap_typedescr=>describe_by_data( lv_ref_zone )->length
act = lo_zone->length ).
cl_abap_unit_assert=>assert_equals(
exp = cl_abap_typedescr=>describe_by_data( lv_ref_reason )->length
act = lo_reason->length ).
cl_abap_unit_assert=>assert_equals(
exp = cl_abap_typedescr=>describe_by_data( lv_ref_amount )->length
act = lo_amount->length ).
cl_abap_unit_assert=>assert_equals(
exp = cl_abap_typedescr=>describe_by_data( lv_ref_stems )->length
act = lo_stems->length ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,61 @@
INTERFACE {{p}}if_bouquet_pricing PUBLIC.
TYPES:
ty_size TYPE c LENGTH 1,
ty_zone TYPE c LENGTH 2,
ty_reason TYPE c LENGTH 12,
ty_amount TYPE p LENGTH 8 DECIMALS 2,
ty_stems TYPE i.
CONSTANTS:
BEGIN OF c_size,
small TYPE ty_size VALUE 'S',
medium TYPE ty_size VALUE 'M',
large TYPE ty_size VALUE 'L',
END OF c_size.
CONSTANTS:
BEGIN OF c_zone,
town TYPE ty_zone VALUE 'T1',
nearby TYPE ty_zone VALUE 'N1',
far TYPE ty_zone VALUE 'F1',
END OF c_zone.
CONSTANTS:
BEGIN OF c_reason,
ok TYPE ty_reason VALUE 'OK',
no_stems TYPE ty_reason VALUE 'NO_STEMS',
too_many TYPE ty_reason VALUE 'TOO_MANY',
bad_size TYPE ty_reason VALUE 'BAD_SIZE',
bad_zone TYPE ty_reason VALUE 'BAD_ZONE',
END OF c_reason.
CONSTANTS:
BEGIN OF c_limit,
min_stems TYPE ty_stems VALUE 5,
max_stems TYPE ty_stems VALUE 60,
END OF c_limit.
CONSTANTS:
BEGIN OF c_fee,
vase TYPE ty_amount VALUE '4.50',
town TYPE ty_amount VALUE '0.00',
nearby TYPE ty_amount VALUE '6.00',
far TYPE ty_amount VALUE '12.00',
END OF c_fee.
METHODS check_order
IMPORTING iv_size TYPE ty_size
iv_stems TYPE ty_stems
iv_zone TYPE ty_zone
RETURNING VALUE(rv_reason) TYPE ty_reason.
METHODS delivery_fee
IMPORTING iv_zone TYPE ty_zone
RETURNING VALUE(rv_fee) TYPE ty_amount.
METHODS bouquet_price
IMPORTING iv_size TYPE ty_size
iv_stems TYPE ty_stems
iv_vase TYPE abap_bool
RETURNING VALUE(rv_price) TYPE ty_amount.
ENDINTERFACE.

View File

@@ -0,0 +1,93 @@
# 1. Goal
The order desk of a florist prices bouquet orders. The shop counter, the web
shop and the telephone desk must all use the same contract. Create the interface
{{P}}IF_BOUQUET_PRICING in package $TMP. The interface fixes the types, the
constants and the methods of the contract.
# 2. Open questions
None.
# 3. Context
- The interface {{P}}IF_BOUQUET_PRICING does not exist yet.
- The interface is in package $TMP.
- Every pricing module of the florist implements this interface. The pricing
modules are not part of this task.
- The hidden tests use a class that implements the interface. That class only
compiles when every type, every constant and every method signature matches.
# 4. Contract
- Create the interface {{P}}IF_BOUQUET_PRICING in package $TMP.
- The interface is global and public.
- The interface contains the types, the constants and the methods of section 5.
- Do not add other components to the interface.
# 5. Business rules
## 5.1 Types
The interface defines these five types.
| Type | Definition |
| --- | --- |
| ty_size | TYPE c LENGTH 1 |
| ty_zone | TYPE c LENGTH 2 |
| ty_reason | TYPE c LENGTH 12 |
| ty_amount | TYPE p LENGTH 8 DECIMALS 2 |
| ty_stems | TYPE i |
## 5.2 Constants
The interface defines these five constant structures.
c_size has the type ty_size. The components are:
- small = 'S'. A small bouquet.
- medium = 'M'. A medium bouquet.
- large = 'L'. A large bouquet.
c_zone has the type ty_zone. The components are:
- town = 'T1'. A delivery inside the town.
- nearby = 'N1'. A delivery in the near area.
- far = 'F1'. A delivery in the far area.
c_reason has the type ty_reason. The components are:
- ok = 'OK'.
- no_stems = 'NO_STEMS'.
- too_many = 'TOO_MANY'.
- bad_size = 'BAD_SIZE'.
- bad_zone = 'BAD_ZONE'.
c_limit has the type ty_stems. The components are:
- min_stems = 5.
- max_stems = 60.
c_fee has the type ty_amount. The components are:
- vase = '4.50'. The fee for a vase.
- town = '0.00'. The delivery fee inside the town.
- nearby = '6.00'. The delivery fee in the near area.
- far = '12.00'. The delivery fee in the far area.
## 5.3 Methods
The interface defines these three methods.
1. check_order
IMPORTING iv_size TYPE ty_size
iv_stems TYPE ty_stems
iv_zone TYPE ty_zone
RETURNING VALUE(rv_reason) TYPE ty_reason.
2. delivery_fee
IMPORTING iv_zone TYPE ty_zone
RETURNING VALUE(rv_fee) TYPE ty_amount.
3. bouquet_price
IMPORTING iv_size TYPE ty_size
iv_stems TYPE ty_stems
iv_vase TYPE abap_bool
RETURNING VALUE(rv_price) TYPE ty_amount.
# 6. Constraints
- Release target: 7.58.
- Coding standards: Clean ABAP. No comment that restates the code.
- Out of scope: no other repository object. Do not change other objects of
package $TMP.
# 7. Acceptance
- The interface {{P}}IF_BOUQUET_PRICING is active and has no syntax error.
- The hidden tests pass.
- Write your own ABAP Unit tests in a global test class in package $TMP.

View File

@@ -0,0 +1,46 @@
{
"id": "G1918",
"category": "A",
"object_type": "INTF",
"difficulty": 2,
"release_target": "v758",
"expected_outcome": "implement",
"budget": {
"max_tool_calls": 60,
"max_activations": 15
},
"seed": [],
"contract": [
{
"type": "INTF",
"name": "{{P}}IF_BOUQUET_PRICING"
}
],
"out_of_scope": [],
"hidden_tests": [
{
"type": "CLAS",
"name": "{{P}}T02_HIDDEN",
"file": "hidden/t02_hidden.clas.abap",
"description": "T02 hidden tests: constants, types and method signatures of {{P}}IF_BOUQUET_PRICING"
}
],
"reference": [
{
"type": "INTF",
"name": "{{P}}IF_BOUQUET_PRICING",
"file": "reference/bouquet_pricing.intf.abap",
"description": "Bouquet pricing contract of the florist order desk"
},
{
"type": "CLAS",
"name": "{{P}}BOUQUET_IF_TEST",
"file": "reference/bouquet_if_test.clas.abap",
"description": "Own ABAP Unit tests for the interface contract"
}
],
"craft_checks": [
"method_length",
"db_operation_in_loop"
]
}

View File

@@ -0,0 +1,17 @@
@EndUserText.label : 'Mountain rescue callout'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table {{p}}rescue {
key client : abap.clnt not null;
callout_id : abap.char(10) not null;
callout_date : abap.dats not null;
location : abap.char(30);
duration_min : abap.int4;
team_size : abap.int4;
rescued_count : abap.int4;
@Semantics.amount.currencyCode : '{{p}}rescue.currency_code'
fee_amount : abap.dec(13,2);
currency_code : abap.cuky;
}

View File

@@ -0,0 +1,17 @@
@EndUserText.label : 'Mountain rescue callout'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table {{p}}rescue {
key client : abap.clnt not null;
key callout_id : abap.char(9) not null;
callout_date : abap.dats not null;
location : abap.char(30);
duration_min : abap.int4;
team_size : abap.int4;
rescued_count : abap.int4;
@Semantics.amount.currencyCode : '{{p}}rescue.currency_code'
fee_amount : abap.dec(13,2);
currency_code : abap.cuky;
}

View File

@@ -0,0 +1,17 @@
@EndUserText.label : 'Mountain rescue callout'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table {{p}}rescue {
key client : abap.clnt not null;
key callout_id : abap.char(10) not null;
callout_date : abap.tims not null;
location : abap.char(30);
duration_min : abap.int4;
team_size : abap.int4;
rescued_count : abap.int4;
@Semantics.amount.currencyCode : '{{p}}rescue.currency_code'
fee_amount : abap.dec(13,2);
currency_code : abap.cuky;
}

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