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

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

View File

@@ -0,0 +1,16 @@
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Product sales'
define view entity {{P}}I_PROD_SALES
as select from {{p}}prod as prod
inner join {{p}}sale as sale on sale.prod_id <> prod.prod_id
{
key prod.prod_id as prod_id,
prod.prod_name as prod_name,
count( * ) as item_count,
sum( sale.quantity ) as total_qty
}
group by
prod.prod_id,
prod.prod_name
having
sum( sale.quantity ) >= 100

View File

@@ -0,0 +1,16 @@
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Product sales'
define view entity {{P}}I_PROD_SALES
as select from {{p}}prod as prod
inner join {{p}}sale as sale on sale.prod_id = prod.prod_id
{
key prod.prod_id as prod_id,
prod.prod_name as prod_name,
count( * ) as item_count,
max( sale.quantity ) as total_qty
}
group by
prod.prod_id,
prod.prod_name
having
sum( sale.quantity ) >= 100

View File

@@ -0,0 +1,16 @@
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Product sales'
define view entity {{P}}I_PROD_SALES
as select from {{p}}prod as prod
inner join {{p}}sale as sale on sale.prod_id = prod.prod_id
{
key prod.prod_id as prod_id,
prod.prod_name as prod_name,
count( * ) as item_count,
sum( sale.quantity ) as total_qty
}
group by
prod.prod_id,
prod.prod_name
having
sum( sale.quantity ) < 100

View File

@@ -0,0 +1,16 @@
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Product sales'
define view entity {{P}}I_PROD_SALES
as select from {{p}}prod as prod
inner join {{p}}sale as sale on sale.prod_id = prod.prod_id
{
key prod.prod_id as prod_id,
prod.prod_name as prod_name,
count( * ) as item_count,
sum( sale.quantity ) as total_qty
}
group by
prod.prod_id,
prod.prod_name
having
sum( sale.quantity ) >= 101

View File

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

View File

