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

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

View File

@@ -0,0 +1,84 @@
CLASS {{p}}log_merger DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES:
ty_log_no TYPE c LENGTH 10,
ty_district TYPE c LENGTH 4,
BEGIN OF ty_log,
log_no TYPE ty_log_no,
district TYPE ty_district,
length_cm TYPE i,
diameter_cm TYPE i,
END OF ty_log,
tt_log TYPE STANDARD TABLE OF ty_log WITH EMPTY KEY,
BEGIN OF ty_district_stat,
district TYPE ty_district,
log_qty TYPE i,
total_length_cm TYPE i,
END OF ty_district_stat,
tt_district_stat TYPE STANDARD TABLE OF ty_district_stat WITH EMPTY KEY.
METHODS combine
IMPORTING it_first TYPE tt_log
it_second TYPE tt_log
RETURNING VALUE(rt_result) TYPE tt_log.
METHODS count_by_district
IMPORTING it_log TYPE tt_log
RETURNING VALUE(rt_stat) TYPE tt_district_stat.
PRIVATE SECTION.
CONSTANTS:
c_min_length TYPE i VALUE 200,
c_min_diameter TYPE i VALUE 20.
TYPES tt_log_keyed TYPE SORTED TABLE OF ty_log WITH UNIQUE KEY log_no.
METHODS add_logs
IMPORTING it_log TYPE tt_log
CHANGING ct_keyed TYPE tt_log_keyed.
METHODS is_ready
IMPORTING is_log TYPE ty_log
RETURNING VALUE(rv_ready) TYPE abap_bool.
ENDCLASS.
CLASS {{p}}log_merger IMPLEMENTATION.
METHOD combine.
DATA lt_keyed TYPE tt_log_keyed.
add_logs( EXPORTING it_log = it_first CHANGING ct_keyed = lt_keyed ).
add_logs( EXPORTING it_log = it_second CHANGING ct_keyed = lt_keyed ).
LOOP AT lt_keyed INTO DATA(ls_log).
IF is_ready( ls_log ) <> abap_true.
INSERT ls_log INTO TABLE rt_result.
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD count_by_district.
DATA lt_stat TYPE SORTED TABLE OF ty_district_stat WITH UNIQUE KEY district.
LOOP AT it_log INTO DATA(ls_log).
ASSIGN lt_stat[ district = ls_log-district ] TO FIELD-SYMBOL(<ls_stat>).
IF sy-subrc <> 0.
INSERT VALUE #( district = ls_log-district
log_qty = 1
total_length_cm = ls_log-length_cm ) INTO TABLE lt_stat.
ELSE.
<ls_stat>-log_qty += 1.
<ls_stat>-total_length_cm += ls_log-length_cm.
ENDIF.
ENDLOOP.
rt_stat = lt_stat.
ENDMETHOD.
METHOD add_logs.
LOOP AT it_log INTO DATA(ls_log).
INSERT ls_log INTO TABLE ct_keyed.
ENDLOOP.
ENDMETHOD.
METHOD is_ready.
rv_ready = xsdbool( is_log-length_cm >= c_min_length
AND is_log-diameter_cm >= c_min_diameter ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,84 @@
CLASS {{p}}log_merger DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES:
ty_log_no TYPE c LENGTH 10,
ty_district TYPE c LENGTH 4,
BEGIN OF ty_log,
log_no TYPE ty_log_no,
district TYPE ty_district,
length_cm TYPE i,
diameter_cm TYPE i,
END OF ty_log,
tt_log TYPE STANDARD TABLE OF ty_log WITH EMPTY KEY,
BEGIN OF ty_district_stat,
district TYPE ty_district,
log_qty TYPE i,
total_length_cm TYPE i,
END OF ty_district_stat,
tt_district_stat TYPE STANDARD TABLE OF ty_district_stat WITH EMPTY KEY.
METHODS combine
IMPORTING it_first TYPE tt_log
it_second TYPE tt_log
RETURNING VALUE(rt_result) TYPE tt_log.
METHODS count_by_district
IMPORTING it_log TYPE tt_log
RETURNING VALUE(rt_stat) TYPE tt_district_stat.
PRIVATE SECTION.
CONSTANTS:
c_min_length TYPE i VALUE 200,
c_min_diameter TYPE i VALUE 20.
TYPES tt_log_keyed TYPE SORTED TABLE OF ty_log WITH UNIQUE KEY log_no.
METHODS add_logs
IMPORTING it_log TYPE tt_log
CHANGING ct_keyed TYPE tt_log_keyed.
METHODS is_ready
IMPORTING is_log TYPE ty_log
RETURNING VALUE(rv_ready) TYPE abap_bool.
ENDCLASS.
CLASS {{p}}log_merger IMPLEMENTATION.
METHOD combine.
DATA lt_keyed TYPE tt_log_keyed.
add_logs( EXPORTING it_log = it_first CHANGING ct_keyed = lt_keyed ).
add_logs( EXPORTING it_log = it_second CHANGING ct_keyed = lt_keyed ).
LOOP AT lt_keyed INTO DATA(ls_log).
IF is_ready( ls_log ) = abap_false.
INSERT ls_log INTO TABLE rt_result.
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD count_by_district.
DATA lt_stat TYPE SORTED TABLE OF ty_district_stat WITH UNIQUE KEY district.
LOOP AT it_log INTO DATA(ls_log).
ASSIGN lt_stat[ district = ls_log-district ] TO FIELD-SYMBOL(<ls_stat>).
IF sy-subrc <> 0.
INSERT VALUE #( district = ls_log-district
log_qty = 1
total_length_cm = ls_log-length_cm ) INTO TABLE lt_stat.
ELSE.
<ls_stat>-log_qty += 1.
<ls_stat>-total_length_cm += ls_log-length_cm.
ENDIF.
ENDLOOP.
rt_stat = lt_stat.
ENDMETHOD.
METHOD add_logs.
LOOP AT it_log INTO DATA(ls_log).
INSERT ls_log INTO TABLE ct_keyed.
ENDLOOP.
ENDMETHOD.
METHOD is_ready.
rv_ready = xsdbool( is_log-length_cm >= c_min_length
AND is_log-diameter_cm >= c_min_diameter ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,84 @@
CLASS {{p}}log_merger DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES:
ty_log_no TYPE c LENGTH 10,
ty_district TYPE c LENGTH 4,
BEGIN OF ty_log,
log_no TYPE ty_log_no,
district TYPE ty_district,
length_cm TYPE i,
diameter_cm TYPE i,
END OF ty_log,
tt_log TYPE STANDARD TABLE OF ty_log WITH EMPTY KEY,
BEGIN OF ty_district_stat,
district TYPE ty_district,
log_qty TYPE i,
total_length_cm TYPE i,
END OF ty_district_stat,
tt_district_stat TYPE STANDARD TABLE OF ty_district_stat WITH EMPTY KEY.
METHODS combine
IMPORTING it_first TYPE tt_log
it_second TYPE tt_log
RETURNING VALUE(rt_result) TYPE tt_log.
METHODS count_by_district
IMPORTING it_log TYPE tt_log
RETURNING VALUE(rt_stat) TYPE tt_district_stat.
PRIVATE SECTION.
CONSTANTS:
c_min_length TYPE i VALUE 200,
c_min_diameter TYPE i VALUE 20.
TYPES tt_log_keyed TYPE SORTED TABLE OF ty_log WITH UNIQUE KEY log_no.
METHODS add_logs
IMPORTING it_log TYPE tt_log
CHANGING ct_keyed TYPE tt_log_keyed.
METHODS is_ready
IMPORTING is_log TYPE ty_log
RETURNING VALUE(rv_ready) TYPE abap_bool.
ENDCLASS.
CLASS {{p}}log_merger IMPLEMENTATION.
METHOD combine.
DATA lt_keyed TYPE tt_log_keyed.
add_logs( EXPORTING it_log = it_first CHANGING ct_keyed = lt_keyed ).
add_logs( EXPORTING it_log = it_second CHANGING ct_keyed = lt_keyed ).
LOOP AT lt_keyed INTO DATA(ls_log).
IF is_ready( ls_log ) = abap_true.
INSERT ls_log INTO TABLE rt_result.
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD count_by_district.
DATA lt_stat TYPE SORTED TABLE OF ty_district_stat WITH UNIQUE KEY district.
LOOP AT it_log INTO DATA(ls_log).
ASSIGN lt_stat[ district = ls_log-district ] TO FIELD-SYMBOL(<ls_stat>).
IF sy-subrc <> 0.
INSERT VALUE #( district = ls_log-district
log_qty = 2
total_length_cm = ls_log-length_cm ) INTO TABLE lt_stat.
ELSE.
<ls_stat>-log_qty += 1.
<ls_stat>-total_length_cm += ls_log-length_cm.
ENDIF.
ENDLOOP.
rt_stat = lt_stat.
ENDMETHOD.
METHOD add_logs.
LOOP AT it_log INTO DATA(ls_log).
INSERT ls_log INTO TABLE ct_keyed.
ENDLOOP.
ENDMETHOD.
METHOD is_ready.
rv_ready = xsdbool( is_log-length_cm >= c_min_length
AND is_log-diameter_cm >= c_min_diameter ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,84 @@
CLASS {{p}}log_merger DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES:
ty_log_no TYPE c LENGTH 10,
ty_district TYPE c LENGTH 4,
BEGIN OF ty_log,
log_no TYPE ty_log_no,
district TYPE ty_district,
length_cm TYPE i,
diameter_cm TYPE i,
END OF ty_log,
tt_log TYPE STANDARD TABLE OF ty_log WITH EMPTY KEY,
BEGIN OF ty_district_stat,
district TYPE ty_district,
log_qty TYPE i,
total_length_cm TYPE i,
END OF ty_district_stat,
tt_district_stat TYPE STANDARD TABLE OF ty_district_stat WITH EMPTY KEY.
METHODS combine
IMPORTING it_first TYPE tt_log
it_second TYPE tt_log
RETURNING VALUE(rt_result) TYPE tt_log.
METHODS count_by_district
IMPORTING it_log TYPE tt_log
RETURNING VALUE(rt_stat) TYPE tt_district_stat.
PRIVATE SECTION.
CONSTANTS:
c_min_length TYPE i VALUE 200,
c_min_diameter TYPE i VALUE 20.
TYPES tt_log_keyed TYPE SORTED TABLE OF ty_log WITH UNIQUE KEY log_no.
METHODS add_logs
IMPORTING it_log TYPE tt_log
CHANGING ct_keyed TYPE tt_log_keyed.
METHODS is_ready
IMPORTING is_log TYPE ty_log
RETURNING VALUE(rv_ready) TYPE abap_bool.
ENDCLASS.
CLASS {{p}}log_merger IMPLEMENTATION.
METHOD combine.
DATA lt_keyed TYPE tt_log_keyed.
add_logs( EXPORTING it_log = it_first CHANGING ct_keyed = lt_keyed ).
add_logs( EXPORTING it_log = it_second CHANGING ct_keyed = lt_keyed ).
LOOP AT lt_keyed INTO DATA(ls_log).
IF is_ready( ls_log ) = abap_true.
INSERT ls_log INTO TABLE rt_result.
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD count_by_district.
DATA lt_stat TYPE SORTED TABLE OF ty_district_stat WITH UNIQUE KEY district.
LOOP AT it_log INTO DATA(ls_log).
ASSIGN lt_stat[ district = ls_log-district ] TO FIELD-SYMBOL(<ls_stat>).
IF sy-subrc <> 0.
INSERT VALUE #( district = ls_log-district
log_qty = 1
total_length_cm = ls_log-length_cm ) INTO TABLE lt_stat.
ELSE.
<ls_stat>-log_qty += 1.
<ls_stat>-total_length_cm += ls_log-length_cm.
ENDIF.
ENDLOOP.
rt_stat = lt_stat.
ENDMETHOD.
METHOD add_logs.
LOOP AT it_log INTO DATA(ls_log).
INSERT ls_log INTO TABLE ct_keyed.
ENDLOOP.
ENDMETHOD.
METHOD is_ready.
rv_ready = xsdbool( is_log-length_cm < c_min_length
AND is_log-diameter_cm >= c_min_diameter ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,84 @@
CLASS {{p}}log_merger DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES:
ty_log_no TYPE c LENGTH 10,
ty_district TYPE c LENGTH 4,
BEGIN OF ty_log,
log_no TYPE ty_log_no,
district TYPE ty_district,
length_cm TYPE i,
diameter_cm TYPE i,
END OF ty_log,
tt_log TYPE STANDARD TABLE OF ty_log WITH EMPTY KEY,
BEGIN OF ty_district_stat,
district TYPE ty_district,
log_qty TYPE i,
total_length_cm TYPE i,
END OF ty_district_stat,
tt_district_stat TYPE STANDARD TABLE OF ty_district_stat WITH EMPTY KEY.
METHODS combine
IMPORTING it_first TYPE tt_log
it_second TYPE tt_log
RETURNING VALUE(rt_result) TYPE tt_log.
METHODS count_by_district
IMPORTING it_log TYPE tt_log
RETURNING VALUE(rt_stat) TYPE tt_district_stat.
PRIVATE SECTION.
CONSTANTS:
c_min_length TYPE i VALUE 200,
c_min_diameter TYPE i VALUE 20.
TYPES tt_log_keyed TYPE SORTED TABLE OF ty_log WITH UNIQUE KEY log_no.
METHODS add_logs
IMPORTING it_log TYPE tt_log
CHANGING ct_keyed TYPE tt_log_keyed.
METHODS is_ready
IMPORTING is_log TYPE ty_log
RETURNING VALUE(rv_ready) TYPE abap_bool.
ENDCLASS.
CLASS {{p}}log_merger IMPLEMENTATION.
METHOD combine.
DATA lt_keyed TYPE tt_log_keyed.
add_logs( EXPORTING it_log = it_first CHANGING ct_keyed = lt_keyed ).
add_logs( EXPORTING it_log = it_second CHANGING ct_keyed = lt_keyed ).
LOOP AT lt_keyed INTO DATA(ls_log).
IF is_ready( ls_log ) = abap_true.
INSERT ls_log INTO TABLE rt_result.
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD count_by_district.
DATA lt_stat TYPE SORTED TABLE OF ty_district_stat WITH UNIQUE KEY district.
LOOP AT it_log INTO DATA(ls_log).
ASSIGN lt_stat[ district = ls_log-district ] TO FIELD-SYMBOL(<ls_stat>).
IF sy-subrc <> 0.
INSERT VALUE #( district = ls_log-district
log_qty = 1
total_length_cm = ls_log-length_cm ) INTO TABLE lt_stat.
ELSE.
<ls_stat>-log_qty += 1.
<ls_stat>-total_length_cm += ls_log-length_cm.
ENDIF.
ENDLOOP.
rt_stat = lt_stat.
ENDMETHOD.
METHOD add_logs.
LOOP AT it_log INTO DATA(ls_log).
INSERT ls_log INTO TABLE ct_keyed.
ENDLOOP.
ENDMETHOD.
METHOD is_ready.
rv_ready = xsdbool( is_log-length_cm >= c_min_length
OR is_log-diameter_cm >= c_min_diameter ).
ENDMETHOD.
ENDCLASS.

