From 6984fc79172555afbabc588e10069db9c6cac03e Mon Sep 17 00:00:00 2001 From: Kral Date: Mon, 5 Oct 2026 22:08:59 +0200 Subject: [PATCH] Snapshot: new training tasks (balanced generation), docs Co-Authored-By: Claude Sonnet 5.5 --- .../train/G1910/faulty/m0_cider.tabl.asabap | 19 ++ .../train/G1910/faulty/m1_cider.tabl.asabap | 19 ++ .../train/G1910/faulty/m2_cider.tabl.asabap | 19 ++ .../train/G1910/faulty/m3_cider.tabl.asabap | 19 ++ .../train/G1910/faulty/m4_cider.tabl.asabap | 19 ++ tasks_gen/train/G1910/generation.json | 19 ++ .../train/G1910/hidden/cider_hidden.clas.abap | 157 +++++++++++ tasks_gen/train/G1910/mutation.json | 56 ++++ .../train/G1910/reference/cider.tabl.asabap | 19 ++ .../G1910/reference/cider_test.clas.abap | 58 ++++ tasks_gen/train/G1910/spec.md | 51 ++++ tasks_gen/train/G1910/task.json | 56 ++++ .../train/G1911/faulty/m0_hire.tabl.asabap | 19 ++ .../train/G1911/faulty/m1_hire.tabl.asabap | 19 ++ .../train/G1911/faulty/m2_hire.tabl.asabap | 19 ++ .../train/G1911/faulty/m3_hire.tabl.asabap | 19 ++ .../train/G1911/faulty/m4_hire.tabl.asabap | 19 ++ tasks_gen/train/G1911/generation.json | 24 ++ .../train/G1911/hidden/hire_hidden.clas.abap | 231 ++++++++++++++++ tasks_gen/train/G1911/mutation.json | 58 ++++ .../train/G1911/reference/hire.tabl.asabap | 19 ++ .../train/G1911/reference/hire_test.clas.abap | 76 ++++++ tasks_gen/train/G1911/spec.md | 78 ++++++ tasks_gen/train/G1911/task.json | 56 ++++ .../train/G1912/faulty/m0_svcjob.tabl.asabap | 16 ++ .../train/G1912/faulty/m1_svcjob.tabl.asabap | 16 ++ .../train/G1912/faulty/m2_svcjob.tabl.asabap | 16 ++ .../train/G1912/faulty/m3_svcjob.tabl.asabap | 16 ++ .../train/G1912/faulty/m4_svcjob.tabl.asabap | 16 ++ tasks_gen/train/G1912/generation.json | 29 ++ .../G1912/hidden/svcjob_hidden.clas.abap | 175 ++++++++++++ tasks_gen/train/G1912/mutation.json | 54 ++++ .../train/G1912/reference/svcjob.tabl.asabap | 16 ++ .../G1912/reference/svcjob_test.clas.abap | 139 ++++++++++ tasks_gen/train/G1912/spec.md | 47 ++++ tasks_gen/train/G1912/task.json | 54 ++++ .../G1913/faulty/m0_if_laundry_fee.intf.abap | 84 ++++++ .../G1913/faulty/m1_if_laundry_fee.intf.abap | 84 ++++++ .../G1913/faulty/m2_if_laundry_fee.intf.abap | 84 ++++++ .../G1913/faulty/m3_if_laundry_fee.intf.abap | 84 ++++++ .../G1913/faulty/m4_if_laundry_fee.intf.abap | 84 ++++++ tasks_gen/train/G1913/generation.json | 38 +++ .../G1913/hidden/laundry_hidden.clas.abap | 197 ++++++++++++++ tasks_gen/train/G1913/mutation.json | 54 ++++ .../G1913/reference/if_laundry_fee.intf.abap | 84 ++++++ .../reference/laundry_fee_test.clas.abap | 114 ++++++++ tasks_gen/train/G1913/spec.md | 119 +++++++++ tasks_gen/train/G1913/task.json | 49 ++++ tasks_gen/train/G1914/generation.json | 33 +++ .../train/G1914/hidden/t58_hidden.clas.abap | 133 ++++++++++ .../G1914/reference/if_rope_check.intf.abap | 28 ++ .../G1914/reference/rope_check_test.clas.abap | 85 ++++++ .../G1914/reference/rope_checker.clas.abap | 67 +++++ .../reference/rope_checker.testclasses.abap | 76 ++++++ tasks_gen/train/G1914/spec.md | 63 +++++ tasks_gen/train/G1914/task.json | 61 +++++ .../train/G1915/faulty/m0_grh.tabl.asabap | 16 ++ .../train/G1915/faulty/m1_grh.tabl.asabap | 16 ++ .../train/G1915/faulty/m2_grh.tabl.asabap | 16 ++ .../train/G1915/faulty/m3_grh.tabl.asabap | 16 ++ .../train/G1915/faulty/m4_grh.tabl.asabap | 16 ++ tasks_gen/train/G1915/generation.json | 24 ++ .../train/G1915/hidden/grh_hidden.clas.abap | 146 ++++++++++ tasks_gen/train/G1915/mutation.json | 55 ++++ .../train/G1915/reference/grh.tabl.asabap | 16 ++ .../train/G1915/reference/grh_test.clas.abap | 64 +++++ tasks_gen/train/G1915/spec.md | 63 +++++ tasks_gen/train/G1915/task.json | 54 ++++ tasks_gen/train/G1916/generation.json | 33 +++ .../G1916/hidden/solar_check_hidden.clas.abap | 179 +++++++++++++ .../G1916/reference/if_solar_check.intf.abap | 41 +++ .../reference/solar_check_test.clas.abap | 114 ++++++++ tasks_gen/train/G1916/spec.md | 87 ++++++ tasks_gen/train/G1916/task.json | 46 ++++ .../faulty/m0_if_bouquet_check.intf.abap | 41 +++ .../faulty/m1_if_bouquet_check.intf.abap | 41 +++ .../faulty/m2_if_bouquet_check.intf.abap | 41 +++ .../faulty/m3_if_bouquet_check.intf.abap | 41 +++ .../faulty/m4_if_bouquet_check.intf.abap | 41 +++ tasks_gen/train/G1917/generation.json | 38 +++ .../hidden/bouquet_check_hidden.clas.abap | 126 +++++++++ tasks_gen/train/G1917/mutation.json | 55 ++++ .../reference/bouquet_check_test.clas.abap | 108 ++++++++ .../reference/if_bouquet_check.intf.abap | 41 +++ tasks_gen/train/G1917/spec.md | 66 +++++ tasks_gen/train/G1917/task.json | 52 ++++ .../G1918/faulty/m0_bouquet_pricing.intf.abap | 61 +++++ .../G1918/faulty/m1_bouquet_pricing.intf.abap | 61 +++++ .../G1918/faulty/m2_bouquet_pricing.intf.abap | 61 +++++ .../G1918/faulty/m3_bouquet_pricing.intf.abap | 61 +++++ tasks_gen/train/G1918/generation.json | 39 +++ .../train/G1918/hidden/t02_hidden.clas.abap | 173 ++++++++++++ tasks_gen/train/G1918/mutation.json | 52 ++++ .../G1918/reference/bouquet_if_test.clas.abap | 142 ++++++++++ .../G1918/reference/bouquet_pricing.intf.abap | 61 +++++ tasks_gen/train/G1918/spec.md | 93 +++++++ tasks_gen/train/G1918/task.json | 46 ++++ .../train/G1919/faulty/m0_rescue.tabl.asabap | 17 ++ .../train/G1919/faulty/m1_rescue.tabl.asabap | 17 ++ .../train/G1919/faulty/m2_rescue.tabl.asabap | 17 ++ .../train/G1919/faulty/m3_rescue.tabl.asabap | 17 ++ .../train/G1919/faulty/m4_rescue.tabl.asabap | 17 ++ tasks_gen/train/G1919/generation.json | 19 ++ .../train/G1919/hidden/t20_hidden.clas.abap | 203 ++++++++++++++ tasks_gen/train/G1919/mutation.json | 57 ++++ .../train/G1919/reference/rescue.tabl.asabap | 17 ++ .../train/G1919/reference/t20_test.clas.abap | 73 +++++ tasks_gen/train/G1919/spec.md | 53 ++++ tasks_gen/train/G1919/task.json | 56 ++++ .../train/G1920/faulty/m0_jump.tabl.asabap | 15 ++ .../train/G1920/faulty/m1_jump.tabl.asabap | 15 ++ .../train/G1920/faulty/m2_jump.tabl.asabap | 15 ++ .../train/G1920/faulty/m3_jump.tabl.asabap | 15 ++ .../train/G1920/faulty/m4_jump.tabl.asabap | 15 ++ tasks_gen/train/G1920/generation.json | 19 ++ .../train/G1920/hidden/jump_hidden.clas.abap | 149 +++++++++++ tasks_gen/train/G1920/mutation.json | 57 ++++ .../train/G1920/reference/jump.tabl.asabap | 15 ++ .../train/G1920/reference/jump_test.clas.abap | 63 +++++ tasks_gen/train/G1920/spec.md | 57 ++++ tasks_gen/train/G1920/task.json | 53 ++++ .../G1921/faulty/m0_if_kiln_quote.intf.abap | 55 ++++ .../G1921/faulty/m2_if_kiln_quote.intf.abap | 55 ++++ .../G1921/faulty/m4_if_kiln_quote.intf.abap | 55 ++++ tasks_gen/train/G1921/generation.json | 34 +++ .../train/G1921/hidden/t02_hidden.clas.abap | 148 +++++++++++ tasks_gen/train/G1921/mutation.json | 50 ++++ .../G1921/reference/if_kiln_quote.intf.abap | 55 ++++ .../reference/if_kiln_quote_test.clas.abap | 98 +++++++ .../if_kiln_quote_test.testclasses.abap | 53 ++++ tasks_gen/train/G1921/spec.md | 78 ++++++ tasks_gen/train/G1921/task.json | 47 ++++ tasks_gen/train/G1922/generation.json | 35 +++ .../G1922/hidden/lift_usage_hidden.clas.abap | 94 +++++++ tasks_gen/train/G1922/mutation.json | 46 ++++ .../G1922/reference/i_lift_usage.ddls.asddls | 16 ++ .../G1922/reference/lift_usage_test.clas.abap | 50 ++++ .../train/G1922/seed/i_lift_usage.ddls.asddls | 16 ++ tasks_gen/train/G1922/seed/lift.tabl.asabap | 11 + .../train/G1922/seed/lift_op.tabl.asabap | 14 + tasks_gen/train/G1922/spec.md | 44 +++ tasks_gen/train/G1922/task.json | 74 ++++++ .../G1923/faulty/m1_i_forge_job.ddls.asddls | 20 ++ .../G1923/faulty/m2_i_forge_job.ddls.asddls | 20 ++ .../G1923/faulty/m3_i_forge_job.ddls.asddls | 20 ++ .../G1923/faulty/m4_i_forge_job.ddls.asddls | 20 ++ tasks_gen/train/G1923/generation.json | 39 +++ .../train/G1923/hidden/forge_hidden.clas.abap | 127 +++++++++ tasks_gen/train/G1923/mutation.json | 56 ++++ .../G1923/reference/forge_test.clas.abap | 60 +++++ .../G1923/reference/i_forge_job.ddls.asddls | 20 ++ .../train/G1923/seed/forgart.tabl.asabap | 12 + .../train/G1923/seed/forgcus.tabl.asabap | 11 + .../train/G1923/seed/forgjob.tabl.asabap | 13 + .../train/G1923/seed/i_forge_job.ddls.asddls | 22 ++ tasks_gen/train/G1923/spec.md | 49 ++++ tasks_gen/train/G1923/task.json | 85 ++++++ tasks_gen/train/G1924/generation.json | 43 +++ .../G1924/hidden/mill_charge_hidden.clas.abap | 117 ++++++++ tasks_gen/train/G1924/mutation.json | 42 +++ .../G1924/reference/i_mill_charge.ddls.asddls | 21 ++ .../reference/mill_charge_test.clas.abap | 56 ++++ .../G1924/seed/i_mill_charge.ddls.asddls | 21 ++ .../train/G1924/seed/milljob.tabl.asabap | 11 + .../train/G1924/seed/milllot.tabl.asabap | 13 + tasks_gen/train/G1924/spec.md | 55 ++++ tasks_gen/train/G1924/task.json | 73 +++++ .../G1926/faulty/m0_if_kart_check.intf.abap | 49 ++++ .../G1926/faulty/m1_if_kart_check.intf.abap | 49 ++++ .../G1926/faulty/m2_if_kart_check.intf.abap | 49 ++++ .../G1926/faulty/m3_if_kart_check.intf.abap | 49 ++++ .../G1926/faulty/m4_if_kart_check.intf.abap | 49 ++++ tasks_gen/train/G1926/generation.json | 44 +++ .../G1926/hidden/kart_check_hidden.clas.abap | 174 ++++++++++++ tasks_gen/train/G1926/mutation.json | 54 ++++ .../G1926/reference/if_kart_check.intf.abap | 49 ++++ .../G1926/reference/kart_check_test.clas.abap | 116 ++++++++ tasks_gen/train/G1926/spec.md | 67 +++++ tasks_gen/train/G1926/task.json | 46 ++++ .../G1927/faulty/m0_i_job_cost.ddls.asddls | 24 ++ .../G1927/faulty/m1_i_job_cost.ddls.asddls | 24 ++ .../G1927/faulty/m2_i_job_cost.ddls.asddls | 24 ++ .../G1927/faulty/m3_i_job_cost.ddls.asddls | 24 ++ .../G1927/faulty/m4_i_job_cost.ddls.asddls | 24 ++ tasks_gen/train/G1927/generation.json | 24 ++ .../train/G1927/hidden/e21_hidden.clas.abap | 101 +++++++ tasks_gen/train/G1927/mutation.json | 61 +++++ .../train/G1927/reference/e21_test.clas.abap | 55 ++++ .../G1927/reference/i_job_cost.ddls.asddls | 24 ++ .../train/G1927/seed/i_job_cost.ddls.asddls | 24 ++ tasks_gen/train/G1927/seed/job.tabl.asabap | 13 + tasks_gen/train/G1927/seed/jobl.tabl.asabap | 12 + tasks_gen/train/G1927/spec.md | 51 ++++ tasks_gen/train/G1927/task.json | 75 ++++++ .../G1928/faulty/m0_i_wind_grade.ddls.asddls | 34 +++ .../G1928/faulty/m1_i_wind_grade.ddls.asddls | 34 +++ .../G1928/faulty/m2_i_wind_grade.ddls.asddls | 34 +++ .../G1928/faulty/m3_i_wind_grade.ddls.asddls | 34 +++ .../G1928/faulty/m4_i_wind_grade.ddls.asddls | 34 +++ tasks_gen/train/G1928/generation.json | 29 ++ .../train/G1928/hidden/t31_hidden.clas.abap | 159 +++++++++++ tasks_gen/train/G1928/mutation.json | 62 +++++ .../G1928/reference/i_wind_grade.ddls.asddls | 34 +++ .../train/G1928/reference/t31_test.clas.abap | 64 +++++ .../train/G1928/seed/i_wind_grade.ddls.asddls | 48 ++++ .../train/G1928/seed/turbine.tabl.asabap | 12 + tasks_gen/train/G1928/seed/yield.tabl.asabap | 12 + tasks_gen/train/G1928/spec.md | 54 ++++ tasks_gen/train/G1928/task.json | 76 ++++++ .../G1929/faulty/m0_i_star_night.ddls.asddls | 18 ++ .../G1929/faulty/m1_i_star_night.ddls.asddls | 18 ++ .../G1929/faulty/m2_i_star_night.ddls.asddls | 18 ++ .../G1929/faulty/m3_i_star_night.ddls.asddls | 18 ++ .../G1929/faulty/m4_i_star_night.ddls.asddls | 18 ++ tasks_gen/train/G1929/generation.json | 38 +++ .../train/G1929/hidden/t61_hidden.clas.abap | 118 +++++++++ tasks_gen/train/G1929/mutation.json | 63 +++++ .../G1929/reference/i_star_night.ddls.asddls | 18 ++ .../train/G1929/reference/t61_test.clas.abap | 51 ++++ tasks_gen/train/G1929/seed/dome.tabl.asabap | 12 + .../train/G1929/seed/i_star_night.ddls.asddls | 20 ++ tasks_gen/train/G1929/seed/night.tabl.asabap | 13 + tasks_gen/train/G1929/seed/scope.tabl.asabap | 12 + tasks_gen/train/G1929/spec.md | 54 ++++ tasks_gen/train/G1929/task.json | 89 +++++++ .../G1930/faulty/m0_i_visit_fee.ddls.asddls | 14 + .../G1930/faulty/m1_i_visit_fee.ddls.asddls | 14 + .../G1930/faulty/m2_i_visit_fee.ddls.asddls | 14 + .../G1930/faulty/m3_i_visit_fee.ddls.asddls | 14 + tasks_gen/train/G1930/generation.json | 24 ++ .../train/G1930/hidden/visit_hidden.clas.abap | 102 +++++++ tasks_gen/train/G1930/mutation.json | 61 +++++ .../G1930/reference/i_visit_fee.ddls.asddls | 14 + .../G1930/reference/visit_test.clas.abap | 46 ++++ tasks_gen/train/G1930/seed/area.tabl.asabap | 11 + .../train/G1930/seed/i_visit_fee.ddls.asddls | 13 + tasks_gen/train/G1930/seed/visit.tabl.asabap | 13 + tasks_gen/train/G1930/spec.md | 44 +++ tasks_gen/train/G1930/task.json | 72 +++++ .../G1931/faulty/m0_i_rental_fee.ddls.asddls | 22 ++ .../G1931/faulty/m1_i_rental_fee.ddls.asddls | 22 ++ .../G1931/faulty/m2_i_rental_fee.ddls.asddls | 22 ++ .../G1931/faulty/m3_i_rental_fee.ddls.asddls | 22 ++ .../G1931/faulty/m4_i_rental_fee.ddls.asddls | 22 ++ tasks_gen/train/G1931/generation.json | 28 ++ .../G1931/hidden/e_rental_hidden.clas.abap | 131 +++++++++ tasks_gen/train/G1931/mutation.json | 68 +++++ .../G1931/reference/e_rental_test.clas.abap | 56 ++++ .../G1931/reference/i_rental_fee.ddls.asddls | 22 ++ .../train/G1931/seed/i_rental_fee.ddls.asddls | 29 ++ tasks_gen/train/G1931/seed/rental.tabl.asabap | 12 + tasks_gen/train/G1931/spec.md | 44 +++ tasks_gen/train/G1931/task.json | 64 +++++ .../train/G1932/faulty/m1_bowl.tabl.asabap | 17 ++ .../train/G1932/faulty/m2_bowl.tabl.asabap | 17 ++ .../train/G1932/faulty/m3_bowl.tabl.asabap | 17 ++ .../train/G1932/faulty/m4_bowl.tabl.asabap | 17 ++ tasks_gen/train/G1932/generation.json | 42 +++ .../train/G1932/hidden/bowl_hidden.clas.abap | 195 ++++++++++++++ tasks_gen/train/G1932/mutation.json | 55 ++++ .../train/G1932/reference/bowl.tabl.asabap | 17 ++ .../train/G1932/reference/bowl_test.clas.abap | 63 +++++ tasks_gen/train/G1932/spec.md | 69 +++++ tasks_gen/train/G1932/task.json | 55 ++++ .../G1933/faulty/m0_if_pyro_order.intf.abap | 50 ++++ .../G1933/faulty/m1_if_pyro_order.intf.abap | 50 ++++ .../G1933/faulty/m2_if_pyro_order.intf.abap | 50 ++++ .../G1933/faulty/m3_if_pyro_order.intf.abap | 50 ++++ .../G1933/faulty/m4_if_pyro_order.intf.abap | 50 ++++ tasks_gen/train/G1933/generation.json | 55 ++++ .../train/G1933/hidden/pyro_hidden.clas.abap | 214 +++++++++++++++ tasks_gen/train/G1933/mutation.json | 54 ++++ .../G1933/reference/if_pyro_order.intf.abap | 50 ++++ .../G1933/reference/pyro_order_test.clas.abap | 182 +++++++++++++ tasks_gen/train/G1933/spec.md | 67 +++++ tasks_gen/train/G1933/task.json | 48 ++++ .../train/G1934/faulty/m0_pitch.tabl.asabap | 16 ++ .../train/G1934/faulty/m1_pitch.tabl.asabap | 16 ++ .../train/G1934/faulty/m2_pitch.tabl.asabap | 16 ++ .../train/G1934/faulty/m3_pitch.tabl.asabap | 16 ++ .../train/G1934/faulty/m4_pitch.tabl.asabap | 16 ++ tasks_gen/train/G1934/generation.json | 24 ++ .../train/G1934/hidden/t16_hidden.clas.abap | 147 ++++++++++ tasks_gen/train/G1934/mutation.json | 55 ++++ .../train/G1934/reference/pitch.tabl.asabap | 16 ++ .../train/G1934/reference/t16_test.clas.abap | 83 ++++++ tasks_gen/train/G1934/spec.md | 50 ++++ tasks_gen/train/G1934/task.json | 54 ++++ tasks_gen/train/G1935/generation.json | 43 +++ .../train/G1935/hidden/t02_hidden.clas.abap | 241 +++++++++++++++++ .../G1935/reference/if_mix_recipe.intf.abap | 107 ++++++++ .../G1935/reference/mix_recipe_test.clas.abap | 82 ++++++ tasks_gen/train/G1935/spec.md | 81 ++++++ tasks_gen/train/G1935/task.json | 46 ++++ .../train/G1936/faulty/m0_syrup.tabl.asabap | 17 ++ .../train/G1936/faulty/m2_syrup.tabl.asabap | 17 ++ .../train/G1936/faulty/m3_syrup.tabl.asabap | 17 ++ .../train/G1936/faulty/m4_syrup.tabl.asabap | 17 ++ tasks_gen/train/G1936/generation.json | 19 ++ .../train/G1936/hidden/syrup_hidden.clas.abap | 183 +++++++++++++ tasks_gen/train/G1936/mutation.json | 53 ++++ .../train/G1936/reference/syrup.tabl.asabap | 17 ++ .../G1936/reference/syrup_test.clas.abap | 65 +++++ tasks_gen/train/G1936/spec.md | 54 ++++ tasks_gen/train/G1936/task.json | 54 ++++ .../G1937/faulty/m0_if_sweep_check.intf.abap | 37 +++ .../G1937/faulty/m1_chimney_checker.clas.abap | 65 +++++ .../G1937/faulty/m2_if_sweep_check.intf.abap | 37 +++ .../G1937/faulty/m3_chimney_checker.clas.abap | 65 +++++ .../G1937/faulty/m4_if_sweep_check.intf.abap | 37 +++ tasks_gen/train/G1937/generation.json | 34 +++ .../train/G1937/hidden/t02_hidden.clas.abap | 215 +++++++++++++++ tasks_gen/train/G1937/mutation.json | 62 +++++ .../G1937/reference/chimney_checker.clas.abap | 65 +++++ .../chimney_checker.testclasses.abap | 102 +++++++ .../G1937/reference/if_sweep_check.intf.abap | 37 +++ tasks_gen/train/G1937/spec.md | 75 ++++++ tasks_gen/train/G1937/task.json | 51 ++++ .../G1938/faulty/m0_if_log_plan.intf.abap | 35 +++ .../G1938/faulty/m1_if_log_plan.intf.abap | 35 +++ .../G1938/faulty/m2_if_log_plan.intf.abap | 35 +++ .../G1938/faulty/m3_if_log_plan.intf.abap | 35 +++ .../G1938/faulty/m4_if_log_plan.intf.abap | 35 +++ tasks_gen/train/G1938/generation.json | 24 ++ .../train/G1938/hidden/t02_hidden.clas.abap | 124 +++++++++ tasks_gen/train/G1938/mutation.json | 55 ++++ .../G1938/reference/if_log_plan.intf.abap | 35 +++ .../reference/if_log_plan_test.clas.abap | 70 +++++ tasks_gen/train/G1938/spec.md | 63 +++++ tasks_gen/train/G1938/task.json | 50 ++++ .../train/G1939/faulty/m0_pluck.tabl.asabap | 18 ++ .../train/G1939/faulty/m1_pluck.tabl.asabap | 18 ++ .../train/G1939/faulty/m2_pluck.tabl.asabap | 18 ++ .../train/G1939/faulty/m4_pluck.tabl.asabap | 18 ++ tasks_gen/train/G1939/generation.json | 24 ++ .../train/G1939/hidden/pluck_hidden.clas.abap | 171 ++++++++++++ tasks_gen/train/G1939/mutation.json | 53 ++++ .../train/G1939/reference/pluck.tabl.asabap | 18 ++ .../G1939/reference/pluck_test.clas.abap | 98 +++++++ tasks_gen/train/G1939/spec.md | 59 +++++ tasks_gen/train/G1939/task.json | 56 ++++ .../G1940/faulty/m0_lift_check.clas.abap | 44 +++ .../G1940/faulty/m2_lift_check.clas.abap | 44 +++ tasks_gen/train/G1940/generation.json | 24 ++ .../train/G1940/hidden/lift_hidden.clas.abap | 139 ++++++++++ tasks_gen/train/G1940/mutation.json | 58 ++++ .../G1940/reference/cx_crane_error.clas.abap | 33 +++ .../G1940/reference/lift_check.clas.abap | 44 +++ .../lift_check.clas.testclasses.abap | 66 +++++ .../train/G1940/reference/lift_test.clas.abap | 63 +++++ tasks_gen/train/G1940/spec.md | 81 ++++++ tasks_gen/train/G1940/task.json | 109 ++++++++ .../G1941/faulty/m0_compost_sum.prog.abap | 108 ++++++++ .../G1941/faulty/m1_compost_sum.prog.abap | 108 ++++++++ .../G1941/faulty/m2_compost_sum.prog.abap | 108 ++++++++ tasks_gen/train/G1941/generation.json | 24 ++ .../G1941/hidden/compost_hidden.clas.abap | 106 ++++++++ tasks_gen/train/G1941/mutation.json | 46 ++++ .../G1941/reference/compost_sum.prog.abap | 108 ++++++++ .../train/G1941/seed/compost_seed.clas.abap | 17 ++ tasks_gen/train/G1941/seed/gwaste.tabl.asabap | 13 + tasks_gen/train/G1941/spec.md | 38 +++ tasks_gen/train/G1941/task.json | 60 +++++ .../G1942/faulty/m0_repair_list.prog.abap | 203 ++++++++++++++ .../G1942/faulty/m1_repair_list.prog.abap | 203 ++++++++++++++ .../G1942/faulty/m2_repair_list.prog.abap | 203 ++++++++++++++ .../G1942/faulty/m3_repair_list.prog.abap | 203 ++++++++++++++ tasks_gen/train/G1942/generation.json | 29 ++ .../train/G1942/hidden/bike_hidden.clas.abap | 93 +++++++ tasks_gen/train/G1942/mutation.json | 59 +++++ .../G1942/reference/repair_list.prog.abap | 203 ++++++++++++++ .../train/G1942/seed/bike_seed.clas.abap | 36 +++ tasks_gen/train/G1942/seed/jobhdr.tabl.asabap | 12 + tasks_gen/train/G1942/seed/jobitm.tabl.asabap | 13 + tasks_gen/train/G1942/seed/mech.tabl.asabap | 10 + tasks_gen/train/G1942/spec.md | 49 ++++ tasks_gen/train/G1942/task.json | 74 ++++++ tasks_gen/train/G1943/generation.json | 43 +++ .../G1943/hidden/game_stru_hidden.clas.abap | 159 +++++++++++ .../G1943/reference/edit_stamp.stru.asabap | 6 + .../G1943/reference/game_round.stru.asabap | 13 + .../G1943/reference/game_stru_test.clas.abap | 77 ++++++ tasks_gen/train/G1943/spec.md | 61 +++++ tasks_gen/train/G1943/task.json | 69 +++++ .../train/G1944/faulty/m1_sharp_sum.prog.abap | 104 ++++++++ .../train/G1944/faulty/m2_sharp_sum.prog.abap | 104 ++++++++ tasks_gen/train/G1944/generation.json | 34 +++ .../train/G1944/hidden/t15_hidden.clas.abap | 102 +++++++ tasks_gen/train/G1944/mutation.json | 40 +++ .../train/G1944/reference/sharp_sum.prog.abap | 104 ++++++++ tasks_gen/train/G1944/seed/kntype.tabl.asabap | 10 + .../train/G1944/seed/sharpen.tabl.asabap | 13 + tasks_gen/train/G1944/seed/t15_seed.clas.abap | 28 ++ tasks_gen/train/G1944/spec.md | 48 ++++ tasks_gen/train/G1944/task.json | 67 +++++ tasks_gen/train/G1945/generation.json | 19 ++ .../train/G1945/hidden/t21_hidden.clas.abap | 111 ++++++++ tasks_gen/train/G1945/mutation.json | 52 ++++ .../G1945/reference/cx_scaf_order.clas.abap | 33 +++ .../train/G1945/reference/t21_test.clas.abap | 87 ++++++ tasks_gen/train/G1945/spec.md | 51 ++++ tasks_gen/train/G1945/task.json | 93 +++++++ .../G1946/faulty/m0_roast_base.stru.asabap | 9 + .../G1946/faulty/m1_roast_result.stru.asabap | 14 + .../G1946/faulty/m2_roast_base.stru.asabap | 9 + .../G1946/faulty/m3_roast_result.stru.asabap | 14 + .../G1946/faulty/m4_roast_base.stru.asabap | 9 + tasks_gen/train/G1946/generation.json | 24 ++ .../train/G1946/hidden/roast_hidden.clas.abap | 135 ++++++++++ tasks_gen/train/G1946/mutation.json | 57 ++++ .../G1946/reference/roast_base.stru.asabap | 9 + .../G1946/reference/roast_result.stru.asabap | 14 + .../G1946/reference/roast_test.clas.abap | 46 ++++ tasks_gen/train/G1946/seed/roast.tabl.asabap | 18 ++ tasks_gen/train/G1946/spec.md | 55 ++++ tasks_gen/train/G1946/task.json | 81 ++++++ .../G1947/faulty/m0_svc_base.ddls.asddls | 6 + .../train/G1947/faulty/m1_svc_job.ddls.asddls | 14 + .../G1947/faulty/m2_svc_base.ddls.asddls | 6 + .../train/G1947/faulty/m3_svc_job.ddls.asddls | 14 + .../G1947/faulty/m4_svc_base.ddls.asddls | 6 + tasks_gen/train/G1947/generation.json | 34 +++ .../G1947/hidden/svc_job_hidden.clas.abap | 193 ++++++++++++++ tasks_gen/train/G1947/mutation.json | 57 ++++ .../G1947/reference/svc_base.ddls.asddls | 6 + .../train/G1947/reference/svc_job.ddls.asddls | 14 + .../G1947/reference/svc_job_test.clas.abap | 55 ++++ tasks_gen/train/G1947/spec.md | 51 ++++ tasks_gen/train/G1947/task.json | 69 +++++ tasks_gen/train/G1948/generation.json | 29 ++ .../train/G1948/hidden/t_arc_hidden.clas.abap | 107 ++++++++ tasks_gen/train/G1948/mutation.json | 52 ++++ .../G1948/reference/cx_bow_check.clas.abap | 48 ++++ .../train/G1948/reference/t_arc_msg.clas.abap | 71 +++++ tasks_gen/train/G1948/spec.md | 58 ++++ tasks_gen/train/G1948/task.json | 90 +++++++ .../G1949/faulty/m0_i_hawk_site.ddls.asddls | 13 + .../G1949/faulty/m1_i_hawk_site.ddls.asddls | 13 + .../G1949/faulty/m2_i_hawk_site.ddls.asddls | 13 + .../G1949/faulty/m3_i_hawk_site.ddls.asddls | 13 + tasks_gen/train/G1949/generation.json | 28 ++ .../train/G1949/hidden/t42_hidden.clas.abap | 86 ++++++ tasks_gen/train/G1949/mutation.json | 50 ++++ .../G1949/reference/i_hawk_site.ddls.asddls | 13 + .../train/G1949/reference/t42_test.clas.abap | 48 ++++ tasks_gen/train/G1949/seed/falcon.tabl.asabap | 14 + tasks_gen/train/G1949/spec.md | 54 ++++ tasks_gen/train/G1949/task.json | 59 +++++ .../faulty/m0_i_product_quality.ddls.asddls | 15 ++ .../faulty/m1_i_product_quality.ddls.asddls | 15 ++ .../faulty/m2_i_product_quality.ddls.asddls | 15 ++ .../faulty/m3_i_product_quality.ddls.asddls | 15 ++ .../faulty/m4_i_product_quality.ddls.asddls | 15 ++ tasks_gen/train/G1950/generation.json | 34 +++ .../train/G1950/hidden/t41_hidden.clas.abap | 115 ++++++++ tasks_gen/train/G1950/mutation.json | 54 ++++ .../reference/i_product_quality.ddls.asddls | 15 ++ .../train/G1950/reference/t41_test.clas.abap | 49 ++++ tasks_gen/train/G1950/seed/batch.tabl.asabap | 14 + .../G1950/seed/i_batch_quality.ddls.asddls | 14 + tasks_gen/train/G1950/spec.md | 46 ++++ tasks_gen/train/G1950/task.json | 67 +++++ tasks_gen/train/G1951/generation.json | 29 ++ .../G1951/hidden/tenancy_hidden.clas.abap | 250 ++++++++++++++++++ .../reference/if_tenancy_check.intf.abap | 35 +++ .../G1951/reference/tenancy_checker.clas.abap | 75 ++++++ .../tenancy_checker.testclasses.abap | 117 ++++++++ tasks_gen/train/G1951/spec.md | 84 ++++++ tasks_gen/train/G1951/task.json | 52 ++++ tasks_gen/train/G1952/generation.json | 33 +++ .../train/G1952/hidden/t16_hidden.clas.abap | 212 +++++++++++++++ .../train/G1952/reference/sess.tabl.asabap | 17 ++ .../train/G1952/reference/t16_test.clas.abap | 75 ++++++ tasks_gen/train/G1952/spec.md | 59 +++++ tasks_gen/train/G1952/task.json | 55 ++++ tasks_gen/train/G1953/generation.json | 35 +++ .../train/G1953/hidden/t44_hidden.clas.abap | 149 +++++++++++ tasks_gen/train/G1953/mutation.json | 8 + .../G1953/reference/if_piano_tuning.intf.abap | 53 ++++ .../reference/piano_tuning_test.clas.abap | 110 ++++++++ tasks_gen/train/G1953/spec.md | 65 +++++ tasks_gen/train/G1953/task.json | 48 ++++ .../G1954/faulty/m0_if_sail_repair.intf.abap | 40 +++ .../G1954/faulty/m1_if_sail_repair.intf.abap | 40 +++ .../G1954/faulty/m2_if_sail_repair.intf.abap | 40 +++ .../G1954/faulty/m3_if_sail_repair.intf.abap | 40 +++ .../G1954/faulty/m4_if_sail_repair.intf.abap | 40 +++ tasks_gen/train/G1954/generation.json | 34 +++ .../train/G1954/hidden/t02_hidden.clas.abap | 105 ++++++++ tasks_gen/train/G1954/mutation.json | 55 ++++ .../reference/cl_sail_repair_test.clas.abap | 81 ++++++ .../G1954/reference/if_sail_repair.intf.abap | 40 +++ tasks_gen/train/G1954/spec.md | 62 +++++ tasks_gen/train/G1954/task.json | 49 ++++ .../train/G1955/faulty/m0_well.tabl.asabap | 19 ++ .../train/G1955/faulty/m1_well.tabl.asabap | 19 ++ .../train/G1955/faulty/m2_well.tabl.asabap | 19 ++ .../train/G1955/faulty/m3_well.tabl.asabap | 19 ++ .../train/G1955/faulty/m4_well.tabl.asabap | 19 ++ tasks_gen/train/G1955/generation.json | 24 ++ .../train/G1955/hidden/well_hidden.clas.abap | 154 +++++++++++ tasks_gen/train/G1955/mutation.json | 56 ++++ .../train/G1955/reference/well.tabl.asabap | 19 ++ .../train/G1955/reference/well_test.clas.abap | 62 +++++ tasks_gen/train/G1955/spec.md | 58 ++++ tasks_gen/train/G1955/task.json | 57 ++++ tasks_gen/train/G1956/generation.json | 33 +++ .../G1956/hidden/cobbler_hidden.clas.abap | 138 ++++++++++ .../G1956/reference/cobbler_test.clas.abap | 130 +++++++++ .../G1956/reference/if_cobbler.intf.abap | 52 ++++ tasks_gen/train/G1956/spec.md | 76 ++++++ tasks_gen/train/G1956/task.json | 43 +++ .../train/G1957/faulty/m0_winjob.tabl.asabap | 16 ++ .../train/G1957/faulty/m1_winjob.tabl.asabap | 16 ++ .../train/G1957/faulty/m2_winjob.tabl.asabap | 16 ++ .../train/G1957/faulty/m3_winjob.tabl.asabap | 16 ++ .../train/G1957/faulty/m4_winjob.tabl.asabap | 16 ++ tasks_gen/train/G1957/generation.json | 44 +++ .../train/G1957/hidden/t61_hidden.clas.abap | 116 ++++++++ tasks_gen/train/G1957/mutation.json | 56 ++++ .../train/G1957/reference/t61_test.clas.abap | 68 +++++ .../train/G1957/reference/winjob.tabl.asabap | 16 ++ tasks_gen/train/G1957/spec.md | 56 ++++ tasks_gen/train/G1957/task.json | 54 ++++ tasks_gen/train/_logs/G1910.json | 23 ++ tasks_gen/train/_logs/G1911.json | 28 ++ tasks_gen/train/_logs/G1912.json | 33 +++ tasks_gen/train/_logs/G1913.json | 42 +++ tasks_gen/train/_logs/G1914.json | 37 +++ tasks_gen/train/_logs/G1915.json | 28 ++ tasks_gen/train/_logs/G1916.json | 37 +++ tasks_gen/train/_logs/G1917.json | 42 +++ tasks_gen/train/_logs/G1918.json | 43 +++ tasks_gen/train/_logs/G1919.json | 23 ++ tasks_gen/train/_logs/G1920.json | 23 ++ tasks_gen/train/_logs/G1921.json | 38 +++ tasks_gen/train/_logs/G1922.json | 39 +++ tasks_gen/train/_logs/G1923.json | 43 +++ tasks_gen/train/_logs/G1924.json | 47 ++++ tasks_gen/train/_logs/G1925.json | 51 ++++ tasks_gen/train/_logs/G1926.json | 48 ++++ tasks_gen/train/_logs/G1927.json | 28 ++ tasks_gen/train/_logs/G1928.json | 33 +++ tasks_gen/train/_logs/G1929.json | 42 +++ tasks_gen/train/_logs/G1930.json | 28 ++ tasks_gen/train/_logs/G1931.json | 32 +++ tasks_gen/train/_logs/G1932.json | 46 ++++ tasks_gen/train/_logs/G1933.json | 59 +++++ tasks_gen/train/_logs/G1934.json | 28 ++ tasks_gen/train/_logs/G1935.json | 47 ++++ tasks_gen/train/_logs/G1936.json | 23 ++ tasks_gen/train/_logs/G1937.json | 38 +++ tasks_gen/train/_logs/G1938.json | 28 ++ tasks_gen/train/_logs/G1939.json | 28 ++ tasks_gen/train/_logs/G1940.json | 28 ++ tasks_gen/train/_logs/G1941.json | 28 ++ tasks_gen/train/_logs/G1942.json | 33 +++ tasks_gen/train/_logs/G1943.json | 47 ++++ tasks_gen/train/_logs/G1944.json | 38 +++ tasks_gen/train/_logs/G1945.json | 23 ++ tasks_gen/train/_logs/G1946.json | 28 ++ tasks_gen/train/_logs/G1947.json | 38 +++ tasks_gen/train/_logs/G1948.json | 33 +++ tasks_gen/train/_logs/G1949.json | 32 +++ tasks_gen/train/_logs/G1950.json | 38 +++ tasks_gen/train/_logs/G1951.json | 33 +++ tasks_gen/train/_logs/G1952.json | 37 +++ tasks_gen/train/_logs/G1953.json | 39 +++ tasks_gen/train/_logs/G1954.json | 38 +++ tasks_gen/train/_logs/G1955.json | 28 ++ tasks_gen/train/_logs/G1956.json | 37 +++ tasks_gen/train/_logs/G1957.json | 48 ++++ 572 files changed, 30024 insertions(+) create mode 100644 tasks_gen/train/G1910/faulty/m0_cider.tabl.asabap create mode 100644 tasks_gen/train/G1910/faulty/m1_cider.tabl.asabap create mode 100644 tasks_gen/train/G1910/faulty/m2_cider.tabl.asabap create mode 100644 tasks_gen/train/G1910/faulty/m3_cider.tabl.asabap create mode 100644 tasks_gen/train/G1910/faulty/m4_cider.tabl.asabap create mode 100644 tasks_gen/train/G1910/generation.json create mode 100644 tasks_gen/train/G1910/hidden/cider_hidden.clas.abap create mode 100644 tasks_gen/train/G1910/mutation.json create mode 100644 tasks_gen/train/G1910/reference/cider.tabl.asabap create mode 100644 tasks_gen/train/G1910/reference/cider_test.clas.abap create mode 100644 tasks_gen/train/G1910/spec.md create mode 100644 tasks_gen/train/G1910/task.json create mode 100644 tasks_gen/train/G1911/faulty/m0_hire.tabl.asabap create mode 100644 tasks_gen/train/G1911/faulty/m1_hire.tabl.asabap create mode 100644 tasks_gen/train/G1911/faulty/m2_hire.tabl.asabap create mode 100644 tasks_gen/train/G1911/faulty/m3_hire.tabl.asabap create mode 100644 tasks_gen/train/G1911/faulty/m4_hire.tabl.asabap create mode 100644 tasks_gen/train/G1911/generation.json create mode 100644 tasks_gen/train/G1911/hidden/hire_hidden.clas.abap create mode 100644 tasks_gen/train/G1911/mutation.json create mode 100644 tasks_gen/train/G1911/reference/hire.tabl.asabap create mode 100644 tasks_gen/train/G1911/reference/hire_test.clas.abap create mode 100644 tasks_gen/train/G1911/spec.md create mode 100644 tasks_gen/train/G1911/task.json create mode 100644 tasks_gen/train/G1912/faulty/m0_svcjob.tabl.asabap create mode 100644 tasks_gen/train/G1912/faulty/m1_svcjob.tabl.asabap create mode 100644 tasks_gen/train/G1912/faulty/m2_svcjob.tabl.asabap create mode 100644 tasks_gen/train/G1912/faulty/m3_svcjob.tabl.asabap create mode 100644 tasks_gen/train/G1912/faulty/m4_svcjob.tabl.asabap create mode 100644 tasks_gen/train/G1912/generation.json create mode 100644 tasks_gen/train/G1912/hidden/svcjob_hidden.clas.abap create mode 100644 tasks_gen/train/G1912/mutation.json create mode 100644 tasks_gen/train/G1912/reference/svcjob.tabl.asabap create mode 100644 tasks_gen/train/G1912/reference/svcjob_test.clas.abap create mode 100644 tasks_gen/train/G1912/spec.md create mode 100644 tasks_gen/train/G1912/task.json create mode 100644 tasks_gen/train/G1913/faulty/m0_if_laundry_fee.intf.abap create mode 100644 tasks_gen/train/G1913/faulty/m1_if_laundry_fee.intf.abap create mode 100644 tasks_gen/train/G1913/faulty/m2_if_laundry_fee.intf.abap create mode 100644 tasks_gen/train/G1913/faulty/m3_if_laundry_fee.intf.abap create mode 100644 tasks_gen/train/G1913/faulty/m4_if_laundry_fee.intf.abap create mode 100644 tasks_gen/train/G1913/generation.json create mode 100644 tasks_gen/train/G1913/hidden/laundry_hidden.clas.abap create mode 100644 tasks_gen/train/G1913/mutation.json create mode 100644 tasks_gen/train/G1913/reference/if_laundry_fee.intf.abap create mode 100644 tasks_gen/train/G1913/reference/laundry_fee_test.clas.abap create mode 100644 tasks_gen/train/G1913/spec.md create mode 100644 tasks_gen/train/G1913/task.json create mode 100644 tasks_gen/train/G1914/generation.json create mode 100644 tasks_gen/train/G1914/hidden/t58_hidden.clas.abap create mode 100644 tasks_gen/train/G1914/reference/if_rope_check.intf.abap create mode 100644 tasks_gen/train/G1914/reference/rope_check_test.clas.abap create mode 100644 tasks_gen/train/G1914/reference/rope_checker.clas.abap create mode 100644 tasks_gen/train/G1914/reference/rope_checker.testclasses.abap create mode 100644 tasks_gen/train/G1914/spec.md create mode 100644 tasks_gen/train/G1914/task.json create mode 100644 tasks_gen/train/G1915/faulty/m0_grh.tabl.asabap create mode 100644 tasks_gen/train/G1915/faulty/m1_grh.tabl.asabap create mode 100644 tasks_gen/train/G1915/faulty/m2_grh.tabl.asabap create mode 100644 tasks_gen/train/G1915/faulty/m3_grh.tabl.asabap create mode 100644 tasks_gen/train/G1915/faulty/m4_grh.tabl.asabap create mode 100644 tasks_gen/train/G1915/generation.json create mode 100644 tasks_gen/train/G1915/hidden/grh_hidden.clas.abap create mode 100644 tasks_gen/train/G1915/mutation.json create mode 100644 tasks_gen/train/G1915/reference/grh.tabl.asabap create mode 100644 tasks_gen/train/G1915/reference/grh_test.clas.abap create mode 100644 tasks_gen/train/G1915/spec.md create mode 100644 tasks_gen/train/G1915/task.json create mode 100644 tasks_gen/train/G1916/generation.json create mode 100644 tasks_gen/train/G1916/hidden/solar_check_hidden.clas.abap create mode 100644 tasks_gen/train/G1916/reference/if_solar_check.intf.abap create mode 100644 tasks_gen/train/G1916/reference/solar_check_test.clas.abap create mode 100644 tasks_gen/train/G1916/spec.md create mode 100644 tasks_gen/train/G1916/task.json create mode 100644 tasks_gen/train/G1917/faulty/m0_if_bouquet_check.intf.abap create mode 100644 tasks_gen/train/G1917/faulty/m1_if_bouquet_check.intf.abap create mode 100644 tasks_gen/train/G1917/faulty/m2_if_bouquet_check.intf.abap create mode 100644 tasks_gen/train/G1917/faulty/m3_if_bouquet_check.intf.abap create mode 100644 tasks_gen/train/G1917/faulty/m4_if_bouquet_check.intf.abap create mode 100644 tasks_gen/train/G1917/generation.json create mode 100644 tasks_gen/train/G1917/hidden/bouquet_check_hidden.clas.abap create mode 100644 tasks_gen/train/G1917/mutation.json create mode 100644 tasks_gen/train/G1917/reference/bouquet_check_test.clas.abap create mode 100644 tasks_gen/train/G1917/reference/if_bouquet_check.intf.abap create mode 100644 tasks_gen/train/G1917/spec.md create mode 100644 tasks_gen/train/G1917/task.json create mode 100644 tasks_gen/train/G1918/faulty/m0_bouquet_pricing.intf.abap create mode 100644 tasks_gen/train/G1918/faulty/m1_bouquet_pricing.intf.abap create mode 100644 tasks_gen/train/G1918/faulty/m2_bouquet_pricing.intf.abap create mode 100644 tasks_gen/train/G1918/faulty/m3_bouquet_pricing.intf.abap create mode 100644 tasks_gen/train/G1918/generation.json create mode 100644 tasks_gen/train/G1918/hidden/t02_hidden.clas.abap create mode 100644 tasks_gen/train/G1918/mutation.json create mode 100644 tasks_gen/train/G1918/reference/bouquet_if_test.clas.abap create mode 100644 tasks_gen/train/G1918/reference/bouquet_pricing.intf.abap create mode 100644 tasks_gen/train/G1918/spec.md create mode 100644 tasks_gen/train/G1918/task.json create mode 100644 tasks_gen/train/G1919/faulty/m0_rescue.tabl.asabap create mode 100644 tasks_gen/train/G1919/faulty/m1_rescue.tabl.asabap create mode 100644 tasks_gen/train/G1919/faulty/m2_rescue.tabl.asabap create mode 100644 tasks_gen/train/G1919/faulty/m3_rescue.tabl.asabap create mode 100644 tasks_gen/train/G1919/faulty/m4_rescue.tabl.asabap create mode 100644 tasks_gen/train/G1919/generation.json create mode 100644 tasks_gen/train/G1919/hidden/t20_hidden.clas.abap create mode 100644 tasks_gen/train/G1919/mutation.json create mode 100644 tasks_gen/train/G1919/reference/rescue.tabl.asabap create mode 100644 tasks_gen/train/G1919/reference/t20_test.clas.abap create mode 100644 tasks_gen/train/G1919/spec.md create mode 100644 tasks_gen/train/G1919/task.json create mode 100644 tasks_gen/train/G1920/faulty/m0_jump.tabl.asabap create mode 100644 tasks_gen/train/G1920/faulty/m1_jump.tabl.asabap create mode 100644 tasks_gen/train/G1920/faulty/m2_jump.tabl.asabap create mode 100644 tasks_gen/train/G1920/faulty/m3_jump.tabl.asabap create mode 100644 tasks_gen/train/G1920/faulty/m4_jump.tabl.asabap create mode 100644 tasks_gen/train/G1920/generation.json create mode 100644 tasks_gen/train/G1920/hidden/jump_hidden.clas.abap create mode 100644 tasks_gen/train/G1920/mutation.json create mode 100644 tasks_gen/train/G1920/reference/jump.tabl.asabap create mode 100644 tasks_gen/train/G1920/reference/jump_test.clas.abap create mode 100644 tasks_gen/train/G1920/spec.md create mode 100644 tasks_gen/train/G1920/task.json create mode 100644 tasks_gen/train/G1921/faulty/m0_if_kiln_quote.intf.abap create mode 100644 tasks_gen/train/G1921/faulty/m2_if_kiln_quote.intf.abap create mode 100644 tasks_gen/train/G1921/faulty/m4_if_kiln_quote.intf.abap create mode 100644 tasks_gen/train/G1921/generation.json create mode 100644 tasks_gen/train/G1921/hidden/t02_hidden.clas.abap create mode 100644 tasks_gen/train/G1921/mutation.json create mode 100644 tasks_gen/train/G1921/reference/if_kiln_quote.intf.abap create mode 100644 tasks_gen/train/G1921/reference/if_kiln_quote_test.clas.abap create mode 100644 tasks_gen/train/G1921/reference/if_kiln_quote_test.testclasses.abap create mode 100644 tasks_gen/train/G1921/spec.md create mode 100644 tasks_gen/train/G1921/task.json create mode 100644 tasks_gen/train/G1922/generation.json create mode 100644 tasks_gen/train/G1922/hidden/lift_usage_hidden.clas.abap create mode 100644 tasks_gen/train/G1922/mutation.json create mode 100644 tasks_gen/train/G1922/reference/i_lift_usage.ddls.asddls create mode 100644 tasks_gen/train/G1922/reference/lift_usage_test.clas.abap create mode 100644 tasks_gen/train/G1922/seed/i_lift_usage.ddls.asddls create mode 100644 tasks_gen/train/G1922/seed/lift.tabl.asabap create mode 100644 tasks_gen/train/G1922/seed/lift_op.tabl.asabap create mode 100644 tasks_gen/train/G1922/spec.md create mode 100644 tasks_gen/train/G1922/task.json create mode 100644 tasks_gen/train/G1923/faulty/m1_i_forge_job.ddls.asddls create mode 100644 tasks_gen/train/G1923/faulty/m2_i_forge_job.ddls.asddls create mode 100644 tasks_gen/train/G1923/faulty/m3_i_forge_job.ddls.asddls create mode 100644 tasks_gen/train/G1923/faulty/m4_i_forge_job.ddls.asddls create mode 100644 tasks_gen/train/G1923/generation.json create mode 100644 tasks_gen/train/G1923/hidden/forge_hidden.clas.abap create mode 100644 tasks_gen/train/G1923/mutation.json create mode 100644 tasks_gen/train/G1923/reference/forge_test.clas.abap create mode 100644 tasks_gen/train/G1923/reference/i_forge_job.ddls.asddls create mode 100644 tasks_gen/train/G1923/seed/forgart.tabl.asabap create mode 100644 tasks_gen/train/G1923/seed/forgcus.tabl.asabap create mode 100644 tasks_gen/train/G1923/seed/forgjob.tabl.asabap create mode 100644 tasks_gen/train/G1923/seed/i_forge_job.ddls.asddls create mode 100644 tasks_gen/train/G1923/spec.md create mode 100644 tasks_gen/train/G1923/task.json create mode 100644 tasks_gen/train/G1924/generation.json create mode 100644 tasks_gen/train/G1924/hidden/mill_charge_hidden.clas.abap create mode 100644 tasks_gen/train/G1924/mutation.json create mode 100644 tasks_gen/train/G1924/reference/i_mill_charge.ddls.asddls create mode 100644 tasks_gen/train/G1924/reference/mill_charge_test.clas.abap create mode 100644 tasks_gen/train/G1924/seed/i_mill_charge.ddls.asddls create mode 100644 tasks_gen/train/G1924/seed/milljob.tabl.asabap create mode 100644 tasks_gen/train/G1924/seed/milllot.tabl.asabap create mode 100644 tasks_gen/train/G1924/spec.md create mode 100644 tasks_gen/train/G1924/task.json create mode 100644 tasks_gen/train/G1926/faulty/m0_if_kart_check.intf.abap create mode 100644 tasks_gen/train/G1926/faulty/m1_if_kart_check.intf.abap create mode 100644 tasks_gen/train/G1926/faulty/m2_if_kart_check.intf.abap create mode 100644 tasks_gen/train/G1926/faulty/m3_if_kart_check.intf.abap create mode 100644 tasks_gen/train/G1926/faulty/m4_if_kart_check.intf.abap create mode 100644 tasks_gen/train/G1926/generation.json create mode 100644 tasks_gen/train/G1926/hidden/kart_check_hidden.clas.abap create mode 100644 tasks_gen/train/G1926/mutation.json create mode 100644 tasks_gen/train/G1926/reference/if_kart_check.intf.abap create mode 100644 tasks_gen/train/G1926/reference/kart_check_test.clas.abap create mode 100644 tasks_gen/train/G1926/spec.md create mode 100644 tasks_gen/train/G1926/task.json create mode 100644 tasks_gen/train/G1927/faulty/m0_i_job_cost.ddls.asddls create mode 100644 tasks_gen/train/G1927/faulty/m1_i_job_cost.ddls.asddls create mode 100644 tasks_gen/train/G1927/faulty/m2_i_job_cost.ddls.asddls create mode 100644 tasks_gen/train/G1927/faulty/m3_i_job_cost.ddls.asddls create mode 100644 tasks_gen/train/G1927/faulty/m4_i_job_cost.ddls.asddls create mode 100644 tasks_gen/train/G1927/generation.json create mode 100644 tasks_gen/train/G1927/hidden/e21_hidden.clas.abap create mode 100644 tasks_gen/train/G1927/mutation.json create mode 100644 tasks_gen/train/G1927/reference/e21_test.clas.abap create mode 100644 tasks_gen/train/G1927/reference/i_job_cost.ddls.asddls create mode 100644 tasks_gen/train/G1927/seed/i_job_cost.ddls.asddls create mode 100644 tasks_gen/train/G1927/seed/job.tabl.asabap create mode 100644 tasks_gen/train/G1927/seed/jobl.tabl.asabap create mode 100644 tasks_gen/train/G1927/spec.md create mode 100644 tasks_gen/train/G1927/task.json create mode 100644 tasks_gen/train/G1928/faulty/m0_i_wind_grade.ddls.asddls create mode 100644 tasks_gen/train/G1928/faulty/m1_i_wind_grade.ddls.asddls create mode 100644 tasks_gen/train/G1928/faulty/m2_i_wind_grade.ddls.asddls create mode 100644 tasks_gen/train/G1928/faulty/m3_i_wind_grade.ddls.asddls create mode 100644 tasks_gen/train/G1928/faulty/m4_i_wind_grade.ddls.asddls create mode 100644 tasks_gen/train/G1928/generation.json create mode 100644 tasks_gen/train/G1928/hidden/t31_hidden.clas.abap create mode 100644 tasks_gen/train/G1928/mutation.json create mode 100644 tasks_gen/train/G1928/reference/i_wind_grade.ddls.asddls create mode 100644 tasks_gen/train/G1928/reference/t31_test.clas.abap create mode 100644 tasks_gen/train/G1928/seed/i_wind_grade.ddls.asddls create mode 100644 tasks_gen/train/G1928/seed/turbine.tabl.asabap create mode 100644 tasks_gen/train/G1928/seed/yield.tabl.asabap create mode 100644 tasks_gen/train/G1928/spec.md create mode 100644 tasks_gen/train/G1928/task.json create mode 100644 tasks_gen/train/G1929/faulty/m0_i_star_night.ddls.asddls create mode 100644 tasks_gen/train/G1929/faulty/m1_i_star_night.ddls.asddls create mode 100644 tasks_gen/train/G1929/faulty/m2_i_star_night.ddls.asddls create mode 100644 tasks_gen/train/G1929/faulty/m3_i_star_night.ddls.asddls create mode 100644 tasks_gen/train/G1929/faulty/m4_i_star_night.ddls.asddls create mode 100644 tasks_gen/train/G1929/generation.json create mode 100644 tasks_gen/train/G1929/hidden/t61_hidden.clas.abap create mode 100644 tasks_gen/train/G1929/mutation.json create mode 100644 tasks_gen/train/G1929/reference/i_star_night.ddls.asddls create mode 100644 tasks_gen/train/G1929/reference/t61_test.clas.abap create mode 100644 tasks_gen/train/G1929/seed/dome.tabl.asabap create mode 100644 tasks_gen/train/G1929/seed/i_star_night.ddls.asddls create mode 100644 tasks_gen/train/G1929/seed/night.tabl.asabap create mode 100644 tasks_gen/train/G1929/seed/scope.tabl.asabap create mode 100644 tasks_gen/train/G1929/spec.md create mode 100644 tasks_gen/train/G1929/task.json create mode 100644 tasks_gen/train/G1930/faulty/m0_i_visit_fee.ddls.asddls create mode 100644 tasks_gen/train/G1930/faulty/m1_i_visit_fee.ddls.asddls create mode 100644 tasks_gen/train/G1930/faulty/m2_i_visit_fee.ddls.asddls create mode 100644 tasks_gen/train/G1930/faulty/m3_i_visit_fee.ddls.asddls create mode 100644 tasks_gen/train/G1930/generation.json create mode 100644 tasks_gen/train/G1930/hidden/visit_hidden.clas.abap create mode 100644 tasks_gen/train/G1930/mutation.json create mode 100644 tasks_gen/train/G1930/reference/i_visit_fee.ddls.asddls create mode 100644 tasks_gen/train/G1930/reference/visit_test.clas.abap create mode 100644 tasks_gen/train/G1930/seed/area.tabl.asabap create mode 100644 tasks_gen/train/G1930/seed/i_visit_fee.ddls.asddls create mode 100644 tasks_gen/train/G1930/seed/visit.tabl.asabap create mode 100644 tasks_gen/train/G1930/spec.md create mode 100644 tasks_gen/train/G1930/task.json create mode 100644 tasks_gen/train/G1931/faulty/m0_i_rental_fee.ddls.asddls create mode 100644 tasks_gen/train/G1931/faulty/m1_i_rental_fee.ddls.asddls create mode 100644 tasks_gen/train/G1931/faulty/m2_i_rental_fee.ddls.asddls create mode 100644 tasks_gen/train/G1931/faulty/m3_i_rental_fee.ddls.asddls create mode 100644 tasks_gen/train/G1931/faulty/m4_i_rental_fee.ddls.asddls create mode 100644 tasks_gen/train/G1931/generation.json create mode 100644 tasks_gen/train/G1931/hidden/e_rental_hidden.clas.abap create mode 100644 tasks_gen/train/G1931/mutation.json create mode 100644 tasks_gen/train/G1931/reference/e_rental_test.clas.abap create mode 100644 tasks_gen/train/G1931/reference/i_rental_fee.ddls.asddls create mode 100644 tasks_gen/train/G1931/seed/i_rental_fee.ddls.asddls create mode 100644 tasks_gen/train/G1931/seed/rental.tabl.asabap create mode 100644 tasks_gen/train/G1931/spec.md create mode 100644 tasks_gen/train/G1931/task.json create mode 100644 tasks_gen/train/G1932/faulty/m1_bowl.tabl.asabap create mode 100644 tasks_gen/train/G1932/faulty/m2_bowl.tabl.asabap create mode 100644 tasks_gen/train/G1932/faulty/m3_bowl.tabl.asabap create mode 100644 tasks_gen/train/G1932/faulty/m4_bowl.tabl.asabap create mode 100644 tasks_gen/train/G1932/generation.json create mode 100644 tasks_gen/train/G1932/hidden/bowl_hidden.clas.abap create mode 100644 tasks_gen/train/G1932/mutation.json create mode 100644 tasks_gen/train/G1932/reference/bowl.tabl.asabap create mode 100644 tasks_gen/train/G1932/reference/bowl_test.clas.abap create mode 100644 tasks_gen/train/G1932/spec.md create mode 100644 tasks_gen/train/G1932/task.json create mode 100644 tasks_gen/train/G1933/faulty/m0_if_pyro_order.intf.abap create mode 100644 tasks_gen/train/G1933/faulty/m1_if_pyro_order.intf.abap create mode 100644 tasks_gen/train/G1933/faulty/m2_if_pyro_order.intf.abap create mode 100644 tasks_gen/train/G1933/faulty/m3_if_pyro_order.intf.abap create mode 100644 tasks_gen/train/G1933/faulty/m4_if_pyro_order.intf.abap create mode 100644 tasks_gen/train/G1933/generation.json create mode 100644 tasks_gen/train/G1933/hidden/pyro_hidden.clas.abap create mode 100644 tasks_gen/train/G1933/mutation.json create mode 100644 tasks_gen/train/G1933/reference/if_pyro_order.intf.abap create mode 100644 tasks_gen/train/G1933/reference/pyro_order_test.clas.abap create mode 100644 tasks_gen/train/G1933/spec.md create mode 100644 tasks_gen/train/G1933/task.json create mode 100644 tasks_gen/train/G1934/faulty/m0_pitch.tabl.asabap create mode 100644 tasks_gen/train/G1934/faulty/m1_pitch.tabl.asabap create mode 100644 tasks_gen/train/G1934/faulty/m2_pitch.tabl.asabap create mode 100644 tasks_gen/train/G1934/faulty/m3_pitch.tabl.asabap create mode 100644 tasks_gen/train/G1934/faulty/m4_pitch.tabl.asabap create mode 100644 tasks_gen/train/G1934/generation.json create mode 100644 tasks_gen/train/G1934/hidden/t16_hidden.clas.abap create mode 100644 tasks_gen/train/G1934/mutation.json create mode 100644 tasks_gen/train/G1934/reference/pitch.tabl.asabap create mode 100644 tasks_gen/train/G1934/reference/t16_test.clas.abap create mode 100644 tasks_gen/train/G1934/spec.md create mode 100644 tasks_gen/train/G1934/task.json create mode 100644 tasks_gen/train/G1935/generation.json create mode 100644 tasks_gen/train/G1935/hidden/t02_hidden.clas.abap create mode 100644 tasks_gen/train/G1935/reference/if_mix_recipe.intf.abap create mode 100644 tasks_gen/train/G1935/reference/mix_recipe_test.clas.abap create mode 100644 tasks_gen/train/G1935/spec.md create mode 100644 tasks_gen/train/G1935/task.json create mode 100644 tasks_gen/train/G1936/faulty/m0_syrup.tabl.asabap create mode 100644 tasks_gen/train/G1936/faulty/m2_syrup.tabl.asabap create mode 100644 tasks_gen/train/G1936/faulty/m3_syrup.tabl.asabap create mode 100644 tasks_gen/train/G1936/faulty/m4_syrup.tabl.asabap create mode 100644 tasks_gen/train/G1936/generation.json create mode 100644 tasks_gen/train/G1936/hidden/syrup_hidden.clas.abap create mode 100644 tasks_gen/train/G1936/mutation.json create mode 100644 tasks_gen/train/G1936/reference/syrup.tabl.asabap create mode 100644 tasks_gen/train/G1936/reference/syrup_test.clas.abap create mode 100644 tasks_gen/train/G1936/spec.md create mode 100644 tasks_gen/train/G1936/task.json create mode 100644 tasks_gen/train/G1937/faulty/m0_if_sweep_check.intf.abap create mode 100644 tasks_gen/train/G1937/faulty/m1_chimney_checker.clas.abap create mode 100644 tasks_gen/train/G1937/faulty/m2_if_sweep_check.intf.abap create mode 100644 tasks_gen/train/G1937/faulty/m3_chimney_checker.clas.abap create mode 100644 tasks_gen/train/G1937/faulty/m4_if_sweep_check.intf.abap create mode 100644 tasks_gen/train/G1937/generation.json create mode 100644 tasks_gen/train/G1937/hidden/t02_hidden.clas.abap create mode 100644 tasks_gen/train/G1937/mutation.json create mode 100644 tasks_gen/train/G1937/reference/chimney_checker.clas.abap create mode 100644 tasks_gen/train/G1937/reference/chimney_checker.testclasses.abap create mode 100644 tasks_gen/train/G1937/reference/if_sweep_check.intf.abap create mode 100644 tasks_gen/train/G1937/spec.md create mode 100644 tasks_gen/train/G1937/task.json create mode 100644 tasks_gen/train/G1938/faulty/m0_if_log_plan.intf.abap create mode 100644 tasks_gen/train/G1938/faulty/m1_if_log_plan.intf.abap create mode 100644 tasks_gen/train/G1938/faulty/m2_if_log_plan.intf.abap create mode 100644 tasks_gen/train/G1938/faulty/m3_if_log_plan.intf.abap create mode 100644 tasks_gen/train/G1938/faulty/m4_if_log_plan.intf.abap create mode 100644 tasks_gen/train/G1938/generation.json create mode 100644 tasks_gen/train/G1938/hidden/t02_hidden.clas.abap create mode 100644 tasks_gen/train/G1938/mutation.json create mode 100644 tasks_gen/train/G1938/reference/if_log_plan.intf.abap create mode 100644 tasks_gen/train/G1938/reference/if_log_plan_test.clas.abap create mode 100644 tasks_gen/train/G1938/spec.md create mode 100644 tasks_gen/train/G1938/task.json create mode 100644 tasks_gen/train/G1939/faulty/m0_pluck.tabl.asabap create mode 100644 tasks_gen/train/G1939/faulty/m1_pluck.tabl.asabap create mode 100644 tasks_gen/train/G1939/faulty/m2_pluck.tabl.asabap create mode 100644 tasks_gen/train/G1939/faulty/m4_pluck.tabl.asabap create mode 100644 tasks_gen/train/G1939/generation.json create mode 100644 tasks_gen/train/G1939/hidden/pluck_hidden.clas.abap create mode 100644 tasks_gen/train/G1939/mutation.json create mode 100644 tasks_gen/train/G1939/reference/pluck.tabl.asabap create mode 100644 tasks_gen/train/G1939/reference/pluck_test.clas.abap create mode 100644 tasks_gen/train/G1939/spec.md create mode 100644 tasks_gen/train/G1939/task.json create mode 100644 tasks_gen/train/G1940/faulty/m0_lift_check.clas.abap create mode 100644 tasks_gen/train/G1940/faulty/m2_lift_check.clas.abap create mode 100644 tasks_gen/train/G1940/generation.json create mode 100644 tasks_gen/train/G1940/hidden/lift_hidden.clas.abap create mode 100644 tasks_gen/train/G1940/mutation.json create mode 100644 tasks_gen/train/G1940/reference/cx_crane_error.clas.abap create mode 100644 tasks_gen/train/G1940/reference/lift_check.clas.abap create mode 100644 tasks_gen/train/G1940/reference/lift_check.clas.testclasses.abap create mode 100644 tasks_gen/train/G1940/reference/lift_test.clas.abap create mode 100644 tasks_gen/train/G1940/spec.md create mode 100644 tasks_gen/train/G1940/task.json create mode 100644 tasks_gen/train/G1941/faulty/m0_compost_sum.prog.abap create mode 100644 tasks_gen/train/G1941/faulty/m1_compost_sum.prog.abap create mode 100644 tasks_gen/train/G1941/faulty/m2_compost_sum.prog.abap create mode 100644 tasks_gen/train/G1941/generation.json create mode 100644 tasks_gen/train/G1941/hidden/compost_hidden.clas.abap create mode 100644 tasks_gen/train/G1941/mutation.json create mode 100644 tasks_gen/train/G1941/reference/compost_sum.prog.abap create mode 100644 tasks_gen/train/G1941/seed/compost_seed.clas.abap create mode 100644 tasks_gen/train/G1941/seed/gwaste.tabl.asabap create mode 100644 tasks_gen/train/G1941/spec.md create mode 100644 tasks_gen/train/G1941/task.json create mode 100644 tasks_gen/train/G1942/faulty/m0_repair_list.prog.abap create mode 100644 tasks_gen/train/G1942/faulty/m1_repair_list.prog.abap create mode 100644 tasks_gen/train/G1942/faulty/m2_repair_list.prog.abap create mode 100644 tasks_gen/train/G1942/faulty/m3_repair_list.prog.abap create mode 100644 tasks_gen/train/G1942/generation.json create mode 100644 tasks_gen/train/G1942/hidden/bike_hidden.clas.abap create mode 100644 tasks_gen/train/G1942/mutation.json create mode 100644 tasks_gen/train/G1942/reference/repair_list.prog.abap create mode 100644 tasks_gen/train/G1942/seed/bike_seed.clas.abap create mode 100644 tasks_gen/train/G1942/seed/jobhdr.tabl.asabap create mode 100644 tasks_gen/train/G1942/seed/jobitm.tabl.asabap create mode 100644 tasks_gen/train/G1942/seed/mech.tabl.asabap create mode 100644 tasks_gen/train/G1942/spec.md create mode 100644 tasks_gen/train/G1942/task.json create mode 100644 tasks_gen/train/G1943/generation.json create mode 100644 tasks_gen/train/G1943/hidden/game_stru_hidden.clas.abap create mode 100644 tasks_gen/train/G1943/reference/edit_stamp.stru.asabap create mode 100644 tasks_gen/train/G1943/reference/game_round.stru.asabap create mode 100644 tasks_gen/train/G1943/reference/game_stru_test.clas.abap create mode 100644 tasks_gen/train/G1943/spec.md create mode 100644 tasks_gen/train/G1943/task.json create mode 100644 tasks_gen/train/G1944/faulty/m1_sharp_sum.prog.abap create mode 100644 tasks_gen/train/G1944/faulty/m2_sharp_sum.prog.abap create mode 100644 tasks_gen/train/G1944/generation.json create mode 100644 tasks_gen/train/G1944/hidden/t15_hidden.clas.abap create mode 100644 tasks_gen/train/G1944/mutation.json create mode 100644 tasks_gen/train/G1944/reference/sharp_sum.prog.abap create mode 100644 tasks_gen/train/G1944/seed/kntype.tabl.asabap create mode 100644 tasks_gen/train/G1944/seed/sharpen.tabl.asabap create mode 100644 tasks_gen/train/G1944/seed/t15_seed.clas.abap create mode 100644 tasks_gen/train/G1944/spec.md create mode 100644 tasks_gen/train/G1944/task.json create mode 100644 tasks_gen/train/G1945/generation.json create mode 100644 tasks_gen/train/G1945/hidden/t21_hidden.clas.abap create mode 100644 tasks_gen/train/G1945/mutation.json create mode 100644 tasks_gen/train/G1945/reference/cx_scaf_order.clas.abap create mode 100644 tasks_gen/train/G1945/reference/t21_test.clas.abap create mode 100644 tasks_gen/train/G1945/spec.md create mode 100644 tasks_gen/train/G1945/task.json create mode 100644 tasks_gen/train/G1946/faulty/m0_roast_base.stru.asabap create mode 100644 tasks_gen/train/G1946/faulty/m1_roast_result.stru.asabap create mode 100644 tasks_gen/train/G1946/faulty/m2_roast_base.stru.asabap create mode 100644 tasks_gen/train/G1946/faulty/m3_roast_result.stru.asabap create mode 100644 tasks_gen/train/G1946/faulty/m4_roast_base.stru.asabap create mode 100644 tasks_gen/train/G1946/generation.json create mode 100644 tasks_gen/train/G1946/hidden/roast_hidden.clas.abap create mode 100644 tasks_gen/train/G1946/mutation.json create mode 100644 tasks_gen/train/G1946/reference/roast_base.stru.asabap create mode 100644 tasks_gen/train/G1946/reference/roast_result.stru.asabap create mode 100644 tasks_gen/train/G1946/reference/roast_test.clas.abap create mode 100644 tasks_gen/train/G1946/seed/roast.tabl.asabap create mode 100644 tasks_gen/train/G1946/spec.md create mode 100644 tasks_gen/train/G1946/task.json create mode 100644 tasks_gen/train/G1947/faulty/m0_svc_base.ddls.asddls create mode 100644 tasks_gen/train/G1947/faulty/m1_svc_job.ddls.asddls create mode 100644 tasks_gen/train/G1947/faulty/m2_svc_base.ddls.asddls create mode 100644 tasks_gen/train/G1947/faulty/m3_svc_job.ddls.asddls create mode 100644 tasks_gen/train/G1947/faulty/m4_svc_base.ddls.asddls create mode 100644 tasks_gen/train/G1947/generation.json create mode 100644 tasks_gen/train/G1947/hidden/svc_job_hidden.clas.abap create mode 100644 tasks_gen/train/G1947/mutation.json create mode 100644 tasks_gen/train/G1947/reference/svc_base.ddls.asddls create mode 100644 tasks_gen/train/G1947/reference/svc_job.ddls.asddls create mode 100644 tasks_gen/train/G1947/reference/svc_job_test.clas.abap create mode 100644 tasks_gen/train/G1947/spec.md create mode 100644 tasks_gen/train/G1947/task.json create mode 100644 tasks_gen/train/G1948/generation.json create mode 100644 tasks_gen/train/G1948/hidden/t_arc_hidden.clas.abap create mode 100644 tasks_gen/train/G1948/mutation.json create mode 100644 tasks_gen/train/G1948/reference/cx_bow_check.clas.abap create mode 100644 tasks_gen/train/G1948/reference/t_arc_msg.clas.abap create mode 100644 tasks_gen/train/G1948/spec.md create mode 100644 tasks_gen/train/G1948/task.json create mode 100644 tasks_gen/train/G1949/faulty/m0_i_hawk_site.ddls.asddls create mode 100644 tasks_gen/train/G1949/faulty/m1_i_hawk_site.ddls.asddls create mode 100644 tasks_gen/train/G1949/faulty/m2_i_hawk_site.ddls.asddls create mode 100644 tasks_gen/train/G1949/faulty/m3_i_hawk_site.ddls.asddls create mode 100644 tasks_gen/train/G1949/generation.json create mode 100644 tasks_gen/train/G1949/hidden/t42_hidden.clas.abap create mode 100644 tasks_gen/train/G1949/mutation.json create mode 100644 tasks_gen/train/G1949/reference/i_hawk_site.ddls.asddls create mode 100644 tasks_gen/train/G1949/reference/t42_test.clas.abap create mode 100644 tasks_gen/train/G1949/seed/falcon.tabl.asabap create mode 100644 tasks_gen/train/G1949/spec.md create mode 100644 tasks_gen/train/G1949/task.json create mode 100644 tasks_gen/train/G1950/faulty/m0_i_product_quality.ddls.asddls create mode 100644 tasks_gen/train/G1950/faulty/m1_i_product_quality.ddls.asddls create mode 100644 tasks_gen/train/G1950/faulty/m2_i_product_quality.ddls.asddls create mode 100644 tasks_gen/train/G1950/faulty/m3_i_product_quality.ddls.asddls create mode 100644 tasks_gen/train/G1950/faulty/m4_i_product_quality.ddls.asddls create mode 100644 tasks_gen/train/G1950/generation.json create mode 100644 tasks_gen/train/G1950/hidden/t41_hidden.clas.abap create mode 100644 tasks_gen/train/G1950/mutation.json create mode 100644 tasks_gen/train/G1950/reference/i_product_quality.ddls.asddls create mode 100644 tasks_gen/train/G1950/reference/t41_test.clas.abap create mode 100644 tasks_gen/train/G1950/seed/batch.tabl.asabap create mode 100644 tasks_gen/train/G1950/seed/i_batch_quality.ddls.asddls create mode 100644 tasks_gen/train/G1950/spec.md create mode 100644 tasks_gen/train/G1950/task.json create mode 100644 tasks_gen/train/G1951/generation.json create mode 100644 tasks_gen/train/G1951/hidden/tenancy_hidden.clas.abap create mode 100644 tasks_gen/train/G1951/reference/if_tenancy_check.intf.abap create mode 100644 tasks_gen/train/G1951/reference/tenancy_checker.clas.abap create mode 100644 tasks_gen/train/G1951/reference/tenancy_checker.testclasses.abap create mode 100644 tasks_gen/train/G1951/spec.md create mode 100644 tasks_gen/train/G1951/task.json create mode 100644 tasks_gen/train/G1952/generation.json create mode 100644 tasks_gen/train/G1952/hidden/t16_hidden.clas.abap create mode 100644 tasks_gen/train/G1952/reference/sess.tabl.asabap create mode 100644 tasks_gen/train/G1952/reference/t16_test.clas.abap create mode 100644 tasks_gen/train/G1952/spec.md create mode 100644 tasks_gen/train/G1952/task.json create mode 100644 tasks_gen/train/G1953/generation.json create mode 100644 tasks_gen/train/G1953/hidden/t44_hidden.clas.abap create mode 100644 tasks_gen/train/G1953/mutation.json create mode 100644 tasks_gen/train/G1953/reference/if_piano_tuning.intf.abap create mode 100644 tasks_gen/train/G1953/reference/piano_tuning_test.clas.abap create mode 100644 tasks_gen/train/G1953/spec.md create mode 100644 tasks_gen/train/G1953/task.json create mode 100644 tasks_gen/train/G1954/faulty/m0_if_sail_repair.intf.abap create mode 100644 tasks_gen/train/G1954/faulty/m1_if_sail_repair.intf.abap create mode 100644 tasks_gen/train/G1954/faulty/m2_if_sail_repair.intf.abap create mode 100644 tasks_gen/train/G1954/faulty/m3_if_sail_repair.intf.abap create mode 100644 tasks_gen/train/G1954/faulty/m4_if_sail_repair.intf.abap create mode 100644 tasks_gen/train/G1954/generation.json create mode 100644 tasks_gen/train/G1954/hidden/t02_hidden.clas.abap create mode 100644 tasks_gen/train/G1954/mutation.json create mode 100644 tasks_gen/train/G1954/reference/cl_sail_repair_test.clas.abap create mode 100644 tasks_gen/train/G1954/reference/if_sail_repair.intf.abap create mode 100644 tasks_gen/train/G1954/spec.md create mode 100644 tasks_gen/train/G1954/task.json create mode 100644 tasks_gen/train/G1955/faulty/m0_well.tabl.asabap create mode 100644 tasks_gen/train/G1955/faulty/m1_well.tabl.asabap create mode 100644 tasks_gen/train/G1955/faulty/m2_well.tabl.asabap create mode 100644 tasks_gen/train/G1955/faulty/m3_well.tabl.asabap create mode 100644 tasks_gen/train/G1955/faulty/m4_well.tabl.asabap create mode 100644 tasks_gen/train/G1955/generation.json create mode 100644 tasks_gen/train/G1955/hidden/well_hidden.clas.abap create mode 100644 tasks_gen/train/G1955/mutation.json create mode 100644 tasks_gen/train/G1955/reference/well.tabl.asabap create mode 100644 tasks_gen/train/G1955/reference/well_test.clas.abap create mode 100644 tasks_gen/train/G1955/spec.md create mode 100644 tasks_gen/train/G1955/task.json create mode 100644 tasks_gen/train/G1956/generation.json create mode 100644 tasks_gen/train/G1956/hidden/cobbler_hidden.clas.abap create mode 100644 tasks_gen/train/G1956/reference/cobbler_test.clas.abap create mode 100644 tasks_gen/train/G1956/reference/if_cobbler.intf.abap create mode 100644 tasks_gen/train/G1956/spec.md create mode 100644 tasks_gen/train/G1956/task.json create mode 100644 tasks_gen/train/G1957/faulty/m0_winjob.tabl.asabap create mode 100644 tasks_gen/train/G1957/faulty/m1_winjob.tabl.asabap create mode 100644 tasks_gen/train/G1957/faulty/m2_winjob.tabl.asabap create mode 100644 tasks_gen/train/G1957/faulty/m3_winjob.tabl.asabap create mode 100644 tasks_gen/train/G1957/faulty/m4_winjob.tabl.asabap create mode 100644 tasks_gen/train/G1957/generation.json create mode 100644 tasks_gen/train/G1957/hidden/t61_hidden.clas.abap create mode 100644 tasks_gen/train/G1957/mutation.json create mode 100644 tasks_gen/train/G1957/reference/t61_test.clas.abap create mode 100644 tasks_gen/train/G1957/reference/winjob.tabl.asabap create mode 100644 tasks_gen/train/G1957/spec.md create mode 100644 tasks_gen/train/G1957/task.json create mode 100644 tasks_gen/train/_logs/G1910.json create mode 100644 tasks_gen/train/_logs/G1911.json create mode 100644 tasks_gen/train/_logs/G1912.json create mode 100644 tasks_gen/train/_logs/G1913.json create mode 100644 tasks_gen/train/_logs/G1914.json create mode 100644 tasks_gen/train/_logs/G1915.json create mode 100644 tasks_gen/train/_logs/G1916.json create mode 100644 tasks_gen/train/_logs/G1917.json create mode 100644 tasks_gen/train/_logs/G1918.json create mode 100644 tasks_gen/train/_logs/G1919.json create mode 100644 tasks_gen/train/_logs/G1920.json create mode 100644 tasks_gen/train/_logs/G1921.json create mode 100644 tasks_gen/train/_logs/G1922.json create mode 100644 tasks_gen/train/_logs/G1923.json create mode 100644 tasks_gen/train/_logs/G1924.json create mode 100644 tasks_gen/train/_logs/G1925.json create mode 100644 tasks_gen/train/_logs/G1926.json create mode 100644 tasks_gen/train/_logs/G1927.json create mode 100644 tasks_gen/train/_logs/G1928.json create mode 100644 tasks_gen/train/_logs/G1929.json create mode 100644 tasks_gen/train/_logs/G1930.json create mode 100644 tasks_gen/train/_logs/G1931.json create mode 100644 tasks_gen/train/_logs/G1932.json create mode 100644 tasks_gen/train/_logs/G1933.json create mode 100644 tasks_gen/train/_logs/G1934.json create mode 100644 tasks_gen/train/_logs/G1935.json create mode 100644 tasks_gen/train/_logs/G1936.json create mode 100644 tasks_gen/train/_logs/G1937.json create mode 100644 tasks_gen/train/_logs/G1938.json create mode 100644 tasks_gen/train/_logs/G1939.json create mode 100644 tasks_gen/train/_logs/G1940.json create mode 100644 tasks_gen/train/_logs/G1941.json create mode 100644 tasks_gen/train/_logs/G1942.json create mode 100644 tasks_gen/train/_logs/G1943.json create mode 100644 tasks_gen/train/_logs/G1944.json create mode 100644 tasks_gen/train/_logs/G1945.json create mode 100644 tasks_gen/train/_logs/G1946.json create mode 100644 tasks_gen/train/_logs/G1947.json create mode 100644 tasks_gen/train/_logs/G1948.json create mode 100644 tasks_gen/train/_logs/G1949.json create mode 100644 tasks_gen/train/_logs/G1950.json create mode 100644 tasks_gen/train/_logs/G1951.json create mode 100644 tasks_gen/train/_logs/G1952.json create mode 100644 tasks_gen/train/_logs/G1953.json create mode 100644 tasks_gen/train/_logs/G1954.json create mode 100644 tasks_gen/train/_logs/G1955.json create mode 100644 tasks_gen/train/_logs/G1956.json create mode 100644 tasks_gen/train/_logs/G1957.json diff --git a/tasks_gen/train/G1910/faulty/m0_cider.tabl.asabap b/tasks_gen/train/G1910/faulty/m0_cider.tabl.asabap new file mode 100644 index 0000000..8cedab0 --- /dev/null +++ b/tasks_gen/train/G1910/faulty/m0_cider.tabl.asabap @@ -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); +} diff --git a/tasks_gen/train/G1910/faulty/m1_cider.tabl.asabap b/tasks_gen/train/G1910/faulty/m1_cider.tabl.asabap new file mode 100644 index 0000000..5fc257c --- /dev/null +++ b/tasks_gen/train/G1910/faulty/m1_cider.tabl.asabap @@ -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); +} diff --git a/tasks_gen/train/G1910/faulty/m2_cider.tabl.asabap b/tasks_gen/train/G1910/faulty/m2_cider.tabl.asabap new file mode 100644 index 0000000..84a53fd --- /dev/null +++ b/tasks_gen/train/G1910/faulty/m2_cider.tabl.asabap @@ -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); +} diff --git a/tasks_gen/train/G1910/faulty/m3_cider.tabl.asabap b/tasks_gen/train/G1910/faulty/m3_cider.tabl.asabap new file mode 100644 index 0000000..92a5ff4 --- /dev/null +++ b/tasks_gen/train/G1910/faulty/m3_cider.tabl.asabap @@ -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); +} diff --git a/tasks_gen/train/G1910/faulty/m4_cider.tabl.asabap b/tasks_gen/train/G1910/faulty/m4_cider.tabl.asabap new file mode 100644 index 0000000..78d3f6e --- /dev/null +++ b/tasks_gen/train/G1910/faulty/m4_cider.tabl.asabap @@ -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); +} diff --git a/tasks_gen/train/G1910/generation.json b/tasks_gen/train/G1910/generation.json new file mode 100644 index 0000000..7712276 --- /dev/null +++ b/tasks_gen/train/G1910/generation.json @@ -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 +} \ No newline at end of file diff --git a/tasks_gen/train/G1910/hidden/cider_hidden.clas.abap b/tasks_gen/train/G1910/hidden/cider_hidden.clas.abap new file mode 100644 index 0000000..bf8eaec --- /dev/null +++ b/tasks_gen/train/G1910/hidden/cider_hidden.clas.abap @@ -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(). + IF sy-subrc = 0. + cl_abap_unit_assert=>assert_equals( exp = 'X' act = + 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. diff --git a/tasks_gen/train/G1910/mutation.json b/tasks_gen/train/G1910/mutation.json new file mode 100644 index 0000000..af0ed20 --- /dev/null +++ b/tasks_gen/train/G1910/mutation.json @@ -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 +} \ No newline at end of file diff --git a/tasks_gen/train/G1910/reference/cider.tabl.asabap b/tasks_gen/train/G1910/reference/cider.tabl.asabap new file mode 100644 index 0000000..8e5efec --- /dev/null +++ b/tasks_gen/train/G1910/reference/cider.tabl.asabap @@ -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); +} diff --git a/tasks_gen/train/G1910/reference/cider_test.clas.abap b/tasks_gen/train/G1910/reference/cider_test.clas.abap new file mode 100644 index 0000000..7ec7638 --- /dev/null +++ b/tasks_gen/train/G1910/reference/cider_test.clas.abap @@ -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. diff --git a/tasks_gen/train/G1910/spec.md b/tasks_gen/train/G1910/spec.md new file mode 100644 index 0000000..107c6f1 --- /dev/null +++ b/tasks_gen/train/G1910/spec.md @@ -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. diff --git a/tasks_gen/train/G1910/task.json b/tasks_gen/train/G1910/task.json new file mode 100644 index 0000000..efde49f --- /dev/null +++ b/tasks_gen/train/G1910/task.json @@ -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": [] +} \ No newline at end of file diff --git a/tasks_gen/train/G1911/faulty/m0_hire.tabl.asabap b/tasks_gen/train/G1911/faulty/m0_hire.tabl.asabap new file mode 100644 index 0000000..ca522ca --- /dev/null +++ b/tasks_gen/train/G1911/faulty/m0_hire.tabl.asabap @@ -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); +} diff --git a/tasks_gen/train/G1911/faulty/m1_hire.tabl.asabap b/tasks_gen/train/G1911/faulty/m1_hire.tabl.asabap new file mode 100644 index 0000000..4ad8d69 --- /dev/null +++ b/tasks_gen/train/G1911/faulty/m1_hire.tabl.asabap @@ -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); +} diff --git a/tasks_gen/train/G1911/faulty/m2_hire.tabl.asabap b/tasks_gen/train/G1911/faulty/m2_hire.tabl.asabap new file mode 100644 index 0000000..4a113a6 --- /dev/null +++ b/tasks_gen/train/G1911/faulty/m2_hire.tabl.asabap @@ -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); +} diff --git a/tasks_gen/train/G1911/faulty/m3_hire.tabl.asabap b/tasks_gen/train/G1911/faulty/m3_hire.tabl.asabap new file mode 100644 index 0000000..ec1680c --- /dev/null +++ b/tasks_gen/train/G1911/faulty/m3_hire.tabl.asabap @@ -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); +} diff --git a/tasks_gen/train/G1911/faulty/m4_hire.tabl.asabap b/tasks_gen/train/G1911/faulty/m4_hire.tabl.asabap new file mode 100644 index 0000000..05f5acd --- /dev/null +++ b/tasks_gen/train/G1911/faulty/m4_hire.tabl.asabap @@ -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); +} diff --git a/tasks_gen/train/G1911/generation.json b/tasks_gen/train/G1911/generation.json new file mode 100644 index 0000000..5e60ed4 --- /dev/null +++ b/tasks_gen/train/G1911/generation.json @@ -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 +} \ No newline at end of file diff --git a/tasks_gen/train/G1911/hidden/hire_hidden.clas.abap b/tasks_gen/train/G1911/hidden/hire_hidden.clas.abap new file mode 100644 index 0000000..159cebd --- /dev/null +++ b/tasks_gen/train/G1911/hidden/hire_hidden.clas.abap @@ -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(). + IF sy-subrc <> 0. + ASSIGN COMPONENT 'NOT_NULL' OF STRUCTURE ls_field TO . + ENDIF. + IF sy-subrc = 0. + IF = '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(). + IF sy-subrc <> 0. + RETURN. + ENDIF. + cl_abap_unit_assert=>assert_equals( exp = 'X' act = ). + 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. diff --git a/tasks_gen/train/G1911/mutation.json b/tasks_gen/train/G1911/mutation.json new file mode 100644 index 0000000..61e8c10 --- /dev/null +++ b/tasks_gen/train/G1911/mutation.json @@ -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 +} \ No newline at end of file diff --git a/tasks_gen/train/G1911/reference/hire.tabl.asabap b/tasks_gen/train/G1911/reference/hire.tabl.asabap new file mode 100644 index 0000000..7250299 --- /dev/null +++ b/tasks_gen/train/G1911/reference/hire.tabl.asabap @@ -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); +} diff --git a/tasks_gen/train/G1911/reference/hire_test.clas.abap b/tasks_gen/train/G1911/reference/hire_test.clas.abap new file mode 100644 index 0000000..7284986 --- /dev/null +++ b/tasks_gen/train/G1911/reference/hire_test.clas.abap @@ -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. diff --git a/tasks_gen/train/G1911/spec.md b/tasks_gen/train/G1911/spec.md new file mode 100644 index 0000000..4b3fe1c --- /dev/null +++ b/tasks_gen/train/G1911/spec.md @@ -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. diff --git a/tasks_gen/train/G1911/task.json b/tasks_gen/train/G1911/task.json new file mode 100644 index 0000000..b3b0da3 --- /dev/null +++ b/tasks_gen/train/G1911/task.json @@ -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": [] +} \ No newline at end of file diff --git a/tasks_gen/train/G1912/faulty/m0_svcjob.tabl.asabap b/tasks_gen/train/G1912/faulty/m0_svcjob.tabl.asabap new file mode 100644 index 0000000..0e7e15f --- /dev/null +++ b/tasks_gen/train/G1912/faulty/m0_svcjob.tabl.asabap @@ -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; +} diff --git a/tasks_gen/train/G1912/faulty/m1_svcjob.tabl.asabap b/tasks_gen/train/G1912/faulty/m1_svcjob.tabl.asabap new file mode 100644 index 0000000..2d68cd5 --- /dev/null +++ b/tasks_gen/train/G1912/faulty/m1_svcjob.tabl.asabap @@ -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; +} diff --git a/tasks_gen/train/G1912/faulty/m2_svcjob.tabl.asabap b/tasks_gen/train/G1912/faulty/m2_svcjob.tabl.asabap new file mode 100644 index 0000000..c8adab1 --- /dev/null +++ b/tasks_gen/train/G1912/faulty/m2_svcjob.tabl.asabap @@ -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; +} diff --git a/tasks_gen/train/G1912/faulty/m3_svcjob.tabl.asabap b/tasks_gen/train/G1912/faulty/m3_svcjob.tabl.asabap new file mode 100644 index 0000000..4581178 --- /dev/null +++ b/tasks_gen/train/G1912/faulty/m3_svcjob.tabl.asabap @@ -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; +} diff --git a/tasks_gen/train/G1912/faulty/m4_svcjob.tabl.asabap b/tasks_gen/train/G1912/faulty/m4_svcjob.tabl.asabap new file mode 100644 index 0000000..90da9ea --- /dev/null +++ b/tasks_gen/train/G1912/faulty/m4_svcjob.tabl.asabap @@ -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; +} diff --git a/tasks_gen/train/G1912/generation.json b/tasks_gen/train/G1912/generation.json new file mode 100644 index 0000000..7f38038 --- /dev/null +++ b/tasks_gen/train/G1912/generation.json @@ -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 +} \ No newline at end of file diff --git a/tasks_gen/train/G1912/hidden/svcjob_hidden.clas.abap b/tasks_gen/train/G1912/hidden/svcjob_hidden.clas.abap new file mode 100644 index 0000000..07b786f --- /dev/null +++ b/tasks_gen/train/G1912/hidden/svcjob_hidden.clas.abap @@ -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. diff --git a/tasks_gen/train/G1912/mutation.json b/tasks_gen/train/G1912/mutation.json new file mode 100644 index 0000000..fa915f7 --- /dev/null +++ b/tasks_gen/train/G1912/mutation.json @@ -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 +} \ No newline at end of file diff --git a/tasks_gen/train/G1912/reference/svcjob.tabl.asabap b/tasks_gen/train/G1912/reference/svcjob.tabl.asabap new file mode 100644 index 0000000..1505595 --- /dev/null +++ b/tasks_gen/train/G1912/reference/svcjob.tabl.asabap @@ -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; +} diff --git a/tasks_gen/train/G1912/reference/svcjob_test.clas.abap b/tasks_gen/train/G1912/reference/svcjob_test.clas.abap new file mode 100644 index 0000000..bf186bd --- /dev/null +++ b/tasks_gen/train/G1912/reference/svcjob_test.clas.abap @@ -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. diff --git a/tasks_gen/train/G1912/spec.md b/tasks_gen/train/G1912/spec.md new file mode 100644 index 0000000..10e5744 --- /dev/null +++ b/tasks_gen/train/G1912/spec.md @@ -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. diff --git a/tasks_gen/train/G1912/task.json b/tasks_gen/train/G1912/task.json new file mode 100644 index 0000000..cbb20f7 --- /dev/null +++ b/tasks_gen/train/G1912/task.json @@ -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": [] +} \ No newline at end of file diff --git a/tasks_gen/train/G1913/faulty/m0_if_laundry_fee.intf.abap b/tasks_gen/train/G1913/faulty/m0_if_laundry_fee.intf.abap new file mode 100644 index 0000000..4707bb2 --- /dev/null +++ b/tasks_gen/train/G1913/faulty/m0_if_laundry_fee.intf.abap @@ -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. diff --git a/tasks_gen/train/G1913/faulty/m1_if_laundry_fee.intf.abap b/tasks_gen/train/G1913/faulty/m1_if_laundry_fee.intf.abap new file mode 100644 index 0000000..000c4f0 --- /dev/null +++ b/tasks_gen/train/G1913/faulty/m1_if_laundry_fee.intf.abap @@ -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. diff --git a/tasks_gen/train/G1913/faulty/m2_if_laundry_fee.intf.abap b/tasks_gen/train/G1913/faulty/m2_if_laundry_fee.intf.abap new file mode 100644 index 0000000..5f266a6 --- /dev/null +++ b/tasks_gen/train/G1913/faulty/m2_if_laundry_fee.intf.abap @@ -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. diff --git a/tasks_gen/train/G1913/faulty/m3_if_laundry_fee.intf.abap b/tasks_gen/train/G1913/faulty/m3_if_laundry_fee.intf.abap new file mode 100644 index 0000000..223148d --- /dev/null +++ b/tasks_gen/train/G1913/faulty/m3_if_laundry_fee.intf.abap @@ -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. diff --git a/tasks_gen/train/G1913/faulty/m4_if_laundry_fee.intf.abap b/tasks_gen/train/G1913/faulty/m4_if_laundry_fee.intf.abap new file mode 100644 index 0000000..1c2ad53 --- /dev/null +++ b/tasks_gen/train/G1913/faulty/m4_if_laundry_fee.intf.abap @@ -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. diff --git a/tasks_gen/train/G1913/generation.json b/tasks_gen/train/G1913/generation.json new file mode 100644 index 0000000..2440fa4 --- /dev/null +++ b/tasks_gen/train/G1913/generation.json @@ -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 +} \ No newline at end of file diff --git a/tasks_gen/train/G1913/hidden/laundry_hidden.clas.abap b/tasks_gen/train/G1913/hidden/laundry_hidden.clas.abap new file mode 100644 index 0000000..4904ad6 --- /dev/null +++ b/tasks_gen/train/G1913/hidden/laundry_hidden.clas.abap @@ -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. diff --git a/tasks_gen/train/G1913/mutation.json b/tasks_gen/train/G1913/mutation.json new file mode 100644 index 0000000..b748d90 --- /dev/null +++ b/tasks_gen/train/G1913/mutation.json @@ -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 +} \ No newline at end of file diff --git a/tasks_gen/train/G1913/reference/if_laundry_fee.intf.abap b/tasks_gen/train/G1913/reference/if_laundry_fee.intf.abap new file mode 100644 index 0000000..4a9d7b8 --- /dev/null +++ b/tasks_gen/train/G1913/reference/if_laundry_fee.intf.abap @@ -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. diff --git a/tasks_gen/train/G1913/reference/laundry_fee_test.clas.abap b/tasks_gen/train/G1913/reference/laundry_fee_test.clas.abap new file mode 100644 index 0000000..da38ce9 --- /dev/null +++ b/tasks_gen/train/G1913/reference/laundry_fee_test.clas.abap @@ -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. diff --git a/tasks_gen/train/G1913/spec.md b/tasks_gen/train/G1913/spec.md new file mode 100644 index 0000000..6f7b429 --- /dev/null +++ b/tasks_gen/train/G1913/spec.md @@ -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. diff --git a/tasks_gen/train/G1913/task.json b/tasks_gen/train/G1913/task.json new file mode 100644 index 0000000..f935306 --- /dev/null +++ b/tasks_gen/train/G1913/task.json @@ -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" + ] +} \ No newline at end of file diff --git a/tasks_gen/train/G1914/generation.json b/tasks_gen/train/G1914/generation.json new file mode 100644 index 0000000..e07260c --- /dev/null +++ b/tasks_gen/train/G1914/generation.json @@ -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 +} \ No newline at end of file diff --git a/tasks_gen/train/G1914/hidden/t58_hidden.clas.abap b/tasks_gen/train/G1914/hidden/t58_hidden.clas.abap new file mode 100644 index 0000000..5fe151c --- /dev/null +++ b/tasks_gen/train/G1914/hidden/t58_hidden.clas.abap @@ -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. diff --git a/tasks_gen/train/G1914/reference/if_rope_check.intf.abap b/tasks_gen/train/G1914/reference/if_rope_check.intf.abap new file mode 100644 index 0000000..dcfb3ff --- /dev/null +++ b/tasks_gen/train/G1914/reference/if_rope_check.intf.abap @@ -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. diff --git a/tasks_gen/train/G1914/reference/rope_check_test.clas.abap b/tasks_gen/train/G1914/reference/rope_check_test.clas.abap new file mode 100644 index 0000000..c8b057c --- /dev/null +++ b/tasks_gen/train/G1914/reference/rope_check_test.clas.abap @@ -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. diff --git a/tasks_gen/train/G1914/reference/rope_checker.clas.abap b/tasks_gen/train/G1914/reference/rope_checker.clas.abap new file mode 100644 index 0000000..5f49969 --- /dev/null +++ b/tasks_gen/train/G1914/reference/rope_checker.clas.abap @@ -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(). + IF sy-subrc <> 0. + rv_reason = {{p}}if_rope_check=>c_reason-ticket. + RETURN. + ENDIF. + + IF iv_age < -min_age. + rv_reason = {{p}}if_rope_check=>c_reason-age. + RETURN. + ENDIF. + + IF iv_logged_hours < -min_hours. + rv_reason = {{p}}if_rope_check=>c_reason-hours. + RETURN. + ENDIF. + + IF iv_height_m > -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. diff --git a/tasks_gen/train/G1914/reference/rope_checker.testclasses.abap b/tasks_gen/train/G1914/reference/rope_checker.testclasses.abap new file mode 100644 index 0000000..fc2e2cb --- /dev/null +++ b/tasks_gen/train/G1914/reference/rope_checker.testclasses.abap @@ -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. diff --git a/tasks_gen/train/G1914/spec.md b/tasks_gen/train/G1914/spec.md new file mode 100644 index 0000000..374d95a --- /dev/null +++ b/tasks_gen/train/G1914/spec.md @@ -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. diff --git a/tasks_gen/train/G1914/task.json b/tasks_gen/train/G1914/task.json new file mode 100644 index 0000000..5828e7c --- /dev/null +++ b/tasks_gen/train/G1914/task.json @@ -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" + ] +} \ No newline at end of file diff --git a/tasks_gen/train/G1915/faulty/m0_grh.tabl.asabap b/tasks_gen/train/G1915/faulty/m0_grh.tabl.asabap new file mode 100644 index 0000000..5c0ca21 --- /dev/null +++ b/tasks_gen/train/G1915/faulty/m0_grh.tabl.asabap @@ -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); +} diff --git a/tasks_gen/train/G1915/faulty/m1_grh.tabl.asabap b/tasks_gen/train/G1915/faulty/m1_grh.tabl.asabap new file mode 100644 index 0000000..5514e0c --- /dev/null +++ b/tasks_gen/train/G1915/faulty/m1_grh.tabl.asabap @@ -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); +} diff --git a/tasks_gen/train/G1915/faulty/m2_grh.tabl.asabap b/tasks_gen/train/G1915/faulty/m2_grh.tabl.asabap new file mode 100644 index 0000000..d8fe2e9 --- /dev/null +++ b/tasks_gen/train/G1915/faulty/m2_grh.tabl.asabap @@ -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); +} diff --git a/tasks_gen/train/G1915/faulty/m3_grh.tabl.asabap b/tasks_gen/train/G1915/faulty/m3_grh.tabl.asabap new file mode 100644 index 0000000..e7d1931 --- /dev/null +++ b/tasks_gen/train/G1915/faulty/m3_grh.tabl.asabap @@ -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); +} diff --git a/tasks_gen/train/G1915/faulty/m4_grh.tabl.asabap b/tasks_gen/train/G1915/faulty/m4_grh.tabl.asabap new file mode 100644 index 0000000..a90fbea --- /dev/null +++ b/tasks_gen/train/G1915/faulty/m4_grh.tabl.asabap @@ -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); +} diff --git a/tasks_gen/train/G1915/generation.json b/tasks_gen/train/G1915/generation.json new file mode 100644 index 0000000..45b3532 --- /dev/null +++ b/tasks_gen/train/G1915/generation.json @@ -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 +} \ No newline at end of file diff --git a/tasks_gen/train/G1915/hidden/grh_hidden.clas.abap b/tasks_gen/train/G1915/hidden/grh_hidden.clas.abap new file mode 100644 index 0000000..aea718f --- /dev/null +++ b/tasks_gen/train/G1915/hidden/grh_hidden.clas.abap @@ -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. diff --git a/tasks_gen/train/G1915/mutation.json b/tasks_gen/train/G1915/mutation.json new file mode 100644 index 0000000..21211e7 --- /dev/null +++ b/tasks_gen/train/G1915/mutation.json @@ -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 +} \ No newline at end of file diff --git a/tasks_gen/train/G1915/reference/grh.tabl.asabap b/tasks_gen/train/G1915/reference/grh.tabl.asabap new file mode 100644 index 0000000..07913ed --- /dev/null +++ b/tasks_gen/train/G1915/reference/grh.tabl.asabap @@ -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); +} diff --git a/tasks_gen/train/G1915/reference/grh_test.clas.abap b/tasks_gen/train/G1915/reference/grh_test.clas.abap new file mode 100644 index 0000000..67d8dc4 --- /dev/null +++ b/tasks_gen/train/G1915/reference/grh_test.clas.abap @@ -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. diff --git a/tasks_gen/train/G1915/spec.md b/tasks_gen/train/G1915/spec.md new file mode 100644 index 0000000..5d7946f --- /dev/null +++ b/tasks_gen/train/G1915/spec.md @@ -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. diff --git a/tasks_gen/train/G1915/task.json b/tasks_gen/train/G1915/task.json new file mode 100644 index 0000000..aa02ee4 --- /dev/null +++ b/tasks_gen/train/G1915/task.json @@ -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": [] +} \ No newline at end of file diff --git a/tasks_gen/train/G1916/generation.json b/tasks_gen/train/G1916/generation.json new file mode 100644 index 0000000..b81e8c1 --- /dev/null +++ b/tasks_gen/train/G1916/generation.json @@ -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 +} \ No newline at end of file diff --git a/tasks_gen/train/G1916/hidden/solar_check_hidden.clas.abap b/tasks_gen/train/G1916/hidden/solar_check_hidden.clas.abap new file mode 100644 index 0000000..780f00c --- /dev/null +++ b/tasks_gen/train/G1916/hidden/solar_check_hidden.clas.abap @@ -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. diff --git a/tasks_gen/train/G1916/reference/if_solar_check.intf.abap b/tasks_gen/train/G1916/reference/if_solar_check.intf.abap new file mode 100644 index 0000000..aedd46f --- /dev/null +++ b/tasks_gen/train/G1916/reference/if_solar_check.intf.abap @@ -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. diff --git a/tasks_gen/train/G1916/reference/solar_check_test.clas.abap b/tasks_gen/train/G1916/reference/solar_check_test.clas.abap new file mode 100644 index 0000000..025ed52 --- /dev/null +++ b/tasks_gen/train/G1916/reference/solar_check_test.clas.abap @@ -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. diff --git a/tasks_gen/train/G1916/spec.md b/tasks_gen/train/G1916/spec.md new file mode 100644 index 0000000..8cc3ca5 --- /dev/null +++ b/tasks_gen/train/G1916/spec.md @@ -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. diff --git a/tasks_gen/train/G1916/task.json b/tasks_gen/train/G1916/task.json new file mode 100644 index 0000000..761c17e --- /dev/null +++ b/tasks_gen/train/G1916/task.json @@ -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" + ] +} \ No newline at end of file diff --git a/tasks_gen/train/G1917/faulty/m0_if_bouquet_check.intf.abap b/tasks_gen/train/G1917/faulty/m0_if_bouquet_check.intf.abap new file mode 100644 index 0000000..9ae6deb --- /dev/null +++ b/tasks_gen/train/G1917/faulty/m0_if_bouquet_check.intf.abap @@ -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. diff --git a/tasks_gen/train/G1917/faulty/m1_if_bouquet_check.intf.abap b/tasks_gen/train/G1917/faulty/m1_if_bouquet_check.intf.abap new file mode 100644 index 0000000..aa75a8d --- /dev/null +++ b/tasks_gen/train/G1917/faulty/m1_if_bouquet_check.intf.abap @@ -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. diff --git a/tasks_gen/train/G1917/faulty/m2_if_bouquet_check.intf.abap b/tasks_gen/train/G1917/faulty/m2_if_bouquet_check.intf.abap new file mode 100644 index 0000000..718d22a --- /dev/null +++ b/tasks_gen/train/G1917/faulty/m2_if_bouquet_check.intf.abap @@ -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. diff --git a/tasks_gen/train/G1917/faulty/m3_if_bouquet_check.intf.abap b/tasks_gen/train/G1917/faulty/m3_if_bouquet_check.intf.abap new file mode 100644 index 0000000..cf7d9cb --- /dev/null +++ b/tasks_gen/train/G1917/faulty/m3_if_bouquet_check.intf.abap @@ -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. diff --git a/tasks_gen/train/G1917/faulty/m4_if_bouquet_check.intf.abap b/tasks_gen/train/G1917/faulty/m4_if_bouquet_check.intf.abap new file mode 100644 index 0000000..2987f83 --- /dev/null +++ b/tasks_gen/train/G1917/faulty/m4_if_bouquet_check.intf.abap @@ -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. diff --git a/tasks_gen/train/G1917/generation.json b/tasks_gen/train/G1917/generation.json new file mode 100644 index 0000000..323e4aa --- /dev/null +++ b/tasks_gen/train/G1917/generation.json @@ -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 +} \ No newline at end of file diff --git a/tasks_gen/train/G1917/hidden/bouquet_check_hidden.clas.abap b/tasks_gen/train/G1917/hidden/bouquet_check_hidden.clas.abap new file mode 100644 index 0000000..b5ea9d0 --- /dev/null +++ b/tasks_gen/train/G1917/hidden/bouquet_check_hidden.clas.abap @@ -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. diff --git a/tasks_gen/train/G1917/mutation.json b/tasks_gen/train/G1917/mutation.json new file mode 100644 index 0000000..9f938d1 --- /dev/null +++ b/tasks_gen/train/G1917/mutation.json @@ -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 +} \ No newline at end of file diff --git a/tasks_gen/train/G1917/reference/bouquet_check_test.clas.abap b/tasks_gen/train/G1917/reference/bouquet_check_test.clas.abap new file mode 100644 index 0000000..850f15e --- /dev/null +++ b/tasks_gen/train/G1917/reference/bouquet_check_test.clas.abap @@ -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. diff --git a/tasks_gen/train/G1917/reference/if_bouquet_check.intf.abap b/tasks_gen/train/G1917/reference/if_bouquet_check.intf.abap new file mode 100644 index 0000000..0444360 --- /dev/null +++ b/tasks_gen/train/G1917/reference/if_bouquet_check.intf.abap @@ -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. diff --git a/tasks_gen/train/G1917/spec.md b/tasks_gen/train/G1917/spec.md new file mode 100644 index 0000000..3bed952 --- /dev/null +++ b/tasks_gen/train/G1917/spec.md @@ -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. diff --git a/tasks_gen/train/G1917/task.json b/tasks_gen/train/G1917/task.json new file mode 100644 index 0000000..05eaa24 --- /dev/null +++ b/tasks_gen/train/G1917/task.json @@ -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" + ] +} \ No newline at end of file diff --git a/tasks_gen/train/G1918/faulty/m0_bouquet_pricing.intf.abap b/tasks_gen/train/G1918/faulty/m0_bouquet_pricing.intf.abap new file mode 100644 index 0000000..e3892e1 --- /dev/null +++ b/tasks_gen/train/G1918/faulty/m0_bouquet_pricing.intf.abap @@ -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. diff --git a/tasks_gen/train/G1918/faulty/m1_bouquet_pricing.intf.abap b/tasks_gen/train/G1918/faulty/m1_bouquet_pricing.intf.abap new file mode 100644 index 0000000..e3ec0a8 --- /dev/null +++ b/tasks_gen/train/G1918/faulty/m1_bouquet_pricing.intf.abap @@ -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. diff --git a/tasks_gen/train/G1918/faulty/m2_bouquet_pricing.intf.abap b/tasks_gen/train/G1918/faulty/m2_bouquet_pricing.intf.abap new file mode 100644 index 0000000..2ddab69 --- /dev/null +++ b/tasks_gen/train/G1918/faulty/m2_bouquet_pricing.intf.abap @@ -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. diff --git a/tasks_gen/train/G1918/faulty/m3_bouquet_pricing.intf.abap b/tasks_gen/train/G1918/faulty/m3_bouquet_pricing.intf.abap new file mode 100644 index 0000000..30bf325 --- /dev/null +++ b/tasks_gen/train/G1918/faulty/m3_bouquet_pricing.intf.abap @@ -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. diff --git a/tasks_gen/train/G1918/generation.json b/tasks_gen/train/G1918/generation.json new file mode 100644 index 0000000..3558307 --- /dev/null +++ b/tasks_gen/train/G1918/generation.json @@ -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 +} \ No newline at end of file diff --git a/tasks_gen/train/G1918/hidden/t02_hidden.clas.abap b/tasks_gen/train/G1918/hidden/t02_hidden.clas.abap new file mode 100644 index 0000000..e1c3758 --- /dev/null +++ b/tasks_gen/train/G1918/hidden/t02_hidden.clas.abap @@ -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. diff --git a/tasks_gen/train/G1918/mutation.json b/tasks_gen/train/G1918/mutation.json new file mode 100644 index 0000000..25bf98a --- /dev/null +++ b/tasks_gen/train/G1918/mutation.json @@ -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 +} \ No newline at end of file diff --git a/tasks_gen/train/G1918/reference/bouquet_if_test.clas.abap b/tasks_gen/train/G1918/reference/bouquet_if_test.clas.abap new file mode 100644 index 0000000..bb940c7 --- /dev/null +++ b/tasks_gen/train/G1918/reference/bouquet_if_test.clas.abap @@ -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. diff --git a/tasks_gen/train/G1918/reference/bouquet_pricing.intf.abap b/tasks_gen/train/G1918/reference/bouquet_pricing.intf.abap new file mode 100644 index 0000000..bb78856 --- /dev/null +++ b/tasks_gen/train/G1918/reference/bouquet_pricing.intf.abap @@ -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. diff --git a/tasks_gen/train/G1918/spec.md b/tasks_gen/train/G1918/spec.md new file mode 100644 index 0000000..4204f32 --- /dev/null +++ b/tasks_gen/train/G1918/spec.md @@ -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. diff --git a/tasks_gen/train/G1918/task.json b/tasks_gen/train/G1918/task.json new file mode 100644 index 0000000..8081723 --- /dev/null +++ b/tasks_gen/train/G1918/task.json @@ -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" + ] +} \ No newline at end of file diff --git a/tasks_gen/train/G1919/faulty/m0_rescue.tabl.asabap b/tasks_gen/train/G1919/faulty/m0_rescue.tabl.asabap new file mode 100644 index 0000000..c85ff0e --- /dev/null +++ b/tasks_gen/train/G1919/faulty/m0_rescue.tabl.asabap @@ -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; +} diff --git a/tasks_gen/train/G1919/faulty/m1_rescue.tabl.asabap b/tasks_gen/train/G1919/faulty/m1_rescue.tabl.asabap new file mode 100644 index 0000000..95ec1ec --- /dev/null +++ b/tasks_gen/train/G1919/faulty/m1_rescue.tabl.asabap @@ -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; +} diff --git a/tasks_gen/train/G1919/faulty/m2_rescue.tabl.asabap b/tasks_gen/train/G1919/faulty/m2_rescue.tabl.asabap new file mode 100644 index 0000000..eec8239 --- /dev/null +++ b/tasks_gen/train/G1919/faulty/m2_rescue.tabl.asabap @@ -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; +} diff --git a/tasks_gen/train/G1919/faulty/m3_rescue.tabl.asabap b/tasks_gen/train/G1919/faulty/m3_rescue.tabl.asabap new file mode 100644 index 0000000..670e0e5 --- /dev/null +++ b/tasks_gen/train/G1919/faulty/m3_rescue.tabl.asabap @@ -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.dats not null; + location : abap.numc(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; +} diff --git a/tasks_gen/train/G1919/faulty/m4_rescue.tabl.asabap b/tasks_gen/train/G1919/faulty/m4_rescue.tabl.asabap new file mode 100644 index 0000000..af9740f --- /dev/null +++ b/tasks_gen/train/G1919/faulty/m4_rescue.tabl.asabap @@ -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.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,3); + currency_code : abap.cuky; +} diff --git a/tasks_gen/train/G1919/generation.json b/tasks_gen/train/G1919/generation.json new file mode 100644 index 0000000..b5654d2 --- /dev/null +++ b/tasks_gen/train/G1919/generation.json @@ -0,0 +1,19 @@ +{ + "id": "G1919", + "pool": "train", + "object_type": "TABL", + "category": "B", + "attempts": [ + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 5, + "killed": 5, + "ok": true + } + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1919/hidden/t20_hidden.clas.abap b/tasks_gen/train/G1919/hidden/t20_hidden.clas.abap new file mode 100644 index 0000000..65e352a --- /dev/null +++ b/tasks_gen/train/G1919/hidden/t20_hidden.clas.abap @@ -0,0 +1,203 @@ +CLASS {{p}}t20_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. + CLASS-METHODS get_fields RETURNING VALUE(rt_fields) TYPE ddfields. + CLASS-METHODS field_of + IMPORTING iv_name TYPE fieldname + RETURNING VALUE(rs_field) TYPE dfies. + CLASS-METHODS not_null_flag + IMPORTING iv_name TYPE fieldname + RETURNING VALUE(rv_flag) TYPE abap_bool. + METHODS setup. + METHODS field_names FOR TESTING. + METHODS key_fields FOR TESTING. + METHODS field_types FOR TESTING. + METHODS field_lengths FOR TESTING. + METHODS decimals FOR TESTING. + METHODS not_null_fields FOR TESTING. + METHODS store_and_read FOR TESTING. + METHODS duplicate_key FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t20_hidden IMPLEMENTATION. + + METHOD class_setup. + go_env = cl_osql_test_environment=>create( i_dependency_list = VALUE #( ( '{{P}}RESCUE' ) ) ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + go_env->clear_doubles( ). + ENDMETHOD. + + METHOD get_fields. + DATA lo_struct TYPE REF TO cl_abap_structdescr. + lo_struct ?= cl_abap_typedescr=>describe_by_name( '{{P}}RESCUE' ). + rt_fields = lo_struct->get_ddic_field_list( ). + ENDMETHOD. + + METHOD field_of. + DATA(lt_fields) = get_fields( ). + LOOP AT lt_fields INTO DATA(ls_field) WHERE fieldname = iv_name. + rs_field = ls_field. + RETURN. + ENDLOOP. + ENDMETHOD. + + METHOD not_null_flag. + SELECT SINGLE notnull FROM dd03l + WHERE tabname = '{{P}}RESCUE' AND fieldname = @iv_name AND as4local = 'A' + INTO @rv_flag. + ENDMETHOD. + + METHOD field_names. + DATA(lt_fields) = get_fields( ). + cl_abap_unit_assert=>assert_equals( exp = 9 act = lines( lt_fields ) ). + DATA(ls_field) = field_of( 'CLIENT' ). + cl_abap_unit_assert=>assert_equals( exp = 'CLIENT' act = ls_field-fieldname ). + ls_field = field_of( 'CALLOUT_ID' ). + cl_abap_unit_assert=>assert_equals( exp = 'CALLOUT_ID' act = ls_field-fieldname ). + ls_field = field_of( 'CALLOUT_DATE' ). + cl_abap_unit_assert=>assert_equals( exp = 'CALLOUT_DATE' act = ls_field-fieldname ). + ls_field = field_of( 'LOCATION' ). + cl_abap_unit_assert=>assert_equals( exp = 'LOCATION' act = ls_field-fieldname ). + ls_field = field_of( 'DURATION_MIN' ). + cl_abap_unit_assert=>assert_equals( exp = 'DURATION_MIN' act = ls_field-fieldname ). + ls_field = field_of( 'TEAM_SIZE' ). + cl_abap_unit_assert=>assert_equals( exp = 'TEAM_SIZE' act = ls_field-fieldname ). + ls_field = field_of( 'RESCUED_COUNT' ). + cl_abap_unit_assert=>assert_equals( exp = 'RESCUED_COUNT' act = ls_field-fieldname ). + ls_field = field_of( 'FEE_AMOUNT' ). + cl_abap_unit_assert=>assert_equals( exp = 'FEE_AMOUNT' act = ls_field-fieldname ). + ls_field = field_of( 'CURRENCY_CODE' ). + cl_abap_unit_assert=>assert_equals( exp = 'CURRENCY_CODE' act = ls_field-fieldname ). + ENDMETHOD. + + METHOD key_fields. + DATA(ls_field) = field_of( 'CLIENT' ). + cl_abap_unit_assert=>assert_equals( exp = 'X' act = ls_field-keyflag ). + ls_field = field_of( 'CALLOUT_ID' ). + cl_abap_unit_assert=>assert_equals( exp = 'X' act = ls_field-keyflag ). + ls_field = field_of( 'CALLOUT_DATE' ). + cl_abap_unit_assert=>assert_initial( act = ls_field-keyflag ). + ls_field = field_of( 'LOCATION' ). + cl_abap_unit_assert=>assert_initial( act = ls_field-keyflag ). + ls_field = field_of( 'DURATION_MIN' ). + cl_abap_unit_assert=>assert_initial( act = ls_field-keyflag ). + ls_field = field_of( 'TEAM_SIZE' ). + cl_abap_unit_assert=>assert_initial( act = ls_field-keyflag ). + ls_field = field_of( 'RESCUED_COUNT' ). + cl_abap_unit_assert=>assert_initial( act = ls_field-keyflag ). + ls_field = field_of( 'FEE_AMOUNT' ). + cl_abap_unit_assert=>assert_initial( act = ls_field-keyflag ). + ls_field = field_of( 'CURRENCY_CODE' ). + cl_abap_unit_assert=>assert_initial( act = ls_field-keyflag ). + 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( 'CALLOUT_ID' ). + cl_abap_unit_assert=>assert_equals( exp = 'CHAR' act = ls_field-datatype ). + ls_field = field_of( 'CALLOUT_DATE' ). + cl_abap_unit_assert=>assert_equals( exp = 'DATS' act = ls_field-datatype ). + ls_field = field_of( 'LOCATION' ). + cl_abap_unit_assert=>assert_equals( exp = 'CHAR' act = ls_field-datatype ). + ls_field = field_of( 'DURATION_MIN' ). + cl_abap_unit_assert=>assert_equals( exp = 'INT4' act = ls_field-datatype ). + ls_field = field_of( 'TEAM_SIZE' ). + cl_abap_unit_assert=>assert_equals( exp = 'INT4' act = ls_field-datatype ). + ls_field = field_of( 'RESCUED_COUNT' ). + cl_abap_unit_assert=>assert_equals( exp = 'INT4' act = ls_field-datatype ). + ls_field = field_of( 'FEE_AMOUNT' ). + cl_abap_unit_assert=>assert_equals( exp = 'DEC' act = ls_field-datatype ). + ls_field = field_of( 'CURRENCY_CODE' ). + cl_abap_unit_assert=>assert_equals( exp = 'CUKY' act = ls_field-datatype ). + ENDMETHOD. + + METHOD field_lengths. + DATA(ls_field) = field_of( 'CLIENT' ). + cl_abap_unit_assert=>assert_equals( exp = 3 act = CONV i( ls_field-leng ) ). + ls_field = field_of( 'CALLOUT_ID' ). + cl_abap_unit_assert=>assert_equals( exp = 10 act = CONV i( ls_field-leng ) ). + ls_field = field_of( 'CALLOUT_DATE' ). + cl_abap_unit_assert=>assert_equals( exp = 8 act = CONV i( ls_field-leng ) ). + ls_field = field_of( 'LOCATION' ). + cl_abap_unit_assert=>assert_equals( exp = 30 act = CONV i( ls_field-leng ) ). + ls_field = field_of( 'DURATION_MIN' ). + cl_abap_unit_assert=>assert_equals( exp = 10 act = CONV i( ls_field-leng ) ). + ls_field = field_of( 'TEAM_SIZE' ). + cl_abap_unit_assert=>assert_equals( exp = 10 act = CONV i( ls_field-leng ) ). + ls_field = field_of( 'RESCUED_COUNT' ). + cl_abap_unit_assert=>assert_equals( exp = 10 act = CONV i( ls_field-leng ) ). + ls_field = field_of( 'FEE_AMOUNT' ). + 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 ) ). + ENDMETHOD. + + METHOD decimals. + DATA(ls_field) = field_of( 'FEE_AMOUNT' ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = CONV i( ls_field-decimals ) ). + ls_field = field_of( 'DURATION_MIN' ). + cl_abap_unit_assert=>assert_equals( exp = 0 act = CONV i( ls_field-decimals ) ). + ls_field = field_of( 'CURRENCY_CODE' ). + cl_abap_unit_assert=>assert_equals( exp = 0 act = CONV i( ls_field-decimals ) ). + ENDMETHOD. + + METHOD not_null_fields. + cl_abap_unit_assert=>assert_equals( exp = 'X' act = not_null_flag( 'CLIENT' ) ). + cl_abap_unit_assert=>assert_equals( exp = 'X' act = not_null_flag( 'CALLOUT_ID' ) ). + cl_abap_unit_assert=>assert_equals( exp = 'X' act = not_null_flag( 'CALLOUT_DATE' ) ). + cl_abap_unit_assert=>assert_initial( act = not_null_flag( 'LOCATION' ) ). + cl_abap_unit_assert=>assert_initial( act = not_null_flag( 'DURATION_MIN' ) ). + cl_abap_unit_assert=>assert_initial( act = not_null_flag( 'TEAM_SIZE' ) ). + cl_abap_unit_assert=>assert_initial( act = not_null_flag( 'RESCUED_COUNT' ) ). + cl_abap_unit_assert=>assert_initial( act = not_null_flag( 'FEE_AMOUNT' ) ). + cl_abap_unit_assert=>assert_initial( act = not_null_flag( 'CURRENCY_CODE' ) ). + ENDMETHOD. + + METHOD store_and_read. + DATA ls_rescue TYPE {{p}}rescue. + ls_rescue-client = sy-mandt. + ls_rescue-callout_id = 'C0001'. + ls_rescue-callout_date = '20250115'. + ls_rescue-location = 'NORTH RIDGE'. + ls_rescue-duration_min = 95. + ls_rescue-team_size = 6. + ls_rescue-rescued_count = 2. + ls_rescue-fee_amount = '1250.50'. + ls_rescue-currency_code = 'EUR'. + INSERT {{p}}rescue FROM @ls_rescue. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + + DATA ls_read TYPE {{p}}rescue. + SELECT SINGLE * FROM {{p}}rescue WHERE callout_id = 'C0001' INTO @ls_read. + cl_abap_unit_assert=>assert_equals( exp = 'NORTH RIDGE' act = ls_read-location ). + cl_abap_unit_assert=>assert_equals( exp = '20250115' act = ls_read-callout_date ). + cl_abap_unit_assert=>assert_equals( exp = 95 act = ls_read-duration_min ). + cl_abap_unit_assert=>assert_equals( exp = 6 act = ls_read-team_size ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = ls_read-rescued_count ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '1250.50' ) + act = CONV decfloat34( ls_read-fee_amount ) ). + cl_abap_unit_assert=>assert_equals( exp = 'EUR' act = ls_read-currency_code ). + ENDMETHOD. + + METHOD duplicate_key. + DATA ls_rescue TYPE {{p}}rescue. + ls_rescue-client = sy-mandt. + ls_rescue-callout_id = 'C0002'. + ls_rescue-callout_date = '20250116'. + INSERT {{p}}rescue FROM @ls_rescue. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + INSERT {{p}}rescue FROM @ls_rescue. + cl_abap_unit_assert=>assert_subrc( exp = 4 ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1919/mutation.json b/tasks_gen/train/G1919/mutation.json new file mode 100644 index 0000000..bcf627c --- /dev/null +++ b/tasks_gen/train/G1919/mutation.json @@ -0,0 +1,57 @@ +{ + "task": "G1919", + "mutants": [ + { + "object": "{{P}}RESCUE", + "mutant": "line 8: key callout_id : -> callout_id : (key)", + "status": "killed", + "hidden": "7/8", + "failed_tests": [ + "KEY_FIELDS" + ] + }, + { + "object": "{{P}}RESCUE", + "mutant": "line 8: abap.char(10) -> abap.char(9) (length)", + "status": "killed", + "hidden": "7/8", + "failed_tests": [ + "FIELD_LENGTHS" + ] + }, + { + "object": "{{P}}RESCUE", + "mutant": "line 9: abap.dats -> abap.tims (type)", + "status": "killed", + "hidden": "5/8", + "failed_tests": [ + "FIELD_LENGTHS", + "FIELD_TYPES", + "STORE_AND_READ" + ] + }, + { + "object": "{{P}}RESCUE", + "mutant": "line 10: abap.char(30) -> abap.numc(30) (type)", + "status": "killed", + "hidden": "6/8", + "failed_tests": [ + "FIELD_TYPES", + "STORE_AND_READ" + ] + }, + { + "object": "{{P}}RESCUE", + "mutant": "line 15: abap.dec(13,2) -> abap.dec(13,3) (decimals)", + "status": "killed", + "hidden": "7/8", + "failed_tests": [ + "DECIMALS" + ] + } + ], + "valid": 5, + "killed": 5, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1919/reference/rescue.tabl.asabap b/tasks_gen/train/G1919/reference/rescue.tabl.asabap new file mode 100644 index 0000000..e0ee5fa --- /dev/null +++ b/tasks_gen/train/G1919/reference/rescue.tabl.asabap @@ -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.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; +} diff --git a/tasks_gen/train/G1919/reference/t20_test.clas.abap b/tasks_gen/train/G1919/reference/t20_test.clas.abap new file mode 100644 index 0000000..ec77298 --- /dev/null +++ b/tasks_gen/train/G1919/reference/t20_test.clas.abap @@ -0,0 +1,73 @@ +CLASS {{p}}t20_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_callout FOR TESTING. + METHODS rejects_duplicate FOR TESTING. + METHODS keeps_amount FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t20_test IMPLEMENTATION. + + METHOD class_setup. + go_env = cl_osql_test_environment=>create( i_dependency_list = VALUE #( ( '{{P}}RESCUE' ) ) ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + go_env->clear_doubles( ). + ENDMETHOD. + + METHOD stores_callout. + DATA ls_rescue TYPE {{p}}rescue. + ls_rescue-client = sy-mandt. + ls_rescue-callout_id = 'R0001'. + ls_rescue-callout_date = '20250310'. + ls_rescue-location = 'EAST FACE'. + ls_rescue-duration_min = 120. + ls_rescue-team_size = 5. + ls_rescue-rescued_count = 1. + ls_rescue-fee_amount = '980.00'. + ls_rescue-currency_code = 'EUR'. + INSERT {{p}}rescue FROM @ls_rescue. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + + DATA ls_read TYPE {{p}}rescue. + SELECT SINGLE * FROM {{p}}rescue WHERE callout_id = 'R0001' INTO @ls_read. + cl_abap_unit_assert=>assert_equals( exp = 'EAST FACE' act = ls_read-location ). + cl_abap_unit_assert=>assert_equals( exp = 120 act = ls_read-duration_min ). + ENDMETHOD. + + METHOD rejects_duplicate. + DATA ls_rescue TYPE {{p}}rescue. + ls_rescue-client = sy-mandt. + ls_rescue-callout_id = 'R0002'. + ls_rescue-callout_date = '20250311'. + INSERT {{p}}rescue FROM @ls_rescue. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + INSERT {{p}}rescue FROM @ls_rescue. + cl_abap_unit_assert=>assert_subrc( exp = 4 ). + ENDMETHOD. + + METHOD keeps_amount. + DATA ls_rescue TYPE {{p}}rescue. + ls_rescue-client = sy-mandt. + ls_rescue-callout_id = 'R0003'. + ls_rescue-callout_date = '20250312'. + ls_rescue-fee_amount = '1234.56'. + ls_rescue-currency_code = 'CHF'. + INSERT {{p}}rescue FROM @ls_rescue. + + DATA ls_read TYPE {{p}}rescue. + SELECT SINGLE * FROM {{p}}rescue WHERE callout_id = 'R0003' INTO @ls_read. + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '1234.56' ) + act = CONV decfloat34( ls_read-fee_amount ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1919/spec.md b/tasks_gen/train/G1919/spec.md new file mode 100644 index 0000000..2d659c4 --- /dev/null +++ b/tasks_gen/train/G1919/spec.md @@ -0,0 +1,53 @@ +# 1. Goal +A mountain rescue service records each callout of its rescue teams. The service +must store the callouts in a database table. A report and an OData service read +the callouts later. Therefore the table needs a fixed structure. + +# 2. Open questions +None. + +# 3. Context +- Package $TMP, client 001. No transports. +- The table is new. No other object of this task exists. +- A callout is the work of one rescue team for one incident. +- The client and the callout ID identify one callout. + +# 4. Contract +- Create the database table {{P}}RESCUE in package $TMP. +- The table contains these fields, in this order: + client, callout_id, callout_date, location, duration_min, team_size, + rescued_count, fee_amount, currency_code. + +# 5. Business rules +1. The key fields of the table are client and callout_id. +2. client has the type abap.clnt and is not null. +3. callout_id has the type abap.char(10) and is not null. A callout ID is + unique for one client. +4. callout_date has the type abap.dats and is not null. It is the day of the + callout. +5. location has the type abap.char(30). It is the place of the incident. The + location can be empty. +6. duration_min has the type abap.int4. It is the duration of the callout in + minutes. +7. team_size has the type abap.int4. It is the number of rescuers. +8. rescued_count has the type abap.int4. It is the number of persons that the + team rescued. +9. fee_amount has the type abap.dec(13,2). It is the fee for the callout. +10. currency_code has the type abap.cuky. It is the currency of fee_amount. + fee_amount is an amount and refers to the currency field of the same table. +11. The table keeps one row for each pair of client and callout_id. A second + insert with the same pair returns sy-subrc = 4. + +# 6. Constraints +- Release target: 8.16. +- Use only built-in types: abap.clnt, abap.char, abap.dats, abap.int4, + abap.dec, abap.cuky. +- The table is not extensible. Delivery class A. Data maintenance is + restricted. +- Write clean ABAP. Do not create ATC priority 1 or priority 2 findings. +- Out of scope: all other objects in package $TMP. + +# 7. Acceptance +- The table {{P}}RESCUE 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. diff --git a/tasks_gen/train/G1919/task.json b/tasks_gen/train/G1919/task.json new file mode 100644 index 0000000..e08b13a --- /dev/null +++ b/tasks_gen/train/G1919/task.json @@ -0,0 +1,56 @@ +{ + "id": "G1919", + "category": "B", + "object_type": "TABL", + "difficulty": 3, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [], + "contract": [ + { + "type": "TABL", + "name": "{{P}}RESCUE", + "fields": [ + "client", + "callout_id", + "callout_date", + "location", + "duration_min", + "team_size", + "rescued_count", + "fee_amount", + "currency_code" + ] + } + ], + "out_of_scope": [ + "Other objects in package $TMP" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T20_HIDDEN", + "file": "hidden/t20_hidden.clas.abap", + "description": "Structure and storage tests for {{P}}RESCUE" + } + ], + "reference": [ + { + "type": "TABL", + "name": "{{P}}RESCUE", + "file": "reference/rescue.tabl.asabap", + "description": "Mountain rescue callouts" + }, + { + "type": "CLAS", + "name": "{{P}}T20_TEST", + "file": "reference/t20_test.clas.abap", + "description": "Own tests for {{P}}RESCUE" + } + ], + "craft_checks": [] +} \ No newline at end of file diff --git a/tasks_gen/train/G1920/faulty/m0_jump.tabl.asabap b/tasks_gen/train/G1920/faulty/m0_jump.tabl.asabap new file mode 100644 index 0000000..64fb9c6 --- /dev/null +++ b/tasks_gen/train/G1920/faulty/m0_jump.tabl.asabap @@ -0,0 +1,15 @@ +@EndUserText.label : 'Jump session' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}jump { + key client : abap.clnt not null; + session_id : abap.char(10) not null; + visitor_id : abap.char(10); + jump_date : abap.dats; + jump_minutes : abap.int4; + locker_no : abap.numc(4); + fee_amount : abap.dec(9,2); + paid : abap.char(1); +} diff --git a/tasks_gen/train/G1920/faulty/m1_jump.tabl.asabap b/tasks_gen/train/G1920/faulty/m1_jump.tabl.asabap new file mode 100644 index 0000000..a1d6c78 --- /dev/null +++ b/tasks_gen/train/G1920/faulty/m1_jump.tabl.asabap @@ -0,0 +1,15 @@ +@EndUserText.label : 'Jump session' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}jump { + key client : abap.clnt not null; + key session_id : abap.char(9) not null; + visitor_id : abap.char(10); + jump_date : abap.dats; + jump_minutes : abap.int4; + locker_no : abap.numc(4); + fee_amount : abap.dec(9,2); + paid : abap.char(1); +} diff --git a/tasks_gen/train/G1920/faulty/m2_jump.tabl.asabap b/tasks_gen/train/G1920/faulty/m2_jump.tabl.asabap new file mode 100644 index 0000000..1fc4838 --- /dev/null +++ b/tasks_gen/train/G1920/faulty/m2_jump.tabl.asabap @@ -0,0 +1,15 @@ +@EndUserText.label : 'Jump session' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}jump { + key client : abap.clnt not null; + key session_id : abap.char(10) not null; + visitor_id : abap.char(10); + jump_date : abap.tims; + jump_minutes : abap.int4; + locker_no : abap.numc(4); + fee_amount : abap.dec(9,2); + paid : abap.char(1); +} diff --git a/tasks_gen/train/G1920/faulty/m3_jump.tabl.asabap b/tasks_gen/train/G1920/faulty/m3_jump.tabl.asabap new file mode 100644 index 0000000..ff00b66 --- /dev/null +++ b/tasks_gen/train/G1920/faulty/m3_jump.tabl.asabap @@ -0,0 +1,15 @@ +@EndUserText.label : 'Jump session' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}jump { + key client : abap.clnt not null; + key session_id : abap.char(10) not null; + visitor_id : abap.char(10); + jump_date : abap.dats; + jump_minutes : abap.int4; + locker_no : abap.numc(3); + fee_amount : abap.dec(9,2); + paid : abap.char(1); +} diff --git a/tasks_gen/train/G1920/faulty/m4_jump.tabl.asabap b/tasks_gen/train/G1920/faulty/m4_jump.tabl.asabap new file mode 100644 index 0000000..07796b6 --- /dev/null +++ b/tasks_gen/train/G1920/faulty/m4_jump.tabl.asabap @@ -0,0 +1,15 @@ +@EndUserText.label : 'Jump session' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}jump { + key client : abap.clnt not null; + key session_id : abap.char(10) not null; + visitor_id : abap.char(10); + jump_date : abap.dats; + jump_minutes : abap.int4; + locker_no : abap.numc(4); + fee_amount : abap.dec(9,3); + paid : abap.char(1); +} diff --git a/tasks_gen/train/G1920/generation.json b/tasks_gen/train/G1920/generation.json new file mode 100644 index 0000000..f630aa4 --- /dev/null +++ b/tasks_gen/train/G1920/generation.json @@ -0,0 +1,19 @@ +{ + "id": "G1920", + "pool": "train", + "object_type": "TABL", + "category": "B", + "attempts": [ + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 5, + "killed": 5, + "ok": true + } + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1920/hidden/jump_hidden.clas.abap b/tasks_gen/train/G1920/hidden/jump_hidden.clas.abap new file mode 100644 index 0000000..47c622d --- /dev/null +++ b/tasks_gen/train/G1920/hidden/jump_hidden.clas.abap @@ -0,0 +1,149 @@ +CLASS {{p}}jump_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-DATA gt_fields TYPE ddfields. + CLASS-METHODS class_setup. + CLASS-METHODS class_teardown. + METHODS setup. + METHODS field_info + IMPORTING iv_name TYPE fieldname + RETURNING VALUE(rs_info) TYPE dfies. + METHODS assert_field_exists + IMPORTING iv_name TYPE fieldname. + METHODS all_fields_exist FOR TESTING. + METHODS key_fields FOR TESTING. + METHODS char_fields FOR TESTING. + METHODS date_field FOR TESTING. + METHODS minutes_field FOR TESTING. + METHODS amount_field FOR TESTING. + METHODS client_field FOR TESTING. + METHODS insert_and_read FOR TESTING. + METHODS duplicate_key FOR TESTING. + METHODS filter_by_date FOR TESTING. +ENDCLASS. + + +CLASS {{p}}jump_hidden IMPLEMENTATION. + + METHOD class_setup. + DATA(lo_struct) = CAST cl_abap_structdescr( cl_abap_typedescr=>describe_by_name( '{{P}}JUMP' ) ). + gt_fields = lo_struct->get_ddic_field_list( ). + go_env = cl_osql_test_environment=>create( i_dependency_list = VALUE #( ( '{{P}}JUMP' ) ) ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + go_env->clear_doubles( ). + ENDMETHOD. + + METHOD field_info. + READ TABLE gt_fields INTO rs_info WITH KEY fieldname = iv_name. + ENDMETHOD. + + METHOD assert_field_exists. + cl_abap_unit_assert=>assert_equals( exp = iv_name act = field_info( iv_name )-fieldname ). + ENDMETHOD. + + METHOD all_fields_exist. + cl_abap_unit_assert=>assert_equals( exp = 8 act = lines( gt_fields ) ). + assert_field_exists( 'CLIENT' ). + assert_field_exists( 'SESSION_ID' ). + assert_field_exists( 'VISITOR_ID' ). + assert_field_exists( 'JUMP_DATE' ). + assert_field_exists( 'JUMP_MINUTES' ). + assert_field_exists( 'LOCKER_NO' ). + assert_field_exists( 'FEE_AMOUNT' ). + assert_field_exists( 'PAID' ). + ENDMETHOD. + + METHOD key_fields. + cl_abap_unit_assert=>assert_equals( exp = 'X' act = field_info( 'CLIENT' )-keyflag ). + cl_abap_unit_assert=>assert_equals( exp = 'X' act = field_info( 'SESSION_ID' )-keyflag ). + cl_abap_unit_assert=>assert_equals( exp = ' ' act = field_info( 'VISITOR_ID' )-keyflag ). + cl_abap_unit_assert=>assert_equals( exp = ' ' act = field_info( 'JUMP_DATE' )-keyflag ). + cl_abap_unit_assert=>assert_equals( exp = ' ' act = field_info( 'JUMP_MINUTES' )-keyflag ). + cl_abap_unit_assert=>assert_equals( exp = ' ' act = field_info( 'LOCKER_NO' )-keyflag ). + cl_abap_unit_assert=>assert_equals( exp = ' ' act = field_info( 'FEE_AMOUNT' )-keyflag ). + cl_abap_unit_assert=>assert_equals( exp = ' ' act = field_info( 'PAID' )-keyflag ). + ENDMETHOD. + + METHOD char_fields. + cl_abap_unit_assert=>assert_equals( exp = 'C' act = field_info( 'SESSION_ID' )-inttype ). + cl_abap_unit_assert=>assert_equals( exp = 10 act = field_info( 'SESSION_ID' )-leng ). + cl_abap_unit_assert=>assert_equals( exp = 'C' act = field_info( 'VISITOR_ID' )-inttype ). + cl_abap_unit_assert=>assert_equals( exp = 10 act = field_info( 'VISITOR_ID' )-leng ). + cl_abap_unit_assert=>assert_equals( exp = 'N' act = field_info( 'LOCKER_NO' )-inttype ). + cl_abap_unit_assert=>assert_equals( exp = 4 act = field_info( 'LOCKER_NO' )-leng ). + cl_abap_unit_assert=>assert_equals( exp = 'C' act = field_info( 'PAID' )-inttype ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = field_info( 'PAID' )-leng ). + ENDMETHOD. + + METHOD date_field. + cl_abap_unit_assert=>assert_equals( exp = 'D' act = field_info( 'JUMP_DATE' )-inttype ). + cl_abap_unit_assert=>assert_equals( exp = 8 act = field_info( 'JUMP_DATE' )-leng ). + ENDMETHOD. + + METHOD minutes_field. + cl_abap_unit_assert=>assert_equals( exp = 'I' act = field_info( 'JUMP_MINUTES' )-inttype ). + cl_abap_unit_assert=>assert_equals( exp = 10 act = field_info( 'JUMP_MINUTES' )-leng ). + ENDMETHOD. + + METHOD amount_field. + cl_abap_unit_assert=>assert_equals( exp = 'P' act = field_info( 'FEE_AMOUNT' )-inttype ). + cl_abap_unit_assert=>assert_equals( exp = 9 act = field_info( 'FEE_AMOUNT' )-leng ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = field_info( 'FEE_AMOUNT' )-decimals ). + ENDMETHOD. + + METHOD client_field. + cl_abap_unit_assert=>assert_equals( exp = 'C' act = field_info( 'CLIENT' )-inttype ). + cl_abap_unit_assert=>assert_equals( exp = 3 act = field_info( 'CLIENT' )-leng ). + ENDMETHOD. + + METHOD insert_and_read. + DATA(ls_jump) = VALUE {{p}}jump( session_id = 'S000000001' + visitor_id = 'V000000001' + jump_date = '20250401' + jump_minutes = 60 + locker_no = '0007' + fee_amount = '12.50' + paid = 'X' ). + INSERT {{p}}jump FROM @ls_jump. + cl_abap_unit_assert=>assert_equals( exp = 0 act = sy-subrc ). + SELECT SINGLE * FROM {{p}}jump WHERE session_id = 'S000000001' INTO @DATA(ls_read). + cl_abap_unit_assert=>assert_equals( exp = ls_jump-visitor_id act = ls_read-visitor_id ). + cl_abap_unit_assert=>assert_equals( exp = ls_jump-jump_date act = ls_read-jump_date ). + cl_abap_unit_assert=>assert_equals( exp = ls_jump-jump_minutes act = ls_read-jump_minutes ). + cl_abap_unit_assert=>assert_equals( exp = ls_jump-locker_no act = ls_read-locker_no ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( ls_jump-fee_amount ) + act = CONV decfloat34( ls_read-fee_amount ) ). + cl_abap_unit_assert=>assert_equals( exp = ls_jump-paid act = ls_read-paid ). + ENDMETHOD. + + METHOD duplicate_key. + DATA(ls_jump) = VALUE {{p}}jump( session_id = 'S000000002' + visitor_id = 'V000000002' + jump_date = '20250402' ). + INSERT {{p}}jump FROM @ls_jump. + cl_abap_unit_assert=>assert_equals( exp = 0 act = sy-subrc ). + INSERT {{p}}jump FROM @ls_jump. + cl_abap_unit_assert=>assert_equals( exp = 4 act = sy-subrc ). + ENDMETHOD. + + METHOD filter_by_date. + DATA lt_jump TYPE STANDARD TABLE OF {{p}}jump WITH EMPTY KEY. + lt_jump = VALUE #( ( session_id = 'S1' visitor_id = 'A' jump_date = '20250401' ) + ( session_id = 'S2' visitor_id = 'B' jump_date = '20250401' ) + ( session_id = 'S3' visitor_id = 'C' jump_date = '20250402' ) ). + INSERT {{p}}jump FROM TABLE @lt_jump. + cl_abap_unit_assert=>assert_equals( exp = 0 act = sy-subrc ). + SELECT * FROM {{p}}jump INTO TABLE @DATA(lt_all). + cl_abap_unit_assert=>assert_equals( exp = 3 act = lines( lt_all ) ). + SELECT * FROM {{p}}jump WHERE jump_date = '20250401' INTO TABLE @DATA(lt_day). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_day ) ). + ENDMETHOD. + +ENDCLASS. diff --git a/tasks_gen/train/G1920/mutation.json b/tasks_gen/train/G1920/mutation.json new file mode 100644 index 0000000..d5c6da0 --- /dev/null +++ b/tasks_gen/train/G1920/mutation.json @@ -0,0 +1,57 @@ +{ + "task": "G1920", + "mutants": [ + { + "object": "{{P}}JUMP", + "mutant": "line 8: key session_id : -> session_id : (key)", + "status": "killed", + "hidden": "8/10", + "failed_tests": [ + "FILTER_BY_DATE", + "KEY_FIELDS" + ] + }, + { + "object": "{{P}}JUMP", + "mutant": "line 8: abap.char(10) -> abap.char(9) (length)", + "status": "killed", + "hidden": "8/10", + "failed_tests": [ + "CHAR_FIELDS", + "INSERT_AND_READ" + ] + }, + { + "object": "{{P}}JUMP", + "mutant": "line 10: abap.dats -> abap.tims (type)", + "status": "killed", + "hidden": "8/10", + "failed_tests": [ + "DATE_FIELD", + "FILTER_BY_DATE" + ] + }, + { + "object": "{{P}}JUMP", + "mutant": "line 12: abap.numc(4) -> abap.numc(3) (length)", + "status": "killed", + "hidden": "9/10", + "failed_tests": [ + "CHAR_FIELDS" + ] + }, + { + "object": "{{P}}JUMP", + "mutant": "line 13: abap.dec(9,2) -> abap.dec(9,3) (decimals)", + "status": "killed", + "hidden": "9/10", + "failed_tests": [ + "AMOUNT_FIELD" + ] + } + ], + "valid": 5, + "killed": 5, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1920/reference/jump.tabl.asabap b/tasks_gen/train/G1920/reference/jump.tabl.asabap new file mode 100644 index 0000000..8567ea8 --- /dev/null +++ b/tasks_gen/train/G1920/reference/jump.tabl.asabap @@ -0,0 +1,15 @@ +@EndUserText.label : 'Jump session' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}jump { + key client : abap.clnt not null; + key session_id : abap.char(10) not null; + visitor_id : abap.char(10); + jump_date : abap.dats; + jump_minutes : abap.int4; + locker_no : abap.numc(4); + fee_amount : abap.dec(9,2); + paid : abap.char(1); +} diff --git a/tasks_gen/train/G1920/reference/jump_test.clas.abap b/tasks_gen/train/G1920/reference/jump_test.clas.abap new file mode 100644 index 0000000..0a95f79 --- /dev/null +++ b/tasks_gen/train/G1920/reference/jump_test.clas.abap @@ -0,0 +1,63 @@ +CLASS {{p}}jump_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 fields_match_spec FOR TESTING. + METHODS insert_and_select FOR TESTING. + METHODS duplicate_key_fails FOR TESTING. +ENDCLASS. + + +CLASS {{p}}jump_test IMPLEMENTATION. + + METHOD class_setup. + go_env = cl_osql_test_environment=>create( i_dependency_list = VALUE #( ( '{{P}}JUMP' ) ) ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + go_env->clear_doubles( ). + ENDMETHOD. + + METHOD fields_match_spec. + DATA(lo_struct) = CAST cl_abap_structdescr( cl_abap_typedescr=>describe_by_name( '{{P}}JUMP' ) ). + DATA(lt_fields) = lo_struct->get_ddic_field_list( ). + cl_abap_unit_assert=>assert_equals( exp = 8 act = lines( lt_fields ) ). + READ TABLE lt_fields INTO DATA(ls_field) WITH KEY fieldname = 'FEE_AMOUNT'. + cl_abap_unit_assert=>assert_equals( exp = 'P' act = ls_field-inttype ). + cl_abap_unit_assert=>assert_equals( exp = 9 act = ls_field-leng ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = ls_field-decimals ). + READ TABLE lt_fields INTO ls_field WITH KEY fieldname = 'SESSION_ID'. + cl_abap_unit_assert=>assert_equals( exp = 'X' act = ls_field-keyflag ). + ENDMETHOD. + + METHOD insert_and_select. + DATA(ls_jump) = VALUE {{p}}jump( session_id = 'S1' + visitor_id = 'V1' + jump_date = '20250401' + jump_minutes = 30 + fee_amount = '9.50' + paid = 'X' ). + INSERT {{p}}jump FROM @ls_jump. + cl_abap_unit_assert=>assert_equals( exp = 0 act = sy-subrc ). + SELECT SINGLE * FROM {{p}}jump WHERE session_id = 'S1' INTO @DATA(ls_read). + cl_abap_unit_assert=>assert_equals( exp = ls_jump-visitor_id act = ls_read-visitor_id ). + cl_abap_unit_assert=>assert_equals( exp = ls_jump-jump_minutes act = ls_read-jump_minutes ). + ENDMETHOD. + + METHOD duplicate_key_fails. + DATA(ls_jump) = VALUE {{p}}jump( session_id = 'S2' + visitor_id = 'V2' + jump_date = '20250402' ). + INSERT {{p}}jump FROM @ls_jump. + INSERT {{p}}jump FROM @ls_jump. + cl_abap_unit_assert=>assert_equals( exp = 4 act = sy-subrc ). + ENDMETHOD. + +ENDCLASS. diff --git a/tasks_gen/train/G1920/spec.md b/tasks_gen/train/G1920/spec.md new file mode 100644 index 0000000..06019db --- /dev/null +++ b/tasks_gen/train/G1920/spec.md @@ -0,0 +1,57 @@ +# 1. Goal +The trampoline park records each jump session of its visitors in one database +table. The booking desk writes the sessions. The reporting tools read the +sessions. Create this database table. + +# 2. Open questions +None. + +# 3. Context +- Package $TMP, client 001. +- The park has no table for the jump sessions. +- The table is a transparent table. + +# 4. Contract +- Create the transparent database table {{P}}JUMP in package $TMP. +- The table has exactly these fields: + +| Field | Type | Key | Not null | +| --- | --- | --- | --- | +| client | ABAP client, length 3 | yes | yes | +| session_id | CHAR, length 10 | yes | yes | +| visitor_id | CHAR, length 10 | no | no | +| jump_date | DATS, length 8 | no | no | +| jump_minutes | INT4, length 10 | no | no | +| locker_no | NUMC, length 4 | no | no | +| fee_amount | DEC, length 9, 2 decimal places | no | no | +| paid | CHAR, length 1 | no | no | + +- Enhancement category: not extensible. +- Delivery class: A. Data maintenance: restricted. + +# 5. Business rules +1. One row of the table is one jump session. +2. client and session_id are the key fields. A session_id is unique for each + client. +3. client and session_id are not null. All other fields can be initial. +4. visitor_id identifies the visitor. It has 10 characters. +5. jump_date is the day of the session. Its format is YYYYMMDD. +6. jump_minutes is the number of minutes of the session. It is a whole number. +7. locker_no is the number of the locker of the visitor. It has 4 characters. +8. fee_amount is the price of the session. It has 9 digits and 2 decimal places. +9. paid is a flag with one character. The value 'X' means that the visitor paid + the fee. An initial value means that the visitor did not pay. +10. A second row with the same client and the same session_id is not possible. + The insert of this row gives the return code 4. + +# 6. Constraints +- Release target: SAP_BASIS 816 (ABAP Platform 2025). +- Coding standards: Clean ABAP. No syntax error. No ATC priority 1 or 2 + findings. +- Out of scope: no other objects. Do not change any other object. + +# 7. Acceptance +- The table {{P}}JUMP is active. +- The table has the fields, the key fields and the data types of the contract. +- The hidden tests pass. +- Write ABAP Unit tests in a global test class. Use CL_OSQL_TEST_ENVIRONMENT. diff --git a/tasks_gen/train/G1920/task.json b/tasks_gen/train/G1920/task.json new file mode 100644 index 0000000..caf9117 --- /dev/null +++ b/tasks_gen/train/G1920/task.json @@ -0,0 +1,53 @@ +{ + "id": "G1920", + "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}}JUMP", + "fields": [ + "client", + "session_id", + "visitor_id", + "jump_date", + "jump_minutes", + "locker_no", + "fee_amount", + "paid" + ] + } + ], + "out_of_scope": [], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}JUMP_HIDDEN", + "file": "hidden/jump_hidden.clas.abap", + "description": "Hidden tests for the table {{P}}JUMP" + } + ], + "reference": [ + { + "type": "TABL", + "name": "{{P}}JUMP", + "file": "reference/jump.tabl.asabap", + "description": "Jump session table" + }, + { + "type": "CLAS", + "name": "{{P}}JUMP_TEST", + "file": "reference/jump_test.clas.abap", + "description": "Own tests for the table" + } + ], + "craft_checks": [] +} \ No newline at end of file diff --git a/tasks_gen/train/G1921/faulty/m0_if_kiln_quote.intf.abap b/tasks_gen/train/G1921/faulty/m0_if_kiln_quote.intf.abap new file mode 100644 index 0000000..6a3674b --- /dev/null +++ b/tasks_gen/train/G1921/faulty/m0_if_kiln_quote.intf.abap @@ -0,0 +1,55 @@ +INTERFACE {{p}}if_kiln_quote PUBLIC. + TYPES ty_reason TYPE c LENGTH 11. + TYPES ty_kiln TYPE c LENGTH 4. + TYPES ty_amount TYPE p LENGTH 7 DECIMALS 2. + + TYPES: BEGIN OF ty_load, + kiln TYPE ty_kiln, + pieces TYPE i, + weight_kg TYPE i, + glazed TYPE abap_bool, + END OF ty_load. + + TYPES: BEGIN OF ty_quote, + kiln TYPE ty_kiln, + base TYPE ty_amount, + weight TYPE ty_amount, + glaze TYPE ty_amount, + total TYPE ty_amount, + reason TYPE ty_reason, + END OF ty_quote. + + CONSTANTS: BEGIN OF c_kiln, + small TYPE ty_kiln VALUE 'SMAL', + medium TYPE ty_kiln VALUE 'MEDI', + large TYPE ty_kiln VALUE 'LARG', + END OF c_kiln. + + CONSTANTS: BEGIN OF c_reason, + ok TYPE ty_reason VALUE 'OK', + kiln TYPE ty_reason VALUE 'KILN', + pieces TYPE ty_reason VALUE 'PIECES', + weight TYPE ty_reason VALUE 'WEIGHT', + END OF c_reason. + + CONSTANTS: + c_base_small TYPE ty_amount VALUE '25.00', + c_base_medium TYPE ty_amount VALUE '40.00', + c_base_large TYPE ty_amount VALUE '60.00', + c_weight_rate TYPE ty_amount VALUE '1.50', + c_glaze_fee TYPE ty_amount VALUE '8.00', + c_max_pieces TYPE i VALUE 40, + c_max_weight TYPE i VALUE 120. + + METHODS check_load + IMPORTING is_load TYPE ty_load + RETURNING VALUE(rv_reason) TYPE ty_reason. + + METHODS kiln_fee + IMPORTING iv_kiln TYPE ty_kiln + RETURNING VALUE(rv_fee) TYPE ty_amount. + + METHODS quote + IMPORTING is_load TYPE ty_load + RETURNING VALUE(rs_quote) TYPE ty_quote. +ENDINTERFACE. diff --git a/tasks_gen/train/G1921/faulty/m2_if_kiln_quote.intf.abap b/tasks_gen/train/G1921/faulty/m2_if_kiln_quote.intf.abap new file mode 100644 index 0000000..4289fb4 --- /dev/null +++ b/tasks_gen/train/G1921/faulty/m2_if_kiln_quote.intf.abap @@ -0,0 +1,55 @@ +INTERFACE {{p}}if_kiln_quote PUBLIC. + TYPES ty_reason TYPE c LENGTH 12. + TYPES ty_kiln TYPE c LENGTH 4. + TYPES ty_amount TYPE p LENGTH 7 DECIMALS 2. + + TYPES: BEGIN OF ty_load, + kiln TYPE ty_kiln, + pieces TYPE i, + weight_kg TYPE i, + glazed TYPE abap_bool, + END OF ty_load. + + TYPES: BEGIN OF ty_quote, + kiln TYPE ty_kiln, + base TYPE ty_amount, + weight TYPE ty_amount, + glaze TYPE ty_amount, + total TYPE ty_amount, + reason TYPE ty_reason, + END OF ty_quote. + + CONSTANTS: BEGIN OF c_kiln, + small TYPE ty_kiln VALUE 'ZMAL', + medium TYPE ty_kiln VALUE 'MEDI', + large TYPE ty_kiln VALUE 'LARG', + END OF c_kiln. + + CONSTANTS: BEGIN OF c_reason, + ok TYPE ty_reason VALUE 'OK', + kiln TYPE ty_reason VALUE 'KILN', + pieces TYPE ty_reason VALUE 'PIECES', + weight TYPE ty_reason VALUE 'WEIGHT', + END OF c_reason. + + CONSTANTS: + c_base_small TYPE ty_amount VALUE '25.00', + c_base_medium TYPE ty_amount VALUE '40.00', + c_base_large TYPE ty_amount VALUE '60.00', + c_weight_rate TYPE ty_amount VALUE '1.50', + c_glaze_fee TYPE ty_amount VALUE '8.00', + c_max_pieces TYPE i VALUE 40, + c_max_weight TYPE i VALUE 120. + + METHODS check_load + IMPORTING is_load TYPE ty_load + RETURNING VALUE(rv_reason) TYPE ty_reason. + + METHODS kiln_fee + IMPORTING iv_kiln TYPE ty_kiln + RETURNING VALUE(rv_fee) TYPE ty_amount. + + METHODS quote + IMPORTING is_load TYPE ty_load + RETURNING VALUE(rs_quote) TYPE ty_quote. +ENDINTERFACE. diff --git a/tasks_gen/train/G1921/faulty/m4_if_kiln_quote.intf.abap b/tasks_gen/train/G1921/faulty/m4_if_kiln_quote.intf.abap new file mode 100644 index 0000000..661ad8c --- /dev/null +++ b/tasks_gen/train/G1921/faulty/m4_if_kiln_quote.intf.abap @@ -0,0 +1,55 @@ +INTERFACE {{p}}if_kiln_quote PUBLIC. + TYPES ty_reason TYPE c LENGTH 12. + TYPES ty_kiln TYPE c LENGTH 4. + TYPES ty_amount TYPE p LENGTH 7 DECIMALS 2. + + TYPES: BEGIN OF ty_load, + kiln TYPE ty_kiln, + pieces TYPE i, + weight_kg TYPE i, + glazed TYPE abap_bool, + END OF ty_load. + + TYPES: BEGIN OF ty_quote, + kiln TYPE ty_kiln, + base TYPE ty_amount, + weight TYPE ty_amount, + glaze TYPE ty_amount, + total TYPE ty_amount, + reason TYPE ty_reason, + END OF ty_quote. + + CONSTANTS: BEGIN OF c_kiln, + small TYPE ty_kiln VALUE 'SMAL', + medium TYPE ty_kiln VALUE 'MEDI', + large TYPE ty_kiln VALUE 'LARG', + END OF c_kiln. + + CONSTANTS: BEGIN OF c_reason, + ok TYPE ty_reason VALUE 'OK', + kiln TYPE ty_reason VALUE 'KILN', + pieces TYPE ty_reason VALUE 'PIECES', + weight TYPE ty_reason VALUE 'WEIGHT', + END OF c_reason. + + CONSTANTS: + c_base_small TYPE ty_amount VALUE '25.00', + c_base_medium TYPE ty_amount VALUE '40.00', + c_base_large TYPE ty_amount VALUE '60.00', + c_weight_rate TYPE ty_amount VALUE '1.50', + c_glaze_fee TYPE ty_amount VALUE '8.00', + c_max_pieces TYPE i VALUE 40, + c_max_weight TYPE i VALUE 121. + + METHODS check_load + IMPORTING is_load TYPE ty_load + RETURNING VALUE(rv_reason) TYPE ty_reason. + + METHODS kiln_fee + IMPORTING iv_kiln TYPE ty_kiln + RETURNING VALUE(rv_fee) TYPE ty_amount. + + METHODS quote + IMPORTING is_load TYPE ty_load + RETURNING VALUE(rs_quote) TYPE ty_quote. +ENDINTERFACE. diff --git a/tasks_gen/train/G1921/generation.json b/tasks_gen/train/G1921/generation.json new file mode 100644 index 0000000..52f2b35 --- /dev/null +++ b/tasks_gen/train/G1921/generation.json @@ -0,0 +1,34 @@ +{ + "id": "G1921", + "pool": "train", + "object_type": "INTF", + "category": "A", + "attempts": [ + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 77.7, + "null": 0 + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 4, + "killed": 3, + "ok": true + } + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1921/hidden/t02_hidden.clas.abap b/tasks_gen/train/G1921/hidden/t02_hidden.clas.abap new file mode 100644 index 0000000..156bd6f --- /dev/null +++ b/tasks_gen/train/G1921/hidden/t02_hidden.clas.abap @@ -0,0 +1,148 @@ +CLASS {{p}}t02_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + + PUBLIC SECTION. + INTERFACES {{p}}if_kiln_quote. + + PRIVATE SECTION. + METHODS kiln_codes FOR TESTING. + METHODS reason_codes FOR TESTING. + METHODS base_fees FOR TESTING. + METHODS extra_fees FOR TESTING. + METHODS load_limits FOR TESTING. + METHODS reason_type_length FOR TESTING. + METHODS kiln_type_length FOR TESTING. + METHODS amount_decimals FOR TESTING. + METHODS load_structure FOR TESTING. + METHODS quote_structure FOR TESTING. + METHODS methods_callable FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t02_hidden IMPLEMENTATION. + METHOD {{p}}if_kiln_quote~check_load. + rv_reason = {{p}}if_kiln_quote=>c_reason-ok. + ENDMETHOD. + + METHOD {{p}}if_kiln_quote~kiln_fee. + rv_fee = {{p}}if_kiln_quote=>c_base_small. + ENDMETHOD. + + METHOD {{p}}if_kiln_quote~quote. + rs_quote-kiln = is_load-kiln. + rs_quote-reason = {{p}}if_kiln_quote=>c_reason-ok. + ENDMETHOD. + + METHOD kiln_codes. + cl_abap_unit_assert=>assert_equals( exp = 'SMAL' act = {{p}}if_kiln_quote=>c_kiln-small ). + cl_abap_unit_assert=>assert_equals( exp = 'MEDI' act = {{p}}if_kiln_quote=>c_kiln-medium ). + cl_abap_unit_assert=>assert_equals( exp = 'LARG' act = {{p}}if_kiln_quote=>c_kiln-large ). + ENDMETHOD. + + METHOD reason_codes. + cl_abap_unit_assert=>assert_equals( exp = 'OK' act = {{p}}if_kiln_quote=>c_reason-ok ). + cl_abap_unit_assert=>assert_equals( exp = 'KILN' act = {{p}}if_kiln_quote=>c_reason-kiln ). + cl_abap_unit_assert=>assert_equals( exp = 'PIECES' act = {{p}}if_kiln_quote=>c_reason-pieces ). + cl_abap_unit_assert=>assert_equals( exp = 'WEIGHT' act = {{p}}if_kiln_quote=>c_reason-weight ). + ENDMETHOD. + + METHOD base_fees. + DATA lv_exp TYPE {{p}}if_kiln_quote=>ty_amount. + lv_exp = '25.00'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = {{p}}if_kiln_quote=>c_base_small ). + lv_exp = '40.00'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = {{p}}if_kiln_quote=>c_base_medium ). + lv_exp = '60.00'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = {{p}}if_kiln_quote=>c_base_large ). + ENDMETHOD. + + METHOD extra_fees. + DATA lv_exp TYPE {{p}}if_kiln_quote=>ty_amount. + lv_exp = '1.50'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = {{p}}if_kiln_quote=>c_weight_rate ). + lv_exp = '8.00'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = {{p}}if_kiln_quote=>c_glaze_fee ). + ENDMETHOD. + + METHOD load_limits. + cl_abap_unit_assert=>assert_equals( exp = 40 act = {{p}}if_kiln_quote=>c_max_pieces ). + cl_abap_unit_assert=>assert_equals( exp = 120 act = {{p}}if_kiln_quote=>c_max_weight ). + ENDMETHOD. + + METHOD reason_type_length. + DATA lv_reason TYPE {{p}}if_kiln_quote=>ty_reason. + DATA lv_src TYPE string. + lv_src = 'ABCDEFGHIJKLM'. + lv_reason = lv_src. + cl_abap_unit_assert=>assert_equals( exp = 'ABCDEFGHIJKL' act = lv_reason ). + ENDMETHOD. + + METHOD kiln_type_length. + DATA lv_kiln TYPE {{p}}if_kiln_quote=>ty_kiln. + DATA lv_src TYPE string. + lv_src = 'ABCDE'. + lv_kiln = lv_src. + cl_abap_unit_assert=>assert_equals( exp = 'ABCD' act = lv_kiln ). + ENDMETHOD. + + METHOD amount_decimals. + DATA lv_amount TYPE {{p}}if_kiln_quote=>ty_amount. + cl_abap_unit_assert=>assert_equals( + exp = 2 + act = cl_abap_typedescr=>describe_by_data( lv_amount )->decimals ). + ENDMETHOD. + + METHOD load_structure. + DATA ls_load TYPE {{p}}if_kiln_quote=>ty_load. + DATA(lo_struct) = CAST cl_abap_structdescr( cl_abap_typedescr=>describe_by_data( ls_load ) ). + DATA(lt_comp) = lo_struct->get_components( ). + cl_abap_unit_assert=>assert_equals( exp = 4 act = lines( lt_comp ) ). + DATA(lv_names) = REDUCE string( INIT s TYPE string + FOR ls IN lt_comp + NEXT s = s && ls-name ). + cl_abap_unit_assert=>assert_true( xsdbool( lv_names CS 'KILN' ) ). + cl_abap_unit_assert=>assert_true( xsdbool( lv_names CS 'PIECES' ) ). + cl_abap_unit_assert=>assert_true( xsdbool( lv_names CS 'WEIGHT_KG' ) ). + cl_abap_unit_assert=>assert_true( xsdbool( lv_names CS 'GLAZED' ) ). + ENDMETHOD. + + METHOD quote_structure. + DATA ls_quote TYPE {{p}}if_kiln_quote=>ty_quote. + DATA(lo_struct) = CAST cl_abap_structdescr( cl_abap_typedescr=>describe_by_data( ls_quote ) ). + DATA(lt_comp) = lo_struct->get_components( ). + cl_abap_unit_assert=>assert_equals( exp = 6 act = lines( lt_comp ) ). + DATA(lv_names) = REDUCE string( INIT s TYPE string + FOR ls IN lt_comp + NEXT s = s && ls-name ). + cl_abap_unit_assert=>assert_true( xsdbool( lv_names CS 'KILN' ) ). + cl_abap_unit_assert=>assert_true( xsdbool( lv_names CS 'BASE' ) ). + cl_abap_unit_assert=>assert_true( xsdbool( lv_names CS 'WEIGHT' ) ). + cl_abap_unit_assert=>assert_true( xsdbool( lv_names CS 'GLAZE' ) ). + cl_abap_unit_assert=>assert_true( xsdbool( lv_names CS 'TOTAL' ) ). + cl_abap_unit_assert=>assert_true( xsdbool( lv_names CS 'REASON' ) ). + ENDMETHOD. + + METHOD methods_callable. + DATA lo_cut TYPE REF TO {{p}}if_kiln_quote. + lo_cut = me. + + DATA ls_load TYPE {{p}}if_kiln_quote=>ty_load. + ls_load-kiln = {{p}}if_kiln_quote=>c_kiln-small. + ls_load-pieces = 5. + ls_load-weight_kg = 10. + ls_load-glazed = abap_true. + + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_kiln_quote=>c_reason-ok + act = lo_cut->check_load( ls_load ) ). + + DATA(ls_quote) = lo_cut->quote( ls_load ). + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_kiln_quote=>c_reason-ok + act = ls_quote-reason ). + + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_kiln_quote=>c_base_small + act = lo_cut->kiln_fee( {{p}}if_kiln_quote=>c_kiln-small ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1921/mutation.json b/tasks_gen/train/G1921/mutation.json new file mode 100644 index 0000000..5285e7f --- /dev/null +++ b/tasks_gen/train/G1921/mutation.json @@ -0,0 +1,50 @@ +{ + "task": "G1921", + "mutants": [ + { + "object": "{{P}}IF_KILN_QUOTE", + "mutant": "line 2: LENGTH 12 -> LENGTH 11 (length)", + "status": "killed", + "hidden": "10/11", + "failed_tests": [ + "REASON_TYPE_LENGTH" + ] + }, + { + "object": "{{P}}IF_KILN_QUOTE", + "mutant": "line 4: LENGTH 7 -> LENGTH 6 (length)", + "status": "survived", + "hidden": "11/11", + "failed_tests": [] + }, + { + "object": "{{P}}IF_KILN_QUOTE", + "mutant": "line 23: VALUE 'SMAL' -> VALUE 'ZMAL' (lit)", + "status": "killed", + "hidden": "10/11", + "failed_tests": [ + "KILN_CODES" + ] + }, + { + "object": "{{P}}IF_KILN_QUOTE", + "mutant": "line 36: VALUE '25.00' -> VALUE 'Z5.00' (lit)", + "status": "invalid", + "hidden": "0/0", + "failed_tests": [] + }, + { + "object": "{{P}}IF_KILN_QUOTE", + "mutant": "line 42: VALUE 120 -> VALUE 121 (const)", + "status": "killed", + "hidden": "10/11", + "failed_tests": [ + "LOAD_LIMITS" + ] + } + ], + "valid": 4, + "killed": 3, + "kill_rate": 0.75, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1921/reference/if_kiln_quote.intf.abap b/tasks_gen/train/G1921/reference/if_kiln_quote.intf.abap new file mode 100644 index 0000000..8ff35df --- /dev/null +++ b/tasks_gen/train/G1921/reference/if_kiln_quote.intf.abap @@ -0,0 +1,55 @@ +INTERFACE {{p}}if_kiln_quote PUBLIC. + TYPES ty_reason TYPE c LENGTH 12. + TYPES ty_kiln TYPE c LENGTH 4. + TYPES ty_amount TYPE p LENGTH 7 DECIMALS 2. + + TYPES: BEGIN OF ty_load, + kiln TYPE ty_kiln, + pieces TYPE i, + weight_kg TYPE i, + glazed TYPE abap_bool, + END OF ty_load. + + TYPES: BEGIN OF ty_quote, + kiln TYPE ty_kiln, + base TYPE ty_amount, + weight TYPE ty_amount, + glaze TYPE ty_amount, + total TYPE ty_amount, + reason TYPE ty_reason, + END OF ty_quote. + + CONSTANTS: BEGIN OF c_kiln, + small TYPE ty_kiln VALUE 'SMAL', + medium TYPE ty_kiln VALUE 'MEDI', + large TYPE ty_kiln VALUE 'LARG', + END OF c_kiln. + + CONSTANTS: BEGIN OF c_reason, + ok TYPE ty_reason VALUE 'OK', + kiln TYPE ty_reason VALUE 'KILN', + pieces TYPE ty_reason VALUE 'PIECES', + weight TYPE ty_reason VALUE 'WEIGHT', + END OF c_reason. + + CONSTANTS: + c_base_small TYPE ty_amount VALUE '25.00', + c_base_medium TYPE ty_amount VALUE '40.00', + c_base_large TYPE ty_amount VALUE '60.00', + c_weight_rate TYPE ty_amount VALUE '1.50', + c_glaze_fee TYPE ty_amount VALUE '8.00', + c_max_pieces TYPE i VALUE 40, + c_max_weight TYPE i VALUE 120. + + METHODS check_load + IMPORTING is_load TYPE ty_load + RETURNING VALUE(rv_reason) TYPE ty_reason. + + METHODS kiln_fee + IMPORTING iv_kiln TYPE ty_kiln + RETURNING VALUE(rv_fee) TYPE ty_amount. + + METHODS quote + IMPORTING is_load TYPE ty_load + RETURNING VALUE(rs_quote) TYPE ty_quote. +ENDINTERFACE. diff --git a/tasks_gen/train/G1921/reference/if_kiln_quote_test.clas.abap b/tasks_gen/train/G1921/reference/if_kiln_quote_test.clas.abap new file mode 100644 index 0000000..4d441f1 --- /dev/null +++ b/tasks_gen/train/G1921/reference/if_kiln_quote_test.clas.abap @@ -0,0 +1,98 @@ +CLASS {{p}}if_kiln_quote_test DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + + PUBLIC SECTION. + INTERFACES {{p}}if_kiln_quote. + + PRIVATE SECTION. + METHODS kiln_codes FOR TESTING. + METHODS reason_codes FOR TESTING. + METHODS fee_values FOR TESTING. + METHODS type_lengths FOR TESTING. + METHODS methods_callable FOR TESTING. +ENDCLASS. + + +CLASS {{p}}if_kiln_quote_test IMPLEMENTATION. + METHOD {{p}}if_kiln_quote~check_load. + rv_reason = {{p}}if_kiln_quote=>c_reason-ok. + ENDMETHOD. + + METHOD {{p}}if_kiln_quote~kiln_fee. + rv_fee = {{p}}if_kiln_quote=>c_base_small. + ENDMETHOD. + + METHOD {{p}}if_kiln_quote~quote. + rs_quote-kiln = is_load-kiln. + rs_quote-reason = {{p}}if_kiln_quote=>c_reason-ok. + ENDMETHOD. + + METHOD kiln_codes. + cl_abap_unit_assert=>assert_equals( exp = 'SMAL' act = {{p}}if_kiln_quote=>c_kiln-small ). + cl_abap_unit_assert=>assert_equals( exp = 'MEDI' act = {{p}}if_kiln_quote=>c_kiln-medium ). + cl_abap_unit_assert=>assert_equals( exp = 'LARG' act = {{p}}if_kiln_quote=>c_kiln-large ). + ENDMETHOD. + + METHOD reason_codes. + cl_abap_unit_assert=>assert_equals( exp = 'OK' act = {{p}}if_kiln_quote=>c_reason-ok ). + cl_abap_unit_assert=>assert_equals( exp = 'KILN' act = {{p}}if_kiln_quote=>c_reason-kiln ). + cl_abap_unit_assert=>assert_equals( exp = 'PIECES' act = {{p}}if_kiln_quote=>c_reason-pieces ). + cl_abap_unit_assert=>assert_equals( exp = 'WEIGHT' act = {{p}}if_kiln_quote=>c_reason-weight ). + ENDMETHOD. + + METHOD fee_values. + DATA lv_exp TYPE {{p}}if_kiln_quote=>ty_amount. + lv_exp = '25.00'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = {{p}}if_kiln_quote=>c_base_small ). + lv_exp = '40.00'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = {{p}}if_kiln_quote=>c_base_medium ). + lv_exp = '60.00'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = {{p}}if_kiln_quote=>c_base_large ). + lv_exp = '1.50'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = {{p}}if_kiln_quote=>c_weight_rate ). + lv_exp = '8.00'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = {{p}}if_kiln_quote=>c_glaze_fee ). + cl_abap_unit_assert=>assert_equals( exp = 40 act = {{p}}if_kiln_quote=>c_max_pieces ). + cl_abap_unit_assert=>assert_equals( exp = 120 act = {{p}}if_kiln_quote=>c_max_weight ). + ENDMETHOD. + + METHOD type_lengths. + DATA lv_reason TYPE {{p}}if_kiln_quote=>ty_reason. + DATA lv_kiln TYPE {{p}}if_kiln_quote=>ty_kiln. + DATA lv_amount TYPE {{p}}if_kiln_quote=>ty_amount. + DATA lv_src TYPE string. + lv_src = 'ABCDEFGHIJKLM'. + lv_reason = lv_src. + cl_abap_unit_assert=>assert_equals( exp = 'ABCDEFGHIJKL' act = lv_reason ). + lv_src = 'ABCDE'. + lv_kiln = lv_src. + cl_abap_unit_assert=>assert_equals( exp = 'ABCD' act = lv_kiln ). + cl_abap_unit_assert=>assert_equals( + exp = 2 + act = cl_abap_typedescr=>describe_by_data( lv_amount )->decimals ). + ENDMETHOD. + + METHOD methods_callable. + DATA lo_cut TYPE REF TO {{p}}if_kiln_quote. + lo_cut = me. + + DATA ls_load TYPE {{p}}if_kiln_quote=>ty_load. + ls_load-kiln = {{p}}if_kiln_quote=>c_kiln-small. + ls_load-pieces = 5. + ls_load-weight_kg = 10. + ls_load-glazed = abap_false. + + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_kiln_quote=>c_reason-ok + act = lo_cut->check_load( ls_load ) ). + + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_kiln_quote=>c_base_small + act = lo_cut->kiln_fee( {{p}}if_kiln_quote=>c_kiln-small ) ). + + DATA(ls_quote) = lo_cut->quote( ls_load ). + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_kiln_quote=>c_reason-ok + act = ls_quote-reason ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1921/reference/if_kiln_quote_test.testclasses.abap b/tasks_gen/train/G1921/reference/if_kiln_quote_test.testclasses.abap new file mode 100644 index 0000000..7ebb841 --- /dev/null +++ b/tasks_gen/train/G1921/reference/if_kiln_quote_test.testclasses.abap @@ -0,0 +1,53 @@ +CLASS ltc_kiln_quote_contract DEFINITION FINAL FOR TESTING + DURATION SHORT RISK LEVEL HARMLESS. + + PRIVATE SECTION. + METHODS kiln_codes FOR TESTING. + METHODS reason_codes FOR TESTING. + METHODS fee_values FOR TESTING. + METHODS type_lengths FOR TESTING. +ENDCLASS. + + +CLASS ltc_kiln_quote_contract IMPLEMENTATION. + METHOD kiln_codes. + cl_abap_unit_assert=>assert_equals( exp = 'SMAL' act = {{p}}if_kiln_quote=>c_kiln-small ). + cl_abap_unit_assert=>assert_equals( exp = 'MEDI' act = {{p}}if_kiln_quote=>c_kiln-medium ). + cl_abap_unit_assert=>assert_equals( exp = 'LARG' act = {{p}}if_kiln_quote=>c_kiln-large ). + ENDMETHOD. + + METHOD reason_codes. + cl_abap_unit_assert=>assert_equals( exp = 'OK' act = {{p}}if_kiln_quote=>c_reason-ok ). + cl_abap_unit_assert=>assert_equals( exp = 'KILN' act = {{p}}if_kiln_quote=>c_reason-kiln ). + cl_abap_unit_assert=>assert_equals( exp = 'PIECES' act = {{p}}if_kiln_quote=>c_reason-pieces ). + cl_abap_unit_assert=>assert_equals( exp = 'WEIGHT' act = {{p}}if_kiln_quote=>c_reason-weight ). + ENDMETHOD. + + METHOD fee_values. + DATA lv_exp TYPE {{p}}if_kiln_quote=>ty_amount. + lv_exp = '25.00'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = {{p}}if_kiln_quote=>c_base_small ). + lv_exp = '40.00'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = {{p}}if_kiln_quote=>c_base_medium ). + lv_exp = '60.00'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = {{p}}if_kiln_quote=>c_base_large ). + cl_abap_unit_assert=>assert_equals( exp = 40 act = {{p}}if_kiln_quote=>c_max_pieces ). + cl_abap_unit_assert=>assert_equals( exp = 120 act = {{p}}if_kiln_quote=>c_max_weight ). + ENDMETHOD. + + METHOD type_lengths. + DATA lv_reason TYPE {{p}}if_kiln_quote=>ty_reason. + DATA lv_kiln TYPE {{p}}if_kiln_quote=>ty_kiln. + DATA lv_amount TYPE {{p}}if_kiln_quote=>ty_amount. + DATA lv_src TYPE string. + lv_src = 'ABCDEFGHIJKLM'. + lv_reason = lv_src. + cl_abap_unit_assert=>assert_equals( exp = 'ABCDEFGHIJKL' act = lv_reason ). + lv_src = 'ABCDE'. + lv_kiln = lv_src. + cl_abap_unit_assert=>assert_equals( exp = 'ABCD' act = lv_kiln ). + cl_abap_unit_assert=>assert_equals( + exp = 2 + act = cl_abap_typedescr=>describe_by_data( lv_amount )->decimals ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1921/spec.md b/tasks_gen/train/G1921/spec.md new file mode 100644 index 0000000..e217466 --- /dev/null +++ b/tasks_gen/train/G1921/spec.md @@ -0,0 +1,78 @@ +# 1. Goal + +A pottery studio fires the ceramic pieces of its customers in three kilns. The +studio has two front ends: a terminal in the workshop and a web shop. Both front +ends must use the same interface for the firing quote. Create this interface. + +# 2. Open questions + +None. + +# 3. Context + +- The package is $TMP, client 001. +- The interface {{P}}IF_KILN_QUOTE does not exist yet. +- The interface is the only object of this task. The two front ends are not part + of this task. +- The interface has no implementation and no test include. + +# 4. Contract + +Create the public interface {{P}}IF_KILN_QUOTE in package $TMP. The interface has +exactly these public components. + +Types: +- ty_reason: character, length 12. +- ty_kiln: character, length 4. +- ty_amount: packed number, length 7, 2 decimal places. +- ty_load: structure with the components kiln (ty_kiln), pieces (i), weight_kg (i) + and glazed (abap_bool), in this order. +- ty_quote: structure with the components kiln (ty_kiln), base (ty_amount), + weight (ty_amount), glaze (ty_amount), total (ty_amount) and reason (ty_reason), + in this order. + +Constants: +- c_kiln: structure with the components small, medium and large. Each component + has the type ty_kiln. +- c_reason: structure with the components ok, kiln, pieces and weight. Each + component has the type ty_reason. +- c_base_small, c_base_medium, c_base_large, c_weight_rate and c_glaze_fee: each + has the type ty_amount. +- c_max_pieces and c_max_weight: each has the type i. + +Methods: +- check_load: IMPORTING is_load TYPE ty_load, RETURNING VALUE(rv_reason) TYPE ty_reason. +- kiln_fee: IMPORTING iv_kiln TYPE ty_kiln, RETURNING VALUE(rv_fee) TYPE ty_amount. +- quote: IMPORTING is_load TYPE ty_load, RETURNING VALUE(rs_quote) TYPE ty_quote. + +Do not add other public components. + +# 5. Business rules + +1. The kiln codes are SMAL for the small kiln, MEDI for the medium kiln and LARG + for the large kiln. +2. The reason codes are OK, KILN, PIECES and WEIGHT. OK means that the load is + valid. KILN means that the kiln code is not one of the three kiln codes. + PIECES means that the number of pieces is less than 1 or more than + c_max_pieces. WEIGHT means that the weight is less than 1 kilogram or more + than c_max_weight kilograms. +3. The base fee of one firing is 25.00 for the small kiln, 40.00 for the medium + kiln and 60.00 for the large kiln. +4. The weight fee is 1.50 for each kilogram. +5. The glaze surcharge is 8.00 for a glazed load and 0.00 for an unglazed load. +6. c_max_pieces is 40. c_max_weight is 120. +7. All amounts are in EUR and have 2 decimal places. + +# 6. Constraints + +- Release target: 8.16. +- Coding standards: Clean ABAP. No comment that restates the code. +- Out of scope: the two front ends and every other object. Do not create a global + implementation of the interface. + +# 7. Acceptance + +- The interface {{P}}IF_KILN_QUOTE is active and has no syntax error. +- The hidden tests pass. +- Write your own ABAP Unit tests in the global test class {{P}}IF_KILN_QUOTE_TEST + in package $TMP. diff --git a/tasks_gen/train/G1921/task.json b/tasks_gen/train/G1921/task.json new file mode 100644 index 0000000..26fc3c6 --- /dev/null +++ b/tasks_gen/train/G1921/task.json @@ -0,0 +1,47 @@ +{ + "id": "G1921", + "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_KILN_QUOTE" + } + ], + "out_of_scope": [], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T02_HIDDEN", + "file": "hidden/t02_hidden.clas.abap", + "description": "Contract tests for {{P}}IF_KILN_QUOTE" + } + ], + "reference": [ + { + "type": "INTF", + "name": "{{P}}IF_KILN_QUOTE", + "file": "reference/if_kiln_quote.intf.abap", + "description": "Kiln quote contract of the pottery studio" + }, + { + "type": "CLAS", + "name": "{{P}}IF_KILN_QUOTE_TEST", + "file": "reference/if_kiln_quote_test.clas.abap", + "description": "Own tests for the interface", + "testclasses_file": "reference/if_kiln_quote_test.testclasses.abap" + } + ], + "craft_checks": [ + "method_length", + "db_operation_in_loop" + ] +} \ No newline at end of file diff --git a/tasks_gen/train/G1922/generation.json b/tasks_gen/train/G1922/generation.json new file mode 100644 index 0000000..0587b1a --- /dev/null +++ b/tasks_gen/train/G1922/generation.json @@ -0,0 +1,35 @@ +{ + "id": "G1922", + "pool": "train", + "object_type": "DDLS", + "category": "E", + "attempts": [ + { + "stage": "bundle", + "errors": [ + "Too close to task G0145 (similarity spec 0.57, rules 0.61, names 0.00). Choose a different business topic and different object names.", + "Too close to task G0146 (similarity spec 0.71, rules 0.64, names 0.00). Choose a different business topic and different object names.", + "Too close to task G0147 (similarity spec 0.73, rules 0.70, names 0.00). Choose a different business topic and different object names." + ], + "by_check": { + "extra": 3 + } + }, + { + "stage": "validate", + "oracle": null, + "null": null + }, + { + "stage": "validate", + "oracle": null, + "null": null + }, + { + "stage": "validate", + "oracle": null, + "null": null + } + ], + "accepted": false +} \ No newline at end of file diff --git a/tasks_gen/train/G1922/hidden/lift_usage_hidden.clas.abap b/tasks_gen/train/G1922/hidden/lift_usage_hidden.clas.abap new file mode 100644 index 0000000..1220808 --- /dev/null +++ b/tasks_gen/train/G1922/hidden/lift_usage_hidden.clas.abap @@ -0,0 +1,94 @@ +CLASS {{p}}lift_usage_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 hours_summed FOR TESTING. + METHODS service_count FOR TESTING. + METHODS last_service_date FOR TESTING. + METHODS trip_total FOR TESTING. + METHODS test_mode_excluded FOR TESTING. + METHODS lift_without_ops FOR TESTING. + METHODS one_row_per_mode FOR TESTING. + METHODS building_shown FOR TESTING. +ENDCLASS. + + +CLASS {{p}}lift_usage_hidden IMPLEMENTATION. + METHOD class_setup. + go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_LIFT_USAGE' ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + DATA lt_lift TYPE STANDARD TABLE OF {{p}}lift WITH EMPTY KEY. + DATA lt_op TYPE STANDARD TABLE OF {{p}}lift_op WITH EMPTY KEY. + go_env->clear_doubles( ). + lt_lift = VALUE #( ( lift_id = 'L1' building_id = 'B1' capacity_kg = '800.00' ) + ( lift_id = 'L2' building_id = 'B2' capacity_kg = '630.00' ) + ( lift_id = 'L3' building_id = 'B1' capacity_kg = '400.00' ) ). + lt_op = VALUE #( ( lift_id = 'L1' run_no = 1 run_date = '20240310' run_hours = '3.50' run_mode = 'AUTO' trips = 12 ) + ( lift_id = 'L1' run_no = 2 run_date = '20240315' run_hours = '1.50' run_mode = 'AUTO' trips = 5 ) + ( lift_id = 'L1' run_no = 3 run_date = '20240312' run_hours = '2.00' run_mode = 'MAN' trips = 8 ) + ( lift_id = 'L1' run_no = 4 run_date = '20240320' run_hours = '9.00' run_mode = 'TEST' trips = 99 ) + ( lift_id = 'L3' run_no = 1 run_date = '20240401' run_hours = '5.00' run_mode = 'AUTO' trips = 20 ) ). + go_env->insert_test_data( lt_lift ). + go_env->insert_test_data( lt_op ). + ENDMETHOD. + + METHOD hours_summed. + SELECT SINGLE service_hours FROM {{p}}i_lift_usage + WHERE lift_id = 'L1' AND run_mode = 'AUTO' INTO @DATA(lv_hours). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '5.00' ) + act = CONV decfloat34( lv_hours ) ). + ENDMETHOD. + + METHOD service_count. + SELECT SINGLE service_count FROM {{p}}i_lift_usage + WHERE lift_id = 'L1' AND run_mode = 'AUTO' INTO @DATA(lv_count). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lv_count ). + ENDMETHOD. + + METHOD last_service_date. + DATA lv_exp TYPE d VALUE '20240315'. + SELECT SINGLE last_service FROM {{p}}i_lift_usage + WHERE lift_id = 'L1' AND run_mode = 'AUTO' INTO @DATA(lv_date). + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_date ). + ENDMETHOD. + + METHOD trip_total. + SELECT SINGLE trip_total FROM {{p}}i_lift_usage + WHERE lift_id = 'L1' AND run_mode = 'AUTO' INTO @DATA(lv_trips). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '17' ) + act = CONV decfloat34( lv_trips ) ). + ENDMETHOD. + + METHOD test_mode_excluded. + SELECT COUNT(*) FROM {{p}}i_lift_usage + WHERE run_mode = 'TEST' INTO @DATA(lv_rows). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_rows ). + ENDMETHOD. + + METHOD lift_without_ops. + SELECT COUNT(*) FROM {{p}}i_lift_usage + WHERE lift_id = 'L2' INTO @DATA(lv_rows). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_rows ). + ENDMETHOD. + + METHOD one_row_per_mode. + SELECT COUNT(*) FROM {{p}}i_lift_usage + WHERE lift_id = 'L1' INTO @DATA(lv_rows). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lv_rows ). + ENDMETHOD. + + METHOD building_shown. + SELECT SINGLE building_id FROM {{p}}i_lift_usage + WHERE lift_id = 'L1' AND run_mode = 'AUTO' INTO @DATA(lv_building). + cl_abap_unit_assert=>assert_equals( exp = 'B1' act = lv_building ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1922/mutation.json b/tasks_gen/train/G1922/mutation.json new file mode 100644 index 0000000..43e20e4 --- /dev/null +++ b/tasks_gen/train/G1922/mutation.json @@ -0,0 +1,46 @@ +{ + "task": "T41", + "mutants": [ + { + "object": "{{P}}I_LIFT_USAGE", + "mutant": "element SERVICE_HOURS: sum( -> max( (agg)", + "status": "killed", + "hidden": "7/8", + "failed_tests": [ + "HOURS_SUMMED" + ] + }, + { + "object": "{{P}}I_LIFT_USAGE", + "mutant": "join: inner join -> left outer join (join)", + "status": "killed", + "hidden": "7/8", + "failed_tests": [ + "LIFT_WITHOUT_OPS" + ] + }, + { + "object": "{{P}}I_LIFT_USAGE", + "mutant": "join condition: remove o.run_mode <> 'TEST' (cond)", + "status": "killed", + "hidden": "6/8", + "failed_tests": [ + "TEST_MODE_EXCLUDED", + "ONE_ROW_PER_MODE" + ] + }, + { + "object": "{{P}}I_LIFT_USAGE", + "mutant": "element LAST_SERVICE: max( -> min( (agg)", + "status": "killed", + "hidden": "7/8", + "failed_tests": [ + "LAST_SERVICE_DATE" + ] + } + ], + "valid": 4, + "killed": 4, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1922/reference/i_lift_usage.ddls.asddls b/tasks_gen/train/G1922/reference/i_lift_usage.ddls.asddls new file mode 100644 index 0000000..9ccee7c --- /dev/null +++ b/tasks_gen/train/G1922/reference/i_lift_usage.ddls.asddls @@ -0,0 +1,16 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Lift usage' +define view entity {{P}}I_LIFT_USAGE + as select from {{p}}lift as l + inner join {{p}}lift_op as o on o.lift_id = l.lift_id + and o.run_mode <> 'TEST' +{ + key l.lift_id as lift_id, + key o.run_mode as run_mode, + l.building_id as building_id, + sum( o.run_hours ) as service_hours, + count( * ) as service_count, + max( o.run_date ) as last_service, + sum( o.trips ) as trip_total +} +group by l.lift_id, o.run_mode, l.building_id diff --git a/tasks_gen/train/G1922/reference/lift_usage_test.clas.abap b/tasks_gen/train/G1922/reference/lift_usage_test.clas.abap new file mode 100644 index 0000000..bae4cd8 --- /dev/null +++ b/tasks_gen/train/G1922/reference/lift_usage_test.clas.abap @@ -0,0 +1,50 @@ +CLASS {{p}}lift_usage_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_mode FOR TESTING. + METHODS test_runs_are_ignored FOR TESTING. +ENDCLASS. + + +CLASS {{p}}lift_usage_test IMPLEMENTATION. + METHOD class_setup. + go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_LIFT_USAGE' ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + DATA lt_lift TYPE STANDARD TABLE OF {{p}}lift WITH EMPTY KEY. + DATA lt_op TYPE STANDARD TABLE OF {{p}}lift_op WITH EMPTY KEY. + go_env->clear_doubles( ). + lt_lift = VALUE #( ( lift_id = 'L1' building_id = 'B1' capacity_kg = '800.00' ) ). + lt_op = VALUE #( ( lift_id = 'L1' run_no = 1 run_date = '20240310' run_hours = '2.00' run_mode = 'AUTO' trips = 4 ) + ( lift_id = 'L1' run_no = 2 run_date = '20240311' run_hours = '1.00' run_mode = 'AUTO' trips = 6 ) + ( lift_id = 'L1' run_no = 3 run_date = '20240312' run_hours = '8.00' run_mode = 'TEST' trips = 50 ) ). + go_env->insert_test_data( lt_lift ). + go_env->insert_test_data( lt_op ). + ENDMETHOD. + + METHOD totals_of_one_mode. + SELECT SINGLE service_hours, service_count, last_service, trip_total + FROM {{p}}i_lift_usage + WHERE lift_id = 'L1' AND run_mode = 'AUTO' + INTO @DATA(ls_row). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '3.00' ) + act = CONV decfloat34( ls_row-service_hours ) ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = ls_row-service_count ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '10' ) + act = CONV decfloat34( ls_row-trip_total ) ). + ENDMETHOD. + + METHOD test_runs_are_ignored. + SELECT COUNT(*) FROM {{p}}i_lift_usage INTO @DATA(lv_rows). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lv_rows ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1922/seed/i_lift_usage.ddls.asddls b/tasks_gen/train/G1922/seed/i_lift_usage.ddls.asddls new file mode 100644 index 0000000..4a5ca05 --- /dev/null +++ b/tasks_gen/train/G1922/seed/i_lift_usage.ddls.asddls @@ -0,0 +1,16 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Lift usage' +define view entity {{P}}I_LIFT_USAGE + as select from {{p}}lift as l + inner join {{p}}lift_op as o on o.lift_id = l.lift_id + and o.run_mode <> 'TEST' +{ + key l.lift_id as lift_id, + key o.run_mode as run_mode, + l.building_id as building_id, + sum( o.run_hours ) as hours, + count( * ) as run_count, + max( o.run_date ) as last_run, + sum( o.trips ) as value +} +group by l.lift_id, o.run_mode, l.building_id diff --git a/tasks_gen/train/G1922/seed/lift.tabl.asabap b/tasks_gen/train/G1922/seed/lift.tabl.asabap new file mode 100644 index 0000000..6ed3296 --- /dev/null +++ b/tasks_gen/train/G1922/seed/lift.tabl.asabap @@ -0,0 +1,11 @@ +@EndUserText.label : 'Lift' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}lift { + key client : abap.clnt not null; + key lift_id : abap.char(10) not null; + building_id : abap.char(10); + capacity_kg : abap.dec(15,2); +} diff --git a/tasks_gen/train/G1922/seed/lift_op.tabl.asabap b/tasks_gen/train/G1922/seed/lift_op.tabl.asabap new file mode 100644 index 0000000..ed5a821 --- /dev/null +++ b/tasks_gen/train/G1922/seed/lift_op.tabl.asabap @@ -0,0 +1,14 @@ +@EndUserText.label : 'Lift operation' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}lift_op { + key client : abap.clnt not null; + key lift_id : abap.char(10) not null; + key run_no : abap.int4 not null; + run_date : abap.dats; + run_hours : abap.dec(5,2); + run_mode : abap.char(4); + trips : abap.int4; +} diff --git a/tasks_gen/train/G1922/spec.md b/tasks_gen/train/G1922/spec.md new file mode 100644 index 0000000..b099540 --- /dev/null +++ b/tasks_gen/train/G1922/spec.md @@ -0,0 +1,44 @@ +# 1. Goal +A lift service company keeps the operating data of its lifts in the tables +{{P}}LIFT and {{P}}LIFT_OP. The CDS view entity {{P}}I_LIFT_USAGE in package $TMP +was written years ago. Its element names are SQL words, so the reporting layer +and the OData service cannot consume the view. Refactor the view in place: the +view name stays, the result stays, the element names become clean. + +# 2. Open questions +None. + +# 3. Context +- {{P}}I_LIFT_USAGE is an active CDS view entity in package $TMP. +- It reads {{P}}LIFT (the lift master data) and {{P}}LIFT_OP (one row for each + operating run of a lift). +- Nobody documented the view. The source of the view is the only specification + of the numbers that it calculates. +- The two tables are not part of this task. + +# 4. Contract +- Refactor the CDS view entity {{P}}I_LIFT_USAGE in package $TMP. The name of the + view does not change. +- The view has these elements with exactly these names: LIFT_ID (key), RUN_MODE + (key), BUILDING_ID, SERVICE_HOURS, SERVICE_COUNT, LAST_SERVICE, TRIP_TOTAL. +- The authorization check stays #NOT_REQUIRED. + +# 5. Business rules +1. The result of the view does not change. For every content of {{P}}LIFT and + {{P}}LIFT_OP the refactored view returns the same rows and the same values as + the legacy view. +2. The legacy source contains the rules. Read the legacy source before you + change it. Do not drop a rule and do not add a rule. +3. No element name is a reserved word and no element name is an SQL word. + +# 6. Constraints +- Release target: 8.16. +- Coding standards: Clean ABAP. Never use a reserved word or an SQL word as an + element name. +- Out of scope: {{P}}LIFT and {{P}}LIFT_OP stay as they are. + +# 7. Acceptance +- The view is active and free of syntax errors. +- The element names are the names of the contract. +- The hidden tests pass. +- Write ABAP Unit tests with CL_CDS_TEST_ENVIRONMENT in a global test class. diff --git a/tasks_gen/train/G1922/task.json b/tasks_gen/train/G1922/task.json new file mode 100644 index 0000000..6a85ba1 --- /dev/null +++ b/tasks_gen/train/G1922/task.json @@ -0,0 +1,74 @@ +{ + "id": "G1922", + "category": "E", + "object_type": "DDLS", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [ + { + "type": "TABL", + "name": "{{P}}LIFT", + "file": "seed/lift.tabl.asabap", + "description": "Lift master data" + }, + { + "type": "TABL", + "name": "{{P}}LIFT_OP", + "file": "seed/lift_op.tabl.asabap", + "description": "Operating run of a lift" + }, + { + "type": "DDLS", + "name": "{{P}}I_LIFT_USAGE", + "file": "seed/i_lift_usage.ddls.asddls", + "description": "Legacy view with SQL words as element names (refactor in place)" + } + ], + "contract": [ + { + "type": "DDLS", + "name": "{{P}}I_LIFT_USAGE", + "fields": [ + "LIFT_ID", + "RUN_MODE", + "BUILDING_ID", + "SERVICE_HOURS", + "SERVICE_COUNT", + "LAST_SERVICE", + "TRIP_TOTAL" + ] + } + ], + "out_of_scope": [ + "{{P}}LIFT", + "{{P}}LIFT_OP" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}LIFT_USAGE_HIDDEN", + "file": "hidden/lift_usage_hidden.clas.abap", + "description": "Hidden tests for the refactored view" + } + ], + "reference": [ + { + "type": "DDLS", + "name": "{{P}}I_LIFT_USAGE", + "file": "reference/i_lift_usage.ddls.asddls", + "description": "Refactored view with clean element names" + }, + { + "type": "CLAS", + "name": "{{P}}LIFT_USAGE_TEST", + "file": "reference/lift_usage_test.clas.abap", + "description": "Own tests for the view" + } + ], + "craft_checks": [] +} \ No newline at end of file diff --git a/tasks_gen/train/G1923/faulty/m1_i_forge_job.ddls.asddls b/tasks_gen/train/G1923/faulty/m1_i_forge_job.ddls.asddls new file mode 100644 index 0000000..56af341 --- /dev/null +++ b/tasks_gen/train/G1923/faulty/m1_i_forge_job.ddls.asddls @@ -0,0 +1,20 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Open forge jobs' +define view entity {{P}}I_FORGE_JOB + as select from {{p}}forgjob as job + inner join {{p}}forgart as art on art.article_id = job.article_id + inner join {{p}}forgcus as cus on cus.customer_id <> art.customer_id +{ + key job.job_id as job_id, + job.job_date as job_date, + art.article_name as article_name, + art.weight_kg as weight_kg, + cus.customer_name as customer_name, + cus.city as city, + job.work_min as work_min, + case when job.work_min > 120 + then 'HEAVY' + else 'LIGHT' + end as effort +} +where job.job_state = 'O' diff --git a/tasks_gen/train/G1923/faulty/m2_i_forge_job.ddls.asddls b/tasks_gen/train/G1923/faulty/m2_i_forge_job.ddls.asddls new file mode 100644 index 0000000..19bee4f --- /dev/null +++ b/tasks_gen/train/G1923/faulty/m2_i_forge_job.ddls.asddls @@ -0,0 +1,20 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Open forge jobs' +define view entity {{P}}I_FORGE_JOB + as select from {{p}}forgjob as job + inner join {{p}}forgart as art on art.article_id = job.article_id + inner join {{p}}forgcus as cus on cus.customer_id = art.customer_id +{ + key job.job_id as job_id, + job.job_date as job_date, + art.article_name as article_name, + art.weight_kg as weight_kg, + cus.customer_name as customer_name, + cus.city as city, + job.work_min as work_min, + case when job.work_min > 121 + then 'HEAVY' + else 'LIGHT' + end as effort +} +where job.job_state = 'O' diff --git a/tasks_gen/train/G1923/faulty/m3_i_forge_job.ddls.asddls b/tasks_gen/train/G1923/faulty/m3_i_forge_job.ddls.asddls new file mode 100644 index 0000000..34eef0c --- /dev/null +++ b/tasks_gen/train/G1923/faulty/m3_i_forge_job.ddls.asddls @@ -0,0 +1,20 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Open forge jobs' +define view entity {{P}}I_FORGE_JOB + as select from {{p}}forgjob as job + inner join {{p}}forgart as art on art.article_id = job.article_id + inner join {{p}}forgcus as cus on cus.customer_id = art.customer_id +{ + key job.job_id as job_id, + job.job_date as job_date, + art.article_name as article_name, + art.weight_kg as weight_kg, + cus.customer_name as customer_name, + cus.city as city, + job.work_min as work_min, + case when job.work_min > 120 + then 'ZEAVY' + else 'LIGHT' + end as effort +} +where job.job_state = 'O' diff --git a/tasks_gen/train/G1923/faulty/m4_i_forge_job.ddls.asddls b/tasks_gen/train/G1923/faulty/m4_i_forge_job.ddls.asddls new file mode 100644 index 0000000..6508356 --- /dev/null +++ b/tasks_gen/train/G1923/faulty/m4_i_forge_job.ddls.asddls @@ -0,0 +1,20 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Open forge jobs' +define view entity {{P}}I_FORGE_JOB + as select from {{p}}forgjob as job + inner join {{p}}forgart as art on art.article_id = job.article_id + inner join {{p}}forgcus as cus on cus.customer_id = art.customer_id +{ + key job.job_id as job_id, + job.job_date as job_date, + art.article_name as article_name, + art.weight_kg as weight_kg, + cus.customer_name as customer_name, + cus.city as city, + job.work_min as work_min, + case when job.work_min > 120 + then 'HEAVY' + else 'ZIGHT' + end as effort +} +where job.job_state = 'O' diff --git a/tasks_gen/train/G1923/generation.json b/tasks_gen/train/G1923/generation.json new file mode 100644 index 0000000..0c0e019 --- /dev/null +++ b/tasks_gen/train/G1923/generation.json @@ -0,0 +1,39 @@ +{ + "id": "G1923", + "pool": "train", + "object_type": "DDLS", + "category": "E", + "attempts": [ + { + "stage": "bundle", + "errors": [ + "Too close to task G0146 (similarity spec 0.70, rules 0.71, names 0.00). Choose a different business topic and different object names.", + "Too close to task G0147 (similarity spec 0.64, rules 0.73, names 0.00). Choose a different business topic and different object names." + ], + "by_check": { + "extra": 2 + } + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 5, + "killed": 3, + "ok": false + } + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 5, + "killed": 4, + "ok": true + } + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1923/hidden/forge_hidden.clas.abap b/tasks_gen/train/G1923/hidden/forge_hidden.clas.abap new file mode 100644 index 0000000..bd02a14 --- /dev/null +++ b/tasks_gen/train/G1923/hidden/forge_hidden.clas.abap @@ -0,0 +1,127 @@ +CLASS {{p}}forge_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 open_jobs_only FOR TESTING. + METHODS done_job_hidden FOR TESTING. + METHODS job_without_article FOR TESTING. + METHODS job_without_customer FOR TESTING. + METHODS article_fields FOR TESTING. + METHODS customer_fields FOR TESTING. + METHODS heavy_effort FOR TESTING. + METHODS light_effort FOR TESTING. + METHODS exact_limit_light FOR TESTING. + METHODS work_min_shown FOR TESTING. + METHODS boundary_over_limit FOR TESTING. + METHODS missing_article_no_row FOR TESTING. +ENDCLASS. + + +CLASS {{p}}forge_hidden IMPLEMENTATION. + METHOD class_setup. + go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_FORGE_JOB' ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + DATA lt_job TYPE STANDARD TABLE OF {{p}}forgjob WITH EMPTY KEY. + DATA lt_art TYPE STANDARD TABLE OF {{p}}forgart WITH EMPTY KEY. + DATA lt_cus TYPE STANDARD TABLE OF {{p}}forgcus WITH EMPTY KEY. + go_env->clear_doubles( ). + lt_job = VALUE #( + ( job_id = 'B1' article_id = 'W1' job_date = '20240301' work_min = 200 job_state = 'O' ) + ( job_id = 'B2' article_id = 'W2' job_date = '20240302' work_min = 60 job_state = 'O' ) + ( job_id = 'B3' article_id = 'W3' job_date = '20240303' work_min = 90 job_state = 'O' ) + ( job_id = 'B4' article_id = 'W1' job_date = '20240304' work_min = 120 job_state = 'D' ) + ( job_id = 'B5' article_id = 'W4' job_date = '20240305' work_min = 30 job_state = 'O' ) + ( job_id = 'B6' article_id = 'W1' job_date = '20240306' work_min = 120 job_state = 'O' ) + ( job_id = 'B7' article_id = 'W2' job_date = '20240307' work_min = 121 job_state = 'O' ) + ( job_id = 'B8' article_id = 'W9' job_date = '20240308' work_min = 45 job_state = 'O' ) ). + lt_art = VALUE #( + ( article_id = 'W1' customer_id = 'K1' article_name = 'GATE' weight_kg = 40 ) + ( article_id = 'W2' customer_id = 'K2' article_name = 'FENCE' weight_kg = 25 ) + ( article_id = 'W4' customer_id = 'K9' article_name = 'RAILING' weight_kg = 15 ) ). + lt_cus = VALUE #( + ( customer_id = 'K1' customer_name = 'ALPHA' city = 'BREMEN' ) + ( customer_id = 'K2' customer_name = 'BETA' city = 'KIEL' ) + ( customer_id = '' customer_name = 'ORPHAN' city = 'NOWHERE' ) ). + go_env->insert_test_data( lt_job ). + go_env->insert_test_data( lt_art ). + go_env->insert_test_data( lt_cus ). + ENDMETHOD. + + METHOD open_jobs_only. + SELECT COUNT(*) FROM {{p}}i_forge_job INTO @DATA(lv_count). + cl_abap_unit_assert=>assert_equals( exp = 4 act = lv_count ). + ENDMETHOD. + + METHOD done_job_hidden. + SELECT COUNT(*) FROM {{p}}i_forge_job WHERE job_id = 'B4' INTO @DATA(lv_count). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_count ). + ENDMETHOD. + + METHOD job_without_article. + SELECT COUNT(*) FROM {{p}}i_forge_job WHERE job_id = 'B3' INTO @DATA(lv_count). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_count ). + ENDMETHOD. + + METHOD job_without_customer. + SELECT COUNT(*) FROM {{p}}i_forge_job WHERE job_id = 'B5' INTO @DATA(lv_count). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_count ). + ENDMETHOD. + + METHOD article_fields. + SELECT SINGLE article_name, weight_kg FROM {{p}}i_forge_job + WHERE job_id = 'B1' INTO @DATA(ls_row). + cl_abap_unit_assert=>assert_equals( exp = 'GATE' act = ls_row-article_name ). + cl_abap_unit_assert=>assert_equals( exp = 40 act = ls_row-weight_kg ). + ENDMETHOD. + + METHOD customer_fields. + SELECT SINGLE customer_name, city FROM {{p}}i_forge_job + WHERE job_id = 'B2' INTO @DATA(ls_row). + cl_abap_unit_assert=>assert_equals( exp = 'BETA' act = ls_row-customer_name ). + cl_abap_unit_assert=>assert_equals( exp = 'KIEL' act = ls_row-city ). + ENDMETHOD. + + METHOD heavy_effort. + SELECT SINGLE effort FROM {{p}}i_forge_job + WHERE job_id = 'B1' INTO @DATA(lv_effort). + cl_abap_unit_assert=>assert_equals( exp = 'HEAVY' act = lv_effort ). + ENDMETHOD. + + METHOD light_effort. + SELECT SINGLE effort FROM {{p}}i_forge_job + WHERE job_id = 'B2' INTO @DATA(lv_effort). + cl_abap_unit_assert=>assert_equals( exp = 'LIGHT' act = lv_effort ). + ENDMETHOD. + + METHOD exact_limit_light. + SELECT SINGLE effort FROM {{p}}i_forge_job + WHERE job_id = 'B6' INTO @DATA(lv_effort). + cl_abap_unit_assert=>assert_equals( exp = 'LIGHT' act = lv_effort ). + ENDMETHOD. + + METHOD work_min_shown. + SELECT SINGLE work_min FROM {{p}}i_forge_job + WHERE job_id = 'B6' INTO @DATA(lv_min). + cl_abap_unit_assert=>assert_equals( exp = 120 act = lv_min ). + ENDMETHOD. + + METHOD boundary_over_limit. + SELECT SINGLE effort FROM {{p}}i_forge_job + WHERE job_id = 'B7' INTO @DATA(lv_effort). + cl_abap_unit_assert=>assert_equals( exp = 'HEAVY' act = lv_effort ). + ENDMETHOD. + + METHOD missing_article_no_row. + SELECT COUNT(*) FROM {{p}}i_forge_job WHERE job_id = 'B8' INTO @DATA(lv_count). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_count ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1923/mutation.json b/tasks_gen/train/G1923/mutation.json new file mode 100644 index 0000000..0121854 --- /dev/null +++ b/tasks_gen/train/G1923/mutation.json @@ -0,0 +1,56 @@ +{ + "task": "G1923", + "mutants": [ + { + "object": "{{P}}I_FORGE_JOB", + "mutant": "line 5: inner join -> left outer join (join)", + "status": "survived", + "hidden": "12/12", + "failed_tests": [] + }, + { + "object": "{{P}}I_FORGE_JOB", + "mutant": "line 6: = -> <> (eq)", + "status": "killed", + "hidden": "9/12", + "failed_tests": [ + "CUSTOMER_FIELDS", + "JOB_WITHOUT_CUSTOMER", + "OPEN_JOBS_ONLY" + ] + }, + { + "object": "{{P}}I_FORGE_JOB", + "mutant": "line 15: 120 -> 121 (const)", + "status": "killed", + "hidden": "11/12", + "failed_tests": [ + "BOUNDARY_OVER_LIMIT" + ] + }, + { + "object": "{{P}}I_FORGE_JOB", + "mutant": "line 16: 'HEAVY' -> 'ZEAVY' (lit)", + "status": "killed", + "hidden": "10/12", + "failed_tests": [ + "BOUNDARY_OVER_LIMIT", + "HEAVY_EFFORT" + ] + }, + { + "object": "{{P}}I_FORGE_JOB", + "mutant": "line 17: 'LIGHT' -> 'ZIGHT' (lit)", + "status": "killed", + "hidden": "10/12", + "failed_tests": [ + "EXACT_LIMIT_LIGHT", + "LIGHT_EFFORT" + ] + } + ], + "valid": 5, + "killed": 4, + "kill_rate": 0.8, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1923/reference/forge_test.clas.abap b/tasks_gen/train/G1923/reference/forge_test.clas.abap new file mode 100644 index 0000000..356f709 --- /dev/null +++ b/tasks_gen/train/G1923/reference/forge_test.clas.abap @@ -0,0 +1,60 @@ +CLASS {{p}}forge_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 shows_open_job FOR TESTING. + METHODS hides_done_job FOR TESTING. + METHODS effort_boundary FOR TESTING. +ENDCLASS. + + +CLASS {{p}}forge_test IMPLEMENTATION. + METHOD class_setup. + go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_FORGE_JOB' ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + DATA lt_job TYPE STANDARD TABLE OF {{p}}forgjob WITH EMPTY KEY. + DATA lt_art TYPE STANDARD TABLE OF {{p}}forgart WITH EMPTY KEY. + DATA lt_cus TYPE STANDARD TABLE OF {{p}}forgcus WITH EMPTY KEY. + go_env->clear_doubles( ). + lt_job = VALUE #( + ( job_id = 'C1' article_id = 'X1' job_date = '20240401' work_min = 180 job_state = 'O' ) + ( job_id = 'C2' article_id = 'X1' job_date = '20240402' work_min = 20 job_state = 'D' ) + ( job_id = 'C3' article_id = 'X1' job_date = '20240403' work_min = 121 job_state = 'O' ) ). + lt_art = VALUE #( + ( article_id = 'X1' customer_id = 'D1' article_name = 'GRID' weight_kg = 55 ) ). + lt_cus = VALUE #( + ( customer_id = 'D1' customer_name = 'SMITH' city = 'ESSEN' ) ). + go_env->insert_test_data( lt_job ). + go_env->insert_test_data( lt_art ). + go_env->insert_test_data( lt_cus ). + ENDMETHOD. + + METHOD shows_open_job. + SELECT SINGLE job_id, article_name, customer_name, effort FROM {{p}}i_forge_job + WHERE job_id = 'C1' INTO @DATA(ls_row). + cl_abap_unit_assert=>assert_equals( exp = 'C1' act = ls_row-job_id ). + cl_abap_unit_assert=>assert_equals( exp = 'GRID' act = ls_row-article_name ). + cl_abap_unit_assert=>assert_equals( exp = 'SMITH' act = ls_row-customer_name ). + cl_abap_unit_assert=>assert_equals( exp = 'HEAVY' act = ls_row-effort ). + ENDMETHOD. + + METHOD hides_done_job. + SELECT COUNT(*) FROM {{p}}i_forge_job WHERE job_id = 'C2' INTO @DATA(lv_count). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_count ). + ENDMETHOD. + + METHOD effort_boundary. + SELECT SINGLE effort FROM {{p}}i_forge_job + WHERE job_id = 'C3' INTO @DATA(lv_effort). + cl_abap_unit_assert=>assert_equals( exp = 'HEAVY' act = lv_effort ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1923/reference/i_forge_job.ddls.asddls b/tasks_gen/train/G1923/reference/i_forge_job.ddls.asddls new file mode 100644 index 0000000..86a33e4 --- /dev/null +++ b/tasks_gen/train/G1923/reference/i_forge_job.ddls.asddls @@ -0,0 +1,20 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Open forge jobs' +define view entity {{P}}I_FORGE_JOB + as select from {{p}}forgjob as job + inner join {{p}}forgart as art on art.article_id = job.article_id + inner join {{p}}forgcus as cus on cus.customer_id = art.customer_id +{ + key job.job_id as job_id, + job.job_date as job_date, + art.article_name as article_name, + art.weight_kg as weight_kg, + cus.customer_name as customer_name, + cus.city as city, + job.work_min as work_min, + case when job.work_min > 120 + then 'HEAVY' + else 'LIGHT' + end as effort +} +where job.job_state = 'O' diff --git a/tasks_gen/train/G1923/seed/forgart.tabl.asabap b/tasks_gen/train/G1923/seed/forgart.tabl.asabap new file mode 100644 index 0000000..0ec616e --- /dev/null +++ b/tasks_gen/train/G1923/seed/forgart.tabl.asabap @@ -0,0 +1,12 @@ +@EndUserText.label : 'Forged article' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}forgart { + key client : abap.clnt not null; + key article_id : abap.char(10) not null; + customer_id : abap.char(10); + article_name : abap.char(20); + weight_kg : abap.int4; +} diff --git a/tasks_gen/train/G1923/seed/forgcus.tabl.asabap b/tasks_gen/train/G1923/seed/forgcus.tabl.asabap new file mode 100644 index 0000000..3c96019 --- /dev/null +++ b/tasks_gen/train/G1923/seed/forgcus.tabl.asabap @@ -0,0 +1,11 @@ +@EndUserText.label : 'Forge customer' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}forgcus { + key client : abap.clnt not null; + key customer_id : abap.char(10) not null; + customer_name : abap.char(20); + city : abap.char(20); +} diff --git a/tasks_gen/train/G1923/seed/forgjob.tabl.asabap b/tasks_gen/train/G1923/seed/forgjob.tabl.asabap new file mode 100644 index 0000000..ee00d35 --- /dev/null +++ b/tasks_gen/train/G1923/seed/forgjob.tabl.asabap @@ -0,0 +1,13 @@ +@EndUserText.label : 'Forge job' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}forgjob { + key client : abap.clnt not null; + key job_id : abap.char(10) not null; + article_id : abap.char(10); + job_date : abap.dats; + work_min : abap.int4; + job_state : abap.char(1); +} diff --git a/tasks_gen/train/G1923/seed/i_forge_job.ddls.asddls b/tasks_gen/train/G1923/seed/i_forge_job.ddls.asddls new file mode 100644 index 0000000..f852493 --- /dev/null +++ b/tasks_gen/train/G1923/seed/i_forge_job.ddls.asddls @@ -0,0 +1,22 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Open forge jobs' +define view entity {{P}}I_FORGE_JOB + as select from {{p}}forgjob as job + inner join {{p}}forgart as a1 on a1.article_id = job.article_id + inner join {{p}}forgart as a2 on a2.article_id = job.article_id + inner join {{p}}forgcus as c1 on c1.customer_id = a1.customer_id + inner join {{p}}forgcus as c2 on c2.customer_id = a2.customer_id +{ + key job.job_id as job_id, + job.job_date as job_date, + a1.article_name as article_name, + a2.weight_kg as weight_kg, + c1.customer_name as customer_name, + c2.city as city, + job.work_min as work_min, + case when job.work_min > 120 + then 'HEAVY' + else 'LIGHT' + end as effort +} +where job.job_state = 'O' diff --git a/tasks_gen/train/G1923/spec.md b/tasks_gen/train/G1923/spec.md new file mode 100644 index 0000000..6e645bd --- /dev/null +++ b/tasks_gen/train/G1923/spec.md @@ -0,0 +1,49 @@ +# 1. Goal +The CDS view entity {{P}}I_FORGE_JOB in package $TMP lists the open jobs of a +blacksmith's forge. The current source of the view joins the same table more +than once. Rework the view so that every source table appears in the join one +time. The view keeps its name, its elements and its result rows. + +# 2. Open questions +None. + +# 3. Context +- {{P}}I_FORGE_JOB is an active CDS view entity in package $TMP. +- The view reads three tables: {{P}}FORGJOB, {{P}}FORGART and {{P}}FORGCUS. +- {{P}}FORGJOB holds one row for each job of the forge. Key: JOB_ID (CHAR 10). + Further fields: ARTICLE_ID (CHAR 10), JOB_DATE (DATS), WORK_MIN (INT4), + JOB_STATE (CHAR 1). +- {{P}}FORGART holds one row for each forged article. Key: ARTICLE_ID + (CHAR 10). Further fields: CUSTOMER_ID (CHAR 10), ARTICLE_NAME (CHAR 20), + WEIGHT_KG (INT4). +- {{P}}FORGCUS holds one row for each customer. Key: CUSTOMER_ID (CHAR 10). + Further fields: CUSTOMER_NAME (CHAR 20), CITY (CHAR 20). +- A report and an OData service read the view with the element names below. +- The current source of the view is part of the seed. Read it. It fixes the + result that the hidden tests expect. + +# 4. Contract +- Rework {{P}}I_FORGE_JOB in package $TMP. The name does not change. +- The elements do not change. Element names: JOB_ID (key), JOB_DATE, + ARTICLE_NAME, WEIGHT_KG, CUSTOMER_NAME, CITY, WORK_MIN, EFFORT. +- The element types do not change. +- Authorization check: #NOT_REQUIRED. + +# 5. Business rules +1. The result of the view does not change. The seed source of {{P}}I_FORGE_JOB + is the definition of the result. Read the seed source. +2. The number of rows, the element names and the element types stay as they + are today. + +# 6. Constraints +- Release target: SAP_BASIS 816 (ABAP Platform 2025), client 001. +- Quality goals: + - No source table of the view may appear in the join more than once. + - The view must stay readable and free of duplicated conditions. +- Coding standards: Clean ABAP, no ATC priority 1 or priority 2 findings. +- Out of scope: do not change {{P}}FORGJOB, {{P}}FORGART and {{P}}FORGCUS. + +# 7. Acceptance +- The view {{P}}I_FORGE_JOB is active and free of syntax errors. +- The hidden tests pass. +- Write ABAP Unit tests with CL_CDS_TEST_ENVIRONMENT in a global test class. diff --git a/tasks_gen/train/G1923/task.json b/tasks_gen/train/G1923/task.json new file mode 100644 index 0000000..de072f6 --- /dev/null +++ b/tasks_gen/train/G1923/task.json @@ -0,0 +1,85 @@ +{ + "id": "G1923", + "category": "E", + "object_type": "DDLS", + "difficulty": 3, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 80, + "max_activations": 20 + }, + "seed": [ + { + "type": "TABL", + "name": "{{P}}FORGJOB", + "file": "seed/forgjob.tabl.asabap", + "description": "Job of the blacksmith's forge" + }, + { + "type": "TABL", + "name": "{{P}}FORGART", + "file": "seed/forgart.tabl.asabap", + "description": "Forged article" + }, + { + "type": "TABL", + "name": "{{P}}FORGCUS", + "file": "seed/forgcus.tabl.asabap", + "description": "Customer of the forge" + }, + { + "type": "DDLS", + "name": "{{P}}I_FORGE_JOB", + "file": "seed/i_forge_job.ddls.asddls", + "description": "Legacy view with repeated join logic" + } + ], + "contract": [ + { + "type": "DDLS", + "name": "{{P}}I_FORGE_JOB", + "fields": [ + "JOB_ID", + "JOB_DATE", + "ARTICLE_NAME", + "WEIGHT_KG", + "CUSTOMER_NAME", + "CITY", + "WORK_MIN", + "EFFORT" + ] + } + ], + "out_of_scope": [ + "{{P}}FORGJOB", + "{{P}}FORGART", + "{{P}}FORGCUS" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}FORGE_HIDDEN", + "file": "hidden/forge_hidden.clas.abap", + "description": "Hidden tests for the reworked view" + } + ], + "reference": [ + { + "type": "DDLS", + "name": "{{P}}I_FORGE_JOB", + "file": "reference/i_forge_job.ddls.asddls", + "description": "Reworked view, each source table joined once" + }, + { + "type": "CLAS", + "name": "{{P}}FORGE_TEST", + "file": "reference/forge_test.clas.abap", + "description": "Own tests for the view" + } + ], + "craft_checks": [ + "No source table of the view appears in the join more than once.", + "The view contains no duplicated join condition." + ] +} \ No newline at end of file diff --git a/tasks_gen/train/G1924/generation.json b/tasks_gen/train/G1924/generation.json new file mode 100644 index 0000000..a6addeb --- /dev/null +++ b/tasks_gen/train/G1924/generation.json @@ -0,0 +1,43 @@ +{ + "id": "G1924", + "pool": "train", + "object_type": "DDLS", + "category": "E", + "attempts": [ + { + "stage": "bundle", + "errors": [ + "Too close to task G0145 (similarity spec 0.60, rules 0.60, names 0.33). Choose a different business topic and different object names.", + "Too close to task G0147 (similarity spec 0.66, rules 0.63, names 0.00). Choose a different business topic and different object names." + ], + "by_check": { + "extra": 2 + } + }, + { + "stage": "bundle", + "errors": [ + "Too close to task G0147 (similarity spec 0.66, rules 0.64, names 0.00). Choose a different business topic and different object names." + ], + "by_check": { + "extra": 1 + } + }, + { + "stage": "bundle", + "errors": [ + "Too close to task G0147 (similarity spec 0.64, rules 0.61, names 0.00). Choose a different business topic and different object names.", + "Too close to task G1148 (similarity spec 0.31, rules 0.12, names 1.00). Choose a different business topic and different object names." + ], + "by_check": { + "extra": 2 + } + }, + { + "stage": "validate", + "oracle": 95.0, + "null": 0 + } + ], + "accepted": false +} \ No newline at end of file diff --git a/tasks_gen/train/G1924/hidden/mill_charge_hidden.clas.abap b/tasks_gen/train/G1924/hidden/mill_charge_hidden.clas.abap new file mode 100644 index 0000000..f4dc356 --- /dev/null +++ b/tasks_gen/train/G1924/hidden/mill_charge_hidden.clas.abap @@ -0,0 +1,117 @@ +CLASS {{p}}mill_charge_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + TYPES ty_min TYPE p LENGTH 8 DECIMALS 2. + CLASS-DATA go_env TYPE REF TO if_cds_test_environment. + CLASS-METHODS class_setup. + CLASS-METHODS class_teardown. + METHODS setup. + METHODS charge_above_min FOR TESTING. + METHODS charge_below_min FOR TESTING. + METHODS mill_amount FOR TESTING. + METHODS counts FOR TESTING. + METHODS min_charge_other FOR TESTING. + METHODS min_charge_low FOR TESTING. + METHODS farmer_shown FOR TESTING. + METHODS job_without_lots FOR TESTING. +ENDCLASS. + + +CLASS {{p}}mill_charge_hidden IMPLEMENTATION. + + METHOD class_setup. + go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_MILL_CHARGE' ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + DATA lt_job TYPE STANDARD TABLE OF {{p}}milljob WITH EMPTY KEY. + DATA lt_lot TYPE STANDARD TABLE OF {{p}}milllot WITH EMPTY KEY. + go_env->clear_doubles( ). + lt_job = VALUE #( + ( job_id = 'J1' farmer = 'ALPHA' delivery_date = '20251001' ) + ( job_id = 'J2' farmer = 'BETA' delivery_date = '20251002' ) + ( job_id = 'J3' farmer = 'GAMMA' delivery_date = '20251003' ) + ( job_id = 'J4' farmer = 'DELTA' delivery_date = '20251004' ) ). + lt_lot = VALUE #( + ( job_id = 'J1' lot_no = 1 grain = 'WHEAT' sacks = 2 mill_rate = '100.00' ) + ( job_id = 'J1' lot_no = 2 grain = 'RYE' sacks = 1 mill_rate = '50.00' ) + ( job_id = 'J2' lot_no = 1 grain = 'WHEAT' sacks = 3 mill_rate = '80.00' ) + ( job_id = 'J4' lot_no = 1 grain = 'OATS' sacks = 1 mill_rate = '10.00' ) ). + go_env->insert_test_data( lt_job ). + go_env->insert_test_data( lt_lot ). + ENDMETHOD. + + METHOD charge_above_min. + DATA lv_min TYPE ty_min. + lv_min = '25.00'. + SELECT SINGLE charge_amount FROM {{p}}i_mill_charge( p_min_charge = @lv_min ) + WHERE job_id = 'J1' INTO @DATA(lv_charge). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '250.00' ) + act = CONV decfloat34( lv_charge ) ). + ENDMETHOD. + + METHOD charge_below_min. + DATA lv_min TYPE ty_min. + lv_min = '25.00'. + SELECT SINGLE charge_amount FROM {{p}}i_mill_charge( p_min_charge = @lv_min ) + WHERE job_id = 'J4' INTO @DATA(lv_charge). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '25.00' ) + act = CONV decfloat34( lv_charge ) ). + ENDMETHOD. + + METHOD mill_amount. + DATA lv_min TYPE ty_min. + lv_min = '25.00'. + SELECT SINGLE mill_amount FROM {{p}}i_mill_charge( p_min_charge = @lv_min ) + WHERE job_id = 'J1' INTO @DATA(lv_amount). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '250.00' ) + act = CONV decfloat34( lv_amount ) ). + ENDMETHOD. + + METHOD counts. + DATA lv_min TYPE ty_min. + lv_min = '25.00'. + SELECT SINGLE lot_count, sack_count FROM {{p}}i_mill_charge( p_min_charge = @lv_min ) + WHERE job_id = 'J1' INTO @DATA(ls_counts). + cl_abap_unit_assert=>assert_equals( exp = 2 act = ls_counts-lot_count ). + cl_abap_unit_assert=>assert_equals( exp = 3 act = ls_counts-sack_count ). + ENDMETHOD. + + METHOD min_charge_other. + DATA lv_min TYPE ty_min. + lv_min = '400.00'. + SELECT SINGLE charge_amount FROM {{p}}i_mill_charge( p_min_charge = @lv_min ) + WHERE job_id = 'J2' INTO @DATA(lv_charge). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '400.00' ) + act = CONV decfloat34( lv_charge ) ). + ENDMETHOD. + + METHOD min_charge_low. + DATA lv_min TYPE ty_min. + lv_min = '5.00'. + SELECT SINGLE charge_amount FROM {{p}}i_mill_charge( p_min_charge = @lv_min ) + WHERE job_id = 'J4' INTO @DATA(lv_charge). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '10.00' ) + act = CONV decfloat34( lv_charge ) ). + ENDMETHOD. + + METHOD farmer_shown. + DATA lv_min TYPE ty_min. + lv_min = '25.00'. + SELECT SINGLE farmer FROM {{p}}i_mill_charge( p_min_charge = @lv_min ) + WHERE job_id = 'J2' INTO @DATA(lv_farmer). + cl_abap_unit_assert=>assert_equals( exp = 'BETA' act = lv_farmer ). + ENDMETHOD. + + METHOD job_without_lots. + DATA lv_min TYPE ty_min. + lv_min = '25.00'. + SELECT COUNT(*) FROM {{p}}i_mill_charge( p_min_charge = @lv_min ) INTO @DATA(lv_rows). + cl_abap_unit_assert=>assert_equals( exp = 4 act = lv_rows ). + ENDMETHOD. + +ENDCLASS. diff --git a/tasks_gen/train/G1924/mutation.json b/tasks_gen/train/G1924/mutation.json new file mode 100644 index 0000000..f2e1ef3 --- /dev/null +++ b/tasks_gen/train/G1924/mutation.json @@ -0,0 +1,42 @@ +{ + "task": "T41", + "mutants": [ + { + "object": "{{P}}I_MILL_CHARGE", + "mutant": "charge_amount then-branch: $parameters.p_min_charge -> literal 25.00", + "status": "killed", + "hidden": "7/8", + "failed_tests": [ + "MIN_CHARGE_OTHER" + ] + }, + { + "object": "{{P}}I_MILL_CHARGE", + "mutant": "charge_amount comparison: < -> >", + "status": "killed", + "hidden": "4/8", + "failed_tests": [ + "CHARGE_ABOVE_MIN", + "CHARGE_BELOW_MIN", + "MIN_CHARGE_LOW", + "MIN_CHARGE_OTHER" + ] + }, + { + "object": "{{P}}I_MILL_CHARGE", + "mutant": "mill_amount: sum( sacks * mill_rate ) -> sum( sacks )", + "status": "killed", + "hidden": "4/8", + "failed_tests": [ + "MILL_AMOUNT", + "CHARGE_ABOVE_MIN", + "MIN_CHARGE_LOW", + "MIN_CHARGE_OTHER" + ] + } + ], + "valid": 3, + "killed": 3, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1924/reference/i_mill_charge.ddls.asddls b/tasks_gen/train/G1924/reference/i_mill_charge.ddls.asddls new file mode 100644 index 0000000..e7bf818 --- /dev/null +++ b/tasks_gen/train/G1924/reference/i_mill_charge.ddls.asddls @@ -0,0 +1,21 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Milling charge' +define view entity {{P}}I_MILL_CHARGE + with parameters + p_min_charge : abap.dec( 15, 2 ) + as select from {{p}}milllot as lot + inner join {{p}}milljob as job on job.job_id = lot.job_id +{ + key job.job_id as job_id, + job.farmer as farmer, + count( * ) as lot_count, + sum( lot.sacks ) as sack_count, + sum( lot.sacks * lot.mill_rate ) as mill_amount, + case when sum( lot.sacks * lot.mill_rate ) < $parameters.p_min_charge + then $parameters.p_min_charge + else sum( lot.sacks * lot.mill_rate ) + end as charge_amount +} +group by + job.job_id, + job.farmer diff --git a/tasks_gen/train/G1924/reference/mill_charge_test.clas.abap b/tasks_gen/train/G1924/reference/mill_charge_test.clas.abap new file mode 100644 index 0000000..62dac41 --- /dev/null +++ b/tasks_gen/train/G1924/reference/mill_charge_test.clas.abap @@ -0,0 +1,56 @@ +CLASS {{p}}mill_charge_test DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + TYPES ty_min TYPE p LENGTH 8 DECIMALS 2. + CLASS-DATA go_env TYPE REF TO if_cds_test_environment. + CLASS-METHODS class_setup. + CLASS-METHODS class_teardown. + METHODS setup. + METHODS charge_of_one_job FOR TESTING. + METHODS min_charge_drives_charge FOR TESTING. +ENDCLASS. + + +CLASS {{p}}mill_charge_test IMPLEMENTATION. + + METHOD class_setup. + go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_MILL_CHARGE' ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + DATA lt_job TYPE STANDARD TABLE OF {{p}}milljob WITH EMPTY KEY. + DATA lt_lot TYPE STANDARD TABLE OF {{p}}milllot WITH EMPTY KEY. + go_env->clear_doubles( ). + lt_job = VALUE #( ( job_id = 'A' farmer = 'C1' delivery_date = '20251101' ) ). + lt_lot = VALUE #( + ( job_id = 'A' lot_no = 1 grain = 'WHEAT' sacks = 2 mill_rate = '30.00' ) + ( job_id = 'A' lot_no = 2 grain = 'RYE' sacks = 1 mill_rate = '20.00' ) ). + go_env->insert_test_data( lt_job ). + go_env->insert_test_data( lt_lot ). + ENDMETHOD. + + METHOD charge_of_one_job. + DATA lv_min TYPE ty_min. + lv_min = '25.00'. + SELECT SINGLE mill_amount, charge_amount FROM {{p}}i_mill_charge( p_min_charge = @lv_min ) + WHERE job_id = 'A' INTO @DATA(ls_charge). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '80.00' ) + act = CONV decfloat34( ls_charge-mill_amount ) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '80.00' ) + act = CONV decfloat34( ls_charge-charge_amount ) ). + ENDMETHOD. + + METHOD min_charge_drives_charge. + DATA lv_min TYPE ty_min. + lv_min = '100.00'. + SELECT SINGLE charge_amount FROM {{p}}i_mill_charge( p_min_charge = @lv_min ) + WHERE job_id = 'A' INTO @DATA(lv_charge). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '100.00' ) + act = CONV decfloat34( lv_charge ) ). + ENDMETHOD. + +ENDCLASS. diff --git a/tasks_gen/train/G1924/seed/i_mill_charge.ddls.asddls b/tasks_gen/train/G1924/seed/i_mill_charge.ddls.asddls new file mode 100644 index 0000000..b6fdabd --- /dev/null +++ b/tasks_gen/train/G1924/seed/i_mill_charge.ddls.asddls @@ -0,0 +1,21 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Milling charge' +define view entity {{P}}I_MILL_CHARGE + with parameters + p_min_charge : abap.dec( 15, 2 ) + as select from {{p}}milllot as lot + inner join {{p}}milljob as job on job.job_id = lot.job_id +{ + key job.job_id as job_id, + job.farmer as farmer, + count( * ) as lot_count, + sum( lot.sacks ) as sack_count, + sum( lot.sacks * lot.mill_rate ) as mill_amount, + case when sum( lot.sacks * lot.mill_rate ) < cast( '25.00' as abap.dec( 15, 2 ) ) + then cast( '25.00' as abap.dec( 15, 2 ) ) + else sum( lot.sacks * lot.mill_rate ) + end as charge_amount +} +group by + job.job_id, + job.farmer diff --git a/tasks_gen/train/G1924/seed/milljob.tabl.asabap b/tasks_gen/train/G1924/seed/milljob.tabl.asabap new file mode 100644 index 0000000..e706ad0 --- /dev/null +++ b/tasks_gen/train/G1924/seed/milljob.tabl.asabap @@ -0,0 +1,11 @@ +@EndUserText.label : 'Milling job header' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}milljob { + key client : abap.clnt not null; + key job_id : abap.char(10) not null; + farmer : abap.char(10); + delivery_date : abap.dats; +} diff --git a/tasks_gen/train/G1924/seed/milllot.tabl.asabap b/tasks_gen/train/G1924/seed/milllot.tabl.asabap new file mode 100644 index 0000000..2592070 --- /dev/null +++ b/tasks_gen/train/G1924/seed/milllot.tabl.asabap @@ -0,0 +1,13 @@ +@EndUserText.label : 'Milling job grain lot' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}milllot { + key client : abap.clnt not null; + key job_id : abap.char(10) not null; + key lot_no : abap.int4 not null; + grain : abap.char(10); + sacks : abap.int4; + mill_rate : abap.dec(15,2); +} diff --git a/tasks_gen/train/G1924/spec.md b/tasks_gen/train/G1924/spec.md new file mode 100644 index 0000000..13b2589 --- /dev/null +++ b/tasks_gen/train/G1924/spec.md @@ -0,0 +1,55 @@ +# 1. Goal +A watermill grinds the grain that farmers deliver. Every job is billed from the +sacks of the job and from the milling rate of each lot. The front desk reads the +charge of a job from the CDS view entity {{P}}I_MILL_CHARGE in package $TMP. + +The definition of that view is old. It activates and it returns correct data, +but a fixed money value sits in its source code and the import parameter +P_MIN_CHARGE is declared and never read. Rework the definition of the view so +that the parameter supplies that money value. The view keeps its name, its +elements and its behaviour. + +# 2. Open questions +None. + +# 3. Context +- Table {{P}}MILLJOB, package $TMP, one row for each milling job. + Key: JOB_ID (CHAR 10). Further fields: FARMER (CHAR 10), DELIVERY_DATE (DATS). +- Table {{P}}MILLLOT, package $TMP, one row for each grain lot of a job. + Key: JOB_ID (CHAR 10), LOT_NO (INT4). Further fields: GRAIN (CHAR 10), + SACKS (INT4), MILL_RATE (DEC 15,2, the price for milling one sack). +- The current definition of {{P}}I_MILL_CHARGE is the legacy code. Open it and + read it. It is the only description of the rules of the view. + +# 4. Contract +- {{P}}I_MILL_CHARGE stays in package $TMP under its current name. +- The elements of the view keep their names and their order: JOB_ID (key), + FARMER, LOT_COUNT, SACK_COUNT, MILL_AMOUNT, CHARGE_AMOUNT. +- The import parameter P_MIN_CHARGE (DEC 15,2) stays. It holds an amount of + money. +- The authorization check stays #NOT_REQUIRED. + +# 5. Business rules +The rules of the view are not repeated in this document. They are inside the +legacy source code of {{P}}I_MILL_CHARGE. Read that source code and keep every +rule exactly as it is. + +The rework must fulfil three quality goals: +1. P_MIN_CHARGE supplies the money value that the legacy code writes as a + literal. That literal disappears from the source code of the view. +2. A caller that passes the money value of the legacy code receives exactly the + values that the view returned before the rework. +3. The view stays Clean ABAP: no unused element, no dead code, one expression + for each element. + +# 6. Constraints +- Release target: SAP_BASIS 816 (ABAP Platform 2025). +- Package $TMP. No transport. +- Out of scope: {{P}}MILLJOB and {{P}}MILLLOT stay untouched. +- The name of the view and the element names stay untouched. +- ATC must report no finding of priority 1 or priority 2. + +# 7. Acceptance +- {{P}}I_MILL_CHARGE is active and free of syntax errors. +- The hidden tests pass. +- Write ABAP Unit tests with CL_CDS_TEST_ENVIRONMENT in a global test class. diff --git a/tasks_gen/train/G1924/task.json b/tasks_gen/train/G1924/task.json new file mode 100644 index 0000000..b4a59db --- /dev/null +++ b/tasks_gen/train/G1924/task.json @@ -0,0 +1,73 @@ +{ + "id": "G1924", + "category": "E", + "object_type": "DDLS", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [ + { + "type": "TABL", + "name": "{{P}}MILLJOB", + "file": "seed/milljob.tabl.asabap", + "description": "Milling job header" + }, + { + "type": "TABL", + "name": "{{P}}MILLLOT", + "file": "seed/milllot.tabl.asabap", + "description": "Milling job grain lot" + }, + { + "type": "DDLS", + "name": "{{P}}I_MILL_CHARGE", + "file": "seed/i_mill_charge.ddls.asddls", + "description": "Legacy charge view of the watermill" + } + ], + "contract": [ + { + "type": "DDLS", + "name": "{{P}}I_MILL_CHARGE", + "fields": [ + "JOB_ID", + "FARMER", + "LOT_COUNT", + "SACK_COUNT", + "MILL_AMOUNT", + "CHARGE_AMOUNT" + ] + } + ], + "out_of_scope": [ + "{{P}}MILLJOB", + "{{P}}MILLLOT" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}MILL_CHARGE_HIDDEN", + "file": "hidden/mill_charge_hidden.clas.abap", + "description": "Hidden tests for the reworked charge view" + } + ], + "reference": [ + { + "type": "DDLS", + "name": "{{P}}I_MILL_CHARGE", + "file": "reference/i_mill_charge.ddls.asddls", + "description": "Reworked charge view" + }, + { + "type": "CLAS", + "name": "{{P}}MILL_CHARGE_TEST", + "file": "reference/mill_charge_test.clas.abap", + "description": "Own tests of the model" + } + ], + "craft_checks": [] +} \ No newline at end of file diff --git a/tasks_gen/train/G1926/faulty/m0_if_kart_check.intf.abap b/tasks_gen/train/G1926/faulty/m0_if_kart_check.intf.abap new file mode 100644 index 0000000..a0abd5e --- /dev/null +++ b/tasks_gen/train/G1926/faulty/m0_if_kart_check.intf.abap @@ -0,0 +1,49 @@ +INTERFACE {{p}}if_kart_check PUBLIC. + TYPES ty_reason TYPE c LENGTH 12. + + TYPES: + BEGIN OF ty_booking, + driver_name TYPE c LENGTH 19, + driver_age TYPE i, + laps TYPE i, + booking_time TYPE t, + END OF ty_booking. + + TYPES tt_bookings TYPE STANDARD TABLE OF ty_booking WITH EMPTY KEY. + + CONSTANTS: + BEGIN OF c_reason, + ok TYPE ty_reason VALUE 'OK', + no_name TYPE ty_reason VALUE 'NO_NAME', + too_young TYPE ty_reason VALUE 'TOO_YOUNG', + too_old TYPE ty_reason VALUE 'TOO_OLD', + bad_laps TYPE ty_reason VALUE 'BAD_LAPS', + closed TYPE ty_reason VALUE 'CLOSED', + too_many TYPE ty_reason VALUE 'TOO_MANY', + END OF c_reason. + + CONSTANTS: + BEGIN OF c_limit, + min_age TYPE i VALUE 12, + max_age TYPE i VALUE 75, + min_laps TYPE i VALUE 5, + max_laps TYPE i VALUE 30, + max_drivers TYPE i VALUE 8, + END OF c_limit. + + CONSTANTS: + c_open_from TYPE t VALUE '090000', + c_open_to TYPE t VALUE '220000'. + + METHODS check_booking + IMPORTING is_booking TYPE ty_booking + RETURNING VALUE(rv_reason) TYPE ty_reason. + + METHODS check_group + IMPORTING it_bookings TYPE tt_bookings + RETURNING VALUE(rv_reason) TYPE ty_reason. + + METHODS is_open + IMPORTING iv_time TYPE t + RETURNING VALUE(rv_open) TYPE abap_bool. +ENDINTERFACE. diff --git a/tasks_gen/train/G1926/faulty/m1_if_kart_check.intf.abap b/tasks_gen/train/G1926/faulty/m1_if_kart_check.intf.abap new file mode 100644 index 0000000..f18824f --- /dev/null +++ b/tasks_gen/train/G1926/faulty/m1_if_kart_check.intf.abap @@ -0,0 +1,49 @@ +INTERFACE {{p}}if_kart_check PUBLIC. + TYPES ty_reason TYPE c LENGTH 12. + + TYPES: + BEGIN OF ty_booking, + driver_name TYPE c LENGTH 20, + driver_age TYPE i, + laps TYPE i, + booking_time TYPE t, + END OF ty_booking. + + TYPES tt_bookings TYPE STANDARD TABLE OF ty_booking WITH EMPTY KEY. + + CONSTANTS: + BEGIN OF c_reason, + ok TYPE ty_reason VALUE 'OK', + no_name TYPE ty_reason VALUE 'ZO_NAME', + too_young TYPE ty_reason VALUE 'TOO_YOUNG', + too_old TYPE ty_reason VALUE 'TOO_OLD', + bad_laps TYPE ty_reason VALUE 'BAD_LAPS', + closed TYPE ty_reason VALUE 'CLOSED', + too_many TYPE ty_reason VALUE 'TOO_MANY', + END OF c_reason. + + CONSTANTS: + BEGIN OF c_limit, + min_age TYPE i VALUE 12, + max_age TYPE i VALUE 75, + min_laps TYPE i VALUE 5, + max_laps TYPE i VALUE 30, + max_drivers TYPE i VALUE 8, + END OF c_limit. + + CONSTANTS: + c_open_from TYPE t VALUE '090000', + c_open_to TYPE t VALUE '220000'. + + METHODS check_booking + IMPORTING is_booking TYPE ty_booking + RETURNING VALUE(rv_reason) TYPE ty_reason. + + METHODS check_group + IMPORTING it_bookings TYPE tt_bookings + RETURNING VALUE(rv_reason) TYPE ty_reason. + + METHODS is_open + IMPORTING iv_time TYPE t + RETURNING VALUE(rv_open) TYPE abap_bool. +ENDINTERFACE. diff --git a/tasks_gen/train/G1926/faulty/m2_if_kart_check.intf.abap b/tasks_gen/train/G1926/faulty/m2_if_kart_check.intf.abap new file mode 100644 index 0000000..4714118 --- /dev/null +++ b/tasks_gen/train/G1926/faulty/m2_if_kart_check.intf.abap @@ -0,0 +1,49 @@ +INTERFACE {{p}}if_kart_check PUBLIC. + TYPES ty_reason TYPE c LENGTH 12. + + TYPES: + BEGIN OF ty_booking, + driver_name TYPE c LENGTH 20, + driver_age TYPE i, + laps TYPE i, + booking_time TYPE t, + END OF ty_booking. + + TYPES tt_bookings TYPE STANDARD TABLE OF ty_booking WITH EMPTY KEY. + + CONSTANTS: + BEGIN OF c_reason, + ok TYPE ty_reason VALUE 'OK', + no_name TYPE ty_reason VALUE 'NO_NAME', + too_young TYPE ty_reason VALUE 'TOO_YOUNG', + too_old TYPE ty_reason VALUE 'TOO_OLD', + bad_laps TYPE ty_reason VALUE 'ZAD_LAPS', + closed TYPE ty_reason VALUE 'CLOSED', + too_many TYPE ty_reason VALUE 'TOO_MANY', + END OF c_reason. + + CONSTANTS: + BEGIN OF c_limit, + min_age TYPE i VALUE 12, + max_age TYPE i VALUE 75, + min_laps TYPE i VALUE 5, + max_laps TYPE i VALUE 30, + max_drivers TYPE i VALUE 8, + END OF c_limit. + + CONSTANTS: + c_open_from TYPE t VALUE '090000', + c_open_to TYPE t VALUE '220000'. + + METHODS check_booking + IMPORTING is_booking TYPE ty_booking + RETURNING VALUE(rv_reason) TYPE ty_reason. + + METHODS check_group + IMPORTING it_bookings TYPE tt_bookings + RETURNING VALUE(rv_reason) TYPE ty_reason. + + METHODS is_open + IMPORTING iv_time TYPE t + RETURNING VALUE(rv_open) TYPE abap_bool. +ENDINTERFACE. diff --git a/tasks_gen/train/G1926/faulty/m3_if_kart_check.intf.abap b/tasks_gen/train/G1926/faulty/m3_if_kart_check.intf.abap new file mode 100644 index 0000000..6d77f90 --- /dev/null +++ b/tasks_gen/train/G1926/faulty/m3_if_kart_check.intf.abap @@ -0,0 +1,49 @@ +INTERFACE {{p}}if_kart_check PUBLIC. + TYPES ty_reason TYPE c LENGTH 12. + + TYPES: + BEGIN OF ty_booking, + driver_name TYPE c LENGTH 20, + driver_age TYPE i, + laps TYPE i, + booking_time TYPE t, + END OF ty_booking. + + TYPES tt_bookings TYPE STANDARD TABLE OF ty_booking WITH EMPTY KEY. + + CONSTANTS: + BEGIN OF c_reason, + ok TYPE ty_reason VALUE 'OK', + no_name TYPE ty_reason VALUE 'NO_NAME', + too_young TYPE ty_reason VALUE 'TOO_YOUNG', + too_old TYPE ty_reason VALUE 'TOO_OLD', + bad_laps TYPE ty_reason VALUE 'BAD_LAPS', + closed TYPE ty_reason VALUE 'ZLOSED', + too_many TYPE ty_reason VALUE 'TOO_MANY', + END OF c_reason. + + CONSTANTS: + BEGIN OF c_limit, + min_age TYPE i VALUE 12, + max_age TYPE i VALUE 75, + min_laps TYPE i VALUE 5, + max_laps TYPE i VALUE 30, + max_drivers TYPE i VALUE 8, + END OF c_limit. + + CONSTANTS: + c_open_from TYPE t VALUE '090000', + c_open_to TYPE t VALUE '220000'. + + METHODS check_booking + IMPORTING is_booking TYPE ty_booking + RETURNING VALUE(rv_reason) TYPE ty_reason. + + METHODS check_group + IMPORTING it_bookings TYPE tt_bookings + RETURNING VALUE(rv_reason) TYPE ty_reason. + + METHODS is_open + IMPORTING iv_time TYPE t + RETURNING VALUE(rv_open) TYPE abap_bool. +ENDINTERFACE. diff --git a/tasks_gen/train/G1926/faulty/m4_if_kart_check.intf.abap b/tasks_gen/train/G1926/faulty/m4_if_kart_check.intf.abap new file mode 100644 index 0000000..0b427e7 --- /dev/null +++ b/tasks_gen/train/G1926/faulty/m4_if_kart_check.intf.abap @@ -0,0 +1,49 @@ +INTERFACE {{p}}if_kart_check PUBLIC. + TYPES ty_reason TYPE c LENGTH 12. + + TYPES: + BEGIN OF ty_booking, + driver_name TYPE c LENGTH 20, + driver_age TYPE i, + laps TYPE i, + booking_time TYPE t, + END OF ty_booking. + + TYPES tt_bookings TYPE STANDARD TABLE OF ty_booking WITH EMPTY KEY. + + CONSTANTS: + BEGIN OF c_reason, + ok TYPE ty_reason VALUE 'OK', + no_name TYPE ty_reason VALUE 'NO_NAME', + too_young TYPE ty_reason VALUE 'TOO_YOUNG', + too_old TYPE ty_reason VALUE 'TOO_OLD', + bad_laps TYPE ty_reason VALUE 'BAD_LAPS', + closed TYPE ty_reason VALUE 'CLOSED', + too_many TYPE ty_reason VALUE 'ZOO_MANY', + END OF c_reason. + + CONSTANTS: + BEGIN OF c_limit, + min_age TYPE i VALUE 12, + max_age TYPE i VALUE 75, + min_laps TYPE i VALUE 5, + max_laps TYPE i VALUE 30, + max_drivers TYPE i VALUE 8, + END OF c_limit. + + CONSTANTS: + c_open_from TYPE t VALUE '090000', + c_open_to TYPE t VALUE '220000'. + + METHODS check_booking + IMPORTING is_booking TYPE ty_booking + RETURNING VALUE(rv_reason) TYPE ty_reason. + + METHODS check_group + IMPORTING it_bookings TYPE tt_bookings + RETURNING VALUE(rv_reason) TYPE ty_reason. + + METHODS is_open + IMPORTING iv_time TYPE t + RETURNING VALUE(rv_open) TYPE abap_bool. +ENDINTERFACE. diff --git a/tasks_gen/train/G1926/generation.json b/tasks_gen/train/G1926/generation.json new file mode 100644 index 0000000..3e43756 --- /dev/null +++ b/tasks_gen/train/G1926/generation.json @@ -0,0 +1,44 @@ +{ + "id": "G1926", + "pool": "train", + "object_type": "INTF", + "category": "A", + "attempts": [ + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "bundle", + "errors": [ + "reference/kart_check_test.clas.abap line 25: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"", + "reference/kart_check_test.clas.abap line 42: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"", + "reference/kart_check_test.clas.abap line 52: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"", + "hidden/kart_check_hidden.clas.abap line 43: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"", + "hidden/kart_check_hidden.clas.abap line 58: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"", + "hidden/kart_check_hidden.clas.abap line 68: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"", + "hidden/kart_check_hidden.clas.abap line 79: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"" + ], + "by_check": { + "abaplint": 7 + } + }, + { + "stage": "validate", + "oracle": 77.0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 5, + "killed": 5, + "ok": true + } + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1926/hidden/kart_check_hidden.clas.abap b/tasks_gen/train/G1926/hidden/kart_check_hidden.clas.abap new file mode 100644 index 0000000..70da4d2 --- /dev/null +++ b/tasks_gen/train/G1926/hidden/kart_check_hidden.clas.abap @@ -0,0 +1,174 @@ +CLASS {{p}}kart_check_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PUBLIC SECTION. + INTERFACES {{p}}if_kart_check. + PRIVATE SECTION. + DATA mo_cut TYPE REF TO {{p}}if_kart_check. + METHODS setup. + METHODS assert_char_length + IMPORTING iv_name TYPE string + iv_length TYPE i. + METHODS assert_number + IMPORTING iv_name TYPE string + iv_value TYPE i. + METHODS reason_ok FOR TESTING. + METHODS reason_codes FOR TESTING. + METHODS limit_values FOR TESTING. + METHODS opening_times FOR TESTING. + METHODS reason_length FOR TESTING. + METHODS booking_components FOR TESTING. + METHODS bookings_is_table FOR TESTING. + METHODS check_booking_ok FOR TESTING. + METHODS check_group_ok FOR TESTING. + METHODS is_open_at_noon FOR TESTING. +ENDCLASS. + + +CLASS {{p}}kart_check_hidden IMPLEMENTATION. + METHOD setup. + mo_cut = me. + ENDMETHOD. + + METHOD assert_char_length. + DATA lv_probe TYPE string. + DATA lv_expected TYPE string. + DATA ls_booking TYPE {{p}}if_kart_check=>ty_booking. + ASSIGN COMPONENT iv_name OF STRUCTURE ls_booking TO FIELD-SYMBOL(). + IF sy-subrc <> 0. + cl_abap_unit_assert=>fail( msg = |Component { iv_name } is missing| ). + RETURN. + ENDIF. + DO iv_length + 1 TIMES. + lv_probe = lv_probe && 'X'. + ENDDO. + DO iv_length TIMES. + lv_expected = lv_expected && 'X'. + ENDDO. + = lv_probe. + cl_abap_unit_assert=>assert_equals( exp = lv_expected + act = + msg = |Length of { iv_name }| ). + ENDMETHOD. + + METHOD assert_number. + DATA ls_booking TYPE {{p}}if_kart_check=>ty_booking. + ASSIGN COMPONENT iv_name OF STRUCTURE ls_booking TO FIELD-SYMBOL(). + IF sy-subrc <> 0. + cl_abap_unit_assert=>fail( msg = |Component { iv_name } is missing| ). + RETURN. + ENDIF. + = iv_value. + cl_abap_unit_assert=>assert_equals( exp = iv_value + act = + msg = |Value of { iv_name }| ). + ENDMETHOD. + + METHOD reason_ok. + cl_abap_unit_assert=>assert_equals( exp = 'OK' + act = {{p}}if_kart_check=>c_reason-ok ). + ENDMETHOD. + + METHOD reason_codes. + cl_abap_unit_assert=>assert_equals( exp = 'NO_NAME' + act = {{p}}if_kart_check=>c_reason-no_name ). + cl_abap_unit_assert=>assert_equals( exp = 'TOO_YOUNG' + act = {{p}}if_kart_check=>c_reason-too_young ). + cl_abap_unit_assert=>assert_equals( exp = 'TOO_OLD' + act = {{p}}if_kart_check=>c_reason-too_old ). + cl_abap_unit_assert=>assert_equals( exp = 'BAD_LAPS' + act = {{p}}if_kart_check=>c_reason-bad_laps ). + cl_abap_unit_assert=>assert_equals( exp = 'CLOSED' + act = {{p}}if_kart_check=>c_reason-closed ). + cl_abap_unit_assert=>assert_equals( exp = 'TOO_MANY' + act = {{p}}if_kart_check=>c_reason-too_many ). + ENDMETHOD. + + METHOD limit_values. + cl_abap_unit_assert=>assert_equals( exp = 12 + act = {{p}}if_kart_check=>c_limit-min_age ). + cl_abap_unit_assert=>assert_equals( exp = 75 + act = {{p}}if_kart_check=>c_limit-max_age ). + cl_abap_unit_assert=>assert_equals( exp = 5 + act = {{p}}if_kart_check=>c_limit-min_laps ). + cl_abap_unit_assert=>assert_equals( exp = 30 + act = {{p}}if_kart_check=>c_limit-max_laps ). + cl_abap_unit_assert=>assert_equals( exp = 8 + act = {{p}}if_kart_check=>c_limit-max_drivers ). + ENDMETHOD. + + METHOD opening_times. + DATA lv_from TYPE t VALUE '090000'. + DATA lv_to TYPE t VALUE '220000'. + cl_abap_unit_assert=>assert_equals( exp = lv_from + act = {{p}}if_kart_check=>c_open_from ). + cl_abap_unit_assert=>assert_equals( exp = lv_to + act = {{p}}if_kart_check=>c_open_to ). + ENDMETHOD. + + METHOD reason_length. + DATA lv_reason TYPE {{p}}if_kart_check=>ty_reason. + DATA lv_probe TYPE string. + DO 13 TIMES. + lv_probe = lv_probe && 'X'. + ENDDO. + lv_reason = lv_probe. + cl_abap_unit_assert=>assert_equals( exp = 'XXXXXXXXXXXX' + act = lv_reason ). + ENDMETHOD. + + METHOD booking_components. + assert_char_length( iv_name = 'DRIVER_NAME' iv_length = 20 ). + assert_number( iv_name = 'DRIVER_AGE' iv_value = 30 ). + assert_number( iv_name = 'LAPS' iv_value = 10 ). + DATA ls_booking TYPE {{p}}if_kart_check=>ty_booking. + ls_booking-booking_time = '235959'. + cl_abap_unit_assert=>assert_equals( exp = '235959' + act = ls_booking-booking_time ). + ENDMETHOD. + + METHOD bookings_is_table. + DATA lt_bookings TYPE {{p}}if_kart_check=>tt_bookings. + DATA(lo_descr) = cl_abap_typedescr=>describe_by_data( lt_bookings ). + cl_abap_unit_assert=>assert_equals( exp = cl_abap_typedescr=>typekind_table + act = lo_descr->type_kind ). + DATA(lo_table) = CAST cl_abap_tabledescr( lo_descr ). + DATA(lo_row) = lo_table->get_table_line_type( ). + DATA(lo_struct) = CAST cl_abap_structdescr( lo_row ). + cl_abap_unit_assert=>assert_equals( exp = 4 + act = lines( lo_struct->components ) ). + ENDMETHOD. + + METHOD check_booking_ok. + DATA ls_booking TYPE {{p}}if_kart_check=>ty_booking. + ls_booking-driver_name = 'MAX MUSTERMANN'. + ls_booking-driver_age = 30. + ls_booking-laps = 10. + ls_booking-booking_time = '140000'. + cl_abap_unit_assert=>assert_equals( exp = 'OK' + act = mo_cut->check_booking( ls_booking ) ). + ENDMETHOD. + + METHOD check_group_ok. + DATA lt_bookings TYPE {{p}}if_kart_check=>tt_bookings. + cl_abap_unit_assert=>assert_equals( exp = 'OK' + act = mo_cut->check_group( lt_bookings ) ). + ENDMETHOD. + + METHOD is_open_at_noon. + DATA lv_time TYPE t VALUE '120000'. + cl_abap_unit_assert=>assert_equals( exp = abap_true + act = mo_cut->is_open( lv_time ) ). + ENDMETHOD. + + METHOD {{p}}if_kart_check~check_booking. + rv_reason = {{p}}if_kart_check=>c_reason-ok. + ENDMETHOD. + + METHOD {{p}}if_kart_check~check_group. + rv_reason = {{p}}if_kart_check=>c_reason-ok. + ENDMETHOD. + + METHOD {{p}}if_kart_check~is_open. + rv_open = abap_true. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1926/mutation.json b/tasks_gen/train/G1926/mutation.json new file mode 100644 index 0000000..b857c6b --- /dev/null +++ b/tasks_gen/train/G1926/mutation.json @@ -0,0 +1,54 @@ +{ + "task": "G1926", + "mutants": [ + { + "object": "{{P}}IF_KART_CHECK", + "mutant": "line 6: LENGTH 20 -> LENGTH 19 (length)", + "status": "killed", + "hidden": "9/10", + "failed_tests": [ + "BOOKING_COMPONENTS" + ] + }, + { + "object": "{{P}}IF_KART_CHECK", + "mutant": "line 17: VALUE 'NO_NAME' -> VALUE 'ZO_NAME' (lit)", + "status": "killed", + "hidden": "9/10", + "failed_tests": [ + "REASON_CODES" + ] + }, + { + "object": "{{P}}IF_KART_CHECK", + "mutant": "line 20: VALUE 'BAD_LAPS' -> VALUE 'ZAD_LAPS' (lit)", + "status": "killed", + "hidden": "9/10", + "failed_tests": [ + "REASON_CODES" + ] + }, + { + "object": "{{P}}IF_KART_CHECK", + "mutant": "line 21: VALUE 'CLOSED' -> VALUE 'ZLOSED' (lit)", + "status": "killed", + "hidden": "9/10", + "failed_tests": [ + "REASON_CODES" + ] + }, + { + "object": "{{P}}IF_KART_CHECK", + "mutant": "line 22: VALUE 'TOO_MANY' -> VALUE 'ZOO_MANY' (lit)", + "status": "killed", + "hidden": "9/10", + "failed_tests": [ + "REASON_CODES" + ] + } + ], + "valid": 5, + "killed": 5, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1926/reference/if_kart_check.intf.abap b/tasks_gen/train/G1926/reference/if_kart_check.intf.abap new file mode 100644 index 0000000..2a59bef --- /dev/null +++ b/tasks_gen/train/G1926/reference/if_kart_check.intf.abap @@ -0,0 +1,49 @@ +INTERFACE {{p}}if_kart_check PUBLIC. + TYPES ty_reason TYPE c LENGTH 12. + + TYPES: + BEGIN OF ty_booking, + driver_name TYPE c LENGTH 20, + driver_age TYPE i, + laps TYPE i, + booking_time TYPE t, + END OF ty_booking. + + TYPES tt_bookings TYPE STANDARD TABLE OF ty_booking WITH EMPTY KEY. + + CONSTANTS: + BEGIN OF c_reason, + ok TYPE ty_reason VALUE 'OK', + no_name TYPE ty_reason VALUE 'NO_NAME', + too_young TYPE ty_reason VALUE 'TOO_YOUNG', + too_old TYPE ty_reason VALUE 'TOO_OLD', + bad_laps TYPE ty_reason VALUE 'BAD_LAPS', + closed TYPE ty_reason VALUE 'CLOSED', + too_many TYPE ty_reason VALUE 'TOO_MANY', + END OF c_reason. + + CONSTANTS: + BEGIN OF c_limit, + min_age TYPE i VALUE 12, + max_age TYPE i VALUE 75, + min_laps TYPE i VALUE 5, + max_laps TYPE i VALUE 30, + max_drivers TYPE i VALUE 8, + END OF c_limit. + + CONSTANTS: + c_open_from TYPE t VALUE '090000', + c_open_to TYPE t VALUE '220000'. + + METHODS check_booking + IMPORTING is_booking TYPE ty_booking + RETURNING VALUE(rv_reason) TYPE ty_reason. + + METHODS check_group + IMPORTING it_bookings TYPE tt_bookings + RETURNING VALUE(rv_reason) TYPE ty_reason. + + METHODS is_open + IMPORTING iv_time TYPE t + RETURNING VALUE(rv_open) TYPE abap_bool. +ENDINTERFACE. diff --git a/tasks_gen/train/G1926/reference/kart_check_test.clas.abap b/tasks_gen/train/G1926/reference/kart_check_test.clas.abap new file mode 100644 index 0000000..9763fbb --- /dev/null +++ b/tasks_gen/train/G1926/reference/kart_check_test.clas.abap @@ -0,0 +1,116 @@ +CLASS {{p}}kart_check_test DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PUBLIC SECTION. + INTERFACES {{p}}if_kart_check. + PRIVATE SECTION. + DATA mo_cut TYPE REF TO {{p}}if_kart_check. + METHODS setup. + METHODS reason_codes_are_fixed FOR TESTING. + METHODS limits_are_fixed FOR TESTING. + METHODS opening_times_are_fixed FOR TESTING. + METHODS reason_type_has_length_12 FOR TESTING. + METHODS booking_has_four_components FOR TESTING. + METHODS bookings_is_a_table FOR TESTING. + METHODS check_booking_returns_ok FOR TESTING. + METHODS is_open_returns_true FOR TESTING. +ENDCLASS. + + +CLASS {{p}}kart_check_test IMPLEMENTATION. + METHOD setup. + mo_cut = me. + ENDMETHOD. + + METHOD reason_codes_are_fixed. + cl_abap_unit_assert=>assert_equals( exp = 'OK' + act = {{p}}if_kart_check=>c_reason-ok ). + cl_abap_unit_assert=>assert_equals( exp = 'NO_NAME' + act = {{p}}if_kart_check=>c_reason-no_name ). + cl_abap_unit_assert=>assert_equals( exp = 'TOO_YOUNG' + act = {{p}}if_kart_check=>c_reason-too_young ). + cl_abap_unit_assert=>assert_equals( exp = 'TOO_OLD' + act = {{p}}if_kart_check=>c_reason-too_old ). + cl_abap_unit_assert=>assert_equals( exp = 'BAD_LAPS' + act = {{p}}if_kart_check=>c_reason-bad_laps ). + cl_abap_unit_assert=>assert_equals( exp = 'CLOSED' + act = {{p}}if_kart_check=>c_reason-closed ). + cl_abap_unit_assert=>assert_equals( exp = 'TOO_MANY' + act = {{p}}if_kart_check=>c_reason-too_many ). + ENDMETHOD. + + METHOD limits_are_fixed. + cl_abap_unit_assert=>assert_equals( exp = 12 + act = {{p}}if_kart_check=>c_limit-min_age ). + cl_abap_unit_assert=>assert_equals( exp = 75 + act = {{p}}if_kart_check=>c_limit-max_age ). + cl_abap_unit_assert=>assert_equals( exp = 5 + act = {{p}}if_kart_check=>c_limit-min_laps ). + cl_abap_unit_assert=>assert_equals( exp = 30 + act = {{p}}if_kart_check=>c_limit-max_laps ). + cl_abap_unit_assert=>assert_equals( exp = 8 + act = {{p}}if_kart_check=>c_limit-max_drivers ). + ENDMETHOD. + + METHOD opening_times_are_fixed. + DATA lv_from TYPE t VALUE '090000'. + DATA lv_to TYPE t VALUE '220000'. + cl_abap_unit_assert=>assert_equals( exp = lv_from + act = {{p}}if_kart_check=>c_open_from ). + cl_abap_unit_assert=>assert_equals( exp = lv_to + act = {{p}}if_kart_check=>c_open_to ). + ENDMETHOD. + + METHOD reason_type_has_length_12. + DATA lv_reason TYPE {{p}}if_kart_check=>ty_reason. + DATA lv_probe TYPE string. + DO 13 TIMES. + lv_probe = lv_probe && 'X'. + ENDDO. + lv_reason = lv_probe. + cl_abap_unit_assert=>assert_equals( exp = 'XXXXXXXXXXXX' + act = lv_reason ). + ENDMETHOD. + + METHOD booking_has_four_components. + DATA ls_booking TYPE {{p}}if_kart_check=>ty_booking. + DATA(lo_descr) = cl_abap_typedescr=>describe_by_data( ls_booking ). + DATA(lo_struct) = CAST cl_abap_structdescr( lo_descr ). + cl_abap_unit_assert=>assert_equals( exp = 4 + act = lines( lo_struct->components ) ). + ENDMETHOD. + + METHOD bookings_is_a_table. + DATA lt_bookings TYPE {{p}}if_kart_check=>tt_bookings. + DATA(lo_descr) = cl_abap_typedescr=>describe_by_data( lt_bookings ). + cl_abap_unit_assert=>assert_equals( exp = cl_abap_typedescr=>typekind_table + act = lo_descr->type_kind ). + ENDMETHOD. + + METHOD check_booking_returns_ok. + DATA ls_booking TYPE {{p}}if_kart_check=>ty_booking. + ls_booking-driver_name = 'ANNA BEISPIEL'. + ls_booking-driver_age = 25. + ls_booking-laps = 8. + ls_booking-booking_time = '100000'. + cl_abap_unit_assert=>assert_equals( exp = 'OK' + act = mo_cut->check_booking( ls_booking ) ). + ENDMETHOD. + + METHOD is_open_returns_true. + DATA lv_time TYPE t VALUE '150000'. + cl_abap_unit_assert=>assert_equals( exp = abap_true + act = mo_cut->is_open( lv_time ) ). + ENDMETHOD. + + METHOD {{p}}if_kart_check~check_booking. + rv_reason = {{p}}if_kart_check=>c_reason-ok. + ENDMETHOD. + + METHOD {{p}}if_kart_check~check_group. + rv_reason = {{p}}if_kart_check=>c_reason-ok. + ENDMETHOD. + + METHOD {{p}}if_kart_check~is_open. + rv_open = abap_true. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1926/spec.md b/tasks_gen/train/G1926/spec.md new file mode 100644 index 0000000..89900b3 --- /dev/null +++ b/tasks_gen/train/G1926/spec.md @@ -0,0 +1,67 @@ +# 1. Goal +A go-kart circuit starts a race only when the booking is correct. The booking +desk and the web shop of the circuit must use the same check. Create the +interface that both programs use as the contract of the check. + +# 2. Open questions +None. + +# 3. Context +- The interface {{P}}IF_KART_CHECK does not exist. Create it in package $TMP. +- The circuit returns one reason code for a booking. The reason codes are + OK, NO_NAME, TOO_YOUNG, TOO_OLD, BAD_LAPS, CLOSED and TOO_MANY. +- The meaning of the reason codes is: + OK - the booking is correct. + NO_NAME - the driver name is empty. + TOO_YOUNG - the driver is younger than MIN_AGE. + TOO_OLD - the driver is older than MAX_AGE. + BAD_LAPS - the number of laps is outside MIN_LAPS and MAX_LAPS. + CLOSED - the booking time is outside the opening hours. + TOO_MANY - the group has more than MAX_DRIVERS bookings. +- The circuit is open from 09:00:00 to 22:00:00. +- The booking desk and the web shop read the reason codes and the limits from + the interface. No other object uses the interface. + +# 4. Contract +- Create the interface {{P}}IF_KART_CHECK in package $TMP. +- The interface is public. +- The interface contains the types, the constants and the methods of the + business rules. Do not add other public components. + +# 5. Business rules +1. The interface has the type TY_REASON. TY_REASON is a character type of + length 12. +2. The interface has the structure type TY_BOOKING. The components are: + DRIVER_NAME (character, length 20), DRIVER_AGE (integer), LAPS (integer), + BOOKING_TIME (time). +3. The interface has the table type TT_BOOKINGS. The row type is TY_BOOKING. + TT_BOOKINGS is a standard table with an empty key. +4. The interface has the constant structure C_REASON. Each component has the + type TY_REASON. The components and the values are: + OK = 'OK', NO_NAME = 'NO_NAME', TOO_YOUNG = 'TOO_YOUNG', + TOO_OLD = 'TOO_OLD', BAD_LAPS = 'BAD_LAPS', CLOSED = 'CLOSED', + TOO_MANY = 'TOO_MANY'. +5. The interface has the constant structure C_LIMIT. Each component has the + type i. The components and the values are: + MIN_AGE = 12, MAX_AGE = 75, MIN_LAPS = 5, MAX_LAPS = 30, MAX_DRIVERS = 8. +6. The interface has the constant C_OPEN_FROM with the value '090000' and the + constant C_OPEN_TO with the value '220000'. Both constants have the type t. +7. The interface has the method CHECK_BOOKING. The importing parameter + IS_BOOKING has the type TY_BOOKING. The returning parameter RV_REASON has + the type TY_REASON. +8. The interface has the method CHECK_GROUP. The importing parameter + IT_BOOKINGS has the type TT_BOOKINGS. The returning parameter RV_REASON has + the type TY_REASON. +9. The interface has the method IS_OPEN. The importing parameter IV_TIME has + the type t. The returning parameter RV_OPEN has the type ABAP_BOOL. + +# 6. Constraints +- Release target: 8.16. +- Coding standards: Clean ABAP. No comment that restates the code. +- Out of scope: do not create other objects. + +# 7. Acceptance +- The interface is active and has no syntax error. +- The hidden tests pass. +- Write your own ABAP Unit tests for the interface. Use a global test class, + for example {{P}}KART_CHECK_TEST. diff --git a/tasks_gen/train/G1926/task.json b/tasks_gen/train/G1926/task.json new file mode 100644 index 0000000..fc40c70 --- /dev/null +++ b/tasks_gen/train/G1926/task.json @@ -0,0 +1,46 @@ +{ + "id": "G1926", + "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_KART_CHECK" + } + ], + "out_of_scope": [], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}KART_CHECK_HIDDEN", + "file": "hidden/kart_check_hidden.clas.abap", + "description": "Hidden tests for the kart check interface. The test class itself implements the interface, so it only compiles when every signature matches. It reads the constants and checks the component lengths and the component values." + } + ], + "reference": [ + { + "type": "INTF", + "name": "{{P}}IF_KART_CHECK", + "file": "reference/if_kart_check.intf.abap", + "description": "Kart check interface with types, constants and methods" + }, + { + "type": "CLAS", + "name": "{{P}}KART_CHECK_TEST", + "file": "reference/kart_check_test.clas.abap", + "description": "Own ABAP Unit tests for the interface" + } + ], + "craft_checks": [ + "method_length", + "db_operation_in_loop" + ] +} \ No newline at end of file diff --git a/tasks_gen/train/G1927/faulty/m0_i_job_cost.ddls.asddls b/tasks_gen/train/G1927/faulty/m0_i_job_cost.ddls.asddls new file mode 100644 index 0000000..1f4275f --- /dev/null +++ b/tasks_gen/train/G1927/faulty/m0_i_job_cost.ddls.asddls @@ -0,0 +1,24 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Service job cost' +define view entity {{P}}I_JOB_COST + as select from {{p}}job as h + left outer join {{p}}jobl as l on l.job_id = h.job_id +{ + key h.job_id as job_id, + h.customer as customer, + h.calc_mode as calc_mode, + h.group_code as group_code, + h.job_date as job_date, + sum( l.work_hours ) as work_hours, + count( * ) as line_count, + sum( case when h.calc_mode = 'F' + then cast( l.rate as abap.dec( 21, 4 ) ) + else cast( l.work_hours * l.rate as abap.dec( 21, 4 ) ) + end ) as job_value +} +group by + h.job_id, + h.customer, + h.calc_mode, + h.group_code, + h.job_date diff --git a/tasks_gen/train/G1927/faulty/m1_i_job_cost.ddls.asddls b/tasks_gen/train/G1927/faulty/m1_i_job_cost.ddls.asddls new file mode 100644 index 0000000..5bccdd8 --- /dev/null +++ b/tasks_gen/train/G1927/faulty/m1_i_job_cost.ddls.asddls @@ -0,0 +1,24 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Service job cost' +define view entity {{P}}I_JOB_COST + as select from {{p}}job as h + inner join {{p}}jobl as l on l.job_id <> h.job_id +{ + key h.job_id as job_id, + h.customer as customer, + h.calc_mode as calc_mode, + h.group_code as group_code, + h.job_date as job_date, + sum( l.work_hours ) as work_hours, + count( * ) as line_count, + sum( case when h.calc_mode = 'F' + then cast( l.rate as abap.dec( 21, 4 ) ) + else cast( l.work_hours * l.rate as abap.dec( 21, 4 ) ) + end ) as job_value +} +group by + h.job_id, + h.customer, + h.calc_mode, + h.group_code, + h.job_date diff --git a/tasks_gen/train/G1927/faulty/m2_i_job_cost.ddls.asddls b/tasks_gen/train/G1927/faulty/m2_i_job_cost.ddls.asddls new file mode 100644 index 0000000..25c0c35 --- /dev/null +++ b/tasks_gen/train/G1927/faulty/m2_i_job_cost.ddls.asddls @@ -0,0 +1,24 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Service job cost' +define view entity {{P}}I_JOB_COST + as select from {{p}}job as h + inner join {{p}}jobl as l on l.job_id = h.job_id +{ + key h.job_id as job_id, + h.customer as customer, + h.calc_mode as calc_mode, + h.group_code as group_code, + h.job_date as job_date, + max( l.work_hours ) as work_hours, + count( * ) as line_count, + sum( case when h.calc_mode = 'F' + then cast( l.rate as abap.dec( 21, 4 ) ) + else cast( l.work_hours * l.rate as abap.dec( 21, 4 ) ) + end ) as job_value +} +group by + h.job_id, + h.customer, + h.calc_mode, + h.group_code, + h.job_date diff --git a/tasks_gen/train/G1927/faulty/m3_i_job_cost.ddls.asddls b/tasks_gen/train/G1927/faulty/m3_i_job_cost.ddls.asddls new file mode 100644 index 0000000..a97784a --- /dev/null +++ b/tasks_gen/train/G1927/faulty/m3_i_job_cost.ddls.asddls @@ -0,0 +1,24 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Service job cost' +define view entity {{P}}I_JOB_COST + as select from {{p}}job as h + inner join {{p}}jobl as l on l.job_id = h.job_id +{ + key h.job_id as job_id, + h.customer as customer, + h.calc_mode as calc_mode, + h.group_code as group_code, + h.job_date as job_date, + sum( l.work_hours ) as work_hours, + count( * ) as line_count, + sum( case when h.calc_mode <> 'F' + then cast( l.rate as abap.dec( 21, 4 ) ) + else cast( l.work_hours * l.rate as abap.dec( 21, 4 ) ) + end ) as job_value +} +group by + h.job_id, + h.customer, + h.calc_mode, + h.group_code, + h.job_date diff --git a/tasks_gen/train/G1927/faulty/m4_i_job_cost.ddls.asddls b/tasks_gen/train/G1927/faulty/m4_i_job_cost.ddls.asddls new file mode 100644 index 0000000..78308e1 --- /dev/null +++ b/tasks_gen/train/G1927/faulty/m4_i_job_cost.ddls.asddls @@ -0,0 +1,24 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Service job cost' +define view entity {{P}}I_JOB_COST + as select from {{p}}job as h + inner join {{p}}jobl as l on l.job_id = h.job_id +{ + key h.job_id as job_id, + h.customer as customer, + h.calc_mode as calc_mode, + h.group_code as group_code, + h.job_date as job_date, + sum( l.work_hours ) as work_hours, + count( * ) as line_count, + sum( case when h.calc_mode = 'Z' + then cast( l.rate as abap.dec( 21, 4 ) ) + else cast( l.work_hours * l.rate as abap.dec( 21, 4 ) ) + end ) as job_value +} +group by + h.job_id, + h.customer, + h.calc_mode, + h.group_code, + h.job_date diff --git a/tasks_gen/train/G1927/generation.json b/tasks_gen/train/G1927/generation.json new file mode 100644 index 0000000..d650252 --- /dev/null +++ b/tasks_gen/train/G1927/generation.json @@ -0,0 +1,24 @@ +{ + "id": "G1927", + "pool": "train", + "object_type": "DDLS", + "category": "E", + "attempts": [ + { + "stage": "validate", + "oracle": null, + "null": null + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 5, + "killed": 5, + "ok": true + } + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1927/hidden/e21_hidden.clas.abap b/tasks_gen/train/G1927/hidden/e21_hidden.clas.abap new file mode 100644 index 0000000..0115bc2 --- /dev/null +++ b/tasks_gen/train/G1927/hidden/e21_hidden.clas.abap @@ -0,0 +1,101 @@ +CLASS {{p}}e21_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 value_hourly FOR TESTING. + METHODS value_fixed FOR TESTING. + METHODS work_hours_sum FOR TESTING. + METHODS line_count FOR TESTING. + METHODS job_without_lines FOR TESTING. + METHODS calc_mode_shown FOR TESTING. + METHODS group_code_shown FOR TESTING. + METHODS customer_shown FOR TESTING. + METHODS job_date_shown FOR TESTING. + METHODS row_count FOR TESTING. +ENDCLASS. + + +CLASS {{p}}e21_hidden IMPLEMENTATION. + METHOD class_setup. + go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_JOB_COST' ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + DATA lt_job TYPE STANDARD TABLE OF {{p}}job WITH EMPTY KEY. + DATA lt_jobl TYPE STANDARD TABLE OF {{p}}jobl WITH EMPTY KEY. + go_env->clear_doubles( ). + lt_job = VALUE #( + ( job_id = 'J1' customer = 'C1' calc_mode = 'H' group_code = 'A1' job_date = '20240101' ) + ( job_id = 'J2' customer = 'C2' calc_mode = 'F' group_code = 'A2' job_date = '20240102' ) + ( job_id = 'J3' customer = 'C3' calc_mode = 'H' group_code = 'A1' job_date = '20240103' ) ). + lt_jobl = VALUE #( + ( job_id = 'J1' line_no = 1 work_hours = '3.00' rate = '10.00' ) + ( job_id = 'J1' line_no = 2 work_hours = '1.00' rate = '2.50' ) + ( job_id = 'J1' line_no = 3 work_hours = '4.00' rate = '0.25' ) + ( job_id = 'J2' line_no = 1 work_hours = '2.00' rate = '100.00' ) + ( job_id = 'J2' line_no = 2 work_hours = '5.00' rate = '50.00' ) ). + go_env->insert_test_data( lt_job ). + go_env->insert_test_data( lt_jobl ). + ENDMETHOD. + + METHOD value_hourly. + SELECT SINGLE job_value FROM {{p}}i_job_cost WHERE job_id = 'J1' INTO @DATA(lv_value). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '33.50' ) + act = CONV decfloat34( lv_value ) ). + ENDMETHOD. + + METHOD value_fixed. + SELECT SINGLE job_value FROM {{p}}i_job_cost WHERE job_id = 'J2' INTO @DATA(lv_value). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '150.00' ) + act = CONV decfloat34( lv_value ) ). + ENDMETHOD. + + METHOD work_hours_sum. + SELECT SINGLE work_hours FROM {{p}}i_job_cost WHERE job_id = 'J1' INTO @DATA(lv_hours). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 8 ) + act = CONV decfloat34( lv_hours ) ). + ENDMETHOD. + + METHOD line_count. + SELECT SINGLE line_count FROM {{p}}i_job_cost WHERE job_id = 'J1' INTO @DATA(lv_count). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 3 ) + act = CONV decfloat34( lv_count ) ). + ENDMETHOD. + + METHOD job_without_lines. + SELECT COUNT(*) FROM {{p}}i_job_cost WHERE job_id = 'J3' INTO @DATA(lv_rows). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_rows ). + ENDMETHOD. + + METHOD calc_mode_shown. + SELECT SINGLE calc_mode FROM {{p}}i_job_cost WHERE job_id = 'J2' INTO @DATA(lv_mode). + cl_abap_unit_assert=>assert_equals( exp = 'F' act = lv_mode ). + ENDMETHOD. + + METHOD group_code_shown. + SELECT SINGLE group_code FROM {{p}}i_job_cost WHERE job_id = 'J1' INTO @DATA(lv_group). + cl_abap_unit_assert=>assert_equals( exp = 'A1' act = lv_group ). + ENDMETHOD. + + METHOD customer_shown. + SELECT SINGLE customer FROM {{p}}i_job_cost WHERE job_id = 'J1' INTO @DATA(lv_customer). + cl_abap_unit_assert=>assert_equals( exp = 'C1' act = lv_customer ). + ENDMETHOD. + + METHOD job_date_shown. + SELECT SINGLE job_date FROM {{p}}i_job_cost WHERE job_id = 'J1' INTO @DATA(lv_date). + cl_abap_unit_assert=>assert_equals( exp = '20240101' act = lv_date ). + ENDMETHOD. + + METHOD row_count. + SELECT COUNT(*) FROM {{p}}i_job_cost INTO @DATA(lv_rows). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lv_rows ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1927/mutation.json b/tasks_gen/train/G1927/mutation.json new file mode 100644 index 0000000..c3d7714 --- /dev/null +++ b/tasks_gen/train/G1927/mutation.json @@ -0,0 +1,61 @@ +{ + "task": "G1927", + "mutants": [ + { + "object": "{{P}}I_JOB_COST", + "mutant": "line 5: inner join -> left outer join (join)", + "status": "killed", + "hidden": "8/10", + "failed_tests": [ + "JOB_WITHOUT_LINES", + "ROW_COUNT" + ] + }, + { + "object": "{{P}}I_JOB_COST", + "mutant": "line 5: = -> <> (eq)", + "status": "killed", + "hidden": "4/10", + "failed_tests": [ + "JOB_WITHOUT_LINES", + "LINE_COUNT", + "ROW_COUNT", + "VALUE_FIXED", + "VALUE_HOURLY", + "WORK_HOURS_SUM" + ] + }, + { + "object": "{{P}}I_JOB_COST", + "mutant": "line 12: sum( -> max( (agg)", + "status": "killed", + "hidden": "9/10", + "failed_tests": [ + "WORK_HOURS_SUM" + ] + }, + { + "object": "{{P}}I_JOB_COST", + "mutant": "line 14: = -> <> (eq)", + "status": "killed", + "hidden": "8/10", + "failed_tests": [ + "VALUE_FIXED", + "VALUE_HOURLY" + ] + }, + { + "object": "{{P}}I_JOB_COST", + "mutant": "line 14: 'F' -> 'Z' (lit)", + "status": "killed", + "hidden": "9/10", + "failed_tests": [ + "VALUE_FIXED" + ] + } + ], + "valid": 5, + "killed": 5, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1927/reference/e21_test.clas.abap b/tasks_gen/train/G1927/reference/e21_test.clas.abap new file mode 100644 index 0000000..af3db98 --- /dev/null +++ b/tasks_gen/train/G1927/reference/e21_test.clas.abap @@ -0,0 +1,55 @@ +CLASS {{p}}e21_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 hourly_value FOR TESTING. + METHODS fixed_value FOR TESTING. +ENDCLASS. + + +CLASS {{p}}e21_test IMPLEMENTATION. + METHOD class_setup. + go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_JOB_COST' ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + go_env->clear_doubles( ). + ENDMETHOD. + + METHOD hourly_value. + DATA lt_job TYPE STANDARD TABLE OF {{p}}job WITH EMPTY KEY. + DATA lt_jobl TYPE STANDARD TABLE OF {{p}}jobl WITH EMPTY KEY. + lt_job = VALUE #( ( job_id = 'A' customer = 'C1' calc_mode = 'H' + group_code = 'G1' job_date = '20240101' ) ). + lt_jobl = VALUE #( ( job_id = 'A' line_no = 1 work_hours = '2.00' rate = '10.00' ) + ( job_id = 'A' line_no = 2 work_hours = '1.50' rate = '4.00' ) ). + go_env->insert_test_data( lt_job ). + go_env->insert_test_data( lt_jobl ). + SELECT SINGLE work_hours, job_value FROM {{p}}i_job_cost WHERE job_id = 'A' + INTO @DATA(ls_row). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '3.50' ) + act = CONV decfloat34( ls_row-work_hours ) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '26.00' ) + act = CONV decfloat34( ls_row-job_value ) ). + ENDMETHOD. + + METHOD fixed_value. + DATA lt_job TYPE STANDARD TABLE OF {{p}}job WITH EMPTY KEY. + DATA lt_jobl TYPE STANDARD TABLE OF {{p}}jobl WITH EMPTY KEY. + lt_job = VALUE #( ( job_id = 'B' customer = 'C2' calc_mode = 'F' + group_code = 'G2' job_date = '20240102' ) ). + lt_jobl = VALUE #( ( job_id = 'B' line_no = 1 work_hours = '1.00' rate = '75.00' ) ). + go_env->insert_test_data( lt_job ). + go_env->insert_test_data( lt_jobl ). + SELECT SINGLE job_value FROM {{p}}i_job_cost WHERE job_id = 'B' INTO @DATA(lv_value). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '75.00' ) + act = CONV decfloat34( lv_value ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1927/reference/i_job_cost.ddls.asddls b/tasks_gen/train/G1927/reference/i_job_cost.ddls.asddls new file mode 100644 index 0000000..c346f4f --- /dev/null +++ b/tasks_gen/train/G1927/reference/i_job_cost.ddls.asddls @@ -0,0 +1,24 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Service job cost' +define view entity {{P}}I_JOB_COST + as select from {{p}}job as h + inner join {{p}}jobl as l on l.job_id = h.job_id +{ + key h.job_id as job_id, + h.customer as customer, + h.calc_mode as calc_mode, + h.group_code as group_code, + h.job_date as job_date, + sum( l.work_hours ) as work_hours, + count( * ) as line_count, + sum( case when h.calc_mode = 'F' + then cast( l.rate as abap.dec( 21, 4 ) ) + else cast( l.work_hours * l.rate as abap.dec( 21, 4 ) ) + end ) as job_value +} +group by + h.job_id, + h.customer, + h.calc_mode, + h.group_code, + h.job_date diff --git a/tasks_gen/train/G1927/seed/i_job_cost.ddls.asddls b/tasks_gen/train/G1927/seed/i_job_cost.ddls.asddls new file mode 100644 index 0000000..81aeaa6 --- /dev/null +++ b/tasks_gen/train/G1927/seed/i_job_cost.ddls.asddls @@ -0,0 +1,24 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Service job cost' +define view entity {{P}}I_JOB_COST + as select from {{p}}job as h + inner join {{p}}jobl as l on l.job_id = h.job_id +{ + key h.job_id as job_id, + h.customer as customer_name, + h.calc_mode as calc_mode_cd, + h.group_code as group_code, + h.job_date as job_date, + sum( l.work_hours ) as hours_sum, + count( * ) as line_count, + sum( case when h.calc_mode = 'F' + then cast( l.rate as abap.dec( 21, 4 ) ) + else cast( l.work_hours * l.rate as abap.dec( 21, 4 ) ) + end ) as value_sum +} +group by + h.job_id, + h.customer, + h.calc_mode, + h.group_code, + h.job_date diff --git a/tasks_gen/train/G1927/seed/job.tabl.asabap b/tasks_gen/train/G1927/seed/job.tabl.asabap new file mode 100644 index 0000000..ca49bd2 --- /dev/null +++ b/tasks_gen/train/G1927/seed/job.tabl.asabap @@ -0,0 +1,13 @@ +@EndUserText.label : 'Service job' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}job { + key client : abap.clnt not null; + key job_id : abap.char(10) not null; + customer : abap.char(10); + calc_mode : abap.char(1); + group_code : abap.char(2); + job_date : abap.dats; +} diff --git a/tasks_gen/train/G1927/seed/jobl.tabl.asabap b/tasks_gen/train/G1927/seed/jobl.tabl.asabap new file mode 100644 index 0000000..defd842 --- /dev/null +++ b/tasks_gen/train/G1927/seed/jobl.tabl.asabap @@ -0,0 +1,12 @@ +@EndUserText.label : 'Service job work line' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}jobl { + key client : abap.clnt not null; + key job_id : abap.char(10) not null; + key line_no : abap.int4 not null; + work_hours : abap.dec(5,2); + rate : abap.dec(15,2); +} diff --git a/tasks_gen/train/G1927/spec.md b/tasks_gen/train/G1927/spec.md new file mode 100644 index 0000000..021ce7c --- /dev/null +++ b/tasks_gen/train/G1927/spec.md @@ -0,0 +1,51 @@ +# 1. Goal +The CDS view entity {{P}}I_JOB_COST in package $TMP shows the cost of the +service jobs of a wind turbine service company. The view is active. Its element +names are old abbreviations that carry stems of SQL keywords. Refactor the view +in place. Keep the view name. Keep the behavior. Rename the elements to the +safe names of the contract. + +# 2. Open questions +None. + +# 3. Context +- Table {{P}}JOB (service job), package $TMP. Key: JOB_ID (CHAR 10). + Fields: CUSTOMER (CHAR 10), CALC_MODE (CHAR 1), GROUP_CODE (CHAR 2), + JOB_DATE (DATS). +- Table {{P}}JOBL (work line of a service job), package $TMP. + Key: JOB_ID (CHAR 10), LINE_NO (INT4). Fields: WORK_HOURS (DEC 5,2), + RATE (DEC 15,2). +- The view {{P}}I_JOB_COST is in package $TMP and is active. The current +definition of the view is the specification of the calculation. +- A report and an OData service read the view. They use the element names of +the contract. + +# 4. Contract +- The CDS view entity {{P}}I_JOB_COST in package $TMP. The view name stays the + same. +- Elements, with these names. They replace the current element names: + - JOB_ID (key) + - CUSTOMER + - CALC_MODE + - GROUP_CODE + - JOB_DATE + - WORK_HOURS + - LINE_COUNT + - JOB_VALUE +- No authorization check (#NOT_REQUIRED). + +# 5. Business rules +1. The behavior of {{P}}I_JOB_COST must not change. Read the current definition + of the view in package $TMP. It is the specification of the calculation. +2. The element names are the names in the contract. No element name is a + reserved word. + +# 6. Constraints +- Release target: 8.16 (ABAP Platform 2025). +- Coding standards: Clean ABAP. No ATC priority 1 or 2 findings. +- Out of scope: do not change {{P}}JOB and {{P}}JOBL. + +# 7. Acceptance +- The view {{P}}I_JOB_COST 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. diff --git a/tasks_gen/train/G1927/task.json b/tasks_gen/train/G1927/task.json new file mode 100644 index 0000000..1dce7f5 --- /dev/null +++ b/tasks_gen/train/G1927/task.json @@ -0,0 +1,75 @@ +{ + "id": "G1927", + "category": "E", + "object_type": "DDLS", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [ + { + "type": "TABL", + "name": "{{P}}JOB", + "file": "seed/job.tabl.asabap", + "description": "Service job header" + }, + { + "type": "TABL", + "name": "{{P}}JOBL", + "file": "seed/jobl.tabl.asabap", + "description": "Service job work line" + }, + { + "type": "DDLS", + "name": "{{P}}I_JOB_COST", + "file": "seed/i_job_cost.ddls.asddls", + "description": "Legacy service job cost view" + } + ], + "contract": [ + { + "type": "DDLS", + "name": "{{P}}I_JOB_COST", + "fields": [ + "JOB_ID", + "CUSTOMER", + "CALC_MODE", + "GROUP_CODE", + "JOB_DATE", + "WORK_HOURS", + "LINE_COUNT", + "JOB_VALUE" + ] + } + ], + "out_of_scope": [ + "{{P}}JOB", + "{{P}}JOBL" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}E21_HIDDEN", + "file": "hidden/e21_hidden.clas.abap", + "description": "E21 hidden tests" + } + ], + "reference": [ + { + "type": "DDLS", + "name": "{{P}}I_JOB_COST", + "file": "reference/i_job_cost.ddls.asddls", + "description": "Service job cost view" + }, + { + "type": "CLAS", + "name": "{{P}}E21_TEST", + "file": "reference/e21_test.clas.abap", + "description": "E21 own tests" + } + ], + "craft_checks": [] +} \ No newline at end of file diff --git a/tasks_gen/train/G1928/faulty/m0_i_wind_grade.ddls.asddls b/tasks_gen/train/G1928/faulty/m0_i_wind_grade.ddls.asddls new file mode 100644 index 0000000..16acf52 --- /dev/null +++ b/tasks_gen/train/G1928/faulty/m0_i_wind_grade.ddls.asddls @@ -0,0 +1,34 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Wind turbine yield grade' +define view entity {{P}}I_WIND_GRADE + as select from {{p}}yield as y + left outer join {{p}}turbine as t on t.turbine_id = y.turbine_id +{ + key y.turbine_id as turbine_id, + key y.calmonth as calmonth, + t.site as site, + y.energy_kwh as energy_kwh, + y.downtime_hrs as downtime_hrs, + case + when y.energy_kwh >= 200000 then 'A' + when y.energy_kwh >= 100000 then 'B' + when y.energy_kwh >= 50000 then 'C' + when y.energy_kwh >= 10000 then 'D' + else 'E' + end as yield_grade, + case + when y.downtime_hrs <= 10 then 'FULL' + when y.downtime_hrs <= 100 then 'PARTIAL' + else 'POOR' + end as availability, + case + when y.energy_kwh >= 200000 and y.downtime_hrs <= 10 then 'TOP' + when y.energy_kwh >= 100000 and y.downtime_hrs <= 100 then 'GOOD' + else 'WEAK' + end as rating, + case + when y.downtime_hrs > 100 then y.downtime_hrs * 25 + when y.downtime_hrs > 10 then y.downtime_hrs * 10 + else 0 + end as penalty +} diff --git a/tasks_gen/train/G1928/faulty/m1_i_wind_grade.ddls.asddls b/tasks_gen/train/G1928/faulty/m1_i_wind_grade.ddls.asddls new file mode 100644 index 0000000..de1c263 --- /dev/null +++ b/tasks_gen/train/G1928/faulty/m1_i_wind_grade.ddls.asddls @@ -0,0 +1,34 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Wind turbine yield grade' +define view entity {{P}}I_WIND_GRADE + as select from {{p}}yield as y + inner join {{p}}turbine as t on t.turbine_id = y.turbine_id +{ + key y.turbine_id as turbine_id, + key y.calmonth as calmonth, + t.site as site, + y.energy_kwh as energy_kwh, + y.downtime_hrs as downtime_hrs, + case + when y.energy_kwh < 200000 then 'A' + when y.energy_kwh >= 100000 then 'B' + when y.energy_kwh >= 50000 then 'C' + when y.energy_kwh >= 10000 then 'D' + else 'E' + end as yield_grade, + case + when y.downtime_hrs <= 10 then 'FULL' + when y.downtime_hrs <= 100 then 'PARTIAL' + else 'POOR' + end as availability, + case + when y.energy_kwh >= 200000 and y.downtime_hrs <= 10 then 'TOP' + when y.energy_kwh >= 100000 and y.downtime_hrs <= 100 then 'GOOD' + else 'WEAK' + end as rating, + case + when y.downtime_hrs > 100 then y.downtime_hrs * 25 + when y.downtime_hrs > 10 then y.downtime_hrs * 10 + else 0 + end as penalty +} diff --git a/tasks_gen/train/G1928/faulty/m2_i_wind_grade.ddls.asddls b/tasks_gen/train/G1928/faulty/m2_i_wind_grade.ddls.asddls new file mode 100644 index 0000000..cd525cf --- /dev/null +++ b/tasks_gen/train/G1928/faulty/m2_i_wind_grade.ddls.asddls @@ -0,0 +1,34 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Wind turbine yield grade' +define view entity {{P}}I_WIND_GRADE + as select from {{p}}yield as y + inner join {{p}}turbine as t on t.turbine_id = y.turbine_id +{ + key y.turbine_id as turbine_id, + key y.calmonth as calmonth, + t.site as site, + y.energy_kwh as energy_kwh, + y.downtime_hrs as downtime_hrs, + case + when y.energy_kwh >= 200000 then 'A' + when y.energy_kwh >= 100000 then 'B' + when y.energy_kwh >= 50000 then 'C' + when y.energy_kwh >= 10000 then 'D' + else 'E' + end as yield_grade, + case + when y.downtime_hrs <= 10 then 'FULL' + when y.downtime_hrs <= 100 then 'PARTIAL' + else 'POOR' + end as availability, + case + when y.energy_kwh >= 200000 or y.downtime_hrs <= 10 then 'TOP' + when y.energy_kwh >= 100000 and y.downtime_hrs <= 100 then 'GOOD' + else 'WEAK' + end as rating, + case + when y.downtime_hrs > 100 then y.downtime_hrs * 25 + when y.downtime_hrs > 10 then y.downtime_hrs * 10 + else 0 + end as penalty +} diff --git a/tasks_gen/train/G1928/faulty/m3_i_wind_grade.ddls.asddls b/tasks_gen/train/G1928/faulty/m3_i_wind_grade.ddls.asddls new file mode 100644 index 0000000..9c03b6c --- /dev/null +++ b/tasks_gen/train/G1928/faulty/m3_i_wind_grade.ddls.asddls @@ -0,0 +1,34 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Wind turbine yield grade' +define view entity {{P}}I_WIND_GRADE + as select from {{p}}yield as y + inner join {{p}}turbine as t on t.turbine_id = y.turbine_id +{ + key y.turbine_id as turbine_id, + key y.calmonth as calmonth, + t.site as site, + y.energy_kwh as energy_kwh, + y.downtime_hrs as downtime_hrs, + case + when y.energy_kwh >= 200000 then 'A' + when y.energy_kwh >= 100000 then 'B' + when y.energy_kwh >= 50000 then 'C' + when y.energy_kwh >= 10000 then 'D' + else 'E' + end as yield_grade, + case + when y.downtime_hrs <= 10 then 'FULL' + when y.downtime_hrs <= 100 then 'PARTIAL' + else 'POOR' + end as availability, + case + when y.energy_kwh >= 200000 and y.downtime_hrs <= 10 then 'TOP' + when y.energy_kwh >= 100000 and y.downtime_hrs <= 101 then 'GOOD' + else 'WEAK' + end as rating, + case + when y.downtime_hrs > 100 then y.downtime_hrs * 25 + when y.downtime_hrs > 10 then y.downtime_hrs * 10 + else 0 + end as penalty +} diff --git a/tasks_gen/train/G1928/faulty/m4_i_wind_grade.ddls.asddls b/tasks_gen/train/G1928/faulty/m4_i_wind_grade.ddls.asddls new file mode 100644 index 0000000..897370d --- /dev/null +++ b/tasks_gen/train/G1928/faulty/m4_i_wind_grade.ddls.asddls @@ -0,0 +1,34 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Wind turbine yield grade' +define view entity {{P}}I_WIND_GRADE + as select from {{p}}yield as y + inner join {{p}}turbine as t on t.turbine_id = y.turbine_id +{ + key y.turbine_id as turbine_id, + key y.calmonth as calmonth, + t.site as site, + y.energy_kwh as energy_kwh, + y.downtime_hrs as downtime_hrs, + case + when y.energy_kwh >= 200000 then 'A' + when y.energy_kwh >= 100000 then 'B' + when y.energy_kwh >= 50000 then 'C' + when y.energy_kwh >= 10000 then 'D' + else 'E' + end as yield_grade, + case + when y.downtime_hrs <= 10 then 'FULL' + when y.downtime_hrs <= 100 then 'PARTIAL' + else 'POOR' + end as availability, + case + when y.energy_kwh >= 200000 and y.downtime_hrs <= 10 then 'TOP' + when y.energy_kwh >= 100000 and y.downtime_hrs <= 100 then 'GOOD' + else 'ZEAK' + end as rating, + case + when y.downtime_hrs > 100 then y.downtime_hrs * 25 + when y.downtime_hrs > 10 then y.downtime_hrs * 10 + else 0 + end as penalty +} diff --git a/tasks_gen/train/G1928/generation.json b/tasks_gen/train/G1928/generation.json new file mode 100644 index 0000000..6df0c86 --- /dev/null +++ b/tasks_gen/train/G1928/generation.json @@ -0,0 +1,29 @@ +{ + "id": "G1928", + "pool": "train", + "object_type": "DDLS", + "category": "E", + "attempts": [ + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 5, + "killed": 3, + "ok": false + } + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 5, + "killed": 5, + "ok": true + } + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1928/hidden/t31_hidden.clas.abap b/tasks_gen/train/G1928/hidden/t31_hidden.clas.abap new file mode 100644 index 0000000..0b61a8c --- /dev/null +++ b/tasks_gen/train/G1928/hidden/t31_hidden.clas.abap @@ -0,0 +1,159 @@ +CLASS {{p}}t31_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 grade_a_top FOR TESTING. + METHODS grade_b_good FOR TESTING. + METHODS grade_c_weak FOR TESTING. + METHODS grade_d_and_e FOR TESTING. + METHODS avail_poor FOR TESTING. + METHODS rating_weak FOR TESTING. + METHODS rating_at_101_hrs FOR TESTING. + METHODS penalty_high FOR TESTING. + METHODS penalty_mid FOR TESTING. + METHODS penalty_zero FOR TESTING. + METHODS row_count FOR TESTING. + METHODS orphan_yield_hidden FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t31_hidden IMPLEMENTATION. + + METHOD class_setup. + go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_WIND_GRADE' ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + DATA lt_turbine TYPE STANDARD TABLE OF {{p}}turbine WITH EMPTY KEY. + DATA lt_yield TYPE STANDARD TABLE OF {{p}}yield WITH EMPTY KEY. + + go_env->clear_doubles( ). + + lt_turbine = VALUE #( + ( turbine_id = 'T1' site = 'NORTH' capacity_kw = 2000 commissioned = '20150101' ) + ( turbine_id = 'T2' site = 'SOUTH' capacity_kw = 1500 commissioned = '20180101' ) + ( turbine_id = 'T3' site = 'NORTH' capacity_kw = 800 commissioned = '20200101' ) ). + + lt_yield = VALUE #( + ( turbine_id = 'T1' calmonth = '202401' energy_kwh = '250000.00' downtime_hrs = 5 ) + ( turbine_id = 'T1' calmonth = '202402' energy_kwh = '200000.00' downtime_hrs = 10 ) + ( turbine_id = 'T1' calmonth = '202403' energy_kwh = '250000.00' downtime_hrs = 200 ) + ( turbine_id = 'T2' calmonth = '202401' energy_kwh = '100000.00' downtime_hrs = 100 ) + ( turbine_id = 'T2' calmonth = '202402' energy_kwh = '99999.99' downtime_hrs = 101 ) + ( turbine_id = 'T2' calmonth = '202403' energy_kwh = '50000.00' downtime_hrs = 11 ) + ( turbine_id = 'T2' calmonth = '202404' energy_kwh = '10000.00' downtime_hrs = 0 ) + ( turbine_id = 'T2' calmonth = '202405' energy_kwh = '9999.99' downtime_hrs = 0 ) + ( turbine_id = 'T2' calmonth = '202406' energy_kwh = '150000.00' downtime_hrs = 101 ) + ( turbine_id = 'T9' calmonth = '202407' energy_kwh = '300000.00' downtime_hrs = 0 ) ). + + go_env->insert_test_data( lt_turbine ). + go_env->insert_test_data( lt_yield ). + ENDMETHOD. + + METHOD grade_a_top. + SELECT SINGLE yield_grade, availability, rating, penalty + FROM {{p}}i_wind_grade + WHERE turbine_id = 'T1' AND calmonth = '202402' + INTO @DATA(ls_row). + cl_abap_unit_assert=>assert_equals( exp = 'A' act = ls_row-yield_grade ). + cl_abap_unit_assert=>assert_equals( exp = 'FULL' act = ls_row-availability ). + cl_abap_unit_assert=>assert_equals( exp = 'TOP' act = ls_row-rating ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 0 ) + act = CONV decfloat34( ls_row-penalty ) ). + ENDMETHOD. + + METHOD grade_b_good. + SELECT SINGLE site, yield_grade, availability, rating, penalty + FROM {{p}}i_wind_grade + WHERE turbine_id = 'T2' AND calmonth = '202401' + INTO @DATA(ls_row). + cl_abap_unit_assert=>assert_equals( exp = 'SOUTH' act = ls_row-site ). + cl_abap_unit_assert=>assert_equals( exp = 'B' act = ls_row-yield_grade ). + cl_abap_unit_assert=>assert_equals( exp = 'PARTIAL' act = ls_row-availability ). + cl_abap_unit_assert=>assert_equals( exp = 'GOOD' act = ls_row-rating ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 1000 ) + act = CONV decfloat34( ls_row-penalty ) ). + ENDMETHOD. + + METHOD grade_c_weak. + SELECT SINGLE yield_grade, rating FROM {{p}}i_wind_grade + WHERE turbine_id = 'T2' AND calmonth = '202403' + INTO @DATA(ls_row). + cl_abap_unit_assert=>assert_equals( exp = 'C' act = ls_row-yield_grade ). + cl_abap_unit_assert=>assert_equals( exp = 'WEAK' act = ls_row-rating ). + ENDMETHOD. + + METHOD grade_d_and_e. + SELECT SINGLE yield_grade FROM {{p}}i_wind_grade + WHERE turbine_id = 'T2' AND calmonth = '202404' INTO @DATA(lv_grade_d). + cl_abap_unit_assert=>assert_equals( exp = 'D' act = lv_grade_d ). + + SELECT SINGLE yield_grade FROM {{p}}i_wind_grade + WHERE turbine_id = 'T2' AND calmonth = '202405' INTO @DATA(lv_grade_e). + cl_abap_unit_assert=>assert_equals( exp = 'E' act = lv_grade_e ). + ENDMETHOD. + + METHOD avail_poor. + SELECT SINGLE yield_grade, availability FROM {{p}}i_wind_grade + WHERE turbine_id = 'T2' AND calmonth = '202402' INTO @DATA(ls_row). + cl_abap_unit_assert=>assert_equals( exp = 'POOR' act = ls_row-availability ). + cl_abap_unit_assert=>assert_equals( exp = 'C' act = ls_row-yield_grade ). + ENDMETHOD. + + METHOD rating_weak. + SELECT SINGLE rating FROM {{p}}i_wind_grade + WHERE turbine_id = 'T1' AND calmonth = '202403' INTO @DATA(lv_rating). + cl_abap_unit_assert=>assert_equals( exp = 'WEAK' act = lv_rating ). + ENDMETHOD. + + METHOD rating_at_101_hrs. + SELECT SINGLE yield_grade, availability, rating FROM {{p}}i_wind_grade + WHERE turbine_id = 'T2' AND calmonth = '202406' INTO @DATA(ls_row). + cl_abap_unit_assert=>assert_equals( exp = 'B' act = ls_row-yield_grade ). + cl_abap_unit_assert=>assert_equals( exp = 'POOR' act = ls_row-availability ). + cl_abap_unit_assert=>assert_equals( exp = 'WEAK' act = ls_row-rating ). + ENDMETHOD. + + METHOD penalty_high. + SELECT SINGLE penalty FROM {{p}}i_wind_grade + WHERE turbine_id = 'T1' AND calmonth = '202403' INTO @DATA(lv_penalty). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 5000 ) + act = CONV decfloat34( lv_penalty ) ). + ENDMETHOD. + + METHOD penalty_mid. + SELECT SINGLE penalty FROM {{p}}i_wind_grade + WHERE turbine_id = 'T2' AND calmonth = '202403' INTO @DATA(lv_penalty). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 110 ) + act = CONV decfloat34( lv_penalty ) ). + ENDMETHOD. + + METHOD penalty_zero. + SELECT SINGLE penalty FROM {{p}}i_wind_grade + WHERE turbine_id = 'T1' AND calmonth = '202401' INTO @DATA(lv_penalty). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 0 ) + act = CONV decfloat34( lv_penalty ) ). + ENDMETHOD. + + METHOD row_count. + SELECT COUNT(*) FROM {{p}}i_wind_grade INTO @DATA(lv_rows). + cl_abap_unit_assert=>assert_equals( exp = 9 act = lv_rows ). + ENDMETHOD. + + METHOD orphan_yield_hidden. + SELECT COUNT(*) FROM {{p}}i_wind_grade + WHERE turbine_id = 'T9' INTO @DATA(lv_orphan). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_orphan ). + + SELECT COUNT(*) FROM {{p}}i_wind_grade + WHERE turbine_id = 'T3' INTO @DATA(lv_no_yield). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_no_yield ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1928/mutation.json b/tasks_gen/train/G1928/mutation.json new file mode 100644 index 0000000..a8cc616 --- /dev/null +++ b/tasks_gen/train/G1928/mutation.json @@ -0,0 +1,62 @@ +{ + "task": "G1928", + "mutants": [ + { + "object": "{{P}}I_WIND_GRADE", + "mutant": "line 5: inner join -> left outer join (join)", + "status": "killed", + "hidden": "10/12", + "failed_tests": [ + "ORPHAN_YIELD_HIDDEN", + "ROW_COUNT" + ] + }, + { + "object": "{{P}}I_WIND_GRADE", + "mutant": "line 13: >= -> < (rel)", + "status": "killed", + "hidden": "6/12", + "failed_tests": [ + "AVAIL_POOR", + "GRADE_A_TOP", + "GRADE_B_GOOD", + "GRADE_C_WEAK", + "GRADE_D_AND_E", + "RATING_AT_101_HRS" + ] + }, + { + "object": "{{P}}I_WIND_GRADE", + "mutant": "line 25: and -> or (logic)", + "status": "killed", + "hidden": "11/12", + "failed_tests": [ + "RATING_WEAK" + ] + }, + { + "object": "{{P}}I_WIND_GRADE", + "mutant": "line 26: 100 -> 101 (const)", + "status": "killed", + "hidden": "11/12", + "failed_tests": [ + "RATING_AT_101_HRS" + ] + }, + { + "object": "{{P}}I_WIND_GRADE", + "mutant": "line 27: 'WEAK' -> 'ZEAK' (lit)", + "status": "killed", + "hidden": "9/12", + "failed_tests": [ + "GRADE_C_WEAK", + "RATING_AT_101_HRS", + "RATING_WEAK" + ] + } + ], + "valid": 5, + "killed": 5, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1928/reference/i_wind_grade.ddls.asddls b/tasks_gen/train/G1928/reference/i_wind_grade.ddls.asddls new file mode 100644 index 0000000..92087cd --- /dev/null +++ b/tasks_gen/train/G1928/reference/i_wind_grade.ddls.asddls @@ -0,0 +1,34 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Wind turbine yield grade' +define view entity {{P}}I_WIND_GRADE + as select from {{p}}yield as y + inner join {{p}}turbine as t on t.turbine_id = y.turbine_id +{ + key y.turbine_id as turbine_id, + key y.calmonth as calmonth, + t.site as site, + y.energy_kwh as energy_kwh, + y.downtime_hrs as downtime_hrs, + case + when y.energy_kwh >= 200000 then 'A' + when y.energy_kwh >= 100000 then 'B' + when y.energy_kwh >= 50000 then 'C' + when y.energy_kwh >= 10000 then 'D' + else 'E' + end as yield_grade, + case + when y.downtime_hrs <= 10 then 'FULL' + when y.downtime_hrs <= 100 then 'PARTIAL' + else 'POOR' + end as availability, + case + when y.energy_kwh >= 200000 and y.downtime_hrs <= 10 then 'TOP' + when y.energy_kwh >= 100000 and y.downtime_hrs <= 100 then 'GOOD' + else 'WEAK' + end as rating, + case + when y.downtime_hrs > 100 then y.downtime_hrs * 25 + when y.downtime_hrs > 10 then y.downtime_hrs * 10 + else 0 + end as penalty +} diff --git a/tasks_gen/train/G1928/reference/t31_test.clas.abap b/tasks_gen/train/G1928/reference/t31_test.clas.abap new file mode 100644 index 0000000..e627cf6 --- /dev/null +++ b/tasks_gen/train/G1928/reference/t31_test.clas.abap @@ -0,0 +1,64 @@ +CLASS {{p}}t31_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 grades_one_month FOR TESTING. + METHODS excludes_turbine_without_yield FOR TESTING. + METHODS excludes_orphan_yield FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t31_test IMPLEMENTATION. + + METHOD class_setup. + go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_WIND_GRADE' ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + DATA lt_turbine TYPE STANDARD TABLE OF {{p}}turbine WITH EMPTY KEY. + DATA lt_yield TYPE STANDARD TABLE OF {{p}}yield WITH EMPTY KEY. + + go_env->clear_doubles( ). + + lt_turbine = VALUE #( + ( turbine_id = 'T1' site = 'NORTH' capacity_kw = 2000 commissioned = '20150101' ) + ( turbine_id = 'T2' site = 'SOUTH' capacity_kw = 1500 commissioned = '20180101' ) ). + + lt_yield = VALUE #( + ( turbine_id = 'T1' calmonth = '202401' energy_kwh = '250000.00' downtime_hrs = 5 ) + ( turbine_id = 'T9' calmonth = '202401' energy_kwh = '300000.00' downtime_hrs = 0 ) ). + + go_env->insert_test_data( lt_turbine ). + go_env->insert_test_data( lt_yield ). + ENDMETHOD. + + METHOD grades_one_month. + SELECT SINGLE yield_grade, availability, rating, penalty + FROM {{p}}i_wind_grade + WHERE turbine_id = 'T1' AND calmonth = '202401' + INTO @DATA(ls_row). + cl_abap_unit_assert=>assert_equals( exp = 'A' act = ls_row-yield_grade ). + cl_abap_unit_assert=>assert_equals( exp = 'FULL' act = ls_row-availability ). + cl_abap_unit_assert=>assert_equals( exp = 'TOP' act = ls_row-rating ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 0 ) + act = CONV decfloat34( ls_row-penalty ) ). + ENDMETHOD. + + METHOD excludes_turbine_without_yield. + SELECT COUNT(*) FROM {{p}}i_wind_grade INTO @DATA(lv_rows). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lv_rows ). + ENDMETHOD. + + METHOD excludes_orphan_yield. + SELECT COUNT(*) FROM {{p}}i_wind_grade + WHERE turbine_id = 'T9' INTO @DATA(lv_rows). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_rows ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1928/seed/i_wind_grade.ddls.asddls b/tasks_gen/train/G1928/seed/i_wind_grade.ddls.asddls new file mode 100644 index 0000000..5235bcd --- /dev/null +++ b/tasks_gen/train/G1928/seed/i_wind_grade.ddls.asddls @@ -0,0 +1,48 @@ +@AbapCatalog.sqlViewName: '{{p}}WGRD' +@AbapCatalog.preserveKey: true +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Wind turbine yield grade' +define view {{P}}I_WIND_GRADE + as select from {{p}}yield as y + inner join {{p}}turbine as t on t.turbine_id = y.turbine_id +{ + key y.turbine_id as turbine_id, + key y.calmonth as calmonth, + t.site as site, + y.energy_kwh as energy_kwh, + y.downtime_hrs as downtime_hrs, + case + when y.energy_kwh >= 200000 then 'A' + else case + when y.energy_kwh >= 100000 then 'B' + else case + when y.energy_kwh >= 50000 then 'C' + else case + when y.energy_kwh >= 10000 then 'D' + else 'E' + end + end + end + end as yield_grade, + case + when y.downtime_hrs <= 10 then 'FULL' + else case + when y.downtime_hrs <= 100 then 'PARTIAL' + else 'POOR' + end + end as availability, + case + when y.energy_kwh >= 200000 and y.downtime_hrs <= 10 then 'TOP' + else case + when y.energy_kwh >= 100000 and y.downtime_hrs <= 100 then 'GOOD' + else 'WEAK' + end + end as rating, + case + when y.downtime_hrs > 100 then y.downtime_hrs * 25 + else case + when y.downtime_hrs > 10 then y.downtime_hrs * 10 + else 0 + end + end as penalty +} diff --git a/tasks_gen/train/G1928/seed/turbine.tabl.asabap b/tasks_gen/train/G1928/seed/turbine.tabl.asabap new file mode 100644 index 0000000..58e1b6c --- /dev/null +++ b/tasks_gen/train/G1928/seed/turbine.tabl.asabap @@ -0,0 +1,12 @@ +@EndUserText.label : 'Wind turbine' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}turbine { + key client : abap.clnt not null; + key turbine_id : abap.char(10) not null; + site : abap.char(10); + capacity_kw : abap.int4; + commissioned : abap.dats; +} diff --git a/tasks_gen/train/G1928/seed/yield.tabl.asabap b/tasks_gen/train/G1928/seed/yield.tabl.asabap new file mode 100644 index 0000000..708a600 --- /dev/null +++ b/tasks_gen/train/G1928/seed/yield.tabl.asabap @@ -0,0 +1,12 @@ +@EndUserText.label : 'Monthly yield of a wind turbine' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}yield { + key client : abap.clnt not null; + key turbine_id : abap.char(10) not null; + key calmonth : abap.char(6) not null; + energy_kwh : abap.dec(15,2); + downtime_hrs : abap.int4; +} diff --git a/tasks_gen/train/G1928/spec.md b/tasks_gen/train/G1928/spec.md new file mode 100644 index 0000000..f05c8fe --- /dev/null +++ b/tasks_gen/train/G1928/spec.md @@ -0,0 +1,54 @@ +# 1. Goal + +Refactor the legacy CDS view {{P}}I_WIND_GRADE in package $TMP. + +A wind farm operator uses the view to grade the monthly yield of each wind +turbine. The view is active, but its CASE expressions are deeply nested and +hard to read. Make the view clean and easy to read. + +The behavior stays the same. The name {{P}}I_WIND_GRADE and all element names +stay the same. A report and an OData service read the view, so the interface +must not change. + +# 2. Open questions + +None. + +# 3. Context + +- Table {{P}}TURBINE (wind turbine master data), package $TMP. + Key: TURBINE_ID (CHAR 10). + Fields: SITE (CHAR 10), CAPACITY_KW (INT4), COMMISSIONED (DATS). +- Table {{P}}YIELD (monthly yield of one wind turbine), package $TMP. + Key: TURBINE_ID (CHAR 10), CALMONTH (CHAR 6, format YYYYMM). + Fields: ENERGY_KWH (DEC 15,2), DOWNTIME_HRS (INT4). +- The view {{P}}I_WIND_GRADE already exists in package $TMP. Its DDL source is + the specification of the behavior. Read the DDL source. + +# 4. Contract + +- Refactor the CDS view {{P}}I_WIND_GRADE in package $TMP. The name stays the + same. +- Elements, with these names: TURBINE_ID (key), CALMONTH (key), SITE, + ENERGY_KWH, DOWNTIME_HRS, YIELD_GRADE, AVAILABILITY, RATING, PENALTY. +- The element names and the element types stay the same. +- No authorization check (#NOT_REQUIRED). + +# 5. Business rules + +The behavior stays the same. The current DDL source of {{P}}I_WIND_GRADE is the +only specification of the behavior. Keep every result value, every limit value +and every element. Do not add an element and do not remove an element. + +# 6. Constraints + +- Release target: 8.16. +- Coding standards: use "define view entity". Write clean CDS. A CASE + expression must not contain another CASE expression. +- Out of scope: do not change {{P}}TURBINE and {{P}}YIELD. + +# 7. Acceptance + +- The view entity 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. diff --git a/tasks_gen/train/G1928/task.json b/tasks_gen/train/G1928/task.json new file mode 100644 index 0000000..557e4df --- /dev/null +++ b/tasks_gen/train/G1928/task.json @@ -0,0 +1,76 @@ +{ + "id": "G1928", + "category": "E", + "object_type": "DDLS", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [ + { + "type": "TABL", + "name": "{{P}}TURBINE", + "file": "seed/turbine.tabl.asabap", + "description": "Wind turbine master data" + }, + { + "type": "TABL", + "name": "{{P}}YIELD", + "file": "seed/yield.tabl.asabap", + "description": "Monthly yield of one wind turbine" + }, + { + "type": "DDLS", + "name": "{{P}}I_WIND_GRADE", + "file": "seed/i_wind_grade.ddls.asddls", + "description": "Legacy view with nested CASE expressions" + } + ], + "contract": [ + { + "type": "DDLS", + "name": "{{P}}I_WIND_GRADE", + "fields": [ + "TURBINE_ID", + "CALMONTH", + "SITE", + "ENERGY_KWH", + "DOWNTIME_HRS", + "YIELD_GRADE", + "AVAILABILITY", + "RATING", + "PENALTY" + ] + } + ], + "out_of_scope": [ + "{{P}}TURBINE", + "{{P}}YIELD" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T31_HIDDEN", + "file": "hidden/t31_hidden.clas.abap", + "description": "T31 hidden tests" + } + ], + "reference": [ + { + "type": "DDLS", + "name": "{{P}}I_WIND_GRADE", + "file": "reference/i_wind_grade.ddls.asddls", + "description": "Refactored view entity with flat CASE expressions" + }, + { + "type": "CLAS", + "name": "{{P}}T31_TEST", + "file": "reference/t31_test.clas.abap", + "description": "T31 own tests" + } + ], + "craft_checks": [] +} \ No newline at end of file diff --git a/tasks_gen/train/G1929/faulty/m0_i_star_night.ddls.asddls b/tasks_gen/train/G1929/faulty/m0_i_star_night.ddls.asddls new file mode 100644 index 0000000..023658a --- /dev/null +++ b/tasks_gen/train/G1929/faulty/m0_i_star_night.ddls.asddls @@ -0,0 +1,18 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Stargazing nights of the observatory' +define view entity {{P}}I_STAR_NIGHT + as select from {{p}}night as night + left outer join {{p}}dome as dome on dome.dome_id = night.dome_id + inner join {{p}}scope as scope on scope.scope_id = night.scope_id +{ + key night.night_id as night_id, + night.dome_id as dome_id, + dome.dome_name as dome_name, + dome.city as dome_city, + night.scope_id as scope_id, + scope.scope_name as scope_name, + scope.aperture_mm as aperture_mm, + night.visitors as visitors, + night.night_date as night_date, + dome.capacity - night.visitors as free_seats +} diff --git a/tasks_gen/train/G1929/faulty/m1_i_star_night.ddls.asddls b/tasks_gen/train/G1929/faulty/m1_i_star_night.ddls.asddls new file mode 100644 index 0000000..d432729 --- /dev/null +++ b/tasks_gen/train/G1929/faulty/m1_i_star_night.ddls.asddls @@ -0,0 +1,18 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Stargazing nights of the observatory' +define view entity {{P}}I_STAR_NIGHT + as select from {{p}}night as night + inner join {{p}}dome as dome on dome.dome_id <> night.dome_id + inner join {{p}}scope as scope on scope.scope_id = night.scope_id +{ + key night.night_id as night_id, + night.dome_id as dome_id, + dome.dome_name as dome_name, + dome.city as dome_city, + night.scope_id as scope_id, + scope.scope_name as scope_name, + scope.aperture_mm as aperture_mm, + night.visitors as visitors, + night.night_date as night_date, + dome.capacity - night.visitors as free_seats +} diff --git a/tasks_gen/train/G1929/faulty/m2_i_star_night.ddls.asddls b/tasks_gen/train/G1929/faulty/m2_i_star_night.ddls.asddls new file mode 100644 index 0000000..df10a7e --- /dev/null +++ b/tasks_gen/train/G1929/faulty/m2_i_star_night.ddls.asddls @@ -0,0 +1,18 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Stargazing nights of the observatory' +define view entity {{P}}I_STAR_NIGHT + as select from {{p}}night as night + inner join {{p}}dome as dome on dome.dome_id = night.dome_id + left outer join {{p}}scope as scope on scope.scope_id = night.scope_id +{ + key night.night_id as night_id, + night.dome_id as dome_id, + dome.dome_name as dome_name, + dome.city as dome_city, + night.scope_id as scope_id, + scope.scope_name as scope_name, + scope.aperture_mm as aperture_mm, + night.visitors as visitors, + night.night_date as night_date, + dome.capacity - night.visitors as free_seats +} diff --git a/tasks_gen/train/G1929/faulty/m3_i_star_night.ddls.asddls b/tasks_gen/train/G1929/faulty/m3_i_star_night.ddls.asddls new file mode 100644 index 0000000..829eedb --- /dev/null +++ b/tasks_gen/train/G1929/faulty/m3_i_star_night.ddls.asddls @@ -0,0 +1,18 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Stargazing nights of the observatory' +define view entity {{P}}I_STAR_NIGHT + as select from {{p}}night as night + inner join {{p}}dome as dome on dome.dome_id = night.dome_id + inner join {{p}}scope as scope on scope.scope_id <> night.scope_id +{ + key night.night_id as night_id, + night.dome_id as dome_id, + dome.dome_name as dome_name, + dome.city as dome_city, + night.scope_id as scope_id, + scope.scope_name as scope_name, + scope.aperture_mm as aperture_mm, + night.visitors as visitors, + night.night_date as night_date, + dome.capacity - night.visitors as free_seats +} diff --git a/tasks_gen/train/G1929/faulty/m4_i_star_night.ddls.asddls b/tasks_gen/train/G1929/faulty/m4_i_star_night.ddls.asddls new file mode 100644 index 0000000..f9521d2 --- /dev/null +++ b/tasks_gen/train/G1929/faulty/m4_i_star_night.ddls.asddls @@ -0,0 +1,18 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Stargazing nights of the observatory' +define view entity {{P}}I_STAR_NIGHT + as select from {{p}}night as night + inner join {{p}}dome as dome on dome.dome_id = night.dome_id + inner join {{p}}scope as scope on scope.scope_id = night.scope_id +{ + key night.night_id as night_id, + night.dome_id as dome_id, + dome.dome_name as dome_name, + dome.city as dome_city, + night.scope_id as scope_id, + scope.scope_name as scope_name, + scope.aperture_mm as aperture_mm, + night.visitors as visitors, + night.night_date as night_date, + dome.capacity + night.visitors as free_seats +} diff --git a/tasks_gen/train/G1929/generation.json b/tasks_gen/train/G1929/generation.json new file mode 100644 index 0000000..5abf7dc --- /dev/null +++ b/tasks_gen/train/G1929/generation.json @@ -0,0 +1,38 @@ +{ + "id": "G1929", + "pool": "train", + "object_type": "DDLS", + "category": "E", + "attempts": [ + { + "stage": "bundle", + "errors": [ + "Too close to task G0146 (similarity spec 0.56, rules 0.65, names 0.00). Choose a different business topic and different object names." + ], + "by_check": { + "extra": 1 + } + }, + { + "stage": "bundle", + "errors": [ + "Too close to task G0146 (similarity spec 0.57, rules 0.67, names 0.00). Choose a different business topic and different object names.", + "Too close to task G0147 (similarity spec 0.51, rules 0.62, names 0.00). Choose a different business topic and different object names." + ], + "by_check": { + "extra": 2 + } + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 5, + "killed": 5, + "ok": true + } + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1929/hidden/t61_hidden.clas.abap b/tasks_gen/train/G1929/hidden/t61_hidden.clas.abap new file mode 100644 index 0000000..b9b9116 --- /dev/null +++ b/tasks_gen/train/G1929/hidden/t61_hidden.clas.abap @@ -0,0 +1,118 @@ +CLASS {{p}}t61_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 shows_dome_data FOR TESTING. + METHODS shows_scope_data FOR TESTING. + METHODS shows_ids_and_visitors FOR TESTING. + METHODS shows_night_date FOR TESTING. + METHODS free_seats_positive FOR TESTING. + METHODS free_seats_negative FOR TESTING. + METHODS hides_unknown_dome FOR TESTING. + METHODS hides_unknown_scope FOR TESTING. + METHODS counts_rows FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t61_hidden IMPLEMENTATION. + METHOD class_setup. + go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_STAR_NIGHT' ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + DATA lt_dome TYPE STANDARD TABLE OF {{p}}dome WITH EMPTY KEY. + DATA lt_scope TYPE STANDARD TABLE OF {{p}}scope WITH EMPTY KEY. + DATA lt_night TYPE STANDARD TABLE OF {{p}}night WITH EMPTY KEY. + go_env->clear_doubles( ). + lt_dome = VALUE #( ( dome_id = 'D1' dome_name = 'Main Dome' city = 'NORTH' capacity = 120 ) + ( dome_id = 'D2' dome_name = 'Side Dome' city = 'SOUTH' capacity = 60 ) ). + lt_scope = VALUE #( ( scope_id = 'S1' scope_name = 'Reflector' aperture_mm = 300 mount_kind = 'EQUATORIAL' ) + ( scope_id = 'S2' scope_name = 'Refractor' aperture_mm = 150 mount_kind = 'ALT_AZ' ) ). + lt_night = VALUE #( ( night_id = 'N1' dome_id = 'D1' scope_id = 'S1' visitors = 100 night_date = '20250601' ) + ( night_id = 'N2' dome_id = 'D2' scope_id = 'S2' visitors = 70 night_date = '20250602' ) + ( night_id = 'N3' dome_id = 'D9' scope_id = 'S1' visitors = 5 night_date = '20250603' ) + ( night_id = 'N4' dome_id = 'D1' scope_id = 'S9' visitors = 5 night_date = '20250604' ) ). + go_env->insert_test_data( lt_dome ). + go_env->insert_test_data( lt_scope ). + go_env->insert_test_data( lt_night ). + ENDMETHOD. + + METHOD shows_dome_data. + SELECT SINGLE dome_name, dome_city + FROM {{p}}i_star_night + WHERE night_id = 'N1' + INTO @DATA(ls_row). + cl_abap_unit_assert=>assert_equals( exp = 'Main Dome' act = ls_row-dome_name ). + cl_abap_unit_assert=>assert_equals( exp = 'NORTH' act = ls_row-dome_city ). + ENDMETHOD. + + METHOD shows_scope_data. + SELECT SINGLE scope_name, aperture_mm + FROM {{p}}i_star_night + WHERE night_id = 'N2' + INTO @DATA(ls_row). + cl_abap_unit_assert=>assert_equals( exp = 'Refractor' act = ls_row-scope_name ). + cl_abap_unit_assert=>assert_equals( exp = 150 act = ls_row-aperture_mm ). + ENDMETHOD. + + METHOD shows_ids_and_visitors. + SELECT SINGLE dome_id, scope_id, visitors + FROM {{p}}i_star_night + WHERE night_id = 'N2' + INTO @DATA(ls_row). + cl_abap_unit_assert=>assert_equals( exp = 'D2' act = ls_row-dome_id ). + cl_abap_unit_assert=>assert_equals( exp = 'S2' act = ls_row-scope_id ). + cl_abap_unit_assert=>assert_equals( exp = 70 act = ls_row-visitors ). + ENDMETHOD. + + METHOD shows_night_date. + DATA lv_expected TYPE dats VALUE '20250601'. + SELECT SINGLE night_date + FROM {{p}}i_star_night + WHERE night_id = 'N1' + INTO @DATA(lv_date). + cl_abap_unit_assert=>assert_equals( exp = lv_expected act = lv_date ). + ENDMETHOD. + + METHOD free_seats_positive. + SELECT SINGLE free_seats + FROM {{p}}i_star_night + WHERE night_id = 'N1' + INTO @DATA(lv_free). + cl_abap_unit_assert=>assert_equals( exp = 20 act = lv_free ). + ENDMETHOD. + + METHOD free_seats_negative. + SELECT SINGLE free_seats + FROM {{p}}i_star_night + WHERE night_id = 'N2' + INTO @DATA(lv_free). + cl_abap_unit_assert=>assert_equals( exp = -10 act = lv_free ). + ENDMETHOD. + + METHOD hides_unknown_dome. + SELECT COUNT(*) FROM {{p}}i_star_night + WHERE dome_id = 'D9' + INTO @DATA(lv_rows). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_rows ). + ENDMETHOD. + + METHOD hides_unknown_scope. + SELECT COUNT(*) FROM {{p}}i_star_night + WHERE scope_id = 'S9' + INTO @DATA(lv_rows). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_rows ). + ENDMETHOD. + + METHOD counts_rows. + SELECT COUNT(*) FROM {{p}}i_star_night INTO @DATA(lv_rows). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lv_rows ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1929/mutation.json b/tasks_gen/train/G1929/mutation.json new file mode 100644 index 0000000..44bddae --- /dev/null +++ b/tasks_gen/train/G1929/mutation.json @@ -0,0 +1,63 @@ +{ + "task": "G1929", + "mutants": [ + { + "object": "{{P}}I_STAR_NIGHT", + "mutant": "line 5: inner join -> left outer join (join)", + "status": "killed", + "hidden": "7/9", + "failed_tests": [ + "COUNTS_ROWS", + "HIDES_UNKNOWN_DOME" + ] + }, + { + "object": "{{P}}I_STAR_NIGHT", + "mutant": "line 5: = -> <> (eq)", + "status": "killed", + "hidden": "4/9", + "failed_tests": [ + "COUNTS_ROWS", + "FREE_SEATS_NEGATIVE", + "FREE_SEATS_POSITIVE", + "HIDES_UNKNOWN_DOME", + "SHOWS_DOME_DATA" + ] + }, + { + "object": "{{P}}I_STAR_NIGHT", + "mutant": "line 6: inner join -> left outer join (join)", + "status": "killed", + "hidden": "7/9", + "failed_tests": [ + "COUNTS_ROWS", + "HIDES_UNKNOWN_SCOPE" + ] + }, + { + "object": "{{P}}I_STAR_NIGHT", + "mutant": "line 6: = -> <> (eq)", + "status": "killed", + "hidden": "6/9", + "failed_tests": [ + "COUNTS_ROWS", + "HIDES_UNKNOWN_SCOPE", + "SHOWS_SCOPE_DATA" + ] + }, + { + "object": "{{P}}I_STAR_NIGHT", + "mutant": "line 17: - -> + (arith)", + "status": "killed", + "hidden": "7/9", + "failed_tests": [ + "FREE_SEATS_NEGATIVE", + "FREE_SEATS_POSITIVE" + ] + } + ], + "valid": 5, + "killed": 5, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1929/reference/i_star_night.ddls.asddls b/tasks_gen/train/G1929/reference/i_star_night.ddls.asddls new file mode 100644 index 0000000..939d6ad --- /dev/null +++ b/tasks_gen/train/G1929/reference/i_star_night.ddls.asddls @@ -0,0 +1,18 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Stargazing nights of the observatory' +define view entity {{P}}I_STAR_NIGHT + as select from {{p}}night as night + inner join {{p}}dome as dome on dome.dome_id = night.dome_id + inner join {{p}}scope as scope on scope.scope_id = night.scope_id +{ + key night.night_id as night_id, + night.dome_id as dome_id, + dome.dome_name as dome_name, + dome.city as dome_city, + night.scope_id as scope_id, + scope.scope_name as scope_name, + scope.aperture_mm as aperture_mm, + night.visitors as visitors, + night.night_date as night_date, + dome.capacity - night.visitors as free_seats +} diff --git a/tasks_gen/train/G1929/reference/t61_test.clas.abap b/tasks_gen/train/G1929/reference/t61_test.clas.abap new file mode 100644 index 0000000..1961db3 --- /dev/null +++ b/tasks_gen/train/G1929/reference/t61_test.clas.abap @@ -0,0 +1,51 @@ +CLASS {{p}}t61_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 reads_master_data_once FOR TESTING. + METHODS drops_night_without_dome FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t61_test IMPLEMENTATION. + METHOD class_setup. + go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_STAR_NIGHT' ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + DATA lt_dome TYPE STANDARD TABLE OF {{p}}dome WITH EMPTY KEY. + DATA lt_scope TYPE STANDARD TABLE OF {{p}}scope WITH EMPTY KEY. + DATA lt_night TYPE STANDARD TABLE OF {{p}}night WITH EMPTY KEY. + go_env->clear_doubles( ). + lt_dome = VALUE #( ( dome_id = 'D1' dome_name = 'Main Dome' city = 'NORTH' capacity = 90 ) ). + lt_scope = VALUE #( ( scope_id = 'S1' scope_name = 'Reflector' aperture_mm = 300 mount_kind = 'EQUATORIAL' ) ). + lt_night = VALUE #( ( night_id = 'A1' dome_id = 'D1' scope_id = 'S1' visitors = 60 night_date = '20250701' ) + ( night_id = 'A2' dome_id = 'DX' scope_id = 'S1' visitors = 10 night_date = '20250702' ) ). + go_env->insert_test_data( lt_dome ). + go_env->insert_test_data( lt_scope ). + go_env->insert_test_data( lt_night ). + ENDMETHOD. + + METHOD reads_master_data_once. + SELECT SINGLE dome_name, dome_city, scope_name, free_seats + FROM {{p}}i_star_night + WHERE night_id = 'A1' + INTO @DATA(ls_row). + cl_abap_unit_assert=>assert_equals( exp = 'Main Dome' act = ls_row-dome_name ). + cl_abap_unit_assert=>assert_equals( exp = 'NORTH' act = ls_row-dome_city ). + cl_abap_unit_assert=>assert_equals( exp = 'Reflector' act = ls_row-scope_name ). + cl_abap_unit_assert=>assert_equals( exp = 30 act = ls_row-free_seats ). + ENDMETHOD. + + METHOD drops_night_without_dome. + SELECT COUNT(*) FROM {{p}}i_star_night INTO @DATA(lv_rows). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lv_rows ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1929/seed/dome.tabl.asabap b/tasks_gen/train/G1929/seed/dome.tabl.asabap new file mode 100644 index 0000000..508dc71 --- /dev/null +++ b/tasks_gen/train/G1929/seed/dome.tabl.asabap @@ -0,0 +1,12 @@ +@EndUserText.label : 'Dome of the observatory' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}dome { + key client : abap.clnt not null; + key dome_id : abap.char(4) not null; + dome_name : abap.char(30); + city : abap.char(20); + capacity : abap.int4; +} diff --git a/tasks_gen/train/G1929/seed/i_star_night.ddls.asddls b/tasks_gen/train/G1929/seed/i_star_night.ddls.asddls new file mode 100644 index 0000000..28c8a30 --- /dev/null +++ b/tasks_gen/train/G1929/seed/i_star_night.ddls.asddls @@ -0,0 +1,20 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Stargazing nights of the observatory (legacy)' +define view entity {{P}}I_STAR_NIGHT + as select from {{p}}night as night + inner join {{p}}dome as dome_a on dome_a.dome_id = night.dome_id + inner join {{p}}dome as dome_b on dome_b.dome_id = night.dome_id + inner join {{p}}scope as scope_a on scope_a.scope_id = night.scope_id + inner join {{p}}scope as scope_b on scope_b.scope_id = night.scope_id +{ + key night.night_id as night_id, + night.dome_id as dome_id, + dome_a.dome_name as dome_name, + dome_b.city as dome_city, + night.scope_id as scope_id, + scope_a.scope_name as scope_name, + scope_b.aperture_mm as aperture_mm, + night.visitors as visitors, + night.night_date as night_date, + dome_b.capacity - night.visitors as free_seats +} diff --git a/tasks_gen/train/G1929/seed/night.tabl.asabap b/tasks_gen/train/G1929/seed/night.tabl.asabap new file mode 100644 index 0000000..40c488d --- /dev/null +++ b/tasks_gen/train/G1929/seed/night.tabl.asabap @@ -0,0 +1,13 @@ +@EndUserText.label : 'Stargazing night' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}night { + key client : abap.clnt not null; + key night_id : abap.char(10) not null; + dome_id : abap.char(4); + scope_id : abap.char(4); + visitors : abap.int4; + night_date : abap.dats; +} diff --git a/tasks_gen/train/G1929/seed/scope.tabl.asabap b/tasks_gen/train/G1929/seed/scope.tabl.asabap new file mode 100644 index 0000000..65d2674 --- /dev/null +++ b/tasks_gen/train/G1929/seed/scope.tabl.asabap @@ -0,0 +1,12 @@ +@EndUserText.label : 'Telescope of the observatory' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}scope { + key client : abap.clnt not null; + key scope_id : abap.char(4) not null; + scope_name : abap.char(30); + aperture_mm : abap.int4; + mount_kind : abap.char(10); +} diff --git a/tasks_gen/train/G1929/spec.md b/tasks_gen/train/G1929/spec.md new file mode 100644 index 0000000..ffa560e --- /dev/null +++ b/tasks_gen/train/G1929/spec.md @@ -0,0 +1,54 @@ +# 1. Goal +The view entity {{P}}I_STAR_NIGHT in package $TMP lists the stargazing nights of +a city observatory. Today the view reads the same master table twice. Remove +that repetition. The view keeps its name, its key element and all its element +names. Its result must not change. + +# 2. Open questions +None. + +# 3. Context +A city observatory opens its domes on clear nights. Each stargazing night takes +place in one dome and uses one telescope. + +Tables in package $TMP: + +- {{P}}NIGHT - the stargazing nights. Key NIGHT_ID (CHAR 10). Further fields: + DOME_ID (CHAR 4), SCOPE_ID (CHAR 4), VISITORS (INT4), NIGHT_DATE (DATS). +- {{P}}DOME - the domes of the observatory. Key DOME_ID (CHAR 4). Further + fields: DOME_NAME (CHAR 30), CITY (CHAR 20), CAPACITY (INT4). +- {{P}}SCOPE - the telescopes. Key SCOPE_ID (CHAR 4). Further fields: + SCOPE_NAME (CHAR 30), APERTURE_MM (INT4), MOUNT_KIND (CHAR 10). + +The view entity {{P}}I_STAR_NIGHT is active and reads the three tables. A report +and an OData service consume it. Take the current source of the view as the +definition of its result. Read the source before you touch it. + +# 4. Contract +- The view entity {{P}}I_STAR_NIGHT stays in package $TMP. +- Key element: NIGHT_ID. +- Element names, unchanged: NIGHT_ID, DOME_ID, DOME_NAME, DOME_CITY, SCOPE_ID, + SCOPE_NAME, APERTURE_MM, VISITORS, NIGHT_DATE, FREE_SEATS. +- Authorization check: #NOT_REQUIRED. + +# 5. Business rules +1. The row set of the view does not change. A night appears exactly as often as + it appears today, and no night appears that does not appear today. +2. Every element keeps its value. NIGHT_ID, DOME_ID, SCOPE_ID, VISITORS and + NIGHT_DATE come from the night. DOME_NAME and DOME_CITY describe the dome of + the night. SCOPE_NAME and APERTURE_MM describe the telescope of the night. + FREE_SEATS is the capacity of the dome minus the visitors of the night. It + may be negative. +3. The element types and the meaning of the key stay as they are. + +# 6. Constraints +- Release target: SAP_BASIS 816 (ABAP Platform 2025). +- Quality goal: no master table is read more than once by the view. A master + table that is needed twice must still be read only once. +- Coding standards: Clean ABAP. The view must activate without a syntax error. +- Out of scope: {{P}}NIGHT, {{P}}DOME, {{P}}SCOPE. + +# 7. Acceptance +- {{P}}I_STAR_NIGHT is active and syntax-clean. +- All hidden tests pass. +- Add ABAP Unit tests with CL_CDS_TEST_ENVIRONMENT in a global test class. diff --git a/tasks_gen/train/G1929/task.json b/tasks_gen/train/G1929/task.json new file mode 100644 index 0000000..8994668 --- /dev/null +++ b/tasks_gen/train/G1929/task.json @@ -0,0 +1,89 @@ +{ + "id": "G1929", + "category": "E", + "object_type": "DDLS", + "difficulty": 3, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [ + { + "type": "TABL", + "name": "{{P}}NIGHT", + "file": "seed/night.tabl.asabap", + "description": "Stargazing nights of the observatory" + }, + { + "type": "TABL", + "name": "{{P}}DOME", + "file": "seed/dome.tabl.asabap", + "description": "Domes of the observatory" + }, + { + "type": "TABL", + "name": "{{P}}SCOPE", + "file": "seed/scope.tabl.asabap", + "description": "Telescopes of the observatory" + }, + { + "type": "DDLS", + "name": "{{P}}I_STAR_NIGHT", + "file": "seed/i_star_night.ddls.asddls", + "description": "Legacy view entity that reads the same master table twice" + } + ], + "contract": [ + { + "type": "DDLS", + "name": "{{P}}I_STAR_NIGHT", + "fields": [ + "NIGHT_ID", + "DOME_ID", + "DOME_NAME", + "DOME_CITY", + "SCOPE_ID", + "SCOPE_NAME", + "APERTURE_MM", + "VISITORS", + "NIGHT_DATE", + "FREE_SEATS" + ] + } + ], + "out_of_scope": [ + "{{P}}NIGHT", + "{{P}}DOME", + "{{P}}SCOPE" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T61_HIDDEN", + "file": "hidden/t61_hidden.clas.abap", + "description": "T61 hidden tests for the refactored view entity" + } + ], + "reference": [ + { + "type": "DDLS", + "name": "{{P}}I_STAR_NIGHT", + "file": "reference/i_star_night.ddls.asddls", + "description": "Refactored view entity, every master table read once" + }, + { + "type": "CLAS", + "name": "{{P}}T61_TEST", + "file": "reference/t61_test.clas.abap", + "description": "T61 own tests with CL_CDS_TEST_ENVIRONMENT" + } + ], + "craft_checks": [ + "The view entity {{P}}I_STAR_NIGHT reads {{P}}DOME only once", + "The view entity {{P}}I_STAR_NIGHT reads {{P}}SCOPE only once", + "The view entity {{P}}I_STAR_NIGHT keeps the key element NIGHT_ID and all ten element names", + "The view entity {{P}}I_STAR_NIGHT drops a night whose dome or telescope does not exist" + ] +} \ No newline at end of file diff --git a/tasks_gen/train/G1930/faulty/m0_i_visit_fee.ddls.asddls b/tasks_gen/train/G1930/faulty/m0_i_visit_fee.ddls.asddls new file mode 100644 index 0000000..df1cad7 --- /dev/null +++ b/tasks_gen/train/G1930/faulty/m0_i_visit_fee.ddls.asddls @@ -0,0 +1,14 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Table fee of a visit' +define view entity {{P}}I_VISIT_FEE + with parameters p_rate : abap.dec( 5, 2 ) + as select from {{p}}visit as v + left outer join {{p}}area as a on a.area_id = v.area_id +{ + key v.visit_id as visit_id, + v.guest as guest, + a.area_name as area_name, + v.num_hours as num_hours, + v.num_hours * $parameters.p_rate as fee +} +where v.visit_state = 'O' diff --git a/tasks_gen/train/G1930/faulty/m1_i_visit_fee.ddls.asddls b/tasks_gen/train/G1930/faulty/m1_i_visit_fee.ddls.asddls new file mode 100644 index 0000000..9d2590e --- /dev/null +++ b/tasks_gen/train/G1930/faulty/m1_i_visit_fee.ddls.asddls @@ -0,0 +1,14 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Table fee of a visit' +define view entity {{P}}I_VISIT_FEE + with parameters p_rate : abap.dec( 5, 2 ) + as select from {{p}}visit as v + inner join {{p}}area as a on a.area_id <> v.area_id +{ + key v.visit_id as visit_id, + v.guest as guest, + a.area_name as area_name, + v.num_hours as num_hours, + v.num_hours * $parameters.p_rate as fee +} +where v.visit_state = 'O' diff --git a/tasks_gen/train/G1930/faulty/m2_i_visit_fee.ddls.asddls b/tasks_gen/train/G1930/faulty/m2_i_visit_fee.ddls.asddls new file mode 100644 index 0000000..7de487e --- /dev/null +++ b/tasks_gen/train/G1930/faulty/m2_i_visit_fee.ddls.asddls @@ -0,0 +1,14 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Table fee of a visit' +define view entity {{P}}I_VISIT_FEE + with parameters p_rate : abap.dec( 5, 2 ) + as select from {{p}}visit as v + inner join {{p}}area as a on a.area_id = v.area_id +{ + key v.visit_id as visit_id, + v.guest as guest, + a.area_name as area_name, + v.num_hours as num_hours, + v.num_hours * $parameters.p_rate as fee +} +where v.visit_state <> 'O' diff --git a/tasks_gen/train/G1930/faulty/m3_i_visit_fee.ddls.asddls b/tasks_gen/train/G1930/faulty/m3_i_visit_fee.ddls.asddls new file mode 100644 index 0000000..b77be66 --- /dev/null +++ b/tasks_gen/train/G1930/faulty/m3_i_visit_fee.ddls.asddls @@ -0,0 +1,14 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Table fee of a visit' +define view entity {{P}}I_VISIT_FEE + with parameters p_rate : abap.dec( 5, 2 ) + as select from {{p}}visit as v + inner join {{p}}area as a on a.area_id = v.area_id +{ + key v.visit_id as visit_id, + v.guest as guest, + a.area_name as area_name, + v.num_hours as num_hours, + v.num_hours * $parameters.p_rate as fee +} +where v.visit_state = 'Z' diff --git a/tasks_gen/train/G1930/generation.json b/tasks_gen/train/G1930/generation.json new file mode 100644 index 0000000..67d3fab --- /dev/null +++ b/tasks_gen/train/G1930/generation.json @@ -0,0 +1,24 @@ +{ + "id": "G1930", + "pool": "train", + "object_type": "DDLS", + "category": "E", + "attempts": [ + { + "stage": "validate", + "oracle": null, + "null": null + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 4, + "killed": 4, + "ok": true + } + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1930/hidden/visit_hidden.clas.abap b/tasks_gen/train/G1930/hidden/visit_hidden.clas.abap new file mode 100644 index 0000000..b5abb76 --- /dev/null +++ b/tasks_gen/train/G1930/hidden/visit_hidden.clas.abap @@ -0,0 +1,102 @@ +CLASS {{p}}visit_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 fee_of_one_visit FOR TESTING. + METHODS fee_of_two_hours FOR TESTING. + METHODS fee_of_zero_hours FOR TESTING. + METHODS cancelled_visit_hidden FOR TESTING. + METHODS orphan_visit_hidden FOR TESTING. + METHODS open_visits_shown FOR TESTING. + METHODS area_name_shown FOR TESTING. + METHODS guest_shown FOR TESTING. + METHODS num_hours_shown FOR TESTING. +ENDCLASS. + + +CLASS {{p}}visit_hidden IMPLEMENTATION. + METHOD class_setup. + go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_VISIT_FEE' ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + DATA lt_area TYPE STANDARD TABLE OF {{p}}area WITH EMPTY KEY. + DATA lt_visit TYPE STANDARD TABLE OF {{p}}visit WITH EMPTY KEY. + go_env->clear_doubles( ). + lt_area = VALUE #( ( area_id = 'A1' area_name = 'Window' seats = 4 ) + ( area_id = 'A2' area_name = 'Corner' seats = 2 ) ). + lt_visit = VALUE #( ( visit_id = 'V1' area_id = 'A1' guest = 'ANNA' num_hours = 3 visit_state = 'O' ) + ( visit_id = 'V2' area_id = 'A2' guest = 'BEN' num_hours = 2 visit_state = 'O' ) + ( visit_id = 'V3' area_id = 'A1' guest = 'CARA' num_hours = 5 visit_state = 'C' ) + ( visit_id = 'V4' area_id = 'A2' guest = 'DAN' num_hours = 0 visit_state = 'O' ) + ( visit_id = 'V5' area_id = 'A9' guest = 'EVE' num_hours = 4 visit_state = 'O' ) ). + go_env->insert_test_data( lt_area ). + go_env->insert_test_data( lt_visit ). + ENDMETHOD. + + METHOD fee_of_one_visit. + SELECT SINGLE fee FROM {{p}}i_visit_fee( p_rate = '7.50' ) + WHERE visit_id = 'V1' INTO @DATA(lv_fee). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '22.50' ) + act = CONV decfloat34( lv_fee ) ). + ENDMETHOD. + + METHOD fee_of_two_hours. + SELECT SINGLE fee FROM {{p}}i_visit_fee( p_rate = '7.50' ) + WHERE visit_id = 'V2' INTO @DATA(lv_fee). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '15.00' ) + act = CONV decfloat34( lv_fee ) ). + ENDMETHOD. + + METHOD fee_of_zero_hours. + SELECT COUNT(*) FROM {{p}}i_visit_fee( p_rate = '7.50' ) + WHERE visit_id = 'V4' INTO @DATA(lv_rows). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lv_rows ). + SELECT SINGLE fee FROM {{p}}i_visit_fee( p_rate = '7.50' ) + WHERE visit_id = 'V4' INTO @DATA(lv_fee). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '0.00' ) + act = CONV decfloat34( lv_fee ) ). + ENDMETHOD. + + METHOD cancelled_visit_hidden. + SELECT COUNT(*) FROM {{p}}i_visit_fee( p_rate = '7.50' ) + WHERE visit_id = 'V3' INTO @DATA(lv_rows). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_rows ). + ENDMETHOD. + + METHOD orphan_visit_hidden. + SELECT COUNT(*) FROM {{p}}i_visit_fee( p_rate = '7.50' ) + WHERE visit_id = 'V5' INTO @DATA(lv_rows). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_rows ). + ENDMETHOD. + + METHOD open_visits_shown. + SELECT COUNT(*) FROM {{p}}i_visit_fee( p_rate = '7.50' ) INTO @DATA(lv_rows). + cl_abap_unit_assert=>assert_equals( exp = 3 act = lv_rows ). + ENDMETHOD. + + METHOD area_name_shown. + SELECT SINGLE area_name FROM {{p}}i_visit_fee( p_rate = '7.50' ) + WHERE visit_id = 'V1' INTO @DATA(lv_name). + cl_abap_unit_assert=>assert_equals( exp = 'Window' act = lv_name ). + ENDMETHOD. + + METHOD guest_shown. + SELECT SINGLE guest FROM {{p}}i_visit_fee( p_rate = '7.50' ) + WHERE visit_id = 'V2' INTO @DATA(lv_guest). + cl_abap_unit_assert=>assert_equals( exp = 'BEN' act = lv_guest ). + ENDMETHOD. + + METHOD num_hours_shown. + SELECT SINGLE num_hours FROM {{p}}i_visit_fee( p_rate = '7.50' ) + WHERE visit_id = 'V1' INTO @DATA(lv_hours). + cl_abap_unit_assert=>assert_equals( exp = 3 act = lv_hours ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1930/mutation.json b/tasks_gen/train/G1930/mutation.json new file mode 100644 index 0000000..a6f72e5 --- /dev/null +++ b/tasks_gen/train/G1930/mutation.json @@ -0,0 +1,61 @@ +{ + "task": "G1930", + "mutants": [ + { + "object": "{{P}}I_VISIT_FEE", + "mutant": "line 6: inner join -> left outer join (join)", + "status": "killed", + "hidden": "7/9", + "failed_tests": [ + "OPEN_VISITS_SHOWN", + "ORPHAN_VISIT_HIDDEN" + ] + }, + { + "object": "{{P}}I_VISIT_FEE", + "mutant": "line 6: = -> <> (eq)", + "status": "killed", + "hidden": "6/9", + "failed_tests": [ + "AREA_NAME_SHOWN", + "OPEN_VISITS_SHOWN", + "ORPHAN_VISIT_HIDDEN" + ] + }, + { + "object": "{{P}}I_VISIT_FEE", + "mutant": "line 14: = -> <> (eq)", + "status": "killed", + "hidden": "1/9", + "failed_tests": [ + "AREA_NAME_SHOWN", + "CANCELLED_VISIT_HIDDEN", + "FEE_OF_ONE_VISIT", + "FEE_OF_TWO_HOURS", + "FEE_OF_ZERO_HOURS", + "GUEST_SHOWN", + "NUM_HOURS_SHOWN", + "OPEN_VISITS_SHOWN" + ] + }, + { + "object": "{{P}}I_VISIT_FEE", + "mutant": "line 14: 'O' -> 'Z' (lit)", + "status": "killed", + "hidden": "2/9", + "failed_tests": [ + "AREA_NAME_SHOWN", + "FEE_OF_ONE_VISIT", + "FEE_OF_TWO_HOURS", + "FEE_OF_ZERO_HOURS", + "GUEST_SHOWN", + "NUM_HOURS_SHOWN", + "OPEN_VISITS_SHOWN" + ] + } + ], + "valid": 4, + "killed": 4, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1930/reference/i_visit_fee.ddls.asddls b/tasks_gen/train/G1930/reference/i_visit_fee.ddls.asddls new file mode 100644 index 0000000..35c91da --- /dev/null +++ b/tasks_gen/train/G1930/reference/i_visit_fee.ddls.asddls @@ -0,0 +1,14 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Table fee of a visit' +define view entity {{P}}I_VISIT_FEE + with parameters p_rate : abap.dec( 5, 2 ) + as select from {{p}}visit as v + inner join {{p}}area as a on a.area_id = v.area_id +{ + key v.visit_id as visit_id, + v.guest as guest, + a.area_name as area_name, + v.num_hours as num_hours, + v.num_hours * $parameters.p_rate as fee +} +where v.visit_state = 'O' diff --git a/tasks_gen/train/G1930/reference/visit_test.clas.abap b/tasks_gen/train/G1930/reference/visit_test.clas.abap new file mode 100644 index 0000000..7697621 --- /dev/null +++ b/tasks_gen/train/G1930/reference/visit_test.clas.abap @@ -0,0 +1,46 @@ +CLASS {{p}}visit_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 fee_of_one_visit FOR TESTING. + METHODS fee_for_another_rate FOR TESTING. +ENDCLASS. + + +CLASS {{p}}visit_test IMPLEMENTATION. + METHOD class_setup. + go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_VISIT_FEE' ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + DATA lt_area TYPE STANDARD TABLE OF {{p}}area WITH EMPTY KEY. + DATA lt_visit TYPE STANDARD TABLE OF {{p}}visit WITH EMPTY KEY. + go_env->clear_doubles( ). + lt_area = VALUE #( ( area_id = 'A1' area_name = 'Window' seats = 4 ) ). + lt_visit = VALUE #( ( visit_id = 'V1' area_id = 'A1' guest = 'ANNA' + num_hours = 3 visit_state = 'O' ) ). + go_env->insert_test_data( lt_area ). + go_env->insert_test_data( lt_visit ). + ENDMETHOD. + + METHOD fee_of_one_visit. + SELECT SINGLE fee FROM {{p}}i_visit_fee( p_rate = '7.50' ) + WHERE visit_id = 'V1' INTO @DATA(lv_fee). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '22.50' ) + act = CONV decfloat34( lv_fee ) ). + ENDMETHOD. + + METHOD fee_for_another_rate. + SELECT SINGLE fee FROM {{p}}i_visit_fee( p_rate = '10.00' ) + WHERE visit_id = 'V1' INTO @DATA(lv_fee). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '30.00' ) + act = CONV decfloat34( lv_fee ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1930/seed/area.tabl.asabap b/tasks_gen/train/G1930/seed/area.tabl.asabap new file mode 100644 index 0000000..89610a2 --- /dev/null +++ b/tasks_gen/train/G1930/seed/area.tabl.asabap @@ -0,0 +1,11 @@ +@EndUserText.label : 'Areas of the cafe' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}area { + key client : abap.clnt not null; + key area_id : abap.char(4) not null; + area_name : abap.char(20); + seats : abap.int4; +} diff --git a/tasks_gen/train/G1930/seed/i_visit_fee.ddls.asddls b/tasks_gen/train/G1930/seed/i_visit_fee.ddls.asddls new file mode 100644 index 0000000..c552568 --- /dev/null +++ b/tasks_gen/train/G1930/seed/i_visit_fee.ddls.asddls @@ -0,0 +1,13 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Table fee of a visit' +define view entity {{P}}I_VISIT_FEE + as select from {{p}}visit as v + inner join {{p}}area as a on a.area_id = v.area_id +{ + key v.visit_id as visit_id, + v.guest as guest, + a.area_name as area_name, + v.num_hours as num_hours, + v.num_hours * cast( 7.50 as abap.dec( 5, 2 ) ) as fee +} +where v.visit_state = 'O' diff --git a/tasks_gen/train/G1930/seed/visit.tabl.asabap b/tasks_gen/train/G1930/seed/visit.tabl.asabap new file mode 100644 index 0000000..616703a --- /dev/null +++ b/tasks_gen/train/G1930/seed/visit.tabl.asabap @@ -0,0 +1,13 @@ +@EndUserText.label : 'Visits of guests' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}visit { + key client : abap.clnt not null; + key visit_id : abap.char(10) not null; + area_id : abap.char(4); + guest : abap.char(10); + num_hours : abap.int4; + visit_state : abap.char(1); +} diff --git a/tasks_gen/train/G1930/spec.md b/tasks_gen/train/G1930/spec.md new file mode 100644 index 0000000..0068446 --- /dev/null +++ b/tasks_gen/train/G1930/spec.md @@ -0,0 +1,44 @@ +# 1. Goal +A board game cafe rents its areas to guests by the hour. The cafe needs the fee +of every open visit together with the area and the guest. A report and an OData +service read this data, so the fee must be calculated in the database, in a CDS +view. + +# 2. Open questions +None. + +# 3. Context +- Table {{P}}AREA (the areas of the cafe), package $TMP. Key: AREA_ID (CHAR 4). + Fields: AREA_NAME (CHAR 20), SEATS (INT4). +- Table {{P}}VISIT (one visit of a guest), package $TMP. Key: VISIT_ID (CHAR 10). + Fields: AREA_ID (CHAR 4), GUEST (CHAR 10), NUM_HOURS (INT4), + VISIT_STATE (CHAR 1). +- The CDS view entity {{P}}I_VISIT_FEE is in package $TMP. It is active and it is + already used by a report and by an OData service. The view is legacy code. + +# 4. Contract +- Refactor the CDS view entity {{P}}I_VISIT_FEE in package $TMP. The name of the + view stays the same. +- The view keeps these elements, with these names: VISIT_ID (key), GUEST, + AREA_NAME, NUM_HOURS, FEE. +- The view gets one parameter: P_RATE, type abap.dec( 5, 2 ). P_RATE is the + hourly rate of the cafe in euro. +- No authorization check (#NOT_REQUIRED). + +# 5. Business rules +The legacy view {{P}}I_VISIT_FEE contains the business rules. Read the legacy +view. The behavior of the view stays the same. The only change is the source of +the hourly rate: the view takes the hourly rate from the parameter P_RATE and +not from a literal value. + +# 6. Constraints +- Release target: SAP_BASIS 816 (ABAP Platform 2025). +- Coding standards: Clean ABAP. Keep the view short and clear. +- Out of scope: do not change {{P}}AREA and {{P}}VISIT. + +# 7. Acceptance +- The view is active and has no syntax error. +- The view does not contain the hourly rate as a literal value. The view takes + the hourly rate from the parameter P_RATE. +- The hidden tests pass. +- Write ABAP Unit tests with CL_CDS_TEST_ENVIRONMENT in a global test class. diff --git a/tasks_gen/train/G1930/task.json b/tasks_gen/train/G1930/task.json new file mode 100644 index 0000000..996c9c4 --- /dev/null +++ b/tasks_gen/train/G1930/task.json @@ -0,0 +1,72 @@ +{ + "id": "G1930", + "category": "E", + "object_type": "DDLS", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [ + { + "type": "TABL", + "name": "{{P}}AREA", + "file": "seed/area.tabl.asabap", + "description": "Areas of the cafe" + }, + { + "type": "TABL", + "name": "{{P}}VISIT", + "file": "seed/visit.tabl.asabap", + "description": "Visits of guests" + }, + { + "type": "DDLS", + "name": "{{P}}I_VISIT_FEE", + "file": "seed/i_visit_fee.ddls.asddls", + "description": "Legacy view: table fee of a visit" + } + ], + "contract": [ + { + "type": "DDLS", + "name": "{{P}}I_VISIT_FEE", + "fields": [ + "VISIT_ID", + "GUEST", + "AREA_NAME", + "NUM_HOURS", + "FEE" + ] + } + ], + "out_of_scope": [ + "{{P}}AREA", + "{{P}}VISIT" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}VISIT_HIDDEN", + "file": "hidden/visit_hidden.clas.abap", + "description": "Hidden tests for the visit fee view" + } + ], + "reference": [ + { + "type": "DDLS", + "name": "{{P}}I_VISIT_FEE", + "file": "reference/i_visit_fee.ddls.asddls", + "description": "Refactored view with the parameter P_RATE" + }, + { + "type": "CLAS", + "name": "{{P}}VISIT_TEST", + "file": "reference/visit_test.clas.abap", + "description": "Own tests with CL_CDS_TEST_ENVIRONMENT" + } + ], + "craft_checks": [] +} \ No newline at end of file diff --git a/tasks_gen/train/G1931/faulty/m0_i_rental_fee.ddls.asddls b/tasks_gen/train/G1931/faulty/m0_i_rental_fee.ddls.asddls new file mode 100644 index 0000000..8b66e28 --- /dev/null +++ b/tasks_gen/train/G1931/faulty/m0_i_rental_fee.ddls.asddls @@ -0,0 +1,22 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Rental fee' +define view entity {{P}}I_RENTAL_FEE + as select from {{p}}rental as rental +{ + key rental.rental_id as rental_id, + rental.car_group as car_group, + rental.rental_days as rental_days, + cast( + case rental.car_group + when 'C' then case rental.season when 'H' then 96 else 80 end + when 'B' then case rental.season when 'Z' then 60 else 50 end + else case rental.season when 'H' then 36 else 30 end + end + * case when rental.rental_days >= 7 then rental.rental_days - 1 else rental.rental_days end + + case rental.car_group + when 'C' then 25 + when 'B' then 15 + else 10 + end + as abap.dec( 15, 2 ) ) as fee +} diff --git a/tasks_gen/train/G1931/faulty/m1_i_rental_fee.ddls.asddls b/tasks_gen/train/G1931/faulty/m1_i_rental_fee.ddls.asddls new file mode 100644 index 0000000..1a4a9c4 --- /dev/null +++ b/tasks_gen/train/G1931/faulty/m1_i_rental_fee.ddls.asddls @@ -0,0 +1,22 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Rental fee' +define view entity {{P}}I_RENTAL_FEE + as select from {{p}}rental as rental +{ + key rental.rental_id as rental_id, + rental.car_group as car_group, + rental.rental_days as rental_days, + cast( + case rental.car_group + when 'C' then case rental.season when 'H' then 96 else 80 end + when 'B' then case rental.season when 'H' then 60 else 50 end + else case rental.season when 'H' then 36 else 30 end + end + * case when rental.rental_days >= 8 then rental.rental_days - 1 else rental.rental_days end + + case rental.car_group + when 'C' then 25 + when 'B' then 15 + else 10 + end + as abap.dec( 15, 2 ) ) as fee +} diff --git a/tasks_gen/train/G1931/faulty/m2_i_rental_fee.ddls.asddls b/tasks_gen/train/G1931/faulty/m2_i_rental_fee.ddls.asddls new file mode 100644 index 0000000..5e4035c --- /dev/null +++ b/tasks_gen/train/G1931/faulty/m2_i_rental_fee.ddls.asddls @@ -0,0 +1,22 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Rental fee' +define view entity {{P}}I_RENTAL_FEE + as select from {{p}}rental as rental +{ + key rental.rental_id as rental_id, + rental.car_group as car_group, + rental.rental_days as rental_days, + cast( + case rental.car_group + when 'C' then case rental.season when 'H' then 96 else 80 end + when 'B' then case rental.season when 'H' then 60 else 50 end + else case rental.season when 'H' then 36 else 30 end + end + * case when rental.rental_days >= 7 then rental.rental_days - 1 else rental.rental_days end + - case rental.car_group + when 'C' then 25 + when 'B' then 15 + else 10 + end + as abap.dec( 15, 2 ) ) as fee +} diff --git a/tasks_gen/train/G1931/faulty/m3_i_rental_fee.ddls.asddls b/tasks_gen/train/G1931/faulty/m3_i_rental_fee.ddls.asddls new file mode 100644 index 0000000..41ee8dc --- /dev/null +++ b/tasks_gen/train/G1931/faulty/m3_i_rental_fee.ddls.asddls @@ -0,0 +1,22 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Rental fee' +define view entity {{P}}I_RENTAL_FEE + as select from {{p}}rental as rental +{ + key rental.rental_id as rental_id, + rental.car_group as car_group, + rental.rental_days as rental_days, + cast( + case rental.car_group + when 'C' then case rental.season when 'H' then 96 else 80 end + when 'B' then case rental.season when 'H' then 60 else 50 end + else case rental.season when 'H' then 36 else 30 end + end + * case when rental.rental_days >= 7 then rental.rental_days - 1 else rental.rental_days end + + case rental.car_group + when 'Z' then 25 + when 'B' then 15 + else 10 + end + as abap.dec( 15, 2 ) ) as fee +} diff --git a/tasks_gen/train/G1931/faulty/m4_i_rental_fee.ddls.asddls b/tasks_gen/train/G1931/faulty/m4_i_rental_fee.ddls.asddls new file mode 100644 index 0000000..f35ddb2 --- /dev/null +++ b/tasks_gen/train/G1931/faulty/m4_i_rental_fee.ddls.asddls @@ -0,0 +1,22 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Rental fee' +define view entity {{P}}I_RENTAL_FEE + as select from {{p}}rental as rental +{ + key rental.rental_id as rental_id, + rental.car_group as car_group, + rental.rental_days as rental_days, + cast( + case rental.car_group + when 'C' then case rental.season when 'H' then 96 else 80 end + when 'B' then case rental.season when 'H' then 60 else 50 end + else case rental.season when 'H' then 36 else 30 end + end + * case when rental.rental_days >= 7 then rental.rental_days - 1 else rental.rental_days end + + case rental.car_group + when 'C' then 25 + when 'B' then 15 + else 11 + end + as abap.dec( 15, 2 ) ) as fee +} diff --git a/tasks_gen/train/G1931/generation.json b/tasks_gen/train/G1931/generation.json new file mode 100644 index 0000000..8f566f2 --- /dev/null +++ b/tasks_gen/train/G1931/generation.json @@ -0,0 +1,28 @@ +{ + "id": "G1931", + "pool": "train", + "object_type": "DDLS", + "category": "E", + "attempts": [ + { + "stage": "bundle", + "errors": [ + "seed/rental.tabl.asabap: field name days is a reserved word; choose another name" + ], + "by_check": { + "static": 1 + } + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 5, + "killed": 5, + "ok": true + } + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1931/hidden/e_rental_hidden.clas.abap b/tasks_gen/train/G1931/hidden/e_rental_hidden.clas.abap new file mode 100644 index 0000000..6ba70e0 --- /dev/null +++ b/tasks_gen/train/G1931/hidden/e_rental_hidden.clas.abap @@ -0,0 +1,131 @@ +CLASS {{p}}e_rental_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 short_low_season FOR TESTING. + METHODS short_high_season FOR TESTING. + METHODS free_day_at_seven FOR TESTING. + METHODS free_day_group_a FOR TESTING. + METHODS six_days_no_free FOR TESTING. + METHODS long_group_c FOR TESTING. + METHODS unknown_group FOR TESTING. + METHODS unknown_season FOR TESTING. + METHODS seven_days_group_b FOR TESTING. + METHODS columns_shown FOR TESTING. + METHODS all_rows_shown FOR TESTING. +ENDCLASS. + + +CLASS {{p}}e_rental_hidden IMPLEMENTATION. + METHOD class_setup. + go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_RENTAL_FEE' ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + DATA lt_rental TYPE STANDARD TABLE OF {{p}}rental WITH EMPTY KEY. + go_env->clear_doubles( ). + lt_rental = VALUE #( + ( rental_id = 'R01' car_group = 'A' season = 'L' rental_days = 3 ) + ( rental_id = 'R02' car_group = 'B' season = 'H' rental_days = 2 ) + ( rental_id = 'R03' car_group = 'C' season = 'L' rental_days = 7 ) + ( rental_id = 'R04' car_group = 'A' season = 'H' rental_days = 10 ) + ( rental_id = 'R05' car_group = 'B' season = 'L' rental_days = 6 ) + ( rental_id = 'R06' car_group = 'C' season = 'H' rental_days = 14 ) + ( rental_id = 'R07' car_group = 'X' season = 'L' rental_days = 1 ) + ( rental_id = 'R08' car_group = 'A' season = 'X' rental_days = 1 ) + ( rental_id = 'R09' car_group = 'B' season = 'H' rental_days = 7 ) ). + go_env->insert_test_data( lt_rental ). + ENDMETHOD. + + METHOD short_low_season. + SELECT SINGLE fee FROM {{p}}i_rental_fee + WHERE rental_id = 'R01' INTO @DATA(lv_fee). + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( '100.00' ) + act = CONV decfloat34( lv_fee ) ). + ENDMETHOD. + + METHOD short_high_season. + SELECT SINGLE fee FROM {{p}}i_rental_fee + WHERE rental_id = 'R02' INTO @DATA(lv_fee). + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( '135.00' ) + act = CONV decfloat34( lv_fee ) ). + ENDMETHOD. + + METHOD free_day_at_seven. + SELECT SINGLE fee FROM {{p}}i_rental_fee + WHERE rental_id = 'R03' INTO @DATA(lv_fee). + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( '505.00' ) + act = CONV decfloat34( lv_fee ) ). + ENDMETHOD. + + METHOD free_day_group_a. + SELECT SINGLE fee FROM {{p}}i_rental_fee + WHERE rental_id = 'R04' INTO @DATA(lv_fee). + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( '334.00' ) + act = CONV decfloat34( lv_fee ) ). + ENDMETHOD. + + METHOD six_days_no_free. + SELECT SINGLE fee FROM {{p}}i_rental_fee + WHERE rental_id = 'R05' INTO @DATA(lv_fee). + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( '315.00' ) + act = CONV decfloat34( lv_fee ) ). + ENDMETHOD. + + METHOD long_group_c. + SELECT SINGLE fee FROM {{p}}i_rental_fee + WHERE rental_id = 'R06' INTO @DATA(lv_fee). + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( '1273.00' ) + act = CONV decfloat34( lv_fee ) ). + ENDMETHOD. + + METHOD unknown_group. + SELECT SINGLE fee FROM {{p}}i_rental_fee + WHERE rental_id = 'R07' INTO @DATA(lv_fee). + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( '40.00' ) + act = CONV decfloat34( lv_fee ) ). + ENDMETHOD. + + METHOD unknown_season. + SELECT SINGLE fee FROM {{p}}i_rental_fee + WHERE rental_id = 'R08' INTO @DATA(lv_fee). + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( '40.00' ) + act = CONV decfloat34( lv_fee ) ). + ENDMETHOD. + + METHOD seven_days_group_b. + SELECT SINGLE fee FROM {{p}}i_rental_fee + WHERE rental_id = 'R09' INTO @DATA(lv_fee). + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( '375.00' ) + act = CONV decfloat34( lv_fee ) ). + ENDMETHOD. + + METHOD columns_shown. + SELECT SINGLE rental_id, car_group, rental_days FROM {{p}}i_rental_fee + WHERE rental_id = 'R01' INTO @DATA(ls_row). + cl_abap_unit_assert=>assert_equals( exp = 'R01' act = ls_row-rental_id ). + cl_abap_unit_assert=>assert_equals( exp = 'A' act = ls_row-car_group ). + cl_abap_unit_assert=>assert_equals( exp = 3 act = ls_row-rental_days ). + ENDMETHOD. + + METHOD all_rows_shown. + SELECT COUNT(*) FROM {{p}}i_rental_fee INTO @DATA(lv_rows). + cl_abap_unit_assert=>assert_equals( exp = 9 act = lv_rows ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1931/mutation.json b/tasks_gen/train/G1931/mutation.json new file mode 100644 index 0000000..eae3557 --- /dev/null +++ b/tasks_gen/train/G1931/mutation.json @@ -0,0 +1,68 @@ +{ + "task": "G1931", + "mutants": [ + { + "object": "{{P}}I_RENTAL_FEE", + "mutant": "line 12: 'H' -> 'Z' (lit)", + "status": "killed", + "hidden": "9/11", + "failed_tests": [ + "SEVEN_DAYS_GROUP_B", + "SHORT_HIGH_SEASON" + ] + }, + { + "object": "{{P}}I_RENTAL_FEE", + "mutant": "line 15: 7 -> 8 (const)", + "status": "killed", + "hidden": "9/11", + "failed_tests": [ + "FREE_DAY_AT_SEVEN", + "SEVEN_DAYS_GROUP_B" + ] + }, + { + "object": "{{P}}I_RENTAL_FEE", + "mutant": "line 16: + -> - (arith)", + "status": "killed", + "hidden": "2/11", + "failed_tests": [ + "FREE_DAY_AT_SEVEN", + "FREE_DAY_GROUP_A", + "LONG_GROUP_C", + "SEVEN_DAYS_GROUP_B", + "SHORT_HIGH_SEASON", + "SHORT_LOW_SEASON", + "SIX_DAYS_NO_FREE", + "UNKNOWN_GROUP", + "UNKNOWN_SEASON" + ] + }, + { + "object": "{{P}}I_RENTAL_FEE", + "mutant": "line 17: 'C' -> 'Z' (lit)", + "status": "killed", + "hidden": "9/11", + "failed_tests": [ + "FREE_DAY_AT_SEVEN", + "LONG_GROUP_C" + ] + }, + { + "object": "{{P}}I_RENTAL_FEE", + "mutant": "line 19: 10 -> 11 (const)", + "status": "killed", + "hidden": "7/11", + "failed_tests": [ + "FREE_DAY_GROUP_A", + "SHORT_LOW_SEASON", + "UNKNOWN_GROUP", + "UNKNOWN_SEASON" + ] + } + ], + "valid": 5, + "killed": 5, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1931/reference/e_rental_test.clas.abap b/tasks_gen/train/G1931/reference/e_rental_test.clas.abap new file mode 100644 index 0000000..b499a8a --- /dev/null +++ b/tasks_gen/train/G1931/reference/e_rental_test.clas.abap @@ -0,0 +1,56 @@ +CLASS {{p}}e_rental_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 short_rental_fee FOR TESTING. + METHODS long_rental_fee FOR TESTING. + METHODS default_group FOR TESTING. +ENDCLASS. + + +CLASS {{p}}e_rental_test IMPLEMENTATION. + METHOD class_setup. + go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_RENTAL_FEE' ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + DATA lt_rental TYPE STANDARD TABLE OF {{p}}rental WITH EMPTY KEY. + go_env->clear_doubles( ). + lt_rental = VALUE #( + ( rental_id = 'A1' car_group = 'A' season = 'L' rental_days = 2 ) + ( rental_id = 'B1' car_group = 'B' season = 'H' rental_days = 9 ) + ( rental_id = 'Z1' car_group = 'Z' season = 'H' rental_days = 1 ) ). + go_env->insert_test_data( lt_rental ). + ENDMETHOD. + + METHOD short_rental_fee. + SELECT SINGLE fee FROM {{p}}i_rental_fee + WHERE rental_id = 'A1' INTO @DATA(lv_fee). + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( '70.00' ) + act = CONV decfloat34( lv_fee ) ). + ENDMETHOD. + + METHOD long_rental_fee. + SELECT SINGLE fee FROM {{p}}i_rental_fee + WHERE rental_id = 'B1' INTO @DATA(lv_fee). + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( '495.00' ) + act = CONV decfloat34( lv_fee ) ). + ENDMETHOD. + + METHOD default_group. + SELECT SINGLE fee FROM {{p}}i_rental_fee + WHERE rental_id = 'Z1' INTO @DATA(lv_fee). + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( '46.00' ) + act = CONV decfloat34( lv_fee ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1931/reference/i_rental_fee.ddls.asddls b/tasks_gen/train/G1931/reference/i_rental_fee.ddls.asddls new file mode 100644 index 0000000..3acee13 --- /dev/null +++ b/tasks_gen/train/G1931/reference/i_rental_fee.ddls.asddls @@ -0,0 +1,22 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Rental fee' +define view entity {{P}}I_RENTAL_FEE + as select from {{p}}rental as rental +{ + key rental.rental_id as rental_id, + rental.car_group as car_group, + rental.rental_days as rental_days, + cast( + case rental.car_group + when 'C' then case rental.season when 'H' then 96 else 80 end + when 'B' then case rental.season when 'H' then 60 else 50 end + else case rental.season when 'H' then 36 else 30 end + end + * case when rental.rental_days >= 7 then rental.rental_days - 1 else rental.rental_days end + + case rental.car_group + when 'C' then 25 + when 'B' then 15 + else 10 + end + as abap.dec( 15, 2 ) ) as fee +} diff --git a/tasks_gen/train/G1931/seed/i_rental_fee.ddls.asddls b/tasks_gen/train/G1931/seed/i_rental_fee.ddls.asddls new file mode 100644 index 0000000..95a0215 --- /dev/null +++ b/tasks_gen/train/G1931/seed/i_rental_fee.ddls.asddls @@ -0,0 +1,29 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Rental fee' +define view entity {{P}}I_RENTAL_FEE + as select from {{p}}rental as rental +{ + key rental.rental_id as rental_id, + rental.car_group as car_group, + rental.rental_days as rental_days, + cast( + case when rental.rental_days >= 7 + then case when rental.car_group = 'C' then case when rental.season = 'H' then 96 else 80 end + when rental.car_group = 'B' then case when rental.season = 'H' then 60 else 50 end + else case when rental.season = 'H' then 36 else 30 end + end * ( rental.rental_days - 1 ) + + case when rental.car_group = 'C' then 25 + when rental.car_group = 'B' then 15 + else 10 + end + else case when rental.car_group = 'C' then case when rental.season = 'H' then 96 else 80 end + when rental.car_group = 'B' then case when rental.season = 'H' then 60 else 50 end + else case when rental.season = 'H' then 36 else 30 end + end * rental.rental_days + + case when rental.car_group = 'C' then 25 + when rental.car_group = 'B' then 15 + else 10 + end + end + as abap.dec( 15, 2 ) ) as fee +} diff --git a/tasks_gen/train/G1931/seed/rental.tabl.asabap b/tasks_gen/train/G1931/seed/rental.tabl.asabap new file mode 100644 index 0000000..7467c21 --- /dev/null +++ b/tasks_gen/train/G1931/seed/rental.tabl.asabap @@ -0,0 +1,12 @@ +@EndUserText.label : 'Rental' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}rental { + key client : abap.clnt not null; + key rental_id : abap.char(10) not null; + car_group : abap.char(1); + season : abap.char(1); + rental_days : abap.int4; +} diff --git a/tasks_gen/train/G1931/spec.md b/tasks_gen/train/G1931/spec.md new file mode 100644 index 0000000..35f9670 --- /dev/null +++ b/tasks_gen/train/G1931/spec.md @@ -0,0 +1,44 @@ +# 1. Goal +The CDS view entity {{P}}I_RENTAL_FEE in package $TMP shows the fee of each +rental of a car rental company. The view returns correct data, but its source +is long and hard to read. Refactor the view in place. The behavior must stay +the same. + +# 2. Open questions +None. + +# 3. Context +- Table {{P}}RENTAL, package $TMP. One row for each rental. + Key: RENTAL_ID (CHAR 10). + Fields: CAR_GROUP (CHAR 1), SEASON (CHAR 1), RENTAL_DAYS (INT4). +- The CDS view entity {{P}}I_RENTAL_FEE already exists in package $TMP. The + view is active. It reads the table {{P}}RENTAL. +- The source of the view is the only specification of the fee. Read the + source before you change it. + +# 4. Contract +- Refactor the CDS view entity {{P}}I_RENTAL_FEE in package $TMP. The name + stays the same. Do not create a second view. +- Elements, with these names and this order: RENTAL_ID (key), CAR_GROUP, + RENTAL_DAYS, FEE. +- The view keeps the annotation @AccessControl.authorizationCheck: + #NOT_REQUIRED. +- The view shows one row for each row of the table {{P}}RENTAL. + +# 5. Business rules +1. The behavior of the view stays the same. The FEE of each row must not + change. +2. Rule 1 holds for all values of CAR_GROUP, SEASON and RENTAL_DAYS. This + includes values that the source does not name. +3. The element names and the element order stay the same. + +# 6. Constraints +- Release target: 8.16. +- Coding standards: clean ABAP. The refactored source must be easy to read. + Remove the deep nesting and the repeated logic. Keep the expressions short. +- Out of scope: do not change the table {{P}}RENTAL. + +# 7. Acceptance +- The view {{P}}I_RENTAL_FEE 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. diff --git a/tasks_gen/train/G1931/task.json b/tasks_gen/train/G1931/task.json new file mode 100644 index 0000000..7e9a1d8 --- /dev/null +++ b/tasks_gen/train/G1931/task.json @@ -0,0 +1,64 @@ +{ + "id": "G1931", + "category": "E", + "object_type": "DDLS", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [ + { + "type": "TABL", + "name": "{{P}}RENTAL", + "file": "seed/rental.tabl.asabap", + "description": "Rental record of the car rental company" + }, + { + "type": "DDLS", + "name": "{{P}}I_RENTAL_FEE", + "file": "seed/i_rental_fee.ddls.asddls", + "description": "Legacy rental fee view with deeply nested CASE expressions" + } + ], + "contract": [ + { + "type": "DDLS", + "name": "{{P}}I_RENTAL_FEE", + "fields": [ + "RENTAL_ID", + "CAR_GROUP", + "RENTAL_DAYS", + "FEE" + ] + } + ], + "out_of_scope": [ + "{{P}}RENTAL" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}E_RENTAL_HIDDEN", + "file": "hidden/e_rental_hidden.clas.abap", + "description": "Hidden tests for the unchanged behavior of the rental fee view" + } + ], + "reference": [ + { + "type": "DDLS", + "name": "{{P}}I_RENTAL_FEE", + "file": "reference/i_rental_fee.ddls.asddls", + "description": "Clean rental fee view entity" + }, + { + "type": "CLAS", + "name": "{{P}}E_RENTAL_TEST", + "file": "reference/e_rental_test.clas.abap", + "description": "Own tests for the rental fee view" + } + ], + "craft_checks": [] +} \ No newline at end of file diff --git a/tasks_gen/train/G1932/faulty/m1_bowl.tabl.asabap b/tasks_gen/train/G1932/faulty/m1_bowl.tabl.asabap new file mode 100644 index 0000000..a10e683 --- /dev/null +++ b/tasks_gen/train/G1932/faulty/m1_bowl.tabl.asabap @@ -0,0 +1,17 @@ +@EndUserText.label : 'Bowling lane booking' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}bowl { + key client : abap.clnt not null; + key booking_id : abap.numc(10) not null; + key lane_no : abap.numc(2) not null; + play_hours : abap.dec(4,2); + game_mode : abap.char(1); + order_no : abap.char(10); + play_date : abap.dats; + player_count : abap.int4; + league_code : abap.char(4); + price_value : abap.dec(11,2); +} diff --git a/tasks_gen/train/G1932/faulty/m2_bowl.tabl.asabap b/tasks_gen/train/G1932/faulty/m2_bowl.tabl.asabap new file mode 100644 index 0000000..1de9a6f --- /dev/null +++ b/tasks_gen/train/G1932/faulty/m2_bowl.tabl.asabap @@ -0,0 +1,17 @@ +@EndUserText.label : 'Bowling lane booking' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}bowl { + key client : abap.clnt not null; + key booking_id : abap.char(9) not null; + key lane_no : abap.numc(2) not null; + play_hours : abap.dec(4,2); + game_mode : abap.char(1); + order_no : abap.char(10); + play_date : abap.dats; + player_count : abap.int4; + league_code : abap.char(4); + price_value : abap.dec(11,2); +} diff --git a/tasks_gen/train/G1932/faulty/m3_bowl.tabl.asabap b/tasks_gen/train/G1932/faulty/m3_bowl.tabl.asabap new file mode 100644 index 0000000..5e0191e --- /dev/null +++ b/tasks_gen/train/G1932/faulty/m3_bowl.tabl.asabap @@ -0,0 +1,17 @@ +@EndUserText.label : 'Bowling lane booking' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}bowl { + key client : abap.clnt not null; + key booking_id : abap.char(10) not null; + key lane_no : abap.numc(2) not null; + play_hours : abap.dec(4,2); + game_mode : abap.char(1); + order_no : abap.char(10); + play_date : abap.tims; + player_count : abap.int4; + league_code : abap.char(4); + price_value : abap.dec(11,2); +} diff --git a/tasks_gen/train/G1932/faulty/m4_bowl.tabl.asabap b/tasks_gen/train/G1932/faulty/m4_bowl.tabl.asabap new file mode 100644 index 0000000..5e67d49 --- /dev/null +++ b/tasks_gen/train/G1932/faulty/m4_bowl.tabl.asabap @@ -0,0 +1,17 @@ +@EndUserText.label : 'Bowling lane booking' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}bowl { + key client : abap.clnt not null; + key booking_id : abap.char(10) not null; + key lane_no : abap.numc(2) not null; + play_hours : abap.dec(4,2); + game_mode : abap.char(1); + order_no : abap.char(10); + play_date : abap.dats; + player_count : abap.int4; + league_code : abap.char(4); + price_value : abap.dec(11,3); +} diff --git a/tasks_gen/train/G1932/generation.json b/tasks_gen/train/G1932/generation.json new file mode 100644 index 0000000..d84cd20 --- /dev/null +++ b/tasks_gen/train/G1932/generation.json @@ -0,0 +1,42 @@ +{ + "id": "G1932", + "pool": "train", + "object_type": "TABL", + "category": "B", + "attempts": [ + { + "stage": "bundle", + "errors": [ + "Too close to task G1912 (similarity spec 0.76, rules 0.51, names 0.00). Choose a different business topic and different object names." + ], + "by_check": { + "extra": 1 + } + }, + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "bundle", + "errors": [ + "hidden/bowl_hidden.clas.abap line 20: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\"" + ], + "by_check": { + "abaplint": 1 + } + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 4, + "killed": 4, + "ok": true + } + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1932/hidden/bowl_hidden.clas.abap b/tasks_gen/train/G1932/hidden/bowl_hidden.clas.abap new file mode 100644 index 0000000..09f6be2 --- /dev/null +++ b/tasks_gen/train/G1932/hidden/bowl_hidden.clas.abap @@ -0,0 +1,195 @@ +CLASS {{p}}bowl_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 field_names FOR TESTING. + METHODS key_fields FOR TESTING. + METHODS char_fields FOR TESTING. + METHODS numc_fields FOR TESTING. + METHODS decimal_fields FOR TESTING. + METHODS date_and_count FOR TESTING. + METHODS no_reserved_names FOR TESTING. + METHODS insert_and_read FOR TESTING. + METHODS duplicate_booking FOR TESTING. + METHODS get_field + IMPORTING iv_name TYPE string + RETURNING VALUE(rs_field) TYPE dfies. +ENDCLASS. + + +CLASS {{p}}bowl_hidden IMPLEMENTATION. + + METHOD class_setup. + go_env = cl_osql_test_environment=>create( i_dependency_list = VALUE #( ( '{{P}}BOWL' ) ) ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + go_env->clear_doubles( ). + ENDMETHOD. + + METHOD get_field. + DATA lo_struct TYPE REF TO cl_abap_structdescr. + lo_struct ?= cl_abap_typedescr=>describe_by_name( '{{P}}BOWL' ). + 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 ). + ENDMETHOD. + + METHOD field_names. + DATA lo_struct TYPE REF TO cl_abap_structdescr. + lo_struct ?= cl_abap_typedescr=>describe_by_name( '{{P}}BOWL' ). + DATA(lt_fields) = lo_struct->get_ddic_field_list( ). + cl_abap_unit_assert=>assert_equals( exp = 10 act = lines( lt_fields ) ). + + DATA lt_names TYPE STANDARD TABLE OF string WITH EMPTY KEY. + lt_names = VALUE #( FOR ls_field IN lt_fields ( to_upper( ls_field-fieldname ) ) ). + + DATA lt_expected TYPE STANDARD TABLE OF string WITH EMPTY KEY. + lt_expected = VALUE #( ( `CLIENT` ) ( `BOOKING_ID` ) ( `LANE_NO` ) ( `PLAY_HOURS` ) + ( `GAME_MODE` ) ( `ORDER_NO` ) ( `PLAY_DATE` ) + ( `PLAYER_COUNT` ) ( `LEAGUE_CODE` ) ( `PRICE_VALUE` ) ). + LOOP AT lt_expected INTO DATA(lv_name). + READ TABLE lt_names TRANSPORTING NO FIELDS WITH KEY table_line = lv_name. + cl_abap_unit_assert=>assert_subrc( exp = 0 act = sy-subrc + msg = |Field { lv_name } is missing| ). + ENDLOOP. + ENDMETHOD. + + METHOD key_fields. + DATA lo_struct TYPE REF TO cl_abap_structdescr. + lo_struct ?= cl_abap_typedescr=>describe_by_name( '{{P}}BOWL' ). + DATA(lt_fields) = lo_struct->get_ddic_field_list( ). + LOOP AT lt_fields INTO DATA(ls_field). + DATA(lv_name) = to_upper( ls_field-fieldname ). + IF lv_name = 'CLIENT' OR lv_name = 'BOOKING_ID' OR lv_name = 'LANE_NO'. + cl_abap_unit_assert=>assert_equals( exp = 'X' act = ls_field-keyflag ). + ELSE. + cl_abap_unit_assert=>assert_equals( exp = ' ' act = ls_field-keyflag ). + ENDIF. + ENDLOOP. + ENDMETHOD. + + METHOD char_fields. + DATA(ls_field) = get_field( 'BOOKING_ID' ). + cl_abap_unit_assert=>assert_equals( exp = 'CHAR' act = ls_field-datatype ). + cl_abap_unit_assert=>assert_equals( exp = 10 act = ls_field-leng ). + + ls_field = get_field( 'ORDER_NO' ). + cl_abap_unit_assert=>assert_equals( exp = 'CHAR' act = ls_field-datatype ). + cl_abap_unit_assert=>assert_equals( exp = 10 act = ls_field-leng ). + + ls_field = get_field( 'LEAGUE_CODE' ). + cl_abap_unit_assert=>assert_equals( exp = 'CHAR' act = ls_field-datatype ). + cl_abap_unit_assert=>assert_equals( exp = 4 act = ls_field-leng ). + + ls_field = get_field( 'GAME_MODE' ). + cl_abap_unit_assert=>assert_equals( exp = 'CHAR' act = ls_field-datatype ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = ls_field-leng ). + ENDMETHOD. + + METHOD numc_fields. + DATA(ls_field) = get_field( 'LANE_NO' ). + cl_abap_unit_assert=>assert_equals( exp = 'NUMC' act = ls_field-datatype ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = ls_field-leng ). + ENDMETHOD. + + METHOD decimal_fields. + DATA(ls_field) = get_field( 'PLAY_HOURS' ). + cl_abap_unit_assert=>assert_equals( exp = 'DEC' act = ls_field-datatype ). + cl_abap_unit_assert=>assert_equals( exp = 4 act = ls_field-leng ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = ls_field-decimals ). + + ls_field = get_field( 'PRICE_VALUE' ). + cl_abap_unit_assert=>assert_equals( exp = 'DEC' act = ls_field-datatype ). + cl_abap_unit_assert=>assert_equals( exp = 11 act = ls_field-leng ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = ls_field-decimals ). + ENDMETHOD. + + METHOD date_and_count. + DATA(ls_field) = get_field( 'PLAY_DATE' ). + cl_abap_unit_assert=>assert_equals( exp = 'DATS' act = ls_field-datatype ). + cl_abap_unit_assert=>assert_equals( exp = 8 act = ls_field-leng ). + + ls_field = get_field( 'PLAYER_COUNT' ). + cl_abap_unit_assert=>assert_equals( exp = 'INT4' act = ls_field-datatype ). + ENDMETHOD. + + METHOD no_reserved_names. + DATA lo_struct TYPE REF TO cl_abap_structdescr. + lo_struct ?= cl_abap_typedescr=>describe_by_name( '{{P}}BOWL' ). + DATA(lt_fields) = lo_struct->get_ddic_field_list( ). + + DATA lt_reserved TYPE STANDARD TABLE OF string WITH EMPTY KEY. + lt_reserved = VALUE #( ( `HOURS` ) ( `MODE` ) ( `ORDER` ) ( `DATE` ) + ( `COUNT` ) ( `GROUP` ) ( `VALUE` ) ( `NUMBER` ) ). + + LOOP AT lt_fields INTO DATA(ls_field). + DATA(lv_name) = to_upper( ls_field-fieldname ). + READ TABLE lt_reserved TRANSPORTING NO FIELDS WITH KEY table_line = lv_name. + cl_abap_unit_assert=>assert_subrc( exp = 4 act = sy-subrc + msg = |Field name { lv_name } is a reserved word| ). + ENDLOOP. + ENDMETHOD. + + METHOD insert_and_read. + DATA lv_lane TYPE {{p}}bowl-lane_no. + DATA ls_booking TYPE {{p}}bowl. + ls_booking-client = sy-mandt. + ls_booking-booking_id = 'B-0001'. + ls_booking-lane_no = '01'. + ls_booking-play_hours = '12.50'. + ls_booking-game_mode = 'N'. + ls_booking-order_no = 'ORD-0001'. + ls_booking-play_date = '20240115'. + ls_booking-player_count = 4. + ls_booking-league_code = 'L-01'. + ls_booking-price_value = '1234.50'. + + INSERT {{p}}bowl FROM @ls_booking. + cl_abap_unit_assert=>assert_subrc( exp = 0 act = sy-subrc ). + + SELECT SINGLE * FROM {{p}}bowl + WHERE booking_id = 'B-0001' AND lane_no = '01' INTO @DATA(ls_read). + cl_abap_unit_assert=>assert_subrc( exp = 0 act = sy-subrc ). + + lv_lane = '01'. + cl_abap_unit_assert=>assert_equals( exp = lv_lane act = ls_read-lane_no ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '12.50' ) + act = CONV decfloat34( ls_read-play_hours ) ). + cl_abap_unit_assert=>assert_equals( exp = 'N' act = ls_read-game_mode ). + cl_abap_unit_assert=>assert_equals( exp = 'ORD-0001' act = ls_read-order_no ). + cl_abap_unit_assert=>assert_equals( exp = CONV d( '20240115' ) act = ls_read-play_date ). + cl_abap_unit_assert=>assert_equals( exp = 4 act = ls_read-player_count ). + cl_abap_unit_assert=>assert_equals( exp = 'L-01' act = ls_read-league_code ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '1234.50' ) + act = CONV decfloat34( ls_read-price_value ) ). + ENDMETHOD. + + METHOD duplicate_booking. + DATA ls_booking TYPE {{p}}bowl. + ls_booking-client = sy-mandt. + ls_booking-booking_id = 'B-0002'. + ls_booking-lane_no = '02'. + ls_booking-game_mode = 'L'. + + INSERT {{p}}bowl FROM @ls_booking. + cl_abap_unit_assert=>assert_subrc( exp = 0 act = sy-subrc ). + + ls_booking-game_mode = 'N'. + INSERT {{p}}bowl FROM @ls_booking. + cl_abap_unit_assert=>assert_equals( exp = 4 act = sy-subrc ). + + SELECT SINGLE game_mode FROM {{p}}bowl + WHERE booking_id = 'B-0002' AND lane_no = '02' INTO @DATA(lv_mode). + cl_abap_unit_assert=>assert_subrc( exp = 0 act = sy-subrc ). + cl_abap_unit_assert=>assert_equals( exp = 'L' act = lv_mode ). + ENDMETHOD. + +ENDCLASS. diff --git a/tasks_gen/train/G1932/mutation.json b/tasks_gen/train/G1932/mutation.json new file mode 100644 index 0000000..0f5b4c5 --- /dev/null +++ b/tasks_gen/train/G1932/mutation.json @@ -0,0 +1,55 @@ +{ + "task": "G1932", + "mutants": [ + { + "object": "{{P}}BOWL", + "mutant": "line 8: key booking_id : -> booking_id : (key)", + "status": "invalid", + "hidden": "0/0", + "failed_tests": [] + }, + { + "object": "{{P}}BOWL", + "mutant": "line 8: abap.char(10) -> abap.numc(10) (type)", + "status": "killed", + "hidden": "6/9", + "failed_tests": [ + "CHAR_FIELDS", + "DUPLICATE_BOOKING", + "INSERT_AND_READ" + ] + }, + { + "object": "{{P}}BOWL", + "mutant": "line 8: abap.char(10) -> abap.char(9) (length)", + "status": "killed", + "hidden": "8/9", + "failed_tests": [ + "CHAR_FIELDS" + ] + }, + { + "object": "{{P}}BOWL", + "mutant": "line 13: abap.dats -> abap.tims (type)", + "status": "killed", + "hidden": "7/9", + "failed_tests": [ + "DATE_AND_COUNT", + "INSERT_AND_READ" + ] + }, + { + "object": "{{P}}BOWL", + "mutant": "line 16: abap.dec(11,2) -> abap.dec(11,3) (decimals)", + "status": "killed", + "hidden": "8/9", + "failed_tests": [ + "DECIMAL_FIELDS" + ] + } + ], + "valid": 4, + "killed": 4, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1932/reference/bowl.tabl.asabap b/tasks_gen/train/G1932/reference/bowl.tabl.asabap new file mode 100644 index 0000000..77fb7b5 --- /dev/null +++ b/tasks_gen/train/G1932/reference/bowl.tabl.asabap @@ -0,0 +1,17 @@ +@EndUserText.label : 'Bowling lane booking' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}bowl { + key client : abap.clnt not null; + key booking_id : abap.char(10) not null; + key lane_no : abap.numc(2) not null; + play_hours : abap.dec(4,2); + game_mode : abap.char(1); + order_no : abap.char(10); + play_date : abap.dats; + player_count : abap.int4; + league_code : abap.char(4); + price_value : abap.dec(11,2); +} diff --git a/tasks_gen/train/G1932/reference/bowl_test.clas.abap b/tasks_gen/train/G1932/reference/bowl_test.clas.abap new file mode 100644 index 0000000..0853562 --- /dev/null +++ b/tasks_gen/train/G1932/reference/bowl_test.clas.abap @@ -0,0 +1,63 @@ +CLASS {{p}}bowl_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_a_booking FOR TESTING. + METHODS rejects_duplicate_booking FOR TESTING. +ENDCLASS. + + +CLASS {{p}}bowl_test IMPLEMENTATION. + + METHOD class_setup. + go_env = cl_osql_test_environment=>create( i_dependency_list = VALUE #( ( '{{P}}BOWL' ) ) ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + go_env->clear_doubles( ). + ENDMETHOD. + + METHOD stores_a_booking. + DATA lv_lane TYPE {{p}}bowl-lane_no. + DATA ls_booking TYPE {{p}}bowl. + ls_booking-client = sy-mandt. + ls_booking-booking_id = 'B-1000'. + ls_booking-lane_no = '03'. + ls_booking-play_hours = '2.50'. + ls_booking-player_count = 2. + + INSERT {{p}}bowl FROM @ls_booking. + cl_abap_unit_assert=>assert_subrc( exp = 0 act = sy-subrc ). + + SELECT SINGLE play_hours, player_count, lane_no FROM {{p}}bowl + WHERE booking_id = 'B-1000' AND lane_no = '03' INTO @DATA(ls_read). + cl_abap_unit_assert=>assert_subrc( exp = 0 act = sy-subrc ). + + lv_lane = '03'. + cl_abap_unit_assert=>assert_equals( exp = lv_lane act = ls_read-lane_no ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '2.50' ) + act = CONV decfloat34( ls_read-play_hours ) ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = ls_read-player_count ). + ENDMETHOD. + + METHOD rejects_duplicate_booking. + DATA ls_booking TYPE {{p}}bowl. + ls_booking-client = sy-mandt. + ls_booking-booking_id = 'B-1001'. + ls_booking-lane_no = '04'. + + INSERT {{p}}bowl FROM @ls_booking. + cl_abap_unit_assert=>assert_subrc( exp = 0 act = sy-subrc ). + + INSERT {{p}}bowl FROM @ls_booking. + cl_abap_unit_assert=>assert_equals( exp = 4 act = sy-subrc ). + ENDMETHOD. + +ENDCLASS. diff --git a/tasks_gen/train/G1932/spec.md b/tasks_gen/train/G1932/spec.md new file mode 100644 index 0000000..b7ca36c --- /dev/null +++ b/tasks_gen/train/G1932/spec.md @@ -0,0 +1,69 @@ +# 1. Goal +The bowling alley "Strike Lane" needs a database table for its lane bookings. +The booking desk will read the bookings with ABAP SQL and later with a CDS view. +In their daily work the staff use the words hours, mode, order, date, count, +group and value. These words are reserved words in ABAP SQL. The new table must +therefore use safe field names. + +# 2. Open questions +None. + +# 3. Context +The bowling alley has 12 lanes. A guest books one lane for a time slot. The +booking desk writes one row for each booking into the new table. The table is +the first object of the bowling alley in package $TMP. No other object exists. + +# 4. Contract +Create the transparent database table {{P}}BOWL in package $TMP. The table has +the following fields, in this order, with these names: + +- client: CLNT 3, key +- booking_id: CHAR 10, key +- lane_no: NUMC 2, key +- play_hours: DEC 4,2 +- game_mode: CHAR 1 +- order_no: CHAR 10 +- play_date: DATS +- player_count: INT4 +- league_code: CHAR 4 +- price_value: DEC 11,2 + +# 5. Business rules +1. The key of the table is the combination of client, booking_id and lane_no. + No other field is a key field. +2. play_hours is the booked time in hours. It has 4 characters and 2 decimals. +3. game_mode is a single character. 'N' means a normal game, 'L' means a league + game. +4. order_no is the number of the order that the guest paid at the counter. It + has 10 characters. +5. play_date is the day of the booking. +6. player_count is the number of players on the lane. It is a whole number. +7. league_code is the code of the league. It has 4 characters. For a normal + game the field is empty. +8. price_value is the value of the booking in the local currency. It has 11 + characters and 2 decimals. +9. No field name is a reserved word of ABAP SQL. The table must not have a + field with the name hours, mode, order, date, count, group or value. +10. The booking number is unique for one client and one lane. A second INSERT + with the same client, the same booking number and the same lane number does + not change the table and gives sy-subrc = 4. + +# 6. Constraints +- Release target: ABAP Platform 2025 (SAP_BASIS 816). Package $TMP. No + transport. +- Use only the built-in Dictionary types abap.clnt, abap.char, abap.numc, + abap.dats, abap.int4 and abap.dec. Do not use abap.curr or abap.quan. +- Write the table as a DDL source with the annotations @EndUserText.label, + @AbapCatalog.enhancement.category : #NOT_EXTENSIBLE, + @AbapCatalog.tableCategory : #TRANSPARENT, @AbapCatalog.deliveryClass : #A + and @AbapCatalog.dataMaintenance : #RESTRICTED. Declare the key fields as + not null. +- Do not create any other repository object than the table and your own test + class. +- Out of scope: a CDS view, a report, a function module and a class with + business logic. + +# 7. Acceptance +- The table {{P}}BOWL 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. diff --git a/tasks_gen/train/G1932/task.json b/tasks_gen/train/G1932/task.json new file mode 100644 index 0000000..62dc0d4 --- /dev/null +++ b/tasks_gen/train/G1932/task.json @@ -0,0 +1,55 @@ +{ + "id": "G1932", + "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}}BOWL", + "fields": [ + "client", + "booking_id", + "lane_no", + "play_hours", + "game_mode", + "order_no", + "play_date", + "player_count", + "league_code", + "price_value" + ] + } + ], + "out_of_scope": [], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}BOWL_HIDDEN", + "file": "hidden/bowl_hidden.clas.abap", + "description": "Hidden tests for the bowling lane booking table" + } + ], + "reference": [ + { + "type": "TABL", + "name": "{{P}}BOWL", + "file": "reference/bowl.tabl.asabap", + "description": "Bowling lane booking table" + }, + { + "type": "CLAS", + "name": "{{P}}BOWL_TEST", + "file": "reference/bowl_test.clas.abap", + "description": "Own tests for the table" + } + ], + "craft_checks": [] +} \ No newline at end of file diff --git a/tasks_gen/train/G1933/faulty/m0_if_pyro_order.intf.abap b/tasks_gen/train/G1933/faulty/m0_if_pyro_order.intf.abap new file mode 100644 index 0000000..e86aac7 --- /dev/null +++ b/tasks_gen/train/G1933/faulty/m0_if_pyro_order.intf.abap @@ -0,0 +1,50 @@ +INTERFACE {{p}}if_pyro_order PUBLIC. + TYPES ty_reason TYPE c LENGTH 11. + TYPES ty_zone TYPE c LENGTH 1. + TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2. + + TYPES BEGIN OF ty_order. + TYPES calibre_mm TYPE i. + TYPES zone_code TYPE ty_zone. + TYPES wind_kmh TYPE i. + TYPES start_hour TYPE i. + TYPES crowd_m TYPE i. + TYPES duration_min TYPE i. + TYPES END OF ty_order. + + CONSTANTS: + BEGIN OF c_reason, + ok TYPE ty_reason VALUE 'OK', + calibre TYPE ty_reason VALUE 'CALIBRE', + zone TYPE ty_reason VALUE 'ZONE', + wind TYPE ty_reason VALUE 'WIND', + time TYPE ty_reason VALUE 'TIME', + distance TYPE ty_reason VALUE 'DISTANCE', + END OF c_reason. + + CONSTANTS: + BEGIN OF c_limit, + max_wind_kmh TYPE i VALUE 30, + min_start_hour TYPE i VALUE 18, + max_start_hour TYPE i VALUE 23, + free_minutes TYPE i VALUE 10, + max_fee_euro TYPE i VALUE 5000, + END OF c_limit. + + CONSTANTS: + BEGIN OF c_distance, + calibre_50 TYPE i VALUE 30, + calibre_75 TYPE i VALUE 45, + calibre_100 TYPE i VALUE 60, + calibre_150 TYPE i VALUE 90, + calibre_200 TYPE i VALUE 120, + END OF c_distance. + + METHODS check_order + IMPORTING is_order TYPE ty_order + RETURNING VALUE(rv_reason) TYPE ty_reason. + + METHODS calc_fee + IMPORTING is_order TYPE ty_order + RETURNING VALUE(rv_fee) TYPE ty_amount. +ENDINTERFACE. diff --git a/tasks_gen/train/G1933/faulty/m1_if_pyro_order.intf.abap b/tasks_gen/train/G1933/faulty/m1_if_pyro_order.intf.abap new file mode 100644 index 0000000..e881eca --- /dev/null +++ b/tasks_gen/train/G1933/faulty/m1_if_pyro_order.intf.abap @@ -0,0 +1,50 @@ +INTERFACE {{p}}if_pyro_order PUBLIC. + TYPES ty_reason TYPE c LENGTH 12. + TYPES ty_zone TYPE c LENGTH 1. + TYPES ty_amount TYPE p LENGTH 7 DECIMALS 2. + + TYPES BEGIN OF ty_order. + TYPES calibre_mm TYPE i. + TYPES zone_code TYPE ty_zone. + TYPES wind_kmh TYPE i. + TYPES start_hour TYPE i. + TYPES crowd_m TYPE i. + TYPES duration_min TYPE i. + TYPES END OF ty_order. + + CONSTANTS: + BEGIN OF c_reason, + ok TYPE ty_reason VALUE 'OK', + calibre TYPE ty_reason VALUE 'CALIBRE', + zone TYPE ty_reason VALUE 'ZONE', + wind TYPE ty_reason VALUE 'WIND', + time TYPE ty_reason VALUE 'TIME', + distance TYPE ty_reason VALUE 'DISTANCE', + END OF c_reason. + + CONSTANTS: + BEGIN OF c_limit, + max_wind_kmh TYPE i VALUE 30, + min_start_hour TYPE i VALUE 18, + max_start_hour TYPE i VALUE 23, + free_minutes TYPE i VALUE 10, + max_fee_euro TYPE i VALUE 5000, + END OF c_limit. + + CONSTANTS: + BEGIN OF c_distance, + calibre_50 TYPE i VALUE 30, + calibre_75 TYPE i VALUE 45, + calibre_100 TYPE i VALUE 60, + calibre_150 TYPE i VALUE 90, + calibre_200 TYPE i VALUE 120, + END OF c_distance. + + METHODS check_order + IMPORTING is_order TYPE ty_order + RETURNING VALUE(rv_reason) TYPE ty_reason. + + METHODS calc_fee + IMPORTING is_order TYPE ty_order + RETURNING VALUE(rv_fee) TYPE ty_amount. +ENDINTERFACE. diff --git a/tasks_gen/train/G1933/faulty/m2_if_pyro_order.intf.abap b/tasks_gen/train/G1933/faulty/m2_if_pyro_order.intf.abap new file mode 100644 index 0000000..32c85f0 --- /dev/null +++ b/tasks_gen/train/G1933/faulty/m2_if_pyro_order.intf.abap @@ -0,0 +1,50 @@ +INTERFACE {{p}}if_pyro_order PUBLIC. + TYPES ty_reason TYPE c LENGTH 12. + TYPES ty_zone TYPE c LENGTH 1. + TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2. + + TYPES BEGIN OF ty_order. + TYPES calibre_mm TYPE i. + TYPES zone_code TYPE ty_zone. + TYPES wind_kmh TYPE i. + TYPES start_hour TYPE i. + TYPES crowd_m TYPE i. + TYPES duration_min TYPE i. + TYPES END OF ty_order. + + CONSTANTS: + BEGIN OF c_reason, + ok TYPE ty_reason VALUE 'OK', + calibre TYPE ty_reason VALUE 'CALIBRE', + zone TYPE ty_reason VALUE 'YONE', + wind TYPE ty_reason VALUE 'WIND', + time TYPE ty_reason VALUE 'TIME', + distance TYPE ty_reason VALUE 'DISTANCE', + END OF c_reason. + + CONSTANTS: + BEGIN OF c_limit, + max_wind_kmh TYPE i VALUE 30, + min_start_hour TYPE i VALUE 18, + max_start_hour TYPE i VALUE 23, + free_minutes TYPE i VALUE 10, + max_fee_euro TYPE i VALUE 5000, + END OF c_limit. + + CONSTANTS: + BEGIN OF c_distance, + calibre_50 TYPE i VALUE 30, + calibre_75 TYPE i VALUE 45, + calibre_100 TYPE i VALUE 60, + calibre_150 TYPE i VALUE 90, + calibre_200 TYPE i VALUE 120, + END OF c_distance. + + METHODS check_order + IMPORTING is_order TYPE ty_order + RETURNING VALUE(rv_reason) TYPE ty_reason. + + METHODS calc_fee + IMPORTING is_order TYPE ty_order + RETURNING VALUE(rv_fee) TYPE ty_amount. +ENDINTERFACE. diff --git a/tasks_gen/train/G1933/faulty/m3_if_pyro_order.intf.abap b/tasks_gen/train/G1933/faulty/m3_if_pyro_order.intf.abap new file mode 100644 index 0000000..f2908e2 --- /dev/null +++ b/tasks_gen/train/G1933/faulty/m3_if_pyro_order.intf.abap @@ -0,0 +1,50 @@ +INTERFACE {{p}}if_pyro_order PUBLIC. + TYPES ty_reason TYPE c LENGTH 12. + TYPES ty_zone TYPE c LENGTH 1. + TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2. + + TYPES BEGIN OF ty_order. + TYPES calibre_mm TYPE i. + TYPES zone_code TYPE ty_zone. + TYPES wind_kmh TYPE i. + TYPES start_hour TYPE i. + TYPES crowd_m TYPE i. + TYPES duration_min TYPE i. + TYPES END OF ty_order. + + CONSTANTS: + BEGIN OF c_reason, + ok TYPE ty_reason VALUE 'OK', + calibre TYPE ty_reason VALUE 'CALIBRE', + zone TYPE ty_reason VALUE 'ZONE', + wind TYPE ty_reason VALUE 'WIND', + time TYPE ty_reason VALUE 'ZIME', + distance TYPE ty_reason VALUE 'DISTANCE', + END OF c_reason. + + CONSTANTS: + BEGIN OF c_limit, + max_wind_kmh TYPE i VALUE 30, + min_start_hour TYPE i VALUE 18, + max_start_hour TYPE i VALUE 23, + free_minutes TYPE i VALUE 10, + max_fee_euro TYPE i VALUE 5000, + END OF c_limit. + + CONSTANTS: + BEGIN OF c_distance, + calibre_50 TYPE i VALUE 30, + calibre_75 TYPE i VALUE 45, + calibre_100 TYPE i VALUE 60, + calibre_150 TYPE i VALUE 90, + calibre_200 TYPE i VALUE 120, + END OF c_distance. + + METHODS check_order + IMPORTING is_order TYPE ty_order + RETURNING VALUE(rv_reason) TYPE ty_reason. + + METHODS calc_fee + IMPORTING is_order TYPE ty_order + RETURNING VALUE(rv_fee) TYPE ty_amount. +ENDINTERFACE. diff --git a/tasks_gen/train/G1933/faulty/m4_if_pyro_order.intf.abap b/tasks_gen/train/G1933/faulty/m4_if_pyro_order.intf.abap new file mode 100644 index 0000000..847cdec --- /dev/null +++ b/tasks_gen/train/G1933/faulty/m4_if_pyro_order.intf.abap @@ -0,0 +1,50 @@ +INTERFACE {{p}}if_pyro_order PUBLIC. + TYPES ty_reason TYPE c LENGTH 12. + TYPES ty_zone TYPE c LENGTH 1. + TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2. + + TYPES BEGIN OF ty_order. + TYPES calibre_mm TYPE i. + TYPES zone_code TYPE ty_zone. + TYPES wind_kmh TYPE i. + TYPES start_hour TYPE i. + TYPES crowd_m TYPE i. + TYPES duration_min TYPE i. + TYPES END OF ty_order. + + CONSTANTS: + BEGIN OF c_reason, + ok TYPE ty_reason VALUE 'OK', + calibre TYPE ty_reason VALUE 'CALIBRE', + zone TYPE ty_reason VALUE 'ZONE', + wind TYPE ty_reason VALUE 'WIND', + time TYPE ty_reason VALUE 'TIME', + distance TYPE ty_reason VALUE 'ZISTANCE', + END OF c_reason. + + CONSTANTS: + BEGIN OF c_limit, + max_wind_kmh TYPE i VALUE 30, + min_start_hour TYPE i VALUE 18, + max_start_hour TYPE i VALUE 23, + free_minutes TYPE i VALUE 10, + max_fee_euro TYPE i VALUE 5000, + END OF c_limit. + + CONSTANTS: + BEGIN OF c_distance, + calibre_50 TYPE i VALUE 30, + calibre_75 TYPE i VALUE 45, + calibre_100 TYPE i VALUE 60, + calibre_150 TYPE i VALUE 90, + calibre_200 TYPE i VALUE 120, + END OF c_distance. + + METHODS check_order + IMPORTING is_order TYPE ty_order + RETURNING VALUE(rv_reason) TYPE ty_reason. + + METHODS calc_fee + IMPORTING is_order TYPE ty_order + RETURNING VALUE(rv_fee) TYPE ty_amount. +ENDINTERFACE. diff --git a/tasks_gen/train/G1933/generation.json b/tasks_gen/train/G1933/generation.json new file mode 100644 index 0000000..f87be79 --- /dev/null +++ b/tasks_gen/train/G1933/generation.json @@ -0,0 +1,55 @@ +{ + "id": "G1933", + "pool": "train", + "object_type": "INTF", + "category": "A", + "attempts": [ + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 76.1, + "null": 0 + }, + { + "stage": "bundle", + "errors": [ + "reference/pyro_order_test.clas.abap line 6: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\"", + "reference/pyro_order_test.clas.abap line 7: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\"", + "reference/pyro_order_test.clas.abap line 8: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\"", + "reference/pyro_order_test.clas.abap line 9: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\"", + "reference/pyro_order_test.clas.abap line 10: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\"", + "reference/pyro_order_test.clas.abap line 11: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\"", + "reference/pyro_order_test.clas.abap line 12: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\"", + "reference/pyro_order_test.clas.abap line 13: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\"", + "hidden/pyro_hidden.clas.abap line 8: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\"", + "hidden/pyro_hidden.clas.abap line 9: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\"", + "hidden/pyro_hidden.clas.abap line 10: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\"", + "hidden/pyro_hidden.clas.abap line 11: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\"", + "hidden/pyro_hidden.clas.abap line 12: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\"", + "hidden/pyro_hidden.clas.abap line 13: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\"", + "hidden/pyro_hidden.clas.abap line 14: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\"", + "hidden/pyro_hidden.clas.abap line 15: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\"", + "hidden/pyro_hidden.clas.abap line 16: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\"", + "hidden/pyro_hidden.clas.abap line 17: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\"" + ], + "by_check": { + "abaplint": 18 + } + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 5, + "killed": 5, + "ok": true + } + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1933/hidden/pyro_hidden.clas.abap b/tasks_gen/train/G1933/hidden/pyro_hidden.clas.abap new file mode 100644 index 0000000..2422404 --- /dev/null +++ b/tasks_gen/train/G1933/hidden/pyro_hidden.clas.abap @@ -0,0 +1,214 @@ +CLASS {{p}}pyro_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PUBLIC SECTION. + INTERFACES {{p}}if_pyro_order. + PRIVATE SECTION. + DATA mo_cut TYPE REF TO {{p}}if_pyro_order. + METHODS setup. + METHODS reason_values FOR TESTING. + METHODS reason_length FOR TESTING. + METHODS zone_length FOR TESTING. + METHODS amount_type FOR TESTING. + METHODS order_structure FOR TESTING. + METHODS reason_structure FOR TESTING. + METHODS limit_values FOR TESTING. + METHODS distance_values FOR TESTING. + METHODS check_order_call FOR TESTING. + METHODS calc_fee_call FOR TESTING. +ENDCLASS. + + +CLASS {{p}}pyro_hidden IMPLEMENTATION. + METHOD setup. + mo_cut = NEW {{p}}pyro_hidden( ). + ENDMETHOD. + + METHOD {{p}}if_pyro_order~check_order. + rv_reason = {{p}}if_pyro_order=>c_reason-ok. + ENDMETHOD. + + METHOD {{p}}if_pyro_order~calc_fee. + rv_fee = 0. + ENDMETHOD. + + METHOD reason_values. + DATA lv_exp TYPE {{p}}if_pyro_order=>ty_reason. + lv_exp = 'OK'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp + act = {{p}}if_pyro_order=>c_reason-ok ). + lv_exp = 'CALIBRE'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp + act = {{p}}if_pyro_order=>c_reason-calibre ). + lv_exp = 'ZONE'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp + act = {{p}}if_pyro_order=>c_reason-zone ). + lv_exp = 'WIND'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp + act = {{p}}if_pyro_order=>c_reason-wind ). + lv_exp = 'TIME'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp + act = {{p}}if_pyro_order=>c_reason-time ). + lv_exp = 'DISTANCE'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp + act = {{p}}if_pyro_order=>c_reason-distance ). + ENDMETHOD. + + METHOD reason_length. + DATA lv_reason TYPE {{p}}if_pyro_order=>ty_reason. + DATA lv_exp TYPE {{p}}if_pyro_order=>ty_reason. + DATA lv_long TYPE c LENGTH 13. + DATA lv_kind TYPE c LENGTH 1. + DATA lv_len TYPE i. + DATA(lo_descr) = cl_abap_typedescr=>describe_by_data( lv_reason ). + lv_kind = 'C'. + cl_abap_unit_assert=>assert_equals( exp = lv_kind act = lo_descr->type_kind ). + lv_long = 'ABCDEFGHIJKLM'. + lv_reason = lv_long. + lv_exp = 'ABCDEFGHIJKL'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_reason ). + lv_len = 12. + cl_abap_unit_assert=>assert_equals( exp = lv_len act = strlen( lv_reason ) ). + ENDMETHOD. + + METHOD zone_length. + DATA lv_zone TYPE {{p}}if_pyro_order=>ty_zone. + DATA lv_exp TYPE {{p}}if_pyro_order=>ty_zone. + DATA lv_long TYPE c LENGTH 2. + DATA lv_kind TYPE c LENGTH 1. + DATA lv_len TYPE i. + DATA(lo_descr) = cl_abap_typedescr=>describe_by_data( lv_zone ). + lv_kind = 'C'. + cl_abap_unit_assert=>assert_equals( exp = lv_kind act = lo_descr->type_kind ). + lv_long = 'AB'. + lv_zone = lv_long. + lv_exp = 'A'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_zone ). + lv_len = 1. + cl_abap_unit_assert=>assert_equals( exp = lv_len act = strlen( lv_zone ) ). + ENDMETHOD. + + METHOD amount_type. + DATA lv_amount TYPE {{p}}if_pyro_order=>ty_amount. + DATA lv_exp TYPE {{p}}if_pyro_order=>ty_amount. + DATA lv_kind TYPE c LENGTH 1. + DATA lv_dec TYPE i. + DATA lv_len TYPE i. + DATA(lo_descr) = cl_abap_typedescr=>describe_by_data( lv_amount ). + lv_kind = 'P'. + cl_abap_unit_assert=>assert_equals( exp = lv_kind act = lo_descr->type_kind ). + lv_dec = 2. + cl_abap_unit_assert=>assert_equals( exp = lv_dec act = lo_descr->decimals ). + lv_len = 8. + cl_abap_unit_assert=>assert_equals( exp = lv_len act = lo_descr->length ). + lv_amount = '1234.56'. + lv_exp = '1234.56'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_amount ). + ENDMETHOD. + + METHOD order_structure. + DATA ls_order TYPE {{p}}if_pyro_order=>ty_order. + DATA lv_count TYPE i. + DATA lv_kind TYPE c LENGTH 1. + DATA lv_name TYPE c LENGTH 30. + DATA lv_exp_name TYPE c LENGTH 30. + DATA(lo_struct) = CAST cl_abap_structdescr( + cl_abap_typedescr=>describe_by_data( ls_order ) ). + DATA(lt_comp) = lo_struct->get_components( ). + lv_count = 6. + cl_abap_unit_assert=>assert_equals( exp = lv_count act = lines( lt_comp ) ). + lv_name = lt_comp[ 1 ]-name. + lv_exp_name = 'CALIBRE_MM'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp_name act = lv_name ). + lv_kind = 'I'. + DATA(lo_elem) = cl_abap_typedescr=>describe_by_data( ls_order-calibre_mm ). + cl_abap_unit_assert=>assert_equals( exp = lv_kind act = lo_elem->type_kind ). + lo_elem = cl_abap_typedescr=>describe_by_data( ls_order-wind_kmh ). + cl_abap_unit_assert=>assert_equals( exp = lv_kind act = lo_elem->type_kind ). + lo_elem = cl_abap_typedescr=>describe_by_data( ls_order-start_hour ). + cl_abap_unit_assert=>assert_equals( exp = lv_kind act = lo_elem->type_kind ). + lo_elem = cl_abap_typedescr=>describe_by_data( ls_order-crowd_m ). + cl_abap_unit_assert=>assert_equals( exp = lv_kind act = lo_elem->type_kind ). + lo_elem = cl_abap_typedescr=>describe_by_data( ls_order-duration_min ). + cl_abap_unit_assert=>assert_equals( exp = lv_kind act = lo_elem->type_kind ). + DATA lv_zone_kind TYPE c LENGTH 1. + lv_zone_kind = 'C'. + lo_elem = cl_abap_typedescr=>describe_by_data( ls_order-zone_code ). + cl_abap_unit_assert=>assert_equals( exp = lv_zone_kind act = lo_elem->type_kind ). + ENDMETHOD. + + METHOD reason_structure. + DATA(ls_reason) = {{p}}if_pyro_order=>c_reason. + DATA lv_count TYPE i. + DATA(lo_struct) = CAST cl_abap_structdescr( + cl_abap_typedescr=>describe_by_data( ls_reason ) ). + DATA(lt_comp) = lo_struct->get_components( ). + lv_count = 6. + cl_abap_unit_assert=>assert_equals( exp = lv_count act = lines( lt_comp ) ). + ENDMETHOD. + + METHOD limit_values. + DATA lv_exp TYPE i. + lv_exp = 30. + cl_abap_unit_assert=>assert_equals( exp = lv_exp + act = {{p}}if_pyro_order=>c_limit-max_wind_kmh ). + lv_exp = 18. + cl_abap_unit_assert=>assert_equals( exp = lv_exp + act = {{p}}if_pyro_order=>c_limit-min_start_hour ). + lv_exp = 23. + cl_abap_unit_assert=>assert_equals( exp = lv_exp + act = {{p}}if_pyro_order=>c_limit-max_start_hour ). + lv_exp = 10. + cl_abap_unit_assert=>assert_equals( exp = lv_exp + act = {{p}}if_pyro_order=>c_limit-free_minutes ). + lv_exp = 5000. + cl_abap_unit_assert=>assert_equals( exp = lv_exp + act = {{p}}if_pyro_order=>c_limit-max_fee_euro ). + ENDMETHOD. + + METHOD distance_values. + DATA lv_exp TYPE i. + lv_exp = 30. + cl_abap_unit_assert=>assert_equals( exp = lv_exp + act = {{p}}if_pyro_order=>c_distance-calibre_50 ). + lv_exp = 45. + cl_abap_unit_assert=>assert_equals( exp = lv_exp + act = {{p}}if_pyro_order=>c_distance-calibre_75 ). + lv_exp = 60. + cl_abap_unit_assert=>assert_equals( exp = lv_exp + act = {{p}}if_pyro_order=>c_distance-calibre_100 ). + lv_exp = 90. + cl_abap_unit_assert=>assert_equals( exp = lv_exp + act = {{p}}if_pyro_order=>c_distance-calibre_150 ). + lv_exp = 120. + cl_abap_unit_assert=>assert_equals( exp = lv_exp + act = {{p}}if_pyro_order=>c_distance-calibre_200 ). + ENDMETHOD. + + METHOD check_order_call. + DATA ls_order TYPE {{p}}if_pyro_order=>ty_order. + DATA lv_exp TYPE {{p}}if_pyro_order=>ty_reason. + ls_order = VALUE #( calibre_mm = 100 + zone_code = 'A' + wind_kmh = 10 + start_hour = 20 + crowd_m = 60 + duration_min = 15 ). + DATA(lv_reason) = mo_cut->check_order( ls_order ). + lv_exp = 'OK'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_reason ). + ENDMETHOD. + + METHOD calc_fee_call. + DATA ls_order TYPE {{p}}if_pyro_order=>ty_order. + DATA lv_exp TYPE {{p}}if_pyro_order=>ty_amount. + ls_order = VALUE #( calibre_mm = 100 + zone_code = 'A' + wind_kmh = 10 + start_hour = 20 + crowd_m = 60 + duration_min = 15 ). + DATA(lv_fee) = mo_cut->calc_fee( ls_order ). + lv_exp = 0. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_fee ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1933/mutation.json b/tasks_gen/train/G1933/mutation.json new file mode 100644 index 0000000..69924e1 --- /dev/null +++ b/tasks_gen/train/G1933/mutation.json @@ -0,0 +1,54 @@ +{ + "task": "G1933", + "mutants": [ + { + "object": "{{P}}IF_PYRO_ORDER", + "mutant": "line 2: LENGTH 12 -> LENGTH 11 (length)", + "status": "killed", + "hidden": "9/10", + "failed_tests": [ + "REASON_LENGTH" + ] + }, + { + "object": "{{P}}IF_PYRO_ORDER", + "mutant": "line 4: LENGTH 8 -> LENGTH 7 (length)", + "status": "killed", + "hidden": "9/10", + "failed_tests": [ + "AMOUNT_TYPE" + ] + }, + { + "object": "{{P}}IF_PYRO_ORDER", + "mutant": "line 19: VALUE 'ZONE' -> VALUE 'YONE' (lit)", + "status": "killed", + "hidden": "9/10", + "failed_tests": [ + "REASON_VALUES" + ] + }, + { + "object": "{{P}}IF_PYRO_ORDER", + "mutant": "line 21: VALUE 'TIME' -> VALUE 'ZIME' (lit)", + "status": "killed", + "hidden": "9/10", + "failed_tests": [ + "REASON_VALUES" + ] + }, + { + "object": "{{P}}IF_PYRO_ORDER", + "mutant": "line 22: VALUE 'DISTANCE' -> VALUE 'ZISTANCE' (lit)", + "status": "killed", + "hidden": "9/10", + "failed_tests": [ + "REASON_VALUES" + ] + } + ], + "valid": 5, + "killed": 5, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1933/reference/if_pyro_order.intf.abap b/tasks_gen/train/G1933/reference/if_pyro_order.intf.abap new file mode 100644 index 0000000..6775a1c --- /dev/null +++ b/tasks_gen/train/G1933/reference/if_pyro_order.intf.abap @@ -0,0 +1,50 @@ +INTERFACE {{p}}if_pyro_order PUBLIC. + TYPES ty_reason TYPE c LENGTH 12. + TYPES ty_zone TYPE c LENGTH 1. + TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2. + + TYPES BEGIN OF ty_order. + TYPES calibre_mm TYPE i. + TYPES zone_code TYPE ty_zone. + TYPES wind_kmh TYPE i. + TYPES start_hour TYPE i. + TYPES crowd_m TYPE i. + TYPES duration_min TYPE i. + TYPES END OF ty_order. + + CONSTANTS: + BEGIN OF c_reason, + ok TYPE ty_reason VALUE 'OK', + calibre TYPE ty_reason VALUE 'CALIBRE', + zone TYPE ty_reason VALUE 'ZONE', + wind TYPE ty_reason VALUE 'WIND', + time TYPE ty_reason VALUE 'TIME', + distance TYPE ty_reason VALUE 'DISTANCE', + END OF c_reason. + + CONSTANTS: + BEGIN OF c_limit, + max_wind_kmh TYPE i VALUE 30, + min_start_hour TYPE i VALUE 18, + max_start_hour TYPE i VALUE 23, + free_minutes TYPE i VALUE 10, + max_fee_euro TYPE i VALUE 5000, + END OF c_limit. + + CONSTANTS: + BEGIN OF c_distance, + calibre_50 TYPE i VALUE 30, + calibre_75 TYPE i VALUE 45, + calibre_100 TYPE i VALUE 60, + calibre_150 TYPE i VALUE 90, + calibre_200 TYPE i VALUE 120, + END OF c_distance. + + METHODS check_order + IMPORTING is_order TYPE ty_order + RETURNING VALUE(rv_reason) TYPE ty_reason. + + METHODS calc_fee + IMPORTING is_order TYPE ty_order + RETURNING VALUE(rv_fee) TYPE ty_amount. +ENDINTERFACE. diff --git a/tasks_gen/train/G1933/reference/pyro_order_test.clas.abap b/tasks_gen/train/G1933/reference/pyro_order_test.clas.abap new file mode 100644 index 0000000..838411a --- /dev/null +++ b/tasks_gen/train/G1933/reference/pyro_order_test.clas.abap @@ -0,0 +1,182 @@ +CLASS {{p}}pyro_order_test DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PUBLIC SECTION. + INTERFACES {{p}}if_pyro_order. + PRIVATE SECTION. + METHODS reason_values FOR TESTING. + METHODS reason_length FOR TESTING. + METHODS zone_length FOR TESTING. + METHODS amount_type FOR TESTING. + METHODS order_structure FOR TESTING. + METHODS limit_values FOR TESTING. + METHODS distance_values FOR TESTING. + METHODS check_order_call FOR TESTING. +ENDCLASS. + + +CLASS {{p}}pyro_order_test IMPLEMENTATION. + METHOD {{p}}if_pyro_order~check_order. + rv_reason = {{p}}if_pyro_order=>c_reason-ok. + ENDMETHOD. + + METHOD {{p}}if_pyro_order~calc_fee. + rv_fee = 0. + ENDMETHOD. + + METHOD reason_values. + DATA lv_exp TYPE {{p}}if_pyro_order=>ty_reason. + lv_exp = 'OK'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp + act = {{p}}if_pyro_order=>c_reason-ok ). + lv_exp = 'CALIBRE'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp + act = {{p}}if_pyro_order=>c_reason-calibre ). + lv_exp = 'ZONE'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp + act = {{p}}if_pyro_order=>c_reason-zone ). + lv_exp = 'WIND'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp + act = {{p}}if_pyro_order=>c_reason-wind ). + lv_exp = 'TIME'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp + act = {{p}}if_pyro_order=>c_reason-time ). + lv_exp = 'DISTANCE'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp + act = {{p}}if_pyro_order=>c_reason-distance ). + ENDMETHOD. + + METHOD reason_length. + DATA lv_reason TYPE {{p}}if_pyro_order=>ty_reason. + DATA lv_exp TYPE {{p}}if_pyro_order=>ty_reason. + DATA lv_long TYPE c LENGTH 13. + DATA lv_kind TYPE c LENGTH 1. + DATA lv_len TYPE i. + DATA(lo_descr) = cl_abap_typedescr=>describe_by_data( lv_reason ). + lv_kind = 'C'. + cl_abap_unit_assert=>assert_equals( exp = lv_kind act = lo_descr->type_kind ). + lv_long = 'ABCDEFGHIJKLM'. + lv_reason = lv_long. + lv_exp = 'ABCDEFGHIJKL'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_reason ). + lv_len = 12. + cl_abap_unit_assert=>assert_equals( exp = lv_len act = strlen( lv_reason ) ). + ENDMETHOD. + + METHOD zone_length. + DATA lv_zone TYPE {{p}}if_pyro_order=>ty_zone. + DATA lv_exp TYPE {{p}}if_pyro_order=>ty_zone. + DATA lv_long TYPE c LENGTH 2. + DATA lv_kind TYPE c LENGTH 1. + DATA lv_len TYPE i. + DATA(lo_descr) = cl_abap_typedescr=>describe_by_data( lv_zone ). + lv_kind = 'C'. + cl_abap_unit_assert=>assert_equals( exp = lv_kind act = lo_descr->type_kind ). + lv_long = 'AB'. + lv_zone = lv_long. + lv_exp = 'A'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_zone ). + lv_len = 1. + cl_abap_unit_assert=>assert_equals( exp = lv_len act = strlen( lv_zone ) ). + ENDMETHOD. + + METHOD amount_type. + DATA lv_amount TYPE {{p}}if_pyro_order=>ty_amount. + DATA lv_exp TYPE {{p}}if_pyro_order=>ty_amount. + DATA lv_kind TYPE c LENGTH 1. + DATA lv_dec TYPE i. + DATA lv_len TYPE i. + DATA(lo_descr) = cl_abap_typedescr=>describe_by_data( lv_amount ). + lv_kind = 'P'. + cl_abap_unit_assert=>assert_equals( exp = lv_kind act = lo_descr->type_kind ). + lv_dec = 2. + cl_abap_unit_assert=>assert_equals( exp = lv_dec act = lo_descr->decimals ). + lv_len = 8. + cl_abap_unit_assert=>assert_equals( exp = lv_len act = lo_descr->length ). + lv_amount = '1234.56'. + lv_exp = '1234.56'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_amount ). + ENDMETHOD. + + METHOD order_structure. + DATA ls_order TYPE {{p}}if_pyro_order=>ty_order. + DATA lv_count TYPE i. + DATA lv_name TYPE c LENGTH 30. + DATA lv_exp_name TYPE c LENGTH 30. + DATA(lo_struct) = CAST cl_abap_structdescr( + cl_abap_typedescr=>describe_by_data( ls_order ) ). + DATA(lt_comp) = lo_struct->get_components( ). + lv_count = 6. + cl_abap_unit_assert=>assert_equals( exp = lv_count act = lines( lt_comp ) ). + lv_name = lt_comp[ 1 ]-name. + lv_exp_name = 'CALIBRE_MM'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp_name act = lv_name ). + DATA lv_kind TYPE c LENGTH 1. + lv_kind = 'I'. + DATA(lo_elem) = cl_abap_typedescr=>describe_by_data( ls_order-calibre_mm ). + cl_abap_unit_assert=>assert_equals( exp = lv_kind act = lo_elem->type_kind ). + lo_elem = cl_abap_typedescr=>describe_by_data( ls_order-wind_kmh ). + cl_abap_unit_assert=>assert_equals( exp = lv_kind act = lo_elem->type_kind ). + lo_elem = cl_abap_typedescr=>describe_by_data( ls_order-start_hour ). + cl_abap_unit_assert=>assert_equals( exp = lv_kind act = lo_elem->type_kind ). + lo_elem = cl_abap_typedescr=>describe_by_data( ls_order-crowd_m ). + cl_abap_unit_assert=>assert_equals( exp = lv_kind act = lo_elem->type_kind ). + lo_elem = cl_abap_typedescr=>describe_by_data( ls_order-duration_min ). + cl_abap_unit_assert=>assert_equals( exp = lv_kind act = lo_elem->type_kind ). + DATA lv_zone_kind TYPE c LENGTH 1. + lv_zone_kind = 'C'. + lo_elem = cl_abap_typedescr=>describe_by_data( ls_order-zone_code ). + cl_abap_unit_assert=>assert_equals( exp = lv_zone_kind act = lo_elem->type_kind ). + ENDMETHOD. + + METHOD limit_values. + DATA lv_exp TYPE i. + lv_exp = 30. + cl_abap_unit_assert=>assert_equals( exp = lv_exp + act = {{p}}if_pyro_order=>c_limit-max_wind_kmh ). + lv_exp = 18. + cl_abap_unit_assert=>assert_equals( exp = lv_exp + act = {{p}}if_pyro_order=>c_limit-min_start_hour ). + lv_exp = 23. + cl_abap_unit_assert=>assert_equals( exp = lv_exp + act = {{p}}if_pyro_order=>c_limit-max_start_hour ). + lv_exp = 10. + cl_abap_unit_assert=>assert_equals( exp = lv_exp + act = {{p}}if_pyro_order=>c_limit-free_minutes ). + lv_exp = 5000. + cl_abap_unit_assert=>assert_equals( exp = lv_exp + act = {{p}}if_pyro_order=>c_limit-max_fee_euro ). + ENDMETHOD. + + METHOD distance_values. + DATA lv_exp TYPE i. + lv_exp = 30. + cl_abap_unit_assert=>assert_equals( exp = lv_exp + act = {{p}}if_pyro_order=>c_distance-calibre_50 ). + lv_exp = 45. + cl_abap_unit_assert=>assert_equals( exp = lv_exp + act = {{p}}if_pyro_order=>c_distance-calibre_75 ). + lv_exp = 60. + cl_abap_unit_assert=>assert_equals( exp = lv_exp + act = {{p}}if_pyro_order=>c_distance-calibre_100 ). + lv_exp = 90. + cl_abap_unit_assert=>assert_equals( exp = lv_exp + act = {{p}}if_pyro_order=>c_distance-calibre_150 ). + lv_exp = 120. + cl_abap_unit_assert=>assert_equals( exp = lv_exp + act = {{p}}if_pyro_order=>c_distance-calibre_200 ). + ENDMETHOD. + + METHOD check_order_call. + DATA ls_order TYPE {{p}}if_pyro_order=>ty_order. + DATA lv_exp TYPE {{p}}if_pyro_order=>ty_reason. + ls_order = VALUE #( calibre_mm = 100 + zone_code = 'A' + wind_kmh = 10 + start_hour = 20 + crowd_m = 60 + duration_min = 15 ). + DATA(lv_reason) = {{p}}if_pyro_order~check_order( ls_order ). + lv_exp = 'OK'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_reason ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1933/spec.md b/tasks_gen/train/G1933/spec.md new file mode 100644 index 0000000..9b71ee3 --- /dev/null +++ b/tasks_gen/train/G1933/spec.md @@ -0,0 +1,67 @@ +# 1. Goal +A fireworks display company plans displays for its clients. The order desk calls +one contract for the check of a display plan and for the fee of the display. +Create the interface that carries this contract. + +# 2. Open questions +None. + +# 3. Context +- The order desk of the fireworks display company receives one display plan for +each order. A plan has the calibre of the shells in millimetres, the zone of the +firing site, the wind speed in kilometres per hour, the start hour, the distance +to the crowd in metres and the duration of the display in minutes. +- The desk checks the plan before it confirms the order. The check stops at the +first rule that fails and returns one reason code. +- The desk calculates the fee of the display in euro after the check. +- The interface {{P}}IF_PYRO_ORDER does not exist yet. Create it in package +$TMP. The interface is the only object that the order desk needs. + +# 4. Contract +- Create the interface {{P}}IF_PYRO_ORDER in package $TMP. +- The interface has the types TY_REASON, TY_ZONE, TY_AMOUNT and TY_ORDER. +- The interface has the constant structures C_REASON, C_LIMIT and C_DISTANCE. +- The interface has the methods CHECK_ORDER and CALC_FEE. +- The interface has no other types, constants or methods. + +# 5. Business rules +1. TY_REASON is a character type of length 12. It holds the reason code of the +check. +2. TY_ZONE is a character type of length 1. It holds the zone of the firing +site. +3. TY_AMOUNT is a packed type of length 8 with 2 decimal places. It holds an +amount in euro. +4. TY_ORDER is a structure with exactly these six components, in this sequence: +CALIBRE_MM of type i, ZONE_CODE of type TY_ZONE, WIND_KMH of type i, +START_HOUR of type i, CROWD_M of type i and DURATION_MIN of type i. +5. C_REASON is a constant structure with exactly six components of type +TY_REASON: +OK = 'OK' for an accepted plan, +CALIBRE = 'CALIBRE' for a calibre that the company does not use, +ZONE = 'ZONE' for a zone that is not A, B or C, +WIND = 'WIND' for a wind that is stronger than the wind limit, +TIME = 'TIME' for a start hour outside the start window, +DISTANCE = 'DISTANCE' for a crowd distance below the safety distance. +6. C_LIMIT is a constant structure with exactly five components of type i: +MAX_WIND_KMH = 30, MIN_START_HOUR = 18, MAX_START_HOUR = 23, +FREE_MINUTES = 10 and MAX_FEE_EURO = 5000. +7. C_DISTANCE is a constant structure with exactly five components of type i: +CALIBRE_50 = 30, CALIBRE_75 = 45, CALIBRE_100 = 60, CALIBRE_150 = 90 and +CALIBRE_200 = 120. A component holds the safety distance in metres for the +calibre of the same name in millimetres. The company uses only these five +calibres. +8. CHECK_ORDER has the importing parameter IS_ORDER of type TY_ORDER and the +returning parameter RV_REASON of type TY_REASON. +9. CALC_FEE has the importing parameter IS_ORDER of type TY_ORDER and the +returning parameter RV_FEE of type TY_AMOUNT. + +# 6. Constraints +- Release target: 8.16. +- Coding standards: Clean ABAP. Upper case for the names of the types, the +constants and the methods. No comment that restates the code. +- Out of scope: do not create other objects in package $TMP. + +# 7. Acceptance +- The interface is active and has no syntax error. +- The hidden tests pass. +- Write your own ABAP Unit tests for the interface. diff --git a/tasks_gen/train/G1933/task.json b/tasks_gen/train/G1933/task.json new file mode 100644 index 0000000..2e35770 --- /dev/null +++ b/tasks_gen/train/G1933/task.json @@ -0,0 +1,48 @@ +{ + "id": "G1933", + "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_PYRO_ORDER" + } + ], + "out_of_scope": [ + "Do not create other objects in package $TMP." + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}PYRO_HIDDEN", + "file": "hidden/pyro_hidden.clas.abap", + "description": "Hidden tests for the interface {{P}}IF_PYRO_ORDER. The global test class itself implements the interface, therefore it only compiles when every signature matches. The tests read the constants, check the type kinds and the lengths of the types, check the components of the structures, and call both methods through the interface." + } + ], + "reference": [ + { + "type": "INTF", + "name": "{{P}}IF_PYRO_ORDER", + "file": "reference/if_pyro_order.intf.abap", + "description": "Contract of the fireworks display order desk" + }, + { + "type": "CLAS", + "name": "{{P}}PYRO_ORDER_TEST", + "file": "reference/pyro_order_test.clas.abap", + "description": "Own ABAP Unit tests for the interface (global test class)" + } + ], + "craft_checks": [ + "method_length", + "db_operation_in_loop" + ] +} \ No newline at end of file diff --git a/tasks_gen/train/G1934/faulty/m0_pitch.tabl.asabap b/tasks_gen/train/G1934/faulty/m0_pitch.tabl.asabap new file mode 100644 index 0000000..a488baa --- /dev/null +++ b/tasks_gen/train/G1934/faulty/m0_pitch.tabl.asabap @@ -0,0 +1,16 @@ +@EndUserText.label : 'Campsite pitch booking' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}pitch { + key client : abap.clnt not null; + booking_id : abap.char(10) not null; + pitch_no : abap.numc(4); + guest_name : abap.char(30); + arrival_date : abap.dats; + departure_date : abap.dats; + persons : abap.int4; + power_hookup : abap.char(1); + rate_per_night : abap.dec(9,2); +} diff --git a/tasks_gen/train/G1934/faulty/m1_pitch.tabl.asabap b/tasks_gen/train/G1934/faulty/m1_pitch.tabl.asabap new file mode 100644 index 0000000..6029a86 --- /dev/null +++ b/tasks_gen/train/G1934/faulty/m1_pitch.tabl.asabap @@ -0,0 +1,16 @@ +@EndUserText.label : 'Campsite pitch booking' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}pitch { + key client : abap.clnt not null; + key booking_id : abap.char(9) not null; + pitch_no : abap.numc(4); + guest_name : abap.char(30); + arrival_date : abap.dats; + departure_date : abap.dats; + persons : abap.int4; + power_hookup : abap.char(1); + rate_per_night : abap.dec(9,2); +} diff --git a/tasks_gen/train/G1934/faulty/m2_pitch.tabl.asabap b/tasks_gen/train/G1934/faulty/m2_pitch.tabl.asabap new file mode 100644 index 0000000..2a172f7 --- /dev/null +++ b/tasks_gen/train/G1934/faulty/m2_pitch.tabl.asabap @@ -0,0 +1,16 @@ +@EndUserText.label : 'Campsite pitch booking' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}pitch { + key client : abap.clnt not null; + key booking_id : abap.char(10) not null; + pitch_no : abap.numc(4); + guest_name : abap.char(30); + arrival_date : abap.tims; + departure_date : abap.dats; + persons : abap.int4; + power_hookup : abap.char(1); + rate_per_night : abap.dec(9,2); +} diff --git a/tasks_gen/train/G1934/faulty/m3_pitch.tabl.asabap b/tasks_gen/train/G1934/faulty/m3_pitch.tabl.asabap new file mode 100644 index 0000000..5276fab --- /dev/null +++ b/tasks_gen/train/G1934/faulty/m3_pitch.tabl.asabap @@ -0,0 +1,16 @@ +@EndUserText.label : 'Campsite pitch booking' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}pitch { + key client : abap.clnt not null; + key booking_id : abap.char(10) not null; + pitch_no : abap.numc(4); + guest_name : abap.char(30); + arrival_date : abap.dats; + departure_date : abap.dats; + persons : abap.int8; + power_hookup : abap.char(1); + rate_per_night : abap.dec(9,2); +} diff --git a/tasks_gen/train/G1934/faulty/m4_pitch.tabl.asabap b/tasks_gen/train/G1934/faulty/m4_pitch.tabl.asabap new file mode 100644 index 0000000..e98c1c9 --- /dev/null +++ b/tasks_gen/train/G1934/faulty/m4_pitch.tabl.asabap @@ -0,0 +1,16 @@ +@EndUserText.label : 'Campsite pitch booking' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}pitch { + key client : abap.clnt not null; + key booking_id : abap.char(10) not null; + pitch_no : abap.numc(4); + guest_name : abap.char(30); + arrival_date : abap.dats; + departure_date : abap.dats; + persons : abap.int4; + power_hookup : abap.char(1); + rate_per_night : abap.dec(9,3); +} diff --git a/tasks_gen/train/G1934/generation.json b/tasks_gen/train/G1934/generation.json new file mode 100644 index 0000000..77d7851 --- /dev/null +++ b/tasks_gen/train/G1934/generation.json @@ -0,0 +1,24 @@ +{ + "id": "G1934", + "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 +} \ No newline at end of file diff --git a/tasks_gen/train/G1934/hidden/t16_hidden.clas.abap b/tasks_gen/train/G1934/hidden/t16_hidden.clas.abap new file mode 100644 index 0000000..eff08e6 --- /dev/null +++ b/tasks_gen/train/G1934/hidden/t16_hidden.clas.abap @@ -0,0 +1,147 @@ +CLASS {{p}}t16_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + + PRIVATE SECTION. + CLASS-DATA gt_fields TYPE ddfields. + CLASS-DATA go_env TYPE REF TO if_osql_test_environment. + + CLASS-METHODS class_setup. + CLASS-METHODS class_teardown. + METHODS setup. + + METHODS all_fields_present FOR TESTING. + METHODS key_fields FOR TESTING. + METHODS text_lengths FOR TESTING. + METHODS date_and_count_types FOR TESTING. + METHODS rate_decimals FOR TESTING. + METHODS insert_and_read FOR TESTING. + METHODS multiple_rows_stored FOR TESTING. + METHODS numc_keeps_leading_zeros FOR TESTING. + + CLASS-METHODS get_field + IMPORTING iv_name TYPE fieldname + RETURNING VALUE(rs_field) TYPE dfies. +ENDCLASS. + + +CLASS {{p}}t16_hidden IMPLEMENTATION. + + METHOD class_setup. + DATA(lo_struct) = CAST cl_abap_structdescr( cl_abap_typedescr=>describe_by_name( '{{P}}PITCH' ) ). + gt_fields = lo_struct->get_ddic_field_list( ). + go_env = cl_osql_test_environment=>create( i_dependency_list = VALUE #( ( '{{P}}PITCH' ) ) ). + ENDMETHOD. + + METHOD class_teardown. + IF go_env IS BOUND. + go_env->destroy( ). + ENDIF. + ENDMETHOD. + + METHOD setup. + go_env->clear_doubles( ). + ENDMETHOD. + + METHOD get_field. + READ TABLE gt_fields INTO rs_field WITH KEY fieldname = iv_name. + cl_abap_unit_assert=>assert_equals( exp = 0 act = sy-subrc + msg = |Field { iv_name } is missing| ). + ENDMETHOD. + + METHOD all_fields_present. + cl_abap_unit_assert=>assert_equals( exp = 9 act = lines( gt_fields ) ). + get_field( 'CLIENT' ). + get_field( 'BOOKING_ID' ). + get_field( 'PITCH_NO' ). + get_field( 'GUEST_NAME' ). + get_field( 'ARRIVAL_DATE' ). + get_field( 'DEPARTURE_DATE' ). + get_field( 'PERSONS' ). + get_field( 'POWER_HOOKUP' ). + get_field( 'RATE_PER_NIGHT' ). + ENDMETHOD. + + METHOD key_fields. + cl_abap_unit_assert=>assert_equals( exp = 'X' act = get_field( 'CLIENT' )-keyflag ). + cl_abap_unit_assert=>assert_equals( exp = 'X' act = get_field( 'BOOKING_ID' )-keyflag ). + cl_abap_unit_assert=>assert_equals( exp = ' ' act = get_field( 'PITCH_NO' )-keyflag ). + cl_abap_unit_assert=>assert_equals( exp = ' ' act = get_field( 'GUEST_NAME' )-keyflag ). + cl_abap_unit_assert=>assert_equals( exp = ' ' act = get_field( 'ARRIVAL_DATE' )-keyflag ). + cl_abap_unit_assert=>assert_equals( exp = ' ' act = get_field( 'DEPARTURE_DATE' )-keyflag ). + cl_abap_unit_assert=>assert_equals( exp = ' ' act = get_field( 'PERSONS' )-keyflag ). + cl_abap_unit_assert=>assert_equals( exp = ' ' act = get_field( 'POWER_HOOKUP' )-keyflag ). + cl_abap_unit_assert=>assert_equals( exp = ' ' act = get_field( 'RATE_PER_NIGHT' )-keyflag ). + ENDMETHOD. + + METHOD text_lengths. + cl_abap_unit_assert=>assert_equals( exp = 'C' act = get_field( 'CLIENT' )-inttype ). + cl_abap_unit_assert=>assert_equals( exp = 3 act = get_field( 'CLIENT' )-leng ). + cl_abap_unit_assert=>assert_equals( exp = 'C' act = get_field( 'BOOKING_ID' )-inttype ). + cl_abap_unit_assert=>assert_equals( exp = 10 act = get_field( 'BOOKING_ID' )-leng ). + cl_abap_unit_assert=>assert_equals( exp = 'N' act = get_field( 'PITCH_NO' )-inttype ). + cl_abap_unit_assert=>assert_equals( exp = 4 act = get_field( 'PITCH_NO' )-leng ). + cl_abap_unit_assert=>assert_equals( exp = 'C' act = get_field( 'GUEST_NAME' )-inttype ). + cl_abap_unit_assert=>assert_equals( exp = 30 act = get_field( 'GUEST_NAME' )-leng ). + cl_abap_unit_assert=>assert_equals( exp = 'C' act = get_field( 'POWER_HOOKUP' )-inttype ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = get_field( 'POWER_HOOKUP' )-leng ). + ENDMETHOD. + + METHOD date_and_count_types. + cl_abap_unit_assert=>assert_equals( exp = 'D' act = get_field( 'ARRIVAL_DATE' )-inttype ). + cl_abap_unit_assert=>assert_equals( exp = 8 act = get_field( 'ARRIVAL_DATE' )-leng ). + cl_abap_unit_assert=>assert_equals( exp = 'D' act = get_field( 'DEPARTURE_DATE' )-inttype ). + cl_abap_unit_assert=>assert_equals( exp = 8 act = get_field( 'DEPARTURE_DATE' )-leng ). + cl_abap_unit_assert=>assert_equals( exp = 'I' act = get_field( 'PERSONS' )-inttype ). + ENDMETHOD. + + METHOD rate_decimals. + cl_abap_unit_assert=>assert_equals( exp = 'P' act = get_field( 'RATE_PER_NIGHT' )-inttype ). + cl_abap_unit_assert=>assert_equals( exp = 9 act = get_field( 'RATE_PER_NIGHT' )-leng ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = get_field( 'RATE_PER_NIGHT' )-decimals ). + ENDMETHOD. + + METHOD insert_and_read. + DATA lt_rows TYPE STANDARD TABLE OF {{p}}pitch WITH EMPTY KEY. + lt_rows = VALUE #( + ( client = sy-mandt booking_id = 'B0001' pitch_no = '0001' guest_name = 'MUELLER' + arrival_date = '20250601' departure_date = '20250608' persons = 4 + power_hookup = 'X' rate_per_night = '12.50' ) ). + INSERT {{p}}pitch FROM TABLE @lt_rows. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + SELECT SINGLE guest_name, pitch_no, persons, power_hookup, departure_date, rate_per_night + FROM {{p}}pitch WHERE booking_id = 'B0001' INTO @DATA(ls_row). + cl_abap_unit_assert=>assert_equals( exp = 'MUELLER' act = ls_row-guest_name ). + cl_abap_unit_assert=>assert_equals( exp = '0001' act = ls_row-pitch_no ). + cl_abap_unit_assert=>assert_equals( exp = 4 act = ls_row-persons ). + cl_abap_unit_assert=>assert_equals( exp = 'X' act = ls_row-power_hookup ). + cl_abap_unit_assert=>assert_equals( exp = '20250608' act = ls_row-departure_date ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '12.50' ) + act = CONV decfloat34( ls_row-rate_per_night ) ). + ENDMETHOD. + + METHOD multiple_rows_stored. + DATA lt_rows TYPE STANDARD TABLE OF {{p}}pitch WITH EMPTY KEY. + lt_rows = VALUE #( + ( client = sy-mandt booking_id = 'C0001' pitch_no = '0003' arrival_date = '20250601' + departure_date = '20250602' persons = 1 rate_per_night = '9.00' ) + ( client = sy-mandt booking_id = 'C0002' pitch_no = '0004' arrival_date = '20250601' + departure_date = '20250602' persons = 2 rate_per_night = '9.00' ) + ( client = sy-mandt booking_id = 'C0003' pitch_no = '0005' arrival_date = '20250601' + departure_date = '20250602' persons = 3 rate_per_night = '9.00' ) ). + INSERT {{p}}pitch FROM TABLE @lt_rows. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + SELECT COUNT(*) FROM {{p}}pitch INTO @DATA(lv_count). + cl_abap_unit_assert=>assert_equals( exp = 3 act = lv_count ). + ENDMETHOD. + + METHOD numc_keeps_leading_zeros. + DATA lt_rows TYPE STANDARD TABLE OF {{p}}pitch WITH EMPTY KEY. + lt_rows = VALUE #( + ( client = sy-mandt booking_id = 'D0001' pitch_no = '0123' arrival_date = '20250601' + departure_date = '20250602' persons = 2 rate_per_night = '10.00' ) ). + INSERT {{p}}pitch FROM TABLE @lt_rows. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + SELECT SINGLE pitch_no FROM {{p}}pitch WHERE booking_id = 'D0001' INTO @DATA(lv_pitch). + cl_abap_unit_assert=>assert_equals( exp = '0123' act = lv_pitch ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1934/mutation.json b/tasks_gen/train/G1934/mutation.json new file mode 100644 index 0000000..89b1146 --- /dev/null +++ b/tasks_gen/train/G1934/mutation.json @@ -0,0 +1,55 @@ +{ + "task": "G1934", + "mutants": [ + { + "object": "{{P}}PITCH", + "mutant": "line 8: key booking_id : -> booking_id : (key)", + "status": "killed", + "hidden": "6/8", + "failed_tests": [ + "KEY_FIELDS", + "MULTIPLE_ROWS_STORED" + ] + }, + { + "object": "{{P}}PITCH", + "mutant": "line 8: abap.char(10) -> abap.char(9) (length)", + "status": "killed", + "hidden": "7/8", + "failed_tests": [ + "TEXT_LENGTHS" + ] + }, + { + "object": "{{P}}PITCH", + "mutant": "line 11: abap.dats -> abap.tims (type)", + "status": "killed", + "hidden": "7/8", + "failed_tests": [ + "DATE_AND_COUNT_TYPES" + ] + }, + { + "object": "{{P}}PITCH", + "mutant": "line 13: abap.int4 -> abap.int8 (type)", + "status": "killed", + "hidden": "7/8", + "failed_tests": [ + "DATE_AND_COUNT_TYPES" + ] + }, + { + "object": "{{P}}PITCH", + "mutant": "line 15: abap.dec(9,2) -> abap.dec(9,3) (decimals)", + "status": "killed", + "hidden": "7/8", + "failed_tests": [ + "RATE_DECIMALS" + ] + } + ], + "valid": 5, + "killed": 5, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1934/reference/pitch.tabl.asabap b/tasks_gen/train/G1934/reference/pitch.tabl.asabap new file mode 100644 index 0000000..6bd8aae --- /dev/null +++ b/tasks_gen/train/G1934/reference/pitch.tabl.asabap @@ -0,0 +1,16 @@ +@EndUserText.label : 'Campsite pitch booking' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}pitch { + key client : abap.clnt not null; + key booking_id : abap.char(10) not null; + pitch_no : abap.numc(4); + guest_name : abap.char(30); + arrival_date : abap.dats; + departure_date : abap.dats; + persons : abap.int4; + power_hookup : abap.char(1); + rate_per_night : abap.dec(9,2); +} diff --git a/tasks_gen/train/G1934/reference/t16_test.clas.abap b/tasks_gen/train/G1934/reference/t16_test.clas.abap new file mode 100644 index 0000000..f8824d1 --- /dev/null +++ b/tasks_gen/train/G1934/reference/t16_test.clas.abap @@ -0,0 +1,83 @@ +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_osql_test_environment. + + CLASS-METHODS class_setup. + CLASS-METHODS class_teardown. + METHODS setup. + + METHODS structure_is_correct FOR TESTING. + METHODS booking_is_stored FOR TESTING. + METHODS two_bookings_are_stored FOR TESTING. + METHODS rate_keeps_decimals FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t16_test IMPLEMENTATION. + + METHOD class_setup. + go_env = cl_osql_test_environment=>create( i_dependency_list = VALUE #( ( '{{P}}PITCH' ) ) ). + ENDMETHOD. + + METHOD class_teardown. + IF go_env IS BOUND. + go_env->destroy( ). + ENDIF. + ENDMETHOD. + + METHOD setup. + go_env->clear_doubles( ). + ENDMETHOD. + + METHOD structure_is_correct. + DATA(lo_struct) = CAST cl_abap_structdescr( cl_abap_typedescr=>describe_by_name( '{{P}}PITCH' ) ). + DATA(lt_fields) = lo_struct->get_ddic_field_list( ). + cl_abap_unit_assert=>assert_equals( exp = 9 act = lines( lt_fields ) ). + READ TABLE lt_fields INTO DATA(ls_field) WITH KEY fieldname = 'BOOKING_ID'. + cl_abap_unit_assert=>assert_equals( exp = 0 act = sy-subrc ). + cl_abap_unit_assert=>assert_equals( exp = 'X' act = ls_field-keyflag ). + cl_abap_unit_assert=>assert_equals( exp = 10 act = ls_field-leng ). + ENDMETHOD. + + METHOD booking_is_stored. + DATA lt_rows TYPE STANDARD TABLE OF {{p}}pitch WITH EMPTY KEY. + lt_rows = VALUE #( + ( client = sy-mandt booking_id = 'T0001' pitch_no = '0007' guest_name = 'WEBER' + arrival_date = '20250701' departure_date = '20250705' persons = 3 + power_hookup = 'X' rate_per_night = '15.00' ) ). + INSERT {{p}}pitch FROM TABLE @lt_rows. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + SELECT SINGLE guest_name, pitch_no, persons FROM {{p}}pitch + WHERE booking_id = 'T0001' INTO @DATA(ls_row). + cl_abap_unit_assert=>assert_equals( exp = 'WEBER' act = ls_row-guest_name ). + cl_abap_unit_assert=>assert_equals( exp = '0007' act = ls_row-pitch_no ). + cl_abap_unit_assert=>assert_equals( exp = 3 act = ls_row-persons ). + ENDMETHOD. + + METHOD two_bookings_are_stored. + DATA lt_rows TYPE STANDARD TABLE OF {{p}}pitch WITH EMPTY KEY. + lt_rows = VALUE #( + ( client = sy-mandt booking_id = 'T0002' pitch_no = '0008' arrival_date = '20250701' + departure_date = '20250705' persons = 2 rate_per_night = '15.00' ) + ( client = sy-mandt booking_id = 'T0003' pitch_no = '0009' arrival_date = '20250701' + departure_date = '20250703' persons = 1 rate_per_night = '12.00' ) ). + INSERT {{p}}pitch FROM TABLE @lt_rows. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + SELECT COUNT(*) FROM {{p}}pitch INTO @DATA(lv_count). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lv_count ). + ENDMETHOD. + + METHOD rate_keeps_decimals. + DATA lt_rows TYPE STANDARD TABLE OF {{p}}pitch WITH EMPTY KEY. + lt_rows = VALUE #( + ( client = sy-mandt booking_id = 'T0004' pitch_no = '0010' arrival_date = '20250701' + departure_date = '20250705' persons = 1 rate_per_night = '12.34' ) ). + INSERT {{p}}pitch FROM TABLE @lt_rows. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + SELECT SINGLE rate_per_night FROM {{p}}pitch WHERE booking_id = 'T0004' INTO @DATA(lv_rate). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '12.34' ) + act = CONV decfloat34( lv_rate ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1934/spec.md b/tasks_gen/train/G1934/spec.md new file mode 100644 index 0000000..c3a9c9b --- /dev/null +++ b/tasks_gen/train/G1934/spec.md @@ -0,0 +1,50 @@ +# 1. Goal +The campsite "Lakeside" must store the bookings of its pitches in a database +table. The reception desk, a nightly list and an OData service read this table, +so the structure of the table must be fixed. + +# 2. Open questions +None. + +# 3. Context +- The campsite rents numbered pitches to guests. +- A booking has a booking number. A booking number occurs only once. +- The campsite runs in one client. The table is client-dependent. + +# 4. Contract +- Create the transparent table {{P}}PITCH in package $TMP. +- Fields: + - client (abap.clnt): the client. Key field. + - booking_id (abap.char(10)): the booking number. Key field. + - pitch_no (abap.numc(4)): the number of the rented pitch. + - guest_name (abap.char(30)): the name of the guest. + - arrival_date (abap.dats): the first night of the stay. + - departure_date (abap.dats): the day of departure. + - persons (abap.int4): the number of persons. + - power_hookup (abap.char(1)): 'X' when a power hookup is booked. + - rate_per_night (abap.dec(9,2)): the price for one night. + +# 5. Business rules +1. One row of the table is one booking. The key of the table is client and + booking_id. A booking number occurs only once. +2. booking_id has 10 characters. +3. pitch_no has 4 characters. The characters are digits. +4. guest_name has 30 characters. +5. arrival_date and departure_date are dates. arrival_date is the first night + of the stay. departure_date is the day of departure. +6. persons is a whole number. +7. power_hookup has 1 character. The value is 'X' when the guest booked a power + hookup. Otherwise the value is empty. +8. rate_per_night has 9 digits and 2 decimals. It is the price for one night. +9. The table has exactly these 9 fields. + +# 6. Constraints +- Release target: SAP_BASIS 816 (ABAP Platform 2025). +- Use Clean ABAP. +- Out of scope: no other objects. + +# 7. Acceptance +- The table {{P}}PITCH is active and has no syntax error. +- The hidden tests pass. +- Write ABAP Unit tests in a global test class. Use CL_OSQL_TEST_ENVIRONMENT + for the database access. diff --git a/tasks_gen/train/G1934/task.json b/tasks_gen/train/G1934/task.json new file mode 100644 index 0000000..c10b88e --- /dev/null +++ b/tasks_gen/train/G1934/task.json @@ -0,0 +1,54 @@ +{ + "id": "G1934", + "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}}PITCH", + "fields": [ + "client", + "booking_id", + "pitch_no", + "guest_name", + "arrival_date", + "departure_date", + "persons", + "power_hookup", + "rate_per_night" + ] + } + ], + "out_of_scope": [], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T16_HIDDEN", + "file": "hidden/t16_hidden.clas.abap", + "description": "Checks the structure of {{P}}PITCH with RTTI and the database access with CL_OSQL_TEST_ENVIRONMENT" + } + ], + "reference": [ + { + "type": "TABL", + "name": "{{P}}PITCH", + "file": "reference/pitch.tabl.asabap", + "description": "Campsite pitch bookings" + }, + { + "type": "CLAS", + "name": "{{P}}T16_TEST", + "file": "reference/t16_test.clas.abap", + "description": "Own tests for {{P}}PITCH" + } + ], + "craft_checks": [] +} \ No newline at end of file diff --git a/tasks_gen/train/G1935/generation.json b/tasks_gen/train/G1935/generation.json new file mode 100644 index 0000000..2d4988e --- /dev/null +++ b/tasks_gen/train/G1935/generation.json @@ -0,0 +1,43 @@ +{ + "id": "G1935", + "pool": "train", + "object_type": "INTF", + "category": "A", + "attempts": [ + { + "stage": "bundle", + "errors": [ + "hidden/t02_hidden.clas.abap line 45: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"", + "Too close to task G1125 (similarity spec 0.51, rules 0.62, names 0.00). Choose a different business topic and different object names." + ], + "by_check": { + "abaplint": 1, + "extra": 1 + } + }, + { + "stage": "bundle", + "errors": [ + "reference/if_concrete_mix.intf.abap line 91: 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": "bundle", + "errors": [ + "reference/mix_calc.clas.abap line 49: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"ASSIGN\"" + ], + "by_check": { + "abaplint": 1 + } + } + ], + "accepted": false +} \ No newline at end of file diff --git a/tasks_gen/train/G1935/hidden/t02_hidden.clas.abap b/tasks_gen/train/G1935/hidden/t02_hidden.clas.abap new file mode 100644 index 0000000..aa66a93 --- /dev/null +++ b/tasks_gen/train/G1935/hidden/t02_hidden.clas.abap @@ -0,0 +1,241 @@ +CLASS {{p}}t02_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + DATA mo_cut TYPE REF TO {{p}}if_mix_recipe. + METHODS setup. + METHODS constants_are_fixed FOR TESTING. + METHODS type_lengths_are_fixed FOR TESTING. + METHODS check_accepts_order FOR TESTING. + METHODS check_rejects_grade FOR TESTING. + METHODS check_rejects_volume FOR TESTING. + METHODS check_grade_before_volume FOR TESTING. + METHODS mix_without_surcharge FOR TESTING. + METHODS mix_with_surcharge FOR TESTING. + METHODS mix_at_min_volume FOR TESTING. + METHODS mix_grade_is_upper FOR TESTING. + METHODS mix_of_invalid_order FOR TESTING. +ENDCLASS. + +CLASS ltc_mix DEFINITION FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_mix_recipe. +ENDCLASS. + +CLASS ltc_mix IMPLEMENTATION. +ENDCLASS. + + +CLASS {{p}}t02_hidden IMPLEMENTATION. + METHOD setup. + mo_cut = NEW ltc_mix( ). + ENDMETHOD. + + METHOD constants_are_fixed. + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_grade( 'C20' ) + act = {{p}}if_mix_recipe=>c_grade-c20 ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_grade( 'C25' ) + act = {{p}}if_mix_recipe=>c_grade-c25 ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_grade( 'C30' ) + act = {{p}}if_mix_recipe=>c_grade-c30 ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_grade( 'C35' ) + act = {{p}}if_mix_recipe=>c_grade-c35 ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_status( 'OK' ) + act = {{p}}if_mix_recipe=>c_status-ok ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_status( 'GRADE' ) + act = {{p}}if_mix_recipe=>c_status-grade ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_status( 'VOLUME' ) + act = {{p}}if_mix_recipe=>c_status-volume ). + ENDMETHOD. + + METHOD type_lengths_are_fixed. + DATA(lo_grade) = cl_abap_typedescr=>describe_by_name( '{{P}}IF_MIX_RECIPE=>TY_GRADE' ). + cl_abap_unit_assert=>assert_equals( exp = 4 act = lo_grade->length ). + DATA(lo_status) = cl_abap_typedescr=>describe_by_name( '{{P}}IF_MIX_RECIPE=>TY_STATUS' ). + cl_abap_unit_assert=>assert_equals( exp = 10 act = lo_status->length ). + DATA(lo_qty) = cl_abap_typedescr=>describe_by_name( '{{P}}IF_MIX_RECIPE=>TY_QTY' ). + cl_abap_unit_assert=>assert_equals( exp = 8 act = lo_qty->length ). + DATA(lo_elem) = CAST cl_abap_elemdescr( lo_qty ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lo_elem->decimals ). + ENDMETHOD. + + METHOD check_accepts_order. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_mix_recipe=>c_status-ok + act = mo_cut->check_order( iv_grade = 'C20' iv_volume = '2.50' ) ). + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_mix_recipe=>c_status-ok + act = mo_cut->check_order( iv_grade = 'c35' iv_volume = '20.00' ) ). + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_mix_recipe=>c_status-ok + act = mo_cut->check_order( iv_grade = 'C30' iv_volume = '0.50' ) ). + ENDMETHOD. + + METHOD check_rejects_grade. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_mix_recipe=>c_status-grade + act = mo_cut->check_order( iv_grade = 'C40' iv_volume = '5.00' ) ). + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_mix_recipe=>c_status-grade + act = mo_cut->check_order( iv_grade = ' ' iv_volume = '5.00' ) ). + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_mix_recipe=>c_status-grade + act = mo_cut->check_order( iv_grade = 'C2' iv_volume = '5.00' ) ). + ENDMETHOD. + + METHOD check_rejects_volume. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_mix_recipe=>c_status-volume + act = mo_cut->check_order( iv_grade = 'C20' iv_volume = '0.49' ) ). + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_mix_recipe=>c_status-volume + act = mo_cut->check_order( iv_grade = 'C20' iv_volume = '20.01' ) ). + ENDMETHOD. + + METHOD check_grade_before_volume. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_mix_recipe=>c_status-grade + act = mo_cut->check_order( iv_grade = 'C40' iv_volume = '0.10' ) ). + ENDMETHOD. + + METHOD mix_without_surcharge. + DATA(ls_mix) = mo_cut->mix_for( iv_grade = 'C20' iv_volume = '2.50' ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '700.00' ) + act = ls_mix-cement_kg ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '1800.00' ) + act = ls_mix-sand_kg ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '2950.00' ) + act = ls_mix-gravel_kg ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '438.00' ) + act = ls_mix-water_l ). + + DATA(ls_large) = mo_cut->mix_for( iv_grade = 'C30' iv_volume = '5.00' ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '1800.00' ) + act = ls_large-cement_kg ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '3400.00' ) + act = ls_large-sand_kg ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '5700.00' ) + act = ls_large-gravel_kg ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '850.00' ) + act = ls_large-water_l ). + ENDMETHOD. + + METHOD mix_with_surcharge. + DATA(ls_small) = mo_cut->mix_for( iv_grade = 'C25' iv_volume = '1.30' ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '458.00' ) + act = ls_small-cement_kg ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '1001.00' ) + act = ls_small-sand_kg ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '1659.00' ) + act = ls_small-gravel_kg ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '251.00' ) + act = ls_small-water_l ). + + DATA(ls_tiny) = mo_cut->mix_for( iv_grade = 'C35' iv_volume = '0.80' ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '352.00' ) + act = ls_tiny-cement_kg ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '581.00' ) + act = ls_tiny-sand_kg ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '986.00' ) + act = ls_tiny-gravel_kg ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '146.00' ) + act = ls_tiny-water_l ). + ENDMETHOD. + + METHOD mix_at_min_volume. + DATA(ls_min) = mo_cut->mix_for( iv_grade = 'C25' iv_volume = '0.50' ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '176.00' ) + act = ls_min-cement_kg ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '385.00' ) + act = ls_min-sand_kg ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '638.00' ) + act = ls_min-gravel_kg ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '97.00' ) + act = ls_min-water_l ). + + DATA(ls_limit) = mo_cut->mix_for( iv_grade = 'C20' iv_volume = '2.00' ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '560.00' ) + act = ls_limit-cement_kg ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '1440.00' ) + act = ls_limit-sand_kg ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '2360.00' ) + act = ls_limit-gravel_kg ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '350.00' ) + act = ls_limit-water_l ). + ENDMETHOD. + + METHOD mix_grade_is_upper. + DATA(ls_mix) = mo_cut->mix_for( iv_grade = 'c35' iv_volume = '5.00' ). + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_mix_recipe=>c_grade-c35 + act = ls_mix-grade ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '2000.00' ) + act = ls_mix-cement_kg ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '3300.00' ) + act = ls_mix-sand_kg ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '5600.00' ) + act = ls_mix-gravel_kg ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '825.00' ) + act = ls_mix-water_l ). + ENDMETHOD. + + METHOD mix_of_invalid_order. + DATA(ls_bad_grade) = mo_cut->mix_for( iv_grade = 'C40' iv_volume = '5.00' ). + cl_abap_unit_assert=>assert_initial( act = ls_bad_grade-grade ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '0.00' ) + act = ls_bad_grade-cement_kg ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '0.00' ) + act = ls_bad_grade-sand_kg ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '0.00' ) + act = ls_bad_grade-gravel_kg ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '0.00' ) + act = ls_bad_grade-water_l ). + + DATA(ls_bad_volume) = mo_cut->mix_for( iv_grade = 'C20' iv_volume = '0.10' ). + cl_abap_unit_assert=>assert_initial( act = ls_bad_volume-grade ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '0.00' ) + act = ls_bad_volume-cement_kg ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '0.00' ) + act = ls_bad_volume-water_l ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1935/reference/if_mix_recipe.intf.abap b/tasks_gen/train/G1935/reference/if_mix_recipe.intf.abap new file mode 100644 index 0000000..9869fed --- /dev/null +++ b/tasks_gen/train/G1935/reference/if_mix_recipe.intf.abap @@ -0,0 +1,107 @@ +INTERFACE {{p}}if_mix_recipe PUBLIC. + TYPES ty_grade TYPE c LENGTH 4. + TYPES ty_qty TYPE p LENGTH 8 DECIMALS 2. + TYPES ty_status TYPE c LENGTH 10. + TYPES: + BEGIN OF ty_mix, + grade TYPE ty_grade, + cement_kg TYPE ty_qty, + sand_kg TYPE ty_qty, + gravel_kg TYPE ty_qty, + water_l TYPE ty_qty, + END OF ty_mix. + + CONSTANTS: + BEGIN OF c_grade, + c20 TYPE ty_grade VALUE 'C20', + c25 TYPE ty_grade VALUE 'C25', + c30 TYPE ty_grade VALUE 'C30', + c35 TYPE ty_grade VALUE 'C35', + END OF c_grade, + BEGIN OF c_status, + ok TYPE ty_status VALUE 'OK', + grade TYPE ty_status VALUE 'GRADE', + volume TYPE ty_status VALUE 'VOLUME', + END OF c_status. + + METHODS check_order + IMPORTING iv_grade TYPE ty_grade + iv_volume TYPE ty_qty + RETURNING VALUE(rv_status) TYPE ty_status. + + METHODS mix_for + IMPORTING iv_grade TYPE ty_grade + iv_volume TYPE ty_qty + RETURNING VALUE(rs_mix) TYPE ty_mix. +ENDINTERFACE. + + +INTERFACE {{p}}if_mix_recipe. + METHOD check_order. + DATA lv_grade TYPE ty_grade. + lv_grade = to_upper( iv_grade ). + IF lv_grade <> c_grade-c20 + AND lv_grade <> c_grade-c25 + AND lv_grade <> c_grade-c30 + AND lv_grade <> c_grade-c35. + rv_status = c_status-grade. + RETURN. + ENDIF. + IF iv_volume < '0.50' OR iv_volume > '20.00'. + rv_status = c_status-volume. + RETURN. + ENDIF. + rv_status = c_status-ok. + ENDMETHOD. + + METHOD mix_for. + IF check_order( iv_grade = iv_grade iv_volume = iv_volume ) <> c_status-ok. + RETURN. + ENDIF. + + DATA lv_grade TYPE ty_grade. + lv_grade = to_upper( iv_grade ). + + DATA lv_cement TYPE ty_qty. + DATA lv_sand TYPE ty_qty. + DATA lv_gravel TYPE ty_qty. + DATA lv_water TYPE ty_qty. + + CASE lv_grade. + WHEN c_grade-c20. + lv_cement = '280.00'. + lv_sand = '720.00'. + lv_gravel = '1180.00'. + lv_water = '175.00'. + WHEN c_grade-c25. + lv_cement = '320.00'. + lv_sand = '700.00'. + lv_gravel = '1160.00'. + lv_water = '175.00'. + WHEN c_grade-c30. + lv_cement = '360.00'. + lv_sand = '680.00'. + lv_gravel = '1140.00'. + lv_water = '170.00'. + WHEN c_grade-c35. + lv_cement = '400.00'. + lv_sand = '660.00'. + lv_gravel = '1120.00'. + lv_water = '165.00'. + WHEN OTHERS. + RETURN. + ENDCASE. + + DATA lv_factor TYPE ty_qty. + lv_factor = '1.00'. + IF iv_volume < '2.00'. + lv_factor = '1.10'. + ENDIF. + + rs_mix-grade = lv_grade. + rs_mix-cement_kg = ceil( lv_cement * iv_volume * lv_factor ). + rs_mix-sand_kg = ceil( lv_sand * iv_volume * lv_factor ). + rs_mix-gravel_kg = ceil( lv_gravel * iv_volume * lv_factor ). + rs_mix-water_l = ceil( lv_water * iv_volume * lv_factor ). + ENDMETHOD. +ENDINTERFACE. diff --git a/tasks_gen/train/G1935/reference/mix_recipe_test.clas.abap b/tasks_gen/train/G1935/reference/mix_recipe_test.clas.abap new file mode 100644 index 0000000..b094711 --- /dev/null +++ b/tasks_gen/train/G1935/reference/mix_recipe_test.clas.abap @@ -0,0 +1,82 @@ +CLASS {{p}}mix_recipe_test DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PUBLIC SECTION. + INTERFACES {{p}}if_mix_recipe. + PRIVATE SECTION. + DATA mo_cut TYPE REF TO {{p}}if_mix_recipe. + METHODS setup. + METHODS valid_order_is_ok FOR TESTING. + METHODS unknown_grade_is_rejected FOR TESTING. + METHODS volume_out_of_range FOR TESTING. + METHODS mix_of_small_order FOR TESTING. + METHODS mix_of_large_order FOR TESTING. + METHODS invalid_order_has_no_mix FOR TESTING. +ENDCLASS. + + +CLASS {{p}}mix_recipe_test IMPLEMENTATION. + METHOD setup. + mo_cut = me. + ENDMETHOD. + + METHOD valid_order_is_ok. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_mix_recipe=>c_status-ok + act = mo_cut->check_order( iv_grade = 'C25' iv_volume = '1.30' ) ). + ENDMETHOD. + + METHOD unknown_grade_is_rejected. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_mix_recipe=>c_status-grade + act = mo_cut->check_order( iv_grade = 'C40' iv_volume = '5.00' ) ). + ENDMETHOD. + + METHOD volume_out_of_range. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_mix_recipe=>c_status-volume + act = mo_cut->check_order( iv_grade = 'C20' iv_volume = '25.00' ) ). + ENDMETHOD. + + METHOD mix_of_small_order. + DATA(ls_mix) = mo_cut->mix_for( iv_grade = 'C25' iv_volume = '1.30' ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '458.00' ) + act = ls_mix-cement_kg ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '1001.00' ) + act = ls_mix-sand_kg ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '1659.00' ) + act = ls_mix-gravel_kg ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '251.00' ) + act = ls_mix-water_l ). + ENDMETHOD. + + METHOD mix_of_large_order. + DATA(ls_mix) = mo_cut->mix_for( iv_grade = 'C35' iv_volume = '5.00' ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '2000.00' ) + act = ls_mix-cement_kg ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '3300.00' ) + act = ls_mix-sand_kg ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '5600.00' ) + act = ls_mix-gravel_kg ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '825.00' ) + act = ls_mix-water_l ). + ENDMETHOD. + + METHOD invalid_order_has_no_mix. + DATA(ls_mix) = mo_cut->mix_for( iv_grade = 'C40' iv_volume = '5.00' ). + cl_abap_unit_assert=>assert_initial( act = ls_mix-grade ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '0.00' ) + act = ls_mix-cement_kg ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_mix_recipe=>ty_qty( '0.00' ) + act = ls_mix-water_l ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1935/spec.md b/tasks_gen/train/G1935/spec.md new file mode 100644 index 0000000..4a36be9 --- /dev/null +++ b/tasks_gen/train/G1935/spec.md @@ -0,0 +1,81 @@ +# 1. Goal +A ready-mix concrete plant supplies building sites. The plant office needs the +quantities of cement, sand, gravel and water for each order. The order desk, the +plant control system and the delivery note must use the same calculation. Create +one interface that holds this calculation. + +# 2. Open questions +None. + +# 3. Context +- One order has a concrete grade and a volume in cubic metres. +- The plant supplies the grades C20, C25, C30 and C35. +- Create the interface {{P}}IF_MIX_RECIPE in package $TMP. +- The interface holds the types, the constants and the methods of section 4. +- The interface contains the logic of section 5. A class that implements the + interface and does not redefine the methods must get the results of section 5. + +# 4. Contract +Interface {{P}}IF_MIX_RECIPE in package $TMP. + +Types: +- TY_GRADE TYPE c LENGTH 4 +- TY_QTY TYPE p LENGTH 8 DECIMALS 2 +- TY_STATUS TYPE c LENGTH 10 +- TY_MIX: a structure with the components GRADE (TY_GRADE), CEMENT_KG, SAND_KG, + GRAVEL_KG and WATER_L (each TY_QTY). + +Constant structure C_GRADE with the components C20, C25, C30 and C35. Each +component has the type TY_GRADE. The values are 'C20', 'C25', 'C30' and 'C35'. + +Constant structure C_STATUS with the components OK, GRADE and VOLUME. Each +component has the type TY_STATUS. The values are 'OK', 'GRADE' and 'VOLUME'. + +Method CHECK_ORDER: + IMPORTING iv_grade TYPE ty_grade + iv_volume TYPE ty_qty + RETURNING VALUE(rv_status) TYPE ty_status + +Method MIX_FOR: + IMPORTING iv_grade TYPE ty_grade + iv_volume TYPE ty_qty + RETURNING VALUE(rs_mix) TYPE ty_mix + +Do not add other public components to the interface. + +# 5. Business rules +CHECK_ORDER returns the status of the first rule that fails. +1. Compare the grade without regard to case. +2. If the grade is not C20, C25, C30 or C35, return GRADE. +3. If the volume is below 0.50 or above 20.00, return VOLUME. +4. Otherwise return OK. + +MIX_FOR returns the quantities of one order. +1. If CHECK_ORDER does not return OK, the component GRADE is empty and the four + quantities are 0. +2. The quantities for one cubic metre are: + + grade cement sand gravel water + C20 280 720 1180 175 + C25 320 700 1160 175 + C30 360 680 1140 170 + C35 400 660 1120 165 + + The unit of cement, sand and gravel is one kilogram. The unit of water is one + litre. +3. Multiply each quantity by the volume. +4. If the volume is below 2.00, add 10% to each quantity. +5. Round each quantity up to the next full kilogram. Round the water up to the + next full litre. +6. The component GRADE of the result is the grade of the order in upper case. + +# 6. Constraints +- Release target: 7.58. +- Coding standards: Clean ABAP. Method length below 40 statements. No global + variables. No comment that restates the code. +- Out of scope: do not change any other object in package $TMP. + +# 7. Acceptance +- The interface is active and has no syntax error. +- The hidden tests pass. +- Write your own ABAP Unit tests for the interface. diff --git a/tasks_gen/train/G1935/task.json b/tasks_gen/train/G1935/task.json new file mode 100644 index 0000000..5f6e5d1 --- /dev/null +++ b/tasks_gen/train/G1935/task.json @@ -0,0 +1,46 @@ +{ + "id": "G1935", + "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_MIX_RECIPE" + } + ], + "out_of_scope": [], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T02_HIDDEN", + "file": "hidden/t02_hidden.clas.abap", + "description": "Hidden tests for {{P}}IF_MIX_RECIPE: constant values, type lengths, order check and mix quantities." + } + ], + "reference": [ + { + "type": "INTF", + "name": "{{P}}IF_MIX_RECIPE", + "file": "reference/if_mix_recipe.intf.abap", + "description": "Concrete mix interface with the default implementations of CHECK_ORDER and MIX_FOR" + }, + { + "type": "CLAS", + "name": "{{P}}MIX_RECIPE_TEST", + "file": "reference/mix_recipe_test.clas.abap", + "description": "Own ABAP Unit tests for the interface" + } + ], + "craft_checks": [ + "method_length", + "cyclomatic_complexity" + ] +} \ No newline at end of file diff --git a/tasks_gen/train/G1936/faulty/m0_syrup.tabl.asabap b/tasks_gen/train/G1936/faulty/m0_syrup.tabl.asabap new file mode 100644 index 0000000..ef47f04 --- /dev/null +++ b/tasks_gen/train/G1936/faulty/m0_syrup.tabl.asabap @@ -0,0 +1,17 @@ +@EndUserText.label : 'Maple sap delivery' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}syrup { + key client : abap.clnt not null; + delivery_id : abap.char(10) not null; + grove_id : abap.char(8); + delivery_date : abap.dats; + sap_liters : abap.dec(9,2); + brix : abap.dec(4,1); + quality_grade : abap.numc(2); + @Semantics.amount.currencyCode : '{{p}}syrup.currency_code' + payout : abap.curr(15,2); + currency_code : abap.cuky; +} diff --git a/tasks_gen/train/G1936/faulty/m2_syrup.tabl.asabap b/tasks_gen/train/G1936/faulty/m2_syrup.tabl.asabap new file mode 100644 index 0000000..04ace88 --- /dev/null +++ b/tasks_gen/train/G1936/faulty/m2_syrup.tabl.asabap @@ -0,0 +1,17 @@ +@EndUserText.label : 'Maple sap delivery' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}syrup { + key client : abap.clnt not null; + key delivery_id : abap.char(10) not null; + grove_id : abap.char(7); + delivery_date : abap.dats; + sap_liters : abap.dec(9,2); + brix : abap.dec(4,1); + quality_grade : abap.numc(2); + @Semantics.amount.currencyCode : '{{p}}syrup.currency_code' + payout : abap.curr(15,2); + currency_code : abap.cuky; +} diff --git a/tasks_gen/train/G1936/faulty/m3_syrup.tabl.asabap b/tasks_gen/train/G1936/faulty/m3_syrup.tabl.asabap new file mode 100644 index 0000000..e874b89 --- /dev/null +++ b/tasks_gen/train/G1936/faulty/m3_syrup.tabl.asabap @@ -0,0 +1,17 @@ +@EndUserText.label : 'Maple sap delivery' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}syrup { + key client : abap.clnt not null; + key delivery_id : abap.char(10) not null; + grove_id : abap.char(8); + delivery_date : abap.dats; + sap_liters : abap.dec(9,2); + brix : abap.dec(4,2); + quality_grade : abap.numc(2); + @Semantics.amount.currencyCode : '{{p}}syrup.currency_code' + payout : abap.curr(15,2); + currency_code : abap.cuky; +} diff --git a/tasks_gen/train/G1936/faulty/m4_syrup.tabl.asabap b/tasks_gen/train/G1936/faulty/m4_syrup.tabl.asabap new file mode 100644 index 0000000..4303de4 --- /dev/null +++ b/tasks_gen/train/G1936/faulty/m4_syrup.tabl.asabap @@ -0,0 +1,17 @@ +@EndUserText.label : 'Maple sap delivery' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}syrup { + key client : abap.clnt not null; + key delivery_id : abap.char(10) not null; + grove_id : abap.char(8); + delivery_date : abap.dats; + sap_liters : abap.dec(9,2); + brix : abap.dec(4,1); + quality_grade : abap.numc(1); + @Semantics.amount.currencyCode : '{{p}}syrup.currency_code' + payout : abap.curr(15,2); + currency_code : abap.cuky; +} diff --git a/tasks_gen/train/G1936/generation.json b/tasks_gen/train/G1936/generation.json new file mode 100644 index 0000000..79ad658 --- /dev/null +++ b/tasks_gen/train/G1936/generation.json @@ -0,0 +1,19 @@ +{ + "id": "G1936", + "pool": "train", + "object_type": "TABL", + "category": "B", + "attempts": [ + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 4, + "killed": 4, + "ok": true + } + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1936/hidden/syrup_hidden.clas.abap b/tasks_gen/train/G1936/hidden/syrup_hidden.clas.abap new file mode 100644 index 0000000..8d9286e --- /dev/null +++ b/tasks_gen/train/G1936/hidden/syrup_hidden.clas.abap @@ -0,0 +1,183 @@ +CLASS {{p}}syrup_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + + PRIVATE SECTION. + TYPES ty_fields TYPE dfies_table. + + CLASS-DATA go_env TYPE REF TO if_osql_test_environment. + + CLASS-METHODS class_setup. + CLASS-METHODS class_teardown. + METHODS setup. + + METHODS all_fields_exist FOR TESTING. + METHODS field_types FOR TESTING. + METHODS key_structure FOR TESTING. + METHODS insert_and_read FOR TESTING. + METHODS amount_round_trip FOR TESTING. + METHODS duplicate_key FOR TESTING. + METHODS filter_by_delivery FOR TESTING. + + METHODS get_fields + RETURNING VALUE(rt_fields) TYPE ty_fields. + + METHODS assert_type + IMPORTING + it_fields TYPE ty_fields + iv_name TYPE fieldname + iv_type TYPE datatype_d + iv_leng TYPE i + iv_dec TYPE i. + + METHODS assert_key + IMPORTING + it_fields TYPE ty_fields + iv_name TYPE fieldname + iv_key TYPE flag. + + METHODS make_row + IMPORTING + iv_id TYPE {{p}}syrup-delivery_id + iv_grove TYPE {{p}}syrup-grove_id + RETURNING + VALUE(rs_row) TYPE {{p}}syrup. +ENDCLASS. + + +CLASS {{p}}syrup_hidden IMPLEMENTATION. + + METHOD class_setup. + go_env = cl_osql_test_environment=>create( i_dependency_list = VALUE #( ( '{{P}}SYRUP' ) ) ). + 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}}SYRUP' ) ). + rt_fields = lo_struct->get_ddic_field_list( ). + ENDMETHOD. + + METHOD assert_type. + READ TABLE it_fields ASSIGNING FIELD-SYMBOL() WITH KEY fieldname = iv_name. + cl_abap_unit_assert=>assert_subrc( exp = 0 msg = |Field { iv_name } is missing| ). + DATA lv_leng TYPE i. + lv_leng = -leng. + DATA lv_dec TYPE i. + lv_dec = -decimals. + cl_abap_unit_assert=>assert_equals( exp = iv_type act = -datatype msg = |Data type of { iv_name }| ). + cl_abap_unit_assert=>assert_equals( exp = iv_leng act = lv_leng msg = |Length of { iv_name }| ). + cl_abap_unit_assert=>assert_equals( exp = iv_dec act = lv_dec msg = |Decimals of { iv_name }| ). + ENDMETHOD. + + METHOD assert_key. + READ TABLE it_fields ASSIGNING FIELD-SYMBOL() WITH KEY fieldname = iv_name. + cl_abap_unit_assert=>assert_subrc( exp = 0 msg = |Field { iv_name } is missing| ). + cl_abap_unit_assert=>assert_equals( exp = iv_key act = -keyflag msg = |Key flag of { iv_name }| ). + ENDMETHOD. + + METHOD make_row. + rs_row-client = sy-mandt. + rs_row-delivery_id = iv_id. + rs_row-grove_id = iv_grove. + rs_row-delivery_date = '20250210'. + rs_row-sap_liters = '120.50'. + rs_row-brix = '3.5'. + rs_row-quality_grade = '02'. + rs_row-payout = '250.00'. + rs_row-currency_code = 'EUR'. + ENDMETHOD. + + METHOD all_fields_exist. + DATA(lt_fields) = get_fields( ). + cl_abap_unit_assert=>assert_equals( exp = 9 act = lines( lt_fields ) ). + DATA lt_expected TYPE STANDARD TABLE OF fieldname WITH EMPTY KEY. + lt_expected = VALUE #( ( 'CLIENT' ) ( 'DELIVERY_ID' ) ( 'GROVE_ID' ) + ( 'DELIVERY_DATE' ) ( 'SAP_LITERS' ) ( 'BRIX' ) + ( 'QUALITY_GRADE' ) ( 'PAYOUT' ) ( 'CURRENCY_CODE' ) ). + LOOP AT lt_expected ASSIGNING FIELD-SYMBOL(). + READ TABLE lt_fields TRANSPORTING NO FIELDS WITH KEY fieldname = . + cl_abap_unit_assert=>assert_subrc( exp = 0 msg = |Field { } is missing| ). + ENDLOOP. + ENDMETHOD. + + METHOD field_types. + DATA(lt_fields) = get_fields( ). + assert_type( it_fields = lt_fields iv_name = 'CLIENT' iv_type = 'CLNT' iv_leng = 3 iv_dec = 0 ). + assert_type( it_fields = lt_fields iv_name = 'DELIVERY_ID' iv_type = 'CHAR' iv_leng = 10 iv_dec = 0 ). + assert_type( it_fields = lt_fields iv_name = 'GROVE_ID' iv_type = 'CHAR' iv_leng = 8 iv_dec = 0 ). + assert_type( it_fields = lt_fields iv_name = 'DELIVERY_DATE' iv_type = 'DATS' iv_leng = 8 iv_dec = 0 ). + assert_type( it_fields = lt_fields iv_name = 'SAP_LITERS' iv_type = 'DEC' iv_leng = 9 iv_dec = 2 ). + assert_type( it_fields = lt_fields iv_name = 'BRIX' iv_type = 'DEC' iv_leng = 4 iv_dec = 1 ). + assert_type( it_fields = lt_fields iv_name = 'QUALITY_GRADE' iv_type = 'NUMC' iv_leng = 2 iv_dec = 0 ). + assert_type( it_fields = lt_fields iv_name = 'PAYOUT' iv_type = 'CURR' iv_leng = 15 iv_dec = 2 ). + assert_type( it_fields = lt_fields iv_name = 'CURRENCY_CODE' iv_type = 'CUKY' iv_leng = 5 iv_dec = 0 ). + ENDMETHOD. + + METHOD key_structure. + DATA(lt_fields) = get_fields( ). + assert_key( it_fields = lt_fields iv_name = 'CLIENT' iv_key = 'X' ). + assert_key( it_fields = lt_fields iv_name = 'DELIVERY_ID' iv_key = 'X' ). + assert_key( it_fields = lt_fields iv_name = 'GROVE_ID' iv_key = '' ). + assert_key( it_fields = lt_fields iv_name = 'DELIVERY_DATE' iv_key = '' ). + assert_key( it_fields = lt_fields iv_name = 'SAP_LITERS' iv_key = '' ). + assert_key( it_fields = lt_fields iv_name = 'BRIX' iv_key = '' ). + assert_key( it_fields = lt_fields iv_name = 'QUALITY_GRADE' iv_key = '' ). + assert_key( it_fields = lt_fields iv_name = 'PAYOUT' iv_key = '' ). + assert_key( it_fields = lt_fields iv_name = 'CURRENCY_CODE' iv_key = '' ). + ENDMETHOD. + + METHOD insert_and_read. + DATA(ls_row) = make_row( iv_id = 'D1' iv_grove = 'G1' ). + INSERT {{p}}syrup FROM @ls_row. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + SELECT SINGLE * FROM {{p}}syrup WHERE delivery_id = 'D1' INTO @DATA(ls_read). + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + cl_abap_unit_assert=>assert_equals( exp = 'G1' act = ls_read-grove_id ). + cl_abap_unit_assert=>assert_equals( exp = '20250210' act = ls_read-delivery_date ). + cl_abap_unit_assert=>assert_equals( exp = '02' act = ls_read-quality_grade ). + ENDMETHOD. + + METHOD amount_round_trip. + DATA(ls_row) = make_row( iv_id = 'D3' iv_grove = 'G3' ). + ls_row-sap_liters = '88.25'. + ls_row-payout = '1234.56'. + ls_row-currency_code = 'CHF'. + INSERT {{p}}syrup FROM @ls_row. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + SELECT SINGLE sap_liters, payout, currency_code FROM {{p}}syrup + WHERE delivery_id = 'D3' INTO @DATA(ls_read). + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '88.25' ) + act = CONV decfloat34( ls_read-sap_liters ) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '1234.56' ) + act = CONV decfloat34( ls_read-payout ) ). + cl_abap_unit_assert=>assert_equals( exp = 'CHF' act = ls_read-currency_code ). + ENDMETHOD. + + METHOD duplicate_key. + DATA(ls_row) = make_row( iv_id = 'D7' iv_grove = 'G7' ). + INSERT {{p}}syrup FROM @ls_row. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + INSERT {{p}}syrup FROM @ls_row. + cl_abap_unit_assert=>assert_subrc( exp = 4 ). + ENDMETHOD. + + METHOD filter_by_delivery. + DATA(ls_first) = make_row( iv_id = 'D5' iv_grove = 'G5' ). + INSERT {{p}}syrup FROM @ls_first. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + DATA(ls_second) = make_row( iv_id = 'D6' iv_grove = 'G6' ). + INSERT {{p}}syrup FROM @ls_second. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + SELECT SINGLE grove_id FROM {{p}}syrup WHERE delivery_id = 'D6' INTO @DATA(lv_grove). + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + cl_abap_unit_assert=>assert_equals( exp = 'G6' act = lv_grove ). + ENDMETHOD. + +ENDCLASS. diff --git a/tasks_gen/train/G1936/mutation.json b/tasks_gen/train/G1936/mutation.json new file mode 100644 index 0000000..6e22c4d --- /dev/null +++ b/tasks_gen/train/G1936/mutation.json @@ -0,0 +1,53 @@ +{ + "task": "G1936", + "mutants": [ + { + "object": "{{P}}SYRUP", + "mutant": "line 8: key delivery_id : -> delivery_id : (key)", + "status": "killed", + "hidden": "5/7", + "failed_tests": [ + "FILTER_BY_DELIVERY", + "KEY_STRUCTURE" + ] + }, + { + "object": "{{P}}SYRUP", + "mutant": "line 9: abap.char(8) -> abap.numc(8) (type)", + "status": "invalid", + "hidden": "0/0", + "failed_tests": [] + }, + { + "object": "{{P}}SYRUP", + "mutant": "line 9: abap.char(8) -> abap.char(7) (length)", + "status": "killed", + "hidden": "6/7", + "failed_tests": [ + "FIELD_TYPES" + ] + }, + { + "object": "{{P}}SYRUP", + "mutant": "line 12: abap.dec(4,1) -> abap.dec(4,2) (decimals)", + "status": "killed", + "hidden": "6/7", + "failed_tests": [ + "FIELD_TYPES" + ] + }, + { + "object": "{{P}}SYRUP", + "mutant": "line 13: abap.numc(2) -> abap.numc(1) (length)", + "status": "killed", + "hidden": "6/7", + "failed_tests": [ + "FIELD_TYPES" + ] + } + ], + "valid": 4, + "killed": 4, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1936/reference/syrup.tabl.asabap b/tasks_gen/train/G1936/reference/syrup.tabl.asabap new file mode 100644 index 0000000..923cb78 --- /dev/null +++ b/tasks_gen/train/G1936/reference/syrup.tabl.asabap @@ -0,0 +1,17 @@ +@EndUserText.label : 'Maple sap delivery' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}syrup { + key client : abap.clnt not null; + key delivery_id : abap.char(10) not null; + grove_id : abap.char(8); + delivery_date : abap.dats; + sap_liters : abap.dec(9,2); + brix : abap.dec(4,1); + quality_grade : abap.numc(2); + @Semantics.amount.currencyCode : '{{p}}syrup.currency_code' + payout : abap.curr(15,2); + currency_code : abap.cuky; +} diff --git a/tasks_gen/train/G1936/reference/syrup_test.clas.abap b/tasks_gen/train/G1936/reference/syrup_test.clas.abap new file mode 100644 index 0000000..a8c73a4 --- /dev/null +++ b/tasks_gen/train/G1936/reference/syrup_test.clas.abap @@ -0,0 +1,65 @@ +CLASS {{p}}syrup_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 fields_are_complete FOR TESTING. + METHODS insert_and_select FOR TESTING. + METHODS duplicate_is_rejected FOR TESTING. +ENDCLASS. + + +CLASS {{p}}syrup_test IMPLEMENTATION. + + METHOD class_setup. + go_env = cl_osql_test_environment=>create( i_dependency_list = VALUE #( ( '{{P}}SYRUP' ) ) ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + go_env->clear_doubles( ). + ENDMETHOD. + + METHOD fields_are_complete. + DATA(lo_struct) = CAST cl_abap_structdescr( cl_abap_typedescr=>describe_by_name( '{{P}}SYRUP' ) ). + DATA(lt_fields) = lo_struct->get_ddic_field_list( ). + cl_abap_unit_assert=>assert_equals( exp = 9 act = lines( lt_fields ) ). + ENDMETHOD. + + METHOD insert_and_select. + DATA ls_row TYPE {{p}}syrup. + ls_row-client = sy-mandt. + ls_row-delivery_id = 'A1'. + ls_row-grove_id = 'G1'. + ls_row-delivery_date = '20250301'. + ls_row-sap_liters = '100.00'. + ls_row-brix = '4.0'. + ls_row-quality_grade = '01'. + ls_row-payout = '300.00'. + ls_row-currency_code = 'EUR'. + INSERT {{p}}syrup FROM @ls_row. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + SELECT SINGLE grove_id FROM {{p}}syrup WHERE delivery_id = 'A1' INTO @DATA(lv_grove). + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + cl_abap_unit_assert=>assert_equals( exp = 'G1' act = lv_grove ). + ENDMETHOD. + + METHOD duplicate_is_rejected. + DATA ls_row TYPE {{p}}syrup. + ls_row-client = sy-mandt. + ls_row-delivery_id = 'A2'. + INSERT {{p}}syrup FROM @ls_row. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + INSERT {{p}}syrup FROM @ls_row. + cl_abap_unit_assert=>assert_subrc( exp = 4 ). + ENDMETHOD. + +ENDCLASS. diff --git a/tasks_gen/train/G1936/spec.md b/tasks_gen/train/G1936/spec.md new file mode 100644 index 0000000..e3dac71 --- /dev/null +++ b/tasks_gen/train/G1936/spec.md @@ -0,0 +1,54 @@ +# 1. Goal +A maple syrup farm collects sap from its groves. The farm must store each sap +delivery in one database table. Later programs and views read the deliveries +from this table. + +# 2. Open questions +None. + +# 3. Context +- The farm works with several groves. Each grove has a grove number. +- One delivery belongs to exactly one grove and has exactly one delivery date. +- The farm measures the sap in litres. The farm measures the sugar content of + the sap in degrees Brix. +- The farm pays the grove for each delivery. The payment is an amount in a + currency. +- All objects are in package $TMP. + +# 4. Contract +- Create the transparent database table {{P}}SYRUP in package $TMP. +- The table has exactly these fields, in this order: + client, delivery_id, grove_id, delivery_date, sap_liters, brix, + quality_grade, payout, currency_code. + +# 5. Business rules +1. The table has the fields of the table below. The table below gives the data + type, the length and the number of decimals of each field. + + | Field | Data type | Length | Decimals | Key | Not null | + | --- | --- | --- | --- | --- | --- | + | client | CLNT | 3 | - | yes | yes | + | delivery_id | CHAR | 10 | - | yes | yes | + | grove_id | CHAR | 8 | - | no | no | + | delivery_date | DATS | 8 | - | no | no | + | sap_liters | DEC | 9 | 2 | no | no | + | brix | DEC | 4 | 1 | no | no | + | quality_grade | NUMC | 2 | - | no | no | + | payout | CURR | 15 | 2 | no | no | + | currency_code | CUKY | 5 | - | no | no | + +2. client and delivery_id are the key fields. No other field is a key field. +3. The key fields are not null. +4. payout is an amount. The currency of payout is the value of currency_code. +5. Two rows with the same client and the same delivery_id are not allowed. + +# 6. Constraints +- Release target: 8.16. +- Coding standards: Clean ABAP. +- Out of scope: no other objects. + +# 7. Acceptance +- The table is active and has no syntax error. +- The hidden tests pass. +- Write ABAP Unit tests in a global test class. Check the field properties with + RTTI and check the table access with CL_OSQL_TEST_ENVIRONMENT. diff --git a/tasks_gen/train/G1936/task.json b/tasks_gen/train/G1936/task.json new file mode 100644 index 0000000..0335fd1 --- /dev/null +++ b/tasks_gen/train/G1936/task.json @@ -0,0 +1,54 @@ +{ + "id": "G1936", + "category": "B", + "object_type": "TABL", + "difficulty": 3, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [], + "contract": [ + { + "type": "TABL", + "name": "{{P}}SYRUP", + "fields": [ + "client", + "delivery_id", + "grove_id", + "delivery_date", + "sap_liters", + "brix", + "quality_grade", + "payout", + "currency_code" + ] + } + ], + "out_of_scope": [], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}SYRUP_HIDDEN", + "file": "hidden/syrup_hidden.clas.abap", + "description": "Hidden tests: RTTI on the table and access with CL_OSQL_TEST_ENVIRONMENT" + } + ], + "reference": [ + { + "type": "TABL", + "name": "{{P}}SYRUP", + "file": "reference/syrup.tabl.asabap", + "description": "Sap delivery table" + }, + { + "type": "CLAS", + "name": "{{P}}SYRUP_TEST", + "file": "reference/syrup_test.clas.abap", + "description": "Own ABAP Unit tests for the table" + } + ], + "craft_checks": [] +} \ No newline at end of file diff --git a/tasks_gen/train/G1937/faulty/m0_if_sweep_check.intf.abap b/tasks_gen/train/G1937/faulty/m0_if_sweep_check.intf.abap new file mode 100644 index 0000000..82c1fb8 --- /dev/null +++ b/tasks_gen/train/G1937/faulty/m0_if_sweep_check.intf.abap @@ -0,0 +1,37 @@ +INTERFACE {{p}}if_sweep_check PUBLIC. + TYPES ty_reason TYPE c LENGTH 10. + TYPES ty_flue_kind TYPE c LENGTH 3. + TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2. + + CONSTANTS: + BEGIN OF c_reason, + ok TYPE ty_reason VALUE 'OK', + no_flues TYPE ty_reason VALUE 'NO_FLUES', + too_many TYPE ty_reason VALUE 'TOO_MANY', + bad_kind TYPE ty_reason VALUE 'BAD_KIND', + blocked TYPE ty_reason VALUE 'BLOCKED', + old_sweep TYPE ty_reason VALUE 'OLD_SWEEP', + END OF c_reason. + + CONSTANTS: + BEGIN OF c_kind, + open TYPE ty_flue_kind VALUE 'OPEN', + closed TYPE ty_flue_kind VALUE 'CLOS', + indust TYPE ty_flue_kind VALUE 'INDU', + END OF c_kind. + + CONSTANTS c_max_flues TYPE i VALUE 12. + + METHODS check_order + IMPORTING iv_flues TYPE i + iv_kind TYPE ty_flue_kind + iv_last_sweep TYPE i + iv_year TYPE i + iv_blocked TYPE abap_bool + RETURNING VALUE(rv_reason) TYPE ty_reason. + + METHODS fee + IMPORTING iv_flues TYPE i + iv_kind TYPE ty_flue_kind + RETURNING VALUE(rv_fee) TYPE ty_amount. +ENDINTERFACE. diff --git a/tasks_gen/train/G1937/faulty/m1_chimney_checker.clas.abap b/tasks_gen/train/G1937/faulty/m1_chimney_checker.clas.abap new file mode 100644 index 0000000..dc42c68 --- /dev/null +++ b/tasks_gen/train/G1937/faulty/m1_chimney_checker.clas.abap @@ -0,0 +1,65 @@ +CLASS {{p}}chimney_checker DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_sweep_check. + + PRIVATE SECTION. + CONSTANTS c_discount TYPE p LENGTH 3 DECIMALS 2 VALUE '0.90'. + + METHODS flue_fee + IMPORTING iv_kind TYPE {{p}}if_sweep_check=>ty_flue_kind + RETURNING VALUE(rv_fee) TYPE {{p}}if_sweep_check=>ty_amount. + + METHODS is_known_kind + IMPORTING iv_kind TYPE {{p}}if_sweep_check=>ty_flue_kind + RETURNING VALUE(rv_known) TYPE abap_bool. +ENDCLASS. + + +CLASS {{p}}chimney_checker IMPLEMENTATION. + METHOD {{p}}if_sweep_check~check_order. + IF iv_flues < 1. + rv_reason = {{p}}if_sweep_check=>c_reason-no_flues. + ELSEIF iv_flues > {{p}}if_sweep_check=>c_max_flues. + rv_reason = {{p}}if_sweep_check=>c_reason-too_many. + ELSEIF is_known_kind( iv_kind ) = abap_true. + rv_reason = {{p}}if_sweep_check=>c_reason-bad_kind. + ELSEIF iv_blocked = abap_true. + rv_reason = {{p}}if_sweep_check=>c_reason-blocked. + ELSEIF iv_year - iv_last_sweep > 2. + rv_reason = {{p}}if_sweep_check=>c_reason-old_sweep. + ELSE. + rv_reason = {{p}}if_sweep_check=>c_reason-ok. + ENDIF. + ENDMETHOD. + + METHOD {{p}}if_sweep_check~fee. + IF iv_flues < 1. + rv_fee = 0. + RETURN. + ENDIF. + DATA lv_total TYPE {{p}}if_sweep_check=>ty_amount. + lv_total = flue_fee( iv_kind ) * iv_flues. + IF iv_flues >= 5. + lv_total = lv_total * c_discount. + ENDIF. + rv_fee = round( val = lv_total dec = 2 ). + ENDMETHOD. + + METHOD flue_fee. + IF iv_kind = {{p}}if_sweep_check=>c_kind-open. + rv_fee = '60.00'. + ELSEIF iv_kind = {{p}}if_sweep_check=>c_kind-closed. + rv_fee = '45.00'. + ELSEIF iv_kind = {{p}}if_sweep_check=>c_kind-indust. + rv_fee = '120.00'. + ELSE. + rv_fee = 0. + ENDIF. + ENDMETHOD. + + METHOD is_known_kind. + rv_known = xsdbool( iv_kind = {{p}}if_sweep_check=>c_kind-open + OR iv_kind = {{p}}if_sweep_check=>c_kind-closed + OR iv_kind = {{p}}if_sweep_check=>c_kind-indust ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1937/faulty/m2_if_sweep_check.intf.abap b/tasks_gen/train/G1937/faulty/m2_if_sweep_check.intf.abap new file mode 100644 index 0000000..c4d00ce --- /dev/null +++ b/tasks_gen/train/G1937/faulty/m2_if_sweep_check.intf.abap @@ -0,0 +1,37 @@ +INTERFACE {{p}}if_sweep_check PUBLIC. + TYPES ty_reason TYPE c LENGTH 10. + TYPES ty_flue_kind TYPE c LENGTH 4. + TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2. + + CONSTANTS: + BEGIN OF c_reason, + ok TYPE ty_reason VALUE 'OK', + no_flues TYPE ty_reason VALUE 'ZO_FLUES', + too_many TYPE ty_reason VALUE 'TOO_MANY', + bad_kind TYPE ty_reason VALUE 'BAD_KIND', + blocked TYPE ty_reason VALUE 'BLOCKED', + old_sweep TYPE ty_reason VALUE 'OLD_SWEEP', + END OF c_reason. + + CONSTANTS: + BEGIN OF c_kind, + open TYPE ty_flue_kind VALUE 'OPEN', + closed TYPE ty_flue_kind VALUE 'CLOS', + indust TYPE ty_flue_kind VALUE 'INDU', + END OF c_kind. + + CONSTANTS c_max_flues TYPE i VALUE 12. + + METHODS check_order + IMPORTING iv_flues TYPE i + iv_kind TYPE ty_flue_kind + iv_last_sweep TYPE i + iv_year TYPE i + iv_blocked TYPE abap_bool + RETURNING VALUE(rv_reason) TYPE ty_reason. + + METHODS fee + IMPORTING iv_flues TYPE i + iv_kind TYPE ty_flue_kind + RETURNING VALUE(rv_fee) TYPE ty_amount. +ENDINTERFACE. diff --git a/tasks_gen/train/G1937/faulty/m3_chimney_checker.clas.abap b/tasks_gen/train/G1937/faulty/m3_chimney_checker.clas.abap new file mode 100644 index 0000000..7e1f1b4 --- /dev/null +++ b/tasks_gen/train/G1937/faulty/m3_chimney_checker.clas.abap @@ -0,0 +1,65 @@ +CLASS {{p}}chimney_checker DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_sweep_check. + + PRIVATE SECTION. + CONSTANTS c_discount TYPE p LENGTH 3 DECIMALS 2 VALUE '0.90'. + + METHODS flue_fee + IMPORTING iv_kind TYPE {{p}}if_sweep_check=>ty_flue_kind + RETURNING VALUE(rv_fee) TYPE {{p}}if_sweep_check=>ty_amount. + + METHODS is_known_kind + IMPORTING iv_kind TYPE {{p}}if_sweep_check=>ty_flue_kind + RETURNING VALUE(rv_known) TYPE abap_bool. +ENDCLASS. + + +CLASS {{p}}chimney_checker IMPLEMENTATION. + METHOD {{p}}if_sweep_check~check_order. + IF iv_flues < 1. + rv_reason = {{p}}if_sweep_check=>c_reason-no_flues. + ELSEIF iv_flues > {{p}}if_sweep_check=>c_max_flues. + rv_reason = {{p}}if_sweep_check=>c_reason-too_many. + ELSEIF is_known_kind( iv_kind ) = abap_false. + rv_reason = {{p}}if_sweep_check=>c_reason-bad_kind. + ELSEIF iv_blocked <> abap_true. + rv_reason = {{p}}if_sweep_check=>c_reason-blocked. + ELSEIF iv_year - iv_last_sweep > 2. + rv_reason = {{p}}if_sweep_check=>c_reason-old_sweep. + ELSE. + rv_reason = {{p}}if_sweep_check=>c_reason-ok. + ENDIF. + ENDMETHOD. + + METHOD {{p}}if_sweep_check~fee. + IF iv_flues < 1. + rv_fee = 0. + RETURN. + ENDIF. + DATA lv_total TYPE {{p}}if_sweep_check=>ty_amount. + lv_total = flue_fee( iv_kind ) * iv_flues. + IF iv_flues >= 5. + lv_total = lv_total * c_discount. + ENDIF. + rv_fee = round( val = lv_total dec = 2 ). + ENDMETHOD. + + METHOD flue_fee. + IF iv_kind = {{p}}if_sweep_check=>c_kind-open. + rv_fee = '60.00'. + ELSEIF iv_kind = {{p}}if_sweep_check=>c_kind-closed. + rv_fee = '45.00'. + ELSEIF iv_kind = {{p}}if_sweep_check=>c_kind-indust. + rv_fee = '120.00'. + ELSE. + rv_fee = 0. + ENDIF. + ENDMETHOD. + + METHOD is_known_kind. + rv_known = xsdbool( iv_kind = {{p}}if_sweep_check=>c_kind-open + OR iv_kind = {{p}}if_sweep_check=>c_kind-closed + OR iv_kind = {{p}}if_sweep_check=>c_kind-indust ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1937/faulty/m4_if_sweep_check.intf.abap b/tasks_gen/train/G1937/faulty/m4_if_sweep_check.intf.abap new file mode 100644 index 0000000..863f743 --- /dev/null +++ b/tasks_gen/train/G1937/faulty/m4_if_sweep_check.intf.abap @@ -0,0 +1,37 @@ +INTERFACE {{p}}if_sweep_check PUBLIC. + TYPES ty_reason TYPE c LENGTH 10. + TYPES ty_flue_kind TYPE c LENGTH 4. + TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2. + + CONSTANTS: + BEGIN OF c_reason, + ok TYPE ty_reason VALUE 'OK', + no_flues TYPE ty_reason VALUE 'NO_FLUES', + too_many TYPE ty_reason VALUE 'TOO_MANY', + bad_kind TYPE ty_reason VALUE 'ZAD_KIND', + blocked TYPE ty_reason VALUE 'BLOCKED', + old_sweep TYPE ty_reason VALUE 'OLD_SWEEP', + END OF c_reason. + + CONSTANTS: + BEGIN OF c_kind, + open TYPE ty_flue_kind VALUE 'OPEN', + closed TYPE ty_flue_kind VALUE 'CLOS', + indust TYPE ty_flue_kind VALUE 'INDU', + END OF c_kind. + + CONSTANTS c_max_flues TYPE i VALUE 12. + + METHODS check_order + IMPORTING iv_flues TYPE i + iv_kind TYPE ty_flue_kind + iv_last_sweep TYPE i + iv_year TYPE i + iv_blocked TYPE abap_bool + RETURNING VALUE(rv_reason) TYPE ty_reason. + + METHODS fee + IMPORTING iv_flues TYPE i + iv_kind TYPE ty_flue_kind + RETURNING VALUE(rv_fee) TYPE ty_amount. +ENDINTERFACE. diff --git a/tasks_gen/train/G1937/generation.json b/tasks_gen/train/G1937/generation.json new file mode 100644 index 0000000..6c2994c --- /dev/null +++ b/tasks_gen/train/G1937/generation.json @@ -0,0 +1,34 @@ +{ + "id": "G1937", + "pool": "train", + "object_type": "INTF", + "category": "A", + "attempts": [ + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 96.7, + "null": 0 + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 5, + "killed": 5, + "ok": true + } + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1937/hidden/t02_hidden.clas.abap b/tasks_gen/train/G1937/hidden/t02_hidden.clas.abap new file mode 100644 index 0000000..86acf1c --- /dev/null +++ b/tasks_gen/train/G1937/hidden/t02_hidden.clas.abap @@ -0,0 +1,215 @@ +CLASS {{p}}t02_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PUBLIC SECTION. + INTERFACES {{p}}if_sweep_check. + PRIVATE SECTION. + DATA mo_cut TYPE REF TO {{p}}if_sweep_check. + METHODS setup. + METHODS ok_order FOR TESTING. + METHODS no_flues FOR TESTING. + METHODS too_many_flues FOR TESTING. + METHODS bad_kind FOR TESTING. + METHODS blocked_order FOR TESTING. + METHODS old_sweep FOR TESTING. + METHODS boundary_ok FOR TESTING. + METHODS reason_priority FOR TESTING. + METHODS fee_by_kind FOR TESTING. + METHODS fee_discount FOR TESTING. + METHODS fee_edge FOR TESTING. + METHODS contract_shape FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t02_hidden IMPLEMENTATION. + METHOD {{p}}if_sweep_check~check_order. + rv_reason = {{p}}if_sweep_check=>c_reason-ok. + ENDMETHOD. + + METHOD {{p}}if_sweep_check~fee. + rv_fee = 0. + ENDMETHOD. + + METHOD setup. + mo_cut = NEW {{p}}chimney_checker( ). + ENDMETHOD. + + METHOD ok_order. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_sweep_check=>c_reason-ok + act = mo_cut->check_order( iv_flues = 3 + iv_kind = {{p}}if_sweep_check=>c_kind-open + iv_last_sweep = 2024 + iv_year = 2025 + iv_blocked = abap_false ) ). + ENDMETHOD. + + METHOD no_flues. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_sweep_check=>c_reason-no_flues + act = mo_cut->check_order( iv_flues = 0 + iv_kind = {{p}}if_sweep_check=>c_kind-closed + iv_last_sweep = 2025 + iv_year = 2025 + iv_blocked = abap_false ) ). + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_sweep_check=>c_reason-no_flues + act = mo_cut->check_order( iv_flues = -2 + iv_kind = {{p}}if_sweep_check=>c_kind-closed + iv_last_sweep = 2025 + iv_year = 2025 + iv_blocked = abap_false ) ). + ENDMETHOD. + + METHOD too_many_flues. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_sweep_check=>c_reason-too_many + act = mo_cut->check_order( iv_flues = 13 + iv_kind = {{p}}if_sweep_check=>c_kind-open + iv_last_sweep = 2025 + iv_year = 2025 + iv_blocked = abap_false ) ). + ENDMETHOD. + + METHOD bad_kind. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_sweep_check=>c_reason-bad_kind + act = mo_cut->check_order( iv_flues = 3 + iv_kind = 'GAS' + iv_last_sweep = 2025 + iv_year = 2025 + iv_blocked = abap_false ) ). + ENDMETHOD. + + METHOD blocked_order. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_sweep_check=>c_reason-blocked + act = mo_cut->check_order( iv_flues = 3 + iv_kind = {{p}}if_sweep_check=>c_kind-indust + iv_last_sweep = 2024 + iv_year = 2025 + iv_blocked = abap_true ) ). + ENDMETHOD. + + METHOD old_sweep. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_sweep_check=>c_reason-old_sweep + act = mo_cut->check_order( iv_flues = 2 + iv_kind = {{p}}if_sweep_check=>c_kind-open + iv_last_sweep = 2022 + iv_year = 2025 + iv_blocked = abap_false ) ). + ENDMETHOD. + + METHOD boundary_ok. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_sweep_check=>c_reason-ok + act = mo_cut->check_order( iv_flues = 12 + iv_kind = {{p}}if_sweep_check=>c_kind-closed + iv_last_sweep = 2023 + iv_year = 2025 + iv_blocked = abap_false ) ). + ENDMETHOD. + + METHOD reason_priority. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_sweep_check=>c_reason-no_flues + act = mo_cut->check_order( iv_flues = 0 + iv_kind = 'GAS' + iv_last_sweep = 2000 + iv_year = 2025 + iv_blocked = abap_true ) ). + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_sweep_check=>c_reason-too_many + act = mo_cut->check_order( iv_flues = 20 + iv_kind = 'GAS' + iv_last_sweep = 2000 + iv_year = 2025 + iv_blocked = abap_true ) ). + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_sweep_check=>c_reason-bad_kind + act = mo_cut->check_order( iv_flues = 3 + iv_kind = 'GAS' + iv_last_sweep = 2000 + iv_year = 2025 + iv_blocked = abap_true ) ). + ENDMETHOD. + + METHOD fee_by_kind. + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_sweep_check=>ty_amount( '240.00' ) + act = mo_cut->fee( iv_flues = 4 iv_kind = {{p}}if_sweep_check=>c_kind-open ) ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_sweep_check=>ty_amount( '180.00' ) + act = mo_cut->fee( iv_flues = 4 iv_kind = {{p}}if_sweep_check=>c_kind-closed ) ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_sweep_check=>ty_amount( '240.00' ) + act = mo_cut->fee( iv_flues = 2 iv_kind = {{p}}if_sweep_check=>c_kind-indust ) ). + ENDMETHOD. + + METHOD fee_discount. + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_sweep_check=>ty_amount( '243.00' ) + act = mo_cut->fee( iv_flues = 6 iv_kind = {{p}}if_sweep_check=>c_kind-closed ) ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_sweep_check=>ty_amount( '270.00' ) + act = mo_cut->fee( iv_flues = 5 iv_kind = {{p}}if_sweep_check=>c_kind-open ) ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_sweep_check=>ty_amount( '540.00' ) + act = mo_cut->fee( iv_flues = 5 iv_kind = {{p}}if_sweep_check=>c_kind-indust ) ). + ENDMETHOD. + + METHOD fee_edge. + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_sweep_check=>ty_amount( '0.00' ) + act = mo_cut->fee( iv_flues = 0 iv_kind = {{p}}if_sweep_check=>c_kind-open ) ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_sweep_check=>ty_amount( '0.00' ) + act = mo_cut->fee( iv_flues = -2 iv_kind = {{p}}if_sweep_check=>c_kind-open ) ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_sweep_check=>ty_amount( '0.00' ) + act = mo_cut->fee( iv_flues = 3 iv_kind = 'GAS' ) ). + ENDMETHOD. + + METHOD contract_shape. + cl_abap_unit_assert=>assert_equals( exp = 12 act = {{p}}if_sweep_check=>c_max_flues ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_sweep_check=>ty_reason( 'OK' ) + act = {{p}}if_sweep_check=>c_reason-ok ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_sweep_check=>ty_reason( 'NO_FLUES' ) + act = {{p}}if_sweep_check=>c_reason-no_flues ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_sweep_check=>ty_reason( 'TOO_MANY' ) + act = {{p}}if_sweep_check=>c_reason-too_many ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_sweep_check=>ty_reason( 'BAD_KIND' ) + act = {{p}}if_sweep_check=>c_reason-bad_kind ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_sweep_check=>ty_reason( 'BLOCKED' ) + act = {{p}}if_sweep_check=>c_reason-blocked ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_sweep_check=>ty_reason( 'OLD_SWEEP' ) + act = {{p}}if_sweep_check=>c_reason-old_sweep ). + cl_abap_unit_assert=>assert_equals( exp = 'OPEN' act = {{p}}if_sweep_check=>c_kind-open ). + cl_abap_unit_assert=>assert_equals( exp = 'CLOS' act = {{p}}if_sweep_check=>c_kind-closed ). + cl_abap_unit_assert=>assert_equals( exp = 'INDU' act = {{p}}if_sweep_check=>c_kind-indust ). + + DATA lv_reason TYPE {{p}}if_sweep_check=>ty_reason. + lv_reason = 'ABCDEFGHIJK'. + cl_abap_unit_assert=>assert_equals( exp = 'ABCDEFGHIJ' act = lv_reason ). + + DATA lv_kind TYPE {{p}}if_sweep_check=>ty_flue_kind. + lv_kind = 'ABCDE'. + cl_abap_unit_assert=>assert_equals( exp = 'ABCD' act = lv_kind ). + + DATA lv_amount TYPE {{p}}if_sweep_check=>ty_amount. + lv_amount = '123.45'. + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_sweep_check=>ty_amount( '123.45' ) + act = lv_amount ). + + DATA lo_self TYPE REF TO {{p}}if_sweep_check. + lo_self = NEW {{p}}t02_hidden( ). + cl_abap_unit_assert=>assert_bound( lo_self ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1937/mutation.json b/tasks_gen/train/G1937/mutation.json new file mode 100644 index 0000000..996ec7e --- /dev/null +++ b/tasks_gen/train/G1937/mutation.json @@ -0,0 +1,62 @@ +{ + "task": "G1937", + "mutants": [ + { + "object": "{{P}}IF_SWEEP_CHECK", + "mutant": "line 3: LENGTH 4 -> LENGTH 3 (length)", + "status": "killed", + "hidden": "11/12", + "failed_tests": [ + "CONTRACT_SHAPE" + ] + }, + { + "object": "{{P}}CHIMNEY_CHECKER", + "mutant": "line 24: abap_false -> abap_true (bool)", + "status": "killed", + "hidden": "6/12", + "failed_tests": [ + "BAD_KIND", + "BLOCKED_ORDER", + "BOUNDARY_OK", + "OK_ORDER", + "OLD_SWEEP", + "REASON_PRIORITY" + ] + }, + { + "object": "{{P}}IF_SWEEP_CHECK", + "mutant": "line 9: VALUE 'NO_FLUES' -> VALUE 'ZO_FLUES' (lit)", + "status": "killed", + "hidden": "11/12", + "failed_tests": [ + "CONTRACT_SHAPE" + ] + }, + { + "object": "{{P}}CHIMNEY_CHECKER", + "mutant": "line 26: = -> <> (eq)", + "status": "killed", + "hidden": "8/12", + "failed_tests": [ + "BLOCKED_ORDER", + "BOUNDARY_OK", + "OK_ORDER", + "OLD_SWEEP" + ] + }, + { + "object": "{{P}}IF_SWEEP_CHECK", + "mutant": "line 11: VALUE 'BAD_KIND' -> VALUE 'ZAD_KIND' (lit)", + "status": "killed", + "hidden": "11/12", + "failed_tests": [ + "CONTRACT_SHAPE" + ] + } + ], + "valid": 5, + "killed": 5, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1937/reference/chimney_checker.clas.abap b/tasks_gen/train/G1937/reference/chimney_checker.clas.abap new file mode 100644 index 0000000..04ca272 --- /dev/null +++ b/tasks_gen/train/G1937/reference/chimney_checker.clas.abap @@ -0,0 +1,65 @@ +CLASS {{p}}chimney_checker DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_sweep_check. + + PRIVATE SECTION. + CONSTANTS c_discount TYPE p LENGTH 3 DECIMALS 2 VALUE '0.90'. + + METHODS flue_fee + IMPORTING iv_kind TYPE {{p}}if_sweep_check=>ty_flue_kind + RETURNING VALUE(rv_fee) TYPE {{p}}if_sweep_check=>ty_amount. + + METHODS is_known_kind + IMPORTING iv_kind TYPE {{p}}if_sweep_check=>ty_flue_kind + RETURNING VALUE(rv_known) TYPE abap_bool. +ENDCLASS. + + +CLASS {{p}}chimney_checker IMPLEMENTATION. + METHOD {{p}}if_sweep_check~check_order. + IF iv_flues < 1. + rv_reason = {{p}}if_sweep_check=>c_reason-no_flues. + ELSEIF iv_flues > {{p}}if_sweep_check=>c_max_flues. + rv_reason = {{p}}if_sweep_check=>c_reason-too_many. + ELSEIF is_known_kind( iv_kind ) = abap_false. + rv_reason = {{p}}if_sweep_check=>c_reason-bad_kind. + ELSEIF iv_blocked = abap_true. + rv_reason = {{p}}if_sweep_check=>c_reason-blocked. + ELSEIF iv_year - iv_last_sweep > 2. + rv_reason = {{p}}if_sweep_check=>c_reason-old_sweep. + ELSE. + rv_reason = {{p}}if_sweep_check=>c_reason-ok. + ENDIF. + ENDMETHOD. + + METHOD {{p}}if_sweep_check~fee. + IF iv_flues < 1. + rv_fee = 0. + RETURN. + ENDIF. + DATA lv_total TYPE {{p}}if_sweep_check=>ty_amount. + lv_total = flue_fee( iv_kind ) * iv_flues. + IF iv_flues >= 5. + lv_total = lv_total * c_discount. + ENDIF. + rv_fee = round( val = lv_total dec = 2 ). + ENDMETHOD. + + METHOD flue_fee. + IF iv_kind = {{p}}if_sweep_check=>c_kind-open. + rv_fee = '60.00'. + ELSEIF iv_kind = {{p}}if_sweep_check=>c_kind-closed. + rv_fee = '45.00'. + ELSEIF iv_kind = {{p}}if_sweep_check=>c_kind-indust. + rv_fee = '120.00'. + ELSE. + rv_fee = 0. + ENDIF. + ENDMETHOD. + + METHOD is_known_kind. + rv_known = xsdbool( iv_kind = {{p}}if_sweep_check=>c_kind-open + OR iv_kind = {{p}}if_sweep_check=>c_kind-closed + OR iv_kind = {{p}}if_sweep_check=>c_kind-indust ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1937/reference/chimney_checker.testclasses.abap b/tasks_gen/train/G1937/reference/chimney_checker.testclasses.abap new file mode 100644 index 0000000..9a01a9f --- /dev/null +++ b/tasks_gen/train/G1937/reference/chimney_checker.testclasses.abap @@ -0,0 +1,102 @@ +CLASS ltc_chimney_checker DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + DATA mo_cut TYPE REF TO {{p}}if_sweep_check. + METHODS setup. + METHODS order_is_ok FOR TESTING. + METHODS no_flues FOR TESTING. + METHODS too_many_flues FOR TESTING. + METHODS unknown_kind FOR TESTING. + METHODS blocked_order FOR TESTING. + METHODS stale_sweep FOR TESTING. + METHODS fee_by_kind FOR TESTING. + METHODS fee_with_discount FOR TESTING. + METHODS fee_without_flues FOR TESTING. +ENDCLASS. + + +CLASS ltc_chimney_checker IMPLEMENTATION. + METHOD setup. + mo_cut = NEW {{p}}chimney_checker( ). + ENDMETHOD. + + METHOD order_is_ok. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_sweep_check=>c_reason-ok + act = mo_cut->check_order( iv_flues = 2 + iv_kind = {{p}}if_sweep_check=>c_kind-open + iv_last_sweep = 2024 + iv_year = 2025 + iv_blocked = abap_false ) ). + ENDMETHOD. + + METHOD no_flues. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_sweep_check=>c_reason-no_flues + act = mo_cut->check_order( iv_flues = 0 + iv_kind = {{p}}if_sweep_check=>c_kind-closed + iv_last_sweep = 2025 + iv_year = 2025 + iv_blocked = abap_false ) ). + ENDMETHOD. + + METHOD too_many_flues. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_sweep_check=>c_reason-too_many + act = mo_cut->check_order( iv_flues = 13 + iv_kind = {{p}}if_sweep_check=>c_kind-open + iv_last_sweep = 2025 + iv_year = 2025 + iv_blocked = abap_false ) ). + ENDMETHOD. + + METHOD unknown_kind. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_sweep_check=>c_reason-bad_kind + act = mo_cut->check_order( iv_flues = 2 + iv_kind = 'GAS' + iv_last_sweep = 2025 + iv_year = 2025 + iv_blocked = abap_false ) ). + ENDMETHOD. + + METHOD blocked_order. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_sweep_check=>c_reason-blocked + act = mo_cut->check_order( iv_flues = 2 + iv_kind = {{p}}if_sweep_check=>c_kind-open + iv_last_sweep = 2024 + iv_year = 2025 + iv_blocked = abap_true ) ). + ENDMETHOD. + + METHOD stale_sweep. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_sweep_check=>c_reason-old_sweep + act = mo_cut->check_order( iv_flues = 2 + iv_kind = {{p}}if_sweep_check=>c_kind-indust + iv_last_sweep = 2022 + iv_year = 2025 + iv_blocked = abap_false ) ). + ENDMETHOD. + + METHOD fee_by_kind. + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_sweep_check=>ty_amount( '240.00' ) + act = mo_cut->fee( iv_flues = 4 iv_kind = {{p}}if_sweep_check=>c_kind-open ) ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_sweep_check=>ty_amount( '180.00' ) + act = mo_cut->fee( iv_flues = 4 iv_kind = {{p}}if_sweep_check=>c_kind-closed ) ). + ENDMETHOD. + + METHOD fee_with_discount. + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_sweep_check=>ty_amount( '243.00' ) + act = mo_cut->fee( iv_flues = 6 iv_kind = {{p}}if_sweep_check=>c_kind-closed ) ). + ENDMETHOD. + + METHOD fee_without_flues. + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}if_sweep_check=>ty_amount( '0.00' ) + act = mo_cut->fee( iv_flues = 0 iv_kind = {{p}}if_sweep_check=>c_kind-open ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1937/reference/if_sweep_check.intf.abap b/tasks_gen/train/G1937/reference/if_sweep_check.intf.abap new file mode 100644 index 0000000..f231c98 --- /dev/null +++ b/tasks_gen/train/G1937/reference/if_sweep_check.intf.abap @@ -0,0 +1,37 @@ +INTERFACE {{p}}if_sweep_check PUBLIC. + TYPES ty_reason TYPE c LENGTH 10. + TYPES ty_flue_kind TYPE c LENGTH 4. + TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2. + + CONSTANTS: + BEGIN OF c_reason, + ok TYPE ty_reason VALUE 'OK', + no_flues TYPE ty_reason VALUE 'NO_FLUES', + too_many TYPE ty_reason VALUE 'TOO_MANY', + bad_kind TYPE ty_reason VALUE 'BAD_KIND', + blocked TYPE ty_reason VALUE 'BLOCKED', + old_sweep TYPE ty_reason VALUE 'OLD_SWEEP', + END OF c_reason. + + CONSTANTS: + BEGIN OF c_kind, + open TYPE ty_flue_kind VALUE 'OPEN', + closed TYPE ty_flue_kind VALUE 'CLOS', + indust TYPE ty_flue_kind VALUE 'INDU', + END OF c_kind. + + CONSTANTS c_max_flues TYPE i VALUE 12. + + METHODS check_order + IMPORTING iv_flues TYPE i + iv_kind TYPE ty_flue_kind + iv_last_sweep TYPE i + iv_year TYPE i + iv_blocked TYPE abap_bool + RETURNING VALUE(rv_reason) TYPE ty_reason. + + METHODS fee + IMPORTING iv_flues TYPE i + iv_kind TYPE ty_flue_kind + RETURNING VALUE(rv_fee) TYPE ty_amount. +ENDINTERFACE. diff --git a/tasks_gen/train/G1937/spec.md b/tasks_gen/train/G1937/spec.md new file mode 100644 index 0000000..800f130 --- /dev/null +++ b/tasks_gen/train/G1937/spec.md @@ -0,0 +1,75 @@ +# 1. Goal +A chimney sweep company serves private houses and small businesses. Before the +dispatcher schedules a sweep, the dispatch program checks each sweep order and +calculates the sweep fee. The program needs one reason code for each order. + +# 2. Open questions +None. + +# 3. Context +- Package $TMP. +- The dispatch program uses the interface {{P}}IF_SWEEP_CHECK and the class + {{P}}CHIMNEY_CHECKER. +- One flue is one chimney channel. A sweep order covers one or more flues. +- iv_last_sweep is the year of the last sweep of the order. +- iv_year is the current year. +- iv_blocked is true when the customer blocked the access to the building. + +# 4. Contract +- Create the interface {{P}}IF_SWEEP_CHECK in package $TMP. The interface has + these public components: + - TYPES ty_reason TYPE c LENGTH 10. + - TYPES ty_flue_kind TYPE c LENGTH 4. + - TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2. + - The constant structure c_reason with the components ok, no_flues, too_many, + bad_kind, blocked, old_sweep. Each component has the type ty_reason and + these values: 'OK', 'NO_FLUES', 'TOO_MANY', 'BAD_KIND', 'BLOCKED', + 'OLD_SWEEP'. + - The constant structure c_kind with the components open, closed, indust. + Each component has the type ty_flue_kind and these values: 'OPEN', 'CLOS', + 'INDU'. + - The constant c_max_flues with the type i and the value 12. + - The method check_order with the parameters + IMPORTING iv_flues TYPE i + iv_kind TYPE ty_flue_kind + iv_last_sweep TYPE i + iv_year TYPE i + iv_blocked TYPE abap_bool + RETURNING VALUE(rv_reason) TYPE ty_reason. + - The method fee with the parameters + IMPORTING iv_flues TYPE i + iv_kind TYPE ty_flue_kind + RETURNING VALUE(rv_fee) TYPE ty_amount. +- Create the class {{P}}CHIMNEY_CHECKER in package $TMP. +- The class is public, final, and has a public constructor without parameters. +- The class implements {{P}}IF_SWEEP_CHECK. +- Do not add other public methods to the class. + +# 5. Business rules +## 5.1 Check of a sweep order +Apply the rules in this sequence. Return the reason of the first rule that fails. +1. If iv_flues is less than 1, return NO_FLUES. +2. If iv_flues is greater than c_max_flues, return TOO_MANY. +3. If iv_kind is not OPEN, CLOS or INDU, return BAD_KIND. +4. If iv_blocked is true, return BLOCKED. +5. If iv_year minus iv_last_sweep is greater than 2, return OLD_SWEEP. +6. Else return OK. + +## 5.2 Fee of a sweep order +1. The fee of one flue depends on the flue kind: OPEN 60.00, CLOS 45.00, + INDU 120.00. Any other flue kind has a fee of 0.00. +2. The total is the fee of one flue multiplied by iv_flues. +3. If iv_flues is 5 or more, reduce the total by 10 percent. +4. Round the result to 2 decimals. +5. If iv_flues is less than 1, the fee is 0.00. + +# 6. Constraints +- Release target: SAP_BASIS 816. +- Coding standards: Clean ABAP. Method length below 40 statements. No global + variables. No comment that restates the code. +- Out of scope: no other objects in package $TMP. + +# 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. diff --git a/tasks_gen/train/G1937/task.json b/tasks_gen/train/G1937/task.json new file mode 100644 index 0000000..f17dfb0 --- /dev/null +++ b/tasks_gen/train/G1937/task.json @@ -0,0 +1,51 @@ +{ + "id": "G1937", + "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_SWEEP_CHECK" + }, + { + "type": "CLAS", + "name": "{{P}}CHIMNEY_CHECKER", + "implements": "{{P}}IF_SWEEP_CHECK" + } + ], + "out_of_scope": [], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T02_HIDDEN", + "file": "hidden/t02_hidden.clas.abap", + "description": "T02 hidden tests: the test class implements the interface, calls the methods through the interface, reads the constants and checks the type lengths" + } + ], + "reference": [ + { + "type": "INTF", + "name": "{{P}}IF_SWEEP_CHECK", + "file": "reference/if_sweep_check.intf.abap", + "description": "Sweep order check contract" + }, + { + "type": "CLAS", + "name": "{{P}}CHIMNEY_CHECKER", + "file": "reference/chimney_checker.clas.abap", + "description": "Chimney sweep order checker and fee calculator", + "testclasses_file": "reference/chimney_checker.testclasses.abap" + } + ], + "craft_checks": [ + "method_length" + ] +} \ No newline at end of file diff --git a/tasks_gen/train/G1938/faulty/m0_if_log_plan.intf.abap b/tasks_gen/train/G1938/faulty/m0_if_log_plan.intf.abap new file mode 100644 index 0000000..937c4fb --- /dev/null +++ b/tasks_gen/train/G1938/faulty/m0_if_log_plan.intf.abap @@ -0,0 +1,35 @@ +INTERFACE {{p}}if_log_plan PUBLIC. + TYPES: + ty_reason TYPE c LENGTH 9, + ty_count TYPE i, + BEGIN OF ty_log, + dia TYPE i, + len TYPE i, + END OF ty_log, + BEGIN OF ty_board, + thick TYPE i, + width TYPE i, + END OF ty_board. + + CONSTANTS: + BEGIN OF c_reason, + ok TYPE ty_reason VALUE 'OK', + size TYPE ty_reason VALUE 'SIZE', + thick TYPE ty_reason VALUE 'THICK', + width TYPE ty_reason VALUE 'WIDTH', + len TYPE ty_reason VALUE 'LEN', + END OF c_reason, + c_min_thick TYPE i VALUE 20, + c_max_thick TYPE i VALUE 100, + c_min_len TYPE i VALUE 100. + + METHODS check + IMPORTING is_log TYPE ty_log + is_board TYPE ty_board + RETURNING VALUE(rv_reason) TYPE ty_reason. + + METHODS board_count + IMPORTING is_log TYPE ty_log + is_board TYPE ty_board + RETURNING VALUE(rv_count) TYPE ty_count. +ENDINTERFACE. diff --git a/tasks_gen/train/G1938/faulty/m1_if_log_plan.intf.abap b/tasks_gen/train/G1938/faulty/m1_if_log_plan.intf.abap new file mode 100644 index 0000000..a9faf83 --- /dev/null +++ b/tasks_gen/train/G1938/faulty/m1_if_log_plan.intf.abap @@ -0,0 +1,35 @@ +INTERFACE {{p}}if_log_plan PUBLIC. + TYPES: + ty_reason TYPE c LENGTH 10, + ty_count TYPE i, + BEGIN OF ty_log, + dia TYPE i, + len TYPE i, + END OF ty_log, + BEGIN OF ty_board, + thick TYPE i, + width TYPE i, + END OF ty_board. + + CONSTANTS: + BEGIN OF c_reason, + ok TYPE ty_reason VALUE 'ZK', + size TYPE ty_reason VALUE 'SIZE', + thick TYPE ty_reason VALUE 'THICK', + width TYPE ty_reason VALUE 'WIDTH', + len TYPE ty_reason VALUE 'LEN', + END OF c_reason, + c_min_thick TYPE i VALUE 20, + c_max_thick TYPE i VALUE 100, + c_min_len TYPE i VALUE 100. + + METHODS check + IMPORTING is_log TYPE ty_log + is_board TYPE ty_board + RETURNING VALUE(rv_reason) TYPE ty_reason. + + METHODS board_count + IMPORTING is_log TYPE ty_log + is_board TYPE ty_board + RETURNING VALUE(rv_count) TYPE ty_count. +ENDINTERFACE. diff --git a/tasks_gen/train/G1938/faulty/m2_if_log_plan.intf.abap b/tasks_gen/train/G1938/faulty/m2_if_log_plan.intf.abap new file mode 100644 index 0000000..7ea67e9 --- /dev/null +++ b/tasks_gen/train/G1938/faulty/m2_if_log_plan.intf.abap @@ -0,0 +1,35 @@ +INTERFACE {{p}}if_log_plan PUBLIC. + TYPES: + ty_reason TYPE c LENGTH 10, + ty_count TYPE i, + BEGIN OF ty_log, + dia TYPE i, + len TYPE i, + END OF ty_log, + BEGIN OF ty_board, + thick TYPE i, + width TYPE i, + END OF ty_board. + + CONSTANTS: + BEGIN OF c_reason, + ok TYPE ty_reason VALUE 'OK', + size TYPE ty_reason VALUE 'SIZE', + thick TYPE ty_reason VALUE 'ZHICK', + width TYPE ty_reason VALUE 'WIDTH', + len TYPE ty_reason VALUE 'LEN', + END OF c_reason, + c_min_thick TYPE i VALUE 20, + c_max_thick TYPE i VALUE 100, + c_min_len TYPE i VALUE 100. + + METHODS check + IMPORTING is_log TYPE ty_log + is_board TYPE ty_board + RETURNING VALUE(rv_reason) TYPE ty_reason. + + METHODS board_count + IMPORTING is_log TYPE ty_log + is_board TYPE ty_board + RETURNING VALUE(rv_count) TYPE ty_count. +ENDINTERFACE. diff --git a/tasks_gen/train/G1938/faulty/m3_if_log_plan.intf.abap b/tasks_gen/train/G1938/faulty/m3_if_log_plan.intf.abap new file mode 100644 index 0000000..1ed7e6c --- /dev/null +++ b/tasks_gen/train/G1938/faulty/m3_if_log_plan.intf.abap @@ -0,0 +1,35 @@ +INTERFACE {{p}}if_log_plan PUBLIC. + TYPES: + ty_reason TYPE c LENGTH 10, + ty_count TYPE i, + BEGIN OF ty_log, + dia TYPE i, + len TYPE i, + END OF ty_log, + BEGIN OF ty_board, + thick TYPE i, + width TYPE i, + END OF ty_board. + + CONSTANTS: + BEGIN OF c_reason, + ok TYPE ty_reason VALUE 'OK', + size TYPE ty_reason VALUE 'SIZE', + thick TYPE ty_reason VALUE 'THICK', + width TYPE ty_reason VALUE 'WIDTH', + len TYPE ty_reason VALUE 'ZEN', + END OF c_reason, + c_min_thick TYPE i VALUE 20, + c_max_thick TYPE i VALUE 100, + c_min_len TYPE i VALUE 100. + + METHODS check + IMPORTING is_log TYPE ty_log + is_board TYPE ty_board + RETURNING VALUE(rv_reason) TYPE ty_reason. + + METHODS board_count + IMPORTING is_log TYPE ty_log + is_board TYPE ty_board + RETURNING VALUE(rv_count) TYPE ty_count. +ENDINTERFACE. diff --git a/tasks_gen/train/G1938/faulty/m4_if_log_plan.intf.abap b/tasks_gen/train/G1938/faulty/m4_if_log_plan.intf.abap new file mode 100644 index 0000000..c11528b --- /dev/null +++ b/tasks_gen/train/G1938/faulty/m4_if_log_plan.intf.abap @@ -0,0 +1,35 @@ +INTERFACE {{p}}if_log_plan PUBLIC. + TYPES: + ty_reason TYPE c LENGTH 10, + ty_count TYPE i, + BEGIN OF ty_log, + dia TYPE i, + len TYPE i, + END OF ty_log, + BEGIN OF ty_board, + thick TYPE i, + width TYPE i, + END OF ty_board. + + CONSTANTS: + BEGIN OF c_reason, + ok TYPE ty_reason VALUE 'OK', + size TYPE ty_reason VALUE 'SIZE', + thick TYPE ty_reason VALUE 'THICK', + width TYPE ty_reason VALUE 'WIDTH', + len TYPE ty_reason VALUE 'LEN', + END OF c_reason, + c_min_thick TYPE i VALUE 20, + c_max_thick TYPE i VALUE 100, + c_min_len TYPE i VALUE 101. + + METHODS check + IMPORTING is_log TYPE ty_log + is_board TYPE ty_board + RETURNING VALUE(rv_reason) TYPE ty_reason. + + METHODS board_count + IMPORTING is_log TYPE ty_log + is_board TYPE ty_board + RETURNING VALUE(rv_count) TYPE ty_count. +ENDINTERFACE. diff --git a/tasks_gen/train/G1938/generation.json b/tasks_gen/train/G1938/generation.json new file mode 100644 index 0000000..f4d514a --- /dev/null +++ b/tasks_gen/train/G1938/generation.json @@ -0,0 +1,24 @@ +{ + "id": "G1938", + "pool": "train", + "object_type": "INTF", + "category": "A", + "attempts": [ + { + "stage": "validate", + "oracle": 85.0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 5, + "killed": 5, + "ok": true + } + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1938/hidden/t02_hidden.clas.abap b/tasks_gen/train/G1938/hidden/t02_hidden.clas.abap new file mode 100644 index 0000000..3e6f6db --- /dev/null +++ b/tasks_gen/train/G1938/hidden/t02_hidden.clas.abap @@ -0,0 +1,124 @@ +CLASS {{p}}t02_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + + PUBLIC SECTION. + INTERFACES {{p}}if_log_plan. + + PRIVATE SECTION. + METHODS reason_ok FOR TESTING. + METHODS reason_size FOR TESTING. + METHODS reason_thick FOR TESTING. + METHODS reason_width FOR TESTING. + METHODS reason_len FOR TESTING. + METHODS limits_are_set FOR TESTING. + METHODS reason_type_is_char10 FOR TESTING. + METHODS count_type_is_integer FOR TESTING. + METHODS log_type_is_two_ints FOR TESTING. + METHODS board_type_is_two_ints FOR TESTING. + METHODS signatures_match FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t02_hidden IMPLEMENTATION. + METHOD {{p}}if_log_plan~check. + rv_reason = {{p}}if_log_plan=>c_reason-ok. + ENDMETHOD. + + METHOD {{p}}if_log_plan~board_count. + rv_count = 0. + ENDMETHOD. + + METHOD reason_ok. + cl_abap_unit_assert=>assert_equals( exp = 'OK' + act = {{p}}if_log_plan=>c_reason-ok ). + ENDMETHOD. + + METHOD reason_size. + cl_abap_unit_assert=>assert_equals( exp = 'SIZE' + act = {{p}}if_log_plan=>c_reason-size ). + ENDMETHOD. + + METHOD reason_thick. + cl_abap_unit_assert=>assert_equals( exp = 'THICK' + act = {{p}}if_log_plan=>c_reason-thick ). + ENDMETHOD. + + METHOD reason_width. + cl_abap_unit_assert=>assert_equals( exp = 'WIDTH' + act = {{p}}if_log_plan=>c_reason-width ). + ENDMETHOD. + + METHOD reason_len. + cl_abap_unit_assert=>assert_equals( exp = 'LEN' + act = {{p}}if_log_plan=>c_reason-len ). + ENDMETHOD. + + METHOD limits_are_set. + cl_abap_unit_assert=>assert_equals( exp = 20 act = {{p}}if_log_plan=>c_min_thick ). + cl_abap_unit_assert=>assert_equals( exp = 100 act = {{p}}if_log_plan=>c_max_thick ). + cl_abap_unit_assert=>assert_equals( exp = 100 act = {{p}}if_log_plan=>c_min_len ). + cl_abap_unit_assert=>assert_equals( + exp = cl_abap_typedescr=>typekind_int + act = cl_abap_typedescr=>describe_by_data( {{p}}if_log_plan=>c_min_thick )->type_kind ). + ENDMETHOD. + + METHOD reason_type_is_char10. + DATA lv_reason TYPE {{p}}if_log_plan=>ty_reason. + DATA lv_len TYPE i. + DESCRIBE FIELD lv_reason LENGTH lv_len IN CHARACTER MODE. + cl_abap_unit_assert=>assert_equals( exp = 10 act = lv_len ). + cl_abap_unit_assert=>assert_equals( + exp = cl_abap_typedescr=>typekind_char + act = cl_abap_typedescr=>describe_by_data( lv_reason )->type_kind ). + ENDMETHOD. + + METHOD count_type_is_integer. + DATA lv_count TYPE {{p}}if_log_plan=>ty_count. + cl_abap_unit_assert=>assert_equals( + exp = cl_abap_typedescr=>typekind_int + act = cl_abap_typedescr=>describe_by_data( lv_count )->type_kind ). + ENDMETHOD. + + METHOD log_type_is_two_ints. + DATA(ls_log) = VALUE {{p}}if_log_plan=>ty_log( dia = 300 len = 400 ). + DATA(lo_descr) = CAST cl_abap_structdescr( + cl_abap_typedescr=>describe_by_data( ls_log ) ). + DATA(lt_comp) = lo_descr->get_components( ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_comp ) ). + cl_abap_unit_assert=>assert_equals( + exp = cl_abap_typedescr=>typekind_int + act = cl_abap_typedescr=>describe_by_data( ls_log-dia )->type_kind ). + cl_abap_unit_assert=>assert_equals( + exp = cl_abap_typedescr=>typekind_int + act = cl_abap_typedescr=>describe_by_data( ls_log-len )->type_kind ). + ENDMETHOD. + + METHOD board_type_is_two_ints. + DATA(ls_board) = VALUE {{p}}if_log_plan=>ty_board( thick = 40 width = 200 ). + DATA(lo_descr) = CAST cl_abap_structdescr( + cl_abap_typedescr=>describe_by_data( ls_board ) ). + DATA(lt_comp) = lo_descr->get_components( ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_comp ) ). + cl_abap_unit_assert=>assert_equals( + exp = cl_abap_typedescr=>typekind_int + act = cl_abap_typedescr=>describe_by_data( ls_board-thick )->type_kind ). + cl_abap_unit_assert=>assert_equals( + exp = cl_abap_typedescr=>typekind_int + act = cl_abap_typedescr=>describe_by_data( ls_board-width )->type_kind ). + ENDMETHOD. + + METHOD signatures_match. + DATA(ls_log) = VALUE {{p}}if_log_plan=>ty_log( dia = 300 len = 400 ). + DATA(ls_board) = VALUE {{p}}if_log_plan=>ty_board( thick = 40 width = 200 ). + DATA(lv_reason) = me->{{p}}if_log_plan~check( is_log = ls_log is_board = ls_board ). + DATA(lv_count) = me->{{p}}if_log_plan~board_count( is_log = ls_log is_board = ls_board ). + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_log_plan=>c_reason-ok act = lv_reason ). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_count ). + DATA lv_len TYPE i. + DESCRIBE FIELD lv_reason LENGTH lv_len IN CHARACTER MODE. + cl_abap_unit_assert=>assert_equals( exp = 10 act = lv_len ). + cl_abap_unit_assert=>assert_equals( + exp = cl_abap_typedescr=>typekind_int + act = cl_abap_typedescr=>describe_by_data( lv_count )->type_kind ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1938/mutation.json b/tasks_gen/train/G1938/mutation.json new file mode 100644 index 0000000..493cabf --- /dev/null +++ b/tasks_gen/train/G1938/mutation.json @@ -0,0 +1,55 @@ +{ + "task": "G1938", + "mutants": [ + { + "object": "{{P}}IF_LOG_PLAN", + "mutant": "line 3: LENGTH 10 -> LENGTH 9 (length)", + "status": "killed", + "hidden": "9/11", + "failed_tests": [ + "REASON_TYPE_IS_CHAR10", + "SIGNATURES_MATCH" + ] + }, + { + "object": "{{P}}IF_LOG_PLAN", + "mutant": "line 16: VALUE 'OK' -> VALUE 'ZK' (lit)", + "status": "killed", + "hidden": "10/11", + "failed_tests": [ + "REASON_OK" + ] + }, + { + "object": "{{P}}IF_LOG_PLAN", + "mutant": "line 18: VALUE 'THICK' -> VALUE 'ZHICK' (lit)", + "status": "killed", + "hidden": "10/11", + "failed_tests": [ + "REASON_THICK" + ] + }, + { + "object": "{{P}}IF_LOG_PLAN", + "mutant": "line 20: VALUE 'LEN' -> VALUE 'ZEN' (lit)", + "status": "killed", + "hidden": "10/11", + "failed_tests": [ + "REASON_LEN" + ] + }, + { + "object": "{{P}}IF_LOG_PLAN", + "mutant": "line 24: VALUE 100 -> VALUE 101 (const)", + "status": "killed", + "hidden": "10/11", + "failed_tests": [ + "LIMITS_ARE_SET" + ] + } + ], + "valid": 5, + "killed": 5, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1938/reference/if_log_plan.intf.abap b/tasks_gen/train/G1938/reference/if_log_plan.intf.abap new file mode 100644 index 0000000..70e9512 --- /dev/null +++ b/tasks_gen/train/G1938/reference/if_log_plan.intf.abap @@ -0,0 +1,35 @@ +INTERFACE {{p}}if_log_plan PUBLIC. + TYPES: + ty_reason TYPE c LENGTH 10, + ty_count TYPE i, + BEGIN OF ty_log, + dia TYPE i, + len TYPE i, + END OF ty_log, + BEGIN OF ty_board, + thick TYPE i, + width TYPE i, + END OF ty_board. + + CONSTANTS: + BEGIN OF c_reason, + ok TYPE ty_reason VALUE 'OK', + size TYPE ty_reason VALUE 'SIZE', + thick TYPE ty_reason VALUE 'THICK', + width TYPE ty_reason VALUE 'WIDTH', + len TYPE ty_reason VALUE 'LEN', + END OF c_reason, + c_min_thick TYPE i VALUE 20, + c_max_thick TYPE i VALUE 100, + c_min_len TYPE i VALUE 100. + + METHODS check + IMPORTING is_log TYPE ty_log + is_board TYPE ty_board + RETURNING VALUE(rv_reason) TYPE ty_reason. + + METHODS board_count + IMPORTING is_log TYPE ty_log + is_board TYPE ty_board + RETURNING VALUE(rv_count) TYPE ty_count. +ENDINTERFACE. diff --git a/tasks_gen/train/G1938/reference/if_log_plan_test.clas.abap b/tasks_gen/train/G1938/reference/if_log_plan_test.clas.abap new file mode 100644 index 0000000..9b99c53 --- /dev/null +++ b/tasks_gen/train/G1938/reference/if_log_plan_test.clas.abap @@ -0,0 +1,70 @@ +CLASS {{p}}if_log_plan_test DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + + PUBLIC SECTION. + INTERFACES {{p}}if_log_plan. + + PRIVATE SECTION. + METHODS reasons_are_set FOR TESTING. + METHODS limits_are_set FOR TESTING. + METHODS types_are_set FOR TESTING. + METHODS signatures_match FOR TESTING. +ENDCLASS. + + +CLASS {{p}}if_log_plan_test IMPLEMENTATION. + METHOD {{p}}if_log_plan~check. + rv_reason = {{p}}if_log_plan=>c_reason-ok. + ENDMETHOD. + + METHOD {{p}}if_log_plan~board_count. + rv_count = 0. + ENDMETHOD. + + METHOD reasons_are_set. + cl_abap_unit_assert=>assert_equals( exp = 'OK' + act = {{p}}if_log_plan=>c_reason-ok ). + cl_abap_unit_assert=>assert_equals( exp = 'SIZE' + act = {{p}}if_log_plan=>c_reason-size ). + cl_abap_unit_assert=>assert_equals( exp = 'THICK' + act = {{p}}if_log_plan=>c_reason-thick ). + cl_abap_unit_assert=>assert_equals( exp = 'WIDTH' + act = {{p}}if_log_plan=>c_reason-width ). + cl_abap_unit_assert=>assert_equals( exp = 'LEN' + act = {{p}}if_log_plan=>c_reason-len ). + ENDMETHOD. + + METHOD limits_are_set. + cl_abap_unit_assert=>assert_equals( exp = 20 act = {{p}}if_log_plan=>c_min_thick ). + cl_abap_unit_assert=>assert_equals( exp = 100 act = {{p}}if_log_plan=>c_max_thick ). + cl_abap_unit_assert=>assert_equals( exp = 100 act = {{p}}if_log_plan=>c_min_len ). + ENDMETHOD. + + METHOD types_are_set. + DATA lv_len TYPE i. + DATA lv_reason TYPE {{p}}if_log_plan=>ty_reason. + DESCRIBE FIELD lv_reason LENGTH lv_len IN CHARACTER MODE. + cl_abap_unit_assert=>assert_equals( exp = 10 act = lv_len ). + + DATA(ls_log) = VALUE {{p}}if_log_plan=>ty_log( dia = 300 len = 400 ). + DATA(lo_log) = CAST cl_abap_structdescr( + cl_abap_typedescr=>describe_by_data( ls_log ) ). + cl_abap_unit_assert=>assert_equals( exp = 2 + act = lines( lo_log->get_components( ) ) ). + + DATA(ls_board) = VALUE {{p}}if_log_plan=>ty_board( thick = 40 width = 200 ). + DATA(lo_board) = CAST cl_abap_structdescr( + cl_abap_typedescr=>describe_by_data( ls_board ) ). + cl_abap_unit_assert=>assert_equals( exp = 2 + act = lines( lo_board->get_components( ) ) ). + ENDMETHOD. + + METHOD signatures_match. + DATA(ls_log) = VALUE {{p}}if_log_plan=>ty_log( dia = 300 len = 400 ). + DATA(ls_board) = VALUE {{p}}if_log_plan=>ty_board( thick = 40 width = 200 ). + DATA(lv_reason) = me->{{p}}if_log_plan~check( is_log = ls_log is_board = ls_board ). + DATA(lv_count) = me->{{p}}if_log_plan~board_count( is_log = ls_log is_board = ls_board ). + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_log_plan=>c_reason-ok act = lv_reason ). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_count ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1938/spec.md b/tasks_gen/train/G1938/spec.md new file mode 100644 index 0000000..29967b2 --- /dev/null +++ b/tasks_gen/train/G1938/spec.md @@ -0,0 +1,63 @@ +# 1. Goal +Define the interface {{P}}IF_LOG_PLAN in package $TMP. The sawmill office and the +sawyer's terminal use this interface to plan the cutting of a log. The interface +is the contract. It fixes the reason codes, the limits and the two method +signatures. + +# 2. Open questions +None. + +# 3. Context +- A sawmill cuts logs into boards. A log has a diameter in millimetres and a + length in centimetres. A board has a thickness in millimetres and a width in + millimetres. +- The office checks an order before the sawyer starts. The reason codes name the + first check that fails: + SIZE - a value is zero or negative. + THICK - the board thickness is outside the limits. + WIDTH - the board is wider than the log. + LEN - the log is shorter than the minimum length. + OK - the order is valid. +- If the check returns OK, the office asks for the number of boards. The number + of boards is the log diameter in millimetres divided by the board thickness in + millimetres, rounded down. +- The interface is the only object of this task. No class implements it here. + +# 4. Contract +- Create the interface {{P}}IF_LOG_PLAN in package $TMP. +- The interface has exactly two methods: check and board_count. +- Do not add other methods. + +# 5. Business rules +1. The interface defines the type ty_reason. ty_reason is a character type of + length 10. +2. The interface defines the type ty_count. ty_count is an integer type. +3. The interface defines the structure type ty_log. ty_log has exactly the two + components dia and len. dia is an integer, the log diameter in millimetres. + len is an integer, the log length in centimetres. +4. The interface defines the structure type ty_board. ty_board has exactly the + two components thick and width. thick is an integer, the board thickness in + millimetres. width is an integer, the board width in millimetres. +5. The interface defines the constant structure c_reason. c_reason has exactly + the five components ok, size, thick, width and len. All five components have + the type ty_reason. The values are 'OK', 'SIZE', 'THICK', 'WIDTH' and 'LEN'. +6. The interface defines the constant c_min_thick with the value 20, the constant + c_max_thick with the value 100 and the constant c_min_len with the value 100. + All three constants have the type i. +7. The interface defines the method check. check has the importing parameters + is_log (TYPE ty_log) and is_board (TYPE ty_board). check has the returning + parameter rv_reason (TYPE ty_reason). +8. The interface defines the method board_count. board_count has the importing + parameters is_log (TYPE ty_log) and is_board (TYPE ty_board). board_count has + the returning parameter rv_count (TYPE ty_count). + +# 6. Constraints +- Release target: SAP_BASIS 8.16. +- Coding standards: Clean ABAP. No comment that restates the code. +- Out of scope: do not create a class that implements {{P}}IF_LOG_PLAN. Do not + create database tables or CDS views. + +# 7. Acceptance +- The interface is active and has no syntax error. +- The hidden tests pass. +- Write your own ABAP Unit tests for the interface. diff --git a/tasks_gen/train/G1938/task.json b/tasks_gen/train/G1938/task.json new file mode 100644 index 0000000..a43c9ca --- /dev/null +++ b/tasks_gen/train/G1938/task.json @@ -0,0 +1,50 @@ +{ + "id": "G1938", + "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_LOG_PLAN" + } + ], + "out_of_scope": [ + "A class that implements {{P}}IF_LOG_PLAN", + "Database tables", + "CDS views" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T02_HIDDEN", + "file": "hidden/t02_hidden.clas.abap", + "description": "Checks the interface {{P}}IF_LOG_PLAN: constants, types and method signatures." + } + ], + "reference": [ + { + "type": "INTF", + "name": "{{P}}IF_LOG_PLAN", + "file": "reference/if_log_plan.intf.abap", + "description": "Contract for the sawmill log plan" + }, + { + "type": "CLAS", + "name": "{{P}}IF_LOG_PLAN_TEST", + "file": "reference/if_log_plan_test.clas.abap", + "description": "Own ABAP Unit tests for the interface" + } + ], + "craft_checks": [ + "method_length", + "db_operation_in_loop" + ] +} \ No newline at end of file diff --git a/tasks_gen/train/G1939/faulty/m0_pluck.tabl.asabap b/tasks_gen/train/G1939/faulty/m0_pluck.tabl.asabap new file mode 100644 index 0000000..bd314e2 --- /dev/null +++ b/tasks_gen/train/G1939/faulty/m0_pluck.tabl.asabap @@ -0,0 +1,18 @@ +@EndUserText.label : 'Tea leaf plucking batch' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}pluck { + key client : abap.clnt not null; + pluck_id : abap.char(10) not null; + field_id : abap.char(6) not null; + pluck_date : abap.dats not null; + team_no : abap.numc(4); + leaf_weight : abap.dec(13,3) not null; + leaf_grade : abap.char(2); + moisture : abap.dec(5,2); + wither_min : abap.int4; + price_per_kg : abap.dec(11,2); + note : abap.char(40); +} diff --git a/tasks_gen/train/G1939/faulty/m1_pluck.tabl.asabap b/tasks_gen/train/G1939/faulty/m1_pluck.tabl.asabap new file mode 100644 index 0000000..a0a8a20 --- /dev/null +++ b/tasks_gen/train/G1939/faulty/m1_pluck.tabl.asabap @@ -0,0 +1,18 @@ +@EndUserText.label : 'Tea leaf plucking batch' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}pluck { + key client : abap.clnt not null; + key pluck_id : abap.char(10) not null; + field_id : abap.char(6) not null; + pluck_date : abap.tims not null; + team_no : abap.numc(4); + leaf_weight : abap.dec(13,3) not null; + leaf_grade : abap.char(2); + moisture : abap.dec(5,2); + wither_min : abap.int4; + price_per_kg : abap.dec(11,2); + note : abap.char(40); +} diff --git a/tasks_gen/train/G1939/faulty/m2_pluck.tabl.asabap b/tasks_gen/train/G1939/faulty/m2_pluck.tabl.asabap new file mode 100644 index 0000000..f9e2a2c --- /dev/null +++ b/tasks_gen/train/G1939/faulty/m2_pluck.tabl.asabap @@ -0,0 +1,18 @@ +@EndUserText.label : 'Tea leaf plucking batch' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}pluck { + key client : abap.clnt not null; + key pluck_id : abap.char(10) not null; + field_id : abap.char(6) not null; + pluck_date : abap.dats not null; + team_no : abap.numc(3); + leaf_weight : abap.dec(13,3) not null; + leaf_grade : abap.char(2); + moisture : abap.dec(5,2); + wither_min : abap.int4; + price_per_kg : abap.dec(11,2); + note : abap.char(40); +} diff --git a/tasks_gen/train/G1939/faulty/m4_pluck.tabl.asabap b/tasks_gen/train/G1939/faulty/m4_pluck.tabl.asabap new file mode 100644 index 0000000..83a78c5 --- /dev/null +++ b/tasks_gen/train/G1939/faulty/m4_pluck.tabl.asabap @@ -0,0 +1,18 @@ +@EndUserText.label : 'Tea leaf plucking batch' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}pluck { + key client : abap.clnt not null; + key pluck_id : abap.char(10) not null; + field_id : abap.char(6) not null; + pluck_date : abap.dats not null; + team_no : abap.numc(4); + leaf_weight : abap.dec(13,3) not null; + leaf_grade : abap.char(2); + moisture : abap.dec(5,2); + wither_min : abap.int4; + price_per_kg : abap.dec(11,3); + note : abap.char(40); +} diff --git a/tasks_gen/train/G1939/generation.json b/tasks_gen/train/G1939/generation.json new file mode 100644 index 0000000..47cfbcb --- /dev/null +++ b/tasks_gen/train/G1939/generation.json @@ -0,0 +1,24 @@ +{ + "id": "G1939", + "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": 4, + "ok": true + } + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1939/hidden/pluck_hidden.clas.abap b/tasks_gen/train/G1939/hidden/pluck_hidden.clas.abap new file mode 100644 index 0000000..aa3187a --- /dev/null +++ b/tasks_gen/train/G1939/hidden/pluck_hidden.clas.abap @@ -0,0 +1,171 @@ +CLASS {{p}}pluck_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + TYPES ty_name_tab TYPE STANDARD TABLE OF fieldname WITH EMPTY KEY. + TYPES ty_field_tab TYPE STANDARD TABLE OF dfies WITH EMPTY KEY. + CLASS-DATA go_env TYPE REF TO if_osql_test_environment. + CLASS-DATA gt_fields TYPE ty_field_tab. + CLASS-METHODS class_setup. + CLASS-METHODS class_teardown. + METHODS setup. + METHODS field_names FOR TESTING. + METHODS key_fields FOR TESTING. + METHODS char_lengths FOR TESTING. + METHODS packed_lengths FOR TESTING. + METHODS other_types FOR TESTING. + METHODS insert_and_read FOR TESTING. + METHODS duplicate_key FOR TESTING. + METHODS empty_fields FOR TESTING. + METHODS get_field + IMPORTING iv_name TYPE fieldname + RETURNING VALUE(rs_field) TYPE dfies. +ENDCLASS. + + +CLASS {{p}}pluck_hidden IMPLEMENTATION. + + METHOD class_setup. + DATA lo_descr TYPE REF TO cl_abap_typedescr. + DATA lo_line TYPE REF TO cl_abap_typedescr. + DATA lo_struct TYPE REF TO cl_abap_structdescr. + lo_descr = cl_abap_typedescr=>describe_by_name( '{{P}}PLUCK' ). + IF lo_descr->kind = cl_abap_typedescr=>kind_table. + lo_line = CAST cl_abap_tabledescr( lo_descr )->get_table_line_type( ). + lo_struct = CAST cl_abap_structdescr( lo_line ). + ELSE. + lo_struct = CAST cl_abap_structdescr( lo_descr ). + ENDIF. + gt_fields = lo_struct->get_ddic_field_list( ). + go_env = cl_osql_test_environment=>create( i_dependency_list = VALUE #( ( '{{P}}PLUCK' ) ) ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + go_env->clear_doubles( ). + ENDMETHOD. + + METHOD get_field. + READ TABLE gt_fields WITH KEY fieldname = iv_name INTO rs_field. + ENDMETHOD. + + METHOD field_names. + DATA(lt_expected) = VALUE ty_name_tab( ( 'CLIENT' ) ( 'PLUCK_ID' ) ( 'FIELD_ID' ) + ( 'PLUCK_DATE' ) ( 'TEAM_NO' ) ( 'LEAF_WEIGHT' ) + ( 'LEAF_GRADE' ) ( 'MOISTURE' ) ( 'WITHER_MIN' ) + ( 'PRICE_PER_KG' ) ( 'NOTE' ) ). + DATA lv_index TYPE i. + cl_abap_unit_assert=>assert_equals( exp = lines( lt_expected ) act = lines( gt_fields ) ). + LOOP AT lt_expected INTO DATA(lv_name). + lv_index = lv_index + 1. + READ TABLE gt_fields INTO DATA(ls_field) INDEX lv_index. + cl_abap_unit_assert=>assert_equals( exp = lv_name act = ls_field-fieldname ). + ENDLOOP. + ENDMETHOD. + + METHOD key_fields. + cl_abap_unit_assert=>assert_equals( exp = 'X' act = get_field( 'CLIENT' )-keyflag ). + cl_abap_unit_assert=>assert_equals( exp = 'X' act = get_field( 'PLUCK_ID' )-keyflag ). + cl_abap_unit_assert=>assert_equals( exp = ' ' act = get_field( 'FIELD_ID' )-keyflag ). + cl_abap_unit_assert=>assert_equals( exp = ' ' act = get_field( 'PLUCK_DATE' )-keyflag ). + cl_abap_unit_assert=>assert_equals( exp = ' ' act = get_field( 'NOTE' )-keyflag ). + ENDMETHOD. + + METHOD char_lengths. + cl_abap_unit_assert=>assert_equals( exp = 3 act = get_field( 'CLIENT' )-leng ). + cl_abap_unit_assert=>assert_equals( exp = 10 act = get_field( 'PLUCK_ID' )-leng ). + cl_abap_unit_assert=>assert_equals( exp = 6 act = get_field( 'FIELD_ID' )-leng ). + cl_abap_unit_assert=>assert_equals( exp = 8 act = get_field( 'PLUCK_DATE' )-leng ). + cl_abap_unit_assert=>assert_equals( exp = 4 act = get_field( 'TEAM_NO' )-leng ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = get_field( 'LEAF_GRADE' )-leng ). + cl_abap_unit_assert=>assert_equals( exp = 40 act = get_field( 'NOTE' )-leng ). + ENDMETHOD. + + METHOD packed_lengths. + cl_abap_unit_assert=>assert_equals( exp = 13 act = get_field( 'LEAF_WEIGHT' )-leng ). + cl_abap_unit_assert=>assert_equals( exp = 3 act = get_field( 'LEAF_WEIGHT' )-decimals ). + cl_abap_unit_assert=>assert_equals( exp = 5 act = get_field( 'MOISTURE' )-leng ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = get_field( 'MOISTURE' )-decimals ). + cl_abap_unit_assert=>assert_equals( exp = 11 act = get_field( 'PRICE_PER_KG' )-leng ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = get_field( 'PRICE_PER_KG' )-decimals ). + ENDMETHOD. + + METHOD other_types. + cl_abap_unit_assert=>assert_equals( exp = 'CLNT' act = get_field( 'CLIENT' )-datatype ). + cl_abap_unit_assert=>assert_equals( exp = 'CHAR' act = get_field( 'PLUCK_ID' )-datatype ). + cl_abap_unit_assert=>assert_equals( exp = 'CHAR' act = get_field( 'FIELD_ID' )-datatype ). + cl_abap_unit_assert=>assert_equals( exp = 'DATS' act = get_field( 'PLUCK_DATE' )-datatype ). + cl_abap_unit_assert=>assert_equals( exp = 'NUMC' act = get_field( 'TEAM_NO' )-datatype ). + cl_abap_unit_assert=>assert_equals( exp = 'DEC' act = get_field( 'LEAF_WEIGHT' )-datatype ). + cl_abap_unit_assert=>assert_equals( exp = 'DEC' act = get_field( 'MOISTURE' )-datatype ). + cl_abap_unit_assert=>assert_equals( exp = 'INT4' act = get_field( 'WITHER_MIN' )-datatype ). + cl_abap_unit_assert=>assert_equals( exp = 'DEC' act = get_field( 'PRICE_PER_KG' )-datatype ). + cl_abap_unit_assert=>assert_equals( exp = 'C' act = get_field( 'CLIENT' )-inttype ). + cl_abap_unit_assert=>assert_equals( exp = 'D' act = get_field( 'PLUCK_DATE' )-inttype ). + cl_abap_unit_assert=>assert_equals( exp = 'N' act = get_field( 'TEAM_NO' )-inttype ). + cl_abap_unit_assert=>assert_equals( exp = 'P' act = get_field( 'LEAF_WEIGHT' )-inttype ). + cl_abap_unit_assert=>assert_equals( exp = 'I' act = get_field( 'WITHER_MIN' )-inttype ). + cl_abap_unit_assert=>assert_equals( exp = 10 act = get_field( 'WITHER_MIN' )-leng ). + ENDMETHOD. + + METHOD insert_and_read. + DATA ls_row TYPE {{p}}pluck. + DATA lv_date TYPE {{p}}pluck-pluck_date. + DATA lv_weight TYPE {{p}}pluck-leaf_weight. + lv_date = '20240401'. + lv_weight = '850.250'. + ls_row = VALUE #( pluck_id = 'B0001' + field_id = 'F01' + pluck_date = lv_date + team_no = '0012' + leaf_weight = lv_weight + leaf_grade = 'A1' + moisture = '3.50' + wither_min = 120 + price_per_kg = '2.10' + note = 'first flush' ). + INSERT {{p}}pluck FROM @ls_row. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + SELECT SINGLE field_id, pluck_date, leaf_weight, wither_min, price_per_kg, note + FROM {{p}}pluck + WHERE pluck_id = 'B0001' + INTO @DATA(ls_read). + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + cl_abap_unit_assert=>assert_equals( exp = 'F01' act = ls_read-field_id ). + cl_abap_unit_assert=>assert_equals( exp = lv_date act = ls_read-pluck_date ). + cl_abap_unit_assert=>assert_equals( exp = lv_weight act = ls_read-leaf_weight ). + cl_abap_unit_assert=>assert_equals( exp = 120 act = ls_read-wither_min ). + cl_abap_unit_assert=>assert_equals( exp = 'first flush' act = ls_read-note ). + ENDMETHOD. + + METHOD duplicate_key. + DATA ls_row TYPE {{p}}pluck. + ls_row = VALUE #( pluck_id = 'B0002' field_id = 'F02' pluck_date = '20240402' + leaf_weight = '100.000' ). + INSERT {{p}}pluck FROM @ls_row. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + INSERT {{p}}pluck FROM @ls_row. + cl_abap_unit_assert=>assert_equals( exp = 4 act = sy-subrc ). + ENDMETHOD. + + METHOD empty_fields. + DATA ls_row TYPE {{p}}pluck. + ls_row = VALUE #( pluck_id = 'B0003' field_id = 'F03' pluck_date = '20240403' + leaf_weight = '0.000' ). + INSERT {{p}}pluck FROM @ls_row. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + SELECT SINGLE team_no, leaf_grade, moisture, wither_min, note + FROM {{p}}pluck + WHERE pluck_id = 'B0003' + INTO @DATA(ls_read). + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + cl_abap_unit_assert=>assert_initial( act = ls_read-team_no ). + cl_abap_unit_assert=>assert_initial( act = ls_read-leaf_grade ). + cl_abap_unit_assert=>assert_initial( act = ls_read-moisture ). + cl_abap_unit_assert=>assert_initial( act = ls_read-wither_min ). + cl_abap_unit_assert=>assert_initial( act = ls_read-note ). + ENDMETHOD. + +ENDCLASS. diff --git a/tasks_gen/train/G1939/mutation.json b/tasks_gen/train/G1939/mutation.json new file mode 100644 index 0000000..d571f3b --- /dev/null +++ b/tasks_gen/train/G1939/mutation.json @@ -0,0 +1,53 @@ +{ + "task": "G1939", + "mutants": [ + { + "object": "{{P}}PLUCK", + "mutant": "line 8: key pluck_id : -> pluck_id : (key)", + "status": "killed", + "hidden": "7/8", + "failed_tests": [ + "KEY_FIELDS" + ] + }, + { + "object": "{{P}}PLUCK", + "mutant": "line 10: abap.dats -> abap.tims (type)", + "status": "killed", + "hidden": "6/8", + "failed_tests": [ + "CHAR_LENGTHS", + "OTHER_TYPES" + ] + }, + { + "object": "{{P}}PLUCK", + "mutant": "line 11: abap.numc(4) -> abap.numc(3) (length)", + "status": "killed", + "hidden": "7/8", + "failed_tests": [ + "CHAR_LENGTHS" + ] + }, + { + "object": "{{P}}PLUCK", + "mutant": "line 13: abap.char(2) -> abap.numc(2) (type)", + "status": "survived", + "hidden": "8/8", + "failed_tests": [] + }, + { + "object": "{{P}}PLUCK", + "mutant": "line 16: abap.dec(11,2) -> abap.dec(11,3) (decimals)", + "status": "killed", + "hidden": "7/8", + "failed_tests": [ + "PACKED_LENGTHS" + ] + } + ], + "valid": 5, + "killed": 4, + "kill_rate": 0.8, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1939/reference/pluck.tabl.asabap b/tasks_gen/train/G1939/reference/pluck.tabl.asabap new file mode 100644 index 0000000..812b89f --- /dev/null +++ b/tasks_gen/train/G1939/reference/pluck.tabl.asabap @@ -0,0 +1,18 @@ +@EndUserText.label : 'Tea leaf plucking batch' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}pluck { + key client : abap.clnt not null; + key pluck_id : abap.char(10) not null; + field_id : abap.char(6) not null; + pluck_date : abap.dats not null; + team_no : abap.numc(4); + leaf_weight : abap.dec(13,3) not null; + leaf_grade : abap.char(2); + moisture : abap.dec(5,2); + wither_min : abap.int4; + price_per_kg : abap.dec(11,2); + note : abap.char(40); +} diff --git a/tasks_gen/train/G1939/reference/pluck_test.clas.abap b/tasks_gen/train/G1939/reference/pluck_test.clas.abap new file mode 100644 index 0000000..e74e835 --- /dev/null +++ b/tasks_gen/train/G1939/reference/pluck_test.clas.abap @@ -0,0 +1,98 @@ +CLASS {{p}}pluck_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_a_batch FOR TESTING. + METHODS rejects_duplicate_key FOR TESTING. + METHODS keeps_empty_fields FOR TESTING. + METHODS counts_the_batches FOR TESTING. +ENDCLASS. + + +CLASS {{p}}pluck_test IMPLEMENTATION. + + METHOD class_setup. + go_env = cl_osql_test_environment=>create( i_dependency_list = VALUE #( ( '{{P}}PLUCK' ) ) ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + go_env->clear_doubles( ). + ENDMETHOD. + + METHOD stores_a_batch. + DATA ls_row TYPE {{p}}pluck. + DATA lv_date TYPE {{p}}pluck-pluck_date. + DATA lv_weight TYPE {{p}}pluck-leaf_weight. + lv_date = '20240401'. + lv_weight = '850.250'. + ls_row = VALUE #( pluck_id = 'B0001' + field_id = 'F01' + pluck_date = lv_date + team_no = '0012' + leaf_weight = lv_weight + leaf_grade = 'A1' + moisture = '3.50' + wither_min = 120 + price_per_kg = '2.10' + note = 'first flush' ). + INSERT {{p}}pluck FROM @ls_row. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + SELECT SINGLE field_id, pluck_date, leaf_weight, wither_min, note + FROM {{p}}pluck + WHERE pluck_id = 'B0001' + INTO @DATA(ls_read). + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + cl_abap_unit_assert=>assert_equals( exp = 'F01' act = ls_read-field_id ). + cl_abap_unit_assert=>assert_equals( exp = lv_date act = ls_read-pluck_date ). + cl_abap_unit_assert=>assert_equals( exp = lv_weight act = ls_read-leaf_weight ). + cl_abap_unit_assert=>assert_equals( exp = 120 act = ls_read-wither_min ). + cl_abap_unit_assert=>assert_equals( exp = 'first flush' act = ls_read-note ). + ENDMETHOD. + + METHOD rejects_duplicate_key. + DATA ls_row TYPE {{p}}pluck. + ls_row = VALUE #( pluck_id = 'B0002' field_id = 'F02' pluck_date = '20240402' + leaf_weight = '100.000' ). + INSERT {{p}}pluck FROM @ls_row. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + INSERT {{p}}pluck FROM @ls_row. + cl_abap_unit_assert=>assert_equals( exp = 4 act = sy-subrc ). + ENDMETHOD. + + METHOD keeps_empty_fields. + DATA ls_row TYPE {{p}}pluck. + ls_row = VALUE #( pluck_id = 'B0003' field_id = 'F03' pluck_date = '20240403' + leaf_weight = '0.000' ). + INSERT {{p}}pluck FROM @ls_row. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + SELECT SINGLE team_no, leaf_grade, wither_min, note + FROM {{p}}pluck + WHERE pluck_id = 'B0003' + INTO @DATA(ls_read). + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + cl_abap_unit_assert=>assert_initial( act = ls_read-team_no ). + cl_abap_unit_assert=>assert_initial( act = ls_read-leaf_grade ). + cl_abap_unit_assert=>assert_initial( act = ls_read-wither_min ). + cl_abap_unit_assert=>assert_initial( act = ls_read-note ). + ENDMETHOD. + + METHOD counts_the_batches. + DATA lt_rows TYPE STANDARD TABLE OF {{p}}pluck WITH EMPTY KEY. + lt_rows = VALUE #( ( pluck_id = 'B0001' field_id = 'F01' pluck_date = '20240401' + leaf_weight = '1.000' ) + ( pluck_id = 'B0002' field_id = 'F01' pluck_date = '20240402' + leaf_weight = '2.000' ) ). + INSERT {{p}}pluck FROM TABLE @lt_rows. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + SELECT COUNT(*) FROM {{p}}pluck INTO @DATA(lv_count). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lv_count ). + ENDMETHOD. + +ENDCLASS. diff --git a/tasks_gen/train/G1939/spec.md b/tasks_gen/train/G1939/spec.md new file mode 100644 index 0000000..5495355 --- /dev/null +++ b/tasks_gen/train/G1939/spec.md @@ -0,0 +1,59 @@ +# 1. Goal +The tea plantation "Highland Leaf" picks the green leaf of its tea fields in +batches. The plantation must store every plucking batch in one database table. +The factory office, the field book and later evaluations read this table, so +the field names and the data types must be exact. + +# 2. Open questions +None. + +# 3. Context +- One plucking batch is the green leaf of one tea field on one day. +- The table is new and is in package $TMP. The table is client-dependent. +- No other object uses the table yet. + +# 4. Contract +- Create the database table {{P}}PLUCK in package $TMP. The table is +transparent. +- The table is not extensible. Delivery class A. Data maintenance is +restricted. +- The table has these fields, in this order: +CLIENT, PLUCK_ID, FIELD_ID, PLUCK_DATE, TEAM_NO, LEAF_WEIGHT, LEAF_GRADE, +MOISTURE, WITHER_MIN, PRICE_PER_KG, NOTE. +- Key fields: CLIENT and PLUCK_ID. + +# 5. Business rules +1. CLIENT is the client field of the table. Data type: client, length 3. Key +field. Not null. +2. PLUCK_ID is the number of the plucking batch. Data type: character, length +10. Key field. Not null. +3. FIELD_ID is the tea field. Data type: character, length 6. Not null. +4. PLUCK_DATE is the day of the plucking. Data type: date, length 8. Not null. +5. TEAM_NO is the number of the picking team. Data type: numeric text, length +4. The field can be empty. +6. LEAF_WEIGHT is the weight of the green leaf in kilogram. Data type: packed +number, 13 digits, 3 decimal places. Not null. +7. LEAF_GRADE is the grade code of the green leaf. Data type: character, +length 2. The field can be empty. +8. MOISTURE is the moisture of the green leaf in percent. Data type: packed +number, 5 digits, 2 decimal places. The field can be empty. +9. WITHER_MIN is the planned withering time in minutes. Data type: integer, +length 10. The field can be empty. +10. PRICE_PER_KG is the price for one kilogram of the green leaf. Data type: +packed number, 11 digits, 2 decimal places. The field can be empty. +11. NOTE is a short note about the batch. Data type: character, length 40. +The field can be empty. +12. Two batches with the same PLUCK_ID must not exist. A second insert with +the same key must fail. + +# 6. Constraints +- Release target: 8.16. +- Coding standards: Clean ABAP. +- Out of scope: do not create a CDS view, a class, a program or a function +module for this task. Do not change any other object. + +# 7. Acceptance +- The table is active and has no syntax error. +- The hidden tests pass. +- Write ABAP Unit tests in a global test class. Use CL_OSQL_TEST_ENVIRONMENT +for the database access. diff --git a/tasks_gen/train/G1939/task.json b/tasks_gen/train/G1939/task.json new file mode 100644 index 0000000..e1b4f1a --- /dev/null +++ b/tasks_gen/train/G1939/task.json @@ -0,0 +1,56 @@ +{ + "id": "G1939", + "category": "B", + "object_type": "TABL", + "difficulty": 3, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [], + "contract": [ + { + "type": "TABL", + "name": "{{P}}PLUCK", + "fields": [ + "client", + "pluck_id", + "field_id", + "pluck_date", + "team_no", + "leaf_weight", + "leaf_grade", + "moisture", + "wither_min", + "price_per_kg", + "note" + ] + } + ], + "out_of_scope": [], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}PLUCK_HIDDEN", + "file": "hidden/pluck_hidden.clas.abap", + "description": "RTTI check of the table and OSQL test double checks" + } + ], + "reference": [ + { + "type": "TABL", + "name": "{{P}}PLUCK", + "file": "reference/pluck.tabl.asabap", + "description": "Tea leaf plucking batch table" + }, + { + "type": "CLAS", + "name": "{{P}}PLUCK_TEST", + "file": "reference/pluck_test.clas.abap", + "description": "Own ABAP Unit tests with CL_OSQL_TEST_ENVIRONMENT" + } + ], + "craft_checks": [] +} \ No newline at end of file diff --git a/tasks_gen/train/G1940/faulty/m0_lift_check.clas.abap b/tasks_gen/train/G1940/faulty/m0_lift_check.clas.abap new file mode 100644 index 0000000..94944fc --- /dev/null +++ b/tasks_gen/train/G1940/faulty/m0_lift_check.clas.abap @@ -0,0 +1,44 @@ +CLASS {{p}}lift_check DEFINITION + PUBLIC + FINAL + CREATE PUBLIC. + + PUBLIC SECTION. + TYPES: + BEGIN OF ty_lift_plan, + plan_id TYPE string, + crane_id TYPE string, + load_kg TYPE decfloat34, + capacity_kg TYPE decfloat34, + wind_kmh TYPE decfloat34, + END OF ty_lift_plan. + + METHODS check_lift_plan + IMPORTING + iv_plan TYPE ty_lift_plan + RAISING + {{p}}cx_crane_error. +ENDCLASS. + + +CLASS {{p}}lift_check IMPLEMENTATION. + METHOD check_lift_plan. + IF iv_plan-crane_id IS INITIAL. + RAISE EXCEPTION TYPE {{p}}cx_crane_error + EXPORTING + iv_msgno = '001' + iv_attr1 = iv_plan-plan_id. + ELSEIF iv_plan-load_kg <= iv_plan-capacity_kg. + RAISE EXCEPTION TYPE {{p}}cx_crane_error + EXPORTING + iv_msgno = '002' + iv_attr1 = iv_plan-plan_id + iv_attr2 = iv_plan-crane_id. + ELSEIF iv_plan-wind_kmh > 60. + RAISE EXCEPTION TYPE {{p}}cx_crane_error + EXPORTING + iv_msgno = '003' + iv_attr1 = iv_plan-plan_id. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1940/faulty/m2_lift_check.clas.abap b/tasks_gen/train/G1940/faulty/m2_lift_check.clas.abap new file mode 100644 index 0000000..7b53a88 --- /dev/null +++ b/tasks_gen/train/G1940/faulty/m2_lift_check.clas.abap @@ -0,0 +1,44 @@ +CLASS {{p}}lift_check DEFINITION + PUBLIC + FINAL + CREATE PUBLIC. + + PUBLIC SECTION. + TYPES: + BEGIN OF ty_lift_plan, + plan_id TYPE string, + crane_id TYPE string, + load_kg TYPE decfloat34, + capacity_kg TYPE decfloat34, + wind_kmh TYPE decfloat34, + END OF ty_lift_plan. + + METHODS check_lift_plan + IMPORTING + iv_plan TYPE ty_lift_plan + RAISING + {{p}}cx_crane_error. +ENDCLASS. + + +CLASS {{p}}lift_check IMPLEMENTATION. + METHOD check_lift_plan. + IF iv_plan-crane_id IS INITIAL. + RAISE EXCEPTION TYPE {{p}}cx_crane_error + EXPORTING + iv_msgno = '001' + iv_attr1 = iv_plan-plan_id. + ELSEIF iv_plan-load_kg > iv_plan-capacity_kg. + RAISE EXCEPTION TYPE {{p}}cx_crane_error + EXPORTING + iv_msgno = '002' + iv_attr1 = iv_plan-plan_id + iv_attr2 = iv_plan-crane_id. + ELSEIF iv_plan-wind_kmh <= 60. + RAISE EXCEPTION TYPE {{p}}cx_crane_error + EXPORTING + iv_msgno = '003' + iv_attr1 = iv_plan-plan_id. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1940/generation.json b/tasks_gen/train/G1940/generation.json new file mode 100644 index 0000000..975089a --- /dev/null +++ b/tasks_gen/train/G1940/generation.json @@ -0,0 +1,24 @@ +{ + "id": "G1940", + "pool": "train", + "object_type": "MSAG", + "category": "D", + "attempts": [ + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 4, + "killed": 4, + "ok": true + } + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1940/hidden/lift_hidden.clas.abap b/tasks_gen/train/G1940/hidden/lift_hidden.clas.abap new file mode 100644 index 0000000..98d800f --- /dev/null +++ b/tasks_gen/train/G1940/hidden/lift_hidden.clas.abap @@ -0,0 +1,139 @@ +CLASS {{p}}lift_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + + PRIVATE SECTION. + METHODS make_plan + IMPORTING iv_crane TYPE string DEFAULT 'K-7' + iv_load TYPE decfloat34 DEFAULT 1000 + iv_capacity TYPE decfloat34 DEFAULT 1000 + iv_wind TYPE decfloat34 DEFAULT 20 + RETURNING VALUE(rs_plan) TYPE {{p}}lift_check=>ty_lift_plan. + + METHODS check_plan + IMPORTING iv_crane TYPE string DEFAULT 'K-7' + iv_load TYPE decfloat34 DEFAULT 1000 + iv_capacity TYPE decfloat34 DEFAULT 1000 + iv_wind TYPE decfloat34 DEFAULT 20 + EXPORTING ev_text TYPE string. + + METHODS msg_001_text FOR TESTING. + METHODS msg_002_text FOR TESTING. + METHODS msg_003_text FOR TESTING. + METHODS msg_004_text FOR TESTING. + METHODS msg_005_text FOR TESTING. + METHODS no_crane_raises FOR TESTING. + METHODS overload_raises FOR TESTING. + METHODS wind_raises FOR TESTING. + METHODS crane_rule_first FOR TESTING. + METHODS wind_limit_ok FOR TESTING. + METHODS valid_plan_passes FOR TESTING. +ENDCLASS. + + +CLASS {{p}}lift_hidden IMPLEMENTATION. + METHOD make_plan. + rs_plan = VALUE #( plan_id = 'L-100' + crane_id = iv_crane + load_kg = iv_load + capacity_kg = iv_capacity + wind_kmh = iv_wind ). + ENDMETHOD. + + METHOD check_plan. + CLEAR ev_text. + DATA(ls_plan) = make_plan( iv_crane = iv_crane + iv_load = iv_load + iv_capacity = iv_capacity + iv_wind = iv_wind ). + DATA(lo_check) = NEW {{p}}lift_check( ). + TRY. + lo_check->check_lift_plan( ls_plan ). + CATCH {{p}}cx_crane_error INTO DATA(lo_error). + ev_text = lo_error->get_message_text( ). + ENDTRY. + ENDMETHOD. + + METHOD msg_001_text. + DATA lv_text TYPE string. + MESSAGE ID '{{P}}MSG_CRANE' TYPE 'E' NUMBER '001' WITH 'L-100' INTO lv_text. + cl_abap_unit_assert=>assert_equals( + exp = 'Lift plan L-100 has no crane' + act = lv_text ). + ENDMETHOD. + + METHOD msg_002_text. + DATA lv_text TYPE string. + MESSAGE ID '{{P}}MSG_CRANE' TYPE 'E' NUMBER '002' WITH 'L-100' 'K-7' INTO lv_text. + cl_abap_unit_assert=>assert_equals( + exp = 'Lift plan L-100 is too heavy for crane K-7' + act = lv_text ). + ENDMETHOD. + + METHOD msg_003_text. + DATA lv_text TYPE string. + MESSAGE ID '{{P}}MSG_CRANE' TYPE 'E' NUMBER '003' WITH 'L-100' INTO lv_text. + cl_abap_unit_assert=>assert_equals( + exp = 'Lift plan L-100 is blocked because of wind' + act = lv_text ). + ENDMETHOD. + + METHOD msg_004_text. + DATA lv_text TYPE string. + MESSAGE ID '{{P}}MSG_CRANE' TYPE 'W' NUMBER '004' WITH 'L-100' INTO lv_text. + cl_abap_unit_assert=>assert_equals( + exp = 'Lift plan L-100 is near the load limit' + act = lv_text ). + ENDMETHOD. + + METHOD msg_005_text. + DATA lv_text TYPE string. + MESSAGE ID '{{P}}MSG_CRANE' TYPE 'I' NUMBER '005' WITH 'L-100' INTO lv_text. + cl_abap_unit_assert=>assert_equals( + exp = 'Lift plan L-100 is approved' + act = lv_text ). + ENDMETHOD. + + METHOD no_crane_raises. + check_plan( EXPORTING iv_crane = '' + IMPORTING ev_text = DATA(lv_text) ). + cl_abap_unit_assert=>assert_equals( + exp = 'Lift plan L-100 has no crane' + act = lv_text ). + ENDMETHOD. + + METHOD overload_raises. + check_plan( EXPORTING iv_load = 1200 iv_capacity = 1000 + IMPORTING ev_text = DATA(lv_text) ). + cl_abap_unit_assert=>assert_equals( + exp = 'Lift plan L-100 is too heavy for crane K-7' + act = lv_text ). + ENDMETHOD. + + METHOD wind_raises. + check_plan( EXPORTING iv_wind = 75 + IMPORTING ev_text = DATA(lv_text) ). + cl_abap_unit_assert=>assert_equals( + exp = 'Lift plan L-100 is blocked because of wind' + act = lv_text ). + ENDMETHOD. + + METHOD crane_rule_first. + check_plan( EXPORTING iv_crane = '' iv_load = 1200 iv_capacity = 1000 iv_wind = 90 + IMPORTING ev_text = DATA(lv_text) ). + cl_abap_unit_assert=>assert_equals( + exp = 'Lift plan L-100 has no crane' + act = lv_text ). + ENDMETHOD. + + METHOD wind_limit_ok. + check_plan( EXPORTING iv_wind = 60 + IMPORTING ev_text = DATA(lv_text) ). + cl_abap_unit_assert=>assert_equals( exp = '' act = lv_text ). + ENDMETHOD. + + METHOD valid_plan_passes. + check_plan( EXPORTING iv_crane = 'K-9' iv_load = 900 iv_capacity = 1000 iv_wind = 10 + IMPORTING ev_text = DATA(lv_text) ). + cl_abap_unit_assert=>assert_equals( exp = '' act = lv_text ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1940/mutation.json b/tasks_gen/train/G1940/mutation.json new file mode 100644 index 0000000..e0b557f --- /dev/null +++ b/tasks_gen/train/G1940/mutation.json @@ -0,0 +1,58 @@ +{ + "task": "G1940", + "mutants": [ + { + "object": "{{P}}LIFT_CHECK", + "mutant": "line 31: > -> <= (rel)", + "status": "killed", + "hidden": "7/11", + "failed_tests": [ + "OVERLOAD_RAISES", + "VALID_PLAN_PASSES", + "WIND_LIMIT_OK", + "WIND_RAISES" + ] + }, + { + "object": "{{P}}MSG_CRANE", + "mutant": "message 002: number + 50 (number)", + "status": "invalid", + "hidden": "0/0", + "failed_tests": [] + }, + { + "object": "{{P}}LIFT_CHECK", + "mutant": "line 37: > -> <= (rel)", + "status": "killed", + "hidden": "8/11", + "failed_tests": [ + "VALID_PLAN_PASSES", + "WIND_LIMIT_OK", + "WIND_RAISES" + ] + }, + { + "object": "{{P}}MSG_CRANE", + "mutant": "message 003: text + ' x' (text)", + "status": "killed", + "hidden": "9/11", + "failed_tests": [ + "MSG_003_TEXT", + "WIND_RAISES" + ] + }, + { + "object": "{{P}}MSG_CRANE", + "mutant": "message 004: &1 -> &2 (placeholder)", + "status": "killed", + "hidden": "10/11", + "failed_tests": [ + "MSG_004_TEXT" + ] + } + ], + "valid": 4, + "killed": 4, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1940/reference/cx_crane_error.clas.abap b/tasks_gen/train/G1940/reference/cx_crane_error.clas.abap new file mode 100644 index 0000000..6f8ea15 --- /dev/null +++ b/tasks_gen/train/G1940/reference/cx_crane_error.clas.abap @@ -0,0 +1,33 @@ +CLASS {{p}}cx_crane_error DEFINITION + PUBLIC + INHERITING FROM cx_static_check + FINAL + CREATE PUBLIC. + + PUBLIC SECTION. + METHODS constructor + IMPORTING + iv_msgno TYPE symsgno + iv_attr1 TYPE string OPTIONAL + iv_attr2 TYPE string OPTIONAL. + + METHODS get_message_text + RETURNING + VALUE(rv_text) TYPE string. + + PRIVATE SECTION. + DATA mv_text TYPE string. +ENDCLASS. + + +CLASS {{p}}cx_crane_error IMPLEMENTATION. + METHOD constructor. + super->constructor( ). + MESSAGE ID '{{P}}MSG_CRANE' TYPE 'I' NUMBER iv_msgno + WITH iv_attr1 iv_attr2 INTO mv_text. + ENDMETHOD. + + METHOD get_message_text. + rv_text = mv_text. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1940/reference/lift_check.clas.abap b/tasks_gen/train/G1940/reference/lift_check.clas.abap new file mode 100644 index 0000000..5f5ec34 --- /dev/null +++ b/tasks_gen/train/G1940/reference/lift_check.clas.abap @@ -0,0 +1,44 @@ +CLASS {{p}}lift_check DEFINITION + PUBLIC + FINAL + CREATE PUBLIC. + + PUBLIC SECTION. + TYPES: + BEGIN OF ty_lift_plan, + plan_id TYPE string, + crane_id TYPE string, + load_kg TYPE decfloat34, + capacity_kg TYPE decfloat34, + wind_kmh TYPE decfloat34, + END OF ty_lift_plan. + + METHODS check_lift_plan + IMPORTING + iv_plan TYPE ty_lift_plan + RAISING + {{p}}cx_crane_error. +ENDCLASS. + + +CLASS {{p}}lift_check IMPLEMENTATION. + METHOD check_lift_plan. + IF iv_plan-crane_id IS INITIAL. + RAISE EXCEPTION TYPE {{p}}cx_crane_error + EXPORTING + iv_msgno = '001' + iv_attr1 = iv_plan-plan_id. + ELSEIF iv_plan-load_kg > iv_plan-capacity_kg. + RAISE EXCEPTION TYPE {{p}}cx_crane_error + EXPORTING + iv_msgno = '002' + iv_attr1 = iv_plan-plan_id + iv_attr2 = iv_plan-crane_id. + ELSEIF iv_plan-wind_kmh > 60. + RAISE EXCEPTION TYPE {{p}}cx_crane_error + EXPORTING + iv_msgno = '003' + iv_attr1 = iv_plan-plan_id. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1940/reference/lift_check.clas.testclasses.abap b/tasks_gen/train/G1940/reference/lift_check.clas.testclasses.abap new file mode 100644 index 0000000..aafcd73 --- /dev/null +++ b/tasks_gen/train/G1940/reference/lift_check.clas.testclasses.abap @@ -0,0 +1,66 @@ +CLASS ltc_lift_check DEFINITION FOR TESTING + DURATION SHORT + RISK LEVEL HARMLESS. + + PRIVATE SECTION. + METHODS no_crane FOR TESTING. + METHODS overload FOR TESTING. + METHODS wind FOR TESTING. + METHODS valid_plan FOR TESTING. +ENDCLASS. + + +CLASS ltc_lift_check IMPLEMENTATION. + METHOD no_crane. + DATA(ls_plan) = VALUE {{p}}lift_check=>ty_lift_plan( + plan_id = 'L-1' crane_id = '' ). + DATA(lo_check) = NEW {{p}}lift_check( ). + TRY. + lo_check->check_lift_plan( ls_plan ). + cl_abap_unit_assert=>fail( msg = 'Exception expected' ). + CATCH {{p}}cx_crane_error INTO DATA(lo_error). + cl_abap_unit_assert=>assert_equals( + exp = 'Lift plan L-1 has no crane' + act = lo_error->get_message_text( ) ). + ENDTRY. + ENDMETHOD. + + METHOD overload. + DATA(ls_plan) = VALUE {{p}}lift_check=>ty_lift_plan( + plan_id = 'L-2' crane_id = 'K-1' load_kg = 2000 capacity_kg = 1000 ). + DATA(lo_check) = NEW {{p}}lift_check( ). + TRY. + lo_check->check_lift_plan( ls_plan ). + cl_abap_unit_assert=>fail( msg = 'Exception expected' ). + CATCH {{p}}cx_crane_error INTO DATA(lo_error). + cl_abap_unit_assert=>assert_equals( + exp = 'Lift plan L-2 is too heavy for crane K-1' + act = lo_error->get_message_text( ) ). + ENDTRY. + ENDMETHOD. + + METHOD wind. + DATA(ls_plan) = VALUE {{p}}lift_check=>ty_lift_plan( + plan_id = 'L-3' crane_id = 'K-1' wind_kmh = 80 ). + DATA(lo_check) = NEW {{p}}lift_check( ). + TRY. + lo_check->check_lift_plan( ls_plan ). + cl_abap_unit_assert=>fail( msg = 'Exception expected' ). + CATCH {{p}}cx_crane_error INTO DATA(lo_error). + cl_abap_unit_assert=>assert_equals( + exp = 'Lift plan L-3 is blocked because of wind' + act = lo_error->get_message_text( ) ). + ENDTRY. + ENDMETHOD. + + METHOD valid_plan. + DATA(ls_plan) = VALUE {{p}}lift_check=>ty_lift_plan( + plan_id = 'L-4' crane_id = 'K-1' load_kg = 500 capacity_kg = 1000 wind_kmh = 30 ). + DATA(lo_check) = NEW {{p}}lift_check( ). + TRY. + lo_check->check_lift_plan( ls_plan ). + CATCH {{p}}cx_crane_error INTO DATA(lo_error). + cl_abap_unit_assert=>fail( msg = lo_error->get_message_text( ) ). + ENDTRY. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1940/reference/lift_test.clas.abap b/tasks_gen/train/G1940/reference/lift_test.clas.abap new file mode 100644 index 0000000..75b918c --- /dev/null +++ b/tasks_gen/train/G1940/reference/lift_test.clas.abap @@ -0,0 +1,63 @@ +CLASS {{p}}lift_test DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + + PRIVATE SECTION. + METHODS message_001 FOR TESTING. + METHODS message_002 FOR TESTING. + METHODS message_003 FOR TESTING. + METHODS message_004 FOR TESTING. + METHODS message_005 FOR TESTING. + METHODS exception_text FOR TESTING. +ENDCLASS. + + +CLASS {{p}}lift_test IMPLEMENTATION. + METHOD message_001. + DATA lv_text TYPE string. + MESSAGE ID '{{P}}MSG_CRANE' TYPE 'E' NUMBER '001' WITH 'L-100' INTO lv_text. + cl_abap_unit_assert=>assert_equals( + exp = 'Lift plan L-100 has no crane' + act = lv_text ). + ENDMETHOD. + + METHOD message_002. + DATA lv_text TYPE string. + MESSAGE ID '{{P}}MSG_CRANE' TYPE 'E' NUMBER '002' WITH 'L-100' 'K-7' INTO lv_text. + cl_abap_unit_assert=>assert_equals( + exp = 'Lift plan L-100 is too heavy for crane K-7' + act = lv_text ). + ENDMETHOD. + + METHOD message_003. + DATA lv_text TYPE string. + MESSAGE ID '{{P}}MSG_CRANE' TYPE 'E' NUMBER '003' WITH 'L-100' INTO lv_text. + cl_abap_unit_assert=>assert_equals( + exp = 'Lift plan L-100 is blocked because of wind' + act = lv_text ). + ENDMETHOD. + + METHOD message_004. + DATA lv_text TYPE string. + MESSAGE ID '{{P}}MSG_CRANE' TYPE 'W' NUMBER '004' WITH 'L-100' INTO lv_text. + cl_abap_unit_assert=>assert_equals( + exp = 'Lift plan L-100 is near the load limit' + act = lv_text ). + ENDMETHOD. + + METHOD message_005. + DATA lv_text TYPE string. + MESSAGE ID '{{P}}MSG_CRANE' TYPE 'I' NUMBER '005' WITH 'L-100' INTO lv_text. + cl_abap_unit_assert=>assert_equals( + exp = 'Lift plan L-100 is approved' + act = lv_text ). + ENDMETHOD. + + METHOD exception_text. + DATA(lo_error) = NEW {{p}}cx_crane_error( iv_msgno = '002' + iv_attr1 = 'L-100' + iv_attr2 = 'K-7' ). + cl_abap_unit_assert=>assert_equals( + exp = 'Lift plan L-100 is too heavy for crane K-7' + act = lo_error->get_message_text( ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1940/spec.md b/tasks_gen/train/G1940/spec.md new file mode 100644 index 0000000..2e4d9e2 --- /dev/null +++ b/tasks_gen/train/G1940/spec.md @@ -0,0 +1,81 @@ +# 1. Goal +A mobile crane hire company checks a lift plan before it dispatches a crane. The +dispatch office calls one check class for each lift plan. If the check fails, the +check class raises a class-based exception. The exception carries a message from a +new message class. + +Create the message class, the exception class, and the check class. + +# 2. Open questions +None. + +# 3. Context +- All objects are in package $TMP. +- The dispatch office already exists. It calls the check class and shows the + message text of the exception. +- No message class for lift plans exists yet. + +# 4. Contract + +## Message class {{P}}MSG_CRANE +Messages 001, 002, 003, 004 and 005 must exist. The Business rules give the +number, the type and the exact text of each message. + +## Exception class {{P}}CX_CRANE_ERROR +- Public and final. It inherits from CX_STATIC_CHECK. +- Public constructor with these parameters: + - iv_msgno, TYPE symsgno + - iv_attr1, TYPE string, optional + - iv_attr2, TYPE string, optional +- Public method get_message_text, returning VALUE rv_text TYPE string. The method + returns the text of the message that the constructor received, with &1 + replaced by iv_attr1 and &2 replaced by iv_attr2. + +## Check class {{P}}LIFT_CHECK +- Public and final. +- Public type ty_lift_plan with these components: + - plan_id, TYPE string + - crane_id, TYPE string + - load_kg, TYPE decfloat34 + - capacity_kg, TYPE decfloat34 + - wind_kmh, TYPE decfloat34 +- Public method check_lift_plan with the importing parameter iv_plan of type + ty_lift_plan. The method raises {{P}}CX_CRANE_ERROR. + +# 5. Business rules + +## 5.1 Messages of {{P}}MSG_CRANE + +| Number | Type | Text | +| ------ | ---- | ---- | +| 001 | E | Lift plan &1 has no crane | +| 002 | E | Lift plan &1 is too heavy for crane &2 | +| 003 | E | Lift plan &1 is blocked because of wind | +| 004 | W | Lift plan &1 is near the load limit | +| 005 | I | Lift plan &1 is approved | + +Messages 001, 002 and 003 are errors. Message 004 is a warning. Message 005 is an +information message. The dispatch list shows messages 004 and 005. + +## 5.2 Check of a lift plan +The method check_lift_plan checks the lift plan in this order: + +1. If crane_id is initial, raise {{P}}CX_CRANE_ERROR with message 001 and + attribute 1 = plan_id. +2. Else if load_kg is greater than capacity_kg, raise {{P}}CX_CRANE_ERROR with + message 002, attribute 1 = plan_id, attribute 2 = crane_id. +3. Else if wind_kmh is greater than 60, raise {{P}}CX_CRANE_ERROR with message + 003 and attribute 1 = plan_id. +4. Else the method ends without an exception. + +# 6. Constraints +- Release target: ABAP Platform 2025 (SAP_BASIS 816). +- Clean ABAP. Keep every method below 40 statements. +- Out of scope: no database table, no CDS view, no report. Do not change other + objects in package $TMP. + +# 7. Acceptance +- All objects are active and have no syntax error. +- The hidden tests pass. +- Write ABAP Unit tests: a global test class for the message class and the + exception class, and local test classes for {{P}}LIFT_CHECK. diff --git a/tasks_gen/train/G1940/task.json b/tasks_gen/train/G1940/task.json new file mode 100644 index 0000000..35f4cdb --- /dev/null +++ b/tasks_gen/train/G1940/task.json @@ -0,0 +1,109 @@ +{ + "id": "G1940", + "category": "D", + "object_type": "MSAG", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [], + "contract": [ + { + "type": "MSAG", + "name": "{{P}}MSG_CRANE", + "messages": [ + { + "msgno": "001" + }, + { + "msgno": "002" + }, + { + "msgno": "003" + }, + { + "msgno": "004" + }, + { + "msgno": "005" + } + ] + }, + { + "type": "CLAS", + "name": "{{P}}CX_CRANE_ERROR" + }, + { + "type": "CLAS", + "name": "{{P}}LIFT_CHECK" + } + ], + "out_of_scope": [ + "database tables", + "CDS view entities", + "reports", + "changes to other objects in package $TMP" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}LIFT_HIDDEN", + "file": "hidden/lift_hidden.clas.abap", + "description": "Hidden tests for the crane message class, the crane exception class, and the lift plan check" + } + ], + "reference": [ + { + "type": "MSAG", + "name": "{{P}}MSG_CRANE", + "description": "Messages of the mobile crane hire company", + "messages": [ + { + "msgno": "001", + "text": "Lift plan &1 has no crane" + }, + { + "msgno": "002", + "text": "Lift plan &1 is too heavy for crane &2" + }, + { + "msgno": "003", + "text": "Lift plan &1 is blocked because of wind" + }, + { + "msgno": "004", + "text": "Lift plan &1 is near the load limit" + }, + { + "msgno": "005", + "text": "Lift plan &1 is approved" + } + ] + }, + { + "type": "CLAS", + "name": "{{P}}CX_CRANE_ERROR", + "file": "reference/cx_crane_error.clas.abap", + "description": "Class-based exception that carries a crane message" + }, + { + "type": "CLAS", + "name": "{{P}}LIFT_CHECK", + "file": "reference/lift_check.clas.abap", + "testclasses_file": "reference/lift_check.clas.testclasses.abap", + "description": "Checks a lift plan and raises the crane exception" + }, + { + "type": "CLAS", + "name": "{{P}}LIFT_TEST", + "file": "reference/lift_test.clas.abap", + "description": "Own tests for the crane message class and the crane exception" + } + ], + "craft_checks": [ + "method_length" + ] +} \ No newline at end of file diff --git a/tasks_gen/train/G1941/faulty/m0_compost_sum.prog.abap b/tasks_gen/train/G1941/faulty/m0_compost_sum.prog.abap new file mode 100644 index 0000000..645f889 --- /dev/null +++ b/tasks_gen/train/G1941/faulty/m0_compost_sum.prog.abap @@ -0,0 +1,108 @@ +REPORT {{p}}compost_sum. + +DATA gv_round TYPE {{p}}gwaste-round_id. + +PARAMETERS p_from TYPE d OBLIGATORY. +SELECT-OPTIONS s_round FOR gv_round. + +CLASS lcl_report DEFINITION FINAL. + PUBLIC SECTION. + TYPES: + BEGIN OF ty_line, + round_id TYPE {{p}}gwaste-round_id, + total_kg TYPE {{p}}gwaste-weight_kg, + deliveries TYPE i, + heavy TYPE i, + END OF ty_line, + tt_line TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY, + tt_round TYPE RANGE OF {{p}}gwaste-round_id. + CONSTANTS c_heavy_kg TYPE {{p}}gwaste-weight_kg VALUE '1000.00'. + METHODS select_totals + IMPORTING iv_from TYPE d + it_round TYPE tt_round + RETURNING VALUE(rt_lines) TYPE tt_line. + METHODS display + CHANGING ct_lines TYPE tt_line. +ENDCLASS. + +CLASS lcl_report IMPLEMENTATION. + METHOD select_totals. + SELECT round_id, weight_kg + FROM {{p}}gwaste + WHERE deliv_date < @iv_from + AND round_id IN @it_round + INTO TABLE @DATA(lt_deliveries). + + DATA lt_work TYPE SORTED TABLE OF ty_line WITH UNIQUE KEY round_id. + LOOP AT lt_deliveries INTO DATA(ls_delivery). + READ TABLE lt_work WITH TABLE KEY round_id = ls_delivery-round_id + ASSIGNING FIELD-SYMBOL(). + IF sy-subrc <> 0. + INSERT VALUE #( round_id = ls_delivery-round_id ) INTO TABLE lt_work ASSIGNING . + ENDIF. + -total_kg += ls_delivery-weight_kg. + -deliveries += 1. + IF ls_delivery-weight_kg >= c_heavy_kg. + -heavy += 1. + ENDIF. + ENDLOOP. + + rt_lines = lt_work. + SORT rt_lines BY total_kg DESCENDING. + ENDMETHOD. + + METHOD display. + TRY. + cl_salv_table=>factory( IMPORTING r_salv_table = DATA(lo_alv) + CHANGING t_table = ct_lines ). + lo_alv->display( ). + CATCH cx_salv_msg INTO DATA(lx_error). + MESSAGE lx_error TYPE 'I' DISPLAY LIKE 'E'. + ENDTRY. + ENDMETHOD. +ENDCLASS. + +START-OF-SELECTION. + DATA(go_report) = NEW lcl_report( ). + DATA(gt_lines) = go_report->select_totals( iv_from = p_from it_round = s_round[] ). + go_report->display( CHANGING ct_lines = gt_lines ). + +CLASS ltc_report DEFINITION FINAL 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 totals_per_round FOR TESTING. + METHODS heavy_and_sorted FOR TESTING. +ENDCLASS. + +CLASS ltc_report IMPLEMENTATION. + METHOD class_setup. + go_env = cl_osql_test_environment=>create( i_dependency_list = VALUE #( ( '{{P}}GWASTE' ) ) ). + DATA lt_waste TYPE STANDARD TABLE OF {{p}}gwaste WITH EMPTY KEY. + lt_waste = VALUE #( + ( delivery_id = 1 round_id = 'A' waste_type = 'GRAS' deliv_date = '20260101' weight_kg = '1200.00' ) + ( delivery_id = 2 round_id = 'A' waste_type = 'HEDG' deliv_date = '20260102' weight_kg = '500.00' ) + ( delivery_id = 3 round_id = 'B' waste_type = 'BRAN' deliv_date = '20260101' weight_kg = '900.00' ) ). + go_env->insert_test_data( lt_waste ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD totals_per_round. + DATA(lt_lines) = NEW lcl_report( )->select_totals( iv_from = '20260101' it_round = VALUE #( ) ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 'A' act = lt_lines[ 1 ]-round_id ). + DATA(lv_total) = lt_lines[ 1 ]-total_kg. + cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}gwaste-weight_kg( 1700 ) act = lv_total ). + ENDMETHOD. + + METHOD heavy_and_sorted. + DATA(lt_lines) = NEW lcl_report( )->select_totals( iv_from = '20260101' it_round = VALUE #( ) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lt_lines[ 1 ]-heavy ). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lt_lines[ 2 ]-heavy ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lt_lines[ 2 ]-deliveries ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1941/faulty/m1_compost_sum.prog.abap b/tasks_gen/train/G1941/faulty/m1_compost_sum.prog.abap new file mode 100644 index 0000000..4d2dd7a --- /dev/null +++ b/tasks_gen/train/G1941/faulty/m1_compost_sum.prog.abap @@ -0,0 +1,108 @@ +REPORT {{p}}compost_sum. + +DATA gv_round TYPE {{p}}gwaste-round_id. + +PARAMETERS p_from TYPE d OBLIGATORY. +SELECT-OPTIONS s_round FOR gv_round. + +CLASS lcl_report DEFINITION FINAL. + PUBLIC SECTION. + TYPES: + BEGIN OF ty_line, + round_id TYPE {{p}}gwaste-round_id, + total_kg TYPE {{p}}gwaste-weight_kg, + deliveries TYPE i, + heavy TYPE i, + END OF ty_line, + tt_line TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY, + tt_round TYPE RANGE OF {{p}}gwaste-round_id. + CONSTANTS c_heavy_kg TYPE {{p}}gwaste-weight_kg VALUE '1000.00'. + METHODS select_totals + IMPORTING iv_from TYPE d + it_round TYPE tt_round + RETURNING VALUE(rt_lines) TYPE tt_line. + METHODS display + CHANGING ct_lines TYPE tt_line. +ENDCLASS. + +CLASS lcl_report IMPLEMENTATION. + METHOD select_totals. + SELECT round_id, weight_kg + FROM {{p}}gwaste + WHERE deliv_date >= @iv_from + OR round_id IN @it_round + INTO TABLE @DATA(lt_deliveries). + + DATA lt_work TYPE SORTED TABLE OF ty_line WITH UNIQUE KEY round_id. + LOOP AT lt_deliveries INTO DATA(ls_delivery). + READ TABLE lt_work WITH TABLE KEY round_id = ls_delivery-round_id + ASSIGNING FIELD-SYMBOL(). + IF sy-subrc <> 0. + INSERT VALUE #( round_id = ls_delivery-round_id ) INTO TABLE lt_work ASSIGNING . + ENDIF. + -total_kg += ls_delivery-weight_kg. + -deliveries += 1. + IF ls_delivery-weight_kg >= c_heavy_kg. + -heavy += 1. + ENDIF. + ENDLOOP. + + rt_lines = lt_work. + SORT rt_lines BY total_kg DESCENDING. + ENDMETHOD. + + METHOD display. + TRY. + cl_salv_table=>factory( IMPORTING r_salv_table = DATA(lo_alv) + CHANGING t_table = ct_lines ). + lo_alv->display( ). + CATCH cx_salv_msg INTO DATA(lx_error). + MESSAGE lx_error TYPE 'I' DISPLAY LIKE 'E'. + ENDTRY. + ENDMETHOD. +ENDCLASS. + +START-OF-SELECTION. + DATA(go_report) = NEW lcl_report( ). + DATA(gt_lines) = go_report->select_totals( iv_from = p_from it_round = s_round[] ). + go_report->display( CHANGING ct_lines = gt_lines ). + +CLASS ltc_report DEFINITION FINAL 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 totals_per_round FOR TESTING. + METHODS heavy_and_sorted FOR TESTING. +ENDCLASS. + +CLASS ltc_report IMPLEMENTATION. + METHOD class_setup. + go_env = cl_osql_test_environment=>create( i_dependency_list = VALUE #( ( '{{P}}GWASTE' ) ) ). + DATA lt_waste TYPE STANDARD TABLE OF {{p}}gwaste WITH EMPTY KEY. + lt_waste = VALUE #( + ( delivery_id = 1 round_id = 'A' waste_type = 'GRAS' deliv_date = '20260101' weight_kg = '1200.00' ) + ( delivery_id = 2 round_id = 'A' waste_type = 'HEDG' deliv_date = '20260102' weight_kg = '500.00' ) + ( delivery_id = 3 round_id = 'B' waste_type = 'BRAN' deliv_date = '20260101' weight_kg = '900.00' ) ). + go_env->insert_test_data( lt_waste ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD totals_per_round. + DATA(lt_lines) = NEW lcl_report( )->select_totals( iv_from = '20260101' it_round = VALUE #( ) ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 'A' act = lt_lines[ 1 ]-round_id ). + DATA(lv_total) = lt_lines[ 1 ]-total_kg. + cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}gwaste-weight_kg( 1700 ) act = lv_total ). + ENDMETHOD. + + METHOD heavy_and_sorted. + DATA(lt_lines) = NEW lcl_report( )->select_totals( iv_from = '20260101' it_round = VALUE #( ) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lt_lines[ 1 ]-heavy ). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lt_lines[ 2 ]-heavy ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lt_lines[ 2 ]-deliveries ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1941/faulty/m2_compost_sum.prog.abap b/tasks_gen/train/G1941/faulty/m2_compost_sum.prog.abap new file mode 100644 index 0000000..8b2dcab --- /dev/null +++ b/tasks_gen/train/G1941/faulty/m2_compost_sum.prog.abap @@ -0,0 +1,108 @@ +REPORT {{p}}compost_sum. + +DATA gv_round TYPE {{p}}gwaste-round_id. + +PARAMETERS p_from TYPE d OBLIGATORY. +SELECT-OPTIONS s_round FOR gv_round. + +CLASS lcl_report DEFINITION FINAL. + PUBLIC SECTION. + TYPES: + BEGIN OF ty_line, + round_id TYPE {{p}}gwaste-round_id, + total_kg TYPE {{p}}gwaste-weight_kg, + deliveries TYPE i, + heavy TYPE i, + END OF ty_line, + tt_line TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY, + tt_round TYPE RANGE OF {{p}}gwaste-round_id. + CONSTANTS c_heavy_kg TYPE {{p}}gwaste-weight_kg VALUE '1000.00'. + METHODS select_totals + IMPORTING iv_from TYPE d + it_round TYPE tt_round + RETURNING VALUE(rt_lines) TYPE tt_line. + METHODS display + CHANGING ct_lines TYPE tt_line. +ENDCLASS. + +CLASS lcl_report IMPLEMENTATION. + METHOD select_totals. + SELECT round_id, weight_kg + FROM {{p}}gwaste + WHERE deliv_date >= @iv_from + AND round_id IN @it_round + INTO TABLE @DATA(lt_deliveries). + + DATA lt_work TYPE SORTED TABLE OF ty_line WITH UNIQUE KEY round_id. + LOOP AT lt_deliveries INTO DATA(ls_delivery). + READ TABLE lt_work WITH TABLE KEY round_id = ls_delivery-round_id + ASSIGNING FIELD-SYMBOL(). + IF sy-subrc <> 0. + INSERT VALUE #( round_id = ls_delivery-round_id ) INTO TABLE lt_work ASSIGNING . + ENDIF. + -total_kg += ls_delivery-weight_kg. + -deliveries += 1. + IF ls_delivery-weight_kg < c_heavy_kg. + -heavy += 1. + ENDIF. + ENDLOOP. + + rt_lines = lt_work. + SORT rt_lines BY total_kg DESCENDING. + ENDMETHOD. + + METHOD display. + TRY. + cl_salv_table=>factory( IMPORTING r_salv_table = DATA(lo_alv) + CHANGING t_table = ct_lines ). + lo_alv->display( ). + CATCH cx_salv_msg INTO DATA(lx_error). + MESSAGE lx_error TYPE 'I' DISPLAY LIKE 'E'. + ENDTRY. + ENDMETHOD. +ENDCLASS. + +START-OF-SELECTION. + DATA(go_report) = NEW lcl_report( ). + DATA(gt_lines) = go_report->select_totals( iv_from = p_from it_round = s_round[] ). + go_report->display( CHANGING ct_lines = gt_lines ). + +CLASS ltc_report DEFINITION FINAL 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 totals_per_round FOR TESTING. + METHODS heavy_and_sorted FOR TESTING. +ENDCLASS. + +CLASS ltc_report IMPLEMENTATION. + METHOD class_setup. + go_env = cl_osql_test_environment=>create( i_dependency_list = VALUE #( ( '{{P}}GWASTE' ) ) ). + DATA lt_waste TYPE STANDARD TABLE OF {{p}}gwaste WITH EMPTY KEY. + lt_waste = VALUE #( + ( delivery_id = 1 round_id = 'A' waste_type = 'GRAS' deliv_date = '20260101' weight_kg = '1200.00' ) + ( delivery_id = 2 round_id = 'A' waste_type = 'HEDG' deliv_date = '20260102' weight_kg = '500.00' ) + ( delivery_id = 3 round_id = 'B' waste_type = 'BRAN' deliv_date = '20260101' weight_kg = '900.00' ) ). + go_env->insert_test_data( lt_waste ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD totals_per_round. + DATA(lt_lines) = NEW lcl_report( )->select_totals( iv_from = '20260101' it_round = VALUE #( ) ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 'A' act = lt_lines[ 1 ]-round_id ). + DATA(lv_total) = lt_lines[ 1 ]-total_kg. + cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}gwaste-weight_kg( 1700 ) act = lv_total ). + ENDMETHOD. + + METHOD heavy_and_sorted. + DATA(lt_lines) = NEW lcl_report( )->select_totals( iv_from = '20260101' it_round = VALUE #( ) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lt_lines[ 1 ]-heavy ). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lt_lines[ 2 ]-heavy ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lt_lines[ 2 ]-deliveries ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1941/generation.json b/tasks_gen/train/G1941/generation.json new file mode 100644 index 0000000..996cea8 --- /dev/null +++ b/tasks_gen/train/G1941/generation.json @@ -0,0 +1,24 @@ +{ + "id": "G1941", + "pool": "train", + "object_type": "PROG", + "category": "C", + "attempts": [ + { + "stage": "validate", + "oracle": 95.5, + "null": 0 + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 3, + "killed": 3, + "ok": true + } + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1941/hidden/compost_hidden.clas.abap b/tasks_gen/train/G1941/hidden/compost_hidden.clas.abap new file mode 100644 index 0000000..e489391 --- /dev/null +++ b/tasks_gen/train/G1941/hidden/compost_hidden.clas.abap @@ -0,0 +1,106 @@ +CLASS {{p}}compost_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + TYPES tt_round TYPE RANGE OF {{p}}gwaste-round_id. + METHODS run + IMPORTING iv_from TYPE d + it_round TYPE tt_round OPTIONAL + RETURNING VALUE(rr_data) TYPE REF TO data. + METHODS value_of + IMPORTING ir_data TYPE REF TO data + iv_row TYPE i + iv_col TYPE string + RETURNING VALUE(rv_value) TYPE string. + METHODS lines_of + IMPORTING ir_data TYPE REF TO data + RETURNING VALUE(rv_lines) TYPE i. + METHODS assert_value + IMPORTING ir_data TYPE REF TO data + iv_row TYPE i + iv_col TYPE string + iv_exp TYPE string. + METHODS all_rounds FOR TESTING. + METHODS sorted_by_total FOR TESTING. + METHODS totals_and_counts FOR TESTING. + METHODS heavy_count FOR TESTING. + METHODS round_filter FOR TESTING. + METHODS date_filter FOR TESTING. + METHODS empty_result FOR TESTING. +ENDCLASS. + + +CLASS {{p}}compost_hidden IMPLEMENTATION. + METHOD run. + cl_salv_bs_runtime_info=>set( display = abap_false metadata = abap_false data = abap_true ). + SUBMIT {{p}}compost_sum WITH p_from = iv_from WITH s_round IN it_round AND RETURN. + TRY. + cl_salv_bs_runtime_info=>get_data_ref( IMPORTING r_data = rr_data ). + CATCH cx_salv_bs_sc_runtime_info. + ENDTRY. + cl_salv_bs_runtime_info=>clear_all( ). + ENDMETHOD. + + METHOD lines_of. + FIELD-SYMBOLS TYPE STANDARD TABLE. + IF ir_data IS BOUND. + ASSIGN ir_data->* TO . + rv_lines = lines( ). + ENDIF. + ENDMETHOD. + + METHOD value_of. + FIELD-SYMBOLS TYPE STANDARD TABLE. + ASSIGN ir_data->* TO . + ASSIGN [ iv_row ] TO FIELD-SYMBOL(). + ASSIGN COMPONENT iv_col OF STRUCTURE TO FIELD-SYMBOL(). + cl_abap_unit_assert=>assert_subrc( exp = 0 msg = |Column { iv_col } missing| ). + rv_value = condense( CONV string( ) ). + ENDMETHOD. + + METHOD assert_value. + cl_abap_unit_assert=>assert_equals( + exp = iv_exp + act = value_of( ir_data = ir_data iv_row = iv_row iv_col = iv_col ) ). + ENDMETHOD. + + METHOD all_rounds. + cl_abap_unit_assert=>assert_equals( exp = 3 act = lines_of( run( '20251201' ) ) ). + ENDMETHOD. + + METHOD sorted_by_total. + DATA(lr_data) = run( '20251201' ). + assert_value( ir_data = lr_data iv_row = 1 iv_col = `ROUND_ID` iv_exp = `R1003` ). + assert_value( ir_data = lr_data iv_row = 3 iv_col = `ROUND_ID` iv_exp = `R1001` ). + ENDMETHOD. + + METHOD totals_and_counts. + DATA(lr_data) = run( '20260101' ). + assert_value( ir_data = lr_data iv_row = 1 iv_col = `ROUND_ID` iv_exp = `R1002` ). + assert_value( ir_data = lr_data iv_row = 1 iv_col = `TOTAL_KG` iv_exp = `3000.00` ). + assert_value( ir_data = lr_data iv_row = 1 iv_col = `DELIVERIES` iv_exp = `1` ). + assert_value( ir_data = lr_data iv_row = 2 iv_col = `TOTAL_KG` iv_exp = `2000.00` ). + assert_value( ir_data = lr_data iv_row = 2 iv_col = `DELIVERIES` iv_exp = `2` ). + ENDMETHOD. + + METHOD heavy_count. + DATA(lr_data) = run( '20260101' ). + assert_value( ir_data = lr_data iv_row = 1 iv_col = `HEAVY` iv_exp = `1` ). + assert_value( ir_data = lr_data iv_row = 3 iv_col = `HEAVY` iv_exp = `0` ). + ENDMETHOD. + + METHOD round_filter. + DATA(lr_data) = run( iv_from = '20260101' + it_round = VALUE #( ( sign = 'I' option = 'EQ' low = 'R1001' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lines_of( lr_data ) ). + assert_value( ir_data = lr_data iv_row = 1 iv_col = `TOTAL_KG` iv_exp = `2000.00` ). + assert_value( ir_data = lr_data iv_row = 1 iv_col = `DELIVERIES` iv_exp = `2` ). + ENDMETHOD. + + METHOD date_filter. + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines_of( run( '20260201' ) ) ). + ENDMETHOD. + + METHOD empty_result. + cl_abap_unit_assert=>assert_equals( exp = 0 act = lines_of( run( '20260401' ) ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1941/mutation.json b/tasks_gen/train/G1941/mutation.json new file mode 100644 index 0000000..87e8c86 --- /dev/null +++ b/tasks_gen/train/G1941/mutation.json @@ -0,0 +1,46 @@ +{ + "task": "G1941", + "mutants": [ + { + "object": "{{P}}COMPOST_SUM", + "mutant": "line 32: >= -> < (rel)", + "status": "killed", + "hidden": "0/7", + "failed_tests": [ + "ALL_ROUNDS", + "DATE_FILTER", + "EMPTY_RESULT", + "HEAVY_COUNT", + "ROUND_FILTER", + "SORTED_BY_TOTAL", + "TOTALS_AND_COUNTS" + ] + }, + { + "object": "{{P}}COMPOST_SUM", + "mutant": "line 33: AND -> OR (logic)", + "status": "killed", + "hidden": "2/7", + "failed_tests": [ + "DATE_FILTER", + "EMPTY_RESULT", + "HEAVY_COUNT", + "ROUND_FILTER", + "TOTALS_AND_COUNTS" + ] + }, + { + "object": "{{P}}COMPOST_SUM", + "mutant": "line 45: >= -> < (rel)", + "status": "killed", + "hidden": "6/7", + "failed_tests": [ + "HEAVY_COUNT" + ] + } + ], + "valid": 3, + "killed": 3, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1941/reference/compost_sum.prog.abap b/tasks_gen/train/G1941/reference/compost_sum.prog.abap new file mode 100644 index 0000000..9f8c3ec --- /dev/null +++ b/tasks_gen/train/G1941/reference/compost_sum.prog.abap @@ -0,0 +1,108 @@ +REPORT {{p}}compost_sum. + +DATA gv_round TYPE {{p}}gwaste-round_id. + +PARAMETERS p_from TYPE d OBLIGATORY. +SELECT-OPTIONS s_round FOR gv_round. + +CLASS lcl_report DEFINITION FINAL. + PUBLIC SECTION. + TYPES: + BEGIN OF ty_line, + round_id TYPE {{p}}gwaste-round_id, + total_kg TYPE {{p}}gwaste-weight_kg, + deliveries TYPE i, + heavy TYPE i, + END OF ty_line, + tt_line TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY, + tt_round TYPE RANGE OF {{p}}gwaste-round_id. + CONSTANTS c_heavy_kg TYPE {{p}}gwaste-weight_kg VALUE '1000.00'. + METHODS select_totals + IMPORTING iv_from TYPE d + it_round TYPE tt_round + RETURNING VALUE(rt_lines) TYPE tt_line. + METHODS display + CHANGING ct_lines TYPE tt_line. +ENDCLASS. + +CLASS lcl_report IMPLEMENTATION. + METHOD select_totals. + SELECT round_id, weight_kg + FROM {{p}}gwaste + WHERE deliv_date >= @iv_from + AND round_id IN @it_round + INTO TABLE @DATA(lt_deliveries). + + DATA lt_work TYPE SORTED TABLE OF ty_line WITH UNIQUE KEY round_id. + LOOP AT lt_deliveries INTO DATA(ls_delivery). + READ TABLE lt_work WITH TABLE KEY round_id = ls_delivery-round_id + ASSIGNING FIELD-SYMBOL(). + IF sy-subrc <> 0. + INSERT VALUE #( round_id = ls_delivery-round_id ) INTO TABLE lt_work ASSIGNING . + ENDIF. + -total_kg += ls_delivery-weight_kg. + -deliveries += 1. + IF ls_delivery-weight_kg >= c_heavy_kg. + -heavy += 1. + ENDIF. + ENDLOOP. + + rt_lines = lt_work. + SORT rt_lines BY total_kg DESCENDING. + ENDMETHOD. + + METHOD display. + TRY. + cl_salv_table=>factory( IMPORTING r_salv_table = DATA(lo_alv) + CHANGING t_table = ct_lines ). + lo_alv->display( ). + CATCH cx_salv_msg INTO DATA(lx_error). + MESSAGE lx_error TYPE 'I' DISPLAY LIKE 'E'. + ENDTRY. + ENDMETHOD. +ENDCLASS. + +START-OF-SELECTION. + DATA(go_report) = NEW lcl_report( ). + DATA(gt_lines) = go_report->select_totals( iv_from = p_from it_round = s_round[] ). + go_report->display( CHANGING ct_lines = gt_lines ). + +CLASS ltc_report DEFINITION FINAL 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 totals_per_round FOR TESTING. + METHODS heavy_and_sorted FOR TESTING. +ENDCLASS. + +CLASS ltc_report IMPLEMENTATION. + METHOD class_setup. + go_env = cl_osql_test_environment=>create( i_dependency_list = VALUE #( ( '{{P}}GWASTE' ) ) ). + DATA lt_waste TYPE STANDARD TABLE OF {{p}}gwaste WITH EMPTY KEY. + lt_waste = VALUE #( + ( delivery_id = 1 round_id = 'A' waste_type = 'GRAS' deliv_date = '20260101' weight_kg = '1200.00' ) + ( delivery_id = 2 round_id = 'A' waste_type = 'HEDG' deliv_date = '20260102' weight_kg = '500.00' ) + ( delivery_id = 3 round_id = 'B' waste_type = 'BRAN' deliv_date = '20260101' weight_kg = '900.00' ) ). + go_env->insert_test_data( lt_waste ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD totals_per_round. + DATA(lt_lines) = NEW lcl_report( )->select_totals( iv_from = '20260101' it_round = VALUE #( ) ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 'A' act = lt_lines[ 1 ]-round_id ). + DATA(lv_total) = lt_lines[ 1 ]-total_kg. + cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}gwaste-weight_kg( 1700 ) act = lv_total ). + ENDMETHOD. + + METHOD heavy_and_sorted. + DATA(lt_lines) = NEW lcl_report( )->select_totals( iv_from = '20260101' it_round = VALUE #( ) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lt_lines[ 1 ]-heavy ). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lt_lines[ 2 ]-heavy ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lt_lines[ 2 ]-deliveries ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1941/seed/compost_seed.clas.abap b/tasks_gen/train/G1941/seed/compost_seed.clas.abap new file mode 100644 index 0000000..ecf4d6f --- /dev/null +++ b/tasks_gen/train/G1941/seed/compost_seed.clas.abap @@ -0,0 +1,17 @@ +CLASS {{p}}compost_seed DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES if_oo_adt_classrun. +ENDCLASS. + +CLASS {{p}}compost_seed IMPLEMENTATION. + METHOD if_oo_adt_classrun~main. + DELETE FROM {{p}}gwaste. + INSERT {{p}}gwaste FROM TABLE @( VALUE #( + ( delivery_id = 1 round_id = 'R1001' waste_type = 'GRAS' deliv_date = '20260110' weight_kg = '1200.00' ) + ( delivery_id = 2 round_id = 'R1001' waste_type = 'HEDG' deliv_date = '20260210' weight_kg = '800.00' ) + ( delivery_id = 3 round_id = 'R1002' waste_type = 'BRAN' deliv_date = '20260115' weight_kg = '3000.00' ) + ( delivery_id = 4 round_id = 'R1003' waste_type = 'GRAS' deliv_date = '20251231' weight_kg = '5000.00' ) + ( delivery_id = 5 round_id = 'R1003' waste_type = 'BRAN' deliv_date = '20260301' weight_kg = '200.00' ) ) ). + out->write( sy-dbcnt ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1941/seed/gwaste.tabl.asabap b/tasks_gen/train/G1941/seed/gwaste.tabl.asabap new file mode 100644 index 0000000..936da48 --- /dev/null +++ b/tasks_gen/train/G1941/seed/gwaste.tabl.asabap @@ -0,0 +1,13 @@ +@EndUserText.label : 'Green waste deliveries' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}gwaste { + key client : abap.clnt not null; + key delivery_id : abap.int4 not null; + round_id : abap.char(6); + waste_type : abap.char(4); + deliv_date : abap.dats; + weight_kg : abap.dec(15,2); +} diff --git a/tasks_gen/train/G1941/spec.md b/tasks_gen/train/G1941/spec.md new file mode 100644 index 0000000..65b5cc1 --- /dev/null +++ b/tasks_gen/train/G1941/spec.md @@ -0,0 +1,38 @@ +# 1. Goal +Show the green waste that each collection round delivered to the composting +plant in an ALV list. The plant office uses the list to compare the rounds for +a period. + +# 2. Open questions +None. + +# 3. Context +- Table {{P}}GWASTE exists in package $TMP. It contains data. + Fields: DELIVERY_ID (INT4, key), ROUND_ID (CHAR 6), WASTE_TYPE (CHAR 4), + DELIV_DATE (DATS), WEIGHT_KG (DEC 15,2). + +# 4. Contract +- Create the executable program {{P}}COMPOST_SUM in package $TMP. +- Selection screen: + - Parameter P_FROM, type DATS, mandatory: the first delivery date to include. + - Select-option S_ROUND for the collection round. +- Show the result with CL_SALV_TABLE. The output table has these columns, with +these names: ROUND_ID, TOTAL_KG (sum of WEIGHT_KG), DELIVERIES (number of +deliveries), HEAVY (number of heavy deliveries). + +# 5. Business rules +1. Include a delivery only if DELIV_DATE is on or after P_FROM and ROUND_ID is + in S_ROUND. +2. Show one line for each round that has at least one included delivery. +3. A delivery is heavy if WEIGHT_KG is 1000 kg or more. +4. Sort the lines by TOTAL_KG, the highest total first. + +# 6. Constraints +- Release target: 8.16. +- Coding standards: Clean ABAP. Read the data with one database access. +- Out of scope: do not change {{P}}GWASTE. + +# 7. Acceptance +- The program is active and has no syntax error. +- The hidden tests pass. +- Write ABAP Unit tests as local test classes in the program. diff --git a/tasks_gen/train/G1941/task.json b/tasks_gen/train/G1941/task.json new file mode 100644 index 0000000..b9eabf4 --- /dev/null +++ b/tasks_gen/train/G1941/task.json @@ -0,0 +1,60 @@ +{ + "id": "G1941", + "category": "C", + "object_type": "PROG", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [ + { + "type": "TABL", + "name": "{{P}}GWASTE", + "file": "seed/gwaste.tabl.asabap", + "description": "Green waste deliveries" + }, + { + "type": "CLAS", + "name": "{{P}}COMPOST_SEED", + "file": "seed/compost_seed.clas.abap", + "description": "Green waste seed data", + "run": true + } + ], + "contract": [ + { + "type": "PROG", + "name": "{{P}}COMPOST_SUM", + "parameters": [ + "p_from", + "s_round" + ] + } + ], + "out_of_scope": [ + "{{P}}GWASTE" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}COMPOST_HIDDEN", + "file": "hidden/compost_hidden.clas.abap", + "description": "Green waste summary hidden tests" + } + ], + "reference": [ + { + "type": "PROG", + "name": "{{P}}COMPOST_SUM", + "file": "reference/compost_sum.prog.abap", + "description": "Green waste per collection round" + } + ], + "craft_checks": [ + "db_operation_in_loop", + "method_length" + ] +} \ No newline at end of file diff --git a/tasks_gen/train/G1942/faulty/m0_repair_list.prog.abap b/tasks_gen/train/G1942/faulty/m0_repair_list.prog.abap new file mode 100644 index 0000000..db61a25 --- /dev/null +++ b/tasks_gen/train/G1942/faulty/m0_repair_list.prog.abap @@ -0,0 +1,203 @@ +REPORT {{p}}repair_list. + +PARAMETERS p_date TYPE d OBLIGATORY. + +CLASS lcl_report DEFINITION FINAL. + PUBLIC SECTION. + TYPES: + BEGIN OF ty_line, + job_id TYPE {{p}}jobhdr-job_id, + customer TYPE {{p}}jobhdr-customer, + mechanic TYPE {{p}}mech-mech_name, + items TYPE i, + total TYPE {{p}}jobitm-price, + END OF ty_line, + tt_line TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY. + METHODS run + IMPORTING iv_date TYPE d + RETURNING VALUE(rt_lines) TYPE tt_line. + METHODS display + CHANGING ct_lines TYPE tt_line. + PRIVATE SECTION. + CONSTANTS c_unknown TYPE {{p}}mech-mech_name VALUE 'UNKNOWN'. + TYPES: + BEGIN OF ty_job, + job_id TYPE {{p}}jobhdr-job_id, + customer TYPE {{p}}jobhdr-customer, + mech_id TYPE {{p}}jobhdr-mech_id, + END OF ty_job, + tt_job TYPE SORTED TABLE OF ty_job WITH UNIQUE KEY job_id. + TYPES: + BEGIN OF ty_sum, + job_id TYPE {{p}}jobhdr-job_id, + items TYPE i, + total TYPE {{p}}jobitm-price, + END OF ty_sum, + tt_sum TYPE SORTED TABLE OF ty_sum WITH UNIQUE KEY job_id. + TYPES: + BEGIN OF ty_mech, + mech_id TYPE {{p}}mech-mech_id, + mech_name TYPE {{p}}mech-mech_name, + END OF ty_mech, + tt_mech TYPE SORTED TABLE OF ty_mech WITH UNIQUE KEY mech_id. + TYPES tt_job_range TYPE RANGE OF {{p}}jobhdr-job_id. + TYPES tt_mech_range TYPE RANGE OF {{p}}mech-mech_id. + METHODS read_jobs + IMPORTING iv_date TYPE d + RETURNING VALUE(rt_jobs) TYPE tt_job. + METHODS job_range + IMPORTING it_jobs TYPE tt_job + RETURNING VALUE(rt_range) TYPE tt_job_range. + METHODS mech_range + IMPORTING it_jobs TYPE tt_job + RETURNING VALUE(rt_range) TYPE tt_mech_range. + METHODS read_sums + IMPORTING it_job_range TYPE tt_job_range + RETURNING VALUE(rt_sums) TYPE tt_sum. + METHODS read_mechanics + IMPORTING it_mech_range TYPE tt_mech_range + RETURNING VALUE(rt_mech) TYPE tt_mech. +ENDCLASS. + +CLASS lcl_report IMPLEMENTATION. + METHOD run. + DATA(lt_jobs) = read_jobs( iv_date ). + IF lt_jobs IS INITIAL. + RETURN. + ENDIF. + + DATA(lt_sums) = read_sums( job_range( lt_jobs ) ). + DATA(lt_mech) = read_mechanics( mech_range( lt_jobs ) ). + + LOOP AT lt_jobs INTO DATA(ls_job). + READ TABLE lt_sums INTO DATA(ls_sum) WITH TABLE KEY job_id = ls_job-job_id. + IF sy-subrc <> 0. + CONTINUE. + ENDIF. + + READ TABLE lt_mech INTO DATA(ls_mech) WITH TABLE KEY mech_id = ls_job-mech_id. + DATA(lv_mechanic) = COND {{p}}mech-mech_name( + WHEN sy-subrc = 0 THEN ls_mech-mech_name + ELSE c_unknown ). + + INSERT VALUE #( job_id = ls_job-job_id + customer = ls_job-customer + mechanic = lv_mechanic + items = ls_sum-items + total = ls_sum-total ) INTO TABLE rt_lines. + ENDLOOP. + + SORT rt_lines BY total DESCENDING job_id ASCENDING. + ENDMETHOD. + + METHOD read_jobs. + SELECT job_id, customer, mech_id + FROM {{p}}jobhdr + WHERE job_date <> @iv_date + INTO CORRESPONDING FIELDS OF TABLE @rt_jobs. + ENDMETHOD. + + METHOD job_range. + rt_range = VALUE #( FOR ls_job IN it_jobs + ( sign = 'I' option = 'EQ' low = ls_job-job_id ) ). + ENDMETHOD. + + METHOD mech_range. + rt_range = VALUE #( FOR ls_job IN it_jobs + ( sign = 'I' option = 'EQ' low = ls_job-mech_id ) ). + ENDMETHOD. + + METHOD read_sums. + SELECT job_id, qty, price + FROM {{p}}jobitm + WHERE job_id IN @it_job_range + INTO TABLE @DATA(lt_items). + + LOOP AT lt_items INTO DATA(ls_item). + READ TABLE rt_sums ASSIGNING FIELD-SYMBOL() WITH TABLE KEY job_id = ls_item-job_id. + IF sy-subrc <> 0. + INSERT VALUE #( job_id = ls_item-job_id ) INTO TABLE rt_sums ASSIGNING . + ENDIF. + -items = -items + 1. + -total = -total + ls_item-qty * ls_item-price. + ENDLOOP. + ENDMETHOD. + + METHOD read_mechanics. + SELECT mech_id, mech_name + FROM {{p}}mech + WHERE mech_id IN @it_mech_range + INTO CORRESPONDING FIELDS OF TABLE @rt_mech. + ENDMETHOD. + + METHOD display. + TRY. + cl_salv_table=>factory( IMPORTING r_salv_table = DATA(lo_alv) + CHANGING t_table = ct_lines ). + lo_alv->display( ). + CATCH cx_salv_msg INTO DATA(lx_error). + MESSAGE lx_error TYPE 'I' DISPLAY LIKE 'E'. + ENDTRY. + ENDMETHOD. +ENDCLASS. + +START-OF-SELECTION. + DATA(go_report) = NEW lcl_report( ). + DATA(gt_lines) = go_report->run( p_date ). + go_report->display( CHANGING ct_lines = gt_lines ). + +CLASS ltc_report DEFINITION FINAL 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 totals_and_items FOR TESTING. + METHODS unknown_mechanic FOR TESTING. + METHODS skips_jobs_without_items FOR TESTING. +ENDCLASS. + +CLASS ltc_report IMPLEMENTATION. + METHOD class_setup. + go_env = cl_osql_test_environment=>create( + i_dependency_list = VALUE #( ( '{{P}}MECH' ) ( '{{P}}JOBHDR' ) ( '{{P}}JOBITM' ) ) ). + + DATA lt_mech TYPE STANDARD TABLE OF {{p}}mech WITH EMPTY KEY. + lt_mech = VALUE #( ( mech_id = 'M1' mech_name = 'Anna' ) ). + go_env->insert_test_data( lt_mech ). + + DATA lt_job TYPE STANDARD TABLE OF {{p}}jobhdr WITH EMPTY KEY. + lt_job = VALUE #( ( job_id = 1 job_date = '20260410' customer = 'A' mech_id = 'M1' ) + ( job_id = 2 job_date = '20260410' customer = 'B' mech_id = 'M9' ) + ( job_id = 3 job_date = '20260410' customer = 'C' mech_id = 'M1' ) ). + go_env->insert_test_data( lt_job ). + + DATA lt_item TYPE STANDARD TABLE OF {{p}}jobitm WITH EMPTY KEY. + lt_item = VALUE #( ( job_id = 1 item_no = 10 spare_part = 'X' qty = 2 price = 10 ) + ( job_id = 1 item_no = 20 spare_part = 'Y' qty = 1 price = 5 ) + ( job_id = 2 item_no = 10 spare_part = 'Z' qty = 1 price = 40 ) ). + go_env->insert_test_data( lt_item ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD totals_and_items. + DATA(lt_lines) = NEW lcl_report( )->run( '20260410' ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 'B' act = lt_lines[ 1 ]-customer ). + cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}jobitm-price( 40 ) act = lt_lines[ 1 ]-total ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lt_lines[ 2 ]-items ). + cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}jobitm-price( 25 ) act = lt_lines[ 2 ]-total ). + ENDMETHOD. + + METHOD unknown_mechanic. + DATA(lt_lines) = NEW lcl_report( )->run( '20260410' ). + cl_abap_unit_assert=>assert_equals( exp = 'UNKNOWN' act = lt_lines[ 1 ]-mechanic ). + ENDMETHOD. + + METHOD skips_jobs_without_items. + DATA(lt_lines) = NEW lcl_report( )->run( '20260410' ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1942/faulty/m1_repair_list.prog.abap b/tasks_gen/train/G1942/faulty/m1_repair_list.prog.abap new file mode 100644 index 0000000..c71285e --- /dev/null +++ b/tasks_gen/train/G1942/faulty/m1_repair_list.prog.abap @@ -0,0 +1,203 @@ +REPORT {{p}}repair_list. + +PARAMETERS p_date TYPE d OBLIGATORY. + +CLASS lcl_report DEFINITION FINAL. + PUBLIC SECTION. + TYPES: + BEGIN OF ty_line, + job_id TYPE {{p}}jobhdr-job_id, + customer TYPE {{p}}jobhdr-customer, + mechanic TYPE {{p}}mech-mech_name, + items TYPE i, + total TYPE {{p}}jobitm-price, + END OF ty_line, + tt_line TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY. + METHODS run + IMPORTING iv_date TYPE d + RETURNING VALUE(rt_lines) TYPE tt_line. + METHODS display + CHANGING ct_lines TYPE tt_line. + PRIVATE SECTION. + CONSTANTS c_unknown TYPE {{p}}mech-mech_name VALUE 'UNKNOWN'. + TYPES: + BEGIN OF ty_job, + job_id TYPE {{p}}jobhdr-job_id, + customer TYPE {{p}}jobhdr-customer, + mech_id TYPE {{p}}jobhdr-mech_id, + END OF ty_job, + tt_job TYPE SORTED TABLE OF ty_job WITH UNIQUE KEY job_id. + TYPES: + BEGIN OF ty_sum, + job_id TYPE {{p}}jobhdr-job_id, + items TYPE i, + total TYPE {{p}}jobitm-price, + END OF ty_sum, + tt_sum TYPE SORTED TABLE OF ty_sum WITH UNIQUE KEY job_id. + TYPES: + BEGIN OF ty_mech, + mech_id TYPE {{p}}mech-mech_id, + mech_name TYPE {{p}}mech-mech_name, + END OF ty_mech, + tt_mech TYPE SORTED TABLE OF ty_mech WITH UNIQUE KEY mech_id. + TYPES tt_job_range TYPE RANGE OF {{p}}jobhdr-job_id. + TYPES tt_mech_range TYPE RANGE OF {{p}}mech-mech_id. + METHODS read_jobs + IMPORTING iv_date TYPE d + RETURNING VALUE(rt_jobs) TYPE tt_job. + METHODS job_range + IMPORTING it_jobs TYPE tt_job + RETURNING VALUE(rt_range) TYPE tt_job_range. + METHODS mech_range + IMPORTING it_jobs TYPE tt_job + RETURNING VALUE(rt_range) TYPE tt_mech_range. + METHODS read_sums + IMPORTING it_job_range TYPE tt_job_range + RETURNING VALUE(rt_sums) TYPE tt_sum. + METHODS read_mechanics + IMPORTING it_mech_range TYPE tt_mech_range + RETURNING VALUE(rt_mech) TYPE tt_mech. +ENDCLASS. + +CLASS lcl_report IMPLEMENTATION. + METHOD run. + DATA(lt_jobs) = read_jobs( iv_date ). + IF lt_jobs IS INITIAL. + RETURN. + ENDIF. + + DATA(lt_sums) = read_sums( job_range( lt_jobs ) ). + DATA(lt_mech) = read_mechanics( mech_range( lt_jobs ) ). + + LOOP AT lt_jobs INTO DATA(ls_job). + READ TABLE lt_sums INTO DATA(ls_sum) WITH TABLE KEY job_id = ls_job-job_id. + IF sy-subrc <> 0. + CONTINUE. + ENDIF. + + READ TABLE lt_mech INTO DATA(ls_mech) WITH TABLE KEY mech_id = ls_job-mech_id. + DATA(lv_mechanic) = COND {{p}}mech-mech_name( + WHEN sy-subrc = 0 THEN ls_mech-mech_name + ELSE c_unknown ). + + INSERT VALUE #( job_id = ls_job-job_id + customer = ls_job-customer + mechanic = lv_mechanic + items = ls_sum-items + total = ls_sum-total ) INTO TABLE rt_lines. + ENDLOOP. + + SORT rt_lines BY total DESCENDING job_id ASCENDING. + ENDMETHOD. + + METHOD read_jobs. + SELECT job_id, customer, mech_id + FROM {{p}}jobhdr + WHERE job_date = @iv_date + INTO CORRESPONDING FIELDS OF TABLE @rt_jobs. + ENDMETHOD. + + METHOD job_range. + rt_range = VALUE #( FOR ls_job IN it_jobs + ( sign = 'I' option = 'EQ' low = ls_job-job_id ) ). + ENDMETHOD. + + METHOD mech_range. + rt_range = VALUE #( FOR ls_job IN it_jobs + ( sign = 'I' option = 'EQ' low = ls_job-mech_id ) ). + ENDMETHOD. + + METHOD read_sums. + SELECT job_id, qty, price + FROM {{p}}jobitm + WHERE job_id IN @it_job_range + INTO TABLE @DATA(lt_items). + + LOOP AT lt_items INTO DATA(ls_item). + READ TABLE rt_sums ASSIGNING FIELD-SYMBOL() WITH TABLE KEY job_id = ls_item-job_id. + IF sy-subrc <> 0. + INSERT VALUE #( job_id = ls_item-job_id ) INTO TABLE rt_sums ASSIGNING . + ENDIF. + -items = -items - 1. + -total = -total + ls_item-qty * ls_item-price. + ENDLOOP. + ENDMETHOD. + + METHOD read_mechanics. + SELECT mech_id, mech_name + FROM {{p}}mech + WHERE mech_id IN @it_mech_range + INTO CORRESPONDING FIELDS OF TABLE @rt_mech. + ENDMETHOD. + + METHOD display. + TRY. + cl_salv_table=>factory( IMPORTING r_salv_table = DATA(lo_alv) + CHANGING t_table = ct_lines ). + lo_alv->display( ). + CATCH cx_salv_msg INTO DATA(lx_error). + MESSAGE lx_error TYPE 'I' DISPLAY LIKE 'E'. + ENDTRY. + ENDMETHOD. +ENDCLASS. + +START-OF-SELECTION. + DATA(go_report) = NEW lcl_report( ). + DATA(gt_lines) = go_report->run( p_date ). + go_report->display( CHANGING ct_lines = gt_lines ). + +CLASS ltc_report DEFINITION FINAL 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 totals_and_items FOR TESTING. + METHODS unknown_mechanic FOR TESTING. + METHODS skips_jobs_without_items FOR TESTING. +ENDCLASS. + +CLASS ltc_report IMPLEMENTATION. + METHOD class_setup. + go_env = cl_osql_test_environment=>create( + i_dependency_list = VALUE #( ( '{{P}}MECH' ) ( '{{P}}JOBHDR' ) ( '{{P}}JOBITM' ) ) ). + + DATA lt_mech TYPE STANDARD TABLE OF {{p}}mech WITH EMPTY KEY. + lt_mech = VALUE #( ( mech_id = 'M1' mech_name = 'Anna' ) ). + go_env->insert_test_data( lt_mech ). + + DATA lt_job TYPE STANDARD TABLE OF {{p}}jobhdr WITH EMPTY KEY. + lt_job = VALUE #( ( job_id = 1 job_date = '20260410' customer = 'A' mech_id = 'M1' ) + ( job_id = 2 job_date = '20260410' customer = 'B' mech_id = 'M9' ) + ( job_id = 3 job_date = '20260410' customer = 'C' mech_id = 'M1' ) ). + go_env->insert_test_data( lt_job ). + + DATA lt_item TYPE STANDARD TABLE OF {{p}}jobitm WITH EMPTY KEY. + lt_item = VALUE #( ( job_id = 1 item_no = 10 spare_part = 'X' qty = 2 price = 10 ) + ( job_id = 1 item_no = 20 spare_part = 'Y' qty = 1 price = 5 ) + ( job_id = 2 item_no = 10 spare_part = 'Z' qty = 1 price = 40 ) ). + go_env->insert_test_data( lt_item ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD totals_and_items. + DATA(lt_lines) = NEW lcl_report( )->run( '20260410' ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 'B' act = lt_lines[ 1 ]-customer ). + cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}jobitm-price( 40 ) act = lt_lines[ 1 ]-total ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lt_lines[ 2 ]-items ). + cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}jobitm-price( 25 ) act = lt_lines[ 2 ]-total ). + ENDMETHOD. + + METHOD unknown_mechanic. + DATA(lt_lines) = NEW lcl_report( )->run( '20260410' ). + cl_abap_unit_assert=>assert_equals( exp = 'UNKNOWN' act = lt_lines[ 1 ]-mechanic ). + ENDMETHOD. + + METHOD skips_jobs_without_items. + DATA(lt_lines) = NEW lcl_report( )->run( '20260410' ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1942/faulty/m2_repair_list.prog.abap b/tasks_gen/train/G1942/faulty/m2_repair_list.prog.abap new file mode 100644 index 0000000..40f79da --- /dev/null +++ b/tasks_gen/train/G1942/faulty/m2_repair_list.prog.abap @@ -0,0 +1,203 @@ +REPORT {{p}}repair_list. + +PARAMETERS p_date TYPE d OBLIGATORY. + +CLASS lcl_report DEFINITION FINAL. + PUBLIC SECTION. + TYPES: + BEGIN OF ty_line, + job_id TYPE {{p}}jobhdr-job_id, + customer TYPE {{p}}jobhdr-customer, + mechanic TYPE {{p}}mech-mech_name, + items TYPE i, + total TYPE {{p}}jobitm-price, + END OF ty_line, + tt_line TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY. + METHODS run + IMPORTING iv_date TYPE d + RETURNING VALUE(rt_lines) TYPE tt_line. + METHODS display + CHANGING ct_lines TYPE tt_line. + PRIVATE SECTION. + CONSTANTS c_unknown TYPE {{p}}mech-mech_name VALUE 'UNKNOWN'. + TYPES: + BEGIN OF ty_job, + job_id TYPE {{p}}jobhdr-job_id, + customer TYPE {{p}}jobhdr-customer, + mech_id TYPE {{p}}jobhdr-mech_id, + END OF ty_job, + tt_job TYPE SORTED TABLE OF ty_job WITH UNIQUE KEY job_id. + TYPES: + BEGIN OF ty_sum, + job_id TYPE {{p}}jobhdr-job_id, + items TYPE i, + total TYPE {{p}}jobitm-price, + END OF ty_sum, + tt_sum TYPE SORTED TABLE OF ty_sum WITH UNIQUE KEY job_id. + TYPES: + BEGIN OF ty_mech, + mech_id TYPE {{p}}mech-mech_id, + mech_name TYPE {{p}}mech-mech_name, + END OF ty_mech, + tt_mech TYPE SORTED TABLE OF ty_mech WITH UNIQUE KEY mech_id. + TYPES tt_job_range TYPE RANGE OF {{p}}jobhdr-job_id. + TYPES tt_mech_range TYPE RANGE OF {{p}}mech-mech_id. + METHODS read_jobs + IMPORTING iv_date TYPE d + RETURNING VALUE(rt_jobs) TYPE tt_job. + METHODS job_range + IMPORTING it_jobs TYPE tt_job + RETURNING VALUE(rt_range) TYPE tt_job_range. + METHODS mech_range + IMPORTING it_jobs TYPE tt_job + RETURNING VALUE(rt_range) TYPE tt_mech_range. + METHODS read_sums + IMPORTING it_job_range TYPE tt_job_range + RETURNING VALUE(rt_sums) TYPE tt_sum. + METHODS read_mechanics + IMPORTING it_mech_range TYPE tt_mech_range + RETURNING VALUE(rt_mech) TYPE tt_mech. +ENDCLASS. + +CLASS lcl_report IMPLEMENTATION. + METHOD run. + DATA(lt_jobs) = read_jobs( iv_date ). + IF lt_jobs IS INITIAL. + RETURN. + ENDIF. + + DATA(lt_sums) = read_sums( job_range( lt_jobs ) ). + DATA(lt_mech) = read_mechanics( mech_range( lt_jobs ) ). + + LOOP AT lt_jobs INTO DATA(ls_job). + READ TABLE lt_sums INTO DATA(ls_sum) WITH TABLE KEY job_id = ls_job-job_id. + IF sy-subrc <> 0. + CONTINUE. + ENDIF. + + READ TABLE lt_mech INTO DATA(ls_mech) WITH TABLE KEY mech_id = ls_job-mech_id. + DATA(lv_mechanic) = COND {{p}}mech-mech_name( + WHEN sy-subrc = 0 THEN ls_mech-mech_name + ELSE c_unknown ). + + INSERT VALUE #( job_id = ls_job-job_id + customer = ls_job-customer + mechanic = lv_mechanic + items = ls_sum-items + total = ls_sum-total ) INTO TABLE rt_lines. + ENDLOOP. + + SORT rt_lines BY total DESCENDING job_id ASCENDING. + ENDMETHOD. + + METHOD read_jobs. + SELECT job_id, customer, mech_id + FROM {{p}}jobhdr + WHERE job_date = @iv_date + INTO CORRESPONDING FIELDS OF TABLE @rt_jobs. + ENDMETHOD. + + METHOD job_range. + rt_range = VALUE #( FOR ls_job IN it_jobs + ( sign = 'I' option = 'EQ' low = ls_job-job_id ) ). + ENDMETHOD. + + METHOD mech_range. + rt_range = VALUE #( FOR ls_job IN it_jobs + ( sign = 'I' option = 'EQ' low = ls_job-mech_id ) ). + ENDMETHOD. + + METHOD read_sums. + SELECT job_id, qty, price + FROM {{p}}jobitm + WHERE job_id IN @it_job_range + INTO TABLE @DATA(lt_items). + + LOOP AT lt_items INTO DATA(ls_item). + READ TABLE rt_sums ASSIGNING FIELD-SYMBOL() WITH TABLE KEY job_id = ls_item-job_id. + IF sy-subrc <> 0. + INSERT VALUE #( job_id = ls_item-job_id ) INTO TABLE rt_sums ASSIGNING . + ENDIF. + -items = -items + 1. + -total = -total - ls_item-qty * ls_item-price. + ENDLOOP. + ENDMETHOD. + + METHOD read_mechanics. + SELECT mech_id, mech_name + FROM {{p}}mech + WHERE mech_id IN @it_mech_range + INTO CORRESPONDING FIELDS OF TABLE @rt_mech. + ENDMETHOD. + + METHOD display. + TRY. + cl_salv_table=>factory( IMPORTING r_salv_table = DATA(lo_alv) + CHANGING t_table = ct_lines ). + lo_alv->display( ). + CATCH cx_salv_msg INTO DATA(lx_error). + MESSAGE lx_error TYPE 'I' DISPLAY LIKE 'E'. + ENDTRY. + ENDMETHOD. +ENDCLASS. + +START-OF-SELECTION. + DATA(go_report) = NEW lcl_report( ). + DATA(gt_lines) = go_report->run( p_date ). + go_report->display( CHANGING ct_lines = gt_lines ). + +CLASS ltc_report DEFINITION FINAL 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 totals_and_items FOR TESTING. + METHODS unknown_mechanic FOR TESTING. + METHODS skips_jobs_without_items FOR TESTING. +ENDCLASS. + +CLASS ltc_report IMPLEMENTATION. + METHOD class_setup. + go_env = cl_osql_test_environment=>create( + i_dependency_list = VALUE #( ( '{{P}}MECH' ) ( '{{P}}JOBHDR' ) ( '{{P}}JOBITM' ) ) ). + + DATA lt_mech TYPE STANDARD TABLE OF {{p}}mech WITH EMPTY KEY. + lt_mech = VALUE #( ( mech_id = 'M1' mech_name = 'Anna' ) ). + go_env->insert_test_data( lt_mech ). + + DATA lt_job TYPE STANDARD TABLE OF {{p}}jobhdr WITH EMPTY KEY. + lt_job = VALUE #( ( job_id = 1 job_date = '20260410' customer = 'A' mech_id = 'M1' ) + ( job_id = 2 job_date = '20260410' customer = 'B' mech_id = 'M9' ) + ( job_id = 3 job_date = '20260410' customer = 'C' mech_id = 'M1' ) ). + go_env->insert_test_data( lt_job ). + + DATA lt_item TYPE STANDARD TABLE OF {{p}}jobitm WITH EMPTY KEY. + lt_item = VALUE #( ( job_id = 1 item_no = 10 spare_part = 'X' qty = 2 price = 10 ) + ( job_id = 1 item_no = 20 spare_part = 'Y' qty = 1 price = 5 ) + ( job_id = 2 item_no = 10 spare_part = 'Z' qty = 1 price = 40 ) ). + go_env->insert_test_data( lt_item ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD totals_and_items. + DATA(lt_lines) = NEW lcl_report( )->run( '20260410' ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 'B' act = lt_lines[ 1 ]-customer ). + cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}jobitm-price( 40 ) act = lt_lines[ 1 ]-total ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lt_lines[ 2 ]-items ). + cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}jobitm-price( 25 ) act = lt_lines[ 2 ]-total ). + ENDMETHOD. + + METHOD unknown_mechanic. + DATA(lt_lines) = NEW lcl_report( )->run( '20260410' ). + cl_abap_unit_assert=>assert_equals( exp = 'UNKNOWN' act = lt_lines[ 1 ]-mechanic ). + ENDMETHOD. + + METHOD skips_jobs_without_items. + DATA(lt_lines) = NEW lcl_report( )->run( '20260410' ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1942/faulty/m3_repair_list.prog.abap b/tasks_gen/train/G1942/faulty/m3_repair_list.prog.abap new file mode 100644 index 0000000..dff04ac --- /dev/null +++ b/tasks_gen/train/G1942/faulty/m3_repair_list.prog.abap @@ -0,0 +1,203 @@ +REPORT {{p}}repair_list. + +PARAMETERS p_date TYPE d OBLIGATORY. + +CLASS lcl_report DEFINITION FINAL. + PUBLIC SECTION. + TYPES: + BEGIN OF ty_line, + job_id TYPE {{p}}jobhdr-job_id, + customer TYPE {{p}}jobhdr-customer, + mechanic TYPE {{p}}mech-mech_name, + items TYPE i, + total TYPE {{p}}jobitm-price, + END OF ty_line, + tt_line TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY. + METHODS run + IMPORTING iv_date TYPE d + RETURNING VALUE(rt_lines) TYPE tt_line. + METHODS display + CHANGING ct_lines TYPE tt_line. + PRIVATE SECTION. + CONSTANTS c_unknown TYPE {{p}}mech-mech_name VALUE 'UNKNOWN'. + TYPES: + BEGIN OF ty_job, + job_id TYPE {{p}}jobhdr-job_id, + customer TYPE {{p}}jobhdr-customer, + mech_id TYPE {{p}}jobhdr-mech_id, + END OF ty_job, + tt_job TYPE SORTED TABLE OF ty_job WITH UNIQUE KEY job_id. + TYPES: + BEGIN OF ty_sum, + job_id TYPE {{p}}jobhdr-job_id, + items TYPE i, + total TYPE {{p}}jobitm-price, + END OF ty_sum, + tt_sum TYPE SORTED TABLE OF ty_sum WITH UNIQUE KEY job_id. + TYPES: + BEGIN OF ty_mech, + mech_id TYPE {{p}}mech-mech_id, + mech_name TYPE {{p}}mech-mech_name, + END OF ty_mech, + tt_mech TYPE SORTED TABLE OF ty_mech WITH UNIQUE KEY mech_id. + TYPES tt_job_range TYPE RANGE OF {{p}}jobhdr-job_id. + TYPES tt_mech_range TYPE RANGE OF {{p}}mech-mech_id. + METHODS read_jobs + IMPORTING iv_date TYPE d + RETURNING VALUE(rt_jobs) TYPE tt_job. + METHODS job_range + IMPORTING it_jobs TYPE tt_job + RETURNING VALUE(rt_range) TYPE tt_job_range. + METHODS mech_range + IMPORTING it_jobs TYPE tt_job + RETURNING VALUE(rt_range) TYPE tt_mech_range. + METHODS read_sums + IMPORTING it_job_range TYPE tt_job_range + RETURNING VALUE(rt_sums) TYPE tt_sum. + METHODS read_mechanics + IMPORTING it_mech_range TYPE tt_mech_range + RETURNING VALUE(rt_mech) TYPE tt_mech. +ENDCLASS. + +CLASS lcl_report IMPLEMENTATION. + METHOD run. + DATA(lt_jobs) = read_jobs( iv_date ). + IF lt_jobs IS INITIAL. + RETURN. + ENDIF. + + DATA(lt_sums) = read_sums( job_range( lt_jobs ) ). + DATA(lt_mech) = read_mechanics( mech_range( lt_jobs ) ). + + LOOP AT lt_jobs INTO DATA(ls_job). + READ TABLE lt_sums INTO DATA(ls_sum) WITH TABLE KEY job_id = ls_job-job_id. + IF sy-subrc <> 0. + CONTINUE. + ENDIF. + + READ TABLE lt_mech INTO DATA(ls_mech) WITH TABLE KEY mech_id = ls_job-mech_id. + DATA(lv_mechanic) = COND {{p}}mech-mech_name( + WHEN sy-subrc = 0 THEN ls_mech-mech_name + ELSE c_unknown ). + + INSERT VALUE #( job_id = ls_job-job_id + customer = ls_job-customer + mechanic = lv_mechanic + items = ls_sum-items + total = ls_sum-total ) INTO TABLE rt_lines. + ENDLOOP. + + SORT rt_lines BY total DESCENDING job_id ASCENDING. + ENDMETHOD. + + METHOD read_jobs. + SELECT job_id, customer, mech_id + FROM {{p}}jobhdr + WHERE job_date = @iv_date + INTO CORRESPONDING FIELDS OF TABLE @rt_jobs. + ENDMETHOD. + + METHOD job_range. + rt_range = VALUE #( FOR ls_job IN it_jobs + ( sign = 'I' option = 'EQ' low = ls_job-job_id ) ). + ENDMETHOD. + + METHOD mech_range. + rt_range = VALUE #( FOR ls_job IN it_jobs + ( sign = 'I' option = 'EQ' low = ls_job-mech_id ) ). + ENDMETHOD. + + METHOD read_sums. + SELECT job_id, qty, price + FROM {{p}}jobitm + WHERE job_id IN @it_job_range + INTO TABLE @DATA(lt_items). + + LOOP AT lt_items INTO DATA(ls_item). + READ TABLE rt_sums ASSIGNING FIELD-SYMBOL() WITH TABLE KEY job_id = ls_item-job_id. + IF sy-subrc <> 0. + INSERT VALUE #( job_id = ls_item-job_id ) INTO TABLE rt_sums ASSIGNING . + ENDIF. + -items = -items + 1. + -total = -total + ls_item-qty / ls_item-price. + ENDLOOP. + ENDMETHOD. + + METHOD read_mechanics. + SELECT mech_id, mech_name + FROM {{p}}mech + WHERE mech_id IN @it_mech_range + INTO CORRESPONDING FIELDS OF TABLE @rt_mech. + ENDMETHOD. + + METHOD display. + TRY. + cl_salv_table=>factory( IMPORTING r_salv_table = DATA(lo_alv) + CHANGING t_table = ct_lines ). + lo_alv->display( ). + CATCH cx_salv_msg INTO DATA(lx_error). + MESSAGE lx_error TYPE 'I' DISPLAY LIKE 'E'. + ENDTRY. + ENDMETHOD. +ENDCLASS. + +START-OF-SELECTION. + DATA(go_report) = NEW lcl_report( ). + DATA(gt_lines) = go_report->run( p_date ). + go_report->display( CHANGING ct_lines = gt_lines ). + +CLASS ltc_report DEFINITION FINAL 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 totals_and_items FOR TESTING. + METHODS unknown_mechanic FOR TESTING. + METHODS skips_jobs_without_items FOR TESTING. +ENDCLASS. + +CLASS ltc_report IMPLEMENTATION. + METHOD class_setup. + go_env = cl_osql_test_environment=>create( + i_dependency_list = VALUE #( ( '{{P}}MECH' ) ( '{{P}}JOBHDR' ) ( '{{P}}JOBITM' ) ) ). + + DATA lt_mech TYPE STANDARD TABLE OF {{p}}mech WITH EMPTY KEY. + lt_mech = VALUE #( ( mech_id = 'M1' mech_name = 'Anna' ) ). + go_env->insert_test_data( lt_mech ). + + DATA lt_job TYPE STANDARD TABLE OF {{p}}jobhdr WITH EMPTY KEY. + lt_job = VALUE #( ( job_id = 1 job_date = '20260410' customer = 'A' mech_id = 'M1' ) + ( job_id = 2 job_date = '20260410' customer = 'B' mech_id = 'M9' ) + ( job_id = 3 job_date = '20260410' customer = 'C' mech_id = 'M1' ) ). + go_env->insert_test_data( lt_job ). + + DATA lt_item TYPE STANDARD TABLE OF {{p}}jobitm WITH EMPTY KEY. + lt_item = VALUE #( ( job_id = 1 item_no = 10 spare_part = 'X' qty = 2 price = 10 ) + ( job_id = 1 item_no = 20 spare_part = 'Y' qty = 1 price = 5 ) + ( job_id = 2 item_no = 10 spare_part = 'Z' qty = 1 price = 40 ) ). + go_env->insert_test_data( lt_item ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD totals_and_items. + DATA(lt_lines) = NEW lcl_report( )->run( '20260410' ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 'B' act = lt_lines[ 1 ]-customer ). + cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}jobitm-price( 40 ) act = lt_lines[ 1 ]-total ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lt_lines[ 2 ]-items ). + cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}jobitm-price( 25 ) act = lt_lines[ 2 ]-total ). + ENDMETHOD. + + METHOD unknown_mechanic. + DATA(lt_lines) = NEW lcl_report( )->run( '20260410' ). + cl_abap_unit_assert=>assert_equals( exp = 'UNKNOWN' act = lt_lines[ 1 ]-mechanic ). + ENDMETHOD. + + METHOD skips_jobs_without_items. + DATA(lt_lines) = NEW lcl_report( )->run( '20260410' ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1942/generation.json b/tasks_gen/train/G1942/generation.json new file mode 100644 index 0000000..6df21d9 --- /dev/null +++ b/tasks_gen/train/G1942/generation.json @@ -0,0 +1,29 @@ +{ + "id": "G1942", + "pool": "train", + "object_type": "PROG", + "category": "C", + "attempts": [ + { + "stage": "validate", + "oracle": null, + "null": null + }, + { + "stage": "validate", + "oracle": 90.0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 4, + "killed": 4, + "ok": true + } + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1942/hidden/bike_hidden.clas.abap b/tasks_gen/train/G1942/hidden/bike_hidden.clas.abap new file mode 100644 index 0000000..49f5d68 --- /dev/null +++ b/tasks_gen/train/G1942/hidden/bike_hidden.clas.abap @@ -0,0 +1,93 @@ +CLASS {{p}}bike_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS run + IMPORTING iv_date TYPE d + RETURNING VALUE(rr_data) TYPE REF TO data. + METHODS lines_of + IMPORTING ir_data TYPE REF TO data + RETURNING VALUE(rv_lines) TYPE i. + METHODS value_of + IMPORTING ir_data TYPE REF TO data + iv_row TYPE i + iv_col TYPE string + RETURNING VALUE(rv_value) TYPE string. + METHODS one_line_per_job FOR TESTING. + METHODS sorted_by_total FOR TESTING. + METHODS totals_and_counts FOR TESTING. + METHODS mechanic_name FOR TESTING. + METHODS unknown_mechanic FOR TESTING. + METHODS other_day FOR TESTING. + METHODS no_jobs_on_day FOR TESTING. +ENDCLASS. + + +CLASS {{p}}bike_hidden IMPLEMENTATION. + METHOD run. + cl_salv_bs_runtime_info=>set( display = abap_false metadata = abap_false data = abap_true ). + SUBMIT {{p}}repair_list WITH p_date = iv_date AND RETURN. + TRY. + cl_salv_bs_runtime_info=>get_data_ref( IMPORTING r_data = rr_data ). + CATCH cx_salv_bs_sc_runtime_info. + ENDTRY. + cl_salv_bs_runtime_info=>clear_all( ). + ENDMETHOD. + + METHOD lines_of. + FIELD-SYMBOLS TYPE STANDARD TABLE. + IF ir_data IS BOUND. + ASSIGN ir_data->* TO . + rv_lines = lines( ). + ENDIF. + ENDMETHOD. + + METHOD value_of. + FIELD-SYMBOLS TYPE STANDARD TABLE. + ASSIGN ir_data->* TO . + ASSIGN [ iv_row ] TO FIELD-SYMBOL(). + ASSIGN COMPONENT iv_col OF STRUCTURE TO FIELD-SYMBOL(). + cl_abap_unit_assert=>assert_subrc( exp = 0 msg = |Column { iv_col } missing| ). + rv_value = condense( CONV string( ) ). + REPLACE ALL OCCURRENCES OF ',' IN rv_value WITH '.'. + ENDMETHOD. + + METHOD one_line_per_job. + cl_abap_unit_assert=>assert_equals( exp = 4 act = lines_of( run( '20260410' ) ) ). + ENDMETHOD. + + METHOD sorted_by_total. + DATA(lr_data) = run( '20260410' ). + cl_abap_unit_assert=>assert_equals( exp = `102` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `JOB_ID` ) ). + cl_abap_unit_assert=>assert_equals( exp = `105` act = value_of( ir_data = lr_data iv_row = 4 iv_col = `JOB_ID` ) ). + ENDMETHOD. + + METHOD totals_and_counts. + DATA(lr_data) = run( '20260410' ). + cl_abap_unit_assert=>assert_equals( exp = `101` act = value_of( ir_data = lr_data iv_row = 2 iv_col = `JOB_ID` ) ). + cl_abap_unit_assert=>assert_equals( exp = `29.00` act = value_of( ir_data = lr_data iv_row = 2 iv_col = `TOTAL` ) ). + cl_abap_unit_assert=>assert_equals( exp = `2` act = value_of( ir_data = lr_data iv_row = 2 iv_col = `ITEMS` ) ). + cl_abap_unit_assert=>assert_equals( exp = `28.50` act = value_of( ir_data = lr_data iv_row = 3 iv_col = `TOTAL` ) ). + ENDMETHOD. + + METHOD mechanic_name. + DATA(lr_data) = run( '20260410' ). + cl_abap_unit_assert=>assert_equals( exp = `Ben Osei` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `MECHANIC` ) ). + cl_abap_unit_assert=>assert_equals( exp = `Anna Keller` act = value_of( ir_data = lr_data iv_row = 2 iv_col = `MECHANIC` ) ). + ENDMETHOD. + + METHOD unknown_mechanic. + DATA(lr_data) = run( '20260410' ). + cl_abap_unit_assert=>assert_equals( exp = `UNKNOWN` act = value_of( ir_data = lr_data iv_row = 4 iv_col = `MECHANIC` ) ). + ENDMETHOD. + + METHOD other_day. + DATA(lr_data) = run( '20260411' ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lines_of( lr_data ) ). + cl_abap_unit_assert=>assert_equals( exp = `104` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `JOB_ID` ) ). + cl_abap_unit_assert=>assert_equals( exp = `40.00` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `TOTAL` ) ). + ENDMETHOD. + + METHOD no_jobs_on_day. + cl_abap_unit_assert=>assert_equals( exp = 0 act = lines_of( run( '20260412' ) ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1942/mutation.json b/tasks_gen/train/G1942/mutation.json new file mode 100644 index 0000000..99d11af --- /dev/null +++ b/tasks_gen/train/G1942/mutation.json @@ -0,0 +1,59 @@ +{ + "task": "G1942", + "mutants": [ + { + "object": "{{P}}REPAIR_LIST", + "mutant": "line 96: = -> <> (eq)", + "status": "killed", + "hidden": "0/7", + "failed_tests": [ + "MECHANIC_NAME", + "NO_JOBS_ON_DAY", + "ONE_LINE_PER_JOB", + "OTHER_DAY", + "SORTED_BY_TOTAL", + "TOTALS_AND_COUNTS", + "UNKNOWN_MECHANIC" + ] + }, + { + "object": "{{P}}REPAIR_LIST", + "mutant": "line 121: + -> - (arith)", + "status": "killed", + "hidden": "6/7", + "failed_tests": [ + "TOTALS_AND_COUNTS" + ] + }, + { + "object": "{{P}}REPAIR_LIST", + "mutant": "line 122: + -> - (arith)", + "status": "killed", + "hidden": "2/7", + "failed_tests": [ + "MECHANIC_NAME", + "OTHER_DAY", + "SORTED_BY_TOTAL", + "TOTALS_AND_COUNTS", + "UNKNOWN_MECHANIC" + ] + }, + { + "object": "{{P}}REPAIR_LIST", + "mutant": "line 122: * -> / (arith)", + "status": "killed", + "hidden": "2/7", + "failed_tests": [ + "MECHANIC_NAME", + "OTHER_DAY", + "SORTED_BY_TOTAL", + "TOTALS_AND_COUNTS", + "UNKNOWN_MECHANIC" + ] + } + ], + "valid": 4, + "killed": 4, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1942/reference/repair_list.prog.abap b/tasks_gen/train/G1942/reference/repair_list.prog.abap new file mode 100644 index 0000000..53afc5c --- /dev/null +++ b/tasks_gen/train/G1942/reference/repair_list.prog.abap @@ -0,0 +1,203 @@ +REPORT {{p}}repair_list. + +PARAMETERS p_date TYPE d OBLIGATORY. + +CLASS lcl_report DEFINITION FINAL. + PUBLIC SECTION. + TYPES: + BEGIN OF ty_line, + job_id TYPE {{p}}jobhdr-job_id, + customer TYPE {{p}}jobhdr-customer, + mechanic TYPE {{p}}mech-mech_name, + items TYPE i, + total TYPE {{p}}jobitm-price, + END OF ty_line, + tt_line TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY. + METHODS run + IMPORTING iv_date TYPE d + RETURNING VALUE(rt_lines) TYPE tt_line. + METHODS display + CHANGING ct_lines TYPE tt_line. + PRIVATE SECTION. + CONSTANTS c_unknown TYPE {{p}}mech-mech_name VALUE 'UNKNOWN'. + TYPES: + BEGIN OF ty_job, + job_id TYPE {{p}}jobhdr-job_id, + customer TYPE {{p}}jobhdr-customer, + mech_id TYPE {{p}}jobhdr-mech_id, + END OF ty_job, + tt_job TYPE SORTED TABLE OF ty_job WITH UNIQUE KEY job_id. + TYPES: + BEGIN OF ty_sum, + job_id TYPE {{p}}jobhdr-job_id, + items TYPE i, + total TYPE {{p}}jobitm-price, + END OF ty_sum, + tt_sum TYPE SORTED TABLE OF ty_sum WITH UNIQUE KEY job_id. + TYPES: + BEGIN OF ty_mech, + mech_id TYPE {{p}}mech-mech_id, + mech_name TYPE {{p}}mech-mech_name, + END OF ty_mech, + tt_mech TYPE SORTED TABLE OF ty_mech WITH UNIQUE KEY mech_id. + TYPES tt_job_range TYPE RANGE OF {{p}}jobhdr-job_id. + TYPES tt_mech_range TYPE RANGE OF {{p}}mech-mech_id. + METHODS read_jobs + IMPORTING iv_date TYPE d + RETURNING VALUE(rt_jobs) TYPE tt_job. + METHODS job_range + IMPORTING it_jobs TYPE tt_job + RETURNING VALUE(rt_range) TYPE tt_job_range. + METHODS mech_range + IMPORTING it_jobs TYPE tt_job + RETURNING VALUE(rt_range) TYPE tt_mech_range. + METHODS read_sums + IMPORTING it_job_range TYPE tt_job_range + RETURNING VALUE(rt_sums) TYPE tt_sum. + METHODS read_mechanics + IMPORTING it_mech_range TYPE tt_mech_range + RETURNING VALUE(rt_mech) TYPE tt_mech. +ENDCLASS. + +CLASS lcl_report IMPLEMENTATION. + METHOD run. + DATA(lt_jobs) = read_jobs( iv_date ). + IF lt_jobs IS INITIAL. + RETURN. + ENDIF. + + DATA(lt_sums) = read_sums( job_range( lt_jobs ) ). + DATA(lt_mech) = read_mechanics( mech_range( lt_jobs ) ). + + LOOP AT lt_jobs INTO DATA(ls_job). + READ TABLE lt_sums INTO DATA(ls_sum) WITH TABLE KEY job_id = ls_job-job_id. + IF sy-subrc <> 0. + CONTINUE. + ENDIF. + + READ TABLE lt_mech INTO DATA(ls_mech) WITH TABLE KEY mech_id = ls_job-mech_id. + DATA(lv_mechanic) = COND {{p}}mech-mech_name( + WHEN sy-subrc = 0 THEN ls_mech-mech_name + ELSE c_unknown ). + + INSERT VALUE #( job_id = ls_job-job_id + customer = ls_job-customer + mechanic = lv_mechanic + items = ls_sum-items + total = ls_sum-total ) INTO TABLE rt_lines. + ENDLOOP. + + SORT rt_lines BY total DESCENDING job_id ASCENDING. + ENDMETHOD. + + METHOD read_jobs. + SELECT job_id, customer, mech_id + FROM {{p}}jobhdr + WHERE job_date = @iv_date + INTO CORRESPONDING FIELDS OF TABLE @rt_jobs. + ENDMETHOD. + + METHOD job_range. + rt_range = VALUE #( FOR ls_job IN it_jobs + ( sign = 'I' option = 'EQ' low = ls_job-job_id ) ). + ENDMETHOD. + + METHOD mech_range. + rt_range = VALUE #( FOR ls_job IN it_jobs + ( sign = 'I' option = 'EQ' low = ls_job-mech_id ) ). + ENDMETHOD. + + METHOD read_sums. + SELECT job_id, qty, price + FROM {{p}}jobitm + WHERE job_id IN @it_job_range + INTO TABLE @DATA(lt_items). + + LOOP AT lt_items INTO DATA(ls_item). + READ TABLE rt_sums ASSIGNING FIELD-SYMBOL() WITH TABLE KEY job_id = ls_item-job_id. + IF sy-subrc <> 0. + INSERT VALUE #( job_id = ls_item-job_id ) INTO TABLE rt_sums ASSIGNING . + ENDIF. + -items = -items + 1. + -total = -total + ls_item-qty * ls_item-price. + ENDLOOP. + ENDMETHOD. + + METHOD read_mechanics. + SELECT mech_id, mech_name + FROM {{p}}mech + WHERE mech_id IN @it_mech_range + INTO CORRESPONDING FIELDS OF TABLE @rt_mech. + ENDMETHOD. + + METHOD display. + TRY. + cl_salv_table=>factory( IMPORTING r_salv_table = DATA(lo_alv) + CHANGING t_table = ct_lines ). + lo_alv->display( ). + CATCH cx_salv_msg INTO DATA(lx_error). + MESSAGE lx_error TYPE 'I' DISPLAY LIKE 'E'. + ENDTRY. + ENDMETHOD. +ENDCLASS. + +START-OF-SELECTION. + DATA(go_report) = NEW lcl_report( ). + DATA(gt_lines) = go_report->run( p_date ). + go_report->display( CHANGING ct_lines = gt_lines ). + +CLASS ltc_report DEFINITION FINAL 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 totals_and_items FOR TESTING. + METHODS unknown_mechanic FOR TESTING. + METHODS skips_jobs_without_items FOR TESTING. +ENDCLASS. + +CLASS ltc_report IMPLEMENTATION. + METHOD class_setup. + go_env = cl_osql_test_environment=>create( + i_dependency_list = VALUE #( ( '{{P}}MECH' ) ( '{{P}}JOBHDR' ) ( '{{P}}JOBITM' ) ) ). + + DATA lt_mech TYPE STANDARD TABLE OF {{p}}mech WITH EMPTY KEY. + lt_mech = VALUE #( ( mech_id = 'M1' mech_name = 'Anna' ) ). + go_env->insert_test_data( lt_mech ). + + DATA lt_job TYPE STANDARD TABLE OF {{p}}jobhdr WITH EMPTY KEY. + lt_job = VALUE #( ( job_id = 1 job_date = '20260410' customer = 'A' mech_id = 'M1' ) + ( job_id = 2 job_date = '20260410' customer = 'B' mech_id = 'M9' ) + ( job_id = 3 job_date = '20260410' customer = 'C' mech_id = 'M1' ) ). + go_env->insert_test_data( lt_job ). + + DATA lt_item TYPE STANDARD TABLE OF {{p}}jobitm WITH EMPTY KEY. + lt_item = VALUE #( ( job_id = 1 item_no = 10 spare_part = 'X' qty = 2 price = 10 ) + ( job_id = 1 item_no = 20 spare_part = 'Y' qty = 1 price = 5 ) + ( job_id = 2 item_no = 10 spare_part = 'Z' qty = 1 price = 40 ) ). + go_env->insert_test_data( lt_item ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD totals_and_items. + DATA(lt_lines) = NEW lcl_report( )->run( '20260410' ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 'B' act = lt_lines[ 1 ]-customer ). + cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}jobitm-price( 40 ) act = lt_lines[ 1 ]-total ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lt_lines[ 2 ]-items ). + cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}jobitm-price( 25 ) act = lt_lines[ 2 ]-total ). + ENDMETHOD. + + METHOD unknown_mechanic. + DATA(lt_lines) = NEW lcl_report( )->run( '20260410' ). + cl_abap_unit_assert=>assert_equals( exp = 'UNKNOWN' act = lt_lines[ 1 ]-mechanic ). + ENDMETHOD. + + METHOD skips_jobs_without_items. + DATA(lt_lines) = NEW lcl_report( )->run( '20260410' ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1942/seed/bike_seed.clas.abap b/tasks_gen/train/G1942/seed/bike_seed.clas.abap new file mode 100644 index 0000000..13b0a90 --- /dev/null +++ b/tasks_gen/train/G1942/seed/bike_seed.clas.abap @@ -0,0 +1,36 @@ +CLASS {{p}}bike_seed DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES if_oo_adt_classrun. +ENDCLASS. + +CLASS {{p}}bike_seed IMPLEMENTATION. + METHOD if_oo_adt_classrun~main. + DELETE FROM {{p}}jobitm. + DELETE FROM {{p}}jobhdr. + DELETE FROM {{p}}mech. + + INSERT {{p}}mech FROM TABLE @( VALUE #( + ( mech_id = 'M001' mech_name = 'Anna Keller' ) + ( mech_id = 'M002' mech_name = 'Ben Osei' ) + ( mech_id = 'M003' mech_name = 'Cara Lund' ) ) ). + + INSERT {{p}}jobhdr FROM TABLE @( VALUE #( + ( job_id = 101 job_date = '20260410' customer = 'Haus Meier' mech_id = 'M001' ) + ( job_id = 102 job_date = '20260410' customer = 'Bistro Nord' mech_id = 'M002' ) + ( job_id = 103 job_date = '20260410' customer = 'Haus Meier' mech_id = 'M001' ) + ( job_id = 104 job_date = '20260411' customer = 'Villa See' mech_id = 'M002' ) + ( job_id = 105 job_date = '20260410' customer = 'Kiosk West' mech_id = 'M009' ) + ( job_id = 106 job_date = '20260410' customer = 'Garage Sued' mech_id = 'M003' ) ) ). + + INSERT {{p}}jobitm FROM TABLE @( VALUE #( + ( job_id = 101 item_no = 10 spare_part = 'Brake pad' qty = 2 price = '12.50' ) + ( job_id = 101 item_no = 20 spare_part = 'Cable' qty = 1 price = '4.00' ) + ( job_id = 102 item_no = 10 spare_part = 'Tyre' qty = 1 price = '35.00' ) + ( job_id = 103 item_no = 10 spare_part = 'Chain' qty = 1 price = '22.00' ) + ( job_id = 103 item_no = 20 spare_part = 'Bell' qty = 1 price = '6.50' ) + ( job_id = 104 item_no = 10 spare_part = 'Saddle' qty = 1 price = '40.00' ) + ( job_id = 105 item_no = 10 spare_part = 'Tube' qty = 2 price = '8.00' ) ) ). + + out->write( |items: { sy-dbcnt }| ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1942/seed/jobhdr.tabl.asabap b/tasks_gen/train/G1942/seed/jobhdr.tabl.asabap new file mode 100644 index 0000000..f286d72 --- /dev/null +++ b/tasks_gen/train/G1942/seed/jobhdr.tabl.asabap @@ -0,0 +1,12 @@ +@EndUserText.label : 'Repair jobs' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}jobhdr { + key client : abap.clnt not null; + key job_id : abap.int4 not null; + job_date : abap.dats; + customer : abap.char(40); + mech_id : abap.char(6); +} diff --git a/tasks_gen/train/G1942/seed/jobitm.tabl.asabap b/tasks_gen/train/G1942/seed/jobitm.tabl.asabap new file mode 100644 index 0000000..a5c47d5 --- /dev/null +++ b/tasks_gen/train/G1942/seed/jobitm.tabl.asabap @@ -0,0 +1,13 @@ +@EndUserText.label : 'Spare parts of a repair job' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}jobitm { + key client : abap.clnt not null; + key job_id : abap.int4 not null; + key item_no : abap.int4 not null; + spare_part : abap.char(20); + qty : abap.int4; + price : abap.dec(15,2); +} diff --git a/tasks_gen/train/G1942/seed/mech.tabl.asabap b/tasks_gen/train/G1942/seed/mech.tabl.asabap new file mode 100644 index 0000000..43216fc --- /dev/null +++ b/tasks_gen/train/G1942/seed/mech.tabl.asabap @@ -0,0 +1,10 @@ +@EndUserText.label : 'Mechanics' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}mech { + key client : abap.clnt not null; + key mech_id : abap.char(6) not null; + mech_name : abap.char(40); +} diff --git a/tasks_gen/train/G1942/spec.md b/tasks_gen/train/G1942/spec.md new file mode 100644 index 0000000..e63b0fd --- /dev/null +++ b/tasks_gen/train/G1942/spec.md @@ -0,0 +1,49 @@ +# 1. Goal +The mobile bicycle repair service "Bike Doctor" repairs bicycles at the homes of +its customers. The office needs a list of the repair jobs of one day. Each line +shows the job, the customer, the mechanic, the number of spare parts and the +total price of the parts. The office uses the list to check the daily work. + +# 2. Open questions +None. + +# 3. Context +- Table {{P}}MECH is in package $TMP. It contains the mechanics. + Fields: MECH_ID (CHAR 6, key), MECH_NAME (CHAR 40). +- Table {{P}}JOBHDR is in package $TMP. It contains the repair jobs. + Fields: JOB_ID (INT4, key), JOB_DATE (DATS), CUSTOMER (CHAR 40), + MECH_ID (CHAR 6). +- Table {{P}}JOBITM is in package $TMP. It contains the spare parts that the + mechanic used for a job. + Fields: JOB_ID (INT4, key), ITEM_NO (INT4, key), SPARE_PART (CHAR 20), + QTY (INT4), PRICE (DEC 15,2). +- The three tables contain data. + +# 4. Contract +- Create the executable program {{P}}REPAIR_LIST in package $TMP. +- Selection screen: + - Parameter P_DATE, type DATS, mandatory: the job date to show. +- Show the result with CL_SALV_TABLE. The output table has these columns with + these names: JOB_ID, CUSTOMER, MECHANIC, ITEMS, TOTAL. + +# 5. Business rules +1. Include a job only if its JOB_DATE is equal to P_DATE. +2. Include a job only if at least one item of this job is in {{P}}JOBITM. +3. ITEMS is the number of the items of the job. +4. TOTAL is the sum of QTY * PRICE over all items of the job. +5. MECHANIC is the MECH_NAME of the mechanic whose MECH_ID is the MECH_ID of + the job. +6. If no mechanic has this MECH_ID, MECHANIC is the text UNKNOWN. +7. Show exactly one line for each included job. +8. Sort the lines by TOTAL, the highest total first. If two lines have the same + TOTAL, sort them by JOB_ID, the lowest first. + +# 6. Constraints +- Release target: SAP_BASIS 816 (ABAP Platform 2025). +- Coding standards: Clean ABAP. Read each table with one database access. +- Out of scope: do not change {{P}}MECH, {{P}}JOBHDR and {{P}}JOBITM. + +# 7. Acceptance +- The program is active and has no syntax error. +- The hidden tests pass. +- Write ABAP Unit tests as local test classes in the program. diff --git a/tasks_gen/train/G1942/task.json b/tasks_gen/train/G1942/task.json new file mode 100644 index 0000000..875f1f2 --- /dev/null +++ b/tasks_gen/train/G1942/task.json @@ -0,0 +1,74 @@ +{ + "id": "G1942", + "category": "C", + "object_type": "PROG", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [ + { + "type": "TABL", + "name": "{{P}}MECH", + "file": "seed/mech.tabl.asabap", + "description": "Mechanics of the mobile bicycle repair service" + }, + { + "type": "TABL", + "name": "{{P}}JOBHDR", + "file": "seed/jobhdr.tabl.asabap", + "description": "Repair jobs" + }, + { + "type": "TABL", + "name": "{{P}}JOBITM", + "file": "seed/jobitm.tabl.asabap", + "description": "Spare parts of the repair jobs" + }, + { + "type": "CLAS", + "name": "{{P}}BIKE_SEED", + "file": "seed/bike_seed.clas.abap", + "description": "Seed data for the repair tables", + "run": true + } + ], + "contract": [ + { + "type": "PROG", + "name": "{{P}}REPAIR_LIST", + "parameters": [ + "p_date" + ] + } + ], + "out_of_scope": [ + "{{P}}MECH", + "{{P}}JOBHDR", + "{{P}}JOBITM" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}BIKE_HIDDEN", + "file": "hidden/bike_hidden.clas.abap", + "description": "Hidden tests for the daily repair list" + } + ], + "reference": [ + { + "type": "PROG", + "name": "{{P}}REPAIR_LIST", + "file": "reference/repair_list.prog.abap", + "description": "Repair list of one day" + } + ], + "craft_checks": [ + "db_operation_in_loop", + "method_length", + "nested_loop" + ] +} \ No newline at end of file diff --git a/tasks_gen/train/G1943/generation.json b/tasks_gen/train/G1943/generation.json new file mode 100644 index 0000000..8efc4d7 --- /dev/null +++ b/tasks_gen/train/G1943/generation.json @@ -0,0 +1,43 @@ +{ + "id": "G1943", + "pool": "train", + "object_type": "STRU", + "category": "B", + "attempts": [ + { + "stage": "bundle", + "errors": [ + "Too close to task G1903 (similarity spec 0.36, rules 0.42, names 1.00). Choose a different business topic and different object names." + ], + "by_check": { + "extra": 1 + } + }, + { + "stage": "bundle", + "errors": [ + "reference/game_stru_test.clas.abap line 60: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"" + ], + "by_check": { + "abaplint": 1 + } + }, + { + "stage": "bundle", + "errors": [ + "reference/game_stru_test.clas.abap line 15: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"CLASS\"", + "hidden/game_stru_hidden.clas.abap line 15: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"CLASS\"", + "hidden/game_stru_hidden.clas.abap line 17: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"CLASS\"" + ], + "by_check": { + "abaplint": 3 + } + }, + { + "stage": "validate", + "oracle": 0, + "null": 0 + } + ], + "accepted": false +} \ No newline at end of file diff --git a/tasks_gen/train/G1943/hidden/game_stru_hidden.clas.abap b/tasks_gen/train/G1943/hidden/game_stru_hidden.clas.abap new file mode 100644 index 0000000..368dd3a --- /dev/null +++ b/tasks_gen/train/G1943/hidden/game_stru_hidden.clas.abap @@ -0,0 +1,159 @@ +CLASS {{p}}game_stru_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + TYPES: BEGIN OF ty_comp, + name TYPE string, + type TYPE REF TO cl_abap_datadescr, + END OF ty_comp, + ty_comps TYPE STANDARD TABLE OF ty_comp WITH DEFAULT KEY. + CLASS-DATA go_line TYPE REF TO cl_abap_structdescr. + CLASS-METHODS class_setup. + CLASS-METHODS flat_components RETURNING VALUE(rt_comp) TYPE ty_comps. + METHODS structure_exists FOR TESTING. + METHODS field_count FOR TESTING. + METHODS field_names FOR TESTING. + METHODS text_lengths FOR TESTING. + METHODS numc_field FOR TESTING. + METHODS packed_decimals FOR TESTING. + METHODS type_kinds FOR TESTING. + METHODS stamp_structure FOR TESTING. + METHODS stamp_at_end FOR TESTING. +ENDCLASS. + + +CLASS {{p}}game_stru_hidden IMPLEMENTATION. + METHOD class_setup. + go_line = CAST cl_abap_structdescr( + cl_abap_typedescr=>describe_by_name( '{{P}}GAME_ROUND' ) ). + ENDMETHOD. + + METHOD flat_components. + DATA(lt_comp) = go_line->get_components( ). + LOOP AT lt_comp INTO DATA(ls_comp). + TRY. + DATA(lo_sub) = CAST cl_abap_structdescr( ls_comp-type ). + DATA(lt_sub) = lo_sub->get_components( ). + LOOP AT lt_sub INTO DATA(ls_sub). + APPEND VALUE #( name = ls_sub-name type = ls_sub-type ) TO rt_comp. + ENDLOOP. + CATCH cx_sy_move_cast_error. + APPEND VALUE #( name = ls_comp-name type = ls_comp-type ) TO rt_comp. + ENDTRY. + ENDLOOP. + ENDMETHOD. + + METHOD structure_exists. + cl_abap_unit_assert=>assert_equals( + exp = abap_true + act = contains( val = to_upper( go_line->absolute_name ) + sub = `GAME_ROUND` ) ). + ENDMETHOD. + + METHOD field_count. + DATA(lt_comp) = flat_components( ). + cl_abap_unit_assert=>assert_equals( exp = 10 act = lines( lt_comp ) ). + ENDMETHOD. + + METHOD field_names. + DATA(lt_comp) = flat_components( ). + DATA(lt_exp) = VALUE string_table( + ( `ROUND_ID` ) ( `PLAY_DATE` ) ( `FIELD_NO` ) ( `TEAM_NAME` ) + ( `PLAYER_COUNT` ) ( `PAINTBALLS` ) ( `ROUND_FEE` ) ( `REFEREE` ) + ( `LAST_EDITOR` ) ( `LAST_EDIT_ON` ) ). + cl_abap_unit_assert=>assert_equals( exp = lines( lt_exp ) act = lines( lt_comp ) ). + DATA(lv_index) = 0. + LOOP AT lt_comp INTO DATA(ls_comp). + lv_index = lv_index + 1. + cl_abap_unit_assert=>assert_equals( + exp = lt_exp[ lv_index ] + act = to_upper( ls_comp-name ) + msg = |Field { lv_index }| ). + ENDLOOP. + ENDMETHOD. + + METHOD text_lengths. + DATA(lt_comp) = flat_components( ). + LOOP AT lt_comp INTO DATA(ls_comp). + DATA(lo_elem) = CAST cl_abap_elemdescr( ls_comp-type ). + CASE to_upper( ls_comp-name ). + WHEN 'ROUND_ID'. + cl_abap_unit_assert=>assert_equals( exp = 20 act = lo_elem->length ). + WHEN 'TEAM_NAME'. + cl_abap_unit_assert=>assert_equals( exp = 40 act = lo_elem->length ). + WHEN 'REFEREE'. + cl_abap_unit_assert=>assert_equals( exp = 30 act = lo_elem->length ). + WHEN 'LAST_EDITOR'. + cl_abap_unit_assert=>assert_equals( exp = 24 act = lo_elem->length ). + ENDCASE. + ENDLOOP. + ENDMETHOD. + + METHOD numc_field. + DATA(lt_comp) = flat_components( ). + LOOP AT lt_comp INTO DATA(ls_comp). + IF to_upper( ls_comp-name ) = 'FIELD_NO'. + DATA(lo_elem) = CAST cl_abap_elemdescr( ls_comp-type ). + cl_abap_unit_assert=>assert_equals( + exp = `N` act = CONV string( lo_elem->type_kind ) ). + cl_abap_unit_assert=>assert_equals( exp = 4 act = lo_elem->length ). + ENDIF. + ENDLOOP. + ENDMETHOD. + + METHOD packed_decimals. + DATA(lt_comp) = flat_components( ). + LOOP AT lt_comp INTO DATA(ls_comp). + IF to_upper( ls_comp-name ) = 'ROUND_FEE'. + DATA(lo_elem) = CAST cl_abap_elemdescr( ls_comp-type ). + cl_abap_unit_assert=>assert_equals( + exp = `P` act = CONV string( lo_elem->type_kind ) ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lo_elem->decimals ). + ENDIF. + ENDLOOP. + ENDMETHOD. + + METHOD type_kinds. + DATA(lt_comp) = flat_components( ). + DATA(lt_exp) = VALUE string_table( + ( `C` ) ( `D` ) ( `N` ) ( `C` ) ( `I` ) ( `I` ) ( `P` ) ( `C` ) + ( `C` ) ( `D` ) ). + cl_abap_unit_assert=>assert_equals( exp = lines( lt_exp ) act = lines( lt_comp ) ). + DATA(lv_index) = 0. + LOOP AT lt_comp INTO DATA(ls_comp). + lv_index = lv_index + 1. + cl_abap_unit_assert=>assert_equals( + exp = lt_exp[ lv_index ] + act = CONV string( ls_comp-type->type_kind ) + msg = |Type kind of field { lv_index }| ). + ENDLOOP. + ENDMETHOD. + + METHOD stamp_structure. + DATA(lo_stamp) = CAST cl_abap_structdescr( + cl_abap_typedescr=>describe_by_name( '{{P}}EDIT_STAMP' ) ). + DATA(lt_comp) = lo_stamp->get_components( ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_comp ) ). + cl_abap_unit_assert=>assert_equals( + exp = `LAST_EDITOR` act = to_upper( lt_comp[ 1 ]-name ) ). + cl_abap_unit_assert=>assert_equals( + exp = `LAST_EDIT_ON` act = to_upper( lt_comp[ 2 ]-name ) ). + DATA(lo_editor) = CAST cl_abap_elemdescr( lt_comp[ 1 ]-type ). + cl_abap_unit_assert=>assert_equals( exp = 24 act = lo_editor->length ). + DATA(lo_edit_on) = CAST cl_abap_elemdescr( lt_comp[ 2 ]-type ). + cl_abap_unit_assert=>assert_equals( + exp = `D` act = CONV string( lo_edit_on->type_kind ) ). + ENDMETHOD. + + METHOD stamp_at_end. + DATA(lt_comp) = flat_components( ). + DATA(lv_lines) = lines( lt_comp ). + cl_abap_unit_assert=>assert_equals( exp = 10 act = lv_lines ). + DATA(lv_index) = lv_lines - 1. + DATA(ls_editor) = lt_comp[ lv_index ]. + cl_abap_unit_assert=>assert_equals( + exp = `LAST_EDITOR` act = to_upper( ls_editor-name ) ). + DATA(ls_edit_on) = lt_comp[ lv_lines ]. + cl_abap_unit_assert=>assert_equals( + exp = `LAST_EDIT_ON` act = to_upper( ls_edit_on-name ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1943/reference/edit_stamp.stru.asabap b/tasks_gen/train/G1943/reference/edit_stamp.stru.asabap new file mode 100644 index 0000000..8297fa5 --- /dev/null +++ b/tasks_gen/train/G1943/reference/edit_stamp.stru.asabap @@ -0,0 +1,6 @@ +@EndUserText.label : 'Last edit of a game round' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +define structure {{p}}edit_stamp { + last_editor : abap.char(12); + last_edit_on : abap.dats; +} diff --git a/tasks_gen/train/G1943/reference/game_round.stru.asabap b/tasks_gen/train/G1943/reference/game_round.stru.asabap new file mode 100644 index 0000000..c711c92 --- /dev/null +++ b/tasks_gen/train/G1943/reference/game_round.stru.asabap @@ -0,0 +1,13 @@ +@EndUserText.label : 'Line type of the round report' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +define structure {{p}}game_round { + round_id : abap.char(10); + play_date : abap.dats; + field_no : abap.numc(2); + team_name : abap.char(20); + player_count : abap.int4; + paintballs : abap.int4; + round_fee : abap.dec(9,2); + referee : abap.char(15); + include {{p}}edit_stamp; +} diff --git a/tasks_gen/train/G1943/reference/game_stru_test.clas.abap b/tasks_gen/train/G1943/reference/game_stru_test.clas.abap new file mode 100644 index 0000000..e0da1a9 --- /dev/null +++ b/tasks_gen/train/G1943/reference/game_stru_test.clas.abap @@ -0,0 +1,77 @@ +CLASS {{p}}game_stru_test DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + TYPES: BEGIN OF ty_comp, + name TYPE string, + type TYPE REF TO cl_abap_datadescr, + END OF ty_comp, + ty_comps TYPE STANDARD TABLE OF ty_comp WITH DEFAULT KEY. + CLASS-DATA go_line TYPE REF TO cl_abap_structdescr. + CLASS-METHODS class_setup. + CLASS-METHODS flat_components RETURNING VALUE(rt_comp) TYPE ty_comps. + METHODS ten_fields FOR TESTING. + METHODS field_order FOR TESTING. + METHODS fee_decimals FOR TESTING. + METHODS stamp_structure FOR TESTING. +ENDCLASS. + + +CLASS {{p}}game_stru_test IMPLEMENTATION. + METHOD class_setup. + go_line = CAST cl_abap_structdescr( + cl_abap_typedescr=>describe_by_name( '{{P}}GAME_ROUND' ) ). + ENDMETHOD. + + METHOD flat_components. + DATA(lt_comp) = go_line->get_components( ). + LOOP AT lt_comp INTO DATA(ls_comp). + TRY. + DATA(lo_sub) = CAST cl_abap_structdescr( ls_comp-type ). + DATA(lt_sub) = lo_sub->get_components( ). + LOOP AT lt_sub INTO DATA(ls_sub). + APPEND VALUE #( name = ls_sub-name type = ls_sub-type ) TO rt_comp. + ENDLOOP. + CATCH cx_sy_move_cast_error. + APPEND VALUE #( name = ls_comp-name type = ls_comp-type ) TO rt_comp. + ENDTRY. + ENDLOOP. + ENDMETHOD. + + METHOD ten_fields. + DATA(lt_comp) = flat_components( ). + cl_abap_unit_assert=>assert_equals( exp = 10 act = lines( lt_comp ) ). + ENDMETHOD. + + METHOD field_order. + DATA(lt_comp) = flat_components( ). + cl_abap_unit_assert=>assert_equals( + exp = `ROUND_ID` act = to_upper( lt_comp[ 1 ]-name ) ). + cl_abap_unit_assert=>assert_equals( + exp = `FIELD_NO` act = to_upper( lt_comp[ 3 ]-name ) ). + cl_abap_unit_assert=>assert_equals( + exp = `LAST_EDIT_ON` act = to_upper( lt_comp[ 10 ]-name ) ). + ENDMETHOD. + + METHOD fee_decimals. + DATA(lt_comp) = flat_components( ). + LOOP AT lt_comp INTO DATA(ls_comp). + IF to_upper( ls_comp-name ) = 'ROUND_FEE'. + DATA(lo_elem) = CAST cl_abap_elemdescr( ls_comp-type ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lo_elem->decimals ). + ENDIF. + ENDLOOP. + ENDMETHOD. + + METHOD stamp_structure. + DATA(lo_stamp) = CAST cl_abap_structdescr( + cl_abap_typedescr=>describe_by_name( '{{P}}EDIT_STAMP' ) ). + DATA(lt_comp) = lo_stamp->get_components( ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_comp ) ). + cl_abap_unit_assert=>assert_equals( + exp = `LAST_EDITOR` act = to_upper( lt_comp[ 1 ]-name ) ). + cl_abap_unit_assert=>assert_equals( + exp = `LAST_EDIT_ON` act = to_upper( lt_comp[ 2 ]-name ) ). + DATA(lo_editor) = CAST cl_abap_elemdescr( lt_comp[ 1 ]-type ). + cl_abap_unit_assert=>assert_equals( exp = 24 act = lo_editor->length ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1943/spec.md b/tasks_gen/train/G1943/spec.md new file mode 100644 index 0000000..7417f5c --- /dev/null +++ b/tasks_gen/train/G1943/spec.md @@ -0,0 +1,61 @@ +# 1. Goal + +A paintball arena records each game round that is played on its fields. A round +report and an OData service must show the same line for a round. Both use one +line type. Create this line type as a DDIC structure. + +# 2. Open questions + +None. + +# 3. Context + +- The arena plays rounds on numbered fields. +- A round has a round number, a play date, the number of the field, the name of + the visiting team, the number of players, the number of paintballs that the + team used, the fee of the round, and the referee. +- The report and the OData service also show who edited the round last and on + which date. +- All objects are in package $TMP. + +# 4. Contract + +- Create the DDIC structure {{P}}GAME_ROUND in package $TMP. +- Create the DDIC structure {{P}}EDIT_STAMP in package $TMP. +- {{P}}GAME_ROUND has these fields, in this order: + ROUND_ID, PLAY_DATE, FIELD_NO, TEAM_NAME, PLAYER_COUNT, PAINTBALLS, + ROUND_FEE, REFEREE, LAST_EDITOR, LAST_EDIT_ON. +- The fields LAST_EDITOR and LAST_EDIT_ON also exist on their own in + {{P}}EDIT_STAMP. + +# 5. Business rules + +1. {{P}}GAME_ROUND is a structure. It has exactly ten fields. +2. ROUND_ID is a character field. Its length is 10. +3. PLAY_DATE is a date field. Its type is DATS. +4. FIELD_NO is a numeric text field. Its length is 2. +5. TEAM_NAME is a character field. Its length is 20. +6. PLAYER_COUNT is an integer field. Its type is INT4. +7. PAINTBALLS is an integer field. Its type is INT4. +8. ROUND_FEE is a packed number. It has 9 digits and 2 decimal places. +9. REFEREE is a character field. Its length is 15. +10. LAST_EDITOR and LAST_EDIT_ON are the last two fields of {{P}}GAME_ROUND. +11. LAST_EDITOR is a character field. Its length is 12. +12. LAST_EDIT_ON is a date field. Its type is DATS. +13. {{P}}EDIT_STAMP is a structure. It has exactly two fields: LAST_EDITOR + (character, length 12) and LAST_EDIT_ON (date, type DATS). +14. {{P}}GAME_ROUND contains the fields of {{P}}EDIT_STAMP at the end. The + fields LAST_EDITOR and LAST_EDIT_ON must not be defined twice. + +# 6. Constraints + +- Release target: ABAP Platform 2025 (SAP_BASIS 816). +- Coding standards: Clean ABAP. +- Out of scope: no other objects in package $TMP. + +# 7. Acceptance + +- Both structures are active and have no syntax error. +- The hidden tests pass. +- Write ABAP Unit tests in a global test class. The tests check the two + structures with RTTI. diff --git a/tasks_gen/train/G1943/task.json b/tasks_gen/train/G1943/task.json new file mode 100644 index 0000000..9759431 --- /dev/null +++ b/tasks_gen/train/G1943/task.json @@ -0,0 +1,69 @@ +{ + "id": "G1943", + "category": "B", + "object_type": "STRU", + "difficulty": 3, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [], + "contract": [ + { + "type": "STRU", + "name": "{{P}}GAME_ROUND", + "fields": [ + "round_id", + "play_date", + "field_no", + "team_name", + "player_count", + "paintballs", + "round_fee", + "referee", + "last_editor", + "last_edit_on" + ] + }, + { + "type": "STRU", + "name": "{{P}}EDIT_STAMP", + "fields": [ + "last_editor", + "last_edit_on" + ] + } + ], + "out_of_scope": [], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}GAME_STRU_HIDDEN", + "file": "hidden/game_stru_hidden.clas.abap", + "description": "RTTI checks for the game round structure and the edit stamp structure" + } + ], + "reference": [ + { + "type": "STRU", + "name": "{{P}}EDIT_STAMP", + "file": "reference/edit_stamp.stru.asabap", + "description": "Last edit of a game round" + }, + { + "type": "STRU", + "name": "{{P}}GAME_ROUND", + "file": "reference/game_round.stru.asabap", + "description": "Line type of the round report" + }, + { + "type": "CLAS", + "name": "{{P}}GAME_STRU_TEST", + "file": "reference/game_stru_test.clas.abap", + "description": "Own tests for the two structures" + } + ], + "craft_checks": [] +} \ No newline at end of file diff --git a/tasks_gen/train/G1944/faulty/m1_sharp_sum.prog.abap b/tasks_gen/train/G1944/faulty/m1_sharp_sum.prog.abap new file mode 100644 index 0000000..6d12f4a --- /dev/null +++ b/tasks_gen/train/G1944/faulty/m1_sharp_sum.prog.abap @@ -0,0 +1,104 @@ +REPORT {{p}}sharp_sum. + +DATA gv_customer TYPE {{p}}sharpen-customer. + +PARAMETERS p_from TYPE d OBLIGATORY. +SELECT-OPTIONS s_cust FOR gv_customer. + +CLASS lcl_report DEFINITION FINAL. + PUBLIC SECTION. + TYPES tt_customer TYPE RANGE OF {{p}}sharpen-customer. + TYPES: + BEGIN OF ty_line, + customer TYPE {{p}}sharpen-customer, + knives TYPE i, + fee TYPE {{p}}kntype-price, + END OF ty_line. + TYPES tt_line TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY. + METHODS select_totals + IMPORTING iv_from TYPE d + it_customer TYPE tt_customer + RETURNING VALUE(rt_lines) TYPE tt_line. + METHODS display + CHANGING ct_lines TYPE tt_line. +ENDCLASS. + +CLASS lcl_report IMPLEMENTATION. + METHOD select_totals. + SELECT s~customer, + SUM( s~knife_count ) AS knives, + SUM( s~knife_count * t~price ) AS fee + FROM {{p}}sharpen AS s + INNER JOIN {{p}}kntype AS t ON t~type_id = s~knife_type + WHERE s~sharp_date < @iv_from + AND s~customer IN @it_customer + GROUP BY s~customer + ORDER BY fee DESCENDING + INTO CORRESPONDING FIELDS OF TABLE @rt_lines. + ENDMETHOD. + + METHOD display. + TRY. + cl_salv_table=>factory( IMPORTING r_salv_table = DATA(lo_alv) + CHANGING t_table = ct_lines ). + lo_alv->display( ). + CATCH cx_salv_msg INTO DATA(lx_error). + MESSAGE lx_error TYPE 'I' DISPLAY LIKE 'E'. + ENDTRY. + ENDMETHOD. +ENDCLASS. + +START-OF-SELECTION. + DATA(go_report) = NEW lcl_report( ). + DATA(gt_lines) = go_report->select_totals( iv_from = p_from it_customer = s_cust[] ). + go_report->display( CHANGING ct_lines = gt_lines ). + +CLASS ltc_report DEFINITION FINAL 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 totals_per_customer FOR TESTING. + METHODS unknown_type_skipped FOR TESTING. +ENDCLASS. + +CLASS ltc_report IMPLEMENTATION. + METHOD class_setup. + go_env = cl_osql_test_environment=>create( + i_dependency_list = VALUE #( ( '{{P}}SHARPEN' ) ( '{{P}}KNTYPE' ) ) ). + + DATA lt_types TYPE STANDARD TABLE OF {{p}}kntype WITH EMPTY KEY. + lt_types = VALUE #( ( type_id = 'CHEF' price = '2.00' ) + ( type_id = 'BONE' price = '3.00' ) ). + go_env->insert_test_data( lt_types ). + + DATA lt_items TYPE STANDARD TABLE OF {{p}}sharpen WITH EMPTY KEY. + lt_items = VALUE #( ( item_id = 1 customer = 'A' knife_type = 'CHEF' knife_count = 10 sharp_date = '20260101' ) + ( item_id = 2 customer = 'A' knife_type = 'BONE' knife_count = 2 sharp_date = '20260102' ) + ( item_id = 3 customer = 'B' knife_type = 'CHEF' knife_count = 5 sharp_date = '20260101' ) + ( item_id = 4 customer = 'B' knife_type = 'PLAS' knife_count = 7 sharp_date = '20260101' ) ). + go_env->insert_test_data( lt_items ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD totals_per_customer. + DATA(lt_lines) = NEW lcl_report( )->select_totals( + iv_from = '20260101' + it_customer = VALUE #( ( sign = 'E' option = 'EQ' low = 'X' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 'A' act = lt_lines[ 1 ]-customer ). + cl_abap_unit_assert=>assert_equals( exp = 12 act = lt_lines[ 1 ]-knives ). + cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}kntype-price( 26 ) act = lt_lines[ 1 ]-fee ). + ENDMETHOD. + + METHOD unknown_type_skipped. + DATA(lt_lines) = NEW lcl_report( )->select_totals( + iv_from = '20260101' + it_customer = VALUE #( ( sign = 'I' option = 'EQ' low = 'B' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 5 act = lt_lines[ 1 ]-knives ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1944/faulty/m2_sharp_sum.prog.abap b/tasks_gen/train/G1944/faulty/m2_sharp_sum.prog.abap new file mode 100644 index 0000000..0d092dd --- /dev/null +++ b/tasks_gen/train/G1944/faulty/m2_sharp_sum.prog.abap @@ -0,0 +1,104 @@ +REPORT {{p}}sharp_sum. + +DATA gv_customer TYPE {{p}}sharpen-customer. + +PARAMETERS p_from TYPE d OBLIGATORY. +SELECT-OPTIONS s_cust FOR gv_customer. + +CLASS lcl_report DEFINITION FINAL. + PUBLIC SECTION. + TYPES tt_customer TYPE RANGE OF {{p}}sharpen-customer. + TYPES: + BEGIN OF ty_line, + customer TYPE {{p}}sharpen-customer, + knives TYPE i, + fee TYPE {{p}}kntype-price, + END OF ty_line. + TYPES tt_line TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY. + METHODS select_totals + IMPORTING iv_from TYPE d + it_customer TYPE tt_customer + RETURNING VALUE(rt_lines) TYPE tt_line. + METHODS display + CHANGING ct_lines TYPE tt_line. +ENDCLASS. + +CLASS lcl_report IMPLEMENTATION. + METHOD select_totals. + SELECT s~customer, + SUM( s~knife_count ) AS knives, + SUM( s~knife_count * t~price ) AS fee + FROM {{p}}sharpen AS s + INNER JOIN {{p}}kntype AS t ON t~type_id = s~knife_type + WHERE s~sharp_date >= @iv_from + OR s~customer IN @it_customer + GROUP BY s~customer + ORDER BY fee DESCENDING + INTO CORRESPONDING FIELDS OF TABLE @rt_lines. + ENDMETHOD. + + METHOD display. + TRY. + cl_salv_table=>factory( IMPORTING r_salv_table = DATA(lo_alv) + CHANGING t_table = ct_lines ). + lo_alv->display( ). + CATCH cx_salv_msg INTO DATA(lx_error). + MESSAGE lx_error TYPE 'I' DISPLAY LIKE 'E'. + ENDTRY. + ENDMETHOD. +ENDCLASS. + +START-OF-SELECTION. + DATA(go_report) = NEW lcl_report( ). + DATA(gt_lines) = go_report->select_totals( iv_from = p_from it_customer = s_cust[] ). + go_report->display( CHANGING ct_lines = gt_lines ). + +CLASS ltc_report DEFINITION FINAL 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 totals_per_customer FOR TESTING. + METHODS unknown_type_skipped FOR TESTING. +ENDCLASS. + +CLASS ltc_report IMPLEMENTATION. + METHOD class_setup. + go_env = cl_osql_test_environment=>create( + i_dependency_list = VALUE #( ( '{{P}}SHARPEN' ) ( '{{P}}KNTYPE' ) ) ). + + DATA lt_types TYPE STANDARD TABLE OF {{p}}kntype WITH EMPTY KEY. + lt_types = VALUE #( ( type_id = 'CHEF' price = '2.00' ) + ( type_id = 'BONE' price = '3.00' ) ). + go_env->insert_test_data( lt_types ). + + DATA lt_items TYPE STANDARD TABLE OF {{p}}sharpen WITH EMPTY KEY. + lt_items = VALUE #( ( item_id = 1 customer = 'A' knife_type = 'CHEF' knife_count = 10 sharp_date = '20260101' ) + ( item_id = 2 customer = 'A' knife_type = 'BONE' knife_count = 2 sharp_date = '20260102' ) + ( item_id = 3 customer = 'B' knife_type = 'CHEF' knife_count = 5 sharp_date = '20260101' ) + ( item_id = 4 customer = 'B' knife_type = 'PLAS' knife_count = 7 sharp_date = '20260101' ) ). + go_env->insert_test_data( lt_items ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD totals_per_customer. + DATA(lt_lines) = NEW lcl_report( )->select_totals( + iv_from = '20260101' + it_customer = VALUE #( ( sign = 'E' option = 'EQ' low = 'X' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 'A' act = lt_lines[ 1 ]-customer ). + cl_abap_unit_assert=>assert_equals( exp = 12 act = lt_lines[ 1 ]-knives ). + cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}kntype-price( 26 ) act = lt_lines[ 1 ]-fee ). + ENDMETHOD. + + METHOD unknown_type_skipped. + DATA(lt_lines) = NEW lcl_report( )->select_totals( + iv_from = '20260101' + it_customer = VALUE #( ( sign = 'I' option = 'EQ' low = 'B' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 5 act = lt_lines[ 1 ]-knives ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1944/generation.json b/tasks_gen/train/G1944/generation.json new file mode 100644 index 0000000..f4c39be --- /dev/null +++ b/tasks_gen/train/G1944/generation.json @@ -0,0 +1,34 @@ +{ + "id": "G1944", + "pool": "train", + "object_type": "PROG", + "category": "C", + "attempts": [ + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 2, + "killed": 2, + "ok": true + } + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1944/hidden/t15_hidden.clas.abap b/tasks_gen/train/G1944/hidden/t15_hidden.clas.abap new file mode 100644 index 0000000..4a2930c --- /dev/null +++ b/tasks_gen/train/G1944/hidden/t15_hidden.clas.abap @@ -0,0 +1,102 @@ +CLASS {{p}}t15_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + TYPES tt_customer TYPE RANGE OF {{p}}sharpen-customer. + METHODS run + IMPORTING iv_from TYPE d + it_customer TYPE tt_customer OPTIONAL + RETURNING VALUE(rr_data) TYPE REF TO data. + METHODS lines_of + IMPORTING ir_data TYPE REF TO data + RETURNING VALUE(rv_lines) TYPE i. + METHODS value_of + IMPORTING ir_data TYPE REF TO data + iv_row TYPE i + iv_col TYPE string + RETURNING VALUE(rv_value) TYPE string. + METHODS all_customers FOR TESTING. + METHODS sorted_by_fee FOR TESTING. + METHODS fee_and_knives FOR TESTING. + METHODS customer_filter FOR TESTING. + METHODS date_filter FOR TESTING. + METHODS unknown_type FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t15_hidden IMPLEMENTATION. + METHOD run. + DATA(lt_customer) = it_customer. + IF lt_customer IS INITIAL. + lt_customer = VALUE #( ( sign = 'E' option = 'EQ' low = 'X' ) ). + ENDIF. + cl_salv_bs_runtime_info=>set( display = abap_false metadata = abap_false data = abap_true ). + SUBMIT {{p}}sharp_sum WITH p_from = iv_from WITH s_cust IN lt_customer AND RETURN. + TRY. + cl_salv_bs_runtime_info=>get_data_ref( IMPORTING r_data = rr_data ). + CATCH cx_salv_bs_sc_runtime_info. + ENDTRY. + cl_salv_bs_runtime_info=>clear_all( ). + ENDMETHOD. + + METHOD lines_of. + FIELD-SYMBOLS TYPE STANDARD TABLE. + IF ir_data IS NOT BOUND. + RETURN. + ENDIF. + ASSIGN ir_data->* TO . + IF sy-subrc = 0. + rv_lines = lines( ). + ENDIF. + ENDMETHOD. + + METHOD value_of. + FIELD-SYMBOLS TYPE STANDARD TABLE. + FIELD-SYMBOLS TYPE any. + FIELD-SYMBOLS TYPE any. + IF ir_data IS NOT BOUND. + cl_abap_unit_assert=>fail( msg = 'No result table' ). + ENDIF. + ASSIGN ir_data->* TO . + cl_abap_unit_assert=>assert_subrc( exp = 0 msg = 'No result table' ). + READ TABLE INDEX iv_row ASSIGNING . + cl_abap_unit_assert=>assert_subrc( exp = 0 msg = |Row { iv_row } is missing| ). + ASSIGN COMPONENT iv_col OF STRUCTURE TO . + cl_abap_unit_assert=>assert_subrc( exp = 0 msg = |Column { iv_col } is missing| ). + rv_value = condense( CONV string( ) ). + ENDMETHOD. + + METHOD all_customers. + cl_abap_unit_assert=>assert_equals( exp = 4 act = lines_of( run( '20260101' ) ) ). + ENDMETHOD. + + METHOD sorted_by_fee. + DATA(lr_data) = run( '20260101' ). + cl_abap_unit_assert=>assert_equals( exp = `CANTEEN` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `CUSTOMER` ) ). + cl_abap_unit_assert=>assert_equals( exp = `DELI` act = value_of( ir_data = lr_data iv_row = 4 iv_col = `CUSTOMER` ) ). + ENDMETHOD. + + METHOD fee_and_knives. + DATA(lr_data) = run( '20260101' ). + cl_abap_unit_assert=>assert_equals( exp = `TRATTORIA` act = value_of( ir_data = lr_data iv_row = 2 iv_col = `CUSTOMER` ) ). + cl_abap_unit_assert=>assert_equals( exp = `14` act = value_of( ir_data = lr_data iv_row = 2 iv_col = `KNIVES` ) ). + cl_abap_unit_assert=>assert_equals( exp = `26.00` act = value_of( ir_data = lr_data iv_row = 2 iv_col = `FEE` ) ). + ENDMETHOD. + + METHOD customer_filter. + DATA(lr_data) = run( iv_from = '20260101' + it_customer = VALUE #( ( sign = 'I' option = 'EQ' low = 'BISTRO' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lines_of( lr_data ) ). + cl_abap_unit_assert=>assert_equals( exp = `12.00` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `FEE` ) ). + ENDMETHOD. + + METHOD date_filter. + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines_of( run( '20260113' ) ) ). + ENDMETHOD. + + METHOD unknown_type. + DATA(lr_data) = run( iv_from = '20260101' + it_customer = VALUE #( ( sign = 'I' option = 'EQ' low = 'DELI' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lines_of( lr_data ) ). + cl_abap_unit_assert=>assert_equals( exp = `5` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `KNIVES` ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1944/mutation.json b/tasks_gen/train/G1944/mutation.json new file mode 100644 index 0000000..2188a09 --- /dev/null +++ b/tasks_gen/train/G1944/mutation.json @@ -0,0 +1,40 @@ +{ + "task": "G1944", + "mutants": [ + { + "object": "{{P}}SHARP_SUM", + "mutant": "line 30: * -> / (arith)", + "status": "invalid", + "hidden": "0/0", + "failed_tests": [] + }, + { + "object": "{{P}}SHARP_SUM", + "mutant": "line 33: >= -> < (rel)", + "status": "killed", + "hidden": "1/6", + "failed_tests": [ + "ALL_CUSTOMERS", + "CUSTOMER_FILTER", + "FEE_AND_KNIVES", + "SORTED_BY_FEE", + "UNKNOWN_TYPE" + ] + }, + { + "object": "{{P}}SHARP_SUM", + "mutant": "line 34: AND -> OR (logic)", + "status": "killed", + "hidden": "3/6", + "failed_tests": [ + "CUSTOMER_FILTER", + "DATE_FILTER", + "UNKNOWN_TYPE" + ] + } + ], + "valid": 2, + "killed": 2, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1944/reference/sharp_sum.prog.abap b/tasks_gen/train/G1944/reference/sharp_sum.prog.abap new file mode 100644 index 0000000..deb12fb --- /dev/null +++ b/tasks_gen/train/G1944/reference/sharp_sum.prog.abap @@ -0,0 +1,104 @@ +REPORT {{p}}sharp_sum. + +DATA gv_customer TYPE {{p}}sharpen-customer. + +PARAMETERS p_from TYPE d OBLIGATORY. +SELECT-OPTIONS s_cust FOR gv_customer. + +CLASS lcl_report DEFINITION FINAL. + PUBLIC SECTION. + TYPES tt_customer TYPE RANGE OF {{p}}sharpen-customer. + TYPES: + BEGIN OF ty_line, + customer TYPE {{p}}sharpen-customer, + knives TYPE i, + fee TYPE {{p}}kntype-price, + END OF ty_line. + TYPES tt_line TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY. + METHODS select_totals + IMPORTING iv_from TYPE d + it_customer TYPE tt_customer + RETURNING VALUE(rt_lines) TYPE tt_line. + METHODS display + CHANGING ct_lines TYPE tt_line. +ENDCLASS. + +CLASS lcl_report IMPLEMENTATION. + METHOD select_totals. + SELECT s~customer, + SUM( s~knife_count ) AS knives, + SUM( s~knife_count * t~price ) AS fee + FROM {{p}}sharpen AS s + INNER JOIN {{p}}kntype AS t ON t~type_id = s~knife_type + WHERE s~sharp_date >= @iv_from + AND s~customer IN @it_customer + GROUP BY s~customer + ORDER BY fee DESCENDING + INTO CORRESPONDING FIELDS OF TABLE @rt_lines. + ENDMETHOD. + + METHOD display. + TRY. + cl_salv_table=>factory( IMPORTING r_salv_table = DATA(lo_alv) + CHANGING t_table = ct_lines ). + lo_alv->display( ). + CATCH cx_salv_msg INTO DATA(lx_error). + MESSAGE lx_error TYPE 'I' DISPLAY LIKE 'E'. + ENDTRY. + ENDMETHOD. +ENDCLASS. + +START-OF-SELECTION. + DATA(go_report) = NEW lcl_report( ). + DATA(gt_lines) = go_report->select_totals( iv_from = p_from it_customer = s_cust[] ). + go_report->display( CHANGING ct_lines = gt_lines ). + +CLASS ltc_report DEFINITION FINAL 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 totals_per_customer FOR TESTING. + METHODS unknown_type_skipped FOR TESTING. +ENDCLASS. + +CLASS ltc_report IMPLEMENTATION. + METHOD class_setup. + go_env = cl_osql_test_environment=>create( + i_dependency_list = VALUE #( ( '{{P}}SHARPEN' ) ( '{{P}}KNTYPE' ) ) ). + + DATA lt_types TYPE STANDARD TABLE OF {{p}}kntype WITH EMPTY KEY. + lt_types = VALUE #( ( type_id = 'CHEF' price = '2.00' ) + ( type_id = 'BONE' price = '3.00' ) ). + go_env->insert_test_data( lt_types ). + + DATA lt_items TYPE STANDARD TABLE OF {{p}}sharpen WITH EMPTY KEY. + lt_items = VALUE #( ( item_id = 1 customer = 'A' knife_type = 'CHEF' knife_count = 10 sharp_date = '20260101' ) + ( item_id = 2 customer = 'A' knife_type = 'BONE' knife_count = 2 sharp_date = '20260102' ) + ( item_id = 3 customer = 'B' knife_type = 'CHEF' knife_count = 5 sharp_date = '20260101' ) + ( item_id = 4 customer = 'B' knife_type = 'PLAS' knife_count = 7 sharp_date = '20260101' ) ). + go_env->insert_test_data( lt_items ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD totals_per_customer. + DATA(lt_lines) = NEW lcl_report( )->select_totals( + iv_from = '20260101' + it_customer = VALUE #( ( sign = 'E' option = 'EQ' low = 'X' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 'A' act = lt_lines[ 1 ]-customer ). + cl_abap_unit_assert=>assert_equals( exp = 12 act = lt_lines[ 1 ]-knives ). + cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}kntype-price( 26 ) act = lt_lines[ 1 ]-fee ). + ENDMETHOD. + + METHOD unknown_type_skipped. + DATA(lt_lines) = NEW lcl_report( )->select_totals( + iv_from = '20260101' + it_customer = VALUE #( ( sign = 'I' option = 'EQ' low = 'B' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 5 act = lt_lines[ 1 ]-knives ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1944/seed/kntype.tabl.asabap b/tasks_gen/train/G1944/seed/kntype.tabl.asabap new file mode 100644 index 0000000..fcd6dd5 --- /dev/null +++ b/tasks_gen/train/G1944/seed/kntype.tabl.asabap @@ -0,0 +1,10 @@ +@EndUserText.label : 'Knife type price list' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}kntype { + key client : abap.clnt not null; + key type_id : abap.char(5) not null; + price : abap.dec(15,2); +} diff --git a/tasks_gen/train/G1944/seed/sharpen.tabl.asabap b/tasks_gen/train/G1944/seed/sharpen.tabl.asabap new file mode 100644 index 0000000..07bbed2 --- /dev/null +++ b/tasks_gen/train/G1944/seed/sharpen.tabl.asabap @@ -0,0 +1,13 @@ +@EndUserText.label : 'Knife sharpening items' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}sharpen { + key client : abap.clnt not null; + key item_id : abap.int4 not null; + customer : abap.char(10); + knife_type : abap.char(5); + knife_count : abap.int4; + sharp_date : abap.dats; +} diff --git a/tasks_gen/train/G1944/seed/t15_seed.clas.abap b/tasks_gen/train/G1944/seed/t15_seed.clas.abap new file mode 100644 index 0000000..cb54eeb --- /dev/null +++ b/tasks_gen/train/G1944/seed/t15_seed.clas.abap @@ -0,0 +1,28 @@ +CLASS {{p}}t15_seed DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES if_oo_adt_classrun. +ENDCLASS. + +CLASS {{p}}t15_seed IMPLEMENTATION. + METHOD if_oo_adt_classrun~main. + DELETE FROM {{p}}kntype. + INSERT {{p}}kntype FROM TABLE @( VALUE #( + ( type_id = 'CHEF' price = '2.00' ) + ( type_id = 'PARI' price = '1.50' ) + ( type_id = 'BONE' price = '3.00' ) + ( type_id = 'BREAD' price = '1.00' ) ) ). + + DELETE FROM {{p}}sharpen. + INSERT {{p}}sharpen FROM TABLE @( VALUE #( + ( item_id = 1 customer = 'TRATTORIA' knife_type = 'CHEF' knife_count = 10 sharp_date = '20260110' ) + ( item_id = 2 customer = 'TRATTORIA' knife_type = 'PARI' knife_count = 4 sharp_date = '20260112' ) + ( item_id = 3 customer = 'BISTRO' knife_type = 'CHEF' knife_count = 6 sharp_date = '20260111' ) + ( item_id = 4 customer = 'BISTRO' knife_type = 'BONE' knife_count = 2 sharp_date = '20251220' ) + ( item_id = 5 customer = 'DELI' knife_type = 'BREAD' knife_count = 5 sharp_date = '20260115' ) + ( item_id = 6 customer = 'DELI' knife_type = 'SUSHI' knife_count = 8 sharp_date = '20260116' ) + ( item_id = 7 customer = 'CANTEEN' knife_type = 'CHEF' knife_count = 20 sharp_date = '20260120' ) ) ). + + COMMIT WORK. + out->write( sy-dbcnt ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1944/spec.md b/tasks_gen/train/G1944/spec.md new file mode 100644 index 0000000..0e11ca3 --- /dev/null +++ b/tasks_gen/train/G1944/spec.md @@ -0,0 +1,48 @@ +# 1. Goal +A mobile knife sharpening service visits restaurants and sharpens their knives. +The office needs a summary of the sharpening fees of each customer for a period. + +# 2. Open questions +None. + +# 3. Context +- Table {{P}}SHARPEN is in package $TMP and contains data. + Fields: ITEM_ID (INT4, key), CUSTOMER (CHAR 10), KNIFE_TYPE (CHAR 5), + KNIFE_COUNT (INT4), SHARP_DATE (DATS). + One row is one item of a sharpening round. +- Table {{P}}KNTYPE is in package $TMP and contains the price list. + Fields: TYPE_ID (CHAR 5, key), PRICE (DEC 15,2). + PRICE is the fee for one knife of that type. + +# 4. Contract +- Create the executable program {{P}}SHARP_SUM in package $TMP. +- Selection screen: + - Parameter P_FROM, type DATS, mandatory: the first sharpening date to include. + - Select-option S_CUST for the customer. +- Show the result with CL_SALV_TABLE. The output table has these columns, with + these names: + - CUSTOMER: the customer. + - KNIVES: the total number of knives. + - FEE: the total fee. FEE is an amount with two decimal places. + +# 5. Business rules +1. Include an item only if SHARP_DATE is on or after P_FROM and CUSTOMER is in + S_CUST. +2. Include an item only if its KNIFE_TYPE has an entry in {{P}}KNTYPE. +3. The fee of an item is KNIFE_COUNT multiplied by the PRICE of its knife type. +4. Show one line for each customer that has at least one included item. +5. KNIVES is the sum of KNIFE_COUNT of the included items of the customer. +6. FEE is the sum of the fees of the included items of the customer. +7. Sort the lines by FEE, the highest fee first. + +# 6. Constraints +- Release target: 7.58. +- Coding standards: Clean ABAP. Read the sharpening items and the prices with + one database access. Do not read the database inside a loop. Keep the methods + below 40 statements. +- Out of scope: do not change {{P}}SHARPEN and {{P}}KNTYPE. + +# 7. Acceptance +- The program is active and has no syntax error. +- The hidden tests pass. +- Write ABAP Unit tests as local test classes in the program. diff --git a/tasks_gen/train/G1944/task.json b/tasks_gen/train/G1944/task.json new file mode 100644 index 0000000..c69c543 --- /dev/null +++ b/tasks_gen/train/G1944/task.json @@ -0,0 +1,67 @@ +{ + "id": "G1944", + "category": "C", + "object_type": "PROG", + "difficulty": 2, + "release_target": "v758", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [ + { + "type": "TABL", + "name": "{{P}}SHARPEN", + "file": "seed/sharpen.tabl.asabap", + "description": "Knife sharpening items" + }, + { + "type": "TABL", + "name": "{{P}}KNTYPE", + "file": "seed/kntype.tabl.asabap", + "description": "Knife type price list" + }, + { + "type": "CLAS", + "name": "{{P}}T15_SEED", + "file": "seed/t15_seed.clas.abap", + "description": "T15 seed data", + "run": true + } + ], + "contract": [ + { + "type": "PROG", + "name": "{{P}}SHARP_SUM", + "parameters": [ + "p_from", + "s_cust" + ] + } + ], + "out_of_scope": [ + "{{P}}SHARPEN", + "{{P}}KNTYPE" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T15_HIDDEN", + "file": "hidden/t15_hidden.clas.abap", + "description": "T15 hidden tests" + } + ], + "reference": [ + { + "type": "PROG", + "name": "{{P}}SHARP_SUM", + "file": "reference/sharp_sum.prog.abap", + "description": "Sharpening fee per customer" + } + ], + "craft_checks": [ + "db_operation_in_loop", + "method_length" + ] +} \ No newline at end of file diff --git a/tasks_gen/train/G1945/generation.json b/tasks_gen/train/G1945/generation.json new file mode 100644 index 0000000..f748cb0 --- /dev/null +++ b/tasks_gen/train/G1945/generation.json @@ -0,0 +1,19 @@ +{ + "id": "G1945", + "pool": "train", + "object_type": "MSAG", + "category": "D", + "attempts": [ + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 4, + "killed": 4, + "ok": true + } + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1945/hidden/t21_hidden.clas.abap b/tasks_gen/train/G1945/hidden/t21_hidden.clas.abap new file mode 100644 index 0000000..b4314ee --- /dev/null +++ b/tasks_gen/train/G1945/hidden/t21_hidden.clas.abap @@ -0,0 +1,111 @@ +CLASS {{p}}t21_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS strip_period + IMPORTING iv_text TYPE string + RETURNING VALUE(rv_text) TYPE string. + METHODS blocked_order FOR TESTING. + METHODS part_not_in_stock FOR TESTING. + METHODS invalid_quantity FOR TESTING. + METHODS load_limit_warning FOR TESTING. + METHODS released_info FOR TESTING. + METHODS exception_text FOR TESTING. + METHODS exception_attributes FOR TESTING. + METHODS exception_is_static_check FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t21_hidden IMPLEMENTATION. + METHOD strip_period. + rv_text = iv_text. + DATA(lv_len) = strlen( rv_text ). + IF lv_len > 1. + DATA(lv_last) = substring( val = rv_text off = lv_len - 1 len = 1 ). + IF lv_last = '.'. + rv_text = substring( val = rv_text len = lv_len - 1 ). + ENDIF. + ENDIF. + ENDMETHOD. + + METHOD blocked_order. + DATA lv_p1 TYPE string VALUE 'SO-4711'. + DATA lv_p2 TYPE string VALUE 'Permit missing'. + DATA lv_text TYPE string. + MESSAGE ID '{{P}}SCAF_MSG' TYPE 'E' NUMBER '001' + WITH lv_p1 lv_p2 INTO lv_text. + cl_abap_unit_assert=>assert_equals( + exp = 'Scaffolding order SO-4711 is blocked: Permit missing' + act = strip_period( lv_text ) ). + ENDMETHOD. + + METHOD part_not_in_stock. + DATA lv_p1 TYPE string VALUE 'STD-200'. + DATA lv_text TYPE string. + MESSAGE ID '{{P}}SCAF_MSG' TYPE 'E' NUMBER '002' + WITH lv_p1 INTO lv_text. + cl_abap_unit_assert=>assert_equals( + exp = 'Scaffold part STD-200 is not in stock' + act = strip_period( lv_text ) ). + ENDMETHOD. + + METHOD invalid_quantity. + DATA lv_p1 TYPE string VALUE '0'. + DATA lv_p2 TYPE string VALUE 'STD-200'. + DATA lv_text TYPE string. + MESSAGE ID '{{P}}SCAF_MSG' TYPE 'E' NUMBER '003' + WITH lv_p1 lv_p2 INTO lv_text. + cl_abap_unit_assert=>assert_equals( + exp = 'Quantity 0 is not valid for part STD-200' + act = strip_period( lv_text ) ). + ENDMETHOD. + + METHOD load_limit_warning. + DATA lv_p1 TYPE string VALUE 'SO-4712'. + DATA lv_p2 TYPE string VALUE '750'. + DATA lv_text TYPE string. + MESSAGE ID '{{P}}SCAF_MSG' TYPE 'W' NUMBER '004' + WITH lv_p1 lv_p2 INTO lv_text. + cl_abap_unit_assert=>assert_equals( + exp = 'Order SO-4712 exceeds the load limit of 750 kg' + act = strip_period( lv_text ) ). + ENDMETHOD. + + METHOD released_info. + DATA lv_p1 TYPE string VALUE 'SO-4713'. + DATA lv_p2 TYPE string VALUE 'North Gate'. + DATA lv_text TYPE string. + MESSAGE ID '{{P}}SCAF_MSG' TYPE 'I' NUMBER '005' + WITH lv_p1 lv_p2 INTO lv_text. + cl_abap_unit_assert=>assert_equals( + exp = 'Order SO-4713 was released for site North Gate' + act = strip_period( lv_text ) ). + ENDMETHOD. + + METHOD exception_text. + DATA(lo_exception) = NEW {{p}}cx_scaf_order( + iv_order_id = 'SO-4711' + iv_reason = 'Permit missing' ). + cl_abap_unit_assert=>assert_equals( + exp = 'Scaffolding order SO-4711 is blocked: Permit missing' + act = strip_period( lo_exception->get_message( ) ) ). + ENDMETHOD. + + METHOD exception_attributes. + DATA(lo_exception) = NEW {{p}}cx_scaf_order( + iv_order_id = 'SO-99' + iv_reason = 'Late delivery' ). + cl_abap_unit_assert=>assert_equals( exp = 'SO-99' act = lo_exception->order_id ). + cl_abap_unit_assert=>assert_equals( exp = 'Late delivery' act = lo_exception->reason ). + ENDMETHOD. + + METHOD exception_is_static_check. + DATA(lo_exception) = NEW {{p}}cx_scaf_order( + iv_order_id = 'SO-1' + iv_reason = 'Test' ). + DATA lv_is_static TYPE abap_bool. + IF lo_exception IS INSTANCE OF cx_static_check. + lv_is_static = abap_true. + ENDIF. + cl_abap_unit_assert=>assert_equals( exp = abap_true act = lv_is_static ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1945/mutation.json b/tasks_gen/train/G1945/mutation.json new file mode 100644 index 0000000..edd991d --- /dev/null +++ b/tasks_gen/train/G1945/mutation.json @@ -0,0 +1,52 @@ +{ + "task": "G1945", + "mutants": [ + { + "object": "{{P}}SCAF_MSG", + "mutant": "message 003: text + ' x' (text)", + "status": "killed", + "hidden": "7/8", + "failed_tests": [ + "INVALID_QUANTITY" + ] + }, + { + "object": "{{P}}SCAF_MSG", + "mutant": "message 004: number + 50 (number)", + "status": "invalid", + "hidden": "0/0", + "failed_tests": [] + }, + { + "object": "{{P}}SCAF_MSG", + "mutant": "message 003: &1 -> &2 (placeholder)", + "status": "killed", + "hidden": "7/8", + "failed_tests": [ + "INVALID_QUANTITY" + ] + }, + { + "object": "{{P}}SCAF_MSG", + "mutant": "message 005: &1 -> &2 (placeholder)", + "status": "killed", + "hidden": "7/8", + "failed_tests": [ + "RELEASED_INFO" + ] + }, + { + "object": "{{P}}SCAF_MSG", + "mutant": "message 002: text + ' x' (text)", + "status": "killed", + "hidden": "7/8", + "failed_tests": [ + "PART_NOT_IN_STOCK" + ] + } + ], + "valid": 4, + "killed": 4, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1945/reference/cx_scaf_order.clas.abap b/tasks_gen/train/G1945/reference/cx_scaf_order.clas.abap new file mode 100644 index 0000000..740aa88 --- /dev/null +++ b/tasks_gen/train/G1945/reference/cx_scaf_order.clas.abap @@ -0,0 +1,33 @@ +CLASS {{p}}cx_scaf_order DEFINITION + PUBLIC + INHERITING FROM cx_static_check + FINAL + CREATE PUBLIC. + + PUBLIC SECTION. + DATA order_id TYPE string READ-ONLY. + DATA reason TYPE string READ-ONLY. + + METHODS constructor + IMPORTING + iv_order_id TYPE string + iv_reason TYPE string. + + METHODS get_message + RETURNING + VALUE(rv_message) TYPE string. +ENDCLASS. + + +CLASS {{p}}cx_scaf_order IMPLEMENTATION. + METHOD constructor. + super->constructor( ). + order_id = iv_order_id. + reason = iv_reason. + ENDMETHOD. + + METHOD get_message. + MESSAGE ID '{{P}}SCAF_MSG' TYPE 'E' NUMBER '001' + WITH order_id reason INTO rv_message. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1945/reference/t21_test.clas.abap b/tasks_gen/train/G1945/reference/t21_test.clas.abap new file mode 100644 index 0000000..6aa85ba --- /dev/null +++ b/tasks_gen/train/G1945/reference/t21_test.clas.abap @@ -0,0 +1,87 @@ +CLASS {{p}}t21_test DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS strip_period + IMPORTING iv_text TYPE string + RETURNING VALUE(rv_text) TYPE string. + METHODS blocked_message FOR TESTING. + METHODS stock_message FOR TESTING. + METHODS warning_message FOR TESTING. + METHODS info_message FOR TESTING. + METHODS exception_message FOR TESTING. + METHODS exception_attributes FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t21_test IMPLEMENTATION. + METHOD strip_period. + rv_text = iv_text. + DATA(lv_len) = strlen( rv_text ). + IF lv_len > 1. + DATA(lv_last) = substring( val = rv_text off = lv_len - 1 len = 1 ). + IF lv_last = '.'. + rv_text = substring( val = rv_text len = lv_len - 1 ). + ENDIF. + ENDIF. + ENDMETHOD. + + METHOD blocked_message. + DATA lv_order TYPE string VALUE 'SO-100'. + DATA lv_reason TYPE string VALUE 'Missing permit'. + DATA lv_text TYPE string. + MESSAGE ID '{{P}}SCAF_MSG' TYPE 'E' NUMBER '001' + WITH lv_order lv_reason INTO lv_text. + cl_abap_unit_assert=>assert_equals( + exp = 'Scaffolding order SO-100 is blocked: Missing permit' + act = strip_period( lv_text ) ). + ENDMETHOD. + + METHOD stock_message. + DATA lv_part TYPE string VALUE 'STD-300'. + DATA lv_text TYPE string. + MESSAGE ID '{{P}}SCAF_MSG' TYPE 'E' NUMBER '002' + WITH lv_part INTO lv_text. + cl_abap_unit_assert=>assert_equals( + exp = 'Scaffold part STD-300 is not in stock' + act = strip_period( lv_text ) ). + ENDMETHOD. + + METHOD warning_message. + DATA lv_order TYPE string VALUE 'SO-101'. + DATA lv_limit TYPE string VALUE '900'. + DATA lv_text TYPE string. + MESSAGE ID '{{P}}SCAF_MSG' TYPE 'W' NUMBER '004' + WITH lv_order lv_limit INTO lv_text. + cl_abap_unit_assert=>assert_equals( + exp = 'Order SO-101 exceeds the load limit of 900 kg' + act = strip_period( lv_text ) ). + ENDMETHOD. + + METHOD info_message. + DATA lv_order TYPE string VALUE 'SO-102'. + DATA lv_site TYPE string VALUE 'South Gate'. + DATA lv_text TYPE string. + MESSAGE ID '{{P}}SCAF_MSG' TYPE 'I' NUMBER '005' + WITH lv_order lv_site INTO lv_text. + cl_abap_unit_assert=>assert_equals( + exp = 'Order SO-102 was released for site South Gate' + act = strip_period( lv_text ) ). + ENDMETHOD. + + METHOD exception_message. + DATA(lo_exception) = NEW {{p}}cx_scaf_order( + iv_order_id = 'SO-100' + iv_reason = 'Missing permit' ). + cl_abap_unit_assert=>assert_equals( + exp = 'Scaffolding order SO-100 is blocked: Missing permit' + act = strip_period( lo_exception->get_message( ) ) ). + ENDMETHOD. + + METHOD exception_attributes. + DATA(lo_exception) = NEW {{p}}cx_scaf_order( + iv_order_id = 'SO-100' + iv_reason = 'Missing permit' ). + cl_abap_unit_assert=>assert_equals( exp = 'SO-100' act = lo_exception->order_id ). + cl_abap_unit_assert=>assert_equals( exp = 'Missing permit' act = lo_exception->reason ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1945/spec.md b/tasks_gen/train/G1945/spec.md new file mode 100644 index 0000000..a1235f5 --- /dev/null +++ b/tasks_gen/train/G1945/spec.md @@ -0,0 +1,51 @@ +# 1. Goal +A scaffolding hire company checks a scaffolding order before the yard loads +the material onto the lorry. The dispatch office must give the customer a +clear reason when it blocks an order. Create the message class that holds +these reasons and the class-based exception that carries the reason of a +blocked order. + +# 2. Open questions +None. + +# 3. Context +- Package $TMP. +- The dispatch program of the scaffolding hire company stops an order with the + class-based exception {{P}}CX_SCAF_ORDER. +- The company has no message class yet. + +# 4. Contract +## Message class {{P}}SCAF_MSG +Create the message class {{P}}SCAF_MSG in package $TMP. It contains the +messages 001 to 005. The business rules give the exact text and the use of +each message. + +## Class {{P}}CX_SCAF_ORDER +Create the class {{P}}CX_SCAF_ORDER in package $TMP. +- The class is public and final. It inherits from CX_STATIC_CHECK. +- Public read-only attributes ORDER_ID and REASON, both of type string. +- Constructor: IMPORTING iv_order_id TYPE string, iv_reason TYPE string. +- Method GET_MESSAGE: RETURNING VALUE(rv_message) TYPE string. + +# 5. Business rules +1. Message 001 is an error message. Text: "Scaffolding order &1 is blocked: &2". &1 is the order id. &2 is the reason. +2. Message 002 is an error message. Text: "Scaffold part &1 is not in stock". &1 is the part number. +3. Message 003 is an error message. Text: "Quantity &1 is not valid for part &2". &1 is the quantity. &2 is the part number. +4. Message 004 is a warning message. Text: "Order &1 exceeds the load limit of &2 kg". &1 is the order id. &2 is the load limit in kilograms. +5. Message 005 is an information message. Text: "Order &1 was released for site &2". &1 is the order id. &2 is the site. +6. The constructor of {{P}}CX_SCAF_ORDER stores the order id in ORDER_ID and the reason in REASON. +7. GET_MESSAGE returns message 001 with &1 = ORDER_ID and &2 = REASON. +8. {{P}}CX_SCAF_ORDER is a static check exception. The caller must handle it. + +# 6. Constraints +- Release target: SAP_BASIS 816 (SAP ABAP Platform 2025). +- Coding standards: Clean ABAP. A method has fewer than 40 statements. +- Out of scope: no other message class and no other exception class. + +# 7. Acceptance +- The message class {{P}}SCAF_MSG is active and contains messages 001 to 005 + with the exact texts of the business rules. +- The class {{P}}CX_SCAF_ORDER is active and has no syntax error. +- The hidden tests pass. +- Write ABAP Unit tests for the message class and for the exception class in + a global test class. diff --git a/tasks_gen/train/G1945/task.json b/tasks_gen/train/G1945/task.json new file mode 100644 index 0000000..d445da9 --- /dev/null +++ b/tasks_gen/train/G1945/task.json @@ -0,0 +1,93 @@ +{ + "id": "G1945", + "category": "D", + "object_type": "MSAG", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [], + "contract": [ + { + "type": "MSAG", + "name": "{{P}}SCAF_MSG", + "messages": [ + { + "msgno": "001" + }, + { + "msgno": "002" + }, + { + "msgno": "003" + }, + { + "msgno": "004" + }, + { + "msgno": "005" + } + ] + }, + { + "type": "CLAS", + "name": "{{P}}CX_SCAF_ORDER" + } + ], + "out_of_scope": [], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T21_HIDDEN", + "file": "hidden/t21_hidden.clas.abap", + "description": "Hidden tests for the message class {{P}}SCAF_MSG and the exception class {{P}}CX_SCAF_ORDER" + } + ], + "reference": [ + { + "type": "MSAG", + "name": "{{P}}SCAF_MSG", + "description": "Messages of the scaffolding hire company", + "messages": [ + { + "msgno": "001", + "text": "Scaffolding order &1 is blocked: &2" + }, + { + "msgno": "002", + "text": "Scaffold part &1 is not in stock" + }, + { + "msgno": "003", + "text": "Quantity &1 is not valid for part &2" + }, + { + "msgno": "004", + "text": "Order &1 exceeds the load limit of &2 kg" + }, + { + "msgno": "005", + "text": "Order &1 was released for site &2" + } + ] + }, + { + "type": "CLAS", + "name": "{{P}}CX_SCAF_ORDER", + "file": "reference/cx_scaf_order.clas.abap", + "description": "Class-based exception of a blocked scaffolding order" + }, + { + "type": "CLAS", + "name": "{{P}}T21_TEST", + "file": "reference/t21_test.clas.abap", + "description": "Own tests of the message class and of the exception class" + } + ], + "craft_checks": [ + "method_length" + ] +} \ No newline at end of file diff --git a/tasks_gen/train/G1946/faulty/m0_roast_base.stru.asabap b/tasks_gen/train/G1946/faulty/m0_roast_base.stru.asabap new file mode 100644 index 0000000..829af59 --- /dev/null +++ b/tasks_gen/train/G1946/faulty/m0_roast_base.stru.asabap @@ -0,0 +1,9 @@ +@EndUserText.label : 'Common fields of a roast batch' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +define structure {{p}}roast_base { + site : abap.numc(4); + batch_no : abap.char(10); + roast_day : abap.dats; + green_kg : abap.dec(9,3); + roasted_kg : abap.dec(9,3); +} diff --git a/tasks_gen/train/G1946/faulty/m1_roast_result.stru.asabap b/tasks_gen/train/G1946/faulty/m1_roast_result.stru.asabap new file mode 100644 index 0000000..9eb54fb --- /dev/null +++ b/tasks_gen/train/G1946/faulty/m1_roast_result.stru.asabap @@ -0,0 +1,14 @@ +@EndUserText.label : 'Result of one roast batch' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +define structure {{p}}roast_result { + site : abap.char(3); + batch_no : abap.char(10); + roast_day : abap.dats; + green_kg : abap.dec(9,3); + roasted_kg : abap.dec(9,3); + roast_level : abap.char(1); + roast_min : abap.int4; + loss_pct : abap.dec(5,2); + roaster_id : abap.char(8); + checked : abap.char(1); +} diff --git a/tasks_gen/train/G1946/faulty/m2_roast_base.stru.asabap b/tasks_gen/train/G1946/faulty/m2_roast_base.stru.asabap new file mode 100644 index 0000000..295a07e --- /dev/null +++ b/tasks_gen/train/G1946/faulty/m2_roast_base.stru.asabap @@ -0,0 +1,9 @@ +@EndUserText.label : 'Common fields of a roast batch' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +define structure {{p}}roast_base { + site : abap.char(3); + batch_no : abap.char(10); + roast_day : abap.dats; + green_kg : abap.dec(9,3); + roasted_kg : abap.dec(9,3); +} diff --git a/tasks_gen/train/G1946/faulty/m3_roast_result.stru.asabap b/tasks_gen/train/G1946/faulty/m3_roast_result.stru.asabap new file mode 100644 index 0000000..c478240 --- /dev/null +++ b/tasks_gen/train/G1946/faulty/m3_roast_result.stru.asabap @@ -0,0 +1,14 @@ +@EndUserText.label : 'Result of one roast batch' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +define structure {{p}}roast_result { + site : abap.numc(4); + batch_no : abap.char(10); + roast_day : abap.dats; + green_kg : abap.dec(9,3); + roasted_kg : abap.dec(9,3); + roast_level : abap.char(1); + roast_min : abap.int4; + loss_pct : abap.dec(5,2); + roaster_id : abap.char(8); + checked : abap.char(1); +} diff --git a/tasks_gen/train/G1946/faulty/m4_roast_base.stru.asabap b/tasks_gen/train/G1946/faulty/m4_roast_base.stru.asabap new file mode 100644 index 0000000..7205fa4 --- /dev/null +++ b/tasks_gen/train/G1946/faulty/m4_roast_base.stru.asabap @@ -0,0 +1,9 @@ +@EndUserText.label : 'Common fields of a roast batch' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +define structure {{p}}roast_base { + site : abap.char(4); + batch_no : abap.char(10); + roast_day : abap.tims; + green_kg : abap.dec(9,3); + roasted_kg : abap.dec(9,3); +} diff --git a/tasks_gen/train/G1946/generation.json b/tasks_gen/train/G1946/generation.json new file mode 100644 index 0000000..ba6d972 --- /dev/null +++ b/tasks_gen/train/G1946/generation.json @@ -0,0 +1,24 @@ +{ + "id": "G1946", + "pool": "train", + "object_type": "STRU", + "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 +} \ No newline at end of file diff --git a/tasks_gen/train/G1946/hidden/roast_hidden.clas.abap b/tasks_gen/train/G1946/hidden/roast_hidden.clas.abap new file mode 100644 index 0000000..420592f --- /dev/null +++ b/tasks_gen/train/G1946/hidden/roast_hidden.clas.abap @@ -0,0 +1,135 @@ +CLASS {{p}}roast_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS base_field_count FOR TESTING. + METHODS base_field_names FOR TESTING. + METHODS base_char_lengths FOR TESTING. + METHODS base_amount_types FOR TESTING. + METHODS base_day_type FOR TESTING. + METHODS result_field_count FOR TESTING. + METHODS result_starts_with_base FOR TESTING. + METHODS result_flag_fields FOR TESTING. + METHODS result_min_type FOR TESTING. + METHODS result_loss_type FOR TESTING. + METHODS result_roaster_type FOR TESTING. +ENDCLASS. + + +CLASS {{p}}roast_hidden IMPLEMENTATION. + METHOD base_field_count. + DATA(lo_str) = CAST cl_abap_structdescr( + cl_abap_typedescr=>describe_by_name( '{{P}}ROAST_BASE' ) ). + DATA(lt_fields) = lo_str->get_ddic_field_list( ). + cl_abap_unit_assert=>assert_equals( exp = 5 act = lines( lt_fields ) ). + ENDMETHOD. + + METHOD base_field_names. + DATA(lo_str) = CAST cl_abap_structdescr( + cl_abap_typedescr=>describe_by_name( '{{P}}ROAST_BASE' ) ). + DATA(lt_fields) = lo_str->get_ddic_field_list( ). + cl_abap_unit_assert=>assert_equals( exp = 'SITE' act = lt_fields[ 1 ]-fieldname ). + cl_abap_unit_assert=>assert_equals( exp = 'BATCH_NO' act = lt_fields[ 2 ]-fieldname ). + cl_abap_unit_assert=>assert_equals( exp = 'ROAST_DAY' act = lt_fields[ 3 ]-fieldname ). + cl_abap_unit_assert=>assert_equals( exp = 'GREEN_KG' act = lt_fields[ 4 ]-fieldname ). + cl_abap_unit_assert=>assert_equals( exp = 'ROASTED_KG' act = lt_fields[ 5 ]-fieldname ). + ENDMETHOD. + + METHOD base_char_lengths. + DATA(lo_str) = CAST cl_abap_structdescr( + cl_abap_typedescr=>describe_by_name( '{{P}}ROAST_BASE' ) ). + DATA(lt_fields) = lo_str->get_ddic_field_list( ). + cl_abap_unit_assert=>assert_equals( exp = 'C' act = lt_fields[ 1 ]-inttype ). + cl_abap_unit_assert=>assert_equals( exp = 4 act = lt_fields[ 1 ]-leng ). + cl_abap_unit_assert=>assert_equals( exp = 'C' act = lt_fields[ 2 ]-inttype ). + cl_abap_unit_assert=>assert_equals( exp = 10 act = lt_fields[ 2 ]-leng ). + ENDMETHOD. + + METHOD base_amount_types. + DATA(lo_str) = CAST cl_abap_structdescr( + cl_abap_typedescr=>describe_by_name( '{{P}}ROAST_BASE' ) ). + DATA(lt_fields) = lo_str->get_ddic_field_list( ). + cl_abap_unit_assert=>assert_equals( exp = 'P' act = lt_fields[ 4 ]-inttype ). + cl_abap_unit_assert=>assert_equals( exp = 9 act = lt_fields[ 4 ]-leng ). + cl_abap_unit_assert=>assert_equals( exp = 3 act = lt_fields[ 4 ]-decimals ). + cl_abap_unit_assert=>assert_equals( exp = 'P' act = lt_fields[ 5 ]-inttype ). + cl_abap_unit_assert=>assert_equals( exp = 9 act = lt_fields[ 5 ]-leng ). + cl_abap_unit_assert=>assert_equals( exp = 3 act = lt_fields[ 5 ]-decimals ). + ENDMETHOD. + + METHOD base_day_type. + DATA(lo_str) = CAST cl_abap_structdescr( + cl_abap_typedescr=>describe_by_name( '{{P}}ROAST_BASE' ) ). + DATA(lt_fields) = lo_str->get_ddic_field_list( ). + cl_abap_unit_assert=>assert_equals( exp = 'D' act = lt_fields[ 3 ]-inttype ). + cl_abap_unit_assert=>assert_equals( exp = 8 act = lt_fields[ 3 ]-leng ). + ENDMETHOD. + + METHOD result_field_count. + DATA(lo_str) = CAST cl_abap_structdescr( + cl_abap_typedescr=>describe_by_name( '{{P}}ROAST_RESULT' ) ). + DATA(lt_fields) = lo_str->get_ddic_field_list( ). + cl_abap_unit_assert=>assert_equals( exp = 10 act = lines( lt_fields ) ). + ENDMETHOD. + + METHOD result_starts_with_base. + DATA(lo_base) = CAST cl_abap_structdescr( + cl_abap_typedescr=>describe_by_name( '{{P}}ROAST_BASE' ) ). + DATA(lo_res) = CAST cl_abap_structdescr( + cl_abap_typedescr=>describe_by_name( '{{P}}ROAST_RESULT' ) ). + DATA(lt_base) = lo_base->get_ddic_field_list( ). + DATA(lt_res) = lo_res->get_ddic_field_list( ). + DO 5 TIMES. + cl_abap_unit_assert=>assert_equals( + exp = lt_base[ sy-index ]-fieldname + act = lt_res[ sy-index ]-fieldname ). + cl_abap_unit_assert=>assert_equals( + exp = lt_base[ sy-index ]-inttype + act = lt_res[ sy-index ]-inttype ). + cl_abap_unit_assert=>assert_equals( + exp = lt_base[ sy-index ]-leng + act = lt_res[ sy-index ]-leng ). + cl_abap_unit_assert=>assert_equals( + exp = lt_base[ sy-index ]-decimals + act = lt_res[ sy-index ]-decimals ). + ENDDO. + ENDMETHOD. + + METHOD result_flag_fields. + DATA(lo_str) = CAST cl_abap_structdescr( + cl_abap_typedescr=>describe_by_name( '{{P}}ROAST_RESULT' ) ). + DATA(lt_fields) = lo_str->get_ddic_field_list( ). + cl_abap_unit_assert=>assert_equals( exp = 'ROAST_LEVEL' act = lt_fields[ 6 ]-fieldname ). + cl_abap_unit_assert=>assert_equals( exp = 'C' act = lt_fields[ 6 ]-inttype ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lt_fields[ 6 ]-leng ). + cl_abap_unit_assert=>assert_equals( exp = 'CHECKED' act = lt_fields[ 10 ]-fieldname ). + cl_abap_unit_assert=>assert_equals( exp = 'C' act = lt_fields[ 10 ]-inttype ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lt_fields[ 10 ]-leng ). + ENDMETHOD. + + METHOD result_min_type. + DATA(lo_str) = CAST cl_abap_structdescr( + cl_abap_typedescr=>describe_by_name( '{{P}}ROAST_RESULT' ) ). + DATA(lt_fields) = lo_str->get_ddic_field_list( ). + cl_abap_unit_assert=>assert_equals( exp = 'ROAST_MIN' act = lt_fields[ 7 ]-fieldname ). + cl_abap_unit_assert=>assert_equals( exp = 'I' act = lt_fields[ 7 ]-inttype ). + ENDMETHOD. + + METHOD result_loss_type. + DATA(lo_str) = CAST cl_abap_structdescr( + cl_abap_typedescr=>describe_by_name( '{{P}}ROAST_RESULT' ) ). + DATA(lt_fields) = lo_str->get_ddic_field_list( ). + cl_abap_unit_assert=>assert_equals( exp = 'LOSS_PCT' act = lt_fields[ 8 ]-fieldname ). + cl_abap_unit_assert=>assert_equals( exp = 'P' act = lt_fields[ 8 ]-inttype ). + cl_abap_unit_assert=>assert_equals( exp = 5 act = lt_fields[ 8 ]-leng ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lt_fields[ 8 ]-decimals ). + ENDMETHOD. + + METHOD result_roaster_type. + DATA(lo_str) = CAST cl_abap_structdescr( + cl_abap_typedescr=>describe_by_name( '{{P}}ROAST_RESULT' ) ). + DATA(lt_fields) = lo_str->get_ddic_field_list( ). + cl_abap_unit_assert=>assert_equals( exp = 'ROASTER_ID' act = lt_fields[ 9 ]-fieldname ). + cl_abap_unit_assert=>assert_equals( exp = 'C' act = lt_fields[ 9 ]-inttype ). + cl_abap_unit_assert=>assert_equals( exp = 8 act = lt_fields[ 9 ]-leng ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1946/mutation.json b/tasks_gen/train/G1946/mutation.json new file mode 100644 index 0000000..8f14346 --- /dev/null +++ b/tasks_gen/train/G1946/mutation.json @@ -0,0 +1,57 @@ +{ + "task": "G1946", + "mutants": [ + { + "object": "{{P}}ROAST_BASE", + "mutant": "line 4: abap.char(4) -> abap.numc(4) (type)", + "status": "killed", + "hidden": "9/11", + "failed_tests": [ + "BASE_CHAR_LENGTHS", + "RESULT_STARTS_WITH_BASE" + ] + }, + { + "object": "{{P}}ROAST_RESULT", + "mutant": "line 4: abap.char(4) -> abap.char(3) (length)", + "status": "killed", + "hidden": "10/11", + "failed_tests": [ + "RESULT_STARTS_WITH_BASE" + ] + }, + { + "object": "{{P}}ROAST_BASE", + "mutant": "line 4: abap.char(4) -> abap.char(3) (length)", + "status": "killed", + "hidden": "9/11", + "failed_tests": [ + "BASE_CHAR_LENGTHS", + "RESULT_STARTS_WITH_BASE" + ] + }, + { + "object": "{{P}}ROAST_RESULT", + "mutant": "line 4: abap.char(4) -> abap.numc(4) (type)", + "status": "killed", + "hidden": "10/11", + "failed_tests": [ + "RESULT_STARTS_WITH_BASE" + ] + }, + { + "object": "{{P}}ROAST_BASE", + "mutant": "line 6: abap.dats -> abap.tims (type)", + "status": "killed", + "hidden": "9/11", + "failed_tests": [ + "BASE_DAY_TYPE", + "RESULT_STARTS_WITH_BASE" + ] + } + ], + "valid": 5, + "killed": 5, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1946/reference/roast_base.stru.asabap b/tasks_gen/train/G1946/reference/roast_base.stru.asabap new file mode 100644 index 0000000..96bd5b2 --- /dev/null +++ b/tasks_gen/train/G1946/reference/roast_base.stru.asabap @@ -0,0 +1,9 @@ +@EndUserText.label : 'Common fields of a roast batch' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +define structure {{p}}roast_base { + site : abap.char(4); + batch_no : abap.char(10); + roast_day : abap.dats; + green_kg : abap.dec(9,3); + roasted_kg : abap.dec(9,3); +} diff --git a/tasks_gen/train/G1946/reference/roast_result.stru.asabap b/tasks_gen/train/G1946/reference/roast_result.stru.asabap new file mode 100644 index 0000000..464c7fe --- /dev/null +++ b/tasks_gen/train/G1946/reference/roast_result.stru.asabap @@ -0,0 +1,14 @@ +@EndUserText.label : 'Result of one roast batch' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +define structure {{p}}roast_result { + site : abap.char(4); + batch_no : abap.char(10); + roast_day : abap.dats; + green_kg : abap.dec(9,3); + roasted_kg : abap.dec(9,3); + roast_level : abap.char(1); + roast_min : abap.int4; + loss_pct : abap.dec(5,2); + roaster_id : abap.char(8); + checked : abap.char(1); +} diff --git a/tasks_gen/train/G1946/reference/roast_test.clas.abap b/tasks_gen/train/G1946/reference/roast_test.clas.abap new file mode 100644 index 0000000..bebb853 --- /dev/null +++ b/tasks_gen/train/G1946/reference/roast_test.clas.abap @@ -0,0 +1,46 @@ +CLASS {{p}}roast_test DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS base_has_five_fields FOR TESTING. + METHODS result_has_ten_fields FOR TESTING. + METHODS loss_has_two_decimals FOR TESTING. + METHODS result_starts_with_base FOR TESTING. +ENDCLASS. + + +CLASS {{p}}roast_test IMPLEMENTATION. + METHOD base_has_five_fields. + DATA(lo_str) = CAST cl_abap_structdescr( + cl_abap_typedescr=>describe_by_name( '{{P}}ROAST_BASE' ) ). + DATA(lt_fields) = lo_str->get_ddic_field_list( ). + cl_abap_unit_assert=>assert_equals( exp = 5 act = lines( lt_fields ) ). + ENDMETHOD. + + METHOD result_has_ten_fields. + DATA(lo_str) = CAST cl_abap_structdescr( + cl_abap_typedescr=>describe_by_name( '{{P}}ROAST_RESULT' ) ). + DATA(lt_fields) = lo_str->get_ddic_field_list( ). + cl_abap_unit_assert=>assert_equals( exp = 10 act = lines( lt_fields ) ). + ENDMETHOD. + + METHOD loss_has_two_decimals. + DATA(lo_str) = CAST cl_abap_structdescr( + cl_abap_typedescr=>describe_by_name( '{{P}}ROAST_RESULT' ) ). + DATA(lt_fields) = lo_str->get_ddic_field_list( ). + READ TABLE lt_fields INTO DATA(ls_field) WITH KEY fieldname = 'LOSS_PCT'. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = ls_field-decimals ). + ENDMETHOD. + + METHOD result_starts_with_base. + DATA(lo_base) = CAST cl_abap_structdescr( + cl_abap_typedescr=>describe_by_name( '{{P}}ROAST_BASE' ) ). + DATA(lo_res) = CAST cl_abap_structdescr( + cl_abap_typedescr=>describe_by_name( '{{P}}ROAST_RESULT' ) ). + DATA(lt_base) = lo_base->get_ddic_field_list( ). + DATA(lt_res) = lo_res->get_ddic_field_list( ). + cl_abap_unit_assert=>assert_equals( exp = lt_base[ 1 ]-fieldname act = lt_res[ 1 ]-fieldname ). + cl_abap_unit_assert=>assert_equals( exp = lt_base[ 5 ]-fieldname act = lt_res[ 5 ]-fieldname ). + cl_abap_unit_assert=>assert_equals( exp = lt_base[ 5 ]-leng act = lt_res[ 5 ]-leng ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1946/seed/roast.tabl.asabap b/tasks_gen/train/G1946/seed/roast.tabl.asabap new file mode 100644 index 0000000..e5c8d80 --- /dev/null +++ b/tasks_gen/train/G1946/seed/roast.tabl.asabap @@ -0,0 +1,18 @@ +@EndUserText.label : 'Roast batch log' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}roast { + key client : abap.clnt not null; + key site : abap.char(4) not null; + key batch_no : abap.char(10) not null; + roast_day : abap.dats; + green_kg : abap.dec(9,3); + roasted_kg : abap.dec(9,3); + roast_level : abap.char(1); + roast_min : abap.int4; + loss_pct : abap.dec(5,2); + roaster_id : abap.char(8); + checked : abap.char(1); +} diff --git a/tasks_gen/train/G1946/spec.md b/tasks_gen/train/G1946/spec.md new file mode 100644 index 0000000..9474b20 --- /dev/null +++ b/tasks_gen/train/G1946/spec.md @@ -0,0 +1,55 @@ +# 1. Goal +The coffee roastery "Ember Roast" records every roast batch in the database table +{{P}}ROAST. A report and an OData service read the roast batches into an internal +table. The line type of this internal table is the structure {{P}}ROAST_RESULT. +Create the two structures that the report and the OData service need. + +# 2. Open questions +None. + +# 3. Context +- Table {{P}}ROAST (roast batch log), package $TMP. The table is in the system. + Key fields: CLIENT (CLNT 3), SITE (CHAR 4), BATCH_NO (CHAR 10). + Other fields: ROAST_DAY (DATS), GREEN_KG (DEC 9,3), ROASTED_KG (DEC 9,3), + ROAST_LEVEL (CHAR 1), ROAST_MIN (INT4), LOSS_PCT (DEC 5,2), + ROASTER_ID (CHAR 8), CHECKED (CHAR 1). +- The report and the OData service use the structure {{P}}ROAST_RESULT as the + line type of their internal table. +- The green coffee intake uses the structure {{P}}ROAST_BASE. It holds the five + fields that every roast batch has in common. + +# 4. Contract +- Create the structure {{P}}ROAST_BASE in package $TMP. +- Create the structure {{P}}ROAST_RESULT in package $TMP. +- Fields of {{P}}ROAST_BASE, in this order: site, batch_no, roast_day, green_kg, + roasted_kg. +- Fields of {{P}}ROAST_RESULT, in this order: site, batch_no, roast_day, green_kg, + roasted_kg, roast_level, roast_min, loss_pct, roaster_id, checked. + +# 5. Business rules +1. The structure {{P}}ROAST_BASE has exactly five fields. The fields are, in this + order: SITE (CHAR 4), BATCH_NO (CHAR 10), ROAST_DAY (DATS), GREEN_KG + (DEC 9,3) and ROASTED_KG (DEC 9,3). +2. The structure {{P}}ROAST_RESULT has exactly ten fields. +3. The first five fields of {{P}}ROAST_RESULT have the same names, data types, + lengths and number of decimals as the five fields of {{P}}ROAST_BASE, in the + same order. +4. The last five fields of {{P}}ROAST_RESULT are, in this order: ROAST_LEVEL + (CHAR 1), ROAST_MIN (INT4), LOSS_PCT (DEC 5,2), ROASTER_ID (CHAR 8) and + CHECKED (CHAR 1). +5. GREEN_KG and ROASTED_KG have 3 decimals. LOSS_PCT has 2 decimals. +6. The fields of the two structures have the same data types, lengths and number + of decimals as the fields with the same names in the table {{P}}ROAST. + +# 6. Constraints +- Release target: ABAP Platform 2025 (SAP_BASIS 816). +- Create both structures as DDL sources (define structure) in package $TMP. +- Both structures are not extensible. +- Out of scope: do not change {{P}}ROAST. + +# 7. Acceptance +- Both structures are active and have no syntax error. +- The hidden tests pass. +- Write ABAP Unit tests in a global test class. The tests read the fields of both + structures with RTTI and check the names, the data types, the lengths and the + number of decimals. diff --git a/tasks_gen/train/G1946/task.json b/tasks_gen/train/G1946/task.json new file mode 100644 index 0000000..6f8e817 --- /dev/null +++ b/tasks_gen/train/G1946/task.json @@ -0,0 +1,81 @@ +{ + "id": "G1946", + "category": "B", + "object_type": "STRU", + "difficulty": 3, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [ + { + "type": "TABL", + "name": "{{P}}ROAST", + "file": "seed/roast.tabl.asabap", + "description": "Roast batch log" + } + ], + "contract": [ + { + "type": "STRU", + "name": "{{P}}ROAST_BASE", + "fields": [ + "site", + "batch_no", + "roast_day", + "green_kg", + "roasted_kg" + ] + }, + { + "type": "STRU", + "name": "{{P}}ROAST_RESULT", + "fields": [ + "site", + "batch_no", + "roast_day", + "green_kg", + "roasted_kg", + "roast_level", + "roast_min", + "loss_pct", + "roaster_id", + "checked" + ] + } + ], + "out_of_scope": [ + "{{P}}ROAST" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}ROAST_HIDDEN", + "file": "hidden/roast_hidden.clas.abap", + "description": "Field checks for both structures" + } + ], + "reference": [ + { + "type": "STRU", + "name": "{{P}}ROAST_BASE", + "file": "reference/roast_base.stru.asabap", + "description": "Common fields of a roast batch" + }, + { + "type": "STRU", + "name": "{{P}}ROAST_RESULT", + "file": "reference/roast_result.stru.asabap", + "description": "Line type of the roast batch report" + }, + { + "type": "CLAS", + "name": "{{P}}ROAST_TEST", + "file": "reference/roast_test.clas.abap", + "description": "Own tests for the two structures" + } + ], + "craft_checks": [] +} \ No newline at end of file diff --git a/tasks_gen/train/G1947/faulty/m0_svc_base.ddls.asddls b/tasks_gen/train/G1947/faulty/m0_svc_base.ddls.asddls new file mode 100644 index 0000000..db1540d --- /dev/null +++ b/tasks_gen/train/G1947/faulty/m0_svc_base.ddls.asddls @@ -0,0 +1,6 @@ +@EndUserText.label : 'Service job base fields' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +define structure {{p}}svc_base { + created_by : abap.numc(12); + created_on : abap.dats; +} diff --git a/tasks_gen/train/G1947/faulty/m1_svc_job.ddls.asddls b/tasks_gen/train/G1947/faulty/m1_svc_job.ddls.asddls new file mode 100644 index 0000000..0134794 --- /dev/null +++ b/tasks_gen/train/G1947/faulty/m1_svc_job.ddls.asddls @@ -0,0 +1,14 @@ +@EndUserText.label : 'Service job line type' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +define structure {{p}}svc_job { + created_by : abap.numc(12); + created_on : abap.dats; + job_id : abap.char(10); + work_hours : abap.dec(5,2); + calc_mode : abap.char(2); + order_ref : abap.char(12); + service_date : abap.dats; + part_count : abap.int4; + group_code : abap.char(4); + net_value : abap.dec(13,2); +} diff --git a/tasks_gen/train/G1947/faulty/m2_svc_base.ddls.asddls b/tasks_gen/train/G1947/faulty/m2_svc_base.ddls.asddls new file mode 100644 index 0000000..ff1d92a --- /dev/null +++ b/tasks_gen/train/G1947/faulty/m2_svc_base.ddls.asddls @@ -0,0 +1,6 @@ +@EndUserText.label : 'Service job base fields' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +define structure {{p}}svc_base { + created_by : abap.char(11); + created_on : abap.dats; +} diff --git a/tasks_gen/train/G1947/faulty/m3_svc_job.ddls.asddls b/tasks_gen/train/G1947/faulty/m3_svc_job.ddls.asddls new file mode 100644 index 0000000..8dd1bbf --- /dev/null +++ b/tasks_gen/train/G1947/faulty/m3_svc_job.ddls.asddls @@ -0,0 +1,14 @@ +@EndUserText.label : 'Service job line type' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +define structure {{p}}svc_job { + created_by : abap.char(12); + created_on : abap.tims; + job_id : abap.char(10); + work_hours : abap.dec(5,2); + calc_mode : abap.char(2); + order_ref : abap.char(12); + service_date : abap.dats; + part_count : abap.int4; + group_code : abap.char(4); + net_value : abap.dec(13,2); +} diff --git a/tasks_gen/train/G1947/faulty/m4_svc_base.ddls.asddls b/tasks_gen/train/G1947/faulty/m4_svc_base.ddls.asddls new file mode 100644 index 0000000..eb844e8 --- /dev/null +++ b/tasks_gen/train/G1947/faulty/m4_svc_base.ddls.asddls @@ -0,0 +1,6 @@ +@EndUserText.label : 'Service job base fields' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +define structure {{p}}svc_base { + created_by : abap.char(12); + created_on : abap.tims; +} diff --git a/tasks_gen/train/G1947/generation.json b/tasks_gen/train/G1947/generation.json new file mode 100644 index 0000000..2923a45 --- /dev/null +++ b/tasks_gen/train/G1947/generation.json @@ -0,0 +1,34 @@ +{ + "id": "G1947", + "pool": "train", + "object_type": "STRU", + "category": "B", + "attempts": [ + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 5, + "killed": 2, + "ok": false + } + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 5, + "killed": 5, + "ok": true + } + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1947/hidden/svc_job_hidden.clas.abap b/tasks_gen/train/G1947/hidden/svc_job_hidden.clas.abap new file mode 100644 index 0000000..b7fd25f --- /dev/null +++ b/tasks_gen/train/G1947/hidden/svc_job_hidden.clas.abap @@ -0,0 +1,193 @@ +CLASS {{p}}svc_job_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + CLASS-DATA go_job TYPE REF TO cl_abap_structdescr. + CLASS-DATA go_base TYPE REF TO cl_abap_structdescr. + CLASS-DATA gt_job TYPE ddfields. + CLASS-DATA gt_base TYPE ddfields. + CLASS-METHODS class_setup. + METHODS assert_job_field + IMPORTING iv_index TYPE i + iv_name TYPE string + iv_type TYPE string + iv_leng TYPE i + iv_dec TYPE i. + METHODS assert_base_field + IMPORTING iv_index TYPE i + iv_name TYPE string + iv_type TYPE string + iv_leng TYPE i + iv_dec TYPE i. + METHODS structure_exists FOR TESTING. + METHODS base_structure_exists FOR TESTING. + METHODS component_order FOR TESTING. + METHODS base_component_order FOR TESTING. + METHODS base_created_by_type FOR TESTING. + METHODS base_created_on_type FOR TESTING. + METHODS char_fields FOR TESTING. + METHODS numeric_fields FOR TESTING. + METHODS date_fields FOR TESTING. +ENDCLASS. + + +CLASS {{p}}svc_job_hidden IMPLEMENTATION. + METHOD class_setup. + TRY. + go_job ?= cl_abap_typedescr=>describe_by_name( '{{P}}SVC_JOB' ). + gt_job = go_job->get_ddic_field_list( ). + CATCH cx_root. + CLEAR go_job. + CLEAR gt_job. + ENDTRY. + TRY. + go_base ?= cl_abap_typedescr=>describe_by_name( '{{P}}SVC_BASE' ). + gt_base = go_base->get_ddic_field_list( ). + CATCH cx_root. + CLEAR go_base. + CLEAR gt_base. + ENDTRY. + DELETE gt_job WHERE fieldname CP '.*'. + DELETE gt_base WHERE fieldname CP '.*'. + ENDMETHOD. + + METHOD assert_job_field. + DATA ls_field TYPE dfies. + cl_abap_unit_assert=>assert_bound( act = go_job + msg = 'Structure {{P}}SVC_JOB is not available' ). + READ TABLE gt_job INTO ls_field INDEX iv_index. + cl_abap_unit_assert=>assert_equals( + exp = iv_name + act = CONV string( ls_field-fieldname ) + msg = |Wrong field name at position { iv_index } of SVC_JOB| ). + cl_abap_unit_assert=>assert_equals( + exp = iv_type + act = CONV string( ls_field-datatype ) + msg = |Wrong data type of field { iv_name }| ). + cl_abap_unit_assert=>assert_equals( + exp = iv_leng + act = ls_field-leng + msg = |Wrong length of field { iv_name }| ). + cl_abap_unit_assert=>assert_equals( + exp = iv_dec + act = ls_field-decimals + msg = |Wrong number of decimals of field { iv_name }| ). + ENDMETHOD. + + METHOD assert_base_field. + DATA ls_field TYPE dfies. + cl_abap_unit_assert=>assert_bound( act = go_base + msg = 'Structure {{P}}SVC_BASE is not available' ). + READ TABLE gt_base INTO ls_field INDEX iv_index. + cl_abap_unit_assert=>assert_equals( + exp = iv_name + act = CONV string( ls_field-fieldname ) + msg = |Wrong field name at position { iv_index } of SVC_BASE| ). + cl_abap_unit_assert=>assert_equals( + exp = iv_type + act = CONV string( ls_field-datatype ) + msg = |Wrong data type of base field { iv_name }| ). + cl_abap_unit_assert=>assert_equals( + exp = iv_leng + act = ls_field-leng + msg = |Wrong length of base field { iv_name }| ). + cl_abap_unit_assert=>assert_equals( + exp = iv_dec + act = ls_field-decimals + msg = |Wrong number of decimals of base field { iv_name }| ). + ENDMETHOD. + + METHOD structure_exists. + DATA lo_descr TYPE REF TO cl_abap_typedescr. + TRY. + lo_descr = cl_abap_typedescr=>describe_by_name( '{{P}}SVC_JOB' ). + CATCH cx_root. + CLEAR lo_descr. + ENDTRY. + cl_abap_unit_assert=>assert_bound( act = lo_descr + msg = 'Structure {{P}}SVC_JOB does not exist' ). + ENDMETHOD. + + METHOD base_structure_exists. + DATA lo_descr TYPE REF TO cl_abap_typedescr. + TRY. + lo_descr = cl_abap_typedescr=>describe_by_name( '{{P}}SVC_BASE' ). + CATCH cx_root. + CLEAR lo_descr. + ENDTRY. + cl_abap_unit_assert=>assert_bound( act = lo_descr + msg = 'Structure {{P}}SVC_BASE does not exist' ). + ENDMETHOD. + + METHOD component_order. + cl_abap_unit_assert=>assert_bound( act = go_job + msg = 'Structure {{P}}SVC_JOB is not available' ). + cl_abap_unit_assert=>assert_equals( exp = 10 act = lines( gt_job ) + msg = 'Structure {{P}}SVC_JOB must have exactly 10 fields' ). + assert_job_field( iv_index = 1 iv_name = `CREATED_BY` iv_type = `CHAR` + iv_leng = 12 iv_dec = 0 ). + assert_job_field( iv_index = 2 iv_name = `CREATED_ON` iv_type = `DATS` + iv_leng = 8 iv_dec = 0 ). + assert_job_field( iv_index = 3 iv_name = `JOB_ID` iv_type = `CHAR` + iv_leng = 10 iv_dec = 0 ). + assert_job_field( iv_index = 4 iv_name = `WORK_HOURS` iv_type = `DEC` + iv_leng = 5 iv_dec = 2 ). + assert_job_field( iv_index = 5 iv_name = `CALC_MODE` iv_type = `CHAR` + iv_leng = 2 iv_dec = 0 ). + assert_job_field( iv_index = 6 iv_name = `ORDER_REF` iv_type = `CHAR` + iv_leng = 12 iv_dec = 0 ). + assert_job_field( iv_index = 7 iv_name = `SERVICE_DATE` iv_type = `DATS` + iv_leng = 8 iv_dec = 0 ). + assert_job_field( iv_index = 8 iv_name = `PART_COUNT` iv_type = `INT4` + iv_leng = 10 iv_dec = 0 ). + assert_job_field( iv_index = 9 iv_name = `GROUP_CODE` iv_type = `CHAR` + iv_leng = 4 iv_dec = 0 ). + assert_job_field( iv_index = 10 iv_name = `NET_VALUE` iv_type = `DEC` + iv_leng = 13 iv_dec = 2 ). + ENDMETHOD. + + METHOD base_component_order. + cl_abap_unit_assert=>assert_bound( act = go_base + msg = 'Structure {{P}}SVC_BASE is not available' ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( gt_base ) + msg = 'Structure {{P}}SVC_BASE must have exactly 2 fields' ). + assert_base_field( iv_index = 1 iv_name = `CREATED_BY` iv_type = `CHAR` + iv_leng = 12 iv_dec = 0 ). + assert_base_field( iv_index = 2 iv_name = `CREATED_ON` iv_type = `DATS` + iv_leng = 8 iv_dec = 0 ). + ENDMETHOD. + + METHOD base_created_by_type. + assert_base_field( iv_index = 1 iv_name = `CREATED_BY` iv_type = `CHAR` + iv_leng = 12 iv_dec = 0 ). + ENDMETHOD. + + METHOD base_created_on_type. + assert_base_field( iv_index = 2 iv_name = `CREATED_ON` iv_type = `DATS` + iv_leng = 8 iv_dec = 0 ). + ENDMETHOD. + + METHOD char_fields. + assert_job_field( iv_index = 3 iv_name = `JOB_ID` iv_type = `CHAR` + iv_leng = 10 iv_dec = 0 ). + assert_job_field( iv_index = 5 iv_name = `CALC_MODE` iv_type = `CHAR` + iv_leng = 2 iv_dec = 0 ). + assert_job_field( iv_index = 6 iv_name = `ORDER_REF` iv_type = `CHAR` + iv_leng = 12 iv_dec = 0 ). + assert_job_field( iv_index = 9 iv_name = `GROUP_CODE` iv_type = `CHAR` + iv_leng = 4 iv_dec = 0 ). + ENDMETHOD. + + METHOD numeric_fields. + assert_job_field( iv_index = 4 iv_name = `WORK_HOURS` iv_type = `DEC` + iv_leng = 5 iv_dec = 2 ). + assert_job_field( iv_index = 8 iv_name = `PART_COUNT` iv_type = `INT4` + iv_leng = 10 iv_dec = 0 ). + assert_job_field( iv_index = 10 iv_name = `NET_VALUE` iv_type = `DEC` + iv_leng = 13 iv_dec = 2 ). + ENDMETHOD. + + METHOD date_fields. + assert_job_field( iv_index = 7 iv_name = `SERVICE_DATE` iv_type = `DATS` + iv_leng = 8 iv_dec = 0 ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1947/mutation.json b/tasks_gen/train/G1947/mutation.json new file mode 100644 index 0000000..61fdf10 --- /dev/null +++ b/tasks_gen/train/G1947/mutation.json @@ -0,0 +1,57 @@ +{ + "task": "G1947", + "mutants": [ + { + "object": "{{P}}SVC_BASE", + "mutant": "line 4: abap.char(12) -> abap.numc(12) (type)", + "status": "killed", + "hidden": "7/9", + "failed_tests": [ + "BASE_COMPONENT_ORDER", + "BASE_CREATED_BY_TYPE" + ] + }, + { + "object": "{{P}}SVC_JOB", + "mutant": "line 4: abap.char(12) -> abap.numc(12) (type)", + "status": "killed", + "hidden": "8/9", + "failed_tests": [ + "COMPONENT_ORDER" + ] + }, + { + "object": "{{P}}SVC_BASE", + "mutant": "line 4: abap.char(12) -> abap.char(11) (length)", + "status": "killed", + "hidden": "7/9", + "failed_tests": [ + "BASE_COMPONENT_ORDER", + "BASE_CREATED_BY_TYPE" + ] + }, + { + "object": "{{P}}SVC_JOB", + "mutant": "line 5: abap.dats -> abap.tims (type)", + "status": "killed", + "hidden": "8/9", + "failed_tests": [ + "COMPONENT_ORDER" + ] + }, + { + "object": "{{P}}SVC_BASE", + "mutant": "line 5: abap.dats -> abap.tims (type)", + "status": "killed", + "hidden": "7/9", + "failed_tests": [ + "BASE_COMPONENT_ORDER", + "BASE_CREATED_ON_TYPE" + ] + } + ], + "valid": 5, + "killed": 5, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1947/reference/svc_base.ddls.asddls b/tasks_gen/train/G1947/reference/svc_base.ddls.asddls new file mode 100644 index 0000000..b13ea52 --- /dev/null +++ b/tasks_gen/train/G1947/reference/svc_base.ddls.asddls @@ -0,0 +1,6 @@ +@EndUserText.label : 'Service job base fields' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +define structure {{p}}svc_base { + created_by : abap.char(12); + created_on : abap.dats; +} diff --git a/tasks_gen/train/G1947/reference/svc_job.ddls.asddls b/tasks_gen/train/G1947/reference/svc_job.ddls.asddls new file mode 100644 index 0000000..6f9d1b8 --- /dev/null +++ b/tasks_gen/train/G1947/reference/svc_job.ddls.asddls @@ -0,0 +1,14 @@ +@EndUserText.label : 'Service job line type' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +define structure {{p}}svc_job { + created_by : abap.char(12); + created_on : abap.dats; + job_id : abap.char(10); + work_hours : abap.dec(5,2); + calc_mode : abap.char(2); + order_ref : abap.char(12); + service_date : abap.dats; + part_count : abap.int4; + group_code : abap.char(4); + net_value : abap.dec(13,2); +} diff --git a/tasks_gen/train/G1947/reference/svc_job_test.clas.abap b/tasks_gen/train/G1947/reference/svc_job_test.clas.abap new file mode 100644 index 0000000..3e0ac9b --- /dev/null +++ b/tasks_gen/train/G1947/reference/svc_job_test.clas.abap @@ -0,0 +1,55 @@ +CLASS {{p}}svc_job_test DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS structure_exists FOR TESTING. + METHODS field_count FOR TESTING. + METHODS net_value_type FOR TESTING. + METHODS base_created_by_type FOR TESTING. +ENDCLASS. + + +CLASS {{p}}svc_job_test IMPLEMENTATION. + METHOD structure_exists. + DATA lo_descr TYPE REF TO cl_abap_typedescr. + TRY. + lo_descr = cl_abap_typedescr=>describe_by_name( '{{P}}SVC_JOB' ). + CATCH cx_root. + CLEAR lo_descr. + ENDTRY. + cl_abap_unit_assert=>assert_bound( act = lo_descr ). + ENDMETHOD. + + METHOD field_count. + DATA lo_structdescr TYPE REF TO cl_abap_structdescr. + DATA lt_fields TYPE ddfields. + lo_structdescr ?= cl_abap_typedescr=>describe_by_name( '{{P}}SVC_JOB' ). + lt_fields = lo_structdescr->get_ddic_field_list( ). + DELETE lt_fields WHERE fieldname CP '.*'. + cl_abap_unit_assert=>assert_equals( exp = 10 act = lines( lt_fields ) ). + ENDMETHOD. + + METHOD net_value_type. + DATA lo_structdescr TYPE REF TO cl_abap_structdescr. + DATA lt_fields TYPE ddfields. + DATA ls_field TYPE dfies. + lo_structdescr ?= cl_abap_typedescr=>describe_by_name( '{{P}}SVC_JOB' ). + lt_fields = lo_structdescr->get_ddic_field_list( ). + READ TABLE lt_fields INTO ls_field WITH KEY fieldname = 'NET_VALUE'. + cl_abap_unit_assert=>assert_equals( exp = `DEC` + act = CONV string( ls_field-datatype ) ). + cl_abap_unit_assert=>assert_equals( exp = 13 act = ls_field-leng ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = ls_field-decimals ). + ENDMETHOD. + + METHOD base_created_by_type. + DATA lo_structdescr TYPE REF TO cl_abap_structdescr. + DATA lt_fields TYPE ddfields. + DATA ls_field TYPE dfies. + lo_structdescr ?= cl_abap_typedescr=>describe_by_name( '{{P}}SVC_BASE' ). + lt_fields = lo_structdescr->get_ddic_field_list( ). + READ TABLE lt_fields INTO ls_field WITH KEY fieldname = 'CREATED_BY'. + cl_abap_unit_assert=>assert_equals( exp = `CHAR` + act = CONV string( ls_field-datatype ) ). + cl_abap_unit_assert=>assert_equals( exp = 12 act = ls_field-leng ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1947/spec.md b/tasks_gen/train/G1947/spec.md new file mode 100644 index 0000000..7e86646 --- /dev/null +++ b/tasks_gen/train/G1947/spec.md @@ -0,0 +1,51 @@ +# 1. Goal +A service company records its service jobs. The company needs one reusable line +type for a service job. The line type is a DDIC structure. The company also +needs a small base structure for the audit fields of its business objects. + +# 2. Open questions +None. + +# 3. Context +- Several programs and one OData service use the service job line type. +- The line type is a DDIC structure. It is not a database table. +- The base structure is a DDIC structure too. +- The company keeps the audit fields in the base structure, so that all of its + business objects use the same audit fields. + +# 4. Contract +- Create the DDIC structure {{P}}SVC_BASE in package $TMP. +- Create the DDIC structure {{P}}SVC_JOB in package $TMP. +- Fields of {{P}}SVC_BASE, in this order: + - created_by : abap.char(12) + - created_on : abap.dats +- Fields of {{P}}SVC_JOB, in this order: + - created_by : abap.char(12) + - created_on : abap.dats + - job_id : abap.char(10) + - work_hours : abap.dec(5,2) + - calc_mode : abap.char(2) + - order_ref : abap.char(12) + - service_date : abap.dats + - part_count : abap.int4 + - group_code : abap.char(4) + - net_value : abap.dec(13,2) + +# 5. Business rules +1. {{P}}SVC_JOB has exactly the ten fields of the contract, in the given order. +2. The field names are the safe names of the contract. Do not use the words + hours, mode, order, date, count, group or value as a field name. +3. The data type and the length of every field are exactly as in the contract. +4. {{P}}SVC_BASE has exactly the two fields of the contract, in the given order. +5. The first two fields of {{P}}SVC_JOB have the same name, data type and length + as the two fields of {{P}}SVC_BASE. + +# 6. Constraints +- Release target: 8.16. +- Coding standards: Clean ABAP. +- Out of scope: do not create database tables. + +# 7. Acceptance +- The structures are active and have no syntax error. +- The hidden tests pass. +- Write ABAP Unit tests with RTTI in a global test class. diff --git a/tasks_gen/train/G1947/task.json b/tasks_gen/train/G1947/task.json new file mode 100644 index 0000000..2650f1b --- /dev/null +++ b/tasks_gen/train/G1947/task.json @@ -0,0 +1,69 @@ +{ + "id": "G1947", + "category": "B", + "object_type": "STRU", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [], + "contract": [ + { + "type": "STRU", + "name": "{{P}}SVC_BASE", + "fields": [ + "created_by", + "created_on" + ] + }, + { + "type": "STRU", + "name": "{{P}}SVC_JOB", + "fields": [ + "created_by", + "created_on", + "job_id", + "work_hours", + "calc_mode", + "order_ref", + "service_date", + "part_count", + "group_code", + "net_value" + ] + } + ], + "out_of_scope": [], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}SVC_JOB_HIDDEN", + "file": "hidden/svc_job_hidden.clas.abap", + "description": "Hidden RTTI tests for the service job structures" + } + ], + "reference": [ + { + "type": "STRU", + "name": "{{P}}SVC_BASE", + "file": "reference/svc_base.ddls.asddls", + "description": "Base structure with the audit fields" + }, + { + "type": "STRU", + "name": "{{P}}SVC_JOB", + "file": "reference/svc_job.ddls.asddls", + "description": "Service job line type" + }, + { + "type": "CLAS", + "name": "{{P}}SVC_JOB_TEST", + "file": "reference/svc_job_test.clas.abap", + "description": "Own RTTI tests for the structures" + } + ], + "craft_checks": [] +} \ No newline at end of file diff --git a/tasks_gen/train/G1948/generation.json b/tasks_gen/train/G1948/generation.json new file mode 100644 index 0000000..fd3e94d --- /dev/null +++ b/tasks_gen/train/G1948/generation.json @@ -0,0 +1,29 @@ +{ + "id": "G1948", + "pool": "train", + "object_type": "MSAG", + "category": "D", + "attempts": [ + { + "stage": "bundle", + "errors": [ + "Too close to task G0137 (similarity spec 0.35, rules 0.19, names 1.00). Choose a different business topic and different object names.", + "Too close to task G1902 (similarity spec 0.68, rules 0.61, names 1.00). Choose a different business topic and different object names." + ], + "by_check": { + "extra": 2 + } + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 4, + "killed": 4, + "ok": true + } + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1948/hidden/t_arc_hidden.clas.abap b/tasks_gen/train/G1948/hidden/t_arc_hidden.clas.abap new file mode 100644 index 0000000..3d57f6b --- /dev/null +++ b/tasks_gen/train/G1948/hidden/t_arc_hidden.clas.abap @@ -0,0 +1,107 @@ +CLASS {{p}}t_arc_hidden DEFINITION + PUBLIC + FINAL + CREATE PUBLIC + FOR TESTING + DURATION SHORT + RISK LEVEL HARMLESS. + + PRIVATE SECTION. + METHODS text_of + IMPORTING iv_type TYPE symsgty + iv_msgno TYPE symsgno + iv_value1 TYPE string + iv_value2 TYPE string + RETURNING VALUE(rv_text) TYPE string. + + METHODS msg_001_text FOR TESTING. + METHODS msg_002_text FOR TESTING. + METHODS msg_003_text FOR TESTING. + METHODS msg_004_text FOR TESTING. + METHODS replaces_placeholders FOR TESTING. + METHODS exception_text FOR TESTING. + METHODS exception_message_id FOR TESTING. + METHODS exception_keeps_values FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t_arc_hidden IMPLEMENTATION. + + METHOD text_of. + MESSAGE ID '{{P}}MSG_ARC' TYPE iv_type NUMBER iv_msgno + WITH iv_value1 iv_value2 INTO rv_text. + ENDMETHOD. + + METHOD msg_001_text. + cl_abap_unit_assert=>assert_equals( + exp = `Archer Robin is not licensed for bow class recurve` + act = text_of( iv_type = 'E' iv_msgno = '001' + iv_value1 = 'Robin' iv_value2 = 'recurve' ) ). + ENDMETHOD. + + METHOD msg_002_text. + cl_abap_unit_assert=>assert_equals( + exp = `Arrows 4 are below the minimum of 12` + act = text_of( iv_type = 'E' iv_msgno = '002' + iv_value1 = '4' iv_value2 = '12' ) ). + ENDMETHOD. + + METHOD msg_003_text. + cl_abap_unit_assert=>assert_equals( + exp = `Group of 9 archers exceeds the range limit of 6` + act = text_of( iv_type = 'W' iv_msgno = '003' + iv_value1 = '9' iv_value2 = '6' ) ). + ENDMETHOD. + + METHOD msg_004_text. + cl_abap_unit_assert=>assert_equals( + exp = `Booking B-2048 is confirmed for 5 archers` + act = text_of( iv_type = 'I' iv_msgno = '004' + iv_value1 = 'B-2048' iv_value2 = '5' ) ). + ENDMETHOD. + + METHOD replaces_placeholders. + cl_abap_unit_assert=>assert_equals( + exp = `Archer Kim is not licensed for bow class longbow` + act = text_of( iv_type = 'E' iv_msgno = '001' + iv_value1 = 'Kim' iv_value2 = 'longbow' ) ). + ENDMETHOD. + + METHOD exception_text. + DATA(lo_error) = NEW {{p}}cx_bow_check( + iv_msgno = '001' + iv_value1 = 'Robin' + iv_value2 = 'recurve' ). + + cl_abap_unit_assert=>assert_equals( + exp = `Archer Robin is not licensed for bow class recurve` + act = lo_error->get_message_text( ) ). + ENDMETHOD. + + METHOD exception_message_id. + DATA(lo_error) = NEW {{p}}cx_bow_check( + iv_msgno = '002' + iv_value1 = '4' + iv_value2 = '12' ). + + DATA(lo_message) = CAST if_t100_message( lo_error ). + + cl_abap_unit_assert=>assert_equals( + exp = CONV symsgid( '{{P}}MSG_ARC' ) + act = lo_message->t100key-msgid ). + cl_abap_unit_assert=>assert_equals( + exp = '002' + act = lo_message->t100key-msgno ). + ENDMETHOD. + + METHOD exception_keeps_values. + DATA(lo_error) = NEW {{p}}cx_bow_check( + iv_msgno = '003' + iv_value1 = '9' + iv_value2 = '6' ). + + cl_abap_unit_assert=>assert_equals( exp = `9` act = lo_error->value1 ). + cl_abap_unit_assert=>assert_equals( exp = `6` act = lo_error->value2 ). + ENDMETHOD. + +ENDCLASS. diff --git a/tasks_gen/train/G1948/mutation.json b/tasks_gen/train/G1948/mutation.json new file mode 100644 index 0000000..6a7a9e0 --- /dev/null +++ b/tasks_gen/train/G1948/mutation.json @@ -0,0 +1,52 @@ +{ + "task": "G1948", + "mutants": [ + { + "object": "{{P}}MSG_ARC", + "mutant": "message 001: number + 50 (number)", + "status": "invalid", + "hidden": "0/0", + "failed_tests": [] + }, + { + "object": "{{P}}MSG_ARC", + "mutant": "message 002: text + ' x' (text)", + "status": "killed", + "hidden": "7/8", + "failed_tests": [ + "MSG_002_TEXT" + ] + }, + { + "object": "{{P}}MSG_ARC", + "mutant": "message 004: text + ' x' (text)", + "status": "killed", + "hidden": "7/8", + "failed_tests": [ + "MSG_004_TEXT" + ] + }, + { + "object": "{{P}}MSG_ARC", + "mutant": "message 004: &1 -> &2 (placeholder)", + "status": "killed", + "hidden": "7/8", + "failed_tests": [ + "MSG_004_TEXT" + ] + }, + { + "object": "{{P}}MSG_ARC", + "mutant": "message 002: &1 -> &2 (placeholder)", + "status": "killed", + "hidden": "7/8", + "failed_tests": [ + "MSG_002_TEXT" + ] + } + ], + "valid": 4, + "killed": 4, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1948/reference/cx_bow_check.clas.abap b/tasks_gen/train/G1948/reference/cx_bow_check.clas.abap new file mode 100644 index 0000000..8c3b662 --- /dev/null +++ b/tasks_gen/train/G1948/reference/cx_bow_check.clas.abap @@ -0,0 +1,48 @@ +CLASS {{p}}cx_bow_check DEFINITION + PUBLIC + INHERITING FROM cx_static_check + FINAL + CREATE PUBLIC. + + PUBLIC SECTION. + INTERFACES if_t100_message. + + METHODS constructor + IMPORTING + iv_msgno TYPE symsgno + iv_value1 TYPE string + iv_value2 TYPE string. + + METHODS get_message_text + RETURNING VALUE(rv_text) TYPE string. + + DATA value1 TYPE string READ-ONLY. + DATA value2 TYPE string READ-ONLY. + + PROTECTED SECTION. + PRIVATE SECTION. + DATA mv_msgno TYPE symsgno. +ENDCLASS. + + +CLASS {{p}}cx_bow_check IMPLEMENTATION. + + METHOD constructor. + super->constructor( ). + + mv_msgno = iv_msgno. + value1 = iv_value1. + value2 = iv_value2. + + if_t100_message~t100key-msgid = '{{P}}MSG_ARC'. + if_t100_message~t100key-msgno = iv_msgno. + if_t100_message~t100key-attr1 = 'VALUE1'. + if_t100_message~t100key-attr2 = 'VALUE2'. + ENDMETHOD. + + METHOD get_message_text. + MESSAGE ID '{{P}}MSG_ARC' TYPE 'E' NUMBER mv_msgno + WITH value1 value2 INTO rv_text. + ENDMETHOD. + +ENDCLASS. diff --git a/tasks_gen/train/G1948/reference/t_arc_msg.clas.abap b/tasks_gen/train/G1948/reference/t_arc_msg.clas.abap new file mode 100644 index 0000000..bb728b6 --- /dev/null +++ b/tasks_gen/train/G1948/reference/t_arc_msg.clas.abap @@ -0,0 +1,71 @@ +CLASS {{p}}t_arc_msg DEFINITION + PUBLIC + FINAL + CREATE PUBLIC + FOR TESTING + DURATION SHORT + RISK LEVEL HARMLESS. + + PRIVATE SECTION. + METHODS text_of + IMPORTING iv_type TYPE symsgty + iv_msgno TYPE symsgno + iv_value1 TYPE string + iv_value2 TYPE string + RETURNING VALUE(rv_text) TYPE string. + + METHODS msg_001 FOR TESTING. + METHODS msg_002 FOR TESTING. + METHODS msg_003 FOR TESTING. + METHODS msg_004 FOR TESTING. + METHODS exception_text FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t_arc_msg IMPLEMENTATION. + + METHOD text_of. + MESSAGE ID '{{P}}MSG_ARC' TYPE iv_type NUMBER iv_msgno + WITH iv_value1 iv_value2 INTO rv_text. + ENDMETHOD. + + METHOD msg_001. + cl_abap_unit_assert=>assert_equals( + exp = `Archer Robin is not licensed for bow class recurve` + act = text_of( iv_type = 'E' iv_msgno = '001' + iv_value1 = 'Robin' iv_value2 = 'recurve' ) ). + ENDMETHOD. + + METHOD msg_002. + cl_abap_unit_assert=>assert_equals( + exp = `Arrows 4 are below the minimum of 12` + act = text_of( iv_type = 'E' iv_msgno = '002' + iv_value1 = '4' iv_value2 = '12' ) ). + ENDMETHOD. + + METHOD msg_003. + cl_abap_unit_assert=>assert_equals( + exp = `Group of 9 archers exceeds the range limit of 6` + act = text_of( iv_type = 'W' iv_msgno = '003' + iv_value1 = '9' iv_value2 = '6' ) ). + ENDMETHOD. + + METHOD msg_004. + cl_abap_unit_assert=>assert_equals( + exp = `Booking B-2048 is confirmed for 5 archers` + act = text_of( iv_type = 'I' iv_msgno = '004' + iv_value1 = 'B-2048' iv_value2 = '5' ) ). + ENDMETHOD. + + METHOD exception_text. + DATA(lo_error) = NEW {{p}}cx_bow_check( + iv_msgno = '004' + iv_value1 = 'B-2048' + iv_value2 = '5' ). + + cl_abap_unit_assert=>assert_equals( + exp = `Booking B-2048 is confirmed for 5 archers` + act = lo_error->get_message_text( ) ). + ENDMETHOD. + +ENDCLASS. diff --git a/tasks_gen/train/G1948/spec.md b/tasks_gen/train/G1948/spec.md new file mode 100644 index 0000000..1d4ebe0 --- /dev/null +++ b/tasks_gen/train/G1948/spec.md @@ -0,0 +1,58 @@ +# 1. Goal +The archery club "Green Quiver" checks a range booking before it confirms the +shooting session. The club keeps all its messages in one message class. The club +also needs a class-based exception that carries one of these messages, so that +the caller of the range check can handle a rejection. + +# 2. Open questions +None. + +# 3. Context +- All objects are in package $TMP. +- The club keeps all its messages in one message class. +- Every message of the club has at most two placeholders. +- The range check raises the exception with the message that describes the + rejection. + +# 4. Contract +- Create the message class {{P}}MSG_ARC in package $TMP. It contains the + messages 001, 002, 003 and 004. +- Create the exception class {{P}}CX_BOW_CHECK in package $TMP. +- The class is public and final. It inherits from CX_STATIC_CHECK. +- The class implements the interface IF_T100_MESSAGE. +- The class has a public constructor with these importing parameters: + - iv_msgno TYPE symsgno + - iv_value1 TYPE string + - iv_value2 TYPE string +- The class has the public read-only attributes value1 and value2, both of type + string. The constructor copies iv_value1 to value1 and iv_value2 to value2. +- The method get_message_text( ) returns the text of the message with the number + iv_msgno of the message class {{P}}MSG_ARC. In this text, &1 is replaced by + iv_value1 and &2 is replaced by iv_value2. + +# 5. Business rules +1. Message 001 is an error message. The range check uses it when the archer is + not licensed for the planned bow class. Its text is + "Archer &1 is not licensed for bow class &2". &1 is the name of the archer. + &2 is the bow class. +2. Message 002 is an error message. The range check uses it when too few arrows + are available. Its text is "Arrows &1 are below the minimum of &2". &1 is + the number of arrows. &2 is the minimum number of arrows. +3. Message 003 is a warning message. The range check uses it when the group is + too large. Its text is "Group of &1 archers exceeds the range limit of &2". + &1 is the group size. &2 is the limit of the range. +4. Message 004 is an information message. The range check uses it when the + booking is confirmed. Its text is "Booking &1 is confirmed for &2 archers". + &1 is the booking number. &2 is the number of archers. + +# 6. Constraints +- Release target: 8.16. +- Use clean ABAP. Keep every method below 40 statements. +- Out of scope: do not create or change other objects. + +# 7. Acceptance +- The message class {{P}}MSG_ARC is active and contains the messages 001 to 004. +- The class {{P}}CX_BOW_CHECK is active and has no syntax error. +- The hidden tests pass. +- Write ABAP Unit tests for the messages and for the exception class in a global + test class. diff --git a/tasks_gen/train/G1948/task.json b/tasks_gen/train/G1948/task.json new file mode 100644 index 0000000..ab1a211 --- /dev/null +++ b/tasks_gen/train/G1948/task.json @@ -0,0 +1,90 @@ +{ + "id": "G1948", + "category": "D", + "object_type": "MSAG", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [], + "contract": [ + { + "type": "MSAG", + "name": "{{P}}MSG_ARC", + "messages": [ + { + "msgno": "001" + }, + { + "msgno": "002" + }, + { + "msgno": "003" + }, + { + "msgno": "004" + } + ] + }, + { + "type": "CLAS", + "name": "{{P}}CX_BOW_CHECK", + "implements": [ + "IF_T100_MESSAGE" + ], + "description": "Exception class that carries a message of the message class {{P}}MSG_ARC" + } + ], + "out_of_scope": [], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T_ARC_HIDDEN", + "file": "hidden/t_arc_hidden.clas.abap", + "description": "Hidden tests for the messages and the exception class" + } + ], + "reference": [ + { + "type": "MSAG", + "name": "{{P}}MSG_ARC", + "description": "Messages of the archery club Green Quiver", + "messages": [ + { + "msgno": "001", + "text": "Archer &1 is not licensed for bow class &2" + }, + { + "msgno": "002", + "text": "Arrows &1 are below the minimum of &2" + }, + { + "msgno": "003", + "text": "Group of &1 archers exceeds the range limit of &2" + }, + { + "msgno": "004", + "text": "Booking &1 is confirmed for &2 archers" + } + ] + }, + { + "type": "CLAS", + "name": "{{P}}CX_BOW_CHECK", + "file": "reference/cx_bow_check.clas.abap", + "description": "Exception class that carries a message of the message class {{P}}MSG_ARC" + }, + { + "type": "CLAS", + "name": "{{P}}T_ARC_MSG", + "file": "reference/t_arc_msg.clas.abap", + "description": "Own ABAP Unit tests for the messages and the exception class" + } + ], + "craft_checks": [ + "method_length" + ] +} \ No newline at end of file diff --git a/tasks_gen/train/G1949/faulty/m0_i_hawk_site.ddls.asddls b/tasks_gen/train/G1949/faulty/m0_i_hawk_site.ddls.asddls new file mode 100644 index 0000000..c2c1061 --- /dev/null +++ b/tasks_gen/train/G1949/faulty/m0_i_hawk_site.ddls.asddls @@ -0,0 +1,13 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Falconry deployments per site' +define view entity {{P}}I_HAWK_SITE + as select from {{p}}falcon +{ + key site as site, + count( * ) as deployments, + max( flight_min ) as total_minutes, + sum( birds ) as total_birds, + sum( cast( flight_min as abap.dec( 10, 0 ) ) * fee_per_min ) as total_fee +} +where flight_min > 0 +group by site diff --git a/tasks_gen/train/G1949/faulty/m1_i_hawk_site.ddls.asddls b/tasks_gen/train/G1949/faulty/m1_i_hawk_site.ddls.asddls new file mode 100644 index 0000000..c788e33 --- /dev/null +++ b/tasks_gen/train/G1949/faulty/m1_i_hawk_site.ddls.asddls @@ -0,0 +1,13 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Falconry deployments per site' +define view entity {{P}}I_HAWK_SITE + as select from {{p}}falcon +{ + key site as site, + count( * ) as deployments, + sum( flight_min ) as total_minutes, + max( birds ) as total_birds, + sum( cast( flight_min as abap.dec( 10, 0 ) ) * fee_per_min ) as total_fee +} +where flight_min > 0 +group by site diff --git a/tasks_gen/train/G1949/faulty/m2_i_hawk_site.ddls.asddls b/tasks_gen/train/G1949/faulty/m2_i_hawk_site.ddls.asddls new file mode 100644 index 0000000..a77bce3 --- /dev/null +++ b/tasks_gen/train/G1949/faulty/m2_i_hawk_site.ddls.asddls @@ -0,0 +1,13 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Falconry deployments per site' +define view entity {{P}}I_HAWK_SITE + as select from {{p}}falcon +{ + key site as site, + count( * ) as deployments, + sum( flight_min ) as total_minutes, + sum( birds ) as total_birds, + max( cast( flight_min as abap.dec( 10, 0 ) ) * fee_per_min ) as total_fee +} +where flight_min > 0 +group by site diff --git a/tasks_gen/train/G1949/faulty/m3_i_hawk_site.ddls.asddls b/tasks_gen/train/G1949/faulty/m3_i_hawk_site.ddls.asddls new file mode 100644 index 0000000..7ac24db --- /dev/null +++ b/tasks_gen/train/G1949/faulty/m3_i_hawk_site.ddls.asddls @@ -0,0 +1,13 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Falconry deployments per site' +define view entity {{P}}I_HAWK_SITE + as select from {{p}}falcon +{ + key site as site, + count( * ) as deployments, + sum( flight_min ) as total_minutes, + sum( birds ) as total_birds, + sum( cast( flight_min as abap.dec( 10, 0 ) ) * fee_per_min ) as total_fee +} +where flight_min <= 0 +group by site diff --git a/tasks_gen/train/G1949/generation.json b/tasks_gen/train/G1949/generation.json new file mode 100644 index 0000000..994f711 --- /dev/null +++ b/tasks_gen/train/G1949/generation.json @@ -0,0 +1,28 @@ +{ + "id": "G1949", + "pool": "train", + "object_type": "DDLS", + "category": "F", + "attempts": [ + { + "stage": "bundle", + "errors": [ + "seed/falcon.tabl.asabap: field name minutes is a reserved word; choose another name" + ], + "by_check": { + "static": 1 + } + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 4, + "killed": 4, + "ok": true + } + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1949/hidden/t42_hidden.clas.abap b/tasks_gen/train/G1949/hidden/t42_hidden.clas.abap new file mode 100644 index 0000000..3d4b1ba --- /dev/null +++ b/tasks_gen/train/G1949/hidden/t42_hidden.clas.abap @@ -0,0 +1,86 @@ +CLASS {{p}}t42_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 row_count FOR TESTING. + METHODS north_deployments FOR TESTING. + METHODS north_minutes FOR TESTING. + METHODS north_birds FOR TESTING. + METHODS north_fee FOR TESTING. + METHODS south_totals FOR TESTING. + METHODS east_not_shown FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t42_hidden IMPLEMENTATION. + METHOD class_setup. + go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_HAWK_SITE' ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + DATA lt_falcon TYPE STANDARD TABLE OF {{p}}falcon WITH EMPTY KEY. + go_env->clear_doubles( ). + lt_falcon = VALUE #( + ( deploy_id = 1 site = 'NORTH' deploy_date = '20240101' flight_min = 30 birds = 2 fee_per_min = '4.00' ) + ( deploy_id = 2 site = 'NORTH' deploy_date = '20240102' flight_min = 20 birds = 1 fee_per_min = '5.00' ) + ( deploy_id = 3 site = 'SOUTH' deploy_date = '20240103' flight_min = 10 birds = 3 fee_per_min = '6.00' ) + ( deploy_id = 4 site = 'SOUTH' deploy_date = '20240104' flight_min = 0 birds = 1 fee_per_min = '9.00' ) + ( deploy_id = 5 site = 'EAST' deploy_date = '20240105' flight_min = 0 birds = 2 fee_per_min = '9.00' ) ). + go_env->insert_test_data( lt_falcon ). + ENDMETHOD. + + METHOD row_count. + SELECT COUNT(*) FROM {{p}}i_hawk_site INTO @DATA(lv_rows). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lv_rows ). + ENDMETHOD. + + METHOD north_deployments. + SELECT SINGLE deployments FROM {{p}}i_hawk_site + WHERE site = 'NORTH' INTO @DATA(lv_deployments). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lv_deployments ). + ENDMETHOD. + + METHOD north_minutes. + SELECT SINGLE total_minutes FROM {{p}}i_hawk_site + WHERE site = 'NORTH' INTO @DATA(lv_minutes). + cl_abap_unit_assert=>assert_equals( exp = 50 act = lv_minutes ). + ENDMETHOD. + + METHOD north_birds. + SELECT SINGLE total_birds FROM {{p}}i_hawk_site + WHERE site = 'NORTH' INTO @DATA(lv_birds). + cl_abap_unit_assert=>assert_equals( exp = 3 act = lv_birds ). + ENDMETHOD. + + METHOD north_fee. + SELECT SINGLE total_fee FROM {{p}}i_hawk_site + WHERE site = 'NORTH' INTO @DATA(lv_fee). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '220.00' ) + act = CONV decfloat34( lv_fee ) ). + ENDMETHOD. + + METHOD south_totals. + SELECT SINGLE deployments, total_minutes, total_birds, total_fee + FROM {{p}}i_hawk_site + WHERE site = 'SOUTH' + INTO @DATA(ls_row). + cl_abap_unit_assert=>assert_equals( exp = 1 act = ls_row-deployments ). + cl_abap_unit_assert=>assert_equals( exp = 10 act = ls_row-total_minutes ). + cl_abap_unit_assert=>assert_equals( exp = 3 act = ls_row-total_birds ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '60.00' ) + act = CONV decfloat34( ls_row-total_fee ) ). + ENDMETHOD. + + METHOD east_not_shown. + SELECT COUNT(*) FROM {{p}}i_hawk_site + WHERE site = 'EAST' INTO @DATA(lv_rows). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_rows ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1949/mutation.json b/tasks_gen/train/G1949/mutation.json new file mode 100644 index 0000000..1f8c993 --- /dev/null +++ b/tasks_gen/train/G1949/mutation.json @@ -0,0 +1,50 @@ +{ + "task": "G1949", + "mutants": [ + { + "object": "{{P}}I_HAWK_SITE", + "mutant": "line 8: sum( -> max( (agg)", + "status": "killed", + "hidden": "6/7", + "failed_tests": [ + "NORTH_MINUTES" + ] + }, + { + "object": "{{P}}I_HAWK_SITE", + "mutant": "line 9: sum( -> max( (agg)", + "status": "killed", + "hidden": "6/7", + "failed_tests": [ + "NORTH_BIRDS" + ] + }, + { + "object": "{{P}}I_HAWK_SITE", + "mutant": "line 10: sum( -> max( (agg)", + "status": "killed", + "hidden": "6/7", + "failed_tests": [ + "NORTH_FEE" + ] + }, + { + "object": "{{P}}I_HAWK_SITE", + "mutant": "line 12: > -> <= (rel)", + "status": "killed", + "hidden": "1/7", + "failed_tests": [ + "EAST_NOT_SHOWN", + "NORTH_BIRDS", + "NORTH_DEPLOYMENTS", + "NORTH_FEE", + "NORTH_MINUTES", + "SOUTH_TOTALS" + ] + } + ], + "valid": 4, + "killed": 4, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1949/reference/i_hawk_site.ddls.asddls b/tasks_gen/train/G1949/reference/i_hawk_site.ddls.asddls new file mode 100644 index 0000000..20ce70e --- /dev/null +++ b/tasks_gen/train/G1949/reference/i_hawk_site.ddls.asddls @@ -0,0 +1,13 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Falconry deployments per site' +define view entity {{P}}I_HAWK_SITE + as select from {{p}}falcon +{ + key site as site, + count( * ) as deployments, + sum( flight_min ) as total_minutes, + sum( birds ) as total_birds, + sum( cast( flight_min as abap.dec( 10, 0 ) ) * fee_per_min ) as total_fee +} +where flight_min > 0 +group by site diff --git a/tasks_gen/train/G1949/reference/t42_test.clas.abap b/tasks_gen/train/G1949/reference/t42_test.clas.abap new file mode 100644 index 0000000..1a49ec9 --- /dev/null +++ b/tasks_gen/train/G1949/reference/t42_test.clas.abap @@ -0,0 +1,48 @@ +CLASS {{p}}t42_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_site FOR TESTING. + METHODS cancelled_not_counted FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t42_test IMPLEMENTATION. + METHOD class_setup. + go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_HAWK_SITE' ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + DATA lt_falcon TYPE STANDARD TABLE OF {{p}}falcon WITH EMPTY KEY. + go_env->clear_doubles( ). + lt_falcon = VALUE #( + ( deploy_id = 1 site = 'A' deploy_date = '20240101' flight_min = 5 birds = 1 fee_per_min = '2.00' ) + ( deploy_id = 2 site = 'A' deploy_date = '20240102' flight_min = 15 birds = 2 fee_per_min = '1.00' ) + ( deploy_id = 3 site = 'A' deploy_date = '20240103' flight_min = 0 birds = 4 fee_per_min = '9.00' ) ). + go_env->insert_test_data( lt_falcon ). + ENDMETHOD. + + METHOD totals_of_one_site. + SELECT SINGLE deployments, total_minutes, total_birds, total_fee + FROM {{p}}i_hawk_site + WHERE site = 'A' + INTO @DATA(ls_row). + cl_abap_unit_assert=>assert_equals( exp = 2 act = ls_row-deployments ). + cl_abap_unit_assert=>assert_equals( exp = 20 act = ls_row-total_minutes ). + cl_abap_unit_assert=>assert_equals( exp = 3 act = ls_row-total_birds ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '25.00' ) + act = CONV decfloat34( ls_row-total_fee ) ). + ENDMETHOD. + + METHOD cancelled_not_counted. + SELECT COUNT(*) FROM {{p}}i_hawk_site INTO @DATA(lv_rows). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lv_rows ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1949/seed/falcon.tabl.asabap b/tasks_gen/train/G1949/seed/falcon.tabl.asabap new file mode 100644 index 0000000..3caa17f --- /dev/null +++ b/tasks_gen/train/G1949/seed/falcon.tabl.asabap @@ -0,0 +1,14 @@ +@EndUserText.label : 'Falconry deployment log' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}falcon { + key client : abap.clnt not null; + key deploy_id : abap.int4 not null; + site : abap.char(10); + deploy_date : abap.dats; + flight_min : abap.int4; + birds : abap.int4; + fee_per_min : abap.dec(15,2); +} diff --git a/tasks_gen/train/G1949/spec.md b/tasks_gen/train/G1949/spec.md new file mode 100644 index 0000000..9c4abe4 --- /dev/null +++ b/tasks_gen/train/G1949/spec.md @@ -0,0 +1,54 @@ +# 1. Goal +A falconry company sends birds of prey to airfields. The birds scare other +birds away from the runways. The company needs one row for each site with the +work that the birds did there. A dashboard and an OData service read this data. +The calculation must be in the database, in a CDS view. + +# 2. Open questions +None. + +# 3. Context +- Table {{P}}FALCON (deployment log), package $TMP. The table is active. This + specification does not list the columns of the table. Read the table + definition to find the column names. +- One row of {{P}}FALCON is one deployment of a bird of prey at a site. The + table stores these values for a deployment: + - the site, + - the date of the deployment, + - the number of flight minutes, + - the number of birds that flew, + - the fee for one flight minute. + +# 4. Contract +- Create the CDS view entity {{P}}I_HAWK_SITE in package $TMP. +- Elements, with these names: + - SITE (key) + - DEPLOYMENTS + - TOTAL_MINUTES + - TOTAL_BIRDS + - TOTAL_FEE +- No authorization check (#NOT_REQUIRED). + +# 5. Business rules +1. Show one row for each site that has at least one valid deployment. +2. A deployment with zero flight minutes is cancelled. A cancelled deployment + must not appear in the view and must not count in any element. +3. DEPLOYMENTS is the number of valid deployments of the site. +4. TOTAL_MINUTES is the sum of the flight minutes of the valid deployments of + the site. +5. TOTAL_BIRDS is the sum of the birds that flew in the valid deployments of + the site. +6. TOTAL_FEE is the sum of the fees of the valid deployments of the site. The + fee of one deployment is the number of flight minutes multiplied by the fee + for one flight minute. The result has 2 decimals. + +# 6. Constraints +- Release target: SAP_BASIS 8.16 (ABAP Platform 2025). +- Use "define view entity". +- Out of scope: do not change {{P}}FALCON. +- Do not use SAP application module data. + +# 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. diff --git a/tasks_gen/train/G1949/task.json b/tasks_gen/train/G1949/task.json new file mode 100644 index 0000000..0d4d17d --- /dev/null +++ b/tasks_gen/train/G1949/task.json @@ -0,0 +1,59 @@ +{ + "id": "G1949", + "category": "F", + "object_type": "DDLS", + "difficulty": 3, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 70, + "max_activations": 18 + }, + "seed": [ + { + "type": "TABL", + "name": "{{P}}FALCON", + "file": "seed/falcon.tabl.asabap", + "description": "Falconry deployment log" + } + ], + "contract": [ + { + "type": "DDLS", + "name": "{{P}}I_HAWK_SITE", + "fields": [ + "SITE", + "DEPLOYMENTS", + "TOTAL_MINUTES", + "TOTAL_BIRDS", + "TOTAL_FEE" + ] + } + ], + "out_of_scope": [ + "{{P}}FALCON" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T42_HIDDEN", + "file": "hidden/t42_hidden.clas.abap", + "description": "T42 hidden tests" + } + ], + "reference": [ + { + "type": "DDLS", + "name": "{{P}}I_HAWK_SITE", + "file": "reference/i_hawk_site.ddls.asddls", + "description": "Deployments per site" + }, + { + "type": "CLAS", + "name": "{{P}}T42_TEST", + "file": "reference/t42_test.clas.abap", + "description": "T42 own tests" + } + ], + "craft_checks": [] +} \ No newline at end of file diff --git a/tasks_gen/train/G1950/faulty/m0_i_product_quality.ddls.asddls b/tasks_gen/train/G1950/faulty/m0_i_product_quality.ddls.asddls new file mode 100644 index 0000000..8f2be9e --- /dev/null +++ b/tasks_gen/train/G1950/faulty/m0_i_product_quality.ddls.asddls @@ -0,0 +1,15 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Product quality totals' +define view entity {{P}}I_PRODUCT_QUALITY + as select from {{p}}i_batch_quality +{ + key product as product, + count( * ) as batch_count, + max( bars_total ) as bars_total, + sum( bars_good ) as bars_good, + sum( bars_scrap ) as bars_scrap, + cast( cast( sum( bars_good ) as abap.dec(15,2) ) * 100 + / cast( sum( bars_total ) as abap.dec(15,2) ) + as abap.dec(5,2) ) as yield_pct +} +group by product diff --git a/tasks_gen/train/G1950/faulty/m1_i_product_quality.ddls.asddls b/tasks_gen/train/G1950/faulty/m1_i_product_quality.ddls.asddls new file mode 100644 index 0000000..1a55bda --- /dev/null +++ b/tasks_gen/train/G1950/faulty/m1_i_product_quality.ddls.asddls @@ -0,0 +1,15 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Product quality totals' +define view entity {{P}}I_PRODUCT_QUALITY + as select from {{p}}i_batch_quality +{ + key product as product, + count( * ) as batch_count, + sum( bars_total ) as bars_total, + max( bars_good ) as bars_good, + sum( bars_scrap ) as bars_scrap, + cast( cast( sum( bars_good ) as abap.dec(15,2) ) * 100 + / cast( sum( bars_total ) as abap.dec(15,2) ) + as abap.dec(5,2) ) as yield_pct +} +group by product diff --git a/tasks_gen/train/G1950/faulty/m2_i_product_quality.ddls.asddls b/tasks_gen/train/G1950/faulty/m2_i_product_quality.ddls.asddls new file mode 100644 index 0000000..be88400 --- /dev/null +++ b/tasks_gen/train/G1950/faulty/m2_i_product_quality.ddls.asddls @@ -0,0 +1,15 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Product quality totals' +define view entity {{P}}I_PRODUCT_QUALITY + as select from {{p}}i_batch_quality +{ + key product as product, + count( * ) as batch_count, + sum( bars_total ) as bars_total, + sum( bars_good ) as bars_good, + max( bars_scrap ) as bars_scrap, + cast( cast( sum( bars_good ) as abap.dec(15,2) ) * 100 + / cast( sum( bars_total ) as abap.dec(15,2) ) + as abap.dec(5,2) ) as yield_pct +} +group by product diff --git a/tasks_gen/train/G1950/faulty/m3_i_product_quality.ddls.asddls b/tasks_gen/train/G1950/faulty/m3_i_product_quality.ddls.asddls new file mode 100644 index 0000000..6f6d9be --- /dev/null +++ b/tasks_gen/train/G1950/faulty/m3_i_product_quality.ddls.asddls @@ -0,0 +1,15 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Product quality totals' +define view entity {{P}}I_PRODUCT_QUALITY + as select from {{p}}i_batch_quality +{ + key product as product, + count( * ) as batch_count, + sum( bars_total ) as bars_total, + sum( bars_good ) as bars_good, + sum( bars_scrap ) as bars_scrap, + cast( cast( max( bars_good ) as abap.dec(15,2) ) * 100 + / cast( sum( bars_total ) as abap.dec(15,2) ) + as abap.dec(5,2) ) as yield_pct +} +group by product diff --git a/tasks_gen/train/G1950/faulty/m4_i_product_quality.ddls.asddls b/tasks_gen/train/G1950/faulty/m4_i_product_quality.ddls.asddls new file mode 100644 index 0000000..e484f1d --- /dev/null +++ b/tasks_gen/train/G1950/faulty/m4_i_product_quality.ddls.asddls @@ -0,0 +1,15 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Product quality totals' +define view entity {{P}}I_PRODUCT_QUALITY + as select from {{p}}i_batch_quality +{ + key product as product, + count( * ) as batch_count, + sum( bars_total ) as bars_total, + sum( bars_good ) as bars_good, + sum( bars_scrap ) as bars_scrap, + cast( cast( sum( bars_good ) as abap.dec(15,2) ) * 100 + / cast( max( bars_total ) as abap.dec(15,2) ) + as abap.dec(5,2) ) as yield_pct +} +group by product diff --git a/tasks_gen/train/G1950/generation.json b/tasks_gen/train/G1950/generation.json new file mode 100644 index 0000000..69cb64d --- /dev/null +++ b/tasks_gen/train/G1950/generation.json @@ -0,0 +1,34 @@ +{ + "id": "G1950", + "pool": "train", + "object_type": "DDLS", + "category": "F", + "attempts": [ + { + "stage": "validate", + "oracle": 95.6, + "null": 0 + }, + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 5, + "killed": 5, + "ok": true + } + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1950/hidden/t41_hidden.clas.abap b/tasks_gen/train/G1950/hidden/t41_hidden.clas.abap new file mode 100644 index 0000000..b8ac7de --- /dev/null +++ b/tasks_gen/train/G1950/hidden/t41_hidden.clas.abap @@ -0,0 +1,115 @@ +CLASS {{p}}t41_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 one_row_per_product FOR TESTING. + METHODS batch_count_choc FOR TESTING. + METHODS batch_count_dark FOR TESTING. + METHODS total_bars_choc FOR TESTING. + METHODS good_bars_choc FOR TESTING. + METHODS scrap_bars_choc FOR TESTING. + METHODS yield_choc FOR TESTING. + METHODS yield_dark FOR TESTING. + METHODS yield_milk FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t41_hidden IMPLEMENTATION. + + METHOD class_setup. + go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_PRODUCT_QUALITY' ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + DATA lt_quality TYPE STANDARD TABLE OF {{p}}i_batch_quality WITH EMPTY KEY. + go_env->clear_doubles( ). + lt_quality = VALUE #( + ( batch_id = 'B1' product = 'CHOC' site = '1000' prod_date = '20250101' + bars_total = 1000 bars_good = 900 bars_scrap = 100 ) + ( batch_id = 'B2' product = 'CHOC' site = '1000' prod_date = '20250102' + bars_total = 1000 bars_good = 750 bars_scrap = 250 ) + ( batch_id = 'B3' product = 'DARK' site = '2000' prod_date = '20250103' + bars_total = 2000 bars_good = 1234 bars_scrap = 766 ) + ( batch_id = 'B4' product = 'MILK' site = '1000' prod_date = '20250105' + bars_total = 4 bars_good = 3 bars_scrap = 1 ) ). + go_env->insert_test_data( lt_quality ). + ENDMETHOD. + + METHOD one_row_per_product. + DATA lv_rows TYPE i. + SELECT COUNT(*) FROM {{p}}i_product_quality INTO @lv_rows. + cl_abap_unit_assert=>assert_equals( exp = 3 act = lv_rows ). + ENDMETHOD. + + METHOD batch_count_choc. + DATA ls_row TYPE {{p}}i_product_quality. + SELECT SINGLE * FROM {{p}}i_product_quality + WHERE product = 'CHOC' INTO @ls_row. + cl_abap_unit_assert=>assert_equals( exp = CONV i( 2 ) + act = CONV i( ls_row-batch_count ) ). + ENDMETHOD. + + METHOD batch_count_dark. + DATA ls_row TYPE {{p}}i_product_quality. + SELECT SINGLE * FROM {{p}}i_product_quality + WHERE product = 'DARK' INTO @ls_row. + cl_abap_unit_assert=>assert_equals( exp = CONV i( 1 ) + act = CONV i( ls_row-batch_count ) ). + ENDMETHOD. + + METHOD total_bars_choc. + DATA ls_row TYPE {{p}}i_product_quality. + SELECT SINGLE * FROM {{p}}i_product_quality + WHERE product = 'CHOC' INTO @ls_row. + cl_abap_unit_assert=>assert_equals( exp = CONV i( 2000 ) + act = CONV i( ls_row-bars_total ) ). + ENDMETHOD. + + METHOD good_bars_choc. + DATA ls_row TYPE {{p}}i_product_quality. + SELECT SINGLE * FROM {{p}}i_product_quality + WHERE product = 'CHOC' INTO @ls_row. + cl_abap_unit_assert=>assert_equals( exp = CONV i( 1650 ) + act = CONV i( ls_row-bars_good ) ). + ENDMETHOD. + + METHOD scrap_bars_choc. + DATA ls_row TYPE {{p}}i_product_quality. + SELECT SINGLE * FROM {{p}}i_product_quality + WHERE product = 'CHOC' INTO @ls_row. + cl_abap_unit_assert=>assert_equals( exp = CONV i( 350 ) + act = CONV i( ls_row-bars_scrap ) ). + ENDMETHOD. + + METHOD yield_choc. + DATA ls_row TYPE {{p}}i_product_quality. + SELECT SINGLE * FROM {{p}}i_product_quality + WHERE product = 'CHOC' INTO @ls_row. + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '82.50' ) + act = CONV decfloat34( ls_row-yield_pct ) ). + ENDMETHOD. + + METHOD yield_dark. + DATA ls_row TYPE {{p}}i_product_quality. + SELECT SINGLE * FROM {{p}}i_product_quality + WHERE product = 'DARK' INTO @ls_row. + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '61.70' ) + act = CONV decfloat34( ls_row-yield_pct ) ). + ENDMETHOD. + + METHOD yield_milk. + DATA ls_row TYPE {{p}}i_product_quality. + SELECT SINGLE * FROM {{p}}i_product_quality + WHERE product = 'MILK' INTO @ls_row. + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '75.00' ) + act = CONV decfloat34( ls_row-yield_pct ) ). + ENDMETHOD. + +ENDCLASS. diff --git a/tasks_gen/train/G1950/mutation.json b/tasks_gen/train/G1950/mutation.json new file mode 100644 index 0000000..f2fe3bf --- /dev/null +++ b/tasks_gen/train/G1950/mutation.json @@ -0,0 +1,54 @@ +{ + "task": "G1950", + "mutants": [ + { + "object": "{{P}}I_PRODUCT_QUALITY", + "mutant": "line 8: sum( -> max( (agg)", + "status": "killed", + "hidden": "8/9", + "failed_tests": [ + "TOTAL_BARS_CHOC" + ] + }, + { + "object": "{{P}}I_PRODUCT_QUALITY", + "mutant": "line 9: sum( -> max( (agg)", + "status": "killed", + "hidden": "8/9", + "failed_tests": [ + "GOOD_BARS_CHOC" + ] + }, + { + "object": "{{P}}I_PRODUCT_QUALITY", + "mutant": "line 10: sum( -> max( (agg)", + "status": "killed", + "hidden": "8/9", + "failed_tests": [ + "SCRAP_BARS_CHOC" + ] + }, + { + "object": "{{P}}I_PRODUCT_QUALITY", + "mutant": "line 11: sum( -> max( (agg)", + "status": "killed", + "hidden": "8/9", + "failed_tests": [ + "YIELD_CHOC" + ] + }, + { + "object": "{{P}}I_PRODUCT_QUALITY", + "mutant": "line 12: sum( -> max( (agg)", + "status": "killed", + "hidden": "8/9", + "failed_tests": [ + "YIELD_CHOC" + ] + } + ], + "valid": 5, + "killed": 5, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1950/reference/i_product_quality.ddls.asddls b/tasks_gen/train/G1950/reference/i_product_quality.ddls.asddls new file mode 100644 index 0000000..a3c3378 --- /dev/null +++ b/tasks_gen/train/G1950/reference/i_product_quality.ddls.asddls @@ -0,0 +1,15 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Product quality totals' +define view entity {{P}}I_PRODUCT_QUALITY + as select from {{p}}i_batch_quality +{ + key product as product, + count( * ) as batch_count, + sum( bars_total ) as bars_total, + sum( bars_good ) as bars_good, + sum( bars_scrap ) as bars_scrap, + cast( cast( sum( bars_good ) as abap.dec(15,2) ) * 100 + / cast( sum( bars_total ) as abap.dec(15,2) ) + as abap.dec(5,2) ) as yield_pct +} +group by product diff --git a/tasks_gen/train/G1950/reference/t41_test.clas.abap b/tasks_gen/train/G1950/reference/t41_test.clas.abap new file mode 100644 index 0000000..2b04e54 --- /dev/null +++ b/tasks_gen/train/G1950/reference/t41_test.clas.abap @@ -0,0 +1,49 @@ +CLASS {{p}}t41_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}}t41_test IMPLEMENTATION. + + METHOD class_setup. + go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_PRODUCT_QUALITY' ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + DATA lt_quality TYPE STANDARD TABLE OF {{p}}i_batch_quality WITH EMPTY KEY. + go_env->clear_doubles( ). + lt_quality = VALUE #( + ( batch_id = 'A1' product = 'BAR' site = '1000' prod_date = '20250101' + bars_total = 400 bars_good = 300 bars_scrap = 100 ) + ( batch_id = 'A2' product = 'BAR' site = '1000' prod_date = '20250102' + bars_total = 600 bars_good = 300 bars_scrap = 300 ) ). + go_env->insert_test_data( lt_quality ). + ENDMETHOD. + + METHOD totals_of_one_product. + DATA ls_row TYPE {{p}}i_product_quality. + SELECT SINGLE * FROM {{p}}i_product_quality + WHERE product = 'BAR' INTO @ls_row. + cl_abap_unit_assert=>assert_equals( exp = CONV i( 2 ) + act = CONV i( ls_row-batch_count ) ). + cl_abap_unit_assert=>assert_equals( exp = CONV i( 1000 ) + act = CONV i( ls_row-bars_total ) ). + cl_abap_unit_assert=>assert_equals( exp = CONV i( 600 ) + act = CONV i( ls_row-bars_good ) ). + cl_abap_unit_assert=>assert_equals( exp = CONV i( 400 ) + act = CONV i( ls_row-bars_scrap ) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '60.00' ) + act = CONV decfloat34( ls_row-yield_pct ) ). + ENDMETHOD. + +ENDCLASS. diff --git a/tasks_gen/train/G1950/seed/batch.tabl.asabap b/tasks_gen/train/G1950/seed/batch.tabl.asabap new file mode 100644 index 0000000..4d3c1d7 --- /dev/null +++ b/tasks_gen/train/G1950/seed/batch.tabl.asabap @@ -0,0 +1,14 @@ +@EndUserText.label : 'Production batch' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}batch { + key client : abap.clnt not null; + key batch_id : abap.char(10) not null; + product : abap.char(10); + site : abap.char(4); + prod_date : abap.dats; + bars_total : abap.int4; + bars_good : abap.int4; +} diff --git a/tasks_gen/train/G1950/seed/i_batch_quality.ddls.asddls b/tasks_gen/train/G1950/seed/i_batch_quality.ddls.asddls new file mode 100644 index 0000000..c06d002 --- /dev/null +++ b/tasks_gen/train/G1950/seed/i_batch_quality.ddls.asddls @@ -0,0 +1,14 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Batch quality' +define view entity {{P}}I_BATCH_QUALITY + as select from {{p}}batch +{ + key batch_id as batch_id, + product as product, + site as site, + prod_date as prod_date, + bars_total as bars_total, + bars_good as bars_good, + bars_total - bars_good as bars_scrap +} +where bars_total > 0 diff --git a/tasks_gen/train/G1950/spec.md b/tasks_gen/train/G1950/spec.md new file mode 100644 index 0000000..baafb38 --- /dev/null +++ b/tasks_gen/train/G1950/spec.md @@ -0,0 +1,46 @@ +# 1. Goal +The chocolate factory "Cocoa Lane" produces chocolate bars in batches. The +production team needs the quality totals of each product. A dashboard and an +OData service read these totals. Therefore the calculation must be in the +database, in a CDS view. The new view reuses the existing batch view. + +# 2. Open questions +None. + +# 3. Context +- The view entity {{P}}I_BATCH_QUALITY in package $TMP shows the production + batches that produced bars. The production team already uses this view in a + dashboard. +- The signature of {{P}}I_BATCH_QUALITY is not in this document. Read the view + entity to see its elements and its source. +- The database table behind {{P}}I_BATCH_QUALITY is a seed object in package + $TMP. + +# 4. Contract +- Create the CDS view entity {{P}}I_PRODUCT_QUALITY in package $TMP. +- The new view reads from {{P}}I_BATCH_QUALITY. Do not change + {{P}}I_BATCH_QUALITY. +- The view has these elements, with these names: PRODUCT (key), BATCH_COUNT, + BARS_TOTAL, BARS_GOOD, BARS_SCRAP, YIELD_PCT. +- No authorization check (#NOT_REQUIRED). + +# 5. Business rules +1. Show one row for each product that has at least one batch in + {{P}}I_BATCH_QUALITY. +2. PRODUCT is the product code. +3. BATCH_COUNT is the number of batches of the product. +4. BARS_TOTAL is the sum of the total bars of these batches. +5. BARS_GOOD is the sum of the good bars of these batches. +6. BARS_SCRAP is the sum of the scrap bars of these batches. +7. YIELD_PCT is BARS_GOOD as a percentage of BARS_TOTAL, with 2 decimal + places. Example: 600 good bars out of 1000 total bars is 60.00. + +# 6. Constraints +- Release target: 8.16 (SAP_BASIS 816). +- Coding standard: Clean ABAP. +- Out of scope: do not change {{P}}I_BATCH_QUALITY and {{P}}BATCH. + +# 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. diff --git a/tasks_gen/train/G1950/task.json b/tasks_gen/train/G1950/task.json new file mode 100644 index 0000000..8f0a0c1 --- /dev/null +++ b/tasks_gen/train/G1950/task.json @@ -0,0 +1,67 @@ +{ + "id": "G1950", + "category": "F", + "object_type": "DDLS", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [ + { + "type": "TABL", + "name": "{{P}}BATCH", + "file": "seed/batch.tabl.asabap", + "description": "Production batch of the chocolate factory" + }, + { + "type": "DDLS", + "name": "{{P}}I_BATCH_QUALITY", + "file": "seed/i_batch_quality.ddls.asddls", + "description": "Batch quality view, already used by the dashboard" + } + ], + "contract": [ + { + "type": "DDLS", + "name": "{{P}}I_PRODUCT_QUALITY", + "fields": [ + "PRODUCT", + "BATCH_COUNT", + "BARS_TOTAL", + "BARS_GOOD", + "BARS_SCRAP", + "YIELD_PCT" + ] + } + ], + "out_of_scope": [ + "{{P}}BATCH", + "{{P}}I_BATCH_QUALITY" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T41_HIDDEN", + "file": "hidden/t41_hidden.clas.abap", + "description": "Hidden tests for the product quality view" + } + ], + "reference": [ + { + "type": "DDLS", + "name": "{{P}}I_PRODUCT_QUALITY", + "file": "reference/i_product_quality.ddls.asddls", + "description": "Product quality totals" + }, + { + "type": "CLAS", + "name": "{{P}}T41_TEST", + "file": "reference/t41_test.clas.abap", + "description": "Own ABAP Unit tests for the view" + } + ], + "craft_checks": [] +} \ No newline at end of file diff --git a/tasks_gen/train/G1951/generation.json b/tasks_gen/train/G1951/generation.json new file mode 100644 index 0000000..d96f220 --- /dev/null +++ b/tasks_gen/train/G1951/generation.json @@ -0,0 +1,29 @@ +{ + "id": "G1951", + "pool": "train", + "object_type": "INTF", + "category": "A", + "attempts": [ + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 0, + "null": 0 + } + ], + "accepted": false +} \ No newline at end of file diff --git a/tasks_gen/train/G1951/hidden/tenancy_hidden.clas.abap b/tasks_gen/train/G1951/hidden/tenancy_hidden.clas.abap new file mode 100644 index 0000000..6bb484d --- /dev/null +++ b/tasks_gen/train/G1951/hidden/tenancy_hidden.clas.abap @@ -0,0 +1,250 @@ +CLASS {{p}}tenancy_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + + PRIVATE SECTION. + TYPES ty_amount TYPE {{p}}if_tenancy_check=>ty_amount. + + DATA mo_cut TYPE REF TO {{p}}if_tenancy_check. + + METHODS setup. + METHODS ok_application FOR TESTING. + METHODS bad_rent FOR TESTING. + METHODS bad_income FOR TESTING. + METHODS no_person FOR TESTING. + METHODS overcrowded FOR TESTING. + METHODS bad_employment FOR TESTING. + METHODS income_too_low FOR TESTING. + METHODS pets_raise_factor FOR TESTING. + METHODS deposit_without_pets FOR TESTING. + METHODS deposit_with_pets FOR TESTING. + METHODS constants_and_types FOR TESTING. +ENDCLASS. + + +CLASS {{p}}tenancy_hidden IMPLEMENTATION. + METHOD setup. + mo_cut = NEW {{p}}tenancy_checker( ). + ENDMETHOD. + + METHOD ok_application. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_tenancy_check=>c_reason-ok + act = mo_cut->check( iv_rent = CONV ty_amount( 1200 ) + iv_income = CONV ty_amount( 4000 ) + iv_rooms = 2 + iv_persons = 2 + iv_employment = {{p}}if_tenancy_check=>c_employment-permanent + iv_pets = abap_false ) ). + ENDMETHOD. + + METHOD bad_rent. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_tenancy_check=>c_reason-rent + act = mo_cut->check( iv_rent = CONV ty_amount( 0 ) + iv_income = CONV ty_amount( 4000 ) + iv_rooms = 2 + iv_persons = 2 + iv_employment = {{p}}if_tenancy_check=>c_employment-permanent + iv_pets = abap_false ) msg = `zero rent` ). + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_tenancy_check=>c_reason-rent + act = mo_cut->check( iv_rent = CONV ty_amount( -100 ) + iv_income = CONV ty_amount( 4000 ) + iv_rooms = 2 + iv_persons = 2 + iv_employment = {{p}}if_tenancy_check=>c_employment-permanent + iv_pets = abap_false ) msg = `negative rent` ). + ENDMETHOD. + + METHOD bad_income. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_tenancy_check=>c_reason-income + act = mo_cut->check( iv_rent = CONV ty_amount( 1200 ) + iv_income = CONV ty_amount( 0 ) + iv_rooms = 2 + iv_persons = 2 + iv_employment = {{p}}if_tenancy_check=>c_employment-permanent + iv_pets = abap_false ) msg = `zero income` ). + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_tenancy_check=>c_reason-income + act = mo_cut->check( iv_rent = CONV ty_amount( 1200 ) + iv_income = CONV ty_amount( -500 ) + iv_rooms = 2 + iv_persons = 2 + iv_employment = {{p}}if_tenancy_check=>c_employment-permanent + iv_pets = abap_false ) msg = `negative income` ). + ENDMETHOD. + + METHOD no_person. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_tenancy_check=>c_reason-persons + act = mo_cut->check( iv_rent = CONV ty_amount( 1200 ) + iv_income = CONV ty_amount( 4000 ) + iv_rooms = 2 + iv_persons = 0 + iv_employment = {{p}}if_tenancy_check=>c_employment-permanent + iv_pets = abap_false ) ). + ENDMETHOD. + + METHOD overcrowded. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_tenancy_check=>c_reason-capacity + act = mo_cut->check( iv_rent = CONV ty_amount( 1200 ) + iv_income = CONV ty_amount( 4000 ) + iv_rooms = 2 + iv_persons = 5 + iv_employment = {{p}}if_tenancy_check=>c_employment-permanent + iv_pets = abap_false ) ). + ENDMETHOD. + + METHOD bad_employment. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_tenancy_check=>c_reason-employment + act = mo_cut->check( iv_rent = CONV ty_amount( 1200 ) + iv_income = CONV ty_amount( 4000 ) + iv_rooms = 2 + iv_persons = 2 + iv_employment = 'X' + iv_pets = abap_false ) ). + ENDMETHOD. + + METHOD income_too_low. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_tenancy_check=>c_reason-ratio + act = mo_cut->check( iv_rent = CONV ty_amount( 1200 ) + iv_income = CONV ty_amount( 3500 ) + iv_rooms = 2 + iv_persons = 2 + iv_employment = {{p}}if_tenancy_check=>c_employment-permanent + iv_pets = abap_false ) msg = `permanent needs 3x` ). + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_tenancy_check=>c_reason-ratio + act = mo_cut->check( iv_rent = CONV ty_amount( 1200 ) + iv_income = CONV ty_amount( 4700 ) + iv_rooms = 2 + iv_persons = 2 + iv_employment = {{p}}if_tenancy_check=>c_employment-fixed + iv_pets = abap_false ) msg = `fixed term needs 4x` ). + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_tenancy_check=>c_reason-ratio + act = mo_cut->check( iv_rent = CONV ty_amount( 1200 ) + iv_income = CONV ty_amount( 5900 ) + iv_rooms = 2 + iv_persons = 2 + iv_employment = {{p}}if_tenancy_check=>c_employment-self + iv_pets = abap_false ) msg = `self employed needs 5x` ). + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_tenancy_check=>c_reason-ok + act = mo_cut->check( iv_rent = CONV ty_amount( 1200 ) + iv_income = CONV ty_amount( 6000 ) + iv_rooms = 2 + iv_persons = 2 + iv_employment = {{p}}if_tenancy_check=>c_employment-self + iv_pets = abap_false ) msg = `self employed is ok` ). + ENDMETHOD. + + METHOD pets_raise_factor. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_tenancy_check=>c_reason-ratio + act = mo_cut->check( iv_rent = CONV ty_amount( 1200 ) + iv_income = CONV ty_amount( 4000 ) + iv_rooms = 2 + iv_persons = 2 + iv_employment = {{p}}if_tenancy_check=>c_employment-permanent + iv_pets = abap_true ) msg = `pets need 4x` ). + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_tenancy_check=>c_reason-ok + act = mo_cut->check( iv_rent = CONV ty_amount( 1200 ) + iv_income = CONV ty_amount( 4800 ) + iv_rooms = 2 + iv_persons = 2 + iv_employment = {{p}}if_tenancy_check=>c_employment-permanent + iv_pets = abap_true ) msg = `pets with 4x is ok` ). + ENDMETHOD. + + METHOD deposit_without_pets. + cl_abap_unit_assert=>assert_equals( + exp = CONV ty_amount( 2400 ) + act = mo_cut->deposit( iv_rent = CONV ty_amount( 1200 ) + iv_pets = abap_false ) ). + cl_abap_unit_assert=>assert_equals( + exp = CONV ty_amount( 0 ) + act = mo_cut->deposit( iv_rent = CONV ty_amount( 0 ) + iv_pets = abap_false ) msg = `zero rent` ). + ENDMETHOD. + + METHOD deposit_with_pets. + cl_abap_unit_assert=>assert_equals( + exp = CONV ty_amount( 3600 ) + act = mo_cut->deposit( iv_rent = CONV ty_amount( 1200 ) + iv_pets = abap_true ) ). + cl_abap_unit_assert=>assert_equals( + exp = CONV ty_amount( 0 ) + act = mo_cut->deposit( iv_rent = CONV ty_amount( 0 ) + iv_pets = abap_true ) msg = `zero rent` ). + ENDMETHOD. + + METHOD constants_and_types. + cl_abap_unit_assert=>assert_equals( exp = 'OK' + act = {{p}}if_tenancy_check=>c_reason-ok ). + cl_abap_unit_assert=>assert_equals( exp = 'RENT' + act = {{p}}if_tenancy_check=>c_reason-rent ). + cl_abap_unit_assert=>assert_equals( exp = 'INCOME' + act = {{p}}if_tenancy_check=>c_reason-income ). + cl_abap_unit_assert=>assert_equals( exp = 'PERSONS' + act = {{p}}if_tenancy_check=>c_reason-persons ). + cl_abap_unit_assert=>assert_equals( exp = 'CAPACITY' + act = {{p}}if_tenancy_check=>c_reason-capacity ). + cl_abap_unit_assert=>assert_equals( exp = 'EMPLOYMENT' + act = {{p}}if_tenancy_check=>c_reason-employment ). + cl_abap_unit_assert=>assert_equals( exp = 'RATIO' + act = {{p}}if_tenancy_check=>c_reason-ratio ). + cl_abap_unit_assert=>assert_equals( exp = 'P' + act = {{p}}if_tenancy_check=>c_employment-permanent ). + cl_abap_unit_assert=>assert_equals( exp = 'F' + act = {{p}}if_tenancy_check=>c_employment-fixed ). + cl_abap_unit_assert=>assert_equals( exp = 'S' + act = {{p}}if_tenancy_check=>c_employment-self ). + + DATA lv_reason TYPE {{p}}if_tenancy_check=>ty_reason. + DATA lv_employment TYPE {{p}}if_tenancy_check=>ty_employment. + DATA lv_amount TYPE {{p}}if_tenancy_check=>ty_amount. + + cl_abap_unit_assert=>assert_equals( + exp = 10 + act = cl_abap_typedescr=>describe_by_data( lv_reason )->length ). + cl_abap_unit_assert=>assert_equals( + exp = cl_abap_typedescr=>typekind_char + act = cl_abap_typedescr=>describe_by_data( lv_reason )->type_kind ). + cl_abap_unit_assert=>assert_equals( + exp = 1 + act = cl_abap_typedescr=>describe_by_data( lv_employment )->length ). + cl_abap_unit_assert=>assert_equals( + exp = cl_abap_typedescr=>typekind_char + act = cl_abap_typedescr=>describe_by_data( lv_employment )->type_kind ). + cl_abap_unit_assert=>assert_equals( + exp = 8 + act = cl_abap_typedescr=>describe_by_data( lv_amount )->length ). + cl_abap_unit_assert=>assert_equals( + exp = 2 + act = cl_abap_typedescr=>describe_by_data( lv_amount )->decimals ). + cl_abap_unit_assert=>assert_equals( + exp = cl_abap_typedescr=>typekind_packed + act = cl_abap_typedescr=>describe_by_data( lv_amount )->type_kind ). + ENDMETHOD. +ENDCLASS. + + +CLASS lcl_tenant DEFINITION. + PUBLIC SECTION. + INTERFACES {{p}}if_tenancy_check. +ENDCLASS. + + +CLASS lcl_tenant IMPLEMENTATION. + METHOD {{p}}if_tenancy_check~check. + ENDMETHOD. + + METHOD {{p}}if_tenancy_check~deposit. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1951/reference/if_tenancy_check.intf.abap b/tasks_gen/train/G1951/reference/if_tenancy_check.intf.abap new file mode 100644 index 0000000..013899d --- /dev/null +++ b/tasks_gen/train/G1951/reference/if_tenancy_check.intf.abap @@ -0,0 +1,35 @@ +INTERFACE {{p}}if_tenancy_check PUBLIC. + TYPES ty_reason TYPE c LENGTH 10. + TYPES ty_employment TYPE c LENGTH 1. + TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2. + + CONSTANTS: + BEGIN OF c_employment, + permanent TYPE ty_employment VALUE 'P', + fixed TYPE ty_employment VALUE 'F', + self TYPE ty_employment VALUE 'S', + END OF c_employment, + BEGIN OF c_reason, + ok TYPE ty_reason VALUE 'OK', + rent TYPE ty_reason VALUE 'RENT', + income TYPE ty_reason VALUE 'INCOME', + persons TYPE ty_reason VALUE 'PERSONS', + capacity TYPE ty_reason VALUE 'CAPACITY', + employment TYPE ty_reason VALUE 'EMPLOYMENT', + ratio TYPE ty_reason VALUE 'RATIO', + END OF c_reason. + + METHODS check + IMPORTING iv_rent TYPE ty_amount + iv_income TYPE ty_amount + iv_rooms TYPE i + iv_persons TYPE i + iv_employment TYPE ty_employment + iv_pets TYPE abap_bool + RETURNING VALUE(rv_reason) TYPE ty_reason. + + METHODS deposit + IMPORTING iv_rent TYPE ty_amount + iv_pets TYPE abap_bool + RETURNING VALUE(rv_deposit) TYPE ty_amount. +ENDINTERFACE. diff --git a/tasks_gen/train/G1951/reference/tenancy_checker.clas.abap b/tasks_gen/train/G1951/reference/tenancy_checker.clas.abap new file mode 100644 index 0000000..f3ad032 --- /dev/null +++ b/tasks_gen/train/G1951/reference/tenancy_checker.clas.abap @@ -0,0 +1,75 @@ +CLASS {{p}}tenancy_checker DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_tenancy_check. + + PRIVATE SECTION. + METHODS income_factor + IMPORTING iv_employment TYPE {{p}}if_tenancy_check=>ty_employment + iv_pets TYPE abap_bool + RETURNING VALUE(rv_factor) TYPE i. +ENDCLASS. + + +CLASS {{p}}tenancy_checker IMPLEMENTATION. + METHOD {{p}}if_tenancy_check~check. + IF iv_rent <= 0. + rv_reason = {{p}}if_tenancy_check=>c_reason-rent. + RETURN. + ENDIF. + + IF iv_income <= 0. + rv_reason = {{p}}if_tenancy_check=>c_reason-income. + RETURN. + ENDIF. + + IF iv_persons < 1. + rv_reason = {{p}}if_tenancy_check=>c_reason-persons. + RETURN. + ENDIF. + + IF iv_persons > 2 * iv_rooms. + rv_reason = {{p}}if_tenancy_check=>c_reason-capacity. + RETURN. + ENDIF. + + IF iv_employment <> {{p}}if_tenancy_check=>c_employment-permanent + AND iv_employment <> {{p}}if_tenancy_check=>c_employment-fixed + AND iv_employment <> {{p}}if_tenancy_check=>c_employment-self. + rv_reason = {{p}}if_tenancy_check=>c_reason-employment. + RETURN. + ENDIF. + + DATA(lv_factor) = income_factor( iv_employment = iv_employment + iv_pets = iv_pets ). + IF iv_income < iv_rent * lv_factor. + rv_reason = {{p}}if_tenancy_check=>c_reason-ratio. + RETURN. + ENDIF. + + rv_reason = {{p}}if_tenancy_check=>c_reason-ok. + ENDMETHOD. + + METHOD {{p}}if_tenancy_check~deposit. + IF iv_rent <= 0. + rv_deposit = 0. + ELSEIF iv_pets = abap_true. + rv_deposit = 3 * iv_rent. + ELSE. + rv_deposit = 2 * iv_rent. + ENDIF. + ENDMETHOD. + + METHOD income_factor. + CASE iv_employment. + WHEN {{p}}if_tenancy_check=>c_employment-permanent. + rv_factor = 3. + WHEN {{p}}if_tenancy_check=>c_employment-fixed. + rv_factor = 4. + WHEN OTHERS. + rv_factor = 5. + ENDCASE. + IF iv_pets = abap_true. + rv_factor = rv_factor + 1. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1951/reference/tenancy_checker.testclasses.abap b/tasks_gen/train/G1951/reference/tenancy_checker.testclasses.abap new file mode 100644 index 0000000..6b684bd --- /dev/null +++ b/tasks_gen/train/G1951/reference/tenancy_checker.testclasses.abap @@ -0,0 +1,117 @@ +CLASS ltc_tenancy_checker DEFINITION FINAL FOR TESTING + DURATION SHORT RISK LEVEL HARMLESS. + + PRIVATE SECTION. + TYPES ty_amount TYPE {{p}}if_tenancy_check=>ty_amount. + + DATA mo_cut TYPE REF TO {{p}}if_tenancy_check. + + METHODS setup. + METHODS ok_application FOR TESTING. + METHODS rent_must_be_positive FOR TESTING. + METHODS income_must_be_positive FOR TESTING. + METHODS overcrowded_flat FOR TESTING. + METHODS unknown_employment FOR TESTING. + METHODS income_too_low FOR TESTING. + METHODS pets_need_more_income FOR TESTING. + METHODS deposit_with_pets FOR TESTING. + METHODS deposit_without_pets FOR TESTING. +ENDCLASS. + + +CLASS ltc_tenancy_checker IMPLEMENTATION. + METHOD setup. + mo_cut = NEW {{p}}tenancy_checker( ). + ENDMETHOD. + + METHOD ok_application. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_tenancy_check=>c_reason-ok + act = mo_cut->check( iv_rent = CONV ty_amount( 1200 ) + iv_income = CONV ty_amount( 4000 ) + iv_rooms = 2 + iv_persons = 2 + iv_employment = {{p}}if_tenancy_check=>c_employment-permanent + iv_pets = abap_false ) ). + ENDMETHOD. + + METHOD rent_must_be_positive. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_tenancy_check=>c_reason-rent + act = mo_cut->check( iv_rent = CONV ty_amount( 0 ) + iv_income = CONV ty_amount( 4000 ) + iv_rooms = 2 + iv_persons = 2 + iv_employment = {{p}}if_tenancy_check=>c_employment-permanent + iv_pets = abap_false ) ). + ENDMETHOD. + + METHOD income_must_be_positive. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_tenancy_check=>c_reason-income + act = mo_cut->check( iv_rent = CONV ty_amount( 1200 ) + iv_income = CONV ty_amount( 0 ) + iv_rooms = 2 + iv_persons = 2 + iv_employment = {{p}}if_tenancy_check=>c_employment-permanent + iv_pets = abap_false ) ). + ENDMETHOD. + + METHOD overcrowded_flat. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_tenancy_check=>c_reason-capacity + act = mo_cut->check( iv_rent = CONV ty_amount( 1200 ) + iv_income = CONV ty_amount( 4000 ) + iv_rooms = 2 + iv_persons = 5 + iv_employment = {{p}}if_tenancy_check=>c_employment-permanent + iv_pets = abap_false ) ). + ENDMETHOD. + + METHOD unknown_employment. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_tenancy_check=>c_reason-employment + act = mo_cut->check( iv_rent = CONV ty_amount( 1200 ) + iv_income = CONV ty_amount( 4000 ) + iv_rooms = 2 + iv_persons = 2 + iv_employment = 'X' + iv_pets = abap_false ) ). + ENDMETHOD. + + METHOD income_too_low. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_tenancy_check=>c_reason-ratio + act = mo_cut->check( iv_rent = CONV ty_amount( 1200 ) + iv_income = CONV ty_amount( 3500 ) + iv_rooms = 2 + iv_persons = 2 + iv_employment = {{p}}if_tenancy_check=>c_employment-permanent + iv_pets = abap_false ) ). + ENDMETHOD. + + METHOD pets_need_more_income. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_tenancy_check=>c_reason-ratio + act = mo_cut->check( iv_rent = CONV ty_amount( 1200 ) + iv_income = CONV ty_amount( 4000 ) + iv_rooms = 2 + iv_persons = 2 + iv_employment = {{p}}if_tenancy_check=>c_employment-permanent + iv_pets = abap_true ) ). + ENDMETHOD. + + METHOD deposit_with_pets. + cl_abap_unit_assert=>assert_equals( + exp = CONV ty_amount( 3600 ) + act = mo_cut->deposit( iv_rent = CONV ty_amount( 1200 ) + iv_pets = abap_true ) ). + ENDMETHOD. + + METHOD deposit_without_pets. + cl_abap_unit_assert=>assert_equals( + exp = CONV ty_amount( 2400 ) + act = mo_cut->deposit( iv_rent = CONV ty_amount( 1200 ) + iv_pets = abap_false ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1951/spec.md b/tasks_gen/train/G1951/spec.md new file mode 100644 index 0000000..fdf4797 --- /dev/null +++ b/tasks_gen/train/G1951/spec.md @@ -0,0 +1,84 @@ +# 1. Goal +A property management company checks a tenancy application before it offers a +flat to an applicant. The office calls the check for each application. The +office also needs the deposit that the applicant must pay. + +# 2. Open questions +None. + +# 3. Context +- The office works with one interface and one class that implements the + interface. +- The interface {{P}}IF_TENANCY_CHECK holds the types, the constants and the + method signatures of the tenancy check. +- The class {{P}}TENANCY_CHECKER holds the logic. +- The method CHECK returns one reason code for each tenancy application. +- The method DEPOSIT returns the deposit of a tenancy application. + +# 4. Contract +Create the interface {{P}}IF_TENANCY_CHECK in package $TMP. The interface is +public. It has these components and no other components. + +Types: +- TY_REASON: type c, length 10. +- TY_EMPLOYMENT: type c, length 1. +- TY_AMOUNT: type p, length 8, 2 decimal places. + +Constants: +- C_EMPLOYMENT: a constant structure with the components PERMANENT, FIXED and + SELF. Each component has the type TY_EMPLOYMENT. The values are: + PERMANENT = 'P', FIXED = 'F', SELF = 'S'. +- C_REASON: a constant structure with the components OK, RENT, INCOME, + PERSONS, CAPACITY, EMPLOYMENT and RATIO. Each component has the type + TY_REASON. The values are: OK = 'OK', RENT = 'RENT', INCOME = 'INCOME', + PERSONS = 'PERSONS', CAPACITY = 'CAPACITY', EMPLOYMENT = 'EMPLOYMENT', + RATIO = 'RATIO'. + +Methods: +- CHECK + IMPORTING iv_rent TYPE ty_amount + iv_income TYPE ty_amount + iv_rooms TYPE i + iv_persons TYPE i + iv_employment TYPE ty_employment + iv_pets TYPE abap_bool + RETURNING VALUE(rv_reason) TYPE ty_reason. +- DEPOSIT + IMPORTING iv_rent TYPE ty_amount + iv_pets TYPE abap_bool + RETURNING VALUE(rv_deposit) TYPE ty_amount. + +Create the class {{P}}TENANCY_CHECKER in package $TMP. +- The class is public, final, and has a public constructor without parameters. +- The class implements {{P}}IF_TENANCY_CHECK. +- Do not add other public methods. + +# 5. Business rules +The method CHECK applies the rules in this sequence. It returns the reason of +the first rule that fails. +1. If iv_rent is less than or equal to zero, return RENT. +2. If iv_income is less than or equal to zero, return INCOME. +3. If iv_persons is less than one, return PERSONS. +4. If iv_persons is greater than two times iv_rooms, return CAPACITY. +5. If iv_employment is not 'P', 'F' or 'S', return EMPLOYMENT. +6. The income factor is 3 for 'P', 4 for 'F' and 5 for 'S'. If iv_pets is + true, add 1 to the income factor. If iv_income is less than iv_rent + multiplied by the income factor, return RATIO. +7. Return OK. + +The method DEPOSIT applies the rules in this sequence. +1. If iv_rent is less than or equal to zero, return 0. +2. If iv_pets is true, return three times iv_rent. +3. Return two times iv_rent. + +# 6. Constraints +- Release target: SAP_BASIS 816 (ABAP Platform 2025). +- Coding standards: Clean ABAP. Method length below 40 statements. No global + variables. No comment that restates the code. +- Out of scope: do not create database tables, CDS views, reports or function + modules. + +# 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. diff --git a/tasks_gen/train/G1951/task.json b/tasks_gen/train/G1951/task.json new file mode 100644 index 0000000..d5f3e32 --- /dev/null +++ b/tasks_gen/train/G1951/task.json @@ -0,0 +1,52 @@ +{ + "id": "G1951", + "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_TENANCY_CHECK" + }, + { + "type": "CLAS", + "name": "{{P}}TENANCY_CHECKER", + "implements": "{{P}}IF_TENANCY_CHECK" + } + ], + "out_of_scope": [], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}TENANCY_HIDDEN", + "file": "hidden/tenancy_hidden.clas.abap", + "description": "T_INTF_TENANCY hidden tests" + } + ], + "reference": [ + { + "type": "INTF", + "name": "{{P}}IF_TENANCY_CHECK", + "file": "reference/if_tenancy_check.intf.abap", + "description": "Tenancy check interface with types, constants and method signatures" + }, + { + "type": "CLAS", + "name": "{{P}}TENANCY_CHECKER", + "file": "reference/tenancy_checker.clas.abap", + "description": "Tenancy checker that implements the interface", + "testclasses_file": "reference/tenancy_checker.testclasses.abap" + } + ], + "craft_checks": [ + "method_length", + "cyclomatic_complexity" + ] +} \ No newline at end of file diff --git a/tasks_gen/train/G1952/generation.json b/tasks_gen/train/G1952/generation.json new file mode 100644 index 0000000..667565b --- /dev/null +++ b/tasks_gen/train/G1952/generation.json @@ -0,0 +1,33 @@ +{ + "id": "G1952", + "pool": "train", + "object_type": "TABL", + "category": "B", + "attempts": [ + { + "stage": "bundle", + "errors": [ + "hidden/t16_hidden.clas.abap line 70: 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": 69.0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 85.0, + "null": 0 + } + ], + "accepted": false +} \ No newline at end of file diff --git a/tasks_gen/train/G1952/hidden/t16_hidden.clas.abap b/tasks_gen/train/G1952/hidden/t16_hidden.clas.abap new file mode 100644 index 0000000..4301ac4 --- /dev/null +++ b/tasks_gen/train/G1952/hidden/t16_hidden.clas.abap @@ -0,0 +1,212 @@ +CLASS {{p}}t16_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + TYPES ty_fields TYPE STANDARD TABLE OF dfies WITH EMPTY KEY. + TYPES ty_fieldname TYPE c LENGTH 30. + TYPES ty_datatype TYPE c LENGTH 4. + TYPES ty_flag 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_attributes FOR TESTING. + METHODS insert_and_read FOR TESTING. + METHODS read_by_date FOR TESTING. + METHODS get_fields RETURNING VALUE(rt_fields) TYPE ty_fields. + METHODS get_field + IMPORTING it_fields TYPE ty_fields + iv_name TYPE ty_fieldname + RETURNING VALUE(rs_field) TYPE dfies. + METHODS assert_present + IMPORTING it_fields TYPE ty_fields + iv_name TYPE ty_fieldname. + METHODS assert_key + IMPORTING it_fields TYPE ty_fields + iv_name TYPE ty_fieldname + iv_key TYPE ty_flag. + METHODS assert_field + IMPORTING it_fields TYPE ty_fields + iv_name TYPE ty_fieldname + iv_type TYPE ty_datatype + iv_leng TYPE i + iv_decimals TYPE i. + METHODS to_struct_descr + IMPORTING io_descr TYPE REF TO cl_abap_typedescr + RETURNING VALUE(ro_struct) TYPE REF TO cl_abap_structdescr. +ENDCLASS. + + +CLASS {{p}}t16_hidden IMPLEMENTATION. + + METHOD class_setup. + go_env = cl_osql_test_environment=>create( i_dependency_list = VALUE #( ( '{{P}}SESS' ) ) ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + go_env->clear_doubles( ). + ENDMETHOD. + + METHOD get_fields. + DATA lo_struct TYPE REF TO cl_abap_structdescr. + lo_struct = to_struct_descr( cl_abap_typedescr=>describe_by_name( '{{P}}SESS' ) ). + rt_fields = lo_struct->get_ddic_field_list( ). + ENDMETHOD. + + METHOD to_struct_descr. + DATA lo_table TYPE REF TO cl_abap_tabledescr. + TRY. + ro_struct = CAST cl_abap_structdescr( io_descr ). + CATCH cx_sy_move_cast_error. + lo_table = CAST cl_abap_tabledescr( io_descr ). + ro_struct = CAST cl_abap_structdescr( lo_table->get_table_line_type( ) ). + ENDTRY. + ENDMETHOD. + + METHOD get_field. + READ TABLE it_fields INTO rs_field WITH KEY fieldname = iv_name. + cl_abap_unit_assert=>assert_equals( + exp = 0 + act = sy-subrc + msg = |Field { iv_name } is missing in table {{P}}SESS| ). + ENDMETHOD. + + METHOD assert_present. + DATA ls_field TYPE dfies. + READ TABLE it_fields INTO ls_field WITH KEY fieldname = iv_name. + cl_abap_unit_assert=>assert_equals( + exp = 0 + act = sy-subrc + msg = |Field { iv_name } is missing in table {{P}}SESS| ). + ENDMETHOD. + + METHOD assert_key. + DATA ls_field TYPE dfies. + DATA lv_flag TYPE ty_flag. + ls_field = get_field( it_fields = it_fields iv_name = iv_name ). + lv_flag = ls_field-keyflag. + cl_abap_unit_assert=>assert_equals( + exp = iv_key + act = lv_flag + msg = |Wrong key flag of field { iv_name }| ). + ENDMETHOD. + + METHOD assert_field. + DATA ls_field TYPE dfies. + DATA lv_leng TYPE i. + DATA lv_decimals TYPE i. + ls_field = get_field( it_fields = it_fields iv_name = iv_name ). + lv_leng = ls_field-leng. + lv_decimals = ls_field-decimals. + cl_abap_unit_assert=>assert_equals( exp = iv_leng act = lv_leng + msg = |Wrong length of { iv_name }| ). + cl_abap_unit_assert=>assert_equals( exp = iv_decimals act = lv_decimals + msg = |Wrong decimals of { iv_name }| ). + cl_abap_unit_assert=>assert_equals( exp = iv_type act = ls_field-datatype + msg = |Wrong type of { iv_name }| ). + ENDMETHOD. + + METHOD field_names. + DATA lt_fields TYPE ty_fields. + lt_fields = get_fields( ). + cl_abap_unit_assert=>assert_equals( exp = 10 act = lines( lt_fields ) + msg = 'Wrong number of fields in {{P}}SESS' ). + assert_present( it_fields = lt_fields iv_name = 'CLIENT' ). + assert_present( it_fields = lt_fields iv_name = 'STUDIO_ID' ). + assert_present( it_fields = lt_fields iv_name = 'SESSION_NO' ). + assert_present( it_fields = lt_fields iv_name = 'CUSTOMER' ). + assert_present( it_fields = lt_fields iv_name = 'SESSION_DATE' ). + assert_present( it_fields = lt_fields iv_name = 'BOOKED_HOURS' ). + assert_present( it_fields = lt_fields iv_name = 'RATE_MODE' ). + assert_present( it_fields = lt_fields iv_name = 'TARIFF_GROUP' ). + assert_present( it_fields = lt_fields iv_name = 'TRACK_COUNT' ). + assert_present( it_fields = lt_fields iv_name = 'SESSION_VALUE' ). + ENDMETHOD. + + METHOD key_fields. + DATA lt_fields TYPE ty_fields. + lt_fields = get_fields( ). + assert_key( it_fields = lt_fields iv_name = 'CLIENT' iv_key = 'X' ). + assert_key( it_fields = lt_fields iv_name = 'STUDIO_ID' iv_key = 'X' ). + assert_key( it_fields = lt_fields iv_name = 'SESSION_NO' iv_key = 'X' ). + assert_key( it_fields = lt_fields iv_name = 'CUSTOMER' iv_key = ' ' ). + assert_key( it_fields = lt_fields iv_name = 'SESSION_DATE' iv_key = ' ' ). + assert_key( it_fields = lt_fields iv_name = 'BOOKED_HOURS' iv_key = ' ' ). + assert_key( it_fields = lt_fields iv_name = 'RATE_MODE' iv_key = ' ' ). + assert_key( it_fields = lt_fields iv_name = 'TARIFF_GROUP' iv_key = ' ' ). + assert_key( it_fields = lt_fields iv_name = 'TRACK_COUNT' iv_key = ' ' ). + assert_key( it_fields = lt_fields iv_name = 'SESSION_VALUE' iv_key = ' ' ). + ENDMETHOD. + + METHOD field_attributes. + DATA lt_fields TYPE ty_fields. + lt_fields = get_fields( ). + assert_field( it_fields = lt_fields iv_name = 'CLIENT' iv_type = 'CLNT' + iv_leng = 3 iv_decimals = 0 ). + assert_field( it_fields = lt_fields iv_name = 'STUDIO_ID' iv_type = 'CHAR' + iv_leng = 4 iv_decimals = 0 ). + assert_field( it_fields = lt_fields iv_name = 'SESSION_NO' iv_type = 'NUMC' + iv_leng = 6 iv_decimals = 0 ). + assert_field( it_fields = lt_fields iv_name = 'CUSTOMER' iv_type = 'CHAR' + iv_leng = 10 iv_decimals = 0 ). + assert_field( it_fields = lt_fields iv_name = 'SESSION_DATE' iv_type = 'DATS' + iv_leng = 8 iv_decimals = 0 ). + assert_field( it_fields = lt_fields iv_name = 'BOOKED_HOURS' iv_type = 'DEC' + iv_leng = 5 iv_decimals = 2 ). + assert_field( it_fields = lt_fields iv_name = 'RATE_MODE' iv_type = 'CHAR' + iv_leng = 4 iv_decimals = 0 ). + assert_field( it_fields = lt_fields iv_name = 'TARIFF_GROUP' iv_type = 'CHAR' + iv_leng = 4 iv_decimals = 0 ). + assert_field( it_fields = lt_fields iv_name = 'TRACK_COUNT' iv_type = 'INT4' + iv_leng = 10 iv_decimals = 0 ). + assert_field( it_fields = lt_fields iv_name = 'SESSION_VALUE' iv_type = 'DEC' + iv_leng = 15 iv_decimals = 2 ). + ENDMETHOD. + + METHOD insert_and_read. + DATA lt_sess TYPE STANDARD TABLE OF {{p}}sess WITH EMPTY KEY. + DATA lv_day TYPE d. + lv_day = '20250110'. + lt_sess = VALUE #( + ( client = sy-mandt studio_id = 'R1' session_no = '000001' + customer = 'CUST01' session_date = lv_day booked_hours = '3.50' + rate_mode = 'STD' tariff_group = 'A' track_count = 8 + session_value = '450.00' ) ). + go_env->insert_test_data( lt_sess ). + SELECT SINGLE * FROM {{p}}sess WHERE studio_id = 'R1' AND session_no = '000001' + INTO @DATA(ls_read). + cl_abap_unit_assert=>assert_equals( exp = 0 act = sy-subrc ). + cl_abap_unit_assert=>assert_equals( exp = 'CUST01' act = ls_read-customer ). + cl_abap_unit_assert=>assert_equals( exp = lv_day act = ls_read-session_date ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '3.50' ) + act = CONV decfloat34( ls_read-booked_hours ) ). + cl_abap_unit_assert=>assert_equals( exp = 'STD' act = ls_read-rate_mode ). + cl_abap_unit_assert=>assert_equals( exp = 'A' act = ls_read-tariff_group ). + cl_abap_unit_assert=>assert_equals( exp = 8 act = ls_read-track_count ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '450.00' ) + act = CONV decfloat34( ls_read-session_value ) ). + ENDMETHOD. + + METHOD read_by_date. + DATA lt_sess TYPE STANDARD TABLE OF {{p}}sess WITH EMPTY KEY. + DATA lv_day TYPE d. + lv_day = '20250301'. + lt_sess = VALUE #( + ( client = sy-mandt studio_id = 'R1' session_no = '000010' + customer = 'CUST10' session_date = lv_day booked_hours = '1.00' + rate_mode = 'STD' tariff_group = 'A' track_count = 1 + session_value = '80.00' ) + ( client = sy-mandt studio_id = 'R2' session_no = '000011' + customer = 'CUST11' session_date = '20250302' booked_hours = '2.00' + rate_mode = 'STD' tariff_group = 'A' track_count = 2 + session_value = '160.00' ) ). + go_env->insert_test_data( lt_sess ). + SELECT COUNT(*) FROM {{p}}sess WHERE session_date = @lv_day INTO @DATA(lv_count). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lv_count ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1952/reference/sess.tabl.asabap b/tasks_gen/train/G1952/reference/sess.tabl.asabap new file mode 100644 index 0000000..aa542e3 --- /dev/null +++ b/tasks_gen/train/G1952/reference/sess.tabl.asabap @@ -0,0 +1,17 @@ +@EndUserText.label : 'Recording session' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}sess { + key client : abap.clnt not null; + key studio_id : abap.char(4) not null; + key session_no : abap.numc(6) not null; + customer : abap.char(10); + session_date : abap.dats; + booked_hours : abap.dec(5,2); + rate_mode : abap.char(4); + tariff_group : abap.char(4); + track_count : abap.int4; + session_value : abap.dec(15,2); +} diff --git a/tasks_gen/train/G1952/reference/t16_test.clas.abap b/tasks_gen/train/G1952/reference/t16_test.clas.abap new file mode 100644 index 0000000..9b91645 --- /dev/null +++ b/tasks_gen/train/G1952/reference/t16_test.clas.abap @@ -0,0 +1,75 @@ +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_osql_test_environment. + CLASS-METHODS class_setup. + CLASS-METHODS class_teardown. + METHODS setup. + METHODS stores_and_reads FOR TESTING. + METHODS rejects_duplicate FOR TESTING. + METHODS counts_by_date FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t16_test IMPLEMENTATION. + + METHOD class_setup. + go_env = cl_osql_test_environment=>create( i_dependency_list = VALUE #( ( '{{P}}SESS' ) ) ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + go_env->clear_doubles( ). + ENDMETHOD. + + METHOD stores_and_reads. + DATA lt_sess TYPE STANDARD TABLE OF {{p}}sess WITH EMPTY KEY. + lt_sess = VALUE #( + ( client = sy-mandt studio_id = 'R1' session_no = '000001' + customer = 'CUST01' session_date = '20250110' booked_hours = '3.50' + rate_mode = 'STD' tariff_group = 'A' track_count = 8 + session_value = '450.00' ) ). + go_env->insert_test_data( lt_sess ). + SELECT SINGLE * FROM {{p}}sess WHERE studio_id = 'R1' AND session_no = '000001' + INTO @DATA(ls_read). + cl_abap_unit_assert=>assert_equals( exp = 0 act = sy-subrc ). + cl_abap_unit_assert=>assert_equals( exp = 'CUST01' act = ls_read-customer ). + cl_abap_unit_assert=>assert_equals( exp = 8 act = ls_read-track_count ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '3.50' ) + act = CONV decfloat34( ls_read-booked_hours ) ). + ENDMETHOD. + + METHOD rejects_duplicate. + DATA lt_sess TYPE STANDARD TABLE OF {{p}}sess WITH EMPTY KEY. + lt_sess = VALUE #( + ( client = sy-mandt studio_id = 'R9' session_no = '000009' + customer = 'CUST09' session_date = '20250401' booked_hours = '1.00' + rate_mode = 'STD' tariff_group = 'A' track_count = 1 + session_value = '80.00' ) ). + INSERT {{p}}sess FROM TABLE @lt_sess. + cl_abap_unit_assert=>assert_equals( exp = 0 act = sy-subrc ). + INSERT {{p}}sess FROM TABLE @lt_sess. + cl_abap_unit_assert=>assert_equals( exp = 4 act = sy-subrc ). + ENDMETHOD. + + METHOD counts_by_date. + DATA lt_sess TYPE STANDARD TABLE OF {{p}}sess WITH EMPTY KEY. + DATA lv_day TYPE d. + lv_day = '20250301'. + lt_sess = VALUE #( + ( client = sy-mandt studio_id = 'R1' session_no = '000010' + customer = 'CUST10' session_date = lv_day booked_hours = '1.00' + rate_mode = 'STD' tariff_group = 'A' track_count = 1 + session_value = '80.00' ) + ( client = sy-mandt studio_id = 'R2' session_no = '000011' + customer = 'CUST11' session_date = '20250302' booked_hours = '2.00' + rate_mode = 'STD' tariff_group = 'A' track_count = 2 + session_value = '160.00' ) ). + go_env->insert_test_data( lt_sess ). + SELECT COUNT(*) FROM {{p}}sess WHERE session_date = @lv_day INTO @DATA(lv_count). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lv_count ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1952/spec.md b/tasks_gen/train/G1952/spec.md new file mode 100644 index 0000000..99a9496 --- /dev/null +++ b/tasks_gen/train/G1952/spec.md @@ -0,0 +1,59 @@ +# 1. Goal +The recording studio "Blue Room" rents its rooms to customers by the hour. Store +every recording session in one database table. The booking desk, an invoicing +program and an OData service read the same table. + +# 2. Open questions +None. + +# 3. Context +- The studio has several rooms. Each room has a room code of 4 characters. +- A customer books a session in a room. The studio numbers the sessions of a + room from 000001. +- For each session the studio records the date, the booked hours, the rate mode, + the tariff group, the number of recorded tracks and the value of the session. +- The table is client-dependent. The client field is the first key field. +- The table is in package $TMP. + +# 4. Contract +- Create the transparent database table {{P}}SESS in package $TMP. +- The table has these fields, in this order: client, studio_id, session_no, + customer, session_date, booked_hours, rate_mode, tariff_group, track_count, + session_value. +- The key fields are client, studio_id and session_no. +- The table has no other fields. + +# 5. Business rules +1. The fields have the names, the types and the lengths of this table: + +| Field | Type | Length | Decimals | Key | +| --- | --- | --- | --- | --- | +| client | abap.clnt | 3 | 0 | yes | +| studio_id | abap.char | 4 | 0 | yes | +| session_no | abap.numc | 6 | 0 | yes | +| customer | abap.char | 10 | 0 | no | +| session_date | abap.dats | 8 | 0 | no | +| booked_hours | abap.dec | 5 | 2 | no | +| rate_mode | abap.char | 4 | 0 | no | +| tariff_group | abap.char | 4 | 0 | no | +| track_count | abap.int4 | 10 | 0 | no | +| session_value | abap.dec | 15 | 2 | no | + +2. The combination of client, studio_id and session_no is the key of the table. + This combination occurs at most once in the table. +3. booked_hours is the number of booked hours with 2 decimal places. +4. session_value is the value of one session with 2 decimal places. +5. The field names are not ABAP SQL reserved words. Words such as HOURS, MODE, + ORDER, DATE, COUNT, GROUP and VALUE are not permitted as field names. Use the + names of the contract. + +# 6. Constraints +- Release target: SAP_BASIS 816 (ABAP Platform 2025). +- Package $TMP. Do not use transports. +- Use Clean ABAP. +- Out of scope: do not create or change other objects. + +# 7. Acceptance +- The table is active and has no syntax error. +- The hidden tests pass. +- Write ABAP Unit tests in a global test class. Use CL_OSQL_TEST_ENVIRONMENT. diff --git a/tasks_gen/train/G1952/task.json b/tasks_gen/train/G1952/task.json new file mode 100644 index 0000000..c1d7ed2 --- /dev/null +++ b/tasks_gen/train/G1952/task.json @@ -0,0 +1,55 @@ +{ + "id": "G1952", + "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}}SESS", + "fields": [ + "client", + "studio_id", + "session_no", + "customer", + "session_date", + "booked_hours", + "rate_mode", + "tariff_group", + "track_count", + "session_value" + ] + } + ], + "out_of_scope": [], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T16_HIDDEN", + "file": "hidden/t16_hidden.clas.abap", + "description": "RTTI checks on {{P}}SESS and CL_OSQL_TEST_ENVIRONMENT checks" + } + ], + "reference": [ + { + "type": "TABL", + "name": "{{P}}SESS", + "file": "reference/sess.tabl.asabap", + "description": "Recording sessions of the studio" + }, + { + "type": "CLAS", + "name": "{{P}}T16_TEST", + "file": "reference/t16_test.clas.abap", + "description": "Own tests for {{P}}SESS" + } + ], + "craft_checks": [] +} \ No newline at end of file diff --git a/tasks_gen/train/G1953/generation.json b/tasks_gen/train/G1953/generation.json new file mode 100644 index 0000000..576b34f --- /dev/null +++ b/tasks_gen/train/G1953/generation.json @@ -0,0 +1,35 @@ +{ + "id": "G1953", + "pool": "train", + "object_type": "INTF", + "category": "A", + "attempts": [ + { + "stage": "bundle", + "errors": [ + "Too close to task G1916 (similarity spec 0.61, rules 0.65, names 0.33). Choose a different business topic and different object names.", + "Too close to task G1918 (similarity spec 0.53, rules 0.60, names 0.00). Choose a different business topic and different object names.", + "Too close to task G1933 (similarity spec 0.56, rules 0.64, names 0.00). Choose a different business topic and different object names." + ], + "by_check": { + "extra": 3 + } + }, + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 79.9, + "null": 0 + }, + { + "stage": "validate", + "oracle": 81.4, + "null": 0 + } + ], + "accepted": false +} \ No newline at end of file diff --git a/tasks_gen/train/G1953/hidden/t44_hidden.clas.abap b/tasks_gen/train/G1953/hidden/t44_hidden.clas.abap new file mode 100644 index 0000000..a5c7087 --- /dev/null +++ b/tasks_gen/train/G1953/hidden/t44_hidden.clas.abap @@ -0,0 +1,149 @@ +CLASS {{p}}t44_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PUBLIC SECTION. + INTERFACES {{p}}if_piano_tuning. + PRIVATE SECTION. + DATA mo_cut TYPE REF TO {{p}}if_piano_tuning. + METHODS setup. + METHODS code_values FOR TESTING. + METHODS number_values FOR TESTING. + METHODS type_lengths FOR TESTING. + METHODS visit_components FOR TESTING. + METHODS summary_components FOR TESTING. + METHODS visit_table FOR TESTING. + METHODS check_visit_signature FOR TESTING. + METHODS check_visits_signature FOR TESTING. + METHODS summarise_signature FOR TESTING. + METHODS count_blocked_signature FOR TESTING. + METHODS model_signature FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t44_hidden IMPLEMENTATION. + METHOD {{p}}if_piano_tuning~check_visit. + rv_code = {{p}}if_piano_tuning=>c_code-ok. + ENDMETHOD. + + METHOD {{p}}if_piano_tuning~check_visits. + rv_code = {{p}}if_piano_tuning=>c_code-ok. + ENDMETHOD. + + METHOD {{p}}if_piano_tuning~summarise. + rs_summary = VALUE #( accepted = lines( it_visits ) + first_code = {{p}}if_piano_tuning=>c_code-ok ). + ENDMETHOD. + + METHOD {{p}}if_piano_tuning~count_blocked. + ev_count = lines( it_visits ). + ev_code = {{p}}if_piano_tuning=>c_code-ok. + ENDMETHOD. + + METHOD {{p}}if_piano_tuning~is_tuning_model. + rv_tuning = abap_true. + ENDMETHOD. + + METHOD setup. + mo_cut = me. + ENDMETHOD. + + METHOD code_values. + cl_abap_unit_assert=>assert_equals( exp = 'OK' act = {{p}}if_piano_tuning=>c_code-ok ). + cl_abap_unit_assert=>assert_equals( exp = 'NO_VISIT' act = {{p}}if_piano_tuning=>c_code-no_visit ). + cl_abap_unit_assert=>assert_equals( exp = 'MODEL' act = {{p}}if_piano_tuning=>c_code-model ). + cl_abap_unit_assert=>assert_equals( exp = 'PITCH' act = {{p}}if_piano_tuning=>c_code-pitch ). + cl_abap_unit_assert=>assert_equals( exp = 'DISTANCE' act = {{p}}if_piano_tuning=>c_code-distance ). + cl_abap_unit_assert=>assert_equals( exp = 'COUNT' act = {{p}}if_piano_tuning=>c_code-too_many ). + ENDMETHOD. + + METHOD number_values. + cl_abap_unit_assert=>assert_equals( exp = 25 act = {{p}}if_piano_tuning=>c_max_pitch ). + cl_abap_unit_assert=>assert_equals( exp = 60 act = {{p}}if_piano_tuning=>c_max_distance ). + cl_abap_unit_assert=>assert_equals( exp = 3 act = {{p}}if_piano_tuning=>c_max_pianos ). + ENDMETHOD. + + METHOD type_lengths. + DATA lv_code TYPE {{p}}if_piano_tuning=>ty_code. + DATA lv_model TYPE {{p}}if_piano_tuning=>ty_model. + DATA lv_visit_id TYPE {{p}}if_piano_tuning=>ty_visit_id. + cl_abap_unit_assert=>assert_equals( + exp = 10 + act = cl_abap_typedescr=>describe_by_data( lv_code )->length ). + cl_abap_unit_assert=>assert_equals( + exp = 4 + act = cl_abap_typedescr=>describe_by_data( lv_model )->length ). + cl_abap_unit_assert=>assert_equals( + exp = 8 + act = cl_abap_typedescr=>describe_by_data( lv_visit_id )->length ). + ENDMETHOD. + + METHOD visit_components. + DATA ls_visit TYPE {{p}}if_piano_tuning=>ty_visit. + ls_visit-visit_id = 'V-000001'. + ls_visit-model = 'UPRI'. + ls_visit-pitch_dev = 12. + ls_visit-distance_km = 30. + ls_visit-piano_count = 2. + cl_abap_unit_assert=>assert_equals( exp = 'UPRI' act = ls_visit-model ). + cl_abap_unit_assert=>assert_equals( exp = 12 act = ls_visit-pitch_dev ). + cl_abap_unit_assert=>assert_equals( exp = 30 act = ls_visit-distance_km ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = ls_visit-piano_count ). + ENDMETHOD. + + METHOD summary_components. + DATA ls_summary TYPE {{p}}if_piano_tuning=>ty_summary. + ls_summary-accepted = 7. + ls_summary-rejected = 3. + ls_summary-first_code = {{p}}if_piano_tuning=>c_code-pitch. + cl_abap_unit_assert=>assert_equals( exp = 7 act = ls_summary-accepted ). + cl_abap_unit_assert=>assert_equals( exp = 3 act = ls_summary-rejected ). + ENDMETHOD. + + METHOD visit_table. + DATA lt_visits TYPE {{p}}if_piano_tuning=>tt_visits. + DATA ls_visit TYPE {{p}}if_piano_tuning=>ty_visit. + ls_visit-visit_id = 'V-000002'. + INSERT ls_visit INTO TABLE lt_visits. + cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_visits ) ). + ENDMETHOD. + + METHOD check_visit_signature. + DATA ls_visit TYPE {{p}}if_piano_tuning=>ty_visit. + ls_visit-visit_id = 'V-000003'. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_piano_tuning=>c_code-ok + act = mo_cut->check_visit( is_visit = ls_visit ) ). + ENDMETHOD. + + METHOD check_visits_signature. + DATA lt_visits TYPE {{p}}if_piano_tuning=>tt_visits. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_piano_tuning=>c_code-ok + act = mo_cut->check_visits( it_visits = lt_visits ) ). + ENDMETHOD. + + METHOD summarise_signature. + DATA lt_visits TYPE {{p}}if_piano_tuning=>tt_visits. + DATA ls_summary TYPE {{p}}if_piano_tuning=>ty_summary. + ls_summary = mo_cut->summarise( it_visits = lt_visits ). + cl_abap_unit_assert=>assert_equals( exp = 0 act = ls_summary-accepted ). + ENDMETHOD. + + METHOD count_blocked_signature. + DATA lt_visits TYPE {{p}}if_piano_tuning=>tt_visits. + DATA lv_count TYPE i. + DATA lv_code TYPE {{p}}if_piano_tuning=>ty_code. + mo_cut->count_blocked( + EXPORTING it_visits = lt_visits + IMPORTING ev_count = lv_count + ev_code = lv_code ). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_count ). + ENDMETHOD. + + METHOD model_signature. + DATA lv_model TYPE {{p}}if_piano_tuning=>ty_model. + lv_model = 'UPRI'. + cl_abap_unit_assert=>assert_equals( + exp = abap_true + act = mo_cut->is_tuning_model( iv_model = lv_model ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1953/mutation.json b/tasks_gen/train/G1953/mutation.json new file mode 100644 index 0000000..b429d23 --- /dev/null +++ b/tasks_gen/train/G1953/mutation.json @@ -0,0 +1,8 @@ +{ + "task": "T44", + "mutants": [], + "valid": 0, + "killed": 0, + "kill_rate": 0.0, + "ok": true +} diff --git a/tasks_gen/train/G1953/reference/if_piano_tuning.intf.abap b/tasks_gen/train/G1953/reference/if_piano_tuning.intf.abap new file mode 100644 index 0000000..e3ede1d --- /dev/null +++ b/tasks_gen/train/G1953/reference/if_piano_tuning.intf.abap @@ -0,0 +1,53 @@ +INTERFACE {{p}}if_piano_tuning PUBLIC. + TYPES: + ty_code TYPE c LENGTH 10, + ty_model TYPE c LENGTH 4, + ty_visit_id TYPE c LENGTH 8, + BEGIN OF ty_visit, + visit_id TYPE ty_visit_id, + model TYPE ty_model, + pitch_dev TYPE i, + distance_km TYPE i, + piano_count TYPE i, + END OF ty_visit, + tt_visits TYPE STANDARD TABLE OF ty_visit WITH EMPTY KEY, + BEGIN OF ty_summary, + accepted TYPE i, + rejected TYPE i, + first_code TYPE ty_code, + END OF ty_summary. + + CONSTANTS: + BEGIN OF c_code, + ok TYPE ty_code VALUE 'OK', + no_visit TYPE ty_code VALUE 'NO_VISIT', + model TYPE ty_code VALUE 'MODEL', + pitch TYPE ty_code VALUE 'PITCH', + distance TYPE ty_code VALUE 'DISTANCE', + too_many TYPE ty_code VALUE 'COUNT', + END OF c_code, + c_max_pitch TYPE i VALUE 25, + c_max_distance TYPE i VALUE 60, + c_max_pianos TYPE i VALUE 3. + + METHODS check_visit + IMPORTING is_visit TYPE ty_visit + RETURNING VALUE(rv_code) TYPE ty_code. + + METHODS check_visits + IMPORTING it_visits TYPE tt_visits + RETURNING VALUE(rv_code) TYPE ty_code. + + METHODS summarise + IMPORTING it_visits TYPE tt_visits + RETURNING VALUE(rs_summary) TYPE ty_summary. + + METHODS count_blocked + IMPORTING it_visits TYPE tt_visits + EXPORTING ev_count TYPE i + ev_code TYPE ty_code. + + METHODS is_tuning_model + IMPORTING iv_model TYPE ty_model + RETURNING VALUE(rv_tuning) TYPE abap_bool. +ENDINTERFACE. diff --git a/tasks_gen/train/G1953/reference/piano_tuning_test.clas.abap b/tasks_gen/train/G1953/reference/piano_tuning_test.clas.abap new file mode 100644 index 0000000..27f6cbd --- /dev/null +++ b/tasks_gen/train/G1953/reference/piano_tuning_test.clas.abap @@ -0,0 +1,110 @@ +CLASS {{p}}piano_tuning_test DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PUBLIC SECTION. + INTERFACES {{p}}if_piano_tuning. + PRIVATE SECTION. + DATA mo_cut TYPE REF TO {{p}}if_piano_tuning. + METHODS setup. + METHODS code_values FOR TESTING. + METHODS number_values FOR TESTING. + METHODS type_lengths FOR TESTING. + METHODS visit_structure FOR TESTING. + METHODS methods_are_callable FOR TESTING. +ENDCLASS. + + +CLASS {{p}}piano_tuning_test IMPLEMENTATION. + METHOD {{p}}if_piano_tuning~check_visit. + rv_code = {{p}}if_piano_tuning=>c_code-ok. + ENDMETHOD. + + METHOD {{p}}if_piano_tuning~check_visits. + rv_code = {{p}}if_piano_tuning=>c_code-ok. + ENDMETHOD. + + METHOD {{p}}if_piano_tuning~summarise. + rs_summary = VALUE #( accepted = lines( it_visits ) + first_code = {{p}}if_piano_tuning=>c_code-ok ). + ENDMETHOD. + + METHOD {{p}}if_piano_tuning~count_blocked. + ev_count = lines( it_visits ). + ev_code = {{p}}if_piano_tuning=>c_code-ok. + ENDMETHOD. + + METHOD {{p}}if_piano_tuning~is_tuning_model. + rv_tuning = abap_true. + ENDMETHOD. + + METHOD setup. + mo_cut = me. + ENDMETHOD. + + METHOD code_values. + cl_abap_unit_assert=>assert_equals( exp = 'OK' act = {{p}}if_piano_tuning=>c_code-ok ). + cl_abap_unit_assert=>assert_equals( exp = 'NO_VISIT' act = {{p}}if_piano_tuning=>c_code-no_visit ). + cl_abap_unit_assert=>assert_equals( exp = 'MODEL' act = {{p}}if_piano_tuning=>c_code-model ). + cl_abap_unit_assert=>assert_equals( exp = 'PITCH' act = {{p}}if_piano_tuning=>c_code-pitch ). + cl_abap_unit_assert=>assert_equals( exp = 'DISTANCE' act = {{p}}if_piano_tuning=>c_code-distance ). + cl_abap_unit_assert=>assert_equals( exp = 'COUNT' act = {{p}}if_piano_tuning=>c_code-too_many ). + ENDMETHOD. + + METHOD number_values. + cl_abap_unit_assert=>assert_equals( exp = 25 act = {{p}}if_piano_tuning=>c_max_pitch ). + cl_abap_unit_assert=>assert_equals( exp = 60 act = {{p}}if_piano_tuning=>c_max_distance ). + cl_abap_unit_assert=>assert_equals( exp = 3 act = {{p}}if_piano_tuning=>c_max_pianos ). + ENDMETHOD. + + METHOD type_lengths. + DATA lv_code TYPE {{p}}if_piano_tuning=>ty_code. + DATA lv_model TYPE {{p}}if_piano_tuning=>ty_model. + DATA lv_visit_id TYPE {{p}}if_piano_tuning=>ty_visit_id. + cl_abap_unit_assert=>assert_equals( + exp = 10 + act = cl_abap_typedescr=>describe_by_data( lv_code )->length ). + cl_abap_unit_assert=>assert_equals( + exp = 4 + act = cl_abap_typedescr=>describe_by_data( lv_model )->length ). + cl_abap_unit_assert=>assert_equals( + exp = 8 + act = cl_abap_typedescr=>describe_by_data( lv_visit_id )->length ). + ENDMETHOD. + + METHOD visit_structure. + DATA ls_visit TYPE {{p}}if_piano_tuning=>ty_visit. + DATA lt_visits TYPE {{p}}if_piano_tuning=>tt_visits. + ls_visit-visit_id = 'V-000010'. + ls_visit-model = 'UPRI'. + ls_visit-pitch_dev = 12. + ls_visit-distance_km = 30. + ls_visit-piano_count = 2. + INSERT ls_visit INTO TABLE lt_visits. + cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_visits ) ). + ENDMETHOD. + + METHOD methods_are_callable. + DATA ls_visit TYPE {{p}}if_piano_tuning=>ty_visit. + DATA lt_visits TYPE {{p}}if_piano_tuning=>tt_visits. + DATA ls_summary TYPE {{p}}if_piano_tuning=>ty_summary. + DATA lv_count TYPE i. + DATA lv_code TYPE {{p}}if_piano_tuning=>ty_code. + DATA lv_model TYPE {{p}}if_piano_tuning=>ty_model. + lv_model = 'UPRI'. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_piano_tuning=>c_code-ok + act = mo_cut->check_visit( ls_visit ) ). + cl_abap_unit_assert=>assert_equals( + exp = {{p}}if_piano_tuning=>c_code-ok + act = mo_cut->check_visits( lt_visits ) ). + ls_summary = mo_cut->summarise( lt_visits ). + cl_abap_unit_assert=>assert_equals( exp = 0 act = ls_summary-accepted ). + mo_cut->count_blocked( + EXPORTING it_visits = lt_visits + IMPORTING ev_count = lv_count + ev_code = lv_code ). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_count ). + cl_abap_unit_assert=>assert_equals( + exp = abap_true + act = mo_cut->is_tuning_model( lv_model ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1953/spec.md b/tasks_gen/train/G1953/spec.md new file mode 100644 index 0000000..30fdcd8 --- /dev/null +++ b/tasks_gen/train/G1953/spec.md @@ -0,0 +1,65 @@ +# 1. Goal +A mobile piano tuning service visits its customers at home. The booking desk and +the technician app must use the same contract when they check a tuning visit. +The contract is one interface. It fixes the result codes, the visit structure +and the check methods that both consumers use. + +# 2. Open questions +None. + +# 3. Context +- Package $TMP. +- The interface {{P}}IF_PIANO_TUNING does not exist yet. Create it. +- The booking desk checks one visit with CHECK_VISIT. The technician app checks a + whole round with CHECK_VISITS. The month report calls SUMMARISE and + COUNT_BLOCKED for a round. The appointment form calls IS_TUNING_MODEL. +- A result code tells the consumer why a visit is not planned: NO_VISIT for a + missing visit id, MODEL for a piano model that the service does not tune, + PITCH for a pitch deviation outside the tolerance, DISTANCE for a distance + above the maximum, and COUNT for a number of pianos above the maximum. + +# 4. Contract +- Create the interface {{P}}IF_PIANO_TUNING in package $TMP. +- Public types: TY_CODE, TY_MODEL, TY_VISIT_ID, TY_VISIT, TT_VISITS, TY_SUMMARY. +- Public constants: C_CODE, C_MAX_PITCH, C_MAX_DISTANCE, C_MAX_PIANOS. +- Public methods: CHECK_VISIT, CHECK_VISITS, SUMMARISE, COUNT_BLOCKED, + IS_TUNING_MODEL. +- Do not add other public components. + +# 5. Business rules +1. TY_CODE is a character type of length 10. +2. TY_MODEL is a character type of length 4. +3. TY_VISIT_ID is a character type of length 8. +4. TY_VISIT is a structure type with exactly these components, in this order: + VISIT_ID (type ty_visit_id), MODEL (type ty_model), PITCH_DEV (type i, the + deviation from concert pitch in cents), DISTANCE_KM (type i, the distance + from the depot in kilometres), PIANO_COUNT (type i). +5. TT_VISITS is a table type with the line type TY_VISIT. +6. TY_SUMMARY is a structure type with exactly these components, in this order: + ACCEPTED (type i), REJECTED (type i), FIRST_CODE (type ty_code). +7. C_CODE is a constant structure with exactly these components, all of type + ty_code: OK = 'OK', NO_VISIT = 'NO_VISIT', MODEL = 'MODEL', PITCH = 'PITCH', + DISTANCE = 'DISTANCE', TOO_MANY = 'COUNT'. +8. C_MAX_PITCH is a constant of type i with the value 25. +9. C_MAX_DISTANCE is a constant of type i with the value 60. +10. C_MAX_PIANOS is a constant of type i with the value 3. +11. CHECK_VISIT has the importing parameter IS_VISIT of type ty_visit and the + returning parameter RV_CODE of type ty_code. +12. CHECK_VISITS has the importing parameter IT_VISITS of type tt_visits and the + returning parameter RV_CODE of type ty_code. +13. SUMMARISE has the importing parameter IT_VISITS of type tt_visits and the + returning parameter RS_SUMMARY of type ty_summary. +14. COUNT_BLOCKED has the importing parameter IT_VISITS of type tt_visits and + the exporting parameters EV_COUNT of type i and EV_CODE of type ty_code. +15. IS_TUNING_MODEL has the importing parameter IV_MODEL of type ty_model and + the returning parameter RV_TUNING of type abap_bool. + +# 6. Constraints +- Release target: SAP_BASIS 816. +- Coding standards: Clean ABAP. No comment that restates the code. +- Out of scope: do not change other objects in package $TMP. + +# 7. Acceptance +- The interface {{P}}IF_PIANO_TUNING is active and has no syntax error. +- The hidden tests pass. +- Write your own ABAP Unit tests for the interface. diff --git a/tasks_gen/train/G1953/task.json b/tasks_gen/train/G1953/task.json new file mode 100644 index 0000000..d3ebff8 --- /dev/null +++ b/tasks_gen/train/G1953/task.json @@ -0,0 +1,48 @@ +{ + "id": "G1953", + "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_PIANO_TUNING" + } + ], + "out_of_scope": [ + "Other objects in package $TMP" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T44_HIDDEN", + "file": "hidden/t44_hidden.clas.abap", + "description": "T44 hidden tests. The global test class itself implements the interface, so it compiles only when every signature matches. The tests read the constant values, the component names and the type lengths with RTTI." + } + ], + "reference": [ + { + "type": "INTF", + "name": "{{P}}IF_PIANO_TUNING", + "file": "reference/if_piano_tuning.intf.abap", + "description": "Piano tuning visit contract" + }, + { + "type": "CLAS", + "name": "{{P}}PIANO_TUNING_TEST", + "file": "reference/piano_tuning_test.clas.abap", + "description": "Own global test class for the interface contract" + } + ], + "craft_checks": [ + "naming", + "interface_contract" + ] +} \ No newline at end of file diff --git a/tasks_gen/train/G1954/faulty/m0_if_sail_repair.intf.abap b/tasks_gen/train/G1954/faulty/m0_if_sail_repair.intf.abap new file mode 100644 index 0000000..eca0bad --- /dev/null +++ b/tasks_gen/train/G1954/faulty/m0_if_sail_repair.intf.abap @@ -0,0 +1,40 @@ +INTERFACE {{p}}if_sail_repair PUBLIC. + TYPES ty_reason TYPE c LENGTH 9. + TYPES ty_damage TYPE c LENGTH 4. + TYPES ty_cloth TYPE c LENGTH 4. + + CONSTANTS: + BEGIN OF c_reason, + ok TYPE ty_reason VALUE 'OK', + empty TYPE ty_reason VALUE 'EMPTY', + damage TYPE ty_reason VALUE 'DAMAGE', + cloth TYPE ty_reason VALUE 'CLOTH', + length TYPE ty_reason VALUE 'LENGTH', + rush TYPE ty_reason VALUE 'RUSH', + END OF c_reason. + + CONSTANTS: + BEGIN OF c_damage, + tear TYPE ty_damage VALUE 'TEAR', + seam TYPE ty_damage VALUE 'SEAM', + eylt TYPE ty_damage VALUE 'EYLT', + batt TYPE ty_damage VALUE 'BATT', + END OF c_damage. + + CONSTANTS: + BEGIN OF c_cloth, + lite TYPE ty_cloth VALUE 'LITE', + medm TYPE ty_cloth VALUE 'MEDM', + heav TYPE ty_cloth VALUE 'HEAV', + END OF c_cloth. + + CONSTANTS c_max_length TYPE i VALUE 400. + CONSTANTS c_rush_limit TYPE i VALUE 200. + + METHODS check_order + IMPORTING iv_damage TYPE ty_damage + iv_cloth TYPE ty_cloth + iv_length TYPE i + iv_rush TYPE abap_bool + RETURNING VALUE(rv_reason) TYPE ty_reason. +ENDINTERFACE. diff --git a/tasks_gen/train/G1954/faulty/m1_if_sail_repair.intf.abap b/tasks_gen/train/G1954/faulty/m1_if_sail_repair.intf.abap new file mode 100644 index 0000000..78ac851 --- /dev/null +++ b/tasks_gen/train/G1954/faulty/m1_if_sail_repair.intf.abap @@ -0,0 +1,40 @@ +INTERFACE {{p}}if_sail_repair PUBLIC. + TYPES ty_reason TYPE c LENGTH 10. + TYPES ty_damage TYPE c LENGTH 3. + TYPES ty_cloth TYPE c LENGTH 4. + + CONSTANTS: + BEGIN OF c_reason, + ok TYPE ty_reason VALUE 'OK', + empty TYPE ty_reason VALUE 'EMPTY', + damage TYPE ty_reason VALUE 'DAMAGE', + cloth TYPE ty_reason VALUE 'CLOTH', + length TYPE ty_reason VALUE 'LENGTH', + rush TYPE ty_reason VALUE 'RUSH', + END OF c_reason. + + CONSTANTS: + BEGIN OF c_damage, + tear TYPE ty_damage VALUE 'TEAR', + seam TYPE ty_damage VALUE 'SEAM', + eylt TYPE ty_damage VALUE 'EYLT', + batt TYPE ty_damage VALUE 'BATT', + END OF c_damage. + + CONSTANTS: + BEGIN OF c_cloth, + lite TYPE ty_cloth VALUE 'LITE', + medm TYPE ty_cloth VALUE 'MEDM', + heav TYPE ty_cloth VALUE 'HEAV', + END OF c_cloth. + + CONSTANTS c_max_length TYPE i VALUE 400. + CONSTANTS c_rush_limit TYPE i VALUE 200. + + METHODS check_order + IMPORTING iv_damage TYPE ty_damage + iv_cloth TYPE ty_cloth + iv_length TYPE i + iv_rush TYPE abap_bool + RETURNING VALUE(rv_reason) TYPE ty_reason. +ENDINTERFACE. diff --git a/tasks_gen/train/G1954/faulty/m2_if_sail_repair.intf.abap b/tasks_gen/train/G1954/faulty/m2_if_sail_repair.intf.abap new file mode 100644 index 0000000..425f921 --- /dev/null +++ b/tasks_gen/train/G1954/faulty/m2_if_sail_repair.intf.abap @@ -0,0 +1,40 @@ +INTERFACE {{p}}if_sail_repair PUBLIC. + TYPES ty_reason TYPE c LENGTH 10. + TYPES ty_damage TYPE c LENGTH 4. + TYPES ty_cloth TYPE c LENGTH 4. + + CONSTANTS: + BEGIN OF c_reason, + ok TYPE ty_reason VALUE 'OK', + empty TYPE ty_reason VALUE 'EMPTY', + damage TYPE ty_reason VALUE 'DAMAGE', + cloth TYPE ty_reason VALUE 'CLOTH', + length TYPE ty_reason VALUE 'LENGTH', + rush TYPE ty_reason VALUE 'RUSH', + END OF c_reason. + + CONSTANTS: + BEGIN OF c_damage, + tear TYPE ty_damage VALUE 'TEAR', + seam TYPE ty_damage VALUE 'SEAM', + eylt TYPE ty_damage VALUE 'ZYLT', + batt TYPE ty_damage VALUE 'BATT', + END OF c_damage. + + CONSTANTS: + BEGIN OF c_cloth, + lite TYPE ty_cloth VALUE 'LITE', + medm TYPE ty_cloth VALUE 'MEDM', + heav TYPE ty_cloth VALUE 'HEAV', + END OF c_cloth. + + CONSTANTS c_max_length TYPE i VALUE 400. + CONSTANTS c_rush_limit TYPE i VALUE 200. + + METHODS check_order + IMPORTING iv_damage TYPE ty_damage + iv_cloth TYPE ty_cloth + iv_length TYPE i + iv_rush TYPE abap_bool + RETURNING VALUE(rv_reason) TYPE ty_reason. +ENDINTERFACE. diff --git a/tasks_gen/train/G1954/faulty/m3_if_sail_repair.intf.abap b/tasks_gen/train/G1954/faulty/m3_if_sail_repair.intf.abap new file mode 100644 index 0000000..be9677e --- /dev/null +++ b/tasks_gen/train/G1954/faulty/m3_if_sail_repair.intf.abap @@ -0,0 +1,40 @@ +INTERFACE {{p}}if_sail_repair PUBLIC. + TYPES ty_reason TYPE c LENGTH 10. + TYPES ty_damage TYPE c LENGTH 4. + TYPES ty_cloth TYPE c LENGTH 4. + + CONSTANTS: + BEGIN OF c_reason, + ok TYPE ty_reason VALUE 'OK', + empty TYPE ty_reason VALUE 'EMPTY', + damage TYPE ty_reason VALUE 'DAMAGE', + cloth TYPE ty_reason VALUE 'CLOTH', + length TYPE ty_reason VALUE 'LENGTH', + rush TYPE ty_reason VALUE 'RUSH', + END OF c_reason. + + CONSTANTS: + BEGIN OF c_damage, + tear TYPE ty_damage VALUE 'TEAR', + seam TYPE ty_damage VALUE 'SEAM', + eylt TYPE ty_damage VALUE 'EYLT', + batt TYPE ty_damage VALUE 'ZATT', + END OF c_damage. + + CONSTANTS: + BEGIN OF c_cloth, + lite TYPE ty_cloth VALUE 'LITE', + medm TYPE ty_cloth VALUE 'MEDM', + heav TYPE ty_cloth VALUE 'HEAV', + END OF c_cloth. + + CONSTANTS c_max_length TYPE i VALUE 400. + CONSTANTS c_rush_limit TYPE i VALUE 200. + + METHODS check_order + IMPORTING iv_damage TYPE ty_damage + iv_cloth TYPE ty_cloth + iv_length TYPE i + iv_rush TYPE abap_bool + RETURNING VALUE(rv_reason) TYPE ty_reason. +ENDINTERFACE. diff --git a/tasks_gen/train/G1954/faulty/m4_if_sail_repair.intf.abap b/tasks_gen/train/G1954/faulty/m4_if_sail_repair.intf.abap new file mode 100644 index 0000000..3e8cdad --- /dev/null +++ b/tasks_gen/train/G1954/faulty/m4_if_sail_repair.intf.abap @@ -0,0 +1,40 @@ +INTERFACE {{p}}if_sail_repair PUBLIC. + TYPES ty_reason TYPE c LENGTH 10. + TYPES ty_damage TYPE c LENGTH 4. + TYPES ty_cloth TYPE c LENGTH 4. + + CONSTANTS: + BEGIN OF c_reason, + ok TYPE ty_reason VALUE 'OK', + empty TYPE ty_reason VALUE 'EMPTY', + damage TYPE ty_reason VALUE 'DAMAGE', + cloth TYPE ty_reason VALUE 'CLOTH', + length TYPE ty_reason VALUE 'LENGTH', + rush TYPE ty_reason VALUE 'RUSH', + END OF c_reason. + + CONSTANTS: + BEGIN OF c_damage, + tear TYPE ty_damage VALUE 'TEAR', + seam TYPE ty_damage VALUE 'SEAM', + eylt TYPE ty_damage VALUE 'EYLT', + batt TYPE ty_damage VALUE 'BATT', + END OF c_damage. + + CONSTANTS: + BEGIN OF c_cloth, + lite TYPE ty_cloth VALUE 'LITE', + medm TYPE ty_cloth VALUE 'MEDM', + heav TYPE ty_cloth VALUE 'HEAV', + END OF c_cloth. + + CONSTANTS c_max_length TYPE i VALUE 400. + CONSTANTS c_rush_limit TYPE i VALUE 201. + + METHODS check_order + IMPORTING iv_damage TYPE ty_damage + iv_cloth TYPE ty_cloth + iv_length TYPE i + iv_rush TYPE abap_bool + RETURNING VALUE(rv_reason) TYPE ty_reason. +ENDINTERFACE. diff --git a/tasks_gen/train/G1954/generation.json b/tasks_gen/train/G1954/generation.json new file mode 100644 index 0000000..ce6e479 --- /dev/null +++ b/tasks_gen/train/G1954/generation.json @@ -0,0 +1,34 @@ +{ + "id": "G1954", + "pool": "train", + "object_type": "INTF", + "category": "A", + "attempts": [ + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 81.4, + "null": 0 + }, + { + "stage": "validate", + "oracle": 81.4, + "null": 0 + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 5, + "killed": 5, + "ok": true + } + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1954/hidden/t02_hidden.clas.abap b/tasks_gen/train/G1954/hidden/t02_hidden.clas.abap new file mode 100644 index 0000000..2e69fc6 --- /dev/null +++ b/tasks_gen/train/G1954/hidden/t02_hidden.clas.abap @@ -0,0 +1,105 @@ +CLASS {{p}}t02_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS reason_ok FOR TESTING. + METHODS reason_empty FOR TESTING. + METHODS reason_damage FOR TESTING. + METHODS reason_cloth FOR TESTING. + METHODS reason_length FOR TESTING. + METHODS reason_rush FOR TESTING. + METHODS damage_codes FOR TESTING. + METHODS cloth_codes FOR TESTING. + METHODS limits FOR TESTING. + METHODS type_lengths FOR TESTING. + METHODS method_signature FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t02_hidden IMPLEMENTATION. + METHOD reason_ok. + cl_abap_unit_assert=>assert_equals( exp = 'OK' + act = {{p}}if_sail_repair=>c_reason-ok ). + ENDMETHOD. + + METHOD reason_empty. + cl_abap_unit_assert=>assert_equals( exp = 'EMPTY' + act = {{p}}if_sail_repair=>c_reason-empty ). + ENDMETHOD. + + METHOD reason_damage. + cl_abap_unit_assert=>assert_equals( exp = 'DAMAGE' + act = {{p}}if_sail_repair=>c_reason-damage ). + ENDMETHOD. + + METHOD reason_cloth. + cl_abap_unit_assert=>assert_equals( exp = 'CLOTH' + act = {{p}}if_sail_repair=>c_reason-cloth ). + ENDMETHOD. + + METHOD reason_length. + cl_abap_unit_assert=>assert_equals( exp = 'LENGTH' + act = {{p}}if_sail_repair=>c_reason-length ). + ENDMETHOD. + + METHOD reason_rush. + cl_abap_unit_assert=>assert_equals( exp = 'RUSH' + act = {{p}}if_sail_repair=>c_reason-rush ). + ENDMETHOD. + + METHOD damage_codes. + cl_abap_unit_assert=>assert_equals( exp = 'TEAR' + act = {{p}}if_sail_repair=>c_damage-tear ). + cl_abap_unit_assert=>assert_equals( exp = 'SEAM' + act = {{p}}if_sail_repair=>c_damage-seam ). + cl_abap_unit_assert=>assert_equals( exp = 'EYLT' + act = {{p}}if_sail_repair=>c_damage-eylt ). + cl_abap_unit_assert=>assert_equals( exp = 'BATT' + act = {{p}}if_sail_repair=>c_damage-batt ). + ENDMETHOD. + + METHOD cloth_codes. + cl_abap_unit_assert=>assert_equals( exp = 'LITE' + act = {{p}}if_sail_repair=>c_cloth-lite ). + cl_abap_unit_assert=>assert_equals( exp = 'MEDM' + act = {{p}}if_sail_repair=>c_cloth-medm ). + cl_abap_unit_assert=>assert_equals( exp = 'HEAV' + act = {{p}}if_sail_repair=>c_cloth-heav ). + ENDMETHOD. + + METHOD limits. + cl_abap_unit_assert=>assert_equals( exp = 400 + act = {{p}}if_sail_repair=>c_max_length ). + cl_abap_unit_assert=>assert_equals( exp = 200 + act = {{p}}if_sail_repair=>c_rush_limit ). + ENDMETHOD. + + METHOD type_lengths. + DATA lv_reason TYPE {{p}}if_sail_repair=>ty_reason. + DATA lv_damage TYPE {{p}}if_sail_repair=>ty_damage. + DATA lv_cloth TYPE {{p}}if_sail_repair=>ty_cloth. + DATA lv_long TYPE string. + lv_long = 'ABCDEFGHIJKLMNOP'. + lv_reason = lv_long. + lv_damage = lv_long. + lv_cloth = lv_long. + cl_abap_unit_assert=>assert_equals( exp = 'ABCDEFGHIJ' act = lv_reason ). + cl_abap_unit_assert=>assert_equals( exp = 'ABCD' act = lv_damage ). + cl_abap_unit_assert=>assert_equals( exp = 'ABCD' act = lv_cloth ). + ENDMETHOD. + + METHOD method_signature. + DATA lo_order TYPE REF TO {{p}}if_sail_repair. + DATA lv_reason TYPE {{p}}if_sail_repair=>ty_reason. + TRY. + lv_reason = lo_order->check_order( + iv_damage = {{p}}if_sail_repair=>c_damage-tear + iv_cloth = {{p}}if_sail_repair=>c_cloth-lite + iv_length = 150 + iv_rush = abap_false ). + CATCH cx_sy_ref_is_initial. + lv_reason = {{p}}if_sail_repair=>c_reason-ok. + ENDTRY. + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_sail_repair=>c_reason-ok + act = lv_reason ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1954/mutation.json b/tasks_gen/train/G1954/mutation.json new file mode 100644 index 0000000..bbd6a9c --- /dev/null +++ b/tasks_gen/train/G1954/mutation.json @@ -0,0 +1,55 @@ +{ + "task": "G1954", + "mutants": [ + { + "object": "{{P}}IF_SAIL_REPAIR", + "mutant": "line 2: LENGTH 10 -> LENGTH 9 (length)", + "status": "killed", + "hidden": "10/11", + "failed_tests": [ + "TYPE_LENGTHS" + ] + }, + { + "object": "{{P}}IF_SAIL_REPAIR", + "mutant": "line 3: LENGTH 4 -> LENGTH 3 (length)", + "status": "killed", + "hidden": "9/11", + "failed_tests": [ + "DAMAGE_CODES", + "TYPE_LENGTHS" + ] + }, + { + "object": "{{P}}IF_SAIL_REPAIR", + "mutant": "line 20: VALUE 'EYLT' -> VALUE 'ZYLT' (lit)", + "status": "killed", + "hidden": "10/11", + "failed_tests": [ + "DAMAGE_CODES" + ] + }, + { + "object": "{{P}}IF_SAIL_REPAIR", + "mutant": "line 21: VALUE 'BATT' -> VALUE 'ZATT' (lit)", + "status": "killed", + "hidden": "10/11", + "failed_tests": [ + "DAMAGE_CODES" + ] + }, + { + "object": "{{P}}IF_SAIL_REPAIR", + "mutant": "line 32: VALUE 200 -> VALUE 201 (const)", + "status": "killed", + "hidden": "10/11", + "failed_tests": [ + "LIMITS" + ] + } + ], + "valid": 5, + "killed": 5, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1954/reference/cl_sail_repair_test.clas.abap b/tasks_gen/train/G1954/reference/cl_sail_repair_test.clas.abap new file mode 100644 index 0000000..1c7f91f --- /dev/null +++ b/tasks_gen/train/G1954/reference/cl_sail_repair_test.clas.abap @@ -0,0 +1,81 @@ +CLASS {{p}}cl_sail_repair_test DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS reason_codes FOR TESTING. + METHODS code_lists FOR TESTING. + METHODS limits FOR TESTING. + METHODS type_lengths FOR TESTING. + METHODS method_signature FOR TESTING. +ENDCLASS. + + +CLASS {{p}}cl_sail_repair_test IMPLEMENTATION. + METHOD reason_codes. + cl_abap_unit_assert=>assert_equals( exp = 'OK' + act = {{p}}if_sail_repair=>c_reason-ok ). + cl_abap_unit_assert=>assert_equals( exp = 'EMPTY' + act = {{p}}if_sail_repair=>c_reason-empty ). + cl_abap_unit_assert=>assert_equals( exp = 'DAMAGE' + act = {{p}}if_sail_repair=>c_reason-damage ). + cl_abap_unit_assert=>assert_equals( exp = 'CLOTH' + act = {{p}}if_sail_repair=>c_reason-cloth ). + cl_abap_unit_assert=>assert_equals( exp = 'LENGTH' + act = {{p}}if_sail_repair=>c_reason-length ). + cl_abap_unit_assert=>assert_equals( exp = 'RUSH' + act = {{p}}if_sail_repair=>c_reason-rush ). + ENDMETHOD. + + METHOD code_lists. + cl_abap_unit_assert=>assert_equals( exp = 'TEAR' + act = {{p}}if_sail_repair=>c_damage-tear ). + cl_abap_unit_assert=>assert_equals( exp = 'SEAM' + act = {{p}}if_sail_repair=>c_damage-seam ). + cl_abap_unit_assert=>assert_equals( exp = 'EYLT' + act = {{p}}if_sail_repair=>c_damage-eylt ). + cl_abap_unit_assert=>assert_equals( exp = 'BATT' + act = {{p}}if_sail_repair=>c_damage-batt ). + cl_abap_unit_assert=>assert_equals( exp = 'LITE' + act = {{p}}if_sail_repair=>c_cloth-lite ). + cl_abap_unit_assert=>assert_equals( exp = 'MEDM' + act = {{p}}if_sail_repair=>c_cloth-medm ). + cl_abap_unit_assert=>assert_equals( exp = 'HEAV' + act = {{p}}if_sail_repair=>c_cloth-heav ). + ENDMETHOD. + + METHOD limits. + cl_abap_unit_assert=>assert_equals( exp = 400 + act = {{p}}if_sail_repair=>c_max_length ). + cl_abap_unit_assert=>assert_equals( exp = 200 + act = {{p}}if_sail_repair=>c_rush_limit ). + ENDMETHOD. + + METHOD type_lengths. + DATA lv_reason TYPE {{p}}if_sail_repair=>ty_reason. + DATA lv_damage TYPE {{p}}if_sail_repair=>ty_damage. + DATA lv_cloth TYPE {{p}}if_sail_repair=>ty_cloth. + DATA lv_long TYPE string. + lv_long = 'ABCDEFGHIJKLMNOP'. + lv_reason = lv_long. + lv_damage = lv_long. + lv_cloth = lv_long. + cl_abap_unit_assert=>assert_equals( exp = 'ABCDEFGHIJ' act = lv_reason ). + cl_abap_unit_assert=>assert_equals( exp = 'ABCD' act = lv_damage ). + cl_abap_unit_assert=>assert_equals( exp = 'ABCD' act = lv_cloth ). + ENDMETHOD. + + METHOD method_signature. + DATA lo_order TYPE REF TO {{p}}if_sail_repair. + DATA lv_reason TYPE {{p}}if_sail_repair=>ty_reason. + TRY. + lv_reason = lo_order->check_order( + iv_damage = {{p}}if_sail_repair=>c_damage-seam + iv_cloth = {{p}}if_sail_repair=>c_cloth-heav + iv_length = 250 + iv_rush = abap_true ). + CATCH cx_sy_ref_is_initial. + lv_reason = {{p}}if_sail_repair=>c_reason-ok. + ENDTRY. + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_sail_repair=>c_reason-ok + act = lv_reason ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1954/reference/if_sail_repair.intf.abap b/tasks_gen/train/G1954/reference/if_sail_repair.intf.abap new file mode 100644 index 0000000..ee0b10b --- /dev/null +++ b/tasks_gen/train/G1954/reference/if_sail_repair.intf.abap @@ -0,0 +1,40 @@ +INTERFACE {{p}}if_sail_repair PUBLIC. + TYPES ty_reason TYPE c LENGTH 10. + TYPES ty_damage TYPE c LENGTH 4. + TYPES ty_cloth TYPE c LENGTH 4. + + CONSTANTS: + BEGIN OF c_reason, + ok TYPE ty_reason VALUE 'OK', + empty TYPE ty_reason VALUE 'EMPTY', + damage TYPE ty_reason VALUE 'DAMAGE', + cloth TYPE ty_reason VALUE 'CLOTH', + length TYPE ty_reason VALUE 'LENGTH', + rush TYPE ty_reason VALUE 'RUSH', + END OF c_reason. + + CONSTANTS: + BEGIN OF c_damage, + tear TYPE ty_damage VALUE 'TEAR', + seam TYPE ty_damage VALUE 'SEAM', + eylt TYPE ty_damage VALUE 'EYLT', + batt TYPE ty_damage VALUE 'BATT', + END OF c_damage. + + CONSTANTS: + BEGIN OF c_cloth, + lite TYPE ty_cloth VALUE 'LITE', + medm TYPE ty_cloth VALUE 'MEDM', + heav TYPE ty_cloth VALUE 'HEAV', + END OF c_cloth. + + CONSTANTS c_max_length TYPE i VALUE 400. + CONSTANTS c_rush_limit TYPE i VALUE 200. + + METHODS check_order + IMPORTING iv_damage TYPE ty_damage + iv_cloth TYPE ty_cloth + iv_length TYPE i + iv_rush TYPE abap_bool + RETURNING VALUE(rv_reason) TYPE ty_reason. +ENDINTERFACE. diff --git a/tasks_gen/train/G1954/spec.md b/tasks_gen/train/G1954/spec.md new file mode 100644 index 0000000..905534f --- /dev/null +++ b/tasks_gen/train/G1954/spec.md @@ -0,0 +1,62 @@ +# 1. Goal +A sailmaker loft repairs sails for yacht owners. Two intake points send a repair +order to the same check: the loft counter and the online form. Both intake points +and the loft work with one interface. The interface is the shared contract of the +repair order check. It holds the codes, the limits and the method signature. + +# 2. Open questions +None. + +# 3. Context +- The interface {{P}}IF_SAIL_REPAIR does not exist yet. Create it in package $TMP. +- A repair order has a damage code, a cloth code, the damaged length in + centimetres, and a rush flag. +- The loft knows four damage codes, three cloth codes and two limits. +- The intake points call the method of the interface before they accept an order. + +# 4. Contract +- Create the interface {{P}}IF_SAIL_REPAIR in package $TMP. +- The interface has these public types: TY_REASON (character 10), + TY_DAMAGE (character 4) and TY_CLOTH (character 4). +- The interface has the public constant structure C_REASON with the components + OK, EMPTY, DAMAGE, CLOTH, LENGTH and RUSH. Each component has the type + TY_REASON. +- The interface has the public constant structure C_DAMAGE with the components + TEAR, SEAM, EYLT and BATT. Each component has the type TY_DAMAGE. +- The interface has the public constant structure C_CLOTH with the components + LITE, MEDM and HEAV. Each component has the type TY_CLOTH. +- The interface has the public constants C_MAX_LENGTH and C_RUSH_LIMIT, both of + type I. +- The interface has one method CHECK_ORDER with the importing parameters + IV_DAMAGE (type TY_DAMAGE), IV_CLOTH (type TY_CLOTH), IV_LENGTH (type I) and + IV_RUSH (type ABAP_BOOL) and the returning parameter RV_REASON (type + TY_REASON). +- Do not add other public components. + +# 5. Business rules +1. The reason codes have these values: OK = 'OK', EMPTY = 'EMPTY', + DAMAGE = 'DAMAGE', CLOTH = 'CLOTH', LENGTH = 'LENGTH', RUSH = 'RUSH'. +2. The damage codes have these values: TEAR = 'TEAR', SEAM = 'SEAM', + EYLT = 'EYLT', BATT = 'BATT'. +3. The cloth codes have these values: LITE = 'LITE', MEDM = 'MEDM', + HEAV = 'HEAV'. +4. C_MAX_LENGTH is 400. C_RUSH_LIMIT is 200. +5. TY_REASON is 10 characters long. TY_DAMAGE is 4 characters long. TY_CLOTH is + 4 characters long. +6. The method CHECK_ORDER has exactly the importing parameters IV_DAMAGE, + IV_CLOTH, IV_LENGTH and IV_RUSH and the returning parameter RV_REASON. + IV_DAMAGE has the type TY_DAMAGE. IV_CLOTH has the type TY_CLOTH. IV_LENGTH + has the type I. IV_RUSH has the type ABAP_BOOL. RV_REASON has the type + TY_REASON. + +# 6. Constraints +- Release target: ABAP Platform 2025 (SAP_BASIS 816). +- Coding standards: Clean ABAP. No global variables. No comment that restates + the code. +- Out of scope: do not create an implementation class. Do not change other + objects in package $TMP. + +# 7. Acceptance +- The interface {{P}}IF_SAIL_REPAIR is active and has no syntax error. +- The hidden tests pass. +- Write your own ABAP Unit tests for the interface. diff --git a/tasks_gen/train/G1954/task.json b/tasks_gen/train/G1954/task.json new file mode 100644 index 0000000..8876e56 --- /dev/null +++ b/tasks_gen/train/G1954/task.json @@ -0,0 +1,49 @@ +{ + "id": "G1954", + "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_SAIL_REPAIR" + } + ], + "out_of_scope": [ + "Do not create an implementation class", + "Do not change other objects in package $TMP" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T02_HIDDEN", + "file": "hidden/t02_hidden.clas.abap", + "description": "T02 hidden tests: constant values, type lengths and the method signature of the sail repair contract" + } + ], + "reference": [ + { + "type": "INTF", + "name": "{{P}}IF_SAIL_REPAIR", + "file": "reference/if_sail_repair.intf.abap", + "description": "Sail repair contract" + }, + { + "type": "CLAS", + "name": "{{P}}CL_SAIL_REPAIR_TEST", + "file": "reference/cl_sail_repair_test.clas.abap", + "description": "Own tests for the sail repair contract" + } + ], + "craft_checks": [ + "naming_conventions", + "constant_values" + ] +} \ No newline at end of file diff --git a/tasks_gen/train/G1955/faulty/m0_well.tabl.asabap b/tasks_gen/train/G1955/faulty/m0_well.tabl.asabap new file mode 100644 index 0000000..434150b --- /dev/null +++ b/tasks_gen/train/G1955/faulty/m0_well.tabl.asabap @@ -0,0 +1,19 @@ +@EndUserText.label : 'Drilling job' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}well { + key client : abap.clnt not null; + job_id : abap.char(10) not null; + site_name : abap.char(40); + drilled_on : abap.dats; + @Semantics.quantity.unitOfMeasure : '{{p}}well.depth_unit' + depth_m : abap.dec(7,2); + depth_unit : abap.unit(3); + @Semantics.amount.currencyCode : '{{p}}well.currency_code' + price : abap.dec(15,2); + currency_code : abap.cuky; + permit_no : abap.numc(8); + crew_size : abap.int4; +} diff --git a/tasks_gen/train/G1955/faulty/m1_well.tabl.asabap b/tasks_gen/train/G1955/faulty/m1_well.tabl.asabap new file mode 100644 index 0000000..72cec19 --- /dev/null +++ b/tasks_gen/train/G1955/faulty/m1_well.tabl.asabap @@ -0,0 +1,19 @@ +@EndUserText.label : 'Drilling job' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}well { + key client : abap.clnt not null; + key job_id : abap.char(10) not null; + site_name : abap.char(40); + drilled_on : abap.tims; + @Semantics.quantity.unitOfMeasure : '{{p}}well.depth_unit' + depth_m : abap.dec(7,2); + depth_unit : abap.unit(3); + @Semantics.amount.currencyCode : '{{p}}well.currency_code' + price : abap.dec(15,2); + currency_code : abap.cuky; + permit_no : abap.numc(8); + crew_size : abap.int4; +} diff --git a/tasks_gen/train/G1955/faulty/m2_well.tabl.asabap b/tasks_gen/train/G1955/faulty/m2_well.tabl.asabap new file mode 100644 index 0000000..3041fe5 --- /dev/null +++ b/tasks_gen/train/G1955/faulty/m2_well.tabl.asabap @@ -0,0 +1,19 @@ +@EndUserText.label : 'Drilling job' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}well { + key client : abap.clnt not null; + key job_id : abap.char(10) not null; + site_name : abap.char(40); + drilled_on : abap.dats; + @Semantics.quantity.unitOfMeasure : '{{p}}well.depth_unit' + depth_m : abap.dec(7,3); + depth_unit : abap.unit(3); + @Semantics.amount.currencyCode : '{{p}}well.currency_code' + price : abap.dec(15,2); + currency_code : abap.cuky; + permit_no : abap.numc(8); + crew_size : abap.int4; +} diff --git a/tasks_gen/train/G1955/faulty/m3_well.tabl.asabap b/tasks_gen/train/G1955/faulty/m3_well.tabl.asabap new file mode 100644 index 0000000..de02a73 --- /dev/null +++ b/tasks_gen/train/G1955/faulty/m3_well.tabl.asabap @@ -0,0 +1,19 @@ +@EndUserText.label : 'Drilling job' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}well { + key client : abap.clnt not null; + key job_id : abap.char(10) not null; + site_name : abap.char(40); + drilled_on : abap.dats; + @Semantics.quantity.unitOfMeasure : '{{p}}well.depth_unit' + depth_m : abap.dec(7,2); + depth_unit : abap.unit(3); + @Semantics.amount.currencyCode : '{{p}}well.currency_code' + price : abap.dec(15,2); + currency_code : abap.cuky; + permit_no : abap.numc(7); + crew_size : abap.int4; +} diff --git a/tasks_gen/train/G1955/faulty/m4_well.tabl.asabap b/tasks_gen/train/G1955/faulty/m4_well.tabl.asabap new file mode 100644 index 0000000..373f044 --- /dev/null +++ b/tasks_gen/train/G1955/faulty/m4_well.tabl.asabap @@ -0,0 +1,19 @@ +@EndUserText.label : 'Drilling job' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}well { + key client : abap.clnt not null; + key job_id : abap.char(10) not null; + site_name : abap.char(40); + drilled_on : abap.dats; + @Semantics.quantity.unitOfMeasure : '{{p}}well.depth_unit' + depth_m : abap.dec(7,2); + depth_unit : abap.unit(3); + @Semantics.amount.currencyCode : '{{p}}well.currency_code' + price : abap.dec(15,2); + currency_code : abap.cuky; + permit_no : abap.numc(8); + crew_size : abap.int8; +} diff --git a/tasks_gen/train/G1955/generation.json b/tasks_gen/train/G1955/generation.json new file mode 100644 index 0000000..dbc7853 --- /dev/null +++ b/tasks_gen/train/G1955/generation.json @@ -0,0 +1,24 @@ +{ + "id": "G1955", + "pool": "train", + "object_type": "TABL", + "category": "B", + "attempts": [ + { + "stage": "validate", + "oracle": 94.3, + "null": 0 + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 5, + "killed": 5, + "ok": true + } + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1955/hidden/well_hidden.clas.abap b/tasks_gen/train/G1955/hidden/well_hidden.clas.abap new file mode 100644 index 0000000..02b3c81 --- /dev/null +++ b/tasks_gen/train/G1955/hidden/well_hidden.clas.abap @@ -0,0 +1,154 @@ +CLASS {{p}}well_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 field_count FOR TESTING. + METHODS field_properties FOR TESTING. + METHODS key_fields FOR TESTING. + METHODS insert_and_read FOR TESTING. + METHODS duplicate_key FOR TESTING. + METHODS same_site_two_jobs FOR TESTING. + METHODS keys_only_row FOR TESTING. + METHODS check_field + IMPORTING iv_name TYPE fieldname + iv_leng TYPE i + iv_dec TYPE i + iv_type TYPE dfies-datatype. +ENDCLASS. + + +CLASS {{p}}well_hidden IMPLEMENTATION. + + METHOD class_setup. + go_env = cl_osql_test_environment=>create( i_dependency_list = VALUE #( ( '{{P}}WELL' ) ) ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + go_env->clear_doubles( ). + ENDMETHOD. + + METHOD field_count. + DATA(lo_struct) = CAST cl_abap_structdescr( cl_abap_typedescr=>describe_by_name( '{{P}}WELL' ) ). + DATA(lt_fields) = lo_struct->get_ddic_field_list( ). + cl_abap_unit_assert=>assert_equals( exp = 10 act = lines( lt_fields ) + msg = |Table {{P}}WELL must have 10 fields| ). + ENDMETHOD. + + METHOD field_properties. + check_field( iv_name = 'CLIENT' iv_leng = 3 iv_dec = 0 iv_type = 'CLNT' ). + check_field( iv_name = 'JOB_ID' iv_leng = 10 iv_dec = 0 iv_type = 'CHAR' ). + check_field( iv_name = 'SITE_NAME' iv_leng = 40 iv_dec = 0 iv_type = 'CHAR' ). + check_field( iv_name = 'DRILLED_ON' iv_leng = 8 iv_dec = 0 iv_type = 'DATS' ). + check_field( iv_name = 'DEPTH_M' iv_leng = 7 iv_dec = 2 iv_type = 'DEC' ). + check_field( iv_name = 'DEPTH_UNIT' iv_leng = 3 iv_dec = 0 iv_type = 'UNIT' ). + check_field( iv_name = 'PRICE' iv_leng = 15 iv_dec = 2 iv_type = 'DEC' ). + check_field( iv_name = 'CURRENCY_CODE' iv_leng = 5 iv_dec = 0 iv_type = 'CUKY' ). + check_field( iv_name = 'PERMIT_NO' iv_leng = 8 iv_dec = 0 iv_type = 'NUMC' ). + check_field( iv_name = 'CREW_SIZE' iv_leng = 10 iv_dec = 0 iv_type = 'INT4' ). + ENDMETHOD. + + METHOD check_field. + DATA(lo_struct) = CAST cl_abap_structdescr( cl_abap_typedescr=>describe_by_name( '{{P}}WELL' ) ). + DATA(lt_fields) = lo_struct->get_ddic_field_list( ). + READ TABLE lt_fields INTO DATA(ls_field) WITH KEY fieldname = iv_name. + cl_abap_unit_assert=>assert_subrc( exp = 0 act = sy-subrc + msg = |Field { iv_name } is missing| ). + cl_abap_unit_assert=>assert_equals( exp = iv_leng act = ls_field-leng + msg = |Length of field { iv_name }| ). + cl_abap_unit_assert=>assert_equals( exp = iv_dec act = ls_field-decimals + msg = |Decimals of field { iv_name }| ). + cl_abap_unit_assert=>assert_equals( exp = iv_type act = ls_field-datatype + msg = |Data type of field { iv_name }| ). + ENDMETHOD. + + METHOD key_fields. + DATA(lo_struct) = CAST cl_abap_structdescr( cl_abap_typedescr=>describe_by_name( '{{P}}WELL' ) ). + DATA(lt_fields) = lo_struct->get_ddic_field_list( ). + 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 = |Field { ls_field-fieldname } must be a key field| ). + ELSE. + cl_abap_unit_assert=>assert_equals( exp = '' act = ls_field-keyflag + msg = |Field { ls_field-fieldname } must not be a key field| ). + ENDIF. + ENDLOOP. + ENDMETHOD. + + METHOD insert_and_read. + DATA ls_job TYPE {{p}}well. + ls_job-client = sy-mandt. + ls_job-job_id = 'J1'. + ls_job-site_name = 'FARM NORTH'. + ls_job-drilled_on = '20250115'. + ls_job-depth_m = '120.50'. + ls_job-depth_unit = 'M'. + ls_job-price = '4500.00'. + ls_job-currency_code = 'EUR'. + ls_job-permit_no = '00001234'. + ls_job-crew_size = 4. + INSERT {{p}}well FROM ls_job. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + + SELECT SINGLE * FROM {{p}}well WHERE job_id = 'J1' INTO @DATA(ls_db). + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + cl_abap_unit_assert=>assert_equals( exp = 'FARM NORTH' act = ls_db-site_name ). + cl_abap_unit_assert=>assert_equals( exp = '20250115' act = ls_db-drilled_on ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '120.50' ) + act = CONV decfloat34( ls_db-depth_m ) ). + cl_abap_unit_assert=>assert_equals( exp = 'M' act = ls_db-depth_unit ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '4500.00' ) + act = CONV decfloat34( ls_db-price ) ). + cl_abap_unit_assert=>assert_equals( exp = 'EUR' act = ls_db-currency_code ). + cl_abap_unit_assert=>assert_equals( exp = '00001234' act = ls_db-permit_no ). + cl_abap_unit_assert=>assert_equals( exp = 4 act = ls_db-crew_size ). + ENDMETHOD. + + METHOD duplicate_key. + DATA ls_job TYPE {{p}}well. + ls_job-client = sy-mandt. + ls_job-job_id = 'J2'. + ls_job-site_name = 'SITE A'. + INSERT {{p}}well FROM ls_job. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + INSERT {{p}}well FROM ls_job. + cl_abap_unit_assert=>assert_equals( exp = 4 act = sy-subrc ). + ENDMETHOD. + + METHOD same_site_two_jobs. + DATA ls_job TYPE {{p}}well. + ls_job-client = sy-mandt. + ls_job-site_name = 'SAME SITE'. + ls_job-job_id = 'J3'. + INSERT {{p}}well FROM ls_job. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + ls_job-job_id = 'J4'. + INSERT {{p}}well FROM ls_job. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + SELECT COUNT(*) FROM {{p}}well WHERE site_name = 'SAME SITE' INTO @DATA(lv_count). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lv_count ). + ENDMETHOD. + + METHOD keys_only_row. + DATA ls_job TYPE {{p}}well. + ls_job-client = sy-mandt. + ls_job-job_id = 'K1'. + INSERT {{p}}well FROM ls_job. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + SELECT SINGLE site_name, depth_m, crew_size FROM {{p}}well WHERE job_id = 'K1' + INTO @DATA(ls_db). + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + cl_abap_unit_assert=>assert_equals( exp = '' act = ls_db-site_name ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 0 ) + act = CONV decfloat34( ls_db-depth_m ) ). + cl_abap_unit_assert=>assert_equals( exp = 0 act = ls_db-crew_size ). + ENDMETHOD. + +ENDCLASS. diff --git a/tasks_gen/train/G1955/mutation.json b/tasks_gen/train/G1955/mutation.json new file mode 100644 index 0000000..234fd35 --- /dev/null +++ b/tasks_gen/train/G1955/mutation.json @@ -0,0 +1,56 @@ +{ + "task": "G1955", + "mutants": [ + { + "object": "{{P}}WELL", + "mutant": "line 8: key job_id : -> job_id : (key)", + "status": "killed", + "hidden": "5/7", + "failed_tests": [ + "KEY_FIELDS", + "SAME_SITE_TWO_JOBS" + ] + }, + { + "object": "{{P}}WELL", + "mutant": "line 10: abap.dats -> abap.tims (type)", + "status": "killed", + "hidden": "5/7", + "failed_tests": [ + "FIELD_PROPERTIES", + "INSERT_AND_READ" + ] + }, + { + "object": "{{P}}WELL", + "mutant": "line 12: abap.dec(7,2) -> abap.dec(7,3) (decimals)", + "status": "killed", + "hidden": "6/7", + "failed_tests": [ + "FIELD_PROPERTIES" + ] + }, + { + "object": "{{P}}WELL", + "mutant": "line 17: abap.numc(8) -> abap.numc(7) (length)", + "status": "killed", + "hidden": "6/7", + "failed_tests": [ + "FIELD_PROPERTIES" + ] + }, + { + "object": "{{P}}WELL", + "mutant": "line 18: abap.int4 -> abap.int8 (type)", + "status": "killed", + "hidden": "6/7", + "failed_tests": [ + "FIELD_PROPERTIES" + ] + } + ], + "valid": 5, + "killed": 5, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1955/reference/well.tabl.asabap b/tasks_gen/train/G1955/reference/well.tabl.asabap new file mode 100644 index 0000000..7d43f80 --- /dev/null +++ b/tasks_gen/train/G1955/reference/well.tabl.asabap @@ -0,0 +1,19 @@ +@EndUserText.label : 'Drilling job' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}well { + key client : abap.clnt not null; + key job_id : abap.char(10) not null; + site_name : abap.char(40); + drilled_on : abap.dats; + @Semantics.quantity.unitOfMeasure : '{{p}}well.depth_unit' + depth_m : abap.dec(7,2); + depth_unit : abap.unit(3); + @Semantics.amount.currencyCode : '{{p}}well.currency_code' + price : abap.dec(15,2); + currency_code : abap.cuky; + permit_no : abap.numc(8); + crew_size : abap.int4; +} diff --git a/tasks_gen/train/G1955/reference/well_test.clas.abap b/tasks_gen/train/G1955/reference/well_test.clas.abap new file mode 100644 index 0000000..67a7021 --- /dev/null +++ b/tasks_gen/train/G1955/reference/well_test.clas.abap @@ -0,0 +1,62 @@ +CLASS {{p}}well_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 table_has_fields FOR TESTING. + METHODS store_and_read FOR TESTING. + METHODS duplicate_key_rejected FOR TESTING. +ENDCLASS. + + +CLASS {{p}}well_test IMPLEMENTATION. + + METHOD class_setup. + go_env = cl_osql_test_environment=>create( i_dependency_list = VALUE #( ( '{{P}}WELL' ) ) ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + go_env->clear_doubles( ). + ENDMETHOD. + + METHOD table_has_fields. + DATA(lo_struct) = CAST cl_abap_structdescr( cl_abap_typedescr=>describe_by_name( '{{P}}WELL' ) ). + DATA(lt_fields) = lo_struct->get_ddic_field_list( ). + cl_abap_unit_assert=>assert_equals( exp = 10 act = lines( lt_fields ) ). + READ TABLE lt_fields TRANSPORTING NO FIELDS WITH KEY fieldname = 'DEPTH_M'. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + ENDMETHOD. + + METHOD store_and_read. + DATA ls_job TYPE {{p}}well. + ls_job-client = sy-mandt. + ls_job-job_id = 'J1'. + ls_job-site_name = 'FARM NORTH'. + ls_job-depth_m = '120.50'. + ls_job-depth_unit = 'M'. + ls_job-price = '4500.00'. + ls_job-currency_code = 'EUR'. + INSERT {{p}}well FROM ls_job. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + SELECT SINGLE site_name, depth_m FROM {{p}}well WHERE job_id = 'J1' INTO @DATA(ls_db). + cl_abap_unit_assert=>assert_equals( exp = 'FARM NORTH' act = ls_db-site_name ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '120.50' ) + act = CONV decfloat34( ls_db-depth_m ) ). + ENDMETHOD. + + METHOD duplicate_key_rejected. + DATA ls_job TYPE {{p}}well. + ls_job-client = sy-mandt. + ls_job-job_id = 'J9'. + INSERT {{p}}well FROM ls_job. + INSERT {{p}}well FROM ls_job. + cl_abap_unit_assert=>assert_equals( exp = 4 act = sy-subrc ). + ENDMETHOD. + +ENDCLASS. diff --git a/tasks_gen/train/G1955/spec.md b/tasks_gen/train/G1955/spec.md new file mode 100644 index 0000000..d56ff9b --- /dev/null +++ b/tasks_gen/train/G1955/spec.md @@ -0,0 +1,58 @@ +# 1. Goal +A well-drilling company drills boreholes for farms and small businesses. The +company needs one database table that stores every drilling job. A report and an +OData service will read the jobs later. Therefore the table must be a +transparent database table in the ABAP Dictionary. + +# 2. Open questions +None. + +# 3. Context +- Package: $TMP. +- No source table exists. Create the table from scratch. +- One row of the table is one drilling job. + +# 4. Contract +- Create the transparent database table {{P}}WELL in package $TMP. +- The table has these fields, with these names: + client, job_id, site_name, drilled_on, depth_m, depth_unit, price, + currency_code, permit_no, crew_size. +- Key fields: client and job_id. + +# 5. Business rules +1. client is the client field. Data type abap.clnt. It is a key field and it is + not null. +2. job_id is the number of the drilling job. Data type abap.char(10). It is a + key field and it is not null. +3. site_name is the name of the drilling site. Data type abap.char(40). +4. drilled_on is the date of the drilling. Data type abap.dats. +5. depth_m is the drilled depth. Data type abap.dec(7,2). It is a quantity. The + unit of measure of the quantity is the value of the field depth_unit of the + same row. +6. depth_unit is the unit of depth_m. Data type abap.unit(3). +7. price is the price of the drilling job. Data type abap.dec(15,2). It is an + amount. The currency of the amount is the value of the field currency_code of + the same row. +8. currency_code is the currency of price. Data type abap.cuky. +9. permit_no is the permit number of the water authority. Data type + abap.numc(8). +10. crew_size is the number of workers on the drilling job. Data type + abap.int4. +11. Only client and job_id are key fields. All other fields are not key fields + and can be empty. Two jobs on the same site are two rows with different + job_id values. + +# 6. Constraints +- Release target: SAP_BASIS 816 (ABAP Platform 2025), client 001. +- Create the table with a DDL source (define table ...). Do not use the classic + Dictionary maintenance screens. +- Coding standard: Clean ABAP. The table must be active and must have no syntax + error. +- Out of scope: do not create a CDS view, a report, a function module, or a + business class in this task. + +# 7. Acceptance +- The table {{P}}WELL is active. +- The hidden tests pass. +- Write ABAP Unit tests for the table in a global test class in package $TMP. + Use CL_OSQL_TEST_ENVIRONMENT as the test double. diff --git a/tasks_gen/train/G1955/task.json b/tasks_gen/train/G1955/task.json new file mode 100644 index 0000000..9faa7d6 --- /dev/null +++ b/tasks_gen/train/G1955/task.json @@ -0,0 +1,57 @@ +{ + "id": "G1955", + "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}}WELL", + "fields": [ + "client", + "job_id", + "site_name", + "drilled_on", + "depth_m", + "depth_unit", + "price", + "currency_code", + "permit_no", + "crew_size" + ] + } + ], + "out_of_scope": [ + "Do not create a CDS view, a report, a function module, or a business class in this task." + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}WELL_HIDDEN", + "file": "hidden/well_hidden.clas.abap", + "description": "T32 hidden tests: DDIC field list and OSQL test double" + } + ], + "reference": [ + { + "type": "TABL", + "name": "{{P}}WELL", + "file": "reference/well.tabl.asabap", + "description": "Drilling job table" + }, + { + "type": "CLAS", + "name": "{{P}}WELL_TEST", + "file": "reference/well_test.clas.abap", + "description": "T32 own tests" + } + ], + "craft_checks": [] +} \ No newline at end of file diff --git a/tasks_gen/train/G1956/generation.json b/tasks_gen/train/G1956/generation.json new file mode 100644 index 0000000..18308da --- /dev/null +++ b/tasks_gen/train/G1956/generation.json @@ -0,0 +1,33 @@ +{ + "id": "G1956", + "pool": "train", + "object_type": "INTF", + "category": "A", + "attempts": [ + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 71.5, + "null": 0 + }, + { + "stage": "validate", + "oracle": 77.0, + "null": 0 + }, + { + "stage": "bundle", + "errors": [ + "invalid JSON: Unterminated string starting at: line 1 column 6570 (char 6569)" + ], + "by_check": { + "json": 1 + } + } + ], + "accepted": false +} \ No newline at end of file diff --git a/tasks_gen/train/G1956/hidden/cobbler_hidden.clas.abap b/tasks_gen/train/G1956/hidden/cobbler_hidden.clas.abap new file mode 100644 index 0000000..0fe7b82 --- /dev/null +++ b/tasks_gen/train/G1956/hidden/cobbler_hidden.clas.abap @@ -0,0 +1,138 @@ +CLASS {{p}}cobbler_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + + PUBLIC SECTION. + INTERFACES {{p}}if_cobbler. + + PRIVATE SECTION. + DATA mo_cut TYPE REF TO {{p}}if_cobbler. + + METHODS setup. + METHODS service_codes FOR TESTING. + METHODS reason_codes FOR TESTING. + METHODS rule_values FOR TESTING. + METHODS base_prices FOR TESTING. + METHODS reason_type FOR TESTING. + METHODS service_type FOR TESTING. + METHODS amount_type FOR TESTING. + METHODS order_type FOR TESTING. + METHODS check_call FOR TESTING. + METHODS price_call FOR TESTING. +ENDCLASS. + + +CLASS {{p}}cobbler_hidden IMPLEMENTATION. + + METHOD {{p}}if_cobbler~check. + rv_reason = {{p}}if_cobbler=>c_reason-ok. + ENDMETHOD. + + METHOD {{p}}if_cobbler~price. + rv_price = 0. + ENDMETHOD. + + METHOD setup. + mo_cut = me. + ENDMETHOD. + + METHOD service_codes. + cl_abap_unit_assert=>assert_equals( exp = 'HEEL' + act = {{p}}if_cobbler=>c_service-heel ). + cl_abap_unit_assert=>assert_equals( exp = 'SOLE' + act = {{p}}if_cobbler=>c_service-sole ). + cl_abap_unit_assert=>assert_equals( exp = 'SEAM' + act = {{p}}if_cobbler=>c_service-seam ). + cl_abap_unit_assert=>assert_equals( exp = 'POLI' + act = {{p}}if_cobbler=>c_service-polish ). + ENDMETHOD. + + METHOD reason_codes. + cl_abap_unit_assert=>assert_equals( exp = 'OK' + act = {{p}}if_cobbler=>c_reason-ok ). + cl_abap_unit_assert=>assert_equals( exp = 'SERVICE' + act = {{p}}if_cobbler=>c_reason-service ). + cl_abap_unit_assert=>assert_equals( exp = 'PAIRS' + act = {{p}}if_cobbler=>c_reason-pairs ). + ENDMETHOD. + + METHOD rule_values. + DATA lv_min_order TYPE {{p}}if_cobbler=>ty_amount. + lv_min_order = '8.00'. + cl_abap_unit_assert=>assert_equals( exp = 12 + act = {{p}}if_cobbler=>c_rule-max_pairs ). + cl_abap_unit_assert=>assert_equals( exp = 40 + act = {{p}}if_cobbler=>c_rule-express_percent ). + cl_abap_unit_assert=>assert_equals( exp = 10 + act = {{p}}if_cobbler=>c_rule-member_percent ). + cl_abap_unit_assert=>assert_equals( exp = lv_min_order + act = {{p}}if_cobbler=>c_rule-min_order ). + ENDMETHOD. + + METHOD base_prices. + DATA lv_exp TYPE {{p}}if_cobbler=>ty_amount. + lv_exp = '12.50'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp + act = {{p}}if_cobbler=>c_base_price-heel ). + lv_exp = '25.00'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp + act = {{p}}if_cobbler=>c_base_price-sole ). + lv_exp = '8.00'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp + act = {{p}}if_cobbler=>c_base_price-seam ). + lv_exp = '6.50'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp + act = {{p}}if_cobbler=>c_base_price-polish ). + ENDMETHOD. + + METHOD reason_type. + DATA(lo_elem) = CAST cl_abap_elemdescr( + cl_abap_typedescr=>describe_by_name( '{{P}}IF_COBBLER=>TY_REASON' ) ). + cl_abap_unit_assert=>assert_equals( exp = 10 act = lo_elem->length ). + ENDMETHOD. + + METHOD service_type. + DATA(lo_elem) = CAST cl_abap_elemdescr( + cl_abap_typedescr=>describe_by_name( '{{P}}IF_COBBLER=>TY_SERVICE' ) ). + cl_abap_unit_assert=>assert_equals( exp = 4 act = lo_elem->length ). + ENDMETHOD. + + METHOD amount_type. + DATA(lo_elem) = CAST cl_abap_elemdescr( + cl_abap_typedescr=>describe_by_name( '{{P}}IF_COBBLER=>TY_AMOUNT' ) ). + cl_abap_unit_assert=>assert_equals( exp = 8 act = lo_elem->length ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lo_elem->decimals ). + ENDMETHOD. + + METHOD order_type. + DATA(lo_struct) = CAST cl_abap_structdescr( + cl_abap_typedescr=>describe_by_name( '{{P}}IF_COBBLER=>TY_ORDER' ) ). + DATA(lt_component) = lo_struct->get_components( ). + cl_abap_unit_assert=>assert_equals( exp = 4 act = lines( lt_component ) ). + cl_abap_unit_assert=>assert_equals( exp = 'SERVICE' act = lt_component[ 1 ]-name ). + cl_abap_unit_assert=>assert_equals( exp = 'PAIRS' act = lt_component[ 2 ]-name ). + cl_abap_unit_assert=>assert_equals( exp = 'EXPRESS' act = lt_component[ 3 ]-name ). + cl_abap_unit_assert=>assert_equals( exp = 'MEMBER' act = lt_component[ 4 ]-name ). + ENDMETHOD. + + METHOD check_call. + DATA ls_order TYPE {{p}}if_cobbler=>ty_order. + ls_order-service = {{p}}if_cobbler=>c_service-heel. + ls_order-pairs = 2. + ls_order-express = abap_true. + ls_order-member = abap_false. + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_cobbler=>c_reason-ok + act = mo_cut->check( ls_order ) ). + ENDMETHOD. + + METHOD price_call. + DATA ls_order TYPE {{p}}if_cobbler=>ty_order. + DATA lv_price TYPE {{p}}if_cobbler=>ty_amount. + DATA lv_zero TYPE {{p}}if_cobbler=>ty_amount. + ls_order-service = {{p}}if_cobbler=>c_service-polish. + ls_order-pairs = 1. + ls_order-express = abap_false. + ls_order-member = abap_false. + lv_price = mo_cut->price( ls_order ). + cl_abap_unit_assert=>assert_equals( exp = lv_zero act = lv_price ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1956/reference/cobbler_test.clas.abap b/tasks_gen/train/G1956/reference/cobbler_test.clas.abap new file mode 100644 index 0000000..2edd5bb --- /dev/null +++ b/tasks_gen/train/G1956/reference/cobbler_test.clas.abap @@ -0,0 +1,130 @@ +CLASS {{p}}cobbler_test DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + + PUBLIC SECTION. + INTERFACES {{p}}if_cobbler. + + PRIVATE SECTION. + DATA mo_cut TYPE REF TO {{p}}if_cobbler. + + METHODS setup. + METHODS service_constants FOR TESTING. + METHODS reason_constants FOR TESTING. + METHODS rule_constants FOR TESTING. + METHODS price_constants FOR TESTING. + METHODS type_lengths FOR TESTING. + METHODS order_components FOR TESTING. + METHODS check_call FOR TESTING. + METHODS price_call FOR TESTING. +ENDCLASS. + + +CLASS {{p}}cobbler_test IMPLEMENTATION. + + METHOD {{p}}if_cobbler~check. + rv_reason = {{p}}if_cobbler=>c_reason-ok. + ENDMETHOD. + + METHOD {{p}}if_cobbler~price. + rv_price = 0. + ENDMETHOD. + + METHOD setup. + mo_cut = me. + ENDMETHOD. + + METHOD service_constants. + cl_abap_unit_assert=>assert_equals( exp = 'HEEL' + act = {{p}}if_cobbler=>c_service-heel ). + cl_abap_unit_assert=>assert_equals( exp = 'SOLE' + act = {{p}}if_cobbler=>c_service-sole ). + cl_abap_unit_assert=>assert_equals( exp = 'SEAM' + act = {{p}}if_cobbler=>c_service-seam ). + cl_abap_unit_assert=>assert_equals( exp = 'POLI' + act = {{p}}if_cobbler=>c_service-polish ). + ENDMETHOD. + + METHOD reason_constants. + cl_abap_unit_assert=>assert_equals( exp = 'OK' + act = {{p}}if_cobbler=>c_reason-ok ). + cl_abap_unit_assert=>assert_equals( exp = 'SERVICE' + act = {{p}}if_cobbler=>c_reason-service ). + cl_abap_unit_assert=>assert_equals( exp = 'PAIRS' + act = {{p}}if_cobbler=>c_reason-pairs ). + ENDMETHOD. + + METHOD rule_constants. + DATA lv_min_order TYPE {{p}}if_cobbler=>ty_amount. + lv_min_order = '8.00'. + cl_abap_unit_assert=>assert_equals( exp = 12 + act = {{p}}if_cobbler=>c_rule-max_pairs ). + cl_abap_unit_assert=>assert_equals( exp = 40 + act = {{p}}if_cobbler=>c_rule-express_percent ). + cl_abap_unit_assert=>assert_equals( exp = 10 + act = {{p}}if_cobbler=>c_rule-member_percent ). + cl_abap_unit_assert=>assert_equals( exp = lv_min_order + act = {{p}}if_cobbler=>c_rule-min_order ). + ENDMETHOD. + + METHOD price_constants. + DATA lv_exp TYPE {{p}}if_cobbler=>ty_amount. + lv_exp = '12.50'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp + act = {{p}}if_cobbler=>c_base_price-heel ). + lv_exp = '25.00'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp + act = {{p}}if_cobbler=>c_base_price-sole ). + lv_exp = '8.00'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp + act = {{p}}if_cobbler=>c_base_price-seam ). + lv_exp = '6.50'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp + act = {{p}}if_cobbler=>c_base_price-polish ). + ENDMETHOD. + + METHOD type_lengths. + DATA(lo_reason) = CAST cl_abap_elemdescr( + cl_abap_typedescr=>describe_by_name( '{{P}}IF_COBBLER=>TY_REASON' ) ). + DATA(lo_service) = CAST cl_abap_elemdescr( + cl_abap_typedescr=>describe_by_name( '{{P}}IF_COBBLER=>TY_SERVICE' ) ). + DATA(lo_amount) = CAST cl_abap_elemdescr( + cl_abap_typedescr=>describe_by_name( '{{P}}IF_COBBLER=>TY_AMOUNT' ) ). + cl_abap_unit_assert=>assert_equals( exp = 10 act = lo_reason->length ). + cl_abap_unit_assert=>assert_equals( exp = 4 act = lo_service->length ). + cl_abap_unit_assert=>assert_equals( exp = 8 act = lo_amount->length ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lo_amount->decimals ). + ENDMETHOD. + + METHOD order_components. + DATA(lo_struct) = CAST cl_abap_structdescr( + cl_abap_typedescr=>describe_by_name( '{{P}}IF_COBBLER=>TY_ORDER' ) ). + DATA(lt_component) = lo_struct->get_components( ). + cl_abap_unit_assert=>assert_equals( exp = 4 act = lines( lt_component ) ). + cl_abap_unit_assert=>assert_equals( exp = 'SERVICE' act = lt_component[ 1 ]-name ). + cl_abap_unit_assert=>assert_equals( exp = 'PAIRS' act = lt_component[ 2 ]-name ). + cl_abap_unit_assert=>assert_equals( exp = 'EXPRESS' act = lt_component[ 3 ]-name ). + cl_abap_unit_assert=>assert_equals( exp = 'MEMBER' act = lt_component[ 4 ]-name ). + ENDMETHOD. + + METHOD check_call. + DATA ls_order TYPE {{p}}if_cobbler=>ty_order. + ls_order-service = {{p}}if_cobbler=>c_service-seam. + ls_order-pairs = 3. + ls_order-express = abap_false. + ls_order-member = abap_true. + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_cobbler=>c_reason-ok + act = mo_cut->check( ls_order ) ). + ENDMETHOD. + + METHOD price_call. + DATA ls_order TYPE {{p}}if_cobbler=>ty_order. + DATA lv_price TYPE {{p}}if_cobbler=>ty_amount. + DATA lv_zero TYPE {{p}}if_cobbler=>ty_amount. + ls_order-service = {{p}}if_cobbler=>c_service-sole. + ls_order-pairs = 1. + ls_order-express = abap_true. + ls_order-member = abap_false. + lv_price = mo_cut->price( ls_order ). + cl_abap_unit_assert=>assert_equals( exp = lv_zero act = lv_price ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1956/reference/if_cobbler.intf.abap b/tasks_gen/train/G1956/reference/if_cobbler.intf.abap new file mode 100644 index 0000000..f87b627 --- /dev/null +++ b/tasks_gen/train/G1956/reference/if_cobbler.intf.abap @@ -0,0 +1,52 @@ +INTERFACE {{p}}if_cobbler PUBLIC. + TYPES ty_reason TYPE c LENGTH 10. + TYPES ty_service TYPE c LENGTH 4. + TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2. + + TYPES: + BEGIN OF ty_order, + service TYPE ty_service, + pairs TYPE i, + express TYPE abap_bool, + member TYPE abap_bool, + END OF ty_order. + + CONSTANTS: + BEGIN OF c_service, + heel TYPE ty_service VALUE 'HEEL', + sole TYPE ty_service VALUE 'SOLE', + seam TYPE ty_service VALUE 'SEAM', + polish TYPE ty_service VALUE 'POLI', + END OF c_service. + + CONSTANTS: + BEGIN OF c_reason, + ok TYPE ty_reason VALUE 'OK', + service TYPE ty_reason VALUE 'SERVICE', + pairs TYPE ty_reason VALUE 'PAIRS', + END OF c_reason. + + CONSTANTS: + BEGIN OF c_rule, + max_pairs TYPE i VALUE 12, + express_percent TYPE i VALUE 40, + member_percent TYPE i VALUE 10, + min_order TYPE ty_amount VALUE '8.00', + END OF c_rule. + + CONSTANTS: + BEGIN OF c_base_price, + heel TYPE ty_amount VALUE '12.50', + sole TYPE ty_amount VALUE '25.00', + seam TYPE ty_amount VALUE '8.00', + polish TYPE ty_amount VALUE '6.50', + END OF c_base_price. + + METHODS check + IMPORTING is_order TYPE ty_order + RETURNING VALUE(rv_reason) TYPE ty_reason. + + METHODS price + IMPORTING is_order TYPE ty_order + RETURNING VALUE(rv_price) TYPE ty_amount. +ENDINTERFACE. diff --git a/tasks_gen/train/G1956/spec.md b/tasks_gen/train/G1956/spec.md new file mode 100644 index 0000000..55c981d --- /dev/null +++ b/tasks_gen/train/G1956/spec.md @@ -0,0 +1,76 @@ +# 1. Goal +Define the interface {{P}}IF_COBBLER in package $TMP. A cobbler's workshop +repairs shoes. The order desk takes the repair orders and the pricing engine +prices them. The interface is the contract between the order desk and the +pricing engine. The interface carries the service codes, the reason codes, +the price parameters and the two methods CHECK and PRICE. + +# 2. Open questions +None. + +# 3. Context +- The interface {{P}}IF_COBBLER does not exist yet. Create it in package $TMP. +- One repair order covers one service and one number of pairs of shoes. +- The method CHECK tells the order desk whether an order can be priced. It + returns C_REASON-SERVICE if the service of the order is not one of the four + codes of C_SERVICE. It returns C_REASON-PAIRS if the number of pairs is less + than 1 or greater than C_RULE-MAX_PAIRS. Else it returns C_REASON-OK. +- The method PRICE calculates the price of an order in euro. It multiplies the + base price of the service with the number of pairs, adds + C_RULE-EXPRESS_PERCENT percent if EXPRESS is true, subtracts + C_RULE-MEMBER_PERCENT percent if MEMBER is true, rounds the result to full + 10 cents (5 cents round up) and never returns less than C_RULE-MIN_ORDER. +- The workshop keeps the service codes and the price parameters in the + interface, so that the order desk and the pricing engine use the same values. +- The pricing engine that implements the interface is not part of this task. +- No database table, no CDS view, no function module and no report is needed. + +# 4. Contract +- Create the interface {{P}}IF_COBBLER in package $TMP. +- The interface is public. +- The interface has the types, the constants and the methods of section 5 and + nothing else. + +# 5. Business rules +1. The interface has exactly two methods: CHECK and PRICE. +2. TY_REASON is a text field of length 10. +3. TY_SERVICE is a text field of length 4. +4. TY_AMOUNT is a packed number of length 8 with 2 decimal places. +5. TY_ORDER is a structure with exactly four components in this order: SERVICE + of type TY_SERVICE, PAIRS of type i, EXPRESS of type abap_bool and MEMBER + of type abap_bool. +6. C_SERVICE holds the four service codes of the workshop. The components, the + types and the values are: HEEL of type TY_SERVICE = 'HEEL' (heel + replacement), SOLE of type TY_SERVICE = 'SOLE' (full sole), SEAM of type + TY_SERVICE = 'SEAM' (seam repair) and POLISH of type TY_SERVICE = 'POLI' + (clean and polish). +7. C_REASON holds the three reason codes of the check. The components, the + types and the values are: OK of type TY_REASON = 'OK', SERVICE of type + TY_REASON = 'SERVICE' and PAIRS of type TY_REASON = 'PAIRS'. +8. C_RULE holds the price parameters. The components, the types and the values + are: MAX_PAIRS of type i = 12, EXPRESS_PERCENT of type i = 40, + MEMBER_PERCENT of type i = 10 and MIN_ORDER of type TY_AMOUNT = 8.00. +9. C_BASE_PRICE holds the price of one pair of shoes for each service. The + components, the types and the values are: HEEL of type TY_AMOUNT = 12.50, + SOLE of type TY_AMOUNT = 25.00, SEAM of type TY_AMOUNT = 8.00 and POLISH of + type TY_AMOUNT = 6.50. +10. The method CHECK has the importing parameter IS_ORDER of type TY_ORDER and + the returning parameter RV_REASON of type TY_REASON. +11. The method PRICE has the importing parameter IS_ORDER of type TY_ORDER and + the returning parameter RV_PRICE of type TY_AMOUNT. + +# 6. Constraints +- Release target: SAP_BASIS 816 (ABAP Platform 2025). +- Coding standards: Clean ABAP. Names as in section 5. No obsolete syntax. +- Out of scope: a class that implements the interface, a database table, a CDS + view, a function module and a report. + +# 7. Acceptance +- The interface is active and has no syntax error. +- The interface has exactly the types, the constants and the methods of + section 5. +- Write your own ABAP Unit tests in the global test class {{P}}COBBLER_TEST in + package $TMP. The class is public, final and it is a test class + (FOR TESTING DURATION SHORT RISK LEVEL HARMLESS). Test the constants, the + type lengths and the method signatures of {{P}}IF_COBBLER. +- The hidden tests pass. diff --git a/tasks_gen/train/G1956/task.json b/tasks_gen/train/G1956/task.json new file mode 100644 index 0000000..525a5e7 --- /dev/null +++ b/tasks_gen/train/G1956/task.json @@ -0,0 +1,43 @@ +{ + "id": "G1956", + "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_COBBLER" + } + ], + "out_of_scope": [], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}COBBLER_HIDDEN", + "file": "hidden/cobbler_hidden.clas.abap", + "description": "Contract tests for {{P}}IF_COBBLER" + } + ], + "reference": [ + { + "type": "INTF", + "name": "{{P}}IF_COBBLER", + "file": "reference/if_cobbler.intf.abap", + "description": "Pricing contract of the cobbler workshop" + }, + { + "type": "CLAS", + "name": "{{P}}COBBLER_TEST", + "file": "reference/cobbler_test.clas.abap", + "description": "Own tests for the interface" + } + ], + "craft_checks": [] +} \ No newline at end of file diff --git a/tasks_gen/train/G1957/faulty/m0_winjob.tabl.asabap b/tasks_gen/train/G1957/faulty/m0_winjob.tabl.asabap new file mode 100644 index 0000000..0aa64e4 --- /dev/null +++ b/tasks_gen/train/G1957/faulty/m0_winjob.tabl.asabap @@ -0,0 +1,16 @@ +@EndUserText.label : 'Window cleaning job' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}winjob { + key client : abap.clnt not null; + job_id : abap.char(10) not null; + customer : abap.char(10); + work_hours : abap.int4; + calc_mode : abap.char(2); + order_date : abap.dats; + pane_count : abap.int4; + group_code : abap.char(4); + net_value : abap.dec(15,2); +} diff --git a/tasks_gen/train/G1957/faulty/m1_winjob.tabl.asabap b/tasks_gen/train/G1957/faulty/m1_winjob.tabl.asabap new file mode 100644 index 0000000..a532f0a --- /dev/null +++ b/tasks_gen/train/G1957/faulty/m1_winjob.tabl.asabap @@ -0,0 +1,16 @@ +@EndUserText.label : 'Window cleaning job' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}winjob { + key client : abap.clnt not null; + key job_id : abap.numc(10) not null; + customer : abap.char(10); + work_hours : abap.int4; + calc_mode : abap.char(2); + order_date : abap.dats; + pane_count : abap.int4; + group_code : abap.char(4); + net_value : abap.dec(15,2); +} diff --git a/tasks_gen/train/G1957/faulty/m2_winjob.tabl.asabap b/tasks_gen/train/G1957/faulty/m2_winjob.tabl.asabap new file mode 100644 index 0000000..6a7c2e5 --- /dev/null +++ b/tasks_gen/train/G1957/faulty/m2_winjob.tabl.asabap @@ -0,0 +1,16 @@ +@EndUserText.label : 'Window cleaning job' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}winjob { + key client : abap.clnt not null; + key job_id : abap.char(10) not null; + customer : abap.char(10); + work_hours : abap.int4; + calc_mode : abap.char(1); + order_date : abap.dats; + pane_count : abap.int4; + group_code : abap.char(4); + net_value : abap.dec(15,2); +} diff --git a/tasks_gen/train/G1957/faulty/m3_winjob.tabl.asabap b/tasks_gen/train/G1957/faulty/m3_winjob.tabl.asabap new file mode 100644 index 0000000..79e00f4 --- /dev/null +++ b/tasks_gen/train/G1957/faulty/m3_winjob.tabl.asabap @@ -0,0 +1,16 @@ +@EndUserText.label : 'Window cleaning job' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}winjob { + key client : abap.clnt not null; + key job_id : abap.char(10) not null; + customer : abap.char(10); + work_hours : abap.int4; + calc_mode : abap.char(2); + order_date : abap.dats; + pane_count : abap.int8; + group_code : abap.char(4); + net_value : abap.dec(15,2); +} diff --git a/tasks_gen/train/G1957/faulty/m4_winjob.tabl.asabap b/tasks_gen/train/G1957/faulty/m4_winjob.tabl.asabap new file mode 100644 index 0000000..b91a7ba --- /dev/null +++ b/tasks_gen/train/G1957/faulty/m4_winjob.tabl.asabap @@ -0,0 +1,16 @@ +@EndUserText.label : 'Window cleaning job' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}winjob { + key client : abap.clnt not null; + key job_id : abap.char(10) not null; + customer : abap.char(10); + work_hours : abap.int4; + calc_mode : abap.char(2); + order_date : abap.dats; + pane_count : abap.int4; + group_code : abap.char(4); + net_value : abap.dec(15,3); +} diff --git a/tasks_gen/train/G1957/generation.json b/tasks_gen/train/G1957/generation.json new file mode 100644 index 0000000..dc023a2 --- /dev/null +++ b/tasks_gen/train/G1957/generation.json @@ -0,0 +1,44 @@ +{ + "id": "G1957", + "pool": "train", + "object_type": "TABL", + "category": "B", + "attempts": [ + { + "stage": "bundle", + "errors": [ + "reference/t61_test.clas.abap line 38: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"INSERT\"", + "reference/t61_test.clas.abap line 48: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"INSERT\"", + "reference/t61_test.clas.abap line 50: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"INSERT\"", + "reference/t61_test.clas.abap line 57: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"INSERT\"", + "hidden/t61_hidden.clas.abap line 106: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"INSERT\"", + "hidden/t61_hidden.clas.abap line 119: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"INSERT\"", + "hidden/t61_hidden.clas.abap line 121: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"INSERT\"" + ], + "by_check": { + "abaplint": 7 + } + }, + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 5, + "killed": 5, + "ok": true + } + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1957/hidden/t61_hidden.clas.abap b/tasks_gen/train/G1957/hidden/t61_hidden.clas.abap new file mode 100644 index 0000000..055a249 --- /dev/null +++ b/tasks_gen/train/G1957/hidden/t61_hidden.clas.abap @@ -0,0 +1,116 @@ +CLASS {{p}}t61_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 table_descr RETURNING VALUE(ro_descr) TYPE REF TO cl_abap_structdescr. + METHODS trimmed IMPORTING iv_value TYPE clike + RETURNING VALUE(rv_value) TYPE string. + METHODS field_names FOR TESTING. + METHODS field_lengths FOR TESTING. + METHODS field_types FOR TESTING. + METHODS field_decimals FOR TESTING. + METHODS insert_and_read FOR TESTING. + METHODS reads_two_jobs FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t61_hidden IMPLEMENTATION. + METHOD class_setup. + go_env = cl_osql_test_environment=>create( i_dependency_list = VALUE #( ( '{{P}}WINJOB' ) ) ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + go_env->clear_doubles( ). + ENDMETHOD. + + METHOD table_descr. + ro_descr = CAST cl_abap_structdescr( cl_abap_typedescr=>describe_by_name( '{{P}}WINJOB' ) ). + ENDMETHOD. + + METHOD trimmed. + rv_value = iv_value. + SHIFT rv_value RIGHT DELETING TRAILING space. + ENDMETHOD. + + METHOD field_names. + DATA(lt_components) = table_descr( )->get_components( ). + DATA(lv_act) = ``. + LOOP AT lt_components INTO DATA(ls_comp). + lv_act = lv_act && ls_comp-name && `;`. + ENDLOOP. + cl_abap_unit_assert=>assert_equals( + exp = `CLIENT;JOB_ID;CUSTOMER;WORK_HOURS;CALC_MODE;ORDER_DATE;PANE_COUNT;GROUP_CODE;NET_VALUE;` + act = lv_act ). + ENDMETHOD. + + METHOD field_lengths. + DATA(lt_components) = table_descr( )->get_components( ). + DATA(lv_act) = ``. + LOOP AT lt_components INTO DATA(ls_comp). + DATA(lo_elem) = CAST cl_abap_elemdescr( ls_comp-type ). + IF lo_elem->type_kind = 'C'. + DATA(lv_len) = lo_elem->length / 2. + lv_act = lv_act && |{ lv_len }| && `;`. + ENDIF. + ENDLOOP. + cl_abap_unit_assert=>assert_equals( exp = `3;10;10;2;4;` act = lv_act ). + ENDMETHOD. + + METHOD field_types. + DATA(lt_components) = table_descr( )->get_components( ). + DATA(lv_act) = ``. + LOOP AT lt_components INTO DATA(ls_comp). + DATA(lo_elem) = CAST cl_abap_elemdescr( ls_comp-type ). + lv_act = lv_act && lo_elem->type_kind && `;`. + ENDLOOP. + cl_abap_unit_assert=>assert_equals( exp = `C;C;C;I;C;D;I;C;P;` act = lv_act ). + ENDMETHOD. + + METHOD field_decimals. + DATA(lt_components) = table_descr( )->get_components( ). + DATA(lv_act) = ``. + LOOP AT lt_components INTO DATA(ls_comp). + DATA(lo_elem) = CAST cl_abap_elemdescr( ls_comp-type ). + IF lo_elem->type_kind = 'P'. + lv_act = lv_act && |{ lo_elem->decimals }| && `;`. + ENDIF. + ENDLOOP. + cl_abap_unit_assert=>assert_equals( exp = `2;` act = lv_act ). + ENDMETHOD. + + METHOD insert_and_read. + DATA lt_job TYPE STANDARD TABLE OF {{p}}winjob WITH EMPTY KEY. + lt_job = VALUE #( ( client = sy-mandt + job_id = 'J1' + customer = 'CUST01' + work_hours = 3 + calc_mode = 'HR' + order_date = '20240115' + pane_count = 12 + group_code = 'PRIV' + net_value = '125.50' ) ). + go_env->insert_test_data( lt_job ). + SELECT SINGLE * FROM {{p}}winjob WHERE job_id = 'J1' INTO @DATA(ls_read). + cl_abap_unit_assert=>assert_equals( exp = `CUST01` act = trimmed( ls_read-customer ) ). + cl_abap_unit_assert=>assert_equals( exp = 3 act = ls_read-work_hours ). + cl_abap_unit_assert=>assert_equals( exp = `PRIV` act = trimmed( ls_read-group_code ) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '125.50' ) + act = CONV decfloat34( ls_read-net_value ) ). + ENDMETHOD. + + METHOD reads_two_jobs. + DATA lt_job TYPE STANDARD TABLE OF {{p}}winjob WITH EMPTY KEY. + lt_job = VALUE #( ( client = sy-mandt job_id = 'K1' customer = 'ALPHA' ) + ( client = sy-mandt job_id = 'K2' customer = 'BETA' ) ). + go_env->insert_test_data( lt_job ). + SELECT COUNT(*) FROM {{p}}winjob INTO @DATA(lv_count). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lv_count ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1957/mutation.json b/tasks_gen/train/G1957/mutation.json new file mode 100644 index 0000000..4d9b016 --- /dev/null +++ b/tasks_gen/train/G1957/mutation.json @@ -0,0 +1,56 @@ +{ + "task": "G1957", + "mutants": [ + { + "object": "{{P}}WINJOB", + "mutant": "line 8: key job_id : -> job_id : (key)", + "status": "killed", + "hidden": "5/6", + "failed_tests": [ + "READS_TWO_JOBS" + ] + }, + { + "object": "{{P}}WINJOB", + "mutant": "line 8: abap.char(10) -> abap.numc(10) (type)", + "status": "killed", + "hidden": "3/6", + "failed_tests": [ + "FIELD_LENGTHS", + "FIELD_TYPES", + "INSERT_AND_READ" + ] + }, + { + "object": "{{P}}WINJOB", + "mutant": "line 11: abap.char(2) -> abap.char(1) (length)", + "status": "killed", + "hidden": "5/6", + "failed_tests": [ + "FIELD_LENGTHS" + ] + }, + { + "object": "{{P}}WINJOB", + "mutant": "line 13: abap.int4 -> abap.int8 (type)", + "status": "killed", + "hidden": "5/6", + "failed_tests": [ + "FIELD_TYPES" + ] + }, + { + "object": "{{P}}WINJOB", + "mutant": "line 15: abap.dec(15,2) -> abap.dec(15,3) (decimals)", + "status": "killed", + "hidden": "5/6", + "failed_tests": [ + "FIELD_DECIMALS" + ] + } + ], + "valid": 5, + "killed": 5, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/train/G1957/reference/t61_test.clas.abap b/tasks_gen/train/G1957/reference/t61_test.clas.abap new file mode 100644 index 0000000..29ddbbf --- /dev/null +++ b/tasks_gen/train/G1957/reference/t61_test.clas.abap @@ -0,0 +1,68 @@ +CLASS {{p}}t61_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 trimmed IMPORTING iv_value TYPE clike + RETURNING VALUE(rv_value) TYPE string. + METHODS stores_a_job FOR TESTING. + METHODS reads_net_value FOR TESTING. + METHODS reads_two_jobs FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t61_test IMPLEMENTATION. + METHOD class_setup. + go_env = cl_osql_test_environment=>create( i_dependency_list = VALUE #( ( '{{P}}WINJOB' ) ) ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + go_env->clear_doubles( ). + ENDMETHOD. + + METHOD trimmed. + rv_value = iv_value. + SHIFT rv_value RIGHT DELETING TRAILING space. + ENDMETHOD. + + METHOD stores_a_job. + DATA lt_job TYPE STANDARD TABLE OF {{p}}winjob WITH EMPTY KEY. + lt_job = VALUE #( ( client = sy-mandt + job_id = 'A1' + customer = 'C1' + work_hours = 2 + calc_mode = 'FX' + order_date = '20240201' + pane_count = 4 + group_code = 'PRIV' + net_value = '99.00' ) ). + go_env->insert_test_data( lt_job ). + SELECT SINGLE * FROM {{p}}winjob WHERE job_id = 'A1' INTO @DATA(ls_read). + cl_abap_unit_assert=>assert_equals( exp = `C1` act = trimmed( ls_read-customer ) ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = ls_read-work_hours ). + ENDMETHOD. + + METHOD reads_net_value. + DATA lt_job TYPE STANDARD TABLE OF {{p}}winjob WITH EMPTY KEY. + lt_job = VALUE #( ( client = sy-mandt job_id = 'A3' net_value = '12.34' ) ). + go_env->insert_test_data( lt_job ). + SELECT SINGLE net_value FROM {{p}}winjob WHERE job_id = 'A3' INTO @DATA(lv_value). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '12.34' ) + act = CONV decfloat34( lv_value ) ). + ENDMETHOD. + + METHOD reads_two_jobs. + DATA lt_job TYPE STANDARD TABLE OF {{p}}winjob WITH EMPTY KEY. + lt_job = VALUE #( ( client = sy-mandt job_id = 'A4' ) + ( client = sy-mandt job_id = 'A5' ) ). + go_env->insert_test_data( lt_job ). + SELECT COUNT(*) FROM {{p}}winjob INTO @DATA(lv_count). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lv_count ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/train/G1957/reference/winjob.tabl.asabap b/tasks_gen/train/G1957/reference/winjob.tabl.asabap new file mode 100644 index 0000000..51ce365 --- /dev/null +++ b/tasks_gen/train/G1957/reference/winjob.tabl.asabap @@ -0,0 +1,16 @@ +@EndUserText.label : 'Window cleaning job' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}winjob { + key client : abap.clnt not null; + key job_id : abap.char(10) not null; + customer : abap.char(10); + work_hours : abap.int4; + calc_mode : abap.char(2); + order_date : abap.dats; + pane_count : abap.int4; + group_code : abap.char(4); + net_value : abap.dec(15,2); +} diff --git a/tasks_gen/train/G1957/spec.md b/tasks_gen/train/G1957/spec.md new file mode 100644 index 0000000..05e5202 --- /dev/null +++ b/tasks_gen/train/G1957/spec.md @@ -0,0 +1,56 @@ +# 1. Goal + +A mobile window cleaning company records each cleaning job. Store the jobs in +one database table. Later reports and services read this table. + +# 2. Open questions + +None. + +# 3. Context + +- Package: $TMP. +- The table is new. There is no other object for this task. +- The company writes one row for each cleaning job. +- A job has a customer, the hours of work, the calculation mode, the date of + the order, the number of panes, the group of the job and the net value. + +# 4. Contract + +- Create the transparent database table {{P}}WINJOB in package $TMP. +- The table has these fields, in this order: client, job_id, customer, + work_hours, calc_mode, order_date, pane_count, group_code, net_value. +- The key fields are client and job_id. + +# 5. Business rules + +1. The fields have these data types: + - client: the client field. Key field. Not null. + - job_id: character, length 10. Key field. Not null. + - customer: character, length 10. + - work_hours: integer. The hours of work. + - calc_mode: character, length 2. The calculation mode. + - order_date: date. The date of the order. + - pane_count: integer. The number of panes. + - group_code: character, length 4. The group of the job. + - net_value: packed number, length 15, 2 decimals. The net value of the job. +2. The key of the table is the client and the job id together. A job id is + unique for one client. +3. All key fields are not null. The other fields can be null. +4. The field order in the table is the field order in the contract. + +# 6. Constraints + +- Release target: SAP_BASIS 816 (ABAP Platform 2025). +- Coding standards: + - Clean ABAP. + - Use the field names of the contract. + - Do not use ABAP SQL reserved words as field names. For example, do not use + hours, mode, order, date, count, group or value. +- Out of scope: do not create other objects. Do not change SAP objects. + +# 7. Acceptance + +- The table {{P}}WINJOB is active and has no syntax error. +- The hidden tests pass. +- Write ABAP Unit tests in a global test class. Use CL_OSQL_TEST_ENVIRONMENT. diff --git a/tasks_gen/train/G1957/task.json b/tasks_gen/train/G1957/task.json new file mode 100644 index 0000000..54400c8 --- /dev/null +++ b/tasks_gen/train/G1957/task.json @@ -0,0 +1,54 @@ +{ + "id": "G1957", + "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}}WINJOB", + "fields": [ + "client", + "job_id", + "customer", + "work_hours", + "calc_mode", + "order_date", + "pane_count", + "group_code", + "net_value" + ] + } + ], + "out_of_scope": [], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T61_HIDDEN", + "file": "hidden/t61_hidden.clas.abap", + "description": "RTTI checks and database tests for {{P}}WINJOB" + } + ], + "reference": [ + { + "type": "TABL", + "name": "{{P}}WINJOB", + "file": "reference/winjob.tabl.asabap", + "description": "Window cleaning jobs" + }, + { + "type": "CLAS", + "name": "{{P}}T61_TEST", + "file": "reference/t61_test.clas.abap", + "description": "Own tests for {{P}}WINJOB" + } + ], + "craft_checks": [] +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1910.json b/tasks_gen/train/_logs/G1910.json new file mode 100644 index 0000000..e6b80b1 --- /dev/null +++ b/tasks_gen/train/_logs/G1910.json @@ -0,0 +1,23 @@ +{ + "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, + "kind": "TABL", + "error_kind": null, + "difficulty": 2, + "spent_total": 99.908 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1911.json b/tasks_gen/train/_logs/G1911.json new file mode 100644 index 0000000..21d881c --- /dev/null +++ b/tasks_gen/train/_logs/G1911.json @@ -0,0 +1,28 @@ +{ + "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, + "kind": "TABL", + "error_kind": null, + "difficulty": 2, + "spent_total": 100.3013 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1912.json b/tasks_gen/train/_logs/G1912.json new file mode 100644 index 0000000..02e1c2e --- /dev/null +++ b/tasks_gen/train/_logs/G1912.json @@ -0,0 +1,33 @@ +{ + "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, + "kind": "TABL", + "error_kind": "reserved-word", + "difficulty": 2, + "spent_total": 100.223 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1913.json b/tasks_gen/train/_logs/G1913.json new file mode 100644 index 0000000..e5717f7 --- /dev/null +++ b/tasks_gen/train/_logs/G1913.json @@ -0,0 +1,42 @@ +{ + "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, + "kind": "INTF", + "error_kind": null, + "difficulty": 3, + "spent_total": 101.1722 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1914.json b/tasks_gen/train/_logs/G1914.json new file mode 100644 index 0000000..69327f9 --- /dev/null +++ b/tasks_gen/train/_logs/G1914.json @@ -0,0 +1,37 @@ +{ + "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, + "kind": "INTF", + "error_kind": null, + "difficulty": 2, + "spent_total": 101.1722 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1915.json b/tasks_gen/train/_logs/G1915.json new file mode 100644 index 0000000..dc04502 --- /dev/null +++ b/tasks_gen/train/_logs/G1915.json @@ -0,0 +1,28 @@ +{ + "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, + "kind": "TABL", + "error_kind": null, + "difficulty": 2, + "spent_total": 100.7499 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1916.json b/tasks_gen/train/_logs/G1916.json new file mode 100644 index 0000000..9aa285e --- /dev/null +++ b/tasks_gen/train/_logs/G1916.json @@ -0,0 +1,37 @@ +{ + "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, + "kind": "INTF", + "error_kind": null, + "difficulty": 3, + "spent_total": 102.2368 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1917.json b/tasks_gen/train/_logs/G1917.json new file mode 100644 index 0000000..3517a2d --- /dev/null +++ b/tasks_gen/train/_logs/G1917.json @@ -0,0 +1,42 @@ +{ + "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, + "kind": "INTF", + "error_kind": null, + "difficulty": 2, + "spent_total": 102.0963 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1918.json b/tasks_gen/train/_logs/G1918.json new file mode 100644 index 0000000..ddf4816 --- /dev/null +++ b/tasks_gen/train/_logs/G1918.json @@ -0,0 +1,43 @@ +{ + "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, + "kind": "INTF", + "error_kind": null, + "difficulty": 2, + "spent_total": 102.0325 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1919.json b/tasks_gen/train/_logs/G1919.json new file mode 100644 index 0000000..89fff38 --- /dev/null +++ b/tasks_gen/train/_logs/G1919.json @@ -0,0 +1,23 @@ +{ + "id": "G1919", + "pool": "train", + "object_type": "TABL", + "category": "B", + "attempts": [ + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 5, + "killed": 5, + "ok": true + } + } + ], + "accepted": true, + "kind": "TABL", + "error_kind": null, + "difficulty": 3, + "spent_total": 102.4861 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1920.json b/tasks_gen/train/_logs/G1920.json new file mode 100644 index 0000000..78423c7 --- /dev/null +++ b/tasks_gen/train/_logs/G1920.json @@ -0,0 +1,23 @@ +{ + "id": "G1920", + "pool": "train", + "object_type": "TABL", + "category": "B", + "attempts": [ + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 5, + "killed": 5, + "ok": true + } + } + ], + "accepted": true, + "kind": "TABL", + "error_kind": null, + "difficulty": 2, + "spent_total": 102.5301 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1921.json b/tasks_gen/train/_logs/G1921.json new file mode 100644 index 0000000..4a11e5f --- /dev/null +++ b/tasks_gen/train/_logs/G1921.json @@ -0,0 +1,38 @@ +{ + "id": "G1921", + "pool": "train", + "object_type": "INTF", + "category": "A", + "attempts": [ + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 77.7, + "null": 0 + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 4, + "killed": 3, + "ok": true + } + } + ], + "accepted": true, + "kind": "INTF", + "error_kind": null, + "difficulty": 2, + "spent_total": 103.3571 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1922.json b/tasks_gen/train/_logs/G1922.json new file mode 100644 index 0000000..209dea6 --- /dev/null +++ b/tasks_gen/train/_logs/G1922.json @@ -0,0 +1,39 @@ +{ + "id": "G1922", + "pool": "train", + "object_type": "DDLS", + "category": "E", + "attempts": [ + { + "stage": "bundle", + "errors": [ + "Too close to task G0145 (similarity spec 0.57, rules 0.61, names 0.00). Choose a different business topic and different object names.", + "Too close to task G0146 (similarity spec 0.71, rules 0.64, names 0.00). Choose a different business topic and different object names.", + "Too close to task G0147 (similarity spec 0.73, rules 0.70, names 0.00). Choose a different business topic and different object names." + ], + "by_check": { + "extra": 3 + } + }, + { + "stage": "validate", + "oracle": null, + "null": null + }, + { + "stage": "validate", + "oracle": null, + "null": null + }, + { + "stage": "validate", + "oracle": null, + "null": null + } + ], + "accepted": false, + "kind": "DDLS", + "error_kind": "reserved-word", + "difficulty": 2, + "spent_total": 103.1111 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1923.json b/tasks_gen/train/_logs/G1923.json new file mode 100644 index 0000000..6971798 --- /dev/null +++ b/tasks_gen/train/_logs/G1923.json @@ -0,0 +1,43 @@ +{ + "id": "G1923", + "pool": "train", + "object_type": "DDLS", + "category": "E", + "attempts": [ + { + "stage": "bundle", + "errors": [ + "Too close to task G0146 (similarity spec 0.70, rules 0.71, names 0.00). Choose a different business topic and different object names.", + "Too close to task G0147 (similarity spec 0.64, rules 0.73, names 0.00). Choose a different business topic and different object names." + ], + "by_check": { + "extra": 2 + } + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 5, + "killed": 3, + "ok": false + } + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 5, + "killed": 4, + "ok": true + } + } + ], + "accepted": true, + "kind": "DDLS", + "error_kind": null, + "difficulty": 3, + "spent_total": 103.5647 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1924.json b/tasks_gen/train/_logs/G1924.json new file mode 100644 index 0000000..1474fb5 --- /dev/null +++ b/tasks_gen/train/_logs/G1924.json @@ -0,0 +1,47 @@ +{ + "id": "G1924", + "pool": "train", + "object_type": "DDLS", + "category": "E", + "attempts": [ + { + "stage": "bundle", + "errors": [ + "Too close to task G0145 (similarity spec 0.60, rules 0.60, names 0.33). Choose a different business topic and different object names.", + "Too close to task G0147 (similarity spec 0.66, rules 0.63, names 0.00). Choose a different business topic and different object names." + ], + "by_check": { + "extra": 2 + } + }, + { + "stage": "bundle", + "errors": [ + "Too close to task G0147 (similarity spec 0.66, rules 0.64, names 0.00). Choose a different business topic and different object names." + ], + "by_check": { + "extra": 1 + } + }, + { + "stage": "bundle", + "errors": [ + "Too close to task G0147 (similarity spec 0.64, rules 0.61, names 0.00). Choose a different business topic and different object names.", + "Too close to task G1148 (similarity spec 0.31, rules 0.12, names 1.00). Choose a different business topic and different object names." + ], + "by_check": { + "extra": 2 + } + }, + { + "stage": "validate", + "oracle": 95.0, + "null": 0 + } + ], + "accepted": false, + "kind": "DDLS", + "error_kind": null, + "difficulty": 2, + "spent_total": 104.1158 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1925.json b/tasks_gen/train/_logs/G1925.json new file mode 100644 index 0000000..c5885a6 --- /dev/null +++ b/tasks_gen/train/_logs/G1925.json @@ -0,0 +1,51 @@ +{ + "id": "G1925", + "pool": "train", + "object_type": "DDLS", + "category": "E", + "attempts": [ + { + "stage": "bundle", + "errors": [ + "Too close to task G0145 (similarity spec 0.56, rules 0.70, names 0.00). Choose a different business topic and different object names." + ], + "by_check": { + "extra": 1 + } + }, + { + "stage": "bundle", + "errors": [ + "Too close to task G0145 (similarity spec 0.55, rules 0.69, names 0.00). Choose a different business topic and different object names." + ], + "by_check": { + "extra": 1 + } + }, + { + "stage": "bundle", + "errors": [ + "reference/turbine_test.clas.abap line 6: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"CLASS_METHODS\"", + "Too close to task G0145 (similarity spec 0.47, rules 0.60, names 0.00). Choose a different business topic and different object names." + ], + "by_check": { + "abaplint": 1, + "extra": 1 + } + }, + { + "stage": "bundle", + "errors": [ + "Too close to task G0145 (similarity spec 0.58, rules 0.63, names 0.00). Choose a different business topic and different object names." + ], + "by_check": { + "extra": 1 + } + } + ], + "accepted": false, + "kind": "DDLS", + "error_kind": null, + "difficulty": 2, + "spent_total": 103.969 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1926.json b/tasks_gen/train/_logs/G1926.json new file mode 100644 index 0000000..7582e31 --- /dev/null +++ b/tasks_gen/train/_logs/G1926.json @@ -0,0 +1,48 @@ +{ + "id": "G1926", + "pool": "train", + "object_type": "INTF", + "category": "A", + "attempts": [ + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "bundle", + "errors": [ + "reference/kart_check_test.clas.abap line 25: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"", + "reference/kart_check_test.clas.abap line 42: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"", + "reference/kart_check_test.clas.abap line 52: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"", + "hidden/kart_check_hidden.clas.abap line 43: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"", + "hidden/kart_check_hidden.clas.abap line 58: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"", + "hidden/kart_check_hidden.clas.abap line 68: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"", + "hidden/kart_check_hidden.clas.abap line 79: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"" + ], + "by_check": { + "abaplint": 7 + } + }, + { + "stage": "validate", + "oracle": 77.0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 5, + "killed": 5, + "ok": true + } + } + ], + "accepted": true, + "kind": "INTF", + "error_kind": null, + "difficulty": 3, + "spent_total": 104.5938 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1927.json b/tasks_gen/train/_logs/G1927.json new file mode 100644 index 0000000..ce48bea --- /dev/null +++ b/tasks_gen/train/_logs/G1927.json @@ -0,0 +1,28 @@ +{ + "id": "G1927", + "pool": "train", + "object_type": "DDLS", + "category": "E", + "attempts": [ + { + "stage": "validate", + "oracle": null, + "null": null + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 5, + "killed": 5, + "ok": true + } + } + ], + "accepted": true, + "kind": "DDLS", + "error_kind": "reserved-word", + "difficulty": 2, + "spent_total": 105.3972 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1928.json b/tasks_gen/train/_logs/G1928.json new file mode 100644 index 0000000..ecc0e06 --- /dev/null +++ b/tasks_gen/train/_logs/G1928.json @@ -0,0 +1,33 @@ +{ + "id": "G1928", + "pool": "train", + "object_type": "DDLS", + "category": "E", + "attempts": [ + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 5, + "killed": 3, + "ok": false + } + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 5, + "killed": 5, + "ok": true + } + } + ], + "accepted": true, + "kind": "DDLS", + "error_kind": null, + "difficulty": 2, + "spent_total": 104.7061 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1929.json b/tasks_gen/train/_logs/G1929.json new file mode 100644 index 0000000..34eee46 --- /dev/null +++ b/tasks_gen/train/_logs/G1929.json @@ -0,0 +1,42 @@ +{ + "id": "G1929", + "pool": "train", + "object_type": "DDLS", + "category": "E", + "attempts": [ + { + "stage": "bundle", + "errors": [ + "Too close to task G0146 (similarity spec 0.56, rules 0.65, names 0.00). Choose a different business topic and different object names." + ], + "by_check": { + "extra": 1 + } + }, + { + "stage": "bundle", + "errors": [ + "Too close to task G0146 (similarity spec 0.57, rules 0.67, names 0.00). Choose a different business topic and different object names.", + "Too close to task G0147 (similarity spec 0.51, rules 0.62, names 0.00). Choose a different business topic and different object names." + ], + "by_check": { + "extra": 2 + } + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 5, + "killed": 5, + "ok": true + } + } + ], + "accepted": true, + "kind": "DDLS", + "error_kind": null, + "difficulty": 3, + "spent_total": 105.3346 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1930.json b/tasks_gen/train/_logs/G1930.json new file mode 100644 index 0000000..8499579 --- /dev/null +++ b/tasks_gen/train/_logs/G1930.json @@ -0,0 +1,28 @@ +{ + "id": "G1930", + "pool": "train", + "object_type": "DDLS", + "category": "E", + "attempts": [ + { + "stage": "validate", + "oracle": null, + "null": null + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 4, + "killed": 4, + "ok": true + } + } + ], + "accepted": true, + "kind": "DDLS", + "error_kind": null, + "difficulty": 2, + "spent_total": 105.3346 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1931.json b/tasks_gen/train/_logs/G1931.json new file mode 100644 index 0000000..bb41040 --- /dev/null +++ b/tasks_gen/train/_logs/G1931.json @@ -0,0 +1,32 @@ +{ + "id": "G1931", + "pool": "train", + "object_type": "DDLS", + "category": "E", + "attempts": [ + { + "stage": "bundle", + "errors": [ + "seed/rental.tabl.asabap: field name days is a reserved word; choose another name" + ], + "by_check": { + "static": 1 + } + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 5, + "killed": 5, + "ok": true + } + } + ], + "accepted": true, + "kind": "DDLS", + "error_kind": null, + "difficulty": 2, + "spent_total": 105.733 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1932.json b/tasks_gen/train/_logs/G1932.json new file mode 100644 index 0000000..973790b --- /dev/null +++ b/tasks_gen/train/_logs/G1932.json @@ -0,0 +1,46 @@ +{ + "id": "G1932", + "pool": "train", + "object_type": "TABL", + "category": "B", + "attempts": [ + { + "stage": "bundle", + "errors": [ + "Too close to task G1912 (similarity spec 0.76, rules 0.51, names 0.00). Choose a different business topic and different object names." + ], + "by_check": { + "extra": 1 + } + }, + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "bundle", + "errors": [ + "hidden/bowl_hidden.clas.abap line 20: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\"" + ], + "by_check": { + "abaplint": 1 + } + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 4, + "killed": 4, + "ok": true + } + } + ], + "accepted": true, + "kind": "TABL", + "error_kind": "reserved-word", + "difficulty": 2, + "spent_total": 105.9456 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1933.json b/tasks_gen/train/_logs/G1933.json new file mode 100644 index 0000000..7985c64 --- /dev/null +++ b/tasks_gen/train/_logs/G1933.json @@ -0,0 +1,59 @@ +{ + "id": "G1933", + "pool": "train", + "object_type": "INTF", + "category": "A", + "attempts": [ + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 76.1, + "null": 0 + }, + { + "stage": "bundle", + "errors": [ + "reference/pyro_order_test.clas.abap line 6: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\"", + "reference/pyro_order_test.clas.abap line 7: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\"", + "reference/pyro_order_test.clas.abap line 8: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\"", + "reference/pyro_order_test.clas.abap line 9: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\"", + "reference/pyro_order_test.clas.abap line 10: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\"", + "reference/pyro_order_test.clas.abap line 11: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\"", + "reference/pyro_order_test.clas.abap line 12: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\"", + "reference/pyro_order_test.clas.abap line 13: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\"", + "hidden/pyro_hidden.clas.abap line 8: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\"", + "hidden/pyro_hidden.clas.abap line 9: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\"", + "hidden/pyro_hidden.clas.abap line 10: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\"", + "hidden/pyro_hidden.clas.abap line 11: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\"", + "hidden/pyro_hidden.clas.abap line 12: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\"", + "hidden/pyro_hidden.clas.abap line 13: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\"", + "hidden/pyro_hidden.clas.abap line 14: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\"", + "hidden/pyro_hidden.clas.abap line 15: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\"", + "hidden/pyro_hidden.clas.abap line 16: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\"", + "hidden/pyro_hidden.clas.abap line 17: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\"" + ], + "by_check": { + "abaplint": 18 + } + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 5, + "killed": 5, + "ok": true + } + } + ], + "accepted": true, + "kind": "INTF", + "error_kind": null, + "difficulty": 3, + "spent_total": 107.6561 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1934.json b/tasks_gen/train/_logs/G1934.json new file mode 100644 index 0000000..a92927d --- /dev/null +++ b/tasks_gen/train/_logs/G1934.json @@ -0,0 +1,28 @@ +{ + "id": "G1934", + "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, + "kind": "TABL", + "error_kind": null, + "difficulty": 2, + "spent_total": 106.337 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1935.json b/tasks_gen/train/_logs/G1935.json new file mode 100644 index 0000000..0ad0353 --- /dev/null +++ b/tasks_gen/train/_logs/G1935.json @@ -0,0 +1,47 @@ +{ + "id": "G1935", + "pool": "train", + "object_type": "INTF", + "category": "A", + "attempts": [ + { + "stage": "bundle", + "errors": [ + "hidden/t02_hidden.clas.abap line 45: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"", + "Too close to task G1125 (similarity spec 0.51, rules 0.62, names 0.00). Choose a different business topic and different object names." + ], + "by_check": { + "abaplint": 1, + "extra": 1 + } + }, + { + "stage": "bundle", + "errors": [ + "reference/if_concrete_mix.intf.abap line 91: 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": "bundle", + "errors": [ + "reference/mix_calc.clas.abap line 49: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"ASSIGN\"" + ], + "by_check": { + "abaplint": 1 + } + } + ], + "accepted": false, + "kind": "INTF", + "error_kind": null, + "difficulty": 2, + "spent_total": 106.7587 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1936.json b/tasks_gen/train/_logs/G1936.json new file mode 100644 index 0000000..ad65da9 --- /dev/null +++ b/tasks_gen/train/_logs/G1936.json @@ -0,0 +1,23 @@ +{ + "id": "G1936", + "pool": "train", + "object_type": "TABL", + "category": "B", + "attempts": [ + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 4, + "killed": 4, + "ok": true + } + } + ], + "accepted": true, + "kind": "TABL", + "error_kind": null, + "difficulty": 3, + "spent_total": 106.6784 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1937.json b/tasks_gen/train/_logs/G1937.json new file mode 100644 index 0000000..12796aa --- /dev/null +++ b/tasks_gen/train/_logs/G1937.json @@ -0,0 +1,38 @@ +{ + "id": "G1937", + "pool": "train", + "object_type": "INTF", + "category": "A", + "attempts": [ + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 96.7, + "null": 0 + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 5, + "killed": 5, + "ok": true + } + } + ], + "accepted": true, + "kind": "INTF", + "error_kind": null, + "difficulty": 2, + "spent_total": 107.5381 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1938.json b/tasks_gen/train/_logs/G1938.json new file mode 100644 index 0000000..9a8674a --- /dev/null +++ b/tasks_gen/train/_logs/G1938.json @@ -0,0 +1,28 @@ +{ + "id": "G1938", + "pool": "train", + "object_type": "INTF", + "category": "A", + "attempts": [ + { + "stage": "validate", + "oracle": 85.0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 5, + "killed": 5, + "ok": true + } + } + ], + "accepted": true, + "kind": "INTF", + "error_kind": null, + "difficulty": 2, + "spent_total": 107.3513 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1939.json b/tasks_gen/train/_logs/G1939.json new file mode 100644 index 0000000..ab35472 --- /dev/null +++ b/tasks_gen/train/_logs/G1939.json @@ -0,0 +1,28 @@ +{ + "id": "G1939", + "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": 4, + "ok": true + } + } + ], + "accepted": true, + "kind": "TABL", + "error_kind": null, + "difficulty": 3, + "spent_total": 107.9873 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1940.json b/tasks_gen/train/_logs/G1940.json new file mode 100644 index 0000000..815cac6 --- /dev/null +++ b/tasks_gen/train/_logs/G1940.json @@ -0,0 +1,28 @@ +{ + "id": "G1940", + "pool": "train", + "object_type": "MSAG", + "category": "D", + "attempts": [ + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 4, + "killed": 4, + "ok": true + } + } + ], + "accepted": true, + "kind": "MSAG", + "error_kind": null, + "difficulty": 2, + "spent_total": 108.3919 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1941.json b/tasks_gen/train/_logs/G1941.json new file mode 100644 index 0000000..bdfd4a1 --- /dev/null +++ b/tasks_gen/train/_logs/G1941.json @@ -0,0 +1,28 @@ +{ + "id": "G1941", + "pool": "train", + "object_type": "PROG", + "category": "C", + "attempts": [ + { + "stage": "validate", + "oracle": 95.5, + "null": 0 + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 3, + "killed": 3, + "ok": true + } + } + ], + "accepted": true, + "kind": "PROG", + "error_kind": null, + "difficulty": 2, + "spent_total": 108.0004 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1942.json b/tasks_gen/train/_logs/G1942.json new file mode 100644 index 0000000..facf260 --- /dev/null +++ b/tasks_gen/train/_logs/G1942.json @@ -0,0 +1,33 @@ +{ + "id": "G1942", + "pool": "train", + "object_type": "PROG", + "category": "C", + "attempts": [ + { + "stage": "validate", + "oracle": null, + "null": null + }, + { + "stage": "validate", + "oracle": 90.0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 4, + "killed": 4, + "ok": true + } + } + ], + "accepted": true, + "kind": "PROG", + "error_kind": null, + "difficulty": 2, + "spent_total": 108.5853 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1943.json b/tasks_gen/train/_logs/G1943.json new file mode 100644 index 0000000..0658a35 --- /dev/null +++ b/tasks_gen/train/_logs/G1943.json @@ -0,0 +1,47 @@ +{ + "id": "G1943", + "pool": "train", + "object_type": "STRU", + "category": "B", + "attempts": [ + { + "stage": "bundle", + "errors": [ + "Too close to task G1903 (similarity spec 0.36, rules 0.42, names 1.00). Choose a different business topic and different object names." + ], + "by_check": { + "extra": 1 + } + }, + { + "stage": "bundle", + "errors": [ + "reference/game_stru_test.clas.abap line 60: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"" + ], + "by_check": { + "abaplint": 1 + } + }, + { + "stage": "bundle", + "errors": [ + "reference/game_stru_test.clas.abap line 15: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"CLASS\"", + "hidden/game_stru_hidden.clas.abap line 15: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"CLASS\"", + "hidden/game_stru_hidden.clas.abap line 17: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"CLASS\"" + ], + "by_check": { + "abaplint": 3 + } + }, + { + "stage": "validate", + "oracle": 0, + "null": 0 + } + ], + "accepted": false, + "kind": "STRU", + "error_kind": null, + "difficulty": 3, + "spent_total": 108.9495 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1944.json b/tasks_gen/train/_logs/G1944.json new file mode 100644 index 0000000..290042e --- /dev/null +++ b/tasks_gen/train/_logs/G1944.json @@ -0,0 +1,38 @@ +{ + "id": "G1944", + "pool": "train", + "object_type": "PROG", + "category": "C", + "attempts": [ + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 2, + "killed": 2, + "ok": true + } + } + ], + "accepted": true, + "kind": "PROG", + "error_kind": null, + "difficulty": 2, + "spent_total": 109.4002 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1945.json b/tasks_gen/train/_logs/G1945.json new file mode 100644 index 0000000..d8a9072 --- /dev/null +++ b/tasks_gen/train/_logs/G1945.json @@ -0,0 +1,23 @@ +{ + "id": "G1945", + "pool": "train", + "object_type": "MSAG", + "category": "D", + "attempts": [ + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 4, + "killed": 4, + "ok": true + } + } + ], + "accepted": true, + "kind": "MSAG", + "error_kind": null, + "difficulty": 2, + "spent_total": 109.063 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1946.json b/tasks_gen/train/_logs/G1946.json new file mode 100644 index 0000000..e1132e1 --- /dev/null +++ b/tasks_gen/train/_logs/G1946.json @@ -0,0 +1,28 @@ +{ + "id": "G1946", + "pool": "train", + "object_type": "STRU", + "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, + "kind": "STRU", + "error_kind": null, + "difficulty": 3, + "spent_total": 111.0047 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1947.json b/tasks_gen/train/_logs/G1947.json new file mode 100644 index 0000000..0bc0cbe --- /dev/null +++ b/tasks_gen/train/_logs/G1947.json @@ -0,0 +1,38 @@ +{ + "id": "G1947", + "pool": "train", + "object_type": "STRU", + "category": "B", + "attempts": [ + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 5, + "killed": 2, + "ok": false + } + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 5, + "killed": 5, + "ok": true + } + } + ], + "accepted": true, + "kind": "STRU", + "error_kind": "reserved-word", + "difficulty": 2, + "spent_total": 110.2764 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1948.json b/tasks_gen/train/_logs/G1948.json new file mode 100644 index 0000000..237f645 --- /dev/null +++ b/tasks_gen/train/_logs/G1948.json @@ -0,0 +1,33 @@ +{ + "id": "G1948", + "pool": "train", + "object_type": "MSAG", + "category": "D", + "attempts": [ + { + "stage": "bundle", + "errors": [ + "Too close to task G0137 (similarity spec 0.35, rules 0.19, names 1.00). Choose a different business topic and different object names.", + "Too close to task G1902 (similarity spec 0.68, rules 0.61, names 1.00). Choose a different business topic and different object names." + ], + "by_check": { + "extra": 2 + } + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 4, + "killed": 4, + "ok": true + } + } + ], + "accepted": true, + "kind": "MSAG", + "error_kind": null, + "difficulty": 2, + "spent_total": 110.3164 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1949.json b/tasks_gen/train/_logs/G1949.json new file mode 100644 index 0000000..4523776 --- /dev/null +++ b/tasks_gen/train/_logs/G1949.json @@ -0,0 +1,32 @@ +{ + "id": "G1949", + "pool": "train", + "object_type": "DDLS", + "category": "F", + "attempts": [ + { + "stage": "bundle", + "errors": [ + "seed/falcon.tabl.asabap: field name minutes is a reserved word; choose another name" + ], + "by_check": { + "static": 1 + } + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 4, + "killed": 4, + "ok": true + } + } + ], + "accepted": true, + "kind": "DDLS", + "error_kind": null, + "difficulty": 3, + "spent_total": 110.49 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1950.json b/tasks_gen/train/_logs/G1950.json new file mode 100644 index 0000000..916db1d --- /dev/null +++ b/tasks_gen/train/_logs/G1950.json @@ -0,0 +1,38 @@ +{ + "id": "G1950", + "pool": "train", + "object_type": "DDLS", + "category": "F", + "attempts": [ + { + "stage": "validate", + "oracle": 95.6, + "null": 0 + }, + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 5, + "killed": 5, + "ok": true + } + } + ], + "accepted": true, + "kind": "DDLS", + "error_kind": null, + "difficulty": 2, + "spent_total": 111.381 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1951.json b/tasks_gen/train/_logs/G1951.json new file mode 100644 index 0000000..a5e735b --- /dev/null +++ b/tasks_gen/train/_logs/G1951.json @@ -0,0 +1,33 @@ +{ + "id": "G1951", + "pool": "train", + "object_type": "INTF", + "category": "A", + "attempts": [ + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 0, + "null": 0 + } + ], + "accepted": false, + "kind": "INTF", + "error_kind": null, + "difficulty": 2, + "spent_total": 111.72 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1952.json b/tasks_gen/train/_logs/G1952.json new file mode 100644 index 0000000..ecb9b15 --- /dev/null +++ b/tasks_gen/train/_logs/G1952.json @@ -0,0 +1,37 @@ +{ + "id": "G1952", + "pool": "train", + "object_type": "TABL", + "category": "B", + "attempts": [ + { + "stage": "bundle", + "errors": [ + "hidden/t16_hidden.clas.abap line 70: 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": 69.0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 85.0, + "null": 0 + } + ], + "accepted": false, + "kind": "TABL", + "error_kind": "reserved-word", + "difficulty": 2, + "spent_total": 112.0254 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1953.json b/tasks_gen/train/_logs/G1953.json new file mode 100644 index 0000000..77fef28 --- /dev/null +++ b/tasks_gen/train/_logs/G1953.json @@ -0,0 +1,39 @@ +{ + "id": "G1953", + "pool": "train", + "object_type": "INTF", + "category": "A", + "attempts": [ + { + "stage": "bundle", + "errors": [ + "Too close to task G1916 (similarity spec 0.61, rules 0.65, names 0.33). Choose a different business topic and different object names.", + "Too close to task G1918 (similarity spec 0.53, rules 0.60, names 0.00). Choose a different business topic and different object names.", + "Too close to task G1933 (similarity spec 0.56, rules 0.64, names 0.00). Choose a different business topic and different object names." + ], + "by_check": { + "extra": 3 + } + }, + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 79.9, + "null": 0 + }, + { + "stage": "validate", + "oracle": 81.4, + "null": 0 + } + ], + "accepted": false, + "kind": "INTF", + "error_kind": null, + "difficulty": 3, + "spent_total": 112.3611 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1954.json b/tasks_gen/train/_logs/G1954.json new file mode 100644 index 0000000..3f5d41b --- /dev/null +++ b/tasks_gen/train/_logs/G1954.json @@ -0,0 +1,38 @@ +{ + "id": "G1954", + "pool": "train", + "object_type": "INTF", + "category": "A", + "attempts": [ + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 81.4, + "null": 0 + }, + { + "stage": "validate", + "oracle": 81.4, + "null": 0 + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 5, + "killed": 5, + "ok": true + } + } + ], + "accepted": true, + "kind": "INTF", + "error_kind": null, + "difficulty": 2, + "spent_total": 112.8801 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1955.json b/tasks_gen/train/_logs/G1955.json new file mode 100644 index 0000000..b620196 --- /dev/null +++ b/tasks_gen/train/_logs/G1955.json @@ -0,0 +1,28 @@ +{ + "id": "G1955", + "pool": "train", + "object_type": "TABL", + "category": "B", + "attempts": [ + { + "stage": "validate", + "oracle": 94.3, + "null": 0 + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 5, + "killed": 5, + "ok": true + } + } + ], + "accepted": true, + "kind": "TABL", + "error_kind": null, + "difficulty": 2, + "spent_total": 112.5668 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1956.json b/tasks_gen/train/_logs/G1956.json new file mode 100644 index 0000000..6701c74 --- /dev/null +++ b/tasks_gen/train/_logs/G1956.json @@ -0,0 +1,37 @@ +{ + "id": "G1956", + "pool": "train", + "object_type": "INTF", + "category": "A", + "attempts": [ + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 71.5, + "null": 0 + }, + { + "stage": "validate", + "oracle": 77.0, + "null": 0 + }, + { + "stage": "bundle", + "errors": [ + "invalid JSON: Unterminated string starting at: line 1 column 6570 (char 6569)" + ], + "by_check": { + "json": 1 + } + } + ], + "accepted": false, + "kind": "INTF", + "error_kind": null, + "difficulty": 3, + "spent_total": 113.36 +} \ No newline at end of file diff --git a/tasks_gen/train/_logs/G1957.json b/tasks_gen/train/_logs/G1957.json new file mode 100644 index 0000000..af9028f --- /dev/null +++ b/tasks_gen/train/_logs/G1957.json @@ -0,0 +1,48 @@ +{ + "id": "G1957", + "pool": "train", + "object_type": "TABL", + "category": "B", + "attempts": [ + { + "stage": "bundle", + "errors": [ + "reference/t61_test.clas.abap line 38: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"INSERT\"", + "reference/t61_test.clas.abap line 48: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"INSERT\"", + "reference/t61_test.clas.abap line 50: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"INSERT\"", + "reference/t61_test.clas.abap line 57: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"INSERT\"", + "hidden/t61_hidden.clas.abap line 106: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"INSERT\"", + "hidden/t61_hidden.clas.abap line 119: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"INSERT\"", + "hidden/t61_hidden.clas.abap line 121: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"INSERT\"" + ], + "by_check": { + "abaplint": 7 + } + }, + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 5, + "killed": 5, + "ok": true + } + } + ], + "accepted": true, + "kind": "TABL", + "error_kind": "reserved-word", + "difficulty": 2, + "spent_total": 113.151 +} \ No newline at end of file