@@ -0,0 +1,74 @@
CLASS {{p}}t16_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
CLASS-DATA go_env TYPE REF TO if_cds_test_environment.
CLASS-METHODS class_setup.
CLASS-METHODS class_teardown.
METHODS setup.
METHODS boundary_included FOR TESTING.
METHODS below_threshold_excluded FOR TESTING.
METHODS product_without_items FOR TESTING.
METHODS totals FOR TESTING.
METHODS product_name FOR TESTING.
METHODS row_count FOR TESTING.
ENDCLASS.
CLASS {{p}}t16_hidden IMPLEMENTATION.
METHOD class_setup.
go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_PROD_SALES' ).
ENDMETHOD.
METHOD class_teardown.
go_env->destroy( ).
ENDMETHOD.
METHOD setup.
DATA lt_prod TYPE STANDARD TABLE OF {{p}}prod WITH EMPTY KEY.
DATA lt_sale TYPE STANDARD TABLE OF {{p}}sale WITH EMPTY KEY.
go_env->clear_doubles( ).
lt_prod = VALUE #( ( prod_id = 'P1' prod_name = 'Widget' )
( prod_id = 'P2' prod_name = 'Gadget' )
( prod_id = 'P3' prod_name = 'Gizmo' )
( prod_id = 'P4' prod_name = 'Spare' ) ).
lt_sale = VALUE #( ( sale_id = 'S1' item_no = 1 prod_id = 'P1' quantity = 60 )
( sale_id = 'S1' item_no = 2 prod_id = 'P1' quantity = 50 )
( sale_id = 'S2' item_no = 1 prod_id = 'P2' quantity = 40 )
( sale_id = 'S2' item_no = 2 prod_id = 'P2' quantity = 30 )
( sale_id = 'S3' item_no = 1 prod_id = 'P3' quantity = 100 ) ).
go_env->insert_test_data( lt_prod ).
go_env->insert_test_data( lt_sale ).
ENDMETHOD.
METHOD boundary_included.
SELECT SINGLE total_qty FROM {{p}}i_prod_sales WHERE prod_id = 'P3' INTO @DATA(lv_total).
cl_abap_unit_assert=>assert_equals( exp = 100 act = lv_total ).
ENDMETHOD.
METHOD below_threshold_excluded.
SELECT COUNT(*) FROM {{p}}i_prod_sales WHERE prod_id = 'P2' INTO @DATA(lv_rows).
cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_rows ).
ENDMETHOD.
METHOD product_without_items.
SELECT COUNT(*) FROM {{p}}i_prod_sales WHERE prod_id = 'P4' INTO @DATA(lv_rows).
cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_rows ).
ENDMETHOD.
METHOD totals.
SELECT SINGLE item_count, total_qty FROM {{p}}i_prod_sales WHERE prod_id = 'P1'
INTO @DATA(ls_row).
cl_abap_unit_assert=>assert_equals( exp = 2 act = ls_row-item_count ).
cl_abap_unit_assert=>assert_equals( exp = 110 act = ls_row-total_qty ).
ENDMETHOD.
METHOD product_name.
SELECT SINGLE prod_name FROM {{p}}i_prod_sales WHERE prod_id = 'P1' INTO @DATA(lv_name).
cl_abap_unit_assert=>assert_equals( exp = 'Widget' act = lv_name ).
ENDMETHOD.
METHOD row_count.
SELECT COUNT(*) FROM {{p}}i_prod_sales INTO @DATA(lv_rows).
cl_abap_unit_assert=>assert_equals( exp = 2 act = lv_rows ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,61 @@
{
"task": "G0110",
"mutants": [
{
"object": "{{P}}I_PROD_SALES",
"mutant": "line 5: inner join -> left outer join (join)",
"status": "survived",
"hidden": "6/6",
"failed_tests": []
},
{
"object": "{{P}}I_PROD_SALES",
"mutant": "line 5: = -> <> (eq)",
"status": "killed",
"hidden": "1/6",
"failed_tests": [
"BELOW_THRESHOLD_EXCLUDED",
"BOUNDARY_INCLUDED",
"PRODUCT_WITHOUT_ITEMS",
"ROW_COUNT",
"TOTALS"
]
},
{
"object": "{{P}}I_PROD_SALES",
"mutant": "line 10: sum( -> max( (agg)",
"status": "killed",
"hidden": "5/6",
"failed_tests": [
"TOTALS"
]
},
{
"object": "{{P}}I_PROD_SALES",
"mutant": "line 16: >= -> < (rel)",
"status": "killed",
"hidden": "1/6",
"failed_tests": [
"BELOW_THRESHOLD_EXCLUDED",
"BOUNDARY_INCLUDED",
"PRODUCT_NAME",
"ROW_COUNT",
"TOTALS"
]
},
{
"object": "{{P}}I_PROD_SALES",
"mutant": "line 16: 100 -> 101 (const)",
"status": "killed",
"hidden": "4/6",
"failed_tests": [
"BOUNDARY_INCLUDED",
"ROW_COUNT"
]
}
],
"valid": 5,
"killed": 4,
"kill_rate": 0.8,
"ok": true
}

View File

@@ -0,0 +1,16 @@
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Product sales'
define view entity {{P}}I_PROD_SALES
as select from {{p}}prod as prod
inner join {{p}}sale as sale on sale.prod_id = prod.prod_id
{
key prod.prod_id as prod_id,
prod.prod_name as prod_name,
count( * ) as item_count,
sum( sale.quantity ) as total_qty
}
group by
prod.prod_id,
prod.prod_name
having
sum( sale.quantity ) >= 100

View File

@@ -0,0 +1,38 @@
CLASS {{p}}t16_test DEFINITION PUBLIC FINAL CREATE PUBLIC
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
CLASS-DATA go_env TYPE REF TO if_cds_test_environment.
CLASS-METHODS class_setup.
CLASS-METHODS class_teardown.
METHODS setup.
METHODS totals_of_one_product FOR TESTING.
ENDCLASS.
CLASS {{p}}t16_test IMPLEMENTATION.
METHOD class_setup.
go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_PROD_SALES' ).
ENDMETHOD.
METHOD class_teardown.
go_env->destroy( ).
ENDMETHOD.
METHOD setup.
go_env->clear_doubles( ).
ENDMETHOD.
METHOD totals_of_one_product.
DATA lt_prod TYPE STANDARD TABLE OF {{p}}prod WITH EMPTY KEY.
DATA lt_sale TYPE STANDARD TABLE OF {{p}}sale WITH EMPTY KEY.
lt_prod = VALUE #( ( prod_id = 'A' prod_name = 'Alpha' ) ).
lt_sale = VALUE #( ( sale_id = 'S1' item_no = 1 prod_id = 'A' quantity = 60 )
( sale_id = 'S1' item_no = 2 prod_id = 'A' quantity = 50 ) ).
go_env->insert_test_data( lt_prod ).
go_env->insert_test_data( lt_sale ).
SELECT SINGLE item_count, total_qty FROM {{p}}i_prod_sales WHERE prod_id = 'A'
INTO @DATA(ls_row).
cl_abap_unit_assert=>assert_equals( exp = 2 act = ls_row-item_count ).
cl_abap_unit_assert=>assert_equals( exp = 110 act = ls_row-total_qty ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,10 @@
@EndUserText.label : 'Product master'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table {{p}}prod {
key client : abap.clnt not null;
key prod_id : abap.char(10) not null;
prod_name : abap.char(40);
}

View File

@@ -0,0 +1,12 @@
@EndUserText.label : 'Sales item'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table {{p}}sale {
key client : abap.clnt not null;
key sale_id : abap.char(10) not null;
key item_no : abap.int4 not null;
prod_id : abap.char(10);
quantity : abap.int4;
}

View File

@@ -0,0 +1,37 @@
# 1. Goal
A sales analyst wants to know which products sell well. Show each product with
the number of sales items and the total sales quantity. Show only products whose
total sales quantity is at least 100. A report and an OData service will read the
result, so the calculation must be in the database, in a CDS view.
# 2. Open questions
None.
# 3. Context
- Table {{P}}PROD (product master), package $TMP. Key: PROD_ID (CHAR 10).
Fields: PROD_NAME (CHAR 40).
- Table {{P}}SALE (sales item), package $TMP. Key: SALE_ID (CHAR 10), ITEM_NO (INT4).
Fields: PROD_ID (CHAR 10), QUANTITY (INT4).
# 4. Contract
- Create the CDS view entity {{P}}I_PROD_SALES in package $TMP.
- Elements, with these names: PROD_ID (key), PROD_NAME, ITEM_COUNT, TOTAL_QTY.
- No authorization check (#NOT_REQUIRED).
# 5. Business rules
1. Show one row for each product that has at least one sales item and whose total
sales quantity is at least 100. Do not show a product with no sales item.
Do not show a product whose total sales quantity is less than 100.
2. ITEM_COUNT is the number of sales items of the product.
3. TOTAL_QTY is the sum of QUANTITY of all sales items of the product.
4. PROD_NAME is the name of the product.
# 6. Constraints
- Release target: 7.58.
- Out of scope: do not change {{P}}PROD and {{P}}SALE.
- Coding standards: Clean ABAP.
# 7. Acceptance
- The view is active and has no syntax error.
- The hidden tests pass.
- Write ABAP Unit tests with CL_CDS_TEST_ENVIRONMENT in a global test class.

View File

@@ -0,0 +1,65 @@
{
"id": "G0110",
"category": "B",
"object_type": "DDLS",
"difficulty": 2,
"release_target": "v758",
"expected_outcome": "implement",
"budget": {
"max_tool_calls": 40,
"max_activations": 10
},
"seed": [
{
"type": "TABL",
"name": "{{P}}PROD",
"file": "seed/prod.tabl.asabap",
"description": "Product master"
},
{
"type": "TABL",
"name": "{{P}}SALE",
"file": "seed/sale.tabl.asabap",
"description": "Sales item"
}
],
"contract": [
{
"type": "DDLS",
"name": "{{P}}I_PROD_SALES",
"fields": [
"PROD_ID",
"PROD_NAME",
"ITEM_COUNT",
"TOTAL_QTY"
]
}
],
"out_of_scope": [
"{{P}}PROD",
"{{P}}SALE"
],
"hidden_tests": [
{
"type": "CLAS",
"name": "{{P}}T16_HIDDEN",
"file": "hidden/t16_hidden.clas.abap",
"description": "T16 hidden tests"
}
],
"reference": [
{
"type": "DDLS",
"name": "{{P}}I_PROD_SALES",
"file": "reference/i_prod_sales.ddls.asddls",
"description": "Product sales"
},
{
"type": "CLAS",
"name": "{{P}}T16_TEST",
"file": "reference/t16_test.clas.abap",
"description": "T16 own tests"
}
],
"craft_checks": []
}