View File

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

View File

@@ -0,0 +1,138 @@
CLASS {{p}}t20_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA mo_cut TYPE REF TO {{p}}log_merger.
DATA mt_empty TYPE {{p}}log_merger=>tt_log.
METHODS setup.
METHODS merges_two_lists FOR TESTING.
METHODS first_wins_on_duplicate FOR TESTING.
METHODS first_wins_within_list FOR TESTING.
METHODS sorts_by_log_no FOR TESTING.
METHODS drops_short_logs FOR TESTING.
METHODS drops_thin_logs FOR TESTING.
METHODS filter_after_dedup FOR TESTING.
METHODS empty_inputs FOR TESTING.
METHODS one_empty_list FOR TESTING.
METHODS counts_by_district FOR TESTING.
METHODS counts_empty_list FOR TESTING.
ENDCLASS.
CLASS {{p}}t20_hidden IMPLEMENTATION.
METHOD setup.
mo_cut = NEW {{p}}log_merger( ).
ENDMETHOD.
METHOD merges_two_lists.
DATA(lt_result) = mo_cut->combine(
it_first = VALUE #( ( log_no = 'LOG0000001' district = 'A001' length_cm = 500 diameter_cm = 30 ) )
it_second = VALUE #( ( log_no = 'LOG0000002' district = 'B001' length_cm = 600 diameter_cm = 40 ) ) ).
cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_result ) ).
cl_abap_unit_assert=>assert_equals( exp = 'LOG0000001' act = lt_result[ 1 ]-log_no ).
cl_abap_unit_assert=>assert_equals( exp = 'A001' act = lt_result[ 1 ]-district ).
cl_abap_unit_assert=>assert_equals( exp = 500 act = lt_result[ 1 ]-length_cm ).
cl_abap_unit_assert=>assert_equals( exp = 'LOG0000002' act = lt_result[ 2 ]-log_no ).
cl_abap_unit_assert=>assert_equals( exp = 'B001' act = lt_result[ 2 ]-district ).
ENDMETHOD.
METHOD first_wins_on_duplicate.
DATA(lt_result) = mo_cut->combine(
it_first = VALUE #( ( log_no = 'LOG0000001' district = 'A001' length_cm = 500 diameter_cm = 30 ) )
it_second = VALUE #( ( log_no = 'LOG0000001' district = 'B001' length_cm = 900 diameter_cm = 50 ) ) ).
cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_result ) ).
cl_abap_unit_assert=>assert_equals( exp = 'A001' act = lt_result[ 1 ]-district ).
cl_abap_unit_assert=>assert_equals( exp = 500 act = lt_result[ 1 ]-length_cm ).
cl_abap_unit_assert=>assert_equals( exp = 30 act = lt_result[ 1 ]-diameter_cm ).
ENDMETHOD.
METHOD first_wins_within_list.
DATA(lt_result) = mo_cut->combine(
it_first = VALUE #( ( log_no = 'LOG0000001' district = 'A001' length_cm = 500 diameter_cm = 30 )
( log_no = 'LOG0000001' district = 'A002' length_cm = 700 diameter_cm = 40 ) )
it_second = mt_empty ).
cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_result ) ).
cl_abap_unit_assert=>assert_equals( exp = 'A001' act = lt_result[ 1 ]-district ).
cl_abap_unit_assert=>assert_equals( exp = 500 act = lt_result[ 1 ]-length_cm ).
ENDMETHOD.
METHOD sorts_by_log_no.
DATA(lt_result) = mo_cut->combine(
it_first = VALUE #( ( log_no = 'LOG0000003' district = 'A001' length_cm = 500 diameter_cm = 30 )
( log_no = 'LOG0000001' district = 'A001' length_cm = 500 diameter_cm = 30 ) )
it_second = VALUE #( ( log_no = 'LOG0000002' district = 'B001' length_cm = 500 diameter_cm = 30 ) ) ).
cl_abap_unit_assert=>assert_equals( exp = 3 act = lines( lt_result ) ).
cl_abap_unit_assert=>assert_equals( exp = 'LOG0000001' act = lt_result[ 1 ]-log_no ).
cl_abap_unit_assert=>assert_equals( exp = 'LOG0000002' act = lt_result[ 2 ]-log_no ).
cl_abap_unit_assert=>assert_equals( exp = 'LOG0000003' act = lt_result[ 3 ]-log_no ).
ENDMETHOD.
METHOD drops_short_logs.
DATA(lt_result) = mo_cut->combine(
it_first = VALUE #( ( log_no = 'LOG0000001' district = 'A001' length_cm = 199 diameter_cm = 30 )
( log_no = 'LOG0000002' district = 'A001' length_cm = 200 diameter_cm = 30 ) )
it_second = mt_empty ).
cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_result ) ).
cl_abap_unit_assert=>assert_equals( exp = 'LOG0000002' act = lt_result[ 1 ]-log_no ).
ENDMETHOD.
METHOD drops_thin_logs.
DATA(lt_result) = mo_cut->combine(
it_first = VALUE #( ( log_no = 'LOG0000001' district = 'A001' length_cm = 500 diameter_cm = 19 )
( log_no = 'LOG0000002' district = 'A001' length_cm = 500 diameter_cm = 20 ) )
it_second = mt_empty ).
cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_result ) ).
cl_abap_unit_assert=>assert_equals( exp = 'LOG0000002' act = lt_result[ 1 ]-log_no ).
ENDMETHOD.
METHOD filter_after_dedup.
DATA(lt_result) = mo_cut->combine(
it_first = VALUE #( ( log_no = 'LOG0000001' district = 'A001' length_cm = 100 diameter_cm = 30 ) )
it_second = VALUE #( ( log_no = 'LOG0000001' district = 'B001' length_cm = 900 diameter_cm = 50 ) ) ).
cl_abap_unit_assert=>assert_equals( exp = 0 act = lines( lt_result ) ).
ENDMETHOD.
METHOD empty_inputs.
DATA(lt_result) = mo_cut->combine( it_first = mt_empty it_second = mt_empty ).
cl_abap_unit_assert=>assert_equals( exp = 0 act = lines( lt_result ) ).
ENDMETHOD.
METHOD one_empty_list.
DATA(lt_result) = mo_cut->combine(
it_first = mt_empty
it_second = VALUE #( ( log_no = 'LOG0000009' district = 'B001' length_cm = 800 diameter_cm = 45 ) ) ).
cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_result ) ).
cl_abap_unit_assert=>assert_equals( exp = 'LOG0000009' act = lt_result[ 1 ]-log_no ).
cl_abap_unit_assert=>assert_equals( exp = 'B001' act = lt_result[ 1 ]-district ).
cl_abap_unit_assert=>assert_equals( exp = 800 act = lt_result[ 1 ]-length_cm ).
ENDMETHOD.
METHOD counts_by_district.
DATA(lt_stat) = mo_cut->count_by_district(
it_log = VALUE #( ( log_no = 'LOG0000001' district = 'A001' length_cm = 500 diameter_cm = 30 )
( log_no = 'LOG0000002' district = 'B001' length_cm = 300 diameter_cm = 25 )
( log_no = 'LOG0000003' district = 'A001' length_cm = 200 diameter_cm = 20 ) ) ).
cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_stat ) ).
cl_abap_unit_assert=>assert_equals( exp = 'A001' act = lt_stat[ 1 ]-district ).
cl_abap_unit_assert=>assert_equals( exp = 2 act = lt_stat[ 1 ]-log_qty ).
cl_abap_unit_assert=>assert_equals( exp = 700 act = lt_stat[ 1 ]-total_length_cm ).
cl_abap_unit_assert=>assert_equals( exp = 'B001' act = lt_stat[ 2 ]-district ).
cl_abap_unit_assert=>assert_equals( exp = 1 act = lt_stat[ 2 ]-log_qty ).
cl_abap_unit_assert=>assert_equals( exp = 300 act = lt_stat[ 2 ]-total_length_cm ).
ENDMETHOD.
METHOD counts_empty_list.
DATA(lt_stat) = mo_cut->count_by_district( it_log = mt_empty ).
cl_abap_unit_assert=>assert_equals( exp = 0 act = lines( lt_stat ) ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,77 @@
{
"task": "G1013",
"mutants": [
{
"object": "{{P}}LOG_MERGER",
"mutant": "line 52: = -> <> (eq)",
"status": "killed",
"hidden": "3/11",
"failed_tests": [
"DROPS_SHORT_LOGS",
"DROPS_THIN_LOGS",
"FILTER_AFTER_DEDUP",
"FIRST_WINS_ON_DUPLICATE",
"FIRST_WINS_WITHIN_LIST",
"MERGES_TWO_LISTS",
"ONE_EMPTY_LIST",
"SORTS_BY_LOG_NO"
]
},
{
"object": "{{P}}LOG_MERGER",
"mutant": "line 52: abap_true -> abap_false (bool)",
"status": "killed",
"hidden": "3/11",
"failed_tests": [
"DROPS_SHORT_LOGS",
"DROPS_THIN_LOGS",
"FILTER_AFTER_DEDUP",
"FIRST_WINS_ON_DUPLICATE",
"FIRST_WINS_WITHIN_LIST",
"MERGES_TWO_LISTS",
"ONE_EMPTY_LIST",
"SORTS_BY_LOG_NO"
]
},
{
"object": "{{P}}LOG_MERGER",
"mutant": "line 64: 1 -> 2 (const)",
"status": "killed",
"hidden": "10/11",
"failed_tests": [
"COUNTS_BY_DISTRICT"
]
},
{
"object": "{{P}}LOG_MERGER",
"mutant": "line 81: >= -> < (rel)",
"status": "killed",
"hidden": "3/11",
"failed_tests": [
"DROPS_SHORT_LOGS",
"DROPS_THIN_LOGS",
"FILTER_AFTER_DEDUP",
"FIRST_WINS_ON_DUPLICATE",
"FIRST_WINS_WITHIN_LIST",
"MERGES_TWO_LISTS",
"ONE_EMPTY_LIST",
"SORTS_BY_LOG_NO"
]
},
{
"object": "{{P}}LOG_MERGER",
"mutant": "line 82: AND -> OR (logic)",
"status": "killed",
"hidden": "8/11",
"failed_tests": [
"DROPS_SHORT_LOGS",
"DROPS_THIN_LOGS",
"FILTER_AFTER_DEDUP"
]
}
],
"valid": 5,
"killed": 5,
"kill_rate": 1.0,
"ok": true
}

View File

@@ -0,0 +1,84 @@
CLASS {{p}}log_merger DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES:
ty_log_no TYPE c LENGTH 10,
ty_district TYPE c LENGTH 4,
BEGIN OF ty_log,
log_no TYPE ty_log_no,
district TYPE ty_district,
length_cm TYPE i,
diameter_cm TYPE i,
END OF ty_log,
tt_log TYPE STANDARD TABLE OF ty_log WITH EMPTY KEY,
BEGIN OF ty_district_stat,
district TYPE ty_district,
log_qty TYPE i,
total_length_cm TYPE i,
END OF ty_district_stat,
tt_district_stat TYPE STANDARD TABLE OF ty_district_stat WITH EMPTY KEY.
METHODS combine
IMPORTING it_first TYPE tt_log
it_second TYPE tt_log
RETURNING VALUE(rt_result) TYPE tt_log.
METHODS count_by_district
IMPORTING it_log TYPE tt_log
RETURNING VALUE(rt_stat) TYPE tt_district_stat.
PRIVATE SECTION.
CONSTANTS:
c_min_length TYPE i VALUE 200,
c_min_diameter TYPE i VALUE 20.
TYPES tt_log_keyed TYPE SORTED TABLE OF ty_log WITH UNIQUE KEY log_no.
METHODS add_logs
IMPORTING it_log TYPE tt_log
CHANGING ct_keyed TYPE tt_log_keyed.
METHODS is_ready
IMPORTING is_log TYPE ty_log
RETURNING VALUE(rv_ready) TYPE abap_bool.
ENDCLASS.
CLASS {{p}}log_merger IMPLEMENTATION.
METHOD combine.
DATA lt_keyed TYPE tt_log_keyed.
add_logs( EXPORTING it_log = it_first CHANGING ct_keyed = lt_keyed ).
add_logs( EXPORTING it_log = it_second CHANGING ct_keyed = lt_keyed ).
LOOP AT lt_keyed INTO DATA(ls_log).
IF is_ready( ls_log ) = abap_true.
INSERT ls_log INTO TABLE rt_result.
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD count_by_district.
DATA lt_stat TYPE SORTED TABLE OF ty_district_stat WITH UNIQUE KEY district.
LOOP AT it_log INTO DATA(ls_log).
ASSIGN lt_stat[ district = ls_log-district ] TO FIELD-SYMBOL(<ls_stat>).
IF sy-subrc <> 0.
INSERT VALUE #( district = ls_log-district
log_qty = 1
total_length_cm = ls_log-length_cm ) INTO TABLE lt_stat.
ELSE.
<ls_stat>-log_qty += 1.
<ls_stat>-total_length_cm += ls_log-length_cm.
ENDIF.
ENDLOOP.
rt_stat = lt_stat.
ENDMETHOD.
METHOD add_logs.
LOOP AT it_log INTO DATA(ls_log).
INSERT ls_log INTO TABLE ct_keyed.
ENDLOOP.
ENDMETHOD.
METHOD is_ready.
rv_ready = xsdbool( is_log-length_cm >= c_min_length
AND is_log-diameter_cm >= c_min_diameter ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,71 @@
CLASS ltc_log_merger DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA mo_cut TYPE REF TO {{p}}log_merger.
DATA mt_empty TYPE {{p}}log_merger=>tt_log.
METHODS setup.
METHODS merges_distinct_logs FOR TESTING.
METHODS keeps_first_duplicate FOR TESTING.
METHODS removes_small_logs FOR TESTING.
METHODS sorts_result FOR TESTING.
METHODS empty_input_is_empty FOR TESTING.
METHODS counts_per_district FOR TESTING.
ENDCLASS.
CLASS ltc_log_merger IMPLEMENTATION.
METHOD setup.
mo_cut = NEW {{p}}log_merger( ).
ENDMETHOD.
METHOD merges_distinct_logs.
DATA(lt_result) = mo_cut->combine(
it_first = VALUE #( ( log_no = 'LOG0000001' district = 'A001' length_cm = 500 diameter_cm = 30 ) )
it_second = VALUE #( ( log_no = 'LOG0000002' district = 'B001' length_cm = 600 diameter_cm = 40 ) ) ).
cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_result ) ).
cl_abap_unit_assert=>assert_equals( exp = 'LOG0000001' act = lt_result[ 1 ]-log_no ).
cl_abap_unit_assert=>assert_equals( exp = 'LOG0000002' act = lt_result[ 2 ]-log_no ).
ENDMETHOD.
METHOD keeps_first_duplicate.
DATA(lt_result) = mo_cut->combine(
it_first = VALUE #( ( log_no = 'LOG0000001' district = 'A001' length_cm = 500 diameter_cm = 30 ) )
it_second = VALUE #( ( log_no = 'LOG0000001' district = 'B001' length_cm = 900 diameter_cm = 50 ) ) ).
cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_result ) ).
cl_abap_unit_assert=>assert_equals( exp = 'A001' act = lt_result[ 1 ]-district ).
ENDMETHOD.
METHOD removes_small_logs.
DATA(lt_result) = mo_cut->combine(
it_first = VALUE #( ( log_no = 'LOG0000001' district = 'A001' length_cm = 150 diameter_cm = 30 ) )
it_second = VALUE #( ( log_no = 'LOG0000002' district = 'A001' length_cm = 500 diameter_cm = 15 ) ) ).
cl_abap_unit_assert=>assert_equals( exp = 0 act = lines( lt_result ) ).
ENDMETHOD.
METHOD sorts_result.
DATA(lt_result) = mo_cut->combine(
it_first = VALUE #( ( log_no = 'LOG0000002' district = 'A001' length_cm = 500 diameter_cm = 30 ) )
it_second = VALUE #( ( log_no = 'LOG0000001' district = 'B001' length_cm = 500 diameter_cm = 30 ) ) ).
cl_abap_unit_assert=>assert_equals( exp = 'LOG0000001' act = lt_result[ 1 ]-log_no ).
cl_abap_unit_assert=>assert_equals( exp = 'LOG0000002' act = lt_result[ 2 ]-log_no ).
ENDMETHOD.
METHOD empty_input_is_empty.
DATA(lt_result) = mo_cut->combine( it_first = mt_empty it_second = mt_empty ).
cl_abap_unit_assert=>assert_equals( exp = 0 act = lines( lt_result ) ).
ENDMETHOD.
METHOD counts_per_district.
DATA(lt_stat) = mo_cut->count_by_district(
it_log = VALUE #( ( log_no = 'LOG0000001' district = 'A001' length_cm = 500 diameter_cm = 30 )
( log_no = 'LOG0000002' district = 'A001' length_cm = 300 diameter_cm = 25 ) ) ).
cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_stat ) ).
cl_abap_unit_assert=>assert_equals( exp = 2 act = lt_stat[ 1 ]-log_qty ).
cl_abap_unit_assert=>assert_equals( exp = 800 act = lt_stat[ 1 ]-total_length_cm ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,63 @@
# 1. Goal
A sawmill plans the cutting of logs. The sawmill receives the log lists of two
forest districts. A planning program calls one service that combines the two
lists into one list of logs that are ready for cutting. The program also needs
the number of logs and the total length for each district.
# 2. Open questions
None.
# 3. Context
- The class {{P}}LOG_MERGER does not exist. Create it in package $TMP.
- A log has a log number, a district, a length in centimetres and a diameter in
centimetres.
- A log number identifies a log. The same log number can occur more than once in
one list and in both lists.
- The caller gives the log lists. The class does not read a database table.
# 4. Contract
- Create the class {{P}}LOG_MERGER in package $TMP.
- The class is public and final. It has a public constructor without parameters.
- Public types of the class:
- TY_LOG_NO: character, length 10.
- TY_DISTRICT: character, length 4.
- TY_LOG: structure with the components LOG_NO (TY_LOG_NO), DISTRICT
(TY_DISTRICT), LENGTH_CM (integer) and DIAMETER_CM (integer).
- TT_LOG: standard table of TY_LOG with an empty key.
- TY_DISTRICT_STAT: structure with the components DISTRICT (TY_DISTRICT),
LOG_QTY (integer) and TOTAL_LENGTH_CM (integer).
- TT_DISTRICT_STAT: standard table of TY_DISTRICT_STAT with an empty key.
- Public methods:
- COMBINE, importing IT_FIRST (TT_LOG) and IT_SECOND (TT_LOG), returning
RT_RESULT (TT_LOG).
- COUNT_BY_DISTRICT, importing IT_LOG (TT_LOG), returning RT_STAT
(TT_DISTRICT_STAT).
- Do not add other public methods.
# 5. Business rules
COMBINE:
1. Build a merged list. Read IT_FIRST first and IT_SECOND second. Add a log to
the merged list only if its log number is not yet in the merged list. Ignore
every later log with the same log number.
2. Remove every log from the merged list with LENGTH_CM below 200 or with
DIAMETER_CM below 20.
3. Sort the result by LOG_NO in ascending order.
4. The result has no two logs with the same log number.
COUNT_BY_DISTRICT:
1. The result has one row for each district that occurs in IT_LOG.
2. LOG_QTY is the number of logs of the district.
3. TOTAL_LENGTH_CM is the sum of LENGTH_CM of the logs of the district.
4. Sort the result by DISTRICT in ascending order.
5. An empty input gives an empty result.
# 6. Constraints
- Release target: ABAP Platform 2025 (SAP_BASIS 816).
- Coding standards: Clean ABAP. Methods below 40 statements. No global
variables. No comment that restates the code.
- Out of scope: do not create other objects.
# 7. Acceptance
- The class is active and has no syntax error.
- The hidden tests pass.
- Write your own ABAP Unit tests for the class.

View File

@@ -0,0 +1,42 @@
{
"id": "G1013",
"category": "C",
"object_type": "CLAS",
"difficulty": 2,
"release_target": "v816",
"expected_outcome": "implement",
"budget": {
"max_tool_calls": 80,
"max_activations": 20
},
"seed": [],
"contract": [
{
"type": "CLAS",
"name": "{{P}}LOG_MERGER"
}
],
"out_of_scope": [],
"hidden_tests": [
{
"type": "CLAS",
"name": "{{P}}T20_HIDDEN",
"file": "hidden/t20_hidden.clas.abap",
"description": "Hidden tests for {{P}}LOG_MERGER"
}
],
"reference": [
{
"type": "CLAS",
"name": "{{P}}LOG_MERGER",
"file": "reference/log_merger.clas.abap",
"description": "Log merger that combines two log lists with keyed internal tables",
"testclasses_file": "reference/log_merger.testclasses.abap"
}
],
"craft_checks": [
"method_length",
"nested_loops",
"keyed_table_access"
]
}