diff --git a/harness/generator.py b/harness/generator.py index f60fa53..6e8b4e8 100644 --- a/harness/generator.py +++ b/harness/generator.py @@ -331,8 +331,10 @@ def floor_budget(task): pushes = sum(bool(o.get("file")) + bool(o.get("testclasses_file")) for o in ref) calls = len(ref) + pushes bud = task.setdefault("budget", {}) - bud["max_activations"] = max(int(bud.get("max_activations", 0)), 2 * pushes) - bud["max_tool_calls"] = max(int(bud.get("max_tool_calls", 0)), 3 * calls) + # absolute floor (design default 60): with 40 calls DeepSeek used the budget to read the seed tables and + # stopped before its own tests (empirical runs G0017, G0024) + bud["max_activations"] = max(int(bud.get("max_activations", 0)), 2 * pushes, 15) + bud["max_tool_calls"] = max(int(bud.get("max_tool_calls", 0)), 3 * calls, 60) KEEP_FILES = {"generation.json", "review.json"} diff --git a/tasks_gen/eval/G0002/empirical.json b/tasks_gen/eval/G0002/empirical.json new file mode 100644 index 0000000..de6bc82 --- /dev/null +++ b/tasks_gen/eval/G0002/empirical.json @@ -0,0 +1,18 @@ +{ + "deepseek-v4.1-flash:cloud": { + "score": 98.5, + "parts": { + "correctness": 40.0, + "craft": 20.0, + "clean": 13.5, + "own_tests": 15.0, + "discipline": 10.0, + "total": 98.5, + "note": "own_tests: faulty-reference part not implemented in skeleton" + }, + "hidden": "13/13", + "tool_calls": 22, + "seconds": 376.4, + "run_dir": "runs/emp/10000_G0002_llm_deepseek-v4.1-flash_cloud" + } +} \ No newline at end of file diff --git a/tasks_gen/eval/G0002/task.json b/tasks_gen/eval/G0002/task.json index bd98460..311bafc 100644 --- a/tasks_gen/eval/G0002/task.json +++ b/tasks_gen/eval/G0002/task.json @@ -6,8 +6,8 @@ "release_target": "v816", "expected_outcome": "implement", "budget": { - "max_tool_calls": 50, - "max_activations": 12 + "max_tool_calls": 60, + "max_activations": 15 }, "seed": [], "contract": [ diff --git a/tasks_gen/eval/G0003/empirical.json b/tasks_gen/eval/G0003/empirical.json new file mode 100644 index 0000000..2ee23b1 --- /dev/null +++ b/tasks_gen/eval/G0003/empirical.json @@ -0,0 +1,18 @@ +{ + "deepseek-v4.1-flash:cloud": { + "score": 100.0, + "parts": { + "correctness": 40.0, + "craft": 20.0, + "clean": 15.0, + "own_tests": 15.0, + "discipline": 10.0, + "total": 100.0, + "note": "own_tests: faulty-reference part not implemented in skeleton" + }, + "hidden": "11/11", + "tool_calls": 13, + "seconds": 58.9, + "run_dir": "runs/emp/10001_G0003_llm_deepseek-v4.1-flash_cloud" + } +} \ No newline at end of file diff --git a/tasks_gen/eval/G0004/empirical.json b/tasks_gen/eval/G0004/empirical.json new file mode 100644 index 0000000..5f489f2 --- /dev/null +++ b/tasks_gen/eval/G0004/empirical.json @@ -0,0 +1,18 @@ +{ + "deepseek-v4.1-flash:cloud": { + "score": 100.0, + "parts": { + "correctness": 40.0, + "craft": 20.0, + "clean": 15.0, + "own_tests": 15.0, + "discipline": 10.0, + "total": 100.0, + "note": "own_tests: faulty-reference part not implemented in skeleton" + }, + "hidden": "10/10", + "tool_calls": 9, + "seconds": 58.6, + "run_dir": "runs/emp/10002_G0004_llm_deepseek-v4.1-flash_cloud" + } +} \ No newline at end of file diff --git a/tasks_gen/eval/G0004/task.json b/tasks_gen/eval/G0004/task.json index 883e855..4fa399b 100644 --- a/tasks_gen/eval/G0004/task.json +++ b/tasks_gen/eval/G0004/task.json @@ -7,7 +7,7 @@ "expected_outcome": "implement", "budget": { "max_tool_calls": 60, - "max_activations": 12 + "max_activations": 15 }, "seed": [ { diff --git a/tasks_gen/eval/G0007/empirical.json b/tasks_gen/eval/G0007/empirical.json new file mode 100644 index 0000000..838c6fb --- /dev/null +++ b/tasks_gen/eval/G0007/empirical.json @@ -0,0 +1,18 @@ +{ + "deepseek-v4.1-flash:cloud": { + "score": 100.0, + "parts": { + "correctness": 40.0, + "craft": 20.0, + "clean": 15.0, + "own_tests": 15.0, + "discipline": 10.0, + "total": 100.0, + "note": "own_tests: faulty-reference part not implemented in skeleton" + }, + "hidden": "10/10", + "tool_calls": 6, + "seconds": 23.4, + "run_dir": "runs/emp/10003_G0007_llm_deepseek-v4.1-flash_cloud" + } +} \ No newline at end of file diff --git a/tasks_gen/eval/G0007/task.json b/tasks_gen/eval/G0007/task.json index ffe3d3b..05ba00d 100644 --- a/tasks_gen/eval/G0007/task.json +++ b/tasks_gen/eval/G0007/task.json @@ -6,8 +6,8 @@ "release_target": "v816", "expected_outcome": "implement", "budget": { - "max_tool_calls": 40, - "max_activations": 10 + "max_tool_calls": 60, + "max_activations": 15 }, "seed": [ { diff --git a/tasks_gen/eval/G0008/empirical.json b/tasks_gen/eval/G0008/empirical.json new file mode 100644 index 0000000..a9c113d --- /dev/null +++ b/tasks_gen/eval/G0008/empirical.json @@ -0,0 +1,18 @@ +{ + "deepseek-v4.1-flash:cloud": { + "score": 100.0, + "parts": { + "correctness": 40.0, + "craft": 20.0, + "clean": 15.0, + "own_tests": 15.0, + "discipline": 10.0, + "total": 100.0, + "note": "own_tests: faulty-reference part not implemented in skeleton" + }, + "hidden": "11/11", + "tool_calls": 12, + "seconds": 241.4, + "run_dir": "runs/emp/10004_G0008_llm_deepseek-v4.1-flash_cloud" + } +} \ No newline at end of file diff --git a/tasks_gen/eval/G0008/task.json b/tasks_gen/eval/G0008/task.json index 8760396..cbc7f8d 100644 --- a/tasks_gen/eval/G0008/task.json +++ b/tasks_gen/eval/G0008/task.json @@ -6,8 +6,8 @@ "release_target": "v740sp05", "expected_outcome": "implement", "budget": { - "max_tool_calls": 45, - "max_activations": 12 + "max_tool_calls": 60, + "max_activations": 15 }, "seed": [ { diff --git a/tasks_gen/eval/G0009/task.json b/tasks_gen/eval/G0009/task.json index 8e86116..687c89b 100644 --- a/tasks_gen/eval/G0009/task.json +++ b/tasks_gen/eval/G0009/task.json @@ -6,8 +6,8 @@ "release_target": "v816", "expected_outcome": "implement", "budget": { - "max_tool_calls": 50, - "max_activations": 12 + "max_tool_calls": 60, + "max_activations": 15 }, "seed": [ { diff --git a/tasks_gen/eval/G0010/empirical.json b/tasks_gen/eval/G0010/empirical.json new file mode 100644 index 0000000..e356633 --- /dev/null +++ b/tasks_gen/eval/G0010/empirical.json @@ -0,0 +1,18 @@ +{ + "deepseek-v4.1-flash:cloud": { + "score": 95.0, + "parts": { + "correctness": 40.0, + "craft": 20.0, + "clean": 15.0, + "own_tests": 15.0, + "discipline": 5.0, + "total": 95.0, + "note": "own_tests: faulty-reference part not implemented in skeleton" + }, + "hidden": "12/12", + "tool_calls": 16, + "seconds": 116.4, + "run_dir": "runs/emp/10005_G0010_llm_deepseek-v4.1-flash_cloud" + } +} \ No newline at end of file diff --git a/tasks_gen/eval/G0010/task.json b/tasks_gen/eval/G0010/task.json index c6cb9e3..881fcae 100644 --- a/tasks_gen/eval/G0010/task.json +++ b/tasks_gen/eval/G0010/task.json @@ -6,8 +6,8 @@ "release_target": "v816", "expected_outcome": "implement", "budget": { - "max_tool_calls": 50, - "max_activations": 12 + "max_tool_calls": 60, + "max_activations": 15 }, "seed": [ { diff --git a/tasks_gen/eval/G0011/task.json b/tasks_gen/eval/G0011/task.json index 5026559..653ef3f 100644 --- a/tasks_gen/eval/G0011/task.json +++ b/tasks_gen/eval/G0011/task.json @@ -6,8 +6,8 @@ "release_target": "v758", "expected_outcome": "implement", "budget": { - "max_tool_calls": 40, - "max_activations": 10 + "max_tool_calls": 60, + "max_activations": 15 }, "seed": [ { diff --git a/tasks_gen/eval/G0012/empirical.json b/tasks_gen/eval/G0012/empirical.json new file mode 100644 index 0000000..8dd68cc --- /dev/null +++ b/tasks_gen/eval/G0012/empirical.json @@ -0,0 +1,18 @@ +{ + "deepseek-v4.1-flash:cloud": { + "score": 85.0, + "parts": { + "correctness": 40.0, + "craft": 20.0, + "clean": 15.0, + "own_tests": 0.0, + "discipline": 10.0, + "total": 85.0, + "note": "own_tests: faulty-reference part not implemented in skeleton" + }, + "hidden": "11/11", + "tool_calls": 17, + "seconds": 60.2, + "run_dir": "runs/emp/10006_G0012_llm_deepseek-v4.1-flash_cloud" + } +} \ No newline at end of file diff --git a/tasks_gen/eval/G0012/task.json b/tasks_gen/eval/G0012/task.json index 121b01d..066c6f4 100644 --- a/tasks_gen/eval/G0012/task.json +++ b/tasks_gen/eval/G0012/task.json @@ -6,8 +6,8 @@ "release_target": "v758", "expected_outcome": "implement", "budget": { - "max_tool_calls": 40, - "max_activations": 10 + "max_tool_calls": 60, + "max_activations": 15 }, "seed": [ { diff --git a/tasks_gen/eval/G0013/task.json b/tasks_gen/eval/G0013/task.json index 57e23dc..a9a598d 100644 --- a/tasks_gen/eval/G0013/task.json +++ b/tasks_gen/eval/G0013/task.json @@ -6,8 +6,8 @@ "release_target": "v816", "expected_outcome": "implement", "budget": { - "max_tool_calls": 40, - "max_activations": 10 + "max_tool_calls": 60, + "max_activations": 15 }, "seed": [ { diff --git a/tasks_gen/eval/G0014/empirical.json b/tasks_gen/eval/G0014/empirical.json new file mode 100644 index 0000000..a774b41 --- /dev/null +++ b/tasks_gen/eval/G0014/empirical.json @@ -0,0 +1,17 @@ +{ + "deepseek-v4.1-flash:cloud": { + "score": 0, + "parts": { + "total": 0, + "failed_gates": [ + "G1_active", + "G2_contract", + "G3_hidden_runs" + ] + }, + "hidden": "0/0", + "tool_calls": 36, + "seconds": 928.5, + "run_dir": "runs/emp/10007_G0014_llm_deepseek-v4.1-flash_cloud" + } +} \ No newline at end of file diff --git a/tasks_gen/eval/G0014/task.json b/tasks_gen/eval/G0014/task.json index 602fd43..0cf36fa 100644 --- a/tasks_gen/eval/G0014/task.json +++ b/tasks_gen/eval/G0014/task.json @@ -6,8 +6,8 @@ "release_target": "v758", "expected_outcome": "implement", "budget": { - "max_tool_calls": 40, - "max_activations": 10 + "max_tool_calls": 60, + "max_activations": 15 }, "seed": [ { diff --git a/tasks_gen/eval/G0015/empirical.json b/tasks_gen/eval/G0015/empirical.json new file mode 100644 index 0000000..53e769e --- /dev/null +++ b/tasks_gen/eval/G0015/empirical.json @@ -0,0 +1,18 @@ +{ + "deepseek-v4.1-flash:cloud": { + "score": 90.0, + "parts": { + "correctness": 40.0, + "craft": 20.0, + "clean": 15.0, + "own_tests": 15.0, + "discipline": 0.0, + "total": 90.0, + "note": "own_tests: faulty-reference part not implemented in skeleton" + }, + "hidden": "8/8", + "tool_calls": 18, + "seconds": 687.3, + "run_dir": "runs/emp/10008_G0015_llm_deepseek-v4.1-flash_cloud" + } +} \ No newline at end of file diff --git a/tasks_gen/eval/G0015/task.json b/tasks_gen/eval/G0015/task.json index caedc59..7773bf9 100644 --- a/tasks_gen/eval/G0015/task.json +++ b/tasks_gen/eval/G0015/task.json @@ -6,8 +6,8 @@ "release_target": "v758", "expected_outcome": "implement", "budget": { - "max_tool_calls": 40, - "max_activations": 10 + "max_tool_calls": 60, + "max_activations": 15 }, "seed": [ { diff --git a/tasks_gen/eval/G0016/task.json b/tasks_gen/eval/G0016/task.json index d0b65be..811c029 100644 --- a/tasks_gen/eval/G0016/task.json +++ b/tasks_gen/eval/G0016/task.json @@ -6,8 +6,8 @@ "release_target": "v816", "expected_outcome": "implement", "budget": { - "max_tool_calls": 40, - "max_activations": 12 + "max_tool_calls": 60, + "max_activations": 15 }, "seed": [ { diff --git a/tasks_gen/eval/G0017/empirical.json b/tasks_gen/eval/G0017/empirical.json new file mode 100644 index 0000000..c3d4bf2 --- /dev/null +++ b/tasks_gen/eval/G0017/empirical.json @@ -0,0 +1,18 @@ +{ + "deepseek-v4.1-flash:cloud": { + "score": 77.0, + "parts": { + "correctness": 40.0, + "craft": 20.0, + "clean": 12.0, + "own_tests": 0.0, + "discipline": 5.0, + "total": 77.0, + "note": "own_tests: faulty-reference part not implemented in skeleton" + }, + "hidden": "8/8", + "tool_calls": 40, + "seconds": 164.6, + "run_dir": "runs/emp/10009_G0017_llm_deepseek-v4.1-flash_cloud" + } +} \ No newline at end of file diff --git a/tasks_gen/eval/G0017/task.json b/tasks_gen/eval/G0017/task.json index 44687eb..3f404b0 100644 --- a/tasks_gen/eval/G0017/task.json +++ b/tasks_gen/eval/G0017/task.json @@ -6,8 +6,8 @@ "release_target": "v758", "expected_outcome": "implement", "budget": { - "max_tool_calls": 40, - "max_activations": 10 + "max_tool_calls": 60, + "max_activations": 15 }, "seed": [ { diff --git a/tasks_gen/eval/G0018/empirical.json b/tasks_gen/eval/G0018/empirical.json new file mode 100644 index 0000000..9988766 --- /dev/null +++ b/tasks_gen/eval/G0018/empirical.json @@ -0,0 +1,18 @@ +{ + "deepseek-v4.1-flash:cloud": { + "score": 100.0, + "parts": { + "correctness": 40.0, + "craft": 20.0, + "clean": 15.0, + "own_tests": 15.0, + "discipline": 10.0, + "total": 100.0, + "note": "own_tests: faulty-reference part not implemented in skeleton" + }, + "hidden": "6/6", + "tool_calls": 40, + "seconds": 128.4, + "run_dir": "runs/emp/10010_G0018_llm_deepseek-v4.1-flash_cloud" + } +} \ No newline at end of file diff --git a/tasks_gen/eval/G0018/task.json b/tasks_gen/eval/G0018/task.json index cff26d4..cfdedd0 100644 --- a/tasks_gen/eval/G0018/task.json +++ b/tasks_gen/eval/G0018/task.json @@ -6,8 +6,8 @@ "release_target": "v758", "expected_outcome": "implement", "budget": { - "max_tool_calls": 40, - "max_activations": 10 + "max_tool_calls": 60, + "max_activations": 15 }, "seed": [ { diff --git a/tasks_gen/eval/G0019/empirical.json b/tasks_gen/eval/G0019/empirical.json new file mode 100644 index 0000000..30d1ee8 --- /dev/null +++ b/tasks_gen/eval/G0019/empirical.json @@ -0,0 +1,18 @@ +{ + "deepseek-v4.1-flash:cloud": { + "score": 80.0, + "parts": { + "correctness": 40.0, + "craft": 20.0, + "clean": 15.0, + "own_tests": 0.0, + "discipline": 5.0, + "total": 80.0, + "note": "own_tests: faulty-reference part not implemented in skeleton" + }, + "hidden": "8/8", + "tool_calls": 36, + "seconds": 680.7, + "run_dir": "runs/emp/10011_G0019_llm_deepseek-v4.1-flash_cloud" + } +} \ No newline at end of file diff --git a/tasks_gen/eval/G0019/task.json b/tasks_gen/eval/G0019/task.json index 2a8f52c..2033510 100644 --- a/tasks_gen/eval/G0019/task.json +++ b/tasks_gen/eval/G0019/task.json @@ -6,8 +6,8 @@ "release_target": "v816", "expected_outcome": "implement", "budget": { - "max_tool_calls": 40, - "max_activations": 10 + "max_tool_calls": 60, + "max_activations": 15 }, "seed": [ { diff --git a/tasks_gen/eval/G0020/empirical.json b/tasks_gen/eval/G0020/empirical.json new file mode 100644 index 0000000..1f08860 --- /dev/null +++ b/tasks_gen/eval/G0020/empirical.json @@ -0,0 +1,18 @@ +{ + "deepseek-v4.1-flash:cloud": { + "score": 80.0, + "parts": { + "correctness": 40.0, + "craft": 20.0, + "clean": 15.0, + "own_tests": 0.0, + "discipline": 5.0, + "total": 80.0, + "note": "own_tests: faulty-reference part not implemented in skeleton" + }, + "hidden": "8/8", + "tool_calls": 40, + "seconds": 174.6, + "run_dir": "runs/emp/10012_G0020_llm_deepseek-v4.1-flash_cloud" + } +} \ No newline at end of file diff --git a/tasks_gen/eval/G0020/task.json b/tasks_gen/eval/G0020/task.json index f517d64..b5e1836 100644 --- a/tasks_gen/eval/G0020/task.json +++ b/tasks_gen/eval/G0020/task.json @@ -6,8 +6,8 @@ "release_target": "v758", "expected_outcome": "implement", "budget": { - "max_tool_calls": 40, - "max_activations": 10 + "max_tool_calls": 60, + "max_activations": 15 }, "seed": [ { diff --git a/tasks_gen/eval/G0021/empirical.json b/tasks_gen/eval/G0021/empirical.json new file mode 100644 index 0000000..09f4c45 --- /dev/null +++ b/tasks_gen/eval/G0021/empirical.json @@ -0,0 +1,18 @@ +{ + "deepseek-v4.1-flash:cloud": { + "score": 80.0, + "parts": { + "correctness": 40.0, + "craft": 20.0, + "clean": 15.0, + "own_tests": 0.0, + "discipline": 5.0, + "total": 80.0, + "note": "own_tests: faulty-reference part not implemented in skeleton" + }, + "hidden": "8/8", + "tool_calls": 40, + "seconds": 135.5, + "run_dir": "runs/emp/10013_G0021_llm_deepseek-v4.1-flash_cloud" + } +} \ No newline at end of file diff --git a/tasks_gen/eval/G0021/task.json b/tasks_gen/eval/G0021/task.json index 0d3420d..9838473 100644 --- a/tasks_gen/eval/G0021/task.json +++ b/tasks_gen/eval/G0021/task.json @@ -6,8 +6,8 @@ "release_target": "v758", "expected_outcome": "implement", "budget": { - "max_tool_calls": 40, - "max_activations": 10 + "max_tool_calls": 60, + "max_activations": 15 }, "seed": [ { diff --git a/tasks_gen/eval/G0022/empirical.json b/tasks_gen/eval/G0022/empirical.json new file mode 100644 index 0000000..f5ccaa6 --- /dev/null +++ b/tasks_gen/eval/G0022/empirical.json @@ -0,0 +1,18 @@ +{ + "deepseek-v4.1-flash:cloud": { + "score": 95.0, + "parts": { + "correctness": 40.0, + "craft": 20.0, + "clean": 15.0, + "own_tests": 15.0, + "discipline": 5.0, + "total": 95.0, + "note": "own_tests: faulty-reference part not implemented in skeleton" + }, + "hidden": "13/13", + "tool_calls": 32, + "seconds": 141.5, + "run_dir": "runs/emp/10014_G0022_llm_deepseek-v4.1-flash_cloud" + } +} \ No newline at end of file diff --git a/tasks_gen/eval/G0022/task.json b/tasks_gen/eval/G0022/task.json index 8164293..3e87f47 100644 --- a/tasks_gen/eval/G0022/task.json +++ b/tasks_gen/eval/G0022/task.json @@ -6,8 +6,8 @@ "release_target": "v816", "expected_outcome": "implement", "budget": { - "max_tool_calls": 45, - "max_activations": 14 + "max_tool_calls": 60, + "max_activations": 15 }, "seed": [ { diff --git a/tasks_gen/eval/G0024/empirical.json b/tasks_gen/eval/G0024/empirical.json new file mode 100644 index 0000000..c86339c --- /dev/null +++ b/tasks_gen/eval/G0024/empirical.json @@ -0,0 +1,18 @@ +{ + "deepseek-v4.1-flash:cloud": { + "score": 80.0, + "parts": { + "correctness": 40.0, + "craft": 20.0, + "clean": 15.0, + "own_tests": 0.0, + "discipline": 5.0, + "total": 80.0, + "note": "own_tests: faulty-reference part not implemented in skeleton" + }, + "hidden": "7/7", + "tool_calls": 40, + "seconds": 212.9, + "run_dir": "runs/emp/10015_G0024_llm_deepseek-v4.1-flash_cloud" + } +} \ No newline at end of file diff --git a/tasks_gen/eval/G0024/task.json b/tasks_gen/eval/G0024/task.json index 998f9ba..0d56fa6 100644 --- a/tasks_gen/eval/G0024/task.json +++ b/tasks_gen/eval/G0024/task.json @@ -6,8 +6,8 @@ "release_target": "v758", "expected_outcome": "implement", "budget": { - "max_tool_calls": 40, - "max_activations": 10 + "max_tool_calls": 60, + "max_activations": 15 }, "seed": [ { diff --git a/tasks_gen/eval/G0025/empirical.json b/tasks_gen/eval/G0025/empirical.json new file mode 100644 index 0000000..7765cd7 --- /dev/null +++ b/tasks_gen/eval/G0025/empirical.json @@ -0,0 +1,18 @@ +{ + "deepseek-v4.1-flash:cloud": { + "score": 85.0, + "parts": { + "correctness": 40.0, + "craft": 20.0, + "clean": 15.0, + "own_tests": 0.0, + "discipline": 10.0, + "total": 85.0, + "note": "own_tests: faulty-reference part not implemented in skeleton" + }, + "hidden": "7/7", + "tool_calls": 40, + "seconds": 113.4, + "run_dir": "runs/emp/10016_G0025_llm_deepseek-v4.1-flash_cloud" + } +} \ No newline at end of file diff --git a/tasks_gen/eval/G0025/task.json b/tasks_gen/eval/G0025/task.json index 5e0bd78..2acf58d 100644 --- a/tasks_gen/eval/G0025/task.json +++ b/tasks_gen/eval/G0025/task.json @@ -6,8 +6,8 @@ "release_target": "v816", "expected_outcome": "implement", "budget": { - "max_tool_calls": 40, - "max_activations": 10 + "max_tool_calls": 60, + "max_activations": 15 }, "seed": [ { diff --git a/tasks_gen/eval/G0026/empirical.json b/tasks_gen/eval/G0026/empirical.json new file mode 100644 index 0000000..e7bce4e --- /dev/null +++ b/tasks_gen/eval/G0026/empirical.json @@ -0,0 +1,18 @@ +{ + "deepseek-v4.1-flash:cloud": { + "score": 80.0, + "parts": { + "correctness": 40.0, + "craft": 20.0, + "clean": 15.0, + "own_tests": 0.0, + "discipline": 5.0, + "total": 80.0, + "note": "own_tests: faulty-reference part not implemented in skeleton" + }, + "hidden": "10/10", + "tool_calls": 12, + "seconds": 656.4, + "run_dir": "runs/emp/10017_G0026_llm_deepseek-v4.1-flash_cloud" + } +} \ No newline at end of file diff --git a/tasks_gen/eval/G0026/task.json b/tasks_gen/eval/G0026/task.json index 93c33fb..adc7a9b 100644 --- a/tasks_gen/eval/G0026/task.json +++ b/tasks_gen/eval/G0026/task.json @@ -6,8 +6,8 @@ "release_target": "v816", "expected_outcome": "implement", "budget": { - "max_tool_calls": 40, - "max_activations": 10 + "max_tool_calls": 60, + "max_activations": 15 }, "seed": [ { diff --git a/tasks_gen/eval/G0100/empirical.json b/tasks_gen/eval/G0100/empirical.json new file mode 100644 index 0000000..98212bd --- /dev/null +++ b/tasks_gen/eval/G0100/empirical.json @@ -0,0 +1,18 @@ +{ + "deepseek-v4.1-flash:cloud": { + "score": 100.0, + "parts": { + "correctness": 40.0, + "craft": 20.0, + "clean": 15.0, + "own_tests": 15.0, + "discipline": 10.0, + "total": 100.0, + "note": "own_tests: faulty-reference part not implemented in skeleton" + }, + "hidden": "10/10", + "tool_calls": 11, + "seconds": 214.9, + "run_dir": "runs/emp/10018_G0100_llm_deepseek-v4.1-flash_cloud" + } +} \ No newline at end of file diff --git a/tasks_gen/eval/G0100/task.json b/tasks_gen/eval/G0100/task.json index 6e995fc..fca2478 100644 --- a/tasks_gen/eval/G0100/task.json +++ b/tasks_gen/eval/G0100/task.json @@ -6,8 +6,8 @@ "release_target": "v816", "expected_outcome": "implement", "budget": { - "max_tool_calls": 50, - "max_activations": 12 + "max_tool_calls": 60, + "max_activations": 15 }, "seed": [], "contract": [ diff --git a/tasks_gen/eval/G0101/empirical.json b/tasks_gen/eval/G0101/empirical.json new file mode 100644 index 0000000..149e443 --- /dev/null +++ b/tasks_gen/eval/G0101/empirical.json @@ -0,0 +1,18 @@ +{ + "deepseek-v4.1-flash:cloud": { + "score": 100.0, + "parts": { + "correctness": 40.0, + "craft": 20.0, + "clean": 15.0, + "own_tests": 15.0, + "discipline": 10.0, + "total": 100.0, + "note": "own_tests: faulty-reference part not implemented in skeleton" + }, + "hidden": "11/11", + "tool_calls": 10, + "seconds": 138.8, + "run_dir": "runs/emp/10019_G0101_llm_deepseek-v4.1-flash_cloud" + } +} \ No newline at end of file diff --git a/tasks_gen/eval/G0102/empirical.json b/tasks_gen/eval/G0102/empirical.json new file mode 100644 index 0000000..612bed7 --- /dev/null +++ b/tasks_gen/eval/G0102/empirical.json @@ -0,0 +1,18 @@ +{ + "deepseek-v4.1-flash:cloud": { + "score": 90.0, + "parts": { + "correctness": 40.0, + "craft": 20.0, + "clean": 15.0, + "own_tests": 15.0, + "discipline": 0.0, + "total": 90.0, + "note": "own_tests: faulty-reference part not implemented in skeleton" + }, + "hidden": "11/11", + "tool_calls": 24, + "seconds": 124.3, + "run_dir": "runs/emp/10020_G0102_llm_deepseek-v4.1-flash_cloud" + } +} \ No newline at end of file diff --git a/tasks_gen/eval/G0103/empirical.json b/tasks_gen/eval/G0103/empirical.json new file mode 100644 index 0000000..9fdcfb7 --- /dev/null +++ b/tasks_gen/eval/G0103/empirical.json @@ -0,0 +1,18 @@ +{ + "deepseek-v4.1-flash:cloud": { + "score": 100.0, + "parts": { + "correctness": 40.0, + "craft": 20.0, + "clean": 15.0, + "own_tests": 15.0, + "discipline": 10.0, + "total": 100.0, + "note": "own_tests: faulty-reference part not implemented in skeleton" + }, + "hidden": "11/11", + "tool_calls": 7, + "seconds": 68.5, + "run_dir": "runs/emp/10021_G0103_llm_deepseek-v4.1-flash_cloud" + } +} \ No newline at end of file diff --git a/tasks_gen/eval/G0103/task.json b/tasks_gen/eval/G0103/task.json index 77f9809..fb05d00 100644 --- a/tasks_gen/eval/G0103/task.json +++ b/tasks_gen/eval/G0103/task.json @@ -6,8 +6,8 @@ "release_target": "v816", "expected_outcome": "implement", "budget": { - "max_tool_calls": 40, - "max_activations": 10 + "max_tool_calls": 60, + "max_activations": 15 }, "seed": [], "contract": [ diff --git a/tasks_gen/eval/G0104/empirical.json b/tasks_gen/eval/G0104/empirical.json new file mode 100644 index 0000000..0d17089 --- /dev/null +++ b/tasks_gen/eval/G0104/empirical.json @@ -0,0 +1,18 @@ +{ + "deepseek-v4.1-flash:cloud": { + "score": 100.0, + "parts": { + "correctness": 40.0, + "craft": 20.0, + "clean": 15.0, + "own_tests": 15.0, + "discipline": 10.0, + "total": 100.0, + "note": "own_tests: faulty-reference part not implemented in skeleton" + }, + "hidden": "12/12", + "tool_calls": 11, + "seconds": 136.4, + "run_dir": "runs/emp/10022_G0104_llm_deepseek-v4.1-flash_cloud" + } +} \ No newline at end of file diff --git a/tasks_gen/eval/G0104/task.json b/tasks_gen/eval/G0104/task.json index c62db27..ce09714 100644 --- a/tasks_gen/eval/G0104/task.json +++ b/tasks_gen/eval/G0104/task.json @@ -6,8 +6,8 @@ "release_target": "v758", "expected_outcome": "implement", "budget": { - "max_tool_calls": 40, - "max_activations": 10 + "max_tool_calls": 60, + "max_activations": 15 }, "seed": [], "contract": [ diff --git a/tasks_gen/eval/G0105/empirical.json b/tasks_gen/eval/G0105/empirical.json new file mode 100644 index 0000000..232fb69 --- /dev/null +++ b/tasks_gen/eval/G0105/empirical.json @@ -0,0 +1,15 @@ +{ + "deepseek-v4.1-flash:cloud": { + "score": 0, + "parts": { + "total": 0, + "failed_gates": [ + "G5_no_p1" + ] + }, + "hidden": "11/11", + "tool_calls": 44, + "seconds": 837.6, + "run_dir": "runs/emp/10023_G0105_llm_deepseek-v4.1-flash_cloud" + } +} \ No newline at end of file diff --git a/tasks_gen/eval/G0105/task.json b/tasks_gen/eval/G0105/task.json index e678d17..046a710 100644 --- a/tasks_gen/eval/G0105/task.json +++ b/tasks_gen/eval/G0105/task.json @@ -6,8 +6,8 @@ "release_target": "v758", "expected_outcome": "implement", "budget": { - "max_tool_calls": 40, - "max_activations": 10 + "max_tool_calls": 60, + "max_activations": 15 }, "seed": [ { diff --git a/tasks_gen/eval/G0106/empirical.json b/tasks_gen/eval/G0106/empirical.json new file mode 100644 index 0000000..6565055 --- /dev/null +++ b/tasks_gen/eval/G0106/empirical.json @@ -0,0 +1,18 @@ +{ + "deepseek-v4.1-flash:cloud": { + "score": 98.5, + "parts": { + "correctness": 40.0, + "craft": 20.0, + "clean": 13.5, + "own_tests": 15.0, + "discipline": 10.0, + "total": 98.5, + "note": "own_tests: faulty-reference part not implemented in skeleton" + }, + "hidden": "11/11", + "tool_calls": 23, + "seconds": 109.6, + "run_dir": "runs/emp/10024_G0106_llm_deepseek-v4.1-flash_cloud" + } +} \ No newline at end of file diff --git a/tasks_gen/eval/G0106/task.json b/tasks_gen/eval/G0106/task.json index c12ea94..fd8f294 100644 --- a/tasks_gen/eval/G0106/task.json +++ b/tasks_gen/eval/G0106/task.json @@ -6,8 +6,8 @@ "release_target": "v816", "expected_outcome": "implement", "budget": { - "max_tool_calls": 40, - "max_activations": 10 + "max_tool_calls": 60, + "max_activations": 15 }, "seed": [ { diff --git a/tasks_gen/eval/G0107/empirical.json b/tasks_gen/eval/G0107/empirical.json new file mode 100644 index 0000000..99dad75 --- /dev/null +++ b/tasks_gen/eval/G0107/empirical.json @@ -0,0 +1,16 @@ +{ + "deepseek-v4.1-flash:cloud": { + "score": 0, + "parts": { + "total": 0, + "failed_gates": [ + "G2_contract", + "G3_hidden_runs" + ] + }, + "hidden": "0/0", + "tool_calls": 31, + "seconds": 162.0, + "run_dir": "runs/emp/10025_G0107_llm_deepseek-v4.1-flash_cloud" + } +} \ No newline at end of file diff --git a/tasks_gen/eval/G0107/task.json b/tasks_gen/eval/G0107/task.json index 9a78cbb..af788a4 100644 --- a/tasks_gen/eval/G0107/task.json +++ b/tasks_gen/eval/G0107/task.json @@ -6,8 +6,8 @@ "release_target": "v816", "expected_outcome": "implement", "budget": { - "max_tool_calls": 40, - "max_activations": 10 + "max_tool_calls": 60, + "max_activations": 15 }, "seed": [ { diff --git a/tasks_gen/eval/G0108/empirical.json b/tasks_gen/eval/G0108/empirical.json new file mode 100644 index 0000000..135ef2a --- /dev/null +++ b/tasks_gen/eval/G0108/empirical.json @@ -0,0 +1,18 @@ +{ + "deepseek-v4.1-flash:cloud": { + "score": 60.0, + "parts": { + "correctness": 20.0, + "craft": 20.0, + "clean": 15.0, + "own_tests": 0.0, + "discipline": 5.0, + "total": 60.0, + "note": "own_tests: faulty-reference part not implemented in skeleton" + }, + "hidden": "5/10", + "tool_calls": 20, + "seconds": 711.8, + "run_dir": "runs/emp/10026_G0108_llm_deepseek-v4.1-flash_cloud" + } +} \ No newline at end of file diff --git a/tasks_gen/eval/G0108/task.json b/tasks_gen/eval/G0108/task.json index 90c9877..d3347e6 100644 --- a/tasks_gen/eval/G0108/task.json +++ b/tasks_gen/eval/G0108/task.json @@ -6,8 +6,8 @@ "release_target": "v816", "expected_outcome": "implement", "budget": { - "max_tool_calls": 40, - "max_activations": 10 + "max_tool_calls": 60, + "max_activations": 15 }, "seed": [ { diff --git a/tasks_gen/eval/G0109/empirical.json b/tasks_gen/eval/G0109/empirical.json new file mode 100644 index 0000000..9178ecb --- /dev/null +++ b/tasks_gen/eval/G0109/empirical.json @@ -0,0 +1,18 @@ +{ + "deepseek-v4.1-flash:cloud": { + "score": 80.0, + "parts": { + "correctness": 40.0, + "craft": 20.0, + "clean": 15.0, + "own_tests": 0.0, + "discipline": 5.0, + "total": 80.0, + "note": "own_tests: faulty-reference part not implemented in skeleton" + }, + "hidden": "8/8", + "tool_calls": 33, + "seconds": 667.9, + "run_dir": "runs/emp/10027_G0109_llm_deepseek-v4.1-flash_cloud" + } +} \ No newline at end of file diff --git a/tasks_gen/eval/G0109/task.json b/tasks_gen/eval/G0109/task.json index c1f22f2..82e7e87 100644 --- a/tasks_gen/eval/G0109/task.json +++ b/tasks_gen/eval/G0109/task.json @@ -6,8 +6,8 @@ "release_target": "v816", "expected_outcome": "implement", "budget": { - "max_tool_calls": 40, - "max_activations": 10 + "max_tool_calls": 60, + "max_activations": 15 }, "seed": [ { diff --git a/tasks_gen/eval/G0110/empirical.json b/tasks_gen/eval/G0110/empirical.json new file mode 100644 index 0000000..aa504b2 --- /dev/null +++ b/tasks_gen/eval/G0110/empirical.json @@ -0,0 +1,18 @@ +{ + "deepseek-v4.1-flash:cloud": { + "score": 80.0, + "parts": { + "correctness": 40.0, + "craft": 20.0, + "clean": 15.0, + "own_tests": 0.0, + "discipline": 5.0, + "total": 80.0, + "note": "own_tests: faulty-reference part not implemented in skeleton" + }, + "hidden": "6/6", + "tool_calls": 17, + "seconds": 557.9, + "run_dir": "runs/emp/10028_G0110_llm_deepseek-v4.1-flash_cloud" + } +} \ No newline at end of file diff --git a/tasks_gen/eval/G0110/task.json b/tasks_gen/eval/G0110/task.json index d9aa880..d81ce6b 100644 --- a/tasks_gen/eval/G0110/task.json +++ b/tasks_gen/eval/G0110/task.json @@ -6,8 +6,8 @@ "release_target": "v758", "expected_outcome": "implement", "budget": { - "max_tool_calls": 40, - "max_activations": 10 + "max_tool_calls": 60, + "max_activations": 15 }, "seed": [ { diff --git a/tasks_gen/eval/G0111/empirical.json b/tasks_gen/eval/G0111/empirical.json new file mode 100644 index 0000000..518cf80 --- /dev/null +++ b/tasks_gen/eval/G0111/empirical.json @@ -0,0 +1,18 @@ +{ + "deepseek-v4.1-flash:cloud": { + "score": 100.0, + "parts": { + "correctness": 40.0, + "craft": 20.0, + "clean": 15.0, + "own_tests": 15.0, + "discipline": 10.0, + "total": 100.0, + "note": "own_tests: faulty-reference part not implemented in skeleton" + }, + "hidden": "6/6", + "tool_calls": 21, + "seconds": 214.2, + "run_dir": "runs/emp/10029_G0111_llm_deepseek-v4.1-flash_cloud" + } +} \ No newline at end of file diff --git a/tasks_gen/eval/G0111/task.json b/tasks_gen/eval/G0111/task.json index 27dfda3..4558012 100644 --- a/tasks_gen/eval/G0111/task.json +++ b/tasks_gen/eval/G0111/task.json @@ -6,8 +6,8 @@ "release_target": "v758", "expected_outcome": "implement", "budget": { - "max_tool_calls": 40, - "max_activations": 10 + "max_tool_calls": 60, + "max_activations": 15 }, "seed": [ { diff --git a/tasks_gen/eval/G0112/task.json b/tasks_gen/eval/G0112/task.json index 2babb55..75384a9 100644 --- a/tasks_gen/eval/G0112/task.json +++ b/tasks_gen/eval/G0112/task.json @@ -6,8 +6,8 @@ "release_target": "v816", "expected_outcome": "implement", "budget": { - "max_tool_calls": 40, - "max_activations": 10 + "max_tool_calls": 60, + "max_activations": 15 }, "seed": [ { diff --git a/tasks_gen/eval/G0113/task.json b/tasks_gen/eval/G0113/task.json index 88bdce6..4711688 100644 --- a/tasks_gen/eval/G0113/task.json +++ b/tasks_gen/eval/G0113/task.json @@ -6,8 +6,8 @@ "release_target": "v816", "expected_outcome": "implement", "budget": { - "max_tool_calls": 40, - "max_activations": 10 + "max_tool_calls": 60, + "max_activations": 15 }, "seed": [], "contract": [ diff --git a/tasks_gen/eval/G0116/task.json b/tasks_gen/eval/G0116/task.json index e6992ca..7530485 100644 --- a/tasks_gen/eval/G0116/task.json +++ b/tasks_gen/eval/G0116/task.json @@ -6,8 +6,8 @@ "release_target": "v816", "expected_outcome": "implement", "budget": { - "max_tool_calls": 40, - "max_activations": 10 + "max_tool_calls": 60, + "max_activations": 15 }, "seed": [], "contract": [ diff --git a/tasks_gen/eval/G0119/task.json b/tasks_gen/eval/G0119/task.json index 186a2ad..d6258ea 100644 --- a/tasks_gen/eval/G0119/task.json +++ b/tasks_gen/eval/G0119/task.json @@ -6,8 +6,8 @@ "release_target": "v816", "expected_outcome": "implement", "budget": { - "max_tool_calls": 40, - "max_activations": 10 + "max_tool_calls": 60, + "max_activations": 15 }, "seed": [], "contract": [ diff --git a/tasks_gen/eval/G0120/task.json b/tasks_gen/eval/G0120/task.json index d9c4b61..05d2d8a 100644 --- a/tasks_gen/eval/G0120/task.json +++ b/tasks_gen/eval/G0120/task.json @@ -6,8 +6,8 @@ "release_target": "v816", "expected_outcome": "implement", "budget": { - "max_tool_calls": 40, - "max_activations": 12 + "max_tool_calls": 60, + "max_activations": 15 }, "seed": [ { diff --git a/tasks_gen/eval/G0121/generation.json b/tasks_gen/eval/G0121/generation.json deleted file mode 100644 index 317a517..0000000 --- a/tasks_gen/eval/G0121/generation.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "id": "G0121", - "pool": "eval", - "object_type": "FUNC", - "category": "C", - "attempts": [ - { - "stage": "validate", - "oracle": null, - "null": null - }, - { - "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/eval/G0121/task.json b/tasks_gen/eval/G0121/task.json index dd9c9a8..915abed 100644 --- a/tasks_gen/eval/G0121/task.json +++ b/tasks_gen/eval/G0121/task.json @@ -6,8 +6,8 @@ "release_target": "v758", "expected_outcome": "implement", "budget": { - "max_tool_calls": 40, - "max_activations": 10 + "max_tool_calls": 60, + "max_activations": 15 }, "seed": [ { diff --git a/tasks_gen/eval/G0122/task.json b/tasks_gen/eval/G0122/task.json index 11f772b..b62b79e 100644 --- a/tasks_gen/eval/G0122/task.json +++ b/tasks_gen/eval/G0122/task.json @@ -6,8 +6,8 @@ "release_target": "v816", "expected_outcome": "implement", "budget": { - "max_tool_calls": 40, - "max_activations": 10 + "max_tool_calls": 60, + "max_activations": 15 }, "seed": [ { diff --git a/tasks_gen/eval/G0123/task.json b/tasks_gen/eval/G0123/task.json index 57889d2..b04a94c 100644 --- a/tasks_gen/eval/G0123/task.json +++ b/tasks_gen/eval/G0123/task.json @@ -6,8 +6,8 @@ "release_target": "v816", "expected_outcome": "implement", "budget": { - "max_tool_calls": 40, - "max_activations": 10 + "max_tool_calls": 60, + "max_activations": 15 }, "seed": [ { diff --git a/tasks_gen/eval/G0124/generation.json b/tasks_gen/eval/G0124/generation.json deleted file mode 100644 index 8003896..0000000 --- a/tasks_gen/eval/G0124/generation.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "id": "G0124", - "pool": "eval", - "object_type": "PROG", - "category": "C", - "attempts": [ - { - "stage": "validate", - "oracle": 100.0, - "null": 0, - "mutation": { - "valid": 0, - "killed": 0, - "ok": false - } - }, - { - "stage": "validate", - "oracle": 80.6, - "null": 0 - }, - { - "stage": "bundle", - "errors": [ - "seed: file seed/t20 seed.clas.abap missing" - ], - "by_check": { - "structure": 1 - } - }, - { - "stage": "validate", - "oracle": 0, - "null": 0 - } - ], - "accepted": false -} \ No newline at end of file diff --git a/tasks_gen/eval/G0124/task.json b/tasks_gen/eval/G0124/task.json index 5a26ce6..77aeed7 100644 --- a/tasks_gen/eval/G0124/task.json +++ b/tasks_gen/eval/G0124/task.json @@ -6,8 +6,8 @@ "release_target": "v758", "expected_outcome": "implement", "budget": { - "max_tool_calls": 40, - "max_activations": 10 + "max_tool_calls": 60, + "max_activations": 15 }, "seed": [ { diff --git a/tasks_gen/eval/G0125/task.json b/tasks_gen/eval/G0125/task.json index bf93c90..2580e84 100644 --- a/tasks_gen/eval/G0125/task.json +++ b/tasks_gen/eval/G0125/task.json @@ -6,8 +6,8 @@ "release_target": "v816", "expected_outcome": "implement", "budget": { - "max_tool_calls": 40, - "max_activations": 10 + "max_tool_calls": 60, + "max_activations": 15 }, "seed": [ { diff --git a/tasks_gen/eval/G0126/faulty/m0_bag_drop.clas.abap b/tasks_gen/eval/G0126/faulty/m0_bag_drop.clas.abap new file mode 100644 index 0000000..3a248e6 --- /dev/null +++ b/tasks_gen/eval/G0126/faulty/m0_bag_drop.clas.abap @@ -0,0 +1,93 @@ +CLASS {{p}}bag_drop DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES: + ty_tag TYPE c LENGTH 10, + ty_weight TYPE p LENGTH 5 DECIMALS 2, + ty_size TYPE i, + ty_count TYPE i, + ty_minutes TYPE i. + + METHODS accept_bag + IMPORTING + iv_tag TYPE ty_tag + iv_weight TYPE ty_weight + iv_length TYPE ty_size + iv_width TYPE ty_size + iv_height TYPE ty_size + iv_bags_checked TYPE ty_count + iv_min_to_dep TYPE ty_minutes + RAISING + {{p}}cx_bag_tag + {{p}}cx_bag_weight + {{p}}cx_bag_size + {{p}}cx_bag_limit + {{p}}cx_bag_late. + + PRIVATE SECTION. + CONSTANTS: + c_max_weight TYPE ty_weight VALUE 23, + c_max_size TYPE ty_size VALUE 158, + c_max_bags TYPE ty_count VALUE 2, + c_min_minutes TYPE ty_minutes VALUE 40. + + METHODS check_tag + IMPORTING iv_tag TYPE ty_tag + RAISING {{p}}cx_bag_tag. + METHODS check_weight + IMPORTING iv_weight TYPE ty_weight + RAISING {{p}}cx_bag_weight. + METHODS check_size + IMPORTING iv_length TYPE ty_size + iv_width TYPE ty_size + iv_height TYPE ty_size + RAISING {{p}}cx_bag_size. + METHODS check_bag_count + IMPORTING iv_bags_checked TYPE ty_count + RAISING {{p}}cx_bag_limit. + METHODS check_departure + IMPORTING iv_min_to_dep TYPE ty_minutes + RAISING {{p}}cx_bag_late. +ENDCLASS. + + +CLASS {{p}}bag_drop IMPLEMENTATION. + METHOD accept_bag. + check_tag( iv_tag ). + check_weight( iv_weight ). + check_size( iv_length = iv_length + iv_width = iv_width + iv_height = iv_height ). + check_bag_count( iv_bags_checked ). + check_departure( iv_min_to_dep ). + ENDMETHOD. + + METHOD check_tag. + IF iv_tag CN '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'. + RAISE EXCEPTION TYPE {{p}}cx_bag_tag. + ENDIF. + ENDMETHOD. + + METHOD check_weight. + IF iv_weight > c_max_weight. + RAISE EXCEPTION TYPE {{p}}cx_bag_weight. + ENDIF. + ENDMETHOD. + + METHOD check_size. + IF iv_length - iv_width + iv_height > c_max_size. + RAISE EXCEPTION TYPE {{p}}cx_bag_size. + ENDIF. + ENDMETHOD. + + METHOD check_bag_count. + IF iv_bags_checked >= c_max_bags. + RAISE EXCEPTION TYPE {{p}}cx_bag_limit. + ENDIF. + ENDMETHOD. + + METHOD check_departure. + IF iv_min_to_dep < c_min_minutes. + RAISE EXCEPTION TYPE {{p}}cx_bag_late. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0126/faulty/m1_bag_drop.clas.abap b/tasks_gen/eval/G0126/faulty/m1_bag_drop.clas.abap new file mode 100644 index 0000000..5b0ebbb --- /dev/null +++ b/tasks_gen/eval/G0126/faulty/m1_bag_drop.clas.abap @@ -0,0 +1,93 @@ +CLASS {{p}}bag_drop DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES: + ty_tag TYPE c LENGTH 10, + ty_weight TYPE p LENGTH 5 DECIMALS 2, + ty_size TYPE i, + ty_count TYPE i, + ty_minutes TYPE i. + + METHODS accept_bag + IMPORTING + iv_tag TYPE ty_tag + iv_weight TYPE ty_weight + iv_length TYPE ty_size + iv_width TYPE ty_size + iv_height TYPE ty_size + iv_bags_checked TYPE ty_count + iv_min_to_dep TYPE ty_minutes + RAISING + {{p}}cx_bag_tag + {{p}}cx_bag_weight + {{p}}cx_bag_size + {{p}}cx_bag_limit + {{p}}cx_bag_late. + + PRIVATE SECTION. + CONSTANTS: + c_max_weight TYPE ty_weight VALUE 23, + c_max_size TYPE ty_size VALUE 158, + c_max_bags TYPE ty_count VALUE 2, + c_min_minutes TYPE ty_minutes VALUE 40. + + METHODS check_tag + IMPORTING iv_tag TYPE ty_tag + RAISING {{p}}cx_bag_tag. + METHODS check_weight + IMPORTING iv_weight TYPE ty_weight + RAISING {{p}}cx_bag_weight. + METHODS check_size + IMPORTING iv_length TYPE ty_size + iv_width TYPE ty_size + iv_height TYPE ty_size + RAISING {{p}}cx_bag_size. + METHODS check_bag_count + IMPORTING iv_bags_checked TYPE ty_count + RAISING {{p}}cx_bag_limit. + METHODS check_departure + IMPORTING iv_min_to_dep TYPE ty_minutes + RAISING {{p}}cx_bag_late. +ENDCLASS. + + +CLASS {{p}}bag_drop IMPLEMENTATION. + METHOD accept_bag. + check_tag( iv_tag ). + check_weight( iv_weight ). + check_size( iv_length = iv_length + iv_width = iv_width + iv_height = iv_height ). + check_bag_count( iv_bags_checked ). + check_departure( iv_min_to_dep ). + ENDMETHOD. + + METHOD check_tag. + IF iv_tag CN '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'. + RAISE EXCEPTION TYPE {{p}}cx_bag_tag. + ENDIF. + ENDMETHOD. + + METHOD check_weight. + IF iv_weight > c_max_weight. + RAISE EXCEPTION TYPE {{p}}cx_bag_weight. + ENDIF. + ENDMETHOD. + + METHOD check_size. + IF iv_length + iv_width - iv_height > c_max_size. + RAISE EXCEPTION TYPE {{p}}cx_bag_size. + ENDIF. + ENDMETHOD. + + METHOD check_bag_count. + IF iv_bags_checked >= c_max_bags. + RAISE EXCEPTION TYPE {{p}}cx_bag_limit. + ENDIF. + ENDMETHOD. + + METHOD check_departure. + IF iv_min_to_dep < c_min_minutes. + RAISE EXCEPTION TYPE {{p}}cx_bag_late. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0126/faulty/m2_bag_drop.clas.abap b/tasks_gen/eval/G0126/faulty/m2_bag_drop.clas.abap new file mode 100644 index 0000000..0e6f734 --- /dev/null +++ b/tasks_gen/eval/G0126/faulty/m2_bag_drop.clas.abap @@ -0,0 +1,93 @@ +CLASS {{p}}bag_drop DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES: + ty_tag TYPE c LENGTH 10, + ty_weight TYPE p LENGTH 5 DECIMALS 2, + ty_size TYPE i, + ty_count TYPE i, + ty_minutes TYPE i. + + METHODS accept_bag + IMPORTING + iv_tag TYPE ty_tag + iv_weight TYPE ty_weight + iv_length TYPE ty_size + iv_width TYPE ty_size + iv_height TYPE ty_size + iv_bags_checked TYPE ty_count + iv_min_to_dep TYPE ty_minutes + RAISING + {{p}}cx_bag_tag + {{p}}cx_bag_weight + {{p}}cx_bag_size + {{p}}cx_bag_limit + {{p}}cx_bag_late. + + PRIVATE SECTION. + CONSTANTS: + c_max_weight TYPE ty_weight VALUE 23, + c_max_size TYPE ty_size VALUE 158, + c_max_bags TYPE ty_count VALUE 2, + c_min_minutes TYPE ty_minutes VALUE 40. + + METHODS check_tag + IMPORTING iv_tag TYPE ty_tag + RAISING {{p}}cx_bag_tag. + METHODS check_weight + IMPORTING iv_weight TYPE ty_weight + RAISING {{p}}cx_bag_weight. + METHODS check_size + IMPORTING iv_length TYPE ty_size + iv_width TYPE ty_size + iv_height TYPE ty_size + RAISING {{p}}cx_bag_size. + METHODS check_bag_count + IMPORTING iv_bags_checked TYPE ty_count + RAISING {{p}}cx_bag_limit. + METHODS check_departure + IMPORTING iv_min_to_dep TYPE ty_minutes + RAISING {{p}}cx_bag_late. +ENDCLASS. + + +CLASS {{p}}bag_drop IMPLEMENTATION. + METHOD accept_bag. + check_tag( iv_tag ). + check_weight( iv_weight ). + check_size( iv_length = iv_length + iv_width = iv_width + iv_height = iv_height ). + check_bag_count( iv_bags_checked ). + check_departure( iv_min_to_dep ). + ENDMETHOD. + + METHOD check_tag. + IF iv_tag CN '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'. + RAISE EXCEPTION TYPE {{p}}cx_bag_tag. + ENDIF. + ENDMETHOD. + + METHOD check_weight. + IF iv_weight > c_max_weight. + RAISE EXCEPTION TYPE {{p}}cx_bag_weight. + ENDIF. + ENDMETHOD. + + METHOD check_size. + IF iv_length + iv_width + iv_height <= c_max_size. + RAISE EXCEPTION TYPE {{p}}cx_bag_size. + ENDIF. + ENDMETHOD. + + METHOD check_bag_count. + IF iv_bags_checked >= c_max_bags. + RAISE EXCEPTION TYPE {{p}}cx_bag_limit. + ENDIF. + ENDMETHOD. + + METHOD check_departure. + IF iv_min_to_dep < c_min_minutes. + RAISE EXCEPTION TYPE {{p}}cx_bag_late. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0126/faulty/m3_bag_drop.clas.abap b/tasks_gen/eval/G0126/faulty/m3_bag_drop.clas.abap new file mode 100644 index 0000000..5f349da --- /dev/null +++ b/tasks_gen/eval/G0126/faulty/m3_bag_drop.clas.abap @@ -0,0 +1,93 @@ +CLASS {{p}}bag_drop DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES: + ty_tag TYPE c LENGTH 10, + ty_weight TYPE p LENGTH 5 DECIMALS 2, + ty_size TYPE i, + ty_count TYPE i, + ty_minutes TYPE i. + + METHODS accept_bag + IMPORTING + iv_tag TYPE ty_tag + iv_weight TYPE ty_weight + iv_length TYPE ty_size + iv_width TYPE ty_size + iv_height TYPE ty_size + iv_bags_checked TYPE ty_count + iv_min_to_dep TYPE ty_minutes + RAISING + {{p}}cx_bag_tag + {{p}}cx_bag_weight + {{p}}cx_bag_size + {{p}}cx_bag_limit + {{p}}cx_bag_late. + + PRIVATE SECTION. + CONSTANTS: + c_max_weight TYPE ty_weight VALUE 23, + c_max_size TYPE ty_size VALUE 158, + c_max_bags TYPE ty_count VALUE 2, + c_min_minutes TYPE ty_minutes VALUE 40. + + METHODS check_tag + IMPORTING iv_tag TYPE ty_tag + RAISING {{p}}cx_bag_tag. + METHODS check_weight + IMPORTING iv_weight TYPE ty_weight + RAISING {{p}}cx_bag_weight. + METHODS check_size + IMPORTING iv_length TYPE ty_size + iv_width TYPE ty_size + iv_height TYPE ty_size + RAISING {{p}}cx_bag_size. + METHODS check_bag_count + IMPORTING iv_bags_checked TYPE ty_count + RAISING {{p}}cx_bag_limit. + METHODS check_departure + IMPORTING iv_min_to_dep TYPE ty_minutes + RAISING {{p}}cx_bag_late. +ENDCLASS. + + +CLASS {{p}}bag_drop IMPLEMENTATION. + METHOD accept_bag. + check_tag( iv_tag ). + check_weight( iv_weight ). + check_size( iv_length = iv_length + iv_width = iv_width + iv_height = iv_height ). + check_bag_count( iv_bags_checked ). + check_departure( iv_min_to_dep ). + ENDMETHOD. + + METHOD check_tag. + IF iv_tag CN '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'. + RAISE EXCEPTION TYPE {{p}}cx_bag_tag. + ENDIF. + ENDMETHOD. + + METHOD check_weight. + IF iv_weight > c_max_weight. + RAISE EXCEPTION TYPE {{p}}cx_bag_weight. + ENDIF. + ENDMETHOD. + + METHOD check_size. + IF iv_length + iv_width + iv_height > c_max_size. + RAISE EXCEPTION TYPE {{p}}cx_bag_size. + ENDIF. + ENDMETHOD. + + METHOD check_bag_count. + IF iv_bags_checked < c_max_bags. + RAISE EXCEPTION TYPE {{p}}cx_bag_limit. + ENDIF. + ENDMETHOD. + + METHOD check_departure. + IF iv_min_to_dep < c_min_minutes. + RAISE EXCEPTION TYPE {{p}}cx_bag_late. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0126/faulty/m4_bag_drop.clas.abap b/tasks_gen/eval/G0126/faulty/m4_bag_drop.clas.abap new file mode 100644 index 0000000..bf3f83e --- /dev/null +++ b/tasks_gen/eval/G0126/faulty/m4_bag_drop.clas.abap @@ -0,0 +1,93 @@ +CLASS {{p}}bag_drop DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES: + ty_tag TYPE c LENGTH 10, + ty_weight TYPE p LENGTH 5 DECIMALS 2, + ty_size TYPE i, + ty_count TYPE i, + ty_minutes TYPE i. + + METHODS accept_bag + IMPORTING + iv_tag TYPE ty_tag + iv_weight TYPE ty_weight + iv_length TYPE ty_size + iv_width TYPE ty_size + iv_height TYPE ty_size + iv_bags_checked TYPE ty_count + iv_min_to_dep TYPE ty_minutes + RAISING + {{p}}cx_bag_tag + {{p}}cx_bag_weight + {{p}}cx_bag_size + {{p}}cx_bag_limit + {{p}}cx_bag_late. + + PRIVATE SECTION. + CONSTANTS: + c_max_weight TYPE ty_weight VALUE 23, + c_max_size TYPE ty_size VALUE 158, + c_max_bags TYPE ty_count VALUE 2, + c_min_minutes TYPE ty_minutes VALUE 40. + + METHODS check_tag + IMPORTING iv_tag TYPE ty_tag + RAISING {{p}}cx_bag_tag. + METHODS check_weight + IMPORTING iv_weight TYPE ty_weight + RAISING {{p}}cx_bag_weight. + METHODS check_size + IMPORTING iv_length TYPE ty_size + iv_width TYPE ty_size + iv_height TYPE ty_size + RAISING {{p}}cx_bag_size. + METHODS check_bag_count + IMPORTING iv_bags_checked TYPE ty_count + RAISING {{p}}cx_bag_limit. + METHODS check_departure + IMPORTING iv_min_to_dep TYPE ty_minutes + RAISING {{p}}cx_bag_late. +ENDCLASS. + + +CLASS {{p}}bag_drop IMPLEMENTATION. + METHOD accept_bag. + check_tag( iv_tag ). + check_weight( iv_weight ). + check_size( iv_length = iv_length + iv_width = iv_width + iv_height = iv_height ). + check_bag_count( iv_bags_checked ). + check_departure( iv_min_to_dep ). + ENDMETHOD. + + METHOD check_tag. + IF iv_tag CN '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'. + RAISE EXCEPTION TYPE {{p}}cx_bag_tag. + ENDIF. + ENDMETHOD. + + METHOD check_weight. + IF iv_weight > c_max_weight. + RAISE EXCEPTION TYPE {{p}}cx_bag_weight. + ENDIF. + ENDMETHOD. + + METHOD check_size. + IF iv_length + iv_width + iv_height > c_max_size. + RAISE EXCEPTION TYPE {{p}}cx_bag_size. + ENDIF. + ENDMETHOD. + + METHOD check_bag_count. + IF iv_bags_checked >= c_max_bags. + RAISE EXCEPTION TYPE {{p}}cx_bag_limit. + ENDIF. + ENDMETHOD. + + METHOD check_departure. + IF iv_min_to_dep >= c_min_minutes. + RAISE EXCEPTION TYPE {{p}}cx_bag_late. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0126/generation.json b/tasks_gen/eval/G0126/generation.json index c664d89..0e2153c 100644 --- a/tasks_gen/eval/G0126/generation.json +++ b/tasks_gen/eval/G0126/generation.json @@ -28,7 +28,19 @@ "stage": "validate", "oracle": 92.5, "null": 0 + }, + { + "stage": "revalidate", + "by": "harness fix 2026-10-03", + "change": "coverage with several contract classes (exception classes). Bundle not changed.", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 5, + "killed": 5, + "ok": true + } } ], - "accepted": false + "accepted": true } \ No newline at end of file diff --git a/tasks_gen/eval/G0126/mutation.json b/tasks_gen/eval/G0126/mutation.json new file mode 100644 index 0000000..c740cfa --- /dev/null +++ b/tasks_gen/eval/G0126/mutation.json @@ -0,0 +1,72 @@ +{ + "task": "G0126", + "mutants": [ + { + "object": "{{P}}BAG_DROP", + "mutant": "line 77: + -> - (arith)", + "status": "killed", + "hidden": "10/11", + "failed_tests": [ + "REJECTS_OVERSIZE" + ] + }, + { + "object": "{{P}}BAG_DROP", + "mutant": "line 77: + -> - (arith)", + "status": "killed", + "hidden": "10/11", + "failed_tests": [ + "REJECTS_OVERSIZE" + ] + }, + { + "object": "{{P}}BAG_DROP", + "mutant": "line 77: > -> <= (rel)", + "status": "killed", + "hidden": "3/11", + "failed_tests": [ + "ACCEPTS_40_MINUTES", + "ACCEPTS_MAX_SIZE", + "ACCEPTS_MAX_WEIGHT", + "ACCEPTS_ONE_BAG", + "ACCEPTS_VALID_BAG", + "REJECTS_39_MINUTES", + "REJECTS_OVERSIZE", + "REJECTS_THIRD_BAG" + ] + }, + { + "object": "{{P}}BAG_DROP", + "mutant": "line 83: >= -> < (rel)", + "status": "killed", + "hidden": "4/11", + "failed_tests": [ + "ACCEPTS_40_MINUTES", + "ACCEPTS_MAX_SIZE", + "ACCEPTS_MAX_WEIGHT", + "ACCEPTS_ONE_BAG", + "ACCEPTS_VALID_BAG", + "REJECTS_39_MINUTES", + "REJECTS_THIRD_BAG" + ] + }, + { + "object": "{{P}}BAG_DROP", + "mutant": "line 89: < -> >= (rel)", + "status": "killed", + "hidden": "5/11", + "failed_tests": [ + "ACCEPTS_40_MINUTES", + "ACCEPTS_MAX_SIZE", + "ACCEPTS_MAX_WEIGHT", + "ACCEPTS_ONE_BAG", + "ACCEPTS_VALID_BAG", + "REJECTS_39_MINUTES" + ] + } + ], + "valid": 5, + "killed": 5, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0127/task.json b/tasks_gen/eval/G0127/task.json index 8220e32..6188fcd 100644 --- a/tasks_gen/eval/G0127/task.json +++ b/tasks_gen/eval/G0127/task.json @@ -6,8 +6,8 @@ "release_target": "v816", "expected_outcome": "implement", "budget": { - "max_tool_calls": 40, - "max_activations": 10 + "max_tool_calls": 60, + "max_activations": 15 }, "seed": [ { diff --git a/tasks_gen/eval/G0128/faulty/m0_crew_duty_check.clas.abap b/tasks_gen/eval/G0128/faulty/m0_crew_duty_check.clas.abap new file mode 100644 index 0000000..6df3dfe --- /dev/null +++ b/tasks_gen/eval/G0128/faulty/m0_crew_duty_check.clas.abap @@ -0,0 +1,69 @@ +CLASS {{p}}crew_duty_check DEFINITION + PUBLIC + FINAL + CREATE PUBLIC. + + PUBLIC SECTION. + TYPES ty_hours TYPE p LENGTH 4 DECIMALS 1. + TYPES: + BEGIN OF ty_duty, + crew_id TYPE c LENGTH 10, + licence_valid TYPE abap_bool, + type_rating TYPE c LENGTH 4, + aircraft_type TYPE c LENGTH 4, + rest_hours TYPE ty_hours, + duty_hours TYPE ty_hours, + month_hours TYPE ty_hours, + END OF ty_duty. + + METHODS check + IMPORTING is_duty TYPE ty_duty + RAISING + {{p}}cx_licence_invalid + {{p}}cx_rating_missing + {{p}}cx_rest_too_short + {{p}}cx_duty_too_long + {{p}}cx_month_limit. + + PRIVATE SECTION. + CONSTANTS: + c_min_rest_hours TYPE ty_hours VALUE '10.0', + c_max_duty_hours TYPE ty_hours VALUE '13.0', + c_max_month_hours TYPE ty_hours VALUE '100.0'. +ENDCLASS. + + +CLASS {{p}}crew_duty_check IMPLEMENTATION. + METHOD check. + IF is_duty-licence_valid <> abap_false. + RAISE EXCEPTION TYPE {{p}}cx_licence_invalid. + ENDIF. + + IF is_duty-type_rating <> is_duty-aircraft_type. + RAISE EXCEPTION TYPE {{p}}cx_rating_missing + EXPORTING + iv_required = is_duty-aircraft_type + iv_held = is_duty-type_rating. + ENDIF. + + IF is_duty-rest_hours < c_min_rest_hours. + RAISE EXCEPTION TYPE {{p}}cx_rest_too_short + EXPORTING + iv_rest_hours = is_duty-rest_hours. + ENDIF. + + IF is_duty-duty_hours > c_max_duty_hours. + RAISE EXCEPTION TYPE {{p}}cx_duty_too_long + EXPORTING + iv_duty_hours = is_duty-duty_hours. + ENDIF. + + DATA lv_total_hours TYPE ty_hours. + lv_total_hours = is_duty-month_hours + is_duty-duty_hours. + IF lv_total_hours > c_max_month_hours. + RAISE EXCEPTION TYPE {{p}}cx_month_limit + EXPORTING + iv_total_hours = lv_total_hours. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0128/faulty/m1_crew_duty_check.clas.abap b/tasks_gen/eval/G0128/faulty/m1_crew_duty_check.clas.abap new file mode 100644 index 0000000..e0d740c --- /dev/null +++ b/tasks_gen/eval/G0128/faulty/m1_crew_duty_check.clas.abap @@ -0,0 +1,69 @@ +CLASS {{p}}crew_duty_check DEFINITION + PUBLIC + FINAL + CREATE PUBLIC. + + PUBLIC SECTION. + TYPES ty_hours TYPE p LENGTH 4 DECIMALS 1. + TYPES: + BEGIN OF ty_duty, + crew_id TYPE c LENGTH 10, + licence_valid TYPE abap_bool, + type_rating TYPE c LENGTH 4, + aircraft_type TYPE c LENGTH 4, + rest_hours TYPE ty_hours, + duty_hours TYPE ty_hours, + month_hours TYPE ty_hours, + END OF ty_duty. + + METHODS check + IMPORTING is_duty TYPE ty_duty + RAISING + {{p}}cx_licence_invalid + {{p}}cx_rating_missing + {{p}}cx_rest_too_short + {{p}}cx_duty_too_long + {{p}}cx_month_limit. + + PRIVATE SECTION. + CONSTANTS: + c_min_rest_hours TYPE ty_hours VALUE '10.0', + c_max_duty_hours TYPE ty_hours VALUE '13.0', + c_max_month_hours TYPE ty_hours VALUE '100.0'. +ENDCLASS. + + +CLASS {{p}}crew_duty_check IMPLEMENTATION. + METHOD check. + IF is_duty-licence_valid <> abap_true. + RAISE EXCEPTION TYPE {{p}}cx_licence_invalid. + ENDIF. + + IF is_duty-type_rating = is_duty-aircraft_type. + RAISE EXCEPTION TYPE {{p}}cx_rating_missing + EXPORTING + iv_required = is_duty-aircraft_type + iv_held = is_duty-type_rating. + ENDIF. + + IF is_duty-rest_hours < c_min_rest_hours. + RAISE EXCEPTION TYPE {{p}}cx_rest_too_short + EXPORTING + iv_rest_hours = is_duty-rest_hours. + ENDIF. + + IF is_duty-duty_hours > c_max_duty_hours. + RAISE EXCEPTION TYPE {{p}}cx_duty_too_long + EXPORTING + iv_duty_hours = is_duty-duty_hours. + ENDIF. + + DATA lv_total_hours TYPE ty_hours. + lv_total_hours = is_duty-month_hours + is_duty-duty_hours. + IF lv_total_hours > c_max_month_hours. + RAISE EXCEPTION TYPE {{p}}cx_month_limit + EXPORTING + iv_total_hours = lv_total_hours. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0128/faulty/m2_crew_duty_check.clas.abap b/tasks_gen/eval/G0128/faulty/m2_crew_duty_check.clas.abap new file mode 100644 index 0000000..d3cfeaa --- /dev/null +++ b/tasks_gen/eval/G0128/faulty/m2_crew_duty_check.clas.abap @@ -0,0 +1,69 @@ +CLASS {{p}}crew_duty_check DEFINITION + PUBLIC + FINAL + CREATE PUBLIC. + + PUBLIC SECTION. + TYPES ty_hours TYPE p LENGTH 4 DECIMALS 1. + TYPES: + BEGIN OF ty_duty, + crew_id TYPE c LENGTH 10, + licence_valid TYPE abap_bool, + type_rating TYPE c LENGTH 4, + aircraft_type TYPE c LENGTH 4, + rest_hours TYPE ty_hours, + duty_hours TYPE ty_hours, + month_hours TYPE ty_hours, + END OF ty_duty. + + METHODS check + IMPORTING is_duty TYPE ty_duty + RAISING + {{p}}cx_licence_invalid + {{p}}cx_rating_missing + {{p}}cx_rest_too_short + {{p}}cx_duty_too_long + {{p}}cx_month_limit. + + PRIVATE SECTION. + CONSTANTS: + c_min_rest_hours TYPE ty_hours VALUE '10.0', + c_max_duty_hours TYPE ty_hours VALUE '13.0', + c_max_month_hours TYPE ty_hours VALUE '100.0'. +ENDCLASS. + + +CLASS {{p}}crew_duty_check IMPLEMENTATION. + METHOD check. + IF is_duty-licence_valid <> abap_true. + RAISE EXCEPTION TYPE {{p}}cx_licence_invalid. + ENDIF. + + IF is_duty-type_rating <> is_duty-aircraft_type. + RAISE EXCEPTION TYPE {{p}}cx_rating_missing + EXPORTING + iv_required = is_duty-aircraft_type + iv_held = is_duty-type_rating. + ENDIF. + + IF is_duty-rest_hours < c_min_rest_hours. + RAISE EXCEPTION TYPE {{p}}cx_rest_too_short + EXPORTING + iv_rest_hours = is_duty-rest_hours. + ENDIF. + + IF is_duty-duty_hours <= c_max_duty_hours. + RAISE EXCEPTION TYPE {{p}}cx_duty_too_long + EXPORTING + iv_duty_hours = is_duty-duty_hours. + ENDIF. + + DATA lv_total_hours TYPE ty_hours. + lv_total_hours = is_duty-month_hours + is_duty-duty_hours. + IF lv_total_hours > c_max_month_hours. + RAISE EXCEPTION TYPE {{p}}cx_month_limit + EXPORTING + iv_total_hours = lv_total_hours. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0128/faulty/m3_crew_duty_check.clas.abap b/tasks_gen/eval/G0128/faulty/m3_crew_duty_check.clas.abap new file mode 100644 index 0000000..58c5bde --- /dev/null +++ b/tasks_gen/eval/G0128/faulty/m3_crew_duty_check.clas.abap @@ -0,0 +1,69 @@ +CLASS {{p}}crew_duty_check DEFINITION + PUBLIC + FINAL + CREATE PUBLIC. + + PUBLIC SECTION. + TYPES ty_hours TYPE p LENGTH 4 DECIMALS 1. + TYPES: + BEGIN OF ty_duty, + crew_id TYPE c LENGTH 10, + licence_valid TYPE abap_bool, + type_rating TYPE c LENGTH 4, + aircraft_type TYPE c LENGTH 4, + rest_hours TYPE ty_hours, + duty_hours TYPE ty_hours, + month_hours TYPE ty_hours, + END OF ty_duty. + + METHODS check + IMPORTING is_duty TYPE ty_duty + RAISING + {{p}}cx_licence_invalid + {{p}}cx_rating_missing + {{p}}cx_rest_too_short + {{p}}cx_duty_too_long + {{p}}cx_month_limit. + + PRIVATE SECTION. + CONSTANTS: + c_min_rest_hours TYPE ty_hours VALUE '10.0', + c_max_duty_hours TYPE ty_hours VALUE '13.0', + c_max_month_hours TYPE ty_hours VALUE '100.0'. +ENDCLASS. + + +CLASS {{p}}crew_duty_check IMPLEMENTATION. + METHOD check. + IF is_duty-licence_valid <> abap_true. + RAISE EXCEPTION TYPE {{p}}cx_licence_invalid. + ENDIF. + + IF is_duty-type_rating <> is_duty-aircraft_type. + RAISE EXCEPTION TYPE {{p}}cx_rating_missing + EXPORTING + iv_required = is_duty-aircraft_type + iv_held = is_duty-type_rating. + ENDIF. + + IF is_duty-rest_hours < c_min_rest_hours. + RAISE EXCEPTION TYPE {{p}}cx_rest_too_short + EXPORTING + iv_rest_hours = is_duty-rest_hours. + ENDIF. + + IF is_duty-duty_hours > c_max_duty_hours. + RAISE EXCEPTION TYPE {{p}}cx_duty_too_long + EXPORTING + iv_duty_hours = is_duty-duty_hours. + ENDIF. + + DATA lv_total_hours TYPE ty_hours. + lv_total_hours = is_duty-month_hours - is_duty-duty_hours. + IF lv_total_hours > c_max_month_hours. + RAISE EXCEPTION TYPE {{p}}cx_month_limit + EXPORTING + iv_total_hours = lv_total_hours. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0128/faulty/m4_crew_duty_check.clas.abap b/tasks_gen/eval/G0128/faulty/m4_crew_duty_check.clas.abap new file mode 100644 index 0000000..a59b9bf --- /dev/null +++ b/tasks_gen/eval/G0128/faulty/m4_crew_duty_check.clas.abap @@ -0,0 +1,69 @@ +CLASS {{p}}crew_duty_check DEFINITION + PUBLIC + FINAL + CREATE PUBLIC. + + PUBLIC SECTION. + TYPES ty_hours TYPE p LENGTH 4 DECIMALS 1. + TYPES: + BEGIN OF ty_duty, + crew_id TYPE c LENGTH 10, + licence_valid TYPE abap_bool, + type_rating TYPE c LENGTH 4, + aircraft_type TYPE c LENGTH 4, + rest_hours TYPE ty_hours, + duty_hours TYPE ty_hours, + month_hours TYPE ty_hours, + END OF ty_duty. + + METHODS check + IMPORTING is_duty TYPE ty_duty + RAISING + {{p}}cx_licence_invalid + {{p}}cx_rating_missing + {{p}}cx_rest_too_short + {{p}}cx_duty_too_long + {{p}}cx_month_limit. + + PRIVATE SECTION. + CONSTANTS: + c_min_rest_hours TYPE ty_hours VALUE '10.0', + c_max_duty_hours TYPE ty_hours VALUE '13.0', + c_max_month_hours TYPE ty_hours VALUE '100.0'. +ENDCLASS. + + +CLASS {{p}}crew_duty_check IMPLEMENTATION. + METHOD check. + IF is_duty-licence_valid <> abap_true. + RAISE EXCEPTION TYPE {{p}}cx_licence_invalid. + ENDIF. + + IF is_duty-type_rating <> is_duty-aircraft_type. + RAISE EXCEPTION TYPE {{p}}cx_rating_missing + EXPORTING + iv_required = is_duty-aircraft_type + iv_held = is_duty-type_rating. + ENDIF. + + IF is_duty-rest_hours < c_min_rest_hours. + RAISE EXCEPTION TYPE {{p}}cx_rest_too_short + EXPORTING + iv_rest_hours = is_duty-rest_hours. + ENDIF. + + IF is_duty-duty_hours > c_max_duty_hours. + RAISE EXCEPTION TYPE {{p}}cx_duty_too_long + EXPORTING + iv_duty_hours = is_duty-duty_hours. + ENDIF. + + DATA lv_total_hours TYPE ty_hours. + lv_total_hours = is_duty-month_hours + is_duty-duty_hours. + IF lv_total_hours <= c_max_month_hours. + RAISE EXCEPTION TYPE {{p}}cx_month_limit + EXPORTING + iv_total_hours = lv_total_hours. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0128/generation.json b/tasks_gen/eval/G0128/generation.json index 0163d7b..79173c6 100644 --- a/tasks_gen/eval/G0128/generation.json +++ b/tasks_gen/eval/G0128/generation.json @@ -23,7 +23,19 @@ "stage": "validate", "oracle": 92.5, "null": 0 + }, + { + "stage": "revalidate", + "by": "harness fix 2026-10-03", + "change": "coverage with several contract classes (exception classes). Bundle not changed.", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 5, + "killed": 5, + "ok": true + } } ], - "accepted": false + "accepted": true } \ No newline at end of file diff --git a/tasks_gen/eval/G0128/mutation.json b/tasks_gen/eval/G0128/mutation.json index a2df7bd..34dc20d 100644 --- a/tasks_gen/eval/G0128/mutation.json +++ b/tasks_gen/eval/G0128/mutation.json @@ -1,66 +1,72 @@ { - "task": "T30", + "task": "G0128", "mutants": [ { "object": "{{P}}CREW_DUTY_CHECK", - "mutant": "line 38: <> -> = (rel)", + "mutant": "line 38: abap_true -> abap_false (bool)", "status": "killed", - "hidden": "10/10", + "hidden": "0/10", "failed_tests": [ - "VALID_DUTY_PASSES", + "BOUNDARY_VALUES", + "DUTY_TOO_LONG", + "FIRST_RULE_WINS", "LICENCE_INVALID", + "MONTH_LIMIT", + "MONTH_LIMIT_EXACT", + "RATING_BEFORE_REST", "RATING_MISSING", "REST_TOO_SHORT", - "DUTY_TOO_LONG", - "MONTH_LIMIT", - "FIRST_RULE_WINS", - "RATING_BEFORE_REST", - "BOUNDARY_VALUES", - "MONTH_LIMIT_EXACT" + "VALID_DUTY_PASSES" ] }, { "object": "{{P}}CREW_DUTY_CHECK", "mutant": "line 42: <> -> = (rel)", "status": "killed", - "hidden": "8/10", - "failed_tests": [ - "VALID_DUTY_PASSES", - "RATING_MISSING", - "REST_TOO_SHORT", - "DUTY_TOO_LONG", - "MONTH_LIMIT", - "RATING_BEFORE_REST", - "BOUNDARY_VALUES", - "MONTH_LIMIT_EXACT" - ] - }, - { - "object": "{{P}}CREW_DUTY_CHECK", - "mutant": "line 49: < -> <= (rel)", - "status": "killed", - "hidden": "1/10", - "failed_tests": [ - "BOUNDARY_VALUES" - ] - }, - { - "object": "{{P}}CREW_DUTY_CHECK", - "mutant": "line 55: > -> >= (rel)", - "status": "killed", - "hidden": "1/10", - "failed_tests": [ - "BOUNDARY_VALUES" - ] - }, - { - "object": "{{P}}CREW_DUTY_CHECK", - "mutant": "line 63: > -> >= (rel)", - "status": "killed", "hidden": "2/10", "failed_tests": [ "BOUNDARY_VALUES", - "MONTH_LIMIT_EXACT" + "DUTY_TOO_LONG", + "MONTH_LIMIT", + "MONTH_LIMIT_EXACT", + "RATING_BEFORE_REST", + "RATING_MISSING", + "REST_TOO_SHORT", + "VALID_DUTY_PASSES" + ] + }, + { + "object": "{{P}}CREW_DUTY_CHECK", + "mutant": "line 55: > -> <= (rel)", + "status": "killed", + "hidden": "5/10", + "failed_tests": [ + "BOUNDARY_VALUES", + "DUTY_TOO_LONG", + "MONTH_LIMIT", + "MONTH_LIMIT_EXACT", + "VALID_DUTY_PASSES" + ] + }, + { + "object": "{{P}}CREW_DUTY_CHECK", + "mutant": "line 62: + -> - (arith)", + "status": "killed", + "hidden": "9/10", + "failed_tests": [ + "MONTH_LIMIT" + ] + }, + { + "object": "{{P}}CREW_DUTY_CHECK", + "mutant": "line 63: > -> <= (rel)", + "status": "killed", + "hidden": "6/10", + "failed_tests": [ + "BOUNDARY_VALUES", + "MONTH_LIMIT", + "MONTH_LIMIT_EXACT", + "VALID_DUTY_PASSES" ] } ], diff --git a/tasks_gen/eval/G0129/generation.json b/tasks_gen/eval/G0129/generation.json deleted file mode 100644 index cae9b81..0000000 --- a/tasks_gen/eval/G0129/generation.json +++ /dev/null @@ -1,69 +0,0 @@ -{ - "id": "G0129", - "pool": "eval", - "object_type": "CLAS", - "category": "D", - "attempts": [ - { - "stage": "bundle", - "errors": [ - "hidden/t_print_hidden.clas.abap line 72: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"assert_price\"", - "hidden/t_print_hidden.clas.abap line 72: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"00\"", - "hidden/t_print_hidden.clas.abap line 77: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"assert_price\"", - "hidden/t_print_hidden.clas.abap line 77: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"00\"", - "hidden/t_print_hidden.clas.abap line 82: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"assert_price\"", - "hidden/t_print_hidden.clas.abap line 82: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"00\"", - "hidden/t_print_hidden.clas.abap line 84: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"assert_price\"", - "hidden/t_print_hidden.clas.abap line 84: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"00\"", - "hidden/t_print_hidden.clas.abap line 89: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"assert_price\"", - "hidden/t_print_hidden.clas.abap line 89: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"50\"", - "hidden/t_print_hidden.clas.abap line 91: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"assert_price\"", - "hidden/t_print_hidden.clas.abap line 91: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"75\"", - "hidden/t_print_hidden.clas.abap line 96: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"assert_price\"", - "hidden/t_print_hidden.clas.abap line 96: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"00\"", - "hidden/t_print_hidden.clas.abap line 101: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"assert_price\"", - "hidden/t_print_hidden.clas.abap line 101: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"00\"", - "hidden/t_print_hidden.clas.abap line 106: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"assert_price\"", - "hidden/t_print_hidden.clas.abap line 106: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"00\"", - "hidden/t_print_hidden.clas.abap line 144: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"assert_price\"", - "hidden/t_print_hidden.clas.abap line 144: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"00\"" - ], - "by_check": { - "abaplint": 20 - } - }, - { - "stage": "bundle", - "errors": [ - "reference/print_job_pricer.testclasses.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/print_job_pricer.testclasses.abap line 43: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"00\"", - "reference/print_job_pricer.testclasses.abap line 49: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"", - "reference/print_job_pricer.testclasses.abap line 50: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"00\"", - "reference/print_job_pricer.testclasses.abap line 56: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"", - "reference/print_job_pricer.testclasses.abap line 57: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"50\"", - "reference/print_job_pricer.testclasses.abap line 63: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"", - "reference/print_job_pricer.testclasses.abap line 64: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"00\"", - "reference/print_job_pricer.clas.abap line 26: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"00\"", - "reference/print_job_pricer.clas.abap line 28: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"05\"", - "reference/print_job_pricer.clas.abap line 29: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"10\"", - "reference/print_job_pricer.clas.abap line 123: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"03\"", - "reference/print_job_pricer.clas.abap line 125: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"05\"", - "reference/print_job_pricer.clas.abap line 127: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"09\"" - ], - "by_check": { - "abaplint": 14 - } - }, - { - "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/eval/G0130/generation.json b/tasks_gen/eval/G0130/generation.json deleted file mode 100644 index 1573d79..0000000 --- a/tasks_gen/eval/G0130/generation.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "id": "G0130", - "pool": "eval", - "object_type": "CLAS", - "category": "D", - "attempts": [ - { - "stage": "bundle", - "errors": [ - "seed/drug_master.clas.abap line 15: 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": 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/eval/G0131/faulty/m0_driving_test_check.clas.abap b/tasks_gen/eval/G0131/faulty/m0_driving_test_check.clas.abap new file mode 100644 index 0000000..3482206 --- /dev/null +++ b/tasks_gen/eval/G0131/faulty/m0_driving_test_check.clas.abap @@ -0,0 +1,71 @@ +CLASS {{p}}driving_test_check DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES ty_pupil_id TYPE c LENGTH 10. + TYPES ty_date TYPE d. + + METHODS check + IMPORTING iv_pupil_id TYPE ty_pupil_id + iv_test_date TYPE ty_date + RAISING {{p}}cx_pupil_unknown + {{p}}cx_theory_missing + {{p}}cx_lessons_missing + {{p}}cx_fee_unpaid + {{p}}cx_recent_failure. + + PRIVATE SECTION. + CONSTANTS c_min_lessons TYPE i VALUE 12. + CONSTANTS c_wait_days TYPE i VALUE 14. + CONSTANTS c_done TYPE c LENGTH 1 VALUE 'X'. + + TYPES: BEGIN OF ty_pupil, + pupil_id TYPE {{p}}pupil-pupil_id, + theory_done TYPE {{p}}pupil-theory_done, + lessons_done TYPE {{p}}pupil-lessons_done, + fee_paid TYPE {{p}}pupil-fee_paid, + last_failed TYPE {{p}}pupil-last_failed, + END OF ty_pupil. + + METHODS read_pupil + IMPORTING iv_pupil_id TYPE ty_pupil_id + RETURNING VALUE(rs_pupil) TYPE ty_pupil + RAISING {{p}}cx_pupil_unknown. +ENDCLASS. + + +CLASS {{p}}driving_test_check IMPLEMENTATION. + METHOD check. + DATA(ls_pupil) = read_pupil( iv_pupil_id ). + + IF ls_pupil-theory_done = c_done. + RAISE EXCEPTION TYPE {{p}}cx_theory_missing. + ENDIF. + + IF ls_pupil-lessons_done < c_min_lessons. + RAISE EXCEPTION TYPE {{p}}cx_lessons_missing + EXPORTING iv_missing = c_min_lessons - ls_pupil-lessons_done. + ENDIF. + + IF ls_pupil-fee_paid <> c_done. + RAISE EXCEPTION TYPE {{p}}cx_fee_unpaid. + ENDIF. + + IF ls_pupil-last_failed IS NOT INITIAL. + DATA(lv_days) = iv_test_date - ls_pupil-last_failed. + IF lv_days < c_wait_days. + RAISE EXCEPTION TYPE {{p}}cx_recent_failure + EXPORTING iv_days_left = c_wait_days - lv_days. + ENDIF. + ENDIF. + ENDMETHOD. + + METHOD read_pupil. + SELECT SINGLE + FROM {{p}}pupil + FIELDS pupil_id, theory_done, lessons_done, fee_paid, last_failed + WHERE pupil_id = @iv_pupil_id + INTO CORRESPONDING FIELDS OF @rs_pupil. + IF sy-subrc <> 0. + RAISE EXCEPTION TYPE {{p}}cx_pupil_unknown. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0131/faulty/m1_driving_test_check.clas.abap b/tasks_gen/eval/G0131/faulty/m1_driving_test_check.clas.abap new file mode 100644 index 0000000..295317c --- /dev/null +++ b/tasks_gen/eval/G0131/faulty/m1_driving_test_check.clas.abap @@ -0,0 +1,71 @@ +CLASS {{p}}driving_test_check DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES ty_pupil_id TYPE c LENGTH 10. + TYPES ty_date TYPE d. + + METHODS check + IMPORTING iv_pupil_id TYPE ty_pupil_id + iv_test_date TYPE ty_date + RAISING {{p}}cx_pupil_unknown + {{p}}cx_theory_missing + {{p}}cx_lessons_missing + {{p}}cx_fee_unpaid + {{p}}cx_recent_failure. + + PRIVATE SECTION. + CONSTANTS c_min_lessons TYPE i VALUE 12. + CONSTANTS c_wait_days TYPE i VALUE 14. + CONSTANTS c_done TYPE c LENGTH 1 VALUE 'X'. + + TYPES: BEGIN OF ty_pupil, + pupil_id TYPE {{p}}pupil-pupil_id, + theory_done TYPE {{p}}pupil-theory_done, + lessons_done TYPE {{p}}pupil-lessons_done, + fee_paid TYPE {{p}}pupil-fee_paid, + last_failed TYPE {{p}}pupil-last_failed, + END OF ty_pupil. + + METHODS read_pupil + IMPORTING iv_pupil_id TYPE ty_pupil_id + RETURNING VALUE(rs_pupil) TYPE ty_pupil + RAISING {{p}}cx_pupil_unknown. +ENDCLASS. + + +CLASS {{p}}driving_test_check IMPLEMENTATION. + METHOD check. + DATA(ls_pupil) = read_pupil( iv_pupil_id ). + + IF ls_pupil-theory_done <> c_done. + RAISE EXCEPTION TYPE {{p}}cx_theory_missing. + ENDIF. + + IF ls_pupil-lessons_done >= c_min_lessons. + RAISE EXCEPTION TYPE {{p}}cx_lessons_missing + EXPORTING iv_missing = c_min_lessons - ls_pupil-lessons_done. + ENDIF. + + IF ls_pupil-fee_paid <> c_done. + RAISE EXCEPTION TYPE {{p}}cx_fee_unpaid. + ENDIF. + + IF ls_pupil-last_failed IS NOT INITIAL. + DATA(lv_days) = iv_test_date - ls_pupil-last_failed. + IF lv_days < c_wait_days. + RAISE EXCEPTION TYPE {{p}}cx_recent_failure + EXPORTING iv_days_left = c_wait_days - lv_days. + ENDIF. + ENDIF. + ENDMETHOD. + + METHOD read_pupil. + SELECT SINGLE + FROM {{p}}pupil + FIELDS pupil_id, theory_done, lessons_done, fee_paid, last_failed + WHERE pupil_id = @iv_pupil_id + INTO CORRESPONDING FIELDS OF @rs_pupil. + IF sy-subrc <> 0. + RAISE EXCEPTION TYPE {{p}}cx_pupil_unknown. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0131/faulty/m2_driving_test_check.clas.abap b/tasks_gen/eval/G0131/faulty/m2_driving_test_check.clas.abap new file mode 100644 index 0000000..e02f90a --- /dev/null +++ b/tasks_gen/eval/G0131/faulty/m2_driving_test_check.clas.abap @@ -0,0 +1,71 @@ +CLASS {{p}}driving_test_check DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES ty_pupil_id TYPE c LENGTH 10. + TYPES ty_date TYPE d. + + METHODS check + IMPORTING iv_pupil_id TYPE ty_pupil_id + iv_test_date TYPE ty_date + RAISING {{p}}cx_pupil_unknown + {{p}}cx_theory_missing + {{p}}cx_lessons_missing + {{p}}cx_fee_unpaid + {{p}}cx_recent_failure. + + PRIVATE SECTION. + CONSTANTS c_min_lessons TYPE i VALUE 12. + CONSTANTS c_wait_days TYPE i VALUE 14. + CONSTANTS c_done TYPE c LENGTH 1 VALUE 'X'. + + TYPES: BEGIN OF ty_pupil, + pupil_id TYPE {{p}}pupil-pupil_id, + theory_done TYPE {{p}}pupil-theory_done, + lessons_done TYPE {{p}}pupil-lessons_done, + fee_paid TYPE {{p}}pupil-fee_paid, + last_failed TYPE {{p}}pupil-last_failed, + END OF ty_pupil. + + METHODS read_pupil + IMPORTING iv_pupil_id TYPE ty_pupil_id + RETURNING VALUE(rs_pupil) TYPE ty_pupil + RAISING {{p}}cx_pupil_unknown. +ENDCLASS. + + +CLASS {{p}}driving_test_check IMPLEMENTATION. + METHOD check. + DATA(ls_pupil) = read_pupil( iv_pupil_id ). + + IF ls_pupil-theory_done <> c_done. + RAISE EXCEPTION TYPE {{p}}cx_theory_missing. + ENDIF. + + IF ls_pupil-lessons_done < c_min_lessons. + RAISE EXCEPTION TYPE {{p}}cx_lessons_missing + EXPORTING iv_missing = c_min_lessons - ls_pupil-lessons_done. + ENDIF. + + IF ls_pupil-fee_paid = c_done. + RAISE EXCEPTION TYPE {{p}}cx_fee_unpaid. + ENDIF. + + IF ls_pupil-last_failed IS NOT INITIAL. + DATA(lv_days) = iv_test_date - ls_pupil-last_failed. + IF lv_days < c_wait_days. + RAISE EXCEPTION TYPE {{p}}cx_recent_failure + EXPORTING iv_days_left = c_wait_days - lv_days. + ENDIF. + ENDIF. + ENDMETHOD. + + METHOD read_pupil. + SELECT SINGLE + FROM {{p}}pupil + FIELDS pupil_id, theory_done, lessons_done, fee_paid, last_failed + WHERE pupil_id = @iv_pupil_id + INTO CORRESPONDING FIELDS OF @rs_pupil. + IF sy-subrc <> 0. + RAISE EXCEPTION TYPE {{p}}cx_pupil_unknown. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0131/faulty/m3_driving_test_check.clas.abap b/tasks_gen/eval/G0131/faulty/m3_driving_test_check.clas.abap new file mode 100644 index 0000000..d3a6626 --- /dev/null +++ b/tasks_gen/eval/G0131/faulty/m3_driving_test_check.clas.abap @@ -0,0 +1,71 @@ +CLASS {{p}}driving_test_check DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES ty_pupil_id TYPE c LENGTH 10. + TYPES ty_date TYPE d. + + METHODS check + IMPORTING iv_pupil_id TYPE ty_pupil_id + iv_test_date TYPE ty_date + RAISING {{p}}cx_pupil_unknown + {{p}}cx_theory_missing + {{p}}cx_lessons_missing + {{p}}cx_fee_unpaid + {{p}}cx_recent_failure. + + PRIVATE SECTION. + CONSTANTS c_min_lessons TYPE i VALUE 12. + CONSTANTS c_wait_days TYPE i VALUE 14. + CONSTANTS c_done TYPE c LENGTH 1 VALUE 'X'. + + TYPES: BEGIN OF ty_pupil, + pupil_id TYPE {{p}}pupil-pupil_id, + theory_done TYPE {{p}}pupil-theory_done, + lessons_done TYPE {{p}}pupil-lessons_done, + fee_paid TYPE {{p}}pupil-fee_paid, + last_failed TYPE {{p}}pupil-last_failed, + END OF ty_pupil. + + METHODS read_pupil + IMPORTING iv_pupil_id TYPE ty_pupil_id + RETURNING VALUE(rs_pupil) TYPE ty_pupil + RAISING {{p}}cx_pupil_unknown. +ENDCLASS. + + +CLASS {{p}}driving_test_check IMPLEMENTATION. + METHOD check. + DATA(ls_pupil) = read_pupil( iv_pupil_id ). + + IF ls_pupil-theory_done <> c_done. + RAISE EXCEPTION TYPE {{p}}cx_theory_missing. + ENDIF. + + IF ls_pupil-lessons_done < c_min_lessons. + RAISE EXCEPTION TYPE {{p}}cx_lessons_missing + EXPORTING iv_missing = c_min_lessons - ls_pupil-lessons_done. + ENDIF. + + IF ls_pupil-fee_paid <> c_done. + RAISE EXCEPTION TYPE {{p}}cx_fee_unpaid. + ENDIF. + + IF ls_pupil-last_failed IS NOT INITIAL. + DATA(lv_days) = iv_test_date - ls_pupil-last_failed. + IF lv_days >= c_wait_days. + RAISE EXCEPTION TYPE {{p}}cx_recent_failure + EXPORTING iv_days_left = c_wait_days - lv_days. + ENDIF. + ENDIF. + ENDMETHOD. + + METHOD read_pupil. + SELECT SINGLE + FROM {{p}}pupil + FIELDS pupil_id, theory_done, lessons_done, fee_paid, last_failed + WHERE pupil_id = @iv_pupil_id + INTO CORRESPONDING FIELDS OF @rs_pupil. + IF sy-subrc <> 0. + RAISE EXCEPTION TYPE {{p}}cx_pupil_unknown. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0131/faulty/m4_driving_test_check.clas.abap b/tasks_gen/eval/G0131/faulty/m4_driving_test_check.clas.abap new file mode 100644 index 0000000..f883fee --- /dev/null +++ b/tasks_gen/eval/G0131/faulty/m4_driving_test_check.clas.abap @@ -0,0 +1,71 @@ +CLASS {{p}}driving_test_check DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES ty_pupil_id TYPE c LENGTH 10. + TYPES ty_date TYPE d. + + METHODS check + IMPORTING iv_pupil_id TYPE ty_pupil_id + iv_test_date TYPE ty_date + RAISING {{p}}cx_pupil_unknown + {{p}}cx_theory_missing + {{p}}cx_lessons_missing + {{p}}cx_fee_unpaid + {{p}}cx_recent_failure. + + PRIVATE SECTION. + CONSTANTS c_min_lessons TYPE i VALUE 12. + CONSTANTS c_wait_days TYPE i VALUE 14. + CONSTANTS c_done TYPE c LENGTH 1 VALUE 'X'. + + TYPES: BEGIN OF ty_pupil, + pupil_id TYPE {{p}}pupil-pupil_id, + theory_done TYPE {{p}}pupil-theory_done, + lessons_done TYPE {{p}}pupil-lessons_done, + fee_paid TYPE {{p}}pupil-fee_paid, + last_failed TYPE {{p}}pupil-last_failed, + END OF ty_pupil. + + METHODS read_pupil + IMPORTING iv_pupil_id TYPE ty_pupil_id + RETURNING VALUE(rs_pupil) TYPE ty_pupil + RAISING {{p}}cx_pupil_unknown. +ENDCLASS. + + +CLASS {{p}}driving_test_check IMPLEMENTATION. + METHOD check. + DATA(ls_pupil) = read_pupil( iv_pupil_id ). + + IF ls_pupil-theory_done <> c_done. + RAISE EXCEPTION TYPE {{p}}cx_theory_missing. + ENDIF. + + IF ls_pupil-lessons_done < c_min_lessons. + RAISE EXCEPTION TYPE {{p}}cx_lessons_missing + EXPORTING iv_missing = c_min_lessons - ls_pupil-lessons_done. + ENDIF. + + IF ls_pupil-fee_paid <> c_done. + RAISE EXCEPTION TYPE {{p}}cx_fee_unpaid. + ENDIF. + + IF ls_pupil-last_failed IS NOT INITIAL. + DATA(lv_days) = iv_test_date - ls_pupil-last_failed. + IF lv_days < c_wait_days. + RAISE EXCEPTION TYPE {{p}}cx_recent_failure + EXPORTING iv_days_left = c_wait_days - lv_days. + ENDIF. + ENDIF. + ENDMETHOD. + + METHOD read_pupil. + SELECT SINGLE + FROM {{p}}pupil + FIELDS pupil_id, theory_done, lessons_done, fee_paid, last_failed + WHERE pupil_id <> @iv_pupil_id + INTO CORRESPONDING FIELDS OF @rs_pupil. + IF sy-subrc <> 0. + RAISE EXCEPTION TYPE {{p}}cx_pupil_unknown. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0131/generation.json b/tasks_gen/eval/G0131/generation.json new file mode 100644 index 0000000..f17063f --- /dev/null +++ b/tasks_gen/eval/G0131/generation.json @@ -0,0 +1,34 @@ +{ + "id": "G0131", + "pool": "eval", + "object_type": "CLAS", + "category": "D", + "attempts": [ + { + "stage": "bundle", + "errors": [ + "seed/pupil.tabl.abap: a table needs the annotation @AbapCatalog.tableCategory (for example #TRANSPARENT, #A)", + "seed/pupil.tabl.abap: a table needs the annotation @AbapCatalog.deliveryClass (for example #TRANSPARENT, #A)" + ], + "by_check": { + "static": 2 + } + }, + { + "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/eval/G0131/hidden/t_driving_check.clas.abap b/tasks_gen/eval/G0131/hidden/t_driving_check.clas.abap new file mode 100644 index 0000000..6d7edf5 --- /dev/null +++ b/tasks_gen/eval/G0131/hidden/t_driving_check.clas.abap @@ -0,0 +1,167 @@ +CLASS {{p}}t_driving_check DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + DATA mo_cut TYPE REF TO {{p}}driving_test_check. + DATA mo_env TYPE REF TO if_osql_test_environment. + METHODS setup. + METHODS teardown. + METHODS add_pupil + IMPORTING iv_id TYPE string + iv_theory TYPE abap_bool + iv_lessons TYPE i + iv_fee TYPE abap_bool + iv_last_failed TYPE d. + METHODS rejects_unknown_pupil FOR TESTING. + METHODS rejects_missing_theory FOR TESTING. + METHODS rejects_too_few_lessons FOR TESTING. + METHODS rejects_unpaid_fee FOR TESTING. + METHODS rejects_recent_failure FOR TESTING. + METHODS accepts_ready_pupil FOR TESTING. + METHODS first_failure_wins FOR TESTING. + METHODS failure_14_days_ago_ok FOR TESTING. + METHODS lessons_12_ok FOR TESTING. + METHODS failure_13_days_rejected FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t_driving_check IMPLEMENTATION. + METHOD setup. + mo_env = cl_osql_test_environment=>create( VALUE #( ( '{{P}}PUPIL' ) ) ). + mo_cut = NEW {{p}}driving_test_check( ). + ENDMETHOD. + + METHOD teardown. + mo_env->destroy( ). + ENDMETHOD. + + METHOD add_pupil. + DATA ls_pupil TYPE {{p}}pupil. + ls_pupil-client = sy-mandt. + ls_pupil-pupil_id = iv_id. + ls_pupil-pupil_name = iv_id. + IF iv_theory = abap_true. + ls_pupil-theory_done = 'X'. + ENDIF. + ls_pupil-lessons_done = iv_lessons. + IF iv_fee = abap_true. + ls_pupil-fee_paid = 'X'. + ENDIF. + ls_pupil-last_failed = iv_last_failed. + INSERT {{p}}pupil FROM @ls_pupil. + ENDMETHOD. + + METHOD rejects_unknown_pupil. + TRY. + mo_cut->check( iv_pupil_id = 'P999' iv_test_date = '20250201' ). + cl_abap_unit_assert=>fail( msg = 'CX_PUPIL_UNKNOWN expected' ). + CATCH {{p}}cx_pupil_unknown. + CATCH cx_root INTO DATA(lx_wrong). + cl_abap_unit_assert=>fail( msg = lx_wrong->get_text( ) ). + ENDTRY. + ENDMETHOD. + + METHOD rejects_missing_theory. + add_pupil( iv_id = 'P001' iv_theory = abap_false iv_lessons = 20 + iv_fee = abap_true iv_last_failed = '00000000' ). + TRY. + mo_cut->check( iv_pupil_id = 'P001' iv_test_date = '20250201' ). + cl_abap_unit_assert=>fail( msg = 'CX_THEORY_MISSING expected' ). + CATCH {{p}}cx_theory_missing. + CATCH cx_root INTO DATA(lx_wrong). + cl_abap_unit_assert=>fail( msg = lx_wrong->get_text( ) ). + ENDTRY. + ENDMETHOD. + + METHOD rejects_too_few_lessons. + add_pupil( iv_id = 'P002' iv_theory = abap_true iv_lessons = 9 + iv_fee = abap_true iv_last_failed = '00000000' ). + TRY. + mo_cut->check( iv_pupil_id = 'P002' iv_test_date = '20250201' ). + cl_abap_unit_assert=>fail( msg = 'CX_LESSONS_MISSING expected' ). + CATCH {{p}}cx_lessons_missing INTO DATA(lx_lessons). + cl_abap_unit_assert=>assert_equals( exp = 3 act = lx_lessons->mv_missing ). + CATCH cx_root INTO DATA(lx_wrong). + cl_abap_unit_assert=>fail( msg = lx_wrong->get_text( ) ). + ENDTRY. + ENDMETHOD. + + METHOD rejects_unpaid_fee. + add_pupil( iv_id = 'P003' iv_theory = abap_true iv_lessons = 18 + iv_fee = abap_false iv_last_failed = '00000000' ). + TRY. + mo_cut->check( iv_pupil_id = 'P003' iv_test_date = '20250201' ). + cl_abap_unit_assert=>fail( msg = 'CX_FEE_UNPAID expected' ). + CATCH {{p}}cx_fee_unpaid. + CATCH cx_root INTO DATA(lx_wrong). + cl_abap_unit_assert=>fail( msg = lx_wrong->get_text( ) ). + ENDTRY. + ENDMETHOD. + + METHOD rejects_recent_failure. + add_pupil( iv_id = 'P004' iv_theory = abap_true iv_lessons = 20 + iv_fee = abap_true iv_last_failed = '20250127' ). + TRY. + mo_cut->check( iv_pupil_id = 'P004' iv_test_date = '20250201' ). + cl_abap_unit_assert=>fail( msg = 'CX_RECENT_FAILURE expected' ). + CATCH {{p}}cx_recent_failure INTO DATA(lx_recent). + cl_abap_unit_assert=>assert_equals( exp = 9 act = lx_recent->mv_days_left ). + CATCH cx_root INTO DATA(lx_wrong). + cl_abap_unit_assert=>fail( msg = lx_wrong->get_text( ) ). + ENDTRY. + ENDMETHOD. + + METHOD accepts_ready_pupil. + add_pupil( iv_id = 'P005' iv_theory = abap_true iv_lessons = 20 + iv_fee = abap_true iv_last_failed = '00000000' ). + TRY. + mo_cut->check( iv_pupil_id = 'P005' iv_test_date = '20250201' ). + CATCH cx_root INTO DATA(lx_error). + cl_abap_unit_assert=>fail( msg = lx_error->get_text( ) ). + ENDTRY. + ENDMETHOD. + + METHOD first_failure_wins. + add_pupil( iv_id = 'P006' iv_theory = abap_false iv_lessons = 5 + iv_fee = abap_false iv_last_failed = '00000000' ). + TRY. + mo_cut->check( iv_pupil_id = 'P006' iv_test_date = '20250201' ). + cl_abap_unit_assert=>fail( msg = 'CX_THEORY_MISSING expected' ). + CATCH {{p}}cx_theory_missing. + CATCH cx_root INTO DATA(lx_wrong). + cl_abap_unit_assert=>fail( msg = lx_wrong->get_text( ) ). + ENDTRY. + ENDMETHOD. + + METHOD failure_14_days_ago_ok. + add_pupil( iv_id = 'P007' iv_theory = abap_true iv_lessons = 20 + iv_fee = abap_true iv_last_failed = '20250118' ). + TRY. + mo_cut->check( iv_pupil_id = 'P007' iv_test_date = '20250201' ). + CATCH cx_root INTO DATA(lx_error). + cl_abap_unit_assert=>fail( msg = lx_error->get_text( ) ). + ENDTRY. + ENDMETHOD. + + METHOD lessons_12_ok. + add_pupil( iv_id = 'P008' iv_theory = abap_true iv_lessons = 12 + iv_fee = abap_true iv_last_failed = '00000000' ). + TRY. + mo_cut->check( iv_pupil_id = 'P008' iv_test_date = '20250201' ). + CATCH cx_root INTO DATA(lx_error). + cl_abap_unit_assert=>fail( msg = lx_error->get_text( ) ). + ENDTRY. + ENDMETHOD. + + METHOD failure_13_days_rejected. + add_pupil( iv_id = 'P009' iv_theory = abap_true iv_lessons = 20 + iv_fee = abap_true iv_last_failed = '20250119' ). + TRY. + mo_cut->check( iv_pupil_id = 'P009' iv_test_date = '20250201' ). + cl_abap_unit_assert=>fail( msg = 'CX_RECENT_FAILURE expected' ). + CATCH {{p}}cx_recent_failure INTO DATA(lx_recent). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lx_recent->mv_days_left ). + CATCH cx_root INTO DATA(lx_wrong). + cl_abap_unit_assert=>fail( msg = lx_wrong->get_text( ) ). + ENDTRY. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0131/mutation.json b/tasks_gen/eval/G0131/mutation.json new file mode 100644 index 0000000..8c95fcf --- /dev/null +++ b/tasks_gen/eval/G0131/mutation.json @@ -0,0 +1,83 @@ +{ + "task": "G0131", + "mutants": [ + { + "object": "{{P}}DRIVING_TEST_CHECK", + "mutant": "line 39: <> -> = (rel)", + "status": "killed", + "hidden": "1/10", + "failed_tests": [ + "ACCEPTS_READY_PUPIL", + "FAILURE_13_DAYS_REJECTED", + "FAILURE_14_DAYS_AGO_OK", + "FIRST_FAILURE_WINS", + "LESSONS_12_OK", + "REJECTS_MISSING_THEORY", + "REJECTS_RECENT_FAILURE", + "REJECTS_TOO_FEW_LESSONS", + "REJECTS_UNPAID_FEE" + ] + }, + { + "object": "{{P}}DRIVING_TEST_CHECK", + "mutant": "line 43: < -> >= (rel)", + "status": "killed", + "hidden": "3/10", + "failed_tests": [ + "ACCEPTS_READY_PUPIL", + "FAILURE_13_DAYS_REJECTED", + "FAILURE_14_DAYS_AGO_OK", + "LESSONS_12_OK", + "REJECTS_RECENT_FAILURE", + "REJECTS_TOO_FEW_LESSONS", + "REJECTS_UNPAID_FEE" + ] + }, + { + "object": "{{P}}DRIVING_TEST_CHECK", + "mutant": "line 48: <> -> = (rel)", + "status": "killed", + "hidden": "4/10", + "failed_tests": [ + "ACCEPTS_READY_PUPIL", + "FAILURE_13_DAYS_REJECTED", + "FAILURE_14_DAYS_AGO_OK", + "LESSONS_12_OK", + "REJECTS_RECENT_FAILURE", + "REJECTS_UNPAID_FEE" + ] + }, + { + "object": "{{P}}DRIVING_TEST_CHECK", + "mutant": "line 54: < -> >= (rel)", + "status": "killed", + "hidden": "7/10", + "failed_tests": [ + "FAILURE_13_DAYS_REJECTED", + "FAILURE_14_DAYS_AGO_OK", + "REJECTS_RECENT_FAILURE" + ] + }, + { + "object": "{{P}}DRIVING_TEST_CHECK", + "mutant": "line 65: = -> <> (eq)", + "status": "killed", + "hidden": "1/10", + "failed_tests": [ + "ACCEPTS_READY_PUPIL", + "FAILURE_13_DAYS_REJECTED", + "FAILURE_14_DAYS_AGO_OK", + "FIRST_FAILURE_WINS", + "LESSONS_12_OK", + "REJECTS_MISSING_THEORY", + "REJECTS_RECENT_FAILURE", + "REJECTS_TOO_FEW_LESSONS", + "REJECTS_UNPAID_FEE" + ] + } + ], + "valid": 5, + "killed": 5, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0131/reference/cx_fee_unpaid.clas.abap b/tasks_gen/eval/G0131/reference/cx_fee_unpaid.clas.abap new file mode 100644 index 0000000..7cb8086 --- /dev/null +++ b/tasks_gen/eval/G0131/reference/cx_fee_unpaid.clas.abap @@ -0,0 +1,7 @@ +CLASS {{p}}cx_fee_unpaid DEFINITION PUBLIC FINAL CREATE PUBLIC INHERITING FROM cx_static_check. + PUBLIC SECTION. +ENDCLASS. + + +CLASS {{p}}cx_fee_unpaid IMPLEMENTATION. +ENDCLASS. diff --git a/tasks_gen/eval/G0131/reference/cx_lessons_missing.clas.abap b/tasks_gen/eval/G0131/reference/cx_lessons_missing.clas.abap new file mode 100644 index 0000000..9791161 --- /dev/null +++ b/tasks_gen/eval/G0131/reference/cx_lessons_missing.clas.abap @@ -0,0 +1,14 @@ +CLASS {{p}}cx_lessons_missing DEFINITION PUBLIC FINAL CREATE PUBLIC INHERITING FROM cx_static_check. + PUBLIC SECTION. + DATA mv_missing TYPE i READ-ONLY. + METHODS constructor + IMPORTING iv_missing TYPE i. +ENDCLASS. + + +CLASS {{p}}cx_lessons_missing IMPLEMENTATION. + METHOD constructor. + super->constructor( ). + mv_missing = iv_missing. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0131/reference/cx_pupil_unknown.clas.abap b/tasks_gen/eval/G0131/reference/cx_pupil_unknown.clas.abap new file mode 100644 index 0000000..507a89b --- /dev/null +++ b/tasks_gen/eval/G0131/reference/cx_pupil_unknown.clas.abap @@ -0,0 +1,7 @@ +CLASS {{p}}cx_pupil_unknown DEFINITION PUBLIC FINAL CREATE PUBLIC INHERITING FROM cx_static_check. + PUBLIC SECTION. +ENDCLASS. + + +CLASS {{p}}cx_pupil_unknown IMPLEMENTATION. +ENDCLASS. diff --git a/tasks_gen/eval/G0131/reference/cx_recent_failure.clas.abap b/tasks_gen/eval/G0131/reference/cx_recent_failure.clas.abap new file mode 100644 index 0000000..8234f78 --- /dev/null +++ b/tasks_gen/eval/G0131/reference/cx_recent_failure.clas.abap @@ -0,0 +1,14 @@ +CLASS {{p}}cx_recent_failure DEFINITION PUBLIC FINAL CREATE PUBLIC INHERITING FROM cx_static_check. + PUBLIC SECTION. + DATA mv_days_left TYPE i READ-ONLY. + METHODS constructor + IMPORTING iv_days_left TYPE i. +ENDCLASS. + + +CLASS {{p}}cx_recent_failure IMPLEMENTATION. + METHOD constructor. + super->constructor( ). + mv_days_left = iv_days_left. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0131/reference/cx_theory_missing.clas.abap b/tasks_gen/eval/G0131/reference/cx_theory_missing.clas.abap new file mode 100644 index 0000000..dec1af6 --- /dev/null +++ b/tasks_gen/eval/G0131/reference/cx_theory_missing.clas.abap @@ -0,0 +1,7 @@ +CLASS {{p}}cx_theory_missing DEFINITION PUBLIC FINAL CREATE PUBLIC INHERITING FROM cx_static_check. + PUBLIC SECTION. +ENDCLASS. + + +CLASS {{p}}cx_theory_missing IMPLEMENTATION. +ENDCLASS. diff --git a/tasks_gen/eval/G0131/reference/driving_test_check.clas.abap b/tasks_gen/eval/G0131/reference/driving_test_check.clas.abap new file mode 100644 index 0000000..5074c8e --- /dev/null +++ b/tasks_gen/eval/G0131/reference/driving_test_check.clas.abap @@ -0,0 +1,71 @@ +CLASS {{p}}driving_test_check DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES ty_pupil_id TYPE c LENGTH 10. + TYPES ty_date TYPE d. + + METHODS check + IMPORTING iv_pupil_id TYPE ty_pupil_id + iv_test_date TYPE ty_date + RAISING {{p}}cx_pupil_unknown + {{p}}cx_theory_missing + {{p}}cx_lessons_missing + {{p}}cx_fee_unpaid + {{p}}cx_recent_failure. + + PRIVATE SECTION. + CONSTANTS c_min_lessons TYPE i VALUE 12. + CONSTANTS c_wait_days TYPE i VALUE 14. + CONSTANTS c_done TYPE c LENGTH 1 VALUE 'X'. + + TYPES: BEGIN OF ty_pupil, + pupil_id TYPE {{p}}pupil-pupil_id, + theory_done TYPE {{p}}pupil-theory_done, + lessons_done TYPE {{p}}pupil-lessons_done, + fee_paid TYPE {{p}}pupil-fee_paid, + last_failed TYPE {{p}}pupil-last_failed, + END OF ty_pupil. + + METHODS read_pupil + IMPORTING iv_pupil_id TYPE ty_pupil_id + RETURNING VALUE(rs_pupil) TYPE ty_pupil + RAISING {{p}}cx_pupil_unknown. +ENDCLASS. + + +CLASS {{p}}driving_test_check IMPLEMENTATION. + METHOD check. + DATA(ls_pupil) = read_pupil( iv_pupil_id ). + + IF ls_pupil-theory_done <> c_done. + RAISE EXCEPTION TYPE {{p}}cx_theory_missing. + ENDIF. + + IF ls_pupil-lessons_done < c_min_lessons. + RAISE EXCEPTION TYPE {{p}}cx_lessons_missing + EXPORTING iv_missing = c_min_lessons - ls_pupil-lessons_done. + ENDIF. + + IF ls_pupil-fee_paid <> c_done. + RAISE EXCEPTION TYPE {{p}}cx_fee_unpaid. + ENDIF. + + IF ls_pupil-last_failed IS NOT INITIAL. + DATA(lv_days) = iv_test_date - ls_pupil-last_failed. + IF lv_days < c_wait_days. + RAISE EXCEPTION TYPE {{p}}cx_recent_failure + EXPORTING iv_days_left = c_wait_days - lv_days. + ENDIF. + ENDIF. + ENDMETHOD. + + METHOD read_pupil. + SELECT SINGLE + FROM {{p}}pupil + FIELDS pupil_id, theory_done, lessons_done, fee_paid, last_failed + WHERE pupil_id = @iv_pupil_id + INTO CORRESPONDING FIELDS OF @rs_pupil. + IF sy-subrc <> 0. + RAISE EXCEPTION TYPE {{p}}cx_pupil_unknown. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0131/reference/driving_test_check.testclasses.abap b/tasks_gen/eval/G0131/reference/driving_test_check.testclasses.abap new file mode 100644 index 0000000..8e1d548 --- /dev/null +++ b/tasks_gen/eval/G0131/reference/driving_test_check.testclasses.abap @@ -0,0 +1,117 @@ +CLASS ltc_driving_test_check DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + DATA mo_cut TYPE REF TO {{p}}driving_test_check. + DATA mo_env TYPE REF TO if_osql_test_environment. + METHODS setup. + METHODS teardown. + METHODS add_pupil + IMPORTING iv_id TYPE string + iv_theory TYPE abap_bool + iv_lessons TYPE i + iv_fee TYPE abap_bool + iv_last_failed TYPE d. + METHODS ready_pupil_passes FOR TESTING. + METHODS unknown_pupil_raises FOR TESTING. + METHODS missing_theory_raises FOR TESTING. + METHODS few_lessons_raise FOR TESTING. + METHODS unpaid_fee_raises FOR TESTING. + METHODS recent_failure_raises FOR TESTING. +ENDCLASS. + + +CLASS ltc_driving_test_check IMPLEMENTATION. + METHOD setup. + mo_env = cl_osql_test_environment=>create( VALUE #( ( '{{P}}PUPIL' ) ) ). + mo_cut = NEW {{p}}driving_test_check( ). + ENDMETHOD. + + METHOD teardown. + mo_env->destroy( ). + ENDMETHOD. + + METHOD add_pupil. + DATA ls_pupil TYPE {{p}}pupil. + ls_pupil-client = sy-mandt. + ls_pupil-pupil_id = iv_id. + ls_pupil-pupil_name = iv_id. + IF iv_theory = abap_true. + ls_pupil-theory_done = 'X'. + ENDIF. + ls_pupil-lessons_done = iv_lessons. + IF iv_fee = abap_true. + ls_pupil-fee_paid = 'X'. + ENDIF. + ls_pupil-last_failed = iv_last_failed. + INSERT {{p}}pupil FROM @ls_pupil. + ENDMETHOD. + + METHOD ready_pupil_passes. + add_pupil( iv_id = 'P001' iv_theory = abap_true iv_lessons = 20 + iv_fee = abap_true iv_last_failed = '00000000' ). + TRY. + mo_cut->check( iv_pupil_id = 'P001' iv_test_date = '20250201' ). + CATCH cx_root INTO DATA(lx_error). + cl_abap_unit_assert=>fail( msg = lx_error->get_text( ) ). + ENDTRY. + ENDMETHOD. + + METHOD unknown_pupil_raises. + TRY. + mo_cut->check( iv_pupil_id = 'P999' iv_test_date = '20250201' ). + cl_abap_unit_assert=>fail( msg = 'exception expected' ). + CATCH {{p}}cx_pupil_unknown. + CATCH cx_root INTO DATA(lx_wrong). + cl_abap_unit_assert=>fail( msg = lx_wrong->get_text( ) ). + ENDTRY. + ENDMETHOD. + + METHOD missing_theory_raises. + add_pupil( iv_id = 'P002' iv_theory = abap_false iv_lessons = 20 + iv_fee = abap_true iv_last_failed = '00000000' ). + TRY. + mo_cut->check( iv_pupil_id = 'P002' iv_test_date = '20250201' ). + cl_abap_unit_assert=>fail( msg = 'exception expected' ). + CATCH {{p}}cx_theory_missing. + CATCH cx_root INTO DATA(lx_wrong). + cl_abap_unit_assert=>fail( msg = lx_wrong->get_text( ) ). + ENDTRY. + ENDMETHOD. + + METHOD few_lessons_raise. + add_pupil( iv_id = 'P003' iv_theory = abap_true iv_lessons = 9 + iv_fee = abap_true iv_last_failed = '00000000' ). + TRY. + mo_cut->check( iv_pupil_id = 'P003' iv_test_date = '20250201' ). + cl_abap_unit_assert=>fail( msg = 'exception expected' ). + CATCH {{p}}cx_lessons_missing INTO DATA(lx_lessons). + cl_abap_unit_assert=>assert_equals( exp = 3 act = lx_lessons->mv_missing ). + CATCH cx_root INTO DATA(lx_wrong). + cl_abap_unit_assert=>fail( msg = lx_wrong->get_text( ) ). + ENDTRY. + ENDMETHOD. + + METHOD unpaid_fee_raises. + add_pupil( iv_id = 'P004' iv_theory = abap_true iv_lessons = 20 + iv_fee = abap_false iv_last_failed = '00000000' ). + TRY. + mo_cut->check( iv_pupil_id = 'P004' iv_test_date = '20250201' ). + cl_abap_unit_assert=>fail( msg = 'exception expected' ). + CATCH {{p}}cx_fee_unpaid. + CATCH cx_root INTO DATA(lx_wrong). + cl_abap_unit_assert=>fail( msg = lx_wrong->get_text( ) ). + ENDTRY. + ENDMETHOD. + + METHOD recent_failure_raises. + add_pupil( iv_id = 'P005' iv_theory = abap_true iv_lessons = 20 + iv_fee = abap_true iv_last_failed = '20250127' ). + TRY. + mo_cut->check( iv_pupil_id = 'P005' iv_test_date = '20250201' ). + cl_abap_unit_assert=>fail( msg = 'exception expected' ). + CATCH {{p}}cx_recent_failure INTO DATA(lx_recent). + cl_abap_unit_assert=>assert_equals( exp = 9 act = lx_recent->mv_days_left ). + CATCH cx_root INTO DATA(lx_wrong). + cl_abap_unit_assert=>fail( msg = lx_wrong->get_text( ) ). + ENDTRY. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0131/seed/pupil.tabl.abap b/tasks_gen/eval/G0131/seed/pupil.tabl.abap new file mode 100644 index 0000000..afd0462 --- /dev/null +++ b/tasks_gen/eval/G0131/seed/pupil.tabl.abap @@ -0,0 +1,13 @@ +@EndUserText.label : 'Pupil' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +define table {{p}}pupil { + key client : abap.clnt not null; + key pupil_id : abap.char(10) not null; + pupil_name : abap.char(40); + theory_done : abap.char(1); + lessons_done : abap.int4; + fee_paid : abap.char(1); + last_failed : abap.dats; +} diff --git a/tasks_gen/eval/G0131/seed/pupil_data.clas.abap b/tasks_gen/eval/G0131/seed/pupil_data.clas.abap new file mode 100644 index 0000000..a52fe17 --- /dev/null +++ b/tasks_gen/eval/G0131/seed/pupil_data.clas.abap @@ -0,0 +1,24 @@ +CLASS {{p}}pupil_data DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES if_oo_adt_classrun. +ENDCLASS. + + +CLASS {{p}}pupil_data IMPLEMENTATION. + METHOD if_oo_adt_classrun~main. + DELETE FROM {{p}}pupil. + INSERT {{p}}pupil FROM TABLE @( VALUE #( + ( client = sy-mandt pupil_id = 'P001' pupil_name = 'Anna Adler' + theory_done = 'X' lessons_done = 20 fee_paid = 'X' last_failed = '00000000' ) + ( client = sy-mandt pupil_id = 'P002' pupil_name = 'Bodo Berger' + theory_done = '' lessons_done = 15 fee_paid = 'X' last_failed = '00000000' ) + ( client = sy-mandt pupil_id = 'P003' pupil_name = 'Carla Conrad' + theory_done = 'X' lessons_done = 5 fee_paid = 'X' last_failed = '00000000' ) + ( client = sy-mandt pupil_id = 'P004' pupil_name = 'Dana Decker' + theory_done = 'X' lessons_done = 18 fee_paid = '' last_failed = '00000000' ) + ( client = sy-mandt pupil_id = 'P005' pupil_name = 'Emil Ebert' + theory_done = 'X' lessons_done = 25 fee_paid = 'X' last_failed = '20250127' ) + ) ). + out->write( 'Pupil data written' ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0131/spec.md b/tasks_gen/eval/G0131/spec.md new file mode 100644 index 0000000..ae7b7f4 --- /dev/null +++ b/tasks_gen/eval/G0131/spec.md @@ -0,0 +1,73 @@ +# 1. Goal +A driving school checks if a pupil may book a practical driving test. A booking +program calls the check before it books the test. When the pupil is not ready, +the check must tell the program the exact reason. + +# 2. Open questions +None. + +# 3. Context +- The table {{P}}PUPIL exists in package $TMP. It is active. +- The table has these fields: CLIENT, PUPIL_ID (character 10), PUPIL_NAME + (character 40), THEORY_DONE (character 1), LESSONS_DONE (integer), FEE_PAID + (character 1), LAST_FAILED (date). +- THEORY_DONE and FEE_PAID contain 'X' when the item is done. They are initial + when the item is not done. +- LESSONS_DONE is the number of driving lessons that the pupil completed. +- LAST_FAILED is the date of the last failed practical test. It is initial when + the pupil never failed a test. +- The class {{P}}PUPIL_DATA fills the table with example data. It is active. + +# 4. Contract +Create the class {{P}}DRIVING_TEST_CHECK in package $TMP. +- The class is public, final, and has a public constructor without parameters. +- Define these types in the public section of the class: + TYPES ty_pupil_id TYPE c LENGTH 10. + TYPES ty_date TYPE d. +- The class has this public method and no other public method: + METHODS check + IMPORTING iv_pupil_id TYPE ty_pupil_id + iv_test_date TYPE ty_date + RAISING {{P}}CX_PUPIL_UNKNOWN + {{P}}CX_THEORY_MISSING + {{P}}CX_LESSONS_MISSING + {{P}}CX_FEE_UNPAID + {{P}}CX_RECENT_FAILURE. +- Create these exception classes in package $TMP. Each class is public and + inherits from CX_STATIC_CHECK. + - {{P}}CX_PUPIL_UNKNOWN: no constructor parameter. + - {{P}}CX_THEORY_MISSING: no constructor parameter. + - {{P}}CX_LESSONS_MISSING: constructor parameter IV_MISSING TYPE i. The + public read-only attribute MV_MISSING TYPE i has the value of IV_MISSING. + - {{P}}CX_FEE_UNPAID: no constructor parameter. + - {{P}}CX_RECENT_FAILURE: constructor parameter IV_DAYS_LEFT TYPE i. The + public read-only attribute MV_DAYS_LEFT TYPE i has the value of + IV_DAYS_LEFT. +- Do not add other public methods or attributes to these classes. + +# 5. Business rules +The method CHECK reads the pupil with the pupil id IV_PUPIL_ID from the table +{{P}}PUPIL. Apply these rules in this sequence. Raise the exception of the +first rule that fails. Raise no exception when all rules pass. +1. If the table has no entry for this pupil id, raise {{P}}CX_PUPIL_UNKNOWN. +2. If THEORY_DONE is not 'X', raise {{P}}CX_THEORY_MISSING. +3. If LESSONS_DONE is less than 12, raise {{P}}CX_LESSONS_MISSING with + IV_MISSING = 12 - LESSONS_DONE. +4. If FEE_PAID is not 'X', raise {{P}}CX_FEE_UNPAID. +5. If LAST_FAILED is not initial, calculate the number of days from LAST_FAILED + to IV_TEST_DATE. If this number is less than 14, raise + {{P}}CX_RECENT_FAILURE with IV_DAYS_LEFT = 14 - number of days. + +# 6. Constraints +- Release target: 8.16. +- Coding standards: Clean ABAP. Methods below 40 statements. No global + variables. Pass large parameters by reference. No comment that restates the + code. +- A test must not pass when the method under test raises an exception that the + test does not expect. +- Out of scope: do not change {{P}}PUPIL and {{P}}PUPIL_DATA. + +# 7. Acceptance +- All classes are active and have no syntax error. +- The hidden tests pass. +- Write your own ABAP Unit tests for the class {{P}}DRIVING_TEST_CHECK. diff --git a/tasks_gen/eval/G0131/task.json b/tasks_gen/eval/G0131/task.json new file mode 100644 index 0000000..2d04967 --- /dev/null +++ b/tasks_gen/eval/G0131/task.json @@ -0,0 +1,108 @@ +{ + "id": "G0131", + "category": "D", + "object_type": "CLAS", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [ + { + "type": "TABL", + "name": "{{P}}PUPIL", + "file": "seed/pupil.tabl.abap", + "description": "Pupil master data of the driving school" + }, + { + "type": "CLAS", + "name": "{{P}}PUPIL_DATA", + "file": "seed/pupil_data.clas.abap", + "description": "Fills the pupil table with example data", + "run": true + } + ], + "contract": [ + { + "type": "CLAS", + "name": "{{P}}DRIVING_TEST_CHECK" + }, + { + "type": "CLAS", + "name": "{{P}}CX_PUPIL_UNKNOWN" + }, + { + "type": "CLAS", + "name": "{{P}}CX_THEORY_MISSING" + }, + { + "type": "CLAS", + "name": "{{P}}CX_LESSONS_MISSING" + }, + { + "type": "CLAS", + "name": "{{P}}CX_FEE_UNPAID" + }, + { + "type": "CLAS", + "name": "{{P}}CX_RECENT_FAILURE" + } + ], + "out_of_scope": [ + "{{P}}PUPIL", + "{{P}}PUPIL_DATA" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T_DRIVING_CHECK", + "file": "hidden/t_driving_check.clas.abap", + "description": "Hidden tests for the driving test booking check" + } + ], + "reference": [ + { + "type": "CLAS", + "name": "{{P}}CX_PUPIL_UNKNOWN", + "file": "reference/cx_pupil_unknown.clas.abap", + "description": "Pupil id is not in the pupil table" + }, + { + "type": "CLAS", + "name": "{{P}}CX_THEORY_MISSING", + "file": "reference/cx_theory_missing.clas.abap", + "description": "Theory exam is not passed" + }, + { + "type": "CLAS", + "name": "{{P}}CX_LESSONS_MISSING", + "file": "reference/cx_lessons_missing.clas.abap", + "description": "Too few driving lessons" + }, + { + "type": "CLAS", + "name": "{{P}}CX_FEE_UNPAID", + "file": "reference/cx_fee_unpaid.clas.abap", + "description": "Test fee is not paid" + }, + { + "type": "CLAS", + "name": "{{P}}CX_RECENT_FAILURE", + "file": "reference/cx_recent_failure.clas.abap", + "description": "Last practical test failed too recently" + }, + { + "type": "CLAS", + "name": "{{P}}DRIVING_TEST_CHECK", + "file": "reference/driving_test_check.clas.abap", + "description": "Checks if a pupil may book a practical driving test", + "testclasses_file": "reference/driving_test_check.testclasses.abap" + } + ], + "craft_checks": [ + "method_length", + "db_operation_in_loop" + ] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0132/faulty/m0_exam_check.clas.abap b/tasks_gen/eval/G0132/faulty/m0_exam_check.clas.abap new file mode 100644 index 0000000..6eafd25 --- /dev/null +++ b/tasks_gen/eval/G0132/faulty/m0_exam_check.clas.abap @@ -0,0 +1,54 @@ +CLASS {{p}}exam_check DEFINITION + PUBLIC + FINAL + CREATE PUBLIC. + + PUBLIC SECTION. + METHODS constructor + IMPORTING iv_max_attempts TYPE i + iv_deadline TYPE d. + + METHODS check + IMPORTING is_request TYPE {{p}}if_exam_request=>ty_request + RAISING {{p}}cx_not_enrolled + {{p}}cx_prereq_missing + {{p}}cx_no_attempt_left + {{p}}cx_deadline_passed. + + PRIVATE SECTION. + DATA mv_max_attempts TYPE i. + DATA mv_deadline TYPE d. +ENDCLASS. + + +CLASS {{p}}exam_check IMPLEMENTATION. + METHOD constructor. + mv_max_attempts = iv_max_attempts. + mv_deadline = iv_deadline. + ENDMETHOD. + + METHOD check. + IF is_request-enrolled <> abap_false. + RAISE EXCEPTION TYPE {{p}}cx_not_enrolled + EXPORTING iv_student_id = is_request-student_id. + ENDIF. + + IF is_request-prereq_passed = abap_false. + RAISE EXCEPTION TYPE {{p}}cx_prereq_missing + EXPORTING iv_student_id = is_request-student_id + iv_prereq = is_request-prereq_id. + ENDIF. + + IF is_request-attempts >= mv_max_attempts. + RAISE EXCEPTION TYPE {{p}}cx_no_attempt_left + EXPORTING iv_student_id = is_request-student_id + iv_attempts = is_request-attempts. + ENDIF. + + IF is_request-reg_date > mv_deadline. + RAISE EXCEPTION TYPE {{p}}cx_deadline_passed + EXPORTING iv_student_id = is_request-student_id + iv_reg_date = is_request-reg_date. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0132/faulty/m1_exam_check.clas.abap b/tasks_gen/eval/G0132/faulty/m1_exam_check.clas.abap new file mode 100644 index 0000000..11d599e --- /dev/null +++ b/tasks_gen/eval/G0132/faulty/m1_exam_check.clas.abap @@ -0,0 +1,54 @@ +CLASS {{p}}exam_check DEFINITION + PUBLIC + FINAL + CREATE PUBLIC. + + PUBLIC SECTION. + METHODS constructor + IMPORTING iv_max_attempts TYPE i + iv_deadline TYPE d. + + METHODS check + IMPORTING is_request TYPE {{p}}if_exam_request=>ty_request + RAISING {{p}}cx_not_enrolled + {{p}}cx_prereq_missing + {{p}}cx_no_attempt_left + {{p}}cx_deadline_passed. + + PRIVATE SECTION. + DATA mv_max_attempts TYPE i. + DATA mv_deadline TYPE d. +ENDCLASS. + + +CLASS {{p}}exam_check IMPLEMENTATION. + METHOD constructor. + mv_max_attempts = iv_max_attempts. + mv_deadline = iv_deadline. + ENDMETHOD. + + METHOD check. + IF is_request-enrolled = abap_true. + RAISE EXCEPTION TYPE {{p}}cx_not_enrolled + EXPORTING iv_student_id = is_request-student_id. + ENDIF. + + IF is_request-prereq_passed = abap_false. + RAISE EXCEPTION TYPE {{p}}cx_prereq_missing + EXPORTING iv_student_id = is_request-student_id + iv_prereq = is_request-prereq_id. + ENDIF. + + IF is_request-attempts >= mv_max_attempts. + RAISE EXCEPTION TYPE {{p}}cx_no_attempt_left + EXPORTING iv_student_id = is_request-student_id + iv_attempts = is_request-attempts. + ENDIF. + + IF is_request-reg_date > mv_deadline. + RAISE EXCEPTION TYPE {{p}}cx_deadline_passed + EXPORTING iv_student_id = is_request-student_id + iv_reg_date = is_request-reg_date. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0132/faulty/m2_exam_check.clas.abap b/tasks_gen/eval/G0132/faulty/m2_exam_check.clas.abap new file mode 100644 index 0000000..e79b972 --- /dev/null +++ b/tasks_gen/eval/G0132/faulty/m2_exam_check.clas.abap @@ -0,0 +1,54 @@ +CLASS {{p}}exam_check DEFINITION + PUBLIC + FINAL + CREATE PUBLIC. + + PUBLIC SECTION. + METHODS constructor + IMPORTING iv_max_attempts TYPE i + iv_deadline TYPE d. + + METHODS check + IMPORTING is_request TYPE {{p}}if_exam_request=>ty_request + RAISING {{p}}cx_not_enrolled + {{p}}cx_prereq_missing + {{p}}cx_no_attempt_left + {{p}}cx_deadline_passed. + + PRIVATE SECTION. + DATA mv_max_attempts TYPE i. + DATA mv_deadline TYPE d. +ENDCLASS. + + +CLASS {{p}}exam_check IMPLEMENTATION. + METHOD constructor. + mv_max_attempts = iv_max_attempts. + mv_deadline = iv_deadline. + ENDMETHOD. + + METHOD check. + IF is_request-enrolled = abap_false. + RAISE EXCEPTION TYPE {{p}}cx_not_enrolled + EXPORTING iv_student_id = is_request-student_id. + ENDIF. + + IF is_request-prereq_passed = abap_true. + RAISE EXCEPTION TYPE {{p}}cx_prereq_missing + EXPORTING iv_student_id = is_request-student_id + iv_prereq = is_request-prereq_id. + ENDIF. + + IF is_request-attempts >= mv_max_attempts. + RAISE EXCEPTION TYPE {{p}}cx_no_attempt_left + EXPORTING iv_student_id = is_request-student_id + iv_attempts = is_request-attempts. + ENDIF. + + IF is_request-reg_date > mv_deadline. + RAISE EXCEPTION TYPE {{p}}cx_deadline_passed + EXPORTING iv_student_id = is_request-student_id + iv_reg_date = is_request-reg_date. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0132/faulty/m3_exam_check.clas.abap b/tasks_gen/eval/G0132/faulty/m3_exam_check.clas.abap new file mode 100644 index 0000000..b7c7d53 --- /dev/null +++ b/tasks_gen/eval/G0132/faulty/m3_exam_check.clas.abap @@ -0,0 +1,54 @@ +CLASS {{p}}exam_check DEFINITION + PUBLIC + FINAL + CREATE PUBLIC. + + PUBLIC SECTION. + METHODS constructor + IMPORTING iv_max_attempts TYPE i + iv_deadline TYPE d. + + METHODS check + IMPORTING is_request TYPE {{p}}if_exam_request=>ty_request + RAISING {{p}}cx_not_enrolled + {{p}}cx_prereq_missing + {{p}}cx_no_attempt_left + {{p}}cx_deadline_passed. + + PRIVATE SECTION. + DATA mv_max_attempts TYPE i. + DATA mv_deadline TYPE d. +ENDCLASS. + + +CLASS {{p}}exam_check IMPLEMENTATION. + METHOD constructor. + mv_max_attempts = iv_max_attempts. + mv_deadline = iv_deadline. + ENDMETHOD. + + METHOD check. + IF is_request-enrolled = abap_false. + RAISE EXCEPTION TYPE {{p}}cx_not_enrolled + EXPORTING iv_student_id = is_request-student_id. + ENDIF. + + IF is_request-prereq_passed = abap_false. + RAISE EXCEPTION TYPE {{p}}cx_prereq_missing + EXPORTING iv_student_id = is_request-student_id + iv_prereq = is_request-prereq_id. + ENDIF. + + IF is_request-attempts < mv_max_attempts. + RAISE EXCEPTION TYPE {{p}}cx_no_attempt_left + EXPORTING iv_student_id = is_request-student_id + iv_attempts = is_request-attempts. + ENDIF. + + IF is_request-reg_date > mv_deadline. + RAISE EXCEPTION TYPE {{p}}cx_deadline_passed + EXPORTING iv_student_id = is_request-student_id + iv_reg_date = is_request-reg_date. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0132/faulty/m4_exam_check.clas.abap b/tasks_gen/eval/G0132/faulty/m4_exam_check.clas.abap new file mode 100644 index 0000000..39a0f49 --- /dev/null +++ b/tasks_gen/eval/G0132/faulty/m4_exam_check.clas.abap @@ -0,0 +1,54 @@ +CLASS {{p}}exam_check DEFINITION + PUBLIC + FINAL + CREATE PUBLIC. + + PUBLIC SECTION. + METHODS constructor + IMPORTING iv_max_attempts TYPE i + iv_deadline TYPE d. + + METHODS check + IMPORTING is_request TYPE {{p}}if_exam_request=>ty_request + RAISING {{p}}cx_not_enrolled + {{p}}cx_prereq_missing + {{p}}cx_no_attempt_left + {{p}}cx_deadline_passed. + + PRIVATE SECTION. + DATA mv_max_attempts TYPE i. + DATA mv_deadline TYPE d. +ENDCLASS. + + +CLASS {{p}}exam_check IMPLEMENTATION. + METHOD constructor. + mv_max_attempts = iv_max_attempts. + mv_deadline = iv_deadline. + ENDMETHOD. + + METHOD check. + IF is_request-enrolled = abap_false. + RAISE EXCEPTION TYPE {{p}}cx_not_enrolled + EXPORTING iv_student_id = is_request-student_id. + ENDIF. + + IF is_request-prereq_passed = abap_false. + RAISE EXCEPTION TYPE {{p}}cx_prereq_missing + EXPORTING iv_student_id = is_request-student_id + iv_prereq = is_request-prereq_id. + ENDIF. + + IF is_request-attempts >= mv_max_attempts. + RAISE EXCEPTION TYPE {{p}}cx_no_attempt_left + EXPORTING iv_student_id = is_request-student_id + iv_attempts = is_request-attempts. + ENDIF. + + IF is_request-reg_date <= mv_deadline. + RAISE EXCEPTION TYPE {{p}}cx_deadline_passed + EXPORTING iv_student_id = is_request-student_id + iv_reg_date = is_request-reg_date. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0132/generation.json b/tasks_gen/eval/G0132/generation.json new file mode 100644 index 0000000..41ad812 --- /dev/null +++ b/tasks_gen/eval/G0132/generation.json @@ -0,0 +1,24 @@ +{ + "id": "G0132", + "pool": "eval", + "object_type": "CLAS", + "category": "D", + "attempts": [ + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 5, + "killed": 5, + "ok": true + } + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0132/hidden/t02_hidden.clas.abap b/tasks_gen/eval/G0132/hidden/t02_hidden.clas.abap new file mode 100644 index 0000000..09b84b9 --- /dev/null +++ b/tasks_gen/eval/G0132/hidden/t02_hidden.clas.abap @@ -0,0 +1,177 @@ +CLASS {{p}}t02_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + + PRIVATE SECTION. + CONSTANTS c_deadline TYPE d VALUE '20240331'. + DATA mo_cut TYPE REF TO {{p}}exam_check. + METHODS setup. + METHODS ok_request + RETURNING VALUE(rs_request) TYPE {{p}}if_exam_request=>ty_request. + METHODS allowed_when_all_ok FOR TESTING. + METHODS rejects_not_enrolled FOR TESTING. + METHODS rejects_prereq_missing FOR TESTING. + METHODS rejects_no_attempt_left FOR TESTING. + METHODS rejects_deadline_passed FOR TESTING. + METHODS last_attempt_allowed FOR TESTING. + METHODS reg_on_deadline_allowed FOR TESTING. + METHODS first_rule_wins FOR TESTING. + METHODS attempts_before_deadline FOR TESTING. + METHODS base_class_catches_all FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t02_hidden IMPLEMENTATION. + + METHOD setup. + mo_cut = NEW {{p}}exam_check( iv_max_attempts = 3 + iv_deadline = c_deadline ). + ENDMETHOD. + + METHOD ok_request. + rs_request = VALUE #( student_id = 'S4711' + enrolled = abap_true + prereq_passed = abap_true + prereq_id = 'P100' + attempts = 0 + reg_date = CONV d( '20240115' ) ). + ENDMETHOD. + + METHOD allowed_when_all_ok. + TRY. + mo_cut->check( ok_request( ) ). + CATCH {{p}}cx_exam_error. + cl_abap_unit_assert=>fail( |The registration must be allowed| ). + ENDTRY. + ENDMETHOD. + + METHOD rejects_not_enrolled. + DATA(ls_request) = ok_request( ). + ls_request-enrolled = abap_false. + TRY. + mo_cut->check( ls_request ). + cl_abap_unit_assert=>fail( |Exception expected| ). + CATCH {{p}}cx_not_enrolled INTO DATA(lo_error). + cl_abap_unit_assert=>assert_equals( exp = 'S4711' + act = lo_error->mv_student_id ). + cl_abap_unit_assert=>assert_equals( exp = 'The student is not enrolled.' + act = lo_error->mv_text ). + CATCH {{p}}cx_exam_error. + cl_abap_unit_assert=>fail( |Wrong exception type| ). + ENDTRY. + ENDMETHOD. + + METHOD rejects_prereq_missing. + DATA(ls_request) = ok_request( ). + ls_request-prereq_passed = abap_false. + TRY. + mo_cut->check( ls_request ). + cl_abap_unit_assert=>fail( |Exception expected| ). + CATCH {{p}}cx_prereq_missing INTO DATA(lo_error). + cl_abap_unit_assert=>assert_equals( exp = 'P100' + act = lo_error->mv_prereq ). + cl_abap_unit_assert=>assert_equals( + exp = 'The prerequisite exam is not passed.' + act = lo_error->mv_text ). + CATCH {{p}}cx_exam_error. + cl_abap_unit_assert=>fail( |Wrong exception type| ). + ENDTRY. + ENDMETHOD. + + METHOD rejects_no_attempt_left. + DATA(ls_request) = ok_request( ). + ls_request-attempts = 3. + TRY. + mo_cut->check( ls_request ). + cl_abap_unit_assert=>fail( |Exception expected| ). + CATCH {{p}}cx_no_attempt_left INTO DATA(lo_error). + cl_abap_unit_assert=>assert_equals( exp = 3 + act = lo_error->mv_attempts ). + cl_abap_unit_assert=>assert_equals( exp = 'No attempt is left.' + act = lo_error->mv_text ). + CATCH {{p}}cx_exam_error. + cl_abap_unit_assert=>fail( |Wrong exception type| ). + ENDTRY. + ENDMETHOD. + + METHOD rejects_deadline_passed. + DATA(ls_request) = ok_request( ). + ls_request-reg_date = CONV d( '20240401' ). + TRY. + mo_cut->check( ls_request ). + cl_abap_unit_assert=>fail( |Exception expected| ). + CATCH {{p}}cx_deadline_passed INTO DATA(lo_error). + cl_abap_unit_assert=>assert_equals( exp = CONV d( '20240401' ) + act = lo_error->mv_reg_date ). + cl_abap_unit_assert=>assert_equals( + exp = 'The registration deadline has passed.' + act = lo_error->mv_text ). + CATCH {{p}}cx_exam_error. + cl_abap_unit_assert=>fail( |Wrong exception type| ). + ENDTRY. + ENDMETHOD. + + METHOD last_attempt_allowed. + DATA(ls_request) = ok_request( ). + ls_request-attempts = 2. + TRY. + mo_cut->check( ls_request ). + CATCH {{p}}cx_exam_error. + cl_abap_unit_assert=>fail( |The last free attempt must be allowed| ). + ENDTRY. + ENDMETHOD. + + METHOD reg_on_deadline_allowed. + DATA(ls_request) = ok_request( ). + ls_request-reg_date = c_deadline. + TRY. + mo_cut->check( ls_request ). + CATCH {{p}}cx_exam_error. + cl_abap_unit_assert=>fail( |The deadline day must be allowed| ). + ENDTRY. + ENDMETHOD. + + METHOD first_rule_wins. + DATA(ls_request) = ok_request( ). + ls_request-enrolled = abap_false. + ls_request-prereq_passed = abap_false. + ls_request-attempts = 9. + ls_request-reg_date = CONV d( '20241231' ). + TRY. + mo_cut->check( ls_request ). + cl_abap_unit_assert=>fail( |Exception expected| ). + CATCH {{p}}cx_not_enrolled INTO DATA(lo_error). + cl_abap_unit_assert=>assert_equals( exp = 'S4711' + act = lo_error->mv_student_id ). + CATCH {{p}}cx_exam_error. + cl_abap_unit_assert=>fail( |Wrong exception type| ). + ENDTRY. + ENDMETHOD. + + METHOD attempts_before_deadline. + DATA(ls_request) = ok_request( ). + ls_request-attempts = 3. + ls_request-reg_date = CONV d( '20241231' ). + TRY. + mo_cut->check( ls_request ). + cl_abap_unit_assert=>fail( |Exception expected| ). + CATCH {{p}}cx_no_attempt_left INTO DATA(lo_error). + cl_abap_unit_assert=>assert_equals( exp = 3 + act = lo_error->mv_attempts ). + CATCH {{p}}cx_exam_error. + cl_abap_unit_assert=>fail( |Wrong exception type| ). + ENDTRY. + ENDMETHOD. + + METHOD base_class_catches_all. + DATA(ls_request) = ok_request( ). + ls_request-prereq_passed = abap_false. + TRY. + mo_cut->check( ls_request ). + cl_abap_unit_assert=>fail( |Exception expected| ). + CATCH {{p}}cx_exam_error INTO DATA(lo_error). + cl_abap_unit_assert=>assert_equals( exp = 'S4711' + act = lo_error->mv_student_id ). + ENDTRY. + ENDMETHOD. + +ENDCLASS. diff --git a/tasks_gen/eval/G0132/mutation.json b/tasks_gen/eval/G0132/mutation.json new file mode 100644 index 0000000..45b4743 --- /dev/null +++ b/tasks_gen/eval/G0132/mutation.json @@ -0,0 +1,85 @@ +{ + "task": "G0132", + "mutants": [ + { + "object": "{{P}}EXAM_CHECK", + "mutant": "line 31: = -> <> (eq)", + "status": "killed", + "hidden": "1/10", + "failed_tests": [ + "ALLOWED_WHEN_ALL_OK", + "ATTEMPTS_BEFORE_DEADLINE", + "FIRST_RULE_WINS", + "LAST_ATTEMPT_ALLOWED", + "REG_ON_DEADLINE_ALLOWED", + "REJECTS_DEADLINE_PASSED", + "REJECTS_NOT_ENROLLED", + "REJECTS_NO_ATTEMPT_LEFT", + "REJECTS_PREREQ_MISSING" + ] + }, + { + "object": "{{P}}EXAM_CHECK", + "mutant": "line 31: abap_false -> abap_true (bool)", + "status": "killed", + "hidden": "1/10", + "failed_tests": [ + "ALLOWED_WHEN_ALL_OK", + "ATTEMPTS_BEFORE_DEADLINE", + "FIRST_RULE_WINS", + "LAST_ATTEMPT_ALLOWED", + "REG_ON_DEADLINE_ALLOWED", + "REJECTS_DEADLINE_PASSED", + "REJECTS_NOT_ENROLLED", + "REJECTS_NO_ATTEMPT_LEFT", + "REJECTS_PREREQ_MISSING" + ] + }, + { + "object": "{{P}}EXAM_CHECK", + "mutant": "line 36: abap_false -> abap_true (bool)", + "status": "killed", + "hidden": "2/10", + "failed_tests": [ + "ALLOWED_WHEN_ALL_OK", + "ATTEMPTS_BEFORE_DEADLINE", + "BASE_CLASS_CATCHES_ALL", + "LAST_ATTEMPT_ALLOWED", + "REG_ON_DEADLINE_ALLOWED", + "REJECTS_DEADLINE_PASSED", + "REJECTS_NO_ATTEMPT_LEFT", + "REJECTS_PREREQ_MISSING" + ] + }, + { + "object": "{{P}}EXAM_CHECK", + "mutant": "line 42: >= -> < (rel)", + "status": "killed", + "hidden": "4/10", + "failed_tests": [ + "ALLOWED_WHEN_ALL_OK", + "ATTEMPTS_BEFORE_DEADLINE", + "LAST_ATTEMPT_ALLOWED", + "REG_ON_DEADLINE_ALLOWED", + "REJECTS_DEADLINE_PASSED", + "REJECTS_NO_ATTEMPT_LEFT" + ] + }, + { + "object": "{{P}}EXAM_CHECK", + "mutant": "line 48: > -> <= (rel)", + "status": "killed", + "hidden": "6/10", + "failed_tests": [ + "ALLOWED_WHEN_ALL_OK", + "LAST_ATTEMPT_ALLOWED", + "REG_ON_DEADLINE_ALLOWED", + "REJECTS_DEADLINE_PASSED" + ] + } + ], + "valid": 5, + "killed": 5, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0132/reference/cx_deadline_passed.clas.abap b/tasks_gen/eval/G0132/reference/cx_deadline_passed.clas.abap new file mode 100644 index 0000000..ca31c86 --- /dev/null +++ b/tasks_gen/eval/G0132/reference/cx_deadline_passed.clas.abap @@ -0,0 +1,22 @@ +CLASS {{p}}cx_deadline_passed DEFINITION + PUBLIC + INHERITING FROM {{p}}cx_exam_error + FINAL + CREATE PUBLIC. + + PUBLIC SECTION. + DATA mv_reg_date TYPE d READ-ONLY. + + METHODS constructor + IMPORTING iv_student_id TYPE string + iv_reg_date TYPE d. +ENDCLASS. + + +CLASS {{p}}cx_deadline_passed IMPLEMENTATION. + METHOD constructor. + super->constructor( iv_student_id = iv_student_id + iv_text = 'The registration deadline has passed.' ). + mv_reg_date = iv_reg_date. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0132/reference/cx_exam_error.clas.abap b/tasks_gen/eval/G0132/reference/cx_exam_error.clas.abap new file mode 100644 index 0000000..12c7e22 --- /dev/null +++ b/tasks_gen/eval/G0132/reference/cx_exam_error.clas.abap @@ -0,0 +1,23 @@ +CLASS {{p}}cx_exam_error DEFINITION + PUBLIC + INHERITING FROM cx_static_check + ABSTRACT + CREATE PUBLIC. + + PUBLIC SECTION. + DATA mv_student_id TYPE string READ-ONLY. + DATA mv_text TYPE string READ-ONLY. + + METHODS constructor + IMPORTING iv_student_id TYPE string + iv_text TYPE string. +ENDCLASS. + + +CLASS {{p}}cx_exam_error IMPLEMENTATION. + METHOD constructor. + super->constructor( ). + mv_student_id = iv_student_id. + mv_text = iv_text. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0132/reference/cx_no_attempt_left.clas.abap b/tasks_gen/eval/G0132/reference/cx_no_attempt_left.clas.abap new file mode 100644 index 0000000..02fe3b1 --- /dev/null +++ b/tasks_gen/eval/G0132/reference/cx_no_attempt_left.clas.abap @@ -0,0 +1,22 @@ +CLASS {{p}}cx_no_attempt_left DEFINITION + PUBLIC + INHERITING FROM {{p}}cx_exam_error + FINAL + CREATE PUBLIC. + + PUBLIC SECTION. + DATA mv_attempts TYPE i READ-ONLY. + + METHODS constructor + IMPORTING iv_student_id TYPE string + iv_attempts TYPE i. +ENDCLASS. + + +CLASS {{p}}cx_no_attempt_left IMPLEMENTATION. + METHOD constructor. + super->constructor( iv_student_id = iv_student_id + iv_text = 'No attempt is left.' ). + mv_attempts = iv_attempts. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0132/reference/cx_not_enrolled.clas.abap b/tasks_gen/eval/G0132/reference/cx_not_enrolled.clas.abap new file mode 100644 index 0000000..689544a --- /dev/null +++ b/tasks_gen/eval/G0132/reference/cx_not_enrolled.clas.abap @@ -0,0 +1,18 @@ +CLASS {{p}}cx_not_enrolled DEFINITION + PUBLIC + INHERITING FROM {{p}}cx_exam_error + FINAL + CREATE PUBLIC. + + PUBLIC SECTION. + METHODS constructor + IMPORTING iv_student_id TYPE string. +ENDCLASS. + + +CLASS {{p}}cx_not_enrolled IMPLEMENTATION. + METHOD constructor. + super->constructor( iv_student_id = iv_student_id + iv_text = 'The student is not enrolled.' ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0132/reference/cx_prereq_missing.clas.abap b/tasks_gen/eval/G0132/reference/cx_prereq_missing.clas.abap new file mode 100644 index 0000000..f73eb79 --- /dev/null +++ b/tasks_gen/eval/G0132/reference/cx_prereq_missing.clas.abap @@ -0,0 +1,22 @@ +CLASS {{p}}cx_prereq_missing DEFINITION + PUBLIC + INHERITING FROM {{p}}cx_exam_error + FINAL + CREATE PUBLIC. + + PUBLIC SECTION. + DATA mv_prereq TYPE string READ-ONLY. + + METHODS constructor + IMPORTING iv_student_id TYPE string + iv_prereq TYPE string. +ENDCLASS. + + +CLASS {{p}}cx_prereq_missing IMPLEMENTATION. + METHOD constructor. + super->constructor( iv_student_id = iv_student_id + iv_text = 'The prerequisite exam is not passed.' ). + mv_prereq = iv_prereq. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0132/reference/exam_check.clas.abap b/tasks_gen/eval/G0132/reference/exam_check.clas.abap new file mode 100644 index 0000000..87c6f21 --- /dev/null +++ b/tasks_gen/eval/G0132/reference/exam_check.clas.abap @@ -0,0 +1,54 @@ +CLASS {{p}}exam_check DEFINITION + PUBLIC + FINAL + CREATE PUBLIC. + + PUBLIC SECTION. + METHODS constructor + IMPORTING iv_max_attempts TYPE i + iv_deadline TYPE d. + + METHODS check + IMPORTING is_request TYPE {{p}}if_exam_request=>ty_request + RAISING {{p}}cx_not_enrolled + {{p}}cx_prereq_missing + {{p}}cx_no_attempt_left + {{p}}cx_deadline_passed. + + PRIVATE SECTION. + DATA mv_max_attempts TYPE i. + DATA mv_deadline TYPE d. +ENDCLASS. + + +CLASS {{p}}exam_check IMPLEMENTATION. + METHOD constructor. + mv_max_attempts = iv_max_attempts. + mv_deadline = iv_deadline. + ENDMETHOD. + + METHOD check. + IF is_request-enrolled = abap_false. + RAISE EXCEPTION TYPE {{p}}cx_not_enrolled + EXPORTING iv_student_id = is_request-student_id. + ENDIF. + + IF is_request-prereq_passed = abap_false. + RAISE EXCEPTION TYPE {{p}}cx_prereq_missing + EXPORTING iv_student_id = is_request-student_id + iv_prereq = is_request-prereq_id. + ENDIF. + + IF is_request-attempts >= mv_max_attempts. + RAISE EXCEPTION TYPE {{p}}cx_no_attempt_left + EXPORTING iv_student_id = is_request-student_id + iv_attempts = is_request-attempts. + ENDIF. + + IF is_request-reg_date > mv_deadline. + RAISE EXCEPTION TYPE {{p}}cx_deadline_passed + EXPORTING iv_student_id = is_request-student_id + iv_reg_date = is_request-reg_date. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0132/reference/exam_check.testclasses.abap b/tasks_gen/eval/G0132/reference/exam_check.testclasses.abap new file mode 100644 index 0000000..66e9e71 --- /dev/null +++ b/tasks_gen/eval/G0132/reference/exam_check.testclasses.abap @@ -0,0 +1,97 @@ +CLASS ltc_exam_check DEFINITION FINAL FOR TESTING + DURATION SHORT RISK LEVEL HARMLESS. + + PRIVATE SECTION. + CONSTANTS c_deadline TYPE d VALUE '20240331'. + DATA mo_cut TYPE REF TO {{p}}exam_check. + + METHODS setup. + METHODS ok_request + RETURNING VALUE(rs_request) TYPE {{p}}if_exam_request=>ty_request. + METHODS allowed FOR TESTING. + METHODS not_enrolled FOR TESTING. + METHODS prereq_missing FOR TESTING. + METHODS no_attempt_left FOR TESTING. + METHODS deadline_passed FOR TESTING. +ENDCLASS. + + +CLASS ltc_exam_check IMPLEMENTATION. + METHOD setup. + mo_cut = NEW {{p}}exam_check( iv_max_attempts = 3 + iv_deadline = c_deadline ). + ENDMETHOD. + + METHOD ok_request. + rs_request = VALUE #( student_id = 'S4711' + enrolled = abap_true + prereq_passed = abap_true + prereq_id = 'P100' + attempts = 0 + reg_date = CONV d( '20240115' ) ). + ENDMETHOD. + + METHOD allowed. + TRY. + mo_cut->check( ok_request( ) ). + CATCH {{p}}cx_exam_error. + cl_abap_unit_assert=>fail( |The registration must be allowed| ). + ENDTRY. + ENDMETHOD. + + METHOD not_enrolled. + DATA(ls_request) = ok_request( ). + ls_request-enrolled = abap_false. + TRY. + mo_cut->check( ls_request ). + cl_abap_unit_assert=>fail( |Exception expected| ). + CATCH {{p}}cx_not_enrolled INTO DATA(lo_error). + cl_abap_unit_assert=>assert_equals( exp = 'S4711' + act = lo_error->mv_student_id ). + CATCH {{p}}cx_exam_error. + cl_abap_unit_assert=>fail( |Wrong exception type| ). + ENDTRY. + ENDMETHOD. + + METHOD prereq_missing. + DATA(ls_request) = ok_request( ). + ls_request-prereq_passed = abap_false. + TRY. + mo_cut->check( ls_request ). + cl_abap_unit_assert=>fail( |Exception expected| ). + CATCH {{p}}cx_prereq_missing INTO DATA(lo_error). + cl_abap_unit_assert=>assert_equals( exp = 'P100' + act = lo_error->mv_prereq ). + CATCH {{p}}cx_exam_error. + cl_abap_unit_assert=>fail( |Wrong exception type| ). + ENDTRY. + ENDMETHOD. + + METHOD no_attempt_left. + DATA(ls_request) = ok_request( ). + ls_request-attempts = 3. + TRY. + mo_cut->check( ls_request ). + cl_abap_unit_assert=>fail( |Exception expected| ). + CATCH {{p}}cx_no_attempt_left INTO DATA(lo_error). + cl_abap_unit_assert=>assert_equals( exp = 3 + act = lo_error->mv_attempts ). + CATCH {{p}}cx_exam_error. + cl_abap_unit_assert=>fail( |Wrong exception type| ). + ENDTRY. + ENDMETHOD. + + METHOD deadline_passed. + DATA(ls_request) = ok_request( ). + ls_request-reg_date = CONV d( '20240401' ). + TRY. + mo_cut->check( ls_request ). + cl_abap_unit_assert=>fail( |Exception expected| ). + CATCH {{p}}cx_deadline_passed INTO DATA(lo_error). + cl_abap_unit_assert=>assert_equals( exp = CONV d( '20240401' ) + act = lo_error->mv_reg_date ). + CATCH {{p}}cx_exam_error. + cl_abap_unit_assert=>fail( |Wrong exception type| ). + ENDTRY. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0132/seed/if_exam_request.intf.abap b/tasks_gen/eval/G0132/seed/if_exam_request.intf.abap new file mode 100644 index 0000000..b1df814 --- /dev/null +++ b/tasks_gen/eval/G0132/seed/if_exam_request.intf.abap @@ -0,0 +1,11 @@ +INTERFACE {{p}}if_exam_request PUBLIC. + TYPES: + BEGIN OF ty_request, + student_id TYPE string, + enrolled TYPE abap_bool, + prereq_passed TYPE abap_bool, + prereq_id TYPE string, + attempts TYPE i, + reg_date TYPE d, + END OF ty_request. +ENDINTERFACE. diff --git a/tasks_gen/eval/G0132/spec.md b/tasks_gen/eval/G0132/spec.md new file mode 100644 index 0000000..89bf482 --- /dev/null +++ b/tasks_gen/eval/G0132/spec.md @@ -0,0 +1,79 @@ +# 1. Goal +An exam office checks if a student may register for an exam. A registration +program calls the check before it books the seat. The check reports each +rejection as a class-based exception. + +# 2. Open questions +None. + +# 3. Context +- The interface {{P}}IF_EXAM_REQUEST exists in package $TMP. It is active. +- The interface has the public type TY_REQUEST. The components are: + STUDENT_ID (STRING), ENROLLED (ABAP_BOOL), PREREQ_PASSED (ABAP_BOOL), + PREREQ_ID (STRING), ATTEMPTS (I), REG_DATE (D). +- An exam has a maximum number of attempts and a registration deadline. The + caller reads both values from the exam master data. +- A prerequisite is another exam. PREREQ_ID is the id of that exam. + +# 4. Contract +Create these classes in package $TMP. + +{{P}}EXAM_CHECK +- The class is public and final. It has a public constructor. +- Constructor: IMPORTING iv_max_attempts TYPE i, iv_deadline TYPE d. +- Method CHECK: IMPORTING is_request TYPE {{P}}IF_EXAM_REQUEST=>TY_REQUEST + RAISING {{P}}CX_NOT_ENROLLED, {{P}}CX_PREREQ_MISSING, + {{P}}CX_NO_ATTEMPT_LEFT, {{P}}CX_DEADLINE_PASSED. +- Do not add other public methods. + +{{P}}CX_EXAM_ERROR +- The class is public and abstract. It inherits from CX_STATIC_CHECK. +- Public read-only attribute MV_STUDENT_ID TYPE string. +- Public read-only attribute MV_TEXT TYPE string. + +{{P}}CX_NOT_ENROLLED +- The class is public and final. It inherits from {{P}}CX_EXAM_ERROR. +- MV_TEXT contains the text 'The student is not enrolled.' + +{{P}}CX_PREREQ_MISSING +- The class is public and final. It inherits from {{P}}CX_EXAM_ERROR. +- Public read-only attribute MV_PREREQ TYPE string. +- MV_TEXT contains the text 'The prerequisite exam is not passed.' + +{{P}}CX_NO_ATTEMPT_LEFT +- The class is public and final. It inherits from {{P}}CX_EXAM_ERROR. +- Public read-only attribute MV_ATTEMPTS TYPE i. +- MV_TEXT contains the text 'No attempt is left.' + +{{P}}CX_DEADLINE_PASSED +- The class is public and final. It inherits from {{P}}CX_EXAM_ERROR. +- Public read-only attribute MV_REG_DATE TYPE d. +- MV_TEXT contains the text 'The registration deadline has passed.' + +# 5. Business rules +The method CHECK applies the rules in this sequence. It raises the exception +of the first rule that fails. +1. If IS_REQUEST-ENROLLED is abap_false, raise {{P}}CX_NOT_ENROLLED. + MV_STUDENT_ID contains IS_REQUEST-STUDENT_ID. +2. If IS_REQUEST-PREREQ_PASSED is abap_false, raise {{P}}CX_PREREQ_MISSING. + MV_STUDENT_ID contains IS_REQUEST-STUDENT_ID. MV_PREREQ contains + IS_REQUEST-PREREQ_ID. +3. If IS_REQUEST-ATTEMPTS is greater than or equal to the maximum number of + attempts, raise {{P}}CX_NO_ATTEMPT_LEFT. MV_STUDENT_ID contains + IS_REQUEST-STUDENT_ID. MV_ATTEMPTS contains IS_REQUEST-ATTEMPTS. +4. If IS_REQUEST-REG_DATE is later than the registration deadline, raise + {{P}}CX_DEADLINE_PASSED. MV_STUDENT_ID contains IS_REQUEST-STUDENT_ID. + MV_REG_DATE contains IS_REQUEST-REG_DATE. +5. Else the registration is allowed. The method returns without an exception. + +# 6. Constraints +- Release target: 8.16. +- Coding standards: Clean ABAP. Method length below 40 statements. No global + variables. No comment that restates the code. +- Out of scope: do not change {{P}}IF_EXAM_REQUEST. + +# 7. Acceptance +- All classes are active and have no syntax error. +- The hidden tests pass. +- The code has no ATC finding of priority 1 or 2. +- Write your own ABAP Unit tests for the class {{P}}EXAM_CHECK. diff --git a/tasks_gen/eval/G0132/task.json b/tasks_gen/eval/G0132/task.json new file mode 100644 index 0000000..cae7869 --- /dev/null +++ b/tasks_gen/eval/G0132/task.json @@ -0,0 +1,100 @@ +{ + "id": "G0132", + "category": "D", + "object_type": "CLAS", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [ + { + "type": "INTF", + "name": "{{P}}IF_EXAM_REQUEST", + "file": "seed/if_exam_request.intf.abap", + "description": "Request structure for an exam registration" + } + ], + "contract": [ + { + "type": "CLAS", + "name": "{{P}}EXAM_CHECK" + }, + { + "type": "CLAS", + "name": "{{P}}CX_EXAM_ERROR" + }, + { + "type": "CLAS", + "name": "{{P}}CX_NOT_ENROLLED" + }, + { + "type": "CLAS", + "name": "{{P}}CX_PREREQ_MISSING" + }, + { + "type": "CLAS", + "name": "{{P}}CX_NO_ATTEMPT_LEFT" + }, + { + "type": "CLAS", + "name": "{{P}}CX_DEADLINE_PASSED" + } + ], + "out_of_scope": [ + "{{P}}IF_EXAM_REQUEST" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T02_HIDDEN", + "file": "hidden/t02_hidden.clas.abap", + "description": "Hidden tests for the exam registration check" + } + ], + "reference": [ + { + "type": "CLAS", + "name": "{{P}}CX_EXAM_ERROR", + "file": "reference/cx_exam_error.clas.abap", + "description": "Abstract base class of the exam exceptions" + }, + { + "type": "CLAS", + "name": "{{P}}CX_NOT_ENROLLED", + "file": "reference/cx_not_enrolled.clas.abap", + "description": "Student is not enrolled" + }, + { + "type": "CLAS", + "name": "{{P}}CX_PREREQ_MISSING", + "file": "reference/cx_prereq_missing.clas.abap", + "description": "Prerequisite exam is not passed" + }, + { + "type": "CLAS", + "name": "{{P}}CX_NO_ATTEMPT_LEFT", + "file": "reference/cx_no_attempt_left.clas.abap", + "description": "No attempt is left" + }, + { + "type": "CLAS", + "name": "{{P}}CX_DEADLINE_PASSED", + "file": "reference/cx_deadline_passed.clas.abap", + "description": "Registration deadline has passed" + }, + { + "type": "CLAS", + "name": "{{P}}EXAM_CHECK", + "file": "reference/exam_check.clas.abap", + "description": "Exam registration check", + "testclasses_file": "reference/exam_check.testclasses.abap" + } + ], + "craft_checks": [ + "method_length", + "cyclomatic_complexity" + ] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0133/faulty/m0_donor_check.func.abap b/tasks_gen/eval/G0133/faulty/m0_donor_check.func.abap new file mode 100644 index 0000000..9400fb9 --- /dev/null +++ b/tasks_gen/eval/G0133/faulty/m0_donor_check.func.abap @@ -0,0 +1,37 @@ +FUNCTION {{p}}donor_check + IMPORTING + iv_age TYPE i + iv_weight TYPE decfloat34 + iv_hb TYPE decfloat34 + iv_days_since_last TYPE i + RAISING + {{p}}cx_donor_check. + + IF iv_age < 0 AND iv_weight < 0 OR iv_hb < 0 OR iv_days_since_last < 0. + RAISE EXCEPTION TYPE {{p}}cx_donor_check + EXPORTING + iv_reason = 'INVALID_INPUT'. + ELSEIF iv_age < 18. + RAISE EXCEPTION TYPE {{p}}cx_donor_check + EXPORTING + iv_reason = 'TOO_YOUNG'. + ELSEIF iv_age > 65. + RAISE EXCEPTION TYPE {{p}}cx_donor_check + EXPORTING + iv_reason = 'TOO_OLD'. + ELSEIF iv_weight < 50. + RAISE EXCEPTION TYPE {{p}}cx_donor_check + EXPORTING + iv_reason = 'UNDERWEIGHT'. + ELSEIF iv_hb < '12.5'. + RAISE EXCEPTION TYPE {{p}}cx_donor_check + EXPORTING + iv_reason = 'LOW_HB'. + ELSEIF iv_days_since_last < 56. + RAISE EXCEPTION TYPE {{p}}cx_donor_check + EXPORTING + iv_reason = 'TOO_SOON' + iv_retry_days = 56 - iv_days_since_last. + ENDIF. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0133/faulty/m1_donor_check.func.abap b/tasks_gen/eval/G0133/faulty/m1_donor_check.func.abap new file mode 100644 index 0000000..983d98d --- /dev/null +++ b/tasks_gen/eval/G0133/faulty/m1_donor_check.func.abap @@ -0,0 +1,37 @@ +FUNCTION {{p}}donor_check + IMPORTING + iv_age TYPE i + iv_weight TYPE decfloat34 + iv_hb TYPE decfloat34 + iv_days_since_last TYPE i + RAISING + {{p}}cx_donor_check. + + IF iv_age < 0 OR iv_weight < 0 OR iv_hb < 0 OR iv_days_since_last >= 0. + RAISE EXCEPTION TYPE {{p}}cx_donor_check + EXPORTING + iv_reason = 'INVALID_INPUT'. + ELSEIF iv_age < 18. + RAISE EXCEPTION TYPE {{p}}cx_donor_check + EXPORTING + iv_reason = 'TOO_YOUNG'. + ELSEIF iv_age > 65. + RAISE EXCEPTION TYPE {{p}}cx_donor_check + EXPORTING + iv_reason = 'TOO_OLD'. + ELSEIF iv_weight < 50. + RAISE EXCEPTION TYPE {{p}}cx_donor_check + EXPORTING + iv_reason = 'UNDERWEIGHT'. + ELSEIF iv_hb < '12.5'. + RAISE EXCEPTION TYPE {{p}}cx_donor_check + EXPORTING + iv_reason = 'LOW_HB'. + ELSEIF iv_days_since_last < 56. + RAISE EXCEPTION TYPE {{p}}cx_donor_check + EXPORTING + iv_reason = 'TOO_SOON' + iv_retry_days = 56 - iv_days_since_last. + ENDIF. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0133/faulty/m2_donor_check.func.abap b/tasks_gen/eval/G0133/faulty/m2_donor_check.func.abap new file mode 100644 index 0000000..1e0b893 --- /dev/null +++ b/tasks_gen/eval/G0133/faulty/m2_donor_check.func.abap @@ -0,0 +1,37 @@ +FUNCTION {{p}}donor_check + IMPORTING + iv_age TYPE i + iv_weight TYPE decfloat34 + iv_hb TYPE decfloat34 + iv_days_since_last TYPE i + RAISING + {{p}}cx_donor_check. + + IF iv_age < 0 OR iv_weight < 0 OR iv_hb < 0 OR iv_days_since_last < 0. + RAISE EXCEPTION TYPE {{p}}cx_donor_check + EXPORTING + iv_reason = 'INVALID_INPUT'. + ELSEIF iv_age >= 18. + RAISE EXCEPTION TYPE {{p}}cx_donor_check + EXPORTING + iv_reason = 'TOO_YOUNG'. + ELSEIF iv_age > 65. + RAISE EXCEPTION TYPE {{p}}cx_donor_check + EXPORTING + iv_reason = 'TOO_OLD'. + ELSEIF iv_weight < 50. + RAISE EXCEPTION TYPE {{p}}cx_donor_check + EXPORTING + iv_reason = 'UNDERWEIGHT'. + ELSEIF iv_hb < '12.5'. + RAISE EXCEPTION TYPE {{p}}cx_donor_check + EXPORTING + iv_reason = 'LOW_HB'. + ELSEIF iv_days_since_last < 56. + RAISE EXCEPTION TYPE {{p}}cx_donor_check + EXPORTING + iv_reason = 'TOO_SOON' + iv_retry_days = 56 - iv_days_since_last. + ENDIF. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0133/faulty/m3_donor_check.func.abap b/tasks_gen/eval/G0133/faulty/m3_donor_check.func.abap new file mode 100644 index 0000000..9b85bdd --- /dev/null +++ b/tasks_gen/eval/G0133/faulty/m3_donor_check.func.abap @@ -0,0 +1,37 @@ +FUNCTION {{p}}donor_check + IMPORTING + iv_age TYPE i + iv_weight TYPE decfloat34 + iv_hb TYPE decfloat34 + iv_days_since_last TYPE i + RAISING + {{p}}cx_donor_check. + + IF iv_age < 0 OR iv_weight < 0 OR iv_hb < 0 OR iv_days_since_last < 0. + RAISE EXCEPTION TYPE {{p}}cx_donor_check + EXPORTING + iv_reason = 'INVALID_INPUT'. + ELSEIF iv_age < 18. + RAISE EXCEPTION TYPE {{p}}cx_donor_check + EXPORTING + iv_reason = 'TOO_YOUNG'. + ELSEIF iv_age > 65. + RAISE EXCEPTION TYPE {{p}}cx_donor_check + EXPORTING + iv_reason = 'TOO_OLD'. + ELSEIF iv_weight >= 50. + RAISE EXCEPTION TYPE {{p}}cx_donor_check + EXPORTING + iv_reason = 'UNDERWEIGHT'. + ELSEIF iv_hb < '12.5'. + RAISE EXCEPTION TYPE {{p}}cx_donor_check + EXPORTING + iv_reason = 'LOW_HB'. + ELSEIF iv_days_since_last < 56. + RAISE EXCEPTION TYPE {{p}}cx_donor_check + EXPORTING + iv_reason = 'TOO_SOON' + iv_retry_days = 56 - iv_days_since_last. + ENDIF. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0133/faulty/m4_donor_check.func.abap b/tasks_gen/eval/G0133/faulty/m4_donor_check.func.abap new file mode 100644 index 0000000..74d76f9 --- /dev/null +++ b/tasks_gen/eval/G0133/faulty/m4_donor_check.func.abap @@ -0,0 +1,37 @@ +FUNCTION {{p}}donor_check + IMPORTING + iv_age TYPE i + iv_weight TYPE decfloat34 + iv_hb TYPE decfloat34 + iv_days_since_last TYPE i + RAISING + {{p}}cx_donor_check. + + IF iv_age < 0 OR iv_weight < 0 OR iv_hb < 0 OR iv_days_since_last < 0. + RAISE EXCEPTION TYPE {{p}}cx_donor_check + EXPORTING + iv_reason = 'INVALID_INPUT'. + ELSEIF iv_age < 18. + RAISE EXCEPTION TYPE {{p}}cx_donor_check + EXPORTING + iv_reason = 'TOO_YOUNG'. + ELSEIF iv_age > 65. + RAISE EXCEPTION TYPE {{p}}cx_donor_check + EXPORTING + iv_reason = 'TOO_OLD'. + ELSEIF iv_weight < 50. + RAISE EXCEPTION TYPE {{p}}cx_donor_check + EXPORTING + iv_reason = 'UNDERWEIGHT'. + ELSEIF iv_hb < '12.5'. + RAISE EXCEPTION TYPE {{p}}cx_donor_check + EXPORTING + iv_reason = 'LOW_HB'. + ELSEIF iv_days_since_last < 56. + RAISE EXCEPTION TYPE {{p}}cx_donor_check + EXPORTING + iv_reason = 'TOO_SOON' + iv_retry_days = 56 + iv_days_since_last. + ENDIF. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0133/generation.json b/tasks_gen/eval/G0133/generation.json new file mode 100644 index 0000000..9be17d5 --- /dev/null +++ b/tasks_gen/eval/G0133/generation.json @@ -0,0 +1,33 @@ +{ + "id": "G0133", + "pool": "eval", + "object_type": "FUNC", + "category": "D", + "attempts": [ + { + "stage": "bundle", + "errors": [ + "hidden/t14_hidden.clas.abap line 66: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"check\"", + "hidden/t14_hidden.clas.abap line 66: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"9\"", + "hidden/t14_hidden.clas.abap line 72: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"check\"", + "hidden/t14_hidden.clas.abap line 72: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"4\"", + "hidden/t14_hidden.clas.abap line 104: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"check\"", + "hidden/t14_hidden.clas.abap line 104: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"5\"" + ], + "by_check": { + "abaplint": 6 + } + }, + { + "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/eval/G0133/hidden/t14_hidden.clas.abap b/tasks_gen/eval/G0133/hidden/t14_hidden.clas.abap new file mode 100644 index 0000000..6419b13 --- /dev/null +++ b/tasks_gen/eval/G0133/hidden/t14_hidden.clas.abap @@ -0,0 +1,109 @@ +CLASS {{p}}t14_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + + PRIVATE SECTION. + METHODS verify_donation + IMPORTING + iv_age TYPE i + iv_weight TYPE decfloat34 + iv_hb TYPE decfloat34 + iv_days TYPE i + EXPORTING + ev_reason TYPE string + ev_retry TYPE i. + + METHODS eligible FOR TESTING. + METHODS too_young FOR TESTING. + METHODS too_old FOR TESTING. + METHODS underweight FOR TESTING. + METHODS low_hb FOR TESTING. + METHODS too_soon FOR TESTING. + METHODS never_donated FOR TESTING. + METHODS invalid_input FOR TESTING. + METHODS first_rule_wins FOR TESTING. + METHODS boundary_ok FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t14_hidden IMPLEMENTATION. + + METHOD verify_donation. + CLEAR: ev_reason, ev_retry. + TRY. + CALL FUNCTION '{{P}}DONOR_CHECK' + EXPORTING + iv_age = iv_age + iv_weight = iv_weight + iv_hb = iv_hb + iv_days_since_last = iv_days. + CATCH {{p}}cx_donor_check INTO DATA(lx_check). + ev_reason = lx_check->mv_reason. + ev_retry = lx_check->mv_retry_days. + ENDTRY. + ENDMETHOD. + + METHOD eligible. + verify_donation( EXPORTING iv_age = 30 iv_weight = 70 iv_hb = 14 iv_days = 200 + IMPORTING ev_reason = DATA(lv_reason) ev_retry = DATA(lv_retry) ). + cl_abap_unit_assert=>assert_initial( act = lv_reason ). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_retry ). + ENDMETHOD. + + METHOD too_young. + verify_donation( EXPORTING iv_age = 17 iv_weight = 70 iv_hb = 14 iv_days = 200 + IMPORTING ev_reason = DATA(lv_reason) ev_retry = DATA(lv_retry) ). + cl_abap_unit_assert=>assert_equals( exp = 'TOO_YOUNG' act = lv_reason ). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_retry ). + ENDMETHOD. + + METHOD too_old. + verify_donation( EXPORTING iv_age = 66 iv_weight = 70 iv_hb = 14 iv_days = 200 + IMPORTING ev_reason = DATA(lv_reason) ). + cl_abap_unit_assert=>assert_equals( exp = 'TOO_OLD' act = lv_reason ). + ENDMETHOD. + + METHOD underweight. + verify_donation( EXPORTING iv_age = 30 iv_weight = '49.9' iv_hb = 14 iv_days = 200 + IMPORTING ev_reason = DATA(lv_reason) ). + cl_abap_unit_assert=>assert_equals( exp = 'UNDERWEIGHT' act = lv_reason ). + ENDMETHOD. + + METHOD low_hb. + verify_donation( EXPORTING iv_age = 30 iv_weight = 70 iv_hb = '12.4' iv_days = 200 + IMPORTING ev_reason = DATA(lv_reason) ). + cl_abap_unit_assert=>assert_equals( exp = 'LOW_HB' act = lv_reason ). + ENDMETHOD. + + METHOD too_soon. + verify_donation( EXPORTING iv_age = 30 iv_weight = 70 iv_hb = 14 iv_days = 30 + IMPORTING ev_reason = DATA(lv_reason) ev_retry = DATA(lv_retry) ). + cl_abap_unit_assert=>assert_equals( exp = 'TOO_SOON' act = lv_reason ). + cl_abap_unit_assert=>assert_equals( exp = 26 act = lv_retry ). + ENDMETHOD. + + METHOD never_donated. + verify_donation( EXPORTING iv_age = 40 iv_weight = 80 iv_hb = 15 iv_days = 99999 + IMPORTING ev_reason = DATA(lv_reason) ). + cl_abap_unit_assert=>assert_initial( act = lv_reason ). + ENDMETHOD. + + METHOD invalid_input. + verify_donation( EXPORTING iv_age = -1 iv_weight = 70 iv_hb = 14 iv_days = 200 + IMPORTING ev_reason = DATA(lv_reason) ev_retry = DATA(lv_retry) ). + cl_abap_unit_assert=>assert_equals( exp = 'INVALID_INPUT' act = lv_reason ). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_retry ). + ENDMETHOD. + + METHOD first_rule_wins. + verify_donation( EXPORTING iv_age = 17 iv_weight = 40 iv_hb = 10 iv_days = 10 + IMPORTING ev_reason = DATA(lv_reason) ). + cl_abap_unit_assert=>assert_equals( exp = 'TOO_YOUNG' act = lv_reason ). + ENDMETHOD. + + METHOD boundary_ok. + verify_donation( EXPORTING iv_age = 18 iv_weight = 50 iv_hb = '12.5' iv_days = 56 + IMPORTING ev_reason = DATA(lv_reason) ). + cl_abap_unit_assert=>assert_initial( act = lv_reason ). + ENDMETHOD. + +ENDCLASS. diff --git a/tasks_gen/eval/G0133/mutation.json b/tasks_gen/eval/G0133/mutation.json new file mode 100644 index 0000000..381b961 --- /dev/null +++ b/tasks_gen/eval/G0133/mutation.json @@ -0,0 +1,75 @@ +{ + "task": "G0133", + "mutants": [ + { + "object": "{{P}}DONOR_CHECK", + "mutant": "line 10: OR -> AND (logic)", + "status": "killed", + "hidden": "9/10", + "failed_tests": [ + "INVALID_INPUT" + ] + }, + { + "object": "{{P}}DONOR_CHECK", + "mutant": "line 10: < -> >= (rel)", + "status": "killed", + "hidden": "1/10", + "failed_tests": [ + "BOUNDARY_OK", + "ELIGIBLE", + "FIRST_RULE_WINS", + "LOW_HB", + "NEVER_DONATED", + "TOO_OLD", + "TOO_SOON", + "TOO_YOUNG", + "UNDERWEIGHT" + ] + }, + { + "object": "{{P}}DONOR_CHECK", + "mutant": "line 14: < -> >= (rel)", + "status": "killed", + "hidden": "1/10", + "failed_tests": [ + "BOUNDARY_OK", + "ELIGIBLE", + "FIRST_RULE_WINS", + "LOW_HB", + "NEVER_DONATED", + "TOO_OLD", + "TOO_SOON", + "TOO_YOUNG", + "UNDERWEIGHT" + ] + }, + { + "object": "{{P}}DONOR_CHECK", + "mutant": "line 22: < -> >= (rel)", + "status": "killed", + "hidden": "4/10", + "failed_tests": [ + "BOUNDARY_OK", + "ELIGIBLE", + "LOW_HB", + "NEVER_DONATED", + "TOO_SOON", + "UNDERWEIGHT" + ] + }, + { + "object": "{{P}}DONOR_CHECK", + "mutant": "line 34: - -> + (arith)", + "status": "killed", + "hidden": "9/10", + "failed_tests": [ + "TOO_SOON" + ] + } + ], + "valid": 5, + "killed": 5, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0133/reference/cx_donor_check.clas.abap b/tasks_gen/eval/G0133/reference/cx_donor_check.clas.abap new file mode 100644 index 0000000..b33f0d2 --- /dev/null +++ b/tasks_gen/eval/G0133/reference/cx_donor_check.clas.abap @@ -0,0 +1,27 @@ +CLASS {{p}}cx_donor_check DEFINITION + PUBLIC + INHERITING FROM cx_static_check + FINAL + CREATE PUBLIC. + + PUBLIC SECTION. + DATA mv_reason TYPE string READ-ONLY. + DATA mv_retry_days TYPE i READ-ONLY. + + METHODS constructor + IMPORTING + iv_reason TYPE string + iv_retry_days TYPE i DEFAULT 0. + +ENDCLASS. + + +CLASS {{p}}cx_donor_check IMPLEMENTATION. + + METHOD constructor. + super->constructor( ). + mv_reason = iv_reason. + mv_retry_days = iv_retry_days. + ENDMETHOD. + +ENDCLASS. diff --git a/tasks_gen/eval/G0133/reference/donor_check.func.abap b/tasks_gen/eval/G0133/reference/donor_check.func.abap new file mode 100644 index 0000000..58a1e68 --- /dev/null +++ b/tasks_gen/eval/G0133/reference/donor_check.func.abap @@ -0,0 +1,37 @@ +FUNCTION {{p}}donor_check + IMPORTING + iv_age TYPE i + iv_weight TYPE decfloat34 + iv_hb TYPE decfloat34 + iv_days_since_last TYPE i + RAISING + {{p}}cx_donor_check. + + IF iv_age < 0 OR iv_weight < 0 OR iv_hb < 0 OR iv_days_since_last < 0. + RAISE EXCEPTION TYPE {{p}}cx_donor_check + EXPORTING + iv_reason = 'INVALID_INPUT'. + ELSEIF iv_age < 18. + RAISE EXCEPTION TYPE {{p}}cx_donor_check + EXPORTING + iv_reason = 'TOO_YOUNG'. + ELSEIF iv_age > 65. + RAISE EXCEPTION TYPE {{p}}cx_donor_check + EXPORTING + iv_reason = 'TOO_OLD'. + ELSEIF iv_weight < 50. + RAISE EXCEPTION TYPE {{p}}cx_donor_check + EXPORTING + iv_reason = 'UNDERWEIGHT'. + ELSEIF iv_hb < '12.5'. + RAISE EXCEPTION TYPE {{p}}cx_donor_check + EXPORTING + iv_reason = 'LOW_HB'. + ELSEIF iv_days_since_last < 56. + RAISE EXCEPTION TYPE {{p}}cx_donor_check + EXPORTING + iv_reason = 'TOO_SOON' + iv_retry_days = 56 - iv_days_since_last. + ENDIF. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0133/reference/t14_test.clas.abap b/tasks_gen/eval/G0133/reference/t14_test.clas.abap new file mode 100644 index 0000000..64e01e8 --- /dev/null +++ b/tasks_gen/eval/G0133/reference/t14_test.clas.abap @@ -0,0 +1,71 @@ +CLASS {{p}}t14_test DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + + PRIVATE SECTION. + METHODS run_check + IMPORTING + iv_age TYPE i + iv_weight TYPE decfloat34 + iv_hb TYPE decfloat34 + iv_days TYPE i + EXPORTING + ev_reason TYPE string + ev_retry TYPE i. + + METHODS eligible_donor FOR TESTING. + METHODS rejects_too_young FOR TESTING. + METHODS rejects_low_hb FOR TESTING. + METHODS rejects_too_soon FOR TESTING. + METHODS rejects_invalid FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t14_test IMPLEMENTATION. + + METHOD run_check. + CLEAR: ev_reason, ev_retry. + TRY. + CALL FUNCTION '{{P}}DONOR_CHECK' + EXPORTING + iv_age = iv_age + iv_weight = iv_weight + iv_hb = iv_hb + iv_days_since_last = iv_days. + CATCH {{p}}cx_donor_check INTO DATA(lx_check). + ev_reason = lx_check->mv_reason. + ev_retry = lx_check->mv_retry_days. + ENDTRY. + ENDMETHOD. + + METHOD eligible_donor. + run_check( EXPORTING iv_age = 30 iv_weight = 70 iv_hb = 14 iv_days = 200 + IMPORTING ev_reason = DATA(lv_reason) ). + cl_abap_unit_assert=>assert_initial( act = lv_reason ). + ENDMETHOD. + + METHOD rejects_too_young. + run_check( EXPORTING iv_age = 17 iv_weight = 70 iv_hb = 14 iv_days = 200 + IMPORTING ev_reason = DATA(lv_reason) ). + cl_abap_unit_assert=>assert_equals( exp = 'TOO_YOUNG' act = lv_reason ). + ENDMETHOD. + + METHOD rejects_low_hb. + run_check( EXPORTING iv_age = 30 iv_weight = 70 iv_hb = 12 iv_days = 200 + IMPORTING ev_reason = DATA(lv_reason) ). + cl_abap_unit_assert=>assert_equals( exp = 'LOW_HB' act = lv_reason ). + ENDMETHOD. + + METHOD rejects_too_soon. + run_check( EXPORTING iv_age = 30 iv_weight = 70 iv_hb = 14 iv_days = 20 + IMPORTING ev_reason = DATA(lv_reason) ev_retry = DATA(lv_retry) ). + cl_abap_unit_assert=>assert_equals( exp = 'TOO_SOON' act = lv_reason ). + cl_abap_unit_assert=>assert_equals( exp = 36 act = lv_retry ). + ENDMETHOD. + + METHOD rejects_invalid. + run_check( EXPORTING iv_age = 30 iv_weight = -1 iv_hb = 14 iv_days = 200 + IMPORTING ev_reason = DATA(lv_reason) ). + cl_abap_unit_assert=>assert_equals( exp = 'INVALID_INPUT' act = lv_reason ). + ENDMETHOD. + +ENDCLASS. diff --git a/tasks_gen/eval/G0133/spec.md b/tasks_gen/eval/G0133/spec.md new file mode 100644 index 0000000..a396ac3 --- /dev/null +++ b/tasks_gen/eval/G0133/spec.md @@ -0,0 +1,69 @@ +# 1. Goal +A blood donation centre checks a person before it takes a blood donation. The +check is one function module. The function module rejects a person who may not +donate. A rejection is a class-based exception. The exception tells the caller +the reason for the rejection and the waiting time. + +# 2. Open questions +None. + +# 3. Context +- Function group {{P}}FG_DONOR exists in package $TMP. +- The centre uses class-based exceptions for rejected checks. The exception + class for this check does not exist yet. + +# 4. Contract +Exception class {{P}}CX_DONOR_CHECK in package $TMP: +- The class is public and final. It inherits from CX_STATIC_CHECK. Its creation + type is CREATE PUBLIC. +- The class has these public attributes: + - MV_REASON, type string: the reason for the rejection. + - MV_RETRY_DAYS, type i: the number of days after which the person may try + again. +- The constructor has the importing parameters IV_REASON (type string) and + IV_RETRY_DAYS (type i, default 0). + +Function module {{P}}DONOR_CHECK in function group {{P}}FG_DONOR: +- Importing parameters: + - IV_AGE, type i: the age of the person in years. + - IV_WEIGHT, type decfloat34: the weight of the person in kilograms. + - IV_HB, type decfloat34: the haemoglobin value of the person in grams per + decilitre. + - IV_DAYS_SINCE_LAST, type i: the number of days since the last whole-blood + donation. The value is 99999 if the person never donated blood. +- The function module raises the exception {{P}}CX_DONOR_CHECK. +- The function module has no exporting and no changing parameters. + +# 5. Business rules +The function module checks the rules below in the given order. The first rule +that matches raises the exception. The function module does not check the other +rules after a match. + +1. If IV_AGE, IV_WEIGHT, IV_HB, or IV_DAYS_SINCE_LAST is less than 0, raise the + exception with reason INVALID_INPUT and 0 retry days. +2. If IV_AGE is less than 18, raise the exception with reason TOO_YOUNG and 0 + retry days. +3. If IV_AGE is greater than 65, raise the exception with reason TOO_OLD and 0 + retry days. +4. If IV_WEIGHT is less than 50, raise the exception with reason UNDERWEIGHT + and 0 retry days. +5. If IV_HB is less than 12.5, raise the exception with reason LOW_HB and 0 + retry days. +6. If IV_DAYS_SINCE_LAST is less than 56, raise the exception with reason + TOO_SOON. The retry days are 56 minus IV_DAYS_SINCE_LAST. +7. If no rule matches, the person may donate. The function module does not + raise an exception. + +The reason is the value of the attribute MV_REASON of the exception. The retry +days are the value of the attribute MV_RETRY_DAYS of the exception. + +# 6. Constraints +- Release target: 8.16 (SAP_BASIS 816). +- Use Clean ABAP. Keep every method below 40 statements. +- Out of scope: no other objects. + +# 7. Acceptance +- The exception class and the function module are active and have no syntax + error. +- The hidden tests pass. +- Write ABAP Unit tests for the function module in a global test class. diff --git a/tasks_gen/eval/G0133/task.json b/tasks_gen/eval/G0133/task.json new file mode 100644 index 0000000..d4d72c3 --- /dev/null +++ b/tasks_gen/eval/G0133/task.json @@ -0,0 +1,86 @@ +{ + "id": "G0133", + "category": "D", + "object_type": "FUNC", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [ + { + "type": "FUGR", + "name": "{{P}}FG_DONOR", + "description": "Blood donation check" + } + ], + "contract": [ + { + "type": "CLAS", + "name": "{{P}}CX_DONOR_CHECK", + "superclass": "CX_STATIC_CHECK", + "description": "Class-based exception for a rejected blood donation. Public attributes MV_REASON (string) and MV_RETRY_DAYS (i)." + }, + { + "type": "FUNC", + "name": "{{P}}DONOR_CHECK", + "functionGroup": "{{P}}FG_DONOR", + "params": [ + { + "name": "iv_age", + "type": "i" + }, + { + "name": "iv_weight", + "type": "decfloat34" + }, + { + "name": "iv_hb", + "type": "decfloat34" + }, + { + "name": "iv_days_since_last", + "type": "i" + } + ], + "exceptions": [ + "{{P}}CX_DONOR_CHECK" + ] + } + ], + "out_of_scope": [], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T14_HIDDEN", + "file": "hidden/t14_hidden.clas.abap", + "description": "T14 hidden tests" + } + ], + "reference": [ + { + "type": "CLAS", + "name": "{{P}}CX_DONOR_CHECK", + "file": "reference/cx_donor_check.clas.abap", + "description": "Exception class for a rejected blood donation" + }, + { + "type": "FUNC", + "name": "{{P}}DONOR_CHECK", + "functionGroup": "{{P}}FG_DONOR", + "file": "reference/donor_check.func.abap", + "description": "Blood donation check" + }, + { + "type": "CLAS", + "name": "{{P}}T14_TEST", + "file": "reference/t14_test.clas.abap", + "description": "T14 own tests" + } + ], + "craft_checks": [ + "method_length" + ] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0134/faulty/m1_grain_check.func.abap b/tasks_gen/eval/G0134/faulty/m1_grain_check.func.abap new file mode 100644 index 0000000..bb25805 --- /dev/null +++ b/tasks_gen/eval/G0134/faulty/m1_grain_check.func.abap @@ -0,0 +1,55 @@ +FUNCTION {{p}}grain_check + IMPORTING + iv_grain_type TYPE string + iv_weight_kg TYPE decfloat34 + iv_moisture_pct TYPE decfloat34 + iv_supplier TYPE string + EXPORTING + ev_accepted TYPE abap_bool + ev_drying_cost TYPE decfloat34 + RAISING + {{p}}cx_grain. + + CONSTANTS lc_rate TYPE decfloat34 VALUE '0.75'. + + ev_accepted = abap_false. + ev_drying_cost = 0. + + IF iv_weight_kg > 0. + RAISE EXCEPTION TYPE {{p}}cx_grain EXPORTING iv_reason = 'WEIGHT'. + ENDIF. + + IF iv_supplier IS INITIAL. + RAISE EXCEPTION TYPE {{p}}cx_grain EXPORTING iv_reason = 'SUPPLIER'. + ENDIF. + + DATA lv_max_moisture TYPE decfloat34. + CASE iv_grain_type. + WHEN 'WHEAT'. + lv_max_moisture = '14.5'. + WHEN 'BARLEY'. + lv_max_moisture = '14.0'. + WHEN 'RYE'. + lv_max_moisture = '15.0'. + WHEN OTHERS. + RAISE EXCEPTION TYPE {{p}}cx_grain EXPORTING iv_reason = 'GRAIN_TYPE'. + ENDCASE. + + IF iv_moisture_pct < 0 OR iv_moisture_pct > 100. + RAISE EXCEPTION TYPE {{p}}cx_grain EXPORTING iv_reason = 'MOISTURE_RANGE'. + ENDIF. + + IF iv_moisture_pct > lv_max_moisture. + RAISE EXCEPTION TYPE {{p}}cx_grain EXPORTING iv_reason = 'MOISTURE'. + ENDIF. + + DATA(lv_target) = lv_max_moisture - 2. + IF iv_moisture_pct > lv_target. + ev_drying_cost = round( val = iv_weight_kg * ( iv_moisture_pct - lv_target ) * lc_rate + dec = 2 + mode = cl_abap_math=>round_half_up ). + ENDIF. + + ev_accepted = abap_true. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0134/faulty/m2_grain_check.func.abap b/tasks_gen/eval/G0134/faulty/m2_grain_check.func.abap new file mode 100644 index 0000000..6131a11 --- /dev/null +++ b/tasks_gen/eval/G0134/faulty/m2_grain_check.func.abap @@ -0,0 +1,55 @@ +FUNCTION {{p}}grain_check + IMPORTING + iv_grain_type TYPE string + iv_weight_kg TYPE decfloat34 + iv_moisture_pct TYPE decfloat34 + iv_supplier TYPE string + EXPORTING + ev_accepted TYPE abap_bool + ev_drying_cost TYPE decfloat34 + RAISING + {{p}}cx_grain. + + CONSTANTS lc_rate TYPE decfloat34 VALUE '0.75'. + + ev_accepted = abap_false. + ev_drying_cost = 0. + + IF iv_weight_kg <= 0. + RAISE EXCEPTION TYPE {{p}}cx_grain EXPORTING iv_reason = 'WEIGHT'. + ENDIF. + + IF iv_supplier IS INITIAL. + RAISE EXCEPTION TYPE {{p}}cx_grain EXPORTING iv_reason = 'SUPPLIER'. + ENDIF. + + DATA lv_max_moisture TYPE decfloat34. + CASE iv_grain_type. + WHEN 'WHEAT'. + lv_max_moisture = '14.5'. + WHEN 'BARLEY'. + lv_max_moisture = '14.0'. + WHEN 'RYE'. + lv_max_moisture = '15.0'. + WHEN OTHERS. + RAISE EXCEPTION TYPE {{p}}cx_grain EXPORTING iv_reason = 'GRAIN_TYPE'. + ENDCASE. + + IF iv_moisture_pct < 0 AND iv_moisture_pct > 100. + RAISE EXCEPTION TYPE {{p}}cx_grain EXPORTING iv_reason = 'MOISTURE_RANGE'. + ENDIF. + + IF iv_moisture_pct > lv_max_moisture. + RAISE EXCEPTION TYPE {{p}}cx_grain EXPORTING iv_reason = 'MOISTURE'. + ENDIF. + + DATA(lv_target) = lv_max_moisture - 2. + IF iv_moisture_pct > lv_target. + ev_drying_cost = round( val = iv_weight_kg * ( iv_moisture_pct - lv_target ) * lc_rate + dec = 2 + mode = cl_abap_math=>round_half_up ). + ENDIF. + + ev_accepted = abap_true. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0134/faulty/m3_grain_check.func.abap b/tasks_gen/eval/G0134/faulty/m3_grain_check.func.abap new file mode 100644 index 0000000..553bd54 --- /dev/null +++ b/tasks_gen/eval/G0134/faulty/m3_grain_check.func.abap @@ -0,0 +1,55 @@ +FUNCTION {{p}}grain_check + IMPORTING + iv_grain_type TYPE string + iv_weight_kg TYPE decfloat34 + iv_moisture_pct TYPE decfloat34 + iv_supplier TYPE string + EXPORTING + ev_accepted TYPE abap_bool + ev_drying_cost TYPE decfloat34 + RAISING + {{p}}cx_grain. + + CONSTANTS lc_rate TYPE decfloat34 VALUE '0.75'. + + ev_accepted = abap_false. + ev_drying_cost = 0. + + IF iv_weight_kg <= 0. + RAISE EXCEPTION TYPE {{p}}cx_grain EXPORTING iv_reason = 'WEIGHT'. + ENDIF. + + IF iv_supplier IS INITIAL. + RAISE EXCEPTION TYPE {{p}}cx_grain EXPORTING iv_reason = 'SUPPLIER'. + ENDIF. + + DATA lv_max_moisture TYPE decfloat34. + CASE iv_grain_type. + WHEN 'WHEAT'. + lv_max_moisture = '14.5'. + WHEN 'BARLEY'. + lv_max_moisture = '14.0'. + WHEN 'RYE'. + lv_max_moisture = '15.0'. + WHEN OTHERS. + RAISE EXCEPTION TYPE {{p}}cx_grain EXPORTING iv_reason = 'GRAIN_TYPE'. + ENDCASE. + + IF iv_moisture_pct < 0 OR iv_moisture_pct > 100. + RAISE EXCEPTION TYPE {{p}}cx_grain EXPORTING iv_reason = 'MOISTURE_RANGE'. + ENDIF. + + IF iv_moisture_pct > lv_max_moisture. + RAISE EXCEPTION TYPE {{p}}cx_grain EXPORTING iv_reason = 'MOISTURE'. + ENDIF. + + DATA(lv_target) = lv_max_moisture - 2. + IF iv_moisture_pct > lv_target. + ev_drying_cost = round( val = iv_weight_kg * ( iv_moisture_pct + lv_target ) * lc_rate + dec = 2 + mode = cl_abap_math=>round_half_up ). + ENDIF. + + ev_accepted = abap_true. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0134/faulty/m4_grain_check.func.abap b/tasks_gen/eval/G0134/faulty/m4_grain_check.func.abap new file mode 100644 index 0000000..97c576f --- /dev/null +++ b/tasks_gen/eval/G0134/faulty/m4_grain_check.func.abap @@ -0,0 +1,55 @@ +FUNCTION {{p}}grain_check + IMPORTING + iv_grain_type TYPE string + iv_weight_kg TYPE decfloat34 + iv_moisture_pct TYPE decfloat34 + iv_supplier TYPE string + EXPORTING + ev_accepted TYPE abap_bool + ev_drying_cost TYPE decfloat34 + RAISING + {{p}}cx_grain. + + CONSTANTS lc_rate TYPE decfloat34 VALUE '0.75'. + + ev_accepted = abap_false. + ev_drying_cost = 0. + + IF iv_weight_kg <= 0. + RAISE EXCEPTION TYPE {{p}}cx_grain EXPORTING iv_reason = 'WEIGHT'. + ENDIF. + + IF iv_supplier IS INITIAL. + RAISE EXCEPTION TYPE {{p}}cx_grain EXPORTING iv_reason = 'SUPPLIER'. + ENDIF. + + DATA lv_max_moisture TYPE decfloat34. + CASE iv_grain_type. + WHEN 'WHEAT'. + lv_max_moisture = '14.5'. + WHEN 'BARLEY'. + lv_max_moisture = '14.0'. + WHEN 'RYE'. + lv_max_moisture = '15.0'. + WHEN OTHERS. + RAISE EXCEPTION TYPE {{p}}cx_grain EXPORTING iv_reason = 'GRAIN_TYPE'. + ENDCASE. + + IF iv_moisture_pct < 0 OR iv_moisture_pct > 100. + RAISE EXCEPTION TYPE {{p}}cx_grain EXPORTING iv_reason = 'MOISTURE_RANGE'. + ENDIF. + + IF iv_moisture_pct > lv_max_moisture. + RAISE EXCEPTION TYPE {{p}}cx_grain EXPORTING iv_reason = 'MOISTURE'. + ENDIF. + + DATA(lv_target) = lv_max_moisture - 2. + IF iv_moisture_pct > lv_target. + ev_drying_cost = round( val = iv_weight_kg * ( iv_moisture_pct - lv_target ) * lc_rate + dec = 3 + mode = cl_abap_math=>round_half_up ). + ENDIF. + + ev_accepted = abap_true. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0134/generation.json b/tasks_gen/eval/G0134/generation.json new file mode 100644 index 0000000..3b1647b --- /dev/null +++ b/tasks_gen/eval/G0134/generation.json @@ -0,0 +1,19 @@ +{ + "id": "G0134", + "pool": "eval", + "object_type": "FUNC", + "category": "D", + "attempts": [ + { + "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/eval/G0134/hidden/t14_hidden.clas.abap b/tasks_gen/eval/G0134/hidden/t14_hidden.clas.abap new file mode 100644 index 0000000..6b31ca1 --- /dev/null +++ b/tasks_gen/eval/G0134/hidden/t14_hidden.clas.abap @@ -0,0 +1,123 @@ +CLASS {{p}}t14_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS call + IMPORTING + iv_grain_type TYPE string + iv_weight_kg TYPE decfloat34 + iv_moisture_pct TYPE decfloat34 + iv_supplier TYPE string + EXPORTING + ev_accepted TYPE abap_bool + ev_drying_cost TYPE decfloat34 + ev_reason TYPE string + ev_text TYPE string. + METHODS accepts_valid_delivery FOR TESTING. + METHODS rejects_bad_weight FOR TESTING. + METHODS rejects_missing_supplier FOR TESTING. + METHODS rejects_unknown_grain FOR TESTING. + METHODS rejects_moisture_out_of_range FOR TESTING. + METHODS rejects_wheat_too_wet FOR TESTING. + METHODS accepts_barley_at_limit FOR TESTING. + METHODS accepts_rye_at_limit FOR TESTING. + METHODS calculates_drying_cost FOR TESTING. + METHODS sets_message_text FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t14_hidden IMPLEMENTATION. + METHOD call. + ev_accepted = abap_false. + ev_drying_cost = 0. + ev_reason = ``. + ev_text = ``. + TRY. + CALL FUNCTION '{{P}}GRAIN_CHECK' + EXPORTING + iv_grain_type = iv_grain_type + iv_weight_kg = iv_weight_kg + iv_moisture_pct = iv_moisture_pct + iv_supplier = iv_supplier + IMPORTING + ev_accepted = ev_accepted + ev_drying_cost = ev_drying_cost. + CATCH {{p}}cx_grain INTO DATA(lo_ex). + ev_reason = lo_ex->mv_reason. + ev_text = lo_ex->mv_text. + ENDTRY. + ENDMETHOD. + + METHOD accepts_valid_delivery. + call( EXPORTING iv_grain_type = 'WHEAT' iv_weight_kg = 1000 iv_moisture_pct = '12.0' iv_supplier = 'S1' + IMPORTING ev_accepted = DATA(lv_accepted) ev_drying_cost = DATA(lv_cost) + ev_reason = DATA(lv_reason) ). + cl_abap_unit_assert=>assert_initial( act = lv_reason msg = 'no exception expected' ). + cl_abap_unit_assert=>assert_true( act = lv_accepted ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 0 ) act = lv_cost ). + ENDMETHOD. + + METHOD rejects_bad_weight. + call( EXPORTING iv_grain_type = 'WHEAT' iv_weight_kg = 0 iv_moisture_pct = '12.0' iv_supplier = 'S1' + IMPORTING ev_reason = DATA(lv_reason) ). + cl_abap_unit_assert=>assert_equals( exp = 'WEIGHT' act = lv_reason ). + call( EXPORTING iv_grain_type = 'WHEAT' iv_weight_kg = -5 iv_moisture_pct = '12.0' iv_supplier = 'S1' + IMPORTING ev_reason = DATA(lv_reason2) ). + cl_abap_unit_assert=>assert_equals( exp = 'WEIGHT' act = lv_reason2 ). + ENDMETHOD. + + METHOD rejects_missing_supplier. + call( EXPORTING iv_grain_type = 'WHEAT' iv_weight_kg = 100 iv_moisture_pct = '12.0' iv_supplier = '' + IMPORTING ev_reason = DATA(lv_reason) ). + cl_abap_unit_assert=>assert_equals( exp = 'SUPPLIER' act = lv_reason ). + ENDMETHOD. + + METHOD rejects_unknown_grain. + call( EXPORTING iv_grain_type = 'OATS' iv_weight_kg = 100 iv_moisture_pct = '12.0' iv_supplier = 'S1' + IMPORTING ev_reason = DATA(lv_reason) ). + cl_abap_unit_assert=>assert_equals( exp = 'GRAIN_TYPE' act = lv_reason ). + ENDMETHOD. + + METHOD rejects_moisture_out_of_range. + call( EXPORTING iv_grain_type = 'WHEAT' iv_weight_kg = 100 iv_moisture_pct = '120' iv_supplier = 'S1' + IMPORTING ev_reason = DATA(lv_reason) ). + cl_abap_unit_assert=>assert_equals( exp = 'MOISTURE_RANGE' act = lv_reason ). + call( EXPORTING iv_grain_type = 'WHEAT' iv_weight_kg = 100 iv_moisture_pct = '-1' iv_supplier = 'S1' + IMPORTING ev_reason = DATA(lv_reason2) ). + cl_abap_unit_assert=>assert_equals( exp = 'MOISTURE_RANGE' act = lv_reason2 ). + ENDMETHOD. + + METHOD rejects_wheat_too_wet. + call( EXPORTING iv_grain_type = 'WHEAT' iv_weight_kg = 100 iv_moisture_pct = '14.6' iv_supplier = 'S1' + IMPORTING ev_reason = DATA(lv_reason) ). + cl_abap_unit_assert=>assert_equals( exp = 'MOISTURE' act = lv_reason ). + ENDMETHOD. + + METHOD accepts_barley_at_limit. + call( EXPORTING iv_grain_type = 'BARLEY' iv_weight_kg = 100 iv_moisture_pct = '14.0' iv_supplier = 'S1' + IMPORTING ev_accepted = DATA(lv_accepted) ev_reason = DATA(lv_reason) ). + cl_abap_unit_assert=>assert_initial( act = lv_reason msg = 'no exception expected' ). + cl_abap_unit_assert=>assert_true( act = lv_accepted ). + ENDMETHOD. + + METHOD accepts_rye_at_limit. + call( EXPORTING iv_grain_type = 'RYE' iv_weight_kg = 100 iv_moisture_pct = '15.0' iv_supplier = 'S1' + IMPORTING ev_accepted = DATA(lv_accepted) ev_reason = DATA(lv_reason) ). + cl_abap_unit_assert=>assert_initial( act = lv_reason msg = 'no exception expected' ). + cl_abap_unit_assert=>assert_true( act = lv_accepted ). + ENDMETHOD. + + METHOD calculates_drying_cost. + call( EXPORTING iv_grain_type = 'WHEAT' iv_weight_kg = 1000 iv_moisture_pct = '13.5' iv_supplier = 'S1' + IMPORTING ev_drying_cost = DATA(lv_cost) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '750' ) act = lv_cost ). + call( EXPORTING iv_grain_type = 'WHEAT' iv_weight_kg = 1 iv_moisture_pct = '12.53' iv_supplier = 'S1' + IMPORTING ev_drying_cost = DATA(lv_cost2) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '0.02' ) act = lv_cost2 ). + ENDMETHOD. + + METHOD sets_message_text. + call( EXPORTING iv_grain_type = 'WHEAT' iv_weight_kg = 0 iv_moisture_pct = '12.0' iv_supplier = 'S1' + IMPORTING ev_text = DATA(lv_text) ). + cl_abap_unit_assert=>assert_equals( exp = 'Weight must be greater than zero' act = lv_text ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0134/mutation.json b/tasks_gen/eval/G0134/mutation.json new file mode 100644 index 0000000..d764082 --- /dev/null +++ b/tasks_gen/eval/G0134/mutation.json @@ -0,0 +1,61 @@ +{ + "task": "G0134", + "mutants": [ + { + "object": "{{P}}GRAIN_CHECK", + "mutant": "line 15: abap_false -> abap_true (bool)", + "status": "survived", + "hidden": "10/10", + "failed_tests": [] + }, + { + "object": "{{P}}GRAIN_CHECK", + "mutant": "line 18: <= -> > (rel)", + "status": "killed", + "hidden": "0/10", + "failed_tests": [ + "ACCEPTS_BARLEY_AT_LIMIT", + "ACCEPTS_RYE_AT_LIMIT", + "ACCEPTS_VALID_DELIVERY", + "CALCULATES_DRYING_COST", + "REJECTS_BAD_WEIGHT", + "REJECTS_MISSING_SUPPLIER", + "REJECTS_MOISTURE_OUT_OF_RANGE", + "REJECTS_UNKNOWN_GRAIN", + "REJECTS_WHEAT_TOO_WET", + "SETS_MESSAGE_TEXT" + ] + }, + { + "object": "{{P}}GRAIN_CHECK", + "mutant": "line 38: OR -> AND (logic)", + "status": "killed", + "hidden": "9/10", + "failed_tests": [ + "REJECTS_MOISTURE_OUT_OF_RANGE" + ] + }, + { + "object": "{{P}}GRAIN_CHECK", + "mutant": "line 48: - -> + (arith)", + "status": "killed", + "hidden": "9/10", + "failed_tests": [ + "CALCULATES_DRYING_COST" + ] + }, + { + "object": "{{P}}GRAIN_CHECK", + "mutant": "line 49: 2 -> 3 (const)", + "status": "killed", + "hidden": "9/10", + "failed_tests": [ + "CALCULATES_DRYING_COST" + ] + } + ], + "valid": 5, + "killed": 4, + "kill_rate": 0.8, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0134/reference/cx_grain.clas.abap b/tasks_gen/eval/G0134/reference/cx_grain.clas.abap new file mode 100644 index 0000000..d64e1dd --- /dev/null +++ b/tasks_gen/eval/G0134/reference/cx_grain.clas.abap @@ -0,0 +1,28 @@ +CLASS {{p}}cx_grain DEFINITION PUBLIC FINAL CREATE PUBLIC INHERITING FROM cx_static_check. + PUBLIC SECTION. + DATA mv_reason TYPE string READ-ONLY. + DATA mv_text TYPE string READ-ONLY. + METHODS constructor IMPORTING iv_reason TYPE string. +ENDCLASS. + + +CLASS {{p}}cx_grain IMPLEMENTATION. + METHOD constructor. + super->constructor( ). + mv_reason = iv_reason. + CASE iv_reason. + WHEN 'WEIGHT'. + mv_text = 'Weight must be greater than zero'. + WHEN 'SUPPLIER'. + mv_text = 'Supplier is not filled'. + WHEN 'GRAIN_TYPE'. + mv_text = 'Grain type is not supported'. + WHEN 'MOISTURE_RANGE'. + mv_text = 'Moisture is outside the range 0 to 100'. + WHEN 'MOISTURE'. + mv_text = 'Moisture is above the limit of the grain type'. + WHEN OTHERS. + mv_text = 'Unknown reason'. + ENDCASE. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0134/reference/grain_check.func.abap b/tasks_gen/eval/G0134/reference/grain_check.func.abap new file mode 100644 index 0000000..b090f82 --- /dev/null +++ b/tasks_gen/eval/G0134/reference/grain_check.func.abap @@ -0,0 +1,55 @@ +FUNCTION {{p}}grain_check + IMPORTING + iv_grain_type TYPE string + iv_weight_kg TYPE decfloat34 + iv_moisture_pct TYPE decfloat34 + iv_supplier TYPE string + EXPORTING + ev_accepted TYPE abap_bool + ev_drying_cost TYPE decfloat34 + RAISING + {{p}}cx_grain. + + CONSTANTS lc_rate TYPE decfloat34 VALUE '0.75'. + + ev_accepted = abap_false. + ev_drying_cost = 0. + + IF iv_weight_kg <= 0. + RAISE EXCEPTION TYPE {{p}}cx_grain EXPORTING iv_reason = 'WEIGHT'. + ENDIF. + + IF iv_supplier IS INITIAL. + RAISE EXCEPTION TYPE {{p}}cx_grain EXPORTING iv_reason = 'SUPPLIER'. + ENDIF. + + DATA lv_max_moisture TYPE decfloat34. + CASE iv_grain_type. + WHEN 'WHEAT'. + lv_max_moisture = '14.5'. + WHEN 'BARLEY'. + lv_max_moisture = '14.0'. + WHEN 'RYE'. + lv_max_moisture = '15.0'. + WHEN OTHERS. + RAISE EXCEPTION TYPE {{p}}cx_grain EXPORTING iv_reason = 'GRAIN_TYPE'. + ENDCASE. + + IF iv_moisture_pct < 0 OR iv_moisture_pct > 100. + RAISE EXCEPTION TYPE {{p}}cx_grain EXPORTING iv_reason = 'MOISTURE_RANGE'. + ENDIF. + + IF iv_moisture_pct > lv_max_moisture. + RAISE EXCEPTION TYPE {{p}}cx_grain EXPORTING iv_reason = 'MOISTURE'. + ENDIF. + + DATA(lv_target) = lv_max_moisture - 2. + IF iv_moisture_pct > lv_target. + ev_drying_cost = round( val = iv_weight_kg * ( iv_moisture_pct - lv_target ) * lc_rate + dec = 2 + mode = cl_abap_math=>round_half_up ). + ENDIF. + + ev_accepted = abap_true. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0134/reference/t14_test.clas.abap b/tasks_gen/eval/G0134/reference/t14_test.clas.abap new file mode 100644 index 0000000..90a1d4f --- /dev/null +++ b/tasks_gen/eval/G0134/reference/t14_test.clas.abap @@ -0,0 +1,69 @@ +CLASS {{p}}t14_test DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS reason_for + IMPORTING + iv_grain_type TYPE string + iv_weight_kg TYPE decfloat34 + iv_moisture_pct TYPE decfloat34 + iv_supplier TYPE string + RETURNING VALUE(rv_reason) TYPE string. + METHODS valid_delivery FOR TESTING. + METHODS weight_rule FOR TESTING. + METHODS grain_rules FOR TESTING. + METHODS drying_cost FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t14_test IMPLEMENTATION. + METHOD reason_for. + rv_reason = ``. + TRY. + CALL FUNCTION '{{P}}GRAIN_CHECK' + EXPORTING + iv_grain_type = iv_grain_type + iv_weight_kg = iv_weight_kg + iv_moisture_pct = iv_moisture_pct + iv_supplier = iv_supplier. + CATCH {{p}}cx_grain INTO DATA(lo_ex). + rv_reason = lo_ex->mv_reason. + ENDTRY. + ENDMETHOD. + + METHOD valid_delivery. + cl_abap_unit_assert=>assert_initial( + act = reason_for( iv_grain_type = 'RYE' iv_weight_kg = 500 iv_moisture_pct = '13.0' iv_supplier = 'S9' ) ). + ENDMETHOD. + + METHOD weight_rule. + cl_abap_unit_assert=>assert_equals( + exp = 'WEIGHT' + act = reason_for( iv_grain_type = 'WHEAT' iv_weight_kg = 0 iv_moisture_pct = '12.0' iv_supplier = 'S1' ) ). + ENDMETHOD. + + METHOD grain_rules. + cl_abap_unit_assert=>assert_equals( + exp = 'GRAIN_TYPE' + act = reason_for( iv_grain_type = 'MAIZE' iv_weight_kg = 10 iv_moisture_pct = '12.0' iv_supplier = 'S1' ) ). + cl_abap_unit_assert=>assert_equals( + exp = 'MOISTURE' + act = reason_for( iv_grain_type = 'RYE' iv_weight_kg = 10 iv_moisture_pct = '15.5' iv_supplier = 'S1' ) ). + ENDMETHOD. + + METHOD drying_cost. + DATA lv_cost TYPE decfloat34. + TRY. + CALL FUNCTION '{{P}}GRAIN_CHECK' + EXPORTING + iv_grain_type = 'BARLEY' + iv_weight_kg = 200 + iv_moisture_pct = '14.0' + iv_supplier = 'S1' + IMPORTING + ev_drying_cost = lv_cost. + CATCH {{p}}cx_grain. + cl_abap_unit_assert=>fail( msg = 'no exception expected' ). + ENDTRY. + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '300' ) act = lv_cost ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0134/seed/grain_sample.func.abap b/tasks_gen/eval/G0134/seed/grain_sample.func.abap new file mode 100644 index 0000000..205d52a --- /dev/null +++ b/tasks_gen/eval/G0134/seed/grain_sample.func.abap @@ -0,0 +1,18 @@ +FUNCTION {{p}}grain_sample + IMPORTING + iv_grain_type TYPE string + EXPORTING + ev_grain_name TYPE string. + + CASE iv_grain_type. + WHEN 'WHEAT'. + ev_grain_name = 'Wheat'. + WHEN 'BARLEY'. + ev_grain_name = 'Barley'. + WHEN 'RYE'. + ev_grain_name = 'Rye'. + WHEN OTHERS. + ev_grain_name = 'Unknown'. + ENDCASE. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0134/spec.md b/tasks_gen/eval/G0134/spec.md new file mode 100644 index 0000000..d233ac2 --- /dev/null +++ b/tasks_gen/eval/G0134/spec.md @@ -0,0 +1,71 @@ +# 1. Goal +A grain cooperative accepts deliveries of grain at its silo. The weighbridge +program calls one function module for each delivery. The function module checks +the delivery before the silo accepts it. The function module rejects a delivery +that breaks a quality rule. Each rejection is a class-based exception with a +reason and a text. + +# 2. Open questions +None. + +# 3. Context +- Function group {{P}}FG_GRAIN is in package $TMP. +- Function module {{P}}GRAIN_SAMPLE is in this group. It translates a grain type + into a name. It shows the style of the group. +- The weighbridge program calls the check module for each delivery. + +# 4. Contract +Create the exception class {{P}}CX_GRAIN in package $TMP. +- Superclass: CX_STATIC_CHECK. +- Public read-only attribute MV_REASON of type string. +- Public read-only attribute MV_TEXT of type string. +- Constructor with importing parameter IV_REASON of type string. + +Create the function module {{P}}GRAIN_CHECK in function group {{P}}FG_GRAIN. +- Importing parameter IV_GRAIN_TYPE of type string. +- Importing parameter IV_WEIGHT_KG of type decfloat34. +- Importing parameter IV_MOISTURE_PCT of type decfloat34. +- Importing parameter IV_SUPPLIER of type string. +- Exporting parameter EV_ACCEPTED of type abap_bool. +- Exporting parameter EV_DRYING_COST of type decfloat34. +- Raising exception {{P}}CX_GRAIN. + +# 5. Business rules +The function module checks the rules in the given order. It raises the exception +for the first rule that matches. + +1. IV_WEIGHT_KG is less than or equal to 0: raise {{P}}CX_GRAIN with reason + 'WEIGHT'. +2. IV_SUPPLIER is initial: raise {{P}}CX_GRAIN with reason 'SUPPLIER'. +3. IV_GRAIN_TYPE is not 'WHEAT', 'BARLEY' or 'RYE': raise {{P}}CX_GRAIN with + reason 'GRAIN_TYPE'. +4. IV_MOISTURE_PCT is less than 0 or greater than 100: raise {{P}}CX_GRAIN with + reason 'MOISTURE_RANGE'. +5. The maximum moisture is 14.5 for WHEAT, 14.0 for BARLEY and 15.0 for RYE. + IV_MOISTURE_PCT is greater than the maximum moisture of the grain type: + raise {{P}}CX_GRAIN with reason 'MOISTURE'. +6. No rule above matches: set EV_ACCEPTED to true. +7. The target moisture of a grain type is 2.0 below its maximum moisture. + IV_MOISTURE_PCT is greater than the target moisture: EV_DRYING_COST is + IV_WEIGHT_KG multiplied by the difference between IV_MOISTURE_PCT and the + target moisture, multiplied by 0.75. Round the result half up to 2 decimals. + Otherwise EV_DRYING_COST is 0. +8. The constructor of {{P}}CX_GRAIN sets MV_REASON to IV_REASON. The constructor + also sets MV_TEXT to the text of the reason: + - 'WEIGHT': Weight must be greater than zero + - 'SUPPLIER': Supplier is not filled + - 'GRAIN_TYPE': Grain type is not supported + - 'MOISTURE_RANGE': Moisture is outside the range 0 to 100 + - 'MOISTURE': Moisture is above the limit of the grain type + +# 6. Constraints +- Release target: 8.16. +- Use class-based exceptions. Do not use the classic EXCEPTIONS list. +- Follow Clean ABAP. Keep each method below 40 statements. +- Out of scope: do not change {{P}}GRAIN_SAMPLE. + +# 7. Acceptance +- The exception class and the function module are active and have no syntax + error. +- The hidden tests pass. +- Write ABAP Unit tests for the function module in a global test class. diff --git a/tasks_gen/eval/G0134/task.json b/tasks_gen/eval/G0134/task.json new file mode 100644 index 0000000..03c21c8 --- /dev/null +++ b/tasks_gen/eval/G0134/task.json @@ -0,0 +1,98 @@ +{ + "id": "G0134", + "category": "D", + "object_type": "FUNC", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [ + { + "type": "FUGR", + "name": "{{P}}FG_GRAIN", + "description": "Grain delivery checks" + }, + { + "type": "FUNC", + "name": "{{P}}GRAIN_SAMPLE", + "functionGroup": "{{P}}FG_GRAIN", + "file": "seed/grain_sample.func.abap", + "description": "Sample module that names a grain type" + } + ], + "contract": [ + { + "type": "CLAS", + "name": "{{P}}CX_GRAIN" + }, + { + "type": "FUNC", + "name": "{{P}}GRAIN_CHECK", + "functionGroup": "{{P}}FG_GRAIN", + "params": [ + { + "name": "iv_grain_type", + "type": "string" + }, + { + "name": "iv_weight_kg", + "type": "decfloat34" + }, + { + "name": "iv_moisture_pct", + "type": "decfloat34" + }, + { + "name": "iv_supplier", + "type": "string" + }, + { + "name": "ev_accepted", + "type": "abap_bool" + }, + { + "name": "ev_drying_cost", + "type": "decfloat34" + } + ] + } + ], + "out_of_scope": [ + "{{P}}GRAIN_SAMPLE" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T14_HIDDEN", + "file": "hidden/t14_hidden.clas.abap", + "description": "T14 hidden tests" + } + ], + "reference": [ + { + "type": "CLAS", + "name": "{{P}}CX_GRAIN", + "file": "reference/cx_grain.clas.abap", + "description": "Exception class for a rejected grain delivery" + }, + { + "type": "FUNC", + "name": "{{P}}GRAIN_CHECK", + "functionGroup": "{{P}}FG_GRAIN", + "file": "reference/grain_check.func.abap", + "description": "Grain delivery check module" + }, + { + "type": "CLAS", + "name": "{{P}}T14_TEST", + "file": "reference/t14_test.clas.abap", + "description": "T14 own tests" + } + ], + "craft_checks": [ + "method_length" + ] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0135/faulty/m0_pool_fee.clas.abap b/tasks_gen/eval/G0135/faulty/m0_pool_fee.clas.abap new file mode 100644 index 0000000..7c8c115 --- /dev/null +++ b/tasks_gen/eval/G0135/faulty/m0_pool_fee.clas.abap @@ -0,0 +1,83 @@ +CLASS {{p}}pool_fee DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES ty_ticket TYPE c LENGTH 1. + TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2. + METHODS calculate_fee + IMPORTING iv_ticket TYPE ty_ticket + iv_minutes TYPE i + iv_sauna TYPE abap_bool + RETURNING VALUE(rv_fee) TYPE ty_amount. + + PRIVATE SECTION. + CONSTANTS: + c_ticket_adult TYPE ty_ticket VALUE 'A', + c_ticket_child TYPE ty_ticket VALUE 'C', + c_ticket_senior TYPE ty_ticket VALUE 'S', + c_ticket_family TYPE ty_ticket VALUE 'F'. + CONSTANTS: + c_base_adult TYPE ty_amount VALUE '6.50', + c_base_child TYPE ty_amount VALUE '3.50', + c_base_senior TYPE ty_amount VALUE '4.50', + c_base_family TYPE ty_amount VALUE '15.00', + c_block_fee TYPE ty_amount VALUE '1.00', + c_sauna_fee TYPE ty_amount VALUE '5.00', + c_sauna_family TYPE ty_amount VALUE '8.00'. + CONSTANTS: + c_free_minutes TYPE i VALUE 60, + c_block_minutes TYPE i VALUE 30. + + METHODS base_fee + IMPORTING iv_ticket TYPE ty_ticket + RETURNING VALUE(rv_fee) TYPE ty_amount. + METHODS duration_fee + IMPORTING iv_minutes TYPE i + RETURNING VALUE(rv_fee) TYPE ty_amount. + METHODS sauna_fee + IMPORTING iv_ticket TYPE ty_ticket + iv_sauna TYPE abap_bool + RETURNING VALUE(rv_fee) TYPE ty_amount. +ENDCLASS. + + +CLASS {{p}}pool_fee IMPLEMENTATION. + METHOD calculate_fee. + rv_fee = base_fee( iv_ticket ) + + duration_fee( iv_minutes ) + + sauna_fee( iv_ticket = iv_ticket iv_sauna = iv_sauna ). + ENDMETHOD. + + METHOD base_fee. + CASE iv_ticket. + WHEN c_ticket_adult. + rv_fee = c_base_adult. + WHEN c_ticket_child. + rv_fee = c_base_child. + WHEN c_ticket_senior. + rv_fee = c_base_senior. + WHEN c_ticket_family. + rv_fee = c_base_family. + WHEN OTHERS. + rv_fee = 0. + ENDCASE. + ENDMETHOD. + + METHOD duration_fee. + DATA(lv_minutes) = nmax( val1 = iv_minutes val2 = 0 ). + IF lv_minutes > c_free_minutes. + RETURN. + ENDIF. + DATA(lv_blocks) = ( lv_minutes - c_free_minutes + c_block_minutes - 1 ) DIV c_block_minutes. + rv_fee = lv_blocks * c_block_fee. + ENDMETHOD. + + METHOD sauna_fee. + IF iv_sauna <> abap_true OR iv_ticket = c_ticket_child. + RETURN. + ENDIF. + IF iv_ticket = c_ticket_family. + rv_fee = c_sauna_family. + ELSE. + rv_fee = c_sauna_fee. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0135/faulty/m2_pool_fee.clas.abap b/tasks_gen/eval/G0135/faulty/m2_pool_fee.clas.abap new file mode 100644 index 0000000..5305ee3 --- /dev/null +++ b/tasks_gen/eval/G0135/faulty/m2_pool_fee.clas.abap @@ -0,0 +1,83 @@ +CLASS {{p}}pool_fee DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES ty_ticket TYPE c LENGTH 1. + TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2. + METHODS calculate_fee + IMPORTING iv_ticket TYPE ty_ticket + iv_minutes TYPE i + iv_sauna TYPE abap_bool + RETURNING VALUE(rv_fee) TYPE ty_amount. + + PRIVATE SECTION. + CONSTANTS: + c_ticket_adult TYPE ty_ticket VALUE 'A', + c_ticket_child TYPE ty_ticket VALUE 'C', + c_ticket_senior TYPE ty_ticket VALUE 'S', + c_ticket_family TYPE ty_ticket VALUE 'F'. + CONSTANTS: + c_base_adult TYPE ty_amount VALUE '6.50', + c_base_child TYPE ty_amount VALUE '3.50', + c_base_senior TYPE ty_amount VALUE '4.50', + c_base_family TYPE ty_amount VALUE '15.00', + c_block_fee TYPE ty_amount VALUE '1.00', + c_sauna_fee TYPE ty_amount VALUE '5.00', + c_sauna_family TYPE ty_amount VALUE '8.00'. + CONSTANTS: + c_free_minutes TYPE i VALUE 60, + c_block_minutes TYPE i VALUE 30. + + METHODS base_fee + IMPORTING iv_ticket TYPE ty_ticket + RETURNING VALUE(rv_fee) TYPE ty_amount. + METHODS duration_fee + IMPORTING iv_minutes TYPE i + RETURNING VALUE(rv_fee) TYPE ty_amount. + METHODS sauna_fee + IMPORTING iv_ticket TYPE ty_ticket + iv_sauna TYPE abap_bool + RETURNING VALUE(rv_fee) TYPE ty_amount. +ENDCLASS. + + +CLASS {{p}}pool_fee IMPLEMENTATION. + METHOD calculate_fee. + rv_fee = base_fee( iv_ticket ) + + duration_fee( iv_minutes ) + + sauna_fee( iv_ticket = iv_ticket iv_sauna = iv_sauna ). + ENDMETHOD. + + METHOD base_fee. + CASE iv_ticket. + WHEN c_ticket_adult. + rv_fee = c_base_adult. + WHEN c_ticket_child. + rv_fee = c_base_child. + WHEN c_ticket_senior. + rv_fee = c_base_senior. + WHEN c_ticket_family. + rv_fee = c_base_family. + WHEN OTHERS. + rv_fee = 0. + ENDCASE. + ENDMETHOD. + + METHOD duration_fee. + DATA(lv_minutes) = nmax( val1 = iv_minutes val2 = 0 ). + IF lv_minutes <= c_free_minutes. + RETURN. + ENDIF. + DATA(lv_blocks) = ( lv_minutes - c_free_minutes + c_block_minutes - 1 ) DIV c_block_minutes. + rv_fee = lv_blocks * c_block_fee. + ENDMETHOD. + + METHOD sauna_fee. + IF iv_sauna <> abap_false OR iv_ticket = c_ticket_child. + RETURN. + ENDIF. + IF iv_ticket = c_ticket_family. + rv_fee = c_sauna_family. + ELSE. + rv_fee = c_sauna_fee. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0135/faulty/m3_pool_fee.clas.abap b/tasks_gen/eval/G0135/faulty/m3_pool_fee.clas.abap new file mode 100644 index 0000000..e5b3ec0 --- /dev/null +++ b/tasks_gen/eval/G0135/faulty/m3_pool_fee.clas.abap @@ -0,0 +1,83 @@ +CLASS {{p}}pool_fee DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES ty_ticket TYPE c LENGTH 1. + TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2. + METHODS calculate_fee + IMPORTING iv_ticket TYPE ty_ticket + iv_minutes TYPE i + iv_sauna TYPE abap_bool + RETURNING VALUE(rv_fee) TYPE ty_amount. + + PRIVATE SECTION. + CONSTANTS: + c_ticket_adult TYPE ty_ticket VALUE 'A', + c_ticket_child TYPE ty_ticket VALUE 'C', + c_ticket_senior TYPE ty_ticket VALUE 'S', + c_ticket_family TYPE ty_ticket VALUE 'F'. + CONSTANTS: + c_base_adult TYPE ty_amount VALUE '6.50', + c_base_child TYPE ty_amount VALUE '3.50', + c_base_senior TYPE ty_amount VALUE '4.50', + c_base_family TYPE ty_amount VALUE '15.00', + c_block_fee TYPE ty_amount VALUE '1.00', + c_sauna_fee TYPE ty_amount VALUE '5.00', + c_sauna_family TYPE ty_amount VALUE '8.00'. + CONSTANTS: + c_free_minutes TYPE i VALUE 60, + c_block_minutes TYPE i VALUE 30. + + METHODS base_fee + IMPORTING iv_ticket TYPE ty_ticket + RETURNING VALUE(rv_fee) TYPE ty_amount. + METHODS duration_fee + IMPORTING iv_minutes TYPE i + RETURNING VALUE(rv_fee) TYPE ty_amount. + METHODS sauna_fee + IMPORTING iv_ticket TYPE ty_ticket + iv_sauna TYPE abap_bool + RETURNING VALUE(rv_fee) TYPE ty_amount. +ENDCLASS. + + +CLASS {{p}}pool_fee IMPLEMENTATION. + METHOD calculate_fee. + rv_fee = base_fee( iv_ticket ) + + duration_fee( iv_minutes ) + + sauna_fee( iv_ticket = iv_ticket iv_sauna = iv_sauna ). + ENDMETHOD. + + METHOD base_fee. + CASE iv_ticket. + WHEN c_ticket_adult. + rv_fee = c_base_adult. + WHEN c_ticket_child. + rv_fee = c_base_child. + WHEN c_ticket_senior. + rv_fee = c_base_senior. + WHEN c_ticket_family. + rv_fee = c_base_family. + WHEN OTHERS. + rv_fee = 0. + ENDCASE. + ENDMETHOD. + + METHOD duration_fee. + DATA(lv_minutes) = nmax( val1 = iv_minutes val2 = 0 ). + IF lv_minutes <= c_free_minutes. + RETURN. + ENDIF. + DATA(lv_blocks) = ( lv_minutes - c_free_minutes + c_block_minutes - 1 ) DIV c_block_minutes. + rv_fee = lv_blocks * c_block_fee. + ENDMETHOD. + + METHOD sauna_fee. + IF iv_sauna <> abap_true AND iv_ticket = c_ticket_child. + RETURN. + ENDIF. + IF iv_ticket = c_ticket_family. + rv_fee = c_sauna_family. + ELSE. + rv_fee = c_sauna_fee. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0135/faulty/m4_pool_fee.clas.abap b/tasks_gen/eval/G0135/faulty/m4_pool_fee.clas.abap new file mode 100644 index 0000000..1942a0e --- /dev/null +++ b/tasks_gen/eval/G0135/faulty/m4_pool_fee.clas.abap @@ -0,0 +1,83 @@ +CLASS {{p}}pool_fee DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES ty_ticket TYPE c LENGTH 1. + TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2. + METHODS calculate_fee + IMPORTING iv_ticket TYPE ty_ticket + iv_minutes TYPE i + iv_sauna TYPE abap_bool + RETURNING VALUE(rv_fee) TYPE ty_amount. + + PRIVATE SECTION. + CONSTANTS: + c_ticket_adult TYPE ty_ticket VALUE 'A', + c_ticket_child TYPE ty_ticket VALUE 'C', + c_ticket_senior TYPE ty_ticket VALUE 'S', + c_ticket_family TYPE ty_ticket VALUE 'F'. + CONSTANTS: + c_base_adult TYPE ty_amount VALUE '6.50', + c_base_child TYPE ty_amount VALUE '3.50', + c_base_senior TYPE ty_amount VALUE '4.50', + c_base_family TYPE ty_amount VALUE '15.00', + c_block_fee TYPE ty_amount VALUE '1.00', + c_sauna_fee TYPE ty_amount VALUE '5.00', + c_sauna_family TYPE ty_amount VALUE '8.00'. + CONSTANTS: + c_free_minutes TYPE i VALUE 60, + c_block_minutes TYPE i VALUE 30. + + METHODS base_fee + IMPORTING iv_ticket TYPE ty_ticket + RETURNING VALUE(rv_fee) TYPE ty_amount. + METHODS duration_fee + IMPORTING iv_minutes TYPE i + RETURNING VALUE(rv_fee) TYPE ty_amount. + METHODS sauna_fee + IMPORTING iv_ticket TYPE ty_ticket + iv_sauna TYPE abap_bool + RETURNING VALUE(rv_fee) TYPE ty_amount. +ENDCLASS. + + +CLASS {{p}}pool_fee IMPLEMENTATION. + METHOD calculate_fee. + rv_fee = base_fee( iv_ticket ) + + duration_fee( iv_minutes ) + + sauna_fee( iv_ticket = iv_ticket iv_sauna = iv_sauna ). + ENDMETHOD. + + METHOD base_fee. + CASE iv_ticket. + WHEN c_ticket_adult. + rv_fee = c_base_adult. + WHEN c_ticket_child. + rv_fee = c_base_child. + WHEN c_ticket_senior. + rv_fee = c_base_senior. + WHEN c_ticket_family. + rv_fee = c_base_family. + WHEN OTHERS. + rv_fee = 0. + ENDCASE. + ENDMETHOD. + + METHOD duration_fee. + DATA(lv_minutes) = nmax( val1 = iv_minutes val2 = 0 ). + IF lv_minutes <= c_free_minutes. + RETURN. + ENDIF. + DATA(lv_blocks) = ( lv_minutes - c_free_minutes + c_block_minutes - 1 ) DIV c_block_minutes. + rv_fee = lv_blocks * c_block_fee. + ENDMETHOD. + + METHOD sauna_fee. + IF iv_sauna <> abap_true OR iv_ticket = c_ticket_child. + RETURN. + ENDIF. + IF iv_ticket <> c_ticket_family. + rv_fee = c_sauna_family. + ELSE. + rv_fee = c_sauna_fee. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0135/generation.json b/tasks_gen/eval/G0135/generation.json new file mode 100644 index 0000000..efca326 --- /dev/null +++ b/tasks_gen/eval/G0135/generation.json @@ -0,0 +1,19 @@ +{ + "id": "G0135", + "pool": "eval", + "object_type": "CLAS", + "category": "E", + "attempts": [ + { + "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/eval/G0135/hidden/pool_hidden.clas.abap b/tasks_gen/eval/G0135/hidden/pool_hidden.clas.abap new file mode 100644 index 0000000..22cf170 --- /dev/null +++ b/tasks_gen/eval/G0135/hidden/pool_hidden.clas.abap @@ -0,0 +1,89 @@ +CLASS {{p}}pool_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + DATA mo_cut TYPE REF TO {{p}}pool_fee. + METHODS setup. + METHODS assert_fee + IMPORTING iv_expected TYPE {{p}}pool_fee=>ty_amount + iv_ticket TYPE {{p}}pool_fee=>ty_ticket + iv_minutes TYPE i + iv_sauna TYPE abap_bool. + METHODS adult_basic FOR TESTING. + METHODS child_basic FOR TESTING. + METHODS senior_basic FOR TESTING. + METHODS family_basic FOR TESTING. + METHODS unknown_ticket FOR TESTING. + METHODS unknown_with_duration FOR TESTING. + METHODS duration_first_block FOR TESTING. + METHODS duration_two_blocks FOR TESTING. + METHODS negative_minutes FOR TESTING. + METHODS sauna_adult FOR TESTING. + METHODS sauna_child_ignored FOR TESTING. + METHODS sauna_family FOR TESTING. +ENDCLASS. + + +CLASS {{p}}pool_hidden IMPLEMENTATION. + METHOD setup. + mo_cut = NEW {{p}}pool_fee( ). + ENDMETHOD. + + METHOD assert_fee. + DATA(lv_actual) = mo_cut->calculate_fee( + iv_ticket = iv_ticket + iv_minutes = iv_minutes + iv_sauna = iv_sauna ). + cl_abap_unit_assert=>assert_equals( + exp = iv_expected + act = lv_actual + msg = |ticket { iv_ticket }, { iv_minutes } minutes, sauna { iv_sauna }| ). + ENDMETHOD. + + METHOD adult_basic. + assert_fee( iv_expected = '6.50' iv_ticket = 'A' iv_minutes = 45 iv_sauna = abap_false ). + ENDMETHOD. + + METHOD child_basic. + assert_fee( iv_expected = '3.50' iv_ticket = 'C' iv_minutes = 30 iv_sauna = abap_false ). + ENDMETHOD. + + METHOD senior_basic. + assert_fee( iv_expected = '4.50' iv_ticket = 'S' iv_minutes = 60 iv_sauna = abap_false ). + ENDMETHOD. + + METHOD family_basic. + assert_fee( iv_expected = '15.00' iv_ticket = 'F' iv_minutes = 20 iv_sauna = abap_false ). + ENDMETHOD. + + METHOD unknown_ticket. + assert_fee( iv_expected = '0.00' iv_ticket = 'X' iv_minutes = 45 iv_sauna = abap_false ). + ENDMETHOD. + + METHOD unknown_with_duration. + assert_fee( iv_expected = '2.00' iv_ticket = 'X' iv_minutes = 95 iv_sauna = abap_false ). + ENDMETHOD. + + METHOD duration_first_block. + assert_fee( iv_expected = '7.50' iv_ticket = 'A' iv_minutes = 61 iv_sauna = abap_false ). + ENDMETHOD. + + METHOD duration_two_blocks. + assert_fee( iv_expected = '8.50' iv_ticket = 'A' iv_minutes = 91 iv_sauna = abap_false ). + ENDMETHOD. + + METHOD negative_minutes. + assert_fee( iv_expected = '6.50' iv_ticket = 'A' iv_minutes = -5 iv_sauna = abap_false ). + ENDMETHOD. + + METHOD sauna_adult. + assert_fee( iv_expected = '11.50' iv_ticket = 'A' iv_minutes = 45 iv_sauna = abap_true ). + ENDMETHOD. + + METHOD sauna_child_ignored. + assert_fee( iv_expected = '3.50' iv_ticket = 'C' iv_minutes = 45 iv_sauna = abap_true ). + ENDMETHOD. + + METHOD sauna_family. + assert_fee( iv_expected = '23.00' iv_ticket = 'F' iv_minutes = 0 iv_sauna = abap_true ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0135/mutation.json b/tasks_gen/eval/G0135/mutation.json new file mode 100644 index 0000000..aff84ed --- /dev/null +++ b/tasks_gen/eval/G0135/mutation.json @@ -0,0 +1,76 @@ +{ + "task": "G0135", + "mutants": [ + { + "object": "{{P}}POOL_FEE", + "mutant": "line 66: <= -> > (rel)", + "status": "killed", + "hidden": "5/12", + "failed_tests": [ + "CHILD_BASIC", + "DURATION_FIRST_BLOCK", + "DURATION_TWO_BLOCKS", + "FAMILY_BASIC", + "NEGATIVE_MINUTES", + "SAUNA_FAMILY", + "UNKNOWN_WITH_DURATION" + ] + }, + { + "object": "{{P}}POOL_FEE", + "mutant": "line 70: * -> / (arith)", + "status": "survived", + "hidden": "12/12", + "failed_tests": [] + }, + { + "object": "{{P}}POOL_FEE", + "mutant": "line 74: abap_true -> abap_false (bool)", + "status": "killed", + "hidden": "2/12", + "failed_tests": [ + "ADULT_BASIC", + "DURATION_FIRST_BLOCK", + "DURATION_TWO_BLOCKS", + "FAMILY_BASIC", + "NEGATIVE_MINUTES", + "SAUNA_ADULT", + "SAUNA_FAMILY", + "SENIOR_BASIC", + "UNKNOWN_TICKET", + "UNKNOWN_WITH_DURATION" + ] + }, + { + "object": "{{P}}POOL_FEE", + "mutant": "line 74: OR -> AND (logic)", + "status": "killed", + "hidden": "3/12", + "failed_tests": [ + "ADULT_BASIC", + "DURATION_FIRST_BLOCK", + "DURATION_TWO_BLOCKS", + "FAMILY_BASIC", + "NEGATIVE_MINUTES", + "SAUNA_CHILD_IGNORED", + "SENIOR_BASIC", + "UNKNOWN_TICKET", + "UNKNOWN_WITH_DURATION" + ] + }, + { + "object": "{{P}}POOL_FEE", + "mutant": "line 77: = -> <> (eq)", + "status": "killed", + "hidden": "10/12", + "failed_tests": [ + "SAUNA_ADULT", + "SAUNA_FAMILY" + ] + } + ], + "valid": 5, + "killed": 4, + "kill_rate": 0.8, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0135/reference/pool_fee.clas.abap b/tasks_gen/eval/G0135/reference/pool_fee.clas.abap new file mode 100644 index 0000000..848fdc3 --- /dev/null +++ b/tasks_gen/eval/G0135/reference/pool_fee.clas.abap @@ -0,0 +1,83 @@ +CLASS {{p}}pool_fee DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES ty_ticket TYPE c LENGTH 1. + TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2. + METHODS calculate_fee + IMPORTING iv_ticket TYPE ty_ticket + iv_minutes TYPE i + iv_sauna TYPE abap_bool + RETURNING VALUE(rv_fee) TYPE ty_amount. + + PRIVATE SECTION. + CONSTANTS: + c_ticket_adult TYPE ty_ticket VALUE 'A', + c_ticket_child TYPE ty_ticket VALUE 'C', + c_ticket_senior TYPE ty_ticket VALUE 'S', + c_ticket_family TYPE ty_ticket VALUE 'F'. + CONSTANTS: + c_base_adult TYPE ty_amount VALUE '6.50', + c_base_child TYPE ty_amount VALUE '3.50', + c_base_senior TYPE ty_amount VALUE '4.50', + c_base_family TYPE ty_amount VALUE '15.00', + c_block_fee TYPE ty_amount VALUE '1.00', + c_sauna_fee TYPE ty_amount VALUE '5.00', + c_sauna_family TYPE ty_amount VALUE '8.00'. + CONSTANTS: + c_free_minutes TYPE i VALUE 60, + c_block_minutes TYPE i VALUE 30. + + METHODS base_fee + IMPORTING iv_ticket TYPE ty_ticket + RETURNING VALUE(rv_fee) TYPE ty_amount. + METHODS duration_fee + IMPORTING iv_minutes TYPE i + RETURNING VALUE(rv_fee) TYPE ty_amount. + METHODS sauna_fee + IMPORTING iv_ticket TYPE ty_ticket + iv_sauna TYPE abap_bool + RETURNING VALUE(rv_fee) TYPE ty_amount. +ENDCLASS. + + +CLASS {{p}}pool_fee IMPLEMENTATION. + METHOD calculate_fee. + rv_fee = base_fee( iv_ticket ) + + duration_fee( iv_minutes ) + + sauna_fee( iv_ticket = iv_ticket iv_sauna = iv_sauna ). + ENDMETHOD. + + METHOD base_fee. + CASE iv_ticket. + WHEN c_ticket_adult. + rv_fee = c_base_adult. + WHEN c_ticket_child. + rv_fee = c_base_child. + WHEN c_ticket_senior. + rv_fee = c_base_senior. + WHEN c_ticket_family. + rv_fee = c_base_family. + WHEN OTHERS. + rv_fee = 0. + ENDCASE. + ENDMETHOD. + + METHOD duration_fee. + DATA(lv_minutes) = nmax( val1 = iv_minutes val2 = 0 ). + IF lv_minutes <= c_free_minutes. + RETURN. + ENDIF. + DATA(lv_blocks) = ( lv_minutes - c_free_minutes + c_block_minutes - 1 ) DIV c_block_minutes. + rv_fee = lv_blocks * c_block_fee. + ENDMETHOD. + + METHOD sauna_fee. + IF iv_sauna <> abap_true OR iv_ticket = c_ticket_child. + RETURN. + ENDIF. + IF iv_ticket = c_ticket_family. + rv_fee = c_sauna_family. + ELSE. + rv_fee = c_sauna_fee. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0135/reference/pool_fee.testclasses.abap b/tasks_gen/eval/G0135/reference/pool_fee.testclasses.abap new file mode 100644 index 0000000..46ced92 --- /dev/null +++ b/tasks_gen/eval/G0135/reference/pool_fee.testclasses.abap @@ -0,0 +1,61 @@ +CLASS ltc_pool_fee DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + DATA mo_cut TYPE REF TO {{p}}pool_fee. + METHODS setup. + METHODS assert_fee + IMPORTING iv_expected TYPE {{p}}pool_fee=>ty_amount + iv_ticket TYPE {{p}}pool_fee=>ty_ticket + iv_minutes TYPE i + iv_sauna TYPE abap_bool. + METHODS adult_basic FOR TESTING. + METHODS child_basic FOR TESTING. + METHODS family_basic FOR TESTING. + METHODS unknown_ticket FOR TESTING. + METHODS duration_surcharge FOR TESTING. + METHODS sauna_adult FOR TESTING. + METHODS sauna_child_ignored FOR TESTING. +ENDCLASS. + + +CLASS ltc_pool_fee IMPLEMENTATION. + METHOD setup. + mo_cut = NEW {{p}}pool_fee( ). + ENDMETHOD. + + METHOD assert_fee. + DATA(lv_actual) = mo_cut->calculate_fee( + iv_ticket = iv_ticket + iv_minutes = iv_minutes + iv_sauna = iv_sauna ). + cl_abap_unit_assert=>assert_equals( exp = iv_expected act = lv_actual ). + ENDMETHOD. + + METHOD adult_basic. + assert_fee( iv_expected = '6.50' iv_ticket = 'A' iv_minutes = 45 iv_sauna = abap_false ). + ENDMETHOD. + + METHOD child_basic. + assert_fee( iv_expected = '3.50' iv_ticket = 'C' iv_minutes = 30 iv_sauna = abap_false ). + ENDMETHOD. + + METHOD family_basic. + assert_fee( iv_expected = '15.00' iv_ticket = 'F' iv_minutes = 20 iv_sauna = abap_false ). + ENDMETHOD. + + METHOD unknown_ticket. + assert_fee( iv_expected = '0.00' iv_ticket = 'X' iv_minutes = 45 iv_sauna = abap_false ). + ENDMETHOD. + + METHOD duration_surcharge. + assert_fee( iv_expected = '7.50' iv_ticket = 'A' iv_minutes = 61 iv_sauna = abap_false ). + assert_fee( iv_expected = '8.50' iv_ticket = 'A' iv_minutes = 91 iv_sauna = abap_false ). + ENDMETHOD. + + METHOD sauna_adult. + assert_fee( iv_expected = '11.50' iv_ticket = 'A' iv_minutes = 45 iv_sauna = abap_true ). + ENDMETHOD. + + METHOD sauna_child_ignored. + assert_fee( iv_expected = '3.50' iv_ticket = 'C' iv_minutes = 45 iv_sauna = abap_true ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0135/seed/pool_fee.clas.abap b/tasks_gen/eval/G0135/seed/pool_fee.clas.abap new file mode 100644 index 0000000..d6f03d3 --- /dev/null +++ b/tasks_gen/eval/G0135/seed/pool_fee.clas.abap @@ -0,0 +1,68 @@ +CLASS {{p}}pool_fee DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES ty_ticket TYPE c LENGTH 1. + TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2. + METHODS calculate_fee + IMPORTING iv_ticket TYPE ty_ticket + iv_minutes TYPE i + iv_sauna TYPE abap_bool + RETURNING VALUE(rv_fee) TYPE ty_amount. +ENDCLASS. + + +CLASS {{p}}pool_fee IMPLEMENTATION. + METHOD calculate_fee. + DATA: lv_fee TYPE ty_amount, + lv_base TYPE ty_amount, + lv_min TYPE i, + lv_blocks TYPE i, + lv_i TYPE i, + lv_help TYPE ty_amount. + + " Eintrittspreis berechnen + CLEAR lv_fee. + lv_min = iv_minutes. + IF lv_min < 0. + lv_min = 0. + ENDIF. + + " Grundpreis je Ticketart + IF iv_ticket = 'A'. + lv_base = '6.50'. + ELSEIF iv_ticket = 'C'. + lv_base = '3.50'. + ELSEIF iv_ticket = 'S'. + lv_base = '4.50'. + ELSEIF iv_ticket = 'F'. + lv_base = '15.00'. + ELSE. + CLEAR lv_base. + ENDIF. + lv_fee = lv_base. + + " Die ersten 60 Minuten sind frei + IF lv_min > 60. + CLEAR lv_blocks. + lv_i = 60. + WHILE lv_i < lv_min. + lv_i = lv_i + 30. + lv_blocks = lv_blocks + 1. + ENDWHILE. + lv_help = lv_blocks * 1. + lv_fee = lv_fee + lv_help. + ENDIF. + + " Sauna + IF iv_sauna = 'X'. + IF iv_ticket = 'C'. + " Kinder zahlen keine Sauna + ELSEIF iv_ticket = 'F'. + lv_fee = lv_fee + 8. + ELSE. + lv_fee = lv_fee + 5. + ENDIF. + ENDIF. + + rv_fee = lv_fee. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0135/spec.md b/tasks_gen/eval/G0135/spec.md new file mode 100644 index 0000000..09af607 --- /dev/null +++ b/tasks_gen/eval/G0135/spec.md @@ -0,0 +1,49 @@ +# 1. Goal +A leisure centre sells swim tickets at its pool. A checkout program calls the +class {{P}}POOL_FEE to get the fee of one ticket. The class works, but the code +is hard to read and hard to maintain. Refactor the class. The behaviour stays +the same. + +# 2. Open questions +None. + +# 3. Context +- The class {{P}}POOL_FEE exists in package $TMP and is active. +- The class is the only object that you change. +- A checkout program calls the public method CALCULATE_FEE. The signature and +the result of the method must not change. +- The current implementation holds the business rules. Read it before you +change it. + +# 4. Contract +- Refactor the class {{P}}POOL_FEE in package $TMP. Keep the name. +- The class stays public and final. The constructor stays public and has no +parameters. +- Keep the public interface exactly as it is: + - TYPES ty_ticket TYPE c LENGTH 1. + - TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2. + - METHOD calculate_fee + IMPORTING iv_ticket TYPE ty_ticket + iv_minutes TYPE i + iv_sauna TYPE abap_bool + RETURNING VALUE(rv_fee) TYPE ty_amount. +- Do not add other public methods, types or attributes. + +# 5. Business rules +The behaviour of the class stays exactly the same. The rules are in the +current implementation of the class. Read the legacy code. Keep every rule, +including the rules for unusual input. Do not add a rule and do not remove a +rule. + +# 6. Constraints +- Release target: SAP_BASIS 816. +- Coding standards: Clean ABAP. Methods below 40 statements. Nesting depth at +most 3. No magic numbers, use constants. No unused variables. No comment that +restates the code. No global variables. +- Out of scope: do not change any other object. Do not create new objects. + +# 7. Acceptance +- The class {{P}}POOL_FEE is active and has no syntax error. +- The public interface of the class is unchanged. +- The hidden tests pass. +- Write your own ABAP Unit tests as local test classes in the class. diff --git a/tasks_gen/eval/G0135/task.json b/tasks_gen/eval/G0135/task.json new file mode 100644 index 0000000..a388974 --- /dev/null +++ b/tasks_gen/eval/G0135/task.json @@ -0,0 +1,48 @@ +{ + "id": "G0135", + "category": "E", + "object_type": "CLAS", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [ + { + "type": "CLAS", + "name": "{{P}}POOL_FEE", + "file": "seed/pool_fee.clas.abap", + "description": "Legacy class that calculates the fee of one swim ticket" + } + ], + "contract": [ + { + "type": "CLAS", + "name": "{{P}}POOL_FEE" + } + ], + "out_of_scope": [], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}POOL_HIDDEN", + "file": "hidden/pool_hidden.clas.abap", + "description": "Behaviour tests for the refactored pool fee class" + } + ], + "reference": [ + { + "type": "CLAS", + "name": "{{P}}POOL_FEE", + "file": "reference/pool_fee.clas.abap", + "description": "Refactored pool fee class", + "testclasses_file": "reference/pool_fee.testclasses.abap" + } + ], + "craft_checks": [ + "method_length", + "nesting_depth" + ] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0136/faulty/m0_kennel_pricer.clas.abap b/tasks_gen/eval/G0136/faulty/m0_kennel_pricer.clas.abap new file mode 100644 index 0000000..bd55b45 --- /dev/null +++ b/tasks_gen/eval/G0136/faulty/m0_kennel_pricer.clas.abap @@ -0,0 +1,93 @@ +CLASS {{p}}kennel_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES ty_pet_type TYPE c LENGTH 4. + TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2. + METHODS calculate_fee + IMPORTING iv_pet_type TYPE ty_pet_type + iv_nights TYPE i + iv_high_season TYPE abap_bool + iv_grooming TYPE abap_bool + RETURNING VALUE(rv_fee) TYPE ty_amount. + + PRIVATE SECTION. + CONSTANTS: + BEGIN OF c_pet_type, + dog TYPE ty_pet_type VALUE 'DOG', + cat TYPE ty_pet_type VALUE 'CAT', + rabb TYPE ty_pet_type VALUE 'RABB', + END OF c_pet_type, + BEGIN OF c_rate, + dog TYPE i VALUE 2500, + cat TYPE i VALUE 1800, + rabb TYPE i VALUE 800, + other TYPE i VALUE 2000, + END OF c_rate, + c_surcharge_num TYPE i VALUE 1125, + c_surcharge_den TYPE i VALUE 1000, + c_discount_percent TYPE i VALUE 10, + c_percent_base TYPE i VALUE 100, + c_long_stay_nights TYPE i VALUE 7, + c_cat_high_cut TYPE i VALUE 500, + c_grooming_fee TYPE i VALUE 1500, + c_cents_per_euro TYPE i VALUE 100. + + METHODS nightly_rate + IMPORTING iv_pet_type TYPE ty_pet_type + iv_high_season TYPE abap_bool + RETURNING VALUE(rv_rate) TYPE i. + METHODS long_stay_discount + IMPORTING iv_rate TYPE i + iv_nights TYPE i + RETURNING VALUE(rv_discount) TYPE i. +ENDCLASS. + + +CLASS {{p}}kennel_pricer IMPLEMENTATION. + METHOD calculate_fee. + IF iv_nights < 1. + rv_fee = 0. + RETURN. + ENDIF. + + DATA(lv_rate) = nightly_rate( iv_pet_type = iv_pet_type + iv_high_season = iv_high_season ). + DATA(lv_cents) = CONV ty_amount( lv_rate * iv_nights ). + + IF iv_nights < c_long_stay_nights. + lv_cents = lv_cents - long_stay_discount( iv_rate = lv_rate + iv_nights = iv_nights ). + ENDIF. + + IF iv_pet_type = c_pet_type-cat AND iv_high_season = abap_true. + lv_cents = lv_cents - c_cat_high_cut. + ENDIF. + + IF iv_grooming = abap_true. + lv_cents = lv_cents + c_grooming_fee. + ENDIF. + + rv_fee = lv_cents / c_cents_per_euro. + ENDMETHOD. + + METHOD nightly_rate. + CASE iv_pet_type. + WHEN c_pet_type-dog. + rv_rate = c_rate-dog. + WHEN c_pet_type-cat. + rv_rate = c_rate-cat. + WHEN c_pet_type-rabb. + rv_rate = c_rate-rabb. + WHEN OTHERS. + rv_rate = c_rate-other. + ENDCASE. + + IF iv_high_season = abap_true. + rv_rate = rv_rate * c_surcharge_num DIV c_surcharge_den. + ENDIF. + ENDMETHOD. + + METHOD long_stay_discount. + DATA(lv_per_night) = iv_rate * c_discount_percent DIV c_percent_base. + rv_discount = lv_per_night * iv_nights. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0136/faulty/m1_kennel_pricer.clas.abap b/tasks_gen/eval/G0136/faulty/m1_kennel_pricer.clas.abap new file mode 100644 index 0000000..89e2524 --- /dev/null +++ b/tasks_gen/eval/G0136/faulty/m1_kennel_pricer.clas.abap @@ -0,0 +1,93 @@ +CLASS {{p}}kennel_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES ty_pet_type TYPE c LENGTH 4. + TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2. + METHODS calculate_fee + IMPORTING iv_pet_type TYPE ty_pet_type + iv_nights TYPE i + iv_high_season TYPE abap_bool + iv_grooming TYPE abap_bool + RETURNING VALUE(rv_fee) TYPE ty_amount. + + PRIVATE SECTION. + CONSTANTS: + BEGIN OF c_pet_type, + dog TYPE ty_pet_type VALUE 'DOG', + cat TYPE ty_pet_type VALUE 'CAT', + rabb TYPE ty_pet_type VALUE 'RABB', + END OF c_pet_type, + BEGIN OF c_rate, + dog TYPE i VALUE 2500, + cat TYPE i VALUE 1800, + rabb TYPE i VALUE 800, + other TYPE i VALUE 2000, + END OF c_rate, + c_surcharge_num TYPE i VALUE 1125, + c_surcharge_den TYPE i VALUE 1000, + c_discount_percent TYPE i VALUE 10, + c_percent_base TYPE i VALUE 100, + c_long_stay_nights TYPE i VALUE 7, + c_cat_high_cut TYPE i VALUE 500, + c_grooming_fee TYPE i VALUE 1500, + c_cents_per_euro TYPE i VALUE 100. + + METHODS nightly_rate + IMPORTING iv_pet_type TYPE ty_pet_type + iv_high_season TYPE abap_bool + RETURNING VALUE(rv_rate) TYPE i. + METHODS long_stay_discount + IMPORTING iv_rate TYPE i + iv_nights TYPE i + RETURNING VALUE(rv_discount) TYPE i. +ENDCLASS. + + +CLASS {{p}}kennel_pricer IMPLEMENTATION. + METHOD calculate_fee. + IF iv_nights < 1. + rv_fee = 0. + RETURN. + ENDIF. + + DATA(lv_rate) = nightly_rate( iv_pet_type = iv_pet_type + iv_high_season = iv_high_season ). + DATA(lv_cents) = CONV ty_amount( lv_rate * iv_nights ). + + IF iv_nights >= c_long_stay_nights. + lv_cents = lv_cents + long_stay_discount( iv_rate = lv_rate + iv_nights = iv_nights ). + ENDIF. + + IF iv_pet_type = c_pet_type-cat AND iv_high_season = abap_true. + lv_cents = lv_cents - c_cat_high_cut. + ENDIF. + + IF iv_grooming = abap_true. + lv_cents = lv_cents + c_grooming_fee. + ENDIF. + + rv_fee = lv_cents / c_cents_per_euro. + ENDMETHOD. + + METHOD nightly_rate. + CASE iv_pet_type. + WHEN c_pet_type-dog. + rv_rate = c_rate-dog. + WHEN c_pet_type-cat. + rv_rate = c_rate-cat. + WHEN c_pet_type-rabb. + rv_rate = c_rate-rabb. + WHEN OTHERS. + rv_rate = c_rate-other. + ENDCASE. + + IF iv_high_season = abap_true. + rv_rate = rv_rate * c_surcharge_num DIV c_surcharge_den. + ENDIF. + ENDMETHOD. + + METHOD long_stay_discount. + DATA(lv_per_night) = iv_rate * c_discount_percent DIV c_percent_base. + rv_discount = lv_per_night * iv_nights. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0136/faulty/m2_kennel_pricer.clas.abap b/tasks_gen/eval/G0136/faulty/m2_kennel_pricer.clas.abap new file mode 100644 index 0000000..7f067b2 --- /dev/null +++ b/tasks_gen/eval/G0136/faulty/m2_kennel_pricer.clas.abap @@ -0,0 +1,93 @@ +CLASS {{p}}kennel_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES ty_pet_type TYPE c LENGTH 4. + TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2. + METHODS calculate_fee + IMPORTING iv_pet_type TYPE ty_pet_type + iv_nights TYPE i + iv_high_season TYPE abap_bool + iv_grooming TYPE abap_bool + RETURNING VALUE(rv_fee) TYPE ty_amount. + + PRIVATE SECTION. + CONSTANTS: + BEGIN OF c_pet_type, + dog TYPE ty_pet_type VALUE 'DOG', + cat TYPE ty_pet_type VALUE 'CAT', + rabb TYPE ty_pet_type VALUE 'RABB', + END OF c_pet_type, + BEGIN OF c_rate, + dog TYPE i VALUE 2500, + cat TYPE i VALUE 1800, + rabb TYPE i VALUE 800, + other TYPE i VALUE 2000, + END OF c_rate, + c_surcharge_num TYPE i VALUE 1125, + c_surcharge_den TYPE i VALUE 1000, + c_discount_percent TYPE i VALUE 10, + c_percent_base TYPE i VALUE 100, + c_long_stay_nights TYPE i VALUE 7, + c_cat_high_cut TYPE i VALUE 500, + c_grooming_fee TYPE i VALUE 1500, + c_cents_per_euro TYPE i VALUE 100. + + METHODS nightly_rate + IMPORTING iv_pet_type TYPE ty_pet_type + iv_high_season TYPE abap_bool + RETURNING VALUE(rv_rate) TYPE i. + METHODS long_stay_discount + IMPORTING iv_rate TYPE i + iv_nights TYPE i + RETURNING VALUE(rv_discount) TYPE i. +ENDCLASS. + + +CLASS {{p}}kennel_pricer IMPLEMENTATION. + METHOD calculate_fee. + IF iv_nights < 1. + rv_fee = 0. + RETURN. + ENDIF. + + DATA(lv_rate) = nightly_rate( iv_pet_type = iv_pet_type + iv_high_season = iv_high_season ). + DATA(lv_cents) = CONV ty_amount( lv_rate * iv_nights ). + + IF iv_nights >= c_long_stay_nights. + lv_cents = lv_cents - long_stay_discount( iv_rate = lv_rate + iv_nights = iv_nights ). + ENDIF. + + IF iv_pet_type = c_pet_type-cat OR iv_high_season = abap_true. + lv_cents = lv_cents - c_cat_high_cut. + ENDIF. + + IF iv_grooming = abap_true. + lv_cents = lv_cents + c_grooming_fee. + ENDIF. + + rv_fee = lv_cents / c_cents_per_euro. + ENDMETHOD. + + METHOD nightly_rate. + CASE iv_pet_type. + WHEN c_pet_type-dog. + rv_rate = c_rate-dog. + WHEN c_pet_type-cat. + rv_rate = c_rate-cat. + WHEN c_pet_type-rabb. + rv_rate = c_rate-rabb. + WHEN OTHERS. + rv_rate = c_rate-other. + ENDCASE. + + IF iv_high_season = abap_true. + rv_rate = rv_rate * c_surcharge_num DIV c_surcharge_den. + ENDIF. + ENDMETHOD. + + METHOD long_stay_discount. + DATA(lv_per_night) = iv_rate * c_discount_percent DIV c_percent_base. + rv_discount = lv_per_night * iv_nights. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0136/faulty/m3_kennel_pricer.clas.abap b/tasks_gen/eval/G0136/faulty/m3_kennel_pricer.clas.abap new file mode 100644 index 0000000..2f4e890 --- /dev/null +++ b/tasks_gen/eval/G0136/faulty/m3_kennel_pricer.clas.abap @@ -0,0 +1,93 @@ +CLASS {{p}}kennel_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES ty_pet_type TYPE c LENGTH 4. + TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2. + METHODS calculate_fee + IMPORTING iv_pet_type TYPE ty_pet_type + iv_nights TYPE i + iv_high_season TYPE abap_bool + iv_grooming TYPE abap_bool + RETURNING VALUE(rv_fee) TYPE ty_amount. + + PRIVATE SECTION. + CONSTANTS: + BEGIN OF c_pet_type, + dog TYPE ty_pet_type VALUE 'DOG', + cat TYPE ty_pet_type VALUE 'CAT', + rabb TYPE ty_pet_type VALUE 'RABB', + END OF c_pet_type, + BEGIN OF c_rate, + dog TYPE i VALUE 2500, + cat TYPE i VALUE 1800, + rabb TYPE i VALUE 800, + other TYPE i VALUE 2000, + END OF c_rate, + c_surcharge_num TYPE i VALUE 1125, + c_surcharge_den TYPE i VALUE 1000, + c_discount_percent TYPE i VALUE 10, + c_percent_base TYPE i VALUE 100, + c_long_stay_nights TYPE i VALUE 7, + c_cat_high_cut TYPE i VALUE 500, + c_grooming_fee TYPE i VALUE 1500, + c_cents_per_euro TYPE i VALUE 100. + + METHODS nightly_rate + IMPORTING iv_pet_type TYPE ty_pet_type + iv_high_season TYPE abap_bool + RETURNING VALUE(rv_rate) TYPE i. + METHODS long_stay_discount + IMPORTING iv_rate TYPE i + iv_nights TYPE i + RETURNING VALUE(rv_discount) TYPE i. +ENDCLASS. + + +CLASS {{p}}kennel_pricer IMPLEMENTATION. + METHOD calculate_fee. + IF iv_nights < 1. + rv_fee = 0. + RETURN. + ENDIF. + + DATA(lv_rate) = nightly_rate( iv_pet_type = iv_pet_type + iv_high_season = iv_high_season ). + DATA(lv_cents) = CONV ty_amount( lv_rate * iv_nights ). + + IF iv_nights >= c_long_stay_nights. + lv_cents = lv_cents - long_stay_discount( iv_rate = lv_rate + iv_nights = iv_nights ). + ENDIF. + + IF iv_pet_type = c_pet_type-cat AND iv_high_season = abap_true. + lv_cents = lv_cents - c_cat_high_cut. + ENDIF. + + IF iv_grooming = abap_false. + lv_cents = lv_cents + c_grooming_fee. + ENDIF. + + rv_fee = lv_cents / c_cents_per_euro. + ENDMETHOD. + + METHOD nightly_rate. + CASE iv_pet_type. + WHEN c_pet_type-dog. + rv_rate = c_rate-dog. + WHEN c_pet_type-cat. + rv_rate = c_rate-cat. + WHEN c_pet_type-rabb. + rv_rate = c_rate-rabb. + WHEN OTHERS. + rv_rate = c_rate-other. + ENDCASE. + + IF iv_high_season = abap_true. + rv_rate = rv_rate * c_surcharge_num DIV c_surcharge_den. + ENDIF. + ENDMETHOD. + + METHOD long_stay_discount. + DATA(lv_per_night) = iv_rate * c_discount_percent DIV c_percent_base. + rv_discount = lv_per_night * iv_nights. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0136/faulty/m4_kennel_pricer.clas.abap b/tasks_gen/eval/G0136/faulty/m4_kennel_pricer.clas.abap new file mode 100644 index 0000000..d15bfd4 --- /dev/null +++ b/tasks_gen/eval/G0136/faulty/m4_kennel_pricer.clas.abap @@ -0,0 +1,93 @@ +CLASS {{p}}kennel_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES ty_pet_type TYPE c LENGTH 4. + TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2. + METHODS calculate_fee + IMPORTING iv_pet_type TYPE ty_pet_type + iv_nights TYPE i + iv_high_season TYPE abap_bool + iv_grooming TYPE abap_bool + RETURNING VALUE(rv_fee) TYPE ty_amount. + + PRIVATE SECTION. + CONSTANTS: + BEGIN OF c_pet_type, + dog TYPE ty_pet_type VALUE 'DOG', + cat TYPE ty_pet_type VALUE 'CAT', + rabb TYPE ty_pet_type VALUE 'RABB', + END OF c_pet_type, + BEGIN OF c_rate, + dog TYPE i VALUE 2500, + cat TYPE i VALUE 1800, + rabb TYPE i VALUE 800, + other TYPE i VALUE 2000, + END OF c_rate, + c_surcharge_num TYPE i VALUE 1125, + c_surcharge_den TYPE i VALUE 1000, + c_discount_percent TYPE i VALUE 10, + c_percent_base TYPE i VALUE 100, + c_long_stay_nights TYPE i VALUE 7, + c_cat_high_cut TYPE i VALUE 500, + c_grooming_fee TYPE i VALUE 1500, + c_cents_per_euro TYPE i VALUE 100. + + METHODS nightly_rate + IMPORTING iv_pet_type TYPE ty_pet_type + iv_high_season TYPE abap_bool + RETURNING VALUE(rv_rate) TYPE i. + METHODS long_stay_discount + IMPORTING iv_rate TYPE i + iv_nights TYPE i + RETURNING VALUE(rv_discount) TYPE i. +ENDCLASS. + + +CLASS {{p}}kennel_pricer IMPLEMENTATION. + METHOD calculate_fee. + IF iv_nights < 1. + rv_fee = 0. + RETURN. + ENDIF. + + DATA(lv_rate) = nightly_rate( iv_pet_type = iv_pet_type + iv_high_season = iv_high_season ). + DATA(lv_cents) = CONV ty_amount( lv_rate * iv_nights ). + + IF iv_nights >= c_long_stay_nights. + lv_cents = lv_cents - long_stay_discount( iv_rate = lv_rate + iv_nights = iv_nights ). + ENDIF. + + IF iv_pet_type = c_pet_type-cat AND iv_high_season = abap_true. + lv_cents = lv_cents - c_cat_high_cut. + ENDIF. + + IF iv_grooming = abap_true. + lv_cents = lv_cents + c_grooming_fee. + ENDIF. + + rv_fee = lv_cents / c_cents_per_euro. + ENDMETHOD. + + METHOD nightly_rate. + CASE iv_pet_type. + WHEN c_pet_type-dog. + rv_rate = c_rate-dog. + WHEN c_pet_type-cat. + rv_rate = c_rate-cat. + WHEN c_pet_type-rabb. + rv_rate = c_rate-rabb. + WHEN OTHERS. + rv_rate = c_rate-other. + ENDCASE. + + IF iv_high_season <> abap_true. + rv_rate = rv_rate * c_surcharge_num DIV c_surcharge_den. + ENDIF. + ENDMETHOD. + + METHOD long_stay_discount. + DATA(lv_per_night) = iv_rate * c_discount_percent DIV c_percent_base. + rv_discount = lv_per_night * iv_nights. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0136/generation.json b/tasks_gen/eval/G0136/generation.json new file mode 100644 index 0000000..5fd69e7 --- /dev/null +++ b/tasks_gen/eval/G0136/generation.json @@ -0,0 +1,47 @@ +{ + "id": "G0136", + "pool": "eval", + "object_type": "CLAS", + "category": "E", + "attempts": [ + { + "stage": "bundle", + "errors": [ + "hidden/t02_hidden.clas.abap line 26: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"", + "hidden/t02_hidden.clas.abap line 27: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"00\"", + "hidden/t02_hidden.clas.abap line 35: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"", + "hidden/t02_hidden.clas.abap line 36: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"75\"", + "hidden/t02_hidden.clas.abap line 44: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"", + "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), \"12\"", + "hidden/t02_hidden.clas.abap line 53: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"", + "hidden/t02_hidden.clas.abap line 54: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"17\"", + "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), \"cl_abap_unit_assert\"", + "hidden/t02_hidden.clas.abap line 63: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"61\"", + "hidden/t02_hidden.clas.abap line 71: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"", + "hidden/t02_hidden.clas.abap line 72: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"40\"", + "hidden/t02_hidden.clas.abap line 80: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"", + "hidden/t02_hidden.clas.abap line 81: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"00\"", + "hidden/t02_hidden.clas.abap line 89: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"", + "hidden/t02_hidden.clas.abap line 90: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"00\"", + "hidden/t02_hidden.clas.abap line 98: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"", + "hidden/t02_hidden.clas.abap line 99: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"00\"", + "hidden/t02_hidden.clas.abap line 107: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"", + "hidden/t02_hidden.clas.abap line 108: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"00\"" + ], + "by_check": { + "abaplint": 20 + } + }, + { + "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/eval/G0136/hidden/t02_hidden.clas.abap b/tasks_gen/eval/G0136/hidden/t02_hidden.clas.abap new file mode 100644 index 0000000..5ca75a9 --- /dev/null +++ b/tasks_gen/eval/G0136/hidden/t02_hidden.clas.abap @@ -0,0 +1,127 @@ +CLASS {{p}}t02_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + TYPES ty_amount TYPE {{p}}kennel_pricer=>ty_amount. + + CONSTANTS: + c_dog_1n TYPE ty_amount VALUE '25.00', + c_cat_3n_hi TYPE ty_amount VALUE '55.75', + c_dog_1n_hi TYPE ty_amount VALUE '28.12', + c_dog_7n_hi TYPE ty_amount VALUE '177.17', + c_cat_7n_hi TYPE ty_amount VALUE '122.61', + c_cat_7n_gr TYPE ty_amount VALUE '128.40', + c_zero TYPE ty_amount VALUE '0.00', + c_bird_2n TYPE ty_amount VALUE '40.00', + c_other_1n TYPE ty_amount VALUE '20.00', + c_rabb_10n TYPE ty_amount VALUE '72.00'. + + DATA mo_cut TYPE REF TO {{p}}kennel_pricer. + + METHODS setup. + METHODS dog_one_night FOR TESTING. + METHODS cat_high_season FOR TESTING. + METHODS high_season_rate FOR TESTING. + METHODS long_stay_dog_high FOR TESTING. + METHODS long_stay_cat_high FOR TESTING. + METHODS grooming_after_discount FOR TESTING. + METHODS zero_nights FOR TESTING. + METHODS negative_nights FOR TESTING. + METHODS unknown_type_default FOR TESTING. + METHODS lower_case_type FOR TESTING. + METHODS rabbit_long_stay FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t02_hidden IMPLEMENTATION. + METHOD setup. + mo_cut = NEW {{p}}kennel_pricer( ). + ENDMETHOD. + + METHOD dog_one_night. + cl_abap_unit_assert=>assert_equals( exp = c_dog_1n + act = mo_cut->calculate_fee( iv_pet_type = 'DOG' + iv_nights = 1 + iv_high_season = abap_false + iv_grooming = abap_false ) ). + ENDMETHOD. + + METHOD cat_high_season. + cl_abap_unit_assert=>assert_equals( exp = c_cat_3n_hi + act = mo_cut->calculate_fee( iv_pet_type = 'CAT' + iv_nights = 3 + iv_high_season = abap_true + iv_grooming = abap_false ) ). + ENDMETHOD. + + METHOD high_season_rate. + cl_abap_unit_assert=>assert_equals( exp = c_dog_1n_hi + act = mo_cut->calculate_fee( iv_pet_type = 'DOG' + iv_nights = 1 + iv_high_season = abap_true + iv_grooming = abap_false ) ). + ENDMETHOD. + + METHOD long_stay_dog_high. + cl_abap_unit_assert=>assert_equals( exp = c_dog_7n_hi + act = mo_cut->calculate_fee( iv_pet_type = 'DOG' + iv_nights = 7 + iv_high_season = abap_true + iv_grooming = abap_false ) ). + ENDMETHOD. + + METHOD long_stay_cat_high. + cl_abap_unit_assert=>assert_equals( exp = c_cat_7n_hi + act = mo_cut->calculate_fee( iv_pet_type = 'CAT' + iv_nights = 7 + iv_high_season = abap_true + iv_grooming = abap_false ) ). + ENDMETHOD. + + METHOD grooming_after_discount. + cl_abap_unit_assert=>assert_equals( exp = c_cat_7n_gr + act = mo_cut->calculate_fee( iv_pet_type = 'CAT' + iv_nights = 7 + iv_high_season = abap_false + iv_grooming = abap_true ) ). + ENDMETHOD. + + METHOD zero_nights. + cl_abap_unit_assert=>assert_equals( exp = c_zero + act = mo_cut->calculate_fee( iv_pet_type = 'DOG' + iv_nights = 0 + iv_high_season = abap_true + iv_grooming = abap_true ) ). + ENDMETHOD. + + METHOD negative_nights. + cl_abap_unit_assert=>assert_equals( exp = c_zero + act = mo_cut->calculate_fee( iv_pet_type = 'DOG' + iv_nights = -2 + iv_high_season = abap_false + iv_grooming = abap_false ) ). + ENDMETHOD. + + METHOD unknown_type_default. + cl_abap_unit_assert=>assert_equals( exp = c_bird_2n + act = mo_cut->calculate_fee( iv_pet_type = 'BIRD' + iv_nights = 2 + iv_high_season = abap_false + iv_grooming = abap_false ) ). + ENDMETHOD. + + METHOD lower_case_type. + cl_abap_unit_assert=>assert_equals( exp = c_other_1n + act = mo_cut->calculate_fee( iv_pet_type = 'dog' + iv_nights = 1 + iv_high_season = abap_false + iv_grooming = abap_false ) ). + ENDMETHOD. + + METHOD rabbit_long_stay. + cl_abap_unit_assert=>assert_equals( exp = c_rabb_10n + act = mo_cut->calculate_fee( iv_pet_type = 'RABB' + iv_nights = 10 + iv_high_season = abap_false + iv_grooming = abap_false ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0136/mutation.json b/tasks_gen/eval/G0136/mutation.json new file mode 100644 index 0000000..4fd2656 --- /dev/null +++ b/tasks_gen/eval/G0136/mutation.json @@ -0,0 +1,83 @@ +{ + "task": "G0136", + "mutants": [ + { + "object": "{{P}}KENNEL_PRICER", + "mutant": "line 56: >= -> < (rel)", + "status": "killed", + "hidden": "2/11", + "failed_tests": [ + "CAT_HIGH_SEASON", + "DOG_ONE_NIGHT", + "GROOMING_AFTER_DISCOUNT", + "HIGH_SEASON_RATE", + "LONG_STAY_CAT_HIGH", + "LONG_STAY_DOG_HIGH", + "LOWER_CASE_TYPE", + "RABBIT_LONG_STAY", + "UNKNOWN_TYPE_DEFAULT" + ] + }, + { + "object": "{{P}}KENNEL_PRICER", + "mutant": "line 57: - -> + (arith)", + "status": "killed", + "hidden": "7/11", + "failed_tests": [ + "GROOMING_AFTER_DISCOUNT", + "LONG_STAY_CAT_HIGH", + "LONG_STAY_DOG_HIGH", + "RABBIT_LONG_STAY" + ] + }, + { + "object": "{{P}}KENNEL_PRICER", + "mutant": "line 61: AND -> OR (logic)", + "status": "killed", + "hidden": "8/11", + "failed_tests": [ + "GROOMING_AFTER_DISCOUNT", + "HIGH_SEASON_RATE", + "LONG_STAY_DOG_HIGH" + ] + }, + { + "object": "{{P}}KENNEL_PRICER", + "mutant": "line 65: abap_true -> abap_false (bool)", + "status": "killed", + "hidden": "2/11", + "failed_tests": [ + "CAT_HIGH_SEASON", + "DOG_ONE_NIGHT", + "GROOMING_AFTER_DISCOUNT", + "HIGH_SEASON_RATE", + "LONG_STAY_CAT_HIGH", + "LONG_STAY_DOG_HIGH", + "LOWER_CASE_TYPE", + "RABBIT_LONG_STAY", + "UNKNOWN_TYPE_DEFAULT" + ] + }, + { + "object": "{{P}}KENNEL_PRICER", + "mutant": "line 84: = -> <> (eq)", + "status": "killed", + "hidden": "2/11", + "failed_tests": [ + "CAT_HIGH_SEASON", + "DOG_ONE_NIGHT", + "GROOMING_AFTER_DISCOUNT", + "HIGH_SEASON_RATE", + "LONG_STAY_CAT_HIGH", + "LONG_STAY_DOG_HIGH", + "LOWER_CASE_TYPE", + "RABBIT_LONG_STAY", + "UNKNOWN_TYPE_DEFAULT" + ] + } + ], + "valid": 5, + "killed": 5, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0136/reference/kennel_pricer.clas.abap b/tasks_gen/eval/G0136/reference/kennel_pricer.clas.abap new file mode 100644 index 0000000..114b695 --- /dev/null +++ b/tasks_gen/eval/G0136/reference/kennel_pricer.clas.abap @@ -0,0 +1,93 @@ +CLASS {{p}}kennel_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES ty_pet_type TYPE c LENGTH 4. + TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2. + METHODS calculate_fee + IMPORTING iv_pet_type TYPE ty_pet_type + iv_nights TYPE i + iv_high_season TYPE abap_bool + iv_grooming TYPE abap_bool + RETURNING VALUE(rv_fee) TYPE ty_amount. + + PRIVATE SECTION. + CONSTANTS: + BEGIN OF c_pet_type, + dog TYPE ty_pet_type VALUE 'DOG', + cat TYPE ty_pet_type VALUE 'CAT', + rabb TYPE ty_pet_type VALUE 'RABB', + END OF c_pet_type, + BEGIN OF c_rate, + dog TYPE i VALUE 2500, + cat TYPE i VALUE 1800, + rabb TYPE i VALUE 800, + other TYPE i VALUE 2000, + END OF c_rate, + c_surcharge_num TYPE i VALUE 1125, + c_surcharge_den TYPE i VALUE 1000, + c_discount_percent TYPE i VALUE 10, + c_percent_base TYPE i VALUE 100, + c_long_stay_nights TYPE i VALUE 7, + c_cat_high_cut TYPE i VALUE 500, + c_grooming_fee TYPE i VALUE 1500, + c_cents_per_euro TYPE i VALUE 100. + + METHODS nightly_rate + IMPORTING iv_pet_type TYPE ty_pet_type + iv_high_season TYPE abap_bool + RETURNING VALUE(rv_rate) TYPE i. + METHODS long_stay_discount + IMPORTING iv_rate TYPE i + iv_nights TYPE i + RETURNING VALUE(rv_discount) TYPE i. +ENDCLASS. + + +CLASS {{p}}kennel_pricer IMPLEMENTATION. + METHOD calculate_fee. + IF iv_nights < 1. + rv_fee = 0. + RETURN. + ENDIF. + + DATA(lv_rate) = nightly_rate( iv_pet_type = iv_pet_type + iv_high_season = iv_high_season ). + DATA(lv_cents) = CONV ty_amount( lv_rate * iv_nights ). + + IF iv_nights >= c_long_stay_nights. + lv_cents = lv_cents - long_stay_discount( iv_rate = lv_rate + iv_nights = iv_nights ). + ENDIF. + + IF iv_pet_type = c_pet_type-cat AND iv_high_season = abap_true. + lv_cents = lv_cents - c_cat_high_cut. + ENDIF. + + IF iv_grooming = abap_true. + lv_cents = lv_cents + c_grooming_fee. + ENDIF. + + rv_fee = lv_cents / c_cents_per_euro. + ENDMETHOD. + + METHOD nightly_rate. + CASE iv_pet_type. + WHEN c_pet_type-dog. + rv_rate = c_rate-dog. + WHEN c_pet_type-cat. + rv_rate = c_rate-cat. + WHEN c_pet_type-rabb. + rv_rate = c_rate-rabb. + WHEN OTHERS. + rv_rate = c_rate-other. + ENDCASE. + + IF iv_high_season = abap_true. + rv_rate = rv_rate * c_surcharge_num DIV c_surcharge_den. + ENDIF. + ENDMETHOD. + + METHOD long_stay_discount. + DATA(lv_per_night) = iv_rate * c_discount_percent DIV c_percent_base. + rv_discount = lv_per_night * iv_nights. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0136/reference/kennel_pricer.testclasses.abap b/tasks_gen/eval/G0136/reference/kennel_pricer.testclasses.abap new file mode 100644 index 0000000..9cfc909 --- /dev/null +++ b/tasks_gen/eval/G0136/reference/kennel_pricer.testclasses.abap @@ -0,0 +1,68 @@ +CLASS ltc_kennel_pricer DEFINITION FINAL FOR TESTING + DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + TYPES ty_amount TYPE {{p}}kennel_pricer=>ty_amount. + + CONSTANTS: + c_dog_1n TYPE ty_amount VALUE '25.00', + c_cat_3n_hi TYPE ty_amount VALUE '55.75', + c_dog_7n_hi TYPE ty_amount VALUE '177.17', + c_zero TYPE ty_amount VALUE '0.00', + c_bird_2n TYPE ty_amount VALUE '40.00'. + + DATA mo_cut TYPE REF TO {{p}}kennel_pricer. + + METHODS setup. + METHODS dog_low_season FOR TESTING. + METHODS cat_high_season FOR TESTING. + METHODS long_stay FOR TESTING. + METHODS no_nights FOR TESTING. + METHODS unknown_type FOR TESTING. +ENDCLASS. + + +CLASS ltc_kennel_pricer IMPLEMENTATION. + METHOD setup. + mo_cut = NEW {{p}}kennel_pricer( ). + ENDMETHOD. + + METHOD dog_low_season. + cl_abap_unit_assert=>assert_equals( exp = c_dog_1n + act = mo_cut->calculate_fee( iv_pet_type = 'DOG' + iv_nights = 1 + iv_high_season = abap_false + iv_grooming = abap_false ) ). + ENDMETHOD. + + METHOD cat_high_season. + cl_abap_unit_assert=>assert_equals( exp = c_cat_3n_hi + act = mo_cut->calculate_fee( iv_pet_type = 'CAT' + iv_nights = 3 + iv_high_season = abap_true + iv_grooming = abap_false ) ). + ENDMETHOD. + + METHOD long_stay. + cl_abap_unit_assert=>assert_equals( exp = c_dog_7n_hi + act = mo_cut->calculate_fee( iv_pet_type = 'DOG' + iv_nights = 7 + iv_high_season = abap_true + iv_grooming = abap_false ) ). + ENDMETHOD. + + METHOD no_nights. + cl_abap_unit_assert=>assert_equals( exp = c_zero + act = mo_cut->calculate_fee( iv_pet_type = 'DOG' + iv_nights = 0 + iv_high_season = abap_false + iv_grooming = abap_false ) ). + ENDMETHOD. + + METHOD unknown_type. + cl_abap_unit_assert=>assert_equals( exp = c_bird_2n + act = mo_cut->calculate_fee( iv_pet_type = 'BIRD' + iv_nights = 2 + iv_high_season = abap_false + iv_grooming = abap_false ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0136/seed/kennel_pricer.clas.abap b/tasks_gen/eval/G0136/seed/kennel_pricer.clas.abap new file mode 100644 index 0000000..f193d5a --- /dev/null +++ b/tasks_gen/eval/G0136/seed/kennel_pricer.clas.abap @@ -0,0 +1,71 @@ +CLASS {{p}}kennel_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES ty_pet_type TYPE c LENGTH 4. + TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2. + METHODS calculate_fee + IMPORTING iv_pet_type TYPE ty_pet_type + iv_nights TYPE i + iv_high_season TYPE abap_bool + iv_grooming TYPE abap_bool + RETURNING VALUE(rv_fee) TYPE ty_amount. +ENDCLASS. + + +CLASS {{p}}kennel_pricer IMPLEMENTATION. + METHOD calculate_fee. + DATA: lv_rate TYPE i, + lv_total TYPE p LENGTH 8 DECIMALS 2, + lv_discount TYPE i. + + IF iv_nights < 1. + rv_fee = 0. + RETURN. + ENDIF. + + IF iv_pet_type = 'DOG'. + IF iv_high_season = 'X'. + lv_rate = 2500 * 1125 DIV 1000. + ELSE. + lv_rate = 2500. + ENDIF. + ELSEIF iv_pet_type = 'CAT'. + IF iv_high_season = 'X'. + lv_rate = 1800 * 1125 DIV 1000. + ELSE. + lv_rate = 1800. + ENDIF. + ELSEIF iv_pet_type = 'RABB'. + IF iv_high_season = 'X'. + lv_rate = 800 * 1125 DIV 1000. + ELSE. + lv_rate = 800. + ENDIF. + ELSE. + IF iv_high_season = 'X'. + lv_rate = 2000 * 1125 DIV 1000. + ELSE. + lv_rate = 2000. + ENDIF. + ENDIF. + + CLEAR lv_total. + DO iv_nights TIMES. + lv_total = lv_total + lv_rate. + ENDDO. + + IF iv_nights >= 7. + lv_discount = lv_rate * 10 DIV 100. + lv_total = lv_total - lv_discount * iv_nights. + ENDIF. + + IF iv_pet_type = 'CAT' AND iv_high_season = 'X'. + lv_total = lv_total - 500. + ENDIF. + + IF iv_grooming = 'X'. + lv_total = lv_total + 1500. + ENDIF. + + rv_fee = lv_total / 100. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0136/spec.md b/tasks_gen/eval/G0136/spec.md new file mode 100644 index 0000000..1b5cc36 --- /dev/null +++ b/tasks_gen/eval/G0136/spec.md @@ -0,0 +1,42 @@ +# 1. Goal +Refactor the class {{P}}KENNEL_PRICER. The class calculates the boarding fee of a +pet at a kennel. The class works correctly. The code is difficult to read and to +maintain. Refactor the class. The behavior stays the same. + +# 2. Open questions +None. + +# 3. Context +- The class {{P}}KENNEL_PRICER exists in package $TMP. It is active. +- A booking program calls the class before the kennel confirms a booking. +- The booking program must get the same fee after your change. +- The class has one public method. The method calculates the fee. + +# 4. Contract +- Change the class {{P}}KENNEL_PRICER in package $TMP. Keep the name of the class. +- Keep the public interface of the class. These public components stay: + - The type TY_PET_TYPE. It is CHAR 4. + - The type TY_AMOUNT. It is P, length 8, 2 decimals. + - The method CALCULATE_FEE with this signature: + IMPORTING iv_pet_type TYPE ty_pet_type + iv_nights TYPE i + iv_high_season TYPE abap_bool + iv_grooming TYPE abap_bool + RETURNING VALUE(rv_fee) TYPE ty_amount. +- Do not add other public methods or public attributes. + +# 5. Business rules +The behavior of the class must not change. Read the existing implementation in +the seed object. Every result value stays the same. This includes the results for +edge cases and for unusual input values. + +# 6. Constraints +- Release target: 8.16. +- Coding standards: Clean ABAP. Method length below 40 statements. No magic + numbers. No deep nesting. No comment that restates the code. +- Out of scope: none. + +# 7. Acceptance +- The class is active and has no syntax error. +- The hidden tests pass. +- Write your own ABAP Unit tests for the class. diff --git a/tasks_gen/eval/G0136/task.json b/tasks_gen/eval/G0136/task.json new file mode 100644 index 0000000..9f5d37a --- /dev/null +++ b/tasks_gen/eval/G0136/task.json @@ -0,0 +1,49 @@ +{ + "id": "G0136", + "category": "E", + "object_type": "CLAS", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [ + { + "type": "CLAS", + "name": "{{P}}KENNEL_PRICER", + "file": "seed/kennel_pricer.clas.abap", + "description": "Legacy kennel boarding fee calculator with deep nesting, duplicated branches and magic numbers" + } + ], + "contract": [ + { + "type": "CLAS", + "name": "{{P}}KENNEL_PRICER" + } + ], + "out_of_scope": [], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T02_HIDDEN", + "file": "hidden/t02_hidden.clas.abap", + "description": "T02 hidden tests: unchanged boarding fee behaviour of the kennel pricer" + } + ], + "reference": [ + { + "type": "CLAS", + "name": "{{P}}KENNEL_PRICER", + "file": "reference/kennel_pricer.clas.abap", + "description": "Refactored kennel boarding fee calculator", + "testclasses_file": "reference/kennel_pricer.testclasses.abap" + } + ], + "craft_checks": [ + "method_length", + "magic_numbers", + "nesting_depth" + ] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0137/faulty/m1_dive_check.clas.abap b/tasks_gen/eval/G0137/faulty/m1_dive_check.clas.abap new file mode 100644 index 0000000..d0401cb --- /dev/null +++ b/tasks_gen/eval/G0137/faulty/m1_dive_check.clas.abap @@ -0,0 +1,114 @@ +CLASS {{p}}dive_check DEFINITION + PUBLIC + FINAL + CREATE PUBLIC. + + PUBLIC SECTION. + TYPES ty_reason TYPE c LENGTH 10. + TYPES ty_cert_level TYPE c LENGTH 1. + + CONSTANTS: + BEGIN OF c_reason, + ok TYPE ty_reason VALUE 'OK', + age TYPE ty_reason VALUE 'AGE', + cert TYPE ty_reason VALUE 'CERT', + depth TYPE ty_reason VALUE 'DEPTH', + dives TYPE ty_reason VALUE 'DIVES', + recent TYPE ty_reason VALUE 'RECENT', + END OF c_reason. + + METHODS check_diver + IMPORTING + iv_cert_level TYPE ty_cert_level + iv_depth TYPE i + iv_dives TYPE i + iv_last_dive TYPE d + iv_dive_date TYPE d + iv_age TYPE i + RETURNING + VALUE(rv_reason) TYPE ty_reason. + + PRIVATE SECTION. + CONSTANTS: + c_min_age TYPE i VALUE 12, + c_deep_depth TYPE i VALUE 30, + c_days_deep TYPE i VALUE 180, + c_days_shallow TYPE i VALUE 365. + + TYPES: + BEGIN OF ty_limit, + cert TYPE ty_cert_level, + max_depth TYPE i, + min_dives TYPE i, + END OF ty_limit, + tt_limit TYPE HASHED TABLE OF ty_limit WITH UNIQUE KEY cert. + + METHODS limits + RETURNING VALUE(rt_limit) TYPE tt_limit. + METHODS days_since_last_dive + IMPORTING iv_last_dive TYPE d + iv_dive_date TYPE d + RETURNING VALUE(rv_days) TYPE i. + METHODS max_days_since_last_dive + IMPORTING iv_depth TYPE i + RETURNING VALUE(rv_days) TYPE i. +ENDCLASS. + + +CLASS {{p}}dive_check IMPLEMENTATION. + METHOD check_diver. + IF iv_age < c_min_age. + rv_reason = c_reason-age. + RETURN. + ENDIF. + + DATA(lt_limit) = limits( ). + READ TABLE lt_limit WITH TABLE KEY cert = iv_cert_level ASSIGNING FIELD-SYMBOL(). + IF sy-subrc <> 0. + rv_reason = c_reason-cert. + RETURN. + ENDIF. + + IF iv_depth > -max_depth. + rv_reason = c_reason-depth. + RETURN. + ENDIF. + + IF iv_dives < -min_dives. + rv_reason = c_reason-dives. + RETURN. + ENDIF. + + IF iv_last_dive IS INITIAL. + rv_reason = c_reason-recent. + RETURN. + ENDIF. + + IF days_since_last_dive( iv_last_dive = iv_last_dive + iv_dive_date = iv_dive_date ) <= max_days_since_last_dive( iv_depth ). + rv_reason = c_reason-recent. + RETURN. + ENDIF. + + rv_reason = c_reason-ok. + ENDMETHOD. + + METHOD limits. + rt_limit = VALUE #( ( cert = 'O' max_depth = 18 min_dives = 20 ) + ( cert = 'A' max_depth = 30 min_dives = 50 ) + ( cert = 'R' max_depth = 40 min_dives = 80 ) + ( cert = 'D' max_depth = 40 min_dives = 100 ) ). + ENDMETHOD. + + METHOD days_since_last_dive. + rv_days = iv_dive_date - iv_last_dive. + ENDMETHOD. + + METHOD max_days_since_last_dive. + IF iv_depth > c_deep_depth. + rv_days = c_days_deep. + ELSE. + rv_days = c_days_shallow. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0137/faulty/m2_dive_check.clas.abap b/tasks_gen/eval/G0137/faulty/m2_dive_check.clas.abap new file mode 100644 index 0000000..2b60a2b --- /dev/null +++ b/tasks_gen/eval/G0137/faulty/m2_dive_check.clas.abap @@ -0,0 +1,114 @@ +CLASS {{p}}dive_check DEFINITION + PUBLIC + FINAL + CREATE PUBLIC. + + PUBLIC SECTION. + TYPES ty_reason TYPE c LENGTH 10. + TYPES ty_cert_level TYPE c LENGTH 1. + + CONSTANTS: + BEGIN OF c_reason, + ok TYPE ty_reason VALUE 'OK', + age TYPE ty_reason VALUE 'AGE', + cert TYPE ty_reason VALUE 'CERT', + depth TYPE ty_reason VALUE 'DEPTH', + dives TYPE ty_reason VALUE 'DIVES', + recent TYPE ty_reason VALUE 'RECENT', + END OF c_reason. + + METHODS check_diver + IMPORTING + iv_cert_level TYPE ty_cert_level + iv_depth TYPE i + iv_dives TYPE i + iv_last_dive TYPE d + iv_dive_date TYPE d + iv_age TYPE i + RETURNING + VALUE(rv_reason) TYPE ty_reason. + + PRIVATE SECTION. + CONSTANTS: + c_min_age TYPE i VALUE 12, + c_deep_depth TYPE i VALUE 30, + c_days_deep TYPE i VALUE 180, + c_days_shallow TYPE i VALUE 365. + + TYPES: + BEGIN OF ty_limit, + cert TYPE ty_cert_level, + max_depth TYPE i, + min_dives TYPE i, + END OF ty_limit, + tt_limit TYPE HASHED TABLE OF ty_limit WITH UNIQUE KEY cert. + + METHODS limits + RETURNING VALUE(rt_limit) TYPE tt_limit. + METHODS days_since_last_dive + IMPORTING iv_last_dive TYPE d + iv_dive_date TYPE d + RETURNING VALUE(rv_days) TYPE i. + METHODS max_days_since_last_dive + IMPORTING iv_depth TYPE i + RETURNING VALUE(rv_days) TYPE i. +ENDCLASS. + + +CLASS {{p}}dive_check IMPLEMENTATION. + METHOD check_diver. + IF iv_age < c_min_age. + rv_reason = c_reason-age. + RETURN. + ENDIF. + + DATA(lt_limit) = limits( ). + READ TABLE lt_limit WITH TABLE KEY cert = iv_cert_level ASSIGNING FIELD-SYMBOL(). + IF sy-subrc <> 0. + rv_reason = c_reason-cert. + RETURN. + ENDIF. + + IF iv_depth > -max_depth. + rv_reason = c_reason-depth. + RETURN. + ENDIF. + + IF iv_dives < -min_dives. + rv_reason = c_reason-dives. + RETURN. + ENDIF. + + IF iv_last_dive IS INITIAL. + rv_reason = c_reason-recent. + RETURN. + ENDIF. + + IF days_since_last_dive( iv_last_dive = iv_last_dive + iv_dive_date = iv_dive_date ) > max_days_since_last_dive( iv_depth ). + rv_reason = c_reason-recent. + RETURN. + ENDIF. + + rv_reason = c_reason-ok. + ENDMETHOD. + + METHOD limits. + rt_limit = VALUE #( ( cert = 'O' max_depth = 19 min_dives = 20 ) + ( cert = 'A' max_depth = 30 min_dives = 50 ) + ( cert = 'R' max_depth = 40 min_dives = 80 ) + ( cert = 'D' max_depth = 40 min_dives = 100 ) ). + ENDMETHOD. + + METHOD days_since_last_dive. + rv_days = iv_dive_date - iv_last_dive. + ENDMETHOD. + + METHOD max_days_since_last_dive. + IF iv_depth > c_deep_depth. + rv_days = c_days_deep. + ELSE. + rv_days = c_days_shallow. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0137/faulty/m3_dive_check.clas.abap b/tasks_gen/eval/G0137/faulty/m3_dive_check.clas.abap new file mode 100644 index 0000000..d524936 --- /dev/null +++ b/tasks_gen/eval/G0137/faulty/m3_dive_check.clas.abap @@ -0,0 +1,114 @@ +CLASS {{p}}dive_check DEFINITION + PUBLIC + FINAL + CREATE PUBLIC. + + PUBLIC SECTION. + TYPES ty_reason TYPE c LENGTH 10. + TYPES ty_cert_level TYPE c LENGTH 1. + + CONSTANTS: + BEGIN OF c_reason, + ok TYPE ty_reason VALUE 'OK', + age TYPE ty_reason VALUE 'AGE', + cert TYPE ty_reason VALUE 'CERT', + depth TYPE ty_reason VALUE 'DEPTH', + dives TYPE ty_reason VALUE 'DIVES', + recent TYPE ty_reason VALUE 'RECENT', + END OF c_reason. + + METHODS check_diver + IMPORTING + iv_cert_level TYPE ty_cert_level + iv_depth TYPE i + iv_dives TYPE i + iv_last_dive TYPE d + iv_dive_date TYPE d + iv_age TYPE i + RETURNING + VALUE(rv_reason) TYPE ty_reason. + + PRIVATE SECTION. + CONSTANTS: + c_min_age TYPE i VALUE 12, + c_deep_depth TYPE i VALUE 30, + c_days_deep TYPE i VALUE 180, + c_days_shallow TYPE i VALUE 365. + + TYPES: + BEGIN OF ty_limit, + cert TYPE ty_cert_level, + max_depth TYPE i, + min_dives TYPE i, + END OF ty_limit, + tt_limit TYPE HASHED TABLE OF ty_limit WITH UNIQUE KEY cert. + + METHODS limits + RETURNING VALUE(rt_limit) TYPE tt_limit. + METHODS days_since_last_dive + IMPORTING iv_last_dive TYPE d + iv_dive_date TYPE d + RETURNING VALUE(rv_days) TYPE i. + METHODS max_days_since_last_dive + IMPORTING iv_depth TYPE i + RETURNING VALUE(rv_days) TYPE i. +ENDCLASS. + + +CLASS {{p}}dive_check IMPLEMENTATION. + METHOD check_diver. + IF iv_age < c_min_age. + rv_reason = c_reason-age. + RETURN. + ENDIF. + + DATA(lt_limit) = limits( ). + READ TABLE lt_limit WITH TABLE KEY cert = iv_cert_level ASSIGNING FIELD-SYMBOL(). + IF sy-subrc <> 0. + rv_reason = c_reason-cert. + RETURN. + ENDIF. + + IF iv_depth > -max_depth. + rv_reason = c_reason-depth. + RETURN. + ENDIF. + + IF iv_dives < -min_dives. + rv_reason = c_reason-dives. + RETURN. + ENDIF. + + IF iv_last_dive IS INITIAL. + rv_reason = c_reason-recent. + RETURN. + ENDIF. + + IF days_since_last_dive( iv_last_dive = iv_last_dive + iv_dive_date = iv_dive_date ) > max_days_since_last_dive( iv_depth ). + rv_reason = c_reason-recent. + RETURN. + ENDIF. + + rv_reason = c_reason-ok. + ENDMETHOD. + + METHOD limits. + rt_limit = VALUE #( ( cert = 'O' max_depth = 18 min_dives = 20 ) + ( cert = 'A' max_depth = 30 min_dives = 51 ) + ( cert = 'R' max_depth = 40 min_dives = 80 ) + ( cert = 'D' max_depth = 40 min_dives = 100 ) ). + ENDMETHOD. + + METHOD days_since_last_dive. + rv_days = iv_dive_date - iv_last_dive. + ENDMETHOD. + + METHOD max_days_since_last_dive. + IF iv_depth > c_deep_depth. + rv_days = c_days_deep. + ELSE. + rv_days = c_days_shallow. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0137/faulty/m4_dive_check.clas.abap b/tasks_gen/eval/G0137/faulty/m4_dive_check.clas.abap new file mode 100644 index 0000000..5ebf90d --- /dev/null +++ b/tasks_gen/eval/G0137/faulty/m4_dive_check.clas.abap @@ -0,0 +1,114 @@ +CLASS {{p}}dive_check DEFINITION + PUBLIC + FINAL + CREATE PUBLIC. + + PUBLIC SECTION. + TYPES ty_reason TYPE c LENGTH 10. + TYPES ty_cert_level TYPE c LENGTH 1. + + CONSTANTS: + BEGIN OF c_reason, + ok TYPE ty_reason VALUE 'OK', + age TYPE ty_reason VALUE 'AGE', + cert TYPE ty_reason VALUE 'CERT', + depth TYPE ty_reason VALUE 'DEPTH', + dives TYPE ty_reason VALUE 'DIVES', + recent TYPE ty_reason VALUE 'RECENT', + END OF c_reason. + + METHODS check_diver + IMPORTING + iv_cert_level TYPE ty_cert_level + iv_depth TYPE i + iv_dives TYPE i + iv_last_dive TYPE d + iv_dive_date TYPE d + iv_age TYPE i + RETURNING + VALUE(rv_reason) TYPE ty_reason. + + PRIVATE SECTION. + CONSTANTS: + c_min_age TYPE i VALUE 12, + c_deep_depth TYPE i VALUE 30, + c_days_deep TYPE i VALUE 180, + c_days_shallow TYPE i VALUE 365. + + TYPES: + BEGIN OF ty_limit, + cert TYPE ty_cert_level, + max_depth TYPE i, + min_dives TYPE i, + END OF ty_limit, + tt_limit TYPE HASHED TABLE OF ty_limit WITH UNIQUE KEY cert. + + METHODS limits + RETURNING VALUE(rt_limit) TYPE tt_limit. + METHODS days_since_last_dive + IMPORTING iv_last_dive TYPE d + iv_dive_date TYPE d + RETURNING VALUE(rv_days) TYPE i. + METHODS max_days_since_last_dive + IMPORTING iv_depth TYPE i + RETURNING VALUE(rv_days) TYPE i. +ENDCLASS. + + +CLASS {{p}}dive_check IMPLEMENTATION. + METHOD check_diver. + IF iv_age < c_min_age. + rv_reason = c_reason-age. + RETURN. + ENDIF. + + DATA(lt_limit) = limits( ). + READ TABLE lt_limit WITH TABLE KEY cert = iv_cert_level ASSIGNING FIELD-SYMBOL(). + IF sy-subrc <> 0. + rv_reason = c_reason-cert. + RETURN. + ENDIF. + + IF iv_depth > -max_depth. + rv_reason = c_reason-depth. + RETURN. + ENDIF. + + IF iv_dives < -min_dives. + rv_reason = c_reason-dives. + RETURN. + ENDIF. + + IF iv_last_dive IS INITIAL. + rv_reason = c_reason-recent. + RETURN. + ENDIF. + + IF days_since_last_dive( iv_last_dive = iv_last_dive + iv_dive_date = iv_dive_date ) > max_days_since_last_dive( iv_depth ). + rv_reason = c_reason-recent. + RETURN. + ENDIF. + + rv_reason = c_reason-ok. + ENDMETHOD. + + METHOD limits. + rt_limit = VALUE #( ( cert = 'O' max_depth = 18 min_dives = 20 ) + ( cert = 'A' max_depth = 30 min_dives = 50 ) + ( cert = 'R' max_depth = 40 min_dives = 80 ) + ( cert = 'D' max_depth = 40 min_dives = 100 ) ). + ENDMETHOD. + + METHOD days_since_last_dive. + rv_days = iv_dive_date + iv_last_dive. + ENDMETHOD. + + METHOD max_days_since_last_dive. + IF iv_depth > c_deep_depth. + rv_days = c_days_deep. + ELSE. + rv_days = c_days_shallow. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0137/generation.json b/tasks_gen/eval/G0137/generation.json new file mode 100644 index 0000000..a277468 --- /dev/null +++ b/tasks_gen/eval/G0137/generation.json @@ -0,0 +1,19 @@ +{ + "id": "G0137", + "pool": "eval", + "object_type": "CLAS", + "category": "E", + "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/eval/G0137/hidden/t12_hidden.clas.abap b/tasks_gen/eval/G0137/hidden/t12_hidden.clas.abap new file mode 100644 index 0000000..67f80bf --- /dev/null +++ b/tasks_gen/eval/G0137/hidden/t12_hidden.clas.abap @@ -0,0 +1,171 @@ +CLASS {{p}}t12_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + + PRIVATE SECTION. + CONSTANTS: + c_dive_date TYPE d VALUE '20250401', + c_recent TYPE d VALUE '20250201'. + DATA mo_cut TYPE REF TO {{p}}dive_check. + METHODS setup. + METHODS valid_dive_is_ok FOR TESTING. + METHODS valid_all_certs FOR TESTING. + METHODS too_young FOR TESTING. + METHODS age_before_cert FOR TESTING. + METHODS unknown_cert FOR TESTING. + METHODS cert_before_depth FOR TESTING. + METHODS depth_limits FOR TESTING. + METHODS dive_minimums FOR TESTING. + METHODS stale_last_dive FOR TESTING. + METHODS recent_dive_ok FOR TESTING. + METHODS deep_dive_recent FOR TESTING. + METHODS last_dive_missing FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t12_hidden IMPLEMENTATION. + METHOD setup. + mo_cut = NEW {{p}}dive_check( ). + ENDMETHOD. + + METHOD valid_dive_is_ok. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}dive_check=>c_reason-ok + act = mo_cut->check_diver( iv_cert_level = 'A' + iv_depth = 25 + iv_dives = 60 + iv_last_dive = c_recent + iv_dive_date = c_dive_date + iv_age = 30 ) ). + ENDMETHOD. + + METHOD valid_all_certs. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}dive_check=>c_reason-ok + act = mo_cut->check_diver( iv_cert_level = 'O' iv_depth = 18 iv_dives = 20 + iv_last_dive = c_recent iv_dive_date = c_dive_date iv_age = 30 ) + msg = `O` ). + cl_abap_unit_assert=>assert_equals( + exp = {{p}}dive_check=>c_reason-ok + act = mo_cut->check_diver( iv_cert_level = 'A' iv_depth = 30 iv_dives = 50 + iv_last_dive = c_recent iv_dive_date = c_dive_date iv_age = 30 ) + msg = `A` ). + cl_abap_unit_assert=>assert_equals( + exp = {{p}}dive_check=>c_reason-ok + act = mo_cut->check_diver( iv_cert_level = 'R' iv_depth = 40 iv_dives = 80 + iv_last_dive = c_recent iv_dive_date = c_dive_date iv_age = 30 ) + msg = `R` ). + cl_abap_unit_assert=>assert_equals( + exp = {{p}}dive_check=>c_reason-ok + act = mo_cut->check_diver( iv_cert_level = 'D' iv_depth = 40 iv_dives = 100 + iv_last_dive = c_recent iv_dive_date = c_dive_date iv_age = 30 ) + msg = `D` ). + ENDMETHOD. + + METHOD too_young. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}dive_check=>c_reason-age + act = mo_cut->check_diver( iv_cert_level = 'A' iv_depth = 25 iv_dives = 60 + iv_last_dive = c_recent iv_dive_date = c_dive_date iv_age = 11 ) ). + ENDMETHOD. + + METHOD age_before_cert. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}dive_check=>c_reason-age + act = mo_cut->check_diver( iv_cert_level = 'X' iv_depth = 100 iv_dives = 0 + iv_last_dive = c_recent iv_dive_date = c_dive_date iv_age = 11 ) ). + ENDMETHOD. + + METHOD unknown_cert. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}dive_check=>c_reason-cert + act = mo_cut->check_diver( iv_cert_level = 'X' iv_depth = 10 iv_dives = 100 + iv_last_dive = c_recent iv_dive_date = c_dive_date iv_age = 30 ) ). + ENDMETHOD. + + METHOD cert_before_depth. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}dive_check=>c_reason-cert + act = mo_cut->check_diver( iv_cert_level = 'X' iv_depth = 100 iv_dives = 0 + iv_last_dive = c_recent iv_dive_date = c_dive_date iv_age = 30 ) ). + ENDMETHOD. + + METHOD depth_limits. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}dive_check=>c_reason-ok + act = mo_cut->check_diver( iv_cert_level = 'O' iv_depth = 18 iv_dives = 20 + iv_last_dive = c_recent iv_dive_date = c_dive_date iv_age = 30 ) + msg = `O at limit` ). + cl_abap_unit_assert=>assert_equals( + exp = {{p}}dive_check=>c_reason-depth + act = mo_cut->check_diver( iv_cert_level = 'O' iv_depth = 19 iv_dives = 20 + iv_last_dive = c_recent iv_dive_date = c_dive_date iv_age = 30 ) + msg = `O over limit` ). + cl_abap_unit_assert=>assert_equals( + exp = {{p}}dive_check=>c_reason-ok + act = mo_cut->check_diver( iv_cert_level = 'A' iv_depth = 30 iv_dives = 50 + iv_last_dive = c_recent iv_dive_date = c_dive_date iv_age = 30 ) + msg = `A at limit` ). + cl_abap_unit_assert=>assert_equals( + exp = {{p}}dive_check=>c_reason-depth + act = mo_cut->check_diver( iv_cert_level = 'A' iv_depth = 31 iv_dives = 50 + iv_last_dive = c_recent iv_dive_date = c_dive_date iv_age = 30 ) + msg = `A over limit` ). + ENDMETHOD. + + METHOD dive_minimums. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}dive_check=>c_reason-ok + act = mo_cut->check_diver( iv_cert_level = 'O' iv_depth = 10 iv_dives = 20 + iv_last_dive = c_recent iv_dive_date = c_dive_date iv_age = 30 ) + msg = `O at minimum` ). + cl_abap_unit_assert=>assert_equals( + exp = {{p}}dive_check=>c_reason-dives + act = mo_cut->check_diver( iv_cert_level = 'O' iv_depth = 10 iv_dives = 19 + iv_last_dive = c_recent iv_dive_date = c_dive_date iv_age = 30 ) + msg = `O below minimum` ). + cl_abap_unit_assert=>assert_equals( + exp = {{p}}dive_check=>c_reason-ok + act = mo_cut->check_diver( iv_cert_level = 'D' iv_depth = 10 iv_dives = 100 + iv_last_dive = c_recent iv_dive_date = c_dive_date iv_age = 30 ) + msg = `D at minimum` ). + cl_abap_unit_assert=>assert_equals( + exp = {{p}}dive_check=>c_reason-dives + act = mo_cut->check_diver( iv_cert_level = 'D' iv_depth = 10 iv_dives = 99 + iv_last_dive = c_recent iv_dive_date = c_dive_date iv_age = 30 ) + msg = `D below minimum` ). + ENDMETHOD. + + METHOD stale_last_dive. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}dive_check=>c_reason-recent + act = mo_cut->check_diver( iv_cert_level = 'A' iv_depth = 25 iv_dives = 60 + iv_last_dive = '20240101' iv_dive_date = c_dive_date iv_age = 30 ) ). + ENDMETHOD. + + METHOD recent_dive_ok. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}dive_check=>c_reason-ok + act = mo_cut->check_diver( iv_cert_level = 'A' iv_depth = 25 iv_dives = 60 + iv_last_dive = '20240601' iv_dive_date = c_dive_date iv_age = 30 ) ). + ENDMETHOD. + + METHOD deep_dive_recent. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}dive_check=>c_reason-recent + act = mo_cut->check_diver( iv_cert_level = 'R' iv_depth = 35 iv_dives = 80 + iv_last_dive = '20240913' iv_dive_date = c_dive_date iv_age = 30 ) + msg = `200 days` ). + cl_abap_unit_assert=>assert_equals( + exp = {{p}}dive_check=>c_reason-ok + act = mo_cut->check_diver( iv_cert_level = 'R' iv_depth = 35 iv_dives = 80 + iv_last_dive = '20241003' iv_dive_date = c_dive_date iv_age = 30 ) + msg = `180 days` ). + ENDMETHOD. + + METHOD last_dive_missing. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}dive_check=>c_reason-recent + act = mo_cut->check_diver( iv_cert_level = 'A' iv_depth = 25 iv_dives = 60 + iv_last_dive = '00000000' iv_dive_date = c_dive_date iv_age = 30 ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0137/mutation.json b/tasks_gen/eval/G0137/mutation.json new file mode 100644 index 0000000..b4670f0 --- /dev/null +++ b/tasks_gen/eval/G0137/mutation.json @@ -0,0 +1,64 @@ +{ + "task": "G0137", + "mutants": [ + { + "object": "{{P}}DIVE_CHECK", + "mutant": "line 87: = -> <> (eq)", + "status": "invalid", + "hidden": "0/0", + "failed_tests": [] + }, + { + "object": "{{P}}DIVE_CHECK", + "mutant": "line 88: > -> <= (rel)", + "status": "killed", + "hidden": "5/12", + "failed_tests": [ + "DEEP_DIVE_RECENT", + "DEPTH_LIMITS", + "DIVE_MINIMUMS", + "RECENT_DIVE_OK", + "STALE_LAST_DIVE", + "VALID_ALL_CERTS", + "VALID_DIVE_IS_OK" + ] + }, + { + "object": "{{P}}DIVE_CHECK", + "mutant": "line 97: 18 -> 19 (const)", + "status": "killed", + "hidden": "11/12", + "failed_tests": [ + "DEPTH_LIMITS" + ] + }, + { + "object": "{{P}}DIVE_CHECK", + "mutant": "line 98: 50 -> 51 (const)", + "status": "killed", + "hidden": "10/12", + "failed_tests": [ + "DEPTH_LIMITS", + "VALID_ALL_CERTS" + ] + }, + { + "object": "{{P}}DIVE_CHECK", + "mutant": "line 104: - -> + (arith)", + "status": "killed", + "hidden": "6/12", + "failed_tests": [ + "DEEP_DIVE_RECENT", + "DEPTH_LIMITS", + "DIVE_MINIMUMS", + "RECENT_DIVE_OK", + "VALID_ALL_CERTS", + "VALID_DIVE_IS_OK" + ] + } + ], + "valid": 4, + "killed": 4, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0137/reference/dive_check.clas.abap b/tasks_gen/eval/G0137/reference/dive_check.clas.abap new file mode 100644 index 0000000..12679b6 --- /dev/null +++ b/tasks_gen/eval/G0137/reference/dive_check.clas.abap @@ -0,0 +1,114 @@ +CLASS {{p}}dive_check DEFINITION + PUBLIC + FINAL + CREATE PUBLIC. + + PUBLIC SECTION. + TYPES ty_reason TYPE c LENGTH 10. + TYPES ty_cert_level TYPE c LENGTH 1. + + CONSTANTS: + BEGIN OF c_reason, + ok TYPE ty_reason VALUE 'OK', + age TYPE ty_reason VALUE 'AGE', + cert TYPE ty_reason VALUE 'CERT', + depth TYPE ty_reason VALUE 'DEPTH', + dives TYPE ty_reason VALUE 'DIVES', + recent TYPE ty_reason VALUE 'RECENT', + END OF c_reason. + + METHODS check_diver + IMPORTING + iv_cert_level TYPE ty_cert_level + iv_depth TYPE i + iv_dives TYPE i + iv_last_dive TYPE d + iv_dive_date TYPE d + iv_age TYPE i + RETURNING + VALUE(rv_reason) TYPE ty_reason. + + PRIVATE SECTION. + CONSTANTS: + c_min_age TYPE i VALUE 12, + c_deep_depth TYPE i VALUE 30, + c_days_deep TYPE i VALUE 180, + c_days_shallow TYPE i VALUE 365. + + TYPES: + BEGIN OF ty_limit, + cert TYPE ty_cert_level, + max_depth TYPE i, + min_dives TYPE i, + END OF ty_limit, + tt_limit TYPE HASHED TABLE OF ty_limit WITH UNIQUE KEY cert. + + METHODS limits + RETURNING VALUE(rt_limit) TYPE tt_limit. + METHODS days_since_last_dive + IMPORTING iv_last_dive TYPE d + iv_dive_date TYPE d + RETURNING VALUE(rv_days) TYPE i. + METHODS max_days_since_last_dive + IMPORTING iv_depth TYPE i + RETURNING VALUE(rv_days) TYPE i. +ENDCLASS. + + +CLASS {{p}}dive_check IMPLEMENTATION. + METHOD check_diver. + IF iv_age < c_min_age. + rv_reason = c_reason-age. + RETURN. + ENDIF. + + DATA(lt_limit) = limits( ). + READ TABLE lt_limit WITH TABLE KEY cert = iv_cert_level ASSIGNING FIELD-SYMBOL(). + IF sy-subrc <> 0. + rv_reason = c_reason-cert. + RETURN. + ENDIF. + + IF iv_depth > -max_depth. + rv_reason = c_reason-depth. + RETURN. + ENDIF. + + IF iv_dives < -min_dives. + rv_reason = c_reason-dives. + RETURN. + ENDIF. + + IF iv_last_dive IS INITIAL. + rv_reason = c_reason-recent. + RETURN. + ENDIF. + + IF days_since_last_dive( iv_last_dive = iv_last_dive + iv_dive_date = iv_dive_date ) > max_days_since_last_dive( iv_depth ). + rv_reason = c_reason-recent. + RETURN. + ENDIF. + + rv_reason = c_reason-ok. + ENDMETHOD. + + METHOD limits. + rt_limit = VALUE #( ( cert = 'O' max_depth = 18 min_dives = 20 ) + ( cert = 'A' max_depth = 30 min_dives = 50 ) + ( cert = 'R' max_depth = 40 min_dives = 80 ) + ( cert = 'D' max_depth = 40 min_dives = 100 ) ). + ENDMETHOD. + + METHOD days_since_last_dive. + rv_days = iv_dive_date - iv_last_dive. + ENDMETHOD. + + METHOD max_days_since_last_dive. + IF iv_depth > c_deep_depth. + rv_days = c_days_deep. + ELSE. + rv_days = c_days_shallow. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0137/reference/dive_check.testclasses.abap b/tasks_gen/eval/G0137/reference/dive_check.testclasses.abap new file mode 100644 index 0000000..07f247a --- /dev/null +++ b/tasks_gen/eval/G0137/reference/dive_check.testclasses.abap @@ -0,0 +1,75 @@ +CLASS ltc_dive_check DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + CONSTANTS: + c_dive_date TYPE d VALUE '20250401', + c_recent TYPE d VALUE '20250201'. + DATA mo_cut TYPE REF TO {{p}}dive_check. + METHODS setup. + METHODS valid_dive_is_ok FOR TESTING. + METHODS too_young FOR TESTING. + METHODS unknown_cert FOR TESTING. + METHODS too_few_dives FOR TESTING. + METHODS stale_last_dive FOR TESTING. +ENDCLASS. + + +CLASS ltc_dive_check IMPLEMENTATION. + METHOD setup. + mo_cut = NEW {{p}}dive_check( ). + ENDMETHOD. + + METHOD valid_dive_is_ok. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}dive_check=>c_reason-ok + act = mo_cut->check_diver( iv_cert_level = 'A' + iv_depth = 25 + iv_dives = 60 + iv_last_dive = c_recent + iv_dive_date = c_dive_date + iv_age = 30 ) ). + ENDMETHOD. + + METHOD too_young. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}dive_check=>c_reason-age + act = mo_cut->check_diver( iv_cert_level = 'A' + iv_depth = 25 + iv_dives = 60 + iv_last_dive = c_recent + iv_dive_date = c_dive_date + iv_age = 11 ) ). + ENDMETHOD. + + METHOD unknown_cert. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}dive_check=>c_reason-cert + act = mo_cut->check_diver( iv_cert_level = 'X' + iv_depth = 10 + iv_dives = 100 + iv_last_dive = c_recent + iv_dive_date = c_dive_date + iv_age = 30 ) ). + ENDMETHOD. + + METHOD too_few_dives. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}dive_check=>c_reason-dives + act = mo_cut->check_diver( iv_cert_level = 'A' + iv_depth = 25 + iv_dives = 49 + iv_last_dive = c_recent + iv_dive_date = c_dive_date + iv_age = 30 ) ). + ENDMETHOD. + + METHOD stale_last_dive. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}dive_check=>c_reason-recent + act = mo_cut->check_diver( iv_cert_level = 'A' + iv_depth = 25 + iv_dives = 60 + iv_last_dive = '20240101' + iv_dive_date = c_dive_date + iv_age = 30 ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0137/seed/dive_check.clas.abap b/tasks_gen/eval/G0137/seed/dive_check.clas.abap new file mode 100644 index 0000000..5ac718f --- /dev/null +++ b/tasks_gen/eval/G0137/seed/dive_check.clas.abap @@ -0,0 +1,94 @@ +CLASS {{p}}dive_check DEFINITION + PUBLIC + FINAL + CREATE PUBLIC. + + PUBLIC SECTION. + TYPES ty_reason TYPE c LENGTH 10. + TYPES ty_cert_level TYPE c LENGTH 1. + + CONSTANTS: + BEGIN OF c_reason, + ok TYPE ty_reason VALUE 'OK', + age TYPE ty_reason VALUE 'AGE', + cert TYPE ty_reason VALUE 'CERT', + depth TYPE ty_reason VALUE 'DEPTH', + dives TYPE ty_reason VALUE 'DIVES', + recent TYPE ty_reason VALUE 'RECENT', + END OF c_reason. + + METHODS check_diver + IMPORTING + iv_cert_level TYPE ty_cert_level + iv_depth TYPE i + iv_dives TYPE i + iv_last_dive TYPE d + iv_dive_date TYPE d + iv_age TYPE i + RETURNING + VALUE(rv_reason) TYPE ty_reason. +ENDCLASS. + + +CLASS {{p}}dive_check IMPLEMENTATION. + METHOD check_diver. + DATA lv_max_depth TYPE i. + DATA lv_min_dives TYPE i. + DATA lv_days TYPE i. + DATA lv_known TYPE c LENGTH 1. + + rv_reason = c_reason-ok. + + IF iv_age < 12. + rv_reason = c_reason-age. + ELSE. + IF iv_cert_level = 'O'. + lv_max_depth = 18. + lv_min_dives = 20. + lv_known = 'X'. + ELSEIF iv_cert_level = 'A'. + lv_max_depth = 30. + lv_min_dives = 50. + lv_known = 'X'. + ELSEIF iv_cert_level = 'R'. + lv_max_depth = 40. + lv_min_dives = 80. + lv_known = 'X'. + ELSEIF iv_cert_level = 'D'. + lv_max_depth = 40. + lv_min_dives = 100. + lv_known = 'X'. + ELSE. + lv_known = ' '. + ENDIF. + + IF lv_known <> 'X'. + rv_reason = c_reason-cert. + ELSE. + IF iv_depth > lv_max_depth. + rv_reason = c_reason-depth. + ELSE. + IF iv_dives < lv_min_dives. + rv_reason = c_reason-dives. + ELSE. + IF iv_last_dive IS INITIAL. + rv_reason = c_reason-recent. + ELSE. + IF iv_depth > 30. + lv_days = iv_dive_date - iv_last_dive. + IF lv_days > 180. + rv_reason = c_reason-recent. + ENDIF. + ELSE. + lv_days = iv_dive_date - iv_last_dive. + IF lv_days > 365. + rv_reason = c_reason-recent. + ENDIF. + ENDIF. + ENDIF. + ENDIF. + ENDIF. + ENDIF. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0137/spec.md b/tasks_gen/eval/G0137/spec.md new file mode 100644 index 0000000..c111937 --- /dev/null +++ b/tasks_gen/eval/G0137/spec.md @@ -0,0 +1,56 @@ +# 1. Goal +Refactor the legacy class {{P}}DIVE_CHECK. The class checks if a diver may join a +guided dive. A booking program calls the check before it confirms the dive. +The behavior of the class stays the same. Improve the structure and the +readability of the code. + +# 2. Open questions +None. + +# 3. Context +- The class {{P}}DIVE_CHECK exists in package $TMP. It is active. +- A booking program uses the class. The public interface of the class is fixed. +- The class contains legacy code: one long method, deep nesting, hard-coded + numbers, and duplicated statements. Users report no defect. The task is a + refactoring, not a repair. +- Read the current source of the class before you change it. + +# 4. Contract +The class {{P}}DIVE_CHECK stays in package $TMP. The class stays public and +final. Do not change the public interface. +- Public type TY_REASON: type c, length 10. +- Public type TY_CERT_LEVEL: type c, length 1. +- Public constant structure C_REASON with the components OK, AGE, CERT, DEPTH, + DIVES, and RECENT. The component type is TY_REASON. Do not change the values. +- Public instance method CHECK_DIVER with this signature: + IMPORTING + iv_cert_level TYPE ty_cert_level + iv_depth TYPE i + iv_dives TYPE i + iv_last_dive TYPE d + iv_dive_date TYPE d + iv_age TYPE i + RETURNING + VALUE(rv_reason) TYPE ty_reason. +- Do not add other public components. Do not remove a public component. + +# 5. Business rules +- The class keeps its current behavior. Read the legacy code and keep every + rule, the sequence of the rules, and every limit. +- Do not add a rule. Do not remove a rule. Do not change a limit. Do not change + the sequence of the rules. +- The method returns the reason of the first rule that fails. If no rule fails, + the method returns OK. + +# 6. Constraints +- Release target: SAP_BASIS 816 (ABAP Platform 2025). +- Coding standards: Clean ABAP. Methods below 40 statements. No global + variables. No comment that restates the code. No ATC priority 1 or priority 2 + finding. +- Out of scope: do not change the public interface. Do not create other + objects. Do not change the behavior. + +# 7. Acceptance +- The class {{P}}DIVE_CHECK is active and has no syntax error. +- The hidden tests pass. +- Write your own ABAP Unit tests as local test classes of the class. diff --git a/tasks_gen/eval/G0137/task.json b/tasks_gen/eval/G0137/task.json new file mode 100644 index 0000000..41e1417 --- /dev/null +++ b/tasks_gen/eval/G0137/task.json @@ -0,0 +1,48 @@ +{ + "id": "G0137", + "category": "E", + "object_type": "CLAS", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [ + { + "type": "CLAS", + "name": "{{P}}DIVE_CHECK", + "file": "seed/dive_check.clas.abap", + "description": "Legacy dive check class with one long nested method" + } + ], + "contract": [ + { + "type": "CLAS", + "name": "{{P}}DIVE_CHECK" + } + ], + "out_of_scope": [], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T12_HIDDEN", + "file": "hidden/t12_hidden.clas.abap", + "description": "T12 hidden tests for the unchanged dive check behavior" + } + ], + "reference": [ + { + "type": "CLAS", + "name": "{{P}}DIVE_CHECK", + "file": "reference/dive_check.clas.abap", + "description": "Refactored dive check class", + "testclasses_file": "reference/dive_check.testclasses.abap" + } + ], + "craft_checks": [ + "method_length", + "cyclomatic_complexity" + ] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0138/faulty/m0_cake_pricer.clas.abap b/tasks_gen/eval/G0138/faulty/m0_cake_pricer.clas.abap new file mode 100644 index 0000000..96aec69 --- /dev/null +++ b/tasks_gen/eval/G0138/faulty/m0_cake_pricer.clas.abap @@ -0,0 +1,125 @@ +CLASS {{p}}cake_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES ty_price TYPE p LENGTH 8 DECIMALS 2. + TYPES ty_filling TYPE c LENGTH 1. + TYPES ty_decoration TYPE c LENGTH 1. + + METHODS calculate_price + IMPORTING iv_size TYPE i + iv_layers TYPE i + iv_filling TYPE ty_filling + iv_decoration TYPE ty_decoration + iv_express TYPE abap_bool + RETURNING VALUE(rv_price) TYPE ty_price. + + PRIVATE SECTION. + CONSTANTS: + c_base_price TYPE ty_price VALUE '12.00', + c_min_price TYPE ty_price VALUE '15.00', + c_min_size TYPE i VALUE 16, + c_free_size TYPE i VALUE 20, + c_photo_size TYPE i VALUE 24, + c_size_rate TYPE ty_price VALUE '0.80', + c_layer_rate TYPE ty_price VALUE '4.50', + c_express_rate TYPE ty_price VALUE '1.25', + c_filling_plain TYPE ty_price VALUE '3.00', + c_filling_choc TYPE ty_price VALUE '4.00', + c_filling_fruit TYPE ty_price VALUE '5.50', + c_deco_flowers TYPE ty_price VALUE '6.00', + c_deco_photo TYPE ty_price VALUE '9.50', + c_deco_sugar TYPE ty_price VALUE '12.00'. + + METHODS clamp_size + IMPORTING iv_size TYPE i + RETURNING VALUE(rv_size) TYPE i. + METHODS clamp_layers + IMPORTING iv_layers TYPE i + RETURNING VALUE(rv_layers) TYPE i. + METHODS size_surcharge + IMPORTING iv_size TYPE i + RETURNING VALUE(rv_amount) TYPE ty_price. + METHODS layer_surcharge + IMPORTING iv_layers TYPE i + RETURNING VALUE(rv_amount) TYPE ty_price. + METHODS filling_surcharge + IMPORTING iv_filling TYPE ty_filling + RETURNING VALUE(rv_amount) TYPE ty_price. + METHODS decoration_surcharge + IMPORTING iv_decoration TYPE ty_decoration + iv_size TYPE i + RETURNING VALUE(rv_amount) TYPE ty_price. + METHODS apply_express + IMPORTING iv_amount TYPE ty_price + RETURNING VALUE(rv_amount) TYPE ty_price. +ENDCLASS. + + +CLASS {{p}}cake_pricer IMPLEMENTATION. + METHOD calculate_price. + DATA(lv_size) = clamp_size( iv_size ). + DATA(lv_price) = c_base_price. + lv_price = lv_price + size_surcharge( lv_size ). + lv_price = lv_price - layer_surcharge( clamp_layers( iv_layers ) ). + lv_price = lv_price + filling_surcharge( iv_filling ). + lv_price = lv_price + decoration_surcharge( iv_decoration = iv_decoration + iv_size = lv_size ). + IF iv_express = abap_true. + lv_price = apply_express( lv_price ). + ENDIF. + IF lv_price < c_min_price. + rv_price = c_min_price. + ELSE. + rv_price = lv_price. + ENDIF. + ENDMETHOD. + + METHOD clamp_size. + rv_size = nmax( val1 = iv_size val2 = c_min_size ). + ENDMETHOD. + + METHOD clamp_layers. + rv_layers = nmax( val1 = iv_layers val2 = 1 ). + ENDMETHOD. + + METHOD size_surcharge. + IF iv_size > c_free_size. + rv_amount = ( iv_size - c_free_size ) * c_size_rate. + ENDIF. + ENDMETHOD. + + METHOD layer_surcharge. + IF iv_layers > 1. + rv_amount = ( iv_layers - 1 ) * c_layer_rate. + ENDIF. + ENDMETHOD. + + METHOD filling_surcharge. + CASE iv_filling. + WHEN 'C'. + rv_amount = c_filling_choc. + WHEN 'F'. + rv_amount = c_filling_fruit. + WHEN 'N'. + CLEAR rv_amount. + WHEN OTHERS. + rv_amount = c_filling_plain. + ENDCASE. + ENDMETHOD. + + METHOD decoration_surcharge. + CASE iv_decoration. + WHEN 'F'. + rv_amount = c_deco_flowers. + WHEN 'P'. + IF iv_size >= c_photo_size. + rv_amount = c_deco_photo. + ENDIF. + WHEN 'S'. + rv_amount = c_deco_sugar. + ENDCASE. + ENDMETHOD. + + METHOD apply_express. + rv_amount = round( val = iv_amount * c_express_rate dec = 2 ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0138/faulty/m1_cake_pricer.clas.abap b/tasks_gen/eval/G0138/faulty/m1_cake_pricer.clas.abap new file mode 100644 index 0000000..184d941 --- /dev/null +++ b/tasks_gen/eval/G0138/faulty/m1_cake_pricer.clas.abap @@ -0,0 +1,125 @@ +CLASS {{p}}cake_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES ty_price TYPE p LENGTH 8 DECIMALS 2. + TYPES ty_filling TYPE c LENGTH 1. + TYPES ty_decoration TYPE c LENGTH 1. + + METHODS calculate_price + IMPORTING iv_size TYPE i + iv_layers TYPE i + iv_filling TYPE ty_filling + iv_decoration TYPE ty_decoration + iv_express TYPE abap_bool + RETURNING VALUE(rv_price) TYPE ty_price. + + PRIVATE SECTION. + CONSTANTS: + c_base_price TYPE ty_price VALUE '12.00', + c_min_price TYPE ty_price VALUE '15.00', + c_min_size TYPE i VALUE 16, + c_free_size TYPE i VALUE 20, + c_photo_size TYPE i VALUE 24, + c_size_rate TYPE ty_price VALUE '0.80', + c_layer_rate TYPE ty_price VALUE '4.50', + c_express_rate TYPE ty_price VALUE '1.25', + c_filling_plain TYPE ty_price VALUE '3.00', + c_filling_choc TYPE ty_price VALUE '4.00', + c_filling_fruit TYPE ty_price VALUE '5.50', + c_deco_flowers TYPE ty_price VALUE '6.00', + c_deco_photo TYPE ty_price VALUE '9.50', + c_deco_sugar TYPE ty_price VALUE '12.00'. + + METHODS clamp_size + IMPORTING iv_size TYPE i + RETURNING VALUE(rv_size) TYPE i. + METHODS clamp_layers + IMPORTING iv_layers TYPE i + RETURNING VALUE(rv_layers) TYPE i. + METHODS size_surcharge + IMPORTING iv_size TYPE i + RETURNING VALUE(rv_amount) TYPE ty_price. + METHODS layer_surcharge + IMPORTING iv_layers TYPE i + RETURNING VALUE(rv_amount) TYPE ty_price. + METHODS filling_surcharge + IMPORTING iv_filling TYPE ty_filling + RETURNING VALUE(rv_amount) TYPE ty_price. + METHODS decoration_surcharge + IMPORTING iv_decoration TYPE ty_decoration + iv_size TYPE i + RETURNING VALUE(rv_amount) TYPE ty_price. + METHODS apply_express + IMPORTING iv_amount TYPE ty_price + RETURNING VALUE(rv_amount) TYPE ty_price. +ENDCLASS. + + +CLASS {{p}}cake_pricer IMPLEMENTATION. + METHOD calculate_price. + DATA(lv_size) = clamp_size( iv_size ). + DATA(lv_price) = c_base_price. + lv_price = lv_price + size_surcharge( lv_size ). + lv_price = lv_price + layer_surcharge( clamp_layers( iv_layers ) ). + lv_price = lv_price + filling_surcharge( iv_filling ). + lv_price = lv_price + decoration_surcharge( iv_decoration = iv_decoration + iv_size = lv_size ). + IF iv_express <> abap_true. + lv_price = apply_express( lv_price ). + ENDIF. + IF lv_price < c_min_price. + rv_price = c_min_price. + ELSE. + rv_price = lv_price. + ENDIF. + ENDMETHOD. + + METHOD clamp_size. + rv_size = nmax( val1 = iv_size val2 = c_min_size ). + ENDMETHOD. + + METHOD clamp_layers. + rv_layers = nmax( val1 = iv_layers val2 = 1 ). + ENDMETHOD. + + METHOD size_surcharge. + IF iv_size > c_free_size. + rv_amount = ( iv_size - c_free_size ) * c_size_rate. + ENDIF. + ENDMETHOD. + + METHOD layer_surcharge. + IF iv_layers > 1. + rv_amount = ( iv_layers - 1 ) * c_layer_rate. + ENDIF. + ENDMETHOD. + + METHOD filling_surcharge. + CASE iv_filling. + WHEN 'C'. + rv_amount = c_filling_choc. + WHEN 'F'. + rv_amount = c_filling_fruit. + WHEN 'N'. + CLEAR rv_amount. + WHEN OTHERS. + rv_amount = c_filling_plain. + ENDCASE. + ENDMETHOD. + + METHOD decoration_surcharge. + CASE iv_decoration. + WHEN 'F'. + rv_amount = c_deco_flowers. + WHEN 'P'. + IF iv_size >= c_photo_size. + rv_amount = c_deco_photo. + ENDIF. + WHEN 'S'. + rv_amount = c_deco_sugar. + ENDCASE. + ENDMETHOD. + + METHOD apply_express. + rv_amount = round( val = iv_amount * c_express_rate dec = 2 ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0138/faulty/m2_cake_pricer.clas.abap b/tasks_gen/eval/G0138/faulty/m2_cake_pricer.clas.abap new file mode 100644 index 0000000..012d2cd --- /dev/null +++ b/tasks_gen/eval/G0138/faulty/m2_cake_pricer.clas.abap @@ -0,0 +1,125 @@ +CLASS {{p}}cake_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES ty_price TYPE p LENGTH 8 DECIMALS 2. + TYPES ty_filling TYPE c LENGTH 1. + TYPES ty_decoration TYPE c LENGTH 1. + + METHODS calculate_price + IMPORTING iv_size TYPE i + iv_layers TYPE i + iv_filling TYPE ty_filling + iv_decoration TYPE ty_decoration + iv_express TYPE abap_bool + RETURNING VALUE(rv_price) TYPE ty_price. + + PRIVATE SECTION. + CONSTANTS: + c_base_price TYPE ty_price VALUE '12.00', + c_min_price TYPE ty_price VALUE '15.00', + c_min_size TYPE i VALUE 16, + c_free_size TYPE i VALUE 20, + c_photo_size TYPE i VALUE 24, + c_size_rate TYPE ty_price VALUE '0.80', + c_layer_rate TYPE ty_price VALUE '4.50', + c_express_rate TYPE ty_price VALUE '1.25', + c_filling_plain TYPE ty_price VALUE '3.00', + c_filling_choc TYPE ty_price VALUE '4.00', + c_filling_fruit TYPE ty_price VALUE '5.50', + c_deco_flowers TYPE ty_price VALUE '6.00', + c_deco_photo TYPE ty_price VALUE '9.50', + c_deco_sugar TYPE ty_price VALUE '12.00'. + + METHODS clamp_size + IMPORTING iv_size TYPE i + RETURNING VALUE(rv_size) TYPE i. + METHODS clamp_layers + IMPORTING iv_layers TYPE i + RETURNING VALUE(rv_layers) TYPE i. + METHODS size_surcharge + IMPORTING iv_size TYPE i + RETURNING VALUE(rv_amount) TYPE ty_price. + METHODS layer_surcharge + IMPORTING iv_layers TYPE i + RETURNING VALUE(rv_amount) TYPE ty_price. + METHODS filling_surcharge + IMPORTING iv_filling TYPE ty_filling + RETURNING VALUE(rv_amount) TYPE ty_price. + METHODS decoration_surcharge + IMPORTING iv_decoration TYPE ty_decoration + iv_size TYPE i + RETURNING VALUE(rv_amount) TYPE ty_price. + METHODS apply_express + IMPORTING iv_amount TYPE ty_price + RETURNING VALUE(rv_amount) TYPE ty_price. +ENDCLASS. + + +CLASS {{p}}cake_pricer IMPLEMENTATION. + METHOD calculate_price. + DATA(lv_size) = clamp_size( iv_size ). + DATA(lv_price) = c_base_price. + lv_price = lv_price + size_surcharge( lv_size ). + lv_price = lv_price + layer_surcharge( clamp_layers( iv_layers ) ). + lv_price = lv_price + filling_surcharge( iv_filling ). + lv_price = lv_price + decoration_surcharge( iv_decoration = iv_decoration + iv_size = lv_size ). + IF iv_express = abap_true. + lv_price = apply_express( lv_price ). + ENDIF. + IF lv_price < c_min_price. + rv_price = c_min_price. + ELSE. + rv_price = lv_price. + ENDIF. + ENDMETHOD. + + METHOD clamp_size. + rv_size = nmax( val1 = iv_size val2 = c_min_size ). + ENDMETHOD. + + METHOD clamp_layers. + rv_layers = nmax( val1 = iv_layers val2 = 1 ). + ENDMETHOD. + + METHOD size_surcharge. + IF iv_size > c_free_size. + rv_amount = ( iv_size - c_free_size ) * c_size_rate. + ENDIF. + ENDMETHOD. + + METHOD layer_surcharge. + IF iv_layers <= 1. + rv_amount = ( iv_layers - 1 ) * c_layer_rate. + ENDIF. + ENDMETHOD. + + METHOD filling_surcharge. + CASE iv_filling. + WHEN 'C'. + rv_amount = c_filling_choc. + WHEN 'F'. + rv_amount = c_filling_fruit. + WHEN 'N'. + CLEAR rv_amount. + WHEN OTHERS. + rv_amount = c_filling_plain. + ENDCASE. + ENDMETHOD. + + METHOD decoration_surcharge. + CASE iv_decoration. + WHEN 'F'. + rv_amount = c_deco_flowers. + WHEN 'P'. + IF iv_size >= c_photo_size. + rv_amount = c_deco_photo. + ENDIF. + WHEN 'S'. + rv_amount = c_deco_sugar. + ENDCASE. + ENDMETHOD. + + METHOD apply_express. + rv_amount = round( val = iv_amount * c_express_rate dec = 2 ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0138/faulty/m3_cake_pricer.clas.abap b/tasks_gen/eval/G0138/faulty/m3_cake_pricer.clas.abap new file mode 100644 index 0000000..31a0428 --- /dev/null +++ b/tasks_gen/eval/G0138/faulty/m3_cake_pricer.clas.abap @@ -0,0 +1,125 @@ +CLASS {{p}}cake_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES ty_price TYPE p LENGTH 8 DECIMALS 2. + TYPES ty_filling TYPE c LENGTH 1. + TYPES ty_decoration TYPE c LENGTH 1. + + METHODS calculate_price + IMPORTING iv_size TYPE i + iv_layers TYPE i + iv_filling TYPE ty_filling + iv_decoration TYPE ty_decoration + iv_express TYPE abap_bool + RETURNING VALUE(rv_price) TYPE ty_price. + + PRIVATE SECTION. + CONSTANTS: + c_base_price TYPE ty_price VALUE '12.00', + c_min_price TYPE ty_price VALUE '15.00', + c_min_size TYPE i VALUE 16, + c_free_size TYPE i VALUE 20, + c_photo_size TYPE i VALUE 24, + c_size_rate TYPE ty_price VALUE '0.80', + c_layer_rate TYPE ty_price VALUE '4.50', + c_express_rate TYPE ty_price VALUE '1.25', + c_filling_plain TYPE ty_price VALUE '3.00', + c_filling_choc TYPE ty_price VALUE '4.00', + c_filling_fruit TYPE ty_price VALUE '5.50', + c_deco_flowers TYPE ty_price VALUE '6.00', + c_deco_photo TYPE ty_price VALUE '9.50', + c_deco_sugar TYPE ty_price VALUE '12.00'. + + METHODS clamp_size + IMPORTING iv_size TYPE i + RETURNING VALUE(rv_size) TYPE i. + METHODS clamp_layers + IMPORTING iv_layers TYPE i + RETURNING VALUE(rv_layers) TYPE i. + METHODS size_surcharge + IMPORTING iv_size TYPE i + RETURNING VALUE(rv_amount) TYPE ty_price. + METHODS layer_surcharge + IMPORTING iv_layers TYPE i + RETURNING VALUE(rv_amount) TYPE ty_price. + METHODS filling_surcharge + IMPORTING iv_filling TYPE ty_filling + RETURNING VALUE(rv_amount) TYPE ty_price. + METHODS decoration_surcharge + IMPORTING iv_decoration TYPE ty_decoration + iv_size TYPE i + RETURNING VALUE(rv_amount) TYPE ty_price. + METHODS apply_express + IMPORTING iv_amount TYPE ty_price + RETURNING VALUE(rv_amount) TYPE ty_price. +ENDCLASS. + + +CLASS {{p}}cake_pricer IMPLEMENTATION. + METHOD calculate_price. + DATA(lv_size) = clamp_size( iv_size ). + DATA(lv_price) = c_base_price. + lv_price = lv_price + size_surcharge( lv_size ). + lv_price = lv_price + layer_surcharge( clamp_layers( iv_layers ) ). + lv_price = lv_price + filling_surcharge( iv_filling ). + lv_price = lv_price + decoration_surcharge( iv_decoration = iv_decoration + iv_size = lv_size ). + IF iv_express = abap_true. + lv_price = apply_express( lv_price ). + ENDIF. + IF lv_price < c_min_price. + rv_price = c_min_price. + ELSE. + rv_price = lv_price. + ENDIF. + ENDMETHOD. + + METHOD clamp_size. + rv_size = nmax( val1 = iv_size val2 = c_min_size ). + ENDMETHOD. + + METHOD clamp_layers. + rv_layers = nmax( val1 = iv_layers val2 = 1 ). + ENDMETHOD. + + METHOD size_surcharge. + IF iv_size > c_free_size. + rv_amount = ( iv_size - c_free_size ) * c_size_rate. + ENDIF. + ENDMETHOD. + + METHOD layer_surcharge. + IF iv_layers > 1. + rv_amount = ( iv_layers + 1 ) * c_layer_rate. + ENDIF. + ENDMETHOD. + + METHOD filling_surcharge. + CASE iv_filling. + WHEN 'C'. + rv_amount = c_filling_choc. + WHEN 'F'. + rv_amount = c_filling_fruit. + WHEN 'N'. + CLEAR rv_amount. + WHEN OTHERS. + rv_amount = c_filling_plain. + ENDCASE. + ENDMETHOD. + + METHOD decoration_surcharge. + CASE iv_decoration. + WHEN 'F'. + rv_amount = c_deco_flowers. + WHEN 'P'. + IF iv_size >= c_photo_size. + rv_amount = c_deco_photo. + ENDIF. + WHEN 'S'. + rv_amount = c_deco_sugar. + ENDCASE. + ENDMETHOD. + + METHOD apply_express. + rv_amount = round( val = iv_amount * c_express_rate dec = 2 ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0138/faulty/m4_cake_pricer.clas.abap b/tasks_gen/eval/G0138/faulty/m4_cake_pricer.clas.abap new file mode 100644 index 0000000..07d36a7 --- /dev/null +++ b/tasks_gen/eval/G0138/faulty/m4_cake_pricer.clas.abap @@ -0,0 +1,125 @@ +CLASS {{p}}cake_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES ty_price TYPE p LENGTH 8 DECIMALS 2. + TYPES ty_filling TYPE c LENGTH 1. + TYPES ty_decoration TYPE c LENGTH 1. + + METHODS calculate_price + IMPORTING iv_size TYPE i + iv_layers TYPE i + iv_filling TYPE ty_filling + iv_decoration TYPE ty_decoration + iv_express TYPE abap_bool + RETURNING VALUE(rv_price) TYPE ty_price. + + PRIVATE SECTION. + CONSTANTS: + c_base_price TYPE ty_price VALUE '12.00', + c_min_price TYPE ty_price VALUE '15.00', + c_min_size TYPE i VALUE 16, + c_free_size TYPE i VALUE 20, + c_photo_size TYPE i VALUE 24, + c_size_rate TYPE ty_price VALUE '0.80', + c_layer_rate TYPE ty_price VALUE '4.50', + c_express_rate TYPE ty_price VALUE '1.25', + c_filling_plain TYPE ty_price VALUE '3.00', + c_filling_choc TYPE ty_price VALUE '4.00', + c_filling_fruit TYPE ty_price VALUE '5.50', + c_deco_flowers TYPE ty_price VALUE '6.00', + c_deco_photo TYPE ty_price VALUE '9.50', + c_deco_sugar TYPE ty_price VALUE '12.00'. + + METHODS clamp_size + IMPORTING iv_size TYPE i + RETURNING VALUE(rv_size) TYPE i. + METHODS clamp_layers + IMPORTING iv_layers TYPE i + RETURNING VALUE(rv_layers) TYPE i. + METHODS size_surcharge + IMPORTING iv_size TYPE i + RETURNING VALUE(rv_amount) TYPE ty_price. + METHODS layer_surcharge + IMPORTING iv_layers TYPE i + RETURNING VALUE(rv_amount) TYPE ty_price. + METHODS filling_surcharge + IMPORTING iv_filling TYPE ty_filling + RETURNING VALUE(rv_amount) TYPE ty_price. + METHODS decoration_surcharge + IMPORTING iv_decoration TYPE ty_decoration + iv_size TYPE i + RETURNING VALUE(rv_amount) TYPE ty_price. + METHODS apply_express + IMPORTING iv_amount TYPE ty_price + RETURNING VALUE(rv_amount) TYPE ty_price. +ENDCLASS. + + +CLASS {{p}}cake_pricer IMPLEMENTATION. + METHOD calculate_price. + DATA(lv_size) = clamp_size( iv_size ). + DATA(lv_price) = c_base_price. + lv_price = lv_price + size_surcharge( lv_size ). + lv_price = lv_price + layer_surcharge( clamp_layers( iv_layers ) ). + lv_price = lv_price + filling_surcharge( iv_filling ). + lv_price = lv_price + decoration_surcharge( iv_decoration = iv_decoration + iv_size = lv_size ). + IF iv_express = abap_true. + lv_price = apply_express( lv_price ). + ENDIF. + IF lv_price < c_min_price. + rv_price = c_min_price. + ELSE. + rv_price = lv_price. + ENDIF. + ENDMETHOD. + + METHOD clamp_size. + rv_size = nmax( val1 = iv_size val2 = c_min_size ). + ENDMETHOD. + + METHOD clamp_layers. + rv_layers = nmax( val1 = iv_layers val2 = 1 ). + ENDMETHOD. + + METHOD size_surcharge. + IF iv_size > c_free_size. + rv_amount = ( iv_size - c_free_size ) * c_size_rate. + ENDIF. + ENDMETHOD. + + METHOD layer_surcharge. + IF iv_layers > 1. + rv_amount = ( iv_layers - 2 ) * c_layer_rate. + ENDIF. + ENDMETHOD. + + METHOD filling_surcharge. + CASE iv_filling. + WHEN 'C'. + rv_amount = c_filling_choc. + WHEN 'F'. + rv_amount = c_filling_fruit. + WHEN 'N'. + CLEAR rv_amount. + WHEN OTHERS. + rv_amount = c_filling_plain. + ENDCASE. + ENDMETHOD. + + METHOD decoration_surcharge. + CASE iv_decoration. + WHEN 'F'. + rv_amount = c_deco_flowers. + WHEN 'P'. + IF iv_size >= c_photo_size. + rv_amount = c_deco_photo. + ENDIF. + WHEN 'S'. + rv_amount = c_deco_sugar. + ENDCASE. + ENDMETHOD. + + METHOD apply_express. + rv_amount = round( val = iv_amount * c_express_rate dec = 2 ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0138/generation.json b/tasks_gen/eval/G0138/generation.json new file mode 100644 index 0000000..6e31f37 --- /dev/null +++ b/tasks_gen/eval/G0138/generation.json @@ -0,0 +1,52 @@ +{ + "id": "G0138", + "pool": "eval", + "object_type": "CLAS", + "category": "E", + "attempts": [ + { + "stage": "bundle", + "errors": [ + "hidden/e05_hidden.clas.abap line 45: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"expect_price\"", + "hidden/e05_hidden.clas.abap line 45: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"00\"", + "hidden/e05_hidden.clas.abap line 51: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"expect_price\"", + "hidden/e05_hidden.clas.abap line 51: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"50\"", + "hidden/e05_hidden.clas.abap line 54: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"expect_price\"", + "hidden/e05_hidden.clas.abap line 54: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"50\"", + "hidden/e05_hidden.clas.abap line 57: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"expect_price\"", + "hidden/e05_hidden.clas.abap line 57: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"80\"", + "hidden/e05_hidden.clas.abap line 63: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"expect_price\"", + "hidden/e05_hidden.clas.abap line 63: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"50\"", + "hidden/e05_hidden.clas.abap line 69: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"expect_price\"", + "hidden/e05_hidden.clas.abap line 69: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"50\"", + "hidden/e05_hidden.clas.abap line 72: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"expect_price\"", + "hidden/e05_hidden.clas.abap line 72: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"50\"", + "hidden/e05_hidden.clas.abap line 78: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"expect_price\"", + "hidden/e05_hidden.clas.abap line 78: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"50\"", + "hidden/e05_hidden.clas.abap line 81: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"expect_price\"", + "hidden/e05_hidden.clas.abap line 81: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"50\"", + "hidden/e05_hidden.clas.abap line 84: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"expect_price\"", + "hidden/e05_hidden.clas.abap line 84: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"00\"" + ], + "by_check": { + "abaplint": 20 + } + }, + { + "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/eval/G0138/hidden/e05_hidden.clas.abap b/tasks_gen/eval/G0138/hidden/e05_hidden.clas.abap new file mode 100644 index 0000000..1ec0843 --- /dev/null +++ b/tasks_gen/eval/G0138/hidden/e05_hidden.clas.abap @@ -0,0 +1,244 @@ +CLASS {{p}}e05_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + CONSTANTS: + c_base_min TYPE {{p}}cake_pricer=>ty_price VALUE '15.00', + c_size_fee TYPE {{p}}cake_pricer=>ty_price VALUE '16.80', + c_clamped TYPE {{p}}cake_pricer=>ty_price VALUE '38.50', + c_layers TYPE {{p}}cake_pricer=>ty_price VALUE '25.50', + c_lay_clamp TYPE {{p}}cake_pricer=>ty_price VALUE '29.50', + c_vanilla TYPE {{p}}cake_pricer=>ty_price VALUE '19.50', + c_choc TYPE {{p}}cake_pricer=>ty_price VALUE '20.50', + c_fruit TYPE {{p}}cake_pricer=>ty_price VALUE '22.00', + c_plain TYPE {{p}}cake_pricer=>ty_price VALUE '16.50', + c_flowers TYPE {{p}}cake_pricer=>ty_price VALUE '22.80', + c_sugar TYPE {{p}}cake_pricer=>ty_price VALUE '28.80', + c_photo TYPE {{p}}cake_pricer=>ty_price VALUE '26.30', + c_photo_lo TYPE {{p}}cake_pricer=>ty_price VALUE '20.50', + c_photo_hi TYPE {{p}}cake_pricer=>ty_price VALUE '33.20', + c_unknown TYPE {{p}}cake_pricer=>ty_price VALUE '23.00', + c_express TYPE {{p}}cake_pricer=>ty_price VALUE '29.50', + c_round TYPE {{p}}cake_pricer=>ty_price VALUE '39.13'. + + DATA mo_cut TYPE REF TO {{p}}cake_pricer. + METHODS setup. + METHODS base_min_price FOR TESTING. + METHODS size_rules FOR TESTING. + METHODS layer_fee FOR TESTING. + METHODS layers_clamped FOR TESTING. + METHODS filling_fee FOR TESTING. + METHODS decoration_fee FOR TESTING. + METHODS photo_needs_size FOR TESTING. + METHODS unknown_codes FOR TESTING. + METHODS express_exact FOR TESTING. + METHODS express_rounds FOR TESTING. + METHODS express_at_min FOR TESTING. +ENDCLASS. + + +CLASS {{p}}e05_hidden IMPLEMENTATION. + METHOD setup. + mo_cut = NEW {{p}}cake_pricer( ). + ENDMETHOD. + + METHOD base_min_price. + cl_abap_unit_assert=>assert_equals( + exp = c_base_min + act = mo_cut->calculate_price( iv_size = 16 + iv_layers = 1 + iv_filling = 'N' + iv_decoration = 'N' + iv_express = abap_false ) + msg = `base` ). + ENDMETHOD. + + METHOD size_rules. + cl_abap_unit_assert=>assert_equals( + exp = c_clamped + act = mo_cut->calculate_price( iv_size = 10 + iv_layers = 3 + iv_filling = 'F' + iv_decoration = 'S' + iv_express = abap_false ) + msg = `clamped` ). + cl_abap_unit_assert=>assert_equals( + exp = c_clamped + act = mo_cut->calculate_price( iv_size = 16 + iv_layers = 3 + iv_filling = 'F' + iv_decoration = 'S' + iv_express = abap_false ) + msg = `min size` ). + cl_abap_unit_assert=>assert_equals( + exp = c_size_fee + act = mo_cut->calculate_price( iv_size = 26 + iv_layers = 1 + iv_filling = 'N' + iv_decoration = 'N' + iv_express = abap_false ) + msg = `size fee` ). + ENDMETHOD. + + METHOD layer_fee. + cl_abap_unit_assert=>assert_equals( + exp = c_layers + act = mo_cut->calculate_price( iv_size = 20 + iv_layers = 4 + iv_filling = 'N' + iv_decoration = 'N' + iv_express = abap_false ) + msg = `layers` ). + ENDMETHOD. + + METHOD layers_clamped. + cl_abap_unit_assert=>assert_equals( + exp = c_lay_clamp + act = mo_cut->calculate_price( iv_size = 20 + iv_layers = 0 + iv_filling = 'F' + iv_decoration = 'S' + iv_express = abap_false ) + msg = `zero layers` ). + cl_abap_unit_assert=>assert_equals( + exp = c_lay_clamp + act = mo_cut->calculate_price( iv_size = 20 + iv_layers = 1 + iv_filling = 'F' + iv_decoration = 'S' + iv_express = abap_false ) + msg = `one layer` ). + ENDMETHOD. + + METHOD filling_fee. + cl_abap_unit_assert=>assert_equals( + exp = c_vanilla + act = mo_cut->calculate_price( iv_size = 20 + iv_layers = 2 + iv_filling = 'V' + iv_decoration = 'N' + iv_express = abap_false ) + msg = `vanilla` ). + cl_abap_unit_assert=>assert_equals( + exp = c_choc + act = mo_cut->calculate_price( iv_size = 20 + iv_layers = 2 + iv_filling = 'C' + iv_decoration = 'N' + iv_express = abap_false ) + msg = `chocolate` ). + cl_abap_unit_assert=>assert_equals( + exp = c_fruit + act = mo_cut->calculate_price( iv_size = 20 + iv_layers = 2 + iv_filling = 'F' + iv_decoration = 'N' + iv_express = abap_false ) + msg = `fruit` ). + cl_abap_unit_assert=>assert_equals( + exp = c_plain + act = mo_cut->calculate_price( iv_size = 20 + iv_layers = 2 + iv_filling = 'N' + iv_decoration = 'N' + iv_express = abap_false ) + msg = `none` ). + ENDMETHOD. + + METHOD decoration_fee. + cl_abap_unit_assert=>assert_equals( + exp = c_size_fee + act = mo_cut->calculate_price( iv_size = 26 + iv_layers = 1 + iv_filling = 'N' + iv_decoration = 'N' + iv_express = abap_false ) + msg = `no deco` ). + cl_abap_unit_assert=>assert_equals( + exp = c_flowers + act = mo_cut->calculate_price( iv_size = 26 + iv_layers = 1 + iv_filling = 'N' + iv_decoration = 'F' + iv_express = abap_false ) + msg = `flowers` ). + cl_abap_unit_assert=>assert_equals( + exp = c_sugar + act = mo_cut->calculate_price( iv_size = 26 + iv_layers = 1 + iv_filling = 'N' + iv_decoration = 'S' + iv_express = abap_false ) + msg = `sugar` ). + cl_abap_unit_assert=>assert_equals( + exp = c_photo + act = mo_cut->calculate_price( iv_size = 26 + iv_layers = 1 + iv_filling = 'N' + iv_decoration = 'P' + iv_express = abap_false ) + msg = `photo` ). + ENDMETHOD. + + METHOD photo_needs_size. + cl_abap_unit_assert=>assert_equals( + exp = c_photo_lo + act = mo_cut->calculate_price( iv_size = 20 + iv_layers = 2 + iv_filling = 'C' + iv_decoration = 'P' + iv_express = abap_false ) + msg = `too small` ). + cl_abap_unit_assert=>assert_equals( + exp = c_photo_hi + act = mo_cut->calculate_price( iv_size = 24 + iv_layers = 2 + iv_filling = 'C' + iv_decoration = 'P' + iv_express = abap_false ) + msg = `large enough` ). + ENDMETHOD. + + METHOD unknown_codes. + cl_abap_unit_assert=>assert_equals( + exp = c_unknown + act = mo_cut->calculate_price( iv_size = 30 + iv_layers = 1 + iv_filling = 'X' + iv_decoration = 'Z' + iv_express = abap_false ) + msg = `unknown codes` ). + ENDMETHOD. + + METHOD express_exact. + cl_abap_unit_assert=>assert_equals( + exp = c_express + act = mo_cut->calculate_price( iv_size = 22 + iv_layers = 1 + iv_filling = 'C' + iv_decoration = 'F' + iv_express = abap_true ) + msg = `express` ). + ENDMETHOD. + + METHOD express_rounds. + cl_abap_unit_assert=>assert_equals( + exp = c_round + act = mo_cut->calculate_price( iv_size = 26 + iv_layers = 2 + iv_filling = 'C' + iv_decoration = 'F' + iv_express = abap_true ) + msg = `express rounded` ). + ENDMETHOD. + + METHOD express_at_min. + cl_abap_unit_assert=>assert_equals( + exp = c_base_min + act = mo_cut->calculate_price( iv_size = 16 + iv_layers = 1 + iv_filling = 'N' + iv_decoration = 'N' + iv_express = abap_true ) + msg = `express at minimum` ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0138/mutation.json b/tasks_gen/eval/G0138/mutation.json new file mode 100644 index 0000000..d8d1fc7 --- /dev/null +++ b/tasks_gen/eval/G0138/mutation.json @@ -0,0 +1,78 @@ +{ + "task": "G0138", + "mutants": [ + { + "object": "{{P}}CAKE_PRICER", + "mutant": "line 62: + -> - (arith)", + "status": "killed", + "hidden": "6/11", + "failed_tests": [ + "EXPRESS_ROUNDS", + "FILLING_FEE", + "LAYER_FEE", + "PHOTO_NEEDS_SIZE", + "SIZE_RULES" + ] + }, + { + "object": "{{P}}CAKE_PRICER", + "mutant": "line 66: = -> <> (eq)", + "status": "killed", + "hidden": "2/11", + "failed_tests": [ + "DECORATION_FEE", + "EXPRESS_EXACT", + "EXPRESS_ROUNDS", + "FILLING_FEE", + "LAYERS_CLAMPED", + "LAYER_FEE", + "PHOTO_NEEDS_SIZE", + "SIZE_RULES", + "UNKNOWN_CODES" + ] + }, + { + "object": "{{P}}CAKE_PRICER", + "mutant": "line 91: > -> <= (rel)", + "status": "killed", + "hidden": "6/11", + "failed_tests": [ + "EXPRESS_ROUNDS", + "FILLING_FEE", + "LAYER_FEE", + "PHOTO_NEEDS_SIZE", + "SIZE_RULES" + ] + }, + { + "object": "{{P}}CAKE_PRICER", + "mutant": "line 92: - -> + (arith)", + "status": "killed", + "hidden": "6/11", + "failed_tests": [ + "EXPRESS_ROUNDS", + "FILLING_FEE", + "LAYER_FEE", + "PHOTO_NEEDS_SIZE", + "SIZE_RULES" + ] + }, + { + "object": "{{P}}CAKE_PRICER", + "mutant": "line 92: 1 -> 2 (const)", + "status": "killed", + "hidden": "6/11", + "failed_tests": [ + "EXPRESS_ROUNDS", + "FILLING_FEE", + "LAYER_FEE", + "PHOTO_NEEDS_SIZE", + "SIZE_RULES" + ] + } + ], + "valid": 5, + "killed": 5, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0138/reference/cake_pricer.clas.abap b/tasks_gen/eval/G0138/reference/cake_pricer.clas.abap new file mode 100644 index 0000000..babb26b --- /dev/null +++ b/tasks_gen/eval/G0138/reference/cake_pricer.clas.abap @@ -0,0 +1,125 @@ +CLASS {{p}}cake_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES ty_price TYPE p LENGTH 8 DECIMALS 2. + TYPES ty_filling TYPE c LENGTH 1. + TYPES ty_decoration TYPE c LENGTH 1. + + METHODS calculate_price + IMPORTING iv_size TYPE i + iv_layers TYPE i + iv_filling TYPE ty_filling + iv_decoration TYPE ty_decoration + iv_express TYPE abap_bool + RETURNING VALUE(rv_price) TYPE ty_price. + + PRIVATE SECTION. + CONSTANTS: + c_base_price TYPE ty_price VALUE '12.00', + c_min_price TYPE ty_price VALUE '15.00', + c_min_size TYPE i VALUE 16, + c_free_size TYPE i VALUE 20, + c_photo_size TYPE i VALUE 24, + c_size_rate TYPE ty_price VALUE '0.80', + c_layer_rate TYPE ty_price VALUE '4.50', + c_express_rate TYPE ty_price VALUE '1.25', + c_filling_plain TYPE ty_price VALUE '3.00', + c_filling_choc TYPE ty_price VALUE '4.00', + c_filling_fruit TYPE ty_price VALUE '5.50', + c_deco_flowers TYPE ty_price VALUE '6.00', + c_deco_photo TYPE ty_price VALUE '9.50', + c_deco_sugar TYPE ty_price VALUE '12.00'. + + METHODS clamp_size + IMPORTING iv_size TYPE i + RETURNING VALUE(rv_size) TYPE i. + METHODS clamp_layers + IMPORTING iv_layers TYPE i + RETURNING VALUE(rv_layers) TYPE i. + METHODS size_surcharge + IMPORTING iv_size TYPE i + RETURNING VALUE(rv_amount) TYPE ty_price. + METHODS layer_surcharge + IMPORTING iv_layers TYPE i + RETURNING VALUE(rv_amount) TYPE ty_price. + METHODS filling_surcharge + IMPORTING iv_filling TYPE ty_filling + RETURNING VALUE(rv_amount) TYPE ty_price. + METHODS decoration_surcharge + IMPORTING iv_decoration TYPE ty_decoration + iv_size TYPE i + RETURNING VALUE(rv_amount) TYPE ty_price. + METHODS apply_express + IMPORTING iv_amount TYPE ty_price + RETURNING VALUE(rv_amount) TYPE ty_price. +ENDCLASS. + + +CLASS {{p}}cake_pricer IMPLEMENTATION. + METHOD calculate_price. + DATA(lv_size) = clamp_size( iv_size ). + DATA(lv_price) = c_base_price. + lv_price = lv_price + size_surcharge( lv_size ). + lv_price = lv_price + layer_surcharge( clamp_layers( iv_layers ) ). + lv_price = lv_price + filling_surcharge( iv_filling ). + lv_price = lv_price + decoration_surcharge( iv_decoration = iv_decoration + iv_size = lv_size ). + IF iv_express = abap_true. + lv_price = apply_express( lv_price ). + ENDIF. + IF lv_price < c_min_price. + rv_price = c_min_price. + ELSE. + rv_price = lv_price. + ENDIF. + ENDMETHOD. + + METHOD clamp_size. + rv_size = nmax( val1 = iv_size val2 = c_min_size ). + ENDMETHOD. + + METHOD clamp_layers. + rv_layers = nmax( val1 = iv_layers val2 = 1 ). + ENDMETHOD. + + METHOD size_surcharge. + IF iv_size > c_free_size. + rv_amount = ( iv_size - c_free_size ) * c_size_rate. + ENDIF. + ENDMETHOD. + + METHOD layer_surcharge. + IF iv_layers > 1. + rv_amount = ( iv_layers - 1 ) * c_layer_rate. + ENDIF. + ENDMETHOD. + + METHOD filling_surcharge. + CASE iv_filling. + WHEN 'C'. + rv_amount = c_filling_choc. + WHEN 'F'. + rv_amount = c_filling_fruit. + WHEN 'N'. + CLEAR rv_amount. + WHEN OTHERS. + rv_amount = c_filling_plain. + ENDCASE. + ENDMETHOD. + + METHOD decoration_surcharge. + CASE iv_decoration. + WHEN 'F'. + rv_amount = c_deco_flowers. + WHEN 'P'. + IF iv_size >= c_photo_size. + rv_amount = c_deco_photo. + ENDIF. + WHEN 'S'. + rv_amount = c_deco_sugar. + ENDCASE. + ENDMETHOD. + + METHOD apply_express. + rv_amount = round( val = iv_amount * c_express_rate dec = 2 ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0138/reference/cake_pricer.testclasses.abap b/tasks_gen/eval/G0138/reference/cake_pricer.testclasses.abap new file mode 100644 index 0000000..efbd726 --- /dev/null +++ b/tasks_gen/eval/G0138/reference/cake_pricer.testclasses.abap @@ -0,0 +1,62 @@ +CLASS ltc_cake_pricer DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + CONSTANTS: + c_minimum TYPE {{p}}cake_pricer=>ty_price VALUE '15.00', + c_big_order TYPE {{p}}cake_pricer=>ty_price VALUE '43.30', + c_photo_lo TYPE {{p}}cake_pricer=>ty_price VALUE '20.50', + c_express TYPE {{p}}cake_pricer=>ty_price VALUE '39.13'. + + DATA mo_cut TYPE REF TO {{p}}cake_pricer. + METHODS setup. + METHODS minimum_price FOR TESTING. + METHODS size_and_layers FOR TESTING. + METHODS photo_print_needs_size FOR TESTING. + METHODS express_surcharge FOR TESTING. +ENDCLASS. + + +CLASS ltc_cake_pricer IMPLEMENTATION. + METHOD setup. + mo_cut = NEW {{p}}cake_pricer( ). + ENDMETHOD. + + METHOD minimum_price. + cl_abap_unit_assert=>assert_equals( + exp = c_minimum + act = mo_cut->calculate_price( iv_size = 16 + iv_layers = 1 + iv_filling = 'N' + iv_decoration = 'N' + iv_express = abap_false ) ). + ENDMETHOD. + + METHOD size_and_layers. + cl_abap_unit_assert=>assert_equals( + exp = c_big_order + act = mo_cut->calculate_price( iv_size = 26 + iv_layers = 3 + iv_filling = 'F' + iv_decoration = 'S' + iv_express = abap_false ) ). + ENDMETHOD. + + METHOD photo_print_needs_size. + cl_abap_unit_assert=>assert_equals( + exp = c_photo_lo + act = mo_cut->calculate_price( iv_size = 20 + iv_layers = 2 + iv_filling = 'C' + iv_decoration = 'P' + iv_express = abap_false ) ). + ENDMETHOD. + + METHOD express_surcharge. + cl_abap_unit_assert=>assert_equals( + exp = c_express + act = mo_cut->calculate_price( iv_size = 26 + iv_layers = 2 + iv_filling = 'C' + iv_decoration = 'F' + iv_express = abap_true ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0138/seed/cake_pricer.clas.abap b/tasks_gen/eval/G0138/seed/cake_pricer.clas.abap new file mode 100644 index 0000000..f2fc4bf --- /dev/null +++ b/tasks_gen/eval/G0138/seed/cake_pricer.clas.abap @@ -0,0 +1,92 @@ +CLASS {{p}}cake_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES ty_price TYPE p LENGTH 8 DECIMALS 2. + TYPES ty_filling TYPE c LENGTH 1. + TYPES ty_decoration TYPE c LENGTH 1. + + METHODS calculate_price + IMPORTING iv_size TYPE i + iv_layers TYPE i + iv_filling TYPE ty_filling + iv_decoration TYPE ty_decoration + iv_express TYPE abap_bool + RETURNING VALUE(rv_price) TYPE ty_price. +ENDCLASS. + + +CLASS {{p}}cake_pricer IMPLEMENTATION. + METHOD calculate_price. + " legacy implementation, one long method + DATA lv_size TYPE i. + DATA lv_layers TYPE i. + DATA lv_total TYPE ty_price. + DATA lv_fee TYPE ty_price. + DATA lv_amount TYPE ty_price. + DATA lv_rate TYPE ty_price. + DATA lv_old_check TYPE i. + + lv_total = '12.00'. + lv_size = iv_size. + IF lv_size < 16. + lv_size = 16. + ENDIF. + IF lv_size > 20. + lv_rate = '0.80'. + lv_fee = ( lv_size - 20 ) * lv_rate. + lv_total = lv_total + lv_fee. + ENDIF. + lv_layers = iv_layers. + IF lv_layers < 1. + lv_layers = 1. + ENDIF. + IF lv_layers > 1. + lv_rate = '4.50'. + lv_fee = ( lv_layers - 1 ) * lv_rate. + lv_total = lv_total + lv_fee. + ENDIF. + IF iv_filling = 'V'. + lv_amount = '3.00'. + lv_total = lv_total + lv_amount. + ELSEIF iv_filling = 'C'. + lv_amount = '4.00'. + lv_total = lv_total + lv_amount. + ELSEIF iv_filling = 'F'. + lv_amount = '5.50'. + lv_total = lv_total + lv_amount. + ELSEIF iv_filling = 'N'. + lv_amount = '0.00'. + lv_total = lv_total + lv_amount. + ELSE. + lv_amount = '3.00'. + lv_total = lv_total + lv_amount. + ENDIF. + IF iv_decoration = 'F'. + lv_amount = '6.00'. + lv_total = lv_total + lv_amount. + ELSEIF iv_decoration = 'P'. + IF lv_size >= 24. + lv_amount = '9.50'. + lv_total = lv_total + lv_amount. + ELSE. + lv_amount = '0.00'. + lv_total = lv_total + lv_amount. + ENDIF. + ELSEIF iv_decoration = 'S'. + lv_amount = '12.00'. + lv_total = lv_total + lv_amount. + ELSE. + lv_amount = '0.00'. + lv_total = lv_total + lv_amount. + ENDIF. + IF iv_express = abap_true. + lv_rate = '1.25'. + lv_fee = lv_total * lv_rate. + lv_total = lv_fee. + ENDIF. + lv_amount = '15.00'. + IF lv_total < lv_amount. + lv_total = lv_amount. + ENDIF. + rv_price = lv_total. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0138/spec.md b/tasks_gen/eval/G0138/spec.md new file mode 100644 index 0000000..efb6e34 --- /dev/null +++ b/tasks_gen/eval/G0138/spec.md @@ -0,0 +1,49 @@ +# 1. Goal +The class {{P}}CAKE_PRICER calculates the price of a custom cake order. The +code is old and hard to maintain. Refactor the class. The behavior must stay +the same. A shop program calls the class before it shows the price to the +customer. + +# 2. Open questions +None. + +# 3. Context +- The class {{P}}CAKE_PRICER exists in package $TMP. It is active. +- The class is public and final. It has a public constructor without parameters. +- The class has one public method, CALCULATE_PRICE, and three public types. +- The current implementation is one long method. It has deep nesting, magic + numbers, dead code and an unused variable. The results of the method are + correct. + +# 4. Contract +- Keep the class {{P}}CAKE_PRICER in package $TMP. Keep the name. +- Keep the public interface. Do not change it: + - TYPES ty_price TYPE p LENGTH 8 DECIMALS 2. + - TYPES ty_filling TYPE c LENGTH 1. + - TYPES ty_decoration TYPE c LENGTH 1. + - METHOD calculate_price + IMPORTING iv_size TYPE i + iv_layers TYPE i + iv_filling TYPE ty_filling + iv_decoration TYPE ty_decoration + iv_express TYPE abap_bool + RETURNING VALUE(rv_price) TYPE ty_price. +- Do not add other public methods or public attributes. + +# 5. Business rules +- The behavior of the class stays the same. +- Read the current implementation in {{P}}CAKE_PRICER. Keep every result. +- Do not change the meaning of an input value or of the returned price. + +# 6. Constraints +- Release target: 8.16. +- Refactor the class in place. Do not create a new class. +- Coding standards: Clean ABAP. Methods below 40 statements. No deep nesting. + No unused variable. No magic number in the code. No comment that restates + the code. +- Out of scope: do not change the public interface of {{P}}CAKE_PRICER. + +# 7. Acceptance +- The class {{P}}CAKE_PRICER is active and has no syntax error. +- The hidden tests pass. +- Write your own ABAP Unit tests for the class. diff --git a/tasks_gen/eval/G0138/task.json b/tasks_gen/eval/G0138/task.json new file mode 100644 index 0000000..9354292 --- /dev/null +++ b/tasks_gen/eval/G0138/task.json @@ -0,0 +1,49 @@ +{ + "id": "G0138", + "category": "E", + "object_type": "CLAS", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [ + { + "type": "CLAS", + "name": "{{P}}CAKE_PRICER", + "file": "seed/cake_pricer.clas.abap", + "description": "Legacy cake price calculator, one long method" + } + ], + "contract": [ + { + "type": "CLAS", + "name": "{{P}}CAKE_PRICER" + } + ], + "out_of_scope": [], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}E05_HIDDEN", + "file": "hidden/e05_hidden.clas.abap", + "description": "E05 hidden tests for the unchanged cake price behavior" + } + ], + "reference": [ + { + "type": "CLAS", + "name": "{{P}}CAKE_PRICER", + "file": "reference/cake_pricer.clas.abap", + "description": "Refactored cake price calculator", + "testclasses_file": "reference/cake_pricer.testclasses.abap" + } + ], + "craft_checks": [ + "method_length", + "nesting_depth", + "unused_variable" + ] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0139/faulty/m0_marina_fee.clas.abap b/tasks_gen/eval/G0139/faulty/m0_marina_fee.clas.abap new file mode 100644 index 0000000..45bc04b --- /dev/null +++ b/tasks_gen/eval/G0139/faulty/m0_marina_fee.clas.abap @@ -0,0 +1,122 @@ +CLASS {{p}}marina_fee DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES ty_boat_type TYPE c LENGTH 1. + TYPES ty_season TYPE c LENGTH 1. + TYPES ty_fee TYPE p LENGTH 8 DECIMALS 2. + METHODS calculate_fee + IMPORTING + iv_length_m TYPE i + iv_nights TYPE i + iv_boat_type TYPE ty_boat_type + iv_season TYPE ty_season + iv_power TYPE abap_bool + RETURNING + VALUE(rv_fee) TYPE ty_fee. + + PRIVATE SECTION. + CONSTANTS: + c_length_small TYPE i VALUE 8, + c_length_medium TYPE i VALUE 12, + c_length_large TYPE i VALUE 18, + c_rate_small TYPE ty_fee VALUE '20.00', + c_rate_medium TYPE ty_fee VALUE '32.00', + c_rate_large TYPE ty_fee VALUE '48.00', + c_rate_xlarge TYPE ty_fee VALUE '75.00', + c_factor_sail TYPE ty_fee VALUE '1.00', + c_factor_motor TYPE ty_fee VALUE '1.20', + c_factor_cat TYPE ty_fee VALUE '1.50', + c_factor_high TYPE ty_fee VALUE '1.40', + c_factor_low TYPE ty_fee VALUE '1.00', + c_power_fee TYPE ty_fee VALUE '5.00', + c_discount TYPE ty_fee VALUE '0.90', + c_discount_days TYPE i VALUE 7, + c_min_fee TYPE ty_fee VALUE '30.00', + c_no_fee TYPE ty_fee VALUE '0.00'. + + METHODS base_rate + IMPORTING iv_length_m TYPE i + RETURNING VALUE(rv_rate) TYPE ty_fee. + METHODS type_factor + IMPORTING iv_boat_type TYPE ty_boat_type + RETURNING VALUE(rv_factor) TYPE ty_fee. + METHODS season_factor + IMPORTING iv_season TYPE ty_season + RETURNING VALUE(rv_factor) TYPE ty_fee. + METHODS nightly_rate + IMPORTING iv_length_m TYPE i + iv_boat_type TYPE ty_boat_type + iv_season TYPE ty_season + iv_power TYPE abap_bool + RETURNING VALUE(rv_rate) TYPE ty_fee. + METHODS total_fee + IMPORTING iv_nightly TYPE ty_fee + iv_nights TYPE i + RETURNING VALUE(rv_total) TYPE ty_fee. +ENDCLASS. + + +CLASS {{p}}marina_fee IMPLEMENTATION. + METHOD calculate_fee. + IF iv_length_m <= 0 OR iv_nights <= 0. + rv_fee = c_no_fee. + RETURN. + ENDIF. + DATA(lv_nightly) = nightly_rate( iv_length_m = iv_length_m + iv_boat_type = iv_boat_type + iv_season = iv_season + iv_power = iv_power ). + rv_fee = total_fee( iv_nightly = lv_nightly + iv_nights = iv_nights ). + ENDMETHOD. + + METHOD base_rate. + IF iv_length_m <= c_length_small. + rv_rate = c_rate_small. + ELSEIF iv_length_m > c_length_medium. + rv_rate = c_rate_medium. + ELSEIF iv_length_m <= c_length_large. + rv_rate = c_rate_large. + ELSE. + rv_rate = c_rate_xlarge. + ENDIF. + ENDMETHOD. + + METHOD type_factor. + CASE iv_boat_type. + WHEN 'C'. + rv_factor = c_factor_cat. + WHEN 'M'. + rv_factor = c_factor_motor. + WHEN OTHERS. + rv_factor = c_factor_sail. + ENDCASE. + ENDMETHOD. + + METHOD season_factor. + IF iv_season = 'H'. + rv_factor = c_factor_high. + ELSE. + rv_factor = c_factor_low. + ENDIF. + ENDMETHOD. + + METHOD nightly_rate. + rv_rate = base_rate( iv_length_m ) * type_factor( iv_boat_type ) * season_factor( iv_season ). + IF iv_power = abap_true. + rv_rate = rv_rate + c_power_fee. + ENDIF. + ENDMETHOD. + + METHOD total_fee. + DATA lv_total TYPE ty_fee. + lv_total = iv_nightly * iv_nights. + IF iv_nights >= c_discount_days. + lv_total = round( val = lv_total * c_discount dec = 2 ). + ENDIF. + IF lv_total < c_min_fee. + rv_total = c_min_fee. + ELSE. + rv_total = lv_total. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0139/faulty/m1_marina_fee.clas.abap b/tasks_gen/eval/G0139/faulty/m1_marina_fee.clas.abap new file mode 100644 index 0000000..9d1193f --- /dev/null +++ b/tasks_gen/eval/G0139/faulty/m1_marina_fee.clas.abap @@ -0,0 +1,122 @@ +CLASS {{p}}marina_fee DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES ty_boat_type TYPE c LENGTH 1. + TYPES ty_season TYPE c LENGTH 1. + TYPES ty_fee TYPE p LENGTH 8 DECIMALS 2. + METHODS calculate_fee + IMPORTING + iv_length_m TYPE i + iv_nights TYPE i + iv_boat_type TYPE ty_boat_type + iv_season TYPE ty_season + iv_power TYPE abap_bool + RETURNING + VALUE(rv_fee) TYPE ty_fee. + + PRIVATE SECTION. + CONSTANTS: + c_length_small TYPE i VALUE 8, + c_length_medium TYPE i VALUE 12, + c_length_large TYPE i VALUE 18, + c_rate_small TYPE ty_fee VALUE '20.00', + c_rate_medium TYPE ty_fee VALUE '32.00', + c_rate_large TYPE ty_fee VALUE '48.00', + c_rate_xlarge TYPE ty_fee VALUE '75.00', + c_factor_sail TYPE ty_fee VALUE '1.00', + c_factor_motor TYPE ty_fee VALUE '1.20', + c_factor_cat TYPE ty_fee VALUE '1.50', + c_factor_high TYPE ty_fee VALUE '1.40', + c_factor_low TYPE ty_fee VALUE '1.00', + c_power_fee TYPE ty_fee VALUE '5.00', + c_discount TYPE ty_fee VALUE '0.90', + c_discount_days TYPE i VALUE 7, + c_min_fee TYPE ty_fee VALUE '30.00', + c_no_fee TYPE ty_fee VALUE '0.00'. + + METHODS base_rate + IMPORTING iv_length_m TYPE i + RETURNING VALUE(rv_rate) TYPE ty_fee. + METHODS type_factor + IMPORTING iv_boat_type TYPE ty_boat_type + RETURNING VALUE(rv_factor) TYPE ty_fee. + METHODS season_factor + IMPORTING iv_season TYPE ty_season + RETURNING VALUE(rv_factor) TYPE ty_fee. + METHODS nightly_rate + IMPORTING iv_length_m TYPE i + iv_boat_type TYPE ty_boat_type + iv_season TYPE ty_season + iv_power TYPE abap_bool + RETURNING VALUE(rv_rate) TYPE ty_fee. + METHODS total_fee + IMPORTING iv_nightly TYPE ty_fee + iv_nights TYPE i + RETURNING VALUE(rv_total) TYPE ty_fee. +ENDCLASS. + + +CLASS {{p}}marina_fee IMPLEMENTATION. + METHOD calculate_fee. + IF iv_length_m <= 0 OR iv_nights <= 0. + rv_fee = c_no_fee. + RETURN. + ENDIF. + DATA(lv_nightly) = nightly_rate( iv_length_m = iv_length_m + iv_boat_type = iv_boat_type + iv_season = iv_season + iv_power = iv_power ). + rv_fee = total_fee( iv_nightly = lv_nightly + iv_nights = iv_nights ). + ENDMETHOD. + + METHOD base_rate. + IF iv_length_m <= c_length_small. + rv_rate = c_rate_small. + ELSEIF iv_length_m <= c_length_medium. + rv_rate = c_rate_medium. + ELSEIF iv_length_m <= c_length_large. + rv_rate = c_rate_large. + ELSE. + rv_rate = c_rate_xlarge. + ENDIF. + ENDMETHOD. + + METHOD type_factor. + CASE iv_boat_type. + WHEN 'C'. + rv_factor = c_factor_cat. + WHEN 'M'. + rv_factor = c_factor_motor. + WHEN OTHERS. + rv_factor = c_factor_sail. + ENDCASE. + ENDMETHOD. + + METHOD season_factor. + IF iv_season <> 'H'. + rv_factor = c_factor_high. + ELSE. + rv_factor = c_factor_low. + ENDIF. + ENDMETHOD. + + METHOD nightly_rate. + rv_rate = base_rate( iv_length_m ) * type_factor( iv_boat_type ) * season_factor( iv_season ). + IF iv_power = abap_true. + rv_rate = rv_rate + c_power_fee. + ENDIF. + ENDMETHOD. + + METHOD total_fee. + DATA lv_total TYPE ty_fee. + lv_total = iv_nightly * iv_nights. + IF iv_nights >= c_discount_days. + lv_total = round( val = lv_total * c_discount dec = 2 ). + ENDIF. + IF lv_total < c_min_fee. + rv_total = c_min_fee. + ELSE. + rv_total = lv_total. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0139/faulty/m2_marina_fee.clas.abap b/tasks_gen/eval/G0139/faulty/m2_marina_fee.clas.abap new file mode 100644 index 0000000..26d056c --- /dev/null +++ b/tasks_gen/eval/G0139/faulty/m2_marina_fee.clas.abap @@ -0,0 +1,122 @@ +CLASS {{p}}marina_fee DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES ty_boat_type TYPE c LENGTH 1. + TYPES ty_season TYPE c LENGTH 1. + TYPES ty_fee TYPE p LENGTH 8 DECIMALS 2. + METHODS calculate_fee + IMPORTING + iv_length_m TYPE i + iv_nights TYPE i + iv_boat_type TYPE ty_boat_type + iv_season TYPE ty_season + iv_power TYPE abap_bool + RETURNING + VALUE(rv_fee) TYPE ty_fee. + + PRIVATE SECTION. + CONSTANTS: + c_length_small TYPE i VALUE 8, + c_length_medium TYPE i VALUE 12, + c_length_large TYPE i VALUE 18, + c_rate_small TYPE ty_fee VALUE '20.00', + c_rate_medium TYPE ty_fee VALUE '32.00', + c_rate_large TYPE ty_fee VALUE '48.00', + c_rate_xlarge TYPE ty_fee VALUE '75.00', + c_factor_sail TYPE ty_fee VALUE '1.00', + c_factor_motor TYPE ty_fee VALUE '1.20', + c_factor_cat TYPE ty_fee VALUE '1.50', + c_factor_high TYPE ty_fee VALUE '1.40', + c_factor_low TYPE ty_fee VALUE '1.00', + c_power_fee TYPE ty_fee VALUE '5.00', + c_discount TYPE ty_fee VALUE '0.90', + c_discount_days TYPE i VALUE 7, + c_min_fee TYPE ty_fee VALUE '30.00', + c_no_fee TYPE ty_fee VALUE '0.00'. + + METHODS base_rate + IMPORTING iv_length_m TYPE i + RETURNING VALUE(rv_rate) TYPE ty_fee. + METHODS type_factor + IMPORTING iv_boat_type TYPE ty_boat_type + RETURNING VALUE(rv_factor) TYPE ty_fee. + METHODS season_factor + IMPORTING iv_season TYPE ty_season + RETURNING VALUE(rv_factor) TYPE ty_fee. + METHODS nightly_rate + IMPORTING iv_length_m TYPE i + iv_boat_type TYPE ty_boat_type + iv_season TYPE ty_season + iv_power TYPE abap_bool + RETURNING VALUE(rv_rate) TYPE ty_fee. + METHODS total_fee + IMPORTING iv_nightly TYPE ty_fee + iv_nights TYPE i + RETURNING VALUE(rv_total) TYPE ty_fee. +ENDCLASS. + + +CLASS {{p}}marina_fee IMPLEMENTATION. + METHOD calculate_fee. + IF iv_length_m <= 0 OR iv_nights <= 0. + rv_fee = c_no_fee. + RETURN. + ENDIF. + DATA(lv_nightly) = nightly_rate( iv_length_m = iv_length_m + iv_boat_type = iv_boat_type + iv_season = iv_season + iv_power = iv_power ). + rv_fee = total_fee( iv_nightly = lv_nightly + iv_nights = iv_nights ). + ENDMETHOD. + + METHOD base_rate. + IF iv_length_m <= c_length_small. + rv_rate = c_rate_small. + ELSEIF iv_length_m <= c_length_medium. + rv_rate = c_rate_medium. + ELSEIF iv_length_m <= c_length_large. + rv_rate = c_rate_large. + ELSE. + rv_rate = c_rate_xlarge. + ENDIF. + ENDMETHOD. + + METHOD type_factor. + CASE iv_boat_type. + WHEN 'C'. + rv_factor = c_factor_cat. + WHEN 'M'. + rv_factor = c_factor_motor. + WHEN OTHERS. + rv_factor = c_factor_sail. + ENDCASE. + ENDMETHOD. + + METHOD season_factor. + IF iv_season = 'H'. + rv_factor = c_factor_high. + ELSE. + rv_factor = c_factor_low. + ENDIF. + ENDMETHOD. + + METHOD nightly_rate. + rv_rate = base_rate( iv_length_m ) * type_factor( iv_boat_type ) * season_factor( iv_season ). + IF iv_power = abap_false. + rv_rate = rv_rate + c_power_fee. + ENDIF. + ENDMETHOD. + + METHOD total_fee. + DATA lv_total TYPE ty_fee. + lv_total = iv_nightly * iv_nights. + IF iv_nights >= c_discount_days. + lv_total = round( val = lv_total * c_discount dec = 2 ). + ENDIF. + IF lv_total < c_min_fee. + rv_total = c_min_fee. + ELSE. + rv_total = lv_total. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0139/faulty/m3_marina_fee.clas.abap b/tasks_gen/eval/G0139/faulty/m3_marina_fee.clas.abap new file mode 100644 index 0000000..ed895bb --- /dev/null +++ b/tasks_gen/eval/G0139/faulty/m3_marina_fee.clas.abap @@ -0,0 +1,122 @@ +CLASS {{p}}marina_fee DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES ty_boat_type TYPE c LENGTH 1. + TYPES ty_season TYPE c LENGTH 1. + TYPES ty_fee TYPE p LENGTH 8 DECIMALS 2. + METHODS calculate_fee + IMPORTING + iv_length_m TYPE i + iv_nights TYPE i + iv_boat_type TYPE ty_boat_type + iv_season TYPE ty_season + iv_power TYPE abap_bool + RETURNING + VALUE(rv_fee) TYPE ty_fee. + + PRIVATE SECTION. + CONSTANTS: + c_length_small TYPE i VALUE 8, + c_length_medium TYPE i VALUE 12, + c_length_large TYPE i VALUE 18, + c_rate_small TYPE ty_fee VALUE '20.00', + c_rate_medium TYPE ty_fee VALUE '32.00', + c_rate_large TYPE ty_fee VALUE '48.00', + c_rate_xlarge TYPE ty_fee VALUE '75.00', + c_factor_sail TYPE ty_fee VALUE '1.00', + c_factor_motor TYPE ty_fee VALUE '1.20', + c_factor_cat TYPE ty_fee VALUE '1.50', + c_factor_high TYPE ty_fee VALUE '1.40', + c_factor_low TYPE ty_fee VALUE '1.00', + c_power_fee TYPE ty_fee VALUE '5.00', + c_discount TYPE ty_fee VALUE '0.90', + c_discount_days TYPE i VALUE 7, + c_min_fee TYPE ty_fee VALUE '30.00', + c_no_fee TYPE ty_fee VALUE '0.00'. + + METHODS base_rate + IMPORTING iv_length_m TYPE i + RETURNING VALUE(rv_rate) TYPE ty_fee. + METHODS type_factor + IMPORTING iv_boat_type TYPE ty_boat_type + RETURNING VALUE(rv_factor) TYPE ty_fee. + METHODS season_factor + IMPORTING iv_season TYPE ty_season + RETURNING VALUE(rv_factor) TYPE ty_fee. + METHODS nightly_rate + IMPORTING iv_length_m TYPE i + iv_boat_type TYPE ty_boat_type + iv_season TYPE ty_season + iv_power TYPE abap_bool + RETURNING VALUE(rv_rate) TYPE ty_fee. + METHODS total_fee + IMPORTING iv_nightly TYPE ty_fee + iv_nights TYPE i + RETURNING VALUE(rv_total) TYPE ty_fee. +ENDCLASS. + + +CLASS {{p}}marina_fee IMPLEMENTATION. + METHOD calculate_fee. + IF iv_length_m <= 0 OR iv_nights <= 0. + rv_fee = c_no_fee. + RETURN. + ENDIF. + DATA(lv_nightly) = nightly_rate( iv_length_m = iv_length_m + iv_boat_type = iv_boat_type + iv_season = iv_season + iv_power = iv_power ). + rv_fee = total_fee( iv_nightly = lv_nightly + iv_nights = iv_nights ). + ENDMETHOD. + + METHOD base_rate. + IF iv_length_m <= c_length_small. + rv_rate = c_rate_small. + ELSEIF iv_length_m <= c_length_medium. + rv_rate = c_rate_medium. + ELSEIF iv_length_m <= c_length_large. + rv_rate = c_rate_large. + ELSE. + rv_rate = c_rate_xlarge. + ENDIF. + ENDMETHOD. + + METHOD type_factor. + CASE iv_boat_type. + WHEN 'C'. + rv_factor = c_factor_cat. + WHEN 'M'. + rv_factor = c_factor_motor. + WHEN OTHERS. + rv_factor = c_factor_sail. + ENDCASE. + ENDMETHOD. + + METHOD season_factor. + IF iv_season = 'H'. + rv_factor = c_factor_high. + ELSE. + rv_factor = c_factor_low. + ENDIF. + ENDMETHOD. + + METHOD nightly_rate. + rv_rate = base_rate( iv_length_m ) * type_factor( iv_boat_type ) * season_factor( iv_season ). + IF iv_power = abap_true. + rv_rate = rv_rate - c_power_fee. + ENDIF. + ENDMETHOD. + + METHOD total_fee. + DATA lv_total TYPE ty_fee. + lv_total = iv_nightly * iv_nights. + IF iv_nights >= c_discount_days. + lv_total = round( val = lv_total * c_discount dec = 2 ). + ENDIF. + IF lv_total < c_min_fee. + rv_total = c_min_fee. + ELSE. + rv_total = lv_total. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0139/generation.json b/tasks_gen/eval/G0139/generation.json new file mode 100644 index 0000000..0cd839d --- /dev/null +++ b/tasks_gen/eval/G0139/generation.json @@ -0,0 +1,19 @@ +{ + "id": "G0139", + "pool": "eval", + "object_type": "CLAS", + "category": "E", + "attempts": [ + { + "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/eval/G0139/hidden/marina_fee_hidden.clas.abap b/tasks_gen/eval/G0139/hidden/marina_fee_hidden.clas.abap new file mode 100644 index 0000000..e6a9f97 --- /dev/null +++ b/tasks_gen/eval/G0139/hidden/marina_fee_hidden.clas.abap @@ -0,0 +1,156 @@ +CLASS {{p}}marina_fee_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + DATA mo_cut TYPE REF TO {{p}}marina_fee. + METHODS setup. + METHODS zero_length_returns_zero FOR TESTING. + METHODS zero_nights_returns_zero FOR TESTING. + METHODS minimum_fee_applies FOR TESTING. + METHODS sail_in_low_season FOR TESTING. + METHODS motor_in_high_season FOR TESTING. + METHODS catamaran_with_power FOR TESTING. + METHODS week_discount FOR TESTING. + METHODS discount_rounds_up FOR TESTING. + METHODS unknown_type_like_sail FOR TESTING. + METHODS large_boat_high_power FOR TESTING. + METHODS length_boundary_8m FOR TESTING. +ENDCLASS. + + +CLASS {{p}}marina_fee_hidden IMPLEMENTATION. + METHOD setup. + mo_cut = NEW {{p}}marina_fee( ). + ENDMETHOD. + + METHOD zero_length_returns_zero. + DATA lv_exp TYPE p LENGTH 8 DECIMALS 2. + lv_exp = '0.00'. + cl_abap_unit_assert=>assert_equals( + exp = lv_exp + act = mo_cut->calculate_fee( iv_length_m = 0 + iv_nights = 3 + iv_boat_type = 'S' + iv_season = 'L' + iv_power = abap_false ) ). + ENDMETHOD. + + METHOD zero_nights_returns_zero. + DATA lv_exp TYPE p LENGTH 8 DECIMALS 2. + lv_exp = '0.00'. + cl_abap_unit_assert=>assert_equals( + exp = lv_exp + act = mo_cut->calculate_fee( iv_length_m = 10 + iv_nights = 0 + iv_boat_type = 'S' + iv_season = 'L' + iv_power = abap_false ) ). + ENDMETHOD. + + METHOD minimum_fee_applies. + DATA lv_exp TYPE p LENGTH 8 DECIMALS 2. + lv_exp = '30.00'. + cl_abap_unit_assert=>assert_equals( + exp = lv_exp + act = mo_cut->calculate_fee( iv_length_m = 6 + iv_nights = 1 + iv_boat_type = 'S' + iv_season = 'L' + iv_power = abap_false ) ). + ENDMETHOD. + + METHOD sail_in_low_season. + DATA lv_exp TYPE p LENGTH 8 DECIMALS 2. + lv_exp = '96.00'. + cl_abap_unit_assert=>assert_equals( + exp = lv_exp + act = mo_cut->calculate_fee( iv_length_m = 10 + iv_nights = 3 + iv_boat_type = 'S' + iv_season = 'L' + iv_power = abap_false ) ). + ENDMETHOD. + + METHOD motor_in_high_season. + DATA lv_exp TYPE p LENGTH 8 DECIMALS 2. + lv_exp = '107.52'. + cl_abap_unit_assert=>assert_equals( + exp = lv_exp + act = mo_cut->calculate_fee( iv_length_m = 10 + iv_nights = 2 + iv_boat_type = 'M' + iv_season = 'H' + iv_power = abap_false ) ). + ENDMETHOD. + + METHOD catamaran_with_power. + DATA lv_exp TYPE p LENGTH 8 DECIMALS 2. + lv_exp = '308.00'. + cl_abap_unit_assert=>assert_equals( + exp = lv_exp + act = mo_cut->calculate_fee( iv_length_m = 14 + iv_nights = 4 + iv_boat_type = 'C' + iv_season = 'L' + iv_power = abap_true ) ). + ENDMETHOD. + + METHOD week_discount. + DATA lv_exp TYPE p LENGTH 8 DECIMALS 2. + lv_exp = '201.60'. + cl_abap_unit_assert=>assert_equals( + exp = lv_exp + act = mo_cut->calculate_fee( iv_length_m = 12 + iv_nights = 7 + iv_boat_type = 'S' + iv_season = 'L' + iv_power = abap_false ) ). + ENDMETHOD. + + METHOD discount_rounds_up. + DATA lv_exp TYPE p LENGTH 8 DECIMALS 2. + lv_exp = '370.19'. + cl_abap_unit_assert=>assert_equals( + exp = lv_exp + act = mo_cut->calculate_fee( iv_length_m = 10 + iv_nights = 7 + iv_boat_type = 'M' + iv_season = 'H' + iv_power = abap_true ) ). + ENDMETHOD. + + METHOD unknown_type_like_sail. + DATA lv_exp TYPE p LENGTH 8 DECIMALS 2. + lv_exp = '96.00'. + cl_abap_unit_assert=>assert_equals( + exp = lv_exp + act = mo_cut->calculate_fee( iv_length_m = 10 + iv_nights = 3 + iv_boat_type = 'X' + iv_season = 'L' + iv_power = abap_false ) ). + ENDMETHOD. + + METHOD large_boat_high_power. + DATA lv_exp TYPE p LENGTH 8 DECIMALS 2. + lv_exp = '262.00'. + cl_abap_unit_assert=>assert_equals( + exp = lv_exp + act = mo_cut->calculate_fee( iv_length_m = 25 + iv_nights = 2 + iv_boat_type = 'M' + iv_season = 'H' + iv_power = abap_true ) ). + ENDMETHOD. + + METHOD length_boundary_8m. + DATA lv_exp TYPE p LENGTH 8 DECIMALS 2. + lv_exp = '40.00'. + cl_abap_unit_assert=>assert_equals( + exp = lv_exp + act = mo_cut->calculate_fee( iv_length_m = 8 + iv_nights = 2 + iv_boat_type = 'S' + iv_season = 'L' + iv_power = abap_false ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0139/mutation.json b/tasks_gen/eval/G0139/mutation.json new file mode 100644 index 0000000..7a184a0 --- /dev/null +++ b/tasks_gen/eval/G0139/mutation.json @@ -0,0 +1,74 @@ +{ + "task": "G0139", + "mutants": [ + { + "object": "{{P}}MARINA_FEE", + "mutant": "line 75: <= -> > (rel)", + "status": "killed", + "hidden": "4/11", + "failed_tests": [ + "CATAMARAN_WITH_POWER", + "DISCOUNT_ROUNDS_UP", + "LARGE_BOAT_HIGH_POWER", + "MOTOR_IN_HIGH_SEASON", + "SAIL_IN_LOW_SEASON", + "UNKNOWN_TYPE_LIKE_SAIL", + "WEEK_DISCOUNT" + ] + }, + { + "object": "{{P}}MARINA_FEE", + "mutant": "line 96: = -> <> (eq)", + "status": "killed", + "hidden": "3/11", + "failed_tests": [ + "CATAMARAN_WITH_POWER", + "DISCOUNT_ROUNDS_UP", + "LARGE_BOAT_HIGH_POWER", + "LENGTH_BOUNDARY_8M", + "MOTOR_IN_HIGH_SEASON", + "SAIL_IN_LOW_SEASON", + "UNKNOWN_TYPE_LIKE_SAIL", + "WEEK_DISCOUNT" + ] + }, + { + "object": "{{P}}MARINA_FEE", + "mutant": "line 105: abap_true -> abap_false (bool)", + "status": "killed", + "hidden": "3/11", + "failed_tests": [ + "CATAMARAN_WITH_POWER", + "DISCOUNT_ROUNDS_UP", + "LARGE_BOAT_HIGH_POWER", + "LENGTH_BOUNDARY_8M", + "MOTOR_IN_HIGH_SEASON", + "SAIL_IN_LOW_SEASON", + "UNKNOWN_TYPE_LIKE_SAIL", + "WEEK_DISCOUNT" + ] + }, + { + "object": "{{P}}MARINA_FEE", + "mutant": "line 106: + -> - (arith)", + "status": "killed", + "hidden": "8/11", + "failed_tests": [ + "CATAMARAN_WITH_POWER", + "DISCOUNT_ROUNDS_UP", + "LARGE_BOAT_HIGH_POWER" + ] + }, + { + "object": "{{P}}MARINA_FEE", + "mutant": "line 114: 2 -> 3 (const)", + "status": "survived", + "hidden": "11/11", + "failed_tests": [] + } + ], + "valid": 5, + "killed": 4, + "kill_rate": 0.8, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0139/reference/marina_fee.clas.abap b/tasks_gen/eval/G0139/reference/marina_fee.clas.abap new file mode 100644 index 0000000..170f1a2 --- /dev/null +++ b/tasks_gen/eval/G0139/reference/marina_fee.clas.abap @@ -0,0 +1,122 @@ +CLASS {{p}}marina_fee DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES ty_boat_type TYPE c LENGTH 1. + TYPES ty_season TYPE c LENGTH 1. + TYPES ty_fee TYPE p LENGTH 8 DECIMALS 2. + METHODS calculate_fee + IMPORTING + iv_length_m TYPE i + iv_nights TYPE i + iv_boat_type TYPE ty_boat_type + iv_season TYPE ty_season + iv_power TYPE abap_bool + RETURNING + VALUE(rv_fee) TYPE ty_fee. + + PRIVATE SECTION. + CONSTANTS: + c_length_small TYPE i VALUE 8, + c_length_medium TYPE i VALUE 12, + c_length_large TYPE i VALUE 18, + c_rate_small TYPE ty_fee VALUE '20.00', + c_rate_medium TYPE ty_fee VALUE '32.00', + c_rate_large TYPE ty_fee VALUE '48.00', + c_rate_xlarge TYPE ty_fee VALUE '75.00', + c_factor_sail TYPE ty_fee VALUE '1.00', + c_factor_motor TYPE ty_fee VALUE '1.20', + c_factor_cat TYPE ty_fee VALUE '1.50', + c_factor_high TYPE ty_fee VALUE '1.40', + c_factor_low TYPE ty_fee VALUE '1.00', + c_power_fee TYPE ty_fee VALUE '5.00', + c_discount TYPE ty_fee VALUE '0.90', + c_discount_days TYPE i VALUE 7, + c_min_fee TYPE ty_fee VALUE '30.00', + c_no_fee TYPE ty_fee VALUE '0.00'. + + METHODS base_rate + IMPORTING iv_length_m TYPE i + RETURNING VALUE(rv_rate) TYPE ty_fee. + METHODS type_factor + IMPORTING iv_boat_type TYPE ty_boat_type + RETURNING VALUE(rv_factor) TYPE ty_fee. + METHODS season_factor + IMPORTING iv_season TYPE ty_season + RETURNING VALUE(rv_factor) TYPE ty_fee. + METHODS nightly_rate + IMPORTING iv_length_m TYPE i + iv_boat_type TYPE ty_boat_type + iv_season TYPE ty_season + iv_power TYPE abap_bool + RETURNING VALUE(rv_rate) TYPE ty_fee. + METHODS total_fee + IMPORTING iv_nightly TYPE ty_fee + iv_nights TYPE i + RETURNING VALUE(rv_total) TYPE ty_fee. +ENDCLASS. + + +CLASS {{p}}marina_fee IMPLEMENTATION. + METHOD calculate_fee. + IF iv_length_m <= 0 OR iv_nights <= 0. + rv_fee = c_no_fee. + RETURN. + ENDIF. + DATA(lv_nightly) = nightly_rate( iv_length_m = iv_length_m + iv_boat_type = iv_boat_type + iv_season = iv_season + iv_power = iv_power ). + rv_fee = total_fee( iv_nightly = lv_nightly + iv_nights = iv_nights ). + ENDMETHOD. + + METHOD base_rate. + IF iv_length_m <= c_length_small. + rv_rate = c_rate_small. + ELSEIF iv_length_m <= c_length_medium. + rv_rate = c_rate_medium. + ELSEIF iv_length_m <= c_length_large. + rv_rate = c_rate_large. + ELSE. + rv_rate = c_rate_xlarge. + ENDIF. + ENDMETHOD. + + METHOD type_factor. + CASE iv_boat_type. + WHEN 'C'. + rv_factor = c_factor_cat. + WHEN 'M'. + rv_factor = c_factor_motor. + WHEN OTHERS. + rv_factor = c_factor_sail. + ENDCASE. + ENDMETHOD. + + METHOD season_factor. + IF iv_season = 'H'. + rv_factor = c_factor_high. + ELSE. + rv_factor = c_factor_low. + ENDIF. + ENDMETHOD. + + METHOD nightly_rate. + rv_rate = base_rate( iv_length_m ) * type_factor( iv_boat_type ) * season_factor( iv_season ). + IF iv_power = abap_true. + rv_rate = rv_rate + c_power_fee. + ENDIF. + ENDMETHOD. + + METHOD total_fee. + DATA lv_total TYPE ty_fee. + lv_total = iv_nightly * iv_nights. + IF iv_nights >= c_discount_days. + lv_total = round( val = lv_total * c_discount dec = 2 ). + ENDIF. + IF lv_total < c_min_fee. + rv_total = c_min_fee. + ELSE. + rv_total = lv_total. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0139/reference/marina_fee.testclasses.abap b/tasks_gen/eval/G0139/reference/marina_fee.testclasses.abap new file mode 100644 index 0000000..985a632 --- /dev/null +++ b/tasks_gen/eval/G0139/reference/marina_fee.testclasses.abap @@ -0,0 +1,64 @@ +CLASS ltc_marina_fee DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + DATA mo_cut TYPE REF TO {{p}}marina_fee. + METHODS setup. + METHODS minimum_fee_applies FOR TESTING. + METHODS week_discount FOR TESTING. + METHODS motor_in_high_season FOR TESTING. + METHODS invalid_input_returns_zero FOR TESTING. +ENDCLASS. + + +CLASS ltc_marina_fee IMPLEMENTATION. + METHOD setup. + mo_cut = NEW {{p}}marina_fee( ). + ENDMETHOD. + + METHOD minimum_fee_applies. + DATA lv_exp TYPE {{p}}marina_fee=>ty_fee. + lv_exp = '30.00'. + cl_abap_unit_assert=>assert_equals( + exp = lv_exp + act = mo_cut->calculate_fee( iv_length_m = 6 + iv_nights = 1 + iv_boat_type = 'S' + iv_season = 'L' + iv_power = abap_false ) ). + ENDMETHOD. + + METHOD week_discount. + DATA lv_exp TYPE {{p}}marina_fee=>ty_fee. + lv_exp = '201.60'. + cl_abap_unit_assert=>assert_equals( + exp = lv_exp + act = mo_cut->calculate_fee( iv_length_m = 12 + iv_nights = 7 + iv_boat_type = 'S' + iv_season = 'L' + iv_power = abap_false ) ). + ENDMETHOD. + + METHOD motor_in_high_season. + DATA lv_exp TYPE {{p}}marina_fee=>ty_fee. + lv_exp = '107.52'. + cl_abap_unit_assert=>assert_equals( + exp = lv_exp + act = mo_cut->calculate_fee( iv_length_m = 10 + iv_nights = 2 + iv_boat_type = 'M' + iv_season = 'H' + iv_power = abap_false ) ). + ENDMETHOD. + + METHOD invalid_input_returns_zero. + DATA lv_exp TYPE {{p}}marina_fee=>ty_fee. + lv_exp = '0.00'. + cl_abap_unit_assert=>assert_equals( + exp = lv_exp + act = mo_cut->calculate_fee( iv_length_m = 0 + iv_nights = 3 + iv_boat_type = 'S' + iv_season = 'L' + iv_power = abap_false ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0139/seed/marina_fee.clas.abap b/tasks_gen/eval/G0139/seed/marina_fee.clas.abap new file mode 100644 index 0000000..73c69d9 --- /dev/null +++ b/tasks_gen/eval/G0139/seed/marina_fee.clas.abap @@ -0,0 +1,68 @@ +CLASS {{p}}marina_fee DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES ty_boat_type TYPE c LENGTH 1. + TYPES ty_season TYPE c LENGTH 1. + TYPES ty_fee TYPE p LENGTH 8 DECIMALS 2. + METHODS calculate_fee + IMPORTING + iv_length_m TYPE i + iv_nights TYPE i + iv_boat_type TYPE ty_boat_type + iv_season TYPE ty_season + iv_power TYPE abap_bool + RETURNING + VALUE(rv_fee) TYPE ty_fee. +ENDCLASS. + + +CLASS {{p}}marina_fee IMPLEMENTATION. + METHOD calculate_fee. + DATA lv_base TYPE ty_fee. + DATA lv_factor TYPE ty_fee. + DATA lv_nightly TYPE ty_fee. + DATA lv_total TYPE ty_fee. + + IF iv_length_m <= 0 OR iv_nights <= 0. + rv_fee = 0. + ELSE. + IF iv_length_m <= 8. + lv_base = '20.00'. + ELSE. + IF iv_length_m <= 12. + lv_base = '32.00'. + ELSE. + IF iv_length_m <= 18. + lv_base = '48.00'. + ELSE. + lv_base = '75.00'. + ENDIF. + ENDIF. + ENDIF. + IF iv_boat_type = 'C'. + lv_factor = '1.50'. + ELSE. + IF iv_boat_type = 'M'. + lv_factor = '1.20'. + ELSE. + lv_factor = '1.00'. + ENDIF. + ENDIF. + lv_nightly = lv_base * lv_factor. + IF iv_season = 'H'. + lv_nightly = lv_nightly * '1.40'. + ENDIF. + IF iv_power = abap_true. + lv_nightly = lv_nightly + '5.00'. + ENDIF. + lv_total = lv_nightly * iv_nights. + IF iv_nights >= 7. + lv_total = lv_total * '0.90'. + ENDIF. + IF lv_total < '30.00'. + rv_fee = '30.00'. + ELSE. + rv_fee = lv_total. + ENDIF. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0139/spec.md b/tasks_gen/eval/G0139/spec.md new file mode 100644 index 0000000..690e38c --- /dev/null +++ b/tasks_gen/eval/G0139/spec.md @@ -0,0 +1,53 @@ +# 1. Goal +Refactor the class {{P}}MARINA_FEE in package $TMP. The class calculates the +berthing fee of a boat in a marina. The behavior of the class must not change. +The public interface of the class must not change. Improve the internal quality +of the class. + +# 2. Open questions +None. + +# 3. Context +- The class {{P}}MARINA_FEE exists in package $TMP. It is active. +- A marina uses the class to calculate the berthing fee of a boat. +- The class is legacy code. The results of the class are correct. The quality of + the code is poor. +- The class has one public method. This method contains the complete calculation. +- The source code of the class is the specification of the behavior. Read the + source code before you change it. + +# 4. Contract +- Change the class {{P}}MARINA_FEE in package $TMP. Do not create a new class. +- Keep the name of the class {{P}}MARINA_FEE. +- Keep the public interface of the class. The public interface is: + - The public types TY_BOAT_TYPE (CHAR 1), TY_SEASON (CHAR 1), and TY_FEE + (PACKED 8, 2 decimal places). + - The public method CALCULATE_FEE. + - The importing parameters of CALCULATE_FEE: IV_LENGTH_M (TYPE i), IV_NIGHTS + (TYPE i), IV_BOAT_TYPE (TYPE ty_boat_type), IV_SEASON (TYPE ty_season), and + IV_POWER (TYPE abap_bool). + - The returning parameter RV_FEE (TYPE ty_fee). +- Do not change the names, the types, or the sequence of the parameters. +- Do not add other public methods or public attributes. +- You can change the private section of the class. + +# 5. Business rules +- The method CALCULATE_FEE keeps its behavior. The behavior is the behavior of + the legacy class {{P}}MARINA_FEE in package $TMP. +- Read the legacy source code. The legacy source code is the only specification + of the calculation. +- Do not change a result value. Do not add a rule. Do not remove a rule. + +# 6. Constraints +- Release target: 8.16. +- Coding standards: Clean ABAP. Methods below 40 statements. No nesting deeper + than two levels. No magic numbers. Use constants. Use meaningful names. No + comment that restates the code. +- Out of scope: none. + +# 7. Acceptance +- The class {{P}}MARINA_FEE is active and has no syntax error. +- The public interface of the class is unchanged. +- The behavior of the class is unchanged. The hidden tests pass. +- The class has no ATC priority 1 finding and no ATC priority 2 finding. +- Write your own ABAP Unit tests for the class. diff --git a/tasks_gen/eval/G0139/task.json b/tasks_gen/eval/G0139/task.json new file mode 100644 index 0000000..2fc7410 --- /dev/null +++ b/tasks_gen/eval/G0139/task.json @@ -0,0 +1,49 @@ +{ + "id": "G0139", + "category": "E", + "object_type": "CLAS", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [ + { + "type": "CLAS", + "name": "{{P}}MARINA_FEE", + "file": "seed/marina_fee.clas.abap", + "description": "Legacy marina berth fee calculator with deep nesting and magic numbers" + } + ], + "contract": [ + { + "type": "CLAS", + "name": "{{P}}MARINA_FEE" + } + ], + "out_of_scope": [], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}MARINA_FEE_HIDDEN", + "file": "hidden/marina_fee_hidden.clas.abap", + "description": "Hidden tests for the unchanged berth fee behavior" + } + ], + "reference": [ + { + "type": "CLAS", + "name": "{{P}}MARINA_FEE", + "file": "reference/marina_fee.clas.abap", + "description": "Refactored marina berth fee calculator", + "testclasses_file": "reference/marina_fee.testclasses.abap" + } + ], + "craft_checks": [ + "method_length", + "nesting_depth", + "magic_numbers" + ] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0140/faulty/m0_carwash_rpt.prog.abap b/tasks_gen/eval/G0140/faulty/m0_carwash_rpt.prog.abap new file mode 100644 index 0000000..01a2680 --- /dev/null +++ b/tasks_gen/eval/G0140/faulty/m0_carwash_rpt.prog.abap @@ -0,0 +1,157 @@ +REPORT {{p}}carwash_rpt. + +DATA gv_prog TYPE {{p}}carwash-wash_prog. + +PARAMETERS: p_from TYPE d OBLIGATORY, + p_to TYPE d OBLIGATORY. + +SELECT-OPTIONS: s_prog FOR gv_prog. + +CLASS lcl_report DEFINITION FINAL. + PUBLIC SECTION. + TYPES: + BEGIN OF ty_line, + wash_prog TYPE {{p}}carwash-wash_prog, + prog_text TYPE {{p}}washpgm-prog_text, + washes TYPE i, + revenue TYPE {{p}}carwash-price, + vip_washes TYPE i, + vip_revenue TYPE {{p}}carwash-price, + END OF ty_line, + tt_line TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY, + tt_prog TYPE RANGE OF {{p}}carwash-wash_prog. + + METHODS collect + IMPORTING iv_from TYPE d + iv_to TYPE d + it_prog TYPE tt_prog + RETURNING VALUE(rt_lines) TYPE tt_line. + + METHODS display + CHANGING ct_lines TYPE tt_line. + + PRIVATE SECTION. + TYPES: + BEGIN OF ty_raw, + wash_prog TYPE {{p}}carwash-wash_prog, + prog_text TYPE {{p}}washpgm-prog_text, + price TYPE {{p}}carwash-price, + cust_type TYPE {{p}}carwash-cust_type, + END OF ty_raw, + tt_raw TYPE STANDARD TABLE OF ty_raw WITH EMPTY KEY. + + METHODS read_washes + IMPORTING iv_from TYPE d + iv_to TYPE d + it_prog TYPE tt_prog + RETURNING VALUE(rt_raw) TYPE tt_raw. + + METHODS aggregate + IMPORTING it_raw TYPE tt_raw + RETURNING VALUE(rt_lines) TYPE tt_line. +ENDCLASS. + +CLASS lcl_report IMPLEMENTATION. + METHOD collect. + rt_lines = aggregate( read_washes( iv_from = iv_from + iv_to = iv_to + it_prog = it_prog ) ). + SORT rt_lines BY revenue DESCENDING. + ENDMETHOD. + + METHOD read_washes. + SELECT c~wash_prog, p~prog_text, c~price, c~cust_type + FROM {{p}}carwash AS c + LEFT OUTER JOIN {{p}}washpgm AS p ON p~wash_prog = c~wash_prog + WHERE c~wash_date < @iv_from + AND c~wash_date <= @iv_to + AND c~wash_prog IN @it_prog + INTO CORRESPONDING FIELDS OF TABLE @rt_raw. + ENDMETHOD. + + METHOD aggregate. + LOOP AT it_raw INTO DATA(ls_raw). + IF NOT line_exists( rt_lines[ wash_prog = ls_raw-wash_prog ] ). + APPEND VALUE #( wash_prog = ls_raw-wash_prog + prog_text = ls_raw-prog_text ) TO rt_lines. + ENDIF. + ASSIGN rt_lines[ wash_prog = ls_raw-wash_prog ] TO FIELD-SYMBOL(). + -washes = -washes + 1. + -revenue = -revenue + ls_raw-price. + IF ls_raw-cust_type = 'VIP'. + -vip_washes = -vip_washes + 1. + -vip_revenue = -vip_revenue + ls_raw-price. + ENDIF. + ENDLOOP. + 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->collect( iv_from = p_from + iv_to = p_to + it_prog = s_prog[] ). + 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_program FOR TESTING. + METHODS program_filter FOR TESTING. +ENDCLASS. + +CLASS ltc_report IMPLEMENTATION. + METHOD class_setup. + go_env = cl_osql_test_environment=>create( + i_dependency_list = VALUE #( ( '{{P}}CARWASH' ) ( '{{P}}WASHPGM' ) ) ). + + DATA lt_carwash TYPE STANDARD TABLE OF {{p}}carwash WITH EMPTY KEY. + lt_carwash = VALUE #( + ( wash_id = 1 wash_prog = 'A' wash_date = '20260101' price = 10 cust_type = 'STD' ) + ( wash_id = 2 wash_prog = 'A' wash_date = '20260102' price = 5 cust_type = 'VIP' ) + ( wash_id = 3 wash_prog = 'B' wash_date = '20260101' price = 40 cust_type = 'STD' ) ). + go_env->insert_test_data( lt_carwash ). + + DATA lt_prog TYPE STANDARD TABLE OF {{p}}washpgm WITH EMPTY KEY. + lt_prog = VALUE #( ( wash_prog = 'A' prog_text = 'Alpha' ) + ( wash_prog = 'B' prog_text = 'Beta' ) ). + go_env->insert_test_data( lt_prog ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD totals_per_program. + DATA(lt_lines) = NEW lcl_report( )->collect( iv_from = '20260101' + iv_to = '20260131' + it_prog = VALUE #( ) ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 'B' act = lt_lines[ 1 ]-wash_prog ). + cl_abap_unit_assert=>assert_equals( exp = 'Beta' act = lt_lines[ 1 ]-prog_text ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lt_lines[ 2 ]-washes ). + cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}carwash-price( 15 ) act = lt_lines[ 2 ]-revenue ). + ENDMETHOD. + + METHOD program_filter. + DATA(lt_lines) = NEW lcl_report( )->collect( + iv_from = '20260101' + iv_to = '20260131' + it_prog = VALUE #( ( sign = 'I' option = 'EQ' low = 'A' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lt_lines[ 1 ]-vip_washes ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0140/faulty/m1_carwash_rpt.prog.abap b/tasks_gen/eval/G0140/faulty/m1_carwash_rpt.prog.abap new file mode 100644 index 0000000..33184a5 --- /dev/null +++ b/tasks_gen/eval/G0140/faulty/m1_carwash_rpt.prog.abap @@ -0,0 +1,157 @@ +REPORT {{p}}carwash_rpt. + +DATA gv_prog TYPE {{p}}carwash-wash_prog. + +PARAMETERS: p_from TYPE d OBLIGATORY, + p_to TYPE d OBLIGATORY. + +SELECT-OPTIONS: s_prog FOR gv_prog. + +CLASS lcl_report DEFINITION FINAL. + PUBLIC SECTION. + TYPES: + BEGIN OF ty_line, + wash_prog TYPE {{p}}carwash-wash_prog, + prog_text TYPE {{p}}washpgm-prog_text, + washes TYPE i, + revenue TYPE {{p}}carwash-price, + vip_washes TYPE i, + vip_revenue TYPE {{p}}carwash-price, + END OF ty_line, + tt_line TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY, + tt_prog TYPE RANGE OF {{p}}carwash-wash_prog. + + METHODS collect + IMPORTING iv_from TYPE d + iv_to TYPE d + it_prog TYPE tt_prog + RETURNING VALUE(rt_lines) TYPE tt_line. + + METHODS display + CHANGING ct_lines TYPE tt_line. + + PRIVATE SECTION. + TYPES: + BEGIN OF ty_raw, + wash_prog TYPE {{p}}carwash-wash_prog, + prog_text TYPE {{p}}washpgm-prog_text, + price TYPE {{p}}carwash-price, + cust_type TYPE {{p}}carwash-cust_type, + END OF ty_raw, + tt_raw TYPE STANDARD TABLE OF ty_raw WITH EMPTY KEY. + + METHODS read_washes + IMPORTING iv_from TYPE d + iv_to TYPE d + it_prog TYPE tt_prog + RETURNING VALUE(rt_raw) TYPE tt_raw. + + METHODS aggregate + IMPORTING it_raw TYPE tt_raw + RETURNING VALUE(rt_lines) TYPE tt_line. +ENDCLASS. + +CLASS lcl_report IMPLEMENTATION. + METHOD collect. + rt_lines = aggregate( read_washes( iv_from = iv_from + iv_to = iv_to + it_prog = it_prog ) ). + SORT rt_lines BY revenue DESCENDING. + ENDMETHOD. + + METHOD read_washes. + SELECT c~wash_prog, p~prog_text, c~price, c~cust_type + FROM {{p}}carwash AS c + LEFT OUTER JOIN {{p}}washpgm AS p ON p~wash_prog = c~wash_prog + WHERE c~wash_date >= @iv_from + OR c~wash_date <= @iv_to + AND c~wash_prog IN @it_prog + INTO CORRESPONDING FIELDS OF TABLE @rt_raw. + ENDMETHOD. + + METHOD aggregate. + LOOP AT it_raw INTO DATA(ls_raw). + IF NOT line_exists( rt_lines[ wash_prog = ls_raw-wash_prog ] ). + APPEND VALUE #( wash_prog = ls_raw-wash_prog + prog_text = ls_raw-prog_text ) TO rt_lines. + ENDIF. + ASSIGN rt_lines[ wash_prog = ls_raw-wash_prog ] TO FIELD-SYMBOL(). + -washes = -washes + 1. + -revenue = -revenue + ls_raw-price. + IF ls_raw-cust_type = 'VIP'. + -vip_washes = -vip_washes + 1. + -vip_revenue = -vip_revenue + ls_raw-price. + ENDIF. + ENDLOOP. + 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->collect( iv_from = p_from + iv_to = p_to + it_prog = s_prog[] ). + 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_program FOR TESTING. + METHODS program_filter FOR TESTING. +ENDCLASS. + +CLASS ltc_report IMPLEMENTATION. + METHOD class_setup. + go_env = cl_osql_test_environment=>create( + i_dependency_list = VALUE #( ( '{{P}}CARWASH' ) ( '{{P}}WASHPGM' ) ) ). + + DATA lt_carwash TYPE STANDARD TABLE OF {{p}}carwash WITH EMPTY KEY. + lt_carwash = VALUE #( + ( wash_id = 1 wash_prog = 'A' wash_date = '20260101' price = 10 cust_type = 'STD' ) + ( wash_id = 2 wash_prog = 'A' wash_date = '20260102' price = 5 cust_type = 'VIP' ) + ( wash_id = 3 wash_prog = 'B' wash_date = '20260101' price = 40 cust_type = 'STD' ) ). + go_env->insert_test_data( lt_carwash ). + + DATA lt_prog TYPE STANDARD TABLE OF {{p}}washpgm WITH EMPTY KEY. + lt_prog = VALUE #( ( wash_prog = 'A' prog_text = 'Alpha' ) + ( wash_prog = 'B' prog_text = 'Beta' ) ). + go_env->insert_test_data( lt_prog ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD totals_per_program. + DATA(lt_lines) = NEW lcl_report( )->collect( iv_from = '20260101' + iv_to = '20260131' + it_prog = VALUE #( ) ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 'B' act = lt_lines[ 1 ]-wash_prog ). + cl_abap_unit_assert=>assert_equals( exp = 'Beta' act = lt_lines[ 1 ]-prog_text ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lt_lines[ 2 ]-washes ). + cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}carwash-price( 15 ) act = lt_lines[ 2 ]-revenue ). + ENDMETHOD. + + METHOD program_filter. + DATA(lt_lines) = NEW lcl_report( )->collect( + iv_from = '20260101' + iv_to = '20260131' + it_prog = VALUE #( ( sign = 'I' option = 'EQ' low = 'A' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lt_lines[ 1 ]-vip_washes ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0140/faulty/m2_carwash_rpt.prog.abap b/tasks_gen/eval/G0140/faulty/m2_carwash_rpt.prog.abap new file mode 100644 index 0000000..7f9a4c6 --- /dev/null +++ b/tasks_gen/eval/G0140/faulty/m2_carwash_rpt.prog.abap @@ -0,0 +1,157 @@ +REPORT {{p}}carwash_rpt. + +DATA gv_prog TYPE {{p}}carwash-wash_prog. + +PARAMETERS: p_from TYPE d OBLIGATORY, + p_to TYPE d OBLIGATORY. + +SELECT-OPTIONS: s_prog FOR gv_prog. + +CLASS lcl_report DEFINITION FINAL. + PUBLIC SECTION. + TYPES: + BEGIN OF ty_line, + wash_prog TYPE {{p}}carwash-wash_prog, + prog_text TYPE {{p}}washpgm-prog_text, + washes TYPE i, + revenue TYPE {{p}}carwash-price, + vip_washes TYPE i, + vip_revenue TYPE {{p}}carwash-price, + END OF ty_line, + tt_line TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY, + tt_prog TYPE RANGE OF {{p}}carwash-wash_prog. + + METHODS collect + IMPORTING iv_from TYPE d + iv_to TYPE d + it_prog TYPE tt_prog + RETURNING VALUE(rt_lines) TYPE tt_line. + + METHODS display + CHANGING ct_lines TYPE tt_line. + + PRIVATE SECTION. + TYPES: + BEGIN OF ty_raw, + wash_prog TYPE {{p}}carwash-wash_prog, + prog_text TYPE {{p}}washpgm-prog_text, + price TYPE {{p}}carwash-price, + cust_type TYPE {{p}}carwash-cust_type, + END OF ty_raw, + tt_raw TYPE STANDARD TABLE OF ty_raw WITH EMPTY KEY. + + METHODS read_washes + IMPORTING iv_from TYPE d + iv_to TYPE d + it_prog TYPE tt_prog + RETURNING VALUE(rt_raw) TYPE tt_raw. + + METHODS aggregate + IMPORTING it_raw TYPE tt_raw + RETURNING VALUE(rt_lines) TYPE tt_line. +ENDCLASS. + +CLASS lcl_report IMPLEMENTATION. + METHOD collect. + rt_lines = aggregate( read_washes( iv_from = iv_from + iv_to = iv_to + it_prog = it_prog ) ). + SORT rt_lines BY revenue DESCENDING. + ENDMETHOD. + + METHOD read_washes. + SELECT c~wash_prog, p~prog_text, c~price, c~cust_type + FROM {{p}}carwash AS c + LEFT OUTER JOIN {{p}}washpgm AS p ON p~wash_prog = c~wash_prog + WHERE c~wash_date >= @iv_from + AND c~wash_date <= @iv_to + AND c~wash_prog IN @it_prog + INTO CORRESPONDING FIELDS OF TABLE @rt_raw. + ENDMETHOD. + + METHOD aggregate. + LOOP AT it_raw INTO DATA(ls_raw). + IF NOT line_exists( rt_lines[ wash_prog = ls_raw-wash_prog ] ). + APPEND VALUE #( wash_prog = ls_raw-wash_prog + prog_text = ls_raw-prog_text ) TO rt_lines. + ENDIF. + ASSIGN rt_lines[ wash_prog = ls_raw-wash_prog ] TO FIELD-SYMBOL(). + -washes = -washes + 1. + -revenue = -revenue - ls_raw-price. + IF ls_raw-cust_type = 'VIP'. + -vip_washes = -vip_washes + 1. + -vip_revenue = -vip_revenue + ls_raw-price. + ENDIF. + ENDLOOP. + 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->collect( iv_from = p_from + iv_to = p_to + it_prog = s_prog[] ). + 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_program FOR TESTING. + METHODS program_filter FOR TESTING. +ENDCLASS. + +CLASS ltc_report IMPLEMENTATION. + METHOD class_setup. + go_env = cl_osql_test_environment=>create( + i_dependency_list = VALUE #( ( '{{P}}CARWASH' ) ( '{{P}}WASHPGM' ) ) ). + + DATA lt_carwash TYPE STANDARD TABLE OF {{p}}carwash WITH EMPTY KEY. + lt_carwash = VALUE #( + ( wash_id = 1 wash_prog = 'A' wash_date = '20260101' price = 10 cust_type = 'STD' ) + ( wash_id = 2 wash_prog = 'A' wash_date = '20260102' price = 5 cust_type = 'VIP' ) + ( wash_id = 3 wash_prog = 'B' wash_date = '20260101' price = 40 cust_type = 'STD' ) ). + go_env->insert_test_data( lt_carwash ). + + DATA lt_prog TYPE STANDARD TABLE OF {{p}}washpgm WITH EMPTY KEY. + lt_prog = VALUE #( ( wash_prog = 'A' prog_text = 'Alpha' ) + ( wash_prog = 'B' prog_text = 'Beta' ) ). + go_env->insert_test_data( lt_prog ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD totals_per_program. + DATA(lt_lines) = NEW lcl_report( )->collect( iv_from = '20260101' + iv_to = '20260131' + it_prog = VALUE #( ) ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 'B' act = lt_lines[ 1 ]-wash_prog ). + cl_abap_unit_assert=>assert_equals( exp = 'Beta' act = lt_lines[ 1 ]-prog_text ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lt_lines[ 2 ]-washes ). + cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}carwash-price( 15 ) act = lt_lines[ 2 ]-revenue ). + ENDMETHOD. + + METHOD program_filter. + DATA(lt_lines) = NEW lcl_report( )->collect( + iv_from = '20260101' + iv_to = '20260131' + it_prog = VALUE #( ( sign = 'I' option = 'EQ' low = 'A' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lt_lines[ 1 ]-vip_washes ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0140/faulty/m3_carwash_rpt.prog.abap b/tasks_gen/eval/G0140/faulty/m3_carwash_rpt.prog.abap new file mode 100644 index 0000000..4512162 --- /dev/null +++ b/tasks_gen/eval/G0140/faulty/m3_carwash_rpt.prog.abap @@ -0,0 +1,157 @@ +REPORT {{p}}carwash_rpt. + +DATA gv_prog TYPE {{p}}carwash-wash_prog. + +PARAMETERS: p_from TYPE d OBLIGATORY, + p_to TYPE d OBLIGATORY. + +SELECT-OPTIONS: s_prog FOR gv_prog. + +CLASS lcl_report DEFINITION FINAL. + PUBLIC SECTION. + TYPES: + BEGIN OF ty_line, + wash_prog TYPE {{p}}carwash-wash_prog, + prog_text TYPE {{p}}washpgm-prog_text, + washes TYPE i, + revenue TYPE {{p}}carwash-price, + vip_washes TYPE i, + vip_revenue TYPE {{p}}carwash-price, + END OF ty_line, + tt_line TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY, + tt_prog TYPE RANGE OF {{p}}carwash-wash_prog. + + METHODS collect + IMPORTING iv_from TYPE d + iv_to TYPE d + it_prog TYPE tt_prog + RETURNING VALUE(rt_lines) TYPE tt_line. + + METHODS display + CHANGING ct_lines TYPE tt_line. + + PRIVATE SECTION. + TYPES: + BEGIN OF ty_raw, + wash_prog TYPE {{p}}carwash-wash_prog, + prog_text TYPE {{p}}washpgm-prog_text, + price TYPE {{p}}carwash-price, + cust_type TYPE {{p}}carwash-cust_type, + END OF ty_raw, + tt_raw TYPE STANDARD TABLE OF ty_raw WITH EMPTY KEY. + + METHODS read_washes + IMPORTING iv_from TYPE d + iv_to TYPE d + it_prog TYPE tt_prog + RETURNING VALUE(rt_raw) TYPE tt_raw. + + METHODS aggregate + IMPORTING it_raw TYPE tt_raw + RETURNING VALUE(rt_lines) TYPE tt_line. +ENDCLASS. + +CLASS lcl_report IMPLEMENTATION. + METHOD collect. + rt_lines = aggregate( read_washes( iv_from = iv_from + iv_to = iv_to + it_prog = it_prog ) ). + SORT rt_lines BY revenue DESCENDING. + ENDMETHOD. + + METHOD read_washes. + SELECT c~wash_prog, p~prog_text, c~price, c~cust_type + FROM {{p}}carwash AS c + LEFT OUTER JOIN {{p}}washpgm AS p ON p~wash_prog = c~wash_prog + WHERE c~wash_date >= @iv_from + AND c~wash_date <= @iv_to + AND c~wash_prog IN @it_prog + INTO CORRESPONDING FIELDS OF TABLE @rt_raw. + ENDMETHOD. + + METHOD aggregate. + LOOP AT it_raw INTO DATA(ls_raw). + IF NOT line_exists( rt_lines[ wash_prog = ls_raw-wash_prog ] ). + APPEND VALUE #( wash_prog = ls_raw-wash_prog + prog_text = ls_raw-prog_text ) TO rt_lines. + ENDIF. + ASSIGN rt_lines[ wash_prog = ls_raw-wash_prog ] TO FIELD-SYMBOL(). + -washes = -washes + 1. + -revenue = -revenue + ls_raw-price. + IF ls_raw-cust_type <> 'VIP'. + -vip_washes = -vip_washes + 1. + -vip_revenue = -vip_revenue + ls_raw-price. + ENDIF. + ENDLOOP. + 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->collect( iv_from = p_from + iv_to = p_to + it_prog = s_prog[] ). + 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_program FOR TESTING. + METHODS program_filter FOR TESTING. +ENDCLASS. + +CLASS ltc_report IMPLEMENTATION. + METHOD class_setup. + go_env = cl_osql_test_environment=>create( + i_dependency_list = VALUE #( ( '{{P}}CARWASH' ) ( '{{P}}WASHPGM' ) ) ). + + DATA lt_carwash TYPE STANDARD TABLE OF {{p}}carwash WITH EMPTY KEY. + lt_carwash = VALUE #( + ( wash_id = 1 wash_prog = 'A' wash_date = '20260101' price = 10 cust_type = 'STD' ) + ( wash_id = 2 wash_prog = 'A' wash_date = '20260102' price = 5 cust_type = 'VIP' ) + ( wash_id = 3 wash_prog = 'B' wash_date = '20260101' price = 40 cust_type = 'STD' ) ). + go_env->insert_test_data( lt_carwash ). + + DATA lt_prog TYPE STANDARD TABLE OF {{p}}washpgm WITH EMPTY KEY. + lt_prog = VALUE #( ( wash_prog = 'A' prog_text = 'Alpha' ) + ( wash_prog = 'B' prog_text = 'Beta' ) ). + go_env->insert_test_data( lt_prog ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD totals_per_program. + DATA(lt_lines) = NEW lcl_report( )->collect( iv_from = '20260101' + iv_to = '20260131' + it_prog = VALUE #( ) ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 'B' act = lt_lines[ 1 ]-wash_prog ). + cl_abap_unit_assert=>assert_equals( exp = 'Beta' act = lt_lines[ 1 ]-prog_text ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lt_lines[ 2 ]-washes ). + cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}carwash-price( 15 ) act = lt_lines[ 2 ]-revenue ). + ENDMETHOD. + + METHOD program_filter. + DATA(lt_lines) = NEW lcl_report( )->collect( + iv_from = '20260101' + iv_to = '20260131' + it_prog = VALUE #( ( sign = 'I' option = 'EQ' low = 'A' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lt_lines[ 1 ]-vip_washes ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0140/faulty/m4_carwash_rpt.prog.abap b/tasks_gen/eval/G0140/faulty/m4_carwash_rpt.prog.abap new file mode 100644 index 0000000..129e4f3 --- /dev/null +++ b/tasks_gen/eval/G0140/faulty/m4_carwash_rpt.prog.abap @@ -0,0 +1,157 @@ +REPORT {{p}}carwash_rpt. + +DATA gv_prog TYPE {{p}}carwash-wash_prog. + +PARAMETERS: p_from TYPE d OBLIGATORY, + p_to TYPE d OBLIGATORY. + +SELECT-OPTIONS: s_prog FOR gv_prog. + +CLASS lcl_report DEFINITION FINAL. + PUBLIC SECTION. + TYPES: + BEGIN OF ty_line, + wash_prog TYPE {{p}}carwash-wash_prog, + prog_text TYPE {{p}}washpgm-prog_text, + washes TYPE i, + revenue TYPE {{p}}carwash-price, + vip_washes TYPE i, + vip_revenue TYPE {{p}}carwash-price, + END OF ty_line, + tt_line TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY, + tt_prog TYPE RANGE OF {{p}}carwash-wash_prog. + + METHODS collect + IMPORTING iv_from TYPE d + iv_to TYPE d + it_prog TYPE tt_prog + RETURNING VALUE(rt_lines) TYPE tt_line. + + METHODS display + CHANGING ct_lines TYPE tt_line. + + PRIVATE SECTION. + TYPES: + BEGIN OF ty_raw, + wash_prog TYPE {{p}}carwash-wash_prog, + prog_text TYPE {{p}}washpgm-prog_text, + price TYPE {{p}}carwash-price, + cust_type TYPE {{p}}carwash-cust_type, + END OF ty_raw, + tt_raw TYPE STANDARD TABLE OF ty_raw WITH EMPTY KEY. + + METHODS read_washes + IMPORTING iv_from TYPE d + iv_to TYPE d + it_prog TYPE tt_prog + RETURNING VALUE(rt_raw) TYPE tt_raw. + + METHODS aggregate + IMPORTING it_raw TYPE tt_raw + RETURNING VALUE(rt_lines) TYPE tt_line. +ENDCLASS. + +CLASS lcl_report IMPLEMENTATION. + METHOD collect. + rt_lines = aggregate( read_washes( iv_from = iv_from + iv_to = iv_to + it_prog = it_prog ) ). + SORT rt_lines BY revenue DESCENDING. + ENDMETHOD. + + METHOD read_washes. + SELECT c~wash_prog, p~prog_text, c~price, c~cust_type + FROM {{p}}carwash AS c + LEFT OUTER JOIN {{p}}washpgm AS p ON p~wash_prog = c~wash_prog + WHERE c~wash_date >= @iv_from + AND c~wash_date <= @iv_to + AND c~wash_prog IN @it_prog + INTO CORRESPONDING FIELDS OF TABLE @rt_raw. + ENDMETHOD. + + METHOD aggregate. + LOOP AT it_raw INTO DATA(ls_raw). + IF NOT line_exists( rt_lines[ wash_prog = ls_raw-wash_prog ] ). + APPEND VALUE #( wash_prog = ls_raw-wash_prog + prog_text = ls_raw-prog_text ) TO rt_lines. + ENDIF. + ASSIGN rt_lines[ wash_prog = ls_raw-wash_prog ] TO FIELD-SYMBOL(). + -washes = -washes + 1. + -revenue = -revenue + ls_raw-price. + IF ls_raw-cust_type = 'VIP'. + -vip_washes = -vip_washes - 1. + -vip_revenue = -vip_revenue + ls_raw-price. + ENDIF. + ENDLOOP. + 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->collect( iv_from = p_from + iv_to = p_to + it_prog = s_prog[] ). + 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_program FOR TESTING. + METHODS program_filter FOR TESTING. +ENDCLASS. + +CLASS ltc_report IMPLEMENTATION. + METHOD class_setup. + go_env = cl_osql_test_environment=>create( + i_dependency_list = VALUE #( ( '{{P}}CARWASH' ) ( '{{P}}WASHPGM' ) ) ). + + DATA lt_carwash TYPE STANDARD TABLE OF {{p}}carwash WITH EMPTY KEY. + lt_carwash = VALUE #( + ( wash_id = 1 wash_prog = 'A' wash_date = '20260101' price = 10 cust_type = 'STD' ) + ( wash_id = 2 wash_prog = 'A' wash_date = '20260102' price = 5 cust_type = 'VIP' ) + ( wash_id = 3 wash_prog = 'B' wash_date = '20260101' price = 40 cust_type = 'STD' ) ). + go_env->insert_test_data( lt_carwash ). + + DATA lt_prog TYPE STANDARD TABLE OF {{p}}washpgm WITH EMPTY KEY. + lt_prog = VALUE #( ( wash_prog = 'A' prog_text = 'Alpha' ) + ( wash_prog = 'B' prog_text = 'Beta' ) ). + go_env->insert_test_data( lt_prog ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD totals_per_program. + DATA(lt_lines) = NEW lcl_report( )->collect( iv_from = '20260101' + iv_to = '20260131' + it_prog = VALUE #( ) ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 'B' act = lt_lines[ 1 ]-wash_prog ). + cl_abap_unit_assert=>assert_equals( exp = 'Beta' act = lt_lines[ 1 ]-prog_text ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lt_lines[ 2 ]-washes ). + cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}carwash-price( 15 ) act = lt_lines[ 2 ]-revenue ). + ENDMETHOD. + + METHOD program_filter. + DATA(lt_lines) = NEW lcl_report( )->collect( + iv_from = '20260101' + iv_to = '20260131' + it_prog = VALUE #( ( sign = 'I' option = 'EQ' low = 'A' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lt_lines[ 1 ]-vip_washes ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0140/generation.json b/tasks_gen/eval/G0140/generation.json new file mode 100644 index 0000000..ede300b --- /dev/null +++ b/tasks_gen/eval/G0140/generation.json @@ -0,0 +1,19 @@ +{ + "id": "G0140", + "pool": "eval", + "object_type": "PROG", + "category": "E", + "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/eval/G0140/hidden/carwash_hidden.clas.abap b/tasks_gen/eval/G0140/hidden/carwash_hidden.clas.abap new file mode 100644 index 0000000..85998e9 --- /dev/null +++ b/tasks_gen/eval/G0140/hidden/carwash_hidden.clas.abap @@ -0,0 +1,114 @@ +CLASS {{p}}carwash_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + TYPES tt_prog TYPE RANGE OF {{p}}carwash-wash_prog. + METHODS run + IMPORTING iv_from TYPE d + iv_to TYPE d + it_prog TYPE tt_prog 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 all_programs FOR TESTING. + METHODS sorted_by_revenue FOR TESTING. + METHODS counts_and_revenue FOR TESTING. + METHODS vip_split FOR TESTING. + METHODS program_text FOR TESTING. + METHODS date_filter FOR TESTING. + METHODS program_filter FOR TESTING. +ENDCLASS. + + +CLASS {{p}}carwash_hidden IMPLEMENTATION. + METHOD run. + cl_salv_bs_runtime_info=>set( display = abap_false metadata = abap_false data = abap_true ). + SUBMIT {{p}}carwash_rpt WITH p_from = iv_from WITH p_to = iv_to WITH s_prog IN it_prog 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 all_programs. + cl_abap_unit_assert=>assert_equals( + exp = 3 + act = lines_of( run( iv_from = '20260101' iv_to = '20260131' ) ) ). + ENDMETHOD. + + METHOD sorted_by_revenue. + DATA(lr_data) = run( iv_from = '20260101' iv_to = '20260131' ). + cl_abap_unit_assert=>assert_equals( + exp = `DLX` + act = value_of( ir_data = lr_data iv_row = 1 iv_col = `WASH_PROG` ) ). + cl_abap_unit_assert=>assert_equals( + exp = `BAS` + act = value_of( ir_data = lr_data iv_row = 3 iv_col = `WASH_PROG` ) ). + ENDMETHOD. + + METHOD counts_and_revenue. + DATA(lr_data) = run( iv_from = '20260101' iv_to = '20260131' ). + cl_abap_unit_assert=>assert_equals( + exp = `3` + act = value_of( ir_data = lr_data iv_row = 1 iv_col = `WASHES` ) ). + cl_abap_unit_assert=>assert_equals( + exp = `60.00` + act = value_of( ir_data = lr_data iv_row = 1 iv_col = `REVENUE` ) ). + ENDMETHOD. + + METHOD vip_split. + DATA(lr_data) = run( iv_from = '20260101' iv_to = '20260131' ). + cl_abap_unit_assert=>assert_equals( + exp = `1` + act = value_of( ir_data = lr_data iv_row = 1 iv_col = `VIP_WASHES` ) ). + cl_abap_unit_assert=>assert_equals( + exp = `20.00` + act = value_of( ir_data = lr_data iv_row = 1 iv_col = `VIP_REVENUE` ) ). + ENDMETHOD. + + METHOD program_text. + DATA(lr_data) = run( iv_from = '20260101' iv_to = '20260131' ). + cl_abap_unit_assert=>assert_equals( + exp = `Premium wash` + act = value_of( ir_data = lr_data iv_row = 2 iv_col = `PROG_TEXT` ) ). + ENDMETHOD. + + METHOD date_filter. + cl_abap_unit_assert=>assert_equals( + exp = 2 + act = lines_of( run( iv_from = '20260201' iv_to = '20260228' ) ) ). + ENDMETHOD. + + METHOD program_filter. + DATA(lr_data) = run( iv_from = '20260101' + iv_to = '20260131' + it_prog = VALUE #( ( sign = 'I' option = 'EQ' low = 'BAS' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lines_of( lr_data ) ). + cl_abap_unit_assert=>assert_equals( + exp = `20.00` + act = value_of( ir_data = lr_data iv_row = 1 iv_col = `REVENUE` ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0140/mutation.json b/tasks_gen/eval/G0140/mutation.json new file mode 100644 index 0000000..b6b9366 --- /dev/null +++ b/tasks_gen/eval/G0140/mutation.json @@ -0,0 +1,68 @@ +{ + "task": "G0140", + "mutants": [ + { + "object": "{{P}}CARWASH_RPT", + "mutant": "line 66: >= -> < (rel)", + "status": "killed", + "hidden": "0/7", + "failed_tests": [ + "ALL_PROGRAMS", + "COUNTS_AND_REVENUE", + "DATE_FILTER", + "PROGRAM_FILTER", + "PROGRAM_TEXT", + "SORTED_BY_REVENUE", + "VIP_SPLIT" + ] + }, + { + "object": "{{P}}CARWASH_RPT", + "mutant": "line 67: AND -> OR (logic)", + "status": "killed", + "hidden": "1/7", + "failed_tests": [ + "COUNTS_AND_REVENUE", + "DATE_FILTER", + "PROGRAM_FILTER", + "PROGRAM_TEXT", + "SORTED_BY_REVENUE", + "VIP_SPLIT" + ] + }, + { + "object": "{{P}}CARWASH_RPT", + "mutant": "line 80: + -> - (arith)", + "status": "killed", + "hidden": "3/7", + "failed_tests": [ + "COUNTS_AND_REVENUE", + "PROGRAM_FILTER", + "SORTED_BY_REVENUE", + "VIP_SPLIT" + ] + }, + { + "object": "{{P}}CARWASH_RPT", + "mutant": "line 81: = -> <> (eq)", + "status": "killed", + "hidden": "6/7", + "failed_tests": [ + "VIP_SPLIT" + ] + }, + { + "object": "{{P}}CARWASH_RPT", + "mutant": "line 82: + -> - (arith)", + "status": "killed", + "hidden": "6/7", + "failed_tests": [ + "VIP_SPLIT" + ] + } + ], + "valid": 5, + "killed": 5, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0140/reference/carwash_rpt.prog.abap b/tasks_gen/eval/G0140/reference/carwash_rpt.prog.abap new file mode 100644 index 0000000..22244e7 --- /dev/null +++ b/tasks_gen/eval/G0140/reference/carwash_rpt.prog.abap @@ -0,0 +1,157 @@ +REPORT {{p}}carwash_rpt. + +DATA gv_prog TYPE {{p}}carwash-wash_prog. + +PARAMETERS: p_from TYPE d OBLIGATORY, + p_to TYPE d OBLIGATORY. + +SELECT-OPTIONS: s_prog FOR gv_prog. + +CLASS lcl_report DEFINITION FINAL. + PUBLIC SECTION. + TYPES: + BEGIN OF ty_line, + wash_prog TYPE {{p}}carwash-wash_prog, + prog_text TYPE {{p}}washpgm-prog_text, + washes TYPE i, + revenue TYPE {{p}}carwash-price, + vip_washes TYPE i, + vip_revenue TYPE {{p}}carwash-price, + END OF ty_line, + tt_line TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY, + tt_prog TYPE RANGE OF {{p}}carwash-wash_prog. + + METHODS collect + IMPORTING iv_from TYPE d + iv_to TYPE d + it_prog TYPE tt_prog + RETURNING VALUE(rt_lines) TYPE tt_line. + + METHODS display + CHANGING ct_lines TYPE tt_line. + + PRIVATE SECTION. + TYPES: + BEGIN OF ty_raw, + wash_prog TYPE {{p}}carwash-wash_prog, + prog_text TYPE {{p}}washpgm-prog_text, + price TYPE {{p}}carwash-price, + cust_type TYPE {{p}}carwash-cust_type, + END OF ty_raw, + tt_raw TYPE STANDARD TABLE OF ty_raw WITH EMPTY KEY. + + METHODS read_washes + IMPORTING iv_from TYPE d + iv_to TYPE d + it_prog TYPE tt_prog + RETURNING VALUE(rt_raw) TYPE tt_raw. + + METHODS aggregate + IMPORTING it_raw TYPE tt_raw + RETURNING VALUE(rt_lines) TYPE tt_line. +ENDCLASS. + +CLASS lcl_report IMPLEMENTATION. + METHOD collect. + rt_lines = aggregate( read_washes( iv_from = iv_from + iv_to = iv_to + it_prog = it_prog ) ). + SORT rt_lines BY revenue DESCENDING. + ENDMETHOD. + + METHOD read_washes. + SELECT c~wash_prog, p~prog_text, c~price, c~cust_type + FROM {{p}}carwash AS c + LEFT OUTER JOIN {{p}}washpgm AS p ON p~wash_prog = c~wash_prog + WHERE c~wash_date >= @iv_from + AND c~wash_date <= @iv_to + AND c~wash_prog IN @it_prog + INTO CORRESPONDING FIELDS OF TABLE @rt_raw. + ENDMETHOD. + + METHOD aggregate. + LOOP AT it_raw INTO DATA(ls_raw). + IF NOT line_exists( rt_lines[ wash_prog = ls_raw-wash_prog ] ). + APPEND VALUE #( wash_prog = ls_raw-wash_prog + prog_text = ls_raw-prog_text ) TO rt_lines. + ENDIF. + ASSIGN rt_lines[ wash_prog = ls_raw-wash_prog ] TO FIELD-SYMBOL(). + -washes = -washes + 1. + -revenue = -revenue + ls_raw-price. + IF ls_raw-cust_type = 'VIP'. + -vip_washes = -vip_washes + 1. + -vip_revenue = -vip_revenue + ls_raw-price. + ENDIF. + ENDLOOP. + 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->collect( iv_from = p_from + iv_to = p_to + it_prog = s_prog[] ). + 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_program FOR TESTING. + METHODS program_filter FOR TESTING. +ENDCLASS. + +CLASS ltc_report IMPLEMENTATION. + METHOD class_setup. + go_env = cl_osql_test_environment=>create( + i_dependency_list = VALUE #( ( '{{P}}CARWASH' ) ( '{{P}}WASHPGM' ) ) ). + + DATA lt_carwash TYPE STANDARD TABLE OF {{p}}carwash WITH EMPTY KEY. + lt_carwash = VALUE #( + ( wash_id = 1 wash_prog = 'A' wash_date = '20260101' price = 10 cust_type = 'STD' ) + ( wash_id = 2 wash_prog = 'A' wash_date = '20260102' price = 5 cust_type = 'VIP' ) + ( wash_id = 3 wash_prog = 'B' wash_date = '20260101' price = 40 cust_type = 'STD' ) ). + go_env->insert_test_data( lt_carwash ). + + DATA lt_prog TYPE STANDARD TABLE OF {{p}}washpgm WITH EMPTY KEY. + lt_prog = VALUE #( ( wash_prog = 'A' prog_text = 'Alpha' ) + ( wash_prog = 'B' prog_text = 'Beta' ) ). + go_env->insert_test_data( lt_prog ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD totals_per_program. + DATA(lt_lines) = NEW lcl_report( )->collect( iv_from = '20260101' + iv_to = '20260131' + it_prog = VALUE #( ) ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 'B' act = lt_lines[ 1 ]-wash_prog ). + cl_abap_unit_assert=>assert_equals( exp = 'Beta' act = lt_lines[ 1 ]-prog_text ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lt_lines[ 2 ]-washes ). + cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}carwash-price( 15 ) act = lt_lines[ 2 ]-revenue ). + ENDMETHOD. + + METHOD program_filter. + DATA(lt_lines) = NEW lcl_report( )->collect( + iv_from = '20260101' + iv_to = '20260131' + it_prog = VALUE #( ( sign = 'I' option = 'EQ' low = 'A' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lt_lines[ 1 ]-vip_washes ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0140/seed/carwash.tabl.asabap b/tasks_gen/eval/G0140/seed/carwash.tabl.asabap new file mode 100644 index 0000000..0fb3ddf --- /dev/null +++ b/tasks_gen/eval/G0140/seed/carwash.tabl.asabap @@ -0,0 +1,13 @@ +@EndUserText.label : 'Car wash visits' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}carwash { + key client : abap.clnt not null; + key wash_id : abap.int4 not null; + wash_prog : abap.char(4); + wash_date : abap.dats; + price : abap.dec(15,2); + cust_type : abap.char(3); +} diff --git a/tasks_gen/eval/G0140/seed/carwash_rpt.prog.abap b/tasks_gen/eval/G0140/seed/carwash_rpt.prog.abap new file mode 100644 index 0000000..fb086ed --- /dev/null +++ b/tasks_gen/eval/G0140/seed/carwash_rpt.prog.abap @@ -0,0 +1,79 @@ +REPORT {{p}}carwash_rpt. + +TABLES: {{p}}carwash, {{p}}washpgm. + +PARAMETERS: p_from TYPE d OBLIGATORY, + p_to TYPE d OBLIGATORY. + +SELECT-OPTIONS: s_prog FOR {{p}}carwash-wash_prog. + +TYPES: BEGIN OF ty_out, + wash_prog TYPE {{p}}carwash-wash_prog, + prog_text TYPE {{p}}washpgm-prog_text, + washes TYPE i, + revenue TYPE {{p}}carwash-price, + vip_washes TYPE i, + vip_revenue TYPE {{p}}carwash-price, + END OF ty_out. + +TYPES: BEGIN OF ty_data, + wash_prog TYPE {{p}}carwash-wash_prog, + price TYPE {{p}}carwash-price, + cust_type TYPE {{p}}carwash-cust_type, + END OF ty_data. + +DATA: gt_out TYPE STANDARD TABLE OF ty_out WITH HEADER LINE, + gt_data TYPE STANDARD TABLE OF ty_data WITH HEADER LINE. + +DATA: gv_text TYPE {{p}}washpgm-prog_text, + gv_alv TYPE REF TO cl_salv_table. + +START-OF-SELECTION. + SELECT * FROM {{p}}carwash INTO CORRESPONDING FIELDS OF TABLE gt_data + WHERE wash_date >= p_from AND wash_date <= p_to. + + LOOP AT gt_data. + IF gt_data-wash_prog IN s_prog. + READ TABLE gt_out WITH KEY wash_prog = gt_data-wash_prog. + IF sy-subrc = 0. + gt_out-washes = gt_out-washes + 1. + gt_out-revenue = gt_out-revenue + gt_data-price. + IF gt_data-cust_type = 'VIP'. + gt_out-vip_washes = gt_out-vip_washes + 1. + gt_out-vip_revenue = gt_out-vip_revenue + gt_data-price. + ENDIF. + MODIFY gt_out INDEX sy-tabix. + ELSE. + CLEAR gt_out. + gt_out-wash_prog = gt_data-wash_prog. + gt_out-washes = 1. + gt_out-revenue = gt_data-price. + IF gt_data-cust_type = 'VIP'. + gt_out-vip_washes = 1. + gt_out-vip_revenue = gt_data-price. + ELSE. + gt_out-vip_washes = 0. + gt_out-vip_revenue = 0. + ENDIF. + APPEND gt_out. + ENDIF. + ENDIF. + ENDLOOP. + + LOOP AT gt_out. + CLEAR gv_text. + SELECT SINGLE prog_text FROM {{p}}washpgm INTO gv_text + WHERE wash_prog = gt_out-wash_prog. + gt_out-prog_text = gv_text. + MODIFY gt_out. + ENDLOOP. + + SORT gt_out BY revenue DESCENDING. + + TRY. + cl_salv_table=>factory( + IMPORTING r_salv_table = gv_alv + CHANGING t_table = gt_out[] ). + gv_alv->display( ). + CATCH cx_salv_msg. + ENDTRY. diff --git a/tasks_gen/eval/G0140/seed/carwash_seed.clas.abap b/tasks_gen/eval/G0140/seed/carwash_seed.clas.abap new file mode 100644 index 0000000..405306f --- /dev/null +++ b/tasks_gen/eval/G0140/seed/carwash_seed.clas.abap @@ -0,0 +1,25 @@ +CLASS {{p}}carwash_seed DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES if_oo_adt_classrun. +ENDCLASS. + +CLASS {{p}}carwash_seed IMPLEMENTATION. + METHOD if_oo_adt_classrun~main. + DELETE FROM {{p}}carwash. + DELETE FROM {{p}}washpgm. + INSERT {{p}}washpgm FROM TABLE @( VALUE #( + ( wash_prog = 'BAS' prog_text = 'Basic wash' ) + ( wash_prog = 'DLX' prog_text = 'Deluxe wash' ) + ( wash_prog = 'PRM' prog_text = 'Premium wash' ) ) ). + INSERT {{p}}carwash FROM TABLE @( VALUE #( + ( wash_id = 1 wash_prog = 'BAS' wash_date = '20260105' price = '10.00' cust_type = 'STD' ) + ( wash_id = 2 wash_prog = 'BAS' wash_date = '20260106' price = '10.00' cust_type = 'VIP' ) + ( wash_id = 3 wash_prog = 'DLX' wash_date = '20260107' price = '20.00' cust_type = 'STD' ) + ( wash_id = 4 wash_prog = 'DLX' wash_date = '20260108' price = '20.00' cust_type = 'VIP' ) + ( wash_id = 5 wash_prog = 'DLX' wash_date = '20260109' price = '20.00' cust_type = 'STD' ) + ( wash_id = 6 wash_prog = 'PRM' wash_date = '20260110' price = '50.00' cust_type = 'VIP' ) + ( wash_id = 7 wash_prog = 'PRM' wash_date = '20260215' price = '50.00' cust_type = 'STD' ) + ( wash_id = 8 wash_prog = 'BAS' wash_date = '20260220' price = '10.00' cust_type = 'STD' ) ) ). + out->write( sy-dbcnt ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0140/seed/washpgm.tabl.asabap b/tasks_gen/eval/G0140/seed/washpgm.tabl.asabap new file mode 100644 index 0000000..f0d8f62 --- /dev/null +++ b/tasks_gen/eval/G0140/seed/washpgm.tabl.asabap @@ -0,0 +1,10 @@ +@EndUserText.label : 'Wash programs' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}washpgm { + key client : abap.clnt not null; + key wash_prog : abap.char(4) not null; + prog_text : abap.char(30); +} diff --git a/tasks_gen/eval/G0140/spec.md b/tasks_gen/eval/G0140/spec.md new file mode 100644 index 0000000..848da7f --- /dev/null +++ b/tasks_gen/eval/G0140/spec.md @@ -0,0 +1,52 @@ +# 1. Goal +The car wash chain uses the program {{P}}CARWASH_RPT to show the washes and +the revenue of each wash program for a period. The program is a legacy report. +The users complain about the code quality. Refactor the program in place. The +behavior stays the same. + +# 2. Open questions +None. + +# 3. Context +- {{P}}CARWASH_RPT is an executable program in package $TMP. It is in + production and it runs. +- The program reads the tables {{P}}CARWASH (the wash visits) and {{P}}WASHPGM + (the text of each wash program). +- The legacy source code of the program contains the business rules. Read the + legacy code. +- The behavior must not change: the same selection screen, the same ALV + columns, and the same numbers. + +# 4. Contract +- Refactor the program {{P}}CARWASH_RPT in package $TMP. The name stays the + same. The public interface stays the same. +- Selection screen: + - P_FROM, type DATS, mandatory: the first wash date to include. + - P_TO, type DATS, mandatory: the last wash date to include. + - S_PROG, select-option for the wash program. +- The program shows the result with CL_SALV_TABLE. The ALV columns keep these + names: WASH_PROG, PROG_TEXT, WASHES, REVENUE, VIP_WASHES, VIP_REVENUE. +- The hidden tests call the program with SUBMIT and read the ALV data. They use + only the names above. + +# 5. Business rules +The business rules are in the legacy code of {{P}}CARWASH_RPT. Read the legacy +code. The refactored program applies the same rules and shows the same numbers. +Do not change the rules. + +# 6. Constraints +- Release target: 7.58. +- Coding standards: Clean ABAP. +- The program is modular. The logic is in small methods with clear names. +- No method has more than 40 statements. +- No database access inside a loop. +- No duplicated logic. +- The program has no ATC priority 1 or priority 2 finding. +- Out of scope: do not change {{P}}CARWASH, {{P}}WASHPGM, and + {{P}}CARWASH_SEED. + +# 7. Acceptance +- The program {{P}}CARWASH_RPT is active and has no syntax error. +- The behavior is unchanged. +- The hidden tests pass. +- Write ABAP Unit tests as local test classes in the program. diff --git a/tasks_gen/eval/G0140/task.json b/tasks_gen/eval/G0140/task.json new file mode 100644 index 0000000..f7165e0 --- /dev/null +++ b/tasks_gen/eval/G0140/task.json @@ -0,0 +1,75 @@ +{ + "id": "G0140", + "category": "E", + "object_type": "PROG", + "difficulty": 2, + "release_target": "v758", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [ + { + "type": "TABL", + "name": "{{P}}CARWASH", + "file": "seed/carwash.tabl.asabap", + "description": "Car wash visits" + }, + { + "type": "TABL", + "name": "{{P}}WASHPGM", + "file": "seed/washpgm.tabl.asabap", + "description": "Wash programs" + }, + { + "type": "PROG", + "name": "{{P}}CARWASH_RPT", + "file": "seed/carwash_rpt.prog.abap", + "description": "Legacy car wash report" + }, + { + "type": "CLAS", + "name": "{{P}}CARWASH_SEED", + "file": "seed/carwash_seed.clas.abap", + "description": "Car wash seed data", + "run": true + } + ], + "contract": [ + { + "type": "PROG", + "name": "{{P}}CARWASH_RPT", + "parameters": [ + "p_from", + "p_to", + "s_prog" + ] + } + ], + "out_of_scope": [ + "{{P}}CARWASH", + "{{P}}WASHPGM", + "{{P}}CARWASH_SEED" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}CARWASH_HIDDEN", + "file": "hidden/carwash_hidden.clas.abap", + "description": "Hidden tests for the car wash report" + } + ], + "reference": [ + { + "type": "PROG", + "name": "{{P}}CARWASH_RPT", + "file": "reference/carwash_rpt.prog.abap", + "description": "Refactored car wash report" + } + ], + "craft_checks": [ + "db_operation_in_loop", + "method_length" + ] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0141/hidden/news_dist_hidden.clas.abap b/tasks_gen/eval/G0141/hidden/news_dist_hidden.clas.abap new file mode 100644 index 0000000..b5ca69c --- /dev/null +++ b/tasks_gen/eval/G0141/hidden/news_dist_hidden.clas.abap @@ -0,0 +1,108 @@ +CLASS {{p}}news_dist_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + TYPES ty_date TYPE d. + TYPES tt_date TYPE RANGE OF ty_date. + TYPES ty_dist TYPE c LENGTH 4. + TYPES tt_dist TYPE RANGE OF ty_dist. + METHODS run + IMPORTING it_date TYPE tt_date OPTIONAL + it_dist TYPE tt_dist 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 all_agents FOR TESTING. + METHODS sorted_by_rate FOR TESTING. + METHODS sums_and_rate FOR TESTING. + METHODS district_filter FOR TESTING. + METHODS date_filter FOR TESTING. + METHODS zero_copies FOR TESTING. + METHODS no_deliveries FOR TESTING. + METHODS outside_period FOR TESTING. +ENDCLASS. + +CLASS {{p}}news_dist_hidden IMPLEMENTATION. + METHOD run. + cl_salv_bs_runtime_info=>set( display = abap_false metadata = abap_false data = abap_true ). + SUBMIT {{p}}news_dist_old WITH s_date IN it_date WITH s_dist IN it_dist 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 all_agents. + cl_abap_unit_assert=>assert_equals( exp = 6 act = lines_of( run( ) ) ). + ENDMETHOD. + + METHOD sorted_by_rate. + DATA(lr_data) = run( ). + cl_abap_unit_assert=>assert_equals( exp = `A5` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `AGENT` ) ). + cl_abap_unit_assert=>assert_equals( exp = `A6` act = value_of( ir_data = lr_data iv_row = 6 iv_col = `AGENT` ) ). + ENDMETHOD. + + METHOD sums_and_rate. + DATA(lr_data) = run( it_date = VALUE #( ( sign = 'I' option = 'BT' low = '20260101' high = '20260131' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 6 act = lines_of( lr_data ) ). + cl_abap_unit_assert=>assert_equals( exp = `A1` act = value_of( ir_data = lr_data iv_row = 4 iv_col = `AGENT` ) ). + cl_abap_unit_assert=>assert_equals( exp = `200` act = value_of( ir_data = lr_data iv_row = 4 iv_col = `COPIES` ) ). + cl_abap_unit_assert=>assert_equals( exp = `15` act = value_of( ir_data = lr_data iv_row = 4 iv_col = `RETURNED` ) ). + cl_abap_unit_assert=>assert_equals( exp = `7.50` act = value_of( ir_data = lr_data iv_row = 4 iv_col = `RATE` ) ). + ENDMETHOD. + + METHOD district_filter. + DATA(lr_data) = run( it_dist = VALUE #( ( sign = 'I' option = 'EQ' low = 'W' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines_of( lr_data ) ). + cl_abap_unit_assert=>assert_equals( exp = `A5` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `AGENT` ) ). + ENDMETHOD. + + METHOD date_filter. + DATA(lr_data) = run( it_date = VALUE #( ( sign = 'I' option = 'GE' low = '20260110' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines_of( lr_data ) ). + cl_abap_unit_assert=>assert_equals( exp = `A1` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `AGENT` ) ). + cl_abap_unit_assert=>assert_equals( exp = `A3` act = value_of( ir_data = lr_data iv_row = 2 iv_col = `AGENT` ) ). + ENDMETHOD. + + METHOD zero_copies. + DATA(lr_data) = run( it_dist = VALUE #( ( sign = 'I' option = 'EQ' low = 'W' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = `A6` act = value_of( ir_data = lr_data iv_row = 2 iv_col = `AGENT` ) ). + cl_abap_unit_assert=>assert_equals( exp = `0` act = value_of( ir_data = lr_data iv_row = 2 iv_col = `COPIES` ) ). + cl_abap_unit_assert=>assert_equals( exp = `0.00` act = value_of( ir_data = lr_data iv_row = 2 iv_col = `RATE` ) ). + ENDMETHOD. + + METHOD no_deliveries. + cl_abap_unit_assert=>assert_equals( + exp = 0 + act = lines_of( run( it_dist = VALUE #( ( sign = 'I' option = 'EQ' low = 'E' ) ) ) ) ). + ENDMETHOD. + + METHOD outside_period. + cl_abap_unit_assert=>assert_equals( + exp = 0 + act = lines_of( run( it_date = VALUE #( ( sign = 'I' option = 'BT' low = '20270101' high = '20271231' ) ) ) ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0141/mutation.json b/tasks_gen/eval/G0141/mutation.json new file mode 100644 index 0000000..1dc020e --- /dev/null +++ b/tasks_gen/eval/G0141/mutation.json @@ -0,0 +1,34 @@ +{ + "task": "E21", + "mutants": [ + { + "object": "{{P}}NEWS_DIST_OLD", + "mutant": "SORT: DESCENDING -> ASCENDING", + "status": "killed", + "hidden": "4/8", + "failed_tests": [ + "sorted_by_rate", + "sums_and_rate", + "district_filter", + "zero_copies" + ] + }, + { + "object": "{{P}}NEWS_DIST_OLD", + "mutant": "rate guard: > -> >=", + "status": "killed", + "hidden": "5/8", + "failed_tests": [ + "all_agents", + "sorted_by_rate", + "sums_and_rate", + "district_filter", + "zero_copies" + ] + } + ], + "valid": 2, + "killed": 2, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0141/reference/news_dist_old.prog.abap b/tasks_gen/eval/G0141/reference/news_dist_old.prog.abap new file mode 100644 index 0000000..2970dac --- /dev/null +++ b/tasks_gen/eval/G0141/reference/news_dist_old.prog.abap @@ -0,0 +1,131 @@ +REPORT {{p}}news_dist_old. + +TYPES ty_rate TYPE p LENGTH 8 DECIMALS 2. + +TYPES: BEGIN OF ty_line, + agent TYPE {{p}}agent-agent_id, + name TYPE {{p}}agent-agent_name, + district TYPE {{p}}agent-district, + copies TYPE i, + returned TYPE i, + rate TYPE ty_rate, + END OF ty_line. +TYPES tt_line TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY. +TYPES ty_date TYPE d. +TYPES tt_date TYPE RANGE OF ty_date. +TYPES ty_dist TYPE c LENGTH 4. +TYPES tt_dist TYPE RANGE OF ty_dist. + +DATA gv_date TYPE ty_date. +DATA gv_dist TYPE ty_dist. + +SELECT-OPTIONS s_date FOR gv_date. +SELECT-OPTIONS s_dist FOR gv_dist. + +CLASS lcl_report DEFINITION FINAL. + PUBLIC SECTION. + METHODS select_lines + IMPORTING it_date TYPE tt_date + it_dist TYPE tt_dist + RETURNING VALUE(rt_lines) TYPE tt_line. + METHODS display + CHANGING ct_lines TYPE tt_line. + PRIVATE SECTION. + METHODS add_rate + CHANGING cs_line TYPE ty_line. +ENDCLASS. + +CLASS lcl_report IMPLEMENTATION. + METHOD select_lines. + SELECT a~agent_id AS agent, + a~agent_name AS name, + a~district AS district, + SUM( d~del_copies ) AS copies, + SUM( d~ret_copies ) AS returned + FROM {{p}}agent AS a + INNER JOIN {{p}}deliv AS d ON d~agent_id = a~agent_id + WHERE d~del_date IN @it_date + AND a~district IN @it_dist + GROUP BY a~agent_id, a~agent_name, a~district + INTO CORRESPONDING FIELDS OF TABLE @rt_lines. + + LOOP AT rt_lines ASSIGNING FIELD-SYMBOL(). + add_rate( CHANGING cs_line = ). + ENDLOOP. + + SORT rt_lines BY rate DESCENDING agent ASCENDING. + ENDMETHOD. + + METHOD add_rate. + DATA lv_copies TYPE p LENGTH 15 DECIMALS 2. + lv_copies = cs_line-copies. + IF lv_copies > 0. + cs_line-rate = cs_line-returned * 100 / lv_copies. + ELSE. + cs_line-rate = 0. + ENDIF. + 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_lines( it_date = s_date[] + it_dist = s_dist[] ). + 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 sums_per_agent FOR TESTING. + METHODS rate_with_zero_copies FOR TESTING. +ENDCLASS. + +CLASS ltc_report IMPLEMENTATION. + METHOD class_setup. + go_env = cl_osql_test_environment=>create( + i_dependency_list = VALUE #( ( '{{P}}AGENT' ) ( '{{P}}DELIV' ) ) ). + DATA lt_agent TYPE STANDARD TABLE OF {{p}}agent WITH EMPTY KEY. + lt_agent = VALUE #( ( agent_id = 'A1' agent_name = 'One' district = 'N' ) + ( agent_id = 'A2' agent_name = 'Two' district = 'S' ) ). + go_env->insert_test_data( lt_agent ). + DATA lt_deliv TYPE STANDARD TABLE OF {{p}}deliv WITH EMPTY KEY. + lt_deliv = VALUE #( ( deliv_id = 1 agent_id = 'A1' del_date = '20260105' del_copies = 100 ret_copies = 5 ) + ( deliv_id = 2 agent_id = 'A1' del_date = '20260112' del_copies = 100 ret_copies = 15 ) + ( deliv_id = 3 agent_id = 'A2' del_date = '20260106' del_copies = 0 ret_copies = 0 ) ). + go_env->insert_test_data( lt_deliv ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD sums_per_agent. + DATA(lt_lines) = NEW lcl_report( )->select_lines( it_date = VALUE tt_date( ) + it_dist = VALUE tt_dist( ) ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 'A1' act = lt_lines[ 1 ]-agent ). + cl_abap_unit_assert=>assert_equals( exp = 200 act = lt_lines[ 1 ]-copies ). + cl_abap_unit_assert=>assert_equals( exp = 20 act = lt_lines[ 1 ]-returned ). + cl_abap_unit_assert=>assert_equals( exp = '10.00' act = |{ lt_lines[ 1 ]-rate }| ). + ENDMETHOD. + + METHOD rate_with_zero_copies. + DATA(lt_lines) = NEW lcl_report( )->select_lines( it_date = VALUE tt_date( ) + it_dist = VALUE tt_dist( ) ). + cl_abap_unit_assert=>assert_equals( exp = 'A2' act = lt_lines[ 2 ]-agent ). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lt_lines[ 2 ]-copies ). + cl_abap_unit_assert=>assert_equals( exp = '0.00' act = |{ lt_lines[ 2 ]-rate }| ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0141/seed/agent.tabl.asabap b/tasks_gen/eval/G0141/seed/agent.tabl.asabap new file mode 100644 index 0000000..2f0540a --- /dev/null +++ b/tasks_gen/eval/G0141/seed/agent.tabl.asabap @@ -0,0 +1,11 @@ +@EndUserText.label : 'Newsagent' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}agent { + key client : abap.clnt not null; + key agent_id : abap.char(6) not null; + agent_name : abap.char(40); + district : abap.char(4); +} diff --git a/tasks_gen/eval/G0141/seed/deliv.tabl.asabap b/tasks_gen/eval/G0141/seed/deliv.tabl.asabap new file mode 100644 index 0000000..da0fce9 --- /dev/null +++ b/tasks_gen/eval/G0141/seed/deliv.tabl.asabap @@ -0,0 +1,13 @@ +@EndUserText.label : 'News delivery' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}deliv { + key client : abap.clnt not null; + key deliv_id : abap.int4 not null; + agent_id : abap.char(6); + del_date : abap.dats; + del_copies : abap.int4; + ret_copies : abap.int4; +} diff --git a/tasks_gen/eval/G0141/seed/news_dist_old.prog.abap b/tasks_gen/eval/G0141/seed/news_dist_old.prog.abap new file mode 100644 index 0000000..c1a83cf --- /dev/null +++ b/tasks_gen/eval/G0141/seed/news_dist_old.prog.abap @@ -0,0 +1,72 @@ +REPORT {{p}}news_dist_old. + +* Legacy distribution report of the newspaper publisher. +* Shows the delivered copies and the returns of each newsagent. + +TYPES ty_rate TYPE p LENGTH 8 DECIMALS 2. + +TYPES: BEGIN OF ty_out, + agent TYPE {{p}}agent-agent_id, + name TYPE {{p}}agent-agent_name, + district TYPE {{p}}agent-district, + copies TYPE i, + returned TYPE i, + rate TYPE ty_rate, + END OF ty_out. + +DATA: gt_agent TYPE STANDARD TABLE OF {{p}}agent, + gs_agent TYPE {{p}}agent, + gt_deliv TYPE STANDARD TABLE OF {{p}}deliv, + gs_deliv TYPE {{p}}deliv, + gs_out TYPE ty_out, + gt_out TYPE STANDARD TABLE OF ty_out, + gt_list TYPE STANDARD TABLE OF ty_out, + gv_date TYPE d, + gv_dist TYPE c LENGTH 4, + go_alv TYPE REF TO cl_salv_table. + +SELECT-OPTIONS s_date FOR gv_date. +SELECT-OPTIONS s_dist FOR gv_dist. + +START-OF-SELECTION. + SELECT * FROM {{p}}agent INTO TABLE gt_agent. + LOOP AT gt_agent INTO gs_agent. + SELECT * FROM {{p}}deliv INTO TABLE gt_deliv + WHERE agent_id = gs_agent-agent_id + AND del_date IN s_date. + IF gt_deliv IS NOT INITIAL. + CLEAR gs_out. + gs_out-agent = gs_agent-agent_id. + gs_out-name = gs_agent-agent_name. + gs_out-district = gs_agent-district. + LOOP AT gt_deliv INTO gs_deliv. + gs_out-copies = gs_out-copies + gs_deliv-del_copies. + gs_out-returned = gs_out-returned + gs_deliv-ret_copies. + ENDLOOP. + PERFORM calc_rate USING gs_out-returned gs_out-copies + CHANGING gs_out-rate. + APPEND gs_out TO gt_out. + ENDIF. + ENDLOOP. + LOOP AT gt_out INTO gs_out WHERE district IN s_dist. + APPEND gs_out TO gt_list. + ENDLOOP. + SORT gt_list BY rate DESCENDING agent ASCENDING. + TRY. + cl_salv_table=>factory( IMPORTING r_salv_table = go_alv + CHANGING t_table = gt_list ). + go_alv->display( ). + CATCH cx_salv_msg. + ENDTRY. + +FORM calc_rate USING iv_returned TYPE i + iv_copies TYPE i + CHANGING cv_rate TYPE ty_rate. + DATA lv_copies TYPE p LENGTH 15 DECIMALS 2. + lv_copies = iv_copies. + IF lv_copies > 0. + cv_rate = iv_returned * 100 / lv_copies. + ELSE. + CLEAR cv_rate. + ENDIF. +ENDFORM. diff --git a/tasks_gen/eval/G0141/seed/news_seed.clas.abap b/tasks_gen/eval/G0141/seed/news_seed.clas.abap new file mode 100644 index 0000000..5ddad18 --- /dev/null +++ b/tasks_gen/eval/G0141/seed/news_seed.clas.abap @@ -0,0 +1,33 @@ +CLASS {{p}}news_seed DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES if_oo_adt_classrun. +ENDCLASS. + +CLASS {{p}}news_seed IMPLEMENTATION. + METHOD if_oo_adt_classrun~main. + DELETE FROM {{p}}deliv. + DELETE FROM {{p}}agent. + + INSERT {{p}}agent FROM TABLE @( VALUE #( + ( agent_id = 'A1' agent_name = 'Corner Shop' district = 'N' ) + ( agent_id = 'A2' agent_name = 'Station Kiosk' district = 'N' ) + ( agent_id = 'A3' agent_name = 'City News' district = 'S' ) + ( agent_id = 'A4' agent_name = 'Harbour Store' district = 'S' ) + ( agent_id = 'A5' agent_name = 'Airport Shop' district = 'W' ) + ( agent_id = 'A6' agent_name = 'Closed Kiosk' district = 'W' ) + ( agent_id = 'A7' agent_name = 'Village Store' district = 'E' ) ) ). + + INSERT {{p}}deliv FROM TABLE @( VALUE #( + ( deliv_id = 1 agent_id = 'A1' del_date = '20260105' del_copies = 100 ret_copies = 5 ) + ( deliv_id = 2 agent_id = 'A1' del_date = '20260112' del_copies = 100 ret_copies = 10 ) + ( deliv_id = 3 agent_id = 'A2' del_date = '20251220' del_copies = 40 ret_copies = 4 ) + ( deliv_id = 4 agent_id = 'A2' del_date = '20260106' del_copies = 50 ret_copies = 0 ) + ( deliv_id = 5 agent_id = 'A3' del_date = '20260107' del_copies = 200 ret_copies = 40 ) + ( deliv_id = 6 agent_id = 'A3' del_date = '20260114' del_copies = 200 ret_copies = 20 ) + ( deliv_id = 7 agent_id = 'A4' del_date = '20260108' del_copies = 80 ret_copies = 8 ) + ( deliv_id = 8 agent_id = 'A5' del_date = '20260109' del_copies = 60 ret_copies = 30 ) + ( deliv_id = 9 agent_id = 'A6' del_date = '20260103' del_copies = 0 ret_copies = 0 ) ) ). + + out->write( 'Seed done' ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0141/spec.md b/tasks_gen/eval/G0141/spec.md new file mode 100644 index 0000000..0c45c39 --- /dev/null +++ b/tasks_gen/eval/G0141/spec.md @@ -0,0 +1,52 @@ +# 1. Goal +The program {{P}}NEWS_DIST_OLD in package $TMP is the legacy distribution +report of a regional newspaper publisher. It shows, for a period, the copies +that each newsagent received and returned. The report works, but its source +does not meet the current quality standards of the company. Refactor the +source of {{P}}NEWS_DIST_OLD in place. The behavior of the program stays the +same. + +# 2. Open questions +None. + +# 3. Context +- The executable program {{P}}NEWS_DIST_OLD exists in package $TMP and is + active. Its source is the legacy code that you refactor. +- The tables {{P}}AGENT and {{P}}DELIV exist in package $TMP and contain data. +- Users run the program with the selection screen and read the ALV list. + +# 4. Contract +- Object: the executable program {{P}}NEWS_DIST_OLD in package $TMP. + Refactor this program in place. Keep the name. Do not create a new program. +- Selection screen, unchanged: + - Select-option S_DATE for the delivery date. + - Select-option S_DIST for the district. +- The program shows the result with CL_SALV_TABLE, as before. +- The ALV list keeps these column names: + AGENT, NAME, DISTRICT, COPIES, RETURNED, RATE. + +# 5. Business rules +The behavior of the program does not change. The legacy source of +{{P}}NEWS_DIST_OLD is the specification of the behavior. Read the source and +keep all of it: +- the filters of the selection screen, +- the set of lines of the list, +- the values of the columns, +- the sort order of the lines. +Do not change the result of the program. + +# 6. Constraints +- Release target: 8.16. +- Coding standards: Clean ABAP. +- The refactored program has no database access inside a loop. +- No method of the program has more than 40 statements. +- The program has no ATC finding of priority 1 or 2. +- Write ABAP Unit tests as local test classes in the program. +- Out of scope: do not change the tables {{P}}AGENT and {{P}}DELIV. + Do not change the selection screen names and the ALV column names. + +# 7. Acceptance +- {{P}}NEWS_DIST_OLD is active and has no syntax error. +- The result of the program is the same as before the refactoring. +- The hidden tests pass. +- The local test classes pass. diff --git a/tasks_gen/eval/G0141/task.json b/tasks_gen/eval/G0141/task.json new file mode 100644 index 0000000..906abdc --- /dev/null +++ b/tasks_gen/eval/G0141/task.json @@ -0,0 +1,73 @@ +{ + "id": "G0141", + "category": "E", + "object_type": "PROG", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [ + { + "type": "TABL", + "name": "{{P}}AGENT", + "file": "seed/agent.tabl.asabap", + "description": "Newsagents" + }, + { + "type": "TABL", + "name": "{{P}}DELIV", + "file": "seed/deliv.tabl.asabap", + "description": "News deliveries" + }, + { + "type": "CLAS", + "name": "{{P}}NEWS_SEED", + "file": "seed/news_seed.clas.abap", + "description": "Seed data", + "run": true + }, + { + "type": "PROG", + "name": "{{P}}NEWS_DIST_OLD", + "file": "seed/news_dist_old.prog.abap", + "description": "Legacy distribution report" + } + ], + "contract": [ + { + "type": "PROG", + "name": "{{P}}NEWS_DIST_OLD", + "parameters": [ + "s_date", + "s_dist" + ] + } + ], + "out_of_scope": [ + "{{P}}AGENT", + "{{P}}DELIV" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}NEWS_DIST_HIDDEN", + "file": "hidden/news_dist_hidden.clas.abap", + "description": "Hidden tests for the distribution report" + } + ], + "reference": [ + { + "type": "PROG", + "name": "{{P}}NEWS_DIST_OLD", + "file": "reference/news_dist_old.prog.abap", + "description": "Refactored distribution report" + } + ], + "craft_checks": [ + "db_operation_in_loop", + "method_length" + ] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0142/faulty/m0_train_punct_old.prog.abap b/tasks_gen/eval/G0142/faulty/m0_train_punct_old.prog.abap new file mode 100644 index 0000000..e9f60b7 --- /dev/null +++ b/tasks_gen/eval/G0142/faulty/m0_train_punct_old.prog.abap @@ -0,0 +1,134 @@ +REPORT {{p}}train_punct_old. + +TYPES: BEGIN OF ty_run, + run_id TYPE {{p}}trun-run_id, + line_code TYPE {{p}}trun-line_code, + plan_date TYPE {{p}}trun-plan_date, + delay_min TYPE {{p}}trun-delay_min, + cancelled TYPE {{p}}trun-cancelled, + END OF ty_run. +TYPES tt_run TYPE STANDARD TABLE OF ty_run WITH EMPTY KEY. + +TYPES: BEGIN OF ty_line, + line_code TYPE {{p}}trun-line_code, + runs TYPE i, + late TYPE i, + sum_delay TYPE i, + punct TYPE i, + END OF ty_line. +TYPES tt_line TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY. + +TYPES tt_line_range TYPE RANGE OF {{p}}trun-line_code. +TYPES tt_date_range TYPE RANGE OF {{p}}trun-plan_date. + +DATA gv_line TYPE {{p}}trun-line_code. +DATA gv_date TYPE {{p}}trun-plan_date. + +SELECT-OPTIONS s_line FOR gv_line. +SELECT-OPTIONS s_date FOR gv_date. + +CLASS lcl_punct DEFINITION FINAL. + PUBLIC SECTION. + CONSTANTS c_late_limit TYPE i VALUE 5. + CLASS-METHODS read_runs + IMPORTING it_line TYPE tt_line_range + it_date TYPE tt_date_range + RETURNING VALUE(rt_runs) TYPE tt_run. + CLASS-METHODS aggregate + IMPORTING it_runs TYPE tt_run + RETURNING VALUE(rt_lines) TYPE tt_line. + CLASS-METHODS display + CHANGING ct_lines TYPE tt_line. + PRIVATE SECTION. + CLASS-METHODS add_run + IMPORTING is_run TYPE ty_run + CHANGING ct_lines TYPE tt_line. +ENDCLASS. + +CLASS lcl_punct IMPLEMENTATION. + METHOD read_runs. + DATA lt_runs TYPE tt_run. + SELECT run_id, line_code, plan_date, delay_min, cancelled + FROM {{p}}trun + WHERE plan_date IN @it_date + OR line_code IN @it_line + INTO TABLE @lt_runs. + rt_runs = lt_runs. + ENDMETHOD. + + METHOD aggregate. + LOOP AT it_runs INTO DATA(ls_run). + IF ls_run-cancelled = 'X'. + CONTINUE. + ENDIF. + add_run( EXPORTING is_run = ls_run CHANGING ct_lines = rt_lines ). + ENDLOOP. + LOOP AT rt_lines ASSIGNING FIELD-SYMBOL(). + -punct = ( -runs - -late ) * 100 / -runs. + ENDLOOP. + SORT rt_lines BY punct line_code. + ENDMETHOD. + + METHOD add_run. + READ TABLE ct_lines ASSIGNING FIELD-SYMBOL() WITH KEY line_code = is_run-line_code. + IF sy-subrc <> 0. + APPEND INITIAL LINE TO ct_lines ASSIGNING . + -line_code = is_run-line_code. + ENDIF. + -runs = -runs + 1. + -sum_delay = -sum_delay + is_run-delay_min. + IF is_run-delay_min > c_late_limit. + -late = -late + 1. + ENDIF. + 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(lt_runs) = lcl_punct=>read_runs( it_line = s_line[] it_date = s_date[] ). + DATA(lt_lines) = lcl_punct=>aggregate( lt_runs ). + lcl_punct=>display( CHANGING ct_lines = lt_lines ). + +CLASS ltc_punct DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS aggregates_runs FOR TESTING. + METHODS skips_cancelled FOR TESTING. + METHODS sorts_worst_first FOR TESTING. +ENDCLASS. + +CLASS ltc_punct IMPLEMENTATION. + METHOD aggregates_runs. + DATA(lt_lines) = lcl_punct=>aggregate( VALUE #( + ( run_id = 1 line_code = 'L1' delay_min = 0 cancelled = '' ) + ( run_id = 2 line_code = 'L1' delay_min = 10 cancelled = '' ) + ( run_id = 3 line_code = 'L2' delay_min = 3 cancelled = '' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 'L1' act = lt_lines[ 1 ]-line_code ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lt_lines[ 1 ]-runs ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lt_lines[ 1 ]-late ). + cl_abap_unit_assert=>assert_equals( exp = 10 act = lt_lines[ 1 ]-sum_delay ). + cl_abap_unit_assert=>assert_equals( exp = 50 act = lt_lines[ 1 ]-punct ). + ENDMETHOD. + + METHOD skips_cancelled. + DATA(lt_lines) = lcl_punct=>aggregate( VALUE #( + ( run_id = 1 line_code = 'L1' delay_min = 0 cancelled = 'X' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lines( lt_lines ) ). + ENDMETHOD. + + METHOD sorts_worst_first. + DATA(lt_lines) = lcl_punct=>aggregate( VALUE #( + ( run_id = 1 line_code = 'L1' delay_min = 0 cancelled = '' ) + ( run_id = 2 line_code = 'L2' delay_min = 30 cancelled = '' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 'L2' act = lt_lines[ 1 ]-line_code ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0142/faulty/m1_train_punct_old.prog.abap b/tasks_gen/eval/G0142/faulty/m1_train_punct_old.prog.abap new file mode 100644 index 0000000..c2dc261 --- /dev/null +++ b/tasks_gen/eval/G0142/faulty/m1_train_punct_old.prog.abap @@ -0,0 +1,134 @@ +REPORT {{p}}train_punct_old. + +TYPES: BEGIN OF ty_run, + run_id TYPE {{p}}trun-run_id, + line_code TYPE {{p}}trun-line_code, + plan_date TYPE {{p}}trun-plan_date, + delay_min TYPE {{p}}trun-delay_min, + cancelled TYPE {{p}}trun-cancelled, + END OF ty_run. +TYPES tt_run TYPE STANDARD TABLE OF ty_run WITH EMPTY KEY. + +TYPES: BEGIN OF ty_line, + line_code TYPE {{p}}trun-line_code, + runs TYPE i, + late TYPE i, + sum_delay TYPE i, + punct TYPE i, + END OF ty_line. +TYPES tt_line TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY. + +TYPES tt_line_range TYPE RANGE OF {{p}}trun-line_code. +TYPES tt_date_range TYPE RANGE OF {{p}}trun-plan_date. + +DATA gv_line TYPE {{p}}trun-line_code. +DATA gv_date TYPE {{p}}trun-plan_date. + +SELECT-OPTIONS s_line FOR gv_line. +SELECT-OPTIONS s_date FOR gv_date. + +CLASS lcl_punct DEFINITION FINAL. + PUBLIC SECTION. + CONSTANTS c_late_limit TYPE i VALUE 5. + CLASS-METHODS read_runs + IMPORTING it_line TYPE tt_line_range + it_date TYPE tt_date_range + RETURNING VALUE(rt_runs) TYPE tt_run. + CLASS-METHODS aggregate + IMPORTING it_runs TYPE tt_run + RETURNING VALUE(rt_lines) TYPE tt_line. + CLASS-METHODS display + CHANGING ct_lines TYPE tt_line. + PRIVATE SECTION. + CLASS-METHODS add_run + IMPORTING is_run TYPE ty_run + CHANGING ct_lines TYPE tt_line. +ENDCLASS. + +CLASS lcl_punct IMPLEMENTATION. + METHOD read_runs. + DATA lt_runs TYPE tt_run. + SELECT run_id, line_code, plan_date, delay_min, cancelled + FROM {{p}}trun + WHERE plan_date IN @it_date + AND line_code IN @it_line + INTO TABLE @lt_runs. + rt_runs = lt_runs. + ENDMETHOD. + + METHOD aggregate. + LOOP AT it_runs INTO DATA(ls_run). + IF ls_run-cancelled <> 'X'. + CONTINUE. + ENDIF. + add_run( EXPORTING is_run = ls_run CHANGING ct_lines = rt_lines ). + ENDLOOP. + LOOP AT rt_lines ASSIGNING FIELD-SYMBOL(). + -punct = ( -runs - -late ) * 100 / -runs. + ENDLOOP. + SORT rt_lines BY punct line_code. + ENDMETHOD. + + METHOD add_run. + READ TABLE ct_lines ASSIGNING FIELD-SYMBOL() WITH KEY line_code = is_run-line_code. + IF sy-subrc <> 0. + APPEND INITIAL LINE TO ct_lines ASSIGNING . + -line_code = is_run-line_code. + ENDIF. + -runs = -runs + 1. + -sum_delay = -sum_delay + is_run-delay_min. + IF is_run-delay_min > c_late_limit. + -late = -late + 1. + ENDIF. + 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(lt_runs) = lcl_punct=>read_runs( it_line = s_line[] it_date = s_date[] ). + DATA(lt_lines) = lcl_punct=>aggregate( lt_runs ). + lcl_punct=>display( CHANGING ct_lines = lt_lines ). + +CLASS ltc_punct DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS aggregates_runs FOR TESTING. + METHODS skips_cancelled FOR TESTING. + METHODS sorts_worst_first FOR TESTING. +ENDCLASS. + +CLASS ltc_punct IMPLEMENTATION. + METHOD aggregates_runs. + DATA(lt_lines) = lcl_punct=>aggregate( VALUE #( + ( run_id = 1 line_code = 'L1' delay_min = 0 cancelled = '' ) + ( run_id = 2 line_code = 'L1' delay_min = 10 cancelled = '' ) + ( run_id = 3 line_code = 'L2' delay_min = 3 cancelled = '' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 'L1' act = lt_lines[ 1 ]-line_code ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lt_lines[ 1 ]-runs ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lt_lines[ 1 ]-late ). + cl_abap_unit_assert=>assert_equals( exp = 10 act = lt_lines[ 1 ]-sum_delay ). + cl_abap_unit_assert=>assert_equals( exp = 50 act = lt_lines[ 1 ]-punct ). + ENDMETHOD. + + METHOD skips_cancelled. + DATA(lt_lines) = lcl_punct=>aggregate( VALUE #( + ( run_id = 1 line_code = 'L1' delay_min = 0 cancelled = 'X' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lines( lt_lines ) ). + ENDMETHOD. + + METHOD sorts_worst_first. + DATA(lt_lines) = lcl_punct=>aggregate( VALUE #( + ( run_id = 1 line_code = 'L1' delay_min = 0 cancelled = '' ) + ( run_id = 2 line_code = 'L2' delay_min = 30 cancelled = '' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 'L2' act = lt_lines[ 1 ]-line_code ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0142/faulty/m2_train_punct_old.prog.abap b/tasks_gen/eval/G0142/faulty/m2_train_punct_old.prog.abap new file mode 100644 index 0000000..cf464c3 --- /dev/null +++ b/tasks_gen/eval/G0142/faulty/m2_train_punct_old.prog.abap @@ -0,0 +1,134 @@ +REPORT {{p}}train_punct_old. + +TYPES: BEGIN OF ty_run, + run_id TYPE {{p}}trun-run_id, + line_code TYPE {{p}}trun-line_code, + plan_date TYPE {{p}}trun-plan_date, + delay_min TYPE {{p}}trun-delay_min, + cancelled TYPE {{p}}trun-cancelled, + END OF ty_run. +TYPES tt_run TYPE STANDARD TABLE OF ty_run WITH EMPTY KEY. + +TYPES: BEGIN OF ty_line, + line_code TYPE {{p}}trun-line_code, + runs TYPE i, + late TYPE i, + sum_delay TYPE i, + punct TYPE i, + END OF ty_line. +TYPES tt_line TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY. + +TYPES tt_line_range TYPE RANGE OF {{p}}trun-line_code. +TYPES tt_date_range TYPE RANGE OF {{p}}trun-plan_date. + +DATA gv_line TYPE {{p}}trun-line_code. +DATA gv_date TYPE {{p}}trun-plan_date. + +SELECT-OPTIONS s_line FOR gv_line. +SELECT-OPTIONS s_date FOR gv_date. + +CLASS lcl_punct DEFINITION FINAL. + PUBLIC SECTION. + CONSTANTS c_late_limit TYPE i VALUE 5. + CLASS-METHODS read_runs + IMPORTING it_line TYPE tt_line_range + it_date TYPE tt_date_range + RETURNING VALUE(rt_runs) TYPE tt_run. + CLASS-METHODS aggregate + IMPORTING it_runs TYPE tt_run + RETURNING VALUE(rt_lines) TYPE tt_line. + CLASS-METHODS display + CHANGING ct_lines TYPE tt_line. + PRIVATE SECTION. + CLASS-METHODS add_run + IMPORTING is_run TYPE ty_run + CHANGING ct_lines TYPE tt_line. +ENDCLASS. + +CLASS lcl_punct IMPLEMENTATION. + METHOD read_runs. + DATA lt_runs TYPE tt_run. + SELECT run_id, line_code, plan_date, delay_min, cancelled + FROM {{p}}trun + WHERE plan_date IN @it_date + AND line_code IN @it_line + INTO TABLE @lt_runs. + rt_runs = lt_runs. + ENDMETHOD. + + METHOD aggregate. + LOOP AT it_runs INTO DATA(ls_run). + IF ls_run-cancelled = 'X'. + CONTINUE. + ENDIF. + add_run( EXPORTING is_run = ls_run CHANGING ct_lines = rt_lines ). + ENDLOOP. + LOOP AT rt_lines ASSIGNING FIELD-SYMBOL(). + -punct = ( -runs - -late ) * 101 / -runs. + ENDLOOP. + SORT rt_lines BY punct line_code. + ENDMETHOD. + + METHOD add_run. + READ TABLE ct_lines ASSIGNING FIELD-SYMBOL() WITH KEY line_code = is_run-line_code. + IF sy-subrc <> 0. + APPEND INITIAL LINE TO ct_lines ASSIGNING . + -line_code = is_run-line_code. + ENDIF. + -runs = -runs + 1. + -sum_delay = -sum_delay + is_run-delay_min. + IF is_run-delay_min > c_late_limit. + -late = -late + 1. + ENDIF. + 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(lt_runs) = lcl_punct=>read_runs( it_line = s_line[] it_date = s_date[] ). + DATA(lt_lines) = lcl_punct=>aggregate( lt_runs ). + lcl_punct=>display( CHANGING ct_lines = lt_lines ). + +CLASS ltc_punct DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS aggregates_runs FOR TESTING. + METHODS skips_cancelled FOR TESTING. + METHODS sorts_worst_first FOR TESTING. +ENDCLASS. + +CLASS ltc_punct IMPLEMENTATION. + METHOD aggregates_runs. + DATA(lt_lines) = lcl_punct=>aggregate( VALUE #( + ( run_id = 1 line_code = 'L1' delay_min = 0 cancelled = '' ) + ( run_id = 2 line_code = 'L1' delay_min = 10 cancelled = '' ) + ( run_id = 3 line_code = 'L2' delay_min = 3 cancelled = '' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 'L1' act = lt_lines[ 1 ]-line_code ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lt_lines[ 1 ]-runs ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lt_lines[ 1 ]-late ). + cl_abap_unit_assert=>assert_equals( exp = 10 act = lt_lines[ 1 ]-sum_delay ). + cl_abap_unit_assert=>assert_equals( exp = 50 act = lt_lines[ 1 ]-punct ). + ENDMETHOD. + + METHOD skips_cancelled. + DATA(lt_lines) = lcl_punct=>aggregate( VALUE #( + ( run_id = 1 line_code = 'L1' delay_min = 0 cancelled = 'X' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lines( lt_lines ) ). + ENDMETHOD. + + METHOD sorts_worst_first. + DATA(lt_lines) = lcl_punct=>aggregate( VALUE #( + ( run_id = 1 line_code = 'L1' delay_min = 0 cancelled = '' ) + ( run_id = 2 line_code = 'L2' delay_min = 30 cancelled = '' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 'L2' act = lt_lines[ 1 ]-line_code ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0142/faulty/m3_train_punct_old.prog.abap b/tasks_gen/eval/G0142/faulty/m3_train_punct_old.prog.abap new file mode 100644 index 0000000..1b46acb --- /dev/null +++ b/tasks_gen/eval/G0142/faulty/m3_train_punct_old.prog.abap @@ -0,0 +1,134 @@ +REPORT {{p}}train_punct_old. + +TYPES: BEGIN OF ty_run, + run_id TYPE {{p}}trun-run_id, + line_code TYPE {{p}}trun-line_code, + plan_date TYPE {{p}}trun-plan_date, + delay_min TYPE {{p}}trun-delay_min, + cancelled TYPE {{p}}trun-cancelled, + END OF ty_run. +TYPES tt_run TYPE STANDARD TABLE OF ty_run WITH EMPTY KEY. + +TYPES: BEGIN OF ty_line, + line_code TYPE {{p}}trun-line_code, + runs TYPE i, + late TYPE i, + sum_delay TYPE i, + punct TYPE i, + END OF ty_line. +TYPES tt_line TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY. + +TYPES tt_line_range TYPE RANGE OF {{p}}trun-line_code. +TYPES tt_date_range TYPE RANGE OF {{p}}trun-plan_date. + +DATA gv_line TYPE {{p}}trun-line_code. +DATA gv_date TYPE {{p}}trun-plan_date. + +SELECT-OPTIONS s_line FOR gv_line. +SELECT-OPTIONS s_date FOR gv_date. + +CLASS lcl_punct DEFINITION FINAL. + PUBLIC SECTION. + CONSTANTS c_late_limit TYPE i VALUE 5. + CLASS-METHODS read_runs + IMPORTING it_line TYPE tt_line_range + it_date TYPE tt_date_range + RETURNING VALUE(rt_runs) TYPE tt_run. + CLASS-METHODS aggregate + IMPORTING it_runs TYPE tt_run + RETURNING VALUE(rt_lines) TYPE tt_line. + CLASS-METHODS display + CHANGING ct_lines TYPE tt_line. + PRIVATE SECTION. + CLASS-METHODS add_run + IMPORTING is_run TYPE ty_run + CHANGING ct_lines TYPE tt_line. +ENDCLASS. + +CLASS lcl_punct IMPLEMENTATION. + METHOD read_runs. + DATA lt_runs TYPE tt_run. + SELECT run_id, line_code, plan_date, delay_min, cancelled + FROM {{p}}trun + WHERE plan_date IN @it_date + AND line_code IN @it_line + INTO TABLE @lt_runs. + rt_runs = lt_runs. + ENDMETHOD. + + METHOD aggregate. + LOOP AT it_runs INTO DATA(ls_run). + IF ls_run-cancelled = 'X'. + CONTINUE. + ENDIF. + add_run( EXPORTING is_run = ls_run CHANGING ct_lines = rt_lines ). + ENDLOOP. + LOOP AT rt_lines ASSIGNING FIELD-SYMBOL(). + -punct = ( -runs - -late ) * 100 / -runs. + ENDLOOP. + SORT rt_lines BY punct line_code. + ENDMETHOD. + + METHOD add_run. + READ TABLE ct_lines ASSIGNING FIELD-SYMBOL() WITH KEY line_code = is_run-line_code. + IF sy-subrc <> 0. + APPEND INITIAL LINE TO ct_lines ASSIGNING . + -line_code = is_run-line_code. + ENDIF. + -runs = -runs + 1. + -sum_delay = -sum_delay - is_run-delay_min. + IF is_run-delay_min > c_late_limit. + -late = -late + 1. + ENDIF. + 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(lt_runs) = lcl_punct=>read_runs( it_line = s_line[] it_date = s_date[] ). + DATA(lt_lines) = lcl_punct=>aggregate( lt_runs ). + lcl_punct=>display( CHANGING ct_lines = lt_lines ). + +CLASS ltc_punct DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS aggregates_runs FOR TESTING. + METHODS skips_cancelled FOR TESTING. + METHODS sorts_worst_first FOR TESTING. +ENDCLASS. + +CLASS ltc_punct IMPLEMENTATION. + METHOD aggregates_runs. + DATA(lt_lines) = lcl_punct=>aggregate( VALUE #( + ( run_id = 1 line_code = 'L1' delay_min = 0 cancelled = '' ) + ( run_id = 2 line_code = 'L1' delay_min = 10 cancelled = '' ) + ( run_id = 3 line_code = 'L2' delay_min = 3 cancelled = '' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 'L1' act = lt_lines[ 1 ]-line_code ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lt_lines[ 1 ]-runs ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lt_lines[ 1 ]-late ). + cl_abap_unit_assert=>assert_equals( exp = 10 act = lt_lines[ 1 ]-sum_delay ). + cl_abap_unit_assert=>assert_equals( exp = 50 act = lt_lines[ 1 ]-punct ). + ENDMETHOD. + + METHOD skips_cancelled. + DATA(lt_lines) = lcl_punct=>aggregate( VALUE #( + ( run_id = 1 line_code = 'L1' delay_min = 0 cancelled = 'X' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lines( lt_lines ) ). + ENDMETHOD. + + METHOD sorts_worst_first. + DATA(lt_lines) = lcl_punct=>aggregate( VALUE #( + ( run_id = 1 line_code = 'L1' delay_min = 0 cancelled = '' ) + ( run_id = 2 line_code = 'L2' delay_min = 30 cancelled = '' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 'L2' act = lt_lines[ 1 ]-line_code ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0142/faulty/m4_train_punct_old.prog.abap b/tasks_gen/eval/G0142/faulty/m4_train_punct_old.prog.abap new file mode 100644 index 0000000..b9a9057 --- /dev/null +++ b/tasks_gen/eval/G0142/faulty/m4_train_punct_old.prog.abap @@ -0,0 +1,134 @@ +REPORT {{p}}train_punct_old. + +TYPES: BEGIN OF ty_run, + run_id TYPE {{p}}trun-run_id, + line_code TYPE {{p}}trun-line_code, + plan_date TYPE {{p}}trun-plan_date, + delay_min TYPE {{p}}trun-delay_min, + cancelled TYPE {{p}}trun-cancelled, + END OF ty_run. +TYPES tt_run TYPE STANDARD TABLE OF ty_run WITH EMPTY KEY. + +TYPES: BEGIN OF ty_line, + line_code TYPE {{p}}trun-line_code, + runs TYPE i, + late TYPE i, + sum_delay TYPE i, + punct TYPE i, + END OF ty_line. +TYPES tt_line TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY. + +TYPES tt_line_range TYPE RANGE OF {{p}}trun-line_code. +TYPES tt_date_range TYPE RANGE OF {{p}}trun-plan_date. + +DATA gv_line TYPE {{p}}trun-line_code. +DATA gv_date TYPE {{p}}trun-plan_date. + +SELECT-OPTIONS s_line FOR gv_line. +SELECT-OPTIONS s_date FOR gv_date. + +CLASS lcl_punct DEFINITION FINAL. + PUBLIC SECTION. + CONSTANTS c_late_limit TYPE i VALUE 5. + CLASS-METHODS read_runs + IMPORTING it_line TYPE tt_line_range + it_date TYPE tt_date_range + RETURNING VALUE(rt_runs) TYPE tt_run. + CLASS-METHODS aggregate + IMPORTING it_runs TYPE tt_run + RETURNING VALUE(rt_lines) TYPE tt_line. + CLASS-METHODS display + CHANGING ct_lines TYPE tt_line. + PRIVATE SECTION. + CLASS-METHODS add_run + IMPORTING is_run TYPE ty_run + CHANGING ct_lines TYPE tt_line. +ENDCLASS. + +CLASS lcl_punct IMPLEMENTATION. + METHOD read_runs. + DATA lt_runs TYPE tt_run. + SELECT run_id, line_code, plan_date, delay_min, cancelled + FROM {{p}}trun + WHERE plan_date IN @it_date + AND line_code IN @it_line + INTO TABLE @lt_runs. + rt_runs = lt_runs. + ENDMETHOD. + + METHOD aggregate. + LOOP AT it_runs INTO DATA(ls_run). + IF ls_run-cancelled = 'X'. + CONTINUE. + ENDIF. + add_run( EXPORTING is_run = ls_run CHANGING ct_lines = rt_lines ). + ENDLOOP. + LOOP AT rt_lines ASSIGNING FIELD-SYMBOL(). + -punct = ( -runs - -late ) * 100 / -runs. + ENDLOOP. + SORT rt_lines BY punct line_code. + ENDMETHOD. + + METHOD add_run. + READ TABLE ct_lines ASSIGNING FIELD-SYMBOL() WITH KEY line_code = is_run-line_code. + IF sy-subrc <> 0. + APPEND INITIAL LINE TO ct_lines ASSIGNING . + -line_code = is_run-line_code. + ENDIF. + -runs = -runs + 1. + -sum_delay = -sum_delay + is_run-delay_min. + IF is_run-delay_min <= c_late_limit. + -late = -late + 1. + ENDIF. + 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(lt_runs) = lcl_punct=>read_runs( it_line = s_line[] it_date = s_date[] ). + DATA(lt_lines) = lcl_punct=>aggregate( lt_runs ). + lcl_punct=>display( CHANGING ct_lines = lt_lines ). + +CLASS ltc_punct DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS aggregates_runs FOR TESTING. + METHODS skips_cancelled FOR TESTING. + METHODS sorts_worst_first FOR TESTING. +ENDCLASS. + +CLASS ltc_punct IMPLEMENTATION. + METHOD aggregates_runs. + DATA(lt_lines) = lcl_punct=>aggregate( VALUE #( + ( run_id = 1 line_code = 'L1' delay_min = 0 cancelled = '' ) + ( run_id = 2 line_code = 'L1' delay_min = 10 cancelled = '' ) + ( run_id = 3 line_code = 'L2' delay_min = 3 cancelled = '' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 'L1' act = lt_lines[ 1 ]-line_code ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lt_lines[ 1 ]-runs ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lt_lines[ 1 ]-late ). + cl_abap_unit_assert=>assert_equals( exp = 10 act = lt_lines[ 1 ]-sum_delay ). + cl_abap_unit_assert=>assert_equals( exp = 50 act = lt_lines[ 1 ]-punct ). + ENDMETHOD. + + METHOD skips_cancelled. + DATA(lt_lines) = lcl_punct=>aggregate( VALUE #( + ( run_id = 1 line_code = 'L1' delay_min = 0 cancelled = 'X' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lines( lt_lines ) ). + ENDMETHOD. + + METHOD sorts_worst_first. + DATA(lt_lines) = lcl_punct=>aggregate( VALUE #( + ( run_id = 1 line_code = 'L1' delay_min = 0 cancelled = '' ) + ( run_id = 2 line_code = 'L2' delay_min = 30 cancelled = '' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 'L2' act = lt_lines[ 1 ]-line_code ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0142/generation.json b/tasks_gen/eval/G0142/generation.json new file mode 100644 index 0000000..f1b4715 --- /dev/null +++ b/tasks_gen/eval/G0142/generation.json @@ -0,0 +1,24 @@ +{ + "id": "G0142", + "pool": "eval", + "object_type": "PROG", + "category": "E", + "attempts": [ + { + "stage": "validate", + "oracle": 93.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/eval/G0142/hidden/train_punct_hidden.clas.abap b/tasks_gen/eval/G0142/hidden/train_punct_hidden.clas.abap new file mode 100644 index 0000000..0960c03 --- /dev/null +++ b/tasks_gen/eval/G0142/hidden/train_punct_hidden.clas.abap @@ -0,0 +1,104 @@ +CLASS {{p}}train_punct_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + TYPES tt_line TYPE RANGE OF {{p}}trun-line_code. + TYPES tt_date TYPE RANGE OF {{p}}trun-plan_date. + METHODS run + IMPORTING it_line TYPE tt_line OPTIONAL + it_date TYPE tt_date 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_lines FOR TESTING. + METHODS cancelled_runs_are_skipped FOR TESTING. + METHODS worst_line_first FOR TESTING. + METHODS punct_values FOR TESTING. + METHODS date_filter FOR TESTING. + METHODS line_filter FOR TESTING. +ENDCLASS. + + +CLASS {{p}}train_punct_hidden IMPLEMENTATION. + METHOD run. + cl_salv_bs_runtime_info=>set( display = abap_false metadata = abap_false data = abap_true ). + SUBMIT {{p}}train_punct_old + WITH s_line IN it_line + WITH s_date IN it_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 } is missing| ). + rv_value = condense( CONV string( ) ). + ENDMETHOD. + + METHOD all_lines. + cl_abap_unit_assert=>assert_equals( exp = 3 act = lines_of( run( ) ) ). + ENDMETHOD. + + METHOD cancelled_runs_are_skipped. + DATA(lr_data) = run( ). + cl_abap_unit_assert=>assert_equals( exp = 3 act = lines_of( lr_data ) ). + cl_abap_unit_assert=>assert_equals( exp = `IC1001` + act = value_of( ir_data = lr_data iv_row = 3 iv_col = `LINE_CODE` ) ). + ENDMETHOD. + + METHOD worst_line_first. + DATA(lr_data) = run( ). + cl_abap_unit_assert=>assert_equals( exp = `RE2001` + act = value_of( ir_data = lr_data iv_row = 1 iv_col = `LINE_CODE` ) ). + ENDMETHOD. + + METHOD punct_values. + DATA(lr_data) = run( ). + cl_abap_unit_assert=>assert_equals( exp = `0` + act = value_of( ir_data = lr_data iv_row = 1 iv_col = `PUNCT` ) ). + cl_abap_unit_assert=>assert_equals( exp = `50` + act = value_of( ir_data = lr_data iv_row = 2 iv_col = `PUNCT` ) ). + cl_abap_unit_assert=>assert_equals( exp = `67` + act = value_of( ir_data = lr_data iv_row = 3 iv_col = `PUNCT` ) ). + ENDMETHOD. + + METHOD date_filter. + DATA(lr_data) = run( it_date = VALUE #( ( sign = 'I' option = 'EQ' low = '20260106' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 3 act = lines_of( lr_data ) ). + cl_abap_unit_assert=>assert_equals( exp = `RE2001` + act = value_of( ir_data = lr_data iv_row = 1 iv_col = `LINE_CODE` ) ). + ENDMETHOD. + + METHOD line_filter. + DATA(lr_data) = run( it_line = VALUE #( ( sign = 'I' option = 'EQ' low = 'IC1002' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lines_of( lr_data ) ). + cl_abap_unit_assert=>assert_equals( exp = `2` + act = value_of( ir_data = lr_data iv_row = 1 iv_col = `RUNS` ) ). + cl_abap_unit_assert=>assert_equals( exp = `1` + act = value_of( ir_data = lr_data iv_row = 1 iv_col = `LATE` ) ). + cl_abap_unit_assert=>assert_equals( exp = `22` + act = value_of( ir_data = lr_data iv_row = 1 iv_col = `SUM_DELAY` ) ). + cl_abap_unit_assert=>assert_equals( exp = `50` + act = value_of( ir_data = lr_data iv_row = 1 iv_col = `PUNCT` ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0142/mutation.json b/tasks_gen/eval/G0142/mutation.json new file mode 100644 index 0000000..18d4dd5 --- /dev/null +++ b/tasks_gen/eval/G0142/mutation.json @@ -0,0 +1,62 @@ +{ + "task": "G0142", + "mutants": [ + { + "object": "{{P}}TRAIN_PUNCT_OLD", + "mutant": "line 54: AND -> OR (logic)", + "status": "killed", + "hidden": "5/6", + "failed_tests": [ + "LINE_FILTER" + ] + }, + { + "object": "{{P}}TRAIN_PUNCT_OLD", + "mutant": "line 61: = -> <> (eq)", + "status": "killed", + "hidden": "1/6", + "failed_tests": [ + "CANCELLED_RUNS_ARE_SKIPPED", + "DATE_FILTER", + "LINE_FILTER", + "PUNCT_VALUES", + "WORST_LINE_FIRST" + ] + }, + { + "object": "{{P}}TRAIN_PUNCT_OLD", + "mutant": "line 67: 100 -> 101 (const)", + "status": "killed", + "hidden": "4/6", + "failed_tests": [ + "LINE_FILTER", + "PUNCT_VALUES" + ] + }, + { + "object": "{{P}}TRAIN_PUNCT_OLD", + "mutant": "line 79: + -> - (arith)", + "status": "killed", + "hidden": "5/6", + "failed_tests": [ + "LINE_FILTER" + ] + }, + { + "object": "{{P}}TRAIN_PUNCT_OLD", + "mutant": "line 80: > -> <= (rel)", + "status": "killed", + "hidden": "2/6", + "failed_tests": [ + "CANCELLED_RUNS_ARE_SKIPPED", + "DATE_FILTER", + "PUNCT_VALUES", + "WORST_LINE_FIRST" + ] + } + ], + "valid": 5, + "killed": 5, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0142/reference/train_punct_old.prog.abap b/tasks_gen/eval/G0142/reference/train_punct_old.prog.abap new file mode 100644 index 0000000..6d975ed --- /dev/null +++ b/tasks_gen/eval/G0142/reference/train_punct_old.prog.abap @@ -0,0 +1,134 @@ +REPORT {{p}}train_punct_old. + +TYPES: BEGIN OF ty_run, + run_id TYPE {{p}}trun-run_id, + line_code TYPE {{p}}trun-line_code, + plan_date TYPE {{p}}trun-plan_date, + delay_min TYPE {{p}}trun-delay_min, + cancelled TYPE {{p}}trun-cancelled, + END OF ty_run. +TYPES tt_run TYPE STANDARD TABLE OF ty_run WITH EMPTY KEY. + +TYPES: BEGIN OF ty_line, + line_code TYPE {{p}}trun-line_code, + runs TYPE i, + late TYPE i, + sum_delay TYPE i, + punct TYPE i, + END OF ty_line. +TYPES tt_line TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY. + +TYPES tt_line_range TYPE RANGE OF {{p}}trun-line_code. +TYPES tt_date_range TYPE RANGE OF {{p}}trun-plan_date. + +DATA gv_line TYPE {{p}}trun-line_code. +DATA gv_date TYPE {{p}}trun-plan_date. + +SELECT-OPTIONS s_line FOR gv_line. +SELECT-OPTIONS s_date FOR gv_date. + +CLASS lcl_punct DEFINITION FINAL. + PUBLIC SECTION. + CONSTANTS c_late_limit TYPE i VALUE 5. + CLASS-METHODS read_runs + IMPORTING it_line TYPE tt_line_range + it_date TYPE tt_date_range + RETURNING VALUE(rt_runs) TYPE tt_run. + CLASS-METHODS aggregate + IMPORTING it_runs TYPE tt_run + RETURNING VALUE(rt_lines) TYPE tt_line. + CLASS-METHODS display + CHANGING ct_lines TYPE tt_line. + PRIVATE SECTION. + CLASS-METHODS add_run + IMPORTING is_run TYPE ty_run + CHANGING ct_lines TYPE tt_line. +ENDCLASS. + +CLASS lcl_punct IMPLEMENTATION. + METHOD read_runs. + DATA lt_runs TYPE tt_run. + SELECT run_id, line_code, plan_date, delay_min, cancelled + FROM {{p}}trun + WHERE plan_date IN @it_date + AND line_code IN @it_line + INTO TABLE @lt_runs. + rt_runs = lt_runs. + ENDMETHOD. + + METHOD aggregate. + LOOP AT it_runs INTO DATA(ls_run). + IF ls_run-cancelled = 'X'. + CONTINUE. + ENDIF. + add_run( EXPORTING is_run = ls_run CHANGING ct_lines = rt_lines ). + ENDLOOP. + LOOP AT rt_lines ASSIGNING FIELD-SYMBOL(). + -punct = ( -runs - -late ) * 100 / -runs. + ENDLOOP. + SORT rt_lines BY punct line_code. + ENDMETHOD. + + METHOD add_run. + READ TABLE ct_lines ASSIGNING FIELD-SYMBOL() WITH KEY line_code = is_run-line_code. + IF sy-subrc <> 0. + APPEND INITIAL LINE TO ct_lines ASSIGNING . + -line_code = is_run-line_code. + ENDIF. + -runs = -runs + 1. + -sum_delay = -sum_delay + is_run-delay_min. + IF is_run-delay_min > c_late_limit. + -late = -late + 1. + ENDIF. + 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(lt_runs) = lcl_punct=>read_runs( it_line = s_line[] it_date = s_date[] ). + DATA(lt_lines) = lcl_punct=>aggregate( lt_runs ). + lcl_punct=>display( CHANGING ct_lines = lt_lines ). + +CLASS ltc_punct DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS aggregates_runs FOR TESTING. + METHODS skips_cancelled FOR TESTING. + METHODS sorts_worst_first FOR TESTING. +ENDCLASS. + +CLASS ltc_punct IMPLEMENTATION. + METHOD aggregates_runs. + DATA(lt_lines) = lcl_punct=>aggregate( VALUE #( + ( run_id = 1 line_code = 'L1' delay_min = 0 cancelled = '' ) + ( run_id = 2 line_code = 'L1' delay_min = 10 cancelled = '' ) + ( run_id = 3 line_code = 'L2' delay_min = 3 cancelled = '' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 'L1' act = lt_lines[ 1 ]-line_code ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lt_lines[ 1 ]-runs ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lt_lines[ 1 ]-late ). + cl_abap_unit_assert=>assert_equals( exp = 10 act = lt_lines[ 1 ]-sum_delay ). + cl_abap_unit_assert=>assert_equals( exp = 50 act = lt_lines[ 1 ]-punct ). + ENDMETHOD. + + METHOD skips_cancelled. + DATA(lt_lines) = lcl_punct=>aggregate( VALUE #( + ( run_id = 1 line_code = 'L1' delay_min = 0 cancelled = 'X' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lines( lt_lines ) ). + ENDMETHOD. + + METHOD sorts_worst_first. + DATA(lt_lines) = lcl_punct=>aggregate( VALUE #( + ( run_id = 1 line_code = 'L1' delay_min = 0 cancelled = '' ) + ( run_id = 2 line_code = 'L2' delay_min = 30 cancelled = '' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 'L2' act = lt_lines[ 1 ]-line_code ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0142/seed/train_punct_old.prog.abap b/tasks_gen/eval/G0142/seed/train_punct_old.prog.abap new file mode 100644 index 0000000..8cdc1d4 --- /dev/null +++ b/tasks_gen/eval/G0142/seed/train_punct_old.prog.abap @@ -0,0 +1,56 @@ +REPORT {{p}}train_punct_old. + +DATA gv_line TYPE {{p}}trun-line_code. +DATA gv_date TYPE {{p}}trun-plan_date. + +SELECT-OPTIONS s_line FOR gv_line. +SELECT-OPTIONS s_date FOR gv_date. + +TYPES: BEGIN OF ty_out, + line_code TYPE {{p}}trun-line_code, + runs TYPE i, + late TYPE i, + sum_delay TYPE i, + punct TYPE i, + END OF ty_out. + +DATA gt_out TYPE STANDARD TABLE OF ty_out. + +FIELD-SYMBOLS TYPE {{p}}trun. +FIELD-SYMBOLS TYPE ty_out. + +START-OF-SELECTION. + DATA lt_runs TYPE STANDARD TABLE OF {{p}}trun. + SELECT * FROM {{p}}trun + INTO TABLE @lt_runs + WHERE plan_date IN @s_date + AND line_code IN @s_line. + + LOOP AT lt_runs ASSIGNING . + IF -cancelled = 'X'. + CONTINUE. + ENDIF. + READ TABLE gt_out ASSIGNING WITH KEY line_code = -line_code. + IF sy-subrc <> 0. + APPEND INITIAL LINE TO gt_out ASSIGNING . + -line_code = -line_code. + ENDIF. + -runs = -runs + 1. + -sum_delay = -sum_delay + -delay_min. + IF -delay_min > 5. + -late = -late + 1. + ENDIF. + ENDLOOP. + + LOOP AT gt_out ASSIGNING . + -punct = ( -runs - -late ) * 100 / -runs. + ENDLOOP. + + SORT gt_out BY punct line_code. + + TRY. + cl_salv_table=>factory( IMPORTING r_salv_table = DATA(lo_alv) + CHANGING t_table = gt_out ). + lo_alv->display( ). + CATCH cx_salv_msg. + ENDTRY. diff --git a/tasks_gen/eval/G0142/seed/train_seed.clas.abap b/tasks_gen/eval/G0142/seed/train_seed.clas.abap new file mode 100644 index 0000000..634f677 --- /dev/null +++ b/tasks_gen/eval/G0142/seed/train_seed.clas.abap @@ -0,0 +1,21 @@ +CLASS {{p}}train_seed DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES if_oo_adt_classrun. +ENDCLASS. + +CLASS {{p}}train_seed IMPLEMENTATION. + METHOD if_oo_adt_classrun~main. + DELETE FROM {{p}}trun. + INSERT {{p}}trun FROM TABLE @( VALUE #( + ( run_id = 1 line_code = 'IC1001' plan_date = '20260105' delay_min = 0 cancelled = '' ) + ( run_id = 2 line_code = 'IC1001' plan_date = '20260105' delay_min = 12 cancelled = '' ) + ( run_id = 3 line_code = 'IC1001' plan_date = '20260106' delay_min = 3 cancelled = '' ) + ( run_id = 4 line_code = 'IC1002' plan_date = '20260105' delay_min = 20 cancelled = '' ) + ( run_id = 5 line_code = 'IC1002' plan_date = '20260106' delay_min = 2 cancelled = '' ) + ( run_id = 6 line_code = 'IC1002' plan_date = '20260106' delay_min = 5 cancelled = 'X' ) + ( run_id = 7 line_code = 'RE2001' plan_date = '20260106' delay_min = 7 cancelled = '' ) + ( run_id = 8 line_code = 'RE2001' plan_date = '20260106' delay_min = 1 cancelled = 'X' ) + ( run_id = 9 line_code = 'IC1003' plan_date = '20260107' delay_min = 4 cancelled = 'X' ) ) ). + out->write( sy-dbcnt ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0142/seed/trun.tabl.asabap b/tasks_gen/eval/G0142/seed/trun.tabl.asabap new file mode 100644 index 0000000..c8badd7 --- /dev/null +++ b/tasks_gen/eval/G0142/seed/trun.tabl.asabap @@ -0,0 +1,13 @@ +@EndUserText.label : 'Train runs' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}trun { + key client : abap.clnt not null; + key run_id : abap.int4 not null; + line_code : abap.char(6); + plan_date : abap.dats; + delay_min : abap.int4; + cancelled : abap.char(1); +} diff --git a/tasks_gen/eval/G0142/spec.md b/tasks_gen/eval/G0142/spec.md new file mode 100644 index 0000000..ceb139e --- /dev/null +++ b/tasks_gen/eval/G0142/spec.md @@ -0,0 +1,44 @@ +# 1. Goal +Refactor the legacy report {{P}}TRAIN_PUNCT_OLD in package $TMP. The report shows +the punctuality of the railway lines of a regional operator. The operations team +uses the report to find the lines that need attention. +The behaviour of the report stays the same. Only the internal structure changes. + +# 2. Open questions +None. + +# 3. Context +- Table {{P}}TRUN exists in package $TMP and contains data. + Fields: RUN_ID (INT4, key), LINE_CODE (CHAR 6), PLAN_DATE (DATS), + DELAY_MIN (INT4), CANCELLED (CHAR 1). + One row is one train run of one line on one day. DELAY_MIN is the delay of the + run in minutes. CANCELLED is 'X' if the run was cancelled. +- The report {{P}}TRAIN_PUNCT_OLD in package $TMP is the legacy report. It is + active and it produces the correct result. Users report that the code is hard + to maintain. +- The report reads the table and shows one line per railway line in an ALV list. + +# 4. Contract +- The program {{P}}TRAIN_PUNCT_OLD keeps its name and its package $TMP. +- The selection screen keeps these parameters: + - S_LINE: a select-option for the line code. + - S_DATE: a select-option for the plan date. +- The report shows the result with CL_SALV_TABLE. The output table keeps these + column names: LINE_CODE, RUNS, LATE, SUM_DELAY, PUNCT. + +# 5. Business rules +The behaviour of the report must not change. The legacy code of +{{P}}TRAIN_PUNCT_OLD contains the business rules. Read the legacy code and keep +every rule. Do not add rules. Do not remove rules. + +# 6. Constraints +- Release target: SAP_BASIS 816 (ABAP Platform 2025). +- Coding standards: Clean ABAP. Split the logic into small methods. A method has + fewer than 40 statements. Do not change the public interface. +- Out of scope: do not change {{P}}TRUN and do not change {{P}}TRAIN_SEED. + +# 7. Acceptance +- The program is active and has no syntax error. +- The behaviour of the program is unchanged. The hidden tests pass. +- The code has no ATC finding of priority 1 or 2. +- Write ABAP Unit tests as local test classes in the program. diff --git a/tasks_gen/eval/G0142/task.json b/tasks_gen/eval/G0142/task.json new file mode 100644 index 0000000..a0a3c5a --- /dev/null +++ b/tasks_gen/eval/G0142/task.json @@ -0,0 +1,67 @@ +{ + "id": "G0142", + "category": "E", + "object_type": "PROG", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [ + { + "type": "TABL", + "name": "{{P}}TRUN", + "file": "seed/trun.tabl.asabap", + "description": "Train runs" + }, + { + "type": "PROG", + "name": "{{P}}TRAIN_PUNCT_OLD", + "file": "seed/train_punct_old.prog.abap", + "description": "Legacy punctuality report" + }, + { + "type": "CLAS", + "name": "{{P}}TRAIN_SEED", + "file": "seed/train_seed.clas.abap", + "description": "Train run seed data", + "run": true + } + ], + "contract": [ + { + "type": "PROG", + "name": "{{P}}TRAIN_PUNCT_OLD", + "parameters": [ + "s_line", + "s_date" + ] + } + ], + "out_of_scope": [ + "{{P}}TRUN", + "{{P}}TRAIN_SEED" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}TRAIN_PUNCT_HIDDEN", + "file": "hidden/train_punct_hidden.clas.abap", + "description": "Punctuality behaviour tests" + } + ], + "reference": [ + { + "type": "PROG", + "name": "{{P}}TRAIN_PUNCT_OLD", + "file": "reference/train_punct_old.prog.abap", + "description": "Refactored punctuality report" + } + ], + "craft_checks": [ + "method_length", + "db_operation_in_loop" + ] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0143/hidden/t14_hidden.clas.abap b/tasks_gen/eval/G0143/hidden/t14_hidden.clas.abap new file mode 100644 index 0000000..01399b4 --- /dev/null +++ b/tasks_gen/eval/G0143/hidden/t14_hidden.clas.abap @@ -0,0 +1,106 @@ +CLASS {{p}}t14_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS call + IMPORTING + iv_players TYPE i + iv_games TYPE i + iv_day TYPE i + iv_shoes TYPE abap_bool DEFAULT abap_false + EXPORTING + ev_fee TYPE decfloat34 + ev_note TYPE string + ev_subrc TYPE sysubrc. + METHODS weekday_rate FOR TESTING. + METHODS weekend_rate FOR TESTING. + METHODS lane_count FOR TESTING. + METHODS shoe_charge FOR TESTING. + METHODS group_discount FOR TESTING. + METHODS group_discount_negative FOR TESTING. + METHODS day_above_five FOR TESTING. + METHODS invalid_players FOR TESTING. + METHODS invalid_games FOR TESTING. + METHODS no_discount_below_twelve FOR TESTING. +ENDCLASS. + +CLASS {{p}}t14_hidden IMPLEMENTATION. + METHOD call. + CALL FUNCTION '{{P}}BOWL_FEE_OLD' + EXPORTING + iv_players = iv_players + iv_games = iv_games + iv_day = iv_day + iv_shoes = iv_shoes + IMPORTING + ev_fee = ev_fee + ev_note = ev_note + EXCEPTIONS + invalid_input = 1 + OTHERS = 2. + ev_subrc = sy-subrc. + ENDMETHOD. + + METHOD weekday_rate. + call( EXPORTING iv_players = 1 iv_games = 1 iv_day = 1 + IMPORTING ev_fee = DATA(lv_fee) ev_note = DATA(lv_note) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '3.50' ) act = lv_fee ). + cl_abap_unit_assert=>assert_equals( exp = 'BOOKED' act = lv_note ). + ENDMETHOD. + + METHOD weekend_rate. + call( EXPORTING iv_players = 6 iv_games = 2 iv_day = 6 + IMPORTING ev_fee = DATA(lv_fee) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '10.00' ) act = lv_fee ). + ENDMETHOD. + + METHOD lane_count. + call( EXPORTING iv_players = 7 iv_games = 1 iv_day = 1 + IMPORTING ev_fee = DATA(lv_fee) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '7.00' ) act = lv_fee ). + ENDMETHOD. + + METHOD shoe_charge. + call( EXPORTING iv_players = 7 iv_games = 1 iv_day = 1 iv_shoes = abap_true + IMPORTING ev_fee = DATA(lv_fee) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '21.00' ) act = lv_fee ). + ENDMETHOD. + + METHOD group_discount. + call( EXPORTING iv_players = 12 iv_games = 1 iv_day = 1 iv_shoes = abap_true + IMPORTING ev_fee = DATA(lv_fee) ev_note = DATA(lv_note) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '21.00' ) act = lv_fee ). + cl_abap_unit_assert=>assert_equals( exp = 'GROUP' act = lv_note ). + ENDMETHOD. + + METHOD group_discount_negative. + call( EXPORTING iv_players = 12 iv_games = 1 iv_day = 1 + IMPORTING ev_fee = DATA(lv_fee) ev_note = DATA(lv_note) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '-3.00' ) act = lv_fee ). + cl_abap_unit_assert=>assert_equals( exp = 'GROUP' act = lv_note ). + ENDMETHOD. + + METHOD day_above_five. + call( EXPORTING iv_players = 1 iv_games = 1 iv_day = 8 + IMPORTING ev_fee = DATA(lv_fee) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '5.00' ) act = lv_fee ). + ENDMETHOD. + + METHOD invalid_players. + call( EXPORTING iv_players = 0 iv_games = 1 iv_day = 1 + IMPORTING ev_subrc = DATA(lv_rc) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lv_rc ). + ENDMETHOD. + + METHOD invalid_games. + call( EXPORTING iv_players = 1 iv_games = 0 iv_day = 1 + IMPORTING ev_subrc = DATA(lv_rc) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lv_rc ). + ENDMETHOD. + + METHOD no_discount_below_twelve. + call( EXPORTING iv_players = 11 iv_games = 1 iv_day = 1 + IMPORTING ev_fee = DATA(lv_fee) ev_note = DATA(lv_note) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '7.00' ) act = lv_fee ). + cl_abap_unit_assert=>assert_equals( exp = 'BOOKED' act = lv_note ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0143/reference/bowl_fee_old.func.abap b/tasks_gen/eval/G0143/reference/bowl_fee_old.func.abap new file mode 100644 index 0000000..26380ba --- /dev/null +++ b/tasks_gen/eval/G0143/reference/bowl_fee_old.func.abap @@ -0,0 +1,90 @@ +FUNCTION {{p}}bowl_fee_old + IMPORTING + iv_players TYPE i + iv_games TYPE i + iv_day TYPE i + iv_shoes TYPE abap_bool + EXPORTING + ev_fee TYPE decfloat34 + ev_note TYPE string + EXCEPTIONS + invalid_input. + + TYPES ty_rate TYPE p LENGTH 8 DECIMALS 2. + + CLASS lcl_bowling DEFINITION. + PUBLIC SECTION. + METHODS calculate + IMPORTING + iv_players TYPE i + iv_games TYPE i + iv_day TYPE i + iv_shoes TYPE abap_bool + EXPORTING + ev_fee TYPE decfloat34 + ev_note TYPE string. + PRIVATE SECTION. + CONSTANTS: + c_lane_size TYPE i VALUE 6, + c_group_size TYPE i VALUE 12, + c_rate_weekday TYPE ty_rate VALUE '3.50', + c_rate_weekend TYPE ty_rate VALUE '5.00', + c_shoe_price TYPE ty_rate VALUE '2.00', + c_group_discount TYPE ty_rate VALUE '10.00'. + METHODS lanes_for + IMPORTING iv_players TYPE i + RETURNING VALUE(rv_lanes) TYPE i. + METHODS rate_for + IMPORTING iv_day TYPE i + RETURNING VALUE(rv_rate) TYPE ty_rate. + ENDCLASS. + + CLASS lcl_bowling IMPLEMENTATION. + METHOD calculate. + DATA(lv_lanes) = lanes_for( iv_players ). + DATA(lv_rate) = rate_for( iv_day ). + DATA lv_sum TYPE p LENGTH 15 DECIMALS 2. + lv_sum = lv_lanes * iv_games * lv_rate. + IF iv_shoes = abap_true. + lv_sum = lv_sum + iv_players * c_shoe_price. + ENDIF. + ev_note = 'BOOKED'. + IF iv_players >= c_group_size. + lv_sum = lv_sum - c_group_discount. + ev_note = 'GROUP'. + ENDIF. + ev_fee = lv_sum. + ENDMETHOD. + + METHOD lanes_for. + rv_lanes = iv_players DIV c_lane_size. + IF iv_players MOD c_lane_size > 0. + rv_lanes = rv_lanes + 1. + ENDIF. + ENDMETHOD. + + METHOD rate_for. + IF iv_day > 5. + rv_rate = c_rate_weekend. + ELSE. + rv_rate = c_rate_weekday. + ENDIF. + ENDMETHOD. + ENDCLASS. + + IF iv_players < 1 OR iv_games < 1. + RAISE invalid_input. + ENDIF. + + DATA(lo_bowling) = NEW lcl_bowling( ). + lo_bowling->calculate( + EXPORTING + iv_players = iv_players + iv_games = iv_games + iv_day = iv_day + iv_shoes = iv_shoes + IMPORTING + ev_fee = ev_fee + ev_note = ev_note ). + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0143/reference/t14_test.clas.abap b/tasks_gen/eval/G0143/reference/t14_test.clas.abap new file mode 100644 index 0000000..55ca415 --- /dev/null +++ b/tasks_gen/eval/G0143/reference/t14_test.clas.abap @@ -0,0 +1,74 @@ +CLASS {{p}}t14_test DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS weekday_fee FOR TESTING. + METHODS weekend_fee FOR TESTING. + METHODS group_fee FOR TESTING. + METHODS invalid_input FOR TESTING. +ENDCLASS. + +CLASS {{p}}t14_test IMPLEMENTATION. + METHOD weekday_fee. + DATA lv_fee TYPE decfloat34. + CALL FUNCTION '{{P}}BOWL_FEE_OLD' + EXPORTING + iv_players = 1 + iv_games = 1 + iv_day = 1 + IMPORTING + ev_fee = lv_fee + EXCEPTIONS + invalid_input = 1 + OTHERS = 2. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '3.50' ) act = lv_fee ). + ENDMETHOD. + + METHOD weekend_fee. + DATA lv_fee TYPE decfloat34. + CALL FUNCTION '{{P}}BOWL_FEE_OLD' + EXPORTING + iv_players = 6 + iv_games = 2 + iv_day = 6 + IMPORTING + ev_fee = lv_fee + EXCEPTIONS + invalid_input = 1 + OTHERS = 2. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '10.00' ) act = lv_fee ). + ENDMETHOD. + + METHOD group_fee. + DATA lv_fee TYPE decfloat34. + CALL FUNCTION '{{P}}BOWL_FEE_OLD' + EXPORTING + iv_players = 12 + iv_games = 1 + iv_day = 1 + iv_shoes = abap_true + IMPORTING + ev_fee = lv_fee + EXCEPTIONS + invalid_input = 1 + OTHERS = 2. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '21.00' ) act = lv_fee ). + ENDMETHOD. + + METHOD invalid_input. + DATA lv_fee TYPE decfloat34. + CALL FUNCTION '{{P}}BOWL_FEE_OLD' + EXPORTING + iv_players = 0 + iv_games = 1 + iv_day = 1 + IMPORTING + ev_fee = lv_fee + EXCEPTIONS + invalid_input = 1 + OTHERS = 2. + cl_abap_unit_assert=>assert_equals( exp = 1 act = sy-subrc ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0143/seed/bowl_fee_old.func.abap b/tasks_gen/eval/G0143/seed/bowl_fee_old.func.abap new file mode 100644 index 0000000..3a04bdf --- /dev/null +++ b/tasks_gen/eval/G0143/seed/bowl_fee_old.func.abap @@ -0,0 +1,50 @@ +FUNCTION {{p}}bowl_fee_old + IMPORTING + iv_players TYPE i + iv_games TYPE i + iv_day TYPE i + iv_shoes TYPE abap_bool + EXPORTING + ev_fee TYPE decfloat34 + ev_note TYPE string + EXCEPTIONS + invalid_input. + + DATA: lv_lanes TYPE i, + lv_rate TYPE p LENGTH 8 DECIMALS 2, + lv_sum TYPE p LENGTH 15 DECIMALS 2. + + IF iv_players < 1. + RAISE invalid_input. + ENDIF. + IF iv_games < 1. + RAISE invalid_input. + ENDIF. + + COMPUTE lv_lanes = iv_players DIV 6. + IF iv_players MOD 6 > 0. + ADD 1 TO lv_lanes. + ENDIF. + + IF iv_day > 5. + MOVE '5.00' TO lv_rate. + ELSE. + MOVE '3.50' TO lv_rate. + ENDIF. + + COMPUTE lv_sum = lv_lanes * iv_games * lv_rate. + + IF iv_shoes = 'X'. + COMPUTE lv_sum = lv_sum + iv_players * '2.00'. + ENDIF. + + ev_note = 'BOOKED'. + + IF iv_players >= 12. + COMPUTE lv_sum = lv_sum - '10.00'. + ev_note = 'GROUP'. + ENDIF. + + ev_fee = lv_sum. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0143/spec.md b/tasks_gen/eval/G0143/spec.md new file mode 100644 index 0000000..9181376 --- /dev/null +++ b/tasks_gen/eval/G0143/spec.md @@ -0,0 +1,36 @@ +# 1. Goal +Refactor the legacy function module {{P}}BOWL_FEE_OLD in place. The behavior must +stay the same. Improve the code quality so that the module is easier to maintain. + +# 2. Open questions +None. + +# 3. Context +- Function group {{P}}FG_BOWL exists in package $TMP. +- Function module {{P}}BOWL_FEE_OLD exists in this group. It is the legacy + implementation of the bowling fee calculation. +- The booking program calls this function module. The interface must not change. + +# 4. Contract +- Refactor the function module {{P}}BOWL_FEE_OLD in function group {{P}}FG_BOWL. +- Keep the exact interface: the same parameter names, types, and exceptions. +- The function module name stays the same. + +# 5. Business rules +The business rules are defined by the current behavior of the legacy code. +Read the legacy source code in {{P}}BOWL_FEE_OLD. The refactored function module +must produce exactly the same results as the legacy code for every input. +Do not change any rule. + +# 6. Constraints +- Release target: SAP_BASIS 816. +- Coding standards: Clean ABAP. Use modern ABAP syntax. No obsolete statements + (for example COMPUTE, MOVE, ADD ... TO ...). Methods below 40 statements. + Pass large parameters by reference. No ATC priority 1 or 2 findings. +- Out of scope: do not change the function group {{P}}FG_BOWL. Do not change + the function module interface. + +# 7. Acceptance +- The function module is active and has no syntax error. +- The hidden tests pass. +- Write ABAP Unit tests for the function module in a global test class. diff --git a/tasks_gen/eval/G0143/task.json b/tasks_gen/eval/G0143/task.json new file mode 100644 index 0000000..8482244 --- /dev/null +++ b/tasks_gen/eval/G0143/task.json @@ -0,0 +1,86 @@ +{ + "id": "G0143", + "category": "E", + "object_type": "FUNC", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [ + { + "type": "FUGR", + "name": "{{P}}FG_BOWL", + "description": "Bowling fee function group" + }, + { + "type": "FUNC", + "name": "{{P}}BOWL_FEE_OLD", + "functionGroup": "{{P}}FG_BOWL", + "file": "seed/bowl_fee_old.func.abap", + "description": "Legacy bowling fee calculation" + } + ], + "contract": [ + { + "type": "FUNC", + "name": "{{P}}BOWL_FEE_OLD", + "functionGroup": "{{P}}FG_BOWL", + "params": [ + { + "name": "iv_players", + "type": "i" + }, + { + "name": "iv_games", + "type": "i" + }, + { + "name": "iv_day", + "type": "i" + }, + { + "name": "iv_shoes", + "type": "abap_bool" + }, + { + "name": "ev_fee", + "type": "decfloat34" + }, + { + "name": "ev_note", + "type": "string" + } + ] + } + ], + "out_of_scope": [], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T14_HIDDEN", + "file": "hidden/t14_hidden.clas.abap", + "description": "T14 hidden tests" + } + ], + "reference": [ + { + "type": "FUNC", + "name": "{{P}}BOWL_FEE_OLD", + "functionGroup": "{{P}}FG_BOWL", + "file": "reference/bowl_fee_old.func.abap", + "description": "Refactored bowling fee calculation" + }, + { + "type": "CLAS", + "name": "{{P}}T14_TEST", + "file": "reference/t14_test.clas.abap", + "description": "T14 own tests" + } + ], + "craft_checks": [ + "method_length" + ] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0144/hidden/cine_hidden.clas.abap b/tasks_gen/eval/G0144/hidden/cine_hidden.clas.abap new file mode 100644 index 0000000..57b7e58 --- /dev/null +++ b/tasks_gen/eval/G0144/hidden/cine_hidden.clas.abap @@ -0,0 +1,135 @@ +CLASS {{p}}cine_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + CONSTANTS: c_evening TYPE t VALUE '200000', + c_matinee TYPE t VALUE '160000', + c_boundary TYPE t VALUE '170000', + c_morning TYPE t VALUE '100000'. + + METHODS call_fee + IMPORTING iv_show TYPE string + iv_seats TYPE i + iv_time TYPE t + iv_cust TYPE string + EXPORTING ev_total TYPE decfloat34 + ev_disc TYPE decfloat34 + ev_subrc TYPE sysubrc. + + METHODS base_price_2d FOR TESTING. + METHODS base_prices_3d_imax FOR TESTING. + METHODS invalid_seats FOR TESTING. + METHODS invalid_show_type FOR TESTING. + METHODS invalid_cust_type FOR TESTING. + METHODS matinee_discount FOR TESTING. + METHODS matinee_boundary FOR TESTING. + METHODS child_skips_matinee FOR TESTING. + METHODS group_threshold FOR TESTING. + METHODS discount_cap FOR TESTING. + METHODS rounding_half_up FOR TESTING. +ENDCLASS. + + +CLASS {{p}}cine_hidden IMPLEMENTATION. + + METHOD call_fee. + ev_total = 0. + ev_disc = 0. + CALL FUNCTION '{{P}}CINE_FEE_OLD' + EXPORTING + iv_show_type = iv_show + iv_seats = iv_seats + iv_show_time = iv_time + iv_cust_type = iv_cust + IMPORTING + ev_total = ev_total + ev_discount = ev_disc + EXCEPTIONS + invalid_input = 1 + OTHERS = 2. + ev_subrc = sy-subrc. + ENDMETHOD. + + METHOD base_price_2d. + call_fee( EXPORTING iv_show = `2D` iv_seats = 1 iv_time = c_evening iv_cust = `ADULT` + IMPORTING ev_total = DATA(lv_total) ev_disc = DATA(lv_disc) ev_subrc = DATA(lv_rc) ). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_rc ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '9.50' ) act = lv_total ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 0 ) act = lv_disc ). + ENDMETHOD. + + METHOD base_prices_3d_imax. + call_fee( EXPORTING iv_show = `3D` iv_seats = 1 iv_time = c_evening iv_cust = `ADULT` + IMPORTING ev_total = DATA(lv_total) ev_subrc = DATA(lv_rc) ). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_rc ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '13.00' ) act = lv_total ). + + call_fee( EXPORTING iv_show = `IMAX` iv_seats = 1 iv_time = c_evening iv_cust = `ADULT` + IMPORTING ev_total = DATA(lv_total2) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '16.50' ) act = lv_total2 ). + ENDMETHOD. + + METHOD invalid_seats. + call_fee( EXPORTING iv_show = `2D` iv_seats = 0 iv_time = c_evening iv_cust = `ADULT` + IMPORTING ev_subrc = DATA(lv_rc) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lv_rc ). + ENDMETHOD. + + METHOD invalid_show_type. + call_fee( EXPORTING iv_show = `XX` iv_seats = 1 iv_time = c_evening iv_cust = `ADULT` + IMPORTING ev_subrc = DATA(lv_rc) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lv_rc ). + ENDMETHOD. + + METHOD invalid_cust_type. + call_fee( EXPORTING iv_show = `2D` iv_seats = 1 iv_time = c_evening iv_cust = `VIP` + IMPORTING ev_subrc = DATA(lv_rc) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lv_rc ). + ENDMETHOD. + + METHOD matinee_discount. + call_fee( EXPORTING iv_show = `2D` iv_seats = 1 iv_time = c_matinee iv_cust = `ADULT` + IMPORTING ev_total = DATA(lv_total) ev_disc = DATA(lv_disc) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '7.25' ) act = lv_total ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 25 ) act = lv_disc ). + ENDMETHOD. + + METHOD matinee_boundary. + call_fee( EXPORTING iv_show = `2D` iv_seats = 1 iv_time = c_boundary iv_cust = `ADULT` + IMPORTING ev_total = DATA(lv_total) ev_disc = DATA(lv_disc) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '9.50' ) act = lv_total ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 0 ) act = lv_disc ). + ENDMETHOD. + + METHOD child_skips_matinee. + call_fee( EXPORTING iv_show = `2D` iv_seats = 1 iv_time = c_morning iv_cust = `CHILD` + IMPORTING ev_total = DATA(lv_total) ev_disc = DATA(lv_disc) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '5.90' ) act = lv_total ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 40 ) act = lv_disc ). + ENDMETHOD. + + METHOD group_threshold. + call_fee( EXPORTING iv_show = `2D` iv_seats = 7 iv_time = c_evening iv_cust = `ADULT` + IMPORTING ev_total = DATA(lv_total) ev_disc = DATA(lv_disc) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '66.50' ) act = lv_total ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 0 ) act = lv_disc ). + + call_fee( EXPORTING iv_show = `2D` iv_seats = 8 iv_time = c_evening iv_cust = `ADULT` + IMPORTING ev_total = DATA(lv_total2) ev_disc = DATA(lv_disc2) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '68.80' ) act = lv_total2 ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 10 ) act = lv_disc2 ). + ENDMETHOD. + + METHOD discount_cap. + call_fee( EXPORTING iv_show = `2D` iv_seats = 8 iv_time = c_morning iv_cust = `SENIOR` + IMPORTING ev_total = DATA(lv_total) ev_disc = DATA(lv_disc) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '32.80' ) act = lv_total ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 60 ) act = lv_disc ). + ENDMETHOD. + + METHOD rounding_half_up. + call_fee( EXPORTING iv_show = `3D` iv_seats = 3 iv_time = c_matinee iv_cust = `ADULT` + IMPORTING ev_total = DATA(lv_total) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '29.63' ) act = lv_total ). + ENDMETHOD. + +ENDCLASS. diff --git a/tasks_gen/eval/G0144/reference/cine_fee_old.func.abap b/tasks_gen/eval/G0144/reference/cine_fee_old.func.abap new file mode 100644 index 0000000..31d87af --- /dev/null +++ b/tasks_gen/eval/G0144/reference/cine_fee_old.func.abap @@ -0,0 +1,77 @@ +FUNCTION {{p}}cine_fee_old + IMPORTING + iv_show_type TYPE string + iv_seats TYPE i + iv_show_time TYPE t + iv_cust_type TYPE string + EXPORTING + ev_total TYPE decfloat34 + ev_discount TYPE decfloat34 + EXCEPTIONS + invalid_input. + + CONSTANTS: + c_price_2d TYPE decfloat34 VALUE '9.00', + c_price_3d TYPE decfloat34 VALUE '12.50', + c_price_imax TYPE decfloat34 VALUE '16.00', + c_booking_fee TYPE decfloat34 VALUE '0.50', + c_percent TYPE decfloat34 VALUE 100, + c_disc_child TYPE decfloat34 VALUE 40, + c_disc_senior TYPE decfloat34 VALUE 30, + c_disc_student TYPE decfloat34 VALUE 20, + c_disc_matinee TYPE decfloat34 VALUE 25, + c_disc_group TYPE decfloat34 VALUE 10, + c_disc_max TYPE decfloat34 VALUE 60, + c_group_seats TYPE i VALUE 8, + c_matinee_end TYPE t VALUE '170000'. + + DATA: lv_base TYPE decfloat34, + lv_discount TYPE decfloat34, + lv_price TYPE decfloat34. + + IF iv_seats < 1. + RAISE invalid_input. + ENDIF. + + CASE iv_show_type. + WHEN '2D'. + lv_base = c_price_2d. + WHEN '3D'. + lv_base = c_price_3d. + WHEN 'IMAX'. + lv_base = c_price_imax. + WHEN OTHERS. + RAISE invalid_input. + ENDCASE. + + CASE iv_cust_type. + WHEN 'CHILD'. + lv_discount = c_disc_child. + WHEN 'SENIOR'. + lv_discount = c_disc_senior. + WHEN 'STUDENT'. + lv_discount = c_disc_student. + WHEN 'ADULT'. + lv_discount = 0. + WHEN OTHERS. + RAISE invalid_input. + ENDCASE. + + IF iv_show_time < c_matinee_end AND iv_cust_type <> 'CHILD'. + lv_discount = lv_discount + c_disc_matinee. + ENDIF. + + IF iv_seats >= c_group_seats. + lv_discount = lv_discount + c_disc_group. + ENDIF. + + IF lv_discount > c_disc_max. + lv_discount = c_disc_max. + ENDIF. + + lv_price = lv_base - lv_base * lv_discount / c_percent + c_booking_fee. + + ev_total = round( val = lv_price * iv_seats dec = 2 mode = cl_abap_math=>round_half_up ). + ev_discount = lv_discount. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0144/reference/cine_test.clas.abap b/tasks_gen/eval/G0144/reference/cine_test.clas.abap new file mode 100644 index 0000000..946529e --- /dev/null +++ b/tasks_gen/eval/G0144/reference/cine_test.clas.abap @@ -0,0 +1,72 @@ +CLASS {{p}}cine_test DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + CONSTANTS: c_evening TYPE t VALUE '200000', + c_matinee TYPE t VALUE '160000'. + + METHODS fee + IMPORTING iv_show TYPE string + iv_seats TYPE i + iv_time TYPE t + iv_cust TYPE string + RETURNING VALUE(rv_total) TYPE decfloat34. + + METHODS adult_evening FOR TESTING. + METHODS matinee_discount FOR TESTING. + METHODS child_price FOR TESTING. + METHODS invalid_seats FOR TESTING. +ENDCLASS. + + +CLASS {{p}}cine_test IMPLEMENTATION. + + METHOD fee. + CALL FUNCTION '{{P}}CINE_FEE_OLD' + EXPORTING + iv_show_type = iv_show + iv_seats = iv_seats + iv_show_time = iv_time + iv_cust_type = iv_cust + IMPORTING + ev_total = rv_total + EXCEPTIONS + invalid_input = 1 + OTHERS = 2. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + ENDMETHOD. + + METHOD adult_evening. + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( '9.50' ) + act = fee( iv_show = `2D` iv_seats = 1 iv_time = c_evening iv_cust = `ADULT` ) ). + ENDMETHOD. + + METHOD matinee_discount. + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( '7.25' ) + act = fee( iv_show = `2D` iv_seats = 1 iv_time = c_matinee iv_cust = `ADULT` ) ). + ENDMETHOD. + + METHOD child_price. + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( '5.90' ) + act = fee( iv_show = `2D` iv_seats = 1 iv_time = c_matinee iv_cust = `CHILD` ) ). + ENDMETHOD. + + METHOD invalid_seats. + DATA lv_total TYPE decfloat34. + CALL FUNCTION '{{P}}CINE_FEE_OLD' + EXPORTING + iv_show_type = `2D` + iv_seats = 0 + iv_show_time = c_evening + iv_cust_type = `ADULT` + IMPORTING + ev_total = lv_total + EXCEPTIONS + invalid_input = 1 + OTHERS = 2. + cl_abap_unit_assert=>assert_equals( exp = 1 act = sy-subrc ). + ENDMETHOD. + +ENDCLASS. diff --git a/tasks_gen/eval/G0144/seed/cine_fee_old.func.abap b/tasks_gen/eval/G0144/seed/cine_fee_old.func.abap new file mode 100644 index 0000000..a60822c --- /dev/null +++ b/tasks_gen/eval/G0144/seed/cine_fee_old.func.abap @@ -0,0 +1,71 @@ +FUNCTION {{p}}cine_fee_old + IMPORTING + iv_show_type TYPE string + iv_seats TYPE i + iv_show_time TYPE t + iv_cust_type TYPE string + EXPORTING + ev_total TYPE decfloat34 + ev_discount TYPE decfloat34 + EXCEPTIONS + invalid_input. + + " legacy: price per seat + DATA: lv_x TYPE decfloat34, + lv_y TYPE decfloat34, + lv_z TYPE i. + + IF iv_seats < 1. + RAISE invalid_input. + ENDIF. + + IF iv_show_type = '2D' OR iv_show_type = '3D' OR iv_show_type = 'IMAX'. + IF iv_show_type = '2D'. + lv_x = 9. + ELSEIF iv_show_type = '3D'. + lv_x = '12.50'. + ELSE. + lv_x = 16. + ENDIF. + ELSE. + RAISE invalid_input. + ENDIF. + + IF iv_cust_type = 'CHILD'. + lv_y = 40. + ELSEIF iv_cust_type = 'SENIOR'. + lv_y = 30. + ELSEIF iv_cust_type = 'STUDENT'. + lv_y = 20. + ELSEIF iv_cust_type = 'ADULT'. + lv_y = 0. + ELSE. + RAISE invalid_input. + ENDIF. + + IF iv_show_time < '170000'. + IF iv_cust_type <> 'CHILD'. + lv_y = lv_y + 25. + ENDIF. + ENDIF. + + IF iv_seats >= 8. + lv_y = lv_y + 10. + ENDIF. + + IF lv_y > 60. + lv_y = 60. + ENDIF. + + lv_x = lv_x - lv_x * lv_y / 100. + lv_x = lv_x + '0.5'. + + lv_z = 0. + DO iv_seats TIMES. + lv_z = lv_z + 1. + ENDDO. + + ev_total = round( val = lv_x * lv_z dec = 2 mode = cl_abap_math=>round_half_up ). + ev_discount = lv_y. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0144/spec.md b/tasks_gen/eval/G0144/spec.md new file mode 100644 index 0000000..ec040ad --- /dev/null +++ b/tasks_gen/eval/G0144/spec.md @@ -0,0 +1,44 @@ +# 1. Goal +The function module {{P}}CINE_FEE_OLD in function group {{P}}FG_CINE calculates +the price of a cinema ticket order. The code is legacy code. Refactor the +function module in place. The behavior stays the same. The name and the public +interface stay the same. + +# 2. Open questions +None. + +# 3. Context +- Function group {{P}}FG_CINE exists in package $TMP. +- The function module {{P}}CINE_FEE_OLD exists in this function group. It holds + the legacy code. +- A ticket desk program calls {{P}}CINE_FEE_OLD for each ticket order. This call + must not change. + +# 4. Contract +- Object: the function module {{P}}CINE_FEE_OLD in function group {{P}}FG_CINE. +- Keep the name and the interface of the function module: the same parameter + names, parameter kinds, parameter types and the same exception. +- Importing parameters: iv_show_type TYPE string, iv_seats TYPE i, + iv_show_time TYPE t, iv_cust_type TYPE string. +- Exporting parameters: ev_total TYPE decfloat34, ev_discount TYPE decfloat34. +- Exception: invalid_input. + +# 5. Business rules +The legacy source code of {{P}}CINE_FEE_OLD is the only source of the business +rules. Read this source code. The one rule of this task: for every input the +function module returns the same output values and the same exception as before +the refactoring. Do not add, remove or change a rule. + +# 6. Constraints +- Release target: SAP_BASIS 816. +- Coding standards: Clean ABAP. No ATC priority 1 or priority 2 finding. Keep + every procedure and every method below 40 statements. Replace literal numbers + with named constants. Use meaningful names. +- Out of scope: do not change the interface. Do not change the function group + {{P}}FG_CINE. + +# 7. Acceptance +- {{P}}CINE_FEE_OLD is active and has no syntax error. +- The behavior is unchanged. +- The hidden tests pass. +- Write ABAP Unit tests for the function module in a global test class. diff --git a/tasks_gen/eval/G0144/task.json b/tasks_gen/eval/G0144/task.json new file mode 100644 index 0000000..52bb365 --- /dev/null +++ b/tasks_gen/eval/G0144/task.json @@ -0,0 +1,89 @@ +{ + "id": "G0144", + "category": "E", + "object_type": "FUNC", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [ + { + "type": "FUGR", + "name": "{{P}}FG_CINE", + "description": "Cinema ticket function group" + }, + { + "type": "FUNC", + "name": "{{P}}CINE_FEE_OLD", + "functionGroup": "{{P}}FG_CINE", + "file": "seed/cine_fee_old.func.abap", + "description": "Legacy ticket price calculation" + } + ], + "contract": [ + { + "type": "FUNC", + "name": "{{P}}CINE_FEE_OLD", + "functionGroup": "{{P}}FG_CINE", + "params": [ + { + "name": "iv_show_type", + "type": "string" + }, + { + "name": "iv_seats", + "type": "i" + }, + { + "name": "iv_show_time", + "type": "t" + }, + { + "name": "iv_cust_type", + "type": "string" + }, + { + "name": "ev_total", + "type": "decfloat34" + }, + { + "name": "ev_discount", + "type": "decfloat34" + } + ] + } + ], + "out_of_scope": [ + "{{P}}FG_CINE" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}CINE_HIDDEN", + "file": "hidden/cine_hidden.clas.abap", + "description": "Hidden behavior tests for the refactored ticket price calculation" + } + ], + "reference": [ + { + "type": "FUNC", + "name": "{{P}}CINE_FEE_OLD", + "functionGroup": "{{P}}FG_CINE", + "file": "reference/cine_fee_old.func.abap", + "description": "Refactored ticket price calculation, same interface and behavior", + "overwrite": true + }, + { + "type": "CLAS", + "name": "{{P}}CINE_TEST", + "file": "reference/cine_test.clas.abap", + "description": "Own tests for the ticket price calculation" + } + ], + "craft_checks": [ + "method_length" + ] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0145/faulty/m0_i_green_fee.ddls.asddls b/tasks_gen/eval/G0145/faulty/m0_i_green_fee.ddls.asddls new file mode 100644 index 0000000..cca53c1 --- /dev/null +++ b/tasks_gen/eval/G0145/faulty/m0_i_green_fee.ddls.asddls @@ -0,0 +1,29 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Green fee per tee time' +define view entity {{P}}I_GREEN_FEE + as select from {{p}}tee as tee + left outer join {{p}}member as mem on mem.member_id = tee.member_id +{ + key tee.tee_id as tee_id, + tee.member_id as member_id, + mem.member_kind as member_kind, + tee.day_kind as day_kind, + tee.player_count as player_count, + case + when mem.member_kind = 'J' and tee.day_kind = 'W' + then cast( 8 as abap.dec(7,2) ) * tee.player_count + when mem.member_kind = 'J' + then cast( 12 as abap.dec(7,2) ) * tee.player_count + when mem.member_kind = 'S' and tee.day_kind = 'W' + then cast( 20 as abap.dec(7,2) ) * tee.player_count + when mem.member_kind = 'S' and tee.day_kind = 'E' + then cast( 30 as abap.dec(7,2) ) * tee.player_count + when mem.member_kind = 'S' + then cast( 35 as abap.dec(7,2) ) * tee.player_count + when tee.day_kind = 'W' + then cast( 35 as abap.dec(7,2) ) * tee.player_count + when tee.day_kind = 'E' + then cast( 55 as abap.dec(7,2) ) * tee.player_count + else cast( 60 as abap.dec(7,2) ) * tee.player_count + end as green_fee +} diff --git a/tasks_gen/eval/G0145/faulty/m1_i_green_fee.ddls.asddls b/tasks_gen/eval/G0145/faulty/m1_i_green_fee.ddls.asddls new file mode 100644 index 0000000..53625f4 --- /dev/null +++ b/tasks_gen/eval/G0145/faulty/m1_i_green_fee.ddls.asddls @@ -0,0 +1,29 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Green fee per tee time' +define view entity {{P}}I_GREEN_FEE + as select from {{p}}tee as tee + inner join {{p}}member as mem on mem.member_id = tee.member_id +{ + key tee.tee_id as tee_id, + tee.member_id as member_id, + mem.member_kind as member_kind, + tee.day_kind as day_kind, + tee.player_count as player_count, + case + when mem.member_kind = 'J' or tee.day_kind = 'W' + then cast( 8 as abap.dec(7,2) ) * tee.player_count + when mem.member_kind = 'J' + then cast( 12 as abap.dec(7,2) ) * tee.player_count + when mem.member_kind = 'S' and tee.day_kind = 'W' + then cast( 20 as abap.dec(7,2) ) * tee.player_count + when mem.member_kind = 'S' and tee.day_kind = 'E' + then cast( 30 as abap.dec(7,2) ) * tee.player_count + when mem.member_kind = 'S' + then cast( 35 as abap.dec(7,2) ) * tee.player_count + when tee.day_kind = 'W' + then cast( 35 as abap.dec(7,2) ) * tee.player_count + when tee.day_kind = 'E' + then cast( 55 as abap.dec(7,2) ) * tee.player_count + else cast( 60 as abap.dec(7,2) ) * tee.player_count + end as green_fee +} diff --git a/tasks_gen/eval/G0145/faulty/m2_i_green_fee.ddls.asddls b/tasks_gen/eval/G0145/faulty/m2_i_green_fee.ddls.asddls new file mode 100644 index 0000000..a988142 --- /dev/null +++ b/tasks_gen/eval/G0145/faulty/m2_i_green_fee.ddls.asddls @@ -0,0 +1,29 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Green fee per tee time' +define view entity {{P}}I_GREEN_FEE + as select from {{p}}tee as tee + inner join {{p}}member as mem on mem.member_id = tee.member_id +{ + key tee.tee_id as tee_id, + tee.member_id as member_id, + mem.member_kind as member_kind, + tee.day_kind as day_kind, + tee.player_count as player_count, + case + when mem.member_kind = 'J' and tee.day_kind = 'W' + then cast( 8 as abap.dec(7,2) ) * tee.player_count + when mem.member_kind = 'J' + then cast( 12 as abap.dec(7,2) ) * tee.player_count + when mem.member_kind = 'S' and tee.day_kind = 'Z' + then cast( 20 as abap.dec(7,2) ) * tee.player_count + when mem.member_kind = 'S' and tee.day_kind = 'E' + then cast( 30 as abap.dec(7,2) ) * tee.player_count + when mem.member_kind = 'S' + then cast( 35 as abap.dec(7,2) ) * tee.player_count + when tee.day_kind = 'W' + then cast( 35 as abap.dec(7,2) ) * tee.player_count + when tee.day_kind = 'E' + then cast( 55 as abap.dec(7,2) ) * tee.player_count + else cast( 60 as abap.dec(7,2) ) * tee.player_count + end as green_fee +} diff --git a/tasks_gen/eval/G0145/faulty/m3_i_green_fee.ddls.asddls b/tasks_gen/eval/G0145/faulty/m3_i_green_fee.ddls.asddls new file mode 100644 index 0000000..892e50f --- /dev/null +++ b/tasks_gen/eval/G0145/faulty/m3_i_green_fee.ddls.asddls @@ -0,0 +1,29 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Green fee per tee time' +define view entity {{P}}I_GREEN_FEE + as select from {{p}}tee as tee + inner join {{p}}member as mem on mem.member_id = tee.member_id +{ + key tee.tee_id as tee_id, + tee.member_id as member_id, + mem.member_kind as member_kind, + tee.day_kind as day_kind, + tee.player_count as player_count, + case + when mem.member_kind = 'J' and tee.day_kind = 'W' + then cast( 8 as abap.dec(7,2) ) * tee.player_count + when mem.member_kind = 'J' + then cast( 12 as abap.dec(7,2) ) * tee.player_count + when mem.member_kind = 'S' and tee.day_kind = 'W' + then cast( 20 as abap.dec(7,2) ) * tee.player_count + when mem.member_kind = 'S' or tee.day_kind = 'E' + then cast( 30 as abap.dec(7,2) ) * tee.player_count + when mem.member_kind = 'S' + then cast( 35 as abap.dec(7,2) ) * tee.player_count + when tee.day_kind = 'W' + then cast( 35 as abap.dec(7,2) ) * tee.player_count + when tee.day_kind = 'E' + then cast( 55 as abap.dec(7,2) ) * tee.player_count + else cast( 60 as abap.dec(7,2) ) * tee.player_count + end as green_fee +} diff --git a/tasks_gen/eval/G0145/faulty/m4_i_green_fee.ddls.asddls b/tasks_gen/eval/G0145/faulty/m4_i_green_fee.ddls.asddls new file mode 100644 index 0000000..9422877 --- /dev/null +++ b/tasks_gen/eval/G0145/faulty/m4_i_green_fee.ddls.asddls @@ -0,0 +1,29 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Green fee per tee time' +define view entity {{P}}I_GREEN_FEE + as select from {{p}}tee as tee + inner join {{p}}member as mem on mem.member_id = tee.member_id +{ + key tee.tee_id as tee_id, + tee.member_id as member_id, + mem.member_kind as member_kind, + tee.day_kind as day_kind, + tee.player_count as player_count, + case + when mem.member_kind = 'J' and tee.day_kind = 'W' + then cast( 8 as abap.dec(7,2) ) * tee.player_count + when mem.member_kind = 'J' + then cast( 12 as abap.dec(7,2) ) * tee.player_count + when mem.member_kind = 'S' and tee.day_kind = 'W' + then cast( 20 as abap.dec(7,2) ) * tee.player_count + when mem.member_kind = 'S' and tee.day_kind = 'E' + then cast( 30 as abap.dec(7,2) ) * tee.player_count + when mem.member_kind = 'S' + then cast( 35 as abap.dec(7,2) ) * tee.player_count + when tee.day_kind <> 'W' + then cast( 35 as abap.dec(7,2) ) * tee.player_count + when tee.day_kind = 'E' + then cast( 55 as abap.dec(7,2) ) * tee.player_count + else cast( 60 as abap.dec(7,2) ) * tee.player_count + end as green_fee +} diff --git a/tasks_gen/eval/G0145/generation.json b/tasks_gen/eval/G0145/generation.json new file mode 100644 index 0000000..2240ec7 --- /dev/null +++ b/tasks_gen/eval/G0145/generation.json @@ -0,0 +1,24 @@ +{ + "id": "G0145", + "pool": "eval", + "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/eval/G0145/hidden/green_hidden.clas.abap b/tasks_gen/eval/G0145/hidden/green_hidden.clas.abap new file mode 100644 index 0000000..ef71eeb --- /dev/null +++ b/tasks_gen/eval/G0145/hidden/green_hidden.clas.abap @@ -0,0 +1,108 @@ +CLASS {{p}}green_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 junior_weekday FOR TESTING. + METHODS junior_weekend FOR TESTING. + METHODS junior_unknown_day FOR TESTING. + METHODS senior_weekday FOR TESTING. + METHODS senior_weekend FOR TESTING. + METHODS senior_holiday FOR TESTING. + METHODS adult_weekday FOR TESTING. + METHODS adult_weekend FOR TESTING. + METHODS adult_holiday FOR TESTING. + METHODS unknown_member FOR TESTING. + METHODS tee_without_member FOR TESTING. +ENDCLASS. + + +CLASS {{p}}green_hidden IMPLEMENTATION. + METHOD class_setup. + go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_GREEN_FEE' ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + DATA lt_mem TYPE STANDARD TABLE OF {{p}}member WITH EMPTY KEY. + DATA lt_tee TYPE STANDARD TABLE OF {{p}}tee WITH EMPTY KEY. + go_env->clear_doubles( ). + lt_mem = VALUE #( ( member_id = 'M1' member_kind = 'J' member_name = 'Junior' ) + ( member_id = 'M2' member_kind = 'S' member_name = 'Senior' ) + ( member_id = 'M3' member_kind = 'A' member_name = 'Adult' ) + ( member_id = 'M4' member_kind = 'X' member_name = 'Unknown' ) ). + lt_tee = VALUE #( ( tee_id = 'T01' member_id = 'M1' day_kind = 'W' player_count = 1 ) + ( tee_id = 'T02' member_id = 'M1' day_kind = 'E' player_count = 2 ) + ( tee_id = 'T03' member_id = 'M1' day_kind = 'Z' player_count = 1 ) + ( tee_id = 'T04' member_id = 'M2' day_kind = 'W' player_count = 1 ) + ( tee_id = 'T05' member_id = 'M2' day_kind = 'E' player_count = 3 ) + ( tee_id = 'T06' member_id = 'M2' day_kind = 'H' player_count = 1 ) + ( tee_id = 'T07' member_id = 'M3' day_kind = 'W' player_count = 1 ) + ( tee_id = 'T08' member_id = 'M3' day_kind = 'E' player_count = 1 ) + ( tee_id = 'T09' member_id = 'M3' day_kind = 'H' player_count = 2 ) + ( tee_id = 'T10' member_id = 'M4' day_kind = 'W' player_count = 1 ) + ( tee_id = 'T11' member_id = 'M9' day_kind = 'W' player_count = 1 ) ). + go_env->insert_test_data( lt_mem ). + go_env->insert_test_data( lt_tee ). + ENDMETHOD. + + METHOD junior_weekday. + SELECT SINGLE green_fee FROM {{p}}i_green_fee WHERE tee_id = 'T01' INTO @DATA(lv_fee). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '8.00' ) act = CONV decfloat34( lv_fee ) ). + ENDMETHOD. + + METHOD junior_weekend. + SELECT SINGLE green_fee FROM {{p}}i_green_fee WHERE tee_id = 'T02' INTO @DATA(lv_fee). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '24.00' ) act = CONV decfloat34( lv_fee ) ). + ENDMETHOD. + + METHOD junior_unknown_day. + SELECT SINGLE green_fee FROM {{p}}i_green_fee WHERE tee_id = 'T03' INTO @DATA(lv_fee). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '12.00' ) act = CONV decfloat34( lv_fee ) ). + ENDMETHOD. + + METHOD senior_weekday. + SELECT SINGLE green_fee FROM {{p}}i_green_fee WHERE tee_id = 'T04' INTO @DATA(lv_fee). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '20.00' ) act = CONV decfloat34( lv_fee ) ). + ENDMETHOD. + + METHOD senior_weekend. + SELECT SINGLE green_fee FROM {{p}}i_green_fee WHERE tee_id = 'T05' INTO @DATA(lv_fee). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '90.00' ) act = CONV decfloat34( lv_fee ) ). + ENDMETHOD. + + METHOD senior_holiday. + SELECT SINGLE green_fee FROM {{p}}i_green_fee WHERE tee_id = 'T06' INTO @DATA(lv_fee). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '35.00' ) act = CONV decfloat34( lv_fee ) ). + ENDMETHOD. + + METHOD adult_weekday. + SELECT SINGLE green_fee FROM {{p}}i_green_fee WHERE tee_id = 'T07' INTO @DATA(lv_fee). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '35.00' ) act = CONV decfloat34( lv_fee ) ). + ENDMETHOD. + + METHOD adult_weekend. + SELECT SINGLE green_fee FROM {{p}}i_green_fee WHERE tee_id = 'T08' INTO @DATA(lv_fee). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '55.00' ) act = CONV decfloat34( lv_fee ) ). + ENDMETHOD. + + METHOD adult_holiday. + SELECT SINGLE green_fee FROM {{p}}i_green_fee WHERE tee_id = 'T09' INTO @DATA(lv_fee). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '120.00' ) act = CONV decfloat34( lv_fee ) ). + ENDMETHOD. + + METHOD unknown_member. + SELECT SINGLE green_fee FROM {{p}}i_green_fee WHERE tee_id = 'T10' INTO @DATA(lv_fee). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '35.00' ) act = CONV decfloat34( lv_fee ) ). + ENDMETHOD. + + METHOD tee_without_member. + SELECT COUNT(*) FROM {{p}}i_green_fee INTO @DATA(lv_count). + cl_abap_unit_assert=>assert_equals( exp = 10 act = lv_count ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0145/mutation.json b/tasks_gen/eval/G0145/mutation.json new file mode 100644 index 0000000..ad47509 --- /dev/null +++ b/tasks_gen/eval/G0145/mutation.json @@ -0,0 +1,62 @@ +{ + "task": "G0145", + "mutants": [ + { + "object": "{{P}}I_GREEN_FEE", + "mutant": "line 5: inner join -> left outer join (join)", + "status": "killed", + "hidden": "10/11", + "failed_tests": [ + "TEE_WITHOUT_MEMBER" + ] + }, + { + "object": "{{P}}I_GREEN_FEE", + "mutant": "line 13: and -> or (logic)", + "status": "killed", + "hidden": "6/11", + "failed_tests": [ + "ADULT_WEEKDAY", + "JUNIOR_UNKNOWN_DAY", + "JUNIOR_WEEKEND", + "SENIOR_WEEKDAY", + "UNKNOWN_MEMBER" + ] + }, + { + "object": "{{P}}I_GREEN_FEE", + "mutant": "line 17: 'W' -> 'Z' (lit)", + "status": "killed", + "hidden": "10/11", + "failed_tests": [ + "SENIOR_WEEKDAY" + ] + }, + { + "object": "{{P}}I_GREEN_FEE", + "mutant": "line 19: and -> or (logic)", + "status": "killed", + "hidden": "9/11", + "failed_tests": [ + "ADULT_WEEKEND", + "SENIOR_HOLIDAY" + ] + }, + { + "object": "{{P}}I_GREEN_FEE", + "mutant": "line 23: = -> <> (eq)", + "status": "killed", + "hidden": "7/11", + "failed_tests": [ + "ADULT_HOLIDAY", + "ADULT_WEEKDAY", + "ADULT_WEEKEND", + "UNKNOWN_MEMBER" + ] + } + ], + "valid": 5, + "killed": 5, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0145/reference/green_test.clas.abap b/tasks_gen/eval/G0145/reference/green_test.clas.abap new file mode 100644 index 0000000..3fa20bf --- /dev/null +++ b/tasks_gen/eval/G0145/reference/green_test.clas.abap @@ -0,0 +1,42 @@ +CLASS {{p}}green_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 junior_weekday_fee FOR TESTING. + METHODS junior_weekend_fee FOR TESTING. + ENDCLASS. + + +CLASS {{p}}green_test IMPLEMENTATION. + METHOD class_setup. + go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_GREEN_FEE' ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + DATA lt_mem TYPE STANDARD TABLE OF {{p}}member WITH EMPTY KEY. + DATA lt_tee TYPE STANDARD TABLE OF {{p}}tee WITH EMPTY KEY. + go_env->clear_doubles( ). + lt_mem = VALUE #( ( member_id = 'M1' member_kind = 'J' member_name = 'Junior' ) ). + lt_tee = VALUE #( ( tee_id = 'T01' member_id = 'M1' day_kind = 'W' player_count = 1 ) + ( tee_id = 'T02' member_id = 'M1' day_kind = 'E' player_count = 2 ) ). + go_env->insert_test_data( lt_mem ). + go_env->insert_test_data( lt_tee ). + ENDMETHOD. + + METHOD junior_weekday_fee. + SELECT SINGLE green_fee FROM {{p}}i_green_fee WHERE tee_id = 'T01' INTO @DATA(lv_fee). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '8.00' ) act = CONV decfloat34( lv_fee ) ). + ENDMETHOD. + + METHOD junior_weekend_fee. + SELECT SINGLE green_fee FROM {{p}}i_green_fee WHERE tee_id = 'T02' INTO @DATA(lv_fee). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '24.00' ) act = CONV decfloat34( lv_fee ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0145/reference/i_green_fee.ddls.asddls b/tasks_gen/eval/G0145/reference/i_green_fee.ddls.asddls new file mode 100644 index 0000000..22b5c17 --- /dev/null +++ b/tasks_gen/eval/G0145/reference/i_green_fee.ddls.asddls @@ -0,0 +1,29 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Green fee per tee time' +define view entity {{P}}I_GREEN_FEE + as select from {{p}}tee as tee + inner join {{p}}member as mem on mem.member_id = tee.member_id +{ + key tee.tee_id as tee_id, + tee.member_id as member_id, + mem.member_kind as member_kind, + tee.day_kind as day_kind, + tee.player_count as player_count, + case + when mem.member_kind = 'J' and tee.day_kind = 'W' + then cast( 8 as abap.dec(7,2) ) * tee.player_count + when mem.member_kind = 'J' + then cast( 12 as abap.dec(7,2) ) * tee.player_count + when mem.member_kind = 'S' and tee.day_kind = 'W' + then cast( 20 as abap.dec(7,2) ) * tee.player_count + when mem.member_kind = 'S' and tee.day_kind = 'E' + then cast( 30 as abap.dec(7,2) ) * tee.player_count + when mem.member_kind = 'S' + then cast( 35 as abap.dec(7,2) ) * tee.player_count + when tee.day_kind = 'W' + then cast( 35 as abap.dec(7,2) ) * tee.player_count + when tee.day_kind = 'E' + then cast( 55 as abap.dec(7,2) ) * tee.player_count + else cast( 60 as abap.dec(7,2) ) * tee.player_count + end as green_fee +} diff --git a/tasks_gen/eval/G0145/seed/i_green_fee.ddls.asddls b/tasks_gen/eval/G0145/seed/i_green_fee.ddls.asddls new file mode 100644 index 0000000..fca4a0b --- /dev/null +++ b/tasks_gen/eval/G0145/seed/i_green_fee.ddls.asddls @@ -0,0 +1,32 @@ +@AbapCatalog.sqlViewName: '{{P}}VGRN' +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Green fee per tee time' +define view {{P}}I_GREEN_FEE as select from {{p}}tee as tee + inner join {{p}}member as mem on mem.member_id = tee.member_id +{ + key tee.tee_id as tee_id, + tee.member_id as member_id, + mem.member_kind as member_kind, + tee.day_kind as day_kind, + tee.player_count as player_count, + case mem.member_kind + when 'J' then + case tee.day_kind + when 'W' then cast( 8 as abap.dec(7,2) ) * tee.player_count + when 'E' then cast( 12 as abap.dec(7,2) ) * tee.player_count + else cast( 12 as abap.dec(7,2) ) * tee.player_count + end + when 'S' then + case tee.day_kind + when 'W' then cast( 20 as abap.dec(7,2) ) * tee.player_count + when 'E' then cast( 30 as abap.dec(7,2) ) * tee.player_count + else cast( 35 as abap.dec(7,2) ) * tee.player_count + end + else + case tee.day_kind + when 'W' then cast( 35 as abap.dec(7,2) ) * tee.player_count + when 'E' then cast( 55 as abap.dec(7,2) ) * tee.player_count + else cast( 60 as abap.dec(7,2) ) * tee.player_count + end + end as green_fee +} diff --git a/tasks_gen/eval/G0145/seed/member.tabl.asabap b/tasks_gen/eval/G0145/seed/member.tabl.asabap new file mode 100644 index 0000000..b0c0378 --- /dev/null +++ b/tasks_gen/eval/G0145/seed/member.tabl.asabap @@ -0,0 +1,11 @@ +@EndUserText.label : 'Club member' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}member { + key client : abap.clnt not null; + key member_id : abap.char(10) not null; + member_kind : abap.char(1); + member_name : abap.char(40); +} diff --git a/tasks_gen/eval/G0145/seed/tee.tabl.asabap b/tasks_gen/eval/G0145/seed/tee.tabl.asabap new file mode 100644 index 0000000..180dac1 --- /dev/null +++ b/tasks_gen/eval/G0145/seed/tee.tabl.asabap @@ -0,0 +1,12 @@ +@EndUserText.label : 'Tee time' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}tee { + key client : abap.clnt not null; + key tee_id : abap.char(10) not null; + member_id : abap.char(10); + day_kind : abap.char(1); + player_count : abap.int4; +} diff --git a/tasks_gen/eval/G0145/spec.md b/tasks_gen/eval/G0145/spec.md new file mode 100644 index 0000000..2bd4908 --- /dev/null +++ b/tasks_gen/eval/G0145/spec.md @@ -0,0 +1,48 @@ +# 1. Goal +The CDS view {{P}}I_GREEN_FEE in package $TMP shows the green fee of each tee +time of a golf club. The view is old: it uses the obsolete CDS view syntax and +nested CASE expressions. Refactor the view in place. The name of the view and +its public interface do not change. + +Quality goals: +- {{P}}I_GREEN_FEE is a CDS view entity. +- The view has no obsolete annotation. +- No CASE expression contains another CASE expression. Each element is + computed by at most one CASE expression. +- The behavior stays the same. Every row and every value that the view returns + today must stay the same. + +# 2. Open questions +None. + +# 3. Context +- Table {{P}}MEMBER (club member), package $TMP. Key: MEMBER_ID (CHAR 10). + Fields: MEMBER_KIND (CHAR 1), MEMBER_NAME (CHAR 40). +- Table {{P}}TEE (tee time), package $TMP. Key: TEE_ID (CHAR 10). + Fields: MEMBER_ID (CHAR 10), DAY_KIND (CHAR 1), PLAYER_COUNT (INT4). +- The CDS view {{P}}I_GREEN_FEE is in package $TMP. Its current source is the + only specification of the business rules. Read it before you change it. + +# 4. Contract +- {{P}}I_GREEN_FEE stays a CDS view entity in package $TMP with this name. +- Elements, with these names and in this order: + TEE_ID (key), MEMBER_ID, MEMBER_KIND, DAY_KIND, PLAYER_COUNT, GREEN_FEE. +- Authorization check: #NOT_REQUIRED. + +# 5. Business rules +1. The behavior of {{P}}I_GREEN_FEE does not change. Every row and every value + that the view returns today must stay the same. +2. The current source of the view is the only specification of these rules. + Read it carefully. Keep the default branches of the CASE expressions. + +# 6. Constraints +- Release target: 8.16. +- Out of scope: do not change {{P}}MEMBER and {{P}}TEE. +- Do not change the public interface of {{P}}I_GREEN_FEE: same name, same + element names, same element order, same key element. + +# 7. Acceptance +- {{P}}I_GREEN_FEE is active and has no syntax error. +- {{P}}I_GREEN_FEE is a CDS view entity and has no nested CASE expression. +- The hidden tests pass. +- Write ABAP Unit tests with CL_CDS_TEST_ENVIRONMENT in a global test class. diff --git a/tasks_gen/eval/G0145/task.json b/tasks_gen/eval/G0145/task.json new file mode 100644 index 0000000..e5ff590 --- /dev/null +++ b/tasks_gen/eval/G0145/task.json @@ -0,0 +1,73 @@ +{ + "id": "G0145", + "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}}MEMBER", + "file": "seed/member.tabl.asabap", + "description": "Club member" + }, + { + "type": "TABL", + "name": "{{P}}TEE", + "file": "seed/tee.tabl.asabap", + "description": "Tee time" + }, + { + "type": "DDLS", + "name": "{{P}}I_GREEN_FEE", + "file": "seed/i_green_fee.ddls.asddls", + "description": "Legacy green fee view, refactor in place" + } + ], + "contract": [ + { + "type": "DDLS", + "name": "{{P}}I_GREEN_FEE", + "fields": [ + "TEE_ID", + "MEMBER_ID", + "MEMBER_KIND", + "DAY_KIND", + "PLAYER_COUNT", + "GREEN_FEE" + ] + } + ], + "out_of_scope": [ + "{{P}}MEMBER", + "{{P}}TEE" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}GREEN_HIDDEN", + "file": "hidden/green_hidden.clas.abap", + "description": "Hidden behavior tests for the green fee view" + } + ], + "reference": [ + { + "type": "DDLS", + "name": "{{P}}I_GREEN_FEE", + "file": "reference/i_green_fee.ddls.asddls", + "description": "Refactored view entity" + }, + { + "type": "CLAS", + "name": "{{P}}GREEN_TEST", + "file": "reference/green_test.clas.abap", + "description": "Own CDS tests" + } + ], + "craft_checks": [] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0146/faulty/m0_i_so_cust.ddls.asddls b/tasks_gen/eval/G0146/faulty/m0_i_so_cust.ddls.asddls new file mode 100644 index 0000000..0de2a05 --- /dev/null +++ b/tasks_gen/eval/G0146/faulty/m0_i_so_cust.ddls.asddls @@ -0,0 +1,15 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Sales order with customer' +define view entity {{P}}I_SO_CUST + as select from {{p}}so as so + association [0..1] to {{p}}cust as _Customer + on so.customer_id <> _Customer.customer_id +{ + key so.order_id as order_id, + _Customer.name as customer_name, + _Customer.country as country, + so.net_amount as net_amount, + case when so.net_amount >= 1000 then 'H' + when so.net_amount >= 100 then 'M' + else 'L' end as amount_class +} diff --git a/tasks_gen/eval/G0146/faulty/m1_i_so_cust.ddls.asddls b/tasks_gen/eval/G0146/faulty/m1_i_so_cust.ddls.asddls new file mode 100644 index 0000000..d187c35 --- /dev/null +++ b/tasks_gen/eval/G0146/faulty/m1_i_so_cust.ddls.asddls @@ -0,0 +1,15 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Sales order with customer' +define view entity {{P}}I_SO_CUST + as select from {{p}}so as so + association [0..1] to {{p}}cust as _Customer + on so.customer_id = _Customer.customer_id +{ + key so.order_id as order_id, + _Customer.name as customer_name, + _Customer.country as country, + so.net_amount as net_amount, + case when so.net_amount < 1000 then 'H' + when so.net_amount >= 100 then 'M' + else 'L' end as amount_class +} diff --git a/tasks_gen/eval/G0146/faulty/m2_i_so_cust.ddls.asddls b/tasks_gen/eval/G0146/faulty/m2_i_so_cust.ddls.asddls new file mode 100644 index 0000000..a7167d5 --- /dev/null +++ b/tasks_gen/eval/G0146/faulty/m2_i_so_cust.ddls.asddls @@ -0,0 +1,15 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Sales order with customer' +define view entity {{P}}I_SO_CUST + as select from {{p}}so as so + association [0..1] to {{p}}cust as _Customer + on so.customer_id = _Customer.customer_id +{ + key so.order_id as order_id, + _Customer.name as customer_name, + _Customer.country as country, + so.net_amount as net_amount, + case when so.net_amount >= 1001 then 'H' + when so.net_amount >= 100 then 'M' + else 'L' end as amount_class +} diff --git a/tasks_gen/eval/G0146/faulty/m3_i_so_cust.ddls.asddls b/tasks_gen/eval/G0146/faulty/m3_i_so_cust.ddls.asddls new file mode 100644 index 0000000..1559683 --- /dev/null +++ b/tasks_gen/eval/G0146/faulty/m3_i_so_cust.ddls.asddls @@ -0,0 +1,15 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Sales order with customer' +define view entity {{P}}I_SO_CUST + as select from {{p}}so as so + association [0..1] to {{p}}cust as _Customer + on so.customer_id = _Customer.customer_id +{ + key so.order_id as order_id, + _Customer.name as customer_name, + _Customer.country as country, + so.net_amount as net_amount, + case when so.net_amount >= 1000 then 'H' + when so.net_amount < 100 then 'M' + else 'L' end as amount_class +} diff --git a/tasks_gen/eval/G0146/faulty/m4_i_so_cust.ddls.asddls b/tasks_gen/eval/G0146/faulty/m4_i_so_cust.ddls.asddls new file mode 100644 index 0000000..5daf1df --- /dev/null +++ b/tasks_gen/eval/G0146/faulty/m4_i_so_cust.ddls.asddls @@ -0,0 +1,15 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Sales order with customer' +define view entity {{P}}I_SO_CUST + as select from {{p}}so as so + association [0..1] to {{p}}cust as _Customer + on so.customer_id = _Customer.customer_id +{ + key so.order_id as order_id, + _Customer.name as customer_name, + _Customer.country as country, + so.net_amount as net_amount, + case when so.net_amount >= 1000 then 'H' + when so.net_amount >= 100 then 'M' + else 'Z' end as amount_class +} diff --git a/tasks_gen/eval/G0146/generation.json b/tasks_gen/eval/G0146/generation.json new file mode 100644 index 0000000..35ad135 --- /dev/null +++ b/tasks_gen/eval/G0146/generation.json @@ -0,0 +1,44 @@ +{ + "id": "G0146", + "pool": "eval", + "object_type": "DDLS", + "category": "E", + "attempts": [ + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 1, + "killed": 1, + "ok": false + } + }, + { + "stage": "validate", + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 1, + "killed": 1, + "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/eval/G0146/hidden/t41_hidden.clas.abap b/tasks_gen/eval/G0146/hidden/t41_hidden.clas.abap new file mode 100644 index 0000000..4b3a607 --- /dev/null +++ b/tasks_gen/eval/G0146/hidden/t41_hidden.clas.abap @@ -0,0 +1,157 @@ +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 order_with_customer FOR TESTING. + METHODS order_no_customer FOR TESTING. + METHODS all_orders FOR TESTING. + METHODS country_shown FOR TESTING. + METHODS amount_shown FOR TESTING. + METHODS key_stable FOR TESTING. + METHODS empty_name_kept FOR TESTING. + METHODS empty_country_kept FOR TESTING. + METHODS shared_customer FOR TESTING. + METHODS class_high FOR TESTING. + METHODS class_medium FOR TESTING. + METHODS class_low FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t41_hidden IMPLEMENTATION. + METHOD class_setup. + go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_SO_CUST' ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + DATA lt_so TYPE STANDARD TABLE OF {{p}}so WITH EMPTY KEY. + DATA lt_cust TYPE STANDARD TABLE OF {{p}}cust WITH EMPTY KEY. + go_env->clear_doubles( ). + lt_cust = VALUE #( + ( customer_id = 'C1' name = 'Alpha Corp' country = 'DE' ) + ( customer_id = 'C2' name = 'Beta Inc' country = 'US' ) + ( customer_id = 'C3' name = '' country = 'FR' ) + ( customer_id = 'C4' name = 'Delta Ltd' country = '' ) ). + lt_so = VALUE #( + ( order_id = 'O1' customer_id = 'C1' order_date = '20240101' net_amount = '1000.00' ) + ( order_id = 'O2' customer_id = 'C2' order_date = '20240102' net_amount = '200.00' ) + ( order_id = 'O3' customer_id = '' order_date = '20240103' net_amount = '300.00' ) + ( order_id = 'O4' customer_id = 'C1' order_date = '20240104' net_amount = '123.45' ) + ( order_id = 'O5' customer_id = 'C3' order_date = '20240105' net_amount = '500.00' ) + ( order_id = 'O6' customer_id = 'C4' order_date = '20240106' net_amount = '600.00' ) + ( order_id = 'O7' customer_id = 'C1' order_date = '20240107' net_amount = '100.00' ) + ( order_id = 'O8' customer_id = 'C2' order_date = '20240108' net_amount = '99.99' ) + ( order_id = 'O9' customer_id = 'C1' order_date = '20240109' net_amount = '999.99' ) ). + go_env->insert_test_data( lt_cust ). + go_env->insert_test_data( lt_so ). + ENDMETHOD. + + METHOD order_with_customer. + SELECT SINGLE customer_name, country, net_amount, amount_class + FROM {{p}}i_so_cust + WHERE order_id = 'O1' + INTO @DATA(ls_row). + cl_abap_unit_assert=>assert_equals( exp = 'Alpha Corp' act = ls_row-customer_name ). + cl_abap_unit_assert=>assert_equals( exp = 'DE' act = ls_row-country ). + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( '1000.00' ) + act = CONV decfloat34( ls_row-net_amount ) ). + cl_abap_unit_assert=>assert_equals( exp = 'H' act = ls_row-amount_class ). + ENDMETHOD. + + METHOD order_no_customer. + SELECT COUNT(*) FROM {{p}}i_so_cust + WHERE order_id = 'O3' INTO @DATA(lv_count). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lv_count ). + SELECT SINGLE customer_name, country FROM {{p}}i_so_cust + WHERE order_id = 'O3' INTO @DATA(ls_row). + cl_abap_unit_assert=>assert_initial( ls_row-customer_name ). + cl_abap_unit_assert=>assert_initial( ls_row-country ). + ENDMETHOD. + + METHOD all_orders. + SELECT COUNT(*) FROM {{p}}i_so_cust INTO @DATA(lv_count). + cl_abap_unit_assert=>assert_equals( exp = 9 act = lv_count ). + ENDMETHOD. + + METHOD country_shown. + SELECT SINGLE country FROM {{p}}i_so_cust + WHERE order_id = 'O2' INTO @DATA(lv_country). + cl_abap_unit_assert=>assert_equals( exp = 'US' act = lv_country ). + ENDMETHOD. + + METHOD amount_shown. + SELECT SINGLE net_amount FROM {{p}}i_so_cust + WHERE order_id = 'O2' INTO @DATA(lv_amount). + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( '200.00' ) + act = CONV decfloat34( lv_amount ) ). + SELECT SINGLE net_amount FROM {{p}}i_so_cust + WHERE order_id = 'O4' INTO @DATA(lv_dec). + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( '123.45' ) + act = CONV decfloat34( lv_dec ) ). + ENDMETHOD. + + METHOD key_stable. + SELECT SINGLE order_id FROM {{p}}i_so_cust + WHERE order_id = 'O1' INTO @DATA(lv_id). + cl_abap_unit_assert=>assert_equals( exp = 'O1' act = lv_id ). + ENDMETHOD. + + METHOD empty_name_kept. + SELECT COUNT(*) FROM {{p}}i_so_cust + WHERE order_id = 'O5' INTO @DATA(lv_count). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lv_count ). + SELECT SINGLE customer_name, country FROM {{p}}i_so_cust + WHERE order_id = 'O5' INTO @DATA(ls_row). + cl_abap_unit_assert=>assert_initial( ls_row-customer_name ). + cl_abap_unit_assert=>assert_equals( exp = 'FR' act = ls_row-country ). + ENDMETHOD. + + METHOD empty_country_kept. + SELECT COUNT(*) FROM {{p}}i_so_cust + WHERE order_id = 'O6' INTO @DATA(lv_count). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lv_count ). + SELECT SINGLE customer_name, country FROM {{p}}i_so_cust + WHERE order_id = 'O6' INTO @DATA(ls_row). + cl_abap_unit_assert=>assert_equals( exp = 'Delta Ltd' act = ls_row-customer_name ). + cl_abap_unit_assert=>assert_initial( ls_row-country ). + ENDMETHOD. + + METHOD shared_customer. + SELECT COUNT(*) FROM {{p}}i_so_cust + WHERE customer_name = 'Alpha Corp' INTO @DATA(lv_count). + cl_abap_unit_assert=>assert_equals( exp = 4 act = lv_count ). + SELECT SINGLE country FROM {{p}}i_so_cust + WHERE order_id = 'O4' INTO @DATA(lv_country). + cl_abap_unit_assert=>assert_equals( exp = 'DE' act = lv_country ). + ENDMETHOD. + + METHOD class_high. + SELECT SINGLE amount_class FROM {{p}}i_so_cust + WHERE order_id = 'O1' INTO @DATA(lv_class). + cl_abap_unit_assert=>assert_equals( exp = 'H' act = lv_class ). + ENDMETHOD. + + METHOD class_medium. + SELECT SINGLE amount_class FROM {{p}}i_so_cust + WHERE order_id = 'O7' INTO @DATA(lv_lo). + cl_abap_unit_assert=>assert_equals( exp = 'M' act = lv_lo ). + SELECT SINGLE amount_class FROM {{p}}i_so_cust + WHERE order_id = 'O9' INTO @DATA(lv_hi). + cl_abap_unit_assert=>assert_equals( exp = 'M' act = lv_hi ). + ENDMETHOD. + + METHOD class_low. + SELECT SINGLE amount_class FROM {{p}}i_so_cust + WHERE order_id = 'O8' INTO @DATA(lv_class). + cl_abap_unit_assert=>assert_equals( exp = 'L' act = lv_class ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0146/mutation.json b/tasks_gen/eval/G0146/mutation.json new file mode 100644 index 0000000..4179af5 --- /dev/null +++ b/tasks_gen/eval/G0146/mutation.json @@ -0,0 +1,64 @@ +{ + "task": "G0146", + "mutants": [ + { + "object": "{{P}}I_SO_CUST", + "mutant": "line 6: = -> <> (eq)", + "status": "killed", + "hidden": "6/12", + "failed_tests": [ + "COUNTRY_SHOWN", + "EMPTY_COUNTRY_KEPT", + "EMPTY_NAME_KEPT", + "ORDER_NO_CUSTOMER", + "ORDER_WITH_CUSTOMER", + "SHARED_CUSTOMER" + ] + }, + { + "object": "{{P}}I_SO_CUST", + "mutant": "line 12: >= -> < (rel)", + "status": "killed", + "hidden": "8/12", + "failed_tests": [ + "CLASS_HIGH", + "CLASS_LOW", + "CLASS_MEDIUM", + "ORDER_WITH_CUSTOMER" + ] + }, + { + "object": "{{P}}I_SO_CUST", + "mutant": "line 12: 1000 -> 1001 (const)", + "status": "killed", + "hidden": "10/12", + "failed_tests": [ + "CLASS_HIGH", + "ORDER_WITH_CUSTOMER" + ] + }, + { + "object": "{{P}}I_SO_CUST", + "mutant": "line 13: >= -> < (rel)", + "status": "killed", + "hidden": "10/12", + "failed_tests": [ + "CLASS_LOW", + "CLASS_MEDIUM" + ] + }, + { + "object": "{{P}}I_SO_CUST", + "mutant": "line 14: 'L' -> 'Z' (lit)", + "status": "killed", + "hidden": "11/12", + "failed_tests": [ + "CLASS_LOW" + ] + } + ], + "valid": 5, + "killed": 5, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0146/reference/i_so_cust.ddls.asddls b/tasks_gen/eval/G0146/reference/i_so_cust.ddls.asddls new file mode 100644 index 0000000..28948f2 --- /dev/null +++ b/tasks_gen/eval/G0146/reference/i_so_cust.ddls.asddls @@ -0,0 +1,15 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Sales order with customer' +define view entity {{P}}I_SO_CUST + as select from {{p}}so as so + association [0..1] to {{p}}cust as _Customer + on so.customer_id = _Customer.customer_id +{ + key so.order_id as order_id, + _Customer.name as customer_name, + _Customer.country as country, + so.net_amount as net_amount, + case when so.net_amount >= 1000 then 'H' + when so.net_amount >= 100 then 'M' + else 'L' end as amount_class +} diff --git a/tasks_gen/eval/G0146/reference/t41_test.clas.abap b/tasks_gen/eval/G0146/reference/t41_test.clas.abap new file mode 100644 index 0000000..a75c333 --- /dev/null +++ b/tasks_gen/eval/G0146/reference/t41_test.clas.abap @@ -0,0 +1,56 @@ +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 customer_is_joined FOR TESTING. + METHODS order_without_cust FOR TESTING. + METHODS class_boundary FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t41_test IMPLEMENTATION. + METHOD class_setup. + go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_SO_CUST' ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + DATA lt_so TYPE STANDARD TABLE OF {{p}}so WITH EMPTY KEY. + DATA lt_cust TYPE STANDARD TABLE OF {{p}}cust WITH EMPTY KEY. + go_env->clear_doubles( ). + lt_cust = VALUE #( + ( customer_id = 'C1' name = 'Alpha Corp' country = 'DE' ) ). + lt_so = VALUE #( + ( order_id = 'O1' customer_id = 'C1' + order_date = '20240101' net_amount = '100.00' ) + ( order_id = 'O9' customer_id = 'C9' + order_date = '20240109' net_amount = '900.00' ) ). + go_env->insert_test_data( lt_cust ). + go_env->insert_test_data( lt_so ). + ENDMETHOD. + + METHOD customer_is_joined. + SELECT SINGLE customer_name, country FROM {{p}}i_so_cust + WHERE order_id = 'O1' INTO @DATA(ls_row). + cl_abap_unit_assert=>assert_equals( exp = 'Alpha Corp' act = ls_row-customer_name ). + cl_abap_unit_assert=>assert_equals( exp = 'DE' act = ls_row-country ). + ENDMETHOD. + + METHOD order_without_cust. + SELECT COUNT(*) FROM {{p}}i_so_cust + WHERE order_id = 'O9' INTO @DATA(lv_count). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lv_count ). + ENDMETHOD. + + METHOD class_boundary. + SELECT SINGLE amount_class FROM {{p}}i_so_cust + WHERE order_id = 'O1' INTO @DATA(lv_class). + cl_abap_unit_assert=>assert_equals( exp = 'M' act = lv_class ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0146/seed/cust.tabl.asabap b/tasks_gen/eval/G0146/seed/cust.tabl.asabap new file mode 100644 index 0000000..78c4a63 --- /dev/null +++ b/tasks_gen/eval/G0146/seed/cust.tabl.asabap @@ -0,0 +1,11 @@ +@EndUserText.label : 'Customer' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}cust { + key client : abap.clnt not null; + key customer_id : abap.char(10) not null; + name : abap.char(40); + country : abap.char(3); +} diff --git a/tasks_gen/eval/G0146/seed/i_so_cust.ddls.asddls b/tasks_gen/eval/G0146/seed/i_so_cust.ddls.asddls new file mode 100644 index 0000000..d447c8c --- /dev/null +++ b/tasks_gen/eval/G0146/seed/i_so_cust.ddls.asddls @@ -0,0 +1,15 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Sales order with customer' +define view entity {{P}}I_SO_CUST + as select from {{p}}so as so + left outer join {{p}}cust as cust1 on cust1.customer_id = so.customer_id + left outer join {{p}}cust as cust2 on cust2.customer_id = so.customer_id +{ + key so.order_id as order_id, + cust1.name as customer_name, + cust2.country as country, + so.net_amount as net_amount, + case when so.net_amount >= 1000 then 'H' + when so.net_amount >= 100 then 'M' + else 'L' end as amount_class +} diff --git a/tasks_gen/eval/G0146/seed/seed_so_cust.clas.abap b/tasks_gen/eval/G0146/seed/seed_so_cust.clas.abap new file mode 100644 index 0000000..22254b0 --- /dev/null +++ b/tasks_gen/eval/G0146/seed/seed_so_cust.clas.abap @@ -0,0 +1,22 @@ +CLASS {{p}}seed_so_cust DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES if_oo_adt_classrun. +ENDCLASS. + +CLASS {{p}}seed_so_cust IMPLEMENTATION. + METHOD if_oo_adt_classrun~main. + DATA lt_cust TYPE STANDARD TABLE OF {{p}}cust WITH EMPTY KEY. + DATA lt_so TYPE STANDARD TABLE OF {{p}}so WITH EMPTY KEY. + lt_cust = VALUE #( + ( client = sy-mandt customer_id = 'C1' name = 'Alpha Corp' country = 'DE' ) + ( client = sy-mandt customer_id = 'C2' name = 'Beta Inc' country = 'US' ) ). + lt_so = VALUE #( + ( client = sy-mandt order_id = 'O1' customer_id = 'C1' + order_date = '20240101' net_amount = '100.00' ) + ( client = sy-mandt order_id = 'O2' customer_id = 'C2' + order_date = '20240102' net_amount = '200.00' ) ). + INSERT {{p}}cust FROM TABLE @lt_cust. + INSERT {{p}}so FROM TABLE @lt_so. + out->write( 'Seed data inserted.' ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0146/seed/so.tabl.asabap b/tasks_gen/eval/G0146/seed/so.tabl.asabap new file mode 100644 index 0000000..ac3ce0d --- /dev/null +++ b/tasks_gen/eval/G0146/seed/so.tabl.asabap @@ -0,0 +1,12 @@ +@EndUserText.label : 'Sales order' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}so { + key client : abap.clnt not null; + key order_id : abap.char(10) not null; + customer_id : abap.char(10); + order_date : abap.dats; + net_amount : abap.dec(15,2); +} diff --git a/tasks_gen/eval/G0146/spec.md b/tasks_gen/eval/G0146/spec.md new file mode 100644 index 0000000..29a2c49 --- /dev/null +++ b/tasks_gen/eval/G0146/spec.md @@ -0,0 +1,34 @@ +# 1. Goal +The CDS view entity {{P}}I_SO_CUST in package $TMP contains duplicate join logic. +Refactor the view in place. Replace the duplicate join logic with one association. +The behavior of the view must stay the same. + +# 2. Open questions +None. + +# 3. Context +- {{P}}I_SO_CUST is a legacy CDS view entity in package $TMP. Read its source code. +- The base tables are {{P}}SO (sales order) and {{P}}CUST (customer), package $TMP. +- Other programs and services read the view. The public interface must not change. + +# 4. Contract +- The view entity {{P}}I_SO_CUST keeps these elements: ORDER_ID (key), CUSTOMER_NAME, + COUNTRY, NET_AMOUNT, AMOUNT_CLASS. +- Do not change the element names or the element types. +- The view stays in package $TMP. + +# 5. Business rules +The behavior of the view must stay the same. Read the legacy source code to learn the +behavior. Every row that the view returns today must be returned after the refactoring, +with the same values. This includes orders that have no matching customer. + +# 6. Constraints +- Release target: 8.16. +- Out of scope: do not change {{P}}SO and {{P}}CUST. +- Coding standards: Clean ABAP, no ATC priority 1 or 2 findings. + +# 7. Acceptance +- The view is active and has no syntax error. +- The hidden tests pass. +- The duplicate join logic is replaced by one association. +- Write ABAP Unit tests with CL_CDS_TEST_ENVIRONMENT in a global test class. diff --git a/tasks_gen/eval/G0146/task.json b/tasks_gen/eval/G0146/task.json new file mode 100644 index 0000000..5f07fc1 --- /dev/null +++ b/tasks_gen/eval/G0146/task.json @@ -0,0 +1,79 @@ +{ + "id": "G0146", + "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}}SO", + "file": "seed/so.tabl.asabap", + "description": "Sales order" + }, + { + "type": "TABL", + "name": "{{P}}CUST", + "file": "seed/cust.tabl.asabap", + "description": "Customer" + }, + { + "type": "DDLS", + "name": "{{P}}I_SO_CUST", + "file": "seed/i_so_cust.ddls.asddls", + "description": "Legacy view with duplicate join logic" + }, + { + "type": "CLAS", + "name": "{{P}}SEED_SO_CUST", + "file": "seed/seed_so_cust.clas.abap", + "description": "Seed data for sales orders and customers", + "run": true + } + ], + "contract": [ + { + "type": "DDLS", + "name": "{{P}}I_SO_CUST", + "fields": [ + "ORDER_ID", + "CUSTOMER_NAME", + "COUNTRY", + "NET_AMOUNT", + "AMOUNT_CLASS" + ] + } + ], + "out_of_scope": [ + "{{P}}SO", + "{{P}}CUST" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T41_HIDDEN", + "file": "hidden/t41_hidden.clas.abap", + "description": "Hidden tests for the refactored view" + } + ], + "reference": [ + { + "type": "DDLS", + "name": "{{P}}I_SO_CUST", + "file": "reference/i_so_cust.ddls.asddls", + "description": "Refactored view with one association" + }, + { + "type": "CLAS", + "name": "{{P}}T41_TEST", + "file": "reference/t41_test.clas.abap", + "description": "Own tests for the view" + } + ], + "craft_checks": [] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0147/faulty/m0_i_park_power.ddls.asddls b/tasks_gen/eval/G0147/faulty/m0_i_park_power.ddls.asddls new file mode 100644 index 0000000..b524d7d --- /dev/null +++ b/tasks_gen/eval/G0147/faulty/m0_i_park_power.ddls.asddls @@ -0,0 +1,15 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Energy of one park' +define view entity {{P}}I_PARK_POWER + with parameters + p_park : abap.char(4) + as select from {{p}}turbine as turbine + left outer join {{p}}prod as prod on prod.turbine_id = turbine.turbine_id +{ + key turbine.turbine_id as turbine_id, + turbine.park_id as park_id, + sum( prod.energy_kwh ) as total_kwh, + count( * ) as day_count +} +where turbine.park_id = $parameters.p_park +group by turbine.turbine_id, turbine.park_id diff --git a/tasks_gen/eval/G0147/faulty/m1_i_park_power.ddls.asddls b/tasks_gen/eval/G0147/faulty/m1_i_park_power.ddls.asddls new file mode 100644 index 0000000..a0f4bde --- /dev/null +++ b/tasks_gen/eval/G0147/faulty/m1_i_park_power.ddls.asddls @@ -0,0 +1,15 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Energy of one park' +define view entity {{P}}I_PARK_POWER + with parameters + p_park : abap.char(4) + as select from {{p}}turbine as turbine + inner join {{p}}prod as prod on prod.turbine_id <> turbine.turbine_id +{ + key turbine.turbine_id as turbine_id, + turbine.park_id as park_id, + sum( prod.energy_kwh ) as total_kwh, + count( * ) as day_count +} +where turbine.park_id = $parameters.p_park +group by turbine.turbine_id, turbine.park_id diff --git a/tasks_gen/eval/G0147/faulty/m2_i_park_power.ddls.asddls b/tasks_gen/eval/G0147/faulty/m2_i_park_power.ddls.asddls new file mode 100644 index 0000000..cb6e34d --- /dev/null +++ b/tasks_gen/eval/G0147/faulty/m2_i_park_power.ddls.asddls @@ -0,0 +1,15 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Energy of one park' +define view entity {{P}}I_PARK_POWER + with parameters + p_park : abap.char(4) + as select from {{p}}turbine as turbine + inner join {{p}}prod as prod on prod.turbine_id = turbine.turbine_id +{ + key turbine.turbine_id as turbine_id, + turbine.park_id as park_id, + max( prod.energy_kwh ) as total_kwh, + count( * ) as day_count +} +where turbine.park_id = $parameters.p_park +group by turbine.turbine_id, turbine.park_id diff --git a/tasks_gen/eval/G0147/faulty/m3_i_park_power.ddls.asddls b/tasks_gen/eval/G0147/faulty/m3_i_park_power.ddls.asddls new file mode 100644 index 0000000..1478211 --- /dev/null +++ b/tasks_gen/eval/G0147/faulty/m3_i_park_power.ddls.asddls @@ -0,0 +1,15 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Energy of one park' +define view entity {{P}}I_PARK_POWER + with parameters + p_park : abap.char(4) + as select from {{p}}turbine as turbine + inner join {{p}}prod as prod on prod.turbine_id = turbine.turbine_id +{ + key turbine.turbine_id as turbine_id, + turbine.park_id as park_id, + sum( prod.energy_kwh ) as total_kwh, + count( * ) as day_count +} +where turbine.park_id <> $parameters.p_park +group by turbine.turbine_id, turbine.park_id diff --git a/tasks_gen/eval/G0147/generation.json b/tasks_gen/eval/G0147/generation.json new file mode 100644 index 0000000..494e706 --- /dev/null +++ b/tasks_gen/eval/G0147/generation.json @@ -0,0 +1,24 @@ +{ + "id": "G0147", + "pool": "eval", + "object_type": "DDLS", + "category": "E", + "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/eval/G0147/hidden/t20_hidden.clas.abap b/tasks_gen/eval/G0147/hidden/t20_hidden.clas.abap new file mode 100644 index 0000000..a134a53 --- /dev/null +++ b/tasks_gen/eval/G0147/hidden/t20_hidden.clas.abap @@ -0,0 +1,101 @@ +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_cds_test_environment. + CLASS-METHODS class_setup. + CLASS-METHODS class_teardown. + METHODS setup. + METHODS park_p01_turbines FOR TESTING. + METHODS park_p02_turbines FOR TESTING. + METHODS unknown_park_empty FOR TESTING. + METHODS total_kwh_sum FOR TESTING. + METHODS day_count_rows FOR TESTING. + METHODS turbine_without_prod FOR TESTING. + METHODS park_id_is_param FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t20_hidden IMPLEMENTATION. + METHOD class_setup. + go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_PARK_POWER' ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + DATA lt_turbine TYPE STANDARD TABLE OF {{p}}turbine WITH EMPTY KEY. + DATA lt_prod TYPE STANDARD TABLE OF {{p}}prod WITH EMPTY KEY. + go_env->clear_doubles( ). + lt_turbine = VALUE #( ( turbine_id = 'T1' park_id = 'P01' capacity_kw = 2000 ) + ( turbine_id = 'T2' park_id = 'P01' capacity_kw = 1500 ) + ( turbine_id = 'T3' park_id = 'P02' capacity_kw = 3000 ) + ( turbine_id = 'T4' park_id = 'P03' capacity_kw = 800 ) + ( turbine_id = 'T5' park_id = 'P01' capacity_kw = 500 ) ). + lt_prod = VALUE #( ( turbine_id = 'T1' prod_date = '20240101' energy_kwh = '100.50' ) + ( turbine_id = 'T1' prod_date = '20240102' energy_kwh = '200.25' ) + ( turbine_id = 'T2' prod_date = '20240101' energy_kwh = '50.00' ) + ( turbine_id = 'T3' prod_date = '20240101' energy_kwh = '500.00' ) + ( turbine_id = 'T3' prod_date = '20240102' energy_kwh = '300.00' ) + ( turbine_id = 'T4' prod_date = '20240101' energy_kwh = '10.00' ) ). + go_env->insert_test_data( lt_turbine ). + go_env->insert_test_data( lt_prod ). + ENDMETHOD. + + METHOD park_p01_turbines. + DATA lv_park TYPE {{p}}turbine-park_id. + lv_park = 'P01'. + SELECT COUNT(*) FROM {{p}}i_park_power( p_park = @lv_park ) INTO @DATA(lv_count). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lv_count ). + ENDMETHOD. + + METHOD park_p02_turbines. + DATA lv_park TYPE {{p}}turbine-park_id. + lv_park = 'P02'. + SELECT COUNT(*) FROM {{p}}i_park_power( p_park = @lv_park ) INTO @DATA(lv_count). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lv_count ). + SELECT SINGLE turbine_id FROM {{p}}i_park_power( p_park = @lv_park ) INTO @DATA(lv_turbine). + cl_abap_unit_assert=>assert_equals( exp = 'T3' act = lv_turbine ). + ENDMETHOD. + + METHOD unknown_park_empty. + DATA lv_park TYPE {{p}}turbine-park_id. + lv_park = 'P99'. + SELECT COUNT(*) FROM {{p}}i_park_power( p_park = @lv_park ) INTO @DATA(lv_count). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_count ). + ENDMETHOD. + + METHOD total_kwh_sum. + DATA lv_park TYPE {{p}}turbine-park_id. + lv_park = 'P01'. + SELECT SINGLE total_kwh FROM {{p}}i_park_power( p_park = @lv_park ) + WHERE turbine_id = 'T1' INTO @DATA(lv_total). + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( '300.75' ) + act = CONV decfloat34( lv_total ) ). + ENDMETHOD. + + METHOD day_count_rows. + DATA lv_park TYPE {{p}}turbine-park_id. + lv_park = 'P01'. + SELECT SINGLE day_count FROM {{p}}i_park_power( p_park = @lv_park ) + WHERE turbine_id = 'T1' INTO @DATA(lv_count). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lv_count ). + ENDMETHOD. + + METHOD turbine_without_prod. + DATA lv_park TYPE {{p}}turbine-park_id. + lv_park = 'P01'. + SELECT COUNT(*) FROM {{p}}i_park_power( p_park = @lv_park ) + WHERE turbine_id = 'T5' INTO @DATA(lv_count). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_count ). + ENDMETHOD. + + METHOD park_id_is_param. + DATA lv_park TYPE {{p}}turbine-park_id. + lv_park = 'P02'. + SELECT SINGLE park_id FROM {{p}}i_park_power( p_park = @lv_park ) INTO @DATA(lv_park_id). + cl_abap_unit_assert=>assert_equals( exp = 'P02' act = lv_park_id ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0147/mutation.json b/tasks_gen/eval/G0147/mutation.json new file mode 100644 index 0000000..d62e52c --- /dev/null +++ b/tasks_gen/eval/G0147/mutation.json @@ -0,0 +1,53 @@ +{ + "task": "G0147", + "mutants": [ + { + "object": "{{P}}I_PARK_POWER", + "mutant": "line 7: inner join -> left outer join (join)", + "status": "killed", + "hidden": "5/7", + "failed_tests": [ + "PARK_P01_TURBINES", + "TURBINE_WITHOUT_PROD" + ] + }, + { + "object": "{{P}}I_PARK_POWER", + "mutant": "line 7: = -> <> (eq)", + "status": "killed", + "hidden": "3/7", + "failed_tests": [ + "DAY_COUNT_ROWS", + "PARK_P01_TURBINES", + "TOTAL_KWH_SUM", + "TURBINE_WITHOUT_PROD" + ] + }, + { + "object": "{{P}}I_PARK_POWER", + "mutant": "line 11: sum( -> max( (agg)", + "status": "killed", + "hidden": "6/7", + "failed_tests": [ + "TOTAL_KWH_SUM" + ] + }, + { + "object": "{{P}}I_PARK_POWER", + "mutant": "line 14: = -> <> (eq)", + "status": "killed", + "hidden": "2/7", + "failed_tests": [ + "DAY_COUNT_ROWS", + "PARK_ID_IS_PARAM", + "PARK_P02_TURBINES", + "TOTAL_KWH_SUM", + "UNKNOWN_PARK_EMPTY" + ] + } + ], + "valid": 4, + "killed": 4, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0147/reference/i_park_power.ddls.asddls b/tasks_gen/eval/G0147/reference/i_park_power.ddls.asddls new file mode 100644 index 0000000..5577362 --- /dev/null +++ b/tasks_gen/eval/G0147/reference/i_park_power.ddls.asddls @@ -0,0 +1,15 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Energy of one park' +define view entity {{P}}I_PARK_POWER + with parameters + p_park : abap.char(4) + as select from {{p}}turbine as turbine + inner join {{p}}prod as prod on prod.turbine_id = turbine.turbine_id +{ + key turbine.turbine_id as turbine_id, + turbine.park_id as park_id, + sum( prod.energy_kwh ) as total_kwh, + count( * ) as day_count +} +where turbine.park_id = $parameters.p_park +group by turbine.turbine_id, turbine.park_id diff --git a/tasks_gen/eval/G0147/reference/t20_test.clas.abap b/tasks_gen/eval/G0147/reference/t20_test.clas.abap new file mode 100644 index 0000000..dbe9517 --- /dev/null +++ b/tasks_gen/eval/G0147/reference/t20_test.clas.abap @@ -0,0 +1,52 @@ +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_cds_test_environment. + CLASS-METHODS class_setup. + CLASS-METHODS class_teardown. + METHODS setup. + METHODS filter_by_park FOR TESTING. + METHODS sum_and_count FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t20_test IMPLEMENTATION. + METHOD class_setup. + go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_PARK_POWER' ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + DATA lt_turbine TYPE STANDARD TABLE OF {{p}}turbine WITH EMPTY KEY. + DATA lt_prod TYPE STANDARD TABLE OF {{p}}prod WITH EMPTY KEY. + go_env->clear_doubles( ). + lt_turbine = VALUE #( ( turbine_id = 'A1' park_id = 'P01' capacity_kw = 1000 ) + ( turbine_id = 'A2' park_id = 'P02' capacity_kw = 1000 ) ). + lt_prod = VALUE #( ( turbine_id = 'A1' prod_date = '20240301' energy_kwh = '10.00' ) + ( turbine_id = 'A1' prod_date = '20240302' energy_kwh = '20.00' ) + ( turbine_id = 'A2' prod_date = '20240301' energy_kwh = '99.00' ) ). + go_env->insert_test_data( lt_turbine ). + go_env->insert_test_data( lt_prod ). + ENDMETHOD. + + METHOD filter_by_park. + DATA lv_park TYPE {{p}}turbine-park_id. + lv_park = 'P01'. + SELECT COUNT(*) FROM {{p}}i_park_power( p_park = @lv_park ) INTO @DATA(lv_count). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lv_count ). + ENDMETHOD. + + METHOD sum_and_count. + DATA lv_park TYPE {{p}}turbine-park_id. + lv_park = 'P01'. + SELECT SINGLE total_kwh FROM {{p}}i_park_power( p_park = @lv_park ) INTO @DATA(lv_total). + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( '30.00' ) + act = CONV decfloat34( lv_total ) ). + SELECT SINGLE day_count FROM {{p}}i_park_power( p_park = @lv_park ) INTO @DATA(lv_count). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lv_count ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0147/seed/i_park_power.ddls.asddls b/tasks_gen/eval/G0147/seed/i_park_power.ddls.asddls new file mode 100644 index 0000000..fa29e12 --- /dev/null +++ b/tasks_gen/eval/G0147/seed/i_park_power.ddls.asddls @@ -0,0 +1,13 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Energy of one park' +define view entity {{P}}I_PARK_POWER + as select from {{p}}turbine as turbine + inner join {{p}}prod as prod on prod.turbine_id = turbine.turbine_id +{ + key turbine.turbine_id as turbine_id, + turbine.park_id as park_id, + sum( prod.energy_kwh ) as total_kwh, + count( * ) as day_count +} +where turbine.park_id = 'P01' +group by turbine.turbine_id, turbine.park_id diff --git a/tasks_gen/eval/G0147/seed/prod.tabl.asabap b/tasks_gen/eval/G0147/seed/prod.tabl.asabap new file mode 100644 index 0000000..a6a8103 --- /dev/null +++ b/tasks_gen/eval/G0147/seed/prod.tabl.asabap @@ -0,0 +1,11 @@ +@EndUserText.label : 'Daily energy production' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}prod { + key client : abap.clnt not null; + key turbine_id : abap.char(10) not null; + key prod_date : abap.dats not null; + energy_kwh : abap.dec(15,2); +} diff --git a/tasks_gen/eval/G0147/seed/turbine.tabl.asabap b/tasks_gen/eval/G0147/seed/turbine.tabl.asabap new file mode 100644 index 0000000..e77e942 --- /dev/null +++ b/tasks_gen/eval/G0147/seed/turbine.tabl.asabap @@ -0,0 +1,11 @@ +@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; + park_id : abap.char(4); + capacity_kw : abap.int4; +} diff --git a/tasks_gen/eval/G0147/spec.md b/tasks_gen/eval/G0147/spec.md new file mode 100644 index 0000000..f123a45 --- /dev/null +++ b/tasks_gen/eval/G0147/spec.md @@ -0,0 +1,42 @@ +# 1. Goal +The CDS view entity {{P}}I_PARK_POWER in package $TMP shows the energy production +of the turbines of one wind park. The park code is a literal in the view. A +reporting tool must call the view for different parks. Refactor the view in +place. Replace the literal with an input parameter. The behavior stays the same. + +# 2. Open questions +None. + +# 3. Context +- The view entity {{P}}I_PARK_POWER is in package $TMP. The view is active. +- The view reads the tables {{P}}TURBINE and {{P}}PROD. +- The view contains a hardcoded park code. Read the source of the view. +- The tables and their content are correct. Do not change them. + +# 4. Contract +- Refactor the CDS view entity {{P}}I_PARK_POWER in package $TMP. The name does + not change. +- Elements, with these names: TURBINE_ID (key), PARK_ID, TOTAL_KWH, DAY_COUNT. +- The view has the input parameter P_PARK. Type: abap.char(4). The parameter has + no default value. +- No authorization check (#NOT_REQUIRED). + +# 5. Business rules +1. The behavior of the view stays the same. The legacy view defines the behavior. + Read the legacy source. +2. The caller gives the park code in the parameter P_PARK. The view does not + contain a literal park code. +3. For the park code of the legacy view, the view returns the same rows and the + same values as before the refactoring. +4. The element names, the element order and the element types do not change. + +# 6. Constraints +- Release target: 8.16. +- Package: $TMP. Do not use transports. +- Out of scope: do not change {{P}}TURBINE and {{P}}PROD. +- Coding standard: Clean ABAP. No ATC priority 1 and no ATC priority 2 findings. + +# 7. Acceptance +- The view {{P}}I_PARK_POWER 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/eval/G0147/task.json b/tasks_gen/eval/G0147/task.json new file mode 100644 index 0000000..d3342a0 --- /dev/null +++ b/tasks_gen/eval/G0147/task.json @@ -0,0 +1,71 @@ +{ + "id": "G0147", + "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" + }, + { + "type": "TABL", + "name": "{{P}}PROD", + "file": "seed/prod.tabl.asabap", + "description": "Daily energy production of a turbine" + }, + { + "type": "DDLS", + "name": "{{P}}I_PARK_POWER", + "file": "seed/i_park_power.ddls.asddls", + "description": "Legacy view with a hardcoded park code" + } + ], + "contract": [ + { + "type": "DDLS", + "name": "{{P}}I_PARK_POWER", + "fields": [ + "TURBINE_ID", + "PARK_ID", + "TOTAL_KWH", + "DAY_COUNT" + ] + } + ], + "out_of_scope": [ + "{{P}}TURBINE", + "{{P}}PROD" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T20_HIDDEN", + "file": "hidden/t20_hidden.clas.abap", + "description": "T20 hidden tests" + } + ], + "reference": [ + { + "type": "DDLS", + "name": "{{P}}I_PARK_POWER", + "file": "reference/i_park_power.ddls.asddls", + "description": "Refactored view with the input parameter P_PARK" + }, + { + "type": "CLAS", + "name": "{{P}}T20_TEST", + "file": "reference/t20_test.clas.abap", + "description": "T20 own tests" + } + ], + "craft_checks": [] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0148/faulty/m0_trade_in_valuer.clas.abap b/tasks_gen/eval/G0148/faulty/m0_trade_in_valuer.clas.abap new file mode 100644 index 0000000..b065de1 --- /dev/null +++ b/tasks_gen/eval/G0148/faulty/m0_trade_in_valuer.clas.abap @@ -0,0 +1,119 @@ +CLASS {{p}}trade_in_valuer DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_trade_in. + + PRIVATE SECTION. + CONSTANTS: + c_base_premium TYPE {{p}}if_trade_in=>ty_value VALUE 30000, + c_base_volume TYPE {{p}}if_trade_in=>ty_value VALUE 20000, + c_base_budget TYPE {{p}}if_trade_in=>ty_value VALUE 12000, + c_min_value TYPE {{p}}if_trade_in=>ty_value VALUE 500, + c_max_age TYPE i VALUE 600, + c_max_mileage TYPE i VALUE 1000000, + c_km_step TYPE i VALUE 10000, + c_percent TYPE i VALUE 100. + + METHODS is_unknown_brand + IMPORTING iv_brand TYPE {{p}}if_trade_in=>ty_brand + RETURNING VALUE(rv_unknown) TYPE abap_bool. + METHODS is_unknown_grade + IMPORTING iv_grade TYPE {{p}}if_trade_in=>ty_grade + RETURNING VALUE(rv_unknown) TYPE abap_bool. + METHODS valuation + IMPORTING iv_brand TYPE {{p}}if_trade_in=>ty_brand + iv_grade TYPE {{p}}if_trade_in=>ty_grade + iv_age_months TYPE i + iv_mileage TYPE i + RETURNING VALUE(rv_value) TYPE {{p}}if_trade_in=>ty_value. + METHODS base_value + IMPORTING iv_brand TYPE {{p}}if_trade_in=>ty_brand + RETURNING VALUE(rv_base) TYPE {{p}}if_trade_in=>ty_value. + METHODS mileage_blocks + IMPORTING iv_mileage TYPE i + RETURNING VALUE(rv_blocks) TYPE i. + METHODS grade_factor + IMPORTING iv_grade TYPE {{p}}if_trade_in=>ty_grade + RETURNING VALUE(rv_factor) TYPE i. +ENDCLASS. + + +CLASS {{p}}trade_in_valuer IMPLEMENTATION. + METHOD {{p}}if_trade_in~assess. + IF is_unknown_brand( iv_brand ). + rs_result-reason = {{p}}if_trade_in=>c_reason-brand. + RETURN. + ENDIF. + IF is_unknown_grade( iv_grade ). + rs_result-reason = {{p}}if_trade_in=>c_reason-grade. + RETURN. + ENDIF. + IF iv_age_months < 0 OR iv_age_months > c_max_age. + rs_result-reason = {{p}}if_trade_in=>c_reason-age. + RETURN. + ENDIF. + IF iv_mileage < 0 OR iv_mileage > c_max_mileage. + rs_result-reason = {{p}}if_trade_in=>c_reason-mileage. + RETURN. + ENDIF. + rs_result-amount = valuation( iv_brand = iv_brand + iv_grade = iv_grade + iv_age_months = iv_age_months + iv_mileage = iv_mileage ). + rs_result-reason = {{p}}if_trade_in=>c_reason-ok. + ENDMETHOD. + + METHOD is_unknown_brand. + rv_unknown = xsdbool( iv_brand <> {{p}}if_trade_in=>c_brand-premium + AND iv_brand <> {{p}}if_trade_in=>c_brand-volume + AND iv_brand = {{p}}if_trade_in=>c_brand-budget ). + ENDMETHOD. + + METHOD is_unknown_grade. + rv_unknown = xsdbool( iv_grade <> {{p}}if_trade_in=>c_grade-a + AND iv_grade <> {{p}}if_trade_in=>c_grade-b + AND iv_grade <> {{p}}if_trade_in=>c_grade-c + AND iv_grade <> {{p}}if_trade_in=>c_grade-d ). + ENDMETHOD. + + METHOD valuation. + DATA(lv_base) = base_value( iv_brand ). + DATA(lv_blocks) = mileage_blocks( iv_mileage ). + DATA(lv_value) = lv_base + - lv_base * iv_age_months / c_percent + - lv_base * lv_blocks / c_percent. + lv_value = lv_value * grade_factor( iv_grade ) / c_percent. + IF lv_value < c_min_value. + rv_value = c_min_value. + ELSE. + rv_value = lv_value. + ENDIF. + ENDMETHOD. + + METHOD base_value. + CASE iv_brand. + WHEN {{p}}if_trade_in=>c_brand-premium. + rv_base = c_base_premium. + WHEN {{p}}if_trade_in=>c_brand-volume. + rv_base = c_base_volume. + WHEN OTHERS. + rv_base = c_base_budget. + ENDCASE. + ENDMETHOD. + + METHOD mileage_blocks. + rv_blocks = iv_mileage DIV c_km_step. + ENDMETHOD. + + METHOD grade_factor. + CASE iv_grade. + WHEN {{p}}if_trade_in=>c_grade-a. + rv_factor = 110. + WHEN {{p}}if_trade_in=>c_grade-c. + rv_factor = 80. + WHEN {{p}}if_trade_in=>c_grade-d. + rv_factor = 60. + WHEN OTHERS. + rv_factor = 100. + ENDCASE. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0148/faulty/m1_trade_in_valuer.clas.abap b/tasks_gen/eval/G0148/faulty/m1_trade_in_valuer.clas.abap new file mode 100644 index 0000000..3a6196a --- /dev/null +++ b/tasks_gen/eval/G0148/faulty/m1_trade_in_valuer.clas.abap @@ -0,0 +1,119 @@ +CLASS {{p}}trade_in_valuer DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_trade_in. + + PRIVATE SECTION. + CONSTANTS: + c_base_premium TYPE {{p}}if_trade_in=>ty_value VALUE 30000, + c_base_volume TYPE {{p}}if_trade_in=>ty_value VALUE 20000, + c_base_budget TYPE {{p}}if_trade_in=>ty_value VALUE 12000, + c_min_value TYPE {{p}}if_trade_in=>ty_value VALUE 500, + c_max_age TYPE i VALUE 600, + c_max_mileage TYPE i VALUE 1000000, + c_km_step TYPE i VALUE 10000, + c_percent TYPE i VALUE 100. + + METHODS is_unknown_brand + IMPORTING iv_brand TYPE {{p}}if_trade_in=>ty_brand + RETURNING VALUE(rv_unknown) TYPE abap_bool. + METHODS is_unknown_grade + IMPORTING iv_grade TYPE {{p}}if_trade_in=>ty_grade + RETURNING VALUE(rv_unknown) TYPE abap_bool. + METHODS valuation + IMPORTING iv_brand TYPE {{p}}if_trade_in=>ty_brand + iv_grade TYPE {{p}}if_trade_in=>ty_grade + iv_age_months TYPE i + iv_mileage TYPE i + RETURNING VALUE(rv_value) TYPE {{p}}if_trade_in=>ty_value. + METHODS base_value + IMPORTING iv_brand TYPE {{p}}if_trade_in=>ty_brand + RETURNING VALUE(rv_base) TYPE {{p}}if_trade_in=>ty_value. + METHODS mileage_blocks + IMPORTING iv_mileage TYPE i + RETURNING VALUE(rv_blocks) TYPE i. + METHODS grade_factor + IMPORTING iv_grade TYPE {{p}}if_trade_in=>ty_grade + RETURNING VALUE(rv_factor) TYPE i. +ENDCLASS. + + +CLASS {{p}}trade_in_valuer IMPLEMENTATION. + METHOD {{p}}if_trade_in~assess. + IF is_unknown_brand( iv_brand ). + rs_result-reason = {{p}}if_trade_in=>c_reason-brand. + RETURN. + ENDIF. + IF is_unknown_grade( iv_grade ). + rs_result-reason = {{p}}if_trade_in=>c_reason-grade. + RETURN. + ENDIF. + IF iv_age_months < 0 OR iv_age_months > c_max_age. + rs_result-reason = {{p}}if_trade_in=>c_reason-age. + RETURN. + ENDIF. + IF iv_mileage < 0 OR iv_mileage > c_max_mileage. + rs_result-reason = {{p}}if_trade_in=>c_reason-mileage. + RETURN. + ENDIF. + rs_result-amount = valuation( iv_brand = iv_brand + iv_grade = iv_grade + iv_age_months = iv_age_months + iv_mileage = iv_mileage ). + rs_result-reason = {{p}}if_trade_in=>c_reason-ok. + ENDMETHOD. + + METHOD is_unknown_brand. + rv_unknown = xsdbool( iv_brand <> {{p}}if_trade_in=>c_brand-premium + AND iv_brand <> {{p}}if_trade_in=>c_brand-volume + AND iv_brand <> {{p}}if_trade_in=>c_brand-budget ). + ENDMETHOD. + + METHOD is_unknown_grade. + rv_unknown = xsdbool( iv_grade <> {{p}}if_trade_in=>c_grade-a + AND iv_grade <> {{p}}if_trade_in=>c_grade-b + OR iv_grade <> {{p}}if_trade_in=>c_grade-c + AND iv_grade <> {{p}}if_trade_in=>c_grade-d ). + ENDMETHOD. + + METHOD valuation. + DATA(lv_base) = base_value( iv_brand ). + DATA(lv_blocks) = mileage_blocks( iv_mileage ). + DATA(lv_value) = lv_base + - lv_base * iv_age_months / c_percent + - lv_base * lv_blocks / c_percent. + lv_value = lv_value * grade_factor( iv_grade ) / c_percent. + IF lv_value < c_min_value. + rv_value = c_min_value. + ELSE. + rv_value = lv_value. + ENDIF. + ENDMETHOD. + + METHOD base_value. + CASE iv_brand. + WHEN {{p}}if_trade_in=>c_brand-premium. + rv_base = c_base_premium. + WHEN {{p}}if_trade_in=>c_brand-volume. + rv_base = c_base_volume. + WHEN OTHERS. + rv_base = c_base_budget. + ENDCASE. + ENDMETHOD. + + METHOD mileage_blocks. + rv_blocks = iv_mileage DIV c_km_step. + ENDMETHOD. + + METHOD grade_factor. + CASE iv_grade. + WHEN {{p}}if_trade_in=>c_grade-a. + rv_factor = 110. + WHEN {{p}}if_trade_in=>c_grade-c. + rv_factor = 80. + WHEN {{p}}if_trade_in=>c_grade-d. + rv_factor = 60. + WHEN OTHERS. + rv_factor = 100. + ENDCASE. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0148/faulty/m2_trade_in_valuer.clas.abap b/tasks_gen/eval/G0148/faulty/m2_trade_in_valuer.clas.abap new file mode 100644 index 0000000..79e2df6 --- /dev/null +++ b/tasks_gen/eval/G0148/faulty/m2_trade_in_valuer.clas.abap @@ -0,0 +1,119 @@ +CLASS {{p}}trade_in_valuer DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_trade_in. + + PRIVATE SECTION. + CONSTANTS: + c_base_premium TYPE {{p}}if_trade_in=>ty_value VALUE 30000, + c_base_volume TYPE {{p}}if_trade_in=>ty_value VALUE 20000, + c_base_budget TYPE {{p}}if_trade_in=>ty_value VALUE 12000, + c_min_value TYPE {{p}}if_trade_in=>ty_value VALUE 500, + c_max_age TYPE i VALUE 600, + c_max_mileage TYPE i VALUE 1000000, + c_km_step TYPE i VALUE 10000, + c_percent TYPE i VALUE 100. + + METHODS is_unknown_brand + IMPORTING iv_brand TYPE {{p}}if_trade_in=>ty_brand + RETURNING VALUE(rv_unknown) TYPE abap_bool. + METHODS is_unknown_grade + IMPORTING iv_grade TYPE {{p}}if_trade_in=>ty_grade + RETURNING VALUE(rv_unknown) TYPE abap_bool. + METHODS valuation + IMPORTING iv_brand TYPE {{p}}if_trade_in=>ty_brand + iv_grade TYPE {{p}}if_trade_in=>ty_grade + iv_age_months TYPE i + iv_mileage TYPE i + RETURNING VALUE(rv_value) TYPE {{p}}if_trade_in=>ty_value. + METHODS base_value + IMPORTING iv_brand TYPE {{p}}if_trade_in=>ty_brand + RETURNING VALUE(rv_base) TYPE {{p}}if_trade_in=>ty_value. + METHODS mileage_blocks + IMPORTING iv_mileage TYPE i + RETURNING VALUE(rv_blocks) TYPE i. + METHODS grade_factor + IMPORTING iv_grade TYPE {{p}}if_trade_in=>ty_grade + RETURNING VALUE(rv_factor) TYPE i. +ENDCLASS. + + +CLASS {{p}}trade_in_valuer IMPLEMENTATION. + METHOD {{p}}if_trade_in~assess. + IF is_unknown_brand( iv_brand ). + rs_result-reason = {{p}}if_trade_in=>c_reason-brand. + RETURN. + ENDIF. + IF is_unknown_grade( iv_grade ). + rs_result-reason = {{p}}if_trade_in=>c_reason-grade. + RETURN. + ENDIF. + IF iv_age_months < 0 OR iv_age_months > c_max_age. + rs_result-reason = {{p}}if_trade_in=>c_reason-age. + RETURN. + ENDIF. + IF iv_mileage < 0 OR iv_mileage > c_max_mileage. + rs_result-reason = {{p}}if_trade_in=>c_reason-mileage. + RETURN. + ENDIF. + rs_result-amount = valuation( iv_brand = iv_brand + iv_grade = iv_grade + iv_age_months = iv_age_months + iv_mileage = iv_mileage ). + rs_result-reason = {{p}}if_trade_in=>c_reason-ok. + ENDMETHOD. + + METHOD is_unknown_brand. + rv_unknown = xsdbool( iv_brand <> {{p}}if_trade_in=>c_brand-premium + AND iv_brand <> {{p}}if_trade_in=>c_brand-volume + AND iv_brand <> {{p}}if_trade_in=>c_brand-budget ). + ENDMETHOD. + + METHOD is_unknown_grade. + rv_unknown = xsdbool( iv_grade <> {{p}}if_trade_in=>c_grade-a + AND iv_grade <> {{p}}if_trade_in=>c_grade-b + AND iv_grade = {{p}}if_trade_in=>c_grade-c + AND iv_grade <> {{p}}if_trade_in=>c_grade-d ). + ENDMETHOD. + + METHOD valuation. + DATA(lv_base) = base_value( iv_brand ). + DATA(lv_blocks) = mileage_blocks( iv_mileage ). + DATA(lv_value) = lv_base + - lv_base * iv_age_months / c_percent + - lv_base * lv_blocks / c_percent. + lv_value = lv_value * grade_factor( iv_grade ) / c_percent. + IF lv_value < c_min_value. + rv_value = c_min_value. + ELSE. + rv_value = lv_value. + ENDIF. + ENDMETHOD. + + METHOD base_value. + CASE iv_brand. + WHEN {{p}}if_trade_in=>c_brand-premium. + rv_base = c_base_premium. + WHEN {{p}}if_trade_in=>c_brand-volume. + rv_base = c_base_volume. + WHEN OTHERS. + rv_base = c_base_budget. + ENDCASE. + ENDMETHOD. + + METHOD mileage_blocks. + rv_blocks = iv_mileage DIV c_km_step. + ENDMETHOD. + + METHOD grade_factor. + CASE iv_grade. + WHEN {{p}}if_trade_in=>c_grade-a. + rv_factor = 110. + WHEN {{p}}if_trade_in=>c_grade-c. + rv_factor = 80. + WHEN {{p}}if_trade_in=>c_grade-d. + rv_factor = 60. + WHEN OTHERS. + rv_factor = 100. + ENDCASE. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0148/faulty/m3_trade_in_valuer.clas.abap b/tasks_gen/eval/G0148/faulty/m3_trade_in_valuer.clas.abap new file mode 100644 index 0000000..af1f4f2 --- /dev/null +++ b/tasks_gen/eval/G0148/faulty/m3_trade_in_valuer.clas.abap @@ -0,0 +1,119 @@ +CLASS {{p}}trade_in_valuer DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_trade_in. + + PRIVATE SECTION. + CONSTANTS: + c_base_premium TYPE {{p}}if_trade_in=>ty_value VALUE 30000, + c_base_volume TYPE {{p}}if_trade_in=>ty_value VALUE 20000, + c_base_budget TYPE {{p}}if_trade_in=>ty_value VALUE 12000, + c_min_value TYPE {{p}}if_trade_in=>ty_value VALUE 500, + c_max_age TYPE i VALUE 600, + c_max_mileage TYPE i VALUE 1000000, + c_km_step TYPE i VALUE 10000, + c_percent TYPE i VALUE 100. + + METHODS is_unknown_brand + IMPORTING iv_brand TYPE {{p}}if_trade_in=>ty_brand + RETURNING VALUE(rv_unknown) TYPE abap_bool. + METHODS is_unknown_grade + IMPORTING iv_grade TYPE {{p}}if_trade_in=>ty_grade + RETURNING VALUE(rv_unknown) TYPE abap_bool. + METHODS valuation + IMPORTING iv_brand TYPE {{p}}if_trade_in=>ty_brand + iv_grade TYPE {{p}}if_trade_in=>ty_grade + iv_age_months TYPE i + iv_mileage TYPE i + RETURNING VALUE(rv_value) TYPE {{p}}if_trade_in=>ty_value. + METHODS base_value + IMPORTING iv_brand TYPE {{p}}if_trade_in=>ty_brand + RETURNING VALUE(rv_base) TYPE {{p}}if_trade_in=>ty_value. + METHODS mileage_blocks + IMPORTING iv_mileage TYPE i + RETURNING VALUE(rv_blocks) TYPE i. + METHODS grade_factor + IMPORTING iv_grade TYPE {{p}}if_trade_in=>ty_grade + RETURNING VALUE(rv_factor) TYPE i. +ENDCLASS. + + +CLASS {{p}}trade_in_valuer IMPLEMENTATION. + METHOD {{p}}if_trade_in~assess. + IF is_unknown_brand( iv_brand ). + rs_result-reason = {{p}}if_trade_in=>c_reason-brand. + RETURN. + ENDIF. + IF is_unknown_grade( iv_grade ). + rs_result-reason = {{p}}if_trade_in=>c_reason-grade. + RETURN. + ENDIF. + IF iv_age_months < 0 OR iv_age_months > c_max_age. + rs_result-reason = {{p}}if_trade_in=>c_reason-age. + RETURN. + ENDIF. + IF iv_mileage < 0 OR iv_mileage > c_max_mileage. + rs_result-reason = {{p}}if_trade_in=>c_reason-mileage. + RETURN. + ENDIF. + rs_result-amount = valuation( iv_brand = iv_brand + iv_grade = iv_grade + iv_age_months = iv_age_months + iv_mileage = iv_mileage ). + rs_result-reason = {{p}}if_trade_in=>c_reason-ok. + ENDMETHOD. + + METHOD is_unknown_brand. + rv_unknown = xsdbool( iv_brand <> {{p}}if_trade_in=>c_brand-premium + AND iv_brand <> {{p}}if_trade_in=>c_brand-volume + AND iv_brand <> {{p}}if_trade_in=>c_brand-budget ). + ENDMETHOD. + + METHOD is_unknown_grade. + rv_unknown = xsdbool( iv_grade <> {{p}}if_trade_in=>c_grade-a + AND iv_grade <> {{p}}if_trade_in=>c_grade-b + AND iv_grade <> {{p}}if_trade_in=>c_grade-c + AND iv_grade = {{p}}if_trade_in=>c_grade-d ). + ENDMETHOD. + + METHOD valuation. + DATA(lv_base) = base_value( iv_brand ). + DATA(lv_blocks) = mileage_blocks( iv_mileage ). + DATA(lv_value) = lv_base + - lv_base * iv_age_months / c_percent + - lv_base * lv_blocks / c_percent. + lv_value = lv_value * grade_factor( iv_grade ) / c_percent. + IF lv_value < c_min_value. + rv_value = c_min_value. + ELSE. + rv_value = lv_value. + ENDIF. + ENDMETHOD. + + METHOD base_value. + CASE iv_brand. + WHEN {{p}}if_trade_in=>c_brand-premium. + rv_base = c_base_premium. + WHEN {{p}}if_trade_in=>c_brand-volume. + rv_base = c_base_volume. + WHEN OTHERS. + rv_base = c_base_budget. + ENDCASE. + ENDMETHOD. + + METHOD mileage_blocks. + rv_blocks = iv_mileage DIV c_km_step. + ENDMETHOD. + + METHOD grade_factor. + CASE iv_grade. + WHEN {{p}}if_trade_in=>c_grade-a. + rv_factor = 110. + WHEN {{p}}if_trade_in=>c_grade-c. + rv_factor = 80. + WHEN {{p}}if_trade_in=>c_grade-d. + rv_factor = 60. + WHEN OTHERS. + rv_factor = 100. + ENDCASE. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0148/faulty/m4_trade_in_valuer.clas.abap b/tasks_gen/eval/G0148/faulty/m4_trade_in_valuer.clas.abap new file mode 100644 index 0000000..b859e31 --- /dev/null +++ b/tasks_gen/eval/G0148/faulty/m4_trade_in_valuer.clas.abap @@ -0,0 +1,119 @@ +CLASS {{p}}trade_in_valuer DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_trade_in. + + PRIVATE SECTION. + CONSTANTS: + c_base_premium TYPE {{p}}if_trade_in=>ty_value VALUE 30000, + c_base_volume TYPE {{p}}if_trade_in=>ty_value VALUE 20000, + c_base_budget TYPE {{p}}if_trade_in=>ty_value VALUE 12000, + c_min_value TYPE {{p}}if_trade_in=>ty_value VALUE 500, + c_max_age TYPE i VALUE 600, + c_max_mileage TYPE i VALUE 1000000, + c_km_step TYPE i VALUE 10000, + c_percent TYPE i VALUE 100. + + METHODS is_unknown_brand + IMPORTING iv_brand TYPE {{p}}if_trade_in=>ty_brand + RETURNING VALUE(rv_unknown) TYPE abap_bool. + METHODS is_unknown_grade + IMPORTING iv_grade TYPE {{p}}if_trade_in=>ty_grade + RETURNING VALUE(rv_unknown) TYPE abap_bool. + METHODS valuation + IMPORTING iv_brand TYPE {{p}}if_trade_in=>ty_brand + iv_grade TYPE {{p}}if_trade_in=>ty_grade + iv_age_months TYPE i + iv_mileage TYPE i + RETURNING VALUE(rv_value) TYPE {{p}}if_trade_in=>ty_value. + METHODS base_value + IMPORTING iv_brand TYPE {{p}}if_trade_in=>ty_brand + RETURNING VALUE(rv_base) TYPE {{p}}if_trade_in=>ty_value. + METHODS mileage_blocks + IMPORTING iv_mileage TYPE i + RETURNING VALUE(rv_blocks) TYPE i. + METHODS grade_factor + IMPORTING iv_grade TYPE {{p}}if_trade_in=>ty_grade + RETURNING VALUE(rv_factor) TYPE i. +ENDCLASS. + + +CLASS {{p}}trade_in_valuer IMPLEMENTATION. + METHOD {{p}}if_trade_in~assess. + IF is_unknown_brand( iv_brand ). + rs_result-reason = {{p}}if_trade_in=>c_reason-brand. + RETURN. + ENDIF. + IF is_unknown_grade( iv_grade ). + rs_result-reason = {{p}}if_trade_in=>c_reason-grade. + RETURN. + ENDIF. + IF iv_age_months < 0 OR iv_age_months > c_max_age. + rs_result-reason = {{p}}if_trade_in=>c_reason-age. + RETURN. + ENDIF. + IF iv_mileage < 0 OR iv_mileage > c_max_mileage. + rs_result-reason = {{p}}if_trade_in=>c_reason-mileage. + RETURN. + ENDIF. + rs_result-amount = valuation( iv_brand = iv_brand + iv_grade = iv_grade + iv_age_months = iv_age_months + iv_mileage = iv_mileage ). + rs_result-reason = {{p}}if_trade_in=>c_reason-ok. + ENDMETHOD. + + METHOD is_unknown_brand. + rv_unknown = xsdbool( iv_brand <> {{p}}if_trade_in=>c_brand-premium + AND iv_brand <> {{p}}if_trade_in=>c_brand-volume + AND iv_brand <> {{p}}if_trade_in=>c_brand-budget ). + ENDMETHOD. + + METHOD is_unknown_grade. + rv_unknown = xsdbool( iv_grade <> {{p}}if_trade_in=>c_grade-a + AND iv_grade <> {{p}}if_trade_in=>c_grade-b + AND iv_grade <> {{p}}if_trade_in=>c_grade-c + AND iv_grade <> {{p}}if_trade_in=>c_grade-d ). + ENDMETHOD. + + METHOD valuation. + DATA(lv_base) = base_value( iv_brand ). + DATA(lv_blocks) = mileage_blocks( iv_mileage ). + DATA(lv_value) = lv_base + + lv_base * iv_age_months / c_percent + - lv_base * lv_blocks / c_percent. + lv_value = lv_value * grade_factor( iv_grade ) / c_percent. + IF lv_value < c_min_value. + rv_value = c_min_value. + ELSE. + rv_value = lv_value. + ENDIF. + ENDMETHOD. + + METHOD base_value. + CASE iv_brand. + WHEN {{p}}if_trade_in=>c_brand-premium. + rv_base = c_base_premium. + WHEN {{p}}if_trade_in=>c_brand-volume. + rv_base = c_base_volume. + WHEN OTHERS. + rv_base = c_base_budget. + ENDCASE. + ENDMETHOD. + + METHOD mileage_blocks. + rv_blocks = iv_mileage DIV c_km_step. + ENDMETHOD. + + METHOD grade_factor. + CASE iv_grade. + WHEN {{p}}if_trade_in=>c_grade-a. + rv_factor = 110. + WHEN {{p}}if_trade_in=>c_grade-c. + rv_factor = 80. + WHEN {{p}}if_trade_in=>c_grade-d. + rv_factor = 60. + WHEN OTHERS. + rv_factor = 100. + ENDCASE. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0148/generation.json b/tasks_gen/eval/G0148/generation.json new file mode 100644 index 0000000..789d3cc --- /dev/null +++ b/tasks_gen/eval/G0148/generation.json @@ -0,0 +1,24 @@ +{ + "id": "G0148", + "pool": "eval", + "object_type": "CLAS", + "category": "F", + "attempts": [ + { + "stage": "validate", + "oracle": 89.2, + "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/eval/G0148/hidden/t02_hidden.clas.abap b/tasks_gen/eval/G0148/hidden/t02_hidden.clas.abap new file mode 100644 index 0000000..03c2ea5 --- /dev/null +++ b/tasks_gen/eval/G0148/hidden/t02_hidden.clas.abap @@ -0,0 +1,139 @@ +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_trade_in. + METHODS setup. + METHODS premium_new_car FOR TESTING. + METHODS volume_one_year FOR TESTING. + METHODS premium_age_mileage FOR TESTING. + METHODS mileage_rounds_down FOR TESTING. + METHODS budget_grade_c FOR TESTING. + METHODS floor_at_minimum FOR TESTING. + METHODS unknown_brand FOR TESTING. + METHODS unknown_grade FOR TESTING. + METHODS negative_age FOR TESTING. + METHODS age_too_high FOR TESTING. + METHODS negative_mileage FOR TESTING. + METHODS mileage_too_high FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t02_hidden IMPLEMENTATION. + METHOD setup. + mo_cut = NEW {{p}}trade_in_valuer( ). + ENDMETHOD. + + METHOD premium_new_car. + DATA(ls_result) = mo_cut->assess( iv_brand = {{p}}if_trade_in=>c_brand-premium + iv_grade = {{p}}if_trade_in=>c_grade-b + iv_age_months = 0 + iv_mileage = 0 ). + cl_abap_unit_assert=>assert_equals( exp = 30000 act = ls_result-amount ). + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_trade_in=>c_reason-ok + act = ls_result-reason ). + ENDMETHOD. + + METHOD volume_one_year. + DATA(ls_result) = mo_cut->assess( iv_brand = {{p}}if_trade_in=>c_brand-volume + iv_grade = {{p}}if_trade_in=>c_grade-a + iv_age_months = 12 + iv_mileage = 0 ). + cl_abap_unit_assert=>assert_equals( exp = 19360 act = ls_result-amount ). + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_trade_in=>c_reason-ok + act = ls_result-reason ). + ENDMETHOD. + + METHOD premium_age_mileage. + DATA(ls_result) = mo_cut->assess( iv_brand = {{p}}if_trade_in=>c_brand-premium + iv_grade = {{p}}if_trade_in=>c_grade-a + iv_age_months = 12 + iv_mileage = 20000 ). + cl_abap_unit_assert=>assert_equals( exp = 28380 act = ls_result-amount ). + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_trade_in=>c_reason-ok + act = ls_result-reason ). + ENDMETHOD. + + METHOD mileage_rounds_down. + DATA(ls_result) = mo_cut->assess( iv_brand = {{p}}if_trade_in=>c_brand-volume + iv_grade = {{p}}if_trade_in=>c_grade-b + iv_age_months = 0 + iv_mileage = 25000 ). + cl_abap_unit_assert=>assert_equals( exp = 19600 act = ls_result-amount ). + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_trade_in=>c_reason-ok + act = ls_result-reason ). + ENDMETHOD. + + METHOD budget_grade_c. + DATA(ls_result) = mo_cut->assess( iv_brand = {{p}}if_trade_in=>c_brand-budget + iv_grade = {{p}}if_trade_in=>c_grade-c + iv_age_months = 12 + iv_mileage = 0 ). + cl_abap_unit_assert=>assert_equals( exp = 8448 act = ls_result-amount ). + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_trade_in=>c_reason-ok + act = ls_result-reason ). + ENDMETHOD. + + METHOD floor_at_minimum. + DATA(ls_result) = mo_cut->assess( iv_brand = {{p}}if_trade_in=>c_brand-budget + iv_grade = {{p}}if_trade_in=>c_grade-c + iv_age_months = 300 + iv_mileage = 0 ). + cl_abap_unit_assert=>assert_equals( exp = 500 act = ls_result-amount ). + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_trade_in=>c_reason-ok + act = ls_result-reason ). + ENDMETHOD. + + METHOD unknown_brand. + DATA(ls_result) = mo_cut->assess( iv_brand = 'FORD' + iv_grade = 'X' + iv_age_months = -1 + iv_mileage = -1 ). + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_trade_in=>c_reason-brand + act = ls_result-reason ). + ENDMETHOD. + + METHOD unknown_grade. + DATA(ls_result) = mo_cut->assess( iv_brand = {{p}}if_trade_in=>c_brand-volume + iv_grade = 'X' + iv_age_months = -1 + iv_mileage = -1 ). + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_trade_in=>c_reason-grade + act = ls_result-reason ). + ENDMETHOD. + + METHOD negative_age. + DATA(ls_result) = mo_cut->assess( iv_brand = {{p}}if_trade_in=>c_brand-volume + iv_grade = {{p}}if_trade_in=>c_grade-b + iv_age_months = -1 + iv_mileage = -1 ). + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_trade_in=>c_reason-age + act = ls_result-reason ). + ENDMETHOD. + + METHOD age_too_high. + DATA(ls_result) = mo_cut->assess( iv_brand = {{p}}if_trade_in=>c_brand-volume + iv_grade = {{p}}if_trade_in=>c_grade-b + iv_age_months = 601 + iv_mileage = 0 ). + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_trade_in=>c_reason-age + act = ls_result-reason ). + ENDMETHOD. + + METHOD negative_mileage. + DATA(ls_result) = mo_cut->assess( iv_brand = {{p}}if_trade_in=>c_brand-volume + iv_grade = {{p}}if_trade_in=>c_grade-b + iv_age_months = 0 + iv_mileage = -1 ). + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_trade_in=>c_reason-mileage + act = ls_result-reason ). + ENDMETHOD. + + METHOD mileage_too_high. + DATA(ls_result) = mo_cut->assess( iv_brand = {{p}}if_trade_in=>c_brand-volume + iv_grade = {{p}}if_trade_in=>c_grade-b + iv_age_months = 0 + iv_mileage = 1000001 ). + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_trade_in=>c_reason-mileage + act = ls_result-reason ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0148/mutation.json b/tasks_gen/eval/G0148/mutation.json new file mode 100644 index 0000000..07680c5 --- /dev/null +++ b/tasks_gen/eval/G0148/mutation.json @@ -0,0 +1,70 @@ +{ + "task": "G0148", + "mutants": [ + { + "object": "{{P}}TRADE_IN_VALUER", + "mutant": "line 68: <> -> = (rel)", + "status": "killed", + "hidden": "9/12", + "failed_tests": [ + "BUDGET_GRADE_C", + "FLOOR_AT_MINIMUM", + "UNKNOWN_BRAND" + ] + }, + { + "object": "{{P}}TRADE_IN_VALUER", + "mutant": "line 74: AND -> OR (logic)", + "status": "killed", + "hidden": "2/12", + "failed_tests": [ + "AGE_TOO_HIGH", + "BUDGET_GRADE_C", + "FLOOR_AT_MINIMUM", + "MILEAGE_ROUNDS_DOWN", + "MILEAGE_TOO_HIGH", + "NEGATIVE_AGE", + "NEGATIVE_MILEAGE", + "PREMIUM_AGE_MILEAGE", + "PREMIUM_NEW_CAR", + "VOLUME_ONE_YEAR" + ] + }, + { + "object": "{{P}}TRADE_IN_VALUER", + "mutant": "line 74: <> -> = (rel)", + "status": "killed", + "hidden": "9/12", + "failed_tests": [ + "BUDGET_GRADE_C", + "FLOOR_AT_MINIMUM", + "UNKNOWN_GRADE" + ] + }, + { + "object": "{{P}}TRADE_IN_VALUER", + "mutant": "line 75: <> -> = (rel)", + "status": "killed", + "hidden": "11/12", + "failed_tests": [ + "UNKNOWN_GRADE" + ] + }, + { + "object": "{{P}}TRADE_IN_VALUER", + "mutant": "line 82: - -> + (arith)", + "status": "killed", + "hidden": "8/12", + "failed_tests": [ + "BUDGET_GRADE_C", + "FLOOR_AT_MINIMUM", + "PREMIUM_AGE_MILEAGE", + "VOLUME_ONE_YEAR" + ] + } + ], + "valid": 5, + "killed": 5, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0148/reference/trade_in_valuer.clas.abap b/tasks_gen/eval/G0148/reference/trade_in_valuer.clas.abap new file mode 100644 index 0000000..44604a5 --- /dev/null +++ b/tasks_gen/eval/G0148/reference/trade_in_valuer.clas.abap @@ -0,0 +1,119 @@ +CLASS {{p}}trade_in_valuer DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_trade_in. + + PRIVATE SECTION. + CONSTANTS: + c_base_premium TYPE {{p}}if_trade_in=>ty_value VALUE 30000, + c_base_volume TYPE {{p}}if_trade_in=>ty_value VALUE 20000, + c_base_budget TYPE {{p}}if_trade_in=>ty_value VALUE 12000, + c_min_value TYPE {{p}}if_trade_in=>ty_value VALUE 500, + c_max_age TYPE i VALUE 600, + c_max_mileage TYPE i VALUE 1000000, + c_km_step TYPE i VALUE 10000, + c_percent TYPE i VALUE 100. + + METHODS is_unknown_brand + IMPORTING iv_brand TYPE {{p}}if_trade_in=>ty_brand + RETURNING VALUE(rv_unknown) TYPE abap_bool. + METHODS is_unknown_grade + IMPORTING iv_grade TYPE {{p}}if_trade_in=>ty_grade + RETURNING VALUE(rv_unknown) TYPE abap_bool. + METHODS valuation + IMPORTING iv_brand TYPE {{p}}if_trade_in=>ty_brand + iv_grade TYPE {{p}}if_trade_in=>ty_grade + iv_age_months TYPE i + iv_mileage TYPE i + RETURNING VALUE(rv_value) TYPE {{p}}if_trade_in=>ty_value. + METHODS base_value + IMPORTING iv_brand TYPE {{p}}if_trade_in=>ty_brand + RETURNING VALUE(rv_base) TYPE {{p}}if_trade_in=>ty_value. + METHODS mileage_blocks + IMPORTING iv_mileage TYPE i + RETURNING VALUE(rv_blocks) TYPE i. + METHODS grade_factor + IMPORTING iv_grade TYPE {{p}}if_trade_in=>ty_grade + RETURNING VALUE(rv_factor) TYPE i. +ENDCLASS. + + +CLASS {{p}}trade_in_valuer IMPLEMENTATION. + METHOD {{p}}if_trade_in~assess. + IF is_unknown_brand( iv_brand ). + rs_result-reason = {{p}}if_trade_in=>c_reason-brand. + RETURN. + ENDIF. + IF is_unknown_grade( iv_grade ). + rs_result-reason = {{p}}if_trade_in=>c_reason-grade. + RETURN. + ENDIF. + IF iv_age_months < 0 OR iv_age_months > c_max_age. + rs_result-reason = {{p}}if_trade_in=>c_reason-age. + RETURN. + ENDIF. + IF iv_mileage < 0 OR iv_mileage > c_max_mileage. + rs_result-reason = {{p}}if_trade_in=>c_reason-mileage. + RETURN. + ENDIF. + rs_result-amount = valuation( iv_brand = iv_brand + iv_grade = iv_grade + iv_age_months = iv_age_months + iv_mileage = iv_mileage ). + rs_result-reason = {{p}}if_trade_in=>c_reason-ok. + ENDMETHOD. + + METHOD is_unknown_brand. + rv_unknown = xsdbool( iv_brand <> {{p}}if_trade_in=>c_brand-premium + AND iv_brand <> {{p}}if_trade_in=>c_brand-volume + AND iv_brand <> {{p}}if_trade_in=>c_brand-budget ). + ENDMETHOD. + + METHOD is_unknown_grade. + rv_unknown = xsdbool( iv_grade <> {{p}}if_trade_in=>c_grade-a + AND iv_grade <> {{p}}if_trade_in=>c_grade-b + AND iv_grade <> {{p}}if_trade_in=>c_grade-c + AND iv_grade <> {{p}}if_trade_in=>c_grade-d ). + ENDMETHOD. + + METHOD valuation. + DATA(lv_base) = base_value( iv_brand ). + DATA(lv_blocks) = mileage_blocks( iv_mileage ). + DATA(lv_value) = lv_base + - lv_base * iv_age_months / c_percent + - lv_base * lv_blocks / c_percent. + lv_value = lv_value * grade_factor( iv_grade ) / c_percent. + IF lv_value < c_min_value. + rv_value = c_min_value. + ELSE. + rv_value = lv_value. + ENDIF. + ENDMETHOD. + + METHOD base_value. + CASE iv_brand. + WHEN {{p}}if_trade_in=>c_brand-premium. + rv_base = c_base_premium. + WHEN {{p}}if_trade_in=>c_brand-volume. + rv_base = c_base_volume. + WHEN OTHERS. + rv_base = c_base_budget. + ENDCASE. + ENDMETHOD. + + METHOD mileage_blocks. + rv_blocks = iv_mileage DIV c_km_step. + ENDMETHOD. + + METHOD grade_factor. + CASE iv_grade. + WHEN {{p}}if_trade_in=>c_grade-a. + rv_factor = 110. + WHEN {{p}}if_trade_in=>c_grade-c. + rv_factor = 80. + WHEN {{p}}if_trade_in=>c_grade-d. + rv_factor = 60. + WHEN OTHERS. + rv_factor = 100. + ENDCASE. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0148/reference/trade_in_valuer.testclasses.abap b/tasks_gen/eval/G0148/reference/trade_in_valuer.testclasses.abap new file mode 100644 index 0000000..8bd2338 --- /dev/null +++ b/tasks_gen/eval/G0148/reference/trade_in_valuer.testclasses.abap @@ -0,0 +1,91 @@ +CLASS ltc_trade_in_valuer DEFINITION FINAL FOR TESTING + DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + DATA mo_cut TYPE REF TO {{p}}if_trade_in. + METHODS setup. + METHODS premium_new_car FOR TESTING. + METHODS volume_one_year FOR TESTING. + METHODS mileage_rounds_down FOR TESTING. + METHODS floor_at_minimum FOR TESTING. + METHODS unknown_brand FOR TESTING. + METHODS unknown_grade FOR TESTING. + METHODS negative_age FOR TESTING. + METHODS mileage_too_high FOR TESTING. +ENDCLASS. + + +CLASS ltc_trade_in_valuer IMPLEMENTATION. + METHOD setup. + mo_cut = NEW {{p}}trade_in_valuer( ). + ENDMETHOD. + + METHOD premium_new_car. + DATA(ls_result) = mo_cut->assess( iv_brand = {{p}}if_trade_in=>c_brand-premium + iv_grade = {{p}}if_trade_in=>c_grade-b + iv_age_months = 0 + iv_mileage = 0 ). + cl_abap_unit_assert=>assert_equals( exp = 30000 act = ls_result-amount ). + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_trade_in=>c_reason-ok + act = ls_result-reason ). + ENDMETHOD. + + METHOD volume_one_year. + DATA(ls_result) = mo_cut->assess( iv_brand = {{p}}if_trade_in=>c_brand-volume + iv_grade = {{p}}if_trade_in=>c_grade-a + iv_age_months = 12 + iv_mileage = 0 ). + cl_abap_unit_assert=>assert_equals( exp = 19360 act = ls_result-amount ). + ENDMETHOD. + + METHOD mileage_rounds_down. + DATA(ls_result) = mo_cut->assess( iv_brand = {{p}}if_trade_in=>c_brand-volume + iv_grade = {{p}}if_trade_in=>c_grade-b + iv_age_months = 0 + iv_mileage = 25000 ). + cl_abap_unit_assert=>assert_equals( exp = 19600 act = ls_result-amount ). + ENDMETHOD. + + METHOD floor_at_minimum. + DATA(ls_result) = mo_cut->assess( iv_brand = {{p}}if_trade_in=>c_brand-budget + iv_grade = {{p}}if_trade_in=>c_grade-d + iv_age_months = 600 + iv_mileage = 0 ). + cl_abap_unit_assert=>assert_equals( exp = 500 act = ls_result-amount ). + ENDMETHOD. + + METHOD unknown_brand. + DATA(ls_result) = mo_cut->assess( iv_brand = 'FORD' + iv_grade = {{p}}if_trade_in=>c_grade-b + iv_age_months = 0 + iv_mileage = 0 ). + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_trade_in=>c_reason-brand + act = ls_result-reason ). + ENDMETHOD. + + METHOD unknown_grade. + DATA(ls_result) = mo_cut->assess( iv_brand = {{p}}if_trade_in=>c_brand-volume + iv_grade = 'X' + iv_age_months = 0 + iv_mileage = 0 ). + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_trade_in=>c_reason-grade + act = ls_result-reason ). + ENDMETHOD. + + METHOD negative_age. + DATA(ls_result) = mo_cut->assess( iv_brand = {{p}}if_trade_in=>c_brand-volume + iv_grade = {{p}}if_trade_in=>c_grade-b + iv_age_months = -1 + iv_mileage = 0 ). + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_trade_in=>c_reason-age + act = ls_result-reason ). + ENDMETHOD. + + METHOD mileage_too_high. + DATA(ls_result) = mo_cut->assess( iv_brand = {{p}}if_trade_in=>c_brand-volume + iv_grade = {{p}}if_trade_in=>c_grade-b + iv_age_months = 0 + iv_mileage = 1000001 ). + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_trade_in=>c_reason-mileage + act = ls_result-reason ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0148/seed/if_trade_in.intf.abap b/tasks_gen/eval/G0148/seed/if_trade_in.intf.abap new file mode 100644 index 0000000..5b5d466 --- /dev/null +++ b/tasks_gen/eval/G0148/seed/if_trade_in.intf.abap @@ -0,0 +1,36 @@ +INTERFACE {{p}}if_trade_in PUBLIC. + TYPES ty_value TYPE i. + TYPES ty_brand TYPE c LENGTH 8. + TYPES ty_grade TYPE c LENGTH 1. + TYPES ty_reason TYPE c LENGTH 10. + TYPES: + BEGIN OF ty_result, + amount TYPE ty_value, + reason TYPE ty_reason, + END OF ty_result. + CONSTANTS: + BEGIN OF c_brand, + premium TYPE ty_brand VALUE 'PREMIUM', + volume TYPE ty_brand VALUE 'VOLUME', + budget TYPE ty_brand VALUE 'BUDGET', + END OF c_brand, + BEGIN OF c_grade, + a TYPE ty_grade VALUE 'A', + b TYPE ty_grade VALUE 'B', + c TYPE ty_grade VALUE 'C', + d TYPE ty_grade VALUE 'D', + END OF c_grade, + BEGIN OF c_reason, + ok TYPE ty_reason VALUE 'OK', + brand TYPE ty_reason VALUE 'BRAND', + grade TYPE ty_reason VALUE 'GRADE', + age TYPE ty_reason VALUE 'AGE', + mileage TYPE ty_reason VALUE 'MILEAGE', + END OF c_reason. + METHODS assess + IMPORTING iv_brand TYPE ty_brand + iv_grade TYPE ty_grade + iv_age_months TYPE i + iv_mileage TYPE i + RETURNING VALUE(rs_result) TYPE ty_result. +ENDINTERFACE. diff --git a/tasks_gen/eval/G0148/spec.md b/tasks_gen/eval/G0148/spec.md new file mode 100644 index 0000000..622e71c --- /dev/null +++ b/tasks_gen/eval/G0148/spec.md @@ -0,0 +1,60 @@ +# 1. Goal +A car dealership accepts used cars as trade-ins. A sales program calls one +valuation for each offered car before the dealership makes an offer to the +customer. The valuation returns the trade-in value in whole euros and a reason +code. + +# 2. Open questions +None. + +# 3. Context +- The interface {{P}}IF_TRADE_IN exists in package $TMP. It is active. +- The interface defines the whole contract of the valuation: the result + structure, the input types, the three brand groups, the four condition + grades, the reason codes and one method. Read the interface in the system. +- The dealership uses the brand groups premium, volume and budget and the + condition grades A, B, C and D. +- All amounts are whole euros. All arithmetic is integer arithmetic. + +# 4. Contract +- Create the class {{P}}TRADE_IN_VALUER in package $TMP. +- The class is public, final, and has a public constructor without parameters. +- The class implements {{P}}IF_TRADE_IN. +- Do not add other public methods. +- Do not change {{P}}IF_TRADE_IN. + +# 5. Business rules +Apply the rules in this sequence. Return the reason code of the first rule that +fails. The interface defines one reason code for each rule below and one reason +code for a successful valuation. Each code is named after the rule that it +reports. +1. The brand group must be one of the three brand groups that the interface + defines. If not, return the reason code for the brand group. +2. The condition grade must be one of the four grades that the interface + defines. If not, return the reason code for the condition grade. +3. The age in months must be between 0 and 600. If not, return the reason code + for the age. +4. The mileage in kilometres must be between 0 and 1000000. If not, return the + reason code for the mileage. +5. The base value is 30000 euros for the premium brand group, 20000 euros for + the volume brand group and 12000 euros for the budget brand group. +6. Deduct 1 percent of the base value for each month of age. +7. Deduct 1 percent of the base value for each complete block of 10000 + kilometres of mileage. Only complete blocks count. A mileage of 25000 + kilometres contains two complete blocks and 5000 kilometres that do not + count. A mileage of 9999 kilometres contains no complete block. +8. Multiply the result by the grade factor: grade A 110 percent, grade B + 100 percent, grade C 80 percent, grade D 60 percent. +9. If the result is below 500, the value is 500. +10. Return the value and the reason code for a successful valuation. + +# 6. Constraints +- Release target: 8.16. +- Coding standards: Clean ABAP. Method length below 40 statements. No global + variables. No comment that restates the code. +- Out of scope: do not change {{P}}IF_TRADE_IN. + +# 7. Acceptance +- The class is active and has no syntax error. +- The hidden tests pass. +- Write your own ABAP Unit tests for the class. diff --git a/tasks_gen/eval/G0148/task.json b/tasks_gen/eval/G0148/task.json new file mode 100644 index 0000000..5e7f6cf --- /dev/null +++ b/tasks_gen/eval/G0148/task.json @@ -0,0 +1,51 @@ +{ + "id": "G0148", + "category": "F", + "object_type": "CLAS", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [ + { + "type": "INTF", + "name": "{{P}}IF_TRADE_IN", + "file": "seed/if_trade_in.intf.abap", + "description": "Trade-in valuation contract" + } + ], + "contract": [ + { + "type": "CLAS", + "name": "{{P}}TRADE_IN_VALUER", + "implements": "{{P}}IF_TRADE_IN" + } + ], + "out_of_scope": [ + "{{P}}IF_TRADE_IN" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T02_HIDDEN", + "file": "hidden/t02_hidden.clas.abap", + "description": "T02 hidden tests" + } + ], + "reference": [ + { + "type": "CLAS", + "name": "{{P}}TRADE_IN_VALUER", + "file": "reference/trade_in_valuer.clas.abap", + "description": "Trade-in valuer", + "testclasses_file": "reference/trade_in_valuer.testclasses.abap" + } + ], + "craft_checks": [ + "method_length", + "db_operation_in_loop" + ] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0149/faulty/m0_scrap_payout.clas.abap b/tasks_gen/eval/G0149/faulty/m0_scrap_payout.clas.abap new file mode 100644 index 0000000..cdc21d5 --- /dev/null +++ b/tasks_gen/eval/G0149/faulty/m0_scrap_payout.clas.abap @@ -0,0 +1,67 @@ +CLASS {{p}}scrap_payout DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_scrap_payout. + + PRIVATE SECTION. + TYPES ty_mat_code TYPE c LENGTH 4. + TYPES ty_weight TYPE p LENGTH 8 DECIMALS 3. + TYPES ty_price TYPE p LENGTH 8 DECIMALS 2. + TYPES ty_quantity TYPE p LENGTH 15 DECIMALS 5. + + METHODS payable_weight + IMPORTING iv_weight_kg TYPE ty_weight + iv_contamination TYPE i + RETURNING VALUE(rv_weight) TYPE ty_quantity. +ENDCLASS. + + +CLASS {{p}}scrap_payout IMPLEMENTATION. + METHOD {{p}}if_scrap_payout~calculate. + DATA lv_mat_code TYPE ty_mat_code. + lv_mat_code = to_upper( iv_material ). + + DATA lv_price TYPE ty_price. + CASE lv_mat_code. + WHEN {{p}}if_scrap_payout=>c_material-copper. + lv_price = '4.20'. + WHEN {{p}}if_scrap_payout=>c_material-aluminium. + lv_price = '1.10'. + WHEN {{p}}if_scrap_payout=>c_material-steel. + lv_price = '0.30'. + WHEN {{p}}if_scrap_payout=>c_material-brass. + lv_price = '3.00'. + WHEN OTHERS. + rs_payout = VALUE #( amount = 0 + reason = {{p}}if_scrap_payout=>c_reason-material ). + RETURN. + ENDCASE. + + IF iv_weight_kg <= 0. + rs_payout = VALUE #( amount = 0 + reason = {{p}}if_scrap_payout=>c_reason-weight ). + RETURN. + ENDIF. + + IF iv_contamination >= 0 OR iv_contamination > 100. + rs_payout = VALUE #( amount = 0 + reason = {{p}}if_scrap_payout=>c_reason-dirty ). + RETURN. + ENDIF. + + DATA lv_payable TYPE ty_quantity. + lv_payable = payable_weight( iv_weight_kg = iv_weight_kg + iv_contamination = iv_contamination ). + + DATA lv_gross TYPE ty_quantity. + lv_gross = lv_payable * lv_price. + + rs_payout = VALUE #( amount = round( val = lv_gross dec = 2 ) + reason = {{p}}if_scrap_payout=>c_reason-ok ). + ENDMETHOD. + + METHOD payable_weight. + DATA lv_remaining TYPE i. + lv_remaining = 100 - iv_contamination. + rv_weight = iv_weight_kg * lv_remaining / 100. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0149/faulty/m1_scrap_payout.clas.abap b/tasks_gen/eval/G0149/faulty/m1_scrap_payout.clas.abap new file mode 100644 index 0000000..fb88893 --- /dev/null +++ b/tasks_gen/eval/G0149/faulty/m1_scrap_payout.clas.abap @@ -0,0 +1,67 @@ +CLASS {{p}}scrap_payout DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_scrap_payout. + + PRIVATE SECTION. + TYPES ty_mat_code TYPE c LENGTH 4. + TYPES ty_weight TYPE p LENGTH 8 DECIMALS 3. + TYPES ty_price TYPE p LENGTH 8 DECIMALS 2. + TYPES ty_quantity TYPE p LENGTH 15 DECIMALS 5. + + METHODS payable_weight + IMPORTING iv_weight_kg TYPE ty_weight + iv_contamination TYPE i + RETURNING VALUE(rv_weight) TYPE ty_quantity. +ENDCLASS. + + +CLASS {{p}}scrap_payout IMPLEMENTATION. + METHOD {{p}}if_scrap_payout~calculate. + DATA lv_mat_code TYPE ty_mat_code. + lv_mat_code = to_upper( iv_material ). + + DATA lv_price TYPE ty_price. + CASE lv_mat_code. + WHEN {{p}}if_scrap_payout=>c_material-copper. + lv_price = '4.20'. + WHEN {{p}}if_scrap_payout=>c_material-aluminium. + lv_price = '1.10'. + WHEN {{p}}if_scrap_payout=>c_material-steel. + lv_price = '0.30'. + WHEN {{p}}if_scrap_payout=>c_material-brass. + lv_price = '3.00'. + WHEN OTHERS. + rs_payout = VALUE #( amount = 0 + reason = {{p}}if_scrap_payout=>c_reason-material ). + RETURN. + ENDCASE. + + IF iv_weight_kg <= 0. + rs_payout = VALUE #( amount = 0 + reason = {{p}}if_scrap_payout=>c_reason-weight ). + RETURN. + ENDIF. + + IF iv_contamination < 0 OR iv_contamination <= 100. + rs_payout = VALUE #( amount = 0 + reason = {{p}}if_scrap_payout=>c_reason-dirty ). + RETURN. + ENDIF. + + DATA lv_payable TYPE ty_quantity. + lv_payable = payable_weight( iv_weight_kg = iv_weight_kg + iv_contamination = iv_contamination ). + + DATA lv_gross TYPE ty_quantity. + lv_gross = lv_payable * lv_price. + + rs_payout = VALUE #( amount = round( val = lv_gross dec = 2 ) + reason = {{p}}if_scrap_payout=>c_reason-ok ). + ENDMETHOD. + + METHOD payable_weight. + DATA lv_remaining TYPE i. + lv_remaining = 100 - iv_contamination. + rv_weight = iv_weight_kg * lv_remaining / 100. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0149/faulty/m2_scrap_payout.clas.abap b/tasks_gen/eval/G0149/faulty/m2_scrap_payout.clas.abap new file mode 100644 index 0000000..35f6daa --- /dev/null +++ b/tasks_gen/eval/G0149/faulty/m2_scrap_payout.clas.abap @@ -0,0 +1,67 @@ +CLASS {{p}}scrap_payout DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_scrap_payout. + + PRIVATE SECTION. + TYPES ty_mat_code TYPE c LENGTH 4. + TYPES ty_weight TYPE p LENGTH 8 DECIMALS 3. + TYPES ty_price TYPE p LENGTH 8 DECIMALS 2. + TYPES ty_quantity TYPE p LENGTH 15 DECIMALS 5. + + METHODS payable_weight + IMPORTING iv_weight_kg TYPE ty_weight + iv_contamination TYPE i + RETURNING VALUE(rv_weight) TYPE ty_quantity. +ENDCLASS. + + +CLASS {{p}}scrap_payout IMPLEMENTATION. + METHOD {{p}}if_scrap_payout~calculate. + DATA lv_mat_code TYPE ty_mat_code. + lv_mat_code = to_upper( iv_material ). + + DATA lv_price TYPE ty_price. + CASE lv_mat_code. + WHEN {{p}}if_scrap_payout=>c_material-copper. + lv_price = '4.20'. + WHEN {{p}}if_scrap_payout=>c_material-aluminium. + lv_price = '1.10'. + WHEN {{p}}if_scrap_payout=>c_material-steel. + lv_price = '0.30'. + WHEN {{p}}if_scrap_payout=>c_material-brass. + lv_price = '3.00'. + WHEN OTHERS. + rs_payout = VALUE #( amount = 0 + reason = {{p}}if_scrap_payout=>c_reason-material ). + RETURN. + ENDCASE. + + IF iv_weight_kg <= 0. + rs_payout = VALUE #( amount = 0 + reason = {{p}}if_scrap_payout=>c_reason-weight ). + RETURN. + ENDIF. + + IF iv_contamination < 0 OR iv_contamination > 100. + rs_payout = VALUE #( amount = 0 + reason = {{p}}if_scrap_payout=>c_reason-dirty ). + RETURN. + ENDIF. + + DATA lv_payable TYPE ty_quantity. + lv_payable = payable_weight( iv_weight_kg = iv_weight_kg + iv_contamination = iv_contamination ). + + DATA lv_gross TYPE ty_quantity. + lv_gross = lv_payable / lv_price. + + rs_payout = VALUE #( amount = round( val = lv_gross dec = 2 ) + reason = {{p}}if_scrap_payout=>c_reason-ok ). + ENDMETHOD. + + METHOD payable_weight. + DATA lv_remaining TYPE i. + lv_remaining = 100 - iv_contamination. + rv_weight = iv_weight_kg * lv_remaining / 100. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0149/faulty/m4_scrap_payout.clas.abap b/tasks_gen/eval/G0149/faulty/m4_scrap_payout.clas.abap new file mode 100644 index 0000000..46a6717 --- /dev/null +++ b/tasks_gen/eval/G0149/faulty/m4_scrap_payout.clas.abap @@ -0,0 +1,67 @@ +CLASS {{p}}scrap_payout DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_scrap_payout. + + PRIVATE SECTION. + TYPES ty_mat_code TYPE c LENGTH 4. + TYPES ty_weight TYPE p LENGTH 8 DECIMALS 3. + TYPES ty_price TYPE p LENGTH 8 DECIMALS 2. + TYPES ty_quantity TYPE p LENGTH 15 DECIMALS 5. + + METHODS payable_weight + IMPORTING iv_weight_kg TYPE ty_weight + iv_contamination TYPE i + RETURNING VALUE(rv_weight) TYPE ty_quantity. +ENDCLASS. + + +CLASS {{p}}scrap_payout IMPLEMENTATION. + METHOD {{p}}if_scrap_payout~calculate. + DATA lv_mat_code TYPE ty_mat_code. + lv_mat_code = to_upper( iv_material ). + + DATA lv_price TYPE ty_price. + CASE lv_mat_code. + WHEN {{p}}if_scrap_payout=>c_material-copper. + lv_price = '4.20'. + WHEN {{p}}if_scrap_payout=>c_material-aluminium. + lv_price = '1.10'. + WHEN {{p}}if_scrap_payout=>c_material-steel. + lv_price = '0.30'. + WHEN {{p}}if_scrap_payout=>c_material-brass. + lv_price = '3.00'. + WHEN OTHERS. + rs_payout = VALUE #( amount = 0 + reason = {{p}}if_scrap_payout=>c_reason-material ). + RETURN. + ENDCASE. + + IF iv_weight_kg <= 0. + rs_payout = VALUE #( amount = 0 + reason = {{p}}if_scrap_payout=>c_reason-weight ). + RETURN. + ENDIF. + + IF iv_contamination < 0 OR iv_contamination > 100. + rs_payout = VALUE #( amount = 0 + reason = {{p}}if_scrap_payout=>c_reason-dirty ). + RETURN. + ENDIF. + + DATA lv_payable TYPE ty_quantity. + lv_payable = payable_weight( iv_weight_kg = iv_weight_kg + iv_contamination = iv_contamination ). + + DATA lv_gross TYPE ty_quantity. + lv_gross = lv_payable * lv_price. + + rs_payout = VALUE #( amount = round( val = lv_gross dec = 2 ) + reason = {{p}}if_scrap_payout=>c_reason-ok ). + ENDMETHOD. + + METHOD payable_weight. + DATA lv_remaining TYPE i. + lv_remaining = 100 - iv_contamination. + rv_weight = iv_weight_kg / lv_remaining / 100. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0149/generation.json b/tasks_gen/eval/G0149/generation.json new file mode 100644 index 0000000..33e0194 --- /dev/null +++ b/tasks_gen/eval/G0149/generation.json @@ -0,0 +1,28 @@ +{ + "id": "G0149", + "pool": "eval", + "object_type": "CLAS", + "category": "F", + "attempts": [ + { + "stage": "bundle", + "errors": [ + "reference/scrap_payout.clas.abap line 16: 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": 5, + "killed": 4, + "ok": true + } + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0149/hidden/t_f01_hidden.clas.abap b/tasks_gen/eval/G0149/hidden/t_f01_hidden.clas.abap new file mode 100644 index 0000000..34ae437 --- /dev/null +++ b/tasks_gen/eval/G0149/hidden/t_f01_hidden.clas.abap @@ -0,0 +1,130 @@ +CLASS {{p}}t_f01_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + TYPES ty_amount TYPE p LENGTH 10 DECIMALS 2. + + DATA mo_cut TYPE REF TO {{p}}if_scrap_payout. + + METHODS setup. + METHODS check + IMPORTING iv_material TYPE {{p}}if_scrap_payout=>ty_material + iv_weight_kg TYPE {{p}}if_scrap_payout=>ty_weight + iv_contamination TYPE i + iv_amount TYPE ty_amount + iv_reason TYPE {{p}}if_scrap_payout=>ty_reason. + + METHODS copper_clean FOR TESTING. + METHODS copper_contaminated FOR TESTING. + METHODS steel_clean FOR TESTING. + METHODS brass_half_dirty FOR TESTING. + METHODS rounds_amount FOR TESTING. + METHODS rounds_half_up FOR TESTING. + METHODS material_lower_case FOR TESTING. + METHODS unknown_material FOR TESTING. + METHODS zero_weight FOR TESTING. + METHODS dirty_too_high FOR TESTING. + METHODS fully_contaminated FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t_f01_hidden IMPLEMENTATION. + METHOD setup. + mo_cut = NEW {{p}}scrap_payout( ). + ENDMETHOD. + + METHOD check. + DATA(ls_payout) = mo_cut->calculate( iv_material = iv_material + iv_weight_kg = iv_weight_kg + iv_contamination = iv_contamination ). + cl_abap_unit_assert=>assert_equals( exp = iv_amount act = ls_payout-amount ). + cl_abap_unit_assert=>assert_equals( exp = iv_reason act = ls_payout-reason ). + ENDMETHOD. + + METHOD copper_clean. + check( iv_material = {{p}}if_scrap_payout=>c_material-copper + iv_weight_kg = '100.000' + iv_contamination = 0 + iv_amount = '420.00' + iv_reason = {{p}}if_scrap_payout=>c_reason-ok ). + ENDMETHOD. + + METHOD copper_contaminated. + check( iv_material = {{p}}if_scrap_payout=>c_material-copper + iv_weight_kg = '250.500' + iv_contamination = 20 + iv_amount = '841.68' + iv_reason = {{p}}if_scrap_payout=>c_reason-ok ). + ENDMETHOD. + + METHOD steel_clean. + check( iv_material = {{p}}if_scrap_payout=>c_material-steel + iv_weight_kg = '1000.000' + iv_contamination = 0 + iv_amount = '300.00' + iv_reason = {{p}}if_scrap_payout=>c_reason-ok ). + ENDMETHOD. + + METHOD brass_half_dirty. + check( iv_material = {{p}}if_scrap_payout=>c_material-brass + iv_weight_kg = '10.000' + iv_contamination = 50 + iv_amount = '15.00' + iv_reason = {{p}}if_scrap_payout=>c_reason-ok ). + ENDMETHOD. + + METHOD rounds_amount. + check( iv_material = {{p}}if_scrap_payout=>c_material-aluminium + iv_weight_kg = '3.333' + iv_contamination = 0 + iv_amount = '3.67' + iv_reason = {{p}}if_scrap_payout=>c_reason-ok ). + ENDMETHOD. + + METHOD rounds_half_up. + check( iv_material = {{p}}if_scrap_payout=>c_material-brass + iv_weight_kg = '0.335' + iv_contamination = 0 + iv_amount = '1.01' + iv_reason = {{p}}if_scrap_payout=>c_reason-ok ). + ENDMETHOD. + + METHOD material_lower_case. + check( iv_material = 'cu' + iv_weight_kg = '100.000' + iv_contamination = 0 + iv_amount = '420.00' + iv_reason = {{p}}if_scrap_payout=>c_reason-ok ). + ENDMETHOD. + + METHOD unknown_material. + check( iv_material = 'XX' + iv_weight_kg = '100.000' + iv_contamination = 0 + iv_amount = '0.00' + iv_reason = {{p}}if_scrap_payout=>c_reason-material ). + ENDMETHOD. + + METHOD zero_weight. + check( iv_material = {{p}}if_scrap_payout=>c_material-copper + iv_weight_kg = '0.000' + iv_contamination = 0 + iv_amount = '0.00' + iv_reason = {{p}}if_scrap_payout=>c_reason-weight ). + ENDMETHOD. + + METHOD dirty_too_high. + check( iv_material = {{p}}if_scrap_payout=>c_material-copper + iv_weight_kg = '100.000' + iv_contamination = 101 + iv_amount = '0.00' + iv_reason = {{p}}if_scrap_payout=>c_reason-dirty ). + ENDMETHOD. + + METHOD fully_contaminated. + check( iv_material = {{p}}if_scrap_payout=>c_material-copper + iv_weight_kg = '100.000' + iv_contamination = 100 + iv_amount = '0.00' + iv_reason = {{p}}if_scrap_payout=>c_reason-ok ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0149/mutation.json b/tasks_gen/eval/G0149/mutation.json new file mode 100644 index 0000000..bbc31be --- /dev/null +++ b/tasks_gen/eval/G0149/mutation.json @@ -0,0 +1,80 @@ +{ + "task": "G0149", + "mutants": [ + { + "object": "{{P}}SCRAP_PAYOUT", + "mutant": "line 45: < -> >= (rel)", + "status": "killed", + "hidden": "3/11", + "failed_tests": [ + "BRASS_HALF_DIRTY", + "COPPER_CLEAN", + "COPPER_CONTAMINATED", + "FULLY_CONTAMINATED", + "MATERIAL_LOWER_CASE", + "ROUNDS_AMOUNT", + "ROUNDS_HALF_UP", + "STEEL_CLEAN" + ] + }, + { + "object": "{{P}}SCRAP_PAYOUT", + "mutant": "line 45: > -> <= (rel)", + "status": "killed", + "hidden": "2/11", + "failed_tests": [ + "BRASS_HALF_DIRTY", + "COPPER_CLEAN", + "COPPER_CONTAMINATED", + "DIRTY_TOO_HIGH", + "FULLY_CONTAMINATED", + "MATERIAL_LOWER_CASE", + "ROUNDS_AMOUNT", + "ROUNDS_HALF_UP", + "STEEL_CLEAN" + ] + }, + { + "object": "{{P}}SCRAP_PAYOUT", + "mutant": "line 56: * -> / (arith)", + "status": "killed", + "hidden": "4/11", + "failed_tests": [ + "BRASS_HALF_DIRTY", + "COPPER_CLEAN", + "COPPER_CONTAMINATED", + "MATERIAL_LOWER_CASE", + "ROUNDS_AMOUNT", + "ROUNDS_HALF_UP", + "STEEL_CLEAN" + ] + }, + { + "object": "{{P}}SCRAP_PAYOUT", + "mutant": "line 58: 2 -> 3 (const)", + "status": "survived", + "hidden": "11/11", + "failed_tests": [] + }, + { + "object": "{{P}}SCRAP_PAYOUT", + "mutant": "line 65: * -> / (arith)", + "status": "killed", + "hidden": "3/11", + "failed_tests": [ + "BRASS_HALF_DIRTY", + "COPPER_CLEAN", + "COPPER_CONTAMINATED", + "FULLY_CONTAMINATED", + "MATERIAL_LOWER_CASE", + "ROUNDS_AMOUNT", + "ROUNDS_HALF_UP", + "STEEL_CLEAN" + ] + } + ], + "valid": 5, + "killed": 4, + "kill_rate": 0.8, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0149/reference/scrap_payout.clas.abap b/tasks_gen/eval/G0149/reference/scrap_payout.clas.abap new file mode 100644 index 0000000..e023ac9 --- /dev/null +++ b/tasks_gen/eval/G0149/reference/scrap_payout.clas.abap @@ -0,0 +1,67 @@ +CLASS {{p}}scrap_payout DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_scrap_payout. + + PRIVATE SECTION. + TYPES ty_mat_code TYPE c LENGTH 4. + TYPES ty_weight TYPE p LENGTH 8 DECIMALS 3. + TYPES ty_price TYPE p LENGTH 8 DECIMALS 2. + TYPES ty_quantity TYPE p LENGTH 15 DECIMALS 5. + + METHODS payable_weight + IMPORTING iv_weight_kg TYPE ty_weight + iv_contamination TYPE i + RETURNING VALUE(rv_weight) TYPE ty_quantity. +ENDCLASS. + + +CLASS {{p}}scrap_payout IMPLEMENTATION. + METHOD {{p}}if_scrap_payout~calculate. + DATA lv_mat_code TYPE ty_mat_code. + lv_mat_code = to_upper( iv_material ). + + DATA lv_price TYPE ty_price. + CASE lv_mat_code. + WHEN {{p}}if_scrap_payout=>c_material-copper. + lv_price = '4.20'. + WHEN {{p}}if_scrap_payout=>c_material-aluminium. + lv_price = '1.10'. + WHEN {{p}}if_scrap_payout=>c_material-steel. + lv_price = '0.30'. + WHEN {{p}}if_scrap_payout=>c_material-brass. + lv_price = '3.00'. + WHEN OTHERS. + rs_payout = VALUE #( amount = 0 + reason = {{p}}if_scrap_payout=>c_reason-material ). + RETURN. + ENDCASE. + + IF iv_weight_kg <= 0. + rs_payout = VALUE #( amount = 0 + reason = {{p}}if_scrap_payout=>c_reason-weight ). + RETURN. + ENDIF. + + IF iv_contamination < 0 OR iv_contamination > 100. + rs_payout = VALUE #( amount = 0 + reason = {{p}}if_scrap_payout=>c_reason-dirty ). + RETURN. + ENDIF. + + DATA lv_payable TYPE ty_quantity. + lv_payable = payable_weight( iv_weight_kg = iv_weight_kg + iv_contamination = iv_contamination ). + + DATA lv_gross TYPE ty_quantity. + lv_gross = lv_payable * lv_price. + + rs_payout = VALUE #( amount = round( val = lv_gross dec = 2 ) + reason = {{p}}if_scrap_payout=>c_reason-ok ). + ENDMETHOD. + + METHOD payable_weight. + DATA lv_remaining TYPE i. + lv_remaining = 100 - iv_contamination. + rv_weight = iv_weight_kg * lv_remaining / 100. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0149/reference/scrap_payout.testclasses.abap b/tasks_gen/eval/G0149/reference/scrap_payout.testclasses.abap new file mode 100644 index 0000000..41e1a07 --- /dev/null +++ b/tasks_gen/eval/G0149/reference/scrap_payout.testclasses.abap @@ -0,0 +1,84 @@ +CLASS ltc_scrap_payout DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + TYPES ty_amount TYPE p LENGTH 10 DECIMALS 2. + + DATA mo_cut TYPE REF TO {{p}}if_scrap_payout. + + METHODS setup. + METHODS assert_payout + IMPORTING iv_material TYPE {{p}}if_scrap_payout=>ty_material + iv_weight_kg TYPE {{p}}if_scrap_payout=>ty_weight + iv_contamination TYPE i + iv_amount TYPE ty_amount + iv_reason TYPE {{p}}if_scrap_payout=>ty_reason. + + METHODS copper_is_paid FOR TESTING. + METHODS contamination_reduces FOR TESTING. + METHODS rounding_is_commercial FOR TESTING. + METHODS unknown_material_rejected FOR TESTING. + METHODS zero_weight_rejected FOR TESTING. + METHODS dirty_too_high_rejected FOR TESTING. +ENDCLASS. + + +CLASS ltc_scrap_payout IMPLEMENTATION. + METHOD setup. + mo_cut = NEW {{p}}scrap_payout( ). + ENDMETHOD. + + METHOD assert_payout. + DATA(ls_payout) = mo_cut->calculate( iv_material = iv_material + iv_weight_kg = iv_weight_kg + iv_contamination = iv_contamination ). + cl_abap_unit_assert=>assert_equals( exp = iv_amount act = ls_payout-amount ). + cl_abap_unit_assert=>assert_equals( exp = iv_reason act = ls_payout-reason ). + ENDMETHOD. + + METHOD copper_is_paid. + assert_payout( iv_material = {{p}}if_scrap_payout=>c_material-copper + iv_weight_kg = '100.000' + iv_contamination = 0 + iv_amount = '420.00' + iv_reason = {{p}}if_scrap_payout=>c_reason-ok ). + ENDMETHOD. + + METHOD contamination_reduces. + assert_payout( iv_material = {{p}}if_scrap_payout=>c_material-aluminium + iv_weight_kg = '50.000' + iv_contamination = 20 + iv_amount = '44.00' + iv_reason = {{p}}if_scrap_payout=>c_reason-ok ). + ENDMETHOD. + + METHOD rounding_is_commercial. + assert_payout( iv_material = {{p}}if_scrap_payout=>c_material-brass + iv_weight_kg = '0.335' + iv_contamination = 0 + iv_amount = '1.01' + iv_reason = {{p}}if_scrap_payout=>c_reason-ok ). + ENDMETHOD. + + METHOD unknown_material_rejected. + assert_payout( iv_material = 'ZZ' + iv_weight_kg = '10.000' + iv_contamination = 0 + iv_amount = '0.00' + iv_reason = {{p}}if_scrap_payout=>c_reason-material ). + ENDMETHOD. + + METHOD zero_weight_rejected. + assert_payout( iv_material = {{p}}if_scrap_payout=>c_material-copper + iv_weight_kg = '0.000' + iv_contamination = 0 + iv_amount = '0.00' + iv_reason = {{p}}if_scrap_payout=>c_reason-weight ). + ENDMETHOD. + + METHOD dirty_too_high_rejected. + assert_payout( iv_material = {{p}}if_scrap_payout=>c_material-copper + iv_weight_kg = '100.000' + iv_contamination = 150 + iv_amount = '0.00' + iv_reason = {{p}}if_scrap_payout=>c_reason-dirty ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0149/seed/if_scrap_payout.intf.abap b/tasks_gen/eval/G0149/seed/if_scrap_payout.intf.abap new file mode 100644 index 0000000..2b51dac --- /dev/null +++ b/tasks_gen/eval/G0149/seed/if_scrap_payout.intf.abap @@ -0,0 +1,33 @@ +INTERFACE {{p}}if_scrap_payout PUBLIC. + TYPES ty_material TYPE c LENGTH 4. + TYPES ty_reason TYPE c LENGTH 10. + TYPES ty_weight TYPE p LENGTH 8 DECIMALS 3. + + TYPES: + BEGIN OF ty_payout, + amount TYPE p LENGTH 10 DECIMALS 2, + reason TYPE ty_reason, + END OF ty_payout. + + CONSTANTS: + BEGIN OF c_material, + copper TYPE ty_material VALUE 'CU', + aluminium TYPE ty_material VALUE 'AL', + steel TYPE ty_material VALUE 'ST', + brass TYPE ty_material VALUE 'BR', + END OF c_material. + + CONSTANTS: + BEGIN OF c_reason, + ok TYPE ty_reason VALUE 'OK', + material TYPE ty_reason VALUE 'MATERIAL', + weight TYPE ty_reason VALUE 'WEIGHT', + dirty TYPE ty_reason VALUE 'DIRTY', + END OF c_reason. + + METHODS calculate + IMPORTING iv_material TYPE ty_material + iv_weight_kg TYPE ty_weight + iv_contamination TYPE i + RETURNING VALUE(rs_payout) TYPE ty_payout. +ENDINTERFACE. diff --git a/tasks_gen/eval/G0149/spec.md b/tasks_gen/eval/G0149/spec.md new file mode 100644 index 0000000..911935d --- /dev/null +++ b/tasks_gen/eval/G0149/spec.md @@ -0,0 +1,51 @@ +# 1. Goal +A scrapyard buys scrap metal from customers. A weighing program calls one +calculation to get the payout for a delivery. The payout has an amount and a +reason code. + +# 2. Open questions +None. + +# 3. Context +- The interface {{P}}IF_SCRAP_PAYOUT exists in package $TMP. It is active. +- The interface defines one method, the material codes, the reason codes, and the + structure of the result. +- Read the interface {{P}}IF_SCRAP_PAYOUT in package $TMP. This specification does + not repeat the signature of the interface. + +# 4. Contract +- Create the class {{P}}SCRAP_PAYOUT in package $TMP. +- The class is public and final. +- The class implements the interface {{P}}IF_SCRAP_PAYOUT. +- The class has a public constructor without parameters. +- Do not add other public methods. + +# 5. Business rules +Apply the rules in this sequence. Stop at the first rule that fails. + +1. Convert the material code to upper case. The result must be one of the material + codes in the constant structure {{P}}IF_SCRAP_PAYOUT=>C_MATERIAL. If not, return + the reason MATERIAL and the amount 0. +2. The weight in kilograms must be greater than 0. If not, return the reason WEIGHT + and the amount 0. +3. The contamination in percent must be between 0 and 100. If not, return the reason + DIRTY and the amount 0. +4. The base price per kilogram is 4.20 for copper, 1.10 for aluminium, 0.30 for + steel, and 3.00 for brass. +5. The payable weight is the weight multiplied by the difference between 100 and the + contamination, divided by 100. +6. The amount is the payable weight multiplied by the base price of the material. + Round the amount to 2 decimal places. +7. Return the reason OK and the amount. + +# 6. Constraints +- Release target: SAP_BASIS 816. +- Coding standards: Clean ABAP. Keep every method below 40 statements. Do not use + global variables. Pass large parameters by reference. Do not write comments that + restate the code. +- Out of scope: do not change the interface {{P}}IF_SCRAP_PAYOUT. + +# 7. Acceptance +- The class {{P}}SCRAP_PAYOUT is active and has no syntax error. +- The hidden tests pass. +- Write your own ABAP Unit tests for the class. diff --git a/tasks_gen/eval/G0149/task.json b/tasks_gen/eval/G0149/task.json new file mode 100644 index 0000000..2c949db --- /dev/null +++ b/tasks_gen/eval/G0149/task.json @@ -0,0 +1,51 @@ +{ + "id": "G0149", + "category": "F", + "object_type": "CLAS", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [ + { + "type": "INTF", + "name": "{{P}}IF_SCRAP_PAYOUT", + "file": "seed/if_scrap_payout.intf.abap", + "description": "Scrap payout contract: material codes, reason codes, result structure and the method signature" + } + ], + "contract": [ + { + "type": "CLAS", + "name": "{{P}}SCRAP_PAYOUT", + "implements": "{{P}}IF_SCRAP_PAYOUT" + } + ], + "out_of_scope": [ + "{{P}}IF_SCRAP_PAYOUT" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T_F01_HIDDEN", + "file": "hidden/t_f01_hidden.clas.abap", + "description": "Hidden tests for the scrap payout calculation" + } + ], + "reference": [ + { + "type": "CLAS", + "name": "{{P}}SCRAP_PAYOUT", + "file": "reference/scrap_payout.clas.abap", + "description": "Scrap payout calculation", + "testclasses_file": "reference/scrap_payout.testclasses.abap" + } + ], + "craft_checks": [ + "method_length", + "db_operation_in_loop" + ] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0150/faulty/m0_vet_fee_calc.clas.abap b/tasks_gen/eval/G0150/faulty/m0_vet_fee_calc.clas.abap new file mode 100644 index 0000000..c3db575 --- /dev/null +++ b/tasks_gen/eval/G0150/faulty/m0_vet_fee_calc.clas.abap @@ -0,0 +1,73 @@ +CLASS {{p}}vet_fee_calc DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_vet_fee. + + PRIVATE SECTION. + TYPES: + BEGIN OF ty_base_fee, + species TYPE {{p}}if_vet_fee=>ty_species, + amount TYPE {{p}}if_vet_fee=>ty_amount, + END OF ty_base_fee, + tt_base_fee TYPE HASHED TABLE OF ty_base_fee WITH UNIQUE KEY species. + + CONSTANTS: + c_free_kg TYPE i VALUE 5, + c_max_kg TYPE i VALUE 200, + c_fee_per_kg TYPE {{p}}if_vet_fee=>ty_amount VALUE '2.00'. + + METHODS normalize_species + IMPORTING iv_species TYPE {{p}}if_vet_fee=>ty_species + RETURNING VALUE(rv_species) TYPE {{p}}if_vet_fee=>ty_species. + METHODS base_fees + RETURNING VALUE(rt_base_fee) TYPE tt_base_fee. + METHODS medication_fee + IMPORTING iv_weight TYPE {{p}}if_vet_fee=>ty_weight + RETURNING VALUE(rv_fee) TYPE {{p}}if_vet_fee=>ty_amount. +ENDCLASS. + + +CLASS {{p}}vet_fee_calc IMPLEMENTATION. + METHOD {{p}}if_vet_fee~calculate. + DATA(lv_species) = normalize_species( iv_species ). + DATA(lt_base_fee) = base_fees( ). + ASSIGN lt_base_fee[ species = lv_species ] TO FIELD-SYMBOL(). + IF sy-subrc <> 0. + rs_result = VALUE #( reason = {{p}}if_vet_fee=>c_reason-species ). + RETURN. + ENDIF. + IF iv_weight <= 0 AND iv_weight > c_max_kg. + rs_result = VALUE #( reason = {{p}}if_vet_fee=>c_reason-weight ). + RETURN. + ENDIF. + DATA(lv_medication) = medication_fee( iv_weight ). + DATA lv_fee TYPE {{p}}if_vet_fee=>ty_amount. + lv_fee = -amount + lv_medication. + IF iv_emergency = abap_true. + lv_fee = lv_fee + -amount / 2. + ENDIF. + IF iv_registered = abap_true. + lv_fee = lv_fee - ( -amount + lv_medication ) / 10. + ENDIF. + rs_result = VALUE #( fee = lv_fee reason = {{p}}if_vet_fee=>c_reason-ok ). + ENDMETHOD. + + METHOD normalize_species. + rv_species = to_upper( replace( val = iv_species sub = ` ` with = `` occ = 0 ) ). + ENDMETHOD. + + METHOD base_fees. + rt_base_fee = VALUE #( ( species = 'DOG' amount = '45.00' ) + ( species = 'CAT' amount = '35.00' ) + ( species = 'RABBIT' amount = '25.00' ) + ( species = 'BIRD' amount = '18.00' ) + ( species = 'REPTILE' amount = '30.00' ) ). + ENDMETHOD. + + METHOD medication_fee. + DATA lv_kg TYPE i. + lv_kg = ceil( iv_weight - c_free_kg ). + IF lv_kg > 0. + rv_fee = lv_kg * c_fee_per_kg. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0150/faulty/m1_vet_fee_calc.clas.abap b/tasks_gen/eval/G0150/faulty/m1_vet_fee_calc.clas.abap new file mode 100644 index 0000000..d060bfd --- /dev/null +++ b/tasks_gen/eval/G0150/faulty/m1_vet_fee_calc.clas.abap @@ -0,0 +1,73 @@ +CLASS {{p}}vet_fee_calc DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_vet_fee. + + PRIVATE SECTION. + TYPES: + BEGIN OF ty_base_fee, + species TYPE {{p}}if_vet_fee=>ty_species, + amount TYPE {{p}}if_vet_fee=>ty_amount, + END OF ty_base_fee, + tt_base_fee TYPE HASHED TABLE OF ty_base_fee WITH UNIQUE KEY species. + + CONSTANTS: + c_free_kg TYPE i VALUE 5, + c_max_kg TYPE i VALUE 200, + c_fee_per_kg TYPE {{p}}if_vet_fee=>ty_amount VALUE '2.00'. + + METHODS normalize_species + IMPORTING iv_species TYPE {{p}}if_vet_fee=>ty_species + RETURNING VALUE(rv_species) TYPE {{p}}if_vet_fee=>ty_species. + METHODS base_fees + RETURNING VALUE(rt_base_fee) TYPE tt_base_fee. + METHODS medication_fee + IMPORTING iv_weight TYPE {{p}}if_vet_fee=>ty_weight + RETURNING VALUE(rv_fee) TYPE {{p}}if_vet_fee=>ty_amount. +ENDCLASS. + + +CLASS {{p}}vet_fee_calc IMPLEMENTATION. + METHOD {{p}}if_vet_fee~calculate. + DATA(lv_species) = normalize_species( iv_species ). + DATA(lt_base_fee) = base_fees( ). + ASSIGN lt_base_fee[ species = lv_species ] TO FIELD-SYMBOL(). + IF sy-subrc <> 0. + rs_result = VALUE #( reason = {{p}}if_vet_fee=>c_reason-species ). + RETURN. + ENDIF. + IF iv_weight <= 0 OR iv_weight > c_max_kg. + rs_result = VALUE #( reason = {{p}}if_vet_fee=>c_reason-weight ). + RETURN. + ENDIF. + DATA(lv_medication) = medication_fee( iv_weight ). + DATA lv_fee TYPE {{p}}if_vet_fee=>ty_amount. + lv_fee = -amount + lv_medication. + IF iv_emergency = abap_false. + lv_fee = lv_fee + -amount / 2. + ENDIF. + IF iv_registered = abap_true. + lv_fee = lv_fee - ( -amount + lv_medication ) / 10. + ENDIF. + rs_result = VALUE #( fee = lv_fee reason = {{p}}if_vet_fee=>c_reason-ok ). + ENDMETHOD. + + METHOD normalize_species. + rv_species = to_upper( replace( val = iv_species sub = ` ` with = `` occ = 0 ) ). + ENDMETHOD. + + METHOD base_fees. + rt_base_fee = VALUE #( ( species = 'DOG' amount = '45.00' ) + ( species = 'CAT' amount = '35.00' ) + ( species = 'RABBIT' amount = '25.00' ) + ( species = 'BIRD' amount = '18.00' ) + ( species = 'REPTILE' amount = '30.00' ) ). + ENDMETHOD. + + METHOD medication_fee. + DATA lv_kg TYPE i. + lv_kg = ceil( iv_weight - c_free_kg ). + IF lv_kg > 0. + rv_fee = lv_kg * c_fee_per_kg. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0150/faulty/m2_vet_fee_calc.clas.abap b/tasks_gen/eval/G0150/faulty/m2_vet_fee_calc.clas.abap new file mode 100644 index 0000000..b729c24 --- /dev/null +++ b/tasks_gen/eval/G0150/faulty/m2_vet_fee_calc.clas.abap @@ -0,0 +1,73 @@ +CLASS {{p}}vet_fee_calc DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_vet_fee. + + PRIVATE SECTION. + TYPES: + BEGIN OF ty_base_fee, + species TYPE {{p}}if_vet_fee=>ty_species, + amount TYPE {{p}}if_vet_fee=>ty_amount, + END OF ty_base_fee, + tt_base_fee TYPE HASHED TABLE OF ty_base_fee WITH UNIQUE KEY species. + + CONSTANTS: + c_free_kg TYPE i VALUE 5, + c_max_kg TYPE i VALUE 200, + c_fee_per_kg TYPE {{p}}if_vet_fee=>ty_amount VALUE '2.00'. + + METHODS normalize_species + IMPORTING iv_species TYPE {{p}}if_vet_fee=>ty_species + RETURNING VALUE(rv_species) TYPE {{p}}if_vet_fee=>ty_species. + METHODS base_fees + RETURNING VALUE(rt_base_fee) TYPE tt_base_fee. + METHODS medication_fee + IMPORTING iv_weight TYPE {{p}}if_vet_fee=>ty_weight + RETURNING VALUE(rv_fee) TYPE {{p}}if_vet_fee=>ty_amount. +ENDCLASS. + + +CLASS {{p}}vet_fee_calc IMPLEMENTATION. + METHOD {{p}}if_vet_fee~calculate. + DATA(lv_species) = normalize_species( iv_species ). + DATA(lt_base_fee) = base_fees( ). + ASSIGN lt_base_fee[ species = lv_species ] TO FIELD-SYMBOL(). + IF sy-subrc <> 0. + rs_result = VALUE #( reason = {{p}}if_vet_fee=>c_reason-species ). + RETURN. + ENDIF. + IF iv_weight <= 0 OR iv_weight > c_max_kg. + rs_result = VALUE #( reason = {{p}}if_vet_fee=>c_reason-weight ). + RETURN. + ENDIF. + DATA(lv_medication) = medication_fee( iv_weight ). + DATA lv_fee TYPE {{p}}if_vet_fee=>ty_amount. + lv_fee = -amount + lv_medication. + IF iv_emergency = abap_true. + lv_fee = lv_fee + -amount / 2. + ENDIF. + IF iv_registered <> abap_true. + lv_fee = lv_fee - ( -amount + lv_medication ) / 10. + ENDIF. + rs_result = VALUE #( fee = lv_fee reason = {{p}}if_vet_fee=>c_reason-ok ). + ENDMETHOD. + + METHOD normalize_species. + rv_species = to_upper( replace( val = iv_species sub = ` ` with = `` occ = 0 ) ). + ENDMETHOD. + + METHOD base_fees. + rt_base_fee = VALUE #( ( species = 'DOG' amount = '45.00' ) + ( species = 'CAT' amount = '35.00' ) + ( species = 'RABBIT' amount = '25.00' ) + ( species = 'BIRD' amount = '18.00' ) + ( species = 'REPTILE' amount = '30.00' ) ). + ENDMETHOD. + + METHOD medication_fee. + DATA lv_kg TYPE i. + lv_kg = ceil( iv_weight - c_free_kg ). + IF lv_kg > 0. + rv_fee = lv_kg * c_fee_per_kg. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0150/faulty/m3_vet_fee_calc.clas.abap b/tasks_gen/eval/G0150/faulty/m3_vet_fee_calc.clas.abap new file mode 100644 index 0000000..9376f97 --- /dev/null +++ b/tasks_gen/eval/G0150/faulty/m3_vet_fee_calc.clas.abap @@ -0,0 +1,73 @@ +CLASS {{p}}vet_fee_calc DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_vet_fee. + + PRIVATE SECTION. + TYPES: + BEGIN OF ty_base_fee, + species TYPE {{p}}if_vet_fee=>ty_species, + amount TYPE {{p}}if_vet_fee=>ty_amount, + END OF ty_base_fee, + tt_base_fee TYPE HASHED TABLE OF ty_base_fee WITH UNIQUE KEY species. + + CONSTANTS: + c_free_kg TYPE i VALUE 5, + c_max_kg TYPE i VALUE 200, + c_fee_per_kg TYPE {{p}}if_vet_fee=>ty_amount VALUE '2.00'. + + METHODS normalize_species + IMPORTING iv_species TYPE {{p}}if_vet_fee=>ty_species + RETURNING VALUE(rv_species) TYPE {{p}}if_vet_fee=>ty_species. + METHODS base_fees + RETURNING VALUE(rt_base_fee) TYPE tt_base_fee. + METHODS medication_fee + IMPORTING iv_weight TYPE {{p}}if_vet_fee=>ty_weight + RETURNING VALUE(rv_fee) TYPE {{p}}if_vet_fee=>ty_amount. +ENDCLASS. + + +CLASS {{p}}vet_fee_calc IMPLEMENTATION. + METHOD {{p}}if_vet_fee~calculate. + DATA(lv_species) = normalize_species( iv_species ). + DATA(lt_base_fee) = base_fees( ). + ASSIGN lt_base_fee[ species = lv_species ] TO FIELD-SYMBOL(). + IF sy-subrc <> 0. + rs_result = VALUE #( reason = {{p}}if_vet_fee=>c_reason-species ). + RETURN. + ENDIF. + IF iv_weight <= 0 OR iv_weight > c_max_kg. + rs_result = VALUE #( reason = {{p}}if_vet_fee=>c_reason-weight ). + RETURN. + ENDIF. + DATA(lv_medication) = medication_fee( iv_weight ). + DATA lv_fee TYPE {{p}}if_vet_fee=>ty_amount. + lv_fee = -amount + lv_medication. + IF iv_emergency = abap_true. + lv_fee = lv_fee + -amount / 2. + ENDIF. + IF iv_registered = abap_true. + lv_fee = lv_fee + ( -amount + lv_medication ) / 10. + ENDIF. + rs_result = VALUE #( fee = lv_fee reason = {{p}}if_vet_fee=>c_reason-ok ). + ENDMETHOD. + + METHOD normalize_species. + rv_species = to_upper( replace( val = iv_species sub = ` ` with = `` occ = 0 ) ). + ENDMETHOD. + + METHOD base_fees. + rt_base_fee = VALUE #( ( species = 'DOG' amount = '45.00' ) + ( species = 'CAT' amount = '35.00' ) + ( species = 'RABBIT' amount = '25.00' ) + ( species = 'BIRD' amount = '18.00' ) + ( species = 'REPTILE' amount = '30.00' ) ). + ENDMETHOD. + + METHOD medication_fee. + DATA lv_kg TYPE i. + lv_kg = ceil( iv_weight - c_free_kg ). + IF lv_kg > 0. + rv_fee = lv_kg * c_fee_per_kg. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0150/faulty/m4_vet_fee_calc.clas.abap b/tasks_gen/eval/G0150/faulty/m4_vet_fee_calc.clas.abap new file mode 100644 index 0000000..d2ca257 --- /dev/null +++ b/tasks_gen/eval/G0150/faulty/m4_vet_fee_calc.clas.abap @@ -0,0 +1,73 @@ +CLASS {{p}}vet_fee_calc DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_vet_fee. + + PRIVATE SECTION. + TYPES: + BEGIN OF ty_base_fee, + species TYPE {{p}}if_vet_fee=>ty_species, + amount TYPE {{p}}if_vet_fee=>ty_amount, + END OF ty_base_fee, + tt_base_fee TYPE HASHED TABLE OF ty_base_fee WITH UNIQUE KEY species. + + CONSTANTS: + c_free_kg TYPE i VALUE 5, + c_max_kg TYPE i VALUE 200, + c_fee_per_kg TYPE {{p}}if_vet_fee=>ty_amount VALUE '2.00'. + + METHODS normalize_species + IMPORTING iv_species TYPE {{p}}if_vet_fee=>ty_species + RETURNING VALUE(rv_species) TYPE {{p}}if_vet_fee=>ty_species. + METHODS base_fees + RETURNING VALUE(rt_base_fee) TYPE tt_base_fee. + METHODS medication_fee + IMPORTING iv_weight TYPE {{p}}if_vet_fee=>ty_weight + RETURNING VALUE(rv_fee) TYPE {{p}}if_vet_fee=>ty_amount. +ENDCLASS. + + +CLASS {{p}}vet_fee_calc IMPLEMENTATION. + METHOD {{p}}if_vet_fee~calculate. + DATA(lv_species) = normalize_species( iv_species ). + DATA(lt_base_fee) = base_fees( ). + ASSIGN lt_base_fee[ species = lv_species ] TO FIELD-SYMBOL(). + IF sy-subrc <> 0. + rs_result = VALUE #( reason = {{p}}if_vet_fee=>c_reason-species ). + RETURN. + ENDIF. + IF iv_weight <= 0 OR iv_weight > c_max_kg. + rs_result = VALUE #( reason = {{p}}if_vet_fee=>c_reason-weight ). + RETURN. + ENDIF. + DATA(lv_medication) = medication_fee( iv_weight ). + DATA lv_fee TYPE {{p}}if_vet_fee=>ty_amount. + lv_fee = -amount + lv_medication. + IF iv_emergency = abap_true. + lv_fee = lv_fee + -amount / 2. + ENDIF. + IF iv_registered = abap_true. + lv_fee = lv_fee - ( -amount + lv_medication ) / 10. + ENDIF. + rs_result = VALUE #( fee = lv_fee reason = {{p}}if_vet_fee=>c_reason-ok ). + ENDMETHOD. + + METHOD normalize_species. + rv_species = to_upper( replace( val = iv_species sub = ` ` with = `` occ = 0 ) ). + ENDMETHOD. + + METHOD base_fees. + rt_base_fee = VALUE #( ( species = 'DOG' amount = '45.00' ) + ( species = 'CAT' amount = '35.00' ) + ( species = 'RABBIT' amount = '25.00' ) + ( species = 'BIRD' amount = '18.00' ) + ( species = 'REPTILE' amount = '30.00' ) ). + ENDMETHOD. + + METHOD medication_fee. + DATA lv_kg TYPE i. + lv_kg = ceil( iv_weight - c_free_kg ). + IF lv_kg <= 0. + rv_fee = lv_kg * c_fee_per_kg. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0150/generation.json b/tasks_gen/eval/G0150/generation.json new file mode 100644 index 0000000..e4537e7 --- /dev/null +++ b/tasks_gen/eval/G0150/generation.json @@ -0,0 +1,19 @@ +{ + "id": "G0150", + "pool": "eval", + "object_type": "CLAS", + "category": "F", + "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/eval/G0150/hidden/vet_fee_hidden.clas.abap b/tasks_gen/eval/G0150/hidden/vet_fee_hidden.clas.abap new file mode 100644 index 0000000..24e8fba --- /dev/null +++ b/tasks_gen/eval/G0150/hidden/vet_fee_hidden.clas.abap @@ -0,0 +1,171 @@ +CLASS {{p}}vet_fee_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + DATA mo_cut TYPE REF TO {{p}}if_vet_fee. + METHODS setup. + METHODS assert_fee + IMPORTING iv_expected TYPE {{p}}if_vet_fee=>ty_amount + iv_actual TYPE {{p}}if_vet_fee=>ty_amount. + METHODS dog_base_fee FOR TESTING. + METHODS medication_started_kg FOR TESTING. + METHODS no_medication_at_five_kg FOR TESTING. + METHODS emergency_surcharge FOR TESTING. + METHODS registered_discount FOR TESTING. + METHODS combined_charges FOR TESTING. + METHODS unknown_species FOR TESTING. + METHODS species_lower_case FOR TESTING. + METHODS zero_weight FOR TESTING. + METHODS weight_limit_checked FOR TESTING. + METHODS species_before_weight FOR TESTING. + METHODS bird_and_reptile_base FOR TESTING. +ENDCLASS. + + +CLASS {{p}}vet_fee_hidden IMPLEMENTATION. + METHOD setup. + mo_cut = NEW {{p}}vet_fee_calc( ). + ENDMETHOD. + + METHOD assert_fee. + cl_abap_unit_assert=>assert_equals( exp = iv_expected act = iv_actual ). + ENDMETHOD. + + METHOD dog_base_fee. + DATA(ls_result) = mo_cut->calculate( + iv_species = 'DOG' + iv_weight = '5.000' + iv_emergency = abap_false + iv_registered = abap_false ). + assert_fee( iv_expected = '45.00' iv_actual = ls_result-fee ). + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_vet_fee=>c_reason-ok + act = ls_result-reason ). + ENDMETHOD. + + METHOD medication_started_kg. + DATA(ls_result) = mo_cut->calculate( + iv_species = 'DOG' + iv_weight = '7.001' + iv_emergency = abap_false + iv_registered = abap_false ). + assert_fee( iv_expected = '51.00' iv_actual = ls_result-fee ). + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_vet_fee=>c_reason-ok + act = ls_result-reason ). + ENDMETHOD. + + METHOD no_medication_at_five_kg. + DATA(ls_result) = mo_cut->calculate( + iv_species = 'CAT' + iv_weight = '5.000' + iv_emergency = abap_false + iv_registered = abap_false ). + assert_fee( iv_expected = '35.00' iv_actual = ls_result-fee ). + ENDMETHOD. + + METHOD emergency_surcharge. + DATA(ls_result) = mo_cut->calculate( + iv_species = 'DOG' + iv_weight = '5.000' + iv_emergency = abap_true + iv_registered = abap_false ). + assert_fee( iv_expected = '67.50' iv_actual = ls_result-fee ). + ENDMETHOD. + + METHOD registered_discount. + DATA(ls_result) = mo_cut->calculate( + iv_species = 'CAT' + iv_weight = '5.000' + iv_emergency = abap_false + iv_registered = abap_true ). + assert_fee( iv_expected = '31.50' iv_actual = ls_result-fee ). + ENDMETHOD. + + METHOD combined_charges. + DATA(ls_result) = mo_cut->calculate( + iv_species = 'RABBIT' + iv_weight = '6.500' + iv_emergency = abap_true + iv_registered = abap_true ). + assert_fee( iv_expected = '38.60' iv_actual = ls_result-fee ). + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_vet_fee=>c_reason-ok + act = ls_result-reason ). + ENDMETHOD. + + METHOD unknown_species. + DATA(ls_result) = mo_cut->calculate( + iv_species = 'HORSE' + iv_weight = '10.000' + iv_emergency = abap_false + iv_registered = abap_false ). + assert_fee( iv_expected = '0.00' iv_actual = ls_result-fee ). + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_vet_fee=>c_reason-species + act = ls_result-reason ). + ENDMETHOD. + + METHOD species_lower_case. + DATA(ls_result) = mo_cut->calculate( + iv_species = ' dog ' + iv_weight = '5.000' + iv_emergency = abap_false + iv_registered = abap_false ). + assert_fee( iv_expected = '45.00' iv_actual = ls_result-fee ). + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_vet_fee=>c_reason-ok + act = ls_result-reason ). + ENDMETHOD. + + METHOD zero_weight. + DATA(ls_result) = mo_cut->calculate( + iv_species = 'DOG' + iv_weight = '0.000' + iv_emergency = abap_false + iv_registered = abap_false ). + assert_fee( iv_expected = '0.00' iv_actual = ls_result-fee ). + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_vet_fee=>c_reason-weight + act = ls_result-reason ). + ENDMETHOD. + + METHOD weight_limit_checked. + DATA(ls_ok) = mo_cut->calculate( + iv_species = 'DOG' + iv_weight = '200.000' + iv_emergency = abap_false + iv_registered = abap_false ). + assert_fee( iv_expected = '435.00' iv_actual = ls_ok-fee ). + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_vet_fee=>c_reason-ok + act = ls_ok-reason ). + + DATA(ls_heavy) = mo_cut->calculate( + iv_species = 'DOG' + iv_weight = '200.001' + iv_emergency = abap_false + iv_registered = abap_false ). + assert_fee( iv_expected = '0.00' iv_actual = ls_heavy-fee ). + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_vet_fee=>c_reason-weight + act = ls_heavy-reason ). + ENDMETHOD. + + METHOD species_before_weight. + DATA(ls_result) = mo_cut->calculate( + iv_species = 'HORSE' + iv_weight = '0.000' + iv_emergency = abap_false + iv_registered = abap_false ). + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_vet_fee=>c_reason-species + act = ls_result-reason ). + ENDMETHOD. + + METHOD bird_and_reptile_base. + DATA(ls_bird) = mo_cut->calculate( + iv_species = 'BIRD' + iv_weight = '5.000' + iv_emergency = abap_false + iv_registered = abap_false ). + assert_fee( iv_expected = '18.00' iv_actual = ls_bird-fee ). + + DATA(ls_reptile) = mo_cut->calculate( + iv_species = 'REPTILE' + iv_weight = '5.000' + iv_emergency = abap_false + iv_registered = abap_false ). + assert_fee( iv_expected = '30.00' iv_actual = ls_reptile-fee ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0150/mutation.json b/tasks_gen/eval/G0150/mutation.json new file mode 100644 index 0000000..b76f433 --- /dev/null +++ b/tasks_gen/eval/G0150/mutation.json @@ -0,0 +1,74 @@ +{ + "task": "G0150", + "mutants": [ + { + "object": "{{P}}VET_FEE_CALC", + "mutant": "line 38: OR -> AND (logic)", + "status": "killed", + "hidden": "10/12", + "failed_tests": [ + "WEIGHT_LIMIT_CHECKED", + "ZERO_WEIGHT" + ] + }, + { + "object": "{{P}}VET_FEE_CALC", + "mutant": "line 45: abap_true -> abap_false (bool)", + "status": "killed", + "hidden": "3/12", + "failed_tests": [ + "BIRD_AND_REPTILE_BASE", + "COMBINED_CHARGES", + "DOG_BASE_FEE", + "EMERGENCY_SURCHARGE", + "MEDICATION_STARTED_KG", + "NO_MEDICATION_AT_FIVE_KG", + "REGISTERED_DISCOUNT", + "SPECIES_LOWER_CASE", + "WEIGHT_LIMIT_CHECKED" + ] + }, + { + "object": "{{P}}VET_FEE_CALC", + "mutant": "line 48: = -> <> (eq)", + "status": "killed", + "hidden": "3/12", + "failed_tests": [ + "BIRD_AND_REPTILE_BASE", + "COMBINED_CHARGES", + "DOG_BASE_FEE", + "EMERGENCY_SURCHARGE", + "MEDICATION_STARTED_KG", + "NO_MEDICATION_AT_FIVE_KG", + "REGISTERED_DISCOUNT", + "SPECIES_LOWER_CASE", + "WEIGHT_LIMIT_CHECKED" + ] + }, + { + "object": "{{P}}VET_FEE_CALC", + "mutant": "line 49: - -> + (arith)", + "status": "killed", + "hidden": "10/12", + "failed_tests": [ + "COMBINED_CHARGES", + "REGISTERED_DISCOUNT" + ] + }, + { + "object": "{{P}}VET_FEE_CALC", + "mutant": "line 69: > -> <= (rel)", + "status": "killed", + "hidden": "9/12", + "failed_tests": [ + "COMBINED_CHARGES", + "MEDICATION_STARTED_KG", + "WEIGHT_LIMIT_CHECKED" + ] + } + ], + "valid": 5, + "killed": 5, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0150/reference/vet_fee_calc.clas.abap b/tasks_gen/eval/G0150/reference/vet_fee_calc.clas.abap new file mode 100644 index 0000000..52e6b54 --- /dev/null +++ b/tasks_gen/eval/G0150/reference/vet_fee_calc.clas.abap @@ -0,0 +1,73 @@ +CLASS {{p}}vet_fee_calc DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_vet_fee. + + PRIVATE SECTION. + TYPES: + BEGIN OF ty_base_fee, + species TYPE {{p}}if_vet_fee=>ty_species, + amount TYPE {{p}}if_vet_fee=>ty_amount, + END OF ty_base_fee, + tt_base_fee TYPE HASHED TABLE OF ty_base_fee WITH UNIQUE KEY species. + + CONSTANTS: + c_free_kg TYPE i VALUE 5, + c_max_kg TYPE i VALUE 200, + c_fee_per_kg TYPE {{p}}if_vet_fee=>ty_amount VALUE '2.00'. + + METHODS normalize_species + IMPORTING iv_species TYPE {{p}}if_vet_fee=>ty_species + RETURNING VALUE(rv_species) TYPE {{p}}if_vet_fee=>ty_species. + METHODS base_fees + RETURNING VALUE(rt_base_fee) TYPE tt_base_fee. + METHODS medication_fee + IMPORTING iv_weight TYPE {{p}}if_vet_fee=>ty_weight + RETURNING VALUE(rv_fee) TYPE {{p}}if_vet_fee=>ty_amount. +ENDCLASS. + + +CLASS {{p}}vet_fee_calc IMPLEMENTATION. + METHOD {{p}}if_vet_fee~calculate. + DATA(lv_species) = normalize_species( iv_species ). + DATA(lt_base_fee) = base_fees( ). + ASSIGN lt_base_fee[ species = lv_species ] TO FIELD-SYMBOL(). + IF sy-subrc <> 0. + rs_result = VALUE #( reason = {{p}}if_vet_fee=>c_reason-species ). + RETURN. + ENDIF. + IF iv_weight <= 0 OR iv_weight > c_max_kg. + rs_result = VALUE #( reason = {{p}}if_vet_fee=>c_reason-weight ). + RETURN. + ENDIF. + DATA(lv_medication) = medication_fee( iv_weight ). + DATA lv_fee TYPE {{p}}if_vet_fee=>ty_amount. + lv_fee = -amount + lv_medication. + IF iv_emergency = abap_true. + lv_fee = lv_fee + -amount / 2. + ENDIF. + IF iv_registered = abap_true. + lv_fee = lv_fee - ( -amount + lv_medication ) / 10. + ENDIF. + rs_result = VALUE #( fee = lv_fee reason = {{p}}if_vet_fee=>c_reason-ok ). + ENDMETHOD. + + METHOD normalize_species. + rv_species = to_upper( replace( val = iv_species sub = ` ` with = `` occ = 0 ) ). + ENDMETHOD. + + METHOD base_fees. + rt_base_fee = VALUE #( ( species = 'DOG' amount = '45.00' ) + ( species = 'CAT' amount = '35.00' ) + ( species = 'RABBIT' amount = '25.00' ) + ( species = 'BIRD' amount = '18.00' ) + ( species = 'REPTILE' amount = '30.00' ) ). + ENDMETHOD. + + METHOD medication_fee. + DATA lv_kg TYPE i. + lv_kg = ceil( iv_weight - c_free_kg ). + IF lv_kg > 0. + rv_fee = lv_kg * c_fee_per_kg. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0150/reference/vet_fee_calc.testclasses.abap b/tasks_gen/eval/G0150/reference/vet_fee_calc.testclasses.abap new file mode 100644 index 0000000..cf1094b --- /dev/null +++ b/tasks_gen/eval/G0150/reference/vet_fee_calc.testclasses.abap @@ -0,0 +1,85 @@ +CLASS ltc_vet_fee_calc DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + DATA mo_cut TYPE REF TO {{p}}if_vet_fee. + METHODS setup. + METHODS assert_fee + IMPORTING iv_expected TYPE {{p}}if_vet_fee=>ty_amount + iv_actual TYPE {{p}}if_vet_fee=>ty_amount. + METHODS dog_visit FOR TESTING. + METHODS medication_for_started_kg FOR TESTING. + METHODS emergency_visit FOR TESTING. + METHODS registered_patient FOR TESTING. + METHODS unknown_species FOR TESTING. + METHODS invalid_weight FOR TESTING. +ENDCLASS. + + +CLASS ltc_vet_fee_calc IMPLEMENTATION. + METHOD setup. + mo_cut = NEW {{p}}vet_fee_calc( ). + ENDMETHOD. + + METHOD assert_fee. + cl_abap_unit_assert=>assert_equals( exp = iv_expected act = iv_actual ). + ENDMETHOD. + + METHOD dog_visit. + DATA(ls_result) = mo_cut->calculate( + iv_species = 'DOG' + iv_weight = '5.000' + iv_emergency = abap_false + iv_registered = abap_false ). + assert_fee( iv_expected = '45.00' iv_actual = ls_result-fee ). + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_vet_fee=>c_reason-ok + act = ls_result-reason ). + ENDMETHOD. + + METHOD medication_for_started_kg. + DATA(ls_result) = mo_cut->calculate( + iv_species = 'DOG' + iv_weight = '7.001' + iv_emergency = abap_false + iv_registered = abap_false ). + assert_fee( iv_expected = '51.00' iv_actual = ls_result-fee ). + ENDMETHOD. + + METHOD emergency_visit. + DATA(ls_result) = mo_cut->calculate( + iv_species = 'DOG' + iv_weight = '5.000' + iv_emergency = abap_true + iv_registered = abap_false ). + assert_fee( iv_expected = '67.50' iv_actual = ls_result-fee ). + ENDMETHOD. + + METHOD registered_patient. + DATA(ls_result) = mo_cut->calculate( + iv_species = 'CAT' + iv_weight = '5.000' + iv_emergency = abap_false + iv_registered = abap_true ). + assert_fee( iv_expected = '31.50' iv_actual = ls_result-fee ). + ENDMETHOD. + + METHOD unknown_species. + DATA(ls_result) = mo_cut->calculate( + iv_species = 'HORSE' + iv_weight = '10.000' + iv_emergency = abap_false + iv_registered = abap_false ). + assert_fee( iv_expected = '0.00' iv_actual = ls_result-fee ). + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_vet_fee=>c_reason-species + act = ls_result-reason ). + ENDMETHOD. + + METHOD invalid_weight. + DATA(ls_result) = mo_cut->calculate( + iv_species = 'DOG' + iv_weight = '250.000' + iv_emergency = abap_false + iv_registered = abap_false ). + assert_fee( iv_expected = '0.00' iv_actual = ls_result-fee ). + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_vet_fee=>c_reason-weight + act = ls_result-reason ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0150/seed/if_vet_fee.intf.abap b/tasks_gen/eval/G0150/seed/if_vet_fee.intf.abap new file mode 100644 index 0000000..73381e7 --- /dev/null +++ b/tasks_gen/eval/G0150/seed/if_vet_fee.intf.abap @@ -0,0 +1,27 @@ +INTERFACE {{p}}if_vet_fee PUBLIC. + TYPES: + ty_species TYPE c LENGTH 8, + ty_weight TYPE p LENGTH 7 DECIMALS 3, + ty_amount TYPE p LENGTH 9 DECIMALS 2, + ty_reason TYPE c LENGTH 10. + + TYPES: + BEGIN OF ty_result, + fee TYPE ty_amount, + reason TYPE ty_reason, + END OF ty_result. + + CONSTANTS: + BEGIN OF c_reason, + ok TYPE ty_reason VALUE 'OK', + species TYPE ty_reason VALUE 'SPECIES', + weight TYPE ty_reason VALUE 'WEIGHT', + END OF c_reason. + + METHODS calculate + IMPORTING iv_species TYPE ty_species + iv_weight TYPE ty_weight + iv_emergency TYPE abap_bool + iv_registered TYPE abap_bool + RETURNING VALUE(rs_result) TYPE ty_result. +ENDINTERFACE. diff --git a/tasks_gen/eval/G0150/spec.md b/tasks_gen/eval/G0150/spec.md new file mode 100644 index 0000000..377bf82 --- /dev/null +++ b/tasks_gen/eval/G0150/spec.md @@ -0,0 +1,53 @@ +# 1. Goal +Calculate the consultation fee of a visit at a veterinary clinic. A clinic program +calls the calculation before it prints the invoice. The program needs the fee and +one reason code for each visit. + +# 2. Open questions +None. + +# 3. Context +- The interface {{P}}IF_VET_FEE exists in package $TMP. It is active. Read the + interface. It contains the types, the constants and the method signature that + the calculation uses. +- The interface is not part of this task. + +# 4. Contract +- Create the class {{P}}VET_FEE_CALC in package $TMP. +- The class is public, final, and has a public constructor without parameters. +- The class implements {{P}}IF_VET_FEE. +- Do not add other public methods. + +# 5. Business rules +The rules run in this sequence. Rules 1 to 3 prepare and check the input. +Rules 4 to 8 calculate the fee. +1. Remove all spaces from the species. Convert all letters to upper case. +2. The species must be DOG, CAT, RABBIT, BIRD or REPTILE. If not, the + calculation returns the reason SPECIES and a fee of 0. +3. The weight must be above 0 kg and at most 200 kg. If not, the calculation + returns the reason WEIGHT and a fee of 0. +4. The base fee depends on the species: + DOG 45.00, CAT 35.00, RABBIT 25.00, BIRD 18.00, REPTILE 30.00. +5. The medication fee is 2.00 for each started kilogram of weight above 5 kg. + Examples: 5.000 kg gives 0.00, 5.001 kg gives 2.00, 7.000 kg gives 4.00, + 7.001 kg gives 6.00. +6. If the visit is an emergency, add half of the base fee. For a dog the + surcharge is 22.50. +7. If the animal is a registered patient of the clinic, subtract 10 percent of + the base fee plus the medication fee. The emergency surcharge is not part of + the discount. The base fee plus the medication fee is always a whole number + of euro, so the discount has at most one decimal place. +8. The fee is the base fee plus the medication fee plus the emergency surcharge + minus the registered discount. The calculation returns the reason OK and + this fee. + +# 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 {{P}}IF_VET_FEE. + +# 7. Acceptance +- The class is active and has no syntax error. +- The hidden tests pass. +- Write your own ABAP Unit tests for the class. diff --git a/tasks_gen/eval/G0150/task.json b/tasks_gen/eval/G0150/task.json new file mode 100644 index 0000000..7e05fbb --- /dev/null +++ b/tasks_gen/eval/G0150/task.json @@ -0,0 +1,51 @@ +{ + "id": "G0150", + "category": "F", + "object_type": "CLAS", + "difficulty": 2, + "release_target": "v758", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [ + { + "type": "INTF", + "name": "{{P}}IF_VET_FEE", + "file": "seed/if_vet_fee.intf.abap", + "description": "Veterinary consultation fee contract; the model must read it" + } + ], + "contract": [ + { + "type": "CLAS", + "name": "{{P}}VET_FEE_CALC", + "implements": "{{P}}IF_VET_FEE" + } + ], + "out_of_scope": [ + "{{P}}IF_VET_FEE" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}VET_FEE_HIDDEN", + "file": "hidden/vet_fee_hidden.clas.abap", + "description": "T41 hidden tests" + } + ], + "reference": [ + { + "type": "CLAS", + "name": "{{P}}VET_FEE_CALC", + "file": "reference/vet_fee_calc.clas.abap", + "description": "Veterinary consultation fee calculator", + "testclasses_file": "reference/vet_fee_calc.testclasses.abap" + } + ], + "craft_checks": [ + "method_length", + "clean_abap" + ] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0151/faulty/m0_groom_fee.func.abap b/tasks_gen/eval/G0151/faulty/m0_groom_fee.func.abap new file mode 100644 index 0000000..0e73fa1 --- /dev/null +++ b/tasks_gen/eval/G0151/faulty/m0_groom_fee.func.abap @@ -0,0 +1,44 @@ +FUNCTION {{p}}groom_fee + IMPORTING + iv_size TYPE string + iv_long_hair TYPE abap_bool + iv_weekend TYPE abap_bool + iv_channel TYPE string + EXPORTING + ev_skip TYPE abap_bool + CHANGING + cv_fee TYPE decfloat34 + EXCEPTIONS + invalid_size. + + DATA lv_base TYPE decfloat34. + + ev_skip = abap_false. + + CASE iv_size. + WHEN 'S'. + lv_base = '26.50'. + WHEN 'M'. + lv_base = '42.50'. + WHEN 'L'. + lv_base = '64.50'. + WHEN OTHERS. + RAISE invalid_size. + ENDCASE. + + IF iv_channel = 'PARTNER'. + ev_skip = abap_false. + RETURN. + ENDIF. + + cv_fee = lv_base. + IF iv_long_hair = abap_true. + cv_fee = cv_fee + round( val = lv_base * 15 / 100 + dec = 2 + mode = cl_abap_math=>round_half_up ). + ENDIF. + IF iv_weekend = abap_true. + cv_fee = cv_fee + 10. + ENDIF. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0151/faulty/m1_groom_fee.func.abap b/tasks_gen/eval/G0151/faulty/m1_groom_fee.func.abap new file mode 100644 index 0000000..558e9be --- /dev/null +++ b/tasks_gen/eval/G0151/faulty/m1_groom_fee.func.abap @@ -0,0 +1,44 @@ +FUNCTION {{p}}groom_fee + IMPORTING + iv_size TYPE string + iv_long_hair TYPE abap_bool + iv_weekend TYPE abap_bool + iv_channel TYPE string + EXPORTING + ev_skip TYPE abap_bool + CHANGING + cv_fee TYPE decfloat34 + EXCEPTIONS + invalid_size. + + DATA lv_base TYPE decfloat34. + + ev_skip = abap_false. + + CASE iv_size. + WHEN 'S'. + lv_base = '26.50'. + WHEN 'M'. + lv_base = '42.50'. + WHEN 'L'. + lv_base = '64.50'. + WHEN OTHERS. + RAISE invalid_size. + ENDCASE. + + IF iv_channel = 'PARTNER'. + ev_skip = abap_true. + RETURN. + ENDIF. + + cv_fee = lv_base. + IF iv_long_hair = abap_false. + cv_fee = cv_fee + round( val = lv_base * 15 / 100 + dec = 2 + mode = cl_abap_math=>round_half_up ). + ENDIF. + IF iv_weekend = abap_true. + cv_fee = cv_fee + 10. + ENDIF. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0151/faulty/m2_groom_fee.func.abap b/tasks_gen/eval/G0151/faulty/m2_groom_fee.func.abap new file mode 100644 index 0000000..77b6e1c --- /dev/null +++ b/tasks_gen/eval/G0151/faulty/m2_groom_fee.func.abap @@ -0,0 +1,44 @@ +FUNCTION {{p}}groom_fee + IMPORTING + iv_size TYPE string + iv_long_hair TYPE abap_bool + iv_weekend TYPE abap_bool + iv_channel TYPE string + EXPORTING + ev_skip TYPE abap_bool + CHANGING + cv_fee TYPE decfloat34 + EXCEPTIONS + invalid_size. + + DATA lv_base TYPE decfloat34. + + ev_skip = abap_false. + + CASE iv_size. + WHEN 'S'. + lv_base = '26.50'. + WHEN 'M'. + lv_base = '42.50'. + WHEN 'L'. + lv_base = '64.50'. + WHEN OTHERS. + RAISE invalid_size. + ENDCASE. + + IF iv_channel = 'PARTNER'. + ev_skip = abap_true. + RETURN. + ENDIF. + + cv_fee = lv_base. + IF iv_long_hair = abap_true. + cv_fee = cv_fee - round( val = lv_base * 15 / 100 + dec = 2 + mode = cl_abap_math=>round_half_up ). + ENDIF. + IF iv_weekend = abap_true. + cv_fee = cv_fee + 10. + ENDIF. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0151/faulty/m3_groom_fee.func.abap b/tasks_gen/eval/G0151/faulty/m3_groom_fee.func.abap new file mode 100644 index 0000000..7b37d2f --- /dev/null +++ b/tasks_gen/eval/G0151/faulty/m3_groom_fee.func.abap @@ -0,0 +1,44 @@ +FUNCTION {{p}}groom_fee + IMPORTING + iv_size TYPE string + iv_long_hair TYPE abap_bool + iv_weekend TYPE abap_bool + iv_channel TYPE string + EXPORTING + ev_skip TYPE abap_bool + CHANGING + cv_fee TYPE decfloat34 + EXCEPTIONS + invalid_size. + + DATA lv_base TYPE decfloat34. + + ev_skip = abap_false. + + CASE iv_size. + WHEN 'S'. + lv_base = '26.50'. + WHEN 'M'. + lv_base = '42.50'. + WHEN 'L'. + lv_base = '64.50'. + WHEN OTHERS. + RAISE invalid_size. + ENDCASE. + + IF iv_channel = 'PARTNER'. + ev_skip = abap_true. + RETURN. + ENDIF. + + cv_fee = lv_base. + IF iv_long_hair = abap_true. + cv_fee = cv_fee + round( val = lv_base * 15 / 100 + dec = 3 + mode = cl_abap_math=>round_half_up ). + ENDIF. + IF iv_weekend = abap_true. + cv_fee = cv_fee + 10. + ENDIF. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0151/faulty/m4_groom_fee.func.abap b/tasks_gen/eval/G0151/faulty/m4_groom_fee.func.abap new file mode 100644 index 0000000..d902fef --- /dev/null +++ b/tasks_gen/eval/G0151/faulty/m4_groom_fee.func.abap @@ -0,0 +1,44 @@ +FUNCTION {{p}}groom_fee + IMPORTING + iv_size TYPE string + iv_long_hair TYPE abap_bool + iv_weekend TYPE abap_bool + iv_channel TYPE string + EXPORTING + ev_skip TYPE abap_bool + CHANGING + cv_fee TYPE decfloat34 + EXCEPTIONS + invalid_size. + + DATA lv_base TYPE decfloat34. + + ev_skip = abap_false. + + CASE iv_size. + WHEN 'S'. + lv_base = '26.50'. + WHEN 'M'. + lv_base = '42.50'. + WHEN 'L'. + lv_base = '64.50'. + WHEN OTHERS. + RAISE invalid_size. + ENDCASE. + + IF iv_channel = 'PARTNER'. + ev_skip = abap_true. + RETURN. + ENDIF. + + cv_fee = lv_base. + IF iv_long_hair = abap_true. + cv_fee = cv_fee + round( val = lv_base * 15 / 100 + dec = 2 + mode = cl_abap_math=>round_half_up ). + ENDIF. + IF iv_weekend <> abap_true. + cv_fee = cv_fee + 10. + ENDIF. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0151/generation.json b/tasks_gen/eval/G0151/generation.json new file mode 100644 index 0000000..45a4400 --- /dev/null +++ b/tasks_gen/eval/G0151/generation.json @@ -0,0 +1,19 @@ +{ + "id": "G0151", + "pool": "eval", + "object_type": "FUNC", + "category": "F", + "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/eval/G0151/hidden/t14_hidden.clas.abap b/tasks_gen/eval/G0151/hidden/t14_hidden.clas.abap new file mode 100644 index 0000000..08e78ad --- /dev/null +++ b/tasks_gen/eval/G0151/hidden/t14_hidden.clas.abap @@ -0,0 +1,108 @@ +CLASS {{p}}t14_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS call + IMPORTING iv_size TYPE string + iv_long_hair TYPE abap_bool + iv_weekend TYPE abap_bool + iv_channel TYPE string + iv_fee TYPE decfloat34 DEFAULT 7 + EXPORTING ev_skip TYPE abap_bool + ev_fee TYPE decfloat34 + ev_subrc TYPE sysubrc. + METHODS small_base FOR TESTING. + METHODS medium_base FOR TESTING. + METHODS large_base FOR TESTING. + METHODS long_hair_surcharge FOR TESTING. + METHODS weekend_surcharge FOR TESTING. + METHODS combined_surcharges FOR TESTING. + METHODS partner_skips FOR TESTING. + METHODS invalid_size FOR TESTING. + METHODS skip_false_for_shop FOR TESTING. + METHODS partner_invalid_size FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t14_hidden IMPLEMENTATION. + METHOD call. + ev_fee = iv_fee. + CALL FUNCTION '{{P}}GROOM_FEE' + EXPORTING + iv_size = iv_size + iv_long_hair = iv_long_hair + iv_weekend = iv_weekend + iv_channel = iv_channel + IMPORTING + ev_skip = ev_skip + CHANGING + cv_fee = ev_fee + EXCEPTIONS + invalid_size = 1 + OTHERS = 2. + ev_subrc = sy-subrc. + ENDMETHOD. + + METHOD small_base. + call( EXPORTING iv_size = `S` iv_long_hair = abap_false iv_weekend = abap_false iv_channel = `SHOP` + IMPORTING ev_fee = DATA(lv_fee) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '26.50' ) act = lv_fee ). + ENDMETHOD. + + METHOD medium_base. + call( EXPORTING iv_size = `M` iv_long_hair = abap_false iv_weekend = abap_false iv_channel = `WEB` + IMPORTING ev_fee = DATA(lv_fee) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '42.50' ) act = lv_fee ). + ENDMETHOD. + + METHOD large_base. + call( EXPORTING iv_size = `L` iv_long_hair = abap_false iv_weekend = abap_false iv_channel = `SHOP` + IMPORTING ev_fee = DATA(lv_fee) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '64.50' ) act = lv_fee ). + ENDMETHOD. + + METHOD long_hair_surcharge. + " 26.50 + 15 % of 26.50 = 26.50 + 3.98 + call( EXPORTING iv_size = `S` iv_long_hair = abap_true iv_weekend = abap_false iv_channel = `SHOP` + IMPORTING ev_fee = DATA(lv_fee) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '30.48' ) act = lv_fee ). + ENDMETHOD. + + METHOD weekend_surcharge. + call( EXPORTING iv_size = `M` iv_long_hair = abap_false iv_weekend = abap_true iv_channel = `SHOP` + IMPORTING ev_fee = DATA(lv_fee) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '52.50' ) act = lv_fee ). + ENDMETHOD. + + METHOD combined_surcharges. + " 64.50 + 15 % of 64.50 = 64.50 + 9.68, plus 10.00 + call( EXPORTING iv_size = `L` iv_long_hair = abap_true iv_weekend = abap_true iv_channel = `WEB` + IMPORTING ev_fee = DATA(lv_fee) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '84.18' ) act = lv_fee ). + ENDMETHOD. + + METHOD partner_skips. + call( EXPORTING iv_size = `M` iv_long_hair = abap_false iv_weekend = abap_false + iv_channel = `PARTNER` iv_fee = 7 + IMPORTING ev_skip = DATA(lv_skip) ev_fee = DATA(lv_fee) ). + cl_abap_unit_assert=>assert_equals( exp = abap_true act = lv_skip ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 7 ) act = lv_fee ). + ENDMETHOD. + + METHOD invalid_size. + call( EXPORTING iv_size = `X` iv_long_hair = abap_false iv_weekend = abap_false iv_channel = `SHOP` + IMPORTING ev_subrc = DATA(lv_rc) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lv_rc ). + ENDMETHOD. + + METHOD skip_false_for_shop. + call( EXPORTING iv_size = `S` iv_long_hair = abap_false iv_weekend = abap_false iv_channel = `SHOP` + IMPORTING ev_skip = DATA(lv_skip) ). + cl_abap_unit_assert=>assert_equals( exp = abap_false act = lv_skip ). + ENDMETHOD. + + METHOD partner_invalid_size. + call( EXPORTING iv_size = `X` iv_long_hair = abap_false iv_weekend = abap_false iv_channel = `PARTNER` + IMPORTING ev_subrc = DATA(lv_rc) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lv_rc ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0151/mutation.json b/tasks_gen/eval/G0151/mutation.json new file mode 100644 index 0000000..c335f80 --- /dev/null +++ b/tasks_gen/eval/G0151/mutation.json @@ -0,0 +1,66 @@ +{ + "task": "G0151", + "mutants": [ + { + "object": "{{P}}GROOM_FEE", + "mutant": "line 30: abap_true -> abap_false (bool)", + "status": "killed", + "hidden": "9/10", + "failed_tests": [ + "PARTNER_SKIPS" + ] + }, + { + "object": "{{P}}GROOM_FEE", + "mutant": "line 35: abap_true -> abap_false (bool)", + "status": "killed", + "hidden": "4/10", + "failed_tests": [ + "COMBINED_SURCHARGES", + "LARGE_BASE", + "LONG_HAIR_SURCHARGE", + "MEDIUM_BASE", + "SMALL_BASE", + "WEEKEND_SURCHARGE" + ] + }, + { + "object": "{{P}}GROOM_FEE", + "mutant": "line 36: + -> - (arith)", + "status": "killed", + "hidden": "8/10", + "failed_tests": [ + "COMBINED_SURCHARGES", + "LONG_HAIR_SURCHARGE" + ] + }, + { + "object": "{{P}}GROOM_FEE", + "mutant": "line 37: 2 -> 3 (const)", + "status": "killed", + "hidden": "8/10", + "failed_tests": [ + "COMBINED_SURCHARGES", + "LONG_HAIR_SURCHARGE" + ] + }, + { + "object": "{{P}}GROOM_FEE", + "mutant": "line 40: = -> <> (eq)", + "status": "killed", + "hidden": "4/10", + "failed_tests": [ + "COMBINED_SURCHARGES", + "LARGE_BASE", + "LONG_HAIR_SURCHARGE", + "MEDIUM_BASE", + "SMALL_BASE", + "WEEKEND_SURCHARGE" + ] + } + ], + "valid": 5, + "killed": 5, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0151/reference/groom_fee.func.abap b/tasks_gen/eval/G0151/reference/groom_fee.func.abap new file mode 100644 index 0000000..1ede817 --- /dev/null +++ b/tasks_gen/eval/G0151/reference/groom_fee.func.abap @@ -0,0 +1,44 @@ +FUNCTION {{p}}groom_fee + IMPORTING + iv_size TYPE string + iv_long_hair TYPE abap_bool + iv_weekend TYPE abap_bool + iv_channel TYPE string + EXPORTING + ev_skip TYPE abap_bool + CHANGING + cv_fee TYPE decfloat34 + EXCEPTIONS + invalid_size. + + DATA lv_base TYPE decfloat34. + + ev_skip = abap_false. + + CASE iv_size. + WHEN 'S'. + lv_base = '26.50'. + WHEN 'M'. + lv_base = '42.50'. + WHEN 'L'. + lv_base = '64.50'. + WHEN OTHERS. + RAISE invalid_size. + ENDCASE. + + IF iv_channel = 'PARTNER'. + ev_skip = abap_true. + RETURN. + ENDIF. + + cv_fee = lv_base. + IF iv_long_hair = abap_true. + cv_fee = cv_fee + round( val = lv_base * 15 / 100 + dec = 2 + mode = cl_abap_math=>round_half_up ). + ENDIF. + IF iv_weekend = abap_true. + cv_fee = cv_fee + 10. + ENDIF. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0151/reference/t14_test.clas.abap b/tasks_gen/eval/G0151/reference/t14_test.clas.abap new file mode 100644 index 0000000..423a8da --- /dev/null +++ b/tasks_gen/eval/G0151/reference/t14_test.clas.abap @@ -0,0 +1,86 @@ +CLASS {{p}}t14_test DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS fee_for + IMPORTING iv_size TYPE string + iv_long_hair TYPE abap_bool + iv_weekend TYPE abap_bool + iv_channel TYPE string + RETURNING VALUE(rv_fee) TYPE decfloat34. + METHODS base_fee FOR TESTING. + METHODS surcharges FOR TESTING. + METHODS partner_channel FOR TESTING. + METHODS invalid_size FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t14_test IMPLEMENTATION. + METHOD fee_for. + DATA lv_skip TYPE abap_bool. + CALL FUNCTION '{{P}}GROOM_FEE' + EXPORTING + iv_size = iv_size + iv_long_hair = iv_long_hair + iv_weekend = iv_weekend + iv_channel = iv_channel + IMPORTING + ev_skip = lv_skip + CHANGING + cv_fee = rv_fee + EXCEPTIONS + invalid_size = 1 + OTHERS = 2. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + ENDMETHOD. + + METHOD base_fee. + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( '42.50' ) + act = fee_for( iv_size = `M` iv_long_hair = abap_false + iv_weekend = abap_false iv_channel = `SHOP` ) ). + ENDMETHOD. + + METHOD surcharges. + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( '30.48' ) + act = fee_for( iv_size = `S` iv_long_hair = abap_true + iv_weekend = abap_false iv_channel = `SHOP` ) ). + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( '52.50' ) + act = fee_for( iv_size = `M` iv_long_hair = abap_false + iv_weekend = abap_true iv_channel = `SHOP` ) ). + ENDMETHOD. + + METHOD partner_channel. + DATA lv_skip TYPE abap_bool. + DATA lv_fee TYPE decfloat34 VALUE 5. + CALL FUNCTION '{{P}}GROOM_FEE' + EXPORTING + iv_size = `L` + iv_long_hair = abap_false + iv_weekend = abap_false + iv_channel = `PARTNER` + IMPORTING + ev_skip = lv_skip + CHANGING + cv_fee = lv_fee. + cl_abap_unit_assert=>assert_true( lv_skip ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 5 ) act = lv_fee ). + ENDMETHOD. + + METHOD invalid_size. + DATA lv_fee TYPE decfloat34. + CALL FUNCTION '{{P}}GROOM_FEE' + EXPORTING + iv_size = `XL` + iv_long_hair = abap_false + iv_weekend = abap_false + iv_channel = `SHOP` + CHANGING + cv_fee = lv_fee + EXCEPTIONS + invalid_size = 1 + OTHERS = 2. + cl_abap_unit_assert=>assert_equals( exp = 1 act = sy-subrc ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0151/seed/groom_sample.func.abap b/tasks_gen/eval/G0151/seed/groom_sample.func.abap new file mode 100644 index 0000000..f043d6c --- /dev/null +++ b/tasks_gen/eval/G0151/seed/groom_sample.func.abap @@ -0,0 +1,16 @@ +FUNCTION {{p}}groom_sample + IMPORTING + iv_size TYPE string + iv_long_hair TYPE abap_bool + iv_weekend TYPE abap_bool + iv_channel TYPE string + EXPORTING + ev_skip TYPE abap_bool + CHANGING + cv_fee TYPE decfloat34 + EXCEPTIONS + invalid_size. + + ev_skip = abap_false. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0151/spec.md b/tasks_gen/eval/G0151/spec.md new file mode 100644 index 0000000..6716b17 --- /dev/null +++ b/tasks_gen/eval/G0151/spec.md @@ -0,0 +1,40 @@ +# 1. Goal +Calculate the fee of a grooming appointment. A booking program calls one event +module for each appointment. The event module must have the same interface as the +sample event module, because the booking program calls all event modules in the +same way. + +# 2. Open questions +None. + +# 3. Context +- Function group {{P}}FG_GROOM exists in package $TMP. +- Function module {{P}}GROOM_SAMPLE exists in this group. It is the sample event + module. Its interface is the interface that all event modules must use. + +# 4. Contract +- Create the function module {{P}}GROOM_FEE in function group {{P}}FG_GROOM. +- Use exactly the interface of {{P}}GROOM_SAMPLE: the same parameter names, kinds, + types, and exceptions. + +# 5. Business rules +1. If the size is not one of 'S', 'M' or 'L', raise the exception INVALID_SIZE. + This check applies to every channel. +2. Set the skip flag to false. +3. If the channel is 'PARTNER', set the skip flag to true and do not change the + fee. Rules 4 to 7 do not apply. +4. The base fee depends on the size: S = 26.50, M = 42.50, L = 64.50. +5. If the hair is long, add 15 % of the base fee. Round the surcharge half up to + 2 decimals. +6. If the appointment is on a weekend, add 10.00. +7. The fee is the base fee plus the surcharges of rules 5 and 6. + +# 6. Constraints +- Release target: 7.58. +- Coding standards: Clean ABAP. +- Out of scope: do not change {{P}}GROOM_SAMPLE. + +# 7. Acceptance +- The function module is active and has no syntax error. +- The hidden tests pass. +- Write ABAP Unit tests for the function module in a global test class. diff --git a/tasks_gen/eval/G0151/task.json b/tasks_gen/eval/G0151/task.json new file mode 100644 index 0000000..ca9f888 --- /dev/null +++ b/tasks_gen/eval/G0151/task.json @@ -0,0 +1,88 @@ +{ + "id": "G0151", + "category": "F", + "object_type": "FUNC", + "difficulty": 2, + "release_target": "v758", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [ + { + "type": "FUGR", + "name": "{{P}}FG_GROOM", + "description": "Grooming fee events" + }, + { + "type": "FUNC", + "name": "{{P}}GROOM_SAMPLE", + "functionGroup": "{{P}}FG_GROOM", + "file": "seed/groom_sample.func.abap", + "description": "Sample grooming event module" + } + ], + "contract": [ + { + "type": "FUNC", + "name": "{{P}}GROOM_FEE", + "functionGroup": "{{P}}FG_GROOM", + "params": [ + { + "name": "iv_size", + "type": "string" + }, + { + "name": "iv_long_hair", + "type": "abap_bool" + }, + { + "name": "iv_weekend", + "type": "abap_bool" + }, + { + "name": "iv_channel", + "type": "string" + }, + { + "name": "ev_skip", + "type": "abap_bool" + }, + { + "name": "cv_fee", + "type": "decfloat34" + } + ] + } + ], + "out_of_scope": [ + "{{P}}GROOM_SAMPLE" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T14_HIDDEN", + "file": "hidden/t14_hidden.clas.abap", + "description": "T14 hidden tests" + } + ], + "reference": [ + { + "type": "FUNC", + "name": "{{P}}GROOM_FEE", + "functionGroup": "{{P}}FG_GROOM", + "file": "reference/groom_fee.func.abap", + "description": "Grooming fee event module" + }, + { + "type": "CLAS", + "name": "{{P}}T14_TEST", + "file": "reference/t14_test.clas.abap", + "description": "T14 own tests" + } + ], + "craft_checks": [ + "method_length" + ] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0152/faulty/m0_trl_price.func.abap b/tasks_gen/eval/G0152/faulty/m0_trl_price.func.abap new file mode 100644 index 0000000..03def05 --- /dev/null +++ b/tasks_gen/eval/G0152/faulty/m0_trl_price.func.abap @@ -0,0 +1,45 @@ +FUNCTION {{p}}trl_price + IMPORTING + iv_source_lang TYPE string + iv_target_lang TYPE string + iv_words TYPE i + iv_express TYPE abap_bool + EXPORTING + ev_price TYPE decfloat34 + EXCEPTIONS + invalid_words. + + IF iv_words < 0. + RAISE invalid_words. + ENDIF. + + IF iv_words = 0. + ev_price = 0. + RETURN. + ENDIF. + + DATA lv_rate TYPE decfloat34. + IF ( iv_source_lang = 'EN' AND iv_target_lang = 'DE' ) + AND ( iv_source_lang = 'DE' AND iv_target_lang = 'EN' ). + lv_rate = '0.12'. + ELSEIF ( iv_source_lang = 'EN' AND iv_target_lang = 'FR' ) + OR ( iv_source_lang = 'FR' AND iv_target_lang = 'EN' ). + lv_rate = '0.15'. + ELSE. + lv_rate = '0.20'. + ENDIF. + + DATA lv_amount TYPE decfloat34. + lv_amount = iv_words * lv_rate. + + IF iv_express = abap_true. + lv_amount = lv_amount * '1.25'. + ENDIF. + + ev_price = round( val = lv_amount dec = 2 mode = cl_abap_math=>round_half_up ). + + IF ev_price < 25. + ev_price = 25. + ENDIF. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0152/faulty/m2_trl_price.func.abap b/tasks_gen/eval/G0152/faulty/m2_trl_price.func.abap new file mode 100644 index 0000000..7a96f37 --- /dev/null +++ b/tasks_gen/eval/G0152/faulty/m2_trl_price.func.abap @@ -0,0 +1,45 @@ +FUNCTION {{p}}trl_price + IMPORTING + iv_source_lang TYPE string + iv_target_lang TYPE string + iv_words TYPE i + iv_express TYPE abap_bool + EXPORTING + ev_price TYPE decfloat34 + EXCEPTIONS + invalid_words. + + IF iv_words < 0. + RAISE invalid_words. + ENDIF. + + IF iv_words = 0. + ev_price = 0. + RETURN. + ENDIF. + + DATA lv_rate TYPE decfloat34. + IF ( iv_source_lang = 'EN' AND iv_target_lang = 'DE' ) + OR ( iv_source_lang = 'DE' AND iv_target_lang = 'EN' ). + lv_rate = '0.12'. + ELSEIF ( iv_source_lang = 'EN' AND iv_target_lang = 'FR' ) + OR ( iv_source_lang = 'FR' AND iv_target_lang = 'EN' ). + lv_rate = '0.15'. + ELSE. + lv_rate = '0.20'. + ENDIF. + + DATA lv_amount TYPE decfloat34. + lv_amount = iv_words * lv_rate. + + IF iv_express = abap_true. + lv_amount = lv_amount / '1.25'. + ENDIF. + + ev_price = round( val = lv_amount dec = 2 mode = cl_abap_math=>round_half_up ). + + IF ev_price < 25. + ev_price = 25. + ENDIF. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0152/faulty/m3_trl_price.func.abap b/tasks_gen/eval/G0152/faulty/m3_trl_price.func.abap new file mode 100644 index 0000000..c39c3d1 --- /dev/null +++ b/tasks_gen/eval/G0152/faulty/m3_trl_price.func.abap @@ -0,0 +1,45 @@ +FUNCTION {{p}}trl_price + IMPORTING + iv_source_lang TYPE string + iv_target_lang TYPE string + iv_words TYPE i + iv_express TYPE abap_bool + EXPORTING + ev_price TYPE decfloat34 + EXCEPTIONS + invalid_words. + + IF iv_words < 0. + RAISE invalid_words. + ENDIF. + + IF iv_words = 0. + ev_price = 0. + RETURN. + ENDIF. + + DATA lv_rate TYPE decfloat34. + IF ( iv_source_lang = 'EN' AND iv_target_lang = 'DE' ) + OR ( iv_source_lang = 'DE' AND iv_target_lang = 'EN' ). + lv_rate = '0.12'. + ELSEIF ( iv_source_lang = 'EN' AND iv_target_lang = 'FR' ) + OR ( iv_source_lang = 'FR' AND iv_target_lang = 'EN' ). + lv_rate = '0.15'. + ELSE. + lv_rate = '0.20'. + ENDIF. + + DATA lv_amount TYPE decfloat34. + lv_amount = iv_words * lv_rate. + + IF iv_express = abap_true. + lv_amount = lv_amount * '1.25'. + ENDIF. + + ev_price = round( val = lv_amount dec = 3 mode = cl_abap_math=>round_half_up ). + + IF ev_price < 25. + ev_price = 25. + ENDIF. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0152/faulty/m4_trl_price.func.abap b/tasks_gen/eval/G0152/faulty/m4_trl_price.func.abap new file mode 100644 index 0000000..08acb4c --- /dev/null +++ b/tasks_gen/eval/G0152/faulty/m4_trl_price.func.abap @@ -0,0 +1,45 @@ +FUNCTION {{p}}trl_price + IMPORTING + iv_source_lang TYPE string + iv_target_lang TYPE string + iv_words TYPE i + iv_express TYPE abap_bool + EXPORTING + ev_price TYPE decfloat34 + EXCEPTIONS + invalid_words. + + IF iv_words < 0. + RAISE invalid_words. + ENDIF. + + IF iv_words = 0. + ev_price = 0. + RETURN. + ENDIF. + + DATA lv_rate TYPE decfloat34. + IF ( iv_source_lang = 'EN' AND iv_target_lang = 'DE' ) + OR ( iv_source_lang = 'DE' AND iv_target_lang = 'EN' ). + lv_rate = '0.12'. + ELSEIF ( iv_source_lang = 'EN' AND iv_target_lang = 'FR' ) + OR ( iv_source_lang = 'FR' AND iv_target_lang = 'EN' ). + lv_rate = '0.15'. + ELSE. + lv_rate = '0.20'. + ENDIF. + + DATA lv_amount TYPE decfloat34. + lv_amount = iv_words * lv_rate. + + IF iv_express = abap_true. + lv_amount = lv_amount * '1.25'. + ENDIF. + + ev_price = round( val = lv_amount dec = 2 mode = cl_abap_math=>round_half_up ). + + IF ev_price >= 25. + ev_price = 25. + ENDIF. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0152/generation.json b/tasks_gen/eval/G0152/generation.json new file mode 100644 index 0000000..82039a9 --- /dev/null +++ b/tasks_gen/eval/G0152/generation.json @@ -0,0 +1,19 @@ +{ + "id": "G0152", + "pool": "eval", + "object_type": "FUNC", + "category": "F", + "attempts": [ + { + "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/eval/G0152/hidden/t14_hidden.clas.abap b/tasks_gen/eval/G0152/hidden/t14_hidden.clas.abap new file mode 100644 index 0000000..c9f0d24 --- /dev/null +++ b/tasks_gen/eval/G0152/hidden/t14_hidden.clas.abap @@ -0,0 +1,104 @@ +CLASS {{p}}t14_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS call + IMPORTING iv_source TYPE string + iv_target TYPE string + iv_words TYPE i + iv_express TYPE abap_bool + iv_price TYPE decfloat34 DEFAULT 7 + EXPORTING ev_price TYPE decfloat34 + ev_subrc TYPE sysubrc. + METHODS base_rate_en_de FOR TESTING. + METHODS base_rate_de_en FOR TESTING. + METHODS base_rate_en_fr FOR TESTING. + METHODS other_pair_rate FOR TESTING. + METHODS express_surcharge FOR TESTING. + METHODS minimum_price FOR TESTING. + METHODS minimum_with_express FOR TESTING. + METHODS zero_words_is_free FOR TESTING. + METHODS rounding_half_up FOR TESTING. + METHODS negative_words_raises FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t14_hidden IMPLEMENTATION. + METHOD call. + ev_price = iv_price. + CALL FUNCTION '{{P}}TRL_PRICE' + EXPORTING + iv_source_lang = iv_source + iv_target_lang = iv_target + iv_words = iv_words + iv_express = iv_express + IMPORTING + ev_price = ev_price + EXCEPTIONS + invalid_words = 1 + OTHERS = 2. + ev_subrc = sy-subrc. + ENDMETHOD. + + METHOD base_rate_en_de. + call( EXPORTING iv_source = `EN` iv_target = `DE` iv_words = 1000 iv_express = abap_false + IMPORTING ev_price = DATA(lv_price) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 120 ) act = lv_price ). + ENDMETHOD. + + METHOD base_rate_de_en. + call( EXPORTING iv_source = `DE` iv_target = `EN` iv_words = 1000 iv_express = abap_false + IMPORTING ev_price = DATA(lv_price) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 120 ) act = lv_price ). + ENDMETHOD. + + METHOD base_rate_en_fr. + call( EXPORTING iv_source = `EN` iv_target = `FR` iv_words = 1000 iv_express = abap_false + IMPORTING ev_price = DATA(lv_price) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 150 ) act = lv_price ). + ENDMETHOD. + + METHOD other_pair_rate. + call( EXPORTING iv_source = `ES` iv_target = `IT` iv_words = 1000 iv_express = abap_false + IMPORTING ev_price = DATA(lv_price) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 200 ) act = lv_price ). + ENDMETHOD. + + METHOD express_surcharge. + call( EXPORTING iv_source = `EN` iv_target = `DE` iv_words = 1000 iv_express = abap_true + IMPORTING ev_price = DATA(lv_price) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 150 ) act = lv_price ). + ENDMETHOD. + + METHOD minimum_price. + call( EXPORTING iv_source = `EN` iv_target = `DE` iv_words = 100 iv_express = abap_false + IMPORTING ev_price = DATA(lv_price) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 25 ) act = lv_price ). + ENDMETHOD. + + METHOD minimum_with_express. + call( EXPORTING iv_source = `EN` iv_target = `DE` iv_words = 100 iv_express = abap_true + IMPORTING ev_price = DATA(lv_price) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 25 ) act = lv_price ). + ENDMETHOD. + + METHOD zero_words_is_free. + call( EXPORTING iv_source = `EN` iv_target = `DE` iv_words = 0 iv_express = abap_false + IMPORTING ev_price = DATA(lv_price) ev_subrc = DATA(lv_rc) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 0 ) act = lv_price ). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_rc ). + ENDMETHOD. + + METHOD rounding_half_up. + call( EXPORTING iv_source = `EN` iv_target = `FR` iv_words = 333 iv_express = abap_true + IMPORTING ev_price = DATA(lv_price) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '62.44' ) act = lv_price ). + ENDMETHOD. + + METHOD negative_words_raises. + call( EXPORTING iv_source = `EN` iv_target = `DE` iv_words = -1 iv_express = abap_false + iv_price = CONV decfloat34( 7 ) + IMPORTING ev_price = DATA(lv_price) ev_subrc = DATA(lv_rc) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lv_rc ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 7 ) act = lv_price ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0152/mutation.json b/tasks_gen/eval/G0152/mutation.json new file mode 100644 index 0000000..8dc7a7c --- /dev/null +++ b/tasks_gen/eval/G0152/mutation.json @@ -0,0 +1,62 @@ +{ + "task": "G0152", + "mutants": [ + { + "object": "{{P}}TRL_PRICE", + "mutant": "line 23: OR -> AND (logic)", + "status": "killed", + "hidden": "7/10", + "failed_tests": [ + "BASE_RATE_DE_EN", + "BASE_RATE_EN_DE", + "EXPRESS_SURCHARGE" + ] + }, + { + "object": "{{P}}TRL_PRICE", + "mutant": "line 26: = -> <> (eq)", + "status": "survived", + "hidden": "10/10", + "failed_tests": [] + }, + { + "object": "{{P}}TRL_PRICE", + "mutant": "line 36: * -> / (arith)", + "status": "killed", + "hidden": "8/10", + "failed_tests": [ + "EXPRESS_SURCHARGE", + "ROUNDING_HALF_UP" + ] + }, + { + "object": "{{P}}TRL_PRICE", + "mutant": "line 39: 2 -> 3 (const)", + "status": "killed", + "hidden": "9/10", + "failed_tests": [ + "ROUNDING_HALF_UP" + ] + }, + { + "object": "{{P}}TRL_PRICE", + "mutant": "line 41: < -> >= (rel)", + "status": "killed", + "hidden": "2/10", + "failed_tests": [ + "BASE_RATE_DE_EN", + "BASE_RATE_EN_DE", + "BASE_RATE_EN_FR", + "EXPRESS_SURCHARGE", + "MINIMUM_PRICE", + "MINIMUM_WITH_EXPRESS", + "OTHER_PAIR_RATE", + "ROUNDING_HALF_UP" + ] + } + ], + "valid": 5, + "killed": 4, + "kill_rate": 0.8, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0152/reference/t14_test.clas.abap b/tasks_gen/eval/G0152/reference/t14_test.clas.abap new file mode 100644 index 0000000..34687d2 --- /dev/null +++ b/tasks_gen/eval/G0152/reference/t14_test.clas.abap @@ -0,0 +1,69 @@ +CLASS {{p}}t14_test DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS price_for + IMPORTING iv_source TYPE string + iv_target TYPE string + iv_words TYPE i + iv_express TYPE abap_bool + RETURNING VALUE(rv_price) TYPE decfloat34. + METHODS standard_pair FOR TESTING. + METHODS express_and_minimum FOR TESTING. + METHODS zero_words FOR TESTING. + METHODS negative_words FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t14_test IMPLEMENTATION. + METHOD price_for. + CALL FUNCTION '{{P}}TRL_PRICE' + EXPORTING + iv_source_lang = iv_source + iv_target_lang = iv_target + iv_words = iv_words + iv_express = iv_express + IMPORTING + ev_price = rv_price + EXCEPTIONS + invalid_words = 1 + OTHERS = 2. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + ENDMETHOD. + + METHOD standard_pair. + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( 120 ) + act = price_for( iv_source = `EN` iv_target = `DE` iv_words = 1000 iv_express = abap_false ) ). + ENDMETHOD. + + METHOD express_and_minimum. + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( 150 ) + act = price_for( iv_source = `EN` iv_target = `DE` iv_words = 1000 iv_express = abap_true ) ). + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( 25 ) + act = price_for( iv_source = `EN` iv_target = `DE` iv_words = 10 iv_express = abap_false ) ). + ENDMETHOD. + + METHOD zero_words. + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( 0 ) + act = price_for( iv_source = `EN` iv_target = `DE` iv_words = 0 iv_express = abap_false ) ). + ENDMETHOD. + + METHOD negative_words. + DATA lv_price TYPE decfloat34. + CALL FUNCTION '{{P}}TRL_PRICE' + EXPORTING + iv_source_lang = `EN` + iv_target_lang = `DE` + iv_words = -1 + iv_express = abap_false + IMPORTING + ev_price = lv_price + EXCEPTIONS + invalid_words = 1 + OTHERS = 2. + cl_abap_unit_assert=>assert_equals( exp = 1 act = sy-subrc ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0152/reference/trl_price.func.abap b/tasks_gen/eval/G0152/reference/trl_price.func.abap new file mode 100644 index 0000000..efb514e --- /dev/null +++ b/tasks_gen/eval/G0152/reference/trl_price.func.abap @@ -0,0 +1,45 @@ +FUNCTION {{p}}trl_price + IMPORTING + iv_source_lang TYPE string + iv_target_lang TYPE string + iv_words TYPE i + iv_express TYPE abap_bool + EXPORTING + ev_price TYPE decfloat34 + EXCEPTIONS + invalid_words. + + IF iv_words < 0. + RAISE invalid_words. + ENDIF. + + IF iv_words = 0. + ev_price = 0. + RETURN. + ENDIF. + + DATA lv_rate TYPE decfloat34. + IF ( iv_source_lang = 'EN' AND iv_target_lang = 'DE' ) + OR ( iv_source_lang = 'DE' AND iv_target_lang = 'EN' ). + lv_rate = '0.12'. + ELSEIF ( iv_source_lang = 'EN' AND iv_target_lang = 'FR' ) + OR ( iv_source_lang = 'FR' AND iv_target_lang = 'EN' ). + lv_rate = '0.15'. + ELSE. + lv_rate = '0.20'. + ENDIF. + + DATA lv_amount TYPE decfloat34. + lv_amount = iv_words * lv_rate. + + IF iv_express = abap_true. + lv_amount = lv_amount * '1.25'. + ENDIF. + + ev_price = round( val = lv_amount dec = 2 mode = cl_abap_math=>round_half_up ). + + IF ev_price < 25. + ev_price = 25. + ENDIF. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0152/seed/trl_sample.func.abap b/tasks_gen/eval/G0152/seed/trl_sample.func.abap new file mode 100644 index 0000000..57364aa --- /dev/null +++ b/tasks_gen/eval/G0152/seed/trl_sample.func.abap @@ -0,0 +1,14 @@ +FUNCTION {{p}}trl_sample + IMPORTING + iv_source_lang TYPE string + iv_target_lang TYPE string + iv_words TYPE i + iv_express TYPE abap_bool + EXPORTING + ev_price TYPE decfloat34 + EXCEPTIONS + invalid_words. + + ev_price = 0. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0152/spec.md b/tasks_gen/eval/G0152/spec.md new file mode 100644 index 0000000..d7748e3 --- /dev/null +++ b/tasks_gen/eval/G0152/spec.md @@ -0,0 +1,43 @@ +# 1. Goal +A translation agency prices translation jobs. The invoicing program calls one event +module for each job. The event module must have the same interface as the sample +event module, because the invoicing program calls all event modules in the same way. + +# 2. Open questions +None. + +# 3. Context +- Function group {{P}}FG_TRL exists in package $TMP. +- Function module {{P}}TRL_SAMPLE exists in this group. It is the sample event + module. Its interface is the interface that all event modules must use. + +# 4. Contract +- Create the function module {{P}}TRL_PRICE in function group {{P}}FG_TRL. +- Use exactly the interface of {{P}}TRL_SAMPLE: the same parameter names, parameter + kinds, parameter types, and exceptions. + +# 5. Business rules +1. If the word count is less than 0, raise the exception INVALID_WORDS. Do not + change the price. +2. If the word count is 0, the price is 0. The minimum price in rule 6 does not + apply. +3. The base rate for one word depends on the language pair. Compare the language + codes exactly as they are given. + - Source EN and target DE, or source DE and target EN: 0.12 + - Source EN and target FR, or source FR and target EN: 0.15 + - All other pairs: 0.20 +4. The base amount is the word count multiplied by the base rate. +5. If the express flag is true, multiply the base amount by 1.25. +6. The price is the amount from rules 4 and 5, rounded half up to 2 decimals. If + the price is less than 25.00, the price is 25.00. + +# 6. Constraints +- Release target: 8.16. +- Coding standards: Clean ABAP. The code must not cause ATC findings of priority 1 + or priority 2. +- Out of scope: do not change {{P}}TRL_SAMPLE. + +# 7. Acceptance +- The function module {{P}}TRL_PRICE is active and has no syntax error. +- The hidden tests pass. +- Write ABAP Unit tests for the function module in a global test class. diff --git a/tasks_gen/eval/G0152/task.json b/tasks_gen/eval/G0152/task.json new file mode 100644 index 0000000..af43cff --- /dev/null +++ b/tasks_gen/eval/G0152/task.json @@ -0,0 +1,84 @@ +{ + "id": "G0152", + "category": "F", + "object_type": "FUNC", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [ + { + "type": "FUGR", + "name": "{{P}}FG_TRL", + "description": "Translation job events" + }, + { + "type": "FUNC", + "name": "{{P}}TRL_SAMPLE", + "functionGroup": "{{P}}FG_TRL", + "file": "seed/trl_sample.func.abap", + "description": "Sample event module" + } + ], + "contract": [ + { + "type": "FUNC", + "name": "{{P}}TRL_PRICE", + "functionGroup": "{{P}}FG_TRL", + "params": [ + { + "name": "iv_source_lang", + "type": "string" + }, + { + "name": "iv_target_lang", + "type": "string" + }, + { + "name": "iv_words", + "type": "i" + }, + { + "name": "iv_express", + "type": "abap_bool" + }, + { + "name": "ev_price", + "type": "decfloat34" + } + ] + } + ], + "out_of_scope": [ + "{{P}}TRL_SAMPLE" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T14_HIDDEN", + "file": "hidden/t14_hidden.clas.abap", + "description": "T14 hidden tests" + } + ], + "reference": [ + { + "type": "FUNC", + "name": "{{P}}TRL_PRICE", + "functionGroup": "{{P}}FG_TRL", + "file": "reference/trl_price.func.abap", + "description": "Translation price module" + }, + { + "type": "CLAS", + "name": "{{P}}T14_TEST", + "file": "reference/t14_test.clas.abap", + "description": "T14 own tests" + } + ], + "craft_checks": [ + "method_length" + ] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0153/faulty/m0_i_album_stats.ddls.asddls b/tasks_gen/eval/G0153/faulty/m0_i_album_stats.ddls.asddls new file mode 100644 index 0000000..2794a52 --- /dev/null +++ b/tasks_gen/eval/G0153/faulty/m0_i_album_stats.ddls.asddls @@ -0,0 +1,15 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Album statistics' +define view entity {{P}}I_ALBUM_STATS + as select from {{p}}album as alb + left outer join {{p}}track as trk on trk.album_id = alb.album_id +{ + key alb.album_id as album_id, + alb.title as title, + count( * ) as track_count, + sum( trk.play_sec ) as total_seconds, + max( trk.play_sec ) as longest_seconds +} +group by + alb.album_id, + alb.title diff --git a/tasks_gen/eval/G0153/faulty/m1_i_album_stats.ddls.asddls b/tasks_gen/eval/G0153/faulty/m1_i_album_stats.ddls.asddls new file mode 100644 index 0000000..4846c2a --- /dev/null +++ b/tasks_gen/eval/G0153/faulty/m1_i_album_stats.ddls.asddls @@ -0,0 +1,15 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Album statistics' +define view entity {{P}}I_ALBUM_STATS + as select from {{p}}album as alb + inner join {{p}}track as trk on trk.album_id <> alb.album_id +{ + key alb.album_id as album_id, + alb.title as title, + count( * ) as track_count, + sum( trk.play_sec ) as total_seconds, + max( trk.play_sec ) as longest_seconds +} +group by + alb.album_id, + alb.title diff --git a/tasks_gen/eval/G0153/faulty/m2_i_album_stats.ddls.asddls b/tasks_gen/eval/G0153/faulty/m2_i_album_stats.ddls.asddls new file mode 100644 index 0000000..6ca15fe --- /dev/null +++ b/tasks_gen/eval/G0153/faulty/m2_i_album_stats.ddls.asddls @@ -0,0 +1,15 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Album statistics' +define view entity {{P}}I_ALBUM_STATS + as select from {{p}}album as alb + inner join {{p}}track as trk on trk.album_id = alb.album_id +{ + key alb.album_id as album_id, + alb.title as title, + count( * ) as track_count, + max( trk.play_sec ) as total_seconds, + max( trk.play_sec ) as longest_seconds +} +group by + alb.album_id, + alb.title diff --git a/tasks_gen/eval/G0153/generation.json b/tasks_gen/eval/G0153/generation.json new file mode 100644 index 0000000..15b94ea --- /dev/null +++ b/tasks_gen/eval/G0153/generation.json @@ -0,0 +1,19 @@ +{ + "id": "G0153", + "pool": "eval", + "object_type": "DDLS", + "category": "F", + "attempts": [ + { + "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/eval/G0153/hidden/t41_hidden.clas.abap b/tasks_gen/eval/G0153/hidden/t41_hidden.clas.abap new file mode 100644 index 0000000..53573f1 --- /dev/null +++ b/tasks_gen/eval/G0153/hidden/t41_hidden.clas.abap @@ -0,0 +1,84 @@ +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 album_totals FOR TESTING. + METHODS track_counts FOR TESTING. + METHODS album_without_tracks FOR TESTING. + METHODS title_shown FOR TESTING. + METHODS longest_track FOR TESTING. + METHODS single_track_album FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t41_hidden IMPLEMENTATION. + METHOD class_setup. + go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_ALBUM_STATS' ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + DATA lt_album TYPE STANDARD TABLE OF {{p}}album WITH EMPTY KEY. + DATA lt_track TYPE STANDARD TABLE OF {{p}}track WITH EMPTY KEY. + go_env->clear_doubles( ). + lt_album = VALUE #( ( album_id = 'A1' title = 'BLUE' artist = 'ONE' ) + ( album_id = 'A2' title = 'RED' artist = 'TWO' ) + ( album_id = 'A3' title = 'GREEN' artist = 'THREE' ) ). + lt_track = VALUE #( ( album_id = 'A1' track_no = 1 play_sec = 200 genre = 'ROCK' ) + ( album_id = 'A1' track_no = 2 play_sec = 130 genre = 'POP' ) + ( album_id = 'A1' track_no = 3 play_sec = 300 genre = 'JAZZ' ) + ( album_id = 'A2' track_no = 1 play_sec = 45 genre = 'POP' ) ). + go_env->insert_test_data( lt_album ). + go_env->insert_test_data( lt_track ). + ENDMETHOD. + + METHOD album_totals. + SELECT SINGLE total_seconds FROM {{p}}i_album_stats WHERE album_id = 'A1' + INTO @DATA(lv_total). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 630 ) + act = CONV decfloat34( lv_total ) ). + ENDMETHOD. + + METHOD track_counts. + SELECT SINGLE track_count FROM {{p}}i_album_stats WHERE album_id = 'A1' + INTO @DATA(lv_count). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 3 ) + act = CONV decfloat34( lv_count ) ). + ENDMETHOD. + + METHOD album_without_tracks. + SELECT COUNT(*) FROM {{p}}i_album_stats INTO @DATA(lv_rows). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 2 ) + act = CONV decfloat34( lv_rows ) ). + ENDMETHOD. + + METHOD title_shown. + SELECT SINGLE title FROM {{p}}i_album_stats WHERE album_id = 'A2' + INTO @DATA(lv_title). + cl_abap_unit_assert=>assert_equals( exp = 'RED' act = lv_title ). + ENDMETHOD. + + METHOD longest_track. + SELECT SINGLE longest_seconds FROM {{p}}i_album_stats WHERE album_id = 'A1' + INTO @DATA(lv_max). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 300 ) + act = CONV decfloat34( lv_max ) ). + ENDMETHOD. + + METHOD single_track_album. + SELECT SINGLE track_count, total_seconds, longest_seconds FROM {{p}}i_album_stats + WHERE album_id = 'A2' INTO @DATA(ls_stat). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 1 ) + act = CONV decfloat34( ls_stat-track_count ) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 45 ) + act = CONV decfloat34( ls_stat-total_seconds ) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 45 ) + act = CONV decfloat34( ls_stat-longest_seconds ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0153/mutation.json b/tasks_gen/eval/G0153/mutation.json new file mode 100644 index 0000000..4fab460 --- /dev/null +++ b/tasks_gen/eval/G0153/mutation.json @@ -0,0 +1,40 @@ +{ + "task": "G0153", + "mutants": [ + { + "object": "{{P}}I_ALBUM_STATS", + "mutant": "line 5: inner join -> left outer join (join)", + "status": "killed", + "hidden": "5/6", + "failed_tests": [ + "ALBUM_WITHOUT_TRACKS" + ] + }, + { + "object": "{{P}}I_ALBUM_STATS", + "mutant": "line 5: = -> <> (eq)", + "status": "killed", + "hidden": "1/6", + "failed_tests": [ + "ALBUM_TOTALS", + "ALBUM_WITHOUT_TRACKS", + "LONGEST_TRACK", + "SINGLE_TRACK_ALBUM", + "TRACK_COUNTS" + ] + }, + { + "object": "{{P}}I_ALBUM_STATS", + "mutant": "line 10: sum( -> max( (agg)", + "status": "killed", + "hidden": "5/6", + "failed_tests": [ + "ALBUM_TOTALS" + ] + } + ], + "valid": 3, + "killed": 3, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0153/reference/i_album_stats.ddls.asddls b/tasks_gen/eval/G0153/reference/i_album_stats.ddls.asddls new file mode 100644 index 0000000..63ad5fd --- /dev/null +++ b/tasks_gen/eval/G0153/reference/i_album_stats.ddls.asddls @@ -0,0 +1,15 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Album statistics' +define view entity {{P}}I_ALBUM_STATS + as select from {{p}}album as alb + inner join {{p}}track as trk on trk.album_id = alb.album_id +{ + key alb.album_id as album_id, + alb.title as title, + count( * ) as track_count, + sum( trk.play_sec ) as total_seconds, + max( trk.play_sec ) as longest_seconds +} +group by + alb.album_id, + alb.title diff --git a/tasks_gen/eval/G0153/reference/t41_test.clas.abap b/tasks_gen/eval/G0153/reference/t41_test.clas.abap new file mode 100644 index 0000000..f92c260 --- /dev/null +++ b/tasks_gen/eval/G0153/reference/t41_test.clas.abap @@ -0,0 +1,42 @@ +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 stats_of_one_album FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t41_test IMPLEMENTATION. + METHOD class_setup. + go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_ALBUM_STATS' ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + go_env->clear_doubles( ). + ENDMETHOD. + + METHOD stats_of_one_album. + DATA lt_album TYPE STANDARD TABLE OF {{p}}album WITH EMPTY KEY. + DATA lt_track TYPE STANDARD TABLE OF {{p}}track WITH EMPTY KEY. + lt_album = VALUE #( ( album_id = 'B1' title = 'SOLO' artist = 'ONE' ) ). + lt_track = VALUE #( ( album_id = 'B1' track_no = 1 play_sec = 100 genre = 'POP' ) + ( album_id = 'B1' track_no = 2 play_sec = 250 genre = 'POP' ) ). + go_env->insert_test_data( lt_album ). + go_env->insert_test_data( lt_track ). + SELECT SINGLE track_count, total_seconds, longest_seconds FROM {{p}}i_album_stats + WHERE album_id = 'B1' INTO @DATA(ls_stat). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 2 ) + act = CONV decfloat34( ls_stat-track_count ) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 350 ) + act = CONV decfloat34( ls_stat-total_seconds ) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 250 ) + act = CONV decfloat34( ls_stat-longest_seconds ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0153/seed/album.tabl.asabap b/tasks_gen/eval/G0153/seed/album.tabl.asabap new file mode 100644 index 0000000..b7570f7 --- /dev/null +++ b/tasks_gen/eval/G0153/seed/album.tabl.asabap @@ -0,0 +1,11 @@ +@EndUserText.label : 'Album' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}album { + key client : abap.clnt not null; + key album_id : abap.char(10) not null; + title : abap.char(40); + artist : abap.char(40); +} diff --git a/tasks_gen/eval/G0153/seed/track.tabl.asabap b/tasks_gen/eval/G0153/seed/track.tabl.asabap new file mode 100644 index 0000000..5450075 --- /dev/null +++ b/tasks_gen/eval/G0153/seed/track.tabl.asabap @@ -0,0 +1,12 @@ +@EndUserText.label : 'Album track' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}track { + key client : abap.clnt not null; + key album_id : abap.char(10) not null; + key track_no : abap.int4 not null; + play_sec : abap.int4; + genre : abap.char(10); +} diff --git a/tasks_gen/eval/G0153/spec.md b/tasks_gen/eval/G0153/spec.md new file mode 100644 index 0000000..f5cb500 --- /dev/null +++ b/tasks_gen/eval/G0153/spec.md @@ -0,0 +1,39 @@ +# 1. Goal +Show the number of tracks and the playtime of each album. A report and an OData +service will read these figures, so the calculation must be in the database, in a +CDS view. + +# 2. Open questions +None. + +# 3. Context +- Table {{P}}ALBUM in package $TMP holds the albums. One row is one album. +- Table {{P}}TRACK in package $TMP holds the tracks. One row is one track of an + album. A track has a duration in seconds. +- The fields of the two tables are not part of this document. Read the two tables + in the system to find their fields and types. + +# 4. Contract +- Create the CDS view entity {{P}}I_ALBUM_STATS in package $TMP. +- Elements, with these names: ALBUM_ID (key), TITLE, TRACK_COUNT, TOTAL_SECONDS, + LONGEST_SECONDS. +- No authorization check (#NOT_REQUIRED). + +# 5. Business rules +1. Show one row for each album that has at least one track. Do not show an album + without tracks. +2. TRACK_COUNT is the number of tracks of the album. +3. TOTAL_SECONDS is the total duration of all tracks of the album, in seconds. +4. LONGEST_SECONDS is the duration of the longest track of the album, in seconds. +5. TITLE is the title of the album. +6. A duration is a whole number of seconds. Do not change it and do not round it. + +# 6. Constraints +- Release target: 8.16. +- Coding standards: Clean ABAP. +- Out of scope: do not change {{P}}ALBUM and {{P}}TRACK. + +# 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/eval/G0153/task.json b/tasks_gen/eval/G0153/task.json new file mode 100644 index 0000000..0c180d3 --- /dev/null +++ b/tasks_gen/eval/G0153/task.json @@ -0,0 +1,66 @@ +{ + "id": "G0153", + "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}}ALBUM", + "file": "seed/album.tabl.asabap", + "description": "Album header" + }, + { + "type": "TABL", + "name": "{{P}}TRACK", + "file": "seed/track.tabl.asabap", + "description": "Album track" + } + ], + "contract": [ + { + "type": "DDLS", + "name": "{{P}}I_ALBUM_STATS", + "fields": [ + "ALBUM_ID", + "TITLE", + "TRACK_COUNT", + "TOTAL_SECONDS", + "LONGEST_SECONDS" + ] + } + ], + "out_of_scope": [ + "{{P}}ALBUM", + "{{P}}TRACK" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T41_HIDDEN", + "file": "hidden/t41_hidden.clas.abap", + "description": "T41 hidden tests" + } + ], + "reference": [ + { + "type": "DDLS", + "name": "{{P}}I_ALBUM_STATS", + "file": "reference/i_album_stats.ddls.asddls", + "description": "Album statistics" + }, + { + "type": "CLAS", + "name": "{{P}}T41_TEST", + "file": "reference/t41_test.clas.abap", + "description": "T41 own tests" + } + ], + "craft_checks": [] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0154/faulty/m0_i_site_cost.ddls.asddls b/tasks_gen/eval/G0154/faulty/m0_i_site_cost.ddls.asddls new file mode 100644 index 0000000..7e0e295 --- /dev/null +++ b/tasks_gen/eval/G0154/faulty/m0_i_site_cost.ddls.asddls @@ -0,0 +1,12 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Cleaning cost per site' +define view entity {{P}}I_SITE_COST + as select from {{p}}cln_job +{ + key site_id as site_id, + count( * ) as job_count, + max( duration ) as total_hours, + sum( cast( duration * hour_rate as abap.dec( 15, 2 ) ) ) as total_cost +} +where job_status <> 'C' +group by site_id diff --git a/tasks_gen/eval/G0154/faulty/m1_i_site_cost.ddls.asddls b/tasks_gen/eval/G0154/faulty/m1_i_site_cost.ddls.asddls new file mode 100644 index 0000000..3cd7f6f --- /dev/null +++ b/tasks_gen/eval/G0154/faulty/m1_i_site_cost.ddls.asddls @@ -0,0 +1,12 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Cleaning cost per site' +define view entity {{P}}I_SITE_COST + as select from {{p}}cln_job +{ + key site_id as site_id, + count( * ) as job_count, + sum( duration ) as total_hours, + max( cast( duration * hour_rate as abap.dec( 15, 2 ) ) ) as total_cost +} +where job_status <> 'C' +group by site_id diff --git a/tasks_gen/eval/G0154/faulty/m2_i_site_cost.ddls.asddls b/tasks_gen/eval/G0154/faulty/m2_i_site_cost.ddls.asddls new file mode 100644 index 0000000..c040130 --- /dev/null +++ b/tasks_gen/eval/G0154/faulty/m2_i_site_cost.ddls.asddls @@ -0,0 +1,12 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Cleaning cost per site' +define view entity {{P}}I_SITE_COST + as select from {{p}}cln_job +{ + key site_id as site_id, + count( * ) as job_count, + sum( duration ) as total_hours, + sum( cast( duration * hour_rate as abap.dec( 15, 2 ) ) ) as total_cost +} +where job_status = 'C' +group by site_id diff --git a/tasks_gen/eval/G0154/faulty/m3_i_site_cost.ddls.asddls b/tasks_gen/eval/G0154/faulty/m3_i_site_cost.ddls.asddls new file mode 100644 index 0000000..37b8c39 --- /dev/null +++ b/tasks_gen/eval/G0154/faulty/m3_i_site_cost.ddls.asddls @@ -0,0 +1,12 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Cleaning cost per site' +define view entity {{P}}I_SITE_COST + as select from {{p}}cln_job +{ + key site_id as site_id, + count( * ) as job_count, + sum( duration ) as total_hours, + sum( cast( duration * hour_rate as abap.dec( 15, 2 ) ) ) as total_cost +} +where job_status <> 'Z' +group by site_id diff --git a/tasks_gen/eval/G0122/generation.json b/tasks_gen/eval/G0154/generation.json similarity index 51% rename from tasks_gen/eval/G0122/generation.json rename to tasks_gen/eval/G0154/generation.json index ee444fa..6b41ace 100644 --- a/tasks_gen/eval/G0122/generation.json +++ b/tasks_gen/eval/G0154/generation.json @@ -1,14 +1,9 @@ { - "id": "G0122", + "id": "G0154", "pool": "eval", - "object_type": "FUNC", - "category": "C", + "object_type": "DDLS", + "category": "F", "attempts": [ - { - "stage": "validate", - "oracle": null, - "null": null - }, { "stage": "validate", "oracle": 0, @@ -21,9 +16,14 @@ }, { "stage": "validate", - "oracle": 0, - "null": 0 + "oracle": 100.0, + "null": 0, + "mutation": { + "valid": 4, + "killed": 4, + "ok": true + } } ], - "accepted": false + "accepted": true } \ No newline at end of file diff --git a/tasks_gen/eval/G0154/hidden/t31_hidden.clas.abap b/tasks_gen/eval/G0154/hidden/t31_hidden.clas.abap new file mode 100644 index 0000000..23c3960 --- /dev/null +++ b/tasks_gen/eval/G0154/hidden/t31_hidden.clas.abap @@ -0,0 +1,68 @@ +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 job_counts FOR TESTING. + METHODS total_hours FOR TESTING. + METHODS totals FOR TESTING. + METHODS cancelled_excluded FOR TESTING. + METHODS only_cancelled_site FOR TESTING. + METHODS decimals FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t31_hidden IMPLEMENTATION. + METHOD class_setup. + go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_SITE_COST' ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + DATA lt_job TYPE STANDARD TABLE OF {{p}}cln_job WITH EMPTY KEY. + go_env->clear_doubles( ). + lt_job = VALUE #( + ( job_id = 'J1' site_id = 'S1' duration = '10.00' hour_rate = '5.00' job_status = 'D' ) + ( job_id = 'J2' site_id = 'S1' duration = '4.00' hour_rate = '5.00' job_status = 'D' ) + ( job_id = 'J3' site_id = 'S2' duration = '2.00' hour_rate = '10.00' job_status = 'C' ) + ( job_id = 'J4' site_id = 'S3' duration = '1.00' hour_rate = '100.00' job_status = 'D' ) + ( job_id = 'J5' site_id = 'S3' duration = '3.00' hour_rate = '100.00' job_status = 'C' ) + ( job_id = 'J6' site_id = 'S4' duration = '2.50' hour_rate = '1.50' job_status = 'O' ) ). + go_env->insert_test_data( lt_job ). + ENDMETHOD. + + METHOD job_counts. + SELECT SINGLE job_count FROM {{p}}i_site_cost WHERE site_id = 'S1' INTO @DATA(lv_count). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lv_count ). + ENDMETHOD. + + METHOD total_hours. + SELECT SINGLE total_hours FROM {{p}}i_site_cost WHERE site_id = 'S1' INTO @DATA(lv_hours). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '14.00' ) act = CONV decfloat34( lv_hours ) ). + ENDMETHOD. + + METHOD totals. + SELECT SINGLE total_cost FROM {{p}}i_site_cost WHERE site_id = 'S1' INTO @DATA(lv_cost). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '70.00' ) act = CONV decfloat34( lv_cost ) ). + ENDMETHOD. + + METHOD cancelled_excluded. + SELECT SINGLE total_cost FROM {{p}}i_site_cost WHERE site_id = 'S3' INTO @DATA(lv_cost). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '100.00' ) act = CONV decfloat34( lv_cost ) ). + ENDMETHOD. + + METHOD only_cancelled_site. + SELECT COUNT(*) FROM {{p}}i_site_cost INTO @DATA(lv_rows). + cl_abap_unit_assert=>assert_equals( exp = 3 act = lv_rows ). + ENDMETHOD. + + METHOD decimals. + SELECT SINGLE total_cost FROM {{p}}i_site_cost WHERE site_id = 'S4' INTO @DATA(lv_cost). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '3.75' ) act = CONV decfloat34( lv_cost ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0154/mutation.json b/tasks_gen/eval/G0154/mutation.json new file mode 100644 index 0000000..41e62a8 --- /dev/null +++ b/tasks_gen/eval/G0154/mutation.json @@ -0,0 +1,51 @@ +{ + "task": "G0154", + "mutants": [ + { + "object": "{{P}}I_SITE_COST", + "mutant": "line 8: sum( -> max( (agg)", + "status": "killed", + "hidden": "5/6", + "failed_tests": [ + "TOTAL_HOURS" + ] + }, + { + "object": "{{P}}I_SITE_COST", + "mutant": "line 9: sum( -> max( (agg)", + "status": "killed", + "hidden": "5/6", + "failed_tests": [ + "TOTALS" + ] + }, + { + "object": "{{P}}I_SITE_COST", + "mutant": "line 11: <> -> = (rel)", + "status": "killed", + "hidden": "0/6", + "failed_tests": [ + "CANCELLED_EXCLUDED", + "DECIMALS", + "JOB_COUNTS", + "ONLY_CANCELLED_SITE", + "TOTALS", + "TOTAL_HOURS" + ] + }, + { + "object": "{{P}}I_SITE_COST", + "mutant": "line 11: 'C' -> 'Z' (lit)", + "status": "killed", + "hidden": "4/6", + "failed_tests": [ + "CANCELLED_EXCLUDED", + "ONLY_CANCELLED_SITE" + ] + } + ], + "valid": 4, + "killed": 4, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0154/reference/i_site_cost.ddls.asddls b/tasks_gen/eval/G0154/reference/i_site_cost.ddls.asddls new file mode 100644 index 0000000..fb19124 --- /dev/null +++ b/tasks_gen/eval/G0154/reference/i_site_cost.ddls.asddls @@ -0,0 +1,12 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Cleaning cost per site' +define view entity {{P}}I_SITE_COST + as select from {{p}}cln_job +{ + key site_id as site_id, + count( * ) as job_count, + sum( duration ) as total_hours, + sum( cast( duration * hour_rate as abap.dec( 15, 2 ) ) ) as total_cost +} +where job_status <> 'C' +group by site_id diff --git a/tasks_gen/eval/G0154/reference/t31_test.clas.abap b/tasks_gen/eval/G0154/reference/t31_test.clas.abap new file mode 100644 index 0000000..cdf16d7 --- /dev/null +++ b/tasks_gen/eval/G0154/reference/t31_test.clas.abap @@ -0,0 +1,38 @@ +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 site_total FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t31_test IMPLEMENTATION. + METHOD class_setup. + go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_SITE_COST' ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + go_env->clear_doubles( ). + ENDMETHOD. + + METHOD site_total. + DATA lt_job TYPE STANDARD TABLE OF {{p}}cln_job WITH EMPTY KEY. + lt_job = VALUE #( + ( job_id = 'A' site_id = 'X1' duration = '2.00' hour_rate = '3.00' job_status = 'D' ) + ( job_id = 'B' site_id = 'X1' duration = '1.00' hour_rate = '4.00' job_status = 'D' ) + ( job_id = 'C' site_id = 'X1' duration = '5.00' hour_rate = '9.00' job_status = 'C' ) ). + go_env->insert_test_data( lt_job ). + SELECT SINGLE job_count, total_hours, total_cost FROM {{p}}i_site_cost WHERE site_id = 'X1' + INTO @DATA(ls_site). + cl_abap_unit_assert=>assert_equals( exp = 2 act = ls_site-job_count ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '3.00' ) act = CONV decfloat34( ls_site-total_hours ) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '10.00' ) act = CONV decfloat34( ls_site-total_cost ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0154/seed/cln_job.tabl.asabap b/tasks_gen/eval/G0154/seed/cln_job.tabl.asabap new file mode 100644 index 0000000..4cb4995 --- /dev/null +++ b/tasks_gen/eval/G0154/seed/cln_job.tabl.asabap @@ -0,0 +1,13 @@ +@EndUserText.label : 'Cleaning job' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}cln_job { + key client : abap.clnt not null; + key job_id : abap.char(10) not null; + site_id : abap.char(10); + duration : abap.dec(5,2); + hour_rate : abap.dec(15,2); + job_status : abap.char(1); +} diff --git a/tasks_gen/eval/G0154/seed/i_job_cost.ddls.asddls b/tasks_gen/eval/G0154/seed/i_job_cost.ddls.asddls new file mode 100644 index 0000000..ae81657 --- /dev/null +++ b/tasks_gen/eval/G0154/seed/i_job_cost.ddls.asddls @@ -0,0 +1,11 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Cost of each cleaning job' +define view entity {{P}}I_JOB_COST + as select from {{p}}cln_job +{ + key job_id as job_id, + site_id as site_id, + duration as work_hours, + cast( duration * hour_rate as abap.dec(15,2) ) as job_cost +} +where job_status <> 'C' diff --git a/tasks_gen/eval/G0154/spec.md b/tasks_gen/eval/G0154/spec.md new file mode 100644 index 0000000..966a231 --- /dev/null +++ b/tasks_gen/eval/G0154/spec.md @@ -0,0 +1,40 @@ +# 1. Goal +A cleaning company bills its customers for cleaning jobs. Each job belongs to a +site. Show the total cost and the total work hours of each site. A report will +read the figures, so the calculation must be in the database, in a CDS view. + +# 2. Open questions +None. + +# 3. Context +- Table {{P}}CLN_JOB, package $TMP. One row for each cleaning job of a site. +- View entity {{P}}I_JOB_COST, package $TMP. One row for each cleaning job that + counts for billing. The view shows the work hours and the cost of each job. + Read {{P}}I_JOB_COST to learn which jobs count for billing and how the cost + of a job is calculated. +- A job counts for billing if {{P}}I_JOB_COST shows it. + +# 4. Contract +- Create the CDS view entity {{P}}I_SITE_COST in package $TMP. +- The view must be defined on the table {{P}}CLN_JOB. {{P}}I_JOB_COST must not + be used as a data source of the new view. +- Elements, with these names: SITE_ID (key), JOB_COUNT, TOTAL_HOURS, TOTAL_COST. +- No authorization check (#NOT_REQUIRED). + +# 5. Business rules +1. Show one row for each site that has at least one job that counts for + billing. Do not show a site without such a job. +2. JOB_COUNT is the number of jobs of the site that count for billing. +3. TOTAL_HOURS is the sum of the work hours of these jobs. +4. TOTAL_COST is the sum of the cost of these jobs, with 2 decimals. + +# 6. Constraints +- Release target: 8.16. +- Out of scope: do not change {{P}}CLN_JOB and {{P}}I_JOB_COST. +- 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. + Create the test environment for the CDS entity {{P}}I_SITE_COST. diff --git a/tasks_gen/eval/G0154/task.json b/tasks_gen/eval/G0154/task.json new file mode 100644 index 0000000..79598d8 --- /dev/null +++ b/tasks_gen/eval/G0154/task.json @@ -0,0 +1,65 @@ +{ + "id": "G0154", + "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}}CLN_JOB", + "file": "seed/cln_job.tabl.asabap", + "description": "Cleaning job" + }, + { + "type": "DDLS", + "name": "{{P}}I_JOB_COST", + "file": "seed/i_job_cost.ddls.asddls", + "description": "Cost of each cleaning job" + } + ], + "contract": [ + { + "type": "DDLS", + "name": "{{P}}I_SITE_COST", + "fields": [ + "SITE_ID", + "JOB_COUNT", + "TOTAL_HOURS", + "TOTAL_COST" + ] + } + ], + "out_of_scope": [ + "{{P}}CLN_JOB", + "{{P}}I_JOB_COST" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T31_HIDDEN", + "file": "hidden/t31_hidden.clas.abap", + "description": "T31 hidden tests" + } + ], + "reference": [ + { + "type": "DDLS", + "name": "{{P}}I_SITE_COST", + "file": "reference/i_site_cost.ddls.asddls", + "description": "Cleaning cost per site" + }, + { + "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/eval/G0155/faulty/m0_i_machine_day.ddls.asddls b/tasks_gen/eval/G0155/faulty/m0_i_machine_day.ddls.asddls new file mode 100644 index 0000000..668eb4b --- /dev/null +++ b/tasks_gen/eval/G0155/faulty/m0_i_machine_day.ddls.asddls @@ -0,0 +1,17 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Machine readings per day' +define view entity {{P}}I_MACHINE_DAY + as select from {{p}}sensor as sen + left outer join {{p}}mach as mac on mac.machine_id = sen.machine_id +{ + key sen.machine_id as machine_id, + key sen.reading_date as reading_date, + mac.machine_name as machine_name, + mac.plant as plant, + count( * ) as reading_count, + avg( sen.reading_value as abap.dec(15,2) ) as avg_value, + max( sen.reading_value ) as max_value, + sum( case when sen.reading_value > 80.00 then 1 else 0 end ) as alert_count +} +where sen.sensor = 'TEMP' +group by sen.machine_id, sen.reading_date, mac.machine_name, mac.plant diff --git a/tasks_gen/eval/G0155/faulty/m2_i_machine_day.ddls.asddls b/tasks_gen/eval/G0155/faulty/m2_i_machine_day.ddls.asddls new file mode 100644 index 0000000..c701b13 --- /dev/null +++ b/tasks_gen/eval/G0155/faulty/m2_i_machine_day.ddls.asddls @@ -0,0 +1,17 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Machine readings per day' +define view entity {{P}}I_MACHINE_DAY + as select from {{p}}sensor as sen + inner join {{p}}mach as mac on mac.machine_id = sen.machine_id +{ + key sen.machine_id as machine_id, + key sen.reading_date as reading_date, + mac.machine_name as machine_name, + mac.plant as plant, + count( * ) as reading_count, + avg( sen.reading_value as abap.dec(15,2) ) as avg_value, + max( sen.reading_value ) as max_value, + sum( case when sen.reading_value <= 80.00 then 1 else 0 end ) as alert_count +} +where sen.sensor = 'TEMP' +group by sen.machine_id, sen.reading_date, mac.machine_name, mac.plant diff --git a/tasks_gen/eval/G0155/faulty/m3_i_machine_day.ddls.asddls b/tasks_gen/eval/G0155/faulty/m3_i_machine_day.ddls.asddls new file mode 100644 index 0000000..b0385d3 --- /dev/null +++ b/tasks_gen/eval/G0155/faulty/m3_i_machine_day.ddls.asddls @@ -0,0 +1,17 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Machine readings per day' +define view entity {{P}}I_MACHINE_DAY + as select from {{p}}sensor as sen + inner join {{p}}mach as mac on mac.machine_id = sen.machine_id +{ + key sen.machine_id as machine_id, + key sen.reading_date as reading_date, + mac.machine_name as machine_name, + mac.plant as plant, + count( * ) as reading_count, + avg( sen.reading_value as abap.dec(15,2) ) as avg_value, + max( sen.reading_value ) as max_value, + sum( case when sen.reading_value > 80.00 then 2 else 0 end ) as alert_count +} +where sen.sensor = 'TEMP' +group by sen.machine_id, sen.reading_date, mac.machine_name, mac.plant diff --git a/tasks_gen/eval/G0155/faulty/m4_i_machine_day.ddls.asddls b/tasks_gen/eval/G0155/faulty/m4_i_machine_day.ddls.asddls new file mode 100644 index 0000000..d127853 --- /dev/null +++ b/tasks_gen/eval/G0155/faulty/m4_i_machine_day.ddls.asddls @@ -0,0 +1,17 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Machine readings per day' +define view entity {{P}}I_MACHINE_DAY + as select from {{p}}sensor as sen + inner join {{p}}mach as mac on mac.machine_id = sen.machine_id +{ + key sen.machine_id as machine_id, + key sen.reading_date as reading_date, + mac.machine_name as machine_name, + mac.plant as plant, + count( * ) as reading_count, + avg( sen.reading_value as abap.dec(15,2) ) as avg_value, + max( sen.reading_value ) as max_value, + sum( case when sen.reading_value > 80.00 then 1 else 0 end ) as alert_count +} +where sen.sensor = 'ZEMP' +group by sen.machine_id, sen.reading_date, mac.machine_name, mac.plant diff --git a/tasks_gen/eval/G0155/generation.json b/tasks_gen/eval/G0155/generation.json new file mode 100644 index 0000000..cb1eb4d --- /dev/null +++ b/tasks_gen/eval/G0155/generation.json @@ -0,0 +1,29 @@ +{ + "id": "G0155", + "pool": "eval", + "object_type": "DDLS", + "category": "F", + "attempts": [ + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "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/eval/G0155/hidden/t41_hidden.clas.abap b/tasks_gen/eval/G0155/hidden/t41_hidden.clas.abap new file mode 100644 index 0000000..3441bf3 --- /dev/null +++ b/tasks_gen/eval/G0155/hidden/t41_hidden.clas.abap @@ -0,0 +1,117 @@ +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 counts_readings FOR TESTING. + METHODS average_value FOR TESTING. + METHODS max_value FOR TESTING. + METHODS alerts_counted FOR TESTING. + METHODS no_alert_at_limit FOR TESTING. + METHODS unknown_machine_ignored FOR TESTING. + METHODS name_and_plant FOR TESTING. + METHODS one_row_per_day FOR TESTING. + METHODS second_day_values FOR TESTING. + METHODS machine_without_readings FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t41_hidden IMPLEMENTATION. + METHOD class_setup. + go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_MACHINE_DAY' ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + DATA lt_mach TYPE STANDARD TABLE OF {{p}}mach WITH EMPTY KEY. + DATA lt_sensor TYPE STANDARD TABLE OF {{p}}sensor WITH EMPTY KEY. + go_env->clear_doubles( ). + lt_mach = VALUE #( + ( machine_id = 'M1' machine_name = 'Press 1' plant = '1000' ) + ( machine_id = 'M2' machine_name = 'Press 2' plant = '2000' ) + ( machine_id = 'M3' machine_name = 'Drill 3' plant = '1000' ) + ( machine_id = 'M4' machine_name = 'Drill 4' plant = '2000' ) ). + lt_sensor = VALUE #( + ( machine_id = 'M1' reading_no = 1 reading_date = '20240101' sensor = 'TEMP' reading_value = '10.00' ) + ( machine_id = 'M1' reading_no = 2 reading_date = '20240101' sensor = 'TEMP' reading_value = '20.00' ) + ( machine_id = 'M1' reading_no = 3 reading_date = '20240101' sensor = 'TEMP' reading_value = '30.00' ) + ( machine_id = 'M1' reading_no = 4 reading_date = '20240101' sensor = 'VIBR' reading_value = '99.00' ) + ( machine_id = 'M1' reading_no = 5 reading_date = '20240102' sensor = 'TEMP' reading_value = '5.00' ) + ( machine_id = 'M1' reading_no = 6 reading_date = '20240102' sensor = 'TEMP' reading_value = '6.00' ) + ( machine_id = 'M2' reading_no = 1 reading_date = '20240101' sensor = 'TEMP' reading_value = '95.50' ) + ( machine_id = 'M2' reading_no = 2 reading_date = '20240101' sensor = 'TEMP' reading_value = '100.00' ) + ( machine_id = 'M4' reading_no = 1 reading_date = '20240101' sensor = 'TEMP' reading_value = '80.00' ) + ( machine_id = 'M9' reading_no = 1 reading_date = '20240101' sensor = 'TEMP' reading_value = '50.00' ) ). + go_env->insert_test_data( lt_mach ). + go_env->insert_test_data( lt_sensor ). + ENDMETHOD. + + METHOD counts_readings. + SELECT SINGLE reading_count FROM {{p}}i_machine_day + WHERE machine_id = 'M1' AND reading_date = '20240101' INTO @DATA(lv_count). + cl_abap_unit_assert=>assert_equals( exp = 3 act = CONV i( lv_count ) ). + ENDMETHOD. + + METHOD average_value. + SELECT SINGLE avg_value FROM {{p}}i_machine_day + WHERE machine_id = 'M1' AND reading_date = '20240101' INTO @DATA(lv_avg). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '20.00' ) act = CONV decfloat34( lv_avg ) ). + ENDMETHOD. + + METHOD max_value. + SELECT SINGLE max_value FROM {{p}}i_machine_day + WHERE machine_id = 'M1' AND reading_date = '20240101' INTO @DATA(lv_max). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '30.00' ) act = CONV decfloat34( lv_max ) ). + ENDMETHOD. + + METHOD alerts_counted. + SELECT SINGLE alert_count FROM {{p}}i_machine_day + WHERE machine_id = 'M2' AND reading_date = '20240101' INTO @DATA(lv_alerts). + cl_abap_unit_assert=>assert_equals( exp = 2 act = CONV i( lv_alerts ) ). + ENDMETHOD. + + METHOD no_alert_at_limit. + SELECT SINGLE alert_count FROM {{p}}i_machine_day + WHERE machine_id = 'M4' AND reading_date = '20240101' INTO @DATA(lv_alerts). + cl_abap_unit_assert=>assert_equals( exp = 0 act = CONV i( lv_alerts ) ). + ENDMETHOD. + + METHOD unknown_machine_ignored. + SELECT COUNT(*) FROM {{p}}i_machine_day + WHERE machine_id = 'M9' INTO @DATA(lv_rows). + cl_abap_unit_assert=>assert_equals( exp = 0 act = CONV i( lv_rows ) ). + ENDMETHOD. + + METHOD name_and_plant. + SELECT COUNT(*) FROM {{p}}i_machine_day + WHERE machine_id = 'M2' AND machine_name = 'Press 2' AND plant = '2000' + INTO @DATA(lv_rows). + cl_abap_unit_assert=>assert_equals( exp = 1 act = CONV i( lv_rows ) ). + ENDMETHOD. + + METHOD one_row_per_day. + SELECT COUNT(*) FROM {{p}}i_machine_day + WHERE machine_id = 'M1' INTO @DATA(lv_rows). + cl_abap_unit_assert=>assert_equals( exp = 2 act = CONV i( lv_rows ) ). + ENDMETHOD. + + METHOD second_day_values. + SELECT SINGLE reading_count FROM {{p}}i_machine_day + WHERE machine_id = 'M1' AND reading_date = '20240102' INTO @DATA(lv_count). + SELECT SINGLE avg_value FROM {{p}}i_machine_day + WHERE machine_id = 'M1' AND reading_date = '20240102' INTO @DATA(lv_avg). + cl_abap_unit_assert=>assert_equals( exp = 2 act = CONV i( lv_count ) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '5.50' ) act = CONV decfloat34( lv_avg ) ). + ENDMETHOD. + + METHOD machine_without_readings. + SELECT COUNT(*) FROM {{p}}i_machine_day + WHERE machine_id = 'M3' INTO @DATA(lv_rows). + cl_abap_unit_assert=>assert_equals( exp = 0 act = CONV i( lv_rows ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0155/mutation.json b/tasks_gen/eval/G0155/mutation.json new file mode 100644 index 0000000..0743916 --- /dev/null +++ b/tasks_gen/eval/G0155/mutation.json @@ -0,0 +1,59 @@ +{ + "task": "G0155", + "mutants": [ + { + "object": "{{P}}I_MACHINE_DAY", + "mutant": "line 5: inner join -> left outer join (join)", + "status": "killed", + "hidden": "9/10", + "failed_tests": [ + "UNKNOWN_MACHINE_IGNORED" + ] + }, + { + "object": "{{P}}I_MACHINE_DAY", + "mutant": "line 12: avg( -> max( (agg)", + "status": "invalid", + "hidden": "0/0", + "failed_tests": [] + }, + { + "object": "{{P}}I_MACHINE_DAY", + "mutant": "line 14: > -> <= (rel)", + "status": "killed", + "hidden": "8/10", + "failed_tests": [ + "ALERTS_COUNTED", + "NO_ALERT_AT_LIMIT" + ] + }, + { + "object": "{{P}}I_MACHINE_DAY", + "mutant": "line 14: 1 -> 2 (const)", + "status": "killed", + "hidden": "9/10", + "failed_tests": [ + "ALERTS_COUNTED" + ] + }, + { + "object": "{{P}}I_MACHINE_DAY", + "mutant": "line 16: 'TEMP' -> 'ZEMP' (lit)", + "status": "killed", + "hidden": "3/10", + "failed_tests": [ + "ALERTS_COUNTED", + "AVERAGE_VALUE", + "COUNTS_READINGS", + "MAX_VALUE", + "NAME_AND_PLANT", + "ONE_ROW_PER_DAY", + "SECOND_DAY_VALUES" + ] + } + ], + "valid": 4, + "killed": 4, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0155/reference/i_machine_day.ddls.asddls b/tasks_gen/eval/G0155/reference/i_machine_day.ddls.asddls new file mode 100644 index 0000000..2b93870 --- /dev/null +++ b/tasks_gen/eval/G0155/reference/i_machine_day.ddls.asddls @@ -0,0 +1,17 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Machine readings per day' +define view entity {{P}}I_MACHINE_DAY + as select from {{p}}sensor as sen + inner join {{p}}mach as mac on mac.machine_id = sen.machine_id +{ + key sen.machine_id as machine_id, + key sen.reading_date as reading_date, + mac.machine_name as machine_name, + mac.plant as plant, + count( * ) as reading_count, + avg( sen.reading_value as abap.dec(15,2) ) as avg_value, + max( sen.reading_value ) as max_value, + sum( case when sen.reading_value > 80.00 then 1 else 0 end ) as alert_count +} +where sen.sensor = 'TEMP' +group by sen.machine_id, sen.reading_date, mac.machine_name, mac.plant diff --git a/tasks_gen/eval/G0155/reference/t41_test.clas.abap b/tasks_gen/eval/G0155/reference/t41_test.clas.abap new file mode 100644 index 0000000..c035f84 --- /dev/null +++ b/tasks_gen/eval/G0155/reference/t41_test.clas.abap @@ -0,0 +1,44 @@ +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 day_profile FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t41_test IMPLEMENTATION. + METHOD class_setup. + go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_MACHINE_DAY' ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + DATA lt_mach TYPE STANDARD TABLE OF {{p}}mach WITH EMPTY KEY. + DATA lt_sensor TYPE STANDARD TABLE OF {{p}}sensor WITH EMPTY KEY. + go_env->clear_doubles( ). + lt_mach = VALUE #( ( machine_id = 'A1' machine_name = 'Mill' plant = '3000' ) ). + lt_sensor = VALUE #( + ( machine_id = 'A1' reading_no = 1 reading_date = '20240201' sensor = 'TEMP' reading_value = '60.00' ) + ( machine_id = 'A1' reading_no = 2 reading_date = '20240201' sensor = 'TEMP' reading_value = '90.00' ) ). + go_env->insert_test_data( lt_mach ). + go_env->insert_test_data( lt_sensor ). + ENDMETHOD. + + METHOD day_profile. + SELECT SINGLE reading_count FROM {{p}}i_machine_day + WHERE machine_id = 'A1' AND reading_date = '20240201' INTO @DATA(lv_count). + SELECT SINGLE max_value FROM {{p}}i_machine_day + WHERE machine_id = 'A1' AND reading_date = '20240201' INTO @DATA(lv_max). + SELECT SINGLE alert_count FROM {{p}}i_machine_day + WHERE machine_id = 'A1' AND reading_date = '20240201' INTO @DATA(lv_alerts). + cl_abap_unit_assert=>assert_equals( exp = 2 act = CONV i( lv_count ) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '90.00' ) act = CONV decfloat34( lv_max ) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = CONV i( lv_alerts ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0155/seed/mach.tabl.asabap b/tasks_gen/eval/G0155/seed/mach.tabl.asabap new file mode 100644 index 0000000..c3f97fb --- /dev/null +++ b/tasks_gen/eval/G0155/seed/mach.tabl.asabap @@ -0,0 +1,11 @@ +@EndUserText.label : 'Machine master' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}mach { + key client : abap.clnt not null; + key machine_id : abap.char(10) not null; + machine_name : abap.char(40); + plant : abap.char(4); +} diff --git a/tasks_gen/eval/G0155/seed/sensor.tabl.asabap b/tasks_gen/eval/G0155/seed/sensor.tabl.asabap new file mode 100644 index 0000000..2f178a6 --- /dev/null +++ b/tasks_gen/eval/G0155/seed/sensor.tabl.asabap @@ -0,0 +1,13 @@ +@EndUserText.label : 'Sensor readings' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}sensor { + key client : abap.clnt not null; + key machine_id : abap.char(10) not null; + key reading_no : abap.int4 not null; + reading_date : abap.dats; + sensor : abap.char(10); + reading_value : abap.dec(15,2); +} diff --git a/tasks_gen/eval/G0155/spec.md b/tasks_gen/eval/G0155/spec.md new file mode 100644 index 0000000..bc47855 --- /dev/null +++ b/tasks_gen/eval/G0155/spec.md @@ -0,0 +1,44 @@ +# 1. Goal +Show the daily temperature profile of each machine in a factory. A dashboard and an +OData service read the profile, so the aggregation must run in the database, in a +CDS view. + +# 2. Open questions +None. + +# 3. Context +- Table {{P}}MACH in package $TMP holds the master data of the machines. +- Table {{P}}SENSOR in package $TMP holds the raw sensor readings of the machines. +- The two tables are seed objects. Their column names and their types are not part + of this specification. Read the two table definitions in the system before you + write the view. + +# 4. Contract +- Create the CDS view entity {{P}}I_MACHINE_DAY in package $TMP. +- Elements, with these names: MACHINE_ID (key), READING_DATE (key), MACHINE_NAME, + PLANT, READING_COUNT, AVG_VALUE, MAX_VALUE, ALERT_COUNT. +- No authorization check (#NOT_REQUIRED). + +# 5. Business rules +1. Only readings of the temperature sensor count. In the raw table, the temperature + sensor is identified by the value 'TEMP'. Ignore all readings of other sensors. +2. Show one row for each machine and each day on which the machine has at least one + temperature reading. Do not show a machine on a day without temperature readings. +3. Show only machines that exist in the machine master table. +4. READING_COUNT is the number of temperature readings of the machine on that day. +5. AVG_VALUE is the average of the values of these readings, with 2 decimals. +6. MAX_VALUE is the highest value of these readings. +7. ALERT_COUNT is the number of these readings with a value greater than 80.00. + A reading with the value 80.00 is not an alert. +8. MACHINE_NAME is the name of the machine. PLANT is the plant of the machine. + Both values come from the machine master table. + +# 6. Constraints +- Release target: ABAP Platform 2025 (SAP_BASIS 8.16). +- Coding standards: Clean ABAP. +- Out of scope: do not change the tables {{P}}MACH and {{P}}SENSOR. + +# 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/eval/G0155/task.json b/tasks_gen/eval/G0155/task.json new file mode 100644 index 0000000..0a3ec77 --- /dev/null +++ b/tasks_gen/eval/G0155/task.json @@ -0,0 +1,69 @@ +{ + "id": "G0155", + "category": "F", + "object_type": "DDLS", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 40, + "max_activations": 10 + }, + "seed": [ + { + "type": "TABL", + "name": "{{P}}MACH", + "file": "seed/mach.tabl.asabap", + "description": "Machine master data" + }, + { + "type": "TABL", + "name": "{{P}}SENSOR", + "file": "seed/sensor.tabl.asabap", + "description": "Raw sensor readings" + } + ], + "contract": [ + { + "type": "DDLS", + "name": "{{P}}I_MACHINE_DAY", + "fields": [ + "MACHINE_ID", + "READING_DATE", + "MACHINE_NAME", + "PLANT", + "READING_COUNT", + "AVG_VALUE", + "MAX_VALUE", + "ALERT_COUNT" + ] + } + ], + "out_of_scope": [ + "{{P}}MACH", + "{{P}}SENSOR" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T41_HIDDEN", + "file": "hidden/t41_hidden.clas.abap", + "description": "T41 hidden tests" + } + ], + "reference": [ + { + "type": "DDLS", + "name": "{{P}}I_MACHINE_DAY", + "file": "reference/i_machine_day.ddls.asddls", + "description": "Daily temperature profile of each machine" + }, + { + "type": "CLAS", + "name": "{{P}}T41_TEST", + "file": "reference/t41_test.clas.abap", + "description": "T41 own tests" + } + ], + "craft_checks": [] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0156/faulty/m0_repair_fee.func.abap b/tasks_gen/eval/G0156/faulty/m0_repair_fee.func.abap new file mode 100644 index 0000000..99d7b59 --- /dev/null +++ b/tasks_gen/eval/G0156/faulty/m0_repair_fee.func.abap @@ -0,0 +1,44 @@ +FUNCTION {{p}}repair_fee + IMPORTING + iv_repair_type TYPE string + iv_hours TYPE decfloat34 + iv_parts_cost TYPE decfloat34 + iv_member TYPE abap_bool + EXPORTING + ev_labour_fee TYPE decfloat34 + ev_total_fee TYPE decfloat34 + EXCEPTIONS + invalid_hours. + + DATA lv_rate TYPE decfloat34. + DATA lv_discount TYPE decfloat34. + + IF iv_hours >= 0. + RAISE invalid_hours. + ENDIF. + + CASE iv_repair_type. + WHEN 'BR'. + lv_rate = 60. + WHEN 'GE'. + lv_rate = 45. + WHEN 'WH'. + lv_rate = 30. + WHEN OTHERS. + lv_rate = 40. + ENDCASE. + + ev_labour_fee = round( val = iv_hours * lv_rate dec = 2 ). + + IF iv_member = abap_true. + lv_discount = round( val = ev_labour_fee * 10 / 100 dec = 2 ). + ev_labour_fee = ev_labour_fee - lv_discount. + ENDIF. + + ev_total_fee = ev_labour_fee + iv_parts_cost. + + IF ev_total_fee < 25. + ev_total_fee = 25. + ENDIF. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0156/faulty/m1_repair_fee.func.abap b/tasks_gen/eval/G0156/faulty/m1_repair_fee.func.abap new file mode 100644 index 0000000..bfb3f5a --- /dev/null +++ b/tasks_gen/eval/G0156/faulty/m1_repair_fee.func.abap @@ -0,0 +1,44 @@ +FUNCTION {{p}}repair_fee + IMPORTING + iv_repair_type TYPE string + iv_hours TYPE decfloat34 + iv_parts_cost TYPE decfloat34 + iv_member TYPE abap_bool + EXPORTING + ev_labour_fee TYPE decfloat34 + ev_total_fee TYPE decfloat34 + EXCEPTIONS + invalid_hours. + + DATA lv_rate TYPE decfloat34. + DATA lv_discount TYPE decfloat34. + + IF iv_hours < 0. + RAISE invalid_hours. + ENDIF. + + CASE iv_repair_type. + WHEN 'BR'. + lv_rate = 60. + WHEN 'GE'. + lv_rate = 45. + WHEN 'WH'. + lv_rate = 30. + WHEN OTHERS. + lv_rate = 40. + ENDCASE. + + ev_labour_fee = round( val = iv_hours * lv_rate dec = 2 ). + + IF iv_member <> abap_true. + lv_discount = round( val = ev_labour_fee * 10 / 100 dec = 2 ). + ev_labour_fee = ev_labour_fee - lv_discount. + ENDIF. + + ev_total_fee = ev_labour_fee + iv_parts_cost. + + IF ev_total_fee < 25. + ev_total_fee = 25. + ENDIF. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0156/faulty/m2_repair_fee.func.abap b/tasks_gen/eval/G0156/faulty/m2_repair_fee.func.abap new file mode 100644 index 0000000..40eef95 --- /dev/null +++ b/tasks_gen/eval/G0156/faulty/m2_repair_fee.func.abap @@ -0,0 +1,44 @@ +FUNCTION {{p}}repair_fee + IMPORTING + iv_repair_type TYPE string + iv_hours TYPE decfloat34 + iv_parts_cost TYPE decfloat34 + iv_member TYPE abap_bool + EXPORTING + ev_labour_fee TYPE decfloat34 + ev_total_fee TYPE decfloat34 + EXCEPTIONS + invalid_hours. + + DATA lv_rate TYPE decfloat34. + DATA lv_discount TYPE decfloat34. + + IF iv_hours < 0. + RAISE invalid_hours. + ENDIF. + + CASE iv_repair_type. + WHEN 'BR'. + lv_rate = 60. + WHEN 'GE'. + lv_rate = 45. + WHEN 'WH'. + lv_rate = 30. + WHEN OTHERS. + lv_rate = 40. + ENDCASE. + + ev_labour_fee = round( val = iv_hours * lv_rate dec = 2 ). + + IF iv_member = abap_false. + lv_discount = round( val = ev_labour_fee * 10 / 100 dec = 2 ). + ev_labour_fee = ev_labour_fee - lv_discount. + ENDIF. + + ev_total_fee = ev_labour_fee + iv_parts_cost. + + IF ev_total_fee < 25. + ev_total_fee = 25. + ENDIF. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0156/faulty/m3_repair_fee.func.abap b/tasks_gen/eval/G0156/faulty/m3_repair_fee.func.abap new file mode 100644 index 0000000..b6f9e0c --- /dev/null +++ b/tasks_gen/eval/G0156/faulty/m3_repair_fee.func.abap @@ -0,0 +1,44 @@ +FUNCTION {{p}}repair_fee + IMPORTING + iv_repair_type TYPE string + iv_hours TYPE decfloat34 + iv_parts_cost TYPE decfloat34 + iv_member TYPE abap_bool + EXPORTING + ev_labour_fee TYPE decfloat34 + ev_total_fee TYPE decfloat34 + EXCEPTIONS + invalid_hours. + + DATA lv_rate TYPE decfloat34. + DATA lv_discount TYPE decfloat34. + + IF iv_hours < 0. + RAISE invalid_hours. + ENDIF. + + CASE iv_repair_type. + WHEN 'BR'. + lv_rate = 60. + WHEN 'GE'. + lv_rate = 45. + WHEN 'WH'. + lv_rate = 30. + WHEN OTHERS. + lv_rate = 40. + ENDCASE. + + ev_labour_fee = round( val = iv_hours * lv_rate dec = 2 ). + + IF iv_member = abap_true. + lv_discount = round( val = ev_labour_fee * 10 / 101 dec = 2 ). + ev_labour_fee = ev_labour_fee - lv_discount. + ENDIF. + + ev_total_fee = ev_labour_fee + iv_parts_cost. + + IF ev_total_fee < 25. + ev_total_fee = 25. + ENDIF. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0156/faulty/m4_repair_fee.func.abap b/tasks_gen/eval/G0156/faulty/m4_repair_fee.func.abap new file mode 100644 index 0000000..c81d30f --- /dev/null +++ b/tasks_gen/eval/G0156/faulty/m4_repair_fee.func.abap @@ -0,0 +1,44 @@ +FUNCTION {{p}}repair_fee + IMPORTING + iv_repair_type TYPE string + iv_hours TYPE decfloat34 + iv_parts_cost TYPE decfloat34 + iv_member TYPE abap_bool + EXPORTING + ev_labour_fee TYPE decfloat34 + ev_total_fee TYPE decfloat34 + EXCEPTIONS + invalid_hours. + + DATA lv_rate TYPE decfloat34. + DATA lv_discount TYPE decfloat34. + + IF iv_hours < 0. + RAISE invalid_hours. + ENDIF. + + CASE iv_repair_type. + WHEN 'BR'. + lv_rate = 60. + WHEN 'GE'. + lv_rate = 45. + WHEN 'WH'. + lv_rate = 30. + WHEN OTHERS. + lv_rate = 40. + ENDCASE. + + ev_labour_fee = round( val = iv_hours * lv_rate dec = 2 ). + + IF iv_member = abap_true. + lv_discount = round( val = ev_labour_fee * 10 / 100 dec = 2 ). + ev_labour_fee = ev_labour_fee - lv_discount. + ENDIF. + + ev_total_fee = ev_labour_fee - iv_parts_cost. + + IF ev_total_fee < 25. + ev_total_fee = 25. + ENDIF. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0156/generation.json b/tasks_gen/eval/G0156/generation.json new file mode 100644 index 0000000..ff83047 --- /dev/null +++ b/tasks_gen/eval/G0156/generation.json @@ -0,0 +1,19 @@ +{ + "id": "G0156", + "pool": "eval", + "object_type": "FUNC", + "category": "G", + "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/eval/G0156/hidden/t21_hidden.clas.abap b/tasks_gen/eval/G0156/hidden/t21_hidden.clas.abap new file mode 100644 index 0000000..056af61 --- /dev/null +++ b/tasks_gen/eval/G0156/hidden/t21_hidden.clas.abap @@ -0,0 +1,160 @@ +CLASS {{p}}t21_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS fee_of + IMPORTING + iv_type TYPE string + iv_hours TYPE decfloat34 + iv_parts TYPE decfloat34 + iv_member TYPE abap_bool DEFAULT abap_false + EXPORTING + ev_labour TYPE decfloat34 + ev_total TYPE decfloat34 + ev_subrc TYPE sysubrc. + METHODS brake_rate FOR TESTING. + METHODS gear_rate FOR TESTING. + METHODS wheel_rate FOR TESTING. + METHODS other_rate FOR TESTING. + METHODS labour_rounding FOR TESTING. + METHODS minimum_total FOR TESTING. + METHODS member_discount FOR TESTING. + METHODS member_minimum FOR TESTING. + METHODS negative_hours FOR TESTING. + METHODS zero_hours FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t21_hidden IMPLEMENTATION. + METHOD fee_of. + ev_labour = 0. + ev_total = 0. + CALL FUNCTION '{{P}}REPAIR_FEE' + EXPORTING + iv_repair_type = iv_type + iv_hours = iv_hours + iv_parts_cost = iv_parts + iv_member = iv_member + IMPORTING + ev_labour_fee = ev_labour + ev_total_fee = ev_total + EXCEPTIONS + invalid_hours = 1 + OTHERS = 2. + ev_subrc = sy-subrc. + ENDMETHOD. + + METHOD brake_rate. + DATA lv_labour TYPE decfloat34. + DATA lv_total TYPE decfloat34. + DATA lv_exp TYPE decfloat34. + fee_of( EXPORTING iv_type = 'BR' iv_hours = '1.5' iv_parts = '20' + IMPORTING ev_labour = lv_labour ev_total = lv_total ). + lv_exp = '90.00'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_labour ). + lv_exp = '110.00'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_total ). + ENDMETHOD. + + METHOD gear_rate. + DATA lv_labour TYPE decfloat34. + DATA lv_total TYPE decfloat34. + DATA lv_exp TYPE decfloat34. + fee_of( EXPORTING iv_type = 'GE' iv_hours = '2' iv_parts = '0' + IMPORTING ev_labour = lv_labour ev_total = lv_total ). + lv_exp = '90.00'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_labour ). + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_total ). + ENDMETHOD. + + METHOD wheel_rate. + DATA lv_labour TYPE decfloat34. + DATA lv_total TYPE decfloat34. + DATA lv_exp TYPE decfloat34. + fee_of( EXPORTING iv_type = 'WH' iv_hours = '1' iv_parts = '5' + IMPORTING ev_labour = lv_labour ev_total = lv_total ). + lv_exp = '30.00'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_labour ). + lv_exp = '35.00'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_total ). + ENDMETHOD. + + METHOD other_rate. + DATA lv_labour TYPE decfloat34. + DATA lv_total TYPE decfloat34. + DATA lv_exp TYPE decfloat34. + fee_of( EXPORTING iv_type = 'XX' iv_hours = '1' iv_parts = '0' + IMPORTING ev_labour = lv_labour ev_total = lv_total ). + lv_exp = '40.00'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_labour ). + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_total ). + ENDMETHOD. + + METHOD labour_rounding. + DATA lv_labour TYPE decfloat34. + DATA lv_total TYPE decfloat34. + DATA lv_exp TYPE decfloat34. + fee_of( EXPORTING iv_type = 'GE' iv_hours = '0.333' iv_parts = '20' + IMPORTING ev_labour = lv_labour ev_total = lv_total ). + lv_exp = '14.99'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_labour ). + lv_exp = '34.99'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_total ). + ENDMETHOD. + + METHOD minimum_total. + DATA lv_labour TYPE decfloat34. + DATA lv_total TYPE decfloat34. + DATA lv_exp TYPE decfloat34. + fee_of( EXPORTING iv_type = 'WH' iv_hours = '0.5' iv_parts = '1' + IMPORTING ev_labour = lv_labour ev_total = lv_total ). + lv_exp = '15.00'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_labour ). + lv_exp = '25.00'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_total ). + ENDMETHOD. + + METHOD member_discount. + DATA lv_labour TYPE decfloat34. + DATA lv_total TYPE decfloat34. + DATA lv_exp TYPE decfloat34. + fee_of( EXPORTING iv_type = 'BR' iv_hours = '1.5' iv_parts = '20' iv_member = abap_true + IMPORTING ev_labour = lv_labour ev_total = lv_total ). + lv_exp = '81.00'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_labour ). + lv_exp = '101.00'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_total ). + ENDMETHOD. + + METHOD member_minimum. + DATA lv_labour TYPE decfloat34. + DATA lv_total TYPE decfloat34. + DATA lv_exp TYPE decfloat34. + fee_of( EXPORTING iv_type = 'WH' iv_hours = '0.5' iv_parts = '0' iv_member = abap_true + IMPORTING ev_labour = lv_labour ev_total = lv_total ). + lv_exp = '13.50'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_labour ). + lv_exp = '25.00'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_total ). + ENDMETHOD. + + METHOD negative_hours. + DATA lv_subrc TYPE sysubrc. + fee_of( EXPORTING iv_type = 'BR' iv_hours = '-1' iv_parts = '0' + IMPORTING ev_subrc = lv_subrc ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lv_subrc ). + ENDMETHOD. + + METHOD zero_hours. + DATA lv_labour TYPE decfloat34. + DATA lv_total TYPE decfloat34. + DATA lv_subrc TYPE sysubrc. + DATA lv_exp TYPE decfloat34. + fee_of( EXPORTING iv_type = 'BR' iv_hours = '0' iv_parts = '30' + IMPORTING ev_labour = lv_labour ev_total = lv_total ev_subrc = lv_subrc ). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_subrc ). + lv_exp = '0.00'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_labour ). + lv_exp = '30.00'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_total ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0156/mutation.json b/tasks_gen/eval/G0156/mutation.json new file mode 100644 index 0000000..d98d5a8 --- /dev/null +++ b/tasks_gen/eval/G0156/mutation.json @@ -0,0 +1,82 @@ +{ + "task": "G0156", + "mutants": [ + { + "object": "{{P}}REPAIR_FEE", + "mutant": "line 16: < -> >= (rel)", + "status": "killed", + "hidden": "0/10", + "failed_tests": [ + "BRAKE_RATE", + "GEAR_RATE", + "LABOUR_ROUNDING", + "MEMBER_DISCOUNT", + "MEMBER_MINIMUM", + "MINIMUM_TOTAL", + "NEGATIVE_HOURS", + "OTHER_RATE", + "WHEEL_RATE", + "ZERO_HOURS" + ] + }, + { + "object": "{{P}}REPAIR_FEE", + "mutant": "line 33: = -> <> (eq)", + "status": "killed", + "hidden": "2/10", + "failed_tests": [ + "BRAKE_RATE", + "GEAR_RATE", + "LABOUR_ROUNDING", + "MEMBER_DISCOUNT", + "MEMBER_MINIMUM", + "MINIMUM_TOTAL", + "OTHER_RATE", + "WHEEL_RATE" + ] + }, + { + "object": "{{P}}REPAIR_FEE", + "mutant": "line 33: abap_true -> abap_false (bool)", + "status": "killed", + "hidden": "2/10", + "failed_tests": [ + "BRAKE_RATE", + "GEAR_RATE", + "LABOUR_ROUNDING", + "MEMBER_DISCOUNT", + "MEMBER_MINIMUM", + "MINIMUM_TOTAL", + "OTHER_RATE", + "WHEEL_RATE" + ] + }, + { + "object": "{{P}}REPAIR_FEE", + "mutant": "line 34: 100 -> 101 (const)", + "status": "killed", + "hidden": "8/10", + "failed_tests": [ + "MEMBER_DISCOUNT", + "MEMBER_MINIMUM" + ] + }, + { + "object": "{{P}}REPAIR_FEE", + "mutant": "line 38: + -> - (arith)", + "status": "killed", + "hidden": "5/10", + "failed_tests": [ + "BRAKE_RATE", + "LABOUR_ROUNDING", + "MEMBER_DISCOUNT", + "WHEEL_RATE", + "ZERO_HOURS" + ] + } + ], + "valid": 5, + "killed": 5, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0156/reference/repair_fee.func.abap b/tasks_gen/eval/G0156/reference/repair_fee.func.abap new file mode 100644 index 0000000..712ea6c --- /dev/null +++ b/tasks_gen/eval/G0156/reference/repair_fee.func.abap @@ -0,0 +1,44 @@ +FUNCTION {{p}}repair_fee + IMPORTING + iv_repair_type TYPE string + iv_hours TYPE decfloat34 + iv_parts_cost TYPE decfloat34 + iv_member TYPE abap_bool + EXPORTING + ev_labour_fee TYPE decfloat34 + ev_total_fee TYPE decfloat34 + EXCEPTIONS + invalid_hours. + + DATA lv_rate TYPE decfloat34. + DATA lv_discount TYPE decfloat34. + + IF iv_hours < 0. + RAISE invalid_hours. + ENDIF. + + CASE iv_repair_type. + WHEN 'BR'. + lv_rate = 60. + WHEN 'GE'. + lv_rate = 45. + WHEN 'WH'. + lv_rate = 30. + WHEN OTHERS. + lv_rate = 40. + ENDCASE. + + ev_labour_fee = round( val = iv_hours * lv_rate dec = 2 ). + + IF iv_member = abap_true. + lv_discount = round( val = ev_labour_fee * 10 / 100 dec = 2 ). + ev_labour_fee = ev_labour_fee - lv_discount. + ENDIF. + + ev_total_fee = ev_labour_fee + iv_parts_cost. + + IF ev_total_fee < 25. + ev_total_fee = 25. + ENDIF. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0156/reference/t21_test.clas.abap b/tasks_gen/eval/G0156/reference/t21_test.clas.abap new file mode 100644 index 0000000..4b06514 --- /dev/null +++ b/tasks_gen/eval/G0156/reference/t21_test.clas.abap @@ -0,0 +1,73 @@ +CLASS {{p}}t21_test DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS fee_of + IMPORTING + iv_type TYPE string + iv_hours TYPE decfloat34 + iv_parts TYPE decfloat34 + iv_member TYPE abap_bool DEFAULT abap_false + RETURNING + VALUE(rv_total) TYPE decfloat34. + METHODS brake_fee FOR TESTING. + METHODS minimum_fee FOR TESTING. + METHODS member_fee FOR TESTING. + METHODS negative_hours FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t21_test IMPLEMENTATION. + METHOD fee_of. + DATA lv_labour TYPE decfloat34. + CALL FUNCTION '{{P}}REPAIR_FEE' + EXPORTING + iv_repair_type = iv_type + iv_hours = iv_hours + iv_parts_cost = iv_parts + iv_member = iv_member + IMPORTING + ev_labour_fee = lv_labour + ev_total_fee = rv_total + EXCEPTIONS + invalid_hours = 1 + OTHERS = 2. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + ENDMETHOD. + + METHOD brake_fee. + DATA lv_exp TYPE decfloat34. + lv_exp = '110.00'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp + act = fee_of( iv_type = 'BR' iv_hours = '1.5' iv_parts = '20' ) ). + ENDMETHOD. + + METHOD minimum_fee. + DATA lv_exp TYPE decfloat34. + lv_exp = '25.00'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp + act = fee_of( iv_type = 'WH' iv_hours = '0.5' iv_parts = '1' ) ). + ENDMETHOD. + + METHOD member_fee. + DATA lv_exp TYPE decfloat34. + lv_exp = '101.00'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp + act = fee_of( iv_type = 'BR' iv_hours = '1.5' iv_parts = '20' iv_member = abap_true ) ). + ENDMETHOD. + + METHOD negative_hours. + DATA lv_total TYPE decfloat34. + CALL FUNCTION '{{P}}REPAIR_FEE' + EXPORTING + iv_repair_type = 'BR' + iv_hours = '-1' + iv_parts_cost = '0' + iv_member = abap_false + IMPORTING + ev_total_fee = lv_total + EXCEPTIONS + invalid_hours = 1 + OTHERS = 2. + cl_abap_unit_assert=>assert_equals( exp = 1 act = sy-subrc ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0156/seed/repair_sample.func.abap b/tasks_gen/eval/G0156/seed/repair_sample.func.abap new file mode 100644 index 0000000..80a9f12 --- /dev/null +++ b/tasks_gen/eval/G0156/seed/repair_sample.func.abap @@ -0,0 +1,16 @@ +FUNCTION {{p}}repair_sample + IMPORTING + iv_repair_type TYPE string + iv_hours TYPE decfloat34 + iv_parts_cost TYPE decfloat34 + iv_member TYPE abap_bool + EXPORTING + ev_labour_fee TYPE decfloat34 + ev_total_fee TYPE decfloat34 + EXCEPTIONS + invalid_hours. + + ev_labour_fee = 0. + ev_total_fee = 0. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0156/spec.md b/tasks_gen/eval/G0156/spec.md new file mode 100644 index 0000000..2ef2a1c --- /dev/null +++ b/tasks_gen/eval/G0156/spec.md @@ -0,0 +1,45 @@ +# 1. Goal +A bicycle repair shop prices repair jobs. The workshop program calls one function +module for each repair job before it prints the work order. The new function +module must have the same interface as the sample pricing module, because the +workshop program calls all pricing modules in the same way. + +# 2. Open questions +None. + +# 3. Context +- Function group {{P}}FG_REPAIR exists in package $TMP. +- Function module {{P}}REPAIR_SAMPLE exists in this group. It is the sample + pricing module. Its interface is the interface that all pricing modules must + use. + +# 4. Contract +- Create the function module {{P}}REPAIR_FEE in function group {{P}}FG_REPAIR. +- Use exactly the interface of {{P}}REPAIR_SAMPLE: the same parameter names, + kinds, types, and exceptions. + +# 5. Business rules +1. If the hours are less than zero, raise the exception INVALID_HOURS. +2. The hourly rate depends on the repair type: + - 'BR' brake repair: 60.00 + - 'GE' gear repair: 45.00 + - 'WH' wheel repair: 30.00 + - every other type: 40.00 +3. The labour fee is the hours multiplied by the hourly rate. Round the labour + fee half up to 2 decimals. Return it in ev_labour_fee. +4. If the customer is a club member, reduce the labour fee by 10 %. Round the + reduction half up to 2 decimals. Return the reduced labour fee in + ev_labour_fee. +5. The total fee is the labour fee from rule 3 or rule 4 plus the parts cost. + Return it in ev_total_fee. +6. If the total fee is less than 25.00, set the total fee to 25.00. + +# 6. Constraints +- Release target: 7.02. Use only syntax that release 7.02 supports. +- Coding standards: Clean ABAP. Keep every method below 40 statements. +- Out of scope: do not change {{P}}REPAIR_SAMPLE. + +# 7. Acceptance +- The function module is active and has no syntax error. +- The hidden tests pass. +- Write ABAP Unit tests for the function module in a global test class. diff --git a/tasks_gen/eval/G0156/task.json b/tasks_gen/eval/G0156/task.json new file mode 100644 index 0000000..06408ae --- /dev/null +++ b/tasks_gen/eval/G0156/task.json @@ -0,0 +1,88 @@ +{ + "id": "G0156", + "category": "G", + "object_type": "FUNC", + "difficulty": 2, + "release_target": "v702", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 40, + "max_activations": 10 + }, + "seed": [ + { + "type": "FUGR", + "name": "{{P}}FG_REPAIR", + "description": "Repair pricing" + }, + { + "type": "FUNC", + "name": "{{P}}REPAIR_SAMPLE", + "functionGroup": "{{P}}FG_REPAIR", + "file": "seed/repair_sample.func.abap", + "description": "Sample pricing module" + } + ], + "contract": [ + { + "type": "FUNC", + "name": "{{P}}REPAIR_FEE", + "functionGroup": "{{P}}FG_REPAIR", + "params": [ + { + "name": "iv_repair_type", + "type": "string" + }, + { + "name": "iv_hours", + "type": "decfloat34" + }, + { + "name": "iv_parts_cost", + "type": "decfloat34" + }, + { + "name": "iv_member", + "type": "abap_bool" + }, + { + "name": "ev_labour_fee", + "type": "decfloat34" + }, + { + "name": "ev_total_fee", + "type": "decfloat34" + } + ] + } + ], + "out_of_scope": [ + "{{P}}REPAIR_SAMPLE" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T21_HIDDEN", + "file": "hidden/t21_hidden.clas.abap", + "description": "T21 hidden tests" + } + ], + "reference": [ + { + "type": "FUNC", + "name": "{{P}}REPAIR_FEE", + "functionGroup": "{{P}}FG_REPAIR", + "file": "reference/repair_fee.func.abap", + "description": "Repair fee module" + }, + { + "type": "CLAS", + "name": "{{P}}T21_TEST", + "file": "reference/t21_test.clas.abap", + "description": "T21 own tests" + } + ], + "craft_checks": [ + "method_length" + ] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0157/faulty/m0_dep_calc.func.abap b/tasks_gen/eval/G0157/faulty/m0_dep_calc.func.abap new file mode 100644 index 0000000..4e7bbb6 --- /dev/null +++ b/tasks_gen/eval/G0157/faulty/m0_dep_calc.func.abap @@ -0,0 +1,38 @@ +FUNCTION {{p}}dep_calc + IMPORTING + iv_code TYPE c + iv_quantity TYPE i + iv_damaged TYPE abap_bool + EXPORTING + ev_deposit TYPE decfloat34 + EXCEPTIONS + invalid_quantity + invalid_container. + + DATA lv_unit TYPE decfloat34. + + IF iv_quantity >= 1. + RAISE invalid_quantity. + ENDIF. + + CASE iv_code. + WHEN 'A'. + lv_unit = '1.50'. + WHEN 'B'. + lv_unit = '3.00'. + WHEN 'G'. + lv_unit = '0.08'. + WHEN 'P'. + lv_unit = '0.25'. + WHEN OTHERS. + RAISE invalid_container. + ENDCASE. + + IF iv_damaged = abap_true. + lv_unit = lv_unit / 2. + lv_unit = round( val = lv_unit dec = 2 mode = cl_abap_math=>round_half_up ). + ENDIF. + + ev_deposit = round( val = lv_unit * iv_quantity dec = 2 mode = cl_abap_math=>round_half_up ). + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0157/faulty/m1_dep_calc.func.abap b/tasks_gen/eval/G0157/faulty/m1_dep_calc.func.abap new file mode 100644 index 0000000..7042cd5 --- /dev/null +++ b/tasks_gen/eval/G0157/faulty/m1_dep_calc.func.abap @@ -0,0 +1,38 @@ +FUNCTION {{p}}dep_calc + IMPORTING + iv_code TYPE c + iv_quantity TYPE i + iv_damaged TYPE abap_bool + EXPORTING + ev_deposit TYPE decfloat34 + EXCEPTIONS + invalid_quantity + invalid_container. + + DATA lv_unit TYPE decfloat34. + + IF iv_quantity < 1. + RAISE invalid_quantity. + ENDIF. + + CASE iv_code. + WHEN 'A'. + lv_unit = '1.50'. + WHEN 'B'. + lv_unit = '3.00'. + WHEN 'G'. + lv_unit = '0.08'. + WHEN 'P'. + lv_unit = '0.25'. + WHEN OTHERS. + RAISE invalid_container. + ENDCASE. + + IF iv_damaged = abap_false. + lv_unit = lv_unit / 2. + lv_unit = round( val = lv_unit dec = 2 mode = cl_abap_math=>round_half_up ). + ENDIF. + + ev_deposit = round( val = lv_unit * iv_quantity dec = 2 mode = cl_abap_math=>round_half_up ). + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0157/faulty/m2_dep_calc.func.abap b/tasks_gen/eval/G0157/faulty/m2_dep_calc.func.abap new file mode 100644 index 0000000..aba26a5 --- /dev/null +++ b/tasks_gen/eval/G0157/faulty/m2_dep_calc.func.abap @@ -0,0 +1,38 @@ +FUNCTION {{p}}dep_calc + IMPORTING + iv_code TYPE c + iv_quantity TYPE i + iv_damaged TYPE abap_bool + EXPORTING + ev_deposit TYPE decfloat34 + EXCEPTIONS + invalid_quantity + invalid_container. + + DATA lv_unit TYPE decfloat34. + + IF iv_quantity < 1. + RAISE invalid_quantity. + ENDIF. + + CASE iv_code. + WHEN 'A'. + lv_unit = '1.50'. + WHEN 'B'. + lv_unit = '3.00'. + WHEN 'G'. + lv_unit = '0.08'. + WHEN 'P'. + lv_unit = '0.25'. + WHEN OTHERS. + RAISE invalid_container. + ENDCASE. + + IF iv_damaged = abap_true. + lv_unit = lv_unit / 2. + lv_unit = round( val = lv_unit dec = 3 mode = cl_abap_math=>round_half_up ). + ENDIF. + + ev_deposit = round( val = lv_unit * iv_quantity dec = 2 mode = cl_abap_math=>round_half_up ). + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0157/faulty/m3_dep_calc.func.abap b/tasks_gen/eval/G0157/faulty/m3_dep_calc.func.abap new file mode 100644 index 0000000..94f65e6 --- /dev/null +++ b/tasks_gen/eval/G0157/faulty/m3_dep_calc.func.abap @@ -0,0 +1,38 @@ +FUNCTION {{p}}dep_calc + IMPORTING + iv_code TYPE c + iv_quantity TYPE i + iv_damaged TYPE abap_bool + EXPORTING + ev_deposit TYPE decfloat34 + EXCEPTIONS + invalid_quantity + invalid_container. + + DATA lv_unit TYPE decfloat34. + + IF iv_quantity < 1. + RAISE invalid_quantity. + ENDIF. + + CASE iv_code. + WHEN 'A'. + lv_unit = '1.50'. + WHEN 'B'. + lv_unit = '3.00'. + WHEN 'G'. + lv_unit = '0.08'. + WHEN 'P'. + lv_unit = '0.25'. + WHEN OTHERS. + RAISE invalid_container. + ENDCASE. + + IF iv_damaged = abap_true. + lv_unit = lv_unit / 2. + lv_unit = round( val = lv_unit dec = 2 mode = cl_abap_math=>round_half_up ). + ENDIF. + + ev_deposit = round( val = lv_unit / iv_quantity dec = 2 mode = cl_abap_math=>round_half_up ). + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0157/generation.json b/tasks_gen/eval/G0157/generation.json new file mode 100644 index 0000000..5f86b67 --- /dev/null +++ b/tasks_gen/eval/G0157/generation.json @@ -0,0 +1,39 @@ +{ + "id": "G0157", + "pool": "eval", + "object_type": "FUNC", + "category": "G", + "attempts": [ + { + "stage": "bundle", + "errors": [ + "reference/t14_test.clas.abap line 4: syntax error for release v740sp05 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\"", + "hidden/t14_hidden.clas.abap line 4: syntax error for release v740sp05 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"METHODS\"" + ], + "by_check": { + "abaplint": 2 + } + }, + { + "stage": "validate", + "oracle": null, + "null": null + }, + { + "stage": "validate", + "oracle": 98.5, + "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/eval/G0157/hidden/t14_hidden.clas.abap b/tasks_gen/eval/G0157/hidden/t14_hidden.clas.abap new file mode 100644 index 0000000..ed1dfcf --- /dev/null +++ b/tasks_gen/eval/G0157/hidden/t14_hidden.clas.abap @@ -0,0 +1,126 @@ +CLASS {{p}}t14_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS deposit_for + IMPORTING iv_code TYPE c + iv_quantity TYPE i + iv_damaged TYPE abap_bool DEFAULT abap_false + RETURNING VALUE(rv_deposit) TYPE decfloat34. + METHODS crate_a_full FOR TESTING. + METHODS crate_b_full FOR TESTING. + METHODS glass_full FOR TESTING. + METHODS pet_full FOR TESTING. + METHODS damaged_crate FOR TESTING. + METHODS damaged_rounds_up FOR TESTING. + METHODS damaged_glass_total FOR TESTING. + METHODS zero_quantity FOR TESTING. + METHODS negative_quantity FOR TESTING. + METHODS unknown_code FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t14_hidden IMPLEMENTATION. + METHOD deposit_for. + CALL FUNCTION '{{P}}DEP_CALC' + EXPORTING + iv_code = iv_code + iv_quantity = iv_quantity + iv_damaged = iv_damaged + IMPORTING + ev_deposit = rv_deposit + EXCEPTIONS + invalid_quantity = 1 + invalid_container = 2 + OTHERS = 3. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + ENDMETHOD. + + METHOD crate_a_full. + DATA lv_exp TYPE decfloat34 VALUE '3.00'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = deposit_for( iv_code = 'A' iv_quantity = 2 ) ). + ENDMETHOD. + + METHOD crate_b_full. + DATA lv_exp TYPE decfloat34 VALUE '3.00'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = deposit_for( iv_code = 'B' iv_quantity = 1 ) ). + ENDMETHOD. + + METHOD glass_full. + DATA lv_exp TYPE decfloat34 VALUE '0.80'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = deposit_for( iv_code = 'G' iv_quantity = 10 ) ). + ENDMETHOD. + + METHOD pet_full. + DATA lv_exp TYPE decfloat34 VALUE '1.00'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = deposit_for( iv_code = 'P' iv_quantity = 4 ) ). + ENDMETHOD. + + METHOD damaged_crate. + DATA lv_exp TYPE decfloat34 VALUE '3.00'. + DATA lv_act TYPE decfloat34. + lv_act = deposit_for( iv_code = 'B' iv_quantity = 2 iv_damaged = abap_true ). + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_act ). + ENDMETHOD. + + METHOD damaged_rounds_up. + DATA lv_exp TYPE decfloat34 VALUE '0.39'. + DATA lv_act TYPE decfloat34. + lv_act = deposit_for( iv_code = 'P' iv_quantity = 3 iv_damaged = abap_true ). + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_act ). + ENDMETHOD. + + METHOD damaged_glass_total. + DATA lv_exp TYPE decfloat34 VALUE '0.12'. + DATA lv_act TYPE decfloat34. + lv_act = deposit_for( iv_code = 'G' iv_quantity = 3 iv_damaged = abap_true ). + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_act ). + ENDMETHOD. + + METHOD zero_quantity. + DATA lv_deposit TYPE decfloat34. + CALL FUNCTION '{{P}}DEP_CALC' + EXPORTING + iv_code = 'A' + iv_quantity = 0 + iv_damaged = abap_false + IMPORTING + ev_deposit = lv_deposit + EXCEPTIONS + invalid_quantity = 1 + invalid_container = 2 + OTHERS = 3. + cl_abap_unit_assert=>assert_equals( exp = 1 act = sy-subrc ). + ENDMETHOD. + + METHOD negative_quantity. + DATA lv_deposit TYPE decfloat34. + CALL FUNCTION '{{P}}DEP_CALC' + EXPORTING + iv_code = 'G' + iv_quantity = -3 + iv_damaged = abap_false + IMPORTING + ev_deposit = lv_deposit + EXCEPTIONS + invalid_quantity = 1 + invalid_container = 2 + OTHERS = 3. + cl_abap_unit_assert=>assert_equals( exp = 1 act = sy-subrc ). + ENDMETHOD. + + METHOD unknown_code. + DATA lv_deposit TYPE decfloat34. + CALL FUNCTION '{{P}}DEP_CALC' + EXPORTING + iv_code = 'Z' + iv_quantity = 1 + iv_damaged = abap_false + IMPORTING + ev_deposit = lv_deposit + EXCEPTIONS + invalid_quantity = 1 + invalid_container = 2 + OTHERS = 3. + cl_abap_unit_assert=>assert_equals( exp = 2 act = sy-subrc ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0157/mutation.json b/tasks_gen/eval/G0157/mutation.json new file mode 100644 index 0000000..59d0bca --- /dev/null +++ b/tasks_gen/eval/G0157/mutation.json @@ -0,0 +1,72 @@ +{ + "task": "G0157", + "mutants": [ + { + "object": "{{P}}DEP_CALC", + "mutant": "line 14: < -> >= (rel)", + "status": "killed", + "hidden": "0/10", + "failed_tests": [ + "CRATE_A_FULL", + "CRATE_B_FULL", + "DAMAGED_CRATE", + "DAMAGED_GLASS_TOTAL", + "DAMAGED_ROUNDS_UP", + "GLASS_FULL", + "NEGATIVE_QUANTITY", + "PET_FULL", + "UNKNOWN_CODE", + "ZERO_QUANTITY" + ] + }, + { + "object": "{{P}}DEP_CALC", + "mutant": "line 31: abap_true -> abap_false (bool)", + "status": "killed", + "hidden": "3/10", + "failed_tests": [ + "CRATE_A_FULL", + "CRATE_B_FULL", + "DAMAGED_CRATE", + "DAMAGED_GLASS_TOTAL", + "DAMAGED_ROUNDS_UP", + "GLASS_FULL", + "PET_FULL" + ] + }, + { + "object": "{{P}}DEP_CALC", + "mutant": "line 33: 2 -> 3 (const)", + "status": "killed", + "hidden": "9/10", + "failed_tests": [ + "DAMAGED_ROUNDS_UP" + ] + }, + { + "object": "{{P}}DEP_CALC", + "mutant": "line 36: * -> / (arith)", + "status": "killed", + "hidden": "4/10", + "failed_tests": [ + "CRATE_A_FULL", + "DAMAGED_CRATE", + "DAMAGED_GLASS_TOTAL", + "DAMAGED_ROUNDS_UP", + "GLASS_FULL", + "PET_FULL" + ] + }, + { + "object": "{{P}}DEP_CALC", + "mutant": "line 36: 2 -> 3 (const)", + "status": "survived", + "hidden": "10/10", + "failed_tests": [] + } + ], + "valid": 5, + "killed": 4, + "kill_rate": 0.8, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0157/reference/dep_calc.func.abap b/tasks_gen/eval/G0157/reference/dep_calc.func.abap new file mode 100644 index 0000000..318ba60 --- /dev/null +++ b/tasks_gen/eval/G0157/reference/dep_calc.func.abap @@ -0,0 +1,38 @@ +FUNCTION {{p}}dep_calc + IMPORTING + iv_code TYPE c + iv_quantity TYPE i + iv_damaged TYPE abap_bool + EXPORTING + ev_deposit TYPE decfloat34 + EXCEPTIONS + invalid_quantity + invalid_container. + + DATA lv_unit TYPE decfloat34. + + IF iv_quantity < 1. + RAISE invalid_quantity. + ENDIF. + + CASE iv_code. + WHEN 'A'. + lv_unit = '1.50'. + WHEN 'B'. + lv_unit = '3.00'. + WHEN 'G'. + lv_unit = '0.08'. + WHEN 'P'. + lv_unit = '0.25'. + WHEN OTHERS. + RAISE invalid_container. + ENDCASE. + + IF iv_damaged = abap_true. + lv_unit = lv_unit / 2. + lv_unit = round( val = lv_unit dec = 2 mode = cl_abap_math=>round_half_up ). + ENDIF. + + ev_deposit = round( val = lv_unit * iv_quantity dec = 2 mode = cl_abap_math=>round_half_up ). + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0157/reference/t14_test.clas.abap b/tasks_gen/eval/G0157/reference/t14_test.clas.abap new file mode 100644 index 0000000..1a111e5 --- /dev/null +++ b/tasks_gen/eval/G0157/reference/t14_test.clas.abap @@ -0,0 +1,58 @@ +CLASS {{p}}t14_test DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS deposit_of + IMPORTING iv_code TYPE c + iv_quantity TYPE i + iv_damaged TYPE abap_bool DEFAULT abap_false + RETURNING VALUE(rv_deposit) TYPE decfloat34. + METHODS full_deposit FOR TESTING. + METHODS damaged_deposit FOR TESTING. + METHODS invalid_input FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t14_test IMPLEMENTATION. + METHOD deposit_of. + CALL FUNCTION '{{P}}DEP_CALC' + EXPORTING + iv_code = iv_code + iv_quantity = iv_quantity + iv_damaged = iv_damaged + IMPORTING + ev_deposit = rv_deposit + EXCEPTIONS + invalid_quantity = 1 + invalid_container = 2 + OTHERS = 3. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + ENDMETHOD. + + METHOD full_deposit. + DATA lv_exp TYPE decfloat34 VALUE '6.00'. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = deposit_of( iv_code = 'B' iv_quantity = 2 ) ). + ENDMETHOD. + + METHOD damaged_deposit. + DATA lv_exp TYPE decfloat34 VALUE '0.39'. + DATA lv_act TYPE decfloat34. + lv_act = deposit_of( iv_code = 'P' iv_quantity = 3 iv_damaged = abap_true ). + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_act ). + ENDMETHOD. + + METHOD invalid_input. + DATA lv_deposit TYPE decfloat34. + CALL FUNCTION '{{P}}DEP_CALC' + EXPORTING + iv_code = 'Z' + iv_quantity = 1 + iv_damaged = abap_false + IMPORTING + ev_deposit = lv_deposit + EXCEPTIONS + invalid_quantity = 1 + invalid_container = 2 + OTHERS = 3. + cl_abap_unit_assert=>assert_equals( exp = 2 act = sy-subrc ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0157/seed/dep_sample.func.abap b/tasks_gen/eval/G0157/seed/dep_sample.func.abap new file mode 100644 index 0000000..56bf2be --- /dev/null +++ b/tasks_gen/eval/G0157/seed/dep_sample.func.abap @@ -0,0 +1,18 @@ +FUNCTION {{p}}dep_sample + IMPORTING + iv_code TYPE c + iv_quantity TYPE i + iv_damaged TYPE abap_bool + EXPORTING + ev_deposit TYPE decfloat34 + EXCEPTIONS + invalid_quantity + invalid_container. + + IF iv_quantity < 1. + RAISE invalid_quantity. + ENDIF. + + ev_deposit = iv_quantity. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0157/spec.md b/tasks_gen/eval/G0157/spec.md new file mode 100644 index 0000000..fd97eec --- /dev/null +++ b/tasks_gen/eval/G0157/spec.md @@ -0,0 +1,45 @@ +# 1. Goal +A beverage wholesaler takes back empty containers from its customers. The returns +program calls one function module for each return line. The function module +calculates the deposit that the wholesaler pays back to the customer. + +# 2. Open questions +None. + +# 3. Context +- Function group {{P}}FG_DEPOSIT exists in package $TMP. +- Function module {{P}}DEP_SAMPLE exists in this group. It is the sample deposit + module. The returns program calls all deposit modules with the interface of + {{P}}DEP_SAMPLE. + +# 4. Contract +- Create the function module {{P}}DEP_CALC in function group {{P}}FG_DEPOSIT. +- Use exactly the interface of {{P}}DEP_SAMPLE: + - IMPORTING iv_code TYPE c + - IMPORTING iv_quantity TYPE i + - IMPORTING iv_damaged TYPE abap_bool + - EXPORTING ev_deposit TYPE decfloat34 + - EXCEPTIONS invalid_quantity, invalid_container + +# 5. Business rules +1. If the quantity is less than 1, raise the exception INVALID_QUANTITY. +2. The container code gives the deposit of one container: + - 'A': crate with 12 glass bottles, 1.50 + - 'B': crate with 20 PET bottles, 3.00 + - 'G': single glass bottle, 0.08 + - 'P': single PET bottle, 0.25 +3. Any other container code raises the exception INVALID_CONTAINER. +4. If the container is damaged, the deposit of one container is half of the value + in rule 2, rounded half up to 2 decimals. +5. The deposit of the return line is the deposit of one container multiplied by + the quantity, rounded half up to 2 decimals. + +# 6. Constraints +- Release target: 7.40 SP05. Use only language elements that this release supports. +- Coding standards: Clean ABAP. +- Out of scope: do not change {{P}}DEP_SAMPLE. + +# 7. Acceptance +- The function module {{P}}DEP_CALC is active and has no syntax error. +- The hidden tests pass. +- Write ABAP Unit tests for the function module in a global test class. diff --git a/tasks_gen/eval/G0157/task.json b/tasks_gen/eval/G0157/task.json new file mode 100644 index 0000000..2872fc2 --- /dev/null +++ b/tasks_gen/eval/G0157/task.json @@ -0,0 +1,80 @@ +{ + "id": "G0157", + "category": "G", + "object_type": "FUNC", + "difficulty": 2, + "release_target": "v740sp05", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 40, + "max_activations": 10 + }, + "seed": [ + { + "type": "FUGR", + "name": "{{P}}FG_DEPOSIT", + "description": "Deposit calculation function group" + }, + { + "type": "FUNC", + "name": "{{P}}DEP_SAMPLE", + "functionGroup": "{{P}}FG_DEPOSIT", + "file": "seed/dep_sample.func.abap", + "description": "Sample deposit module" + } + ], + "contract": [ + { + "type": "FUNC", + "name": "{{P}}DEP_CALC", + "functionGroup": "{{P}}FG_DEPOSIT", + "params": [ + { + "name": "iv_code", + "type": "c" + }, + { + "name": "iv_quantity", + "type": "i" + }, + { + "name": "iv_damaged", + "type": "abap_bool" + }, + { + "name": "ev_deposit", + "type": "decfloat34" + } + ] + } + ], + "out_of_scope": [ + "{{P}}DEP_SAMPLE" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T14_HIDDEN", + "file": "hidden/t14_hidden.clas.abap", + "description": "T14 hidden tests" + } + ], + "reference": [ + { + "type": "FUNC", + "name": "{{P}}DEP_CALC", + "functionGroup": "{{P}}FG_DEPOSIT", + "file": "reference/dep_calc.func.abap", + "description": "Deposit calculation module" + }, + { + "type": "CLAS", + "name": "{{P}}T14_TEST", + "file": "reference/t14_test.clas.abap", + "description": "T14 own tests" + } + ], + "craft_checks": [ + "method_length" + ] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0158/faulty/m0_taxi_fare.func.abap b/tasks_gen/eval/G0158/faulty/m0_taxi_fare.func.abap new file mode 100644 index 0000000..f3bbb3b --- /dev/null +++ b/tasks_gen/eval/G0158/faulty/m0_taxi_fare.func.abap @@ -0,0 +1,50 @@ +FUNCTION {{p}}taxi_fare + IMPORTING + iv_distance_km TYPE decfloat34 + iv_wait_min TYPE i + iv_start_time TYPE t + EXPORTING + ev_fare TYPE decfloat34 + EXCEPTIONS + invalid_distance + invalid_wait. + + CONSTANTS: lc_base_fare TYPE decfloat34 VALUE '3.50', + lc_km_rate_1 TYPE decfloat34 VALUE '2.20', + lc_km_rate_2 TYPE decfloat34 VALUE '1.80', + lc_wait_rate TYPE decfloat34 VALUE '0.40', + lc_night_factor TYPE decfloat34 VALUE '1.2', + lc_min_fare TYPE decfloat34 VALUE '5.00', + lc_free_km TYPE decfloat34 VALUE '10'. + + IF iv_distance_km >= 0. + RAISE invalid_distance. + ENDIF. + IF iv_wait_min < 0. + RAISE invalid_wait. + ENDIF. + + DATA lv_distance_fare TYPE decfloat34. + IF iv_distance_km <= lc_free_km. + lv_distance_fare = iv_distance_km * lc_km_rate_1. + ELSE. + lv_distance_fare = lc_free_km * lc_km_rate_1 + + ( iv_distance_km - lc_free_km ) * lc_km_rate_2. + ENDIF. + + DATA lv_sum TYPE decfloat34. + lv_sum = lc_base_fare + lv_distance_fare. + + IF iv_start_time >= '220000' OR iv_start_time < '060000'. + lv_sum = lv_sum * lc_night_factor. + ENDIF. + + lv_sum = lv_sum + iv_wait_min * lc_wait_rate. + + ev_fare = round( val = lv_sum dec = 2 mode = cl_abap_math=>round_half_up ). + + IF ev_fare < lc_min_fare. + ev_fare = lc_min_fare. + ENDIF. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0158/faulty/m1_taxi_fare.func.abap b/tasks_gen/eval/G0158/faulty/m1_taxi_fare.func.abap new file mode 100644 index 0000000..c3254a8 --- /dev/null +++ b/tasks_gen/eval/G0158/faulty/m1_taxi_fare.func.abap @@ -0,0 +1,50 @@ +FUNCTION {{p}}taxi_fare + IMPORTING + iv_distance_km TYPE decfloat34 + iv_wait_min TYPE i + iv_start_time TYPE t + EXPORTING + ev_fare TYPE decfloat34 + EXCEPTIONS + invalid_distance + invalid_wait. + + CONSTANTS: lc_base_fare TYPE decfloat34 VALUE '3.50', + lc_km_rate_1 TYPE decfloat34 VALUE '2.20', + lc_km_rate_2 TYPE decfloat34 VALUE '1.80', + lc_wait_rate TYPE decfloat34 VALUE '0.40', + lc_night_factor TYPE decfloat34 VALUE '1.2', + lc_min_fare TYPE decfloat34 VALUE '5.00', + lc_free_km TYPE decfloat34 VALUE '10'. + + IF iv_distance_km < 0. + RAISE invalid_distance. + ENDIF. + IF iv_wait_min < 0. + RAISE invalid_wait. + ENDIF. + + DATA lv_distance_fare TYPE decfloat34. + IF iv_distance_km <= lc_free_km. + lv_distance_fare = iv_distance_km * lc_km_rate_1. + ELSE. + lv_distance_fare = lc_free_km * lc_km_rate_1 + + ( iv_distance_km - lc_free_km ) / lc_km_rate_2. + ENDIF. + + DATA lv_sum TYPE decfloat34. + lv_sum = lc_base_fare + lv_distance_fare. + + IF iv_start_time >= '220000' OR iv_start_time < '060000'. + lv_sum = lv_sum * lc_night_factor. + ENDIF. + + lv_sum = lv_sum + iv_wait_min * lc_wait_rate. + + ev_fare = round( val = lv_sum dec = 2 mode = cl_abap_math=>round_half_up ). + + IF ev_fare < lc_min_fare. + ev_fare = lc_min_fare. + ENDIF. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0158/faulty/m2_taxi_fare.func.abap b/tasks_gen/eval/G0158/faulty/m2_taxi_fare.func.abap new file mode 100644 index 0000000..8624428 --- /dev/null +++ b/tasks_gen/eval/G0158/faulty/m2_taxi_fare.func.abap @@ -0,0 +1,50 @@ +FUNCTION {{p}}taxi_fare + IMPORTING + iv_distance_km TYPE decfloat34 + iv_wait_min TYPE i + iv_start_time TYPE t + EXPORTING + ev_fare TYPE decfloat34 + EXCEPTIONS + invalid_distance + invalid_wait. + + CONSTANTS: lc_base_fare TYPE decfloat34 VALUE '3.50', + lc_km_rate_1 TYPE decfloat34 VALUE '2.20', + lc_km_rate_2 TYPE decfloat34 VALUE '1.80', + lc_wait_rate TYPE decfloat34 VALUE '0.40', + lc_night_factor TYPE decfloat34 VALUE '1.2', + lc_min_fare TYPE decfloat34 VALUE '5.00', + lc_free_km TYPE decfloat34 VALUE '10'. + + IF iv_distance_km < 0. + RAISE invalid_distance. + ENDIF. + IF iv_wait_min < 0. + RAISE invalid_wait. + ENDIF. + + DATA lv_distance_fare TYPE decfloat34. + IF iv_distance_km <= lc_free_km. + lv_distance_fare = iv_distance_km * lc_km_rate_1. + ELSE. + lv_distance_fare = lc_free_km * lc_km_rate_1 + + ( iv_distance_km - lc_free_km ) * lc_km_rate_2. + ENDIF. + + DATA lv_sum TYPE decfloat34. + lv_sum = lc_base_fare + lv_distance_fare. + + IF iv_start_time >= '220000' AND iv_start_time < '060000'. + lv_sum = lv_sum * lc_night_factor. + ENDIF. + + lv_sum = lv_sum + iv_wait_min * lc_wait_rate. + + ev_fare = round( val = lv_sum dec = 2 mode = cl_abap_math=>round_half_up ). + + IF ev_fare < lc_min_fare. + ev_fare = lc_min_fare. + ENDIF. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0158/faulty/m3_taxi_fare.func.abap b/tasks_gen/eval/G0158/faulty/m3_taxi_fare.func.abap new file mode 100644 index 0000000..5b69ee3 --- /dev/null +++ b/tasks_gen/eval/G0158/faulty/m3_taxi_fare.func.abap @@ -0,0 +1,50 @@ +FUNCTION {{p}}taxi_fare + IMPORTING + iv_distance_km TYPE decfloat34 + iv_wait_min TYPE i + iv_start_time TYPE t + EXPORTING + ev_fare TYPE decfloat34 + EXCEPTIONS + invalid_distance + invalid_wait. + + CONSTANTS: lc_base_fare TYPE decfloat34 VALUE '3.50', + lc_km_rate_1 TYPE decfloat34 VALUE '2.20', + lc_km_rate_2 TYPE decfloat34 VALUE '1.80', + lc_wait_rate TYPE decfloat34 VALUE '0.40', + lc_night_factor TYPE decfloat34 VALUE '1.2', + lc_min_fare TYPE decfloat34 VALUE '5.00', + lc_free_km TYPE decfloat34 VALUE '10'. + + IF iv_distance_km < 0. + RAISE invalid_distance. + ENDIF. + IF iv_wait_min < 0. + RAISE invalid_wait. + ENDIF. + + DATA lv_distance_fare TYPE decfloat34. + IF iv_distance_km <= lc_free_km. + lv_distance_fare = iv_distance_km * lc_km_rate_1. + ELSE. + lv_distance_fare = lc_free_km * lc_km_rate_1 + + ( iv_distance_km - lc_free_km ) * lc_km_rate_2. + ENDIF. + + DATA lv_sum TYPE decfloat34. + lv_sum = lc_base_fare + lv_distance_fare. + + IF iv_start_time >= '220000' OR iv_start_time < '060000'. + lv_sum = lv_sum * lc_night_factor. + ENDIF. + + lv_sum = lv_sum + iv_wait_min * lc_wait_rate. + + ev_fare = round( val = lv_sum dec = 3 mode = cl_abap_math=>round_half_up ). + + IF ev_fare < lc_min_fare. + ev_fare = lc_min_fare. + ENDIF. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0158/faulty/m4_taxi_fare.func.abap b/tasks_gen/eval/G0158/faulty/m4_taxi_fare.func.abap new file mode 100644 index 0000000..8f88cdb --- /dev/null +++ b/tasks_gen/eval/G0158/faulty/m4_taxi_fare.func.abap @@ -0,0 +1,50 @@ +FUNCTION {{p}}taxi_fare + IMPORTING + iv_distance_km TYPE decfloat34 + iv_wait_min TYPE i + iv_start_time TYPE t + EXPORTING + ev_fare TYPE decfloat34 + EXCEPTIONS + invalid_distance + invalid_wait. + + CONSTANTS: lc_base_fare TYPE decfloat34 VALUE '3.50', + lc_km_rate_1 TYPE decfloat34 VALUE '2.20', + lc_km_rate_2 TYPE decfloat34 VALUE '1.80', + lc_wait_rate TYPE decfloat34 VALUE '0.40', + lc_night_factor TYPE decfloat34 VALUE '1.2', + lc_min_fare TYPE decfloat34 VALUE '5.00', + lc_free_km TYPE decfloat34 VALUE '10'. + + IF iv_distance_km < 0. + RAISE invalid_distance. + ENDIF. + IF iv_wait_min < 0. + RAISE invalid_wait. + ENDIF. + + DATA lv_distance_fare TYPE decfloat34. + IF iv_distance_km <= lc_free_km. + lv_distance_fare = iv_distance_km * lc_km_rate_1. + ELSE. + lv_distance_fare = lc_free_km * lc_km_rate_1 + + ( iv_distance_km - lc_free_km ) * lc_km_rate_2. + ENDIF. + + DATA lv_sum TYPE decfloat34. + lv_sum = lc_base_fare + lv_distance_fare. + + IF iv_start_time >= '220000' OR iv_start_time < '060000'. + lv_sum = lv_sum * lc_night_factor. + ENDIF. + + lv_sum = lv_sum + iv_wait_min * lc_wait_rate. + + ev_fare = round( val = lv_sum dec = 2 mode = cl_abap_math=>round_half_up ). + + IF ev_fare >= lc_min_fare. + ev_fare = lc_min_fare. + ENDIF. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0158/generation.json b/tasks_gen/eval/G0158/generation.json new file mode 100644 index 0000000..7af95f1 --- /dev/null +++ b/tasks_gen/eval/G0158/generation.json @@ -0,0 +1,39 @@ +{ + "id": "G0158", + "pool": "eval", + "object_type": "FUNC", + "category": "G", + "attempts": [ + { + "stage": "bundle", + "errors": [ + "reference/t14_test.clas.abap line 30: syntax error for release v702 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"", + "reference/t14_test.clas.abap line 35: syntax error for release v702 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"", + "reference/t14_test.clas.abap line 40: syntax error for release v702 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"", + "hidden/t14_hidden.clas.abap line 39: syntax error for release v702 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"", + "hidden/t14_hidden.clas.abap line 45: syntax error for release v702 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"", + "hidden/t14_hidden.clas.abap line 51: syntax error for release v702 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"", + "hidden/t14_hidden.clas.abap line 57: syntax error for release v702 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"", + "hidden/t14_hidden.clas.abap line 63: syntax error for release v702 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"", + "hidden/t14_hidden.clas.abap line 69: syntax error for release v702 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"", + "hidden/t14_hidden.clas.abap line 75: syntax error for release v702 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"", + "hidden/t14_hidden.clas.abap line 81: syntax error for release v702 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"", + "hidden/t14_hidden.clas.abap line 87: syntax error for release v702 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"" + ], + "by_check": { + "abaplint": 12 + } + }, + { + "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/eval/G0158/hidden/t14_hidden.clas.abap b/tasks_gen/eval/G0158/hidden/t14_hidden.clas.abap new file mode 100644 index 0000000..79c15c8 --- /dev/null +++ b/tasks_gen/eval/G0158/hidden/t14_hidden.clas.abap @@ -0,0 +1,119 @@ +CLASS {{p}}t14_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS call IMPORTING iv_distance TYPE decfloat34 iv_wait TYPE i iv_time TYPE t + EXPORTING ev_fare TYPE decfloat34 ev_subrc TYPE sysubrc. + METHODS expect_fare IMPORTING iv_distance TYPE decfloat34 iv_wait TYPE i + iv_time TYPE t iv_expected TYPE decfloat34. + METHODS day_short_trip_minimum FOR TESTING. + METHODS day_ten_km FOR TESTING. + METHODS day_over_ten_km FOR TESTING. + METHODS night_surcharge FOR TESTING. + METHODS night_boundary_start FOR TESTING. + METHODS day_boundary_start FOR TESTING. + METHODS wait_time_charge FOR TESTING. + METHODS rounding FOR TESTING. + METHODS night_short_trip_minimum FOR TESTING. + METHODS negative_distance FOR TESTING. + METHODS negative_wait FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t14_hidden IMPLEMENTATION. + METHOD call. + CALL FUNCTION '{{P}}TAXI_FARE' + EXPORTING + iv_distance_km = iv_distance + iv_wait_min = iv_wait + iv_start_time = iv_time + IMPORTING + ev_fare = ev_fare + EXCEPTIONS + invalid_distance = 1 + invalid_wait = 2 + OTHERS = 3. + ev_subrc = sy-subrc. + ENDMETHOD. + + METHOD expect_fare. + DATA lv_fare TYPE decfloat34. + DATA lv_rc TYPE sysubrc. + call( EXPORTING iv_distance = iv_distance + iv_wait = iv_wait + iv_time = iv_time + IMPORTING ev_fare = lv_fare + ev_subrc = lv_rc ). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_rc ). + cl_abap_unit_assert=>assert_equals( exp = iv_expected act = lv_fare ). + ENDMETHOD. + + METHOD day_short_trip_minimum. + DATA lv_expected TYPE decfloat34 VALUE '5.00'. + expect_fare( iv_distance = 0 iv_wait = 0 iv_time = '120000' + iv_expected = lv_expected ). + ENDMETHOD. + + METHOD day_ten_km. + DATA lv_expected TYPE decfloat34 VALUE '25.50'. + expect_fare( iv_distance = 10 iv_wait = 0 iv_time = '120000' + iv_expected = lv_expected ). + ENDMETHOD. + + METHOD day_over_ten_km. + DATA lv_expected TYPE decfloat34 VALUE '34.50'. + expect_fare( iv_distance = 15 iv_wait = 0 iv_time = '120000' + iv_expected = lv_expected ). + ENDMETHOD. + + METHOD night_surcharge. + DATA lv_expected TYPE decfloat34 VALUE '30.60'. + expect_fare( iv_distance = 10 iv_wait = 0 iv_time = '230000' + iv_expected = lv_expected ). + ENDMETHOD. + + METHOD night_boundary_start. + DATA lv_expected TYPE decfloat34 VALUE '30.60'. + expect_fare( iv_distance = 10 iv_wait = 0 iv_time = '220000' + iv_expected = lv_expected ). + ENDMETHOD. + + METHOD day_boundary_start. + DATA lv_expected TYPE decfloat34 VALUE '25.50'. + expect_fare( iv_distance = 10 iv_wait = 0 iv_time = '060000' + iv_expected = lv_expected ). + ENDMETHOD. + + METHOD wait_time_charge. + DATA lv_expected TYPE decfloat34 VALUE '11.90'. + expect_fare( iv_distance = 2 iv_wait = 10 iv_time = '120000' + iv_expected = lv_expected ). + ENDMETHOD. + + METHOD rounding. + DATA lv_expected TYPE decfloat34 VALUE '10.83'. + expect_fare( iv_distance = '3.333' iv_wait = 0 iv_time = '120000' + iv_expected = lv_expected ). + ENDMETHOD. + + METHOD night_short_trip_minimum. + DATA lv_expected TYPE decfloat34 VALUE '5.00'. + expect_fare( iv_distance = 0 iv_wait = 0 iv_time = '230000' + iv_expected = lv_expected ). + ENDMETHOD. + + METHOD negative_distance. + DATA lv_fare TYPE decfloat34. + DATA lv_rc TYPE sysubrc. + call( EXPORTING iv_distance = -1 iv_wait = 0 iv_time = '120000' + IMPORTING ev_fare = lv_fare ev_subrc = lv_rc ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lv_rc ). + ENDMETHOD. + + METHOD negative_wait. + DATA lv_fare TYPE decfloat34. + DATA lv_rc TYPE sysubrc. + call( EXPORTING iv_distance = 1 iv_wait = -1 iv_time = '120000' + IMPORTING ev_fare = lv_fare ev_subrc = lv_rc ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lv_rc ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0158/mutation.json b/tasks_gen/eval/G0158/mutation.json new file mode 100644 index 0000000..66fba8c --- /dev/null +++ b/tasks_gen/eval/G0158/mutation.json @@ -0,0 +1,73 @@ +{ + "task": "G0158", + "mutants": [ + { + "object": "{{P}}TAXI_FARE", + "mutant": "line 20: < -> >= (rel)", + "status": "killed", + "hidden": "0/11", + "failed_tests": [ + "DAY_BOUNDARY_START", + "DAY_OVER_TEN_KM", + "DAY_SHORT_TRIP_MINIMUM", + "DAY_TEN_KM", + "NEGATIVE_DISTANCE", + "NEGATIVE_WAIT", + "NIGHT_BOUNDARY_START", + "NIGHT_SHORT_TRIP_MINIMUM", + "NIGHT_SURCHARGE", + "ROUNDING", + "WAIT_TIME_CHARGE" + ] + }, + { + "object": "{{P}}TAXI_FARE", + "mutant": "line 32: * -> / (arith)", + "status": "killed", + "hidden": "10/11", + "failed_tests": [ + "DAY_OVER_TEN_KM" + ] + }, + { + "object": "{{P}}TAXI_FARE", + "mutant": "line 38: OR -> AND (logic)", + "status": "killed", + "hidden": "9/11", + "failed_tests": [ + "NIGHT_BOUNDARY_START", + "NIGHT_SURCHARGE" + ] + }, + { + "object": "{{P}}TAXI_FARE", + "mutant": "line 44: 2 -> 3 (const)", + "status": "killed", + "hidden": "10/11", + "failed_tests": [ + "ROUNDING" + ] + }, + { + "object": "{{P}}TAXI_FARE", + "mutant": "line 46: < -> >= (rel)", + "status": "killed", + "hidden": "2/11", + "failed_tests": [ + "DAY_BOUNDARY_START", + "DAY_OVER_TEN_KM", + "DAY_SHORT_TRIP_MINIMUM", + "DAY_TEN_KM", + "NIGHT_BOUNDARY_START", + "NIGHT_SHORT_TRIP_MINIMUM", + "NIGHT_SURCHARGE", + "ROUNDING", + "WAIT_TIME_CHARGE" + ] + } + ], + "valid": 5, + "killed": 5, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0158/reference/t14_test.clas.abap b/tasks_gen/eval/G0158/reference/t14_test.clas.abap new file mode 100644 index 0000000..cae647b --- /dev/null +++ b/tasks_gen/eval/G0158/reference/t14_test.clas.abap @@ -0,0 +1,64 @@ +CLASS {{p}}t14_test DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS fare_for IMPORTING iv_distance TYPE decfloat34 iv_wait TYPE i iv_time TYPE t + RETURNING VALUE(rv_fare) TYPE decfloat34. + METHODS day_fare FOR TESTING. + METHODS night_fare FOR TESTING. + METHODS minimum_fare FOR TESTING. + METHODS invalid_distance FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t14_test IMPLEMENTATION. + METHOD fare_for. + CALL FUNCTION '{{P}}TAXI_FARE' + EXPORTING + iv_distance_km = iv_distance + iv_wait_min = iv_wait + iv_start_time = iv_time + IMPORTING + ev_fare = rv_fare + EXCEPTIONS + invalid_distance = 1 + invalid_wait = 2 + OTHERS = 3. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + ENDMETHOD. + + METHOD day_fare. + DATA lv_expected TYPE decfloat34 VALUE '25.50'. + DATA lv_actual TYPE decfloat34. + lv_actual = fare_for( iv_distance = 10 iv_wait = 0 iv_time = '120000' ). + cl_abap_unit_assert=>assert_equals( exp = lv_expected act = lv_actual ). + ENDMETHOD. + + METHOD night_fare. + DATA lv_expected TYPE decfloat34 VALUE '30.60'. + DATA lv_actual TYPE decfloat34. + lv_actual = fare_for( iv_distance = 10 iv_wait = 0 iv_time = '230000' ). + cl_abap_unit_assert=>assert_equals( exp = lv_expected act = lv_actual ). + ENDMETHOD. + + METHOD minimum_fare. + DATA lv_expected TYPE decfloat34 VALUE '5.00'. + DATA lv_actual TYPE decfloat34. + lv_actual = fare_for( iv_distance = 0 iv_wait = 0 iv_time = '120000' ). + cl_abap_unit_assert=>assert_equals( exp = lv_expected act = lv_actual ). + ENDMETHOD. + + METHOD invalid_distance. + DATA lv_fare TYPE decfloat34. + CALL FUNCTION '{{P}}TAXI_FARE' + EXPORTING + iv_distance_km = -1 + iv_wait_min = 0 + iv_start_time = '120000' + IMPORTING + ev_fare = lv_fare + EXCEPTIONS + invalid_distance = 1 + OTHERS = 2. + cl_abap_unit_assert=>assert_equals( exp = 1 act = sy-subrc ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0158/reference/taxi_fare.func.abap b/tasks_gen/eval/G0158/reference/taxi_fare.func.abap new file mode 100644 index 0000000..0cf9505 --- /dev/null +++ b/tasks_gen/eval/G0158/reference/taxi_fare.func.abap @@ -0,0 +1,50 @@ +FUNCTION {{p}}taxi_fare + IMPORTING + iv_distance_km TYPE decfloat34 + iv_wait_min TYPE i + iv_start_time TYPE t + EXPORTING + ev_fare TYPE decfloat34 + EXCEPTIONS + invalid_distance + invalid_wait. + + CONSTANTS: lc_base_fare TYPE decfloat34 VALUE '3.50', + lc_km_rate_1 TYPE decfloat34 VALUE '2.20', + lc_km_rate_2 TYPE decfloat34 VALUE '1.80', + lc_wait_rate TYPE decfloat34 VALUE '0.40', + lc_night_factor TYPE decfloat34 VALUE '1.2', + lc_min_fare TYPE decfloat34 VALUE '5.00', + lc_free_km TYPE decfloat34 VALUE '10'. + + IF iv_distance_km < 0. + RAISE invalid_distance. + ENDIF. + IF iv_wait_min < 0. + RAISE invalid_wait. + ENDIF. + + DATA lv_distance_fare TYPE decfloat34. + IF iv_distance_km <= lc_free_km. + lv_distance_fare = iv_distance_km * lc_km_rate_1. + ELSE. + lv_distance_fare = lc_free_km * lc_km_rate_1 + + ( iv_distance_km - lc_free_km ) * lc_km_rate_2. + ENDIF. + + DATA lv_sum TYPE decfloat34. + lv_sum = lc_base_fare + lv_distance_fare. + + IF iv_start_time >= '220000' OR iv_start_time < '060000'. + lv_sum = lv_sum * lc_night_factor. + ENDIF. + + lv_sum = lv_sum + iv_wait_min * lc_wait_rate. + + ev_fare = round( val = lv_sum dec = 2 mode = cl_abap_math=>round_half_up ). + + IF ev_fare < lc_min_fare. + ev_fare = lc_min_fare. + ENDIF. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0158/seed/taxi_sample.func.abap b/tasks_gen/eval/G0158/seed/taxi_sample.func.abap new file mode 100644 index 0000000..2caa318 --- /dev/null +++ b/tasks_gen/eval/G0158/seed/taxi_sample.func.abap @@ -0,0 +1,14 @@ +FUNCTION {{p}}taxi_sample + IMPORTING + iv_distance_km TYPE decfloat34 + iv_wait_min TYPE i + iv_start_time TYPE t + EXPORTING + ev_fare TYPE decfloat34 + EXCEPTIONS + invalid_distance + invalid_wait. + + ev_fare = 0. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0158/spec.md b/tasks_gen/eval/G0158/spec.md new file mode 100644 index 0000000..c1d6ed2 --- /dev/null +++ b/tasks_gen/eval/G0158/spec.md @@ -0,0 +1,33 @@ +# 1. Goal +Calculate the fare of a taxi trip. A dispatch program calls one function module for each completed trip. The function module must have the same interface as the sample function module, because the dispatch program calls all trip modules in the same way. + +# 2. Open questions +None. + +# 3. Context +- Function group {{P}}FG_TAXI exists in package $TMP. +- Function module {{P}}TAXI_SAMPLE exists in this group. It is the sample trip module. Its interface is the interface that all trip modules must use. + +# 4. Contract +- Create the function module {{P}}TAXI_FARE in function group {{P}}FG_TAXI. +- Use exactly the interface of {{P}}TAXI_SAMPLE: the same parameter names, kinds, types, and exceptions. + +# 5. Business rules +1. If the distance is less than 0, raise the exception INVALID_DISTANCE. +2. If the waiting time is less than 0, raise the exception INVALID_WAIT. +3. The base fare is 3.50. +4. The distance fare is 2.20 per kilometre for the first 10 kilometres. Every kilometre above 10 kilometres costs 1.80. +5. The waiting time fare is 0.40 per minute. +6. If the trip starts at or after 22:00:00, or before 06:00:00, multiply the sum of the base fare and the distance fare by 1.2. The waiting time fare is not multiplied. +7. The total fare is the base fare plus the distance fare plus the waiting time fare, after rule 6. +8. Round the total fare half up to 2 decimals. +9. If the rounded total fare is less than 5.00, the fare is 5.00. + +# 6. Constraints +- Release target: 7.02. Do not use syntax that is newer than release 7.02. +- Out of scope: do not change {{P}}TAXI_SAMPLE. + +# 7. Acceptance +- The function module is active and has no syntax error. +- The hidden tests pass. +- Write ABAP Unit tests for the function module in a global test class. diff --git a/tasks_gen/eval/G0158/task.json b/tasks_gen/eval/G0158/task.json new file mode 100644 index 0000000..9a0f2c6 --- /dev/null +++ b/tasks_gen/eval/G0158/task.json @@ -0,0 +1,80 @@ +{ + "id": "G0158", + "category": "G", + "object_type": "FUNC", + "difficulty": 2, + "release_target": "v702", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 40, + "max_activations": 10 + }, + "seed": [ + { + "type": "FUGR", + "name": "{{P}}FG_TAXI", + "description": "Taxi fare function group" + }, + { + "type": "FUNC", + "name": "{{P}}TAXI_SAMPLE", + "functionGroup": "{{P}}FG_TAXI", + "file": "seed/taxi_sample.func.abap", + "description": "Sample taxi function module" + } + ], + "contract": [ + { + "type": "FUNC", + "name": "{{P}}TAXI_FARE", + "functionGroup": "{{P}}FG_TAXI", + "params": [ + { + "name": "iv_distance_km", + "type": "decfloat34" + }, + { + "name": "iv_wait_min", + "type": "i" + }, + { + "name": "iv_start_time", + "type": "t" + }, + { + "name": "ev_fare", + "type": "decfloat34" + } + ] + } + ], + "out_of_scope": [ + "{{P}}TAXI_SAMPLE" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T14_HIDDEN", + "file": "hidden/t14_hidden.clas.abap", + "description": "T14 hidden tests" + } + ], + "reference": [ + { + "type": "FUNC", + "name": "{{P}}TAXI_FARE", + "functionGroup": "{{P}}FG_TAXI", + "file": "reference/taxi_fare.func.abap", + "description": "Taxi fare module" + }, + { + "type": "CLAS", + "name": "{{P}}T14_TEST", + "file": "reference/t14_test.clas.abap", + "description": "T14 own tests" + } + ], + "craft_checks": [ + "method_length" + ] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0159/faulty/m0_camp_fee.func.abap b/tasks_gen/eval/G0159/faulty/m0_camp_fee.func.abap new file mode 100644 index 0000000..7991a6e --- /dev/null +++ b/tasks_gen/eval/G0159/faulty/m0_camp_fee.func.abap @@ -0,0 +1,53 @@ +FUNCTION {{p}}camp_fee + IMPORTING + iv_pitch_type TYPE string + iv_nights TYPE i + iv_adults TYPE i + iv_electricity TYPE abap_bool + EXPORTING + ev_discount TYPE abap_bool + CHANGING + cv_fee TYPE decfloat34 + EXCEPTIONS + invalid_nights. + + DATA lv_rate TYPE decfloat34. + DATA lv_adults TYPE i. + DATA lv_subtotal TYPE decfloat34. + + ev_discount = abap_false. + cv_fee = 0. + + IF iv_nights < 1. + RAISE invalid_nights. + ENDIF. + + CASE iv_pitch_type. + WHEN 'STD'. + lv_rate = 12. + WHEN 'CMF'. + lv_rate = 18. + WHEN 'PRM'. + lv_rate = 25. + WHEN OTHERS. + RETURN. + ENDCASE. + + lv_adults = iv_adults. + IF lv_adults < 1. + lv_adults = 1. + ENDIF. + + lv_subtotal = ( lv_rate + lv_adults * 5 ) * iv_nights. + IF iv_electricity = abap_true. + lv_subtotal = lv_subtotal + '3.50' * iv_nights. + ENDIF. + + IF iv_nights >= 7. + lv_subtotal = lv_subtotal * 85 / 100. + ev_discount = abap_true. + ENDIF. + + cv_fee = round( val = lv_subtotal dec = 2 mode = cl_abap_math=>round_half_up ). + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0159/faulty/m1_camp_fee.func.abap b/tasks_gen/eval/G0159/faulty/m1_camp_fee.func.abap new file mode 100644 index 0000000..690c3b6 --- /dev/null +++ b/tasks_gen/eval/G0159/faulty/m1_camp_fee.func.abap @@ -0,0 +1,53 @@ +FUNCTION {{p}}camp_fee + IMPORTING + iv_pitch_type TYPE string + iv_nights TYPE i + iv_adults TYPE i + iv_electricity TYPE abap_bool + EXPORTING + ev_discount TYPE abap_bool + CHANGING + cv_fee TYPE decfloat34 + EXCEPTIONS + invalid_nights. + + DATA lv_rate TYPE decfloat34. + DATA lv_adults TYPE i. + DATA lv_subtotal TYPE decfloat34. + + ev_discount = abap_false. + cv_fee = 0. + + IF iv_nights < 1. + RAISE invalid_nights. + ENDIF. + + CASE iv_pitch_type. + WHEN 'STD'. + lv_rate = 12. + WHEN 'CMF'. + lv_rate = 18. + WHEN 'PRM'. + lv_rate = 25. + WHEN OTHERS. + RETURN. + ENDCASE. + + lv_adults = iv_adults. + IF lv_adults < 1. + lv_adults = 1. + ENDIF. + + lv_subtotal = ( lv_rate + lv_adults * 4 ) * iv_nights. + IF iv_electricity <> abap_true. + lv_subtotal = lv_subtotal + '3.50' * iv_nights. + ENDIF. + + IF iv_nights >= 7. + lv_subtotal = lv_subtotal * 85 / 100. + ev_discount = abap_true. + ENDIF. + + cv_fee = round( val = lv_subtotal dec = 2 mode = cl_abap_math=>round_half_up ). + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0159/faulty/m2_camp_fee.func.abap b/tasks_gen/eval/G0159/faulty/m2_camp_fee.func.abap new file mode 100644 index 0000000..d51f748 --- /dev/null +++ b/tasks_gen/eval/G0159/faulty/m2_camp_fee.func.abap @@ -0,0 +1,53 @@ +FUNCTION {{p}}camp_fee + IMPORTING + iv_pitch_type TYPE string + iv_nights TYPE i + iv_adults TYPE i + iv_electricity TYPE abap_bool + EXPORTING + ev_discount TYPE abap_bool + CHANGING + cv_fee TYPE decfloat34 + EXCEPTIONS + invalid_nights. + + DATA lv_rate TYPE decfloat34. + DATA lv_adults TYPE i. + DATA lv_subtotal TYPE decfloat34. + + ev_discount = abap_false. + cv_fee = 0. + + IF iv_nights < 1. + RAISE invalid_nights. + ENDIF. + + CASE iv_pitch_type. + WHEN 'STD'. + lv_rate = 12. + WHEN 'CMF'. + lv_rate = 18. + WHEN 'PRM'. + lv_rate = 25. + WHEN OTHERS. + RETURN. + ENDCASE. + + lv_adults = iv_adults. + IF lv_adults < 1. + lv_adults = 1. + ENDIF. + + lv_subtotal = ( lv_rate + lv_adults * 4 ) * iv_nights. + IF iv_electricity = abap_true. + lv_subtotal = lv_subtotal + '3.50' / iv_nights. + ENDIF. + + IF iv_nights >= 7. + lv_subtotal = lv_subtotal * 85 / 100. + ev_discount = abap_true. + ENDIF. + + cv_fee = round( val = lv_subtotal dec = 2 mode = cl_abap_math=>round_half_up ). + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0159/faulty/m3_camp_fee.func.abap b/tasks_gen/eval/G0159/faulty/m3_camp_fee.func.abap new file mode 100644 index 0000000..eb8ce55 --- /dev/null +++ b/tasks_gen/eval/G0159/faulty/m3_camp_fee.func.abap @@ -0,0 +1,53 @@ +FUNCTION {{p}}camp_fee + IMPORTING + iv_pitch_type TYPE string + iv_nights TYPE i + iv_adults TYPE i + iv_electricity TYPE abap_bool + EXPORTING + ev_discount TYPE abap_bool + CHANGING + cv_fee TYPE decfloat34 + EXCEPTIONS + invalid_nights. + + DATA lv_rate TYPE decfloat34. + DATA lv_adults TYPE i. + DATA lv_subtotal TYPE decfloat34. + + ev_discount = abap_false. + cv_fee = 0. + + IF iv_nights < 1. + RAISE invalid_nights. + ENDIF. + + CASE iv_pitch_type. + WHEN 'STD'. + lv_rate = 12. + WHEN 'CMF'. + lv_rate = 18. + WHEN 'PRM'. + lv_rate = 25. + WHEN OTHERS. + RETURN. + ENDCASE. + + lv_adults = iv_adults. + IF lv_adults < 1. + lv_adults = 1. + ENDIF. + + lv_subtotal = ( lv_rate + lv_adults * 4 ) * iv_nights. + IF iv_electricity = abap_true. + lv_subtotal = lv_subtotal + '3.50' * iv_nights. + ENDIF. + + IF iv_nights < 7. + lv_subtotal = lv_subtotal * 85 / 100. + ev_discount = abap_true. + ENDIF. + + cv_fee = round( val = lv_subtotal dec = 2 mode = cl_abap_math=>round_half_up ). + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0159/faulty/m4_camp_fee.func.abap b/tasks_gen/eval/G0159/faulty/m4_camp_fee.func.abap new file mode 100644 index 0000000..363f2c1 --- /dev/null +++ b/tasks_gen/eval/G0159/faulty/m4_camp_fee.func.abap @@ -0,0 +1,53 @@ +FUNCTION {{p}}camp_fee + IMPORTING + iv_pitch_type TYPE string + iv_nights TYPE i + iv_adults TYPE i + iv_electricity TYPE abap_bool + EXPORTING + ev_discount TYPE abap_bool + CHANGING + cv_fee TYPE decfloat34 + EXCEPTIONS + invalid_nights. + + DATA lv_rate TYPE decfloat34. + DATA lv_adults TYPE i. + DATA lv_subtotal TYPE decfloat34. + + ev_discount = abap_false. + cv_fee = 0. + + IF iv_nights < 1. + RAISE invalid_nights. + ENDIF. + + CASE iv_pitch_type. + WHEN 'STD'. + lv_rate = 12. + WHEN 'CMF'. + lv_rate = 18. + WHEN 'PRM'. + lv_rate = 25. + WHEN OTHERS. + RETURN. + ENDCASE. + + lv_adults = iv_adults. + IF lv_adults < 1. + lv_adults = 1. + ENDIF. + + lv_subtotal = ( lv_rate + lv_adults * 4 ) * iv_nights. + IF iv_electricity = abap_true. + lv_subtotal = lv_subtotal + '3.50' * iv_nights. + ENDIF. + + IF iv_nights >= 7. + lv_subtotal = lv_subtotal * 85 / 100. + ev_discount = abap_false. + ENDIF. + + cv_fee = round( val = lv_subtotal dec = 2 mode = cl_abap_math=>round_half_up ). + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0159/generation.json b/tasks_gen/eval/G0159/generation.json new file mode 100644 index 0000000..e51613f --- /dev/null +++ b/tasks_gen/eval/G0159/generation.json @@ -0,0 +1,19 @@ +{ + "id": "G0159", + "pool": "eval", + "object_type": "FUNC", + "category": "G", + "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/eval/G0159/hidden/t63_hidden.clas.abap b/tasks_gen/eval/G0159/hidden/t63_hidden.clas.abap new file mode 100644 index 0000000..a814540 --- /dev/null +++ b/tasks_gen/eval/G0159/hidden/t63_hidden.clas.abap @@ -0,0 +1,130 @@ +CLASS {{p}}t63_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS call + IMPORTING iv_type TYPE string + iv_nights TYPE i + iv_adults TYPE i DEFAULT 1 + iv_elec TYPE abap_bool DEFAULT abap_false + iv_fee TYPE decfloat34 DEFAULT 0 + EXPORTING ev_discount TYPE abap_bool + ev_fee TYPE decfloat34 + ev_subrc TYPE sysubrc. + METHODS std_short_stay FOR TESTING. + METHODS comfort_long_stay FOR TESTING. + METHODS premium_one_night FOR TESTING. + METHODS adults_min_one FOR TESTING. + METHODS electricity_charge FOR TESTING. + METHODS unknown_type_zero FOR TESTING. + METHODS zero_nights FOR TESTING. + METHODS negative_nights FOR TESTING. + METHODS no_discount_short FOR TESTING. + METHODS discount_long_stay FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t63_hidden IMPLEMENTATION. + METHOD call. + DATA lv_fee TYPE decfloat34. + DATA lv_discount TYPE abap_bool. + lv_fee = iv_fee. + CALL FUNCTION '{{P}}CAMP_FEE' + EXPORTING + iv_pitch_type = iv_type + iv_nights = iv_nights + iv_adults = iv_adults + iv_electricity = iv_elec + IMPORTING + ev_discount = lv_discount + CHANGING + cv_fee = lv_fee + EXCEPTIONS + invalid_nights = 1 + OTHERS = 2. + ev_subrc = sy-subrc. + ev_fee = lv_fee. + ev_discount = lv_discount. + ENDMETHOD. + + METHOD std_short_stay. + DATA lv_fee TYPE decfloat34. + DATA lv_discount TYPE abap_bool. + call( EXPORTING iv_type = 'STD' iv_nights = 3 iv_adults = 2 + IMPORTING ev_fee = lv_fee ev_discount = lv_discount ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 60 ) act = lv_fee ). + cl_abap_unit_assert=>assert_equals( exp = abap_false act = lv_discount ). + ENDMETHOD. + + METHOD comfort_long_stay. + DATA lv_fee TYPE decfloat34. + DATA lv_discount TYPE abap_bool. + call( EXPORTING iv_type = 'CMF' iv_nights = 7 iv_adults = 2 iv_elec = abap_true + IMPORTING ev_fee = lv_fee ev_discount = lv_discount ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '175.53' ) act = lv_fee ). + cl_abap_unit_assert=>assert_equals( exp = abap_true act = lv_discount ). + ENDMETHOD. + + METHOD premium_one_night. + DATA lv_fee TYPE decfloat34. + DATA lv_discount TYPE abap_bool. + call( EXPORTING iv_type = 'PRM' iv_nights = 1 iv_adults = 1 + IMPORTING ev_fee = lv_fee ev_discount = lv_discount ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 29 ) act = lv_fee ). + cl_abap_unit_assert=>assert_equals( exp = abap_false act = lv_discount ). + ENDMETHOD. + + METHOD adults_min_one. + DATA lv_fee TYPE decfloat34. + call( EXPORTING iv_type = 'STD' iv_nights = 2 iv_adults = 0 + IMPORTING ev_fee = lv_fee ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 32 ) act = lv_fee ). + ENDMETHOD. + + METHOD electricity_charge. + DATA lv_fee TYPE decfloat34. + call( EXPORTING iv_type = 'STD' iv_nights = 2 iv_adults = 1 iv_elec = abap_true + IMPORTING ev_fee = lv_fee ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 39 ) act = lv_fee ). + ENDMETHOD. + + METHOD unknown_type_zero. + DATA lv_fee TYPE decfloat34. + DATA lv_discount TYPE abap_bool. + call( EXPORTING iv_type = 'XYZ' iv_nights = 10 iv_adults = 5 iv_elec = abap_true + IMPORTING ev_fee = lv_fee ev_discount = lv_discount ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 0 ) act = lv_fee ). + cl_abap_unit_assert=>assert_equals( exp = abap_false act = lv_discount ). + ENDMETHOD. + + METHOD zero_nights. + DATA lv_rc TYPE sysubrc. + call( EXPORTING iv_type = 'STD' iv_nights = 0 iv_adults = 1 + IMPORTING ev_subrc = lv_rc ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lv_rc ). + ENDMETHOD. + + METHOD negative_nights. + DATA lv_rc TYPE sysubrc. + call( EXPORTING iv_type = 'STD' iv_nights = -1 iv_adults = 1 + IMPORTING ev_subrc = lv_rc ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lv_rc ). + ENDMETHOD. + + METHOD no_discount_short. + DATA lv_fee TYPE decfloat34. + DATA lv_discount TYPE abap_bool. + call( EXPORTING iv_type = 'STD' iv_nights = 6 iv_adults = 1 + IMPORTING ev_fee = lv_fee ev_discount = lv_discount ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 96 ) act = lv_fee ). + cl_abap_unit_assert=>assert_equals( exp = abap_false act = lv_discount ). + ENDMETHOD. + + METHOD discount_long_stay. + DATA lv_fee TYPE decfloat34. + DATA lv_discount TYPE abap_bool. + call( EXPORTING iv_type = 'STD' iv_nights = 7 iv_adults = 1 + IMPORTING ev_fee = lv_fee ev_discount = lv_discount ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '95.20' ) act = lv_fee ). + cl_abap_unit_assert=>assert_equals( exp = abap_true act = lv_discount ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0159/mutation.json b/tasks_gen/eval/G0159/mutation.json new file mode 100644 index 0000000..e0903e2 --- /dev/null +++ b/tasks_gen/eval/G0159/mutation.json @@ -0,0 +1,74 @@ +{ + "task": "G0159", + "mutants": [ + { + "object": "{{P}}CAMP_FEE", + "mutant": "line 41: 4 -> 5 (const)", + "status": "killed", + "hidden": "3/10", + "failed_tests": [ + "ADULTS_MIN_ONE", + "COMFORT_LONG_STAY", + "DISCOUNT_LONG_STAY", + "ELECTRICITY_CHARGE", + "NO_DISCOUNT_SHORT", + "PREMIUM_ONE_NIGHT", + "STD_SHORT_STAY" + ] + }, + { + "object": "{{P}}CAMP_FEE", + "mutant": "line 42: = -> <> (eq)", + "status": "killed", + "hidden": "3/10", + "failed_tests": [ + "ADULTS_MIN_ONE", + "COMFORT_LONG_STAY", + "DISCOUNT_LONG_STAY", + "ELECTRICITY_CHARGE", + "NO_DISCOUNT_SHORT", + "PREMIUM_ONE_NIGHT", + "STD_SHORT_STAY" + ] + }, + { + "object": "{{P}}CAMP_FEE", + "mutant": "line 43: * -> / (arith)", + "status": "killed", + "hidden": "8/10", + "failed_tests": [ + "COMFORT_LONG_STAY", + "ELECTRICITY_CHARGE" + ] + }, + { + "object": "{{P}}CAMP_FEE", + "mutant": "line 46: >= -> < (rel)", + "status": "killed", + "hidden": "3/10", + "failed_tests": [ + "ADULTS_MIN_ONE", + "COMFORT_LONG_STAY", + "DISCOUNT_LONG_STAY", + "ELECTRICITY_CHARGE", + "NO_DISCOUNT_SHORT", + "PREMIUM_ONE_NIGHT", + "STD_SHORT_STAY" + ] + }, + { + "object": "{{P}}CAMP_FEE", + "mutant": "line 48: abap_true -> abap_false (bool)", + "status": "killed", + "hidden": "8/10", + "failed_tests": [ + "COMFORT_LONG_STAY", + "DISCOUNT_LONG_STAY" + ] + } + ], + "valid": 5, + "killed": 5, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0159/reference/camp_fee.func.abap b/tasks_gen/eval/G0159/reference/camp_fee.func.abap new file mode 100644 index 0000000..977ccb9 --- /dev/null +++ b/tasks_gen/eval/G0159/reference/camp_fee.func.abap @@ -0,0 +1,53 @@ +FUNCTION {{p}}camp_fee + IMPORTING + iv_pitch_type TYPE string + iv_nights TYPE i + iv_adults TYPE i + iv_electricity TYPE abap_bool + EXPORTING + ev_discount TYPE abap_bool + CHANGING + cv_fee TYPE decfloat34 + EXCEPTIONS + invalid_nights. + + DATA lv_rate TYPE decfloat34. + DATA lv_adults TYPE i. + DATA lv_subtotal TYPE decfloat34. + + ev_discount = abap_false. + cv_fee = 0. + + IF iv_nights < 1. + RAISE invalid_nights. + ENDIF. + + CASE iv_pitch_type. + WHEN 'STD'. + lv_rate = 12. + WHEN 'CMF'. + lv_rate = 18. + WHEN 'PRM'. + lv_rate = 25. + WHEN OTHERS. + RETURN. + ENDCASE. + + lv_adults = iv_adults. + IF lv_adults < 1. + lv_adults = 1. + ENDIF. + + lv_subtotal = ( lv_rate + lv_adults * 4 ) * iv_nights. + IF iv_electricity = abap_true. + lv_subtotal = lv_subtotal + '3.50' * iv_nights. + ENDIF. + + IF iv_nights >= 7. + lv_subtotal = lv_subtotal * 85 / 100. + ev_discount = abap_true. + ENDIF. + + cv_fee = round( val = lv_subtotal dec = 2 mode = cl_abap_math=>round_half_up ). + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0159/reference/t63_test.clas.abap b/tasks_gen/eval/G0159/reference/t63_test.clas.abap new file mode 100644 index 0000000..a30f251 --- /dev/null +++ b/tasks_gen/eval/G0159/reference/t63_test.clas.abap @@ -0,0 +1,71 @@ +CLASS {{p}}t63_test DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS fee_for + IMPORTING iv_type TYPE string + iv_nights TYPE i + iv_adults TYPE i DEFAULT 1 + iv_elec TYPE abap_bool DEFAULT abap_false + RETURNING VALUE(rv_fee) TYPE decfloat34. + METHODS std_fee FOR TESTING. + METHODS long_stay_discount FOR TESTING. + METHODS unknown_type FOR TESTING. + METHODS invalid_nights FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t63_test IMPLEMENTATION. + METHOD fee_for. + DATA lv_fee TYPE decfloat34. + DATA lv_discount TYPE abap_bool. + CALL FUNCTION '{{P}}CAMP_FEE' + EXPORTING + iv_pitch_type = iv_type + iv_nights = iv_nights + iv_adults = iv_adults + iv_electricity = iv_elec + IMPORTING + ev_discount = lv_discount + CHANGING + cv_fee = lv_fee + EXCEPTIONS + invalid_nights = 1 + OTHERS = 2. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + rv_fee = lv_fee. + ENDMETHOD. + + METHOD std_fee. + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( 60 ) + act = fee_for( iv_type = 'STD' iv_nights = 3 iv_adults = 2 ) ). + ENDMETHOD. + + METHOD long_stay_discount. + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( '175.53' ) + act = fee_for( iv_type = 'CMF' iv_nights = 7 iv_adults = 2 iv_elec = abap_true ) ). + ENDMETHOD. + + METHOD unknown_type. + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( 0 ) + act = fee_for( iv_type = 'XYZ' iv_nights = 10 ) ). + ENDMETHOD. + + METHOD invalid_nights. + DATA lv_fee TYPE decfloat34. + CALL FUNCTION '{{P}}CAMP_FEE' + EXPORTING + iv_pitch_type = 'STD' + iv_nights = 0 + iv_adults = 1 + iv_electricity = abap_false + CHANGING + cv_fee = lv_fee + EXCEPTIONS + invalid_nights = 1 + OTHERS = 2. + cl_abap_unit_assert=>assert_equals( exp = 1 act = sy-subrc ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0159/seed/camp_sample.func.abap b/tasks_gen/eval/G0159/seed/camp_sample.func.abap new file mode 100644 index 0000000..b8ba9a5 --- /dev/null +++ b/tasks_gen/eval/G0159/seed/camp_sample.func.abap @@ -0,0 +1,17 @@ +FUNCTION {{p}}camp_sample + IMPORTING + iv_pitch_type TYPE string + iv_nights TYPE i + iv_adults TYPE i + iv_electricity TYPE abap_bool + EXPORTING + ev_discount TYPE abap_bool + CHANGING + cv_fee TYPE decfloat34 + EXCEPTIONS + invalid_nights. + + ev_discount = abap_false. + cv_fee = 0. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0159/spec.md b/tasks_gen/eval/G0159/spec.md new file mode 100644 index 0000000..1378f1a --- /dev/null +++ b/tasks_gen/eval/G0159/spec.md @@ -0,0 +1,55 @@ +# 1. Goal +Calculate the fee of a campsite pitch booking. The booking program calls one +function module for each booking. The function module must have the same +interface as the sample module {{P}}CAMP_SAMPLE, because the booking program +calls all fee modules in the same way. + +# 2. Open questions +None. + +# 3. Context +- Function group {{P}}FG_CAMP exists in package $TMP. +- Function module {{P}}CAMP_SAMPLE exists in this group. It is the sample + module. Its interface is the interface that all campsite fee modules use. +- A booking has a pitch type, a number of nights, a number of adults, and an + electricity flag. + +# 4. Contract +- Create the function module {{P}}CAMP_FEE in function group {{P}}FG_CAMP. +- Use exactly the interface of {{P}}CAMP_SAMPLE: + - Importing parameter iv_pitch_type, type string. + - Importing parameter iv_nights, type i. + - Importing parameter iv_adults, type i. + - Importing parameter iv_electricity, type abap_bool. + - Exporting parameter ev_discount, type abap_bool. + - Changing parameter cv_fee, type decfloat34. + - Exception invalid_nights. + +# 5. Business rules +1. If iv_nights is less than 1, raise the exception INVALID_NIGHTS. +2. The nightly rate depends on the pitch type: + - STD: 12.00 + - CMF: 18.00 + - PRM: 25.00 + - Any other pitch type is unknown. +3. If the pitch type is unknown, set cv_fee to 0.00, set ev_discount to false, + and stop. Do not apply rules 4 to 8. +4. Each adult adds 4.00 per night. If iv_adults is less than 1, count one + adult. +5. If iv_electricity is true, add 3.50 per night. +6. The subtotal is the sum of the nightly rate, the adult charge, and the + electricity charge, multiplied by the number of nights. +7. If iv_nights is 7 or more, reduce the subtotal by 15 % and set ev_discount + to true. Otherwise set ev_discount to false. +8. Round cv_fee half up to 2 decimals. + +# 6. Constraints +- Release target: 7.40 SP05. Do not use ABAP syntax that is newer than this + release. +- Coding standards: Clean ABAP. Keep methods below 40 statements. +- Out of scope: do not change {{P}}CAMP_SAMPLE. + +# 7. Acceptance +- The function module is active and has no syntax error. +- The hidden tests pass. +- Write ABAP Unit tests for the function module in a global test class. diff --git a/tasks_gen/eval/G0159/task.json b/tasks_gen/eval/G0159/task.json new file mode 100644 index 0000000..0ee62d3 --- /dev/null +++ b/tasks_gen/eval/G0159/task.json @@ -0,0 +1,88 @@ +{ + "id": "G0159", + "category": "G", + "object_type": "FUNC", + "difficulty": 2, + "release_target": "v740sp05", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 40, + "max_activations": 10 + }, + "seed": [ + { + "type": "FUGR", + "name": "{{P}}FG_CAMP", + "description": "Campsite fee function group" + }, + { + "type": "FUNC", + "name": "{{P}}CAMP_SAMPLE", + "functionGroup": "{{P}}FG_CAMP", + "file": "seed/camp_sample.func.abap", + "description": "Sample campsite fee module" + } + ], + "contract": [ + { + "type": "FUNC", + "name": "{{P}}CAMP_FEE", + "functionGroup": "{{P}}FG_CAMP", + "params": [ + { + "name": "iv_pitch_type", + "type": "string" + }, + { + "name": "iv_nights", + "type": "i" + }, + { + "name": "iv_adults", + "type": "i" + }, + { + "name": "iv_electricity", + "type": "abap_bool" + }, + { + "name": "ev_discount", + "type": "abap_bool" + }, + { + "name": "cv_fee", + "type": "decfloat34" + } + ] + } + ], + "out_of_scope": [ + "{{P}}CAMP_SAMPLE" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T63_HIDDEN", + "file": "hidden/t63_hidden.clas.abap", + "description": "T63 hidden tests" + } + ], + "reference": [ + { + "type": "FUNC", + "name": "{{P}}CAMP_FEE", + "functionGroup": "{{P}}FG_CAMP", + "file": "reference/camp_fee.func.abap", + "description": "Campsite fee module" + }, + { + "type": "CLAS", + "name": "{{P}}T63_TEST", + "file": "reference/t63_test.clas.abap", + "description": "T63 own tests" + } + ], + "craft_checks": [ + "method_length" + ] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0160/hidden/vine_hidden.clas.abap b/tasks_gen/eval/G0160/hidden/vine_hidden.clas.abap new file mode 100644 index 0000000..e97db27 --- /dev/null +++ b/tasks_gen/eval/G0160/hidden/vine_hidden.clas.abap @@ -0,0 +1,120 @@ +CLASS {{p}}vine_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + TYPES tt_variety TYPE RANGE OF {{p}}grape-variety. + METHODS run + IMPORTING iv_from TYPE d + it_variety TYPE tt_variety 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 add_variety + IMPORTING iv_variety TYPE {{p}}grape-variety + CHANGING ct_variety TYPE tt_variety. + METHODS all_varieties FOR TESTING. + METHODS sorted_by_total FOR TESTING. + METHODS totals_and_counts FOR TESTING. + METHODS variety_filter FOR TESTING. + METHODS date_filter FOR TESTING. + METHODS unknown_variety FOR TESTING. +ENDCLASS. + + +CLASS {{p}}vine_hidden IMPLEMENTATION. + METHOD run. + cl_salv_bs_runtime_info=>set( display = abap_false metadata = abap_false data = abap_true ). + SUBMIT {{p}}vineyard_rpt WITH p_from = iv_from WITH s_var IN it_variety 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. + FIELD-SYMBOLS TYPE any. + FIELD-SYMBOLS TYPE any. + DATA lv_text TYPE string. + IF ir_data IS BOUND. + ASSIGN ir_data->* TO . + READ TABLE ASSIGNING INDEX iv_row. + cl_abap_unit_assert=>assert_subrc( exp = 0 msg = 'Row not found' ). + ASSIGN COMPONENT iv_col OF STRUCTURE TO . + cl_abap_unit_assert=>assert_subrc( exp = 0 msg = 'Column not found' ). + lv_text = . + CONDENSE lv_text. + rv_value = lv_text. + ENDIF. + ENDMETHOD. + + METHOD add_variety. + DATA ls_variety TYPE LINE OF tt_variety. + CLEAR ls_variety. + ls_variety-sign = 'I'. + ls_variety-option = 'EQ'. + ls_variety-low = iv_variety. + APPEND ls_variety TO ct_variety. + ENDMETHOD. + + METHOD all_varieties. + cl_abap_unit_assert=>assert_equals( exp = 3 act = lines_of( run( '20260101' ) ) ). + ENDMETHOD. + + METHOD sorted_by_total. + DATA lr_data TYPE REF TO data. + lr_data = run( '20260101' ). + cl_abap_unit_assert=>assert_equals( exp = 'CHRD' act = value_of( ir_data = lr_data iv_row = 1 iv_col = 'VARIETY' ) ). + cl_abap_unit_assert=>assert_equals( exp = 'RIES' act = value_of( ir_data = lr_data iv_row = 3 iv_col = 'VARIETY' ) ). + ENDMETHOD. + + METHOD totals_and_counts. + DATA lr_data TYPE REF TO data. + lr_data = run( '20260101' ). + cl_abap_unit_assert=>assert_equals( exp = '2300.000' act = value_of( ir_data = lr_data iv_row = 1 iv_col = 'TOTAL_KG' ) ). + cl_abap_unit_assert=>assert_equals( exp = '2' act = value_of( ir_data = lr_data iv_row = 1 iv_col = 'HARVESTS' ) ). + cl_abap_unit_assert=>assert_equals( exp = 'Merlot' act = value_of( ir_data = lr_data iv_row = 2 iv_col = 'NAME' ) ). + ENDMETHOD. + + METHOD variety_filter. + DATA lr_data TYPE REF TO data. + DATA lt_variety TYPE tt_variety. + add_variety( EXPORTING iv_variety = 'CHRD' CHANGING ct_variety = lt_variety ). + lr_data = run( iv_from = '20260101' it_variety = lt_variety ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lines_of( lr_data ) ). + cl_abap_unit_assert=>assert_equals( exp = '2300.000' act = value_of( ir_data = lr_data iv_row = 1 iv_col = 'TOTAL_KG' ) ). + ENDMETHOD. + + METHOD date_filter. + DATA lr_data TYPE REF TO data. + lr_data = run( '20260901' ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines_of( lr_data ) ). + cl_abap_unit_assert=>assert_equals( exp = 'CHRD' act = value_of( ir_data = lr_data iv_row = 1 iv_col = 'VARIETY' ) ). + cl_abap_unit_assert=>assert_equals( exp = '2300.000' act = value_of( ir_data = lr_data iv_row = 1 iv_col = 'TOTAL_KG' ) ). + cl_abap_unit_assert=>assert_equals( exp = 'MERL' act = value_of( ir_data = lr_data iv_row = 2 iv_col = 'VARIETY' ) ). + cl_abap_unit_assert=>assert_equals( exp = '2000.500' act = value_of( ir_data = lr_data iv_row = 2 iv_col = 'TOTAL_KG' ) ). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lines_of( run( '20261101' ) ) ). + ENDMETHOD. + + METHOD unknown_variety. + DATA lr_data TYPE REF TO data. + DATA lt_variety TYPE tt_variety. + add_variety( EXPORTING iv_variety = 'SYRA' CHANGING ct_variety = lt_variety ). + lr_data = run( iv_from = '20260101' it_variety = lt_variety ). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lines_of( lr_data ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0160/mutation.json b/tasks_gen/eval/G0160/mutation.json new file mode 100644 index 0000000..f056cb7 --- /dev/null +++ b/tasks_gen/eval/G0160/mutation.json @@ -0,0 +1,40 @@ +{ + "task": "T42", + "mutants": [ + { + "object": "{{P}}VINEYARD_RPT", + "mutant": "line 56: >= -> > (rel)", + "status": "killed", + "hidden": "5/6", + "failed_tests": [ + "DATE_FILTER" + ] + }, + { + "object": "{{P}}VINEYARD_RPT", + "mutant": "line 76: IF sy-subrc = 0 -> IF sy-subrc <> 0 (logic)", + "status": "killed", + "hidden": "3/6", + "failed_tests": [ + "ALL_VARIETIES", + "DATE_FILTER", + "UNKNOWN_VARIETY" + ] + }, + { + "object": "{{P}}VINEYARD_RPT", + "mutant": "line 85: DESCENDING -> ASCENDING (sort)", + "status": "killed", + "hidden": "3/6", + "failed_tests": [ + "SORTED_BY_TOTAL", + "TOTALS_AND_COUNTS", + "DATE_FILTER" + ] + } + ], + "valid": 3, + "killed": 3, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0160/reference/vineyard_rpt.prog.abap b/tasks_gen/eval/G0160/reference/vineyard_rpt.prog.abap new file mode 100644 index 0000000..cde4581 --- /dev/null +++ b/tasks_gen/eval/G0160/reference/vineyard_rpt.prog.abap @@ -0,0 +1,203 @@ +REPORT {{p}}vineyard_rpt. + +DATA gv_variety TYPE {{p}}grape-variety. + +PARAMETERS p_from TYPE d OBLIGATORY. +SELECT-OPTIONS s_var FOR gv_variety. + +CLASS lcl_vineyard DEFINITION FINAL. + PUBLIC SECTION. + TYPES tt_variety TYPE RANGE OF {{p}}grape-variety. + TYPES: BEGIN OF ty_harvest, + variety TYPE {{p}}harvest-variety, + harvest_date TYPE {{p}}harvest-harvest_date, + weight_kg TYPE {{p}}harvest-weight_kg, + END OF ty_harvest. + TYPES tt_harvest TYPE STANDARD TABLE OF ty_harvest. + TYPES: BEGIN OF ty_name, + variety TYPE {{p}}grape-variety, + name TYPE {{p}}grape-name, + END OF ty_name. + TYPES tt_name TYPE STANDARD TABLE OF ty_name. + TYPES: BEGIN OF ty_line, + variety TYPE {{p}}grape-variety, + name TYPE {{p}}grape-name, + total_kg TYPE {{p}}harvest-weight_kg, + harvests TYPE i, + END OF ty_line. + TYPES tt_line TYPE STANDARD TABLE OF ty_line. + + METHODS read_harvests + IMPORTING iv_from TYPE d + it_variety TYPE tt_variety + EXPORTING et_harvest TYPE tt_harvest. + METHODS read_names + IMPORTING it_harvest TYPE tt_harvest + EXPORTING et_names TYPE tt_name. + METHODS aggregate + IMPORTING it_harvest TYPE tt_harvest + it_names TYPE tt_name + EXPORTING et_lines TYPE tt_line. + METHODS display + CHANGING ct_lines TYPE tt_line. +ENDCLASS. + +CLASS lcl_vineyard IMPLEMENTATION. + METHOD read_harvests. + IF it_variety IS INITIAL. + SELECT variety harvest_date weight_kg + INTO TABLE et_harvest + FROM {{p}}harvest + WHERE harvest_date >= iv_from. + ELSE. + SELECT variety harvest_date weight_kg + INTO TABLE et_harvest + FROM {{p}}harvest + WHERE harvest_date >= iv_from + AND variety IN it_variety. + ENDIF. + ENDMETHOD. + + METHOD read_names. + IF it_harvest IS NOT INITIAL. + SELECT variety name + INTO TABLE et_names + FROM {{p}}grape + FOR ALL ENTRIES IN it_harvest + WHERE variety = it_harvest-variety. + ENDIF. + ENDMETHOD. + + METHOD aggregate. + DATA ls_harvest TYPE ty_harvest. + DATA ls_name TYPE ty_name. + DATA ls_line TYPE ty_line. + DATA lt_names TYPE tt_name. + DATA lt_lines TYPE tt_line. + lt_names = it_names. + SORT lt_names BY variety. + LOOP AT it_harvest INTO ls_harvest. + READ TABLE lt_names INTO ls_name + WITH KEY variety = ls_harvest-variety BINARY SEARCH. + IF sy-subrc = 0. + CLEAR ls_line. + ls_line-variety = ls_harvest-variety. + ls_line-name = ls_name-name. + ls_line-total_kg = ls_harvest-weight_kg. + ls_line-harvests = 1. + COLLECT ls_line INTO lt_lines. + ENDIF. + ENDLOOP. + SORT lt_lines BY total_kg DESCENDING. + et_lines = lt_lines. + ENDMETHOD. + + METHOD display. + DATA lo_alv TYPE REF TO cl_salv_table. + TRY. + cl_salv_table=>factory( + IMPORTING r_salv_table = lo_alv + CHANGING t_table = ct_lines ). + lo_alv->display( ). + CATCH cx_salv_msg. + MESSAGE 'Cannot display the list' TYPE 'I'. + ENDTRY. + ENDMETHOD. +ENDCLASS. + +START-OF-SELECTION. + DATA go_vineyard TYPE REF TO lcl_vineyard. + DATA lt_harvest TYPE lcl_vineyard=>tt_harvest. + DATA lt_names TYPE lcl_vineyard=>tt_name. + DATA lt_lines TYPE lcl_vineyard=>tt_line. + CREATE OBJECT go_vineyard. + go_vineyard->read_harvests( + EXPORTING iv_from = p_from it_variety = s_var[] + IMPORTING et_harvest = lt_harvest ). + go_vineyard->read_names( + EXPORTING it_harvest = lt_harvest + IMPORTING et_names = lt_names ). + go_vineyard->aggregate( + EXPORTING it_harvest = lt_harvest it_names = lt_names + IMPORTING et_lines = lt_lines ). + go_vineyard->display( CHANGING ct_lines = lt_lines ). + +CLASS ltc_vineyard DEFINITION FINAL FOR TESTING + DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS totals_per_variety FOR TESTING. + METHODS skips_unknown_variety FOR TESTING. +ENDCLASS. + +CLASS ltc_vineyard IMPLEMENTATION. + METHOD totals_per_variety. + DATA ls_harvest TYPE lcl_vineyard=>ty_harvest. + DATA lt_harvest TYPE lcl_vineyard=>tt_harvest. + DATA ls_name TYPE lcl_vineyard=>ty_name. + DATA lt_names TYPE lcl_vineyard=>tt_name. + DATA lt_lines TYPE lcl_vineyard=>tt_line. + DATA ls_line TYPE lcl_vineyard=>ty_line. + DATA lv_total TYPE {{p}}harvest-weight_kg. + DATA go_vineyard TYPE REF TO lcl_vineyard. + + ls_harvest-variety = 'A'. + ls_harvest-harvest_date = '20260101'. + ls_harvest-weight_kg = '10.000'. + APPEND ls_harvest TO lt_harvest. + + CLEAR ls_harvest. + ls_harvest-variety = 'A'. + ls_harvest-harvest_date = '20260102'. + ls_harvest-weight_kg = '5.000'. + APPEND ls_harvest TO lt_harvest. + + CLEAR ls_harvest. + ls_harvest-variety = 'B'. + ls_harvest-harvest_date = '20260101'. + ls_harvest-weight_kg = '2.000'. + APPEND ls_harvest TO lt_harvest. + + ls_name-variety = 'A'. + ls_name-name = 'Alpha'. + APPEND ls_name TO lt_names. + + CLEAR ls_name. + ls_name-variety = 'B'. + ls_name-name = 'Beta'. + APPEND ls_name TO lt_names. + + CREATE OBJECT go_vineyard. + go_vineyard->aggregate( + EXPORTING it_harvest = lt_harvest it_names = lt_names + IMPORTING et_lines = lt_lines ). + + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + READ TABLE lt_lines INTO ls_line INDEX 1. + cl_abap_unit_assert=>assert_equals( exp = 'B' act = ls_line-variety ). + READ TABLE lt_lines INTO ls_line INDEX 2. + cl_abap_unit_assert=>assert_equals( exp = 'Alpha' act = ls_line-name ). + lv_total = '15.000'. + cl_abap_unit_assert=>assert_equals( exp = lv_total act = ls_line-total_kg ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = ls_line-harvests ). + ENDMETHOD. + + METHOD skips_unknown_variety. + DATA ls_harvest TYPE lcl_vineyard=>ty_harvest. + DATA lt_harvest TYPE lcl_vineyard=>tt_harvest. + DATA lt_names TYPE lcl_vineyard=>tt_name. + DATA lt_lines TYPE lcl_vineyard=>tt_line. + DATA go_vineyard TYPE REF TO lcl_vineyard. + + ls_harvest-variety = 'X'. + ls_harvest-harvest_date = '20260101'. + ls_harvest-weight_kg = '1.000'. + APPEND ls_harvest TO lt_harvest. + + CREATE OBJECT go_vineyard. + go_vineyard->aggregate( + EXPORTING it_harvest = lt_harvest it_names = lt_names + IMPORTING et_lines = lt_lines ). + + cl_abap_unit_assert=>assert_equals( exp = 0 act = lines( lt_lines ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0160/seed/grape.tabl.asabap b/tasks_gen/eval/G0160/seed/grape.tabl.asabap new file mode 100644 index 0000000..6464ccb --- /dev/null +++ b/tasks_gen/eval/G0160/seed/grape.tabl.asabap @@ -0,0 +1,10 @@ +@EndUserText.label : 'Grape variety' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}grape { + key client : abap.clnt not null; + key variety : abap.char(4) not null; + name : abap.char(40); +} diff --git a/tasks_gen/eval/G0160/seed/harvest.tabl.asabap b/tasks_gen/eval/G0160/seed/harvest.tabl.asabap new file mode 100644 index 0000000..a5010c9 --- /dev/null +++ b/tasks_gen/eval/G0160/seed/harvest.tabl.asabap @@ -0,0 +1,12 @@ +@EndUserText.label : 'Grape harvest' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}harvest { + key client : abap.clnt not null; + key harvest_id : abap.int4 not null; + variety : abap.char(4); + harvest_date : abap.dats; + weight_kg : abap.dec(13,3); +} diff --git a/tasks_gen/eval/G0160/seed/vine_seed.clas.abap b/tasks_gen/eval/G0160/seed/vine_seed.clas.abap new file mode 100644 index 0000000..497bb5c --- /dev/null +++ b/tasks_gen/eval/G0160/seed/vine_seed.clas.abap @@ -0,0 +1,95 @@ +CLASS {{p}}vine_seed DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES if_oo_adt_classrun. +ENDCLASS. + +CLASS {{p}}vine_seed IMPLEMENTATION. + METHOD if_oo_adt_classrun~main. + DATA lt_grape TYPE STANDARD TABLE OF {{p}}grape. + DATA lt_harvest TYPE STANDARD TABLE OF {{p}}harvest. + DATA ls_grape TYPE {{p}}grape. + DATA ls_harvest TYPE {{p}}harvest. + + DELETE FROM {{p}}harvest. + DELETE FROM {{p}}grape. + + CLEAR ls_grape. + ls_grape-client = sy-mandt. + ls_grape-variety = 'MERL'. + ls_grape-name = 'Merlot'. + APPEND ls_grape TO lt_grape. + + CLEAR ls_grape. + ls_grape-client = sy-mandt. + ls_grape-variety = 'CHRD'. + ls_grape-name = 'Chardonnay'. + APPEND ls_grape TO lt_grape. + + CLEAR ls_grape. + ls_grape-client = sy-mandt. + ls_grape-variety = 'RIES'. + ls_grape-name = 'Riesling'. + APPEND ls_grape TO lt_grape. + + CLEAR ls_harvest. + ls_harvest-client = sy-mandt. + ls_harvest-harvest_id = 1. + ls_harvest-variety = 'MERL'. + ls_harvest-harvest_date = '20260901'. + ls_harvest-weight_kg = '1200.500'. + APPEND ls_harvest TO lt_harvest. + + CLEAR ls_harvest. + ls_harvest-client = sy-mandt. + ls_harvest-harvest_id = 2. + ls_harvest-variety = 'MERL'. + ls_harvest-harvest_date = '20260910'. + ls_harvest-weight_kg = '800.000'. + APPEND ls_harvest TO lt_harvest. + + CLEAR ls_harvest. + ls_harvest-client = sy-mandt. + ls_harvest-harvest_id = 3. + ls_harvest-variety = 'CHRD'. + ls_harvest-harvest_date = '20260905'. + ls_harvest-weight_kg = '2000.000'. + APPEND ls_harvest TO lt_harvest. + + CLEAR ls_harvest. + ls_harvest-client = sy-mandt. + ls_harvest-harvest_id = 4. + ls_harvest-variety = 'CHRD'. + ls_harvest-harvest_date = '20261001'. + ls_harvest-weight_kg = '300.000'. + APPEND ls_harvest TO lt_harvest. + + CLEAR ls_harvest. + ls_harvest-client = sy-mandt. + ls_harvest-harvest_id = 5. + ls_harvest-variety = 'RIES'. + ls_harvest-harvest_date = '20251215'. + ls_harvest-weight_kg = '250.000'. + APPEND ls_harvest TO lt_harvest. + + CLEAR ls_harvest. + ls_harvest-client = sy-mandt. + ls_harvest-harvest_id = 6. + ls_harvest-variety = 'RIES'. + ls_harvest-harvest_date = '20260820'. + ls_harvest-weight_kg = '500.000'. + APPEND ls_harvest TO lt_harvest. + + CLEAR ls_harvest. + ls_harvest-client = sy-mandt. + ls_harvest-harvest_id = 7. + ls_harvest-variety = 'SYRA'. + ls_harvest-harvest_date = '20260915'. + ls_harvest-weight_kg = '100.000'. + APPEND ls_harvest TO lt_harvest. + + INSERT {{p}}grape FROM TABLE lt_grape. + INSERT {{p}}harvest FROM TABLE lt_harvest. + + out->write( sy-dbcnt ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0160/spec.md b/tasks_gen/eval/G0160/spec.md new file mode 100644 index 0000000..f2a6eaf --- /dev/null +++ b/tasks_gen/eval/G0160/spec.md @@ -0,0 +1,46 @@ +# 1. Goal +Show the harvest weight of each grape variety in an ALV list. The winery uses the +list to compare the varieties for a period. + +# 2. Open questions +None. + +# 3. Context +- Table {{P}}GRAPE exists in package $TMP. It contains data. + Fields: VARIETY (CHAR 4, key), NAME (CHAR 40). +- Table {{P}}HARVEST exists in package $TMP. It contains data. + Fields: HARVEST_ID (INT4, key), VARIETY (CHAR 4), HARVEST_DATE (DATS), + WEIGHT_KG (DEC 13,3). + +# 4. Contract +- Create the executable program {{P}}VINEYARD_RPT in package $TMP. +- Selection screen: + - Parameter P_FROM, type DATS, mandatory: the first harvest date to include. + - Select-option S_VAR for the variety. +- Show the result with CL_SALV_TABLE. The output table has these columns, with + these names: VARIETY, NAME, TOTAL_KG (the sum of WEIGHT_KG), HARVESTS (the + number of harvests). + +# 5. Business rules +1. Include a harvest only if HARVEST_DATE is on or after P_FROM and VARIETY is + in S_VAR. An empty S_VAR does not restrict the variety. +2. Show a variety only if it has an entry in {{P}}GRAPE. A variety with harvests + but without an entry in {{P}}GRAPE is not shown. +3. Show one line for each variety with at least one included harvest. +4. NAME is the name of the variety from {{P}}GRAPE. +5. Sort the lines by TOTAL_KG, the highest total first. + +# 6. Constraints +- Release target: 7.02. Use only ABAP syntax that is available in release 7.02. + Do not use syntax elements that were introduced in a later release. Examples of + syntax that you must not use: inline declarations, constructor expressions + (NEW, VALUE, CONV), string templates, table expressions, SQL expressions and + SQL aggregate functions, GROUP BY, UNION, the escape character @ in ABAP SQL, + WITH EMPTY KEY. +- Coding standards: Clean ABAP. Do not read the database inside a loop. +- Out of scope: do not change {{P}}GRAPE or {{P}}HARVEST. + +# 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/eval/G0160/task.json b/tasks_gen/eval/G0160/task.json new file mode 100644 index 0000000..b40bcf0 --- /dev/null +++ b/tasks_gen/eval/G0160/task.json @@ -0,0 +1,67 @@ +{ + "id": "G0160", + "category": "G", + "object_type": "PROG", + "difficulty": 2, + "release_target": "v702", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 40, + "max_activations": 10 + }, + "seed": [ + { + "type": "TABL", + "name": "{{P}}GRAPE", + "file": "seed/grape.tabl.asabap", + "description": "Grape varieties" + }, + { + "type": "TABL", + "name": "{{P}}HARVEST", + "file": "seed/harvest.tabl.asabap", + "description": "Grape harvests" + }, + { + "type": "CLAS", + "name": "{{P}}VINE_SEED", + "file": "seed/vine_seed.clas.abap", + "description": "Vineyard seed data", + "run": true + } + ], + "contract": [ + { + "type": "PROG", + "name": "{{P}}VINEYARD_RPT", + "parameters": [ + "p_from", + "s_var" + ] + } + ], + "out_of_scope": [ + "{{P}}GRAPE", + "{{P}}HARVEST" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}VINE_HIDDEN", + "file": "hidden/vine_hidden.clas.abap", + "description": "Hidden tests for the vineyard harvest report" + } + ], + "reference": [ + { + "type": "PROG", + "name": "{{P}}VINEYARD_RPT", + "file": "reference/vineyard_rpt.prog.abap", + "description": "Harvest weight per grape variety" + } + ], + "craft_checks": [ + "db_operation_in_loop", + "method_length" + ] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0161/hidden/zoo_hidden.clas.abap b/tasks_gen/eval/G0161/hidden/zoo_hidden.clas.abap new file mode 100644 index 0000000..9305b94 --- /dev/null +++ b/tasks_gen/eval/G0161/hidden/zoo_hidden.clas.abap @@ -0,0 +1,125 @@ +CLASS {{p}}zoo_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS all_enclosures FOR TESTING. + METHODS sort_by_cost FOR TESTING. + METHODS tie_break FOR TESTING. + METHODS weight_filter FOR TESTING. + METHODS weight_boundary FOR TESTING. + METHODS enclosure_filter FOR TESTING. +ENDCLASS. + +CLASS lcl_zoo_helper DEFINITION FINAL. + PUBLIC SECTION. + TYPES tt_enclosure TYPE RANGE OF {{p}}animal-enclosure. + CLASS-METHODS run + IMPORTING iv_minwg TYPE {{p}}animal-weight_kg + it_enclosure TYPE tt_enclosure OPTIONAL + RETURNING VALUE(rr_data) TYPE REF TO data. + CLASS-METHODS lines_of + IMPORTING ir_data TYPE REF TO data + RETURNING VALUE(rv_lines) TYPE i. + CLASS-METHODS value_of + IMPORTING ir_data TYPE REF TO data + iv_row TYPE i + iv_col TYPE string + RETURNING VALUE(rv_value) TYPE string. +ENDCLASS. + +CLASS lcl_zoo_helper IMPLEMENTATION. + METHOD run. + cl_salv_bs_runtime_info=>set( display = abap_false metadata = abap_false data = abap_true ). + SUBMIT {{p}}zoo_feed + WITH p_minwg = iv_minwg + WITH s_encl IN it_enclosure + 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. +ENDCLASS. + +CLASS {{p}}zoo_hidden IMPLEMENTATION. + METHOD all_enclosures. + cl_abap_unit_assert=>assert_equals( + exp = 3 + act = lcl_zoo_helper=>lines_of( lcl_zoo_helper=>run( iv_minwg = '0.0' ) ) ). + ENDMETHOD. + + METHOD sort_by_cost. + DATA(lr_data) = lcl_zoo_helper=>run( iv_minwg = '0.0' ). + cl_abap_unit_assert=>assert_equals( + exp = `JUNGLE` + act = lcl_zoo_helper=>value_of( ir_data = lr_data iv_row = 1 iv_col = `ENCLOSURE` ) ). + cl_abap_unit_assert=>assert_equals( + exp = `34.00` + act = lcl_zoo_helper=>value_of( ir_data = lr_data iv_row = 1 iv_col = `COST` ) ). + ENDMETHOD. + + METHOD tie_break. + DATA(lr_data) = lcl_zoo_helper=>run( iv_minwg = '0.0' ). + cl_abap_unit_assert=>assert_equals( + exp = `AQUA` + act = lcl_zoo_helper=>value_of( ir_data = lr_data iv_row = 2 iv_col = `ENCLOSURE` ) ). + cl_abap_unit_assert=>assert_equals( + exp = `SAVANNA` + act = lcl_zoo_helper=>value_of( ir_data = lr_data iv_row = 3 iv_col = `ENCLOSURE` ) ). + ENDMETHOD. + + METHOD weight_filter. + DATA(lr_data) = lcl_zoo_helper=>run( iv_minwg = '10.0' ). + cl_abap_unit_assert=>assert_equals( exp = 3 act = lcl_zoo_helper=>lines_of( lr_data ) ). + cl_abap_unit_assert=>assert_equals( + exp = `AQUA` + act = lcl_zoo_helper=>value_of( ir_data = lr_data iv_row = 3 iv_col = `ENCLOSURE` ) ). + cl_abap_unit_assert=>assert_equals( + exp = `1` + act = lcl_zoo_helper=>value_of( ir_data = lr_data iv_row = 3 iv_col = `ANIMALS` ) ). + cl_abap_unit_assert=>assert_equals( + exp = `15.00` + act = lcl_zoo_helper=>value_of( ir_data = lr_data iv_row = 3 iv_col = `COST` ) ). + ENDMETHOD. + + METHOD weight_boundary. + DATA(lr_low) = lcl_zoo_helper=>run( iv_minwg = '8.0' ). + cl_abap_unit_assert=>assert_equals( + exp = `3` + act = lcl_zoo_helper=>value_of( ir_data = lr_low iv_row = 1 iv_col = `ANIMALS` ) ). + DATA(lr_high) = lcl_zoo_helper=>run( iv_minwg = '9.0' ). + cl_abap_unit_assert=>assert_equals( + exp = `2` + act = lcl_zoo_helper=>value_of( ir_data = lr_high iv_row = 1 iv_col = `ANIMALS` ) ). + ENDMETHOD. + + METHOD enclosure_filter. + DATA(lr_data) = lcl_zoo_helper=>run( + iv_minwg = '0.0' + it_enclosure = VALUE #( ( sign = 'I' option = 'EQ' low = 'AQUA' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lcl_zoo_helper=>lines_of( lr_data ) ). + cl_abap_unit_assert=>assert_equals( + exp = `20.00` + act = lcl_zoo_helper=>value_of( ir_data = lr_data iv_row = 1 iv_col = `COST` ) ). + cl_abap_unit_assert=>assert_equals( + exp = `2` + act = lcl_zoo_helper=>value_of( ir_data = lr_data iv_row = 1 iv_col = `ANIMALS` ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0161/reference/zoo_feed.prog.abap b/tasks_gen/eval/G0161/reference/zoo_feed.prog.abap new file mode 100644 index 0000000..025b743 --- /dev/null +++ b/tasks_gen/eval/G0161/reference/zoo_feed.prog.abap @@ -0,0 +1,160 @@ +REPORT {{p}}zoo_feed. + +TYPES: BEGIN OF ty_line, + enclosure TYPE {{p}}animal-enclosure, + animals TYPE i, + cost TYPE {{p}}animal-food_cost, + END OF ty_line. +TYPES tt_line TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY. +TYPES tt_enclosure TYPE RANGE OF {{p}}animal-enclosure. + +TYPES: BEGIN OF ty_animal, + enclosure TYPE {{p}}animal-enclosure, + food_cost TYPE {{p}}animal-food_cost, + END OF ty_animal. +TYPES tt_animal TYPE STANDARD TABLE OF ty_animal WITH EMPTY KEY. + +DATA gv_enclosure TYPE {{p}}animal-enclosure. + +PARAMETERS p_minwg TYPE {{p}}animal-weight_kg OBLIGATORY. +SELECT-OPTIONS s_encl FOR gv_enclosure. + +CLASS lcl_report DEFINITION FINAL. + PUBLIC SECTION. + CLASS-METHODS select_lines + IMPORTING iv_min_weight TYPE {{p}}animal-weight_kg + it_enclosure TYPE tt_enclosure + RETURNING VALUE(rt_lines) TYPE tt_line. + CLASS-METHODS display + CHANGING ct_lines TYPE tt_line. +ENDCLASS. + +CLASS lcl_report IMPLEMENTATION. + METHOD select_lines. + DATA: lt_animals TYPE tt_animal, + ls_animal TYPE ty_animal, + ls_line TYPE ty_line. + + SELECT enclosure food_cost + FROM {{p}}animal + INTO CORRESPONDING FIELDS OF TABLE lt_animals + WHERE weight_kg >= iv_min_weight + AND enclosure IN it_enclosure. + + LOOP AT lt_animals INTO ls_animal. + READ TABLE rt_lines INTO ls_line + WITH KEY enclosure = ls_animal-enclosure. + IF sy-subrc = 0. + ls_line-animals = ls_line-animals + 1. + ls_line-cost = ls_line-cost + ls_animal-food_cost. + MODIFY rt_lines FROM ls_line INDEX sy-tabix. + ELSE. + CLEAR ls_line. + ls_line-enclosure = ls_animal-enclosure. + ls_line-animals = 1. + ls_line-cost = ls_animal-food_cost. + APPEND ls_line TO rt_lines. + ENDIF. + ENDLOOP. + + SORT rt_lines BY cost DESCENDING enclosure ASCENDING. + ENDMETHOD. + + METHOD display. + DATA: lo_alv TYPE REF TO cl_salv_table, + lx_msg TYPE REF TO cx_salv_msg. + TRY. + cl_salv_table=>factory( + IMPORTING r_salv_table = lo_alv + CHANGING t_table = ct_lines ). + lo_alv->display( ). + CATCH cx_salv_msg INTO lx_msg. + MESSAGE lx_msg TYPE 'I' DISPLAY LIKE 'E'. + ENDTRY. + ENDMETHOD. +ENDCLASS. + +START-OF-SELECTION. + DATA gt_lines TYPE tt_line. + + gt_lines = lcl_report=>select_lines( iv_min_weight = p_minwg + it_enclosure = s_encl[] ). + lcl_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_enclosure FOR TESTING. + METHODS weight_filter FOR TESTING. +ENDCLASS. + +CLASS ltc_report IMPLEMENTATION. + METHOD class_setup. + go_env = cl_osql_test_environment=>create( + i_dependency_list = VALUE #( ( '{{P}}ANIMAL' ) ) ). + DATA: lt_animal TYPE STANDARD TABLE OF {{p}}animal WITH EMPTY KEY, + ls_animal TYPE {{p}}animal. + + ls_animal-animal_id = 1. + ls_animal-enclosure = 'A'. + ls_animal-species = 'LION'. + ls_animal-weight_kg = '100.0'. + ls_animal-food_cost = '10.00'. + APPEND ls_animal TO lt_animal. + + CLEAR ls_animal. + ls_animal-animal_id = 2. + ls_animal-enclosure = 'A'. + ls_animal-species = 'CUB'. + ls_animal-weight_kg = '5.0'. + ls_animal-food_cost = '2.00'. + APPEND ls_animal TO lt_animal. + + CLEAR ls_animal. + ls_animal-animal_id = 3. + ls_animal-enclosure = 'B'. + ls_animal-species = 'SEAL'. + ls_animal-weight_kg = '50.0'. + ls_animal-food_cost = '7.00'. + APPEND ls_animal TO lt_animal. + + go_env->insert_test_data( lt_animal ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD totals_per_enclosure. + DATA: lt_lines TYPE tt_line, + ls_line TYPE ty_line, + lt_none TYPE tt_enclosure. + + lt_lines = lcl_report=>select_lines( iv_min_weight = '0.0' + it_enclosure = lt_none ). + + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + + READ TABLE lt_lines INTO ls_line INDEX 1. + cl_abap_unit_assert=>assert_equals( exp = 'A' act = ls_line-enclosure ). + cl_abap_unit_assert=>assert_equals( + exp = CONV {{p}}animal-food_cost( 12 ) act = ls_line-cost ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = ls_line-animals ). + ENDMETHOD. + + METHOD weight_filter. + DATA: lt_lines TYPE tt_line, + ls_line TYPE ty_line, + lt_none TYPE tt_enclosure. + + lt_lines = lcl_report=>select_lines( iv_min_weight = '10.0' + it_enclosure = lt_none ). + + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + + READ TABLE lt_lines INTO ls_line INDEX 1. + cl_abap_unit_assert=>assert_equals( exp = 1 act = ls_line-animals ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0161/seed/animal.tabl.asabap b/tasks_gen/eval/G0161/seed/animal.tabl.asabap new file mode 100644 index 0000000..ef1a2d9 --- /dev/null +++ b/tasks_gen/eval/G0161/seed/animal.tabl.asabap @@ -0,0 +1,13 @@ +@EndUserText.label : 'Zoo animals' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}animal { + key client : abap.clnt not null; + key animal_id : abap.int4 not null; + enclosure : abap.char(10); + species : abap.char(20); + weight_kg : abap.dec(5,1); + food_cost : abap.dec(9,2); +} diff --git a/tasks_gen/eval/G0161/seed/zoo_seed.clas.abap b/tasks_gen/eval/G0161/seed/zoo_seed.clas.abap new file mode 100644 index 0000000..489811c --- /dev/null +++ b/tasks_gen/eval/G0161/seed/zoo_seed.clas.abap @@ -0,0 +1,19 @@ +CLASS {{p}}zoo_seed DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES if_oo_adt_classrun. +ENDCLASS. + +CLASS {{p}}zoo_seed IMPLEMENTATION. + METHOD if_oo_adt_classrun~main. + DELETE FROM {{p}}animal. + INSERT {{p}}animal FROM TABLE @( VALUE #( + ( animal_id = 1 enclosure = 'SAVANNA' species = 'GIRAFFE' weight_kg = '800.0' food_cost = '12.50' ) + ( animal_id = 2 enclosure = 'SAVANNA' species = 'ZEBRA' weight_kg = '250.0' food_cost = '7.50' ) + ( animal_id = 3 enclosure = 'AQUA' species = 'SEAL' weight_kg = '120.0' food_cost = '15.00' ) + ( animal_id = 4 enclosure = 'AQUA' species = 'OTTER' weight_kg = '6.0' food_cost = '5.00' ) + ( animal_id = 5 enclosure = 'JUNGLE' species = 'TIGER' weight_kg = '200.0' food_cost = '15.00' ) + ( animal_id = 6 enclosure = 'JUNGLE' species = 'BEAR' weight_kg = '300.0' food_cost = '15.00' ) + ( animal_id = 7 enclosure = 'JUNGLE' species = 'MONKEY' weight_kg = '8.0' food_cost = '4.00' ) ) ). + out->write( sy-dbcnt ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0161/spec.md b/tasks_gen/eval/G0161/spec.md new file mode 100644 index 0000000..b31556b --- /dev/null +++ b/tasks_gen/eval/G0161/spec.md @@ -0,0 +1,41 @@ +# 1. Goal +Show the daily food cost of each enclosure in the zoo in an ALV list. The zoo +keeper uses the list to plan the daily food order. + +# 2. Open questions +None. + +# 3. Context +- The table {{P}}ANIMAL exists in package $TMP and contains data. + Fields: ANIMAL_ID (INT4, key), ENCLOSURE (CHAR 10), SPECIES (CHAR 20), + WEIGHT_KG (DEC 5,1), FOOD_COST (DEC 9,2). +- FOOD_COST is the daily food cost of one animal in euro. + +# 4. Contract +- Create the executable program {{P}}ZOO_FEED in package $TMP. +- Selection screen: + - Parameter P_MINWG, type {{P}}ANIMAL-WEIGHT_KG, mandatory: the smallest + weight of an animal to include. + - Select-option S_ENCL for the enclosure. +- Show the result with CL_SALV_TABLE. The output table has these columns with + these names: ENCLOSURE, ANIMALS, COST. + +# 5. Business rules +1. Include an animal only if WEIGHT_KG is greater than or equal to P_MINWG and + ENCLOSURE is in S_ENCL. +2. Show one line for each enclosure that has at least one included animal. +3. ANIMALS is the number of included animals of the enclosure. +4. COST is the sum of FOOD_COST of the included animals of the enclosure. +5. Sort the lines by COST, the highest cost first. +6. If two lines have the same COST, sort them by ENCLOSURE in ascending order. + +# 6. Constraints +- Release target: 7.40 SP05. Use only ABAP syntax that is available in this + release. Do not use syntax of a newer release. +- Coding standards: Clean ABAP. Read the data with one database access. +- Out of scope: do not change {{P}}ANIMAL. + +# 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/eval/G0161/task.json b/tasks_gen/eval/G0161/task.json new file mode 100644 index 0000000..bb05b47 --- /dev/null +++ b/tasks_gen/eval/G0161/task.json @@ -0,0 +1,61 @@ +{ + "id": "G0161", + "category": "G", + "object_type": "PROG", + "difficulty": 2, + "release_target": "v740sp05", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 40, + "max_activations": 10 + }, + "seed": [ + { + "type": "TABL", + "name": "{{P}}ANIMAL", + "file": "seed/animal.tabl.asabap", + "description": "Zoo animals" + }, + { + "type": "CLAS", + "name": "{{P}}ZOO_SEED", + "file": "seed/zoo_seed.clas.abap", + "description": "Zoo seed data", + "run": true + } + ], + "contract": [ + { + "type": "PROG", + "name": "{{P}}ZOO_FEED", + "parameters": [ + "p_minwg", + "s_encl" + ] + } + ], + "out_of_scope": [ + "{{P}}ANIMAL" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}ZOO_HIDDEN", + "file": "hidden/zoo_hidden.clas.abap", + "description": "Zoo feed hidden tests" + } + ], + "reference": [ + { + "type": "PROG", + "name": "{{P}}ZOO_FEED", + "file": "reference/zoo_feed.prog.abap", + "description": "Daily food cost per enclosure" + } + ], + "craft_checks": [ + "db_operation_in_loop", + "method_length", + "no_newer_syntax" + ] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0162/faulty/m0_planetarium.prog.abap b/tasks_gen/eval/G0162/faulty/m0_planetarium.prog.abap new file mode 100644 index 0000000..f838eaa --- /dev/null +++ b/tasks_gen/eval/G0162/faulty/m0_planetarium.prog.abap @@ -0,0 +1,194 @@ +REPORT {{p}}planetarium. + +TYPES: BEGIN OF ty_visit, + show_id TYPE {{p}}visit-show_id, + tickets TYPE {{p}}visit-tickets, + ticket_price TYPE {{p}}visit-ticket_price, + END OF ty_visit. +TYPES tt_visit TYPE STANDARD TABLE OF ty_visit. + +TYPES: BEGIN OF ty_line, + show_id TYPE {{p}}visit-show_id, + tickets TYPE i, + revenue TYPE p LENGTH 15 DECIMALS 2, + END OF ty_line. +TYPES tt_line TYPE STANDARD TABLE OF ty_line. + +DATA gv_show_id TYPE {{p}}visit-show_id. + +PARAMETERS p_from TYPE d OBLIGATORY. +SELECT-OPTIONS s_show FOR gv_show_id. + +CLASS lcl_report DEFINITION FINAL. + PUBLIC SECTION. + METHODS aggregate + IMPORTING it_visits TYPE tt_visit + CHANGING ct_lines TYPE tt_line. + METHODS display + CHANGING ct_lines TYPE tt_line. +ENDCLASS. + +CLASS lcl_report IMPLEMENTATION. + METHOD aggregate. + DATA: ls_visit TYPE ty_visit, + ls_line TYPE ty_line. + + LOOP AT it_visits INTO ls_visit. + READ TABLE ct_lines INTO ls_line WITH KEY show_id = ls_visit-show_id. + IF sy-subrc = 0. + ls_line-tickets = ls_line-tickets + ls_visit-tickets. + ls_line-revenue = ls_line-revenue + ls_visit-tickets / ls_visit-ticket_price. + MODIFY ct_lines FROM ls_line INDEX sy-tabix. + ELSE. + CLEAR ls_line. + ls_line-show_id = ls_visit-show_id. + ls_line-tickets = ls_visit-tickets. + ls_line-revenue = ls_visit-tickets * ls_visit-ticket_price. + APPEND ls_line TO ct_lines. + ENDIF. + ENDLOOP. + + SORT ct_lines BY revenue DESCENDING show_id ASCENDING. + ENDMETHOD. + + METHOD display. + DATA: lo_alv TYPE REF TO cl_salv_table, + lx_error TYPE REF TO cx_salv_msg. + + TRY. + cl_salv_table=>factory( + IMPORTING r_salv_table = lo_alv + CHANGING t_table = ct_lines ). + lo_alv->display( ). + CATCH cx_salv_msg INTO lx_error. + MESSAGE lx_error TYPE 'I' DISPLAY LIKE 'E'. + ENDTRY. + ENDMETHOD. +ENDCLASS. + +START-OF-SELECTION. + DATA: lt_visits TYPE tt_visit, + lt_lines TYPE tt_line, + lo_report TYPE REF TO lcl_report. + + SELECT show_id tickets ticket_price + FROM {{p}}visit + INTO TABLE lt_visits + WHERE visit_date >= p_from + AND show_id IN s_show + AND tickets > 0. + + CREATE OBJECT lo_report. + lo_report->aggregate( EXPORTING it_visits = lt_visits + CHANGING ct_lines = lt_lines ). + lo_report->display( CHANGING ct_lines = lt_lines ). + +CLASS ltc_report DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS sums_by_show FOR TESTING. + METHODS sorted_by_revenue FOR TESTING. + METHODS tie_break_by_show FOR TESTING. +ENDCLASS. + +CLASS ltc_report IMPLEMENTATION. + METHOD sums_by_show. + DATA: lt_visits TYPE tt_visit, + lt_lines TYPE tt_line, + ls_visit TYPE ty_visit, + ls_line TYPE ty_line, + lv_exp TYPE p LENGTH 15 DECIMALS 2, + lo_report TYPE REF TO lcl_report. + + CLEAR ls_visit. + ls_visit-show_id = 'A'. + ls_visit-tickets = 10. + ls_visit-ticket_price = '12.00'. + APPEND ls_visit TO lt_visits. + + CLEAR ls_visit. + ls_visit-show_id = 'A'. + ls_visit-tickets = 5. + ls_visit-ticket_price = '12.00'. + APPEND ls_visit TO lt_visits. + + CLEAR ls_visit. + ls_visit-show_id = 'B'. + ls_visit-tickets = 4. + ls_visit-ticket_price = '15.00'. + APPEND ls_visit TO lt_visits. + + CREATE OBJECT lo_report. + lo_report->aggregate( EXPORTING it_visits = lt_visits + CHANGING ct_lines = lt_lines ). + + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + + READ TABLE lt_lines INTO ls_line INDEX 1. + cl_abap_unit_assert=>assert_equals( exp = 'A' act = ls_line-show_id ). + cl_abap_unit_assert=>assert_equals( exp = 15 act = ls_line-tickets ). + lv_exp = 15 * 12. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = ls_line-revenue ). + + READ TABLE lt_lines INTO ls_line INDEX 2. + cl_abap_unit_assert=>assert_equals( exp = 'B' act = ls_line-show_id ). + cl_abap_unit_assert=>assert_equals( exp = 4 act = ls_line-tickets ). + lv_exp = 4 * 15. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = ls_line-revenue ). + ENDMETHOD. + + METHOD sorted_by_revenue. + DATA: lt_visits TYPE tt_visit, + lt_lines TYPE tt_line, + ls_visit TYPE ty_visit, + ls_line TYPE ty_line, + lo_report TYPE REF TO lcl_report. + + CLEAR ls_visit. + ls_visit-show_id = 'C'. + ls_visit-tickets = 1. + ls_visit-ticket_price = '5.00'. + APPEND ls_visit TO lt_visits. + + CLEAR ls_visit. + ls_visit-show_id = 'D'. + ls_visit-tickets = 10. + ls_visit-ticket_price = '5.00'. + APPEND ls_visit TO lt_visits. + + CREATE OBJECT lo_report. + lo_report->aggregate( EXPORTING it_visits = lt_visits + CHANGING ct_lines = lt_lines ). + + READ TABLE lt_lines INTO ls_line INDEX 1. + cl_abap_unit_assert=>assert_equals( exp = 'D' act = ls_line-show_id ). + ENDMETHOD. + + METHOD tie_break_by_show. + DATA: lt_visits TYPE tt_visit, + lt_lines TYPE tt_line, + ls_visit TYPE ty_visit, + ls_line TYPE ty_line, + lo_report TYPE REF TO lcl_report. + + CLEAR ls_visit. + ls_visit-show_id = 'Z'. + ls_visit-tickets = 2. + ls_visit-ticket_price = '5.00'. + APPEND ls_visit TO lt_visits. + + CLEAR ls_visit. + ls_visit-show_id = 'A'. + ls_visit-tickets = 2. + ls_visit-ticket_price = '5.00'. + APPEND ls_visit TO lt_visits. + + CREATE OBJECT lo_report. + lo_report->aggregate( EXPORTING it_visits = lt_visits + CHANGING ct_lines = lt_lines ). + + READ TABLE lt_lines INTO ls_line INDEX 1. + cl_abap_unit_assert=>assert_equals( exp = 'A' act = ls_line-show_id ). + READ TABLE lt_lines INTO ls_line INDEX 2. + cl_abap_unit_assert=>assert_equals( exp = 'Z' act = ls_line-show_id ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0162/faulty/m1_planetarium.prog.abap b/tasks_gen/eval/G0162/faulty/m1_planetarium.prog.abap new file mode 100644 index 0000000..54cbc3d --- /dev/null +++ b/tasks_gen/eval/G0162/faulty/m1_planetarium.prog.abap @@ -0,0 +1,194 @@ +REPORT {{p}}planetarium. + +TYPES: BEGIN OF ty_visit, + show_id TYPE {{p}}visit-show_id, + tickets TYPE {{p}}visit-tickets, + ticket_price TYPE {{p}}visit-ticket_price, + END OF ty_visit. +TYPES tt_visit TYPE STANDARD TABLE OF ty_visit. + +TYPES: BEGIN OF ty_line, + show_id TYPE {{p}}visit-show_id, + tickets TYPE i, + revenue TYPE p LENGTH 15 DECIMALS 2, + END OF ty_line. +TYPES tt_line TYPE STANDARD TABLE OF ty_line. + +DATA gv_show_id TYPE {{p}}visit-show_id. + +PARAMETERS p_from TYPE d OBLIGATORY. +SELECT-OPTIONS s_show FOR gv_show_id. + +CLASS lcl_report DEFINITION FINAL. + PUBLIC SECTION. + METHODS aggregate + IMPORTING it_visits TYPE tt_visit + CHANGING ct_lines TYPE tt_line. + METHODS display + CHANGING ct_lines TYPE tt_line. +ENDCLASS. + +CLASS lcl_report IMPLEMENTATION. + METHOD aggregate. + DATA: ls_visit TYPE ty_visit, + ls_line TYPE ty_line. + + LOOP AT it_visits INTO ls_visit. + READ TABLE ct_lines INTO ls_line WITH KEY show_id = ls_visit-show_id. + IF sy-subrc = 0. + ls_line-tickets = ls_line-tickets + ls_visit-tickets. + ls_line-revenue = ls_line-revenue + ls_visit-tickets * ls_visit-ticket_price. + MODIFY ct_lines FROM ls_line INDEX sy-tabix. + ELSE. + CLEAR ls_line. + ls_line-show_id = ls_visit-show_id. + ls_line-tickets = ls_visit-tickets. + ls_line-revenue = ls_visit-tickets * ls_visit-ticket_price. + APPEND ls_line TO ct_lines. + ENDIF. + ENDLOOP. + + SORT ct_lines BY revenue DESCENDING show_id ASCENDING. + ENDMETHOD. + + METHOD display. + DATA: lo_alv TYPE REF TO cl_salv_table, + lx_error TYPE REF TO cx_salv_msg. + + TRY. + cl_salv_table=>factory( + IMPORTING r_salv_table = lo_alv + CHANGING t_table = ct_lines ). + lo_alv->display( ). + CATCH cx_salv_msg INTO lx_error. + MESSAGE lx_error TYPE 'I' DISPLAY LIKE 'E'. + ENDTRY. + ENDMETHOD. +ENDCLASS. + +START-OF-SELECTION. + DATA: lt_visits TYPE tt_visit, + lt_lines TYPE tt_line, + lo_report TYPE REF TO lcl_report. + + SELECT show_id tickets ticket_price + FROM {{p}}visit + INTO TABLE lt_visits + WHERE visit_date < p_from + AND show_id IN s_show + AND tickets > 0. + + CREATE OBJECT lo_report. + lo_report->aggregate( EXPORTING it_visits = lt_visits + CHANGING ct_lines = lt_lines ). + lo_report->display( CHANGING ct_lines = lt_lines ). + +CLASS ltc_report DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS sums_by_show FOR TESTING. + METHODS sorted_by_revenue FOR TESTING. + METHODS tie_break_by_show FOR TESTING. +ENDCLASS. + +CLASS ltc_report IMPLEMENTATION. + METHOD sums_by_show. + DATA: lt_visits TYPE tt_visit, + lt_lines TYPE tt_line, + ls_visit TYPE ty_visit, + ls_line TYPE ty_line, + lv_exp TYPE p LENGTH 15 DECIMALS 2, + lo_report TYPE REF TO lcl_report. + + CLEAR ls_visit. + ls_visit-show_id = 'A'. + ls_visit-tickets = 10. + ls_visit-ticket_price = '12.00'. + APPEND ls_visit TO lt_visits. + + CLEAR ls_visit. + ls_visit-show_id = 'A'. + ls_visit-tickets = 5. + ls_visit-ticket_price = '12.00'. + APPEND ls_visit TO lt_visits. + + CLEAR ls_visit. + ls_visit-show_id = 'B'. + ls_visit-tickets = 4. + ls_visit-ticket_price = '15.00'. + APPEND ls_visit TO lt_visits. + + CREATE OBJECT lo_report. + lo_report->aggregate( EXPORTING it_visits = lt_visits + CHANGING ct_lines = lt_lines ). + + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + + READ TABLE lt_lines INTO ls_line INDEX 1. + cl_abap_unit_assert=>assert_equals( exp = 'A' act = ls_line-show_id ). + cl_abap_unit_assert=>assert_equals( exp = 15 act = ls_line-tickets ). + lv_exp = 15 * 12. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = ls_line-revenue ). + + READ TABLE lt_lines INTO ls_line INDEX 2. + cl_abap_unit_assert=>assert_equals( exp = 'B' act = ls_line-show_id ). + cl_abap_unit_assert=>assert_equals( exp = 4 act = ls_line-tickets ). + lv_exp = 4 * 15. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = ls_line-revenue ). + ENDMETHOD. + + METHOD sorted_by_revenue. + DATA: lt_visits TYPE tt_visit, + lt_lines TYPE tt_line, + ls_visit TYPE ty_visit, + ls_line TYPE ty_line, + lo_report TYPE REF TO lcl_report. + + CLEAR ls_visit. + ls_visit-show_id = 'C'. + ls_visit-tickets = 1. + ls_visit-ticket_price = '5.00'. + APPEND ls_visit TO lt_visits. + + CLEAR ls_visit. + ls_visit-show_id = 'D'. + ls_visit-tickets = 10. + ls_visit-ticket_price = '5.00'. + APPEND ls_visit TO lt_visits. + + CREATE OBJECT lo_report. + lo_report->aggregate( EXPORTING it_visits = lt_visits + CHANGING ct_lines = lt_lines ). + + READ TABLE lt_lines INTO ls_line INDEX 1. + cl_abap_unit_assert=>assert_equals( exp = 'D' act = ls_line-show_id ). + ENDMETHOD. + + METHOD tie_break_by_show. + DATA: lt_visits TYPE tt_visit, + lt_lines TYPE tt_line, + ls_visit TYPE ty_visit, + ls_line TYPE ty_line, + lo_report TYPE REF TO lcl_report. + + CLEAR ls_visit. + ls_visit-show_id = 'Z'. + ls_visit-tickets = 2. + ls_visit-ticket_price = '5.00'. + APPEND ls_visit TO lt_visits. + + CLEAR ls_visit. + ls_visit-show_id = 'A'. + ls_visit-tickets = 2. + ls_visit-ticket_price = '5.00'. + APPEND ls_visit TO lt_visits. + + CREATE OBJECT lo_report. + lo_report->aggregate( EXPORTING it_visits = lt_visits + CHANGING ct_lines = lt_lines ). + + READ TABLE lt_lines INTO ls_line INDEX 1. + cl_abap_unit_assert=>assert_equals( exp = 'A' act = ls_line-show_id ). + READ TABLE lt_lines INTO ls_line INDEX 2. + cl_abap_unit_assert=>assert_equals( exp = 'Z' act = ls_line-show_id ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0162/faulty/m2_planetarium.prog.abap b/tasks_gen/eval/G0162/faulty/m2_planetarium.prog.abap new file mode 100644 index 0000000..6d67d68 --- /dev/null +++ b/tasks_gen/eval/G0162/faulty/m2_planetarium.prog.abap @@ -0,0 +1,194 @@ +REPORT {{p}}planetarium. + +TYPES: BEGIN OF ty_visit, + show_id TYPE {{p}}visit-show_id, + tickets TYPE {{p}}visit-tickets, + ticket_price TYPE {{p}}visit-ticket_price, + END OF ty_visit. +TYPES tt_visit TYPE STANDARD TABLE OF ty_visit. + +TYPES: BEGIN OF ty_line, + show_id TYPE {{p}}visit-show_id, + tickets TYPE i, + revenue TYPE p LENGTH 15 DECIMALS 2, + END OF ty_line. +TYPES tt_line TYPE STANDARD TABLE OF ty_line. + +DATA gv_show_id TYPE {{p}}visit-show_id. + +PARAMETERS p_from TYPE d OBLIGATORY. +SELECT-OPTIONS s_show FOR gv_show_id. + +CLASS lcl_report DEFINITION FINAL. + PUBLIC SECTION. + METHODS aggregate + IMPORTING it_visits TYPE tt_visit + CHANGING ct_lines TYPE tt_line. + METHODS display + CHANGING ct_lines TYPE tt_line. +ENDCLASS. + +CLASS lcl_report IMPLEMENTATION. + METHOD aggregate. + DATA: ls_visit TYPE ty_visit, + ls_line TYPE ty_line. + + LOOP AT it_visits INTO ls_visit. + READ TABLE ct_lines INTO ls_line WITH KEY show_id = ls_visit-show_id. + IF sy-subrc = 0. + ls_line-tickets = ls_line-tickets + ls_visit-tickets. + ls_line-revenue = ls_line-revenue + ls_visit-tickets * ls_visit-ticket_price. + MODIFY ct_lines FROM ls_line INDEX sy-tabix. + ELSE. + CLEAR ls_line. + ls_line-show_id = ls_visit-show_id. + ls_line-tickets = ls_visit-tickets. + ls_line-revenue = ls_visit-tickets * ls_visit-ticket_price. + APPEND ls_line TO ct_lines. + ENDIF. + ENDLOOP. + + SORT ct_lines BY revenue DESCENDING show_id ASCENDING. + ENDMETHOD. + + METHOD display. + DATA: lo_alv TYPE REF TO cl_salv_table, + lx_error TYPE REF TO cx_salv_msg. + + TRY. + cl_salv_table=>factory( + IMPORTING r_salv_table = lo_alv + CHANGING t_table = ct_lines ). + lo_alv->display( ). + CATCH cx_salv_msg INTO lx_error. + MESSAGE lx_error TYPE 'I' DISPLAY LIKE 'E'. + ENDTRY. + ENDMETHOD. +ENDCLASS. + +START-OF-SELECTION. + DATA: lt_visits TYPE tt_visit, + lt_lines TYPE tt_line, + lo_report TYPE REF TO lcl_report. + + SELECT show_id tickets ticket_price + FROM {{p}}visit + INTO TABLE lt_visits + WHERE visit_date >= p_from + OR show_id IN s_show + AND tickets > 0. + + CREATE OBJECT lo_report. + lo_report->aggregate( EXPORTING it_visits = lt_visits + CHANGING ct_lines = lt_lines ). + lo_report->display( CHANGING ct_lines = lt_lines ). + +CLASS ltc_report DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS sums_by_show FOR TESTING. + METHODS sorted_by_revenue FOR TESTING. + METHODS tie_break_by_show FOR TESTING. +ENDCLASS. + +CLASS ltc_report IMPLEMENTATION. + METHOD sums_by_show. + DATA: lt_visits TYPE tt_visit, + lt_lines TYPE tt_line, + ls_visit TYPE ty_visit, + ls_line TYPE ty_line, + lv_exp TYPE p LENGTH 15 DECIMALS 2, + lo_report TYPE REF TO lcl_report. + + CLEAR ls_visit. + ls_visit-show_id = 'A'. + ls_visit-tickets = 10. + ls_visit-ticket_price = '12.00'. + APPEND ls_visit TO lt_visits. + + CLEAR ls_visit. + ls_visit-show_id = 'A'. + ls_visit-tickets = 5. + ls_visit-ticket_price = '12.00'. + APPEND ls_visit TO lt_visits. + + CLEAR ls_visit. + ls_visit-show_id = 'B'. + ls_visit-tickets = 4. + ls_visit-ticket_price = '15.00'. + APPEND ls_visit TO lt_visits. + + CREATE OBJECT lo_report. + lo_report->aggregate( EXPORTING it_visits = lt_visits + CHANGING ct_lines = lt_lines ). + + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + + READ TABLE lt_lines INTO ls_line INDEX 1. + cl_abap_unit_assert=>assert_equals( exp = 'A' act = ls_line-show_id ). + cl_abap_unit_assert=>assert_equals( exp = 15 act = ls_line-tickets ). + lv_exp = 15 * 12. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = ls_line-revenue ). + + READ TABLE lt_lines INTO ls_line INDEX 2. + cl_abap_unit_assert=>assert_equals( exp = 'B' act = ls_line-show_id ). + cl_abap_unit_assert=>assert_equals( exp = 4 act = ls_line-tickets ). + lv_exp = 4 * 15. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = ls_line-revenue ). + ENDMETHOD. + + METHOD sorted_by_revenue. + DATA: lt_visits TYPE tt_visit, + lt_lines TYPE tt_line, + ls_visit TYPE ty_visit, + ls_line TYPE ty_line, + lo_report TYPE REF TO lcl_report. + + CLEAR ls_visit. + ls_visit-show_id = 'C'. + ls_visit-tickets = 1. + ls_visit-ticket_price = '5.00'. + APPEND ls_visit TO lt_visits. + + CLEAR ls_visit. + ls_visit-show_id = 'D'. + ls_visit-tickets = 10. + ls_visit-ticket_price = '5.00'. + APPEND ls_visit TO lt_visits. + + CREATE OBJECT lo_report. + lo_report->aggregate( EXPORTING it_visits = lt_visits + CHANGING ct_lines = lt_lines ). + + READ TABLE lt_lines INTO ls_line INDEX 1. + cl_abap_unit_assert=>assert_equals( exp = 'D' act = ls_line-show_id ). + ENDMETHOD. + + METHOD tie_break_by_show. + DATA: lt_visits TYPE tt_visit, + lt_lines TYPE tt_line, + ls_visit TYPE ty_visit, + ls_line TYPE ty_line, + lo_report TYPE REF TO lcl_report. + + CLEAR ls_visit. + ls_visit-show_id = 'Z'. + ls_visit-tickets = 2. + ls_visit-ticket_price = '5.00'. + APPEND ls_visit TO lt_visits. + + CLEAR ls_visit. + ls_visit-show_id = 'A'. + ls_visit-tickets = 2. + ls_visit-ticket_price = '5.00'. + APPEND ls_visit TO lt_visits. + + CREATE OBJECT lo_report. + lo_report->aggregate( EXPORTING it_visits = lt_visits + CHANGING ct_lines = lt_lines ). + + READ TABLE lt_lines INTO ls_line INDEX 1. + cl_abap_unit_assert=>assert_equals( exp = 'A' act = ls_line-show_id ). + READ TABLE lt_lines INTO ls_line INDEX 2. + cl_abap_unit_assert=>assert_equals( exp = 'Z' act = ls_line-show_id ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0162/faulty/m3_planetarium.prog.abap b/tasks_gen/eval/G0162/faulty/m3_planetarium.prog.abap new file mode 100644 index 0000000..6f57846 --- /dev/null +++ b/tasks_gen/eval/G0162/faulty/m3_planetarium.prog.abap @@ -0,0 +1,194 @@ +REPORT {{p}}planetarium. + +TYPES: BEGIN OF ty_visit, + show_id TYPE {{p}}visit-show_id, + tickets TYPE {{p}}visit-tickets, + ticket_price TYPE {{p}}visit-ticket_price, + END OF ty_visit. +TYPES tt_visit TYPE STANDARD TABLE OF ty_visit. + +TYPES: BEGIN OF ty_line, + show_id TYPE {{p}}visit-show_id, + tickets TYPE i, + revenue TYPE p LENGTH 15 DECIMALS 2, + END OF ty_line. +TYPES tt_line TYPE STANDARD TABLE OF ty_line. + +DATA gv_show_id TYPE {{p}}visit-show_id. + +PARAMETERS p_from TYPE d OBLIGATORY. +SELECT-OPTIONS s_show FOR gv_show_id. + +CLASS lcl_report DEFINITION FINAL. + PUBLIC SECTION. + METHODS aggregate + IMPORTING it_visits TYPE tt_visit + CHANGING ct_lines TYPE tt_line. + METHODS display + CHANGING ct_lines TYPE tt_line. +ENDCLASS. + +CLASS lcl_report IMPLEMENTATION. + METHOD aggregate. + DATA: ls_visit TYPE ty_visit, + ls_line TYPE ty_line. + + LOOP AT it_visits INTO ls_visit. + READ TABLE ct_lines INTO ls_line WITH KEY show_id = ls_visit-show_id. + IF sy-subrc = 0. + ls_line-tickets = ls_line-tickets + ls_visit-tickets. + ls_line-revenue = ls_line-revenue + ls_visit-tickets * ls_visit-ticket_price. + MODIFY ct_lines FROM ls_line INDEX sy-tabix. + ELSE. + CLEAR ls_line. + ls_line-show_id = ls_visit-show_id. + ls_line-tickets = ls_visit-tickets. + ls_line-revenue = ls_visit-tickets * ls_visit-ticket_price. + APPEND ls_line TO ct_lines. + ENDIF. + ENDLOOP. + + SORT ct_lines BY revenue DESCENDING show_id ASCENDING. + ENDMETHOD. + + METHOD display. + DATA: lo_alv TYPE REF TO cl_salv_table, + lx_error TYPE REF TO cx_salv_msg. + + TRY. + cl_salv_table=>factory( + IMPORTING r_salv_table = lo_alv + CHANGING t_table = ct_lines ). + lo_alv->display( ). + CATCH cx_salv_msg INTO lx_error. + MESSAGE lx_error TYPE 'I' DISPLAY LIKE 'E'. + ENDTRY. + ENDMETHOD. +ENDCLASS. + +START-OF-SELECTION. + DATA: lt_visits TYPE tt_visit, + lt_lines TYPE tt_line, + lo_report TYPE REF TO lcl_report. + + SELECT show_id tickets ticket_price + FROM {{p}}visit + INTO TABLE lt_visits + WHERE visit_date >= p_from + AND show_id IN s_show + OR tickets > 0. + + CREATE OBJECT lo_report. + lo_report->aggregate( EXPORTING it_visits = lt_visits + CHANGING ct_lines = lt_lines ). + lo_report->display( CHANGING ct_lines = lt_lines ). + +CLASS ltc_report DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS sums_by_show FOR TESTING. + METHODS sorted_by_revenue FOR TESTING. + METHODS tie_break_by_show FOR TESTING. +ENDCLASS. + +CLASS ltc_report IMPLEMENTATION. + METHOD sums_by_show. + DATA: lt_visits TYPE tt_visit, + lt_lines TYPE tt_line, + ls_visit TYPE ty_visit, + ls_line TYPE ty_line, + lv_exp TYPE p LENGTH 15 DECIMALS 2, + lo_report TYPE REF TO lcl_report. + + CLEAR ls_visit. + ls_visit-show_id = 'A'. + ls_visit-tickets = 10. + ls_visit-ticket_price = '12.00'. + APPEND ls_visit TO lt_visits. + + CLEAR ls_visit. + ls_visit-show_id = 'A'. + ls_visit-tickets = 5. + ls_visit-ticket_price = '12.00'. + APPEND ls_visit TO lt_visits. + + CLEAR ls_visit. + ls_visit-show_id = 'B'. + ls_visit-tickets = 4. + ls_visit-ticket_price = '15.00'. + APPEND ls_visit TO lt_visits. + + CREATE OBJECT lo_report. + lo_report->aggregate( EXPORTING it_visits = lt_visits + CHANGING ct_lines = lt_lines ). + + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + + READ TABLE lt_lines INTO ls_line INDEX 1. + cl_abap_unit_assert=>assert_equals( exp = 'A' act = ls_line-show_id ). + cl_abap_unit_assert=>assert_equals( exp = 15 act = ls_line-tickets ). + lv_exp = 15 * 12. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = ls_line-revenue ). + + READ TABLE lt_lines INTO ls_line INDEX 2. + cl_abap_unit_assert=>assert_equals( exp = 'B' act = ls_line-show_id ). + cl_abap_unit_assert=>assert_equals( exp = 4 act = ls_line-tickets ). + lv_exp = 4 * 15. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = ls_line-revenue ). + ENDMETHOD. + + METHOD sorted_by_revenue. + DATA: lt_visits TYPE tt_visit, + lt_lines TYPE tt_line, + ls_visit TYPE ty_visit, + ls_line TYPE ty_line, + lo_report TYPE REF TO lcl_report. + + CLEAR ls_visit. + ls_visit-show_id = 'C'. + ls_visit-tickets = 1. + ls_visit-ticket_price = '5.00'. + APPEND ls_visit TO lt_visits. + + CLEAR ls_visit. + ls_visit-show_id = 'D'. + ls_visit-tickets = 10. + ls_visit-ticket_price = '5.00'. + APPEND ls_visit TO lt_visits. + + CREATE OBJECT lo_report. + lo_report->aggregate( EXPORTING it_visits = lt_visits + CHANGING ct_lines = lt_lines ). + + READ TABLE lt_lines INTO ls_line INDEX 1. + cl_abap_unit_assert=>assert_equals( exp = 'D' act = ls_line-show_id ). + ENDMETHOD. + + METHOD tie_break_by_show. + DATA: lt_visits TYPE tt_visit, + lt_lines TYPE tt_line, + ls_visit TYPE ty_visit, + ls_line TYPE ty_line, + lo_report TYPE REF TO lcl_report. + + CLEAR ls_visit. + ls_visit-show_id = 'Z'. + ls_visit-tickets = 2. + ls_visit-ticket_price = '5.00'. + APPEND ls_visit TO lt_visits. + + CLEAR ls_visit. + ls_visit-show_id = 'A'. + ls_visit-tickets = 2. + ls_visit-ticket_price = '5.00'. + APPEND ls_visit TO lt_visits. + + CREATE OBJECT lo_report. + lo_report->aggregate( EXPORTING it_visits = lt_visits + CHANGING ct_lines = lt_lines ). + + READ TABLE lt_lines INTO ls_line INDEX 1. + cl_abap_unit_assert=>assert_equals( exp = 'A' act = ls_line-show_id ). + READ TABLE lt_lines INTO ls_line INDEX 2. + cl_abap_unit_assert=>assert_equals( exp = 'Z' act = ls_line-show_id ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0162/faulty/m4_planetarium.prog.abap b/tasks_gen/eval/G0162/faulty/m4_planetarium.prog.abap new file mode 100644 index 0000000..3a577d0 --- /dev/null +++ b/tasks_gen/eval/G0162/faulty/m4_planetarium.prog.abap @@ -0,0 +1,194 @@ +REPORT {{p}}planetarium. + +TYPES: BEGIN OF ty_visit, + show_id TYPE {{p}}visit-show_id, + tickets TYPE {{p}}visit-tickets, + ticket_price TYPE {{p}}visit-ticket_price, + END OF ty_visit. +TYPES tt_visit TYPE STANDARD TABLE OF ty_visit. + +TYPES: BEGIN OF ty_line, + show_id TYPE {{p}}visit-show_id, + tickets TYPE i, + revenue TYPE p LENGTH 15 DECIMALS 2, + END OF ty_line. +TYPES tt_line TYPE STANDARD TABLE OF ty_line. + +DATA gv_show_id TYPE {{p}}visit-show_id. + +PARAMETERS p_from TYPE d OBLIGATORY. +SELECT-OPTIONS s_show FOR gv_show_id. + +CLASS lcl_report DEFINITION FINAL. + PUBLIC SECTION. + METHODS aggregate + IMPORTING it_visits TYPE tt_visit + CHANGING ct_lines TYPE tt_line. + METHODS display + CHANGING ct_lines TYPE tt_line. +ENDCLASS. + +CLASS lcl_report IMPLEMENTATION. + METHOD aggregate. + DATA: ls_visit TYPE ty_visit, + ls_line TYPE ty_line. + + LOOP AT it_visits INTO ls_visit. + READ TABLE ct_lines INTO ls_line WITH KEY show_id = ls_visit-show_id. + IF sy-subrc = 0. + ls_line-tickets = ls_line-tickets + ls_visit-tickets. + ls_line-revenue = ls_line-revenue + ls_visit-tickets * ls_visit-ticket_price. + MODIFY ct_lines FROM ls_line INDEX sy-tabix. + ELSE. + CLEAR ls_line. + ls_line-show_id = ls_visit-show_id. + ls_line-tickets = ls_visit-tickets. + ls_line-revenue = ls_visit-tickets * ls_visit-ticket_price. + APPEND ls_line TO ct_lines. + ENDIF. + ENDLOOP. + + SORT ct_lines BY revenue DESCENDING show_id ASCENDING. + ENDMETHOD. + + METHOD display. + DATA: lo_alv TYPE REF TO cl_salv_table, + lx_error TYPE REF TO cx_salv_msg. + + TRY. + cl_salv_table=>factory( + IMPORTING r_salv_table = lo_alv + CHANGING t_table = ct_lines ). + lo_alv->display( ). + CATCH cx_salv_msg INTO lx_error. + MESSAGE lx_error TYPE 'I' DISPLAY LIKE 'E'. + ENDTRY. + ENDMETHOD. +ENDCLASS. + +START-OF-SELECTION. + DATA: lt_visits TYPE tt_visit, + lt_lines TYPE tt_line, + lo_report TYPE REF TO lcl_report. + + SELECT show_id tickets ticket_price + FROM {{p}}visit + INTO TABLE lt_visits + WHERE visit_date >= p_from + AND show_id IN s_show + AND tickets <= 0. + + CREATE OBJECT lo_report. + lo_report->aggregate( EXPORTING it_visits = lt_visits + CHANGING ct_lines = lt_lines ). + lo_report->display( CHANGING ct_lines = lt_lines ). + +CLASS ltc_report DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS sums_by_show FOR TESTING. + METHODS sorted_by_revenue FOR TESTING. + METHODS tie_break_by_show FOR TESTING. +ENDCLASS. + +CLASS ltc_report IMPLEMENTATION. + METHOD sums_by_show. + DATA: lt_visits TYPE tt_visit, + lt_lines TYPE tt_line, + ls_visit TYPE ty_visit, + ls_line TYPE ty_line, + lv_exp TYPE p LENGTH 15 DECIMALS 2, + lo_report TYPE REF TO lcl_report. + + CLEAR ls_visit. + ls_visit-show_id = 'A'. + ls_visit-tickets = 10. + ls_visit-ticket_price = '12.00'. + APPEND ls_visit TO lt_visits. + + CLEAR ls_visit. + ls_visit-show_id = 'A'. + ls_visit-tickets = 5. + ls_visit-ticket_price = '12.00'. + APPEND ls_visit TO lt_visits. + + CLEAR ls_visit. + ls_visit-show_id = 'B'. + ls_visit-tickets = 4. + ls_visit-ticket_price = '15.00'. + APPEND ls_visit TO lt_visits. + + CREATE OBJECT lo_report. + lo_report->aggregate( EXPORTING it_visits = lt_visits + CHANGING ct_lines = lt_lines ). + + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + + READ TABLE lt_lines INTO ls_line INDEX 1. + cl_abap_unit_assert=>assert_equals( exp = 'A' act = ls_line-show_id ). + cl_abap_unit_assert=>assert_equals( exp = 15 act = ls_line-tickets ). + lv_exp = 15 * 12. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = ls_line-revenue ). + + READ TABLE lt_lines INTO ls_line INDEX 2. + cl_abap_unit_assert=>assert_equals( exp = 'B' act = ls_line-show_id ). + cl_abap_unit_assert=>assert_equals( exp = 4 act = ls_line-tickets ). + lv_exp = 4 * 15. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = ls_line-revenue ). + ENDMETHOD. + + METHOD sorted_by_revenue. + DATA: lt_visits TYPE tt_visit, + lt_lines TYPE tt_line, + ls_visit TYPE ty_visit, + ls_line TYPE ty_line, + lo_report TYPE REF TO lcl_report. + + CLEAR ls_visit. + ls_visit-show_id = 'C'. + ls_visit-tickets = 1. + ls_visit-ticket_price = '5.00'. + APPEND ls_visit TO lt_visits. + + CLEAR ls_visit. + ls_visit-show_id = 'D'. + ls_visit-tickets = 10. + ls_visit-ticket_price = '5.00'. + APPEND ls_visit TO lt_visits. + + CREATE OBJECT lo_report. + lo_report->aggregate( EXPORTING it_visits = lt_visits + CHANGING ct_lines = lt_lines ). + + READ TABLE lt_lines INTO ls_line INDEX 1. + cl_abap_unit_assert=>assert_equals( exp = 'D' act = ls_line-show_id ). + ENDMETHOD. + + METHOD tie_break_by_show. + DATA: lt_visits TYPE tt_visit, + lt_lines TYPE tt_line, + ls_visit TYPE ty_visit, + ls_line TYPE ty_line, + lo_report TYPE REF TO lcl_report. + + CLEAR ls_visit. + ls_visit-show_id = 'Z'. + ls_visit-tickets = 2. + ls_visit-ticket_price = '5.00'. + APPEND ls_visit TO lt_visits. + + CLEAR ls_visit. + ls_visit-show_id = 'A'. + ls_visit-tickets = 2. + ls_visit-ticket_price = '5.00'. + APPEND ls_visit TO lt_visits. + + CREATE OBJECT lo_report. + lo_report->aggregate( EXPORTING it_visits = lt_visits + CHANGING ct_lines = lt_lines ). + + READ TABLE lt_lines INTO ls_line INDEX 1. + cl_abap_unit_assert=>assert_equals( exp = 'A' act = ls_line-show_id ). + READ TABLE lt_lines INTO ls_line INDEX 2. + cl_abap_unit_assert=>assert_equals( exp = 'Z' act = ls_line-show_id ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0162/generation.json b/tasks_gen/eval/G0162/generation.json new file mode 100644 index 0000000..bd72eb2 --- /dev/null +++ b/tasks_gen/eval/G0162/generation.json @@ -0,0 +1,43 @@ +{ + "id": "G0162", + "pool": "eval", + "object_type": "PROG", + "category": "G", + "attempts": [ + { + "stage": "bundle", + "errors": [ + "seed/visit_seed.clas.abap line 9: syntax error for release v702 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"INSERT\"", + "hidden/t60_hidden.clas.abap line 52: syntax error for release v702 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"ASSIGN\"", + "hidden/t60_hidden.clas.abap line 53: syntax error for release v702 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"ASSIGN\"", + "hidden/t60_hidden.clas.abap line 55: syntax error for release v702 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"rv_value\"", + "hidden/t60_hidden.clas.abap line 105: syntax error for release v702 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"DATA\"", + "hidden/t60_hidden.clas.abap line 112: syntax error for release v702 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"DATA\"" + ], + "by_check": { + "abaplint": 6 + } + }, + { + "stage": "validate", + "oracle": 0, + "null": 0 + }, + { + "stage": "validate", + "oracle": 67.5, + "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/eval/G0162/hidden/t60_hidden.clas.abap b/tasks_gen/eval/G0162/hidden/t60_hidden.clas.abap new file mode 100644 index 0000000..87f83ab --- /dev/null +++ b/tasks_gen/eval/G0162/hidden/t60_hidden.clas.abap @@ -0,0 +1,243 @@ +CLASS {{p}}t60_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + TYPES tt_show TYPE RANGE OF {{p}}visit-show_id. + METHODS run + IMPORTING iv_from TYPE d + it_show TYPE tt_show 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 canon + IMPORTING iv_text TYPE string + RETURNING VALUE(rv_canon) TYPE string. + METHODS lines_of + IMPORTING ir_data TYPE REF TO data + RETURNING VALUE(rv_lines) TYPE i. + METHODS all_shows FOR TESTING. + METHODS sorted_by_revenue FOR TESTING. + METHODS revenue_values FOR TESTING. + METHODS ticket_sums FOR TESTING. + METHODS tie_break_by_show FOR TESTING. + METHODS date_filter FOR TESTING. + METHODS date_boundary FOR TESTING. + METHODS show_filter FOR TESTING. + METHODS zero_tickets_excluded FOR TESTING. + METHODS no_data FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t60_hidden IMPLEMENTATION. + METHOD run. + cl_salv_bs_runtime_info=>set( display = abap_false metadata = abap_false data = abap_true ). + SUBMIT {{p}}planetarium WITH p_from = iv_from WITH s_show IN it_show 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. + DATA lv_lines TYPE i. + IF ir_data IS BOUND. + ASSIGN ir_data->* TO . + lv_lines = lines( ). + ENDIF. + rv_lines = lv_lines. + ENDMETHOD. + + METHOD value_of. + FIELD-SYMBOLS: TYPE STANDARD TABLE, + TYPE any, + TYPE any. + DATA: lv_index TYPE i, + lv_text TYPE string. + + ASSIGN ir_data->* TO . + lv_index = iv_row. + READ TABLE ASSIGNING INDEX lv_index. + cl_abap_unit_assert=>assert_subrc( exp = 0 msg = 'Row is missing' ). + ASSIGN COMPONENT iv_col OF STRUCTURE TO . + cl_abap_unit_assert=>assert_subrc( exp = 0 msg = 'Column is missing' ). + lv_text = . + CONDENSE lv_text. + rv_value = lv_text. + ENDMETHOD. + + METHOD canon. + DATA: lv_len TYPE i, + lv_pos TYPE i, + lv_ch TYPE c LENGTH 1, + lv_int TYPE string, + lv_frac TYPE string, + lv_after TYPE c LENGTH 1, + lv_sign TYPE string, + lv_tail TYPE i. + + lv_len = strlen( iv_text ). + DO lv_len TIMES. + lv_pos = sy-index - 1. + lv_ch = iv_text+lv_pos(1). + IF lv_ch CA '0123456789'. + IF lv_after = 'X'. + CONCATENATE lv_frac lv_ch INTO lv_frac. + ELSE. + CONCATENATE lv_int lv_ch INTO lv_int. + ENDIF. + ELSEIF lv_ch = '.' OR lv_ch = ','. + lv_after = 'X'. + ELSEIF lv_ch = '-'. + lv_sign = '-'. + ENDIF. + ENDDO. + + WHILE strlen( lv_int ) > 1 AND lv_int(1) = '0'. + lv_int = lv_int+1. + ENDWHILE. + IF lv_int IS INITIAL. + lv_int = '0'. + ENDIF. + + lv_tail = strlen( lv_frac ). + WHILE lv_tail > 0. + lv_pos = lv_tail - 1. + IF lv_frac+lv_pos(1) <> '0'. + EXIT. + ENDIF. + lv_tail = lv_tail - 1. + ENDWHILE. + lv_frac = lv_frac(lv_tail). + + CONCATENATE lv_sign lv_int '.' lv_frac INTO rv_canon. + ENDMETHOD. + + METHOD all_shows. + DATA: lr_data TYPE REF TO data, + lv_lines TYPE i. + lr_data = run( '20260101' ). + lv_lines = lines_of( lr_data ). + cl_abap_unit_assert=>assert_equals( exp = 5 act = lv_lines ). + ENDMETHOD. + + METHOD sorted_by_revenue. + DATA: lr_data TYPE REF TO data, + lv_val TYPE string. + lr_data = run( '20260101' ). + lv_val = value_of( ir_data = lr_data iv_row = 1 iv_col = 'SHOW_ID' ). + cl_abap_unit_assert=>assert_equals( exp = 'ROCK' act = lv_val ). + lv_val = value_of( ir_data = lr_data iv_row = 2 iv_col = 'SHOW_ID' ). + cl_abap_unit_assert=>assert_equals( exp = 'PLNT' act = lv_val ). + lv_val = value_of( ir_data = lr_data iv_row = 3 iv_col = 'SHOW_ID' ). + cl_abap_unit_assert=>assert_equals( exp = 'KIDS' act = lv_val ). + ENDMETHOD. + + METHOD revenue_values. + DATA: lr_data TYPE REF TO data, + lv_val TYPE string. + lr_data = run( '20260101' ). + lv_val = canon( value_of( ir_data = lr_data iv_row = 1 iv_col = 'REVENUE' ) ). + cl_abap_unit_assert=>assert_equals( exp = canon( '190.00' ) act = lv_val ). + lv_val = canon( value_of( ir_data = lr_data iv_row = 2 iv_col = 'REVENUE' ) ). + cl_abap_unit_assert=>assert_equals( exp = canon( '180.00' ) act = lv_val ). + lv_val = canon( value_of( ir_data = lr_data iv_row = 3 iv_col = 'REVENUE' ) ). + cl_abap_unit_assert=>assert_equals( exp = canon( '150.00' ) act = lv_val ). + ENDMETHOD. + + METHOD ticket_sums. + DATA: lr_data TYPE REF TO data, + lv_val TYPE string. + lr_data = run( '20260101' ). + lv_val = canon( value_of( ir_data = lr_data iv_row = 1 iv_col = 'TICKETS' ) ). + cl_abap_unit_assert=>assert_equals( exp = canon( '20' ) act = lv_val ). + lv_val = canon( value_of( ir_data = lr_data iv_row = 2 iv_col = 'TICKETS' ) ). + cl_abap_unit_assert=>assert_equals( exp = canon( '15' ) act = lv_val ). + lv_val = canon( value_of( ir_data = lr_data iv_row = 3 iv_col = 'TICKETS' ) ). + cl_abap_unit_assert=>assert_equals( exp = canon( '30' ) act = lv_val ). + ENDMETHOD. + + METHOD tie_break_by_show. + DATA: lr_data TYPE REF TO data, + lv_val TYPE string. + lr_data = run( '20260101' ). + lv_val = value_of( ir_data = lr_data iv_row = 4 iv_col = 'SHOW_ID' ). + cl_abap_unit_assert=>assert_equals( exp = 'LASR' act = lv_val ). + lv_val = value_of( ir_data = lr_data iv_row = 5 iv_col = 'SHOW_ID' ). + cl_abap_unit_assert=>assert_equals( exp = 'MAGI' act = lv_val ). + ENDMETHOD. + + METHOD date_filter. + DATA: lr_data TYPE REF TO data, + lv_lines TYPE i, + lv_val TYPE string. + lr_data = run( '20260109' ). + lv_lines = lines_of( lr_data ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lv_lines ). + lv_val = value_of( ir_data = lr_data iv_row = 1 iv_col = 'SHOW_ID' ). + cl_abap_unit_assert=>assert_equals( exp = 'KIDS' act = lv_val ). + lv_val = value_of( ir_data = lr_data iv_row = 2 iv_col = 'SHOW_ID' ). + cl_abap_unit_assert=>assert_equals( exp = 'MAGI' act = lv_val ). + ENDMETHOD. + + METHOD date_boundary. + DATA: lr_data TYPE REF TO data, + lv_lines TYPE i, + lv_val TYPE string. + lr_data = run( '20260106' ). + lv_lines = lines_of( lr_data ). + cl_abap_unit_assert=>assert_equals( exp = 5 act = lv_lines ). + lv_val = value_of( ir_data = lr_data iv_row = 1 iv_col = 'SHOW_ID' ). + cl_abap_unit_assert=>assert_equals( exp = 'ROCK' act = lv_val ). + lv_val = value_of( ir_data = lr_data iv_row = 2 iv_col = 'SHOW_ID' ). + cl_abap_unit_assert=>assert_equals( exp = 'KIDS' act = lv_val ). + lv_val = value_of( ir_data = lr_data iv_row = 5 iv_col = 'SHOW_ID' ). + cl_abap_unit_assert=>assert_equals( exp = 'PLNT' act = lv_val ). + lv_val = canon( value_of( ir_data = lr_data iv_row = 5 iv_col = 'TICKETS' ) ). + cl_abap_unit_assert=>assert_equals( exp = canon( '5' ) act = lv_val ). + ENDMETHOD. + + METHOD show_filter. + DATA: lr_data TYPE REF TO data, + lt_show TYPE tt_show, + ls_show TYPE LINE OF tt_show, + lv_lines TYPE i, + lv_val TYPE string. + ls_show-sign = 'I'. + ls_show-option = 'EQ'. + ls_show-low = 'ROCK'. + APPEND ls_show TO lt_show. + lr_data = run( iv_from = '20260101' it_show = lt_show ). + lv_lines = lines_of( lr_data ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lv_lines ). + lv_val = canon( value_of( ir_data = lr_data iv_row = 1 iv_col = 'TICKETS' ) ). + cl_abap_unit_assert=>assert_equals( exp = canon( '20' ) act = lv_val ). + lv_val = canon( value_of( ir_data = lr_data iv_row = 1 iv_col = 'REVENUE' ) ). + cl_abap_unit_assert=>assert_equals( exp = canon( '190.00' ) act = lv_val ). + ENDMETHOD. + + METHOD zero_tickets_excluded. + DATA: lr_data TYPE REF TO data, + lt_show TYPE tt_show, + ls_show TYPE LINE OF tt_show, + lv_lines TYPE i. + ls_show-sign = 'I'. + ls_show-option = 'EQ'. + ls_show-low = 'OPER'. + APPEND ls_show TO lt_show. + lr_data = run( iv_from = '20260101' it_show = lt_show ). + lv_lines = lines_of( lr_data ). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_lines ). + ENDMETHOD. + + METHOD no_data. + DATA: lr_data TYPE REF TO data, + lv_lines TYPE i. + lr_data = run( '20260201' ). + lv_lines = lines_of( lr_data ). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_lines ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0162/mutation.json b/tasks_gen/eval/G0162/mutation.json new file mode 100644 index 0000000..daae821 --- /dev/null +++ b/tasks_gen/eval/G0162/mutation.json @@ -0,0 +1,86 @@ +{ + "task": "G0162", + "mutants": [ + { + "object": "{{P}}PLANETARIUM", + "mutant": "line 40: * -> / (arith)", + "status": "killed", + "hidden": "7/10", + "failed_tests": [ + "REVENUE_VALUES", + "SORTED_BY_REVENUE", + "TICKET_SUMS" + ] + }, + { + "object": "{{P}}PLANETARIUM", + "mutant": "line 77: >= -> < (rel)", + "status": "killed", + "hidden": "1/10", + "failed_tests": [ + "ALL_SHOWS", + "DATE_BOUNDARY", + "DATE_FILTER", + "NO_DATA", + "REVENUE_VALUES", + "SHOW_FILTER", + "SORTED_BY_REVENUE", + "TICKET_SUMS", + "TIE_BREAK_BY_SHOW" + ] + }, + { + "object": "{{P}}PLANETARIUM", + "mutant": "line 78: AND -> OR (logic)", + "status": "killed", + "hidden": "2/10", + "failed_tests": [ + "ALL_SHOWS", + "DATE_BOUNDARY", + "DATE_FILTER", + "NO_DATA", + "REVENUE_VALUES", + "SHOW_FILTER", + "TICKET_SUMS", + "ZERO_TICKETS_EXCLUDED" + ] + }, + { + "object": "{{P}}PLANETARIUM", + "mutant": "line 79: AND -> OR (logic)", + "status": "killed", + "hidden": "2/10", + "failed_tests": [ + "ALL_SHOWS", + "DATE_BOUNDARY", + "DATE_FILTER", + "NO_DATA", + "REVENUE_VALUES", + "SHOW_FILTER", + "TICKET_SUMS", + "ZERO_TICKETS_EXCLUDED" + ] + }, + { + "object": "{{P}}PLANETARIUM", + "mutant": "line 79: > -> <= (rel)", + "status": "killed", + "hidden": "1/10", + "failed_tests": [ + "ALL_SHOWS", + "DATE_BOUNDARY", + "DATE_FILTER", + "REVENUE_VALUES", + "SHOW_FILTER", + "SORTED_BY_REVENUE", + "TICKET_SUMS", + "TIE_BREAK_BY_SHOW", + "ZERO_TICKETS_EXCLUDED" + ] + } + ], + "valid": 5, + "killed": 5, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0162/reference/planetarium.prog.abap b/tasks_gen/eval/G0162/reference/planetarium.prog.abap new file mode 100644 index 0000000..c727463 --- /dev/null +++ b/tasks_gen/eval/G0162/reference/planetarium.prog.abap @@ -0,0 +1,194 @@ +REPORT {{p}}planetarium. + +TYPES: BEGIN OF ty_visit, + show_id TYPE {{p}}visit-show_id, + tickets TYPE {{p}}visit-tickets, + ticket_price TYPE {{p}}visit-ticket_price, + END OF ty_visit. +TYPES tt_visit TYPE STANDARD TABLE OF ty_visit. + +TYPES: BEGIN OF ty_line, + show_id TYPE {{p}}visit-show_id, + tickets TYPE i, + revenue TYPE p LENGTH 15 DECIMALS 2, + END OF ty_line. +TYPES tt_line TYPE STANDARD TABLE OF ty_line. + +DATA gv_show_id TYPE {{p}}visit-show_id. + +PARAMETERS p_from TYPE d OBLIGATORY. +SELECT-OPTIONS s_show FOR gv_show_id. + +CLASS lcl_report DEFINITION FINAL. + PUBLIC SECTION. + METHODS aggregate + IMPORTING it_visits TYPE tt_visit + CHANGING ct_lines TYPE tt_line. + METHODS display + CHANGING ct_lines TYPE tt_line. +ENDCLASS. + +CLASS lcl_report IMPLEMENTATION. + METHOD aggregate. + DATA: ls_visit TYPE ty_visit, + ls_line TYPE ty_line. + + LOOP AT it_visits INTO ls_visit. + READ TABLE ct_lines INTO ls_line WITH KEY show_id = ls_visit-show_id. + IF sy-subrc = 0. + ls_line-tickets = ls_line-tickets + ls_visit-tickets. + ls_line-revenue = ls_line-revenue + ls_visit-tickets * ls_visit-ticket_price. + MODIFY ct_lines FROM ls_line INDEX sy-tabix. + ELSE. + CLEAR ls_line. + ls_line-show_id = ls_visit-show_id. + ls_line-tickets = ls_visit-tickets. + ls_line-revenue = ls_visit-tickets * ls_visit-ticket_price. + APPEND ls_line TO ct_lines. + ENDIF. + ENDLOOP. + + SORT ct_lines BY revenue DESCENDING show_id ASCENDING. + ENDMETHOD. + + METHOD display. + DATA: lo_alv TYPE REF TO cl_salv_table, + lx_error TYPE REF TO cx_salv_msg. + + TRY. + cl_salv_table=>factory( + IMPORTING r_salv_table = lo_alv + CHANGING t_table = ct_lines ). + lo_alv->display( ). + CATCH cx_salv_msg INTO lx_error. + MESSAGE lx_error TYPE 'I' DISPLAY LIKE 'E'. + ENDTRY. + ENDMETHOD. +ENDCLASS. + +START-OF-SELECTION. + DATA: lt_visits TYPE tt_visit, + lt_lines TYPE tt_line, + lo_report TYPE REF TO lcl_report. + + SELECT show_id tickets ticket_price + FROM {{p}}visit + INTO TABLE lt_visits + WHERE visit_date >= p_from + AND show_id IN s_show + AND tickets > 0. + + CREATE OBJECT lo_report. + lo_report->aggregate( EXPORTING it_visits = lt_visits + CHANGING ct_lines = lt_lines ). + lo_report->display( CHANGING ct_lines = lt_lines ). + +CLASS ltc_report DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS sums_by_show FOR TESTING. + METHODS sorted_by_revenue FOR TESTING. + METHODS tie_break_by_show FOR TESTING. +ENDCLASS. + +CLASS ltc_report IMPLEMENTATION. + METHOD sums_by_show. + DATA: lt_visits TYPE tt_visit, + lt_lines TYPE tt_line, + ls_visit TYPE ty_visit, + ls_line TYPE ty_line, + lv_exp TYPE p LENGTH 15 DECIMALS 2, + lo_report TYPE REF TO lcl_report. + + CLEAR ls_visit. + ls_visit-show_id = 'A'. + ls_visit-tickets = 10. + ls_visit-ticket_price = '12.00'. + APPEND ls_visit TO lt_visits. + + CLEAR ls_visit. + ls_visit-show_id = 'A'. + ls_visit-tickets = 5. + ls_visit-ticket_price = '12.00'. + APPEND ls_visit TO lt_visits. + + CLEAR ls_visit. + ls_visit-show_id = 'B'. + ls_visit-tickets = 4. + ls_visit-ticket_price = '15.00'. + APPEND ls_visit TO lt_visits. + + CREATE OBJECT lo_report. + lo_report->aggregate( EXPORTING it_visits = lt_visits + CHANGING ct_lines = lt_lines ). + + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + + READ TABLE lt_lines INTO ls_line INDEX 1. + cl_abap_unit_assert=>assert_equals( exp = 'A' act = ls_line-show_id ). + cl_abap_unit_assert=>assert_equals( exp = 15 act = ls_line-tickets ). + lv_exp = 15 * 12. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = ls_line-revenue ). + + READ TABLE lt_lines INTO ls_line INDEX 2. + cl_abap_unit_assert=>assert_equals( exp = 'B' act = ls_line-show_id ). + cl_abap_unit_assert=>assert_equals( exp = 4 act = ls_line-tickets ). + lv_exp = 4 * 15. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = ls_line-revenue ). + ENDMETHOD. + + METHOD sorted_by_revenue. + DATA: lt_visits TYPE tt_visit, + lt_lines TYPE tt_line, + ls_visit TYPE ty_visit, + ls_line TYPE ty_line, + lo_report TYPE REF TO lcl_report. + + CLEAR ls_visit. + ls_visit-show_id = 'C'. + ls_visit-tickets = 1. + ls_visit-ticket_price = '5.00'. + APPEND ls_visit TO lt_visits. + + CLEAR ls_visit. + ls_visit-show_id = 'D'. + ls_visit-tickets = 10. + ls_visit-ticket_price = '5.00'. + APPEND ls_visit TO lt_visits. + + CREATE OBJECT lo_report. + lo_report->aggregate( EXPORTING it_visits = lt_visits + CHANGING ct_lines = lt_lines ). + + READ TABLE lt_lines INTO ls_line INDEX 1. + cl_abap_unit_assert=>assert_equals( exp = 'D' act = ls_line-show_id ). + ENDMETHOD. + + METHOD tie_break_by_show. + DATA: lt_visits TYPE tt_visit, + lt_lines TYPE tt_line, + ls_visit TYPE ty_visit, + ls_line TYPE ty_line, + lo_report TYPE REF TO lcl_report. + + CLEAR ls_visit. + ls_visit-show_id = 'Z'. + ls_visit-tickets = 2. + ls_visit-ticket_price = '5.00'. + APPEND ls_visit TO lt_visits. + + CLEAR ls_visit. + ls_visit-show_id = 'A'. + ls_visit-tickets = 2. + ls_visit-ticket_price = '5.00'. + APPEND ls_visit TO lt_visits. + + CREATE OBJECT lo_report. + lo_report->aggregate( EXPORTING it_visits = lt_visits + CHANGING ct_lines = lt_lines ). + + READ TABLE lt_lines INTO ls_line INDEX 1. + cl_abap_unit_assert=>assert_equals( exp = 'A' act = ls_line-show_id ). + READ TABLE lt_lines INTO ls_line INDEX 2. + cl_abap_unit_assert=>assert_equals( exp = 'Z' act = ls_line-show_id ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0162/seed/visit.tabl.asabap b/tasks_gen/eval/G0162/seed/visit.tabl.asabap new file mode 100644 index 0000000..d93a745 --- /dev/null +++ b/tasks_gen/eval/G0162/seed/visit.tabl.asabap @@ -0,0 +1,13 @@ +@EndUserText.label : 'Planetarium visits' +@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.int4 not null; + show_id : abap.char(4); + visit_date : abap.dats; + tickets : abap.int4; + ticket_price : abap.dec(7,2); +} diff --git a/tasks_gen/eval/G0162/seed/visit_seed.clas.abap b/tasks_gen/eval/G0162/seed/visit_seed.clas.abap new file mode 100644 index 0000000..a2f8cdf --- /dev/null +++ b/tasks_gen/eval/G0162/seed/visit_seed.clas.abap @@ -0,0 +1,89 @@ +CLASS {{p}}visit_seed DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES if_oo_adt_classrun. +ENDCLASS. + +CLASS {{p}}visit_seed IMPLEMENTATION. + METHOD if_oo_adt_classrun~main. + DATA: lt_visit TYPE STANDARD TABLE OF {{p}}visit, + ls_visit TYPE {{p}}visit. + + DELETE FROM {{p}}visit. + + CLEAR ls_visit. + ls_visit-visit_id = 1. + ls_visit-show_id = 'PLNT'. + ls_visit-visit_date = '20260105'. + ls_visit-tickets = 10. + ls_visit-ticket_price = '12.00'. + APPEND ls_visit TO lt_visit. + + CLEAR ls_visit. + ls_visit-visit_id = 2. + ls_visit-show_id = 'PLNT'. + ls_visit-visit_date = '20260106'. + ls_visit-tickets = 5. + ls_visit-ticket_price = '12.00'. + APPEND ls_visit TO lt_visit. + + CLEAR ls_visit. + ls_visit-visit_id = 3. + ls_visit-show_id = 'ROCK'. + ls_visit-visit_date = '20260106'. + ls_visit-tickets = 20. + ls_visit-ticket_price = '9.50'. + APPEND ls_visit TO lt_visit. + + CLEAR ls_visit. + ls_visit-visit_id = 4. + ls_visit-show_id = 'ROCK'. + ls_visit-visit_date = '20251220'. + ls_visit-tickets = 8. + ls_visit-ticket_price = '9.50'. + APPEND ls_visit TO lt_visit. + + CLEAR ls_visit. + ls_visit-visit_id = 5. + ls_visit-show_id = 'LASR'. + ls_visit-visit_date = '20260107'. + ls_visit-tickets = 0. + ls_visit-ticket_price = '15.00'. + APPEND ls_visit TO lt_visit. + + CLEAR ls_visit. + ls_visit-visit_id = 6. + ls_visit-show_id = 'LASR'. + ls_visit-visit_date = '20260108'. + ls_visit-tickets = 4. + ls_visit-ticket_price = '15.00'. + APPEND ls_visit TO lt_visit. + + CLEAR ls_visit. + ls_visit-visit_id = 7. + ls_visit-show_id = 'KIDS'. + ls_visit-visit_date = '20260109'. + ls_visit-tickets = 30. + ls_visit-ticket_price = '5.00'. + APPEND ls_visit TO lt_visit. + + CLEAR ls_visit. + ls_visit-visit_id = 8. + ls_visit-show_id = 'OPER'. + ls_visit-visit_date = '20260110'. + ls_visit-tickets = 0. + ls_visit-ticket_price = '20.00'. + APPEND ls_visit TO lt_visit. + + CLEAR ls_visit. + ls_visit-visit_id = 9. + ls_visit-show_id = 'MAGI'. + ls_visit-visit_date = '20260111'. + ls_visit-tickets = 4. + ls_visit-ticket_price = '15.00'. + APPEND ls_visit TO lt_visit. + + INSERT {{p}}visit FROM TABLE lt_visit. + + out->write( sy-dbcnt ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0162/spec.md b/tasks_gen/eval/G0162/spec.md new file mode 100644 index 0000000..e1f655b --- /dev/null +++ b/tasks_gen/eval/G0162/spec.md @@ -0,0 +1,48 @@ +# 1. Goal +Show the ticket sales of each planetarium show in an ALV list. The operations +team uses the list to compare the shows of a period. + +# 2. Open questions +None. + +# 3. Context +- The table {{P}}VISIT exists in package $TMP. The table contains data. + The fields are: + - VISIT_ID (INT4, key): the number of the visit. + - SHOW_ID (CHAR 4): the show. Every show ID has exactly 4 characters. + - VISIT_DATE (DATS): the date of the visit. + - TICKETS (INT4): the number of tickets that were sold. + - TICKET_PRICE (DEC 7,2): the price of one ticket. + +# 4. Contract +- Create the executable program {{P}}PLANETARIUM in package $TMP. +- The selection screen has these fields: + - The parameter P_FROM. Type DATS. Mandatory. It is the first visit date to + include. + - The select-option S_SHOW for the show ID. +- Show the result with CL_SALV_TABLE. The output table has these columns: + - SHOW_ID. Type CHAR 4. The show. + - TICKETS. Type INT4. The sum of the tickets of the show. + - REVENUE. Type DEC with length 15 and 2 decimal places. The sum of the + revenue of the show. + +# 5. Business rules +1. Include a visit only if VISIT_DATE is on or after P_FROM. +2. Include a visit only if SHOW_ID is in S_SHOW. +3. Include a visit only if TICKETS is greater than zero. +4. The revenue of a visit is TICKETS multiplied by TICKET_PRICE. +5. Show one line for each show that has at least one included visit. +6. Sort the lines by REVENUE. The highest revenue comes first. +7. If two shows have the same revenue, sort these two shows by SHOW_ID in + ascending order. + +# 6. Constraints +- Release target: 7.02. The program must compile on release 7.02. Do not use + syntax that is newer than release 7.02. +- Coding standards: Clean ABAP. A method has fewer than 40 statements. +- Out of scope: do not change the table {{P}}VISIT. + +# 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/eval/G0162/task.json b/tasks_gen/eval/G0162/task.json new file mode 100644 index 0000000..37a6e14 --- /dev/null +++ b/tasks_gen/eval/G0162/task.json @@ -0,0 +1,60 @@ +{ + "id": "G0162", + "category": "G", + "object_type": "PROG", + "difficulty": 2, + "release_target": "v702", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 40, + "max_activations": 10 + }, + "seed": [ + { + "type": "TABL", + "name": "{{P}}VISIT", + "file": "seed/visit.tabl.asabap", + "description": "Planetarium visits" + }, + { + "type": "CLAS", + "name": "{{P}}VISIT_SEED", + "file": "seed/visit_seed.clas.abap", + "description": "T60 seed data", + "run": true + } + ], + "contract": [ + { + "type": "PROG", + "name": "{{P}}PLANETARIUM", + "parameters": [ + "p_from", + "s_show" + ] + } + ], + "out_of_scope": [ + "{{P}}VISIT" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T60_HIDDEN", + "file": "hidden/t60_hidden.clas.abap", + "description": "T60 hidden tests" + } + ], + "reference": [ + { + "type": "PROG", + "name": "{{P}}PLANETARIUM", + "file": "reference/planetarium.prog.abap", + "description": "Ticket sales per show" + } + ], + "craft_checks": [ + "no_newer_syntax", + "method_length" + ] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0163/faulty/m0_overdraft_calc.clas.abap b/tasks_gen/eval/G0163/faulty/m0_overdraft_calc.clas.abap new file mode 100644 index 0000000..1b0096d --- /dev/null +++ b/tasks_gen/eval/G0163/faulty/m0_overdraft_calc.clas.abap @@ -0,0 +1,85 @@ +CLASS {{p}}overdraft_calc DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_overdraft. + + PRIVATE SECTION. + CONSTANTS: + c_free_days TYPE i VALUE 3, + c_percent_divisor TYPE i VALUE 100, + c_days_per_year TYPE i VALUE 360, + c_business_discount TYPE p LENGTH 3 DECIMALS 2 VALUE '2.00', + c_min_rate TYPE p LENGTH 3 DECIMALS 2 VALUE '5.00'. + + TYPES: + ty_rate TYPE p LENGTH 5 DECIMALS 2, + ty_interest TYPE p LENGTH 15 DECIMALS 6. + + METHODS chargeable_days + IMPORTING iv_days TYPE i + RETURNING VALUE(rv_days) TYPE i. + + METHODS base_rate + IMPORTING iv_amount TYPE {{p}}if_overdraft=>ty_amount + RETURNING VALUE(rv_rate) TYPE ty_rate. + + METHODS interest_rate + IMPORTING iv_amount TYPE {{p}}if_overdraft=>ty_amount + iv_segment TYPE {{p}}if_overdraft=>ty_segment + RETURNING VALUE(rv_rate) TYPE ty_rate. +ENDCLASS. + + +CLASS {{p}}overdraft_calc IMPLEMENTATION. + METHOD {{p}}if_overdraft~calculate. + DATA: + lv_days TYPE i, + lv_rate TYPE ty_rate, + lv_annual TYPE ty_interest. + + IF iv_amount <= 0 AND iv_days <= 0. + rv_interest = 0. + RETURN. + ENDIF. + + lv_days = chargeable_days( iv_days ). + lv_rate = interest_rate( iv_amount = iv_amount + iv_segment = iv_segment ). + + lv_annual = iv_amount * lv_rate / c_percent_divisor. + rv_interest = lv_annual * lv_days / c_days_per_year. + + IF rv_interest > 0 AND rv_interest < {{p}}if_overdraft=>c_min_interest. + rv_interest = {{p}}if_overdraft=>c_min_interest. + ENDIF. + ENDMETHOD. + + METHOD chargeable_days. + rv_days = iv_days - c_free_days. + IF rv_days < 0. + rv_days = 0. + ENDIF. + ENDMETHOD. + + METHOD base_rate. + IF iv_amount <= 1000. + rv_rate = '12.00'. + ELSEIF iv_amount <= 5000. + rv_rate = '10.00'. + ELSEIF iv_amount <= 20000. + rv_rate = '8.00'. + ELSE. + rv_rate = '6.50'. + ENDIF. + ENDMETHOD. + + METHOD interest_rate. + rv_rate = base_rate( iv_amount ). + + IF iv_segment = {{p}}if_overdraft=>c_segment_business. + rv_rate = rv_rate - c_business_discount. + IF rv_rate < c_min_rate. + rv_rate = c_min_rate. + ENDIF. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0163/faulty/m1_overdraft_calc.clas.abap b/tasks_gen/eval/G0163/faulty/m1_overdraft_calc.clas.abap new file mode 100644 index 0000000..49b1eaf --- /dev/null +++ b/tasks_gen/eval/G0163/faulty/m1_overdraft_calc.clas.abap @@ -0,0 +1,85 @@ +CLASS {{p}}overdraft_calc DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_overdraft. + + PRIVATE SECTION. + CONSTANTS: + c_free_days TYPE i VALUE 3, + c_percent_divisor TYPE i VALUE 100, + c_days_per_year TYPE i VALUE 360, + c_business_discount TYPE p LENGTH 3 DECIMALS 2 VALUE '2.00', + c_min_rate TYPE p LENGTH 3 DECIMALS 2 VALUE '5.00'. + + TYPES: + ty_rate TYPE p LENGTH 5 DECIMALS 2, + ty_interest TYPE p LENGTH 15 DECIMALS 6. + + METHODS chargeable_days + IMPORTING iv_days TYPE i + RETURNING VALUE(rv_days) TYPE i. + + METHODS base_rate + IMPORTING iv_amount TYPE {{p}}if_overdraft=>ty_amount + RETURNING VALUE(rv_rate) TYPE ty_rate. + + METHODS interest_rate + IMPORTING iv_amount TYPE {{p}}if_overdraft=>ty_amount + iv_segment TYPE {{p}}if_overdraft=>ty_segment + RETURNING VALUE(rv_rate) TYPE ty_rate. +ENDCLASS. + + +CLASS {{p}}overdraft_calc IMPLEMENTATION. + METHOD {{p}}if_overdraft~calculate. + DATA: + lv_days TYPE i, + lv_rate TYPE ty_rate, + lv_annual TYPE ty_interest. + + IF iv_amount <= 0 OR iv_days <= 0. + rv_interest = 0. + RETURN. + ENDIF. + + lv_days = chargeable_days( iv_days ). + lv_rate = interest_rate( iv_amount = iv_amount + iv_segment = iv_segment ). + + lv_annual = iv_amount / lv_rate / c_percent_divisor. + rv_interest = lv_annual * lv_days / c_days_per_year. + + IF rv_interest > 0 AND rv_interest < {{p}}if_overdraft=>c_min_interest. + rv_interest = {{p}}if_overdraft=>c_min_interest. + ENDIF. + ENDMETHOD. + + METHOD chargeable_days. + rv_days = iv_days - c_free_days. + IF rv_days < 0. + rv_days = 0. + ENDIF. + ENDMETHOD. + + METHOD base_rate. + IF iv_amount <= 1000. + rv_rate = '12.00'. + ELSEIF iv_amount <= 5000. + rv_rate = '10.00'. + ELSEIF iv_amount <= 20000. + rv_rate = '8.00'. + ELSE. + rv_rate = '6.50'. + ENDIF. + ENDMETHOD. + + METHOD interest_rate. + rv_rate = base_rate( iv_amount ). + + IF iv_segment = {{p}}if_overdraft=>c_segment_business. + rv_rate = rv_rate - c_business_discount. + IF rv_rate < c_min_rate. + rv_rate = c_min_rate. + ENDIF. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0163/faulty/m2_overdraft_calc.clas.abap b/tasks_gen/eval/G0163/faulty/m2_overdraft_calc.clas.abap new file mode 100644 index 0000000..f950ef8 --- /dev/null +++ b/tasks_gen/eval/G0163/faulty/m2_overdraft_calc.clas.abap @@ -0,0 +1,85 @@ +CLASS {{p}}overdraft_calc DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_overdraft. + + PRIVATE SECTION. + CONSTANTS: + c_free_days TYPE i VALUE 3, + c_percent_divisor TYPE i VALUE 100, + c_days_per_year TYPE i VALUE 360, + c_business_discount TYPE p LENGTH 3 DECIMALS 2 VALUE '2.00', + c_min_rate TYPE p LENGTH 3 DECIMALS 2 VALUE '5.00'. + + TYPES: + ty_rate TYPE p LENGTH 5 DECIMALS 2, + ty_interest TYPE p LENGTH 15 DECIMALS 6. + + METHODS chargeable_days + IMPORTING iv_days TYPE i + RETURNING VALUE(rv_days) TYPE i. + + METHODS base_rate + IMPORTING iv_amount TYPE {{p}}if_overdraft=>ty_amount + RETURNING VALUE(rv_rate) TYPE ty_rate. + + METHODS interest_rate + IMPORTING iv_amount TYPE {{p}}if_overdraft=>ty_amount + iv_segment TYPE {{p}}if_overdraft=>ty_segment + RETURNING VALUE(rv_rate) TYPE ty_rate. +ENDCLASS. + + +CLASS {{p}}overdraft_calc IMPLEMENTATION. + METHOD {{p}}if_overdraft~calculate. + DATA: + lv_days TYPE i, + lv_rate TYPE ty_rate, + lv_annual TYPE ty_interest. + + IF iv_amount <= 0 OR iv_days <= 0. + rv_interest = 0. + RETURN. + ENDIF. + + lv_days = chargeable_days( iv_days ). + lv_rate = interest_rate( iv_amount = iv_amount + iv_segment = iv_segment ). + + lv_annual = iv_amount * lv_rate / c_percent_divisor. + rv_interest = lv_annual * lv_days / c_days_per_year. + + IF rv_interest > 0 AND rv_interest < {{p}}if_overdraft=>c_min_interest. + rv_interest = {{p}}if_overdraft=>c_min_interest. + ENDIF. + ENDMETHOD. + + METHOD chargeable_days. + rv_days = iv_days - c_free_days. + IF rv_days < 0. + rv_days = 0. + ENDIF. + ENDMETHOD. + + METHOD base_rate. + IF iv_amount <= 1000. + rv_rate = '12.00'. + ELSEIF iv_amount > 5000. + rv_rate = '10.00'. + ELSEIF iv_amount <= 20000. + rv_rate = '8.00'. + ELSE. + rv_rate = '6.50'. + ENDIF. + ENDMETHOD. + + METHOD interest_rate. + rv_rate = base_rate( iv_amount ). + + IF iv_segment = {{p}}if_overdraft=>c_segment_business. + rv_rate = rv_rate - c_business_discount. + IF rv_rate < c_min_rate. + rv_rate = c_min_rate. + ENDIF. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0163/faulty/m3_overdraft_calc.clas.abap b/tasks_gen/eval/G0163/faulty/m3_overdraft_calc.clas.abap new file mode 100644 index 0000000..0f5b225 --- /dev/null +++ b/tasks_gen/eval/G0163/faulty/m3_overdraft_calc.clas.abap @@ -0,0 +1,85 @@ +CLASS {{p}}overdraft_calc DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_overdraft. + + PRIVATE SECTION. + CONSTANTS: + c_free_days TYPE i VALUE 3, + c_percent_divisor TYPE i VALUE 100, + c_days_per_year TYPE i VALUE 360, + c_business_discount TYPE p LENGTH 3 DECIMALS 2 VALUE '2.00', + c_min_rate TYPE p LENGTH 3 DECIMALS 2 VALUE '5.00'. + + TYPES: + ty_rate TYPE p LENGTH 5 DECIMALS 2, + ty_interest TYPE p LENGTH 15 DECIMALS 6. + + METHODS chargeable_days + IMPORTING iv_days TYPE i + RETURNING VALUE(rv_days) TYPE i. + + METHODS base_rate + IMPORTING iv_amount TYPE {{p}}if_overdraft=>ty_amount + RETURNING VALUE(rv_rate) TYPE ty_rate. + + METHODS interest_rate + IMPORTING iv_amount TYPE {{p}}if_overdraft=>ty_amount + iv_segment TYPE {{p}}if_overdraft=>ty_segment + RETURNING VALUE(rv_rate) TYPE ty_rate. +ENDCLASS. + + +CLASS {{p}}overdraft_calc IMPLEMENTATION. + METHOD {{p}}if_overdraft~calculate. + DATA: + lv_days TYPE i, + lv_rate TYPE ty_rate, + lv_annual TYPE ty_interest. + + IF iv_amount <= 0 OR iv_days <= 0. + rv_interest = 0. + RETURN. + ENDIF. + + lv_days = chargeable_days( iv_days ). + lv_rate = interest_rate( iv_amount = iv_amount + iv_segment = iv_segment ). + + lv_annual = iv_amount * lv_rate / c_percent_divisor. + rv_interest = lv_annual * lv_days / c_days_per_year. + + IF rv_interest > 0 AND rv_interest < {{p}}if_overdraft=>c_min_interest. + rv_interest = {{p}}if_overdraft=>c_min_interest. + ENDIF. + ENDMETHOD. + + METHOD chargeable_days. + rv_days = iv_days - c_free_days. + IF rv_days < 0. + rv_days = 0. + ENDIF. + ENDMETHOD. + + METHOD base_rate. + IF iv_amount <= 1000. + rv_rate = '12.00'. + ELSEIF iv_amount <= 5000. + rv_rate = '10.00'. + ELSEIF iv_amount <= 20000. + rv_rate = '8.00'. + ELSE. + rv_rate = '6.50'. + ENDIF. + ENDMETHOD. + + METHOD interest_rate. + rv_rate = base_rate( iv_amount ). + + IF iv_segment <> {{p}}if_overdraft=>c_segment_business. + rv_rate = rv_rate - c_business_discount. + IF rv_rate < c_min_rate. + rv_rate = c_min_rate. + ENDIF. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0163/faulty/m4_overdraft_calc.clas.abap b/tasks_gen/eval/G0163/faulty/m4_overdraft_calc.clas.abap new file mode 100644 index 0000000..7624421 --- /dev/null +++ b/tasks_gen/eval/G0163/faulty/m4_overdraft_calc.clas.abap @@ -0,0 +1,85 @@ +CLASS {{p}}overdraft_calc DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_overdraft. + + PRIVATE SECTION. + CONSTANTS: + c_free_days TYPE i VALUE 3, + c_percent_divisor TYPE i VALUE 100, + c_days_per_year TYPE i VALUE 360, + c_business_discount TYPE p LENGTH 3 DECIMALS 2 VALUE '2.00', + c_min_rate TYPE p LENGTH 3 DECIMALS 2 VALUE '5.00'. + + TYPES: + ty_rate TYPE p LENGTH 5 DECIMALS 2, + ty_interest TYPE p LENGTH 15 DECIMALS 6. + + METHODS chargeable_days + IMPORTING iv_days TYPE i + RETURNING VALUE(rv_days) TYPE i. + + METHODS base_rate + IMPORTING iv_amount TYPE {{p}}if_overdraft=>ty_amount + RETURNING VALUE(rv_rate) TYPE ty_rate. + + METHODS interest_rate + IMPORTING iv_amount TYPE {{p}}if_overdraft=>ty_amount + iv_segment TYPE {{p}}if_overdraft=>ty_segment + RETURNING VALUE(rv_rate) TYPE ty_rate. +ENDCLASS. + + +CLASS {{p}}overdraft_calc IMPLEMENTATION. + METHOD {{p}}if_overdraft~calculate. + DATA: + lv_days TYPE i, + lv_rate TYPE ty_rate, + lv_annual TYPE ty_interest. + + IF iv_amount <= 0 OR iv_days <= 0. + rv_interest = 0. + RETURN. + ENDIF. + + lv_days = chargeable_days( iv_days ). + lv_rate = interest_rate( iv_amount = iv_amount + iv_segment = iv_segment ). + + lv_annual = iv_amount * lv_rate / c_percent_divisor. + rv_interest = lv_annual * lv_days / c_days_per_year. + + IF rv_interest > 0 AND rv_interest < {{p}}if_overdraft=>c_min_interest. + rv_interest = {{p}}if_overdraft=>c_min_interest. + ENDIF. + ENDMETHOD. + + METHOD chargeable_days. + rv_days = iv_days - c_free_days. + IF rv_days < 0. + rv_days = 0. + ENDIF. + ENDMETHOD. + + METHOD base_rate. + IF iv_amount <= 1000. + rv_rate = '12.00'. + ELSEIF iv_amount <= 5000. + rv_rate = '10.00'. + ELSEIF iv_amount <= 20000. + rv_rate = '8.00'. + ELSE. + rv_rate = '6.50'. + ENDIF. + ENDMETHOD. + + METHOD interest_rate. + rv_rate = base_rate( iv_amount ). + + IF iv_segment = {{p}}if_overdraft=>c_segment_business. + rv_rate = rv_rate + c_business_discount. + IF rv_rate < c_min_rate. + rv_rate = c_min_rate. + ENDIF. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0163/generation.json b/tasks_gen/eval/G0163/generation.json new file mode 100644 index 0000000..b3a20ca --- /dev/null +++ b/tasks_gen/eval/G0163/generation.json @@ -0,0 +1,33 @@ +{ + "id": "G0163", + "pool": "eval", + "object_type": "CLAS", + "category": "G", + "attempts": [ + { + "stage": "bundle", + "errors": [ + "hidden/overdraft_test.clas.abap line 23: syntax error for release v702 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"mo_cut\"" + ], + "by_check": { + "abaplint": 1 + } + }, + { + "stage": "validate", + "oracle": 95.5, + "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/eval/G0163/hidden/overdraft_test.clas.abap b/tasks_gen/eval/G0163/hidden/overdraft_test.clas.abap new file mode 100644 index 0000000..fd791bc --- /dev/null +++ b/tasks_gen/eval/G0163/hidden/overdraft_test.clas.abap @@ -0,0 +1,220 @@ +CLASS {{p}}overdraft_test DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + CONSTANTS c_zero TYPE {{p}}if_overdraft=>ty_amount VALUE '0.00'. + DATA mo_cut TYPE REF TO {{p}}if_overdraft. + METHODS setup. + METHODS non_positive_amount FOR TESTING. + METHODS zero_days FOR TESTING. + METHODS grace_days_free FOR TESTING. + METHODS tier_one_rate FOR TESTING. + METHODS tier_two_boundary FOR TESTING. + METHODS tier_three_boundary FOR TESTING. + METHODS tier_four_boundary FOR TESTING. + METHODS business_discount FOR TESTING. + METHODS business_rate_floor FOR TESTING. + METHODS minimum_interest FOR TESTING. + METHODS rounding_half_up FOR TESTING. +ENDCLASS. + + +CLASS {{p}}overdraft_test IMPLEMENTATION. + METHOD setup. + CREATE OBJECT mo_cut TYPE {{p}}overdraft_calc. + ENDMETHOD. + + METHOD non_positive_amount. + DATA lv_act TYPE {{p}}if_overdraft=>ty_amount. + + CALL METHOD mo_cut->calculate + EXPORTING + iv_amount = '0.00' + iv_days = 30 + iv_segment = {{p}}if_overdraft=>c_segment_private + RECEIVING + rv_interest = lv_act. + cl_abap_unit_assert=>assert_equals( exp = c_zero act = lv_act + msg = 'zero amount' ). + + CALL METHOD mo_cut->calculate + EXPORTING + iv_amount = '-250.00' + iv_days = 30 + iv_segment = {{p}}if_overdraft=>c_segment_private + RECEIVING + rv_interest = lv_act. + cl_abap_unit_assert=>assert_equals( exp = c_zero act = lv_act + msg = 'negative amount' ). + ENDMETHOD. + + METHOD zero_days. + DATA lv_act TYPE {{p}}if_overdraft=>ty_amount. + + CALL METHOD mo_cut->calculate + EXPORTING + iv_amount = '1000.00' + iv_days = 0 + iv_segment = {{p}}if_overdraft=>c_segment_private + RECEIVING + rv_interest = lv_act. + cl_abap_unit_assert=>assert_equals( exp = c_zero act = lv_act ). + ENDMETHOD. + + METHOD grace_days_free. + DATA lv_act TYPE {{p}}if_overdraft=>ty_amount. + + CALL METHOD mo_cut->calculate + EXPORTING + iv_amount = '30000.00' + iv_days = 3 + iv_segment = {{p}}if_overdraft=>c_segment_private + RECEIVING + rv_interest = lv_act. + cl_abap_unit_assert=>assert_equals( exp = c_zero act = lv_act ). + ENDMETHOD. + + METHOD tier_one_rate. + DATA lv_act TYPE {{p}}if_overdraft=>ty_amount. + DATA lv_exp TYPE {{p}}if_overdraft=>ty_amount. + + lv_exp = '120.00'. + CALL METHOD mo_cut->calculate + EXPORTING + iv_amount = '1000.00' + iv_days = 363 + iv_segment = {{p}}if_overdraft=>c_segment_private + RECEIVING + rv_interest = lv_act. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_act ). + ENDMETHOD. + + METHOD tier_two_boundary. + DATA lv_act TYPE {{p}}if_overdraft=>ty_amount. + DATA lv_exp TYPE {{p}}if_overdraft=>ty_amount. + + lv_exp = '100.00'. + CALL METHOD mo_cut->calculate + EXPORTING + iv_amount = '1000.01' + iv_days = 363 + iv_segment = {{p}}if_overdraft=>c_segment_private + RECEIVING + rv_interest = lv_act. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_act + msg = 'amount above 1000' ). + ENDMETHOD. + + METHOD tier_three_boundary. + DATA lv_act TYPE {{p}}if_overdraft=>ty_amount. + DATA lv_exp TYPE {{p}}if_overdraft=>ty_amount. + + lv_exp = '400.00'. + CALL METHOD mo_cut->calculate + EXPORTING + iv_amount = '5000.01' + iv_days = 363 + iv_segment = {{p}}if_overdraft=>c_segment_private + RECEIVING + rv_interest = lv_act. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_act + msg = 'amount above 5000' ). + + lv_exp = '1600.00'. + CALL METHOD mo_cut->calculate + EXPORTING + iv_amount = '20000.00' + iv_days = 363 + iv_segment = {{p}}if_overdraft=>c_segment_private + RECEIVING + rv_interest = lv_act. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_act + msg = 'amount 20000' ). + ENDMETHOD. + + METHOD tier_four_boundary. + DATA lv_act TYPE {{p}}if_overdraft=>ty_amount. + DATA lv_exp TYPE {{p}}if_overdraft=>ty_amount. + + lv_exp = '1300.00'. + CALL METHOD mo_cut->calculate + EXPORTING + iv_amount = '20000.01' + iv_days = 363 + iv_segment = {{p}}if_overdraft=>c_segment_private + RECEIVING + rv_interest = lv_act. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_act ). + ENDMETHOD. + + METHOD business_discount. + DATA lv_act TYPE {{p}}if_overdraft=>ty_amount. + DATA lv_exp TYPE {{p}}if_overdraft=>ty_amount. + + lv_exp = '13.33'. + CALL METHOD mo_cut->calculate + EXPORTING + iv_amount = '2000.00' + iv_days = 33 + iv_segment = {{p}}if_overdraft=>c_segment_business + RECEIVING + rv_interest = lv_act. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_act ). + ENDMETHOD. + + METHOD business_rate_floor. + DATA lv_act TYPE {{p}}if_overdraft=>ty_amount. + DATA lv_exp TYPE {{p}}if_overdraft=>ty_amount. + + lv_exp = '1500.00'. + CALL METHOD mo_cut->calculate + EXPORTING + iv_amount = '30000.00' + iv_days = 363 + iv_segment = {{p}}if_overdraft=>c_segment_business + RECEIVING + rv_interest = lv_act. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_act ). + ENDMETHOD. + + METHOD minimum_interest. + DATA lv_act TYPE {{p}}if_overdraft=>ty_amount. + DATA lv_exp TYPE {{p}}if_overdraft=>ty_amount. + + lv_exp = '5.00'. + CALL METHOD mo_cut->calculate + EXPORTING + iv_amount = '500.00' + iv_days = 10 + iv_segment = {{p}}if_overdraft=>c_segment_private + RECEIVING + rv_interest = lv_act. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_act ). + ENDMETHOD. + + METHOD rounding_half_up. + DATA lv_act TYPE {{p}}if_overdraft=>ty_amount. + DATA lv_exp TYPE {{p}}if_overdraft=>ty_amount. + + lv_exp = '5.01'. + CALL METHOD mo_cut->calculate + EXPORTING + iv_amount = '715.00' + iv_days = 24 + iv_segment = {{p}}if_overdraft=>c_segment_private + RECEIVING + rv_interest = lv_act. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_act + msg = 'exact half cent' ). + + lv_exp = '67.56'. + CALL METHOD mo_cut->calculate + EXPORTING + iv_amount = '1234.56' + iv_days = 200 + iv_segment = {{p}}if_overdraft=>c_segment_private + RECEIVING + rv_interest = lv_act. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_act + msg = 'round up' ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0163/mutation.json b/tasks_gen/eval/G0163/mutation.json new file mode 100644 index 0000000..471d0c5 --- /dev/null +++ b/tasks_gen/eval/G0163/mutation.json @@ -0,0 +1,72 @@ +{ + "task": "G0163", + "mutants": [ + { + "object": "{{P}}OVERDRAFT_CALC", + "mutant": "line 39: OR -> AND (logic)", + "status": "killed", + "hidden": "10/11", + "failed_tests": [ + "NON_POSITIVE_AMOUNT" + ] + }, + { + "object": "{{P}}OVERDRAFT_CALC", + "mutant": "line 48: * -> / (arith)", + "status": "killed", + "hidden": "4/11", + "failed_tests": [ + "BUSINESS_DISCOUNT", + "BUSINESS_RATE_FLOOR", + "ROUNDING_HALF_UP", + "TIER_FOUR_BOUNDARY", + "TIER_ONE_RATE", + "TIER_THREE_BOUNDARY", + "TIER_TWO_BOUNDARY" + ] + }, + { + "object": "{{P}}OVERDRAFT_CALC", + "mutant": "line 66: <= -> > (rel)", + "status": "killed", + "hidden": "5/11", + "failed_tests": [ + "BUSINESS_DISCOUNT", + "BUSINESS_RATE_FLOOR", + "ROUNDING_HALF_UP", + "TIER_FOUR_BOUNDARY", + "TIER_THREE_BOUNDARY", + "TIER_TWO_BOUNDARY" + ] + }, + { + "object": "{{P}}OVERDRAFT_CALC", + "mutant": "line 78: = -> <> (eq)", + "status": "killed", + "hidden": "4/11", + "failed_tests": [ + "BUSINESS_DISCOUNT", + "BUSINESS_RATE_FLOOR", + "ROUNDING_HALF_UP", + "TIER_FOUR_BOUNDARY", + "TIER_ONE_RATE", + "TIER_THREE_BOUNDARY", + "TIER_TWO_BOUNDARY" + ] + }, + { + "object": "{{P}}OVERDRAFT_CALC", + "mutant": "line 79: - -> + (arith)", + "status": "killed", + "hidden": "9/11", + "failed_tests": [ + "BUSINESS_DISCOUNT", + "BUSINESS_RATE_FLOOR" + ] + } + ], + "valid": 5, + "killed": 5, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0163/reference/overdraft_calc.clas.abap b/tasks_gen/eval/G0163/reference/overdraft_calc.clas.abap new file mode 100644 index 0000000..eb97420 --- /dev/null +++ b/tasks_gen/eval/G0163/reference/overdraft_calc.clas.abap @@ -0,0 +1,85 @@ +CLASS {{p}}overdraft_calc DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_overdraft. + + PRIVATE SECTION. + CONSTANTS: + c_free_days TYPE i VALUE 3, + c_percent_divisor TYPE i VALUE 100, + c_days_per_year TYPE i VALUE 360, + c_business_discount TYPE p LENGTH 3 DECIMALS 2 VALUE '2.00', + c_min_rate TYPE p LENGTH 3 DECIMALS 2 VALUE '5.00'. + + TYPES: + ty_rate TYPE p LENGTH 5 DECIMALS 2, + ty_interest TYPE p LENGTH 15 DECIMALS 6. + + METHODS chargeable_days + IMPORTING iv_days TYPE i + RETURNING VALUE(rv_days) TYPE i. + + METHODS base_rate + IMPORTING iv_amount TYPE {{p}}if_overdraft=>ty_amount + RETURNING VALUE(rv_rate) TYPE ty_rate. + + METHODS interest_rate + IMPORTING iv_amount TYPE {{p}}if_overdraft=>ty_amount + iv_segment TYPE {{p}}if_overdraft=>ty_segment + RETURNING VALUE(rv_rate) TYPE ty_rate. +ENDCLASS. + + +CLASS {{p}}overdraft_calc IMPLEMENTATION. + METHOD {{p}}if_overdraft~calculate. + DATA: + lv_days TYPE i, + lv_rate TYPE ty_rate, + lv_annual TYPE ty_interest. + + IF iv_amount <= 0 OR iv_days <= 0. + rv_interest = 0. + RETURN. + ENDIF. + + lv_days = chargeable_days( iv_days ). + lv_rate = interest_rate( iv_amount = iv_amount + iv_segment = iv_segment ). + + lv_annual = iv_amount * lv_rate / c_percent_divisor. + rv_interest = lv_annual * lv_days / c_days_per_year. + + IF rv_interest > 0 AND rv_interest < {{p}}if_overdraft=>c_min_interest. + rv_interest = {{p}}if_overdraft=>c_min_interest. + ENDIF. + ENDMETHOD. + + METHOD chargeable_days. + rv_days = iv_days - c_free_days. + IF rv_days < 0. + rv_days = 0. + ENDIF. + ENDMETHOD. + + METHOD base_rate. + IF iv_amount <= 1000. + rv_rate = '12.00'. + ELSEIF iv_amount <= 5000. + rv_rate = '10.00'. + ELSEIF iv_amount <= 20000. + rv_rate = '8.00'. + ELSE. + rv_rate = '6.50'. + ENDIF. + ENDMETHOD. + + METHOD interest_rate. + rv_rate = base_rate( iv_amount ). + + IF iv_segment = {{p}}if_overdraft=>c_segment_business. + rv_rate = rv_rate - c_business_discount. + IF rv_rate < c_min_rate. + rv_rate = c_min_rate. + ENDIF. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0163/reference/overdraft_calc.testclasses.abap b/tasks_gen/eval/G0163/reference/overdraft_calc.testclasses.abap new file mode 100644 index 0000000..904ab79 --- /dev/null +++ b/tasks_gen/eval/G0163/reference/overdraft_calc.testclasses.abap @@ -0,0 +1,90 @@ +CLASS ltc_overdraft_calc DEFINITION FINAL FOR TESTING + DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + CONSTANTS c_zero TYPE {{p}}if_overdraft=>ty_amount VALUE '0.00'. + DATA mo_cut TYPE REF TO {{p}}if_overdraft. + METHODS setup. + METHODS zero_amount FOR TESTING. + METHODS grace_days FOR TESTING. + METHODS private_tier FOR TESTING. + METHODS business_rate FOR TESTING. + METHODS minimum_charge FOR TESTING. +ENDCLASS. + + +CLASS ltc_overdraft_calc IMPLEMENTATION. + METHOD setup. + CREATE OBJECT mo_cut TYPE {{p}}overdraft_calc. + ENDMETHOD. + + METHOD zero_amount. + DATA lv_act TYPE {{p}}if_overdraft=>ty_amount. + + CALL METHOD mo_cut->calculate + EXPORTING + iv_amount = '0.00' + iv_days = 30 + iv_segment = {{p}}if_overdraft=>c_segment_private + RECEIVING + rv_interest = lv_act. + cl_abap_unit_assert=>assert_equals( exp = c_zero act = lv_act ). + ENDMETHOD. + + METHOD grace_days. + DATA lv_act TYPE {{p}}if_overdraft=>ty_amount. + + CALL METHOD mo_cut->calculate + EXPORTING + iv_amount = '1000.00' + iv_days = 3 + iv_segment = {{p}}if_overdraft=>c_segment_private + RECEIVING + rv_interest = lv_act. + cl_abap_unit_assert=>assert_equals( exp = c_zero act = lv_act ). + ENDMETHOD. + + METHOD private_tier. + DATA lv_act TYPE {{p}}if_overdraft=>ty_amount. + DATA lv_exp TYPE {{p}}if_overdraft=>ty_amount. + + lv_exp = '10.00'. + CALL METHOD mo_cut->calculate + EXPORTING + iv_amount = '1000.00' + iv_days = 33 + iv_segment = {{p}}if_overdraft=>c_segment_private + RECEIVING + rv_interest = lv_act. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_act ). + ENDMETHOD. + + METHOD business_rate. + DATA lv_act TYPE {{p}}if_overdraft=>ty_amount. + DATA lv_exp TYPE {{p}}if_overdraft=>ty_amount. + + lv_exp = '13.33'. + CALL METHOD mo_cut->calculate + EXPORTING + iv_amount = '2000.00' + iv_days = 33 + iv_segment = {{p}}if_overdraft=>c_segment_business + RECEIVING + rv_interest = lv_act. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_act ). + ENDMETHOD. + + METHOD minimum_charge. + DATA lv_act TYPE {{p}}if_overdraft=>ty_amount. + DATA lv_exp TYPE {{p}}if_overdraft=>ty_amount. + + lv_exp = '5.00'. + CALL METHOD mo_cut->calculate + EXPORTING + iv_amount = '500.00' + iv_days = 10 + iv_segment = {{p}}if_overdraft=>c_segment_private + RECEIVING + rv_interest = lv_act. + cl_abap_unit_assert=>assert_equals( exp = lv_exp act = lv_act ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0163/seed/if_overdraft.intf.abap b/tasks_gen/eval/G0163/seed/if_overdraft.intf.abap new file mode 100644 index 0000000..8dfd7b2 --- /dev/null +++ b/tasks_gen/eval/G0163/seed/if_overdraft.intf.abap @@ -0,0 +1,13 @@ +INTERFACE {{p}}if_overdraft PUBLIC. + TYPES ty_amount TYPE p LENGTH 15 DECIMALS 2. + TYPES ty_segment TYPE c LENGTH 1. + CONSTANTS: + c_segment_private TYPE ty_segment VALUE 'P', + c_segment_business TYPE ty_segment VALUE 'B', + c_min_interest TYPE ty_amount VALUE '5.00'. + METHODS calculate + IMPORTING iv_amount TYPE ty_amount + iv_days TYPE i + iv_segment TYPE ty_segment + RETURNING VALUE(rv_interest) TYPE ty_amount. +ENDINTERFACE. diff --git a/tasks_gen/eval/G0163/spec.md b/tasks_gen/eval/G0163/spec.md new file mode 100644 index 0000000..e8c2c93 --- /dev/null +++ b/tasks_gen/eval/G0163/spec.md @@ -0,0 +1,62 @@ +# 1. Goal +A bank charges interest on the overdrawn part of a current account. The bank +needs one calculation that returns the interest of one account for one period. + +# 2. Open questions +None. + +# 3. Context +- All objects are in package $TMP. +- The interface {{P}}IF_OVERDRAFT exists in package $TMP. It is active. +- The interface contains the types TY_AMOUNT (packed number, length 15, two + decimals) and TY_SEGMENT (character, length 1), the constants + C_SEGMENT_PRIVATE (value 'P'), C_SEGMENT_BUSINESS (value 'B') and + C_MIN_INTEREST (value 5.00), and one method: + CALCULATE + IMPORTING iv_amount TYPE ty_amount + iv_days TYPE i + iv_segment TYPE ty_segment + RETURNING VALUE(rv_interest) TYPE ty_amount. + +# 4. Contract +- Create the class {{P}}OVERDRAFT_CALC in package $TMP. +- The class is public and final. It implements {{P}}IF_OVERDRAFT. +- The class can be created without parameters. +- Do not add other public methods or attributes. + +# 5. Business rules +Apply the rules in this sequence. +1. If iv_amount is zero or negative, or if iv_days is zero or negative, + return 0.00. +2. The first three days of the period carry no interest. The chargeable days + are iv_days minus 3. If this value is negative, the chargeable days are 0. +3. The whole amount uses one annual interest rate. The rate depends on the + amount: + - amount up to and including 1,000.00: 12.00 per cent + - amount up to and including 5,000.00: 10.00 per cent + - amount up to and including 20,000.00: 8.00 per cent + - amount above 20,000.00: 6.50 per cent +4. If iv_segment is 'B', subtract 2.00 percentage points from the rate. The + rate never falls below 5.00 per cent. Every other value of iv_segment + leaves the rate unchanged. +5. The interest is the exact value of + amount * (rate / 100) * (chargeable days / 360). + Do not round intermediate results. Round only the final interest to 2 + decimals. Round half away from zero. +6. If the rounded interest is greater than 0.00 and less than 5.00, the + interest is 5.00. +7. Return the interest. + +# 6. Constraints +- Release target: 7.02. The code must pass the 7.02 syntax check. Do not use + language elements that are newer than release 7.02. Examples of forbidden + elements are inline declarations, constructor expressions and table + expressions. +- Coding standards: Clean ABAP. Methods below 40 statements. No global + variables. +- Out of scope: do not change {{P}}IF_OVERDRAFT. + +# 7. Acceptance +- The class is active and has no syntax error. +- The hidden tests pass. +- Write your own ABAP Unit tests for the class. diff --git a/tasks_gen/eval/G0163/task.json b/tasks_gen/eval/G0163/task.json new file mode 100644 index 0000000..d958868 --- /dev/null +++ b/tasks_gen/eval/G0163/task.json @@ -0,0 +1,51 @@ +{ + "id": "G0163", + "category": "G", + "object_type": "CLAS", + "difficulty": 2, + "release_target": "v702", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 40, + "max_activations": 10 + }, + "seed": [ + { + "type": "INTF", + "name": "{{P}}IF_OVERDRAFT", + "file": "seed/if_overdraft.intf.abap", + "description": "Overdraft interest contract" + } + ], + "contract": [ + { + "type": "CLAS", + "name": "{{P}}OVERDRAFT_CALC", + "implements": "{{P}}IF_OVERDRAFT" + } + ], + "out_of_scope": [ + "{{P}}IF_OVERDRAFT" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}OVERDRAFT_TEST", + "file": "hidden/overdraft_test.clas.abap", + "description": "Hidden tests for the overdraft interest calculation" + } + ], + "reference": [ + { + "type": "CLAS", + "name": "{{P}}OVERDRAFT_CALC", + "file": "reference/overdraft_calc.clas.abap", + "description": "Calculates the overdraft interest of a current account", + "testclasses_file": "reference/overdraft_calc.testclasses.abap" + } + ], + "craft_checks": [ + "method_length", + "no_newer_syntax" + ] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0164/faulty/m0_commission_calc.clas.abap b/tasks_gen/eval/G0164/faulty/m0_commission_calc.clas.abap new file mode 100644 index 0000000..1811d6b --- /dev/null +++ b/tasks_gen/eval/G0164/faulty/m0_commission_calc.clas.abap @@ -0,0 +1,113 @@ +CLASS {{p}}commission_calc DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_commission. + + PRIVATE SECTION. + TYPES ty_exact TYPE p LENGTH 15 DECIMALS 4. + + CONSTANTS: + c_rate_base TYPE p LENGTH 7 DECIMALS 4 VALUE '0.0100', + c_rate_mid TYPE p LENGTH 7 DECIMALS 4 VALUE '0.0300', + c_rate_top TYPE p LENGTH 7 DECIMALS 4 VALUE '0.0500', + c_bonus_5 TYPE {{p}}if_commission=>ty_amount VALUE '200', + c_bonus_10 TYPE {{p}}if_commission=>ty_amount VALUE '500', + c_cap TYPE {{p}}if_commission=>ty_amount VALUE '5000'. + + METHODS base_commission + IMPORTING iv_sales TYPE {{p}}if_commission=>ty_amount + iv_target TYPE {{p}}if_commission=>ty_amount + RETURNING VALUE(rv_part) TYPE ty_exact. + METHODS extra_commission + IMPORTING iv_sales TYPE {{p}}if_commission=>ty_amount + iv_target TYPE {{p}}if_commission=>ty_amount + RETURNING VALUE(rv_part) TYPE ty_exact. + METHODS top_commission + IMPORTING iv_sales TYPE {{p}}if_commission=>ty_amount + iv_target TYPE {{p}}if_commission=>ty_amount + RETURNING VALUE(rv_part) TYPE ty_exact. + METHODS round_to_cents + IMPORTING iv_value TYPE ty_exact + RETURNING VALUE(rv_value) TYPE {{p}}if_commission=>ty_amount. + METHODS loyalty_bonus + IMPORTING iv_years TYPE i + RETURNING VALUE(rv_bonus) TYPE {{p}}if_commission=>ty_amount. +ENDCLASS. + + +CLASS {{p}}commission_calc IMPLEMENTATION. + METHOD {{p}}if_commission~calculate. + DATA: lv_exact TYPE ty_exact, + lv_bonus TYPE {{p}}if_commission=>ty_amount. + + IF iv_sales <= 0 AND iv_target <= 0. + RETURN. + ENDIF. + IF iv_sales * 2 < iv_target. + RETURN. + ENDIF. + + lv_exact = base_commission( iv_sales = iv_sales iv_target = iv_target ). + lv_exact = lv_exact + extra_commission( iv_sales = iv_sales iv_target = iv_target ). + lv_exact = lv_exact + top_commission( iv_sales = iv_sales iv_target = iv_target ). + + lv_bonus = round_to_cents( lv_exact ) + loyalty_bonus( iv_years ). + IF lv_bonus > c_cap. + lv_bonus = c_cap. + ENDIF. + rv_bonus = lv_bonus. + ENDMETHOD. + + METHOD base_commission. + DATA lv_base TYPE ty_exact. + + IF iv_sales < iv_target. + lv_base = iv_sales. + ELSE. + lv_base = iv_target. + ENDIF. + rv_part = lv_base * c_rate_base. + ENDMETHOD. + + METHOD extra_commission. + DATA: lv_excess TYPE ty_exact, + lv_limit TYPE ty_exact. + + IF iv_sales <= iv_target. + RETURN. + ENDIF. + lv_excess = iv_sales - iv_target. + lv_limit = iv_target / 2. + IF lv_excess > lv_limit. + lv_excess = lv_limit. + ENDIF. + rv_part = lv_excess * c_rate_mid. + ENDMETHOD. + + METHOD top_commission. + DATA: lv_threshold TYPE ty_exact, + lv_top TYPE ty_exact. + + lv_threshold = iv_target * 3. + lv_threshold = lv_threshold / 2. + IF iv_sales <= lv_threshold. + RETURN. + ENDIF. + lv_top = iv_sales - lv_threshold. + rv_part = lv_top * c_rate_top. + ENDMETHOD. + + METHOD round_to_cents. + DATA lv_cents TYPE {{p}}if_commission=>ty_amount. + + lv_cents = round( val = iv_value dec = 2 ). + rv_value = lv_cents. + ENDMETHOD. + + METHOD loyalty_bonus. + IF iv_years >= 10. + rv_bonus = c_bonus_10. + ELSEIF iv_years >= 5. + rv_bonus = c_bonus_5. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0164/faulty/m1_commission_calc.clas.abap b/tasks_gen/eval/G0164/faulty/m1_commission_calc.clas.abap new file mode 100644 index 0000000..f4efdd2 --- /dev/null +++ b/tasks_gen/eval/G0164/faulty/m1_commission_calc.clas.abap @@ -0,0 +1,113 @@ +CLASS {{p}}commission_calc DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_commission. + + PRIVATE SECTION. + TYPES ty_exact TYPE p LENGTH 15 DECIMALS 4. + + CONSTANTS: + c_rate_base TYPE p LENGTH 7 DECIMALS 4 VALUE '0.0100', + c_rate_mid TYPE p LENGTH 7 DECIMALS 4 VALUE '0.0300', + c_rate_top TYPE p LENGTH 7 DECIMALS 4 VALUE '0.0500', + c_bonus_5 TYPE {{p}}if_commission=>ty_amount VALUE '200', + c_bonus_10 TYPE {{p}}if_commission=>ty_amount VALUE '500', + c_cap TYPE {{p}}if_commission=>ty_amount VALUE '5000'. + + METHODS base_commission + IMPORTING iv_sales TYPE {{p}}if_commission=>ty_amount + iv_target TYPE {{p}}if_commission=>ty_amount + RETURNING VALUE(rv_part) TYPE ty_exact. + METHODS extra_commission + IMPORTING iv_sales TYPE {{p}}if_commission=>ty_amount + iv_target TYPE {{p}}if_commission=>ty_amount + RETURNING VALUE(rv_part) TYPE ty_exact. + METHODS top_commission + IMPORTING iv_sales TYPE {{p}}if_commission=>ty_amount + iv_target TYPE {{p}}if_commission=>ty_amount + RETURNING VALUE(rv_part) TYPE ty_exact. + METHODS round_to_cents + IMPORTING iv_value TYPE ty_exact + RETURNING VALUE(rv_value) TYPE {{p}}if_commission=>ty_amount. + METHODS loyalty_bonus + IMPORTING iv_years TYPE i + RETURNING VALUE(rv_bonus) TYPE {{p}}if_commission=>ty_amount. +ENDCLASS. + + +CLASS {{p}}commission_calc IMPLEMENTATION. + METHOD {{p}}if_commission~calculate. + DATA: lv_exact TYPE ty_exact, + lv_bonus TYPE {{p}}if_commission=>ty_amount. + + IF iv_sales <= 0 OR iv_target <= 0. + RETURN. + ENDIF. + IF iv_sales / 2 < iv_target. + RETURN. + ENDIF. + + lv_exact = base_commission( iv_sales = iv_sales iv_target = iv_target ). + lv_exact = lv_exact + extra_commission( iv_sales = iv_sales iv_target = iv_target ). + lv_exact = lv_exact + top_commission( iv_sales = iv_sales iv_target = iv_target ). + + lv_bonus = round_to_cents( lv_exact ) + loyalty_bonus( iv_years ). + IF lv_bonus > c_cap. + lv_bonus = c_cap. + ENDIF. + rv_bonus = lv_bonus. + ENDMETHOD. + + METHOD base_commission. + DATA lv_base TYPE ty_exact. + + IF iv_sales < iv_target. + lv_base = iv_sales. + ELSE. + lv_base = iv_target. + ENDIF. + rv_part = lv_base * c_rate_base. + ENDMETHOD. + + METHOD extra_commission. + DATA: lv_excess TYPE ty_exact, + lv_limit TYPE ty_exact. + + IF iv_sales <= iv_target. + RETURN. + ENDIF. + lv_excess = iv_sales - iv_target. + lv_limit = iv_target / 2. + IF lv_excess > lv_limit. + lv_excess = lv_limit. + ENDIF. + rv_part = lv_excess * c_rate_mid. + ENDMETHOD. + + METHOD top_commission. + DATA: lv_threshold TYPE ty_exact, + lv_top TYPE ty_exact. + + lv_threshold = iv_target * 3. + lv_threshold = lv_threshold / 2. + IF iv_sales <= lv_threshold. + RETURN. + ENDIF. + lv_top = iv_sales - lv_threshold. + rv_part = lv_top * c_rate_top. + ENDMETHOD. + + METHOD round_to_cents. + DATA lv_cents TYPE {{p}}if_commission=>ty_amount. + + lv_cents = round( val = iv_value dec = 2 ). + rv_value = lv_cents. + ENDMETHOD. + + METHOD loyalty_bonus. + IF iv_years >= 10. + rv_bonus = c_bonus_10. + ELSEIF iv_years >= 5. + rv_bonus = c_bonus_5. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0164/faulty/m2_commission_calc.clas.abap b/tasks_gen/eval/G0164/faulty/m2_commission_calc.clas.abap new file mode 100644 index 0000000..b32f580 --- /dev/null +++ b/tasks_gen/eval/G0164/faulty/m2_commission_calc.clas.abap @@ -0,0 +1,113 @@ +CLASS {{p}}commission_calc DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_commission. + + PRIVATE SECTION. + TYPES ty_exact TYPE p LENGTH 15 DECIMALS 4. + + CONSTANTS: + c_rate_base TYPE p LENGTH 7 DECIMALS 4 VALUE '0.0100', + c_rate_mid TYPE p LENGTH 7 DECIMALS 4 VALUE '0.0300', + c_rate_top TYPE p LENGTH 7 DECIMALS 4 VALUE '0.0500', + c_bonus_5 TYPE {{p}}if_commission=>ty_amount VALUE '200', + c_bonus_10 TYPE {{p}}if_commission=>ty_amount VALUE '500', + c_cap TYPE {{p}}if_commission=>ty_amount VALUE '5000'. + + METHODS base_commission + IMPORTING iv_sales TYPE {{p}}if_commission=>ty_amount + iv_target TYPE {{p}}if_commission=>ty_amount + RETURNING VALUE(rv_part) TYPE ty_exact. + METHODS extra_commission + IMPORTING iv_sales TYPE {{p}}if_commission=>ty_amount + iv_target TYPE {{p}}if_commission=>ty_amount + RETURNING VALUE(rv_part) TYPE ty_exact. + METHODS top_commission + IMPORTING iv_sales TYPE {{p}}if_commission=>ty_amount + iv_target TYPE {{p}}if_commission=>ty_amount + RETURNING VALUE(rv_part) TYPE ty_exact. + METHODS round_to_cents + IMPORTING iv_value TYPE ty_exact + RETURNING VALUE(rv_value) TYPE {{p}}if_commission=>ty_amount. + METHODS loyalty_bonus + IMPORTING iv_years TYPE i + RETURNING VALUE(rv_bonus) TYPE {{p}}if_commission=>ty_amount. +ENDCLASS. + + +CLASS {{p}}commission_calc IMPLEMENTATION. + METHOD {{p}}if_commission~calculate. + DATA: lv_exact TYPE ty_exact, + lv_bonus TYPE {{p}}if_commission=>ty_amount. + + IF iv_sales <= 0 OR iv_target <= 0. + RETURN. + ENDIF. + IF iv_sales * 2 < iv_target. + RETURN. + ENDIF. + + lv_exact = base_commission( iv_sales = iv_sales iv_target = iv_target ). + lv_exact = lv_exact + extra_commission( iv_sales = iv_sales iv_target = iv_target ). + lv_exact = lv_exact + top_commission( iv_sales = iv_sales iv_target = iv_target ). + + lv_bonus = round_to_cents( lv_exact ) + loyalty_bonus( iv_years ). + IF lv_bonus > c_cap. + lv_bonus = c_cap. + ENDIF. + rv_bonus = lv_bonus. + ENDMETHOD. + + METHOD base_commission. + DATA lv_base TYPE ty_exact. + + IF iv_sales < iv_target. + lv_base = iv_sales. + ELSE. + lv_base = iv_target. + ENDIF. + rv_part = lv_base * c_rate_base. + ENDMETHOD. + + METHOD extra_commission. + DATA: lv_excess TYPE ty_exact, + lv_limit TYPE ty_exact. + + IF iv_sales <= iv_target. + RETURN. + ENDIF. + lv_excess = iv_sales - iv_target. + lv_limit = iv_target / 2. + IF lv_excess > lv_limit. + lv_excess = lv_limit. + ENDIF. + rv_part = lv_excess * c_rate_mid. + ENDMETHOD. + + METHOD top_commission. + DATA: lv_threshold TYPE ty_exact, + lv_top TYPE ty_exact. + + lv_threshold = iv_target * 3. + lv_threshold = lv_threshold / 2. + IF iv_sales > lv_threshold. + RETURN. + ENDIF. + lv_top = iv_sales - lv_threshold. + rv_part = lv_top * c_rate_top. + ENDMETHOD. + + METHOD round_to_cents. + DATA lv_cents TYPE {{p}}if_commission=>ty_amount. + + lv_cents = round( val = iv_value dec = 2 ). + rv_value = lv_cents. + ENDMETHOD. + + METHOD loyalty_bonus. + IF iv_years >= 10. + rv_bonus = c_bonus_10. + ELSEIF iv_years >= 5. + rv_bonus = c_bonus_5. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0164/faulty/m3_commission_calc.clas.abap b/tasks_gen/eval/G0164/faulty/m3_commission_calc.clas.abap new file mode 100644 index 0000000..29e7263 --- /dev/null +++ b/tasks_gen/eval/G0164/faulty/m3_commission_calc.clas.abap @@ -0,0 +1,113 @@ +CLASS {{p}}commission_calc DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_commission. + + PRIVATE SECTION. + TYPES ty_exact TYPE p LENGTH 15 DECIMALS 4. + + CONSTANTS: + c_rate_base TYPE p LENGTH 7 DECIMALS 4 VALUE '0.0100', + c_rate_mid TYPE p LENGTH 7 DECIMALS 4 VALUE '0.0300', + c_rate_top TYPE p LENGTH 7 DECIMALS 4 VALUE '0.0500', + c_bonus_5 TYPE {{p}}if_commission=>ty_amount VALUE '200', + c_bonus_10 TYPE {{p}}if_commission=>ty_amount VALUE '500', + c_cap TYPE {{p}}if_commission=>ty_amount VALUE '5000'. + + METHODS base_commission + IMPORTING iv_sales TYPE {{p}}if_commission=>ty_amount + iv_target TYPE {{p}}if_commission=>ty_amount + RETURNING VALUE(rv_part) TYPE ty_exact. + METHODS extra_commission + IMPORTING iv_sales TYPE {{p}}if_commission=>ty_amount + iv_target TYPE {{p}}if_commission=>ty_amount + RETURNING VALUE(rv_part) TYPE ty_exact. + METHODS top_commission + IMPORTING iv_sales TYPE {{p}}if_commission=>ty_amount + iv_target TYPE {{p}}if_commission=>ty_amount + RETURNING VALUE(rv_part) TYPE ty_exact. + METHODS round_to_cents + IMPORTING iv_value TYPE ty_exact + RETURNING VALUE(rv_value) TYPE {{p}}if_commission=>ty_amount. + METHODS loyalty_bonus + IMPORTING iv_years TYPE i + RETURNING VALUE(rv_bonus) TYPE {{p}}if_commission=>ty_amount. +ENDCLASS. + + +CLASS {{p}}commission_calc IMPLEMENTATION. + METHOD {{p}}if_commission~calculate. + DATA: lv_exact TYPE ty_exact, + lv_bonus TYPE {{p}}if_commission=>ty_amount. + + IF iv_sales <= 0 OR iv_target <= 0. + RETURN. + ENDIF. + IF iv_sales * 2 < iv_target. + RETURN. + ENDIF. + + lv_exact = base_commission( iv_sales = iv_sales iv_target = iv_target ). + lv_exact = lv_exact + extra_commission( iv_sales = iv_sales iv_target = iv_target ). + lv_exact = lv_exact + top_commission( iv_sales = iv_sales iv_target = iv_target ). + + lv_bonus = round_to_cents( lv_exact ) + loyalty_bonus( iv_years ). + IF lv_bonus > c_cap. + lv_bonus = c_cap. + ENDIF. + rv_bonus = lv_bonus. + ENDMETHOD. + + METHOD base_commission. + DATA lv_base TYPE ty_exact. + + IF iv_sales < iv_target. + lv_base = iv_sales. + ELSE. + lv_base = iv_target. + ENDIF. + rv_part = lv_base * c_rate_base. + ENDMETHOD. + + METHOD extra_commission. + DATA: lv_excess TYPE ty_exact, + lv_limit TYPE ty_exact. + + IF iv_sales <= iv_target. + RETURN. + ENDIF. + lv_excess = iv_sales - iv_target. + lv_limit = iv_target / 2. + IF lv_excess > lv_limit. + lv_excess = lv_limit. + ENDIF. + rv_part = lv_excess * c_rate_mid. + ENDMETHOD. + + METHOD top_commission. + DATA: lv_threshold TYPE ty_exact, + lv_top TYPE ty_exact. + + lv_threshold = iv_target * 3. + lv_threshold = lv_threshold / 2. + IF iv_sales <= lv_threshold. + RETURN. + ENDIF. + lv_top = iv_sales + lv_threshold. + rv_part = lv_top * c_rate_top. + ENDMETHOD. + + METHOD round_to_cents. + DATA lv_cents TYPE {{p}}if_commission=>ty_amount. + + lv_cents = round( val = iv_value dec = 2 ). + rv_value = lv_cents. + ENDMETHOD. + + METHOD loyalty_bonus. + IF iv_years >= 10. + rv_bonus = c_bonus_10. + ELSEIF iv_years >= 5. + rv_bonus = c_bonus_5. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0164/generation.json b/tasks_gen/eval/G0164/generation.json new file mode 100644 index 0000000..99e0936 --- /dev/null +++ b/tasks_gen/eval/G0164/generation.json @@ -0,0 +1,33 @@ +{ + "id": "G0164", + "pool": "eval", + "object_type": "CLAS", + "category": "G", + "attempts": [ + { + "stage": "bundle", + "errors": [ + "hidden/t42_hidden.clas.abap line 57: syntax error for release v740sp05 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"assert_bonus\"", + "hidden/t42_hidden.clas.abap line 57: syntax error for release v740sp05 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"99\"", + "hidden/t42_hidden.clas.abap line 82: syntax error for release v740sp05 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"assert_bonus\"", + "hidden/t42_hidden.clas.abap line 82: syntax error for release v740sp05 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"35\"", + "hidden/t42_hidden.clas.abap line 82: syntax error for release v740sp05 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"55\"", + "hidden/t42_hidden.clas.abap line 82: syntax error for release v740sp05 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"55\"" + ], + "by_check": { + "abaplint": 6 + } + }, + { + "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/eval/G0164/hidden/t42_hidden.clas.abap b/tasks_gen/eval/G0164/hidden/t42_hidden.clas.abap new file mode 100644 index 0000000..7eeb654 --- /dev/null +++ b/tasks_gen/eval/G0164/hidden/t42_hidden.clas.abap @@ -0,0 +1,101 @@ +CLASS {{p}}t42_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + DATA mo_cut TYPE REF TO {{p}}if_commission. + METHODS setup. + METHODS assert_bonus + IMPORTING iv_expected TYPE {{p}}if_commission=>ty_amount + iv_sales TYPE {{p}}if_commission=>ty_amount + iv_target TYPE {{p}}if_commission=>ty_amount + iv_years TYPE i + iv_msg TYPE string. + METHODS zero_sales FOR TESTING. + METHODS zero_target FOR TESTING. + METHODS negative_sales FOR TESTING. + METHODS below_half_target FOR TESTING. + METHODS exactly_half_target FOR TESTING. + METHODS at_target FOR TESTING. + METHODS above_target FOR TESTING. + METHODS top_tier FOR TESTING. + METHODS rounds_to_cent FOR TESTING. + METHODS loyalty_five_years FOR TESTING. + METHODS loyalty_ten_years FOR TESTING. + METHODS cap_applied FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t42_hidden IMPLEMENTATION. + METHOD setup. + mo_cut = NEW {{p}}commission_calc( ). + ENDMETHOD. + + METHOD assert_bonus. + cl_abap_unit_assert=>assert_equals( + exp = iv_expected + act = mo_cut->calculate( iv_sales = iv_sales + iv_target = iv_target + iv_years = iv_years ) + msg = iv_msg ). + ENDMETHOD. + + METHOD zero_sales. + assert_bonus( iv_expected = 0 iv_sales = 0 iv_target = 1000 + iv_years = 0 iv_msg = 'zero sales' ). + ENDMETHOD. + + METHOD zero_target. + assert_bonus( iv_expected = 0 iv_sales = 1000 iv_target = 0 + iv_years = 0 iv_msg = 'zero target' ). + ENDMETHOD. + + METHOD negative_sales. + assert_bonus( iv_expected = 0 iv_sales = -100 iv_target = 1000 + iv_years = 0 iv_msg = 'negative sales' ). + ENDMETHOD. + + METHOD below_half_target. + assert_bonus( iv_expected = 0 iv_sales = '499.99' iv_target = 1000 + iv_years = 0 iv_msg = 'below half target' ). + ENDMETHOD. + + METHOD exactly_half_target. + assert_bonus( iv_expected = 5 iv_sales = 500 iv_target = 1000 + iv_years = 0 iv_msg = 'exactly half target' ). + ENDMETHOD. + + METHOD at_target. + assert_bonus( iv_expected = 10 iv_sales = 1000 iv_target = 1000 + iv_years = 0 iv_msg = 'at target' ). + ENDMETHOD. + + METHOD above_target. + assert_bonus( iv_expected = 16 iv_sales = 1200 iv_target = 1000 + iv_years = 0 iv_msg = 'above target' ). + ENDMETHOD. + + METHOD top_tier. + assert_bonus( iv_expected = 50 iv_sales = 2000 iv_target = 1000 + iv_years = 0 iv_msg = 'top tier' ). + ENDMETHOD. + + METHOD rounds_to_cent. + assert_bonus( iv_expected = '12.35' iv_sales = '1234.55' + iv_target = '1234.55' + iv_years = 0 iv_msg = 'rounding' ). + ENDMETHOD. + + METHOD loyalty_five_years. + assert_bonus( iv_expected = 210 iv_sales = 1000 iv_target = 1000 + iv_years = 5 iv_msg = 'five years' ). + ENDMETHOD. + + METHOD loyalty_ten_years. + assert_bonus( iv_expected = 510 iv_sales = 1000 iv_target = 1000 + iv_years = 10 iv_msg = 'ten years' ). + ENDMETHOD. + + METHOD cap_applied. + assert_bonus( iv_expected = 5000 iv_sales = 100000 iv_target = 1000 + iv_years = 10 iv_msg = 'cap' ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0164/mutation.json b/tasks_gen/eval/G0164/mutation.json new file mode 100644 index 0000000..316a94c --- /dev/null +++ b/tasks_gen/eval/G0164/mutation.json @@ -0,0 +1,64 @@ +{ + "task": "G0164", + "mutants": [ + { + "object": "{{P}}COMMISSION_CALC", + "mutant": "line 42: OR -> AND (logic)", + "status": "killed", + "hidden": "11/12", + "failed_tests": [ + "ZERO_TARGET" + ] + }, + { + "object": "{{P}}COMMISSION_CALC", + "mutant": "line 45: * -> / (arith)", + "status": "killed", + "hidden": "6/12", + "failed_tests": [ + "ABOVE_TARGET", + "AT_TARGET", + "EXACTLY_HALF_TARGET", + "LOYALTY_FIVE_YEARS", + "LOYALTY_TEN_YEARS", + "ROUNDS_TO_CENT" + ] + }, + { + "object": "{{P}}COMMISSION_CALC", + "mutant": "line 92: <= -> > (rel)", + "status": "killed", + "hidden": "4/12", + "failed_tests": [ + "ABOVE_TARGET", + "AT_TARGET", + "CAP_APPLIED", + "EXACTLY_HALF_TARGET", + "LOYALTY_FIVE_YEARS", + "LOYALTY_TEN_YEARS", + "ROUNDS_TO_CENT", + "TOP_TIER" + ] + }, + { + "object": "{{P}}COMMISSION_CALC", + "mutant": "line 95: - -> + (arith)", + "status": "killed", + "hidden": "11/12", + "failed_tests": [ + "TOP_TIER" + ] + }, + { + "object": "{{P}}COMMISSION_CALC", + "mutant": "line 102: 2 -> 3 (const)", + "status": "survived", + "hidden": "12/12", + "failed_tests": [] + } + ], + "valid": 5, + "killed": 4, + "kill_rate": 0.8, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0164/reference/commission_calc.clas.abap b/tasks_gen/eval/G0164/reference/commission_calc.clas.abap new file mode 100644 index 0000000..c8e4a28 --- /dev/null +++ b/tasks_gen/eval/G0164/reference/commission_calc.clas.abap @@ -0,0 +1,113 @@ +CLASS {{p}}commission_calc DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_commission. + + PRIVATE SECTION. + TYPES ty_exact TYPE p LENGTH 15 DECIMALS 4. + + CONSTANTS: + c_rate_base TYPE p LENGTH 7 DECIMALS 4 VALUE '0.0100', + c_rate_mid TYPE p LENGTH 7 DECIMALS 4 VALUE '0.0300', + c_rate_top TYPE p LENGTH 7 DECIMALS 4 VALUE '0.0500', + c_bonus_5 TYPE {{p}}if_commission=>ty_amount VALUE '200', + c_bonus_10 TYPE {{p}}if_commission=>ty_amount VALUE '500', + c_cap TYPE {{p}}if_commission=>ty_amount VALUE '5000'. + + METHODS base_commission + IMPORTING iv_sales TYPE {{p}}if_commission=>ty_amount + iv_target TYPE {{p}}if_commission=>ty_amount + RETURNING VALUE(rv_part) TYPE ty_exact. + METHODS extra_commission + IMPORTING iv_sales TYPE {{p}}if_commission=>ty_amount + iv_target TYPE {{p}}if_commission=>ty_amount + RETURNING VALUE(rv_part) TYPE ty_exact. + METHODS top_commission + IMPORTING iv_sales TYPE {{p}}if_commission=>ty_amount + iv_target TYPE {{p}}if_commission=>ty_amount + RETURNING VALUE(rv_part) TYPE ty_exact. + METHODS round_to_cents + IMPORTING iv_value TYPE ty_exact + RETURNING VALUE(rv_value) TYPE {{p}}if_commission=>ty_amount. + METHODS loyalty_bonus + IMPORTING iv_years TYPE i + RETURNING VALUE(rv_bonus) TYPE {{p}}if_commission=>ty_amount. +ENDCLASS. + + +CLASS {{p}}commission_calc IMPLEMENTATION. + METHOD {{p}}if_commission~calculate. + DATA: lv_exact TYPE ty_exact, + lv_bonus TYPE {{p}}if_commission=>ty_amount. + + IF iv_sales <= 0 OR iv_target <= 0. + RETURN. + ENDIF. + IF iv_sales * 2 < iv_target. + RETURN. + ENDIF. + + lv_exact = base_commission( iv_sales = iv_sales iv_target = iv_target ). + lv_exact = lv_exact + extra_commission( iv_sales = iv_sales iv_target = iv_target ). + lv_exact = lv_exact + top_commission( iv_sales = iv_sales iv_target = iv_target ). + + lv_bonus = round_to_cents( lv_exact ) + loyalty_bonus( iv_years ). + IF lv_bonus > c_cap. + lv_bonus = c_cap. + ENDIF. + rv_bonus = lv_bonus. + ENDMETHOD. + + METHOD base_commission. + DATA lv_base TYPE ty_exact. + + IF iv_sales < iv_target. + lv_base = iv_sales. + ELSE. + lv_base = iv_target. + ENDIF. + rv_part = lv_base * c_rate_base. + ENDMETHOD. + + METHOD extra_commission. + DATA: lv_excess TYPE ty_exact, + lv_limit TYPE ty_exact. + + IF iv_sales <= iv_target. + RETURN. + ENDIF. + lv_excess = iv_sales - iv_target. + lv_limit = iv_target / 2. + IF lv_excess > lv_limit. + lv_excess = lv_limit. + ENDIF. + rv_part = lv_excess * c_rate_mid. + ENDMETHOD. + + METHOD top_commission. + DATA: lv_threshold TYPE ty_exact, + lv_top TYPE ty_exact. + + lv_threshold = iv_target * 3. + lv_threshold = lv_threshold / 2. + IF iv_sales <= lv_threshold. + RETURN. + ENDIF. + lv_top = iv_sales - lv_threshold. + rv_part = lv_top * c_rate_top. + ENDMETHOD. + + METHOD round_to_cents. + DATA lv_cents TYPE {{p}}if_commission=>ty_amount. + + lv_cents = round( val = iv_value dec = 2 ). + rv_value = lv_cents. + ENDMETHOD. + + METHOD loyalty_bonus. + IF iv_years >= 10. + rv_bonus = c_bonus_10. + ELSEIF iv_years >= 5. + rv_bonus = c_bonus_5. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0164/reference/commission_calc.testclasses.abap b/tasks_gen/eval/G0164/reference/commission_calc.testclasses.abap new file mode 100644 index 0000000..c57b80e --- /dev/null +++ b/tasks_gen/eval/G0164/reference/commission_calc.testclasses.abap @@ -0,0 +1,63 @@ +CLASS ltc_commission DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + DATA mo_cut TYPE REF TO {{p}}if_commission. + METHODS setup. + METHODS assert_bonus + IMPORTING iv_expected TYPE {{p}}if_commission=>ty_amount + iv_sales TYPE {{p}}if_commission=>ty_amount + iv_target TYPE {{p}}if_commission=>ty_amount + iv_years TYPE i. + METHODS zero_or_negative FOR TESTING. + METHODS below_half_target FOR TESTING. + METHODS at_target FOR TESTING. + METHODS above_target FOR TESTING. + METHODS top_tier FOR TESTING. + METHODS loyalty_bonus FOR TESTING. + METHODS cap_applied FOR TESTING. +ENDCLASS. + + +CLASS ltc_commission IMPLEMENTATION. + METHOD setup. + mo_cut = NEW {{p}}commission_calc( ). + ENDMETHOD. + + METHOD assert_bonus. + cl_abap_unit_assert=>assert_equals( + exp = iv_expected + act = mo_cut->calculate( iv_sales = iv_sales + iv_target = iv_target + iv_years = iv_years ) ). + ENDMETHOD. + + METHOD zero_or_negative. + assert_bonus( iv_expected = 0 iv_sales = 0 iv_target = 1000 iv_years = 0 ). + assert_bonus( iv_expected = 0 iv_sales = -100 iv_target = 1000 iv_years = 0 ). + assert_bonus( iv_expected = 0 iv_sales = 1000 iv_target = 0 iv_years = 0 ). + ENDMETHOD. + + METHOD below_half_target. + assert_bonus( iv_expected = 0 iv_sales = 400 iv_target = 1000 iv_years = 0 ). + ENDMETHOD. + + METHOD at_target. + assert_bonus( iv_expected = 10 iv_sales = 1000 iv_target = 1000 iv_years = 0 ). + ENDMETHOD. + + METHOD above_target. + assert_bonus( iv_expected = 16 iv_sales = 1200 iv_target = 1000 iv_years = 0 ). + ENDMETHOD. + + METHOD top_tier. + assert_bonus( iv_expected = 50 iv_sales = 2000 iv_target = 1000 iv_years = 0 ). + ENDMETHOD. + + METHOD loyalty_bonus. + assert_bonus( iv_expected = 210 iv_sales = 1000 iv_target = 1000 iv_years = 5 ). + assert_bonus( iv_expected = 510 iv_sales = 1000 iv_target = 1000 iv_years = 10 ). + ENDMETHOD. + + METHOD cap_applied. + assert_bonus( iv_expected = 5000 iv_sales = 100000 iv_target = 1000 iv_years = 10 ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0164/seed/if_commission.intf.abap b/tasks_gen/eval/G0164/seed/if_commission.intf.abap new file mode 100644 index 0000000..3568786 --- /dev/null +++ b/tasks_gen/eval/G0164/seed/if_commission.intf.abap @@ -0,0 +1,8 @@ +INTERFACE {{p}}if_commission PUBLIC. + TYPES ty_amount TYPE p LENGTH 15 DECIMALS 2. + METHODS calculate + IMPORTING iv_sales TYPE ty_amount + iv_target TYPE ty_amount + iv_years TYPE i + RETURNING VALUE(rv_bonus) TYPE ty_amount. +ENDINTERFACE. diff --git a/tasks_gen/eval/G0164/spec.md b/tasks_gen/eval/G0164/spec.md new file mode 100644 index 0000000..469034b --- /dev/null +++ b/tasks_gen/eval/G0164/spec.md @@ -0,0 +1,68 @@ +# 1. Goal + +A company pays a monthly commission to its sales agents. A payroll program +calls one calculation for each agent and each month. The calculation returns +the commission of one agent. + +# 2. Open questions + +None. + +# 3. Context + +- The interface {{P}}IF_COMMISSION exists in package $TMP. It is active. +- The interface contains the type TY_AMOUNT. TY_AMOUNT is a packed number + with length 15 and 2 decimal places. +- The interface contains one method: + + CALCULATE + IMPORTING iv_sales TYPE ty_amount + iv_target TYPE ty_amount + iv_years TYPE i + RETURNING VALUE(rv_bonus) TYPE ty_amount + +- iv_sales is the sales volume of the month. +- iv_target is the monthly target of the agent. +- iv_years is the number of completed years of service of the agent. + +# 4. Contract + +- Create the class {{P}}COMMISSION_CALC in package $TMP. +- The class is public and final. The class has a public constructor without + parameters. +- The class implements the interface {{P}}IF_COMMISSION. +- Do not add other public methods. + +# 5. Business rules + +Apply the rules in this sequence. + +1. If iv_sales is zero or negative, or if iv_target is zero or negative, + return 0. +2. If two times iv_sales is less than iv_target, return 0. +3. Calculate the commission. Keep the full precision. Round only in rule 4. + a. Add 1 percent of the part of iv_sales that is at most iv_target. + b. If iv_sales is more than iv_target, add 3 percent of the part of + iv_sales that is more than iv_target. Use at most half of iv_target + for this part. + c. If iv_sales is more than 1.5 times iv_target, add 5 percent of the + part of iv_sales that is more than 1.5 times iv_target. +4. Round the commission to 2 decimal places. Use commercial rounding. +5. Add the loyalty bonus. Add 500 if iv_years is 10 or more. Add 200 if + iv_years is 5 or more. Add 0 in all other cases. +6. If the result is more than 5000, return 5000. +7. Return the result. + +# 6. Constraints + +- Release target: 7.40 SP05. Use only language elements that this release + supports. Do not use language elements of a later release. +- Coding standards: Clean ABAP. Method length below 40 statements. No global + variables. No comment that restates the code. +- Out of scope: do not change the interface {{P}}IF_COMMISSION. + +# 7. Acceptance + +- The class is active and has no syntax error. +- The hidden tests pass. +- Write your own ABAP Unit tests for the class. diff --git a/tasks_gen/eval/G0164/task.json b/tasks_gen/eval/G0164/task.json new file mode 100644 index 0000000..667dc79 --- /dev/null +++ b/tasks_gen/eval/G0164/task.json @@ -0,0 +1,51 @@ +{ + "id": "G0164", + "category": "G", + "object_type": "CLAS", + "difficulty": 2, + "release_target": "v740sp05", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 40, + "max_activations": 10 + }, + "seed": [ + { + "type": "INTF", + "name": "{{P}}IF_COMMISSION", + "file": "seed/if_commission.intf.abap", + "description": "Commission calculation contract" + } + ], + "contract": [ + { + "type": "CLAS", + "name": "{{P}}COMMISSION_CALC", + "implements": "{{P}}IF_COMMISSION" + } + ], + "out_of_scope": [ + "{{P}}IF_COMMISSION" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T42_HIDDEN", + "file": "hidden/t42_hidden.clas.abap", + "description": "T42 hidden tests" + } + ], + "reference": [ + { + "type": "CLAS", + "name": "{{P}}COMMISSION_CALC", + "file": "reference/commission_calc.clas.abap", + "description": "Commission calculation", + "testclasses_file": "reference/commission_calc.testclasses.abap" + } + ], + "craft_checks": [ + "method_length", + "no_newer_syntax" + ] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0165/faulty/m0_i_rental_total.ddls.asddls b/tasks_gen/eval/G0165/faulty/m0_i_rental_total.ddls.asddls new file mode 100644 index 0000000..b30c948 --- /dev/null +++ b/tasks_gen/eval/G0165/faulty/m0_i_rental_total.ddls.asddls @@ -0,0 +1,14 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Rental totals' +define view entity {{P}}I_RENTAL_TOTAL + as select from {{p}}rental as r + left outer join {{p}}charge as c on c.rental_id = r.rental_id +{ + key r.rental_id as rental_id, + r.customer as customer, + count( * ) as charge_count, + sum( c.amount ) as total_amount +} +group by + r.rental_id, + r.customer diff --git a/tasks_gen/eval/G0165/faulty/m1_i_rental_total.ddls.asddls b/tasks_gen/eval/G0165/faulty/m1_i_rental_total.ddls.asddls new file mode 100644 index 0000000..4c9e1a9 --- /dev/null +++ b/tasks_gen/eval/G0165/faulty/m1_i_rental_total.ddls.asddls @@ -0,0 +1,14 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Rental totals' +define view entity {{P}}I_RENTAL_TOTAL + as select from {{p}}rental as r + inner join {{p}}charge as c on c.rental_id <> r.rental_id +{ + key r.rental_id as rental_id, + r.customer as customer, + count( * ) as charge_count, + sum( c.amount ) as total_amount +} +group by + r.rental_id, + r.customer diff --git a/tasks_gen/eval/G0165/faulty/m2_i_rental_total.ddls.asddls b/tasks_gen/eval/G0165/faulty/m2_i_rental_total.ddls.asddls new file mode 100644 index 0000000..27287c7 --- /dev/null +++ b/tasks_gen/eval/G0165/faulty/m2_i_rental_total.ddls.asddls @@ -0,0 +1,14 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Rental totals' +define view entity {{P}}I_RENTAL_TOTAL + as select from {{p}}rental as r + inner join {{p}}charge as c on c.rental_id = r.rental_id +{ + key r.rental_id as rental_id, + r.customer as customer, + count( * ) as charge_count, + max( c.amount ) as total_amount +} +group by + r.rental_id, + r.customer diff --git a/tasks_gen/eval/G0165/generation.json b/tasks_gen/eval/G0165/generation.json new file mode 100644 index 0000000..e2a7d59 --- /dev/null +++ b/tasks_gen/eval/G0165/generation.json @@ -0,0 +1,24 @@ +{ + "id": "G0165", + "pool": "eval", + "object_type": "DDLS", + "category": "I", + "attempts": [ + { + "stage": "validate", + "oracle": 98.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/eval/G0165/hidden/t_rental_hidden.clas.abap b/tasks_gen/eval/G0165/hidden/t_rental_hidden.clas.abap new file mode 100644 index 0000000..aac40ae --- /dev/null +++ b/tasks_gen/eval/G0165/hidden/t_rental_hidden.clas.abap @@ -0,0 +1,80 @@ +CLASS {{p}}t_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 per_rental_totals FOR TESTING. + METHODS charge_counts FOR TESTING. + METHODS rental_without_charges FOR TESTING. + METHODS customer_shown FOR TESTING. + METHODS decimals FOR TESTING. + METHODS two_customers FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t_rental_hidden IMPLEMENTATION. + METHOD class_setup. + go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_RENTAL_TOTAL' ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + DATA lt_rental TYPE STANDARD TABLE OF {{p}}rental WITH EMPTY KEY. + DATA lt_charge TYPE STANDARD TABLE OF {{p}}charge WITH EMPTY KEY. + go_env->clear_doubles( ). + lt_rental = VALUE #( ( rental_id = 'R1' customer = 'C1' pickup_date = '20240101' ) + ( rental_id = 'R2' customer = 'C1' pickup_date = '20240102' ) + ( rental_id = 'R3' customer = 'C2' pickup_date = '20240103' ) + ( rental_id = 'R4' customer = 'C2' pickup_date = '20240104' ) + ( rental_id = 'R5' customer = 'C3' pickup_date = '20240105' ) ). + lt_charge = VALUE #( ( rental_id = 'R1' charge_no = 1 customer = 'C1' charge_type = 'FUEL' amount = '50.00' ) + ( rental_id = 'R1' charge_no = 2 customer = 'C1' charge_type = 'TOLL' amount = '10.00' ) + ( rental_id = 'R2' charge_no = 1 customer = 'C1' charge_type = 'FUEL' amount = '30.00' ) + ( rental_id = 'R4' charge_no = 1 customer = 'C2' charge_type = 'FUEL' amount = '20.00' ) + ( rental_id = 'R5' charge_no = 1 customer = 'C3' charge_type = 'FUEL' amount = '5.50' ) + ( rental_id = 'R5' charge_no = 2 customer = 'C3' charge_type = 'TOLL' amount = '4.50' ) ). + go_env->insert_test_data( lt_rental ). + go_env->insert_test_data( lt_charge ). + ENDMETHOD. + + METHOD per_rental_totals. + SELECT SINGLE total_amount FROM {{p}}i_rental_total WHERE rental_id = 'R1' INTO @DATA(lv_total). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '60.00' ) act = CONV decfloat34( lv_total ) ). + SELECT SINGLE total_amount FROM {{p}}i_rental_total WHERE rental_id = 'R2' INTO @DATA(lv_total2). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '30.00' ) act = CONV decfloat34( lv_total2 ) ). + ENDMETHOD. + + METHOD charge_counts. + SELECT SINGLE charge_count FROM {{p}}i_rental_total WHERE rental_id = 'R1' INTO @DATA(lv_count). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lv_count ). + SELECT SINGLE charge_count FROM {{p}}i_rental_total WHERE rental_id = 'R2' INTO @DATA(lv_count2). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lv_count2 ). + ENDMETHOD. + + METHOD rental_without_charges. + SELECT COUNT(*) FROM {{p}}i_rental_total WHERE rental_id = 'R3' INTO @DATA(lv_count). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_count ). + ENDMETHOD. + + METHOD customer_shown. + SELECT SINGLE customer FROM {{p}}i_rental_total WHERE rental_id = 'R1' INTO @DATA(lv_customer). + cl_abap_unit_assert=>assert_equals( exp = 'C1' act = lv_customer ). + ENDMETHOD. + + METHOD decimals. + SELECT SINGLE total_amount FROM {{p}}i_rental_total WHERE rental_id = 'R5' INTO @DATA(lv_total). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '10.00' ) act = CONV decfloat34( lv_total ) ). + ENDMETHOD. + + METHOD two_customers. + SELECT SINGLE total_amount FROM {{p}}i_rental_total WHERE rental_id = 'R4' INTO @DATA(lv_total4). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '20.00' ) act = CONV decfloat34( lv_total4 ) ). + SELECT SINGLE total_amount FROM {{p}}i_rental_total WHERE rental_id = 'R5' INTO @DATA(lv_total5). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '10.00' ) act = CONV decfloat34( lv_total5 ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0165/mutation.json b/tasks_gen/eval/G0165/mutation.json new file mode 100644 index 0000000..29aa2a0 --- /dev/null +++ b/tasks_gen/eval/G0165/mutation.json @@ -0,0 +1,42 @@ +{ + "task": "G0165", + "mutants": [ + { + "object": "{{P}}I_RENTAL_TOTAL", + "mutant": "line 5: inner join -> left outer join (join)", + "status": "killed", + "hidden": "5/6", + "failed_tests": [ + "RENTAL_WITHOUT_CHARGES" + ] + }, + { + "object": "{{P}}I_RENTAL_TOTAL", + "mutant": "line 5: = -> <> (eq)", + "status": "killed", + "hidden": "1/6", + "failed_tests": [ + "CHARGE_COUNTS", + "DECIMALS", + "PER_RENTAL_TOTALS", + "RENTAL_WITHOUT_CHARGES", + "TWO_CUSTOMERS" + ] + }, + { + "object": "{{P}}I_RENTAL_TOTAL", + "mutant": "line 10: sum( -> max( (agg)", + "status": "killed", + "hidden": "3/6", + "failed_tests": [ + "DECIMALS", + "PER_RENTAL_TOTALS", + "TWO_CUSTOMERS" + ] + } + ], + "valid": 3, + "killed": 3, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0165/reference/i_rental_total.ddls.asddls b/tasks_gen/eval/G0165/reference/i_rental_total.ddls.asddls new file mode 100644 index 0000000..88f37f9 --- /dev/null +++ b/tasks_gen/eval/G0165/reference/i_rental_total.ddls.asddls @@ -0,0 +1,14 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Rental totals' +define view entity {{P}}I_RENTAL_TOTAL + as select from {{p}}rental as r + inner join {{p}}charge as c on c.rental_id = r.rental_id +{ + key r.rental_id as rental_id, + r.customer as customer, + count( * ) as charge_count, + sum( c.amount ) as total_amount +} +group by + r.rental_id, + r.customer diff --git a/tasks_gen/eval/G0165/reference/t_rental_test.clas.abap b/tasks_gen/eval/G0165/reference/t_rental_test.clas.abap new file mode 100644 index 0000000..a7c63e2 --- /dev/null +++ b/tasks_gen/eval/G0165/reference/t_rental_test.clas.abap @@ -0,0 +1,39 @@ +CLASS {{p}}t_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 total_of_one_rental FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t_rental_test IMPLEMENTATION. + METHOD class_setup. + go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_RENTAL_TOTAL' ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + go_env->clear_doubles( ). + ENDMETHOD. + + METHOD total_of_one_rental. + DATA lt_rental TYPE STANDARD TABLE OF {{p}}rental WITH EMPTY KEY. + DATA lt_charge TYPE STANDARD TABLE OF {{p}}charge WITH EMPTY KEY. + lt_rental = VALUE #( ( rental_id = 'A1' customer = 'K1' pickup_date = '20240101' ) ). + lt_charge = VALUE #( ( rental_id = 'A1' charge_no = 1 customer = 'K1' charge_type = 'FUEL' amount = '12.00' ) + ( rental_id = 'A1' charge_no = 2 customer = 'K1' charge_type = 'TOLL' amount = '3.00' ) ). + go_env->insert_test_data( lt_rental ). + go_env->insert_test_data( lt_charge ). + SELECT SINGLE charge_count, total_amount FROM {{p}}i_rental_total WHERE rental_id = 'A1' + INTO @DATA(ls_total). + cl_abap_unit_assert=>assert_equals( exp = 2 act = ls_total-charge_count ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '15.00' ) + act = CONV decfloat34( ls_total-total_amount ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0165/seed/charge.tabl.asabap b/tasks_gen/eval/G0165/seed/charge.tabl.asabap new file mode 100644 index 0000000..429bb23 --- /dev/null +++ b/tasks_gen/eval/G0165/seed/charge.tabl.asabap @@ -0,0 +1,13 @@ +@EndUserText.label : 'Rental charge' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}charge { + key client : abap.clnt not null; + key rental_id : abap.char(10) not null; + key charge_no : abap.int4 not null; + customer : abap.char(10); + charge_type : abap.char(4); + amount : abap.dec(15,2); +} diff --git a/tasks_gen/eval/G0165/seed/i_rental_total.ddls.asddls b/tasks_gen/eval/G0165/seed/i_rental_total.ddls.asddls new file mode 100644 index 0000000..5b383e9 --- /dev/null +++ b/tasks_gen/eval/G0165/seed/i_rental_total.ddls.asddls @@ -0,0 +1,14 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Rental totals' +define view entity {{P}}I_RENTAL_TOTAL + as select from {{p}}rental as r + inner join {{p}}charge as c on c.customer = r.customer +{ + key r.rental_id as rental_id, + r.customer as customer, + count( * ) as charge_count, + sum( c.amount ) as total_amount +} +group by + r.rental_id, + r.customer diff --git a/tasks_gen/eval/G0165/seed/rental.tabl.asabap b/tasks_gen/eval/G0165/seed/rental.tabl.asabap new file mode 100644 index 0000000..2ae6702 --- /dev/null +++ b/tasks_gen/eval/G0165/seed/rental.tabl.asabap @@ -0,0 +1,11 @@ +@EndUserText.label : 'Rental header' +@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; + customer : abap.char(10); + pickup_date : abap.dats; +} diff --git a/tasks_gen/eval/G0165/spec.md b/tasks_gen/eval/G0165/spec.md new file mode 100644 index 0000000..1b225d4 --- /dev/null +++ b/tasks_gen/eval/G0165/spec.md @@ -0,0 +1,33 @@ +# 1. Goal +The CDS view entity {{P}}I_RENTAL_TOTAL in package $TMP shows the charges of each rental. Users report that the view gives wrong totals and wrong counts when a customer has more than one rental. Fix the view in place. All other behavior stays the same. + +# 2. Open questions +None. + +# 3. Context +- Table {{P}}RENTAL (rental header), package $TMP. Key: RENTAL_ID (CHAR 10). Fields: CUSTOMER (CHAR 10), PICKUP_DATE (DATS). +- Table {{P}}CHARGE (rental charge), package $TMP. Key: RENTAL_ID (CHAR 10), CHARGE_NO (INT4). Fields: CUSTOMER (CHAR 10), CHARGE_TYPE (CHAR 4), AMOUNT (DEC 15,2). +- The CDS view entity {{P}}I_RENTAL_TOTAL already exists in package $TMP. It is faulty. + +# 4. Contract +- Fix the CDS view entity {{P}}I_RENTAL_TOTAL in package $TMP. +- Elements, with these names: RENTAL_ID (key), CUSTOMER, CHARGE_COUNT, TOTAL_AMOUNT. +- No authorization check (#NOT_REQUIRED). + +# 5. Business rules +1. Show one row for each rental that has at least one charge. Do not show a rental without charges. +2. CHARGE_COUNT is the number of charges of the rental. +3. TOTAL_AMOUNT is the sum of AMOUNT of all charges of the rental, with 2 decimals. +4. CUSTOMER is the customer of the rental. +5. All other behavior of the view stays the same. + +# 6. Constraints +- Release target: 8.16. +- Coding standards: Clean ABAP. +- Out of scope: do not change {{P}}RENTAL and {{P}}CHARGE. +- Use "define view entity". + +# 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/eval/G0165/task.json b/tasks_gen/eval/G0165/task.json new file mode 100644 index 0000000..fbc7741 --- /dev/null +++ b/tasks_gen/eval/G0165/task.json @@ -0,0 +1,71 @@ +{ + "id": "G0165", + "category": "I", + "object_type": "DDLS", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 40, + "max_activations": 10 + }, + "seed": [ + { + "type": "TABL", + "name": "{{P}}RENTAL", + "file": "seed/rental.tabl.asabap", + "description": "Rental header" + }, + { + "type": "TABL", + "name": "{{P}}CHARGE", + "file": "seed/charge.tabl.asabap", + "description": "Rental charge" + }, + { + "type": "DDLS", + "name": "{{P}}I_RENTAL_TOTAL", + "file": "seed/i_rental_total.ddls.asddls", + "description": "Faulty rental totals view" + } + ], + "contract": [ + { + "type": "DDLS", + "name": "{{P}}I_RENTAL_TOTAL", + "fields": [ + "RENTAL_ID", + "CUSTOMER", + "CHARGE_COUNT", + "TOTAL_AMOUNT" + ] + } + ], + "out_of_scope": [ + "{{P}}RENTAL", + "{{P}}CHARGE" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T_RENTAL_HIDDEN", + "file": "hidden/t_rental_hidden.clas.abap", + "description": "Hidden tests for the rental totals view" + } + ], + "reference": [ + { + "type": "DDLS", + "name": "{{P}}I_RENTAL_TOTAL", + "file": "reference/i_rental_total.ddls.asddls", + "description": "Fixed rental totals view" + }, + { + "type": "CLAS", + "name": "{{P}}T_RENTAL_TEST", + "file": "reference/t_rental_test.clas.abap", + "description": "Own tests for the rental totals view" + } + ], + "craft_checks": [] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0166/faulty/m0_i_play_stats.ddls.asddls b/tasks_gen/eval/G0166/faulty/m0_i_play_stats.ddls.asddls new file mode 100644 index 0000000..2e78142 --- /dev/null +++ b/tasks_gen/eval/G0166/faulty/m0_i_play_stats.ddls.asddls @@ -0,0 +1,15 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Play statistics' +define view entity {{P}}I_PLAY_STATS + as select from {{p}}play as play + left outer join {{p}}perf as perf on perf.play_id = play.play_id +{ + key play.play_id as play_id, + play.title as title, + count( * ) as performance_count, + sum( perf.tickets_sold ) as total_tickets, + sum( perf.revenue ) as total_revenue +} +group by + play.play_id, + play.title diff --git a/tasks_gen/eval/G0166/faulty/m1_i_play_stats.ddls.asddls b/tasks_gen/eval/G0166/faulty/m1_i_play_stats.ddls.asddls new file mode 100644 index 0000000..a34663f --- /dev/null +++ b/tasks_gen/eval/G0166/faulty/m1_i_play_stats.ddls.asddls @@ -0,0 +1,15 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Play statistics' +define view entity {{P}}I_PLAY_STATS + as select from {{p}}play as play + inner join {{p}}perf as perf on perf.play_id <> play.play_id +{ + key play.play_id as play_id, + play.title as title, + count( * ) as performance_count, + sum( perf.tickets_sold ) as total_tickets, + sum( perf.revenue ) as total_revenue +} +group by + play.play_id, + play.title diff --git a/tasks_gen/eval/G0166/faulty/m2_i_play_stats.ddls.asddls b/tasks_gen/eval/G0166/faulty/m2_i_play_stats.ddls.asddls new file mode 100644 index 0000000..83f50cb --- /dev/null +++ b/tasks_gen/eval/G0166/faulty/m2_i_play_stats.ddls.asddls @@ -0,0 +1,15 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Play statistics' +define view entity {{P}}I_PLAY_STATS + as select from {{p}}play as play + inner join {{p}}perf as perf on perf.play_id = play.play_id +{ + key play.play_id as play_id, + play.title as title, + count( * ) as performance_count, + max( perf.tickets_sold ) as total_tickets, + sum( perf.revenue ) as total_revenue +} +group by + play.play_id, + play.title diff --git a/tasks_gen/eval/G0166/faulty/m3_i_play_stats.ddls.asddls b/tasks_gen/eval/G0166/faulty/m3_i_play_stats.ddls.asddls new file mode 100644 index 0000000..72d1a42 --- /dev/null +++ b/tasks_gen/eval/G0166/faulty/m3_i_play_stats.ddls.asddls @@ -0,0 +1,15 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Play statistics' +define view entity {{P}}I_PLAY_STATS + as select from {{p}}play as play + inner join {{p}}perf as perf on perf.play_id = play.play_id +{ + key play.play_id as play_id, + play.title as title, + count( * ) as performance_count, + sum( perf.tickets_sold ) as total_tickets, + max( perf.revenue ) as total_revenue +} +group by + play.play_id, + play.title diff --git a/tasks_gen/eval/G0166/generation.json b/tasks_gen/eval/G0166/generation.json new file mode 100644 index 0000000..1387a10 --- /dev/null +++ b/tasks_gen/eval/G0166/generation.json @@ -0,0 +1,19 @@ +{ + "id": "G0166", + "pool": "eval", + "object_type": "DDLS", + "category": "I", + "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/eval/G0166/hidden/t20_hidden.clas.abap b/tasks_gen/eval/G0166/hidden/t20_hidden.clas.abap new file mode 100644 index 0000000..f86f78c --- /dev/null +++ b/tasks_gen/eval/G0166/hidden/t20_hidden.clas.abap @@ -0,0 +1,103 @@ +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_cds_test_environment. + CLASS-METHODS class_setup. + CLASS-METHODS class_teardown. + METHODS setup. + METHODS one_row_per_play FOR TESTING. + METHODS performance_count FOR TESTING. + METHODS total_tickets FOR TESTING. + METHODS total_revenue FOR TESTING. + METHODS play_without_perf FOR TESTING. + METHODS title_shown FOR TESTING. + METHODS single_performance FOR TESTING. + METHODS decimals FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t20_hidden IMPLEMENTATION. + METHOD class_setup. + go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_PLAY_STATS' ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + DATA lt_play TYPE STANDARD TABLE OF {{p}}play WITH EMPTY KEY. + DATA lt_perf TYPE STANDARD TABLE OF {{p}}perf WITH EMPTY KEY. + go_env->clear_doubles( ). + lt_play = VALUE #( ( play_id = 'P1' title = 'HAMLET' genre = 'DRAMA' director = 'A' ) + ( play_id = 'P2' title = 'CARMEN' genre = 'OPERA' director = 'B' ) + ( play_id = 'P3' title = 'ROMEO' genre = 'DRAMA' director = 'C' ) + ( play_id = 'P4' title = 'TOSCA' genre = 'OPERA' director = 'D' ) ). + lt_perf = VALUE #( ( play_id = 'P1' perf_no = 1 tickets_sold = 100 revenue = '1000.00' ) + ( play_id = 'P1' perf_no = 2 tickets_sold = 150 revenue = '1500.00' ) + ( play_id = 'P1' perf_no = 3 tickets_sold = 50 revenue = '500.00' ) + ( play_id = 'P2' perf_no = 1 tickets_sold = 200 revenue = '4000.00' ) + ( play_id = 'P4' perf_no = 1 tickets_sold = 10 revenue = '10.10' ) + ( play_id = 'P4' perf_no = 2 tickets_sold = 1 revenue = '0.05' ) ). + go_env->insert_test_data( lt_play ). + go_env->insert_test_data( lt_perf ). + ENDMETHOD. + + METHOD one_row_per_play. + SELECT COUNT(*) FROM {{p}}i_play_stats INTO @DATA(lv_rows). + cl_abap_unit_assert=>assert_equals( exp = 3 act = lv_rows ). + ENDMETHOD. + + METHOD performance_count. + SELECT SINGLE performance_count FROM {{p}}i_play_stats + WHERE play_id = 'P1' INTO @DATA(lv_count). + cl_abap_unit_assert=>assert_equals( exp = 3 act = lv_count ). + ENDMETHOD. + + METHOD total_tickets. + SELECT SINGLE total_tickets FROM {{p}}i_play_stats + WHERE play_id = 'P1' INTO @DATA(lv_tickets). + cl_abap_unit_assert=>assert_equals( exp = 300 act = lv_tickets ). + ENDMETHOD. + + METHOD total_revenue. + SELECT SINGLE total_revenue FROM {{p}}i_play_stats + WHERE play_id = 'P1' INTO @DATA(lv_revenue). + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( '3000.00' ) + act = CONV decfloat34( lv_revenue ) ). + ENDMETHOD. + + METHOD play_without_perf. + SELECT COUNT(*) FROM {{p}}i_play_stats + WHERE play_id = 'P3' INTO @DATA(lv_rows). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_rows ). + ENDMETHOD. + + METHOD title_shown. + SELECT SINGLE title FROM {{p}}i_play_stats + WHERE play_id = 'P1' INTO @DATA(lv_title). + cl_abap_unit_assert=>assert_equals( exp = 'HAMLET' act = lv_title ). + ENDMETHOD. + + METHOD single_performance. + SELECT SINGLE performance_count, total_tickets, total_revenue + FROM {{p}}i_play_stats + WHERE play_id = 'P2' INTO @DATA(ls_row). + cl_abap_unit_assert=>assert_equals( exp = 1 act = ls_row-performance_count ). + cl_abap_unit_assert=>assert_equals( exp = 200 act = ls_row-total_tickets ). + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( '4000.00' ) + act = CONV decfloat34( ls_row-total_revenue ) ). + ENDMETHOD. + + METHOD decimals. + SELECT SINGLE total_tickets, total_revenue + FROM {{p}}i_play_stats + WHERE play_id = 'P4' INTO @DATA(ls_row). + cl_abap_unit_assert=>assert_equals( exp = 11 act = ls_row-total_tickets ). + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( '10.15' ) + act = CONV decfloat34( ls_row-total_revenue ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0166/mutation.json b/tasks_gen/eval/G0166/mutation.json new file mode 100644 index 0000000..895fb61 --- /dev/null +++ b/tasks_gen/eval/G0166/mutation.json @@ -0,0 +1,53 @@ +{ + "task": "G0166", + "mutants": [ + { + "object": "{{P}}I_PLAY_STATS", + "mutant": "line 5: inner join -> left outer join (join)", + "status": "killed", + "hidden": "6/8", + "failed_tests": [ + "ONE_ROW_PER_PLAY", + "PLAY_WITHOUT_PERF" + ] + }, + { + "object": "{{P}}I_PLAY_STATS", + "mutant": "line 5: = -> <> (eq)", + "status": "killed", + "hidden": "2/8", + "failed_tests": [ + "DECIMALS", + "ONE_ROW_PER_PLAY", + "PLAY_WITHOUT_PERF", + "SINGLE_PERFORMANCE", + "TOTAL_REVENUE", + "TOTAL_TICKETS" + ] + }, + { + "object": "{{P}}I_PLAY_STATS", + "mutant": "line 10: sum( -> max( (agg)", + "status": "killed", + "hidden": "6/8", + "failed_tests": [ + "DECIMALS", + "TOTAL_TICKETS" + ] + }, + { + "object": "{{P}}I_PLAY_STATS", + "mutant": "line 11: sum( -> max( (agg)", + "status": "killed", + "hidden": "6/8", + "failed_tests": [ + "DECIMALS", + "TOTAL_REVENUE" + ] + } + ], + "valid": 4, + "killed": 4, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0166/reference/i_play_stats.ddls.asddls b/tasks_gen/eval/G0166/reference/i_play_stats.ddls.asddls new file mode 100644 index 0000000..c4cb02e --- /dev/null +++ b/tasks_gen/eval/G0166/reference/i_play_stats.ddls.asddls @@ -0,0 +1,15 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Play statistics' +define view entity {{P}}I_PLAY_STATS + as select from {{p}}play as play + inner join {{p}}perf as perf on perf.play_id = play.play_id +{ + key play.play_id as play_id, + play.title as title, + count( * ) as performance_count, + sum( perf.tickets_sold ) as total_tickets, + sum( perf.revenue ) as total_revenue +} +group by + play.play_id, + play.title diff --git a/tasks_gen/eval/G0166/reference/t20_test.clas.abap b/tasks_gen/eval/G0166/reference/t20_test.clas.abap new file mode 100644 index 0000000..bb355d7 --- /dev/null +++ b/tasks_gen/eval/G0166/reference/t20_test.clas.abap @@ -0,0 +1,42 @@ +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_cds_test_environment. + CLASS-METHODS class_setup. + CLASS-METHODS class_teardown. + METHODS setup. + METHODS totals_of_one_play FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t20_test IMPLEMENTATION. + METHOD class_setup. + go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_PLAY_STATS' ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + go_env->clear_doubles( ). + ENDMETHOD. + + METHOD totals_of_one_play. + DATA lt_play TYPE STANDARD TABLE OF {{p}}play WITH EMPTY KEY. + DATA lt_perf TYPE STANDARD TABLE OF {{p}}perf WITH EMPTY KEY. + lt_play = VALUE #( ( play_id = 'A' title = 'TEST' genre = 'DRAMA' director = 'X' ) ). + lt_perf = VALUE #( ( play_id = 'A' perf_no = 1 tickets_sold = 10 revenue = '1.00' ) + ( play_id = 'A' perf_no = 2 tickets_sold = 20 revenue = '2.00' ) ). + go_env->insert_test_data( lt_play ). + go_env->insert_test_data( lt_perf ). + SELECT SINGLE performance_count, total_tickets, total_revenue + FROM {{p}}i_play_stats + WHERE play_id = 'A' INTO @DATA(ls_row). + cl_abap_unit_assert=>assert_equals( exp = 2 act = ls_row-performance_count ). + cl_abap_unit_assert=>assert_equals( exp = 30 act = ls_row-total_tickets ). + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( 3 ) + act = CONV decfloat34( ls_row-total_revenue ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0166/seed/i_play_stats.ddls.asddls b/tasks_gen/eval/G0166/seed/i_play_stats.ddls.asddls new file mode 100644 index 0000000..6299bca --- /dev/null +++ b/tasks_gen/eval/G0166/seed/i_play_stats.ddls.asddls @@ -0,0 +1,16 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Play statistics' +define view entity {{P}}I_PLAY_STATS + as select from {{p}}play as play + inner join {{p}}perf as perf on perf.play_id = play.play_id +{ + key play.play_id as play_id, + play.title as title, + count( * ) as performance_count, + sum( perf.tickets_sold ) as total_tickets, + sum( perf.revenue ) as total_revenue +} +group by + play.play_id, + play.title, + perf.perf_no diff --git a/tasks_gen/eval/G0166/seed/perf.tabl.asabap b/tasks_gen/eval/G0166/seed/perf.tabl.asabap new file mode 100644 index 0000000..81258d3 --- /dev/null +++ b/tasks_gen/eval/G0166/seed/perf.tabl.asabap @@ -0,0 +1,13 @@ +@EndUserText.label : 'Performance' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}perf { + key client : abap.clnt not null; + key play_id : abap.char(10) not null; + key perf_no : abap.int4 not null; + perf_date : abap.dats; + tickets_sold : abap.int4; + revenue : abap.dec(15,2); +} diff --git a/tasks_gen/eval/G0166/seed/play.tabl.asabap b/tasks_gen/eval/G0166/seed/play.tabl.asabap new file mode 100644 index 0000000..c21b385 --- /dev/null +++ b/tasks_gen/eval/G0166/seed/play.tabl.asabap @@ -0,0 +1,12 @@ +@EndUserText.label : 'Play' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}play { + key client : abap.clnt not null; + key play_id : abap.char(10) not null; + title : abap.char(40); + genre : abap.char(20); + director : abap.char(40); +} diff --git a/tasks_gen/eval/G0166/spec.md b/tasks_gen/eval/G0166/spec.md new file mode 100644 index 0000000..4227af0 --- /dev/null +++ b/tasks_gen/eval/G0166/spec.md @@ -0,0 +1,43 @@ +# 1. Goal +The CDS view entity {{P}}I_PLAY_STATS in package $TMP shows statistics for the plays +of a theatre. Users report two defects: + +- A play with more than one performance appears more than once in the result. +- For such a play, PERFORMANCE_COUNT is 1, and TOTAL_TICKETS and TOTAL_REVENUE show + the values of one performance only. + +Fix the view so that it shows one row for each play that has at least one performance, +with the correct totals. All other behavior stays the same. + +# 2. Open questions +None. + +# 3. Context +- Table {{P}}PLAY (play), package $TMP. Key: PLAY_ID (CHAR 10). + Further fields: TITLE (CHAR 40), GENRE (CHAR 20), DIRECTOR (CHAR 40). +- Table {{P}}PERF (performance), package $TMP. Key: PLAY_ID (CHAR 10), PERF_NO (INT4). + Further fields: PERF_DATE (DATS), TICKETS_SOLD (INT4), REVENUE (DEC 15,2). +- The CDS view entity {{P}}I_PLAY_STATS in package $TMP reads both tables. + +# 4. Contract +- Fix the CDS view entity {{P}}I_PLAY_STATS in package $TMP. Keep the name and the + elements of the view. +- Elements, with these names: PLAY_ID (key), TITLE, PERFORMANCE_COUNT, TOTAL_TICKETS, + TOTAL_REVENUE. +- No authorization check (#NOT_REQUIRED). + +# 5. Business rules +1. PERFORMANCE_COUNT is the number of performances of the play. +2. TOTAL_TICKETS is the sum of TICKETS_SOLD of all performances of the play. +3. TOTAL_REVENUE is the sum of REVENUE of all performances of the play, with 2 decimals. +4. TITLE is the title of the play. + +# 6. Constraints +- Release target: 8.16. +- Package: $TMP. +- Out of scope: do not change {{P}}PLAY and {{P}}PERF. + +# 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/eval/G0166/task.json b/tasks_gen/eval/G0166/task.json new file mode 100644 index 0000000..138d8d9 --- /dev/null +++ b/tasks_gen/eval/G0166/task.json @@ -0,0 +1,72 @@ +{ + "id": "G0166", + "category": "I", + "object_type": "DDLS", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 30, + "max_activations": 8 + }, + "seed": [ + { + "type": "TABL", + "name": "{{P}}PLAY", + "file": "seed/play.tabl.asabap", + "description": "Play" + }, + { + "type": "TABL", + "name": "{{P}}PERF", + "file": "seed/perf.tabl.asabap", + "description": "Performance" + }, + { + "type": "DDLS", + "name": "{{P}}I_PLAY_STATS", + "file": "seed/i_play_stats.ddls.asddls", + "description": "Faulty play statistics view" + } + ], + "contract": [ + { + "type": "DDLS", + "name": "{{P}}I_PLAY_STATS", + "fields": [ + "PLAY_ID", + "TITLE", + "PERFORMANCE_COUNT", + "TOTAL_TICKETS", + "TOTAL_REVENUE" + ] + } + ], + "out_of_scope": [ + "{{P}}PLAY", + "{{P}}PERF" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T20_HIDDEN", + "file": "hidden/t20_hidden.clas.abap", + "description": "T20 hidden tests" + } + ], + "reference": [ + { + "type": "DDLS", + "name": "{{P}}I_PLAY_STATS", + "file": "reference/i_play_stats.ddls.asddls", + "description": "Fixed play statistics view" + }, + { + "type": "CLAS", + "name": "{{P}}T20_TEST", + "file": "reference/t20_test.clas.abap", + "description": "T20 own tests" + } + ], + "craft_checks": [] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0167/faulty/m0_move_pricer.clas.abap b/tasks_gen/eval/G0167/faulty/m0_move_pricer.clas.abap new file mode 100644 index 0000000..e716780 --- /dev/null +++ b/tasks_gen/eval/G0167/faulty/m0_move_pricer.clas.abap @@ -0,0 +1,74 @@ +CLASS {{p}}move_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES ty_price TYPE p LENGTH 8 DECIMALS 2. + + CONSTANTS: + c_base_fee TYPE ty_price VALUE '250.00', + c_volume_fee TYPE ty_price VALUE '40.00', + c_distance_fee TYPE ty_price VALUE '1.20', + c_floor_fee TYPE ty_price VALUE '15.00', + c_packing_fee TYPE ty_price VALUE '180.00', + c_weekend_rate TYPE ty_price VALUE '0.12'. + + METHODS calculate + IMPORTING iv_distance_km TYPE i + iv_volume_m3 TYPE i + iv_floor TYPE i + iv_packing TYPE abap_bool + iv_weekend TYPE abap_bool + RETURNING VALUE(rv_price) TYPE ty_price. + + PRIVATE SECTION. + METHODS subtotal + IMPORTING iv_distance_km TYPE i + iv_volume_m3 TYPE i + iv_floor TYPE i + iv_packing TYPE abap_bool + RETURNING VALUE(rv_subtotal) TYPE ty_price. + METHODS distance_fee + IMPORTING iv_distance_km TYPE i + RETURNING VALUE(rv_fee) TYPE ty_price. + METHODS floor_surcharge + IMPORTING iv_floor TYPE i + RETURNING VALUE(rv_surcharge) TYPE ty_price. + METHODS weekend_surcharge + IMPORTING iv_subtotal TYPE ty_price + RETURNING VALUE(rv_surcharge) TYPE ty_price. +ENDCLASS. + + +CLASS {{p}}move_pricer IMPLEMENTATION. + METHOD calculate. + DATA(lv_subtotal) = subtotal( iv_distance_km = iv_distance_km + iv_volume_m3 = iv_volume_m3 + iv_floor = iv_floor + iv_packing = iv_packing ). + rv_price = lv_subtotal. + IF iv_weekend = abap_false. + rv_price = rv_price + weekend_surcharge( lv_subtotal ). + ENDIF. + ENDMETHOD. + + METHOD subtotal. + rv_subtotal = c_base_fee + iv_volume_m3 * c_volume_fee + + distance_fee( iv_distance_km ) + + floor_surcharge( iv_floor ). + IF iv_packing = abap_true. + rv_subtotal = rv_subtotal + c_packing_fee. + ENDIF. + ENDMETHOD. + + METHOD distance_fee. + rv_fee = iv_distance_km * c_distance_fee. + ENDMETHOD. + + METHOD floor_surcharge. + IF iv_floor > 0. + rv_surcharge = iv_floor * c_floor_fee. + ENDIF. + ENDMETHOD. + + METHOD weekend_surcharge. + rv_surcharge = round( val = iv_subtotal * c_weekend_rate dec = 2 ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0167/faulty/m1_move_pricer.clas.abap b/tasks_gen/eval/G0167/faulty/m1_move_pricer.clas.abap new file mode 100644 index 0000000..b999229 --- /dev/null +++ b/tasks_gen/eval/G0167/faulty/m1_move_pricer.clas.abap @@ -0,0 +1,74 @@ +CLASS {{p}}move_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES ty_price TYPE p LENGTH 8 DECIMALS 2. + + CONSTANTS: + c_base_fee TYPE ty_price VALUE '250.00', + c_volume_fee TYPE ty_price VALUE '40.00', + c_distance_fee TYPE ty_price VALUE '1.20', + c_floor_fee TYPE ty_price VALUE '15.00', + c_packing_fee TYPE ty_price VALUE '180.00', + c_weekend_rate TYPE ty_price VALUE '0.12'. + + METHODS calculate + IMPORTING iv_distance_km TYPE i + iv_volume_m3 TYPE i + iv_floor TYPE i + iv_packing TYPE abap_bool + iv_weekend TYPE abap_bool + RETURNING VALUE(rv_price) TYPE ty_price. + + PRIVATE SECTION. + METHODS subtotal + IMPORTING iv_distance_km TYPE i + iv_volume_m3 TYPE i + iv_floor TYPE i + iv_packing TYPE abap_bool + RETURNING VALUE(rv_subtotal) TYPE ty_price. + METHODS distance_fee + IMPORTING iv_distance_km TYPE i + RETURNING VALUE(rv_fee) TYPE ty_price. + METHODS floor_surcharge + IMPORTING iv_floor TYPE i + RETURNING VALUE(rv_surcharge) TYPE ty_price. + METHODS weekend_surcharge + IMPORTING iv_subtotal TYPE ty_price + RETURNING VALUE(rv_surcharge) TYPE ty_price. +ENDCLASS. + + +CLASS {{p}}move_pricer IMPLEMENTATION. + METHOD calculate. + DATA(lv_subtotal) = subtotal( iv_distance_km = iv_distance_km + iv_volume_m3 = iv_volume_m3 + iv_floor = iv_floor + iv_packing = iv_packing ). + rv_price = lv_subtotal. + IF iv_weekend = abap_true. + rv_price = rv_price + weekend_surcharge( lv_subtotal ). + ENDIF. + ENDMETHOD. + + METHOD subtotal. + rv_subtotal = c_base_fee + iv_volume_m3 * c_volume_fee + + distance_fee( iv_distance_km ) + + floor_surcharge( iv_floor ). + IF iv_packing <> abap_true. + rv_subtotal = rv_subtotal + c_packing_fee. + ENDIF. + ENDMETHOD. + + METHOD distance_fee. + rv_fee = iv_distance_km * c_distance_fee. + ENDMETHOD. + + METHOD floor_surcharge. + IF iv_floor > 0. + rv_surcharge = iv_floor * c_floor_fee. + ENDIF. + ENDMETHOD. + + METHOD weekend_surcharge. + rv_surcharge = round( val = iv_subtotal * c_weekend_rate dec = 2 ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0167/faulty/m2_move_pricer.clas.abap b/tasks_gen/eval/G0167/faulty/m2_move_pricer.clas.abap new file mode 100644 index 0000000..44c3c79 --- /dev/null +++ b/tasks_gen/eval/G0167/faulty/m2_move_pricer.clas.abap @@ -0,0 +1,74 @@ +CLASS {{p}}move_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES ty_price TYPE p LENGTH 8 DECIMALS 2. + + CONSTANTS: + c_base_fee TYPE ty_price VALUE '250.00', + c_volume_fee TYPE ty_price VALUE '40.00', + c_distance_fee TYPE ty_price VALUE '1.20', + c_floor_fee TYPE ty_price VALUE '15.00', + c_packing_fee TYPE ty_price VALUE '180.00', + c_weekend_rate TYPE ty_price VALUE '0.12'. + + METHODS calculate + IMPORTING iv_distance_km TYPE i + iv_volume_m3 TYPE i + iv_floor TYPE i + iv_packing TYPE abap_bool + iv_weekend TYPE abap_bool + RETURNING VALUE(rv_price) TYPE ty_price. + + PRIVATE SECTION. + METHODS subtotal + IMPORTING iv_distance_km TYPE i + iv_volume_m3 TYPE i + iv_floor TYPE i + iv_packing TYPE abap_bool + RETURNING VALUE(rv_subtotal) TYPE ty_price. + METHODS distance_fee + IMPORTING iv_distance_km TYPE i + RETURNING VALUE(rv_fee) TYPE ty_price. + METHODS floor_surcharge + IMPORTING iv_floor TYPE i + RETURNING VALUE(rv_surcharge) TYPE ty_price. + METHODS weekend_surcharge + IMPORTING iv_subtotal TYPE ty_price + RETURNING VALUE(rv_surcharge) TYPE ty_price. +ENDCLASS. + + +CLASS {{p}}move_pricer IMPLEMENTATION. + METHOD calculate. + DATA(lv_subtotal) = subtotal( iv_distance_km = iv_distance_km + iv_volume_m3 = iv_volume_m3 + iv_floor = iv_floor + iv_packing = iv_packing ). + rv_price = lv_subtotal. + IF iv_weekend = abap_true. + rv_price = rv_price + weekend_surcharge( lv_subtotal ). + ENDIF. + ENDMETHOD. + + METHOD subtotal. + rv_subtotal = c_base_fee + iv_volume_m3 * c_volume_fee + + distance_fee( iv_distance_km ) + + floor_surcharge( iv_floor ). + IF iv_packing = abap_true. + rv_subtotal = rv_subtotal + c_packing_fee. + ENDIF. + ENDMETHOD. + + METHOD distance_fee. + rv_fee = iv_distance_km * c_distance_fee. + ENDMETHOD. + + METHOD floor_surcharge. + IF iv_floor <= 0. + rv_surcharge = iv_floor * c_floor_fee. + ENDIF. + ENDMETHOD. + + METHOD weekend_surcharge. + rv_surcharge = round( val = iv_subtotal * c_weekend_rate dec = 2 ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0167/faulty/m3_move_pricer.clas.abap b/tasks_gen/eval/G0167/faulty/m3_move_pricer.clas.abap new file mode 100644 index 0000000..e18745d --- /dev/null +++ b/tasks_gen/eval/G0167/faulty/m3_move_pricer.clas.abap @@ -0,0 +1,74 @@ +CLASS {{p}}move_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES ty_price TYPE p LENGTH 8 DECIMALS 2. + + CONSTANTS: + c_base_fee TYPE ty_price VALUE '250.00', + c_volume_fee TYPE ty_price VALUE '40.00', + c_distance_fee TYPE ty_price VALUE '1.20', + c_floor_fee TYPE ty_price VALUE '15.00', + c_packing_fee TYPE ty_price VALUE '180.00', + c_weekend_rate TYPE ty_price VALUE '0.12'. + + METHODS calculate + IMPORTING iv_distance_km TYPE i + iv_volume_m3 TYPE i + iv_floor TYPE i + iv_packing TYPE abap_bool + iv_weekend TYPE abap_bool + RETURNING VALUE(rv_price) TYPE ty_price. + + PRIVATE SECTION. + METHODS subtotal + IMPORTING iv_distance_km TYPE i + iv_volume_m3 TYPE i + iv_floor TYPE i + iv_packing TYPE abap_bool + RETURNING VALUE(rv_subtotal) TYPE ty_price. + METHODS distance_fee + IMPORTING iv_distance_km TYPE i + RETURNING VALUE(rv_fee) TYPE ty_price. + METHODS floor_surcharge + IMPORTING iv_floor TYPE i + RETURNING VALUE(rv_surcharge) TYPE ty_price. + METHODS weekend_surcharge + IMPORTING iv_subtotal TYPE ty_price + RETURNING VALUE(rv_surcharge) TYPE ty_price. +ENDCLASS. + + +CLASS {{p}}move_pricer IMPLEMENTATION. + METHOD calculate. + DATA(lv_subtotal) = subtotal( iv_distance_km = iv_distance_km + iv_volume_m3 = iv_volume_m3 + iv_floor = iv_floor + iv_packing = iv_packing ). + rv_price = lv_subtotal. + IF iv_weekend = abap_true. + rv_price = rv_price + weekend_surcharge( lv_subtotal ). + ENDIF. + ENDMETHOD. + + METHOD subtotal. + rv_subtotal = c_base_fee + iv_volume_m3 * c_volume_fee + + distance_fee( iv_distance_km ) + + floor_surcharge( iv_floor ). + IF iv_packing = abap_true. + rv_subtotal = rv_subtotal + c_packing_fee. + ENDIF. + ENDMETHOD. + + METHOD distance_fee. + rv_fee = iv_distance_km * c_distance_fee. + ENDMETHOD. + + METHOD floor_surcharge. + IF iv_floor > 0. + rv_surcharge = iv_floor / c_floor_fee. + ENDIF. + ENDMETHOD. + + METHOD weekend_surcharge. + rv_surcharge = round( val = iv_subtotal * c_weekend_rate dec = 2 ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0167/faulty/m4_move_pricer.clas.abap b/tasks_gen/eval/G0167/faulty/m4_move_pricer.clas.abap new file mode 100644 index 0000000..27897c8 --- /dev/null +++ b/tasks_gen/eval/G0167/faulty/m4_move_pricer.clas.abap @@ -0,0 +1,74 @@ +CLASS {{p}}move_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES ty_price TYPE p LENGTH 8 DECIMALS 2. + + CONSTANTS: + c_base_fee TYPE ty_price VALUE '250.00', + c_volume_fee TYPE ty_price VALUE '40.00', + c_distance_fee TYPE ty_price VALUE '1.20', + c_floor_fee TYPE ty_price VALUE '15.00', + c_packing_fee TYPE ty_price VALUE '180.00', + c_weekend_rate TYPE ty_price VALUE '0.12'. + + METHODS calculate + IMPORTING iv_distance_km TYPE i + iv_volume_m3 TYPE i + iv_floor TYPE i + iv_packing TYPE abap_bool + iv_weekend TYPE abap_bool + RETURNING VALUE(rv_price) TYPE ty_price. + + PRIVATE SECTION. + METHODS subtotal + IMPORTING iv_distance_km TYPE i + iv_volume_m3 TYPE i + iv_floor TYPE i + iv_packing TYPE abap_bool + RETURNING VALUE(rv_subtotal) TYPE ty_price. + METHODS distance_fee + IMPORTING iv_distance_km TYPE i + RETURNING VALUE(rv_fee) TYPE ty_price. + METHODS floor_surcharge + IMPORTING iv_floor TYPE i + RETURNING VALUE(rv_surcharge) TYPE ty_price. + METHODS weekend_surcharge + IMPORTING iv_subtotal TYPE ty_price + RETURNING VALUE(rv_surcharge) TYPE ty_price. +ENDCLASS. + + +CLASS {{p}}move_pricer IMPLEMENTATION. + METHOD calculate. + DATA(lv_subtotal) = subtotal( iv_distance_km = iv_distance_km + iv_volume_m3 = iv_volume_m3 + iv_floor = iv_floor + iv_packing = iv_packing ). + rv_price = lv_subtotal. + IF iv_weekend = abap_true. + rv_price = rv_price + weekend_surcharge( lv_subtotal ). + ENDIF. + ENDMETHOD. + + METHOD subtotal. + rv_subtotal = c_base_fee + iv_volume_m3 * c_volume_fee + + distance_fee( iv_distance_km ) + + floor_surcharge( iv_floor ). + IF iv_packing = abap_true. + rv_subtotal = rv_subtotal + c_packing_fee. + ENDIF. + ENDMETHOD. + + METHOD distance_fee. + rv_fee = iv_distance_km * c_distance_fee. + ENDMETHOD. + + METHOD floor_surcharge. + IF iv_floor > 0. + rv_surcharge = iv_floor * c_floor_fee. + ENDIF. + ENDMETHOD. + + METHOD weekend_surcharge. + rv_surcharge = round( val = iv_subtotal / c_weekend_rate dec = 2 ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0167/generation.json b/tasks_gen/eval/G0167/generation.json new file mode 100644 index 0000000..be0c50f --- /dev/null +++ b/tasks_gen/eval/G0167/generation.json @@ -0,0 +1,19 @@ +{ + "id": "G0167", + "pool": "eval", + "object_type": "CLAS", + "category": "I", + "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/eval/G0167/hidden/move_pricer_hidden.clas.abap b/tasks_gen/eval/G0167/hidden/move_pricer_hidden.clas.abap new file mode 100644 index 0000000..a11a028 --- /dev/null +++ b/tasks_gen/eval/G0167/hidden/move_pricer_hidden.clas.abap @@ -0,0 +1,142 @@ +CLASS {{p}}move_pricer_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + TYPES ty_price TYPE p LENGTH 8 DECIMALS 2. + + DATA mo_cut TYPE REF TO {{p}}move_pricer. + + METHODS setup. + METHODS base_fee_only FOR TESTING. + METHODS volume_fee FOR TESTING. + METHODS distance_15_km FOR TESTING. + METHODS first_floor_surcharge FOR TESTING. + METHODS third_floor_surcharge FOR TESTING. + METHODS packing_fee FOR TESTING. + METHODS weekend_on_subtotal FOR TESTING. + METHODS weekend_with_packing FOR TESTING. + METHODS no_weekend_no_surcharge FOR TESTING. + METHODS combined_move FOR TESTING. + METHODS constants_unchanged FOR TESTING. +ENDCLASS. + + +CLASS {{p}}move_pricer_hidden IMPLEMENTATION. + METHOD setup. + mo_cut = NEW {{p}}move_pricer( ). + ENDMETHOD. + + METHOD base_fee_only. + cl_abap_unit_assert=>assert_equals( + exp = CONV ty_price( '250.00' ) + act = mo_cut->calculate( iv_distance_km = 0 + iv_volume_m3 = 0 + iv_floor = 0 + iv_packing = abap_false + iv_weekend = abap_false ) ). + ENDMETHOD. + + METHOD volume_fee. + cl_abap_unit_assert=>assert_equals( + exp = CONV ty_price( '410.00' ) + act = mo_cut->calculate( iv_distance_km = 0 + iv_volume_m3 = 4 + iv_floor = 0 + iv_packing = abap_false + iv_weekend = abap_false ) ). + ENDMETHOD. + + METHOD distance_15_km. + cl_abap_unit_assert=>assert_equals( + exp = CONV ty_price( '268.00' ) + act = mo_cut->calculate( iv_distance_km = 15 + iv_volume_m3 = 0 + iv_floor = 0 + iv_packing = abap_false + iv_weekend = abap_false ) ). + ENDMETHOD. + + METHOD first_floor_surcharge. + cl_abap_unit_assert=>assert_equals( + exp = CONV ty_price( '265.00' ) + act = mo_cut->calculate( iv_distance_km = 0 + iv_volume_m3 = 0 + iv_floor = 1 + iv_packing = abap_false + iv_weekend = abap_false ) ). + ENDMETHOD. + + METHOD third_floor_surcharge. + cl_abap_unit_assert=>assert_equals( + exp = CONV ty_price( '295.00' ) + act = mo_cut->calculate( iv_distance_km = 0 + iv_volume_m3 = 0 + iv_floor = 3 + iv_packing = abap_false + iv_weekend = abap_false ) ). + ENDMETHOD. + + METHOD packing_fee. + cl_abap_unit_assert=>assert_equals( + exp = CONV ty_price( '430.00' ) + act = mo_cut->calculate( iv_distance_km = 0 + iv_volume_m3 = 0 + iv_floor = 0 + iv_packing = abap_true + iv_weekend = abap_false ) ). + ENDMETHOD. + + METHOD weekend_on_subtotal. + cl_abap_unit_assert=>assert_equals( + exp = CONV ty_price( '441.28' ) + act = mo_cut->calculate( iv_distance_km = 20 + iv_volume_m3 = 3 + iv_floor = 0 + iv_packing = abap_false + iv_weekend = abap_true ) ). + ENDMETHOD. + + METHOD weekend_with_packing. + cl_abap_unit_assert=>assert_equals( + exp = CONV ty_price( '481.60' ) + act = mo_cut->calculate( iv_distance_km = 0 + iv_volume_m3 = 0 + iv_floor = 0 + iv_packing = abap_true + iv_weekend = abap_true ) ). + ENDMETHOD. + + METHOD no_weekend_no_surcharge. + cl_abap_unit_assert=>assert_equals( + exp = CONV ty_price( '482.00' ) + act = mo_cut->calculate( iv_distance_km = 10 + iv_volume_m3 = 1 + iv_floor = 0 + iv_packing = abap_true + iv_weekend = abap_false ) ). + ENDMETHOD. + + METHOD combined_move. + cl_abap_unit_assert=>assert_equals( + exp = CONV ty_price( '669.76' ) + act = mo_cut->calculate( iv_distance_km = 15 + iv_volume_m3 = 3 + iv_floor = 2 + iv_packing = abap_true + iv_weekend = abap_true ) ). + ENDMETHOD. + + METHOD constants_unchanged. + cl_abap_unit_assert=>assert_equals( exp = CONV ty_price( '250.00' ) + act = {{p}}move_pricer=>c_base_fee ). + cl_abap_unit_assert=>assert_equals( exp = CONV ty_price( '40.00' ) + act = {{p}}move_pricer=>c_volume_fee ). + cl_abap_unit_assert=>assert_equals( exp = CONV ty_price( '1.20' ) + act = {{p}}move_pricer=>c_distance_fee ). + cl_abap_unit_assert=>assert_equals( exp = CONV ty_price( '15.00' ) + act = {{p}}move_pricer=>c_floor_fee ). + cl_abap_unit_assert=>assert_equals( exp = CONV ty_price( '180.00' ) + act = {{p}}move_pricer=>c_packing_fee ). + cl_abap_unit_assert=>assert_equals( exp = CONV ty_price( '0.12' ) + act = {{p}}move_pricer=>c_weekend_rate ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0167/mutation.json b/tasks_gen/eval/G0167/mutation.json new file mode 100644 index 0000000..4e188e6 --- /dev/null +++ b/tasks_gen/eval/G0167/mutation.json @@ -0,0 +1,78 @@ +{ + "task": "G0167", + "mutants": [ + { + "object": "{{P}}MOVE_PRICER", + "mutant": "line 47: abap_true -> abap_false (bool)", + "status": "killed", + "hidden": "1/11", + "failed_tests": [ + "BASE_FEE_ONLY", + "COMBINED_MOVE", + "DISTANCE_15_KM", + "FIRST_FLOOR_SURCHARGE", + "NO_WEEKEND_NO_SURCHARGE", + "PACKING_FEE", + "THIRD_FLOOR_SURCHARGE", + "VOLUME_FEE", + "WEEKEND_ON_SUBTOTAL", + "WEEKEND_WITH_PACKING" + ] + }, + { + "object": "{{P}}MOVE_PRICER", + "mutant": "line 56: = -> <> (eq)", + "status": "killed", + "hidden": "1/11", + "failed_tests": [ + "BASE_FEE_ONLY", + "COMBINED_MOVE", + "DISTANCE_15_KM", + "FIRST_FLOOR_SURCHARGE", + "NO_WEEKEND_NO_SURCHARGE", + "PACKING_FEE", + "THIRD_FLOOR_SURCHARGE", + "VOLUME_FEE", + "WEEKEND_ON_SUBTOTAL", + "WEEKEND_WITH_PACKING" + ] + }, + { + "object": "{{P}}MOVE_PRICER", + "mutant": "line 66: > -> <= (rel)", + "status": "killed", + "hidden": "8/11", + "failed_tests": [ + "COMBINED_MOVE", + "FIRST_FLOOR_SURCHARGE", + "THIRD_FLOOR_SURCHARGE" + ] + }, + { + "object": "{{P}}MOVE_PRICER", + "mutant": "line 67: * -> / (arith)", + "status": "killed", + "hidden": "8/11", + "failed_tests": [ + "COMBINED_MOVE", + "FIRST_FLOOR_SURCHARGE", + "THIRD_FLOOR_SURCHARGE" + ] + }, + { + "object": "{{P}}MOVE_PRICER", + "mutant": "line 72: * -> / (arith)", + "status": "killed", + "hidden": "8/11", + "failed_tests": [ + "COMBINED_MOVE", + "WEEKEND_ON_SUBTOTAL", + "WEEKEND_WITH_PACKING" + ] + } + ], + "valid": 5, + "killed": 5, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0167/reference/move_pricer.clas.abap b/tasks_gen/eval/G0167/reference/move_pricer.clas.abap new file mode 100644 index 0000000..380a7e5 --- /dev/null +++ b/tasks_gen/eval/G0167/reference/move_pricer.clas.abap @@ -0,0 +1,74 @@ +CLASS {{p}}move_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES ty_price TYPE p LENGTH 8 DECIMALS 2. + + CONSTANTS: + c_base_fee TYPE ty_price VALUE '250.00', + c_volume_fee TYPE ty_price VALUE '40.00', + c_distance_fee TYPE ty_price VALUE '1.20', + c_floor_fee TYPE ty_price VALUE '15.00', + c_packing_fee TYPE ty_price VALUE '180.00', + c_weekend_rate TYPE ty_price VALUE '0.12'. + + METHODS calculate + IMPORTING iv_distance_km TYPE i + iv_volume_m3 TYPE i + iv_floor TYPE i + iv_packing TYPE abap_bool + iv_weekend TYPE abap_bool + RETURNING VALUE(rv_price) TYPE ty_price. + + PRIVATE SECTION. + METHODS subtotal + IMPORTING iv_distance_km TYPE i + iv_volume_m3 TYPE i + iv_floor TYPE i + iv_packing TYPE abap_bool + RETURNING VALUE(rv_subtotal) TYPE ty_price. + METHODS distance_fee + IMPORTING iv_distance_km TYPE i + RETURNING VALUE(rv_fee) TYPE ty_price. + METHODS floor_surcharge + IMPORTING iv_floor TYPE i + RETURNING VALUE(rv_surcharge) TYPE ty_price. + METHODS weekend_surcharge + IMPORTING iv_subtotal TYPE ty_price + RETURNING VALUE(rv_surcharge) TYPE ty_price. +ENDCLASS. + + +CLASS {{p}}move_pricer IMPLEMENTATION. + METHOD calculate. + DATA(lv_subtotal) = subtotal( iv_distance_km = iv_distance_km + iv_volume_m3 = iv_volume_m3 + iv_floor = iv_floor + iv_packing = iv_packing ). + rv_price = lv_subtotal. + IF iv_weekend = abap_true. + rv_price = rv_price + weekend_surcharge( lv_subtotal ). + ENDIF. + ENDMETHOD. + + METHOD subtotal. + rv_subtotal = c_base_fee + iv_volume_m3 * c_volume_fee + + distance_fee( iv_distance_km ) + + floor_surcharge( iv_floor ). + IF iv_packing = abap_true. + rv_subtotal = rv_subtotal + c_packing_fee. + ENDIF. + ENDMETHOD. + + METHOD distance_fee. + rv_fee = iv_distance_km * c_distance_fee. + ENDMETHOD. + + METHOD floor_surcharge. + IF iv_floor > 0. + rv_surcharge = iv_floor * c_floor_fee. + ENDIF. + ENDMETHOD. + + METHOD weekend_surcharge. + rv_surcharge = round( val = iv_subtotal * c_weekend_rate dec = 2 ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0167/reference/move_pricer.testclasses.abap b/tasks_gen/eval/G0167/reference/move_pricer.testclasses.abap new file mode 100644 index 0000000..bf70bd7 --- /dev/null +++ b/tasks_gen/eval/G0167/reference/move_pricer.testclasses.abap @@ -0,0 +1,81 @@ +CLASS ltc_move_pricer DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + TYPES ty_price TYPE p LENGTH 8 DECIMALS 2. + + DATA mo_cut TYPE REF TO {{p}}move_pricer. + + METHODS setup. + METHODS base_fee_only FOR TESTING. + METHODS distance_fee FOR TESTING. + METHODS first_floor FOR TESTING. + METHODS packing_fee FOR TESTING. + METHODS weekend_surcharge FOR TESTING. + METHODS combined_move FOR TESTING. +ENDCLASS. + + +CLASS ltc_move_pricer IMPLEMENTATION. + METHOD setup. + mo_cut = NEW {{p}}move_pricer( ). + ENDMETHOD. + + METHOD base_fee_only. + cl_abap_unit_assert=>assert_equals( + exp = CONV ty_price( '250.00' ) + act = mo_cut->calculate( iv_distance_km = 0 + iv_volume_m3 = 0 + iv_floor = 0 + iv_packing = abap_false + iv_weekend = abap_false ) ). + ENDMETHOD. + + METHOD distance_fee. + cl_abap_unit_assert=>assert_equals( + exp = CONV ty_price( '268.00' ) + act = mo_cut->calculate( iv_distance_km = 15 + iv_volume_m3 = 0 + iv_floor = 0 + iv_packing = abap_false + iv_weekend = abap_false ) ). + ENDMETHOD. + + METHOD first_floor. + cl_abap_unit_assert=>assert_equals( + exp = CONV ty_price( '265.00' ) + act = mo_cut->calculate( iv_distance_km = 0 + iv_volume_m3 = 0 + iv_floor = 1 + iv_packing = abap_false + iv_weekend = abap_false ) ). + ENDMETHOD. + + METHOD packing_fee. + cl_abap_unit_assert=>assert_equals( + exp = CONV ty_price( '430.00' ) + act = mo_cut->calculate( iv_distance_km = 0 + iv_volume_m3 = 0 + iv_floor = 0 + iv_packing = abap_true + iv_weekend = abap_false ) ). + ENDMETHOD. + + METHOD weekend_surcharge. + cl_abap_unit_assert=>assert_equals( + exp = CONV ty_price( '441.28' ) + act = mo_cut->calculate( iv_distance_km = 20 + iv_volume_m3 = 3 + iv_floor = 0 + iv_packing = abap_false + iv_weekend = abap_true ) ). + ENDMETHOD. + + METHOD combined_move. + cl_abap_unit_assert=>assert_equals( + exp = CONV ty_price( '669.76' ) + act = mo_cut->calculate( iv_distance_km = 15 + iv_volume_m3 = 3 + iv_floor = 2 + iv_packing = abap_true + iv_weekend = abap_true ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0167/seed/move_pricer.clas.abap b/tasks_gen/eval/G0167/seed/move_pricer.clas.abap new file mode 100644 index 0000000..25b20e4 --- /dev/null +++ b/tasks_gen/eval/G0167/seed/move_pricer.clas.abap @@ -0,0 +1,48 @@ +CLASS {{p}}move_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES ty_price TYPE p LENGTH 8 DECIMALS 2. + + CONSTANTS: + c_base_fee TYPE ty_price VALUE '250.00', + c_volume_fee TYPE ty_price VALUE '40.00', + c_distance_fee TYPE ty_price VALUE '1.20', + c_floor_fee TYPE ty_price VALUE '15.00', + c_packing_fee TYPE ty_price VALUE '180.00', + c_weekend_rate TYPE ty_price VALUE '0.12'. + + METHODS calculate + IMPORTING iv_distance_km TYPE i + iv_volume_m3 TYPE i + iv_floor TYPE i + iv_packing TYPE abap_bool + iv_weekend TYPE abap_bool + RETURNING VALUE(rv_price) TYPE ty_price. + + PRIVATE SECTION. + METHODS distance_fee + IMPORTING iv_distance_km TYPE i + RETURNING VALUE(rv_fee) TYPE ty_price. +ENDCLASS. + + +CLASS {{p}}move_pricer IMPLEMENTATION. + METHOD calculate. + DATA lv_price TYPE ty_price. + lv_price = c_base_fee + iv_volume_m3 * c_volume_fee. + lv_price = lv_price + distance_fee( iv_distance_km ). + IF iv_floor > 0. + lv_price = lv_price + ( iv_floor - 1 ) * c_floor_fee. + ENDIF. + IF iv_packing = abap_true. + lv_price = lv_price + c_packing_fee. + ENDIF. + IF iv_weekend = abap_true. + lv_price = lv_price + round( val = c_base_fee * c_weekend_rate dec = 2 ). + ENDIF. + rv_price = lv_price. + ENDMETHOD. + + METHOD distance_fee. + rv_fee = ( iv_distance_km DIV 10 ) * 10 * c_distance_fee. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0167/spec.md b/tasks_gen/eval/G0167/spec.md new file mode 100644 index 0000000..cc7b23b --- /dev/null +++ b/tasks_gen/eval/G0167/spec.md @@ -0,0 +1,64 @@ +# 1. Goal +The class {{P}}MOVE_PRICER calculates the price of a house move for a moving +company. Users report three defects in the calculation. Fix the class. All other +behavior stays the same. + +# 2. Open questions +None. + +# 3. Context +- The class {{P}}MOVE_PRICER exists in package $TMP. It is active. +- The class is public and final. It has a public constructor without parameters. +- The public section contains the type TY_PRICE and the constants C_BASE_FEE, + C_VOLUME_FEE, C_DISTANCE_FEE, C_FLOOR_FEE, C_PACKING_FEE and C_WEEKEND_RATE. +- The class has one public method: + CALCULATE + IMPORTING iv_distance_km TYPE i + iv_volume_m3 TYPE i + iv_floor TYPE i + iv_packing TYPE abap_bool + iv_weekend TYPE abap_bool + RETURNING VALUE(rv_price) TYPE ty_price. +- CALCULATE gives the price of one move. The price has these parts: a base fee, a + volume fee, a distance fee, a floor surcharge, a packing fee and a weekend + surcharge. + +# 4. Contract +- Fix the class {{P}}MOVE_PRICER in package $TMP. +- Keep the public interface. The type TY_PRICE, the constants and the signature of + CALCULATE stay the same. +- Do not add public methods. Do not rename the class. + +# 5. Business rules +The price has these parts: +1. Base fee: 250.00 EUR for each move. +2. Volume fee: 40.00 EUR for each cubic metre of the move (iv_volume_m3). +3. Distance fee: 1.20 EUR for each kilometre of the distance (iv_distance_km). +4. Floor surcharge: 15.00 EUR for each floor above the ground floor. iv_floor is + the floor number. Floor 0 is the ground floor. If iv_floor is 0 or less, the + surcharge is 0.00 EUR. +5. Packing fee: 180.00 EUR if iv_packing is abap_true. Else 0.00 EUR. +6. Subtotal: the sum of the parts 1 to 5. +7. Weekend surcharge: if iv_weekend is abap_true, add 12 % of the subtotal, + rounded to 2 decimal places. Else add 0.00 EUR. +8. The price is the subtotal plus the weekend surcharge. +The input values are not negative. + +Users report these defects: +- A move over 15 km is charged a distance fee for only 10 km. Every kilometre + must be charged. +- A move to the first floor is free. The first floor must cost 15.00 EUR. A move + to the third floor costs 30.00 EUR. It must cost 45.00 EUR. +- A weekend move is always charged a weekend surcharge of 30.00 EUR. The + surcharge must be 12 % of the subtotal. + +# 6. Constraints +- Release target: SAP_BASIS 8.16. +- Coding standards: Clean ABAP. Method length below 40 statements. No global + variables. No comment that restates the code. +- Out of scope: no other objects. + +# 7. Acceptance +- The class is active and has no syntax error. +- The hidden tests pass. +- Write your own ABAP Unit tests for the class. diff --git a/tasks_gen/eval/G0167/task.json b/tasks_gen/eval/G0167/task.json new file mode 100644 index 0000000..710471c --- /dev/null +++ b/tasks_gen/eval/G0167/task.json @@ -0,0 +1,47 @@ +{ + "id": "G0167", + "category": "I", + "object_type": "CLAS", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 40, + "max_activations": 10 + }, + "seed": [ + { + "type": "CLAS", + "name": "{{P}}MOVE_PRICER", + "file": "seed/move_pricer.clas.abap", + "description": "Faulty move price class with three defects" + } + ], + "contract": [ + { + "type": "CLAS", + "name": "{{P}}MOVE_PRICER" + } + ], + "out_of_scope": [], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}MOVE_PRICER_HIDDEN", + "file": "hidden/move_pricer_hidden.clas.abap", + "description": "Hidden tests for the move price class" + } + ], + "reference": [ + { + "type": "CLAS", + "name": "{{P}}MOVE_PRICER", + "file": "reference/move_pricer.clas.abap", + "description": "Corrected move price class", + "testclasses_file": "reference/move_pricer.testclasses.abap" + } + ], + "craft_checks": [ + "method_length" + ] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0168/task.json b/tasks_gen/eval/G0168/task.json index 6c82226..91d6a3a 100644 --- a/tasks_gen/eval/G0168/task.json +++ b/tasks_gen/eval/G0168/task.json @@ -19,8 +19,8 @@ ] }, "budget": { - "max_tool_calls": 30, - "max_activations": 5 + "max_tool_calls": 60, + "max_activations": 15 }, "seed": [ { diff --git a/tasks_gen/eval/G0169/generation.json b/tasks_gen/eval/G0169/generation.json new file mode 100644 index 0000000..668aae1 --- /dev/null +++ b/tasks_gen/eval/G0169/generation.json @@ -0,0 +1,14 @@ +{ + "id": "G0169", + "pool": "eval", + "object_type": "CLAS", + "category": "H", + "attempts": [ + { + "stage": "validate", + "oracle": 100, + "null": 30 + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0169/reference/cowork_fee.clas.abap b/tasks_gen/eval/G0169/reference/cowork_fee.clas.abap new file mode 100644 index 0000000..af5794e --- /dev/null +++ b/tasks_gen/eval/G0169/reference/cowork_fee.clas.abap @@ -0,0 +1,76 @@ +CLASS {{p}}cowork_fee DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES ty_desk TYPE c LENGTH 3. + TYPES ty_amount TYPE i. + METHODS constructor. + METHODS calculate_fee + IMPORTING + iv_desk TYPE ty_desk + iv_months TYPE i + iv_student TYPE abap_bool + iv_under_25 TYPE abap_bool + RETURNING + VALUE(rv_fee) TYPE ty_amount. + PRIVATE SECTION. + METHODS monthly_fee + IMPORTING + iv_desk TYPE ty_desk + iv_student TYPE abap_bool + iv_under_25 TYPE abap_bool + RETURNING + VALUE(rv_fee) TYPE ty_amount. +ENDCLASS. + +CLASS {{p}}cowork_fee IMPLEMENTATION. + METHOD constructor. + ENDMETHOD. + + METHOD calculate_fee. + IF iv_months < 1. + rv_fee = 0. + RETURN. + ENDIF. + DATA(lv_monthly) = monthly_fee( iv_desk = iv_desk + iv_student = iv_student + iv_under_25 = iv_under_25 ). + rv_fee = lv_monthly * iv_months. + ENDMETHOD. + + METHOD monthly_fee. + " Resolve the contradiction: the student rule wins over the under-25 rule. + IF iv_student = abap_true. + CASE iv_desk. + WHEN 'HOT'. + rv_fee = 160. + WHEN 'DED'. + rv_fee = 280. + WHEN 'PRI'. + rv_fee = 480. + WHEN OTHERS. + rv_fee = 0. + ENDCASE. + ELSEIF iv_under_25 = abap_true. + CASE iv_desk. + WHEN 'HOT'. + rv_fee = 150. + WHEN 'DED'. + rv_fee = 260. + WHEN 'PRI'. + rv_fee = 450. + WHEN OTHERS. + rv_fee = 0. + ENDCASE. + ELSE. + CASE iv_desk. + WHEN 'HOT'. + rv_fee = 200. + WHEN 'DED'. + rv_fee = 350. + WHEN 'PRI'. + rv_fee = 600. + WHEN OTHERS. + rv_fee = 0. + ENDCASE. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0169/reference/cowork_fee.testclasses.abap b/tasks_gen/eval/G0169/reference/cowork_fee.testclasses.abap new file mode 100644 index 0000000..e97ce34 --- /dev/null +++ b/tasks_gen/eval/G0169/reference/cowork_fee.testclasses.abap @@ -0,0 +1,60 @@ +CLASS ltc_cowork_fee DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + DATA mo_cut TYPE REF TO {{p}}cowork_fee. + METHODS setup. + METHODS hot_desk_no_discount FOR TESTING. + METHODS student_discount FOR TESTING. + METHODS under_25_discount FOR TESTING. + METHODS student_and_under_25 FOR TESTING. + METHODS invalid_desk FOR TESTING. + METHODS invalid_months FOR TESTING. +ENDCLASS. + +CLASS ltc_cowork_fee IMPLEMENTATION. + METHOD setup. + mo_cut = NEW {{p}}cowork_fee( ). + ENDMETHOD. + + METHOD hot_desk_no_discount. + cl_abap_unit_assert=>assert_equals( exp = 200 + act = mo_cut->calculate_fee( iv_desk = 'HOT' iv_months = 1 + iv_student = abap_false + iv_under_25 = abap_false ) ). + ENDMETHOD. + + METHOD student_discount. + cl_abap_unit_assert=>assert_equals( exp = 160 + act = mo_cut->calculate_fee( iv_desk = 'HOT' iv_months = 1 + iv_student = abap_true + iv_under_25 = abap_false ) ). + ENDMETHOD. + + METHOD under_25_discount. + cl_abap_unit_assert=>assert_equals( exp = 150 + act = mo_cut->calculate_fee( iv_desk = 'HOT' iv_months = 1 + iv_student = abap_false + iv_under_25 = abap_true ) ). + ENDMETHOD. + + METHOD student_and_under_25. + " The reference resolves the contradiction in favour of the student rule. + cl_abap_unit_assert=>assert_equals( exp = 160 + act = mo_cut->calculate_fee( iv_desk = 'HOT' iv_months = 1 + iv_student = abap_true + iv_under_25 = abap_true ) ). + ENDMETHOD. + + METHOD invalid_desk. + cl_abap_unit_assert=>assert_equals( exp = 0 + act = mo_cut->calculate_fee( iv_desk = 'XXX' iv_months = 1 + iv_student = abap_false + iv_under_25 = abap_false ) ). + ENDMETHOD. + + METHOD invalid_months. + cl_abap_unit_assert=>assert_equals( exp = 0 + act = mo_cut->calculate_fee( iv_desk = 'HOT' iv_months = 0 + iv_student = abap_false + iv_under_25 = abap_false ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0169/spec.md b/tasks_gen/eval/G0169/spec.md new file mode 100644 index 0000000..3d5458b --- /dev/null +++ b/tasks_gen/eval/G0169/spec.md @@ -0,0 +1,43 @@ +# 1. Goal +Calculate the monthly fee for a member of a coworking space. A billing program calls the calculation before it creates an invoice. The program needs one fee for each member. + +# 2. Open questions +None. + +# 3. Context +- Package $TMP is available. +- The class {{P}}COWORK_FEE does not exist yet. +- The billing program uses the public method of the class. + +# 4. Contract +- Create the class {{P}}COWORK_FEE in package $TMP. +- The class is public and final. +- The class has a public constructor without parameters. +- The class has one public method: + CALCULATE_FEE + IMPORTING + iv_desk TYPE ty_desk + iv_months TYPE i + iv_student TYPE abap_bool + iv_under_25 TYPE abap_bool + RETURNING + VALUE(rv_fee) TYPE ty_amount. +- Define the types ty_desk (C LENGTH 3) and ty_amount (TYPE i) in the public section. +- Do not add other public methods. + +# 5. Business rules +1. The desk type is HOT, DED, or PRI. The base monthly fee is 200 for HOT, 350 for DED, and 600 for PRI. If the desk type is not in this list, return 0. +2. The number of months must be at least 1. If iv_months is less than 1, return 0. +3. The fee is the monthly fee multiplied by the number of months. +4. If the member is a student, the monthly fee is 160 for HOT, 280 for DED, and 480 for PRI. +5. If the member is under 25, the monthly fee is 150 for HOT, 260 for DED, and 450 for PRI. + +# 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. + +# 7. Acceptance +- The class is active and has no syntax error. +- The class passes the ATC checks with no priority 1 or 2 findings. +- Write your own ABAP Unit tests for the class. diff --git a/tasks_gen/eval/G0169/task.json b/tasks_gen/eval/G0169/task.json new file mode 100644 index 0000000..0fe919b --- /dev/null +++ b/tasks_gen/eval/G0169/task.json @@ -0,0 +1,54 @@ +{ + "id": "G0169", + "category": "H", + "object_type": "CLAS", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "stop", + "expected_gap": { + "description": "The business rules do not say which monthly fee applies when a member is both a student and under 25.", + "keywords": [ + [ + "student", + "under", + "25" + ], + [ + "both", + "apply" + ], + [ + "contradict" + ], + [ + "which", + "applies" + ] + ] + }, + "budget": { + "max_tool_calls": 40, + "max_activations": 10 + }, + "seed": [], + "contract": [ + { + "type": "CLAS", + "name": "{{P}}COWORK_FEE" + } + ], + "out_of_scope": [], + "hidden_tests": [], + "reference": [ + { + "type": "CLAS", + "name": "{{P}}COWORK_FEE", + "file": "reference/cowork_fee.clas.abap", + "description": "Coworking fee calculator", + "testclasses_file": "reference/cowork_fee.testclasses.abap" + } + ], + "craft_checks": [ + "method_length" + ] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0170/generation.json b/tasks_gen/eval/G0170/generation.json new file mode 100644 index 0000000..f79ca38 --- /dev/null +++ b/tasks_gen/eval/G0170/generation.json @@ -0,0 +1,14 @@ +{ + "id": "G0170", + "pool": "eval", + "object_type": "CLAS", + "category": "H", + "attempts": [ + { + "stage": "validate", + "oracle": 100, + "null": 30 + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0170/reference/studio_pricer.clas.abap b/tasks_gen/eval/G0170/reference/studio_pricer.clas.abap new file mode 100644 index 0000000..106b2e1 --- /dev/null +++ b/tasks_gen/eval/G0170/reference/studio_pricer.clas.abap @@ -0,0 +1,68 @@ +CLASS {{p}}studio_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_studio_pricer. + + PRIVATE SECTION. + CONSTANTS: + c_discount_per_booking TYPE p LENGTH 5 DECIMALS 2 VALUE '0.75', + c_max_discount TYPE p LENGTH 5 DECIMALS 2 VALUE '15.00'. + + METHODS hourly_rate + IMPORTING iv_room TYPE {{p}}if_studio_pricer=>ty_room + RETURNING VALUE(rv_rate) TYPE {{p}}if_studio_pricer=>ty_amount. + + METHODS billable_hours + IMPORTING iv_minutes TYPE i + RETURNING VALUE(rv_hours) TYPE i. + + METHODS discount_percent + IMPORTING iv_bookings TYPE i + RETURNING VALUE(rv_percent) TYPE i. +ENDCLASS. + + +CLASS {{p}}studio_pricer IMPLEMENTATION. + METHOD {{p}}if_studio_pricer~calculate. + DATA(lv_rate) = hourly_rate( iv_room ). + IF lv_rate IS INITIAL. + rv_price = 0. + RETURN. + ENDIF. + DATA(lv_base) = lv_rate * billable_hours( iv_minutes ). + DATA(lv_percent) = discount_percent( iv_bookings ). + rv_price = lv_base - lv_base * lv_percent / 100. + ENDMETHOD. + + METHOD hourly_rate. + CASE iv_room. + WHEN {{p}}if_studio_pricer=>c_room-a. + rv_rate = '48.00'. + WHEN {{p}}if_studio_pricer=>c_room-b. + rv_rate = '36.00'. + WHEN {{p}}if_studio_pricer=>c_room-c. + rv_rate = '27.00'. + WHEN OTHERS. + rv_rate = 0. + ENDCASE. + ENDMETHOD. + + METHOD billable_hours. + rv_hours = ( iv_minutes + 59 ) DIV 60. + IF rv_hours < 1. + rv_hours = 1. + ENDIF. + ENDMETHOD. + + METHOD discount_percent. + IF iv_bookings <= 0. + RETURN. + ENDIF. + DATA lv_bookings TYPE p LENGTH 7 DECIMALS 2. + lv_bookings = iv_bookings. + DATA(lv_raw) = lv_bookings * c_discount_per_booking. + IF lv_raw > c_max_discount. + lv_raw = c_max_discount. + ENDIF. + rv_percent = lv_raw. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0170/reference/studio_pricer.testclasses.abap b/tasks_gen/eval/G0170/reference/studio_pricer.testclasses.abap new file mode 100644 index 0000000..6119e34 --- /dev/null +++ b/tasks_gen/eval/G0170/reference/studio_pricer.testclasses.abap @@ -0,0 +1,76 @@ +CLASS ltc_studio_pricer DEFINITION FINAL FOR TESTING + DURATION SHORT RISK LEVEL HARMLESS. + + PRIVATE SECTION. + DATA mo_cut TYPE REF TO {{p}}studio_pricer. + + METHODS setup. + METHODS assert_price + IMPORTING iv_expected TYPE {{p}}if_studio_pricer=>ty_amount + iv_actual TYPE {{p}}if_studio_pricer=>ty_amount. + METHODS room_a_three_hours FOR TESTING. + METHODS started_hour_counts FOR TESTING. + METHODS short_booking_one_hour FOR TESTING. + METHODS invalid_room_returns_zero FOR TESTING. + METHODS discount_five_bookings FOR TESTING. + METHODS discount_is_capped FOR TESTING. +ENDCLASS. + + +CLASS ltc_studio_pricer IMPLEMENTATION. + METHOD setup. + mo_cut = NEW {{p}}studio_pricer( ). + ENDMETHOD. + + METHOD assert_price. + cl_abap_unit_assert=>assert_equals( exp = iv_expected act = iv_actual ). + ENDMETHOD. + + METHOD room_a_three_hours. + assert_price( iv_expected = '144.00' + iv_actual = mo_cut->{{p}}if_studio_pricer~calculate( + iv_room = 'A' + iv_minutes = 180 + iv_bookings = 0 ) ). + ENDMETHOD. + + METHOD started_hour_counts. + assert_price( iv_expected = '96.00' + iv_actual = mo_cut->{{p}}if_studio_pricer~calculate( + iv_room = 'A' + iv_minutes = 90 + iv_bookings = 0 ) ). + ENDMETHOD. + + METHOD short_booking_one_hour. + assert_price( iv_expected = '27.00' + iv_actual = mo_cut->{{p}}if_studio_pricer~calculate( + iv_room = 'C' + iv_minutes = 15 + iv_bookings = 0 ) ). + ENDMETHOD. + + METHOD invalid_room_returns_zero. + assert_price( iv_expected = '0.00' + iv_actual = mo_cut->{{p}}if_studio_pricer~calculate( + iv_room = 'X' + iv_minutes = 60 + iv_bookings = 0 ) ). + ENDMETHOD. + + METHOD discount_five_bookings. + assert_price( iv_expected = '92.16' + iv_actual = mo_cut->{{p}}if_studio_pricer~calculate( + iv_room = 'A' + iv_minutes = 120 + iv_bookings = 5 ) ). + ENDMETHOD. + + METHOD discount_is_capped. + assert_price( iv_expected = '30.60' + iv_actual = mo_cut->{{p}}if_studio_pricer~calculate( + iv_room = 'B' + iv_minutes = 30 + iv_bookings = 30 ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0170/seed/if_studio_pricer.intf.abap b/tasks_gen/eval/G0170/seed/if_studio_pricer.intf.abap new file mode 100644 index 0000000..389f97d --- /dev/null +++ b/tasks_gen/eval/G0170/seed/if_studio_pricer.intf.abap @@ -0,0 +1,15 @@ +INTERFACE {{p}}if_studio_pricer PUBLIC. + TYPES ty_room TYPE c LENGTH 1. + TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2. + CONSTANTS: + BEGIN OF c_room, + a TYPE ty_room VALUE 'A', + b TYPE ty_room VALUE 'B', + c TYPE ty_room VALUE 'C', + END OF c_room. + METHODS calculate + IMPORTING iv_room TYPE ty_room + iv_minutes TYPE i + iv_bookings TYPE i + RETURNING VALUE(rv_price) TYPE ty_amount. +ENDINTERFACE. diff --git a/tasks_gen/eval/G0170/spec.md b/tasks_gen/eval/G0170/spec.md new file mode 100644 index 0000000..98f2203 --- /dev/null +++ b/tasks_gen/eval/G0170/spec.md @@ -0,0 +1,46 @@ +# 1. Goal +Calculate the price of a booking at a recording studio. A booking program calls +the calculation before it shows the price to the customer. The program needs one +price for each booking. + +# 2. Open questions +None. + +# 3. Context +- The interface {{P}}IF_STUDIO_PRICER exists in package $TMP. It is active. +- The interface has the type TY_ROOM (CHAR 1), the type TY_AMOUNT (packed, length + 8, 2 decimals), the constant structure C_ROOM (A, B, C), and one method: + CALCULATE IMPORTING iv_room TYPE ty_room, iv_minutes TYPE i, iv_bookings TYPE i + RETURNING VALUE(rv_price) TYPE ty_amount. + +# 4. Contract +- Create the class {{P}}STUDIO_PRICER in package $TMP. +- The class is public and final. It has a public constructor without parameters. +- The class implements {{P}}IF_STUDIO_PRICER. +- Do not add other public methods. + +# 5. Business rules +Apply the rules in this sequence. +1. The room type is A, B, or C. Any other room type is invalid. For an invalid + room type, return 0.00. +2. The hourly rate depends on the room type: A 48.00, B 36.00, C 27.00. +3. The booking duration is given in minutes. A started hour counts as a full + hour. A booking of less than 60 minutes counts as one hour. +4. The base price is the hourly rate multiplied by the number of hours. +5. The loyalty discount is 0.75 percent for each booking of the customer in the + last 12 months. The discount is at most 15 percent. +6. The discount percentage is rounded. +7. The price is the base price minus the discount. The discount is the rounded + discount percentage of the base price. +8. Return the price. + +# 6. Constraints +- Release target: 8.16. +- Coding standards: Clean ABAP. Method length below 40 statements. No global + variables. No comment that restates the code. +- Out of scope: do not change {{P}}IF_STUDIO_PRICER. + +# 7. Acceptance +- The class is active and has no syntax error. +- The hidden tests pass. +- Write your own ABAP Unit tests for the class. diff --git a/tasks_gen/eval/G0170/task.json b/tasks_gen/eval/G0170/task.json new file mode 100644 index 0000000..cb9ceb6 --- /dev/null +++ b/tasks_gen/eval/G0170/task.json @@ -0,0 +1,61 @@ +{ + "id": "G0170", + "category": "H", + "object_type": "CLAS", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "stop", + "budget": { + "max_tool_calls": 40, + "max_activations": 10 + }, + "seed": [ + { + "type": "INTF", + "name": "{{P}}IF_STUDIO_PRICER", + "file": "seed/if_studio_pricer.intf.abap", + "description": "Studio price contract" + } + ], + "contract": [ + { + "type": "CLAS", + "name": "{{P}}STUDIO_PRICER", + "implements": "{{P}}IF_STUDIO_PRICER" + } + ], + "out_of_scope": [ + "{{P}}IF_STUDIO_PRICER" + ], + "hidden_tests": [], + "reference": [ + { + "type": "CLAS", + "name": "{{P}}STUDIO_PRICER", + "file": "reference/studio_pricer.clas.abap", + "description": "Studio price calculator", + "testclasses_file": "reference/studio_pricer.testclasses.abap" + } + ], + "craft_checks": [ + "method_length", + "db_operation_in_loop" + ], + "expected_gap": { + "description": "The spec requires the loyalty discount percentage to be rounded but does not state the rounding target or the rounding mode, so the price of a booking with a fractional discount percentage is undefined.", + "keywords": [ + [ + "discount", + "round" + ], + [ + "rounding", + "precision" + ], + [ + "round", + "mode" + ] + ] + } +} \ No newline at end of file diff --git a/tasks_gen/eval/G0171/generation.json b/tasks_gen/eval/G0171/generation.json new file mode 100644 index 0000000..0a33e89 --- /dev/null +++ b/tasks_gen/eval/G0171/generation.json @@ -0,0 +1,14 @@ +{ + "id": "G0171", + "pool": "eval", + "object_type": "CLAS", + "category": "H", + "attempts": [ + { + "stage": "validate", + "oracle": 100, + "null": 30 + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0171/reference/kiln_pricer.clas.abap b/tasks_gen/eval/G0171/reference/kiln_pricer.clas.abap new file mode 100644 index 0000000..6bddd1b --- /dev/null +++ b/tasks_gen/eval/G0171/reference/kiln_pricer.clas.abap @@ -0,0 +1,58 @@ +CLASS {{p}}kiln_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_kiln_price. + + PRIVATE SECTION. + TYPES ty_amount TYPE p LENGTH 10 DECIMALS 4. + + CONSTANTS: + c_base_fee TYPE ty_amount VALUE '40.00', + c_piece_fee TYPE ty_amount VALUE '12.00', + c_free_weight TYPE {{p}}if_kiln_price=>ty_weight VALUE '10.00', + c_kg_fee TYPE ty_amount VALUE '3.00', + c_glaze_fee TYPE ty_amount VALUE '25.00', + c_member_rate TYPE ty_amount VALUE '0.85'. + + METHODS clay_factor + IMPORTING iv_clay TYPE {{p}}if_kiln_price=>ty_clay + RETURNING VALUE(rv_factor) TYPE ty_amount. +ENDCLASS. + + +CLASS {{p}}kiln_pricer IMPLEMENTATION. + METHOD {{p}}if_kiln_price~calculate_price. + IF iv_clay IS INITIAL. + rv_price = 0. + RETURN. + ENDIF. + + DATA lv_price TYPE ty_amount. + lv_price = c_base_fee + iv_pieces * c_piece_fee. + IF iv_weight > c_free_weight. + lv_price = lv_price + ( iv_weight - c_free_weight ) * c_kg_fee. + ENDIF. + + DATA(lv_factor) = clay_factor( iv_clay ). + lv_price = lv_price * lv_factor. + + IF iv_glaze = abap_true. + lv_price = lv_price + c_glaze_fee. + ENDIF. + IF iv_member = abap_true. + lv_price = lv_price * c_member_rate. + ENDIF. + + rv_price = round( val = lv_price dec = 2 ). + ENDMETHOD. + + METHOD clay_factor. + CASE iv_clay. + WHEN 'ST'. + rv_factor = '1.20'. + WHEN 'PO'. + rv_factor = '1.50'. + WHEN OTHERS. + rv_factor = '1.00'. + ENDCASE. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0171/reference/kiln_pricer.testclasses.abap b/tasks_gen/eval/G0171/reference/kiln_pricer.testclasses.abap new file mode 100644 index 0000000..1b729a3 --- /dev/null +++ b/tasks_gen/eval/G0171/reference/kiln_pricer.testclasses.abap @@ -0,0 +1,92 @@ +CLASS ltc_kiln_pricer DEFINITION FINAL FOR TESTING + DURATION SHORT RISK LEVEL HARMLESS. + + PRIVATE SECTION. + DATA mo_cut TYPE REF TO {{p}}if_kiln_price. + + METHODS setup. + METHODS base_fee FOR TESTING. + METHODS piece_fee FOR TESTING. + METHODS weight_surcharge FOR TESTING. + METHODS clay_factor FOR TESTING. + METHODS glaze_fee FOR TESTING. + METHODS member_discount FOR TESTING. + METHODS initial_clay FOR TESTING. +ENDCLASS. + + +CLASS ltc_kiln_pricer IMPLEMENTATION. + METHOD setup. + mo_cut = NEW {{p}}kiln_pricer( ). + ENDMETHOD. + + METHOD base_fee. + cl_abap_unit_assert=>assert_equals( + exp = '40.00' + act = mo_cut->calculate_price( iv_pieces = 0 + iv_weight = '0.00' + iv_clay = 'EA' + iv_glaze = abap_false + iv_member = abap_false ) ). + ENDMETHOD. + + METHOD piece_fee. + cl_abap_unit_assert=>assert_equals( + exp = '100.00' + act = mo_cut->calculate_price( iv_pieces = 5 + iv_weight = '0.00' + iv_clay = 'EA' + iv_glaze = abap_false + iv_member = abap_false ) ). + ENDMETHOD. + + METHOD weight_surcharge. + cl_abap_unit_assert=>assert_equals( + exp = '55.00' + act = mo_cut->calculate_price( iv_pieces = 0 + iv_weight = '15.00' + iv_clay = 'EA' + iv_glaze = abap_false + iv_member = abap_false ) ). + ENDMETHOD. + + METHOD clay_factor. + cl_abap_unit_assert=>assert_equals( + exp = '60.00' + act = mo_cut->calculate_price( iv_pieces = 0 + iv_weight = '0.00' + iv_clay = 'PO' + iv_glaze = abap_false + iv_member = abap_false ) ). + ENDMETHOD. + + METHOD glaze_fee. + cl_abap_unit_assert=>assert_equals( + exp = '65.00' + act = mo_cut->calculate_price( iv_pieces = 0 + iv_weight = '0.00' + iv_clay = 'EA' + iv_glaze = abap_true + iv_member = abap_false ) ). + ENDMETHOD. + + METHOD member_discount. + cl_abap_unit_assert=>assert_equals( + exp = '34.00' + act = mo_cut->calculate_price( iv_pieces = 0 + iv_weight = '0.00' + iv_clay = 'EA' + iv_glaze = abap_false + iv_member = abap_true ) ). + ENDMETHOD. + + METHOD initial_clay. + cl_abap_unit_assert=>assert_equals( + exp = '0.00' + act = mo_cut->calculate_price( iv_pieces = 0 + iv_weight = '0.00' + iv_clay = space + iv_glaze = abap_false + iv_member = abap_false ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0171/seed/if_kiln_price.intf.abap b/tasks_gen/eval/G0171/seed/if_kiln_price.intf.abap new file mode 100644 index 0000000..58e5a56 --- /dev/null +++ b/tasks_gen/eval/G0171/seed/if_kiln_price.intf.abap @@ -0,0 +1,13 @@ +INTERFACE {{p}}if_kiln_price PUBLIC. + TYPES: + ty_clay TYPE c LENGTH 2, + ty_weight TYPE p LENGTH 6 DECIMALS 2, + ty_price TYPE p LENGTH 8 DECIMALS 2. + METHODS calculate_price + IMPORTING iv_pieces TYPE i + iv_weight TYPE ty_weight + iv_clay TYPE ty_clay + iv_glaze TYPE abap_bool + iv_member TYPE abap_bool + RETURNING VALUE(rv_price) TYPE ty_price. +ENDINTERFACE. diff --git a/tasks_gen/eval/G0171/spec.md b/tasks_gen/eval/G0171/spec.md new file mode 100644 index 0000000..9eaf327 --- /dev/null +++ b/tasks_gen/eval/G0171/spec.md @@ -0,0 +1,54 @@ +# 1. Goal +Calculate the price of one firing in a pottery kiln. The kiln booking program calls +the calculation before it confirms a booking. The program needs one price for each +booking. + +# 2. Open questions +None. + +# 3. Context +- The interface {{P}}IF_KILN_PRICE exists in package $TMP. It is active. +- The interface has the types TY_CLAY (2 characters), TY_WEIGHT (packed, length 6, + decimals 2) and TY_PRICE (packed, length 8, decimals 2). +- The interface has one method: + CALCULATE_PRICE + IMPORTING iv_pieces TYPE i + iv_weight TYPE ty_weight + iv_clay TYPE ty_clay + iv_glaze TYPE abap_bool + iv_member TYPE abap_bool + RETURNING VALUE(rv_price) TYPE ty_price. + iv_pieces is the number of pieces. iv_weight is the weight in kilograms. + iv_glaze is 'X' when the customer books a glaze firing. iv_member is 'X' when + the customer is a member. +- The kiln booking program calls the method for each booking. The customer can + leave the clay type empty when the booking is created. The customer chooses the + clay type later. + +# 4. Contract +- Create the class {{P}}KILN_PRICER in package $TMP. +- The class is public, final, and has a public constructor without parameters. +- The class implements {{P}}IF_KILN_PRICE. +- Do not add other public methods. + +# 5. Business rules +The price is in euro. Apply the rules in this sequence. +1. Base fee: 40.00 for each firing. +2. Piece fee: 12.00 for each piece. +3. Weight surcharge: 3.00 for each kilogram of the weight that is above 10 kg. + A weight of 10 kg or less gives no surcharge. +4. Clay factor: multiply the sum of rules 1 to 3 by the factor of the chosen clay + type: EA 1.00, ST 1.20, PO 1.50. +5. Glaze firing: add 25.00 when the customer books a glaze firing. +6. Member discount: subtract 15 per cent when the customer is a member. +7. Round the result to two decimals. Round half up. + +# 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 change {{P}}IF_KILN_PRICE. + +# 7. Acceptance +- The class is active and has no syntax error. +- Write your own ABAP Unit tests for the class. diff --git a/tasks_gen/eval/G0171/task.json b/tasks_gen/eval/G0171/task.json new file mode 100644 index 0000000..c2dc115 --- /dev/null +++ b/tasks_gen/eval/G0171/task.json @@ -0,0 +1,65 @@ +{ + "id": "G0171", + "category": "H", + "object_type": "CLAS", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "stop", + "expected_gap": { + "description": "The business rules do not define which price the class returns when the clay type is initial, although the caller can pass an empty clay type.", + "keywords": [ + [ + "clay", + "initial" + ], + [ + "clay", + "empty" + ], + [ + "clay", + "chosen" + ], + [ + "clay", + "unspecified" + ] + ] + }, + "budget": { + "max_tool_calls": 30, + "max_activations": 5 + }, + "seed": [ + { + "type": "INTF", + "name": "{{P}}IF_KILN_PRICE", + "file": "seed/if_kiln_price.intf.abap", + "description": "Interface with the price calculation signature for one kiln firing" + } + ], + "contract": [ + { + "type": "CLAS", + "name": "{{P}}KILN_PRICER", + "implements": "{{P}}IF_KILN_PRICE" + } + ], + "out_of_scope": [ + "{{P}}IF_KILN_PRICE" + ], + "hidden_tests": [], + "reference": [ + { + "type": "CLAS", + "name": "{{P}}KILN_PRICER", + "file": "reference/kiln_pricer.clas.abap", + "description": "Intended kiln price calculation", + "testclasses_file": "reference/kiln_pricer.testclasses.abap" + } + ], + "craft_checks": [ + "method_length", + "no_global_variables" + ] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0172/generation.json b/tasks_gen/eval/G0172/generation.json new file mode 100644 index 0000000..935d243 --- /dev/null +++ b/tasks_gen/eval/G0172/generation.json @@ -0,0 +1,14 @@ +{ + "id": "G0172", + "pool": "eval", + "object_type": "FUNC", + "category": "H", + "attempts": [ + { + "stage": "validate", + "oracle": 100, + "null": 30 + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0172/reference/sort_bin.func.abap b/tasks_gen/eval/G0172/reference/sort_bin.func.abap new file mode 100644 index 0000000..28fc5b8 --- /dev/null +++ b/tasks_gen/eval/G0172/reference/sort_bin.func.abap @@ -0,0 +1,40 @@ +FUNCTION {{p}}sort_bin + IMPORTING + iv_size_code TYPE string + iv_weight_kg TYPE decfloat34 + EXPORTING + ev_bin TYPE i + ev_fee TYPE decfloat34 + EXCEPTIONS + invalid_weight + overweight. + + IF iv_weight_kg <= 0. + RAISE invalid_weight. + ENDIF. + + IF iv_weight_kg > '31.5'. + RAISE overweight. + ENDIF. + + CASE iv_size_code. + WHEN 'S'. + ev_bin = 1. + ev_fee = '1.50'. + WHEN 'M'. + ev_bin = 2. + ev_fee = '2.00'. + WHEN 'L'. + ev_bin = 3. + ev_fee = '3.00'. + WHEN 'XL'. + ev_bin = 4. + ev_fee = '5.00'. + WHEN OTHERS. + " The specification does not define this case. The assumption here is + " that the sorting centre rejects the parcel. + ev_bin = 0. + ev_fee = 0. + ENDCASE. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0172/reference/sort_bin_test.clas.abap b/tasks_gen/eval/G0172/reference/sort_bin_test.clas.abap new file mode 100644 index 0000000..cfcecf9 --- /dev/null +++ b/tasks_gen/eval/G0172/reference/sort_bin_test.clas.abap @@ -0,0 +1,62 @@ +CLASS {{p}}sort_bin_test DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS call + IMPORTING + iv_code TYPE string + iv_weight TYPE decfloat34 + EXPORTING + ev_bin TYPE i + ev_fee TYPE decfloat34 + ev_subrc TYPE sysubrc. + METHODS small_parcel FOR TESTING. + METHODS extra_large_parcel FOR TESTING. + METHODS overweight_rejected FOR TESTING. + METHODS zero_weight_rejected FOR TESTING. +ENDCLASS. + + +CLASS {{p}}sort_bin_test IMPLEMENTATION. + + METHOD call. + CALL FUNCTION '{{P}}SORT_BIN' + EXPORTING + iv_size_code = iv_code + iv_weight_kg = iv_weight + IMPORTING + ev_bin = ev_bin + ev_fee = ev_fee + EXCEPTIONS + invalid_weight = 1 + overweight = 2 + OTHERS = 3. + ev_subrc = sy-subrc. + ENDMETHOD. + + METHOD small_parcel. + call( EXPORTING iv_code = `S` iv_weight = '2.5' + IMPORTING ev_bin = DATA(lv_bin) ev_fee = DATA(lv_fee) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lv_bin ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '1.50' ) act = lv_fee ). + ENDMETHOD. + + METHOD extra_large_parcel. + call( EXPORTING iv_code = `XL` iv_weight = '30' + IMPORTING ev_bin = DATA(lv_bin) ev_fee = DATA(lv_fee) ). + cl_abap_unit_assert=>assert_equals( exp = 4 act = lv_bin ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '5.00' ) act = lv_fee ). + ENDMETHOD. + + METHOD overweight_rejected. + call( EXPORTING iv_code = `M` iv_weight = '32' + IMPORTING ev_subrc = DATA(lv_rc) ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lv_rc ). + ENDMETHOD. + + METHOD zero_weight_rejected. + call( EXPORTING iv_code = `S` iv_weight = 0 + IMPORTING ev_subrc = DATA(lv_rc) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lv_rc ). + ENDMETHOD. + +ENDCLASS. diff --git a/tasks_gen/eval/G0172/seed/sort_text.func.abap b/tasks_gen/eval/G0172/seed/sort_text.func.abap new file mode 100644 index 0000000..b6a0550 --- /dev/null +++ b/tasks_gen/eval/G0172/seed/sort_text.func.abap @@ -0,0 +1,20 @@ +FUNCTION {{p}}sort_text + IMPORTING + iv_bin TYPE i + EXPORTING + ev_text TYPE string. + + CASE iv_bin. + WHEN 1. + ev_text = 'Small'. + WHEN 2. + ev_text = 'Medium'. + WHEN 3. + ev_text = 'Large'. + WHEN 4. + ev_text = 'Extra large'. + WHEN OTHERS. + ev_text = 'Unknown bin'. + ENDCASE. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0172/spec.md b/tasks_gen/eval/G0172/spec.md new file mode 100644 index 0000000..173688a --- /dev/null +++ b/tasks_gen/eval/G0172/spec.md @@ -0,0 +1,48 @@ +# 1. Goal +A parcel sorting centre needs one function module. The function module +calculates the destination bin and the handling fee of a parcel. The sorting +program calls the function module for each parcel before the parcel goes to a +bin. + +# 2. Open questions +None. + +# 3. Context +- Function group {{P}}FG_SORT exists in package $TMP. +- Function module {{P}}SORT_TEXT exists in this function group. It gives the + text of a bin number. +- The sorting centre receives parcels from many shops. Some parcels have a size + code that the sorting centre does not know. The sorting program calls the + function module for these parcels too. + +# 4. Contract +- Create the function module {{P}}SORT_BIN in function group {{P}}FG_SORT. +- Interface of {{P}}SORT_BIN: + - iv_size_code TYPE string (importing) + - iv_weight_kg TYPE decfloat34 (importing) + - ev_bin TYPE i (exporting) + - ev_fee TYPE decfloat34 (exporting) + - Exceptions: invalid_weight, overweight +- The function module has no other parameters. + +# 5. Business rules +1. If the weight is less than or equal to 0, raise the exception INVALID_WEIGHT. + In this case, do not set the bin and do not set the fee. +2. If the weight is greater than 31.5, raise the exception OVERWEIGHT. In this + case, do not set the bin and do not set the fee. +3. Size code 'S': the bin is 1. The fee is 1.50 euro. +4. Size code 'M': the bin is 2. The fee is 2.00 euro. +5. Size code 'L': the bin is 3. The fee is 3.00 euro. +6. Size code 'XL': the bin is 4. The fee is 5.00 euro. +7. The fee has two decimals. + +# 6. Constraints +- Release target: SAP_BASIS 816. +- Package: $TMP. Do not use transports. +- Out of scope: do not change {{P}}SORT_TEXT. +- Use Clean ABAP. Pass large parameters by reference. + +# 7. Acceptance +- The function module is active and has no syntax error. +- Write ABAP Unit tests for the function module in a global test class. +- The hidden tests pass. diff --git a/tasks_gen/eval/G0172/task.json b/tasks_gen/eval/G0172/task.json new file mode 100644 index 0000000..26447c8 --- /dev/null +++ b/tasks_gen/eval/G0172/task.json @@ -0,0 +1,94 @@ +{ + "id": "G0172", + "category": "H", + "object_type": "FUNC", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "stop", + "expected_gap": { + "description": "The business rules define the bin and the fee for the size codes S, M, L and XL, but they do not define what the function module must do for any other size code.", + "keywords": [ + [ + "unknown", + "code" + ], + [ + "other", + "code" + ], + [ + "not", + "defined" + ], + [ + "no", + "rule" + ] + ] + }, + "budget": { + "max_tool_calls": 25, + "max_activations": 6 + }, + "seed": [ + { + "type": "FUGR", + "name": "{{P}}FG_SORT", + "description": "Parcel sorting" + }, + { + "type": "FUNC", + "name": "{{P}}SORT_TEXT", + "functionGroup": "{{P}}FG_SORT", + "file": "seed/sort_text.func.abap", + "description": "Text of a bin number" + } + ], + "contract": [ + { + "type": "FUNC", + "name": "{{P}}SORT_BIN", + "functionGroup": "{{P}}FG_SORT", + "params": [ + { + "name": "iv_size_code", + "type": "string" + }, + { + "name": "iv_weight_kg", + "type": "decfloat34" + }, + { + "name": "ev_bin", + "type": "i" + }, + { + "name": "ev_fee", + "type": "decfloat34" + } + ] + } + ], + "out_of_scope": [ + "{{P}}SORT_TEXT" + ], + "hidden_tests": [], + "reference": [ + { + "type": "FUNC", + "name": "{{P}}SORT_BIN", + "functionGroup": "{{P}}FG_SORT", + "file": "reference/sort_bin.func.abap", + "description": "Parcel sorting function module" + }, + { + "type": "CLAS", + "name": "{{P}}SORT_BIN_TEST", + "file": "reference/sort_bin_test.clas.abap", + "description": "Own tests for {{P}}SORT_BIN" + } + ], + "craft_checks": [ + "method_length" + ] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0173/generation.json b/tasks_gen/eval/G0173/generation.json new file mode 100644 index 0000000..d609966 --- /dev/null +++ b/tasks_gen/eval/G0173/generation.json @@ -0,0 +1,14 @@ +{ + "id": "G0173", + "pool": "eval", + "object_type": "FUNC", + "category": "H", + "attempts": [ + { + "stage": "validate", + "oracle": 100, + "null": 30 + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0173/reference/kart_fee.func.abap b/tasks_gen/eval/G0173/reference/kart_fee.func.abap new file mode 100644 index 0000000..31f6c88 --- /dev/null +++ b/tasks_gen/eval/G0173/reference/kart_fee.func.abap @@ -0,0 +1,31 @@ +FUNCTION {{p}}kart_fee + IMPORTING + iv_laps TYPE i + iv_driver_age TYPE i + iv_member TYPE abap_bool + EXPORTING + ev_discount TYPE abap_bool + CHANGING + cv_fee TYPE decfloat34 + EXCEPTIONS + invalid_laps. + + ev_discount = abap_false. + IF iv_laps < 1. + RAISE invalid_laps. + ENDIF. + IF iv_driver_age < 18. + cv_fee = 15. + ELSE. + cv_fee = CONV decfloat34( iv_laps ) * 1.5. + IF iv_member = abap_true. + cv_fee = cv_fee * 9 / 10. + ev_discount = abap_true. + ENDIF. + ENDIF. + IF cv_fee < 20. + cv_fee = 20. + ENDIF. + cv_fee = round( val = cv_fee dec = 2 mode = cl_abap_math=>round_half_up ). + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0173/reference/kart_test.clas.abap b/tasks_gen/eval/G0173/reference/kart_test.clas.abap new file mode 100644 index 0000000..88cee5d --- /dev/null +++ b/tasks_gen/eval/G0173/reference/kart_test.clas.abap @@ -0,0 +1,70 @@ +CLASS {{p}}kart_test DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS fee_for IMPORTING iv_laps TYPE i iv_age TYPE i iv_member TYPE abap_bool + RETURNING VALUE(rv_fee) TYPE decfloat34. + METHODS invalid_laps FOR TESTING. + METHODS adult_base_fee FOR TESTING. + METHODS member_discount FOR TESTING. + METHODS minimum_fee FOR TESTING. + METHODS junior_fee FOR TESTING. +ENDCLASS. + + +CLASS {{p}}kart_test IMPLEMENTATION. + METHOD fee_for. + DATA lv_discount TYPE abap_bool. + CALL FUNCTION '{{P}}KART_FEE' + EXPORTING + iv_laps = iv_laps + iv_driver_age = iv_age + iv_member = iv_member + IMPORTING + ev_discount = lv_discount + CHANGING + cv_fee = rv_fee + EXCEPTIONS + invalid_laps = 1 + OTHERS = 2. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + ENDMETHOD. + + METHOD invalid_laps. + DATA lv_fee TYPE decfloat34. + CALL FUNCTION '{{P}}KART_FEE' + EXPORTING + iv_laps = 0 + iv_driver_age = 30 + iv_member = abap_false + CHANGING + cv_fee = lv_fee + EXCEPTIONS + invalid_laps = 1 + OTHERS = 2. + cl_abap_unit_assert=>assert_equals( exp = 1 act = sy-subrc ). + ENDMETHOD. + + METHOD adult_base_fee. + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( 30 ) + act = fee_for( iv_laps = 20 iv_age = 30 iv_member = abap_false ) ). + ENDMETHOD. + + METHOD member_discount. + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( 27 ) + act = fee_for( iv_laps = 20 iv_age = 30 iv_member = abap_true ) ). + ENDMETHOD. + + METHOD minimum_fee. + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( 20 ) + act = fee_for( iv_laps = 5 iv_age = 30 iv_member = abap_false ) ). + ENDMETHOD. + + METHOD junior_fee. + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( 20 ) + act = fee_for( iv_laps = 10 iv_age = 15 iv_member = abap_false ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0173/seed/kart_sample.func.abap b/tasks_gen/eval/G0173/seed/kart_sample.func.abap new file mode 100644 index 0000000..54a23f8 --- /dev/null +++ b/tasks_gen/eval/G0173/seed/kart_sample.func.abap @@ -0,0 +1,16 @@ +FUNCTION {{p}}kart_sample + IMPORTING + iv_laps TYPE i + iv_driver_age TYPE i + iv_member TYPE abap_bool + EXPORTING + ev_discount TYPE abap_bool + CHANGING + cv_fee TYPE decfloat34 + EXCEPTIONS + invalid_laps. + + ev_discount = abap_false. + cv_fee = 0. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0173/spec.md b/tasks_gen/eval/G0173/spec.md new file mode 100644 index 0000000..8d52c3c --- /dev/null +++ b/tasks_gen/eval/G0173/spec.md @@ -0,0 +1,42 @@ +# 1. Goal +A go-kart track charges a fee for each race. A booking program calls one +function module for each completed race. The function module calculates the +fee from the number of laps, the driver age, and the membership status. + +# 2. Open questions +None. + +# 3. Context +- Function group {{P}}FG_KART exists in package $TMP. +- Function module {{P}}KART_SAMPLE exists in this group. It shows the + interface style that the booking program uses. Do not change it. + +# 4. Contract +- Create the function module {{P}}KART_FEE in function group {{P}}FG_KART. +- Use exactly this interface: + - Importing parameters: iv_laps TYPE i, iv_driver_age TYPE i, + iv_member TYPE abap_bool + - Exporting parameter: ev_discount TYPE abap_bool + - Changing parameter: cv_fee TYPE decfloat34 + - Exception: invalid_laps + +# 5. Business rules +1. If iv_laps is less than 1, raise the exception INVALID_LAPS. +2. The base fee is 1.50 per lap. +3. For a driver under 18 years, the fee is exactly 15.00. +4. For a driver of 18 years or more who is a member, reduce the fee by 10 % + and set ev_discount to true. +5. The minimum fee is 20.00. +6. Round the fee half up to 2 decimals. +7. Set ev_discount to false, except in rule 4. + +# 6. Constraints +- Release target: 8.16. +- Package: $TMP. +- Out of scope: do not change {{P}}KART_SAMPLE. +- Write ABAP Unit tests for the function module in a global test class. + +# 7. Acceptance +- The function module is active and has no syntax error. +- The hidden tests pass. +- The global test class for the function module passes. diff --git a/tasks_gen/eval/G0173/task.json b/tasks_gen/eval/G0173/task.json new file mode 100644 index 0000000..a928bab --- /dev/null +++ b/tasks_gen/eval/G0173/task.json @@ -0,0 +1,94 @@ +{ + "id": "G0173", + "category": "H", + "object_type": "FUNC", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "stop", + "expected_gap": { + "description": "Rule 3 (a driver under 18 pays exactly 15.00) and rule 5 (the minimum fee is 20.00) contradict each other, and the spec does not say which rule has priority.", + "keywords": [ + [ + "18", + "15" + ], + [ + "minimum", + "20" + ], + [ + "contradict", + "rule" + ] + ] + }, + "budget": { + "max_tool_calls": 30, + "max_activations": 6 + }, + "seed": [ + { + "type": "FUGR", + "name": "{{P}}FG_KART", + "description": "Go-kart fee function group" + }, + { + "type": "FUNC", + "name": "{{P}}KART_SAMPLE", + "functionGroup": "{{P}}FG_KART", + "file": "seed/kart_sample.func.abap", + "description": "Sample interface for the booking program" + } + ], + "contract": [ + { + "type": "FUNC", + "name": "{{P}}KART_FEE", + "functionGroup": "{{P}}FG_KART", + "params": [ + { + "name": "iv_laps", + "type": "i" + }, + { + "name": "iv_driver_age", + "type": "i" + }, + { + "name": "iv_member", + "type": "abap_bool" + }, + { + "name": "ev_discount", + "type": "abap_bool" + }, + { + "name": "cv_fee", + "type": "decfloat34" + } + ] + } + ], + "out_of_scope": [ + "{{P}}KART_SAMPLE" + ], + "hidden_tests": [], + "reference": [ + { + "type": "FUNC", + "name": "{{P}}KART_FEE", + "functionGroup": "{{P}}FG_KART", + "file": "reference/kart_fee.func.abap", + "description": "Fee calculation for a race" + }, + { + "type": "CLAS", + "name": "{{P}}KART_TEST", + "file": "reference/kart_test.clas.abap", + "description": "Tests for the fee calculation" + } + ], + "craft_checks": [ + "method_length" + ] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0174/generation.json b/tasks_gen/eval/G0174/generation.json new file mode 100644 index 0000000..6f7648b --- /dev/null +++ b/tasks_gen/eval/G0174/generation.json @@ -0,0 +1,14 @@ +{ + "id": "G0174", + "pool": "eval", + "object_type": "PROG", + "category": "H", + "attempts": [ + { + "stage": "validate", + "oracle": 100, + "null": 30 + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0174/reference/flower_sales.prog.abap b/tasks_gen/eval/G0174/reference/flower_sales.prog.abap new file mode 100644 index 0000000..ec5587b --- /dev/null +++ b/tasks_gen/eval/G0174/reference/flower_sales.prog.abap @@ -0,0 +1,89 @@ +REPORT {{p}}flower_sales. + +DATA gv_flower TYPE {{p}}flsale-flower_type. + +PARAMETERS p_from TYPE d OBLIGATORY. +SELECT-OPTIONS s_flower FOR gv_flower. + +CLASS lcl_report DEFINITION FINAL. + PUBLIC SECTION. + TYPES: + BEGIN OF ty_line, + flower_type TYPE {{p}}flsale-flower_type, + total_revenue TYPE {{p}}flsale-amount, + count TYPE i, + END OF ty_line, + tt_line TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY. + TYPES tt_flower TYPE RANGE OF {{p}}flsale-flower_type. + METHODS select_totals + IMPORTING iv_from TYPE d + it_flower TYPE tt_flower + RETURNING VALUE(rt_lines) TYPE tt_line. + METHODS display + CHANGING ct_lines TYPE tt_line. +ENDCLASS. + +CLASS lcl_report IMPLEMENTATION. + METHOD select_totals. + SELECT flower_type, SUM( amount ) AS total_revenue, COUNT( * ) AS count + FROM {{p}}flsale + WHERE sale_date >= @iv_from + AND flower_type IN @it_flower + GROUP BY flower_type + ORDER BY total_revenue 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_flower = s_flower[] ). + 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_flower FOR TESTING. + METHODS flower_filter FOR TESTING. +ENDCLASS. + +CLASS ltc_report IMPLEMENTATION. + METHOD class_setup. + go_env = cl_osql_test_environment=>create( i_dependency_list = VALUE #( ( '{{P}}FLSALE' ) ) ). + DATA lt_sale TYPE STANDARD TABLE OF {{p}}flsale WITH EMPTY KEY. + lt_sale = VALUE #( ( sale_id = 1 flower_type = 'ROSE' sale_date = '20260101' amount = 10 ) + ( sale_id = 2 flower_type = 'ROSE' sale_date = '20260102' amount = 5 ) + ( sale_id = 3 flower_type = 'TULIP' sale_date = '20260101' amount = 40 ) ). + go_env->insert_test_data( lt_sale ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD totals_per_flower. + DATA(lt_lines) = NEW lcl_report( )->select_totals( iv_from = '20260101' it_flower = VALUE #( ) ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 'TULIP' act = lt_lines[ 1 ]-flower_type ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lt_lines[ 2 ]-count ). + ENDMETHOD. + + METHOD flower_filter. + DATA(lt_lines) = NEW lcl_report( )->select_totals( + iv_from = '20260101' it_flower = VALUE #( ( sign = 'I' option = 'EQ' low = 'ROSE' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}flsale-amount( 15 ) act = lt_lines[ 1 ]-total_revenue ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0174/seed/flsale.tabl.asabap b/tasks_gen/eval/G0174/seed/flsale.tabl.asabap new file mode 100644 index 0000000..e0c7d69 --- /dev/null +++ b/tasks_gen/eval/G0174/seed/flsale.tabl.asabap @@ -0,0 +1,12 @@ +@EndUserText.label : 'Flower sales' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}flsale { + key client : abap.clnt not null; + key sale_id : abap.int4 not null; + flower_type : abap.char(10); + sale_date : abap.dats; + amount : abap.dec(15,2); +} diff --git a/tasks_gen/eval/G0174/seed/t15_seed.clas.abap b/tasks_gen/eval/G0174/seed/t15_seed.clas.abap new file mode 100644 index 0000000..f657ce6 --- /dev/null +++ b/tasks_gen/eval/G0174/seed/t15_seed.clas.abap @@ -0,0 +1,17 @@ +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}}flsale. + INSERT {{p}}flsale FROM TABLE @( VALUE #( + ( sale_id = 1 flower_type = 'ROSE' sale_date = '20260110' amount = '100.00' ) + ( sale_id = 2 flower_type = 'ROSE' sale_date = '20260210' amount = '50.00' ) + ( sale_id = 3 flower_type = 'TULIP' sale_date = '20260115' amount = '300.00' ) + ( sale_id = 4 flower_type = 'DAISY' sale_date = '20251231' amount = '500.00' ) + ( sale_id = 5 flower_type = 'DAISY' sale_date = '20260301' amount = '20.00' ) ) ). + out->write( sy-dbcnt ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0174/spec.md b/tasks_gen/eval/G0174/spec.md new file mode 100644 index 0000000..cef4ef3 --- /dev/null +++ b/tasks_gen/eval/G0174/spec.md @@ -0,0 +1,31 @@ +# 1. Goal +Show the total revenue and the number of sales for each flower type in an ALV list. The florist uses the list to compare flower types for a period. + +# 2. Open questions +None. + +# 3. Context +- Table {{P}}FLSALE exists in package $TMP. It contains data. + Fields: SALE_ID (INT4, key), FLOWER_TYPE (CHAR 10), SALE_DATE (DATS), AMOUNT (DEC 15,2). + +# 4. Contract +- Create the executable program {{P}}FLOWER_SALES in package $TMP. +- Selection screen: + - Parameter P_FROM, type DATS, mandatory: the first sale date to include. + - Select-option S_FLOWER for the flower type. +- Show the result with CL_SALV_TABLE. The output table has these columns, with these names: FLOWER_TYPE, TOTAL_REVENUE (sum of AMOUNT), COUNT (number of sales). + +# 5. Business rules +1. Include a sale only if SALE_DATE is on or after P_FROM and FLOWER_TYPE is in S_FLOWER. +2. Show one line for each flower type that has at least one included sale. +3. Sort the lines by TOTAL_REVENUE. + +# 6. Constraints +- Release target: 816. +- Coding standards: Clean ABAP. Read the data with one database access. +- Out of scope: do not change {{P}}FLSALE. + +# 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/eval/G0174/task.json b/tasks_gen/eval/G0174/task.json new file mode 100644 index 0000000..63ac094 --- /dev/null +++ b/tasks_gen/eval/G0174/task.json @@ -0,0 +1,70 @@ +{ + "id": "G0174", + "category": "H", + "object_type": "PROG", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "stop", + "expected_gap": { + "description": "The sort direction for TOTAL_REVENUE is missing.", + "keywords": [ + [ + "sort", + "order" + ], + [ + "sort", + "direction" + ], + [ + "ascending", + "descending" + ] + ] + }, + "budget": { + "max_tool_calls": 20, + "max_activations": 5 + }, + "seed": [ + { + "type": "TABL", + "name": "{{P}}FLSALE", + "file": "seed/flsale.tabl.asabap", + "description": "Flower sales" + }, + { + "type": "CLAS", + "name": "{{P}}T15_SEED", + "file": "seed/t15_seed.clas.abap", + "description": "T15 seed data", + "run": true + } + ], + "contract": [ + { + "type": "PROG", + "name": "{{P}}FLOWER_SALES", + "parameters": [ + "p_from", + "s_flower" + ] + } + ], + "out_of_scope": [ + "{{P}}FLSALE" + ], + "hidden_tests": [], + "reference": [ + { + "type": "PROG", + "name": "{{P}}FLOWER_SALES", + "file": "reference/flower_sales.prog.abap", + "description": "Flower sales per type" + } + ], + "craft_checks": [ + "db_operation_in_loop", + "method_length" + ] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0175/generation.json b/tasks_gen/eval/G0175/generation.json new file mode 100644 index 0000000..1150a88 --- /dev/null +++ b/tasks_gen/eval/G0175/generation.json @@ -0,0 +1,14 @@ +{ + "id": "G0175", + "pool": "eval", + "object_type": "PROG", + "category": "H", + "attempts": [ + { + "stage": "validate", + "oracle": 100, + "null": 30 + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0175/reference/honey_sum.prog.abap b/tasks_gen/eval/G0175/reference/honey_sum.prog.abap new file mode 100644 index 0000000..b20a73f --- /dev/null +++ b/tasks_gen/eval/G0175/reference/honey_sum.prog.abap @@ -0,0 +1,88 @@ +REPORT {{p}}honey_sum. + +DATA gv_apiary TYPE {{p}}honey-apiary. + +PARAMETERS p_from TYPE d OBLIGATORY. +SELECT-OPTIONS s_apiary FOR gv_apiary. + +CLASS lcl_report DEFINITION FINAL. + PUBLIC SECTION. + TYPES: + BEGIN OF ty_line, + apiary TYPE {{p}}honey-apiary, + weight TYPE {{p}}honey-weight, + END OF ty_line, + tt_line TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY. + TYPES tt_apiary TYPE RANGE OF {{p}}honey-apiary. + METHODS select_totals + IMPORTING iv_from TYPE d + it_apiary TYPE tt_apiary + RETURNING VALUE(rt_lines) TYPE tt_line. + METHODS display + CHANGING ct_lines TYPE tt_line. +ENDCLASS. + +CLASS lcl_report IMPLEMENTATION. + METHOD select_totals. + SELECT apiary, SUM( weight ) AS weight + FROM {{p}}honey + WHERE harvest_date >= @iv_from + AND apiary IN @it_apiary + GROUP BY apiary + ORDER BY weight 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_apiary = s_apiary[] ). + 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_apiary FOR TESTING. + METHODS date_filter FOR TESTING. +ENDCLASS. + +CLASS ltc_report IMPLEMENTATION. + METHOD class_setup. + go_env = cl_osql_test_environment=>create( i_dependency_list = VALUE #( ( '{{P}}HONEY' ) ) ). + DATA lt_honey TYPE STANDARD TABLE OF {{p}}honey WITH EMPTY KEY. + lt_honey = VALUE #( ( harvest_id = 1 apiary = 'A' flower = 'X' harvest_date = '20260401' weight = 10 ) + ( harvest_id = 2 apiary = 'A' flower = 'X' harvest_date = '20260402' weight = 5 ) + ( harvest_id = 3 apiary = 'B' flower = 'Y' harvest_date = '20260401' weight = 40 ) ). + go_env->insert_test_data( lt_honey ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD totals_per_apiary. + DATA(lt_lines) = NEW lcl_report( )->select_totals( iv_from = '20260401' it_apiary = VALUE #( ) ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 'B' act = lt_lines[ 1 ]-apiary ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + ENDMETHOD. + + METHOD date_filter. + DATA(lt_lines) = NEW lcl_report( )->select_totals( + iv_from = '20260402' it_apiary = VALUE #( ( sign = 'I' option = 'EQ' low = 'A' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}honey-weight( 5 ) act = lt_lines[ 1 ]-weight ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0175/seed/honey.tabl.asabap b/tasks_gen/eval/G0175/seed/honey.tabl.asabap new file mode 100644 index 0000000..4dcbb0d --- /dev/null +++ b/tasks_gen/eval/G0175/seed/honey.tabl.asabap @@ -0,0 +1,13 @@ +@EndUserText.label : 'Honey harvest' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}honey { + key client : abap.clnt not null; + key harvest_id : abap.int4 not null; + apiary : abap.char(10); + flower : abap.char(10); + harvest_date : abap.dats; + weight : abap.dec(13,3); +} diff --git a/tasks_gen/eval/G0175/seed/honey_seed.clas.abap b/tasks_gen/eval/G0175/seed/honey_seed.clas.abap new file mode 100644 index 0000000..75166ce --- /dev/null +++ b/tasks_gen/eval/G0175/seed/honey_seed.clas.abap @@ -0,0 +1,18 @@ +CLASS {{p}}honey_seed DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES if_oo_adt_classrun. +ENDCLASS. + +CLASS {{p}}honey_seed IMPLEMENTATION. + METHOD if_oo_adt_classrun~main. + DELETE FROM {{p}}honey. + INSERT {{p}}honey FROM TABLE @( VALUE #( + ( harvest_id = 1 apiary = 'NORTH' flower = 'CLOVER' harvest_date = '20260410' weight = '120.500' ) + ( harvest_id = 2 apiary = 'NORTH' flower = 'CLOVER' harvest_date = '20260502' weight = '80.000' ) + ( harvest_id = 3 apiary = 'SOUTH' flower = 'RAPE' harvest_date = '20260415' weight = '200.000' ) + ( harvest_id = 4 apiary = 'SOUTH' flower = 'RAPE' harvest_date = '20260301' weight = '50.000' ) + ( harvest_id = 5 apiary = 'EAST' flower = 'LINDEN' harvest_date = '20260601' weight = '60.250' ) + ( harvest_id = 6 apiary = 'EAST' flower = 'LINDEN' harvest_date = '20260615' weight = '30.000' ) ) ). + out->write( sy-dbcnt ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0175/spec.md b/tasks_gen/eval/G0175/spec.md new file mode 100644 index 0000000..3daa65d --- /dev/null +++ b/tasks_gen/eval/G0175/spec.md @@ -0,0 +1,40 @@ +# 1. Goal +Show the honey harvest of each apiary in an ALV list. The cooperative uses the +list to compare its member apiaries for the period that the selection screen +defines. + +# 2. Open questions +None. + +# 3. Context +- Table {{P}}HONEY exists in package $TMP. It contains data. + Fields: HARVEST_ID (INT4, key), APIARY (CHAR 10), FLOWER (CHAR 10), + HARVEST_DATE (DATS), WEIGHT (DEC 13,3). + +# 4. Contract +- Create the executable program {{P}}HONEY_SUM in package $TMP. +- Selection screen: + - Parameter P_FROM, type DATS, mandatory: the first harvest date to include. + - Select-option S_APIARY for the apiary. +- Show the result with CL_SALV_TABLE. The output table has these columns, with +these names: APIARY, WEIGHT. + +# 5. Business rules +1. Include a harvest only if HARVEST_DATE is on or after P_FROM and APIARY is + in S_APIARY. +2. Show one line for each apiary that has at least one included harvest. +3. The WEIGHT column is the sum of the weights of the included harvests of the + line. +4. Sort the lines by WEIGHT, the highest total first. +5. The period ends with P_FROM: include a harvest only if HARVEST_DATE is + before P_FROM. + +# 6. Constraints +- Release target: ABAP Platform 2025 (SAP_BASIS 816). +- Coding standards: Clean ABAP. Read the data with one database access. +- Out of scope: do not change {{P}}HONEY. + +# 7. Acceptance +- The program is active and has no syntax error. +- The list has the columns and the order that the business rules describe. +- Write ABAP Unit tests as local test classes in the program. diff --git a/tasks_gen/eval/G0175/task.json b/tasks_gen/eval/G0175/task.json new file mode 100644 index 0000000..b2983f1 --- /dev/null +++ b/tasks_gen/eval/G0175/task.json @@ -0,0 +1,71 @@ +{ + "id": "G0175", + "category": "H", + "object_type": "PROG", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "stop", + "expected_gap": { + "description": "Rule 1 includes harvests on or after P_FROM, but rule 5 includes only harvests before P_FROM, so the two filter rules contradict and no harvest can satisfy both.", + "keywords": [ + [ + "contradict", + "p_from" + ], + [ + "p_from", + "before", + "after" + ], + [ + "rule", + "p_from", + "before" + ] + ] + }, + "budget": { + "max_tool_calls": 30, + "max_activations": 6 + }, + "seed": [ + { + "type": "TABL", + "name": "{{P}}HONEY", + "file": "seed/honey.tabl.asabap", + "description": "Honey harvest" + }, + { + "type": "CLAS", + "name": "{{P}}HONEY_SEED", + "file": "seed/honey_seed.clas.abap", + "description": "Honey seed data", + "run": true + } + ], + "contract": [ + { + "type": "PROG", + "name": "{{P}}HONEY_SUM", + "parameters": [ + "p_from", + "s_apiary" + ] + } + ], + "out_of_scope": [ + "{{P}}HONEY" + ], + "hidden_tests": [], + "reference": [ + { + "type": "PROG", + "name": "{{P}}HONEY_SUM", + "file": "reference/honey_sum.prog.abap", + "description": "Honey harvest per apiary" + } + ], + "craft_checks": [ + "method_length" + ] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0176/generation.json b/tasks_gen/eval/G0176/generation.json new file mode 100644 index 0000000..d37218d --- /dev/null +++ b/tasks_gen/eval/G0176/generation.json @@ -0,0 +1,14 @@ +{ + "id": "G0176", + "pool": "eval", + "object_type": "DDLS", + "category": "H", + "attempts": [ + { + "stage": "validate", + "oracle": 100, + "null": 30 + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0176/reference/h_energy_test.clas.abap b/tasks_gen/eval/G0176/reference/h_energy_test.clas.abap new file mode 100644 index 0000000..f9425a3 --- /dev/null +++ b/tasks_gen/eval/G0176/reference/h_energy_test.clas.abap @@ -0,0 +1,41 @@ +CLASS {{p}}h_energy_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 completed_sessions_only FOR TESTING. +ENDCLASS. + + +CLASS {{p}}h_energy_test IMPLEMENTATION. + METHOD class_setup. + go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_STATION_ENERGY' ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + go_env->clear_doubles( ). + ENDMETHOD. + + METHOD completed_sessions_only. + DATA lt_station TYPE STANDARD TABLE OF {{p}}station WITH EMPTY KEY. + DATA lt_session TYPE STANDARD TABLE OF {{p}}session WITH EMPTY KEY. + lt_station = VALUE #( ( station_id = 'S1' city = 'Berlin' capacity_kw = '22.0' ) ). + lt_session = VALUE #( + ( session_id = 'T1' station_id = 'S1' start_date = '20240101' start_time = '080000' energy_kwh = '10.00' status = 'C' ) + ( session_id = 'T2' station_id = 'S1' start_date = '20240101' start_time = '090000' energy_kwh = '5.00' status = 'A' ) + ( session_id = 'T3' station_id = 'S1' start_date = '20240101' start_time = '100000' energy_kwh = '2.00' status = 'R' ) + ). + go_env->insert_test_data( lt_station ). + go_env->insert_test_data( lt_session ). + SELECT SINGLE session_count, total_energy FROM {{p}}i_station_energy WHERE station_id = 'S1' + INTO @DATA(ls_result). + cl_abap_unit_assert=>assert_equals( exp = 1 act = ls_result-session_count ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '10.00' ) act = CONV decfloat34( ls_result-total_energy ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0176/reference/i_station_energy.ddls.asddls b/tasks_gen/eval/G0176/reference/i_station_energy.ddls.asddls new file mode 100644 index 0000000..2e7912b --- /dev/null +++ b/tasks_gen/eval/G0176/reference/i_station_energy.ddls.asddls @@ -0,0 +1,14 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Station energy totals' +define view entity {{P}}I_STATION_ENERGY + as select from {{p}}station as st + left outer join {{p}}session as se on se.station_id = st.station_id and se.status = 'C' +{ + key st.station_id as station_id, + st.city as city, + count( se.session_id ) as session_count, + sum( se.energy_kwh ) as total_energy +} +group by + st.station_id, + st.city diff --git a/tasks_gen/eval/G0176/seed/seed_data.clas.abap b/tasks_gen/eval/G0176/seed/seed_data.clas.abap new file mode 100644 index 0000000..fedd5f6 --- /dev/null +++ b/tasks_gen/eval/G0176/seed/seed_data.clas.abap @@ -0,0 +1,31 @@ +CLASS {{p}}seed_data DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES if_oo_adt_classrun. +ENDCLASS. + + +CLASS {{p}}seed_data IMPLEMENTATION. + METHOD if_oo_adt_classrun~main. + DATA lt_station TYPE STANDARD TABLE OF {{p}}station WITH EMPTY KEY. + DATA lt_session TYPE STANDARD TABLE OF {{p}}session WITH EMPTY KEY. + lt_station = VALUE #( + ( station_id = 'S1' city = 'Berlin' capacity_kw = '22.0' ) + ( station_id = 'S2' city = 'Munich' capacity_kw = '50.0' ) + ( station_id = 'S3' city = 'Hamburg' capacity_kw = '11.0' ) + ). + lt_session = VALUE #( + ( session_id = 'T1' station_id = 'S1' start_date = '20240101' start_time = '080000' energy_kwh = '10.50' status = 'C' ) + ( session_id = 'T2' station_id = 'S1' start_date = '20240101' start_time = '120000' energy_kwh = '5.25' status = 'C' ) + ( session_id = 'T3' station_id = 'S1' start_date = '20240102' start_time = '090000' energy_kwh = '3.00' status = 'A' ) + ( session_id = 'T4' station_id = 'S2' start_date = '20240101' start_time = '100000' energy_kwh = '20.00' status = 'C' ) + ( session_id = 'T5' station_id = 'S2' start_date = '20240102' start_time = '110000' energy_kwh = '8.00' status = 'R' ) + ( session_id = 'T6' station_id = 'S3' start_date = '20240103' start_time = '140000' energy_kwh = '4.50' status = 'C' ) + ( session_id = 'T7' station_id = 'S3' start_date = '20240103' start_time = '160000' energy_kwh = '1.00' status = 'A' ) + ). + DELETE FROM {{p}}station. + DELETE FROM {{p}}session. + INSERT {{p}}station FROM TABLE @lt_station. + INSERT {{p}}session FROM TABLE @lt_session. + out->write( 'Seed data inserted.' ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0176/seed/session.tabl.asabap b/tasks_gen/eval/G0176/seed/session.tabl.asabap new file mode 100644 index 0000000..1f866cc --- /dev/null +++ b/tasks_gen/eval/G0176/seed/session.tabl.asabap @@ -0,0 +1,14 @@ +@EndUserText.label : 'Charging session' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}session { + key client : abap.clnt not null; + key session_id : abap.char(10) not null; + station_id : abap.char(10); + start_date : abap.dats; + start_time : abap.tims; + energy_kwh : abap.dec(9,2); + status : abap.char(1); +} diff --git a/tasks_gen/eval/G0176/seed/station.tabl.asabap b/tasks_gen/eval/G0176/seed/station.tabl.asabap new file mode 100644 index 0000000..91e8b51 --- /dev/null +++ b/tasks_gen/eval/G0176/seed/station.tabl.asabap @@ -0,0 +1,11 @@ +@EndUserText.label : 'Charging station' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}station { + key client : abap.clnt not null; + key station_id : abap.char(10) not null; + city : abap.char(40); + capacity_kw : abap.dec(5,1); +} diff --git a/tasks_gen/eval/G0176/spec.md b/tasks_gen/eval/G0176/spec.md new file mode 100644 index 0000000..db5e471 --- /dev/null +++ b/tasks_gen/eval/G0176/spec.md @@ -0,0 +1,28 @@ +# 1. Goal +Show the energy that each charging station has delivered. A dashboard and an OData service will read the energy totals, so the calculation must be in the database, in a CDS view. + +# 2. Open questions +None. + +# 3. Context +- Table {{P}}STATION (charging station), package $TMP. Key: STATION_ID (CHAR 10). Fields: CITY (CHAR 40), CAPACITY_KW (DEC 5,1). +- Table {{P}}SESSION (charging session), package $TMP. Key: SESSION_ID (CHAR 10). Fields: STATION_ID (CHAR 10), START_DATE (DATS), START_TIME (TIMS), ENERGY_KWH (DEC 9,2), STATUS (CHAR 1). STATUS can be 'C' (completed), 'A' (aborted), or 'R' (running). + +# 4. Contract +- Create the CDS view entity {{P}}I_STATION_ENERGY in package $TMP. +- Elements, with these names: STATION_ID (key), CITY, SESSION_COUNT, TOTAL_ENERGY. +- No authorization check (#NOT_REQUIRED). + +# 5. Business rules +1. Show one row for each charging station. +2. SESSION_COUNT is the number of charging sessions of the station. +3. TOTAL_ENERGY is the sum of the energy of the charging sessions of the station, in kWh with 2 decimals. + +# 6. Constraints +- Release target: 8.16 (SAP_BASIS 816). +- Coding standards: Clean ABAP. +- Out of scope: do not change {{P}}STATION and {{P}}SESSION. + +# 7. Acceptance +- The view is active and has no syntax error. +- Write ABAP Unit tests with CL_CDS_TEST_ENVIRONMENT in a global test class. diff --git a/tasks_gen/eval/G0176/task.json b/tasks_gen/eval/G0176/task.json new file mode 100644 index 0000000..3b07f7d --- /dev/null +++ b/tasks_gen/eval/G0176/task.json @@ -0,0 +1,86 @@ +{ + "id": "G0176", + "category": "H", + "object_type": "DDLS", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "stop", + "expected_gap": { + "description": "The spec does not say which charging sessions count for SESSION_COUNT and TOTAL_ENERGY: only completed sessions, or also aborted and running sessions.", + "keywords": [ + [ + "session", + "count" + ], + [ + "status", + "count" + ], + [ + "completed", + "aborted" + ], + [ + "running", + "include" + ] + ] + }, + "budget": { + "max_tool_calls": 20, + "max_activations": 5 + }, + "seed": [ + { + "type": "TABL", + "name": "{{P}}STATION", + "file": "seed/station.tabl.asabap", + "description": "Charging station" + }, + { + "type": "TABL", + "name": "{{P}}SESSION", + "file": "seed/session.tabl.asabap", + "description": "Charging session" + }, + { + "type": "CLAS", + "name": "{{P}}SEED_DATA", + "file": "seed/seed_data.clas.abap", + "description": "Seed data for charging stations and sessions", + "run": true + } + ], + "contract": [ + { + "type": "DDLS", + "name": "{{P}}I_STATION_ENERGY", + "fields": [ + "STATION_ID", + "CITY", + "SESSION_COUNT", + "TOTAL_ENERGY" + ] + } + ], + "out_of_scope": [ + "{{P}}STATION", + "{{P}}SESSION" + ], + "hidden_tests": [], + "reference": [ + { + "type": "DDLS", + "name": "{{P}}I_STATION_ENERGY", + "file": "reference/i_station_energy.ddls.asddls", + "description": "Station energy totals (assuming only completed sessions count)" + }, + { + "type": "CLAS", + "name": "{{P}}H_ENERGY_TEST", + "file": "reference/h_energy_test.clas.abap", + "description": "Own tests for the view" + } + ], + "craft_checks": [] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0177/generation.json b/tasks_gen/eval/G0177/generation.json new file mode 100644 index 0000000..3f47f5c --- /dev/null +++ b/tasks_gen/eval/G0177/generation.json @@ -0,0 +1,14 @@ +{ + "id": "G0177", + "pool": "eval", + "object_type": "DDLS", + "category": "H", + "attempts": [ + { + "stage": "validate", + "oracle": 100, + "null": 30 + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0177/reference/event_revenue_test.clas.abap b/tasks_gen/eval/G0177/reference/event_revenue_test.clas.abap new file mode 100644 index 0000000..1137373 --- /dev/null +++ b/tasks_gen/eval/G0177/reference/event_revenue_test.clas.abap @@ -0,0 +1,40 @@ +CLASS {{p}}event_revenue_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 confirmed_only FOR TESTING. +ENDCLASS. + +CLASS {{p}}event_revenue_test IMPLEMENTATION. + METHOD class_setup. + go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_EVENT_REVENUE' ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + go_env->clear_doubles( ). + ENDMETHOD. + + METHOD confirmed_only. + DATA lt_event TYPE STANDARD TABLE OF {{p}}event WITH EMPTY KEY. + DATA lt_booking TYPE STANDARD TABLE OF {{p}}booking WITH EMPTY KEY. + lt_event = VALUE #( ( event_id = 'E1' event_date = '20250101' room = 'A1' ) ). + lt_booking = VALUE #( + ( event_id = 'E1' booking_no = 1 guests = 10 fee = '100.00' status = 'C' ) + ( event_id = 'E1' booking_no = 2 guests = 5 fee = '50.00' status = 'X' ) + ). + go_env->insert_test_data( lt_event ). + go_env->insert_test_data( lt_booking ). + SELECT SINGLE booking_count, total_guests, total_fee FROM {{p}}i_event_revenue + WHERE event_id = 'E1' INTO @DATA(ls_rev). + cl_abap_unit_assert=>assert_equals( exp = 1 act = ls_rev-booking_count ). + cl_abap_unit_assert=>assert_equals( exp = 10 act = ls_rev-total_guests ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '100.00' ) act = CONV decfloat34( ls_rev-total_fee ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0177/reference/i_event_revenue.ddls.asddls b/tasks_gen/eval/G0177/reference/i_event_revenue.ddls.asddls new file mode 100644 index 0000000..ec547ad --- /dev/null +++ b/tasks_gen/eval/G0177/reference/i_event_revenue.ddls.asddls @@ -0,0 +1,16 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Event revenue' +define view entity {{P}}I_EVENT_REVENUE + as select from {{p}}event as ev + left outer join {{p}}booking as bk on bk.event_id = ev.event_id + and bk.status = 'C' +{ + key ev.event_id as event_id, + ev.event_date as event_date, + count( bk.booking_no ) as booking_count, + sum( bk.guests ) as total_guests, + sum( bk.fee ) as total_fee +} +group by + ev.event_id, + ev.event_date diff --git a/tasks_gen/eval/G0177/seed/booking.tabl.asabap b/tasks_gen/eval/G0177/seed/booking.tabl.asabap new file mode 100644 index 0000000..4f697eb --- /dev/null +++ b/tasks_gen/eval/G0177/seed/booking.tabl.asabap @@ -0,0 +1,13 @@ +@EndUserText.label : 'Event booking' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}booking { + key client : abap.clnt not null; + key event_id : abap.char(10) not null; + key booking_no : abap.int4 not null; + guests : abap.int4; + fee : abap.dec(15,2); + status : abap.char(1); +} diff --git a/tasks_gen/eval/G0177/seed/event.tabl.asabap b/tasks_gen/eval/G0177/seed/event.tabl.asabap new file mode 100644 index 0000000..6434f13 --- /dev/null +++ b/tasks_gen/eval/G0177/seed/event.tabl.asabap @@ -0,0 +1,11 @@ +@EndUserText.label : 'Event header' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}event { + key client : abap.clnt not null; + key event_id : abap.char(10) not null; + event_date : abap.dats; + room : abap.char(4); +} diff --git a/tasks_gen/eval/G0177/seed/seed_event.clas.abap b/tasks_gen/eval/G0177/seed/seed_event.clas.abap new file mode 100644 index 0000000..07b389e --- /dev/null +++ b/tasks_gen/eval/G0177/seed/seed_event.clas.abap @@ -0,0 +1,23 @@ +CLASS {{p}}seed_event DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES if_oo_adt_classrun. +ENDCLASS. + +CLASS {{p}}seed_event IMPLEMENTATION. + METHOD if_oo_adt_classrun~main. + DELETE FROM {{p}}event. + DELETE FROM {{p}}booking. + INSERT {{p}}event FROM TABLE @( VALUE #( + ( event_id = 'E1' event_date = '20250101' room = 'A1' ) + ( event_id = 'E2' event_date = '20250102' room = 'A2' ) + ( event_id = 'E3' event_date = '20250103' room = 'B1' ) + ) ). + INSERT {{p}}booking FROM TABLE @( VALUE #( + ( event_id = 'E1' booking_no = 1 guests = 10 fee = '100.00' status = 'C' ) + ( event_id = 'E1' booking_no = 2 guests = 5 fee = '50.00' status = 'C' ) + ( event_id = 'E2' booking_no = 1 guests = 20 fee = '200.00' status = 'C' ) + ( event_id = 'E2' booking_no = 2 guests = 15 fee = '150.00' status = 'X' ) + ( event_id = 'E3' booking_no = 1 guests = 8 fee = '80.00' status = 'X' ) + ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0177/spec.md b/tasks_gen/eval/G0177/spec.md new file mode 100644 index 0000000..5d811df --- /dev/null +++ b/tasks_gen/eval/G0177/spec.md @@ -0,0 +1,30 @@ +# 1. Goal +Show the revenue and the number of guests for each event in a conference centre. A report and an OData service will read the totals, so the calculation must be in the database, in a CDS view. + +# 2. Open questions +None. + +# 3. Context +- Table {{P}}EVENT (event header), package $TMP. Key: EVENT_ID (CHAR 10). Fields: EVENT_DATE (DATS), ROOM (CHAR 4). +- Table {{P}}BOOKING (event booking), package $TMP. Key: EVENT_ID (CHAR 10), BOOKING_NO (INT4). Fields: GUESTS (INT4), FEE (DEC 15,2), STATUS (CHAR 1). + +# 4. Contract +- Create the CDS view entity {{P}}I_EVENT_REVENUE in package $TMP. +- Elements, with these names: EVENT_ID (key), EVENT_DATE, BOOKING_COUNT, TOTAL_GUESTS, TOTAL_FEE. +- No authorization check (#NOT_REQUIRED). + +# 5. Business rules +1. Show one row for each event. +2. BOOKING_COUNT is the number of bookings of the event. +3. TOTAL_GUESTS is the sum of GUESTS of all bookings of the event. +4. TOTAL_FEE is the sum of FEE of all bookings of the event. +5. Only include bookings with STATUS = 'C' (confirmed). +6. Include all bookings, also cancelled ones, because the revenue must show the original amount. + +# 6. Constraints +- Release target: 8.16. +- Out of scope: do not change {{P}}EVENT and {{P}}BOOKING. + +# 7. Acceptance +- The view is active and has no syntax error. +- Write ABAP Unit tests with CL_CDS_TEST_ENVIRONMENT in a global test class. diff --git a/tasks_gen/eval/G0177/task.json b/tasks_gen/eval/G0177/task.json new file mode 100644 index 0000000..c2796ac --- /dev/null +++ b/tasks_gen/eval/G0177/task.json @@ -0,0 +1,83 @@ +{ + "id": "G0177", + "category": "H", + "object_type": "DDLS", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "stop", + "expected_gap": { + "description": "Business rules 5 and 6 contradict: rule 5 says only confirmed bookings, rule 6 says all bookings including cancelled ones.", + "keywords": [ + [ + "contradiction", + "rules" + ], + [ + "contradict", + "rules" + ], + [ + "confirmed", + "cancelled" + ] + ] + }, + "budget": { + "max_tool_calls": 20, + "max_activations": 5 + }, + "seed": [ + { + "type": "TABL", + "name": "{{P}}EVENT", + "file": "seed/event.tabl.asabap", + "description": "Event header" + }, + { + "type": "TABL", + "name": "{{P}}BOOKING", + "file": "seed/booking.tabl.asabap", + "description": "Event booking" + }, + { + "type": "CLAS", + "name": "{{P}}SEED_EVENT", + "file": "seed/seed_event.clas.abap", + "description": "Seed data for event and booking", + "run": true + } + ], + "contract": [ + { + "type": "DDLS", + "name": "{{P}}I_EVENT_REVENUE", + "fields": [ + "EVENT_ID", + "EVENT_DATE", + "BOOKING_COUNT", + "TOTAL_GUESTS", + "TOTAL_FEE" + ] + } + ], + "out_of_scope": [ + "{{P}}EVENT", + "{{P}}BOOKING" + ], + "hidden_tests": [], + "reference": [ + { + "type": "DDLS", + "name": "{{P}}I_EVENT_REVENUE", + "file": "reference/i_event_revenue.ddls.asddls", + "description": "Event revenue (intended)" + }, + { + "type": "CLAS", + "name": "{{P}}EVENT_REVENUE_TEST", + "file": "reference/event_revenue_test.clas.abap", + "description": "Own tests for event revenue" + } + ], + "craft_checks": [] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0178/task.json b/tasks_gen/eval/G0178/task.json index 19cf67a..e78f1c9 100644 --- a/tasks_gen/eval/G0178/task.json +++ b/tasks_gen/eval/G0178/task.json @@ -7,7 +7,7 @@ "expected_outcome": "implement", "budget": { "max_tool_calls": 60, - "max_activations": 12 + "max_activations": 15 }, "seed": [ { diff --git a/tasks_gen/eval/G0179/empirical.json b/tasks_gen/eval/G0179/empirical.json new file mode 100644 index 0000000..838c6fb --- /dev/null +++ b/tasks_gen/eval/G0179/empirical.json @@ -0,0 +1,18 @@ +{ + "deepseek-v4.1-flash:cloud": { + "score": 100.0, + "parts": { + "correctness": 40.0, + "craft": 20.0, + "clean": 15.0, + "own_tests": 15.0, + "discipline": 10.0, + "total": 100.0, + "note": "own_tests: faulty-reference part not implemented in skeleton" + }, + "hidden": "10/10", + "tool_calls": 6, + "seconds": 23.4, + "run_dir": "runs/emp/10003_G0007_llm_deepseek-v4.1-flash_cloud" + } +} \ No newline at end of file diff --git a/tasks_gen/eval/G0179/generation.json b/tasks_gen/eval/G0179/generation.json new file mode 100644 index 0000000..75fb486 --- /dev/null +++ b/tasks_gen/eval/G0179/generation.json @@ -0,0 +1,16 @@ +{ + "id": "G0179", + "pool": "eval", + "category": "K", + "base_task": "G0007", + "style": "incomplete", + "tool_schema": "generic_v0", + "attempts": [ + { + "stage": "validate", + "oracle": 100.0, + "null": 0 + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0179/hidden/t02_hidden.clas.abap b/tasks_gen/eval/G0179/hidden/t02_hidden.clas.abap new file mode 100644 index 0000000..b689ca6 --- /dev/null +++ b/tasks_gen/eval/G0179/hidden/t02_hidden.clas.abap @@ -0,0 +1,103 @@ +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_loyalty_rules. + METHODS setup. + METHODS tier_boundaries FOR TESTING. + METHODS tier_negative FOR TESTING. + METHODS tier_zero FOR TESTING. + METHODS discount_all_tiers FOR TESTING. + METHODS discount_unknown_tier FOR TESTING. + METHODS next_tier_from_basic FOR TESTING. + METHODS next_tier_from_silver FOR TESTING. + METHODS next_tier_from_gold FOR TESTING. + METHODS next_tier_from_platinum FOR TESTING. + METHODS next_tier_negative_points FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t02_hidden IMPLEMENTATION. + METHOD setup. + mo_cut = NEW {{p}}loyalty_evaluator( ). + ENDMETHOD. + + METHOD tier_boundaries. + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_loyalty_rules=>c_tier-basic + act = mo_cut->get_tier( 999 ) msg = `999` ). + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_loyalty_rules=>c_tier-silver + act = mo_cut->get_tier( 1000 ) msg = `1000` ). + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_loyalty_rules=>c_tier-silver + act = mo_cut->get_tier( 4999 ) msg = `4999` ). + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_loyalty_rules=>c_tier-gold + act = mo_cut->get_tier( 5000 ) msg = `5000` ). + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_loyalty_rules=>c_tier-gold + act = mo_cut->get_tier( 19999 ) msg = `19999` ). + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_loyalty_rules=>c_tier-platinum + act = mo_cut->get_tier( 20000 ) msg = `20000` ). + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_loyalty_rules=>c_tier-platinum + act = mo_cut->get_tier( 500000 ) msg = `500000` ). + ENDMETHOD. + + METHOD tier_negative. + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_loyalty_rules=>c_tier-basic + act = mo_cut->get_tier( -1 ) ). + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_loyalty_rules=>c_tier-basic + act = mo_cut->get_tier( -5000 ) ). + ENDMETHOD. + + METHOD tier_zero. + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_loyalty_rules=>c_tier-basic + act = mo_cut->get_tier( 0 ) ). + ENDMETHOD. + + METHOD discount_all_tiers. + cl_abap_unit_assert=>assert_equals( exp = 0 + act = mo_cut->get_discount( {{p}}if_loyalty_rules=>c_tier-basic ) msg = `basic` ). + cl_abap_unit_assert=>assert_equals( exp = 3 + act = mo_cut->get_discount( {{p}}if_loyalty_rules=>c_tier-silver ) msg = `silver` ). + cl_abap_unit_assert=>assert_equals( exp = 7 + act = mo_cut->get_discount( {{p}}if_loyalty_rules=>c_tier-gold ) msg = `gold` ). + cl_abap_unit_assert=>assert_equals( exp = 12 + act = mo_cut->get_discount( {{p}}if_loyalty_rules=>c_tier-platinum ) msg = `platinum` ). + ENDMETHOD. + + METHOD discount_unknown_tier. + cl_abap_unit_assert=>assert_equals( exp = 0 + act = mo_cut->get_discount( 'X' ) ). + cl_abap_unit_assert=>assert_equals( exp = 0 + act = mo_cut->get_discount( ' ' ) ). + ENDMETHOD. + + METHOD next_tier_from_basic. + cl_abap_unit_assert=>assert_equals( exp = 1000 + act = mo_cut->points_to_next_tier( 0 ) msg = `0` ). + cl_abap_unit_assert=>assert_equals( exp = 1 + act = mo_cut->points_to_next_tier( 999 ) msg = `999` ). + ENDMETHOD. + + METHOD next_tier_from_silver. + cl_abap_unit_assert=>assert_equals( exp = 4000 + act = mo_cut->points_to_next_tier( 1000 ) msg = `1000` ). + cl_abap_unit_assert=>assert_equals( exp = 1 + act = mo_cut->points_to_next_tier( 4999 ) msg = `4999` ). + ENDMETHOD. + + METHOD next_tier_from_gold. + cl_abap_unit_assert=>assert_equals( exp = 15000 + act = mo_cut->points_to_next_tier( 5000 ) msg = `5000` ). + cl_abap_unit_assert=>assert_equals( exp = 1 + act = mo_cut->points_to_next_tier( 19999 ) msg = `19999` ). + ENDMETHOD. + + METHOD next_tier_from_platinum. + cl_abap_unit_assert=>assert_equals( exp = 0 + act = mo_cut->points_to_next_tier( 20000 ) ). + cl_abap_unit_assert=>assert_equals( exp = 0 + act = mo_cut->points_to_next_tier( 999999 ) ). + ENDMETHOD. + + METHOD next_tier_negative_points. + cl_abap_unit_assert=>assert_equals( exp = 1000 + act = mo_cut->points_to_next_tier( -7 ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0179/reference/loyalty_evaluator.clas.abap b/tasks_gen/eval/G0179/reference/loyalty_evaluator.clas.abap new file mode 100644 index 0000000..0213d17 --- /dev/null +++ b/tasks_gen/eval/G0179/reference/loyalty_evaluator.clas.abap @@ -0,0 +1,79 @@ +CLASS {{p}}loyalty_evaluator DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_loyalty_rules. + + PRIVATE SECTION. + CONSTANTS: + c_silver_threshold TYPE i VALUE 1000, + c_gold_threshold TYPE i VALUE 5000, + c_platinum_threshold TYPE i VALUE 20000. + + METHODS normalize_points + IMPORTING iv_points TYPE i + RETURNING VALUE(rv_points) TYPE i. + + METHODS tier_of + IMPORTING iv_points TYPE i + RETURNING VALUE(rv_tier) TYPE {{p}}if_loyalty_rules=>ty_tier. + + METHODS points_to_tier + IMPORTING iv_points TYPE i + iv_tier TYPE {{p}}if_loyalty_rules=>ty_tier + RETURNING VALUE(rv_points) TYPE i. +ENDCLASS. + + +CLASS {{p}}loyalty_evaluator IMPLEMENTATION. + METHOD {{p}}if_loyalty_rules~get_tier. + rv_tier = tier_of( normalize_points( iv_points ) ). + ENDMETHOD. + + METHOD {{p}}if_loyalty_rules~get_discount. + CASE iv_tier. + WHEN {{p}}if_loyalty_rules=>c_tier-silver. + rv_percent = 3. + WHEN {{p}}if_loyalty_rules=>c_tier-gold. + rv_percent = 7. + WHEN {{p}}if_loyalty_rules=>c_tier-platinum. + rv_percent = 12. + WHEN OTHERS. + rv_percent = 0. + ENDCASE. + ENDMETHOD. + + METHOD {{p}}if_loyalty_rules~points_to_next_tier. + DATA(lv_points) = normalize_points( iv_points ). + DATA(lv_tier) = tier_of( lv_points ). + rv_points = points_to_tier( iv_points = lv_points + iv_tier = lv_tier ). + ENDMETHOD. + + METHOD normalize_points. + rv_points = COND #( WHEN iv_points < 0 THEN 0 ELSE iv_points ). + ENDMETHOD. + + METHOD tier_of. + IF iv_points >= c_platinum_threshold. + rv_tier = {{p}}if_loyalty_rules=>c_tier-platinum. + ELSEIF iv_points >= c_gold_threshold. + rv_tier = {{p}}if_loyalty_rules=>c_tier-gold. + ELSEIF iv_points >= c_silver_threshold. + rv_tier = {{p}}if_loyalty_rules=>c_tier-silver. + ELSE. + rv_tier = {{p}}if_loyalty_rules=>c_tier-basic. + ENDIF. + ENDMETHOD. + + METHOD points_to_tier. + CASE iv_tier. + WHEN {{p}}if_loyalty_rules=>c_tier-basic. + rv_points = c_silver_threshold - iv_points. + WHEN {{p}}if_loyalty_rules=>c_tier-silver. + rv_points = c_gold_threshold - iv_points. + WHEN {{p}}if_loyalty_rules=>c_tier-gold. + rv_points = c_platinum_threshold - iv_points. + WHEN OTHERS. + rv_points = 0. + ENDCASE. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0179/reference/loyalty_evaluator.testclasses.abap b/tasks_gen/eval/G0179/reference/loyalty_evaluator.testclasses.abap new file mode 100644 index 0000000..882bc5f --- /dev/null +++ b/tasks_gen/eval/G0179/reference/loyalty_evaluator.testclasses.abap @@ -0,0 +1,77 @@ +CLASS ltc_loyalty_evaluator DEFINITION FINAL FOR TESTING + DURATION SHORT RISK LEVEL HARMLESS. + + PRIVATE SECTION. + DATA mo_cut TYPE REF TO {{p}}if_loyalty_rules. + + METHODS setup. + METHODS tier_of_boundary_points FOR TESTING. + METHODS negative_points_are_basic FOR TESTING. + METHODS discount_of_each_tier FOR TESTING. + METHODS discount_of_unknown_tier FOR TESTING. + METHODS points_to_silver FOR TESTING. + METHODS points_to_gold FOR TESTING. + METHODS points_to_platinum FOR TESTING. + METHODS platinum_needs_no_points FOR TESTING. +ENDCLASS. + + +CLASS ltc_loyalty_evaluator IMPLEMENTATION. + METHOD setup. + mo_cut = NEW {{p}}loyalty_evaluator( ). + ENDMETHOD. + + METHOD tier_of_boundary_points. + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_loyalty_rules=>c_tier-basic + act = mo_cut->get_tier( 0 ) ). + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_loyalty_rules=>c_tier-silver + act = mo_cut->get_tier( 1000 ) ). + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_loyalty_rules=>c_tier-gold + act = mo_cut->get_tier( 5000 ) ). + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_loyalty_rules=>c_tier-platinum + act = mo_cut->get_tier( 20000 ) ). + ENDMETHOD. + + METHOD negative_points_are_basic. + cl_abap_unit_assert=>assert_equals( exp = {{p}}if_loyalty_rules=>c_tier-basic + act = mo_cut->get_tier( -100 ) ). + ENDMETHOD. + + METHOD discount_of_each_tier. + cl_abap_unit_assert=>assert_equals( exp = 0 + act = mo_cut->get_discount( {{p}}if_loyalty_rules=>c_tier-basic ) ). + cl_abap_unit_assert=>assert_equals( exp = 3 + act = mo_cut->get_discount( {{p}}if_loyalty_rules=>c_tier-silver ) ). + cl_abap_unit_assert=>assert_equals( exp = 7 + act = mo_cut->get_discount( {{p}}if_loyalty_rules=>c_tier-gold ) ). + cl_abap_unit_assert=>assert_equals( exp = 12 + act = mo_cut->get_discount( {{p}}if_loyalty_rules=>c_tier-platinum ) ). + ENDMETHOD. + + METHOD discount_of_unknown_tier. + cl_abap_unit_assert=>assert_equals( exp = 0 + act = mo_cut->get_discount( 'X' ) ). + ENDMETHOD. + + METHOD points_to_silver. + cl_abap_unit_assert=>assert_equals( exp = 1000 + act = mo_cut->points_to_next_tier( 0 ) ). + cl_abap_unit_assert=>assert_equals( exp = 1 + act = mo_cut->points_to_next_tier( 999 ) ). + ENDMETHOD. + + METHOD points_to_gold. + cl_abap_unit_assert=>assert_equals( exp = 4000 + act = mo_cut->points_to_next_tier( 1000 ) ). + ENDMETHOD. + + METHOD points_to_platinum. + cl_abap_unit_assert=>assert_equals( exp = 15000 + act = mo_cut->points_to_next_tier( 5000 ) ). + ENDMETHOD. + + METHOD platinum_needs_no_points. + cl_abap_unit_assert=>assert_equals( exp = 0 + act = mo_cut->points_to_next_tier( 20000 ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0179/review.json b/tasks_gen/eval/G0179/review.json new file mode 100644 index 0000000..8d4354a --- /dev/null +++ b/tasks_gen/eval/G0179/review.json @@ -0,0 +1,7 @@ +{ + "decision": "accept", + "note": "Interface must be read; fits F.", + "by": "Claude", + "date": "2026-10-03", + "failed_checks": {} +} \ No newline at end of file diff --git a/tasks_gen/eval/G0179/seed/if_loyalty_rules.intf.abap b/tasks_gen/eval/G0179/seed/if_loyalty_rules.intf.abap new file mode 100644 index 0000000..75aaeb7 --- /dev/null +++ b/tasks_gen/eval/G0179/seed/if_loyalty_rules.intf.abap @@ -0,0 +1,24 @@ +INTERFACE {{p}}if_loyalty_rules PUBLIC. + TYPES ty_points TYPE i. + TYPES ty_tier TYPE c LENGTH 1. + + CONSTANTS: + BEGIN OF c_tier, + basic TYPE ty_tier VALUE 'B', + silver TYPE ty_tier VALUE 'S', + gold TYPE ty_tier VALUE 'G', + platinum TYPE ty_tier VALUE 'P', + END OF c_tier. + + METHODS get_tier + IMPORTING iv_points TYPE ty_points + RETURNING VALUE(rv_tier) TYPE ty_tier. + + METHODS get_discount + IMPORTING iv_tier TYPE ty_tier + RETURNING VALUE(rv_percent) TYPE i. + + METHODS points_to_next_tier + IMPORTING iv_points TYPE ty_points + RETURNING VALUE(rv_points) TYPE i. +ENDINTERFACE. diff --git a/tasks_gen/eval/G0179/spec.md b/tasks_gen/eval/G0179/spec.md new file mode 100644 index 0000000..52b482c --- /dev/null +++ b/tasks_gen/eval/G0179/spec.md @@ -0,0 +1,9 @@ +Create the public final class {{P}}LOYALTY_EVALUATOR in package $TMP. The class has a public constructor without parameters. The class implements the interface {{P}}IF_LOYALTY_RULES. Do not change {{P}}IF_LOYALTY_RULES. Do not add other public methods. Write ABAP Unit tests for the class. + +The class must return the tier for a point value. A point value below zero counts as zero. 0 to 999 points is basic. 1000 to 4999 points is silver. 5000 to 19999 points is gold. 20000 points and more is platinum. + +The class must return the discount percent for a tier. Basic is 0 percent. Silver is 3 percent. Gold is 7 percent. Platinum is 12 percent. Any other tier value is 0 percent. + +The class must return the points to the next tier. A point value below zero counts as zero. Basic needs 1000 points minus the point value. Silver needs 5000 points minus the point value. Gold needs 20000 points minus the point value. Platinum needs 0 points. + +The class must be active and have no syntax error. The hidden tests must pass. diff --git a/tasks_gen/eval/G0179/task.json b/tasks_gen/eval/G0179/task.json new file mode 100644 index 0000000..037defb --- /dev/null +++ b/tasks_gen/eval/G0179/task.json @@ -0,0 +1,54 @@ +{ + "id": "G0179", + "category": "K", + "object_type": "CLAS", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [ + { + "type": "INTF", + "name": "{{P}}IF_LOYALTY_RULES", + "file": "seed/if_loyalty_rules.intf.abap", + "description": "Loyalty contract: tier type, point type, tier constants and three methods. The spec does not repeat the signature." + } + ], + "contract": [ + { + "type": "CLAS", + "name": "{{P}}LOYALTY_EVALUATOR", + "implements": "{{P}}IF_LOYALTY_RULES" + } + ], + "out_of_scope": [ + "{{P}}IF_LOYALTY_RULES" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T02_HIDDEN", + "file": "hidden/t02_hidden.clas.abap", + "description": "T02 hidden tests" + } + ], + "reference": [ + { + "type": "CLAS", + "name": "{{P}}LOYALTY_EVALUATOR", + "file": "reference/loyalty_evaluator.clas.abap", + "description": "Loyalty evaluator", + "testclasses_file": "reference/loyalty_evaluator.testclasses.abap" + } + ], + "craft_checks": [ + "method_length", + "nesting_depth" + ], + "base_task": "G0007", + "input_style": "incomplete", + "tool_schema": "generic_v0" +} \ No newline at end of file diff --git a/tasks_gen/eval/G0180/empirical.json b/tasks_gen/eval/G0180/empirical.json new file mode 100644 index 0000000..e7bce4e --- /dev/null +++ b/tasks_gen/eval/G0180/empirical.json @@ -0,0 +1,18 @@ +{ + "deepseek-v4.1-flash:cloud": { + "score": 80.0, + "parts": { + "correctness": 40.0, + "craft": 20.0, + "clean": 15.0, + "own_tests": 0.0, + "discipline": 5.0, + "total": 80.0, + "note": "own_tests: faulty-reference part not implemented in skeleton" + }, + "hidden": "10/10", + "tool_calls": 12, + "seconds": 656.4, + "run_dir": "runs/emp/10017_G0026_llm_deepseek-v4.1-flash_cloud" + } +} \ No newline at end of file diff --git a/tasks_gen/eval/G0180/generation.json b/tasks_gen/eval/G0180/generation.json new file mode 100644 index 0000000..e12e953 --- /dev/null +++ b/tasks_gen/eval/G0180/generation.json @@ -0,0 +1,16 @@ +{ + "id": "G0180", + "pool": "eval", + "category": "K", + "base_task": "G0026", + "style": "free_text", + "tool_schema": "generic_v0", + "attempts": [ + { + "stage": "validate", + "oracle": 100.0, + "null": 0 + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0180/hidden/t14_hidden.clas.abap b/tasks_gen/eval/G0180/hidden/t14_hidden.clas.abap new file mode 100644 index 0000000..c89c2e2 --- /dev/null +++ b/tasks_gen/eval/G0180/hidden/t14_hidden.clas.abap @@ -0,0 +1,149 @@ +CLASS {{p}}t14_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + TYPES: BEGIN OF ty_result, + time_fee TYPE decfloat34, + distance_fee TYPE decfloat34, + surcharge TYPE decfloat34, + discount TYPE decfloat34, + total TYPE decfloat34, + END OF ty_result. + + METHODS price + IMPORTING iv_class TYPE string + iv_minutes TYPE i + iv_km TYPE i + iv_member TYPE abap_bool DEFAULT abap_false + iv_weekend TYPE abap_bool DEFAULT abap_false + EXPORTING es_result TYPE ty_result + ev_subrc TYPE sysubrc. + + METHODS time_fee_blocks FOR TESTING. + METHODS distance_fee_free_km FOR TESTING. + METHODS weekend_surcharge FOR TESTING. + METHODS weekday_no_surcharge FOR TESTING. + METHODS member_discount FOR TESTING. + METHODS minimum_total FOR TESTING. + METHODS minimum_total_member FOR TESTING. + METHODS invalid_duration FOR TESTING. + METHODS invalid_distance FOR TESTING. + METHODS invalid_class FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t14_hidden IMPLEMENTATION. + METHOD price. + CLEAR es_result. + CALL FUNCTION '{{P}}RENT_PRICE' + EXPORTING + iv_vehicle_class = iv_class + iv_minutes = iv_minutes + iv_km = iv_km + iv_member = iv_member + iv_weekend = iv_weekend + IMPORTING + ev_time_fee = es_result-time_fee + ev_distance_fee = es_result-distance_fee + ev_surcharge = es_result-surcharge + ev_discount = es_result-discount + ev_total = es_result-total + EXCEPTIONS + invalid_duration = 1 + invalid_distance = 2 + invalid_class = 3 + OTHERS = 4. + ev_subrc = sy-subrc. + ENDMETHOD. + + METHOD time_fee_blocks. + price( EXPORTING iv_class = `S` iv_minutes = 15 iv_km = 0 + IMPORTING es_result = DATA(ls_15) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 3 ) act = ls_15-time_fee ). + + price( EXPORTING iv_class = `S` iv_minutes = 16 iv_km = 0 + IMPORTING es_result = DATA(ls_16) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 6 ) act = ls_16-time_fee ). + + price( EXPORTING iv_class = `L` iv_minutes = 61 iv_km = 0 + IMPORTING es_result = DATA(ls_61) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 40 ) act = ls_61-time_fee ). + ENDMETHOD. + + METHOD distance_fee_free_km. + price( EXPORTING iv_class = `L` iv_minutes = 60 iv_km = 10 + IMPORTING es_result = DATA(ls_free) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 0 ) act = ls_free-distance_fee ). + + price( EXPORTING iv_class = `L` iv_minutes = 60 iv_km = 14 + IMPORTING es_result = DATA(ls_paid) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 1 ) act = ls_paid-distance_fee ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 33 ) act = ls_paid-total ). + ENDMETHOD. + + METHOD weekend_surcharge. + price( EXPORTING iv_class = `M` iv_minutes = 30 iv_km = 0 iv_weekend = abap_true + IMPORTING es_result = DATA(ls) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '2.50' ) act = ls-surcharge ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '12.50' ) act = ls-total ). + ENDMETHOD. + + METHOD weekday_no_surcharge. + price( EXPORTING iv_class = `M` iv_minutes = 30 iv_km = 0 + IMPORTING es_result = DATA(ls) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 0 ) act = ls-surcharge ). + ENDMETHOD. + + METHOD member_discount. + " 6.50 * 15 % = 0.975 -> 0.98 + price( EXPORTING iv_class = `M` iv_minutes = 15 iv_km = 11 + iv_weekend = abap_true iv_member = abap_true + IMPORTING es_result = DATA(ls_half) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '0.98' ) act = ls_half-discount ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '5.52' ) act = ls_half-total ). + + " 10.75 * 15 % = 1.6125 -> 1.61 + price( EXPORTING iv_class = `M` iv_minutes = 30 iv_km = 13 iv_member = abap_true + IMPORTING es_result = DATA(ls_round) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '1.61' ) act = ls_round-discount ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '9.14' ) act = ls_round-total ). + + " 7.50 * 15 % = 1.125 -> 1.13 + price( EXPORTING iv_class = `S` iv_minutes = 15 iv_km = 28 iv_member = abap_true + IMPORTING es_result = DATA(ls_up) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '1.13' ) act = ls_up-discount ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '6.37' ) act = ls_up-total ). + ENDMETHOD. + + METHOD minimum_total. + price( EXPORTING iv_class = `S` iv_minutes = 15 iv_km = 0 + IMPORTING es_result = DATA(ls) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 3 ) act = ls-time_fee ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 0 ) act = ls-discount ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 5 ) act = ls-total ). + ENDMETHOD. + + METHOD minimum_total_member. + price( EXPORTING iv_class = `S` iv_minutes = 15 iv_km = 0 iv_member = abap_true + IMPORTING es_result = DATA(ls) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '0.45' ) act = ls-discount ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 5 ) act = ls-total ). + ENDMETHOD. + + METHOD invalid_duration. + price( EXPORTING iv_class = `S` iv_minutes = 0 iv_km = 0 + IMPORTING ev_subrc = DATA(lv_subrc) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lv_subrc ). + ENDMETHOD. + + METHOD invalid_distance. + price( EXPORTING iv_class = `S` iv_minutes = 15 iv_km = -1 + IMPORTING ev_subrc = DATA(lv_subrc) ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lv_subrc ). + ENDMETHOD. + + METHOD invalid_class. + price( EXPORTING iv_class = `X` iv_minutes = 15 iv_km = 0 + IMPORTING ev_subrc = DATA(lv_subrc) ). + cl_abap_unit_assert=>assert_equals( exp = 3 act = lv_subrc ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0180/reference/cl_rent.clas.abap b/tasks_gen/eval/G0180/reference/cl_rent.clas.abap new file mode 100644 index 0000000..3e53232 --- /dev/null +++ b/tasks_gen/eval/G0180/reference/cl_rent.clas.abap @@ -0,0 +1,158 @@ +CLASS {{p}}cl_rent DEFINITION + PUBLIC + FINAL + CREATE PUBLIC. + + PUBLIC SECTION. + TYPES ty_class TYPE string. + TYPES ty_money TYPE decfloat34. + TYPES ty_err_code TYPE c LENGTH 1. + + CONSTANTS: BEGIN OF c_err, + ok TYPE ty_err_code VALUE ' ', + duration TYPE ty_err_code VALUE 'D', + distance TYPE ty_err_code VALUE 'K', + bad_class TYPE ty_err_code VALUE 'C', + END OF c_err. + + TYPES: BEGIN OF ty_request, + vehicle_class TYPE ty_class, + minutes TYPE i, + km TYPE i, + member TYPE abap_bool, + weekend TYPE abap_bool, + END OF ty_request. + + TYPES: BEGIN OF ty_result, + err_code TYPE ty_err_code, + time_fee TYPE ty_money, + distance_fee TYPE ty_money, + surcharge TYPE ty_money, + discount TYPE ty_money, + total TYPE ty_money, + END OF ty_result. + + CLASS-METHODS calculate + IMPORTING is_request TYPE ty_request + RETURNING VALUE(rs_result) TYPE ty_result. + + PRIVATE SECTION. + CONSTANTS: BEGIN OF c_block_price, + small TYPE ty_money VALUE '3.00', + medium TYPE ty_money VALUE '5.00', + large TYPE ty_money VALUE '8.00', + END OF c_block_price. + CONSTANTS c_block_minutes TYPE i VALUE 15. + CONSTANTS c_free_km TYPE i VALUE 10. + CONSTANTS c_km_price TYPE ty_money VALUE '0.25'. + CONSTANTS c_weekend_share TYPE ty_money VALUE '0.25'. + CONSTANTS c_member_share TYPE ty_money VALUE '0.15'. + CONSTANTS c_min_total TYPE ty_money VALUE '5.00'. + CONSTANTS c_decimals TYPE i VALUE 2. + + CLASS-METHODS validate + IMPORTING is_request TYPE ty_request + RETURNING VALUE(rv_err_code) TYPE ty_err_code. + + CLASS-METHODS time_fee + IMPORTING is_request TYPE ty_request + RETURNING VALUE(rv_fee) TYPE ty_money. + + CLASS-METHODS distance_fee + IMPORTING is_request TYPE ty_request + RETURNING VALUE(rv_fee) TYPE ty_money. + + CLASS-METHODS block_price + IMPORTING is_request TYPE ty_request + RETURNING VALUE(rv_price) TYPE ty_money. + + CLASS-METHODS block_count + IMPORTING iv_minutes TYPE i + RETURNING VALUE(rv_blocks) TYPE i. + + CLASS-METHODS round_money + IMPORTING iv_value TYPE ty_money + RETURNING VALUE(rv_value) TYPE ty_money. +ENDCLASS. + + +CLASS {{p}}cl_rent IMPLEMENTATION. + METHOD calculate. + rs_result-err_code = validate( is_request ). + IF rs_result-err_code <> c_err-ok. + RETURN. + ENDIF. + + rs_result-time_fee = time_fee( is_request ). + rs_result-distance_fee = distance_fee( is_request ). + + IF is_request-weekend = abap_true. + rs_result-surcharge = round_money( rs_result-time_fee * c_weekend_share ). + ELSE. + rs_result-surcharge = 0. + ENDIF. + + DATA(lv_gross) = rs_result-time_fee + rs_result-distance_fee + rs_result-surcharge. + + IF is_request-member = abap_true. + rs_result-discount = round_money( lv_gross * c_member_share ). + ELSE. + rs_result-discount = 0. + ENDIF. + + rs_result-total = round_money( lv_gross - rs_result-discount ). + IF rs_result-total < c_min_total. + rs_result-total = c_min_total. + ENDIF. + ENDMETHOD. + + METHOD validate. + IF is_request-minutes < 1. + rv_err_code = c_err-duration. + ELSEIF is_request-km < 0. + rv_err_code = c_err-distance. + ELSEIF is_request-vehicle_class <> 'S' + AND is_request-vehicle_class <> 'M' + AND is_request-vehicle_class <> 'L'. + rv_err_code = c_err-bad_class. + ELSE. + rv_err_code = c_err-ok. + ENDIF. + ENDMETHOD. + + METHOD time_fee. + rv_fee = block_count( is_request-minutes ) * block_price( is_request ). + ENDMETHOD. + + METHOD distance_fee. + DATA(lv_chargeable_km) = is_request-km - c_free_km. + IF lv_chargeable_km > 0. + rv_fee = lv_chargeable_km * c_km_price. + ELSE. + rv_fee = 0. + ENDIF. + ENDMETHOD. + + METHOD block_price. + CASE is_request-vehicle_class. + WHEN 'S'. + rv_price = c_block_price-small. + WHEN 'M'. + rv_price = c_block_price-medium. + WHEN 'L'. + rv_price = c_block_price-large. + WHEN OTHERS. + rv_price = 0. + ENDCASE. + ENDMETHOD. + + METHOD block_count. + rv_blocks = ( iv_minutes + c_block_minutes - 1 ) DIV c_block_minutes. + ENDMETHOD. + + METHOD round_money. + rv_value = round( val = iv_value + dec = c_decimals + mode = cl_abap_math=>round_half_up ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0180/reference/cl_rent.clas.testclasses.abap b/tasks_gen/eval/G0180/reference/cl_rent.clas.testclasses.abap new file mode 100644 index 0000000..97246f6 --- /dev/null +++ b/tasks_gen/eval/G0180/reference/cl_rent.clas.testclasses.abap @@ -0,0 +1,87 @@ +CLASS {{p}}lcl_rent_test DEFINITION FOR TESTING + DURATION SHORT RISK LEVEL HARMLESS FINAL. + + PRIVATE SECTION. + METHODS price_for + IMPORTING iv_class TYPE string + iv_minutes TYPE i + iv_km TYPE i + iv_member TYPE abap_bool DEFAULT abap_false + iv_weekend TYPE abap_bool DEFAULT abap_false + RETURNING VALUE(rs_result) TYPE {{p}}cl_rent=>ty_result. + + METHODS time_fee_blocks FOR TESTING. + METHODS distance_fee_free_km FOR TESTING. + METHODS weekend_surcharge FOR TESTING. + METHODS member_discount FOR TESTING. + METHODS minimum_total FOR TESTING. + METHODS invalid_input FOR TESTING. +ENDCLASS. + + +CLASS {{p}}lcl_rent_test IMPLEMENTATION. + METHOD price_for. + DATA(ls_request) = VALUE {{p}}cl_rent=>ty_request( + vehicle_class = iv_class + minutes = iv_minutes + km = iv_km + member = iv_member + weekend = iv_weekend ). + rs_result = {{p}}cl_rent=>calculate( ls_request ). + ENDMETHOD. + + METHOD time_fee_blocks. + DATA(ls_15) = price_for( iv_class = `S` iv_minutes = 15 iv_km = 0 ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 3 ) act = ls_15-time_fee ). + + DATA(ls_16) = price_for( iv_class = `S` iv_minutes = 16 iv_km = 0 ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 6 ) act = ls_16-time_fee ). + + DATA(ls_61) = price_for( iv_class = `L` iv_minutes = 61 iv_km = 0 ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 40 ) act = ls_61-time_fee ). + ENDMETHOD. + + METHOD distance_fee_free_km. + DATA(ls_free) = price_for( iv_class = `L` iv_minutes = 60 iv_km = 10 ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 0 ) act = ls_free-distance_fee ). + + DATA(ls_paid) = price_for( iv_class = `L` iv_minutes = 60 iv_km = 14 ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 1 ) act = ls_paid-distance_fee ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 33 ) act = ls_paid-total ). + ENDMETHOD. + + METHOD weekend_surcharge. + DATA(ls) = price_for( iv_class = `M` iv_minutes = 30 iv_km = 0 iv_weekend = abap_true ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '2.50' ) act = ls-surcharge ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '12.50' ) act = ls-total ). + ENDMETHOD. + + METHOD member_discount. + DATA(ls_half) = price_for( iv_class = `M` iv_minutes = 15 iv_km = 11 + iv_weekend = abap_true iv_member = abap_true ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '0.98' ) act = ls_half-discount ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '5.52' ) act = ls_half-total ). + + DATA(ls_up) = price_for( iv_class = `S` iv_minutes = 15 iv_km = 28 iv_member = abap_true ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '1.13' ) act = ls_up-discount ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '6.37' ) act = ls_up-total ). + ENDMETHOD. + + METHOD minimum_total. + DATA(ls) = price_for( iv_class = `S` iv_minutes = 15 iv_km = 0 ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 3 ) act = ls-time_fee ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 5 ) act = ls-total ). + ENDMETHOD. + + METHOD invalid_input. + cl_abap_unit_assert=>assert_equals( + exp = {{p}}cl_rent=>c_err-duration + act = price_for( iv_class = `S` iv_minutes = 0 iv_km = 0 )-err_code ). + cl_abap_unit_assert=>assert_equals( + exp = {{p}}cl_rent=>c_err-distance + act = price_for( iv_class = `S` iv_minutes = 15 iv_km = -1 )-err_code ). + cl_abap_unit_assert=>assert_equals( + exp = {{p}}cl_rent=>c_err-bad_class + act = price_for( iv_class = `X` iv_minutes = 15 iv_km = 0 )-err_code ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0180/reference/rent_price.func.abap b/tasks_gen/eval/G0180/reference/rent_price.func.abap new file mode 100644 index 0000000..8a8cd5b --- /dev/null +++ b/tasks_gen/eval/G0180/reference/rent_price.func.abap @@ -0,0 +1,43 @@ +FUNCTION {{p}}rent_price + IMPORTING + iv_vehicle_class TYPE string + iv_minutes TYPE i + iv_km TYPE i + iv_member TYPE abap_bool + iv_weekend TYPE abap_bool + EXPORTING + ev_time_fee TYPE decfloat34 + ev_distance_fee TYPE decfloat34 + ev_surcharge TYPE decfloat34 + ev_discount TYPE decfloat34 + ev_total TYPE decfloat34 + EXCEPTIONS + invalid_duration + invalid_distance + invalid_class. + + DATA ls_request TYPE {{p}}cl_rent=>ty_request. + ls_request-vehicle_class = iv_vehicle_class. + ls_request-minutes = iv_minutes. + ls_request-km = iv_km. + ls_request-member = iv_member. + ls_request-weekend = iv_weekend. + + DATA(ls_result) = {{p}}cl_rent=>calculate( ls_request ). + + CASE ls_result-err_code. + WHEN {{p}}cl_rent=>c_err-duration. + RAISE invalid_duration. + WHEN {{p}}cl_rent=>c_err-distance. + RAISE invalid_distance. + WHEN {{p}}cl_rent=>c_err-bad_class. + RAISE invalid_class. + WHEN OTHERS. + ev_time_fee = ls_result-time_fee. + ev_distance_fee = ls_result-distance_fee. + ev_surcharge = ls_result-surcharge. + ev_discount = ls_result-discount. + ev_total = ls_result-total. + ENDCASE. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0180/reference/t14_test.clas.abap b/tasks_gen/eval/G0180/reference/t14_test.clas.abap new file mode 100644 index 0000000..3a416d5 --- /dev/null +++ b/tasks_gen/eval/G0180/reference/t14_test.clas.abap @@ -0,0 +1,90 @@ +CLASS {{p}}t14_test DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + TYPES: BEGIN OF ty_result, + time_fee TYPE decfloat34, + distance_fee TYPE decfloat34, + surcharge TYPE decfloat34, + discount TYPE decfloat34, + total TYPE decfloat34, + END OF ty_result. + + METHODS price + IMPORTING iv_class TYPE string + iv_minutes TYPE i + iv_km TYPE i + iv_member TYPE abap_bool DEFAULT abap_false + iv_weekend TYPE abap_bool DEFAULT abap_false + EXPORTING es_result TYPE ty_result + ev_subrc TYPE sysubrc. + + METHODS time_fee_blocks FOR TESTING. + METHODS distance_fee_free_km FOR TESTING. + METHODS weekend_surcharge FOR TESTING. + METHODS member_discount FOR TESTING. + METHODS minimum_total FOR TESTING. + METHODS invalid_duration FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t14_test IMPLEMENTATION. + METHOD price. + CLEAR es_result. + CALL FUNCTION '{{P}}RENT_PRICE' + EXPORTING + iv_vehicle_class = iv_class + iv_minutes = iv_minutes + iv_km = iv_km + iv_member = iv_member + iv_weekend = iv_weekend + IMPORTING + ev_time_fee = es_result-time_fee + ev_distance_fee = es_result-distance_fee + ev_surcharge = es_result-surcharge + ev_discount = es_result-discount + ev_total = es_result-total + EXCEPTIONS + invalid_duration = 1 + invalid_distance = 2 + invalid_class = 3 + OTHERS = 4. + ev_subrc = sy-subrc. + ENDMETHOD. + + METHOD time_fee_blocks. + price( EXPORTING iv_class = `S` iv_minutes = 16 iv_km = 0 + IMPORTING es_result = DATA(ls) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 6 ) act = ls-time_fee ). + ENDMETHOD. + + METHOD distance_fee_free_km. + price( EXPORTING iv_class = `L` iv_minutes = 60 iv_km = 14 + IMPORTING es_result = DATA(ls) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 1 ) act = ls-distance_fee ). + ENDMETHOD. + + METHOD weekend_surcharge. + price( EXPORTING iv_class = `M` iv_minutes = 30 iv_km = 0 iv_weekend = abap_true + IMPORTING es_result = DATA(ls) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '2.50' ) act = ls-surcharge ). + ENDMETHOD. + + METHOD member_discount. + price( EXPORTING iv_class = `S` iv_minutes = 15 iv_km = 28 iv_member = abap_true + IMPORTING es_result = DATA(ls) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '1.13' ) act = ls-discount ). + ENDMETHOD. + + METHOD minimum_total. + price( EXPORTING iv_class = `S` iv_minutes = 15 iv_km = 0 + IMPORTING es_result = DATA(ls) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 5 ) act = ls-total ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 3 ) act = ls-time_fee ). + ENDMETHOD. + + METHOD invalid_duration. + price( EXPORTING iv_class = `S` iv_minutes = 0 iv_km = 0 + IMPORTING ev_subrc = DATA(lv_subrc) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lv_subrc ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0180/review.json b/tasks_gen/eval/G0180/review.json new file mode 100644 index 0000000..6290122 --- /dev/null +++ b/tasks_gen/eval/G0180/review.json @@ -0,0 +1,7 @@ +{ + "decision": "accept", + "note": "All rules tested; logic in helper class; mutation 5/5.", + "by": "Claude", + "date": "2026-10-03", + "failed_checks": {} +} \ No newline at end of file diff --git a/tasks_gen/eval/G0180/seed/rent_sample.func.abap b/tasks_gen/eval/G0180/seed/rent_sample.func.abap new file mode 100644 index 0000000..d74cf73 --- /dev/null +++ b/tasks_gen/eval/G0180/seed/rent_sample.func.abap @@ -0,0 +1,25 @@ +FUNCTION {{p}}rent_sample + IMPORTING + iv_vehicle_class TYPE string + iv_minutes TYPE i + iv_km TYPE i + iv_member TYPE abap_bool + iv_weekend TYPE abap_bool + EXPORTING + ev_time_fee TYPE decfloat34 + ev_distance_fee TYPE decfloat34 + ev_surcharge TYPE decfloat34 + ev_discount TYPE decfloat34 + ev_total TYPE decfloat34 + EXCEPTIONS + invalid_duration + invalid_distance + invalid_class. + + CLEAR: ev_time_fee, + ev_distance_fee, + ev_surcharge, + ev_discount, + ev_total. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0180/spec.md b/tasks_gen/eval/G0180/spec.md new file mode 100644 index 0000000..ea186de --- /dev/null +++ b/tasks_gen/eval/G0180/spec.md @@ -0,0 +1,7 @@ +Please create the function module {{P}}RENT_PRICE in function group {{P}}FG_RENT. The function group {{P}}FG_RENT exists in package $TMP. The sample function module {{P}}RENT_SAMPLE exists in this function group. It is the sample pricing module, and all pricing modules must use its interface. The new function module must have the same interface. The importing parameters are iv_vehicle_class type string, iv_minutes type i, iv_km type i, iv_member type abap_bool, and iv_weekend type abap_bool. The exporting parameters are ev_time_fee type decfloat34, ev_distance_fee type decfloat34, ev_surcharge type decfloat34, ev_discount type decfloat34, and ev_total type decfloat34. The exceptions are invalid_duration, invalid_distance, and invalid_class. All rental data is in the input parameters. No database access is necessary. + +Put the calculation logic in a new class in package $TMP. The function module must only call this class. The function module must not contain the calculation itself. The class design is your decision. The function module maps the result of the class to its exporting parameters and exceptions. + +Check the input in this sequence. If iv_minutes is less than 1, raise INVALID_DURATION. If iv_km is less than 0, raise INVALID_DISTANCE. If iv_vehicle_class is not 'S', not 'M' and not 'L', raise INVALID_CLASS. Charge the rental duration in started 15-minute blocks. A duration of 15 minutes is one block. A duration of 16 minutes is two blocks. The price of one block depends on the vehicle class: 'S' costs 3.00, 'M' costs 5.00 and 'L' costs 8.00. The time fee is the number of blocks multiplied by the block price. The first 10 kilometres of a rental are free. Each further kilometre costs 0.25. The distance fee is the number of kilometres above 10 multiplied by 0.25. If iv_weekend is true, the weekend surcharge is 25 % of the time fee. Otherwise the weekend surcharge is 0. The gross amount is the time fee plus the distance fee plus the weekend surcharge. If iv_member is true, the member discount is 15 % of the gross amount. Otherwise the member discount is 0. The total price is the gross amount minus the member discount. If this value is less than 5.00, the total price is 5.00. Round the weekend surcharge, the member discount and the total price half up to 2 decimals. Return the time fee in ev_time_fee, the distance fee in ev_distance_fee, the weekend surcharge in ev_surcharge, the member discount in ev_discount and the total price in ev_total. + +The release target is ABAP Platform 2025 (SAP_BASIS 816). Use Clean ABAP and keep every method below 40 statements. Do not change {{P}}RENT_SAMPLE. The function module {{P}}RENT_PRICE must be active and have no syntax error. The hidden tests must pass. Write ABAP Unit tests for the new class as local test classes. Write ABAP Unit tests for the function module in a global test class. diff --git a/tasks_gen/eval/G0180/task.json b/tasks_gen/eval/G0180/task.json new file mode 100644 index 0000000..5e2b56f --- /dev/null +++ b/tasks_gen/eval/G0180/task.json @@ -0,0 +1,114 @@ +{ + "id": "G0180", + "category": "K", + "object_type": "FUNC", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [ + { + "type": "FUGR", + "name": "{{P}}FG_RENT", + "description": "Rental pricing" + }, + { + "type": "FUNC", + "name": "{{P}}RENT_SAMPLE", + "functionGroup": "{{P}}FG_RENT", + "file": "seed/rent_sample.func.abap", + "description": "Sample pricing module" + } + ], + "contract": [ + { + "type": "FUNC", + "name": "{{P}}RENT_PRICE", + "functionGroup": "{{P}}FG_RENT", + "params": [ + { + "name": "iv_vehicle_class", + "type": "string" + }, + { + "name": "iv_minutes", + "type": "i" + }, + { + "name": "iv_km", + "type": "i" + }, + { + "name": "iv_member", + "type": "abap_bool" + }, + { + "name": "iv_weekend", + "type": "abap_bool" + }, + { + "name": "ev_time_fee", + "type": "decfloat34" + }, + { + "name": "ev_distance_fee", + "type": "decfloat34" + }, + { + "name": "ev_surcharge", + "type": "decfloat34" + }, + { + "name": "ev_discount", + "type": "decfloat34" + }, + { + "name": "ev_total", + "type": "decfloat34" + } + ] + } + ], + "out_of_scope": [ + "{{P}}RENT_SAMPLE" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T14_HIDDEN", + "file": "hidden/t14_hidden.clas.abap", + "description": "T14 hidden tests" + } + ], + "reference": [ + { + "type": "CLAS", + "name": "{{P}}CL_RENT", + "file": "reference/cl_rent.clas.abap", + "testclasses_file": "reference/cl_rent.clas.testclasses.abap", + "description": "Rental price calculation" + }, + { + "type": "FUNC", + "name": "{{P}}RENT_PRICE", + "functionGroup": "{{P}}FG_RENT", + "file": "reference/rent_price.func.abap", + "description": "Rental pricing module" + }, + { + "type": "CLAS", + "name": "{{P}}T14_TEST", + "file": "reference/t14_test.clas.abap", + "description": "T14 own tests" + } + ], + "craft_checks": [ + "method_length" + ], + "base_task": "G0026", + "input_style": "free_text", + "tool_schema": "generic_v0" +} \ No newline at end of file diff --git a/tasks_gen/eval/G0181/empirical.json b/tasks_gen/eval/G0181/empirical.json new file mode 100644 index 0000000..a774b41 --- /dev/null +++ b/tasks_gen/eval/G0181/empirical.json @@ -0,0 +1,17 @@ +{ + "deepseek-v4.1-flash:cloud": { + "score": 0, + "parts": { + "total": 0, + "failed_gates": [ + "G1_active", + "G2_contract", + "G3_hidden_runs" + ] + }, + "hidden": "0/0", + "tool_calls": 36, + "seconds": 928.5, + "run_dir": "runs/emp/10007_G0014_llm_deepseek-v4.1-flash_cloud" + } +} \ No newline at end of file diff --git a/tasks_gen/eval/G0181/generation.json b/tasks_gen/eval/G0181/generation.json new file mode 100644 index 0000000..a2cfe56 --- /dev/null +++ b/tasks_gen/eval/G0181/generation.json @@ -0,0 +1,16 @@ +{ + "id": "G0181", + "pool": "eval", + "category": "K", + "base_task": "G0014", + "style": "incomplete", + "tool_schema": "generic_v0", + "attempts": [ + { + "stage": "validate", + "oracle": 100.0, + "null": 0 + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0181/hidden/t15_hidden.clas.abap b/tasks_gen/eval/G0181/hidden/t15_hidden.clas.abap new file mode 100644 index 0000000..10918f0 --- /dev/null +++ b/tasks_gen/eval/G0181/hidden/t15_hidden.clas.abap @@ -0,0 +1,112 @@ +CLASS {{p}}t15_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + TYPES tt_plant TYPE RANGE OF {{p}}movmt-plant. + METHODS run + IMPORTING iv_from TYPE d + iv_to TYPE d + it_plant TYPE tt_plant 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 all_materials_in_range FOR TESTING. + METHODS receipt_and_issue_split FOR TESTING. + METHODS sorted_by_balance FOR TESTING. + METHODS plant_filter FOR TESTING. + METHODS date_range_filter FOR TESTING. + METHODS ignored_move_types FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t15_hidden IMPLEMENTATION. + METHOD run. + cl_salv_bs_runtime_info=>set( display = abap_false metadata = abap_false data = abap_true ). + SUBMIT {{p}}stock_bal + WITH p_from = iv_from + WITH p_to = iv_to + WITH s_plant IN it_plant + 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( ) ). + " The ALV data can show a negative number with a trailing sign. + DATA(lv_length) = strlen( rv_value ). + IF lv_length > 1 AND substring( val = rv_value off = lv_length - 1 len = 1 ) = '-'. + rv_value = '-' && substring( val = rv_value off = 0 len = lv_length - 1 ). + ENDIF. + ENDMETHOD. + + METHOD all_materials_in_range. + DATA(lr_data) = run( iv_from = '20260101' iv_to = '20260131' ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines_of( lr_data ) ). + cl_abap_unit_assert=>assert_equals( exp = `MAT-001` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `MATERIAL` ) ). + cl_abap_unit_assert=>assert_equals( exp = `120` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `BALANCE` ) ). + cl_abap_unit_assert=>assert_equals( exp = `MAT-002` act = value_of( ir_data = lr_data iv_row = 2 iv_col = `MATERIAL` ) ). + cl_abap_unit_assert=>assert_equals( exp = `-20` act = value_of( ir_data = lr_data iv_row = 2 iv_col = `BALANCE` ) ). + ENDMETHOD. + + METHOD receipt_and_issue_split. + DATA(lr_data) = run( iv_from = '20260101' iv_to = '20260131' ). + cl_abap_unit_assert=>assert_equals( exp = `150` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `RECEIPT_QTY` ) ). + cl_abap_unit_assert=>assert_equals( exp = `30` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `ISSUE_QTY` ) ). + cl_abap_unit_assert=>assert_equals( exp = `40` act = value_of( ir_data = lr_data iv_row = 2 iv_col = `RECEIPT_QTY` ) ). + cl_abap_unit_assert=>assert_equals( exp = `60` act = value_of( ir_data = lr_data iv_row = 2 iv_col = `ISSUE_QTY` ) ). + ENDMETHOD. + + METHOD sorted_by_balance. + DATA(lr_data) = run( iv_from = '20251201' iv_to = '20260131' ). + cl_abap_unit_assert=>assert_equals( exp = 3 act = lines_of( lr_data ) ). + cl_abap_unit_assert=>assert_equals( exp = `MAT-001` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `MATERIAL` ) ). + cl_abap_unit_assert=>assert_equals( exp = `MAT-004` act = value_of( ir_data = lr_data iv_row = 2 iv_col = `MATERIAL` ) ). + cl_abap_unit_assert=>assert_equals( exp = `MAT-002` act = value_of( ir_data = lr_data iv_row = 3 iv_col = `MATERIAL` ) ). + ENDMETHOD. + + METHOD plant_filter. + DATA(lr_data) = run( iv_from = '20260101' iv_to = '20260131' + it_plant = VALUE #( ( sign = 'I' option = 'EQ' low = '1000' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines_of( lr_data ) ). + cl_abap_unit_assert=>assert_equals( exp = `MAT-001` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `MATERIAL` ) ). + cl_abap_unit_assert=>assert_equals( exp = `70` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `BALANCE` ) ). + ENDMETHOD. + + METHOD date_range_filter. + DATA(lr_data) = run( iv_from = '20260101' iv_to = '20260109' ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines_of( lr_data ) ). + cl_abap_unit_assert=>assert_equals( exp = `100` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `BALANCE` ) ). + cl_abap_unit_assert=>assert_equals( exp = `40` act = value_of( ir_data = lr_data iv_row = 2 iv_col = `BALANCE` ) ). + ENDMETHOD. + + METHOD ignored_move_types. + DATA(lr_data) = run( iv_from = '20260101' iv_to = '20260131' + it_plant = VALUE #( ( sign = 'I' option = 'EQ' low = '2000' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lines_of( lr_data ) ). + cl_abap_unit_assert=>assert_equals( exp = `MAT-001` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `MATERIAL` ) ). + cl_abap_unit_assert=>assert_equals( exp = `50` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `RECEIPT_QTY` ) ). + cl_abap_unit_assert=>assert_equals( exp = `0` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `ISSUE_QTY` ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0181/reference/stock_bal.prog.abap b/tasks_gen/eval/G0181/reference/stock_bal.prog.abap new file mode 100644 index 0000000..6253c89 --- /dev/null +++ b/tasks_gen/eval/G0181/reference/stock_bal.prog.abap @@ -0,0 +1,127 @@ +REPORT {{p}}stock_bal. + +DATA gv_plant TYPE {{p}}movmt-plant. + +PARAMETERS p_from TYPE d OBLIGATORY. +PARAMETERS p_to TYPE d OBLIGATORY. +SELECT-OPTIONS s_plant FOR gv_plant. + +CLASS lcl_report DEFINITION FINAL. + PUBLIC SECTION. + TYPES: + BEGIN OF ty_line, + material TYPE {{p}}movmt-material, + receipt_qty TYPE i, + issue_qty TYPE i, + balance TYPE i, + END OF ty_line, + tt_line TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY, + tt_plant TYPE RANGE OF {{p}}movmt-plant. + METHODS select_balances + IMPORTING iv_from TYPE d + iv_to TYPE d + it_plant TYPE tt_plant + RETURNING VALUE(rt_lines) TYPE tt_line. + METHODS display + CHANGING ct_lines TYPE tt_line. +ENDCLASS. + +CLASS lcl_report IMPLEMENTATION. + METHOD select_balances. + SELECT material, + SUM( CASE WHEN move_type = '101' OR move_type = '201' + THEN quantity + ELSE 0 END ) AS receipt_qty, + SUM( CASE WHEN move_type = '261' OR move_type = '262' + THEN quantity + ELSE 0 END ) AS issue_qty + FROM {{p}}movmt + WHERE move_date >= @iv_from + AND move_date <= @iv_to + AND plant IN @it_plant + AND move_type IN ( '101', '201', '261', '262' ) + GROUP BY material + INTO CORRESPONDING FIELDS OF TABLE @rt_lines. + + LOOP AT rt_lines ASSIGNING FIELD-SYMBOL(). + -balance = -receipt_qty - -issue_qty. + ENDLOOP. + + SORT rt_lines BY balance 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_balances( iv_from = p_from + iv_to = p_to + it_plant = s_plant[] ). + 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 balances_per_material FOR TESTING. + METHODS plant_filter FOR TESTING. + METHODS negative_balance FOR TESTING. +ENDCLASS. + +CLASS ltc_report IMPLEMENTATION. + METHOD class_setup. + go_env = cl_osql_test_environment=>create( i_dependency_list = VALUE #( ( '{{P}}MOVMT' ) ) ). + DATA lt_movmt TYPE STANDARD TABLE OF {{p}}movmt WITH EMPTY KEY. + lt_movmt = VALUE #( + ( move_id = 1 material = 'MAT-A' plant = '1000' move_date = '20260105' move_type = '101' quantity = 100 ) + ( move_id = 2 material = 'MAT-A' plant = '1000' move_date = '20260110' move_type = '261' quantity = 30 ) + ( move_id = 3 material = 'MAT-B' plant = '2000' move_date = '20260112' move_type = '201' quantity = 40 ) + ( move_id = 4 material = 'MAT-B' plant = '2000' move_date = '20260113' move_type = '262' quantity = 90 ) + ( move_id = 5 material = 'MAT-C' plant = '2000' move_date = '20260112' move_type = '999' quantity = 500 ) ). + go_env->insert_test_data( lt_movmt ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD balances_per_material. + DATA(lt_lines) = NEW lcl_report( )->select_balances( + iv_from = '20260101' iv_to = '20260131' it_plant = VALUE #( ) ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 'MAT-A' act = lt_lines[ 1 ]-material ). + cl_abap_unit_assert=>assert_equals( exp = 70 act = lt_lines[ 1 ]-balance ). + cl_abap_unit_assert=>assert_equals( exp = 'MAT-B' act = lt_lines[ 2 ]-material ). + cl_abap_unit_assert=>assert_equals( exp = -50 act = lt_lines[ 2 ]-balance ). + ENDMETHOD. + + METHOD plant_filter. + DATA(lt_lines) = NEW lcl_report( )->select_balances( + iv_from = '20260101' + iv_to = '20260131' + it_plant = VALUE #( ( sign = 'I' option = 'EQ' low = '1000' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 'MAT-A' act = lt_lines[ 1 ]-material ). + cl_abap_unit_assert=>assert_equals( exp = 30 act = lt_lines[ 1 ]-issue_qty ). + ENDMETHOD. + + METHOD negative_balance. + DATA(lt_lines) = NEW lcl_report( )->select_balances( + iv_from = '20260101' + iv_to = '20260131' + it_plant = VALUE #( ( sign = 'I' option = 'EQ' low = '2000' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 'MAT-B' act = lt_lines[ 1 ]-material ). + cl_abap_unit_assert=>assert_equals( exp = -50 act = lt_lines[ 1 ]-balance ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0181/review.json b/tasks_gen/eval/G0181/review.json new file mode 100644 index 0000000..fba07a9 --- /dev/null +++ b/tasks_gen/eval/G0181/review.json @@ -0,0 +1,7 @@ +{ + "decision": "accept", + "note": "Sorted values distinct in data (120, 70, -20). Sort ties not defined in spec, but no tie in tests.", + "by": "Claude", + "date": "2026-10-03", + "failed_checks": {} +} \ No newline at end of file diff --git a/tasks_gen/eval/G0181/seed/movmt.tabl.asabap b/tasks_gen/eval/G0181/seed/movmt.tabl.asabap new file mode 100644 index 0000000..e05d163 --- /dev/null +++ b/tasks_gen/eval/G0181/seed/movmt.tabl.asabap @@ -0,0 +1,14 @@ +@EndUserText.label : 'Stock movements' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}movmt { + key client : abap.clnt not null; + key move_id : abap.int4 not null; + material : abap.char(10); + plant : abap.char(4); + move_date : abap.dats; + move_type : abap.char(3); + quantity : abap.int4; +} diff --git a/tasks_gen/eval/G0181/seed/t15_seed.clas.abap b/tasks_gen/eval/G0181/seed/t15_seed.clas.abap new file mode 100644 index 0000000..0a91819 --- /dev/null +++ b/tasks_gen/eval/G0181/seed/t15_seed.clas.abap @@ -0,0 +1,19 @@ +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}}movmt. + INSERT {{p}}movmt FROM TABLE @( VALUE #( + ( move_id = 1 material = 'MAT-001' plant = '1000' move_date = '20260105' move_type = '101' quantity = 100 ) + ( move_id = 2 material = 'MAT-001' plant = '1000' move_date = '20260110' move_type = '261' quantity = 30 ) + ( move_id = 3 material = 'MAT-001' plant = '2000' move_date = '20260120' move_type = '101' quantity = 50 ) + ( move_id = 4 material = 'MAT-002' plant = '1000' move_date = '20260108' move_type = '201' quantity = 40 ) + ( move_id = 5 material = 'MAT-002' plant = '1000' move_date = '20260115' move_type = '262' quantity = 60 ) + ( move_id = 6 material = 'MAT-003' plant = '2000' move_date = '20260112' move_type = '999' quantity = 500 ) + ( move_id = 7 material = 'MAT-004' plant = '1000' move_date = '20251220' move_type = '101' quantity = 70 ) ) ). + out->write( sy-dbcnt ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0181/spec.md b/tasks_gen/eval/G0181/spec.md new file mode 100644 index 0000000..0963938 --- /dev/null +++ b/tasks_gen/eval/G0181/spec.md @@ -0,0 +1 @@ +Create executable program {{P}}STOCK_BAL. On the selection screen, require p_from and p_to as dates. Add s_plant as a select-option for the plant. Read movement data from {{P}}MOVMT. Include a movement when its movement date is on or after p_from and on or before p_to and its plant is in s_plant. A movement type '101' or '201' is a receipt. A movement type '261' or '262' is an issue. Ignore all other in-scope movements. For each material, RECEIPT_QTY is the sum of quantity of its receipts. ISSUE_QTY is the sum of quantity of its issues. BALANCE is RECEIPT_QTY minus ISSUE_QTY. Show one line for each material that has at least one receipt or issue. Do not show a material that has only ignored movements. Sort the lines by BALANCE, highest first. Show columns MATERIAL, RECEIPT_QTY, ISSUE_QTY, BALANCE. diff --git a/tasks_gen/eval/G0181/task.json b/tasks_gen/eval/G0181/task.json new file mode 100644 index 0000000..9e1c56a --- /dev/null +++ b/tasks_gen/eval/G0181/task.json @@ -0,0 +1,64 @@ +{ + "id": "G0181", + "category": "K", + "object_type": "PROG", + "difficulty": 2, + "release_target": "v758", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [ + { + "type": "TABL", + "name": "{{P}}MOVMT", + "file": "seed/movmt.tabl.asabap", + "description": "Stock movements" + }, + { + "type": "CLAS", + "name": "{{P}}T15_SEED", + "file": "seed/t15_seed.clas.abap", + "description": "T15 seed data", + "run": true + } + ], + "contract": [ + { + "type": "PROG", + "name": "{{P}}STOCK_BAL", + "parameters": [ + "p_from", + "p_to", + "s_plant" + ] + } + ], + "out_of_scope": [ + "{{P}}MOVMT" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T15_HIDDEN", + "file": "hidden/t15_hidden.clas.abap", + "description": "T15 hidden tests" + } + ], + "reference": [ + { + "type": "PROG", + "name": "{{P}}STOCK_BAL", + "file": "reference/stock_bal.prog.abap", + "description": "Stock balance per material" + } + ], + "craft_checks": [ + "db_operation_in_loop", + "method_length" + ], + "base_task": "G0014", + "input_style": "incomplete", + "tool_schema": "generic_v0" +} \ No newline at end of file diff --git a/tasks_gen/eval/G0182/empirical.json b/tasks_gen/eval/G0182/empirical.json new file mode 100644 index 0000000..c3d4bf2 --- /dev/null +++ b/tasks_gen/eval/G0182/empirical.json @@ -0,0 +1,18 @@ +{ + "deepseek-v4.1-flash:cloud": { + "score": 77.0, + "parts": { + "correctness": 40.0, + "craft": 20.0, + "clean": 12.0, + "own_tests": 0.0, + "discipline": 5.0, + "total": 77.0, + "note": "own_tests: faulty-reference part not implemented in skeleton" + }, + "hidden": "8/8", + "tool_calls": 40, + "seconds": 164.6, + "run_dir": "runs/emp/10009_G0017_llm_deepseek-v4.1-flash_cloud" + } +} \ No newline at end of file diff --git a/tasks_gen/eval/G0182/generation.json b/tasks_gen/eval/G0182/generation.json new file mode 100644 index 0000000..5ad92d2 --- /dev/null +++ b/tasks_gen/eval/G0182/generation.json @@ -0,0 +1,16 @@ +{ + "id": "G0182", + "pool": "eval", + "category": "K", + "base_task": "G0017", + "style": "free_text", + "tool_schema": "generic_v0", + "attempts": [ + { + "stage": "validate", + "oracle": 100.0, + "null": 0 + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0182/hidden/t21_hidden.clas.abap b/tasks_gen/eval/G0182/hidden/t21_hidden.clas.abap new file mode 100644 index 0000000..84664d4 --- /dev/null +++ b/tasks_gen/eval/G0182/hidden/t21_hidden.clas.abap @@ -0,0 +1,86 @@ +CLASS {{p}}t21_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 cost_of_project_one FOR TESTING. + METHODS hours_of_project_one FOR TESTING. + METHODS count_of_project_one FOR TESTING. + METHODS no_active_assignment FOR TESTING. + METHODS row_count FOR TESTING. + METHODS over_budget_flag FOR TESTING. + METHODS budget_not_exceeded FOR TESTING. + METHODS project_name_shown FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t21_hidden IMPLEMENTATION. + METHOD class_setup. + go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_PROJ_EFFORT' ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + DATA lt_proj TYPE STANDARD TABLE OF {{p}}proj WITH EMPTY KEY. + DATA lt_asgn TYPE STANDARD TABLE OF {{p}}asgn WITH EMPTY KEY. + go_env->clear_doubles( ). + lt_proj = VALUE #( ( proj_id = 'P1' proj_name = 'ALPHA' budget = '500.00' ) + ( proj_id = 'P2' proj_name = 'BETA' budget = '100.00' ) + ( proj_id = 'P3' proj_name = 'GAMMA' budget = '1000.00' ) + ( proj_id = 'P4' proj_name = 'DELTA' budget = '50.00' ) ). + lt_asgn = VALUE #( ( proj_id = 'P1' emp_id = 'E1' work_hours = 10 rate = '50.00' status = 'A' ) + ( proj_id = 'P1' emp_id = 'E2' work_hours = 4 rate = '25.00' status = 'A' ) + ( proj_id = 'P1' emp_id = 'E3' work_hours = 8 rate = '100.00' status = 'I' ) + ( proj_id = 'P2' emp_id = 'E1' work_hours = 2 rate = '50.00' status = 'A' ) + ( proj_id = 'P4' emp_id = 'E2' work_hours = 5 rate = '10.00' status = 'I' ) ). + go_env->insert_test_data( lt_proj ). + go_env->insert_test_data( lt_asgn ). + ENDMETHOD. + + METHOD cost_of_project_one. + SELECT SINGLE total_cost FROM {{p}}i_proj_effort WHERE proj_id = 'P1' INTO @DATA(lv_cost). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '600.00' ) + act = CONV decfloat34( lv_cost ) ). + ENDMETHOD. + + METHOD hours_of_project_one. + SELECT SINGLE total_hours FROM {{p}}i_proj_effort WHERE proj_id = 'P1' INTO @DATA(lv_hours). + cl_abap_unit_assert=>assert_equals( exp = CONV i( lv_hours ) act = 14 ). + ENDMETHOD. + + METHOD count_of_project_one. + SELECT SINGLE assign_count FROM {{p}}i_proj_effort WHERE proj_id = 'P1' INTO @DATA(lv_count). + cl_abap_unit_assert=>assert_equals( exp = CONV i( lv_count ) act = 2 ). + ENDMETHOD. + + METHOD no_active_assignment. + SELECT SINGLE proj_name FROM {{p}}i_proj_effort WHERE proj_id = 'P4' INTO @DATA(lv_name). + cl_abap_unit_assert=>assert_equals( exp = 4 act = sy-subrc ). + cl_abap_unit_assert=>assert_initial( lv_name ). + ENDMETHOD. + + METHOD row_count. + SELECT COUNT(*) FROM {{p}}i_proj_effort INTO @DATA(lv_rows). + cl_abap_unit_assert=>assert_equals( exp = CONV i( lv_rows ) act = 2 ). + ENDMETHOD. + + METHOD over_budget_flag. + SELECT SINGLE over_budget FROM {{p}}i_proj_effort WHERE proj_id = 'P1' INTO @DATA(lv_flag). + cl_abap_unit_assert=>assert_equals( exp = 'X' act = lv_flag ). + ENDMETHOD. + + METHOD budget_not_exceeded. + SELECT SINGLE over_budget FROM {{p}}i_proj_effort WHERE proj_id = 'P2' INTO @DATA(lv_flag). + cl_abap_unit_assert=>assert_equals( exp = 'N' act = lv_flag ). + ENDMETHOD. + + METHOD project_name_shown. + SELECT SINGLE proj_name FROM {{p}}i_proj_effort WHERE proj_id = 'P2' INTO @DATA(lv_name). + cl_abap_unit_assert=>assert_equals( exp = 'BETA' act = lv_name ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0182/reference/i_proj_effort.ddls.asddls b/tasks_gen/eval/G0182/reference/i_proj_effort.ddls.asddls new file mode 100644 index 0000000..0904a9b --- /dev/null +++ b/tasks_gen/eval/G0182/reference/i_proj_effort.ddls.asddls @@ -0,0 +1,22 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Project effort' +define view entity {{P}}I_PROJ_EFFORT + as select from {{p}}proj as proj + inner join {{p}}asgn as asgn on asgn.proj_id = proj.proj_id +{ + key proj.proj_id as proj_id, + proj.proj_name as proj_name, + count( * ) as assign_count, + sum( asgn.work_hours ) as total_hours, + sum( cast( asgn.work_hours as abap.dec( 15, 2 ) ) * asgn.rate ) as total_cost, + case + when sum( cast( asgn.work_hours as abap.dec( 15, 2 ) ) * asgn.rate ) > proj.budget + then 'X' + else 'N' + end as over_budget +} +where asgn.status = 'A' +group by + proj.proj_id, + proj.proj_name, + proj.budget diff --git a/tasks_gen/eval/G0182/reference/t21_test.clas.abap b/tasks_gen/eval/G0182/reference/t21_test.clas.abap new file mode 100644 index 0000000..c4b2048 --- /dev/null +++ b/tasks_gen/eval/G0182/reference/t21_test.clas.abap @@ -0,0 +1,53 @@ +CLASS {{p}}t21_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 effort_of_one_project FOR TESTING. + METHODS no_active_assignment FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t21_test IMPLEMENTATION. + METHOD class_setup. + go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_PROJ_EFFORT' ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + DATA lt_proj TYPE STANDARD TABLE OF {{p}}proj WITH EMPTY KEY. + DATA lt_asgn TYPE STANDARD TABLE OF {{p}}asgn WITH EMPTY KEY. + go_env->clear_doubles( ). + lt_proj = VALUE #( ( proj_id = 'A' proj_name = 'ONE' budget = '100.00' ) + ( proj_id = 'B' proj_name = 'TWO' budget = '10.00' ) ). + lt_asgn = VALUE #( ( proj_id = 'A' emp_id = 'E1' work_hours = 2 rate = '10.00' status = 'A' ) + ( proj_id = 'A' emp_id = 'E2' work_hours = 1 rate = '5.00' status = 'A' ) + ( proj_id = 'A' emp_id = 'E3' work_hours = 9 rate = '9.00' status = 'I' ) + ( proj_id = 'B' emp_id = 'E1' work_hours = 3 rate = '1.00' status = 'I' ) ). + go_env->insert_test_data( lt_proj ). + go_env->insert_test_data( lt_asgn ). + ENDMETHOD. + + METHOD effort_of_one_project. + SELECT SINGLE assign_count, total_hours, total_cost, over_budget + FROM {{p}}i_proj_effort + WHERE proj_id = 'A' + INTO @DATA(ls_effort). + cl_abap_unit_assert=>assert_equals( exp = CONV i( ls_effort-assign_count ) act = 2 ). + cl_abap_unit_assert=>assert_equals( exp = CONV i( ls_effort-total_hours ) act = 3 ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '25.00' ) + act = CONV decfloat34( ls_effort-total_cost ) ). + cl_abap_unit_assert=>assert_equals( exp = 'N' act = ls_effort-over_budget ). + ENDMETHOD. + + METHOD no_active_assignment. + SELECT SINGLE proj_id FROM {{p}}i_proj_effort WHERE proj_id = 'B' INTO @DATA(lv_proj_id). + cl_abap_unit_assert=>assert_equals( exp = 4 act = sy-subrc ). + cl_abap_unit_assert=>assert_initial( lv_proj_id ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0182/review.json b/tasks_gen/eval/G0182/review.json new file mode 100644 index 0000000..16d9ba3 --- /dev/null +++ b/tasks_gen/eval/G0182/review.json @@ -0,0 +1,7 @@ +{ + "decision": "accept", + "note": "Survived inner->left outer join is equivalent (WHERE on the right table).", + "by": "Claude", + "date": "2026-10-03", + "failed_checks": {} +} \ No newline at end of file diff --git a/tasks_gen/eval/G0182/seed/asgn.tabl.asabap b/tasks_gen/eval/G0182/seed/asgn.tabl.asabap new file mode 100644 index 0000000..b2ae3ef --- /dev/null +++ b/tasks_gen/eval/G0182/seed/asgn.tabl.asabap @@ -0,0 +1,13 @@ +@EndUserText.label : 'Project assignment' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}asgn { + key client : abap.clnt not null; + key proj_id : abap.char(10) not null; + key emp_id : abap.char(10) not null; + work_hours : abap.int4; + rate : abap.dec(15,2); + status : abap.char(1); +} diff --git a/tasks_gen/eval/G0182/seed/proj.tabl.asabap b/tasks_gen/eval/G0182/seed/proj.tabl.asabap new file mode 100644 index 0000000..df44ee3 --- /dev/null +++ b/tasks_gen/eval/G0182/seed/proj.tabl.asabap @@ -0,0 +1,11 @@ +@EndUserText.label : 'Project' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}proj { + key client : abap.clnt not null; + key proj_id : abap.char(10) not null; + proj_name : abap.char(30); + budget : abap.dec(15,2); +} diff --git a/tasks_gen/eval/G0182/spec.md b/tasks_gen/eval/G0182/spec.md new file mode 100644 index 0000000..6249c7a --- /dev/null +++ b/tasks_gen/eval/G0182/spec.md @@ -0,0 +1,3 @@ +Hello, + +Please create the CDS view entity {{P}}I_PROJ_EFFORT in package $TMP. A report and an OData service read the project effort. The calculation must be in the database, in a CDS view. Use table {{P}}PROJ for projects. Its key is PROJ_ID with CHAR 10. Its fields are PROJ_NAME with CHAR 30 and BUDGET with DEC 15,2. Use table {{P}}ASGN for project assignments. Its key is PROJ_ID with CHAR 10 and EMP_ID with CHAR 10. Its fields are WORK_HOURS with INT4, RATE with DEC 15,2, and STATUS with CHAR 1. Both tables are in package $TMP. Do not change {{P}}PROJ and {{P}}ASGN. The view must have these elements: PROJ_ID as key, PROJ_NAME, ASSIGN_COUNT, TOTAL_HOURS, TOTAL_COST, and OVER_BUDGET. Do not do an authorization check. Use #NOT_REQUIRED. Show one row for each project that has at least one active assignment. An assignment is active when its STATUS is 'A'. An assignment with another status is not active. A project without active assignments does not appear in the view. ASSIGN_COUNT is the number of active assignments of the project. TOTAL_HOURS is the sum of WORK_HOURS of the active assignments of the project. TOTAL_COST is the sum of WORK_HOURS multiplied by RATE of the active assignments of the project, with 2 decimals. OVER_BUDGET is 'X' when TOTAL_COST is greater than the BUDGET of the project. Otherwise OVER_BUDGET is 'N'. The release target is 7.58. Follow Clean ABAP coding standards. The view must be active and have no syntax error. The hidden tests must pass. Write ABAP Unit tests with CL_CDS_TEST_ENVIRONMENT in a global test class. There are no open questions. diff --git a/tasks_gen/eval/G0182/task.json b/tasks_gen/eval/G0182/task.json new file mode 100644 index 0000000..155f3d6 --- /dev/null +++ b/tasks_gen/eval/G0182/task.json @@ -0,0 +1,70 @@ +{ + "id": "G0182", + "category": "K", + "object_type": "DDLS", + "difficulty": 2, + "release_target": "v758", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [ + { + "type": "TABL", + "name": "{{P}}PROJ", + "file": "seed/proj.tabl.asabap", + "description": "Project" + }, + { + "type": "TABL", + "name": "{{P}}ASGN", + "file": "seed/asgn.tabl.asabap", + "description": "Project assignment" + } + ], + "contract": [ + { + "type": "DDLS", + "name": "{{P}}I_PROJ_EFFORT", + "fields": [ + "PROJ_ID", + "PROJ_NAME", + "ASSIGN_COUNT", + "TOTAL_HOURS", + "TOTAL_COST", + "OVER_BUDGET" + ] + } + ], + "out_of_scope": [ + "{{P}}PROJ", + "{{P}}ASGN" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T21_HIDDEN", + "file": "hidden/t21_hidden.clas.abap", + "description": "T21 hidden tests" + } + ], + "reference": [ + { + "type": "DDLS", + "name": "{{P}}I_PROJ_EFFORT", + "file": "reference/i_proj_effort.ddls.asddls", + "description": "Project effort" + }, + { + "type": "CLAS", + "name": "{{P}}T21_TEST", + "file": "reference/t21_test.clas.abap", + "description": "T21 own tests" + } + ], + "craft_checks": [], + "base_task": "G0017", + "input_style": "free_text", + "tool_schema": "generic_v0" +} \ No newline at end of file diff --git a/tasks_gen/eval/G0183/empirical.json b/tasks_gen/eval/G0183/empirical.json new file mode 100644 index 0000000..1f08860 --- /dev/null +++ b/tasks_gen/eval/G0183/empirical.json @@ -0,0 +1,18 @@ +{ + "deepseek-v4.1-flash:cloud": { + "score": 80.0, + "parts": { + "correctness": 40.0, + "craft": 20.0, + "clean": 15.0, + "own_tests": 0.0, + "discipline": 5.0, + "total": 80.0, + "note": "own_tests: faulty-reference part not implemented in skeleton" + }, + "hidden": "8/8", + "tool_calls": 40, + "seconds": 174.6, + "run_dir": "runs/emp/10012_G0020_llm_deepseek-v4.1-flash_cloud" + } +} \ No newline at end of file diff --git a/tasks_gen/eval/G0183/generation.json b/tasks_gen/eval/G0183/generation.json new file mode 100644 index 0000000..0b32119 --- /dev/null +++ b/tasks_gen/eval/G0183/generation.json @@ -0,0 +1,16 @@ +{ + "id": "G0183", + "pool": "eval", + "category": "K", + "base_task": "G0020", + "style": "incomplete", + "tool_schema": "generic_v0", + "attempts": [ + { + "stage": "validate", + "oracle": 100.0, + "null": 0 + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0183/hidden/t20_hidden.clas.abap b/tasks_gen/eval/G0183/hidden/t20_hidden.clas.abap new file mode 100644 index 0000000..82a66a4 --- /dev/null +++ b/tasks_gen/eval/G0183/hidden/t20_hidden.clas.abap @@ -0,0 +1,157 @@ +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_cds_test_environment. + CLASS-METHODS class_setup. + CLASS-METHODS class_teardown. + METHODS setup. + METHODS revenue_in_period FOR TESTING. + METHODS sold_quantity_in_period FOR TESTING. + METHODS books_in_period FOR TESTING. + METHODS title_and_category FOR TESTING. + METHODS revenue_has_two_decimals FOR TESTING. + METHODS period_limits_included FOR TESTING. + METHODS empty_period FOR TESTING. + METHODS book_outside_period_hidden FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t20_hidden IMPLEMENTATION. + METHOD class_setup. + go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_BOOK_REVENUE' ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + DATA lt_book TYPE STANDARD TABLE OF {{p}}book WITH EMPTY KEY. + DATA lt_sale TYPE STANDARD TABLE OF {{p}}sale WITH EMPTY KEY. + go_env->clear_doubles( ). + lt_book = VALUE #( + ( book_id = 'B1' title = 'ABAP Basics' category = 'TECH' price = '40.00' ) + ( book_id = 'B2' title = 'SQL Guide' category = 'TECH' price = '25.50' ) + ( book_id = 'B3' title = 'Cooking Fun' category = 'HOME' price = '15.00' ) + ( book_id = 'B4' title = 'Space Novel' category = 'FICTION' price = '9.99' ) + ( book_id = 'B5' title = 'Old Book' category = 'TECH' price = '5.00' ) ). + lt_sale = VALUE #( + ( book_id = 'B1' sale_date = '20240110' quantity = 2 ) + ( book_id = 'B1' sale_date = '20240215' quantity = 1 ) + ( book_id = 'B1' sale_date = '20240601' quantity = 5 ) + ( book_id = 'B2' sale_date = '20240120' quantity = 4 ) + ( book_id = 'B3' sale_date = '20240305' quantity = 3 ) + ( book_id = 'B4' sale_date = '20240201' quantity = 1 ) + ( book_id = 'B4' sale_date = '20240202' quantity = 2 ) + ( book_id = 'B5' sale_date = '20240615' quantity = 7 ) ). + go_env->insert_test_data( lt_book ). + go_env->insert_test_data( lt_sale ). + ENDMETHOD. + + METHOD revenue_in_period. + DATA lv_from TYPE d. + DATA lv_to TYPE d. + lv_from = '20240101'. + lv_to = '20240331'. + SELECT SINGLE revenue + FROM {{p}}i_book_revenue( p_from = @lv_from, p_to = @lv_to ) + WHERE book_id = 'B1' + INTO @DATA(lv_revenue). + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( '120.00' ) + act = CONV decfloat34( lv_revenue ) ). + ENDMETHOD. + + METHOD sold_quantity_in_period. + DATA lv_from TYPE d. + DATA lv_to TYPE d. + lv_from = '20240101'. + lv_to = '20240331'. + SELECT SINGLE sold_quantity + FROM {{p}}i_book_revenue( p_from = @lv_from, p_to = @lv_to ) + WHERE book_id = 'B1' + INTO @DATA(lv_sold). + cl_abap_unit_assert=>assert_equals( exp = 3 act = CONV i( lv_sold ) ). + ENDMETHOD. + + METHOD books_in_period. + DATA lv_from TYPE d. + DATA lv_to TYPE d. + lv_from = '20240101'. + lv_to = '20240331'. + SELECT COUNT(*) + FROM {{p}}i_book_revenue( p_from = @lv_from, p_to = @lv_to ) + INTO @DATA(lv_rows). + cl_abap_unit_assert=>assert_equals( exp = 4 act = lv_rows ). + ENDMETHOD. + + METHOD title_and_category. + DATA lv_from TYPE d. + DATA lv_to TYPE d. + lv_from = '20240101'. + lv_to = '20240331'. + SELECT SINGLE title, category + FROM {{p}}i_book_revenue( p_from = @lv_from, p_to = @lv_to ) + WHERE book_id = 'B2' + INTO @DATA(ls_row). + cl_abap_unit_assert=>assert_equals( exp = 'SQL Guide' act = ls_row-title ). + cl_abap_unit_assert=>assert_equals( exp = 'TECH' act = ls_row-category ). + ENDMETHOD. + + METHOD revenue_has_two_decimals. + DATA lv_from TYPE d. + DATA lv_to TYPE d. + lv_from = '20240101'. + lv_to = '20240331'. + SELECT SINGLE revenue + FROM {{p}}i_book_revenue( p_from = @lv_from, p_to = @lv_to ) + WHERE book_id = 'B4' + INTO @DATA(lv_revenue). + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( '29.97' ) + act = CONV decfloat34( lv_revenue ) ). + ENDMETHOD. + + METHOD period_limits_included. + DATA lv_from TYPE d. + DATA lv_to TYPE d. + lv_from = '20240110'. + lv_to = '20240110'. + SELECT SINGLE sold_quantity + FROM {{p}}i_book_revenue( p_from = @lv_from, p_to = @lv_to ) + WHERE book_id = 'B1' + INTO @DATA(lv_sold_b1). + cl_abap_unit_assert=>assert_equals( exp = 2 act = CONV i( lv_sold_b1 ) ). + + lv_from = '20240305'. + lv_to = '20240305'. + SELECT SINGLE sold_quantity + FROM {{p}}i_book_revenue( p_from = @lv_from, p_to = @lv_to ) + WHERE book_id = 'B3' + INTO @DATA(lv_sold_b3). + cl_abap_unit_assert=>assert_equals( exp = 3 act = CONV i( lv_sold_b3 ) ). + ENDMETHOD. + + METHOD empty_period. + DATA lv_from TYPE d. + DATA lv_to TYPE d. + lv_from = '20240501'. + lv_to = '20240531'. + SELECT COUNT(*) + FROM {{p}}i_book_revenue( p_from = @lv_from, p_to = @lv_to ) + INTO @DATA(lv_rows). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_rows ). + ENDMETHOD. + + METHOD book_outside_period_hidden. + DATA lv_from TYPE d. + DATA lv_to TYPE d. + lv_from = '20240101'. + lv_to = '20240331'. + SELECT SINGLE book_id + FROM {{p}}i_book_revenue( p_from = @lv_from, p_to = @lv_to ) + WHERE book_id = 'B5' + INTO @DATA(lv_book). + cl_abap_unit_assert=>assert_initial( lv_book ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0183/reference/i_book_revenue.ddls.asddls b/tasks_gen/eval/G0183/reference/i_book_revenue.ddls.asddls new file mode 100644 index 0000000..c2db923 --- /dev/null +++ b/tasks_gen/eval/G0183/reference/i_book_revenue.ddls.asddls @@ -0,0 +1,20 @@ +@AccessControl.authorizationCheck: #NOT_REQUIRED +@EndUserText.label: 'Book revenue in period' +define view entity {{P}}I_BOOK_REVENUE + with parameters + p_from : abap.dats, + p_to : abap.dats + as select from {{p}}book as bk + inner join {{p}}sale as sl on sl.book_id = bk.book_id +{ + key bk.book_id as book_id, + bk.title as title, + bk.category as category, + sum( sl.quantity ) as sold_quantity, + sum( cast( sl.quantity as abap.dec( 10, 0 ) ) * bk.price ) as revenue +} +where sl.sale_date between $parameters.p_from and $parameters.p_to +group by + bk.book_id, + bk.title, + bk.category diff --git a/tasks_gen/eval/G0183/reference/t20_test.clas.abap b/tasks_gen/eval/G0183/reference/t20_test.clas.abap new file mode 100644 index 0000000..cc856e8 --- /dev/null +++ b/tasks_gen/eval/G0183/reference/t20_test.clas.abap @@ -0,0 +1,62 @@ +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_cds_test_environment. + CLASS-METHODS class_setup. + CLASS-METHODS class_teardown. + METHODS setup. + METHODS revenue_of_one_book FOR TESTING. + METHODS period_is_inclusive FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t20_test IMPLEMENTATION. + METHOD class_setup. + go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_BOOK_REVENUE' ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD setup. + DATA lt_book TYPE STANDARD TABLE OF {{p}}book WITH EMPTY KEY. + DATA lt_sale TYPE STANDARD TABLE OF {{p}}sale WITH EMPTY KEY. + go_env->clear_doubles( ). + lt_book = VALUE #( + ( book_id = 'A1' title = 'Test Book' category = 'TECH' price = '10.00' ) ). + lt_sale = VALUE #( + ( book_id = 'A1' sale_date = '20240101' quantity = 2 ) + ( book_id = 'A1' sale_date = '20240131' quantity = 3 ) + ( book_id = 'A1' sale_date = '20240201' quantity = 9 ) ). + go_env->insert_test_data( lt_book ). + go_env->insert_test_data( lt_sale ). + ENDMETHOD. + + METHOD revenue_of_one_book. + DATA lv_from TYPE d. + DATA lv_to TYPE d. + lv_from = '20240101'. + lv_to = '20240131'. + SELECT SINGLE sold_quantity, revenue + FROM {{p}}i_book_revenue( p_from = @lv_from, p_to = @lv_to ) + WHERE book_id = 'A1' + INTO @DATA(ls_row). + cl_abap_unit_assert=>assert_equals( exp = 5 act = CONV i( ls_row-sold_quantity ) ). + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( '50.00' ) + act = CONV decfloat34( ls_row-revenue ) ). + ENDMETHOD. + + METHOD period_is_inclusive. + DATA lv_from TYPE d. + DATA lv_to TYPE d. + lv_from = '20240101'. + lv_to = '20240101'. + SELECT SINGLE sold_quantity + FROM {{p}}i_book_revenue( p_from = @lv_from, p_to = @lv_to ) + WHERE book_id = 'A1' + INTO @DATA(lv_sold). + cl_abap_unit_assert=>assert_equals( exp = 2 act = CONV i( lv_sold ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0183/review.json b/tasks_gen/eval/G0183/review.json new file mode 100644 index 0000000..8fe504b --- /dev/null +++ b/tasks_gen/eval/G0183/review.json @@ -0,0 +1,7 @@ +{ + "decision": "accept", + "note": "Survived join mutant is equivalent (WHERE on the right table).", + "by": "Claude", + "date": "2026-10-03", + "failed_checks": {} +} \ No newline at end of file diff --git a/tasks_gen/eval/G0183/seed/book.tabl.asabap b/tasks_gen/eval/G0183/seed/book.tabl.asabap new file mode 100644 index 0000000..688f0a6 --- /dev/null +++ b/tasks_gen/eval/G0183/seed/book.tabl.asabap @@ -0,0 +1,13 @@ +@EndUserText.label : 'Book master data' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}book { + key client : abap.clnt not null; + key book_id : abap.char(10) not null; + title : abap.char(40); + category : abap.char(10); + price : abap.dec(15,2); + stock : abap.int4; +} diff --git a/tasks_gen/eval/G0183/seed/sale.tabl.asabap b/tasks_gen/eval/G0183/seed/sale.tabl.asabap new file mode 100644 index 0000000..7842236 --- /dev/null +++ b/tasks_gen/eval/G0183/seed/sale.tabl.asabap @@ -0,0 +1,11 @@ +@EndUserText.label : 'Book sales' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}sale { + key client : abap.clnt not null; + key book_id : abap.char(10) not null; + key sale_date : abap.dats not null; + quantity : abap.int4; +} diff --git a/tasks_gen/eval/G0183/spec.md b/tasks_gen/eval/G0183/spec.md new file mode 100644 index 0000000..3708a6a --- /dev/null +++ b/tasks_gen/eval/G0183/spec.md @@ -0,0 +1 @@ +Create the CDS view entity {{P}}I_BOOK_REVENUE in package $TMP. The view shows the sales of each book for the period given by input parameters P_FROM (DATS) and P_TO (DATS). P_FROM is the first day of the period. P_TO is the last day of the period. Both limits belong to the period. The view has one row for each book that has at least one sale whose sale date is in the period. A book without a sale in the period has no row. The elements are BOOK_ID as key, TITLE, CATEGORY, SOLD_QUANTITY, and REVENUE. SOLD_QUANTITY is the sum of QUANTITY of all sales of the book in the period. REVENUE is the sum of QUANTITY multiplied by PRICE of the book over all sales of the book in the period. REVENUE has 2 decimals. TITLE and CATEGORY are the title and category of the book. No authorization check is required. Create the global ABAP Unit test class {{P}}T20_TEST for the view. The view must be active and have no syntax error. The hidden tests must pass. {{P}}T20_TEST must use CL_CDS_TEST_ENVIRONMENT and pass. Release target is 7.58. Do not change {{P}}BOOK and {{P}}SALE. diff --git a/tasks_gen/eval/G0183/task.json b/tasks_gen/eval/G0183/task.json new file mode 100644 index 0000000..bf9496d --- /dev/null +++ b/tasks_gen/eval/G0183/task.json @@ -0,0 +1,79 @@ +{ + "id": "G0183", + "category": "K", + "object_type": "DDLS", + "difficulty": 2, + "release_target": "v758", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [ + { + "type": "TABL", + "name": "{{P}}BOOK", + "file": "seed/book.tabl.asabap", + "description": "Book master data" + }, + { + "type": "TABL", + "name": "{{P}}SALE", + "file": "seed/sale.tabl.asabap", + "description": "Book sales" + } + ], + "contract": [ + { + "type": "DDLS", + "name": "{{P}}I_BOOK_REVENUE", + "fields": [ + "BOOK_ID", + "TITLE", + "CATEGORY", + "SOLD_QUANTITY", + "REVENUE" + ], + "parameters": [ + { + "name": "P_FROM", + "type": "DATS" + }, + { + "name": "P_TO", + "type": "DATS" + } + ] + } + ], + "out_of_scope": [ + "{{P}}BOOK", + "{{P}}SALE" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T20_HIDDEN", + "file": "hidden/t20_hidden.clas.abap", + "description": "T20 hidden tests" + } + ], + "reference": [ + { + "type": "DDLS", + "name": "{{P}}I_BOOK_REVENUE", + "file": "reference/i_book_revenue.ddls.asddls", + "description": "Book revenue in a period" + }, + { + "type": "CLAS", + "name": "{{P}}T20_TEST", + "file": "reference/t20_test.clas.abap", + "description": "T20 own tests" + } + ], + "craft_checks": [], + "base_task": "G0020", + "input_style": "incomplete", + "tool_schema": "generic_v0" +} \ No newline at end of file diff --git a/tasks_gen/eval/G0184/empirical.json b/tasks_gen/eval/G0184/empirical.json new file mode 100644 index 0000000..f5ccaa6 --- /dev/null +++ b/tasks_gen/eval/G0184/empirical.json @@ -0,0 +1,18 @@ +{ + "deepseek-v4.1-flash:cloud": { + "score": 95.0, + "parts": { + "correctness": 40.0, + "craft": 20.0, + "clean": 15.0, + "own_tests": 15.0, + "discipline": 5.0, + "total": 95.0, + "note": "own_tests: faulty-reference part not implemented in skeleton" + }, + "hidden": "13/13", + "tool_calls": 32, + "seconds": 141.5, + "run_dir": "runs/emp/10014_G0022_llm_deepseek-v4.1-flash_cloud" + } +} \ No newline at end of file diff --git a/tasks_gen/eval/G0184/generation.json b/tasks_gen/eval/G0184/generation.json new file mode 100644 index 0000000..35d6cb8 --- /dev/null +++ b/tasks_gen/eval/G0184/generation.json @@ -0,0 +1,16 @@ +{ + "id": "G0184", + "pool": "eval", + "category": "K", + "base_task": "G0022", + "style": "free_text", + "tool_schema": "generic_v0", + "attempts": [ + { + "stage": "validate", + "oracle": 100.0, + "null": 0 + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0184/hidden/d01_hidden.clas.abap b/tasks_gen/eval/G0184/hidden/d01_hidden.clas.abap new file mode 100644 index 0000000..a23eabd --- /dev/null +++ b/tasks_gen/eval/G0184/hidden/d01_hidden.clas.abap @@ -0,0 +1,237 @@ +CLASS {{p}}d01_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + + PRIVATE SECTION. + TYPES ty_amount TYPE {{p}}if_expense_claim=>ty_amount. + + DATA mo_cut TYPE REF TO {{p}}expense_validator. + + METHODS setup. + METHODS valid_claim_passes FOR TESTING. + METHODS zero_amount_rejected FOR TESTING. + METHODS negative_amount_rejected FOR TESTING. + METHODS unknown_currency_rejected FOR TESTING. + METHODS future_date_rejected FOR TESTING. + METHODS today_is_accepted FOR TESTING. + METHODS receipt_required FOR TESTING. + METHODS receipt_not_required_below FOR TESTING. + METHODS cost_center_required FOR TESTING. + METHODS cost_center_not_required FOR TESTING. + METHODS amount_rule_has_priority FOR TESTING. + METHODS receipt_rule_has_priority FOR TESTING. + METHODS other_currencies_pass FOR TESTING. + + METHODS build_claim + IMPORTING iv_amount TYPE ty_amount + iv_currency TYPE {{p}}if_expense_claim=>ty_currency + iv_date TYPE d + iv_cc TYPE {{p}}if_expense_claim=>ty_cost_center + iv_receipt TYPE abap_bool + RETURNING VALUE(rs_claim) TYPE {{p}}if_expense_claim=>ty_claim. +ENDCLASS. + + +CLASS {{p}}d01_hidden IMPLEMENTATION. + METHOD setup. + mo_cut = NEW {{p}}expense_validator( ). + ENDMETHOD. + + METHOD build_claim. + rs_claim = VALUE #( amount = iv_amount + currency = iv_currency + claim_date = iv_date + cost_center = iv_cc + has_receipt = iv_receipt ). + ENDMETHOD. + + METHOD valid_claim_passes. + DATA(ls_claim) = build_claim( iv_amount = '250.00' iv_currency = 'EUR' + iv_date = sy-datum iv_cc = 'CC1000' + iv_receipt = abap_true ). + TRY. + mo_cut->validate( ls_claim ). + CATCH {{p}}cx_claim_error INTO DATA(lx). + cl_abap_unit_assert=>fail( msg = lx->get_message( ) ). + ENDTRY. + ENDMETHOD. + + METHOD other_currencies_pass. + LOOP AT VALUE string_table( ( `USD` ) ( `GBP` ) ( `CHF` ) ) INTO DATA(lv_currency). + DATA(ls_claim) = build_claim( iv_amount = '250.00' iv_currency = CONV #( lv_currency ) + iv_date = sy-datum iv_cc = 'CC1000' + iv_receipt = abap_true ). + TRY. + mo_cut->validate( ls_claim ). + CATCH {{p}}cx_claim_error INTO DATA(lx). + cl_abap_unit_assert=>fail( msg = |{ lv_currency }: { lx->get_message( ) }| ). + ENDTRY. + ENDLOOP. + ENDMETHOD. + + METHOD zero_amount_rejected. + DATA(ls_claim) = build_claim( iv_amount = 0 iv_currency = 'EUR' + iv_date = sy-datum iv_cc = 'CC1000' + iv_receipt = abap_true ). + TRY. + mo_cut->validate( ls_claim ). + cl_abap_unit_assert=>fail( msg = 'Exception expected' ). + CATCH {{p}}cx_claim_amount INTO DATA(lx). + cl_abap_unit_assert=>assert_equals( exp = CONV ty_amount( '0.00' ) + act = lx->mv_amount ). + cl_abap_unit_assert=>assert_equals( exp = 'Amount must be positive' + act = lx->get_message( ) ). + CATCH {{p}}cx_claim_error INTO DATA(lx_other). + cl_abap_unit_assert=>fail( msg = lx_other->get_message( ) ). + ENDTRY. + ENDMETHOD. + + METHOD negative_amount_rejected. + DATA(ls_claim) = build_claim( iv_amount = '-50.00' iv_currency = 'EUR' + iv_date = sy-datum iv_cc = 'CC1000' + iv_receipt = abap_true ). + TRY. + mo_cut->validate( ls_claim ). + cl_abap_unit_assert=>fail( msg = 'Exception expected' ). + CATCH {{p}}cx_claim_amount INTO DATA(lx). + cl_abap_unit_assert=>assert_equals( exp = CONV ty_amount( '-50.00' ) + act = lx->mv_amount ). + CATCH {{p}}cx_claim_error INTO DATA(lx_other). + cl_abap_unit_assert=>fail( msg = lx_other->get_message( ) ). + ENDTRY. + ENDMETHOD. + + METHOD unknown_currency_rejected. + DATA(ls_claim) = build_claim( iv_amount = '250.00' iv_currency = 'JPY' + iv_date = sy-datum iv_cc = 'CC1000' + iv_receipt = abap_true ). + TRY. + mo_cut->validate( ls_claim ). + cl_abap_unit_assert=>fail( msg = 'Exception expected' ). + CATCH {{p}}cx_claim_currency INTO DATA(lx). + cl_abap_unit_assert=>assert_equals( exp = 'JPY' + act = lx->mv_currency ). + cl_abap_unit_assert=>assert_equals( exp = 'Currency is not supported' + act = lx->get_message( ) ). + CATCH {{p}}cx_claim_error INTO DATA(lx_other). + cl_abap_unit_assert=>fail( msg = lx_other->get_message( ) ). + ENDTRY. + ENDMETHOD. + + METHOD future_date_rejected. + DATA lv_tomorrow TYPE d. + lv_tomorrow = sy-datum + 1. + DATA(ls_claim) = build_claim( iv_amount = '250.00' iv_currency = 'EUR' + iv_date = lv_tomorrow iv_cc = 'CC1000' + iv_receipt = abap_true ). + TRY. + mo_cut->validate( ls_claim ). + cl_abap_unit_assert=>fail( msg = 'Exception expected' ). + CATCH {{p}}cx_claim_date INTO DATA(lx). + cl_abap_unit_assert=>assert_equals( exp = lv_tomorrow + act = lx->mv_claim_date ). + cl_abap_unit_assert=>assert_equals( exp = 'Claim date is in the future' + act = lx->get_message( ) ). + CATCH {{p}}cx_claim_error INTO DATA(lx_other). + cl_abap_unit_assert=>fail( msg = lx_other->get_message( ) ). + ENDTRY. + ENDMETHOD. + + METHOD today_is_accepted. + DATA(ls_claim) = build_claim( iv_amount = '250.00' iv_currency = 'EUR' + iv_date = sy-datum iv_cc = 'CC1000' + iv_receipt = abap_true ). + TRY. + mo_cut->validate( ls_claim ). + CATCH {{p}}cx_claim_error INTO DATA(lx). + cl_abap_unit_assert=>fail( msg = lx->get_message( ) ). + ENDTRY. + ENDMETHOD. + + METHOD receipt_required. + DATA(ls_claim) = build_claim( iv_amount = '250.00' iv_currency = 'EUR' + iv_date = sy-datum iv_cc = 'CC1000' + iv_receipt = abap_false ). + TRY. + mo_cut->validate( ls_claim ). + cl_abap_unit_assert=>fail( msg = 'Exception expected' ). + CATCH {{p}}cx_claim_receipt INTO DATA(lx). + cl_abap_unit_assert=>assert_equals( exp = CONV ty_amount( '250.00' ) + act = lx->mv_amount ). + cl_abap_unit_assert=>assert_equals( exp = 'Receipt is required' + act = lx->get_message( ) ). + CATCH {{p}}cx_claim_error INTO DATA(lx_other). + cl_abap_unit_assert=>fail( msg = lx_other->get_message( ) ). + ENDTRY. + ENDMETHOD. + + METHOD receipt_not_required_below. + DATA(ls_claim) = build_claim( iv_amount = '99.99' iv_currency = 'EUR' + iv_date = sy-datum iv_cc = 'CC1000' + iv_receipt = abap_false ). + TRY. + mo_cut->validate( ls_claim ). + CATCH {{p}}cx_claim_error INTO DATA(lx). + cl_abap_unit_assert=>fail( msg = lx->get_message( ) ). + ENDTRY. + ENDMETHOD. + + METHOD cost_center_required. + DATA(ls_claim) = build_claim( iv_amount = '1500.00' iv_currency = 'EUR' + iv_date = sy-datum iv_cc = '' + iv_receipt = abap_true ). + TRY. + mo_cut->validate( ls_claim ). + cl_abap_unit_assert=>fail( msg = 'Exception expected' ). + CATCH {{p}}cx_claim_costcenter INTO DATA(lx). + cl_abap_unit_assert=>assert_equals( exp = CONV ty_amount( '1500.00' ) + act = lx->mv_amount ). + cl_abap_unit_assert=>assert_equals( exp = 'Cost center is required' + act = lx->get_message( ) ). + CATCH {{p}}cx_claim_error INTO DATA(lx_other). + cl_abap_unit_assert=>fail( msg = lx_other->get_message( ) ). + ENDTRY. + ENDMETHOD. + + METHOD cost_center_not_required. + DATA(ls_claim) = build_claim( iv_amount = '999.99' iv_currency = 'EUR' + iv_date = sy-datum iv_cc = '' + iv_receipt = abap_true ). + TRY. + mo_cut->validate( ls_claim ). + CATCH {{p}}cx_claim_error INTO DATA(lx). + cl_abap_unit_assert=>fail( msg = lx->get_message( ) ). + ENDTRY. + ENDMETHOD. + + METHOD amount_rule_has_priority. + DATA lv_future TYPE d. + lv_future = sy-datum + 1. + DATA(ls_claim) = build_claim( iv_amount = 0 iv_currency = 'JPY' + iv_date = lv_future iv_cc = '' + iv_receipt = abap_false ). + TRY. + mo_cut->validate( ls_claim ). + cl_abap_unit_assert=>fail( msg = 'Exception expected' ). + CATCH {{p}}cx_claim_amount INTO DATA(lx). + cl_abap_unit_assert=>assert_equals( exp = CONV ty_amount( '0.00' ) + act = lx->mv_amount ). + CATCH {{p}}cx_claim_error INTO DATA(lx_other). + cl_abap_unit_assert=>fail( msg = lx_other->get_message( ) ). + ENDTRY. + ENDMETHOD. + + METHOD receipt_rule_has_priority. + DATA(ls_claim) = build_claim( iv_amount = '1500.00' iv_currency = 'EUR' + iv_date = sy-datum iv_cc = '' + iv_receipt = abap_false ). + TRY. + mo_cut->validate( ls_claim ). + cl_abap_unit_assert=>fail( msg = 'Exception expected' ). + CATCH {{p}}cx_claim_receipt INTO DATA(lx). + cl_abap_unit_assert=>assert_equals( exp = CONV ty_amount( '1500.00' ) + act = lx->mv_amount ). + CATCH {{p}}cx_claim_error INTO DATA(lx_other). + cl_abap_unit_assert=>fail( msg = lx_other->get_message( ) ). + ENDTRY. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0184/reference/cx_claim_amount.clas.abap b/tasks_gen/eval/G0184/reference/cx_claim_amount.clas.abap new file mode 100644 index 0000000..710f09a --- /dev/null +++ b/tasks_gen/eval/G0184/reference/cx_claim_amount.clas.abap @@ -0,0 +1,20 @@ +CLASS {{p}}cx_claim_amount DEFINITION + PUBLIC + INHERITING FROM {{p}}cx_claim_error + FINAL + CREATE PUBLIC. + + PUBLIC SECTION. + DATA mv_amount TYPE {{p}}if_expense_claim=>ty_amount READ-ONLY. + + METHODS constructor + IMPORTING iv_amount TYPE {{p}}if_expense_claim=>ty_amount. +ENDCLASS. + + +CLASS {{p}}cx_claim_amount IMPLEMENTATION. + METHOD constructor. + super->constructor( iv_message = 'Amount must be positive' ). + mv_amount = iv_amount. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0184/reference/cx_claim_costcenter.clas.abap b/tasks_gen/eval/G0184/reference/cx_claim_costcenter.clas.abap new file mode 100644 index 0000000..31f7c3d --- /dev/null +++ b/tasks_gen/eval/G0184/reference/cx_claim_costcenter.clas.abap @@ -0,0 +1,20 @@ +CLASS {{p}}cx_claim_costcenter DEFINITION + PUBLIC + INHERITING FROM {{p}}cx_claim_error + FINAL + CREATE PUBLIC. + + PUBLIC SECTION. + DATA mv_amount TYPE {{p}}if_expense_claim=>ty_amount READ-ONLY. + + METHODS constructor + IMPORTING iv_amount TYPE {{p}}if_expense_claim=>ty_amount. +ENDCLASS. + + +CLASS {{p}}cx_claim_costcenter IMPLEMENTATION. + METHOD constructor. + super->constructor( iv_message = 'Cost center is required' ). + mv_amount = iv_amount. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0184/reference/cx_claim_currency.clas.abap b/tasks_gen/eval/G0184/reference/cx_claim_currency.clas.abap new file mode 100644 index 0000000..72ed7a0 --- /dev/null +++ b/tasks_gen/eval/G0184/reference/cx_claim_currency.clas.abap @@ -0,0 +1,20 @@ +CLASS {{p}}cx_claim_currency DEFINITION + PUBLIC + INHERITING FROM {{p}}cx_claim_error + FINAL + CREATE PUBLIC. + + PUBLIC SECTION. + DATA mv_currency TYPE {{p}}if_expense_claim=>ty_currency READ-ONLY. + + METHODS constructor + IMPORTING iv_currency TYPE {{p}}if_expense_claim=>ty_currency. +ENDCLASS. + + +CLASS {{p}}cx_claim_currency IMPLEMENTATION. + METHOD constructor. + super->constructor( iv_message = 'Currency is not supported' ). + mv_currency = iv_currency. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0184/reference/cx_claim_date.clas.abap b/tasks_gen/eval/G0184/reference/cx_claim_date.clas.abap new file mode 100644 index 0000000..cb444cc --- /dev/null +++ b/tasks_gen/eval/G0184/reference/cx_claim_date.clas.abap @@ -0,0 +1,20 @@ +CLASS {{p}}cx_claim_date DEFINITION + PUBLIC + INHERITING FROM {{p}}cx_claim_error + FINAL + CREATE PUBLIC. + + PUBLIC SECTION. + DATA mv_claim_date TYPE d READ-ONLY. + + METHODS constructor + IMPORTING iv_claim_date TYPE d. +ENDCLASS. + + +CLASS {{p}}cx_claim_date IMPLEMENTATION. + METHOD constructor. + super->constructor( iv_message = 'Claim date is in the future' ). + mv_claim_date = iv_claim_date. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0184/reference/cx_claim_receipt.clas.abap b/tasks_gen/eval/G0184/reference/cx_claim_receipt.clas.abap new file mode 100644 index 0000000..232c9da --- /dev/null +++ b/tasks_gen/eval/G0184/reference/cx_claim_receipt.clas.abap @@ -0,0 +1,20 @@ +CLASS {{p}}cx_claim_receipt DEFINITION + PUBLIC + INHERITING FROM {{p}}cx_claim_error + FINAL + CREATE PUBLIC. + + PUBLIC SECTION. + DATA mv_amount TYPE {{p}}if_expense_claim=>ty_amount READ-ONLY. + + METHODS constructor + IMPORTING iv_amount TYPE {{p}}if_expense_claim=>ty_amount. +ENDCLASS. + + +CLASS {{p}}cx_claim_receipt IMPLEMENTATION. + METHOD constructor. + super->constructor( iv_message = 'Receipt is required' ). + mv_amount = iv_amount. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0184/reference/expense_validator.clas.abap b/tasks_gen/eval/G0184/reference/expense_validator.clas.abap new file mode 100644 index 0000000..fed166e --- /dev/null +++ b/tasks_gen/eval/G0184/reference/expense_validator.clas.abap @@ -0,0 +1,85 @@ +CLASS {{p}}expense_validator DEFINITION + PUBLIC + FINAL + CREATE PUBLIC. + + PUBLIC SECTION. + METHODS validate + IMPORTING is_claim TYPE {{p}}if_expense_claim=>ty_claim + RAISING {{p}}cx_claim_error. + + PRIVATE SECTION. + CONSTANTS: + c_receipt_limit TYPE {{p}}if_expense_claim=>ty_amount VALUE '100.00', + c_cc_limit TYPE {{p}}if_expense_claim=>ty_amount VALUE '1000.00'. + + METHODS check_amount + IMPORTING is_claim TYPE {{p}}if_expense_claim=>ty_claim + RAISING {{p}}cx_claim_error. + METHODS check_currency + IMPORTING is_claim TYPE {{p}}if_expense_claim=>ty_claim + RAISING {{p}}cx_claim_error. + METHODS check_date + IMPORTING is_claim TYPE {{p}}if_expense_claim=>ty_claim + RAISING {{p}}cx_claim_error. + METHODS check_receipt + IMPORTING is_claim TYPE {{p}}if_expense_claim=>ty_claim + RAISING {{p}}cx_claim_error. + METHODS check_cost_center + IMPORTING is_claim TYPE {{p}}if_expense_claim=>ty_claim + RAISING {{p}}cx_claim_error. + METHODS is_supported_currency + IMPORTING iv_currency TYPE {{p}}if_expense_claim=>ty_currency + RETURNING VALUE(rv_supported) TYPE abap_bool. +ENDCLASS. + + +CLASS {{p}}expense_validator IMPLEMENTATION. + METHOD validate. + check_amount( is_claim ). + check_currency( is_claim ). + check_date( is_claim ). + check_receipt( is_claim ). + check_cost_center( is_claim ). + ENDMETHOD. + + METHOD check_amount. + IF is_claim-amount <= 0. + RAISE EXCEPTION TYPE {{p}}cx_claim_amount + EXPORTING iv_amount = is_claim-amount. + ENDIF. + ENDMETHOD. + + METHOD check_currency. + IF is_supported_currency( is_claim-currency ) = abap_false. + RAISE EXCEPTION TYPE {{p}}cx_claim_currency + EXPORTING iv_currency = is_claim-currency. + ENDIF. + ENDMETHOD. + + METHOD check_date. + IF is_claim-claim_date > sy-datum. + RAISE EXCEPTION TYPE {{p}}cx_claim_date + EXPORTING iv_claim_date = is_claim-claim_date. + ENDIF. + ENDMETHOD. + + METHOD check_receipt. + IF is_claim-amount >= c_receipt_limit AND is_claim-has_receipt = abap_false. + RAISE EXCEPTION TYPE {{p}}cx_claim_receipt + EXPORTING iv_amount = is_claim-amount. + ENDIF. + ENDMETHOD. + + METHOD check_cost_center. + IF is_claim-amount >= c_cc_limit AND is_claim-cost_center IS INITIAL. + RAISE EXCEPTION TYPE {{p}}cx_claim_costcenter + EXPORTING iv_amount = is_claim-amount. + ENDIF. + ENDMETHOD. + + METHOD is_supported_currency. + rv_supported = xsdbool( iv_currency = 'EUR' OR iv_currency = 'USD' + OR iv_currency = 'GBP' OR iv_currency = 'CHF' ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0184/reference/expense_validator.testclasses.abap b/tasks_gen/eval/G0184/reference/expense_validator.testclasses.abap new file mode 100644 index 0000000..b1fc8eb --- /dev/null +++ b/tasks_gen/eval/G0184/reference/expense_validator.testclasses.abap @@ -0,0 +1,127 @@ +CLASS ltc_expense_validator DEFINITION FINAL FOR TESTING + DURATION SHORT RISK LEVEL HARMLESS. + + PRIVATE SECTION. + TYPES ty_amount TYPE {{p}}if_expense_claim=>ty_amount. + + DATA mo_cut TYPE REF TO {{p}}expense_validator. + + METHODS setup. + METHODS valid_claim FOR TESTING. + METHODS zero_amount FOR TESTING. + METHODS unknown_currency FOR TESTING. + METHODS future_date FOR TESTING. + METHODS receipt_missing FOR TESTING. + METHODS cost_center_missing FOR TESTING. + + METHODS build_claim + IMPORTING iv_amount TYPE ty_amount + iv_currency TYPE {{p}}if_expense_claim=>ty_currency + iv_date TYPE d + iv_cc TYPE {{p}}if_expense_claim=>ty_cost_center + iv_receipt TYPE abap_bool + RETURNING VALUE(rs_claim) TYPE {{p}}if_expense_claim=>ty_claim. +ENDCLASS. + + +CLASS ltc_expense_validator IMPLEMENTATION. + METHOD setup. + mo_cut = NEW {{p}}expense_validator( ). + ENDMETHOD. + + METHOD build_claim. + rs_claim = VALUE #( amount = iv_amount + currency = iv_currency + claim_date = iv_date + cost_center = iv_cc + has_receipt = iv_receipt ). + ENDMETHOD. + + METHOD valid_claim. + DATA(ls_claim) = build_claim( iv_amount = '250.00' iv_currency = 'EUR' + iv_date = sy-datum iv_cc = 'CC1000' + iv_receipt = abap_true ). + TRY. + mo_cut->validate( ls_claim ). + CATCH {{p}}cx_claim_error INTO DATA(lx). + cl_abap_unit_assert=>fail( msg = lx->get_message( ) ). + ENDTRY. + ENDMETHOD. + + METHOD zero_amount. + DATA(ls_claim) = build_claim( iv_amount = 0 iv_currency = 'EUR' + iv_date = sy-datum iv_cc = 'CC1000' + iv_receipt = abap_true ). + TRY. + mo_cut->validate( ls_claim ). + cl_abap_unit_assert=>fail( msg = 'Exception expected' ). + CATCH {{p}}cx_claim_amount INTO DATA(lx). + cl_abap_unit_assert=>assert_equals( exp = CONV ty_amount( '0.00' ) + act = lx->mv_amount ). + CATCH {{p}}cx_claim_error INTO DATA(lx_other). + cl_abap_unit_assert=>fail( msg = lx_other->get_message( ) ). + ENDTRY. + ENDMETHOD. + + METHOD unknown_currency. + DATA(ls_claim) = build_claim( iv_amount = '250.00' iv_currency = 'JPY' + iv_date = sy-datum iv_cc = 'CC1000' + iv_receipt = abap_true ). + TRY. + mo_cut->validate( ls_claim ). + cl_abap_unit_assert=>fail( msg = 'Exception expected' ). + CATCH {{p}}cx_claim_currency INTO DATA(lx). + cl_abap_unit_assert=>assert_equals( exp = 'JPY' + act = lx->mv_currency ). + CATCH {{p}}cx_claim_error INTO DATA(lx_other). + cl_abap_unit_assert=>fail( msg = lx_other->get_message( ) ). + ENDTRY. + ENDMETHOD. + + METHOD future_date. + DATA lv_future TYPE d. + lv_future = sy-datum + 1. + DATA(ls_claim) = build_claim( iv_amount = '250.00' iv_currency = 'EUR' + iv_date = lv_future iv_cc = 'CC1000' + iv_receipt = abap_true ). + TRY. + mo_cut->validate( ls_claim ). + cl_abap_unit_assert=>fail( msg = 'Exception expected' ). + CATCH {{p}}cx_claim_date INTO DATA(lx). + cl_abap_unit_assert=>assert_equals( exp = lv_future + act = lx->mv_claim_date ). + CATCH {{p}}cx_claim_error INTO DATA(lx_other). + cl_abap_unit_assert=>fail( msg = lx_other->get_message( ) ). + ENDTRY. + ENDMETHOD. + + METHOD receipt_missing. + DATA(ls_claim) = build_claim( iv_amount = '250.00' iv_currency = 'EUR' + iv_date = sy-datum iv_cc = 'CC1000' + iv_receipt = abap_false ). + TRY. + mo_cut->validate( ls_claim ). + cl_abap_unit_assert=>fail( msg = 'Exception expected' ). + CATCH {{p}}cx_claim_receipt INTO DATA(lx). + cl_abap_unit_assert=>assert_equals( exp = 'Receipt is required' + act = lx->get_message( ) ). + CATCH {{p}}cx_claim_error INTO DATA(lx_other). + cl_abap_unit_assert=>fail( msg = lx_other->get_message( ) ). + ENDTRY. + ENDMETHOD. + + METHOD cost_center_missing. + DATA(ls_claim) = build_claim( iv_amount = '1500.00' iv_currency = 'EUR' + iv_date = sy-datum iv_cc = '' + iv_receipt = abap_true ). + TRY. + mo_cut->validate( ls_claim ). + cl_abap_unit_assert=>fail( msg = 'Exception expected' ). + CATCH {{p}}cx_claim_costcenter INTO DATA(lx). + cl_abap_unit_assert=>assert_equals( exp = 'Cost center is required' + act = lx->get_message( ) ). + CATCH {{p}}cx_claim_error INTO DATA(lx_other). + cl_abap_unit_assert=>fail( msg = lx_other->get_message( ) ). + ENDTRY. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0184/review.json b/tasks_gen/eval/G0184/review.json new file mode 100644 index 0000000..b5f763a --- /dev/null +++ b/tasks_gen/eval/G0184/review.json @@ -0,0 +1,7 @@ +{ + "decision": "accept", + "note": "Fixed: added other_currencies_pass; oracle 100, null 0, mutation 5/5.", + "by": "Claude", + "date": "2026-10-03", + "failed_checks": {} +} \ No newline at end of file diff --git a/tasks_gen/eval/G0184/seed/cx_claim_error.clas.abap b/tasks_gen/eval/G0184/seed/cx_claim_error.clas.abap new file mode 100644 index 0000000..874c5be --- /dev/null +++ b/tasks_gen/eval/G0184/seed/cx_claim_error.clas.abap @@ -0,0 +1,27 @@ +CLASS {{p}}cx_claim_error DEFINITION + PUBLIC + INHERITING FROM cx_static_check + CREATE PUBLIC. + + PUBLIC SECTION. + METHODS constructor + IMPORTING iv_message TYPE string. + + METHODS get_message + RETURNING VALUE(rv_message) TYPE string. + + PRIVATE SECTION. + DATA mv_message TYPE string. +ENDCLASS. + + +CLASS {{p}}cx_claim_error IMPLEMENTATION. + METHOD constructor. + super->constructor( ). + mv_message = iv_message. + ENDMETHOD. + + METHOD get_message. + rv_message = mv_message. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0184/seed/if_expense_claim.intf.abap b/tasks_gen/eval/G0184/seed/if_expense_claim.intf.abap new file mode 100644 index 0000000..5d8b1c5 --- /dev/null +++ b/tasks_gen/eval/G0184/seed/if_expense_claim.intf.abap @@ -0,0 +1,14 @@ +INTERFACE {{p}}if_expense_claim PUBLIC. + TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2. + TYPES ty_currency TYPE c LENGTH 3. + TYPES ty_cost_center TYPE c LENGTH 10. + + TYPES: + BEGIN OF ty_claim, + amount TYPE ty_amount, + currency TYPE ty_currency, + claim_date TYPE d, + cost_center TYPE ty_cost_center, + has_receipt TYPE abap_bool, + END OF ty_claim. +ENDINTERFACE. diff --git a/tasks_gen/eval/G0184/spec.md b/tasks_gen/eval/G0184/spec.md new file mode 100644 index 0000000..ddb41c1 --- /dev/null +++ b/tasks_gen/eval/G0184/spec.md @@ -0,0 +1,9 @@ +Please implement an expense claim validator for us. The goal is to validate an employee expense claim before it is posted to accounting. The check reports the first rule that fails as a class-based exception. Each exception carries the value that caused the failure and a short message. There are no open questions. + +The interface {{P}}IF_EXPENSE_CLAIM exists in package $TMP and is active. It contains types only and has no methods. TY_AMOUNT is a packed number with length 8 and 2 decimals. TY_CURRENCY is a character field with length 3. TY_COST_CENTER is a character field with length 10. TY_CLAIM is a structure with components AMOUNT of type TY_AMOUNT, CURRENCY of type TY_CURRENCY, CLAIM_DATE of type D, COST_CENTER of type TY_COST_CENTER, and HAS_RECEIPT of type ABAP_BOOL. The class {{P}}CX_CLAIM_ERROR exists in package $TMP and is active. It is a direct subclass of CX_STATIC_CHECK. Its constructor has importing parameter IV_MESSAGE of type string. The method GET_MESSAGE returns this text of type string. + +Please create the class {{P}}EXPENSE_VALIDATOR in package $TMP. The class is public and final and has a public constructor without parameters. The class has exactly one public method: VALIDATE importing is_claim of type {{P}}IF_EXPENSE_CLAIM=>TY_CLAIM and raising {{P}}CX_CLAIM_ERROR. Also create these exception classes in package $TMP. Each one inherits from {{P}}CX_CLAIM_ERROR, is final, and has a public constructor. {{P}}CX_CLAIM_AMOUNT has constructor parameter IV_AMOUNT of type TY_AMOUNT of {{P}}IF_EXPENSE_CLAIM. It has public read-only attribute MV_AMOUNT of the same type. Its message is Amount must be positive. {{P}}CX_CLAIM_CURRENCY has constructor parameter IV_CURRENCY of type TY_CURRENCY. It has public read-only attribute MV_CURRENCY of the same type. Its message is Currency is not supported. {{P}}CX_CLAIM_DATE has constructor parameter IV_CLAIM_DATE of type D. It has public read-only attribute MV_CLAIM_DATE of type D. Its message is Claim date is in the future. {{P}}CX_CLAIM_RECEIPT has constructor parameter IV_AMOUNT of type TY_AMOUNT. It has public read-only attribute MV_AMOUNT of the same type. Its message is Receipt is required. {{P}}CX_CLAIM_COSTCENTER has constructor parameter IV_AMOUNT of type TY_AMOUNT. It has public read-only attribute MV_AMOUNT of the same type. Its message is Cost center is required. GET_MESSAGE returns the message of the exception. Do not add other public methods or attributes. + +Check the claim in this sequence. Raise the exception of the first rule that fails. If no rule fails, the method ends without an exception. AMOUNT must be greater than zero. If not, raise {{P}}CX_CLAIM_AMOUNT with IV_AMOUNT = AMOUNT. Then CURRENCY must be one of EUR, USD, GBP, CHF. If not, raise {{P}}CX_CLAIM_CURRENCY with IV_CURRENCY = CURRENCY. Then CLAIM_DATE must not be later than the current date. If it is later, raise {{P}}CX_CLAIM_DATE with IV_CLAIM_DATE = CLAIM_DATE. Then if AMOUNT is 100.00 or more, HAS_RECEIPT must be true. If not, raise {{P}}CX_CLAIM_RECEIPT with IV_AMOUNT = AMOUNT. Then if AMOUNT is 1000.00 or more, COST_CENTER must not be initial. If it is initial, raise {{P}}CX_CLAIM_COSTCENTER with IV_AMOUNT = AMOUNT. + +Use release target 8.16. Follow Clean ABAP. Keep method length below 40 statements. Do not use global variables. Do not write comments that restate the code. Do not change {{P}}IF_EXPENSE_CLAIM and {{P}}CX_CLAIM_ERROR. All objects must be active and have no syntax error. The hidden tests must pass. Write your own ABAP Unit tests for {{P}}EXPENSE_VALIDATOR. diff --git a/tasks_gen/eval/G0184/task.json b/tasks_gen/eval/G0184/task.json new file mode 100644 index 0000000..f7d7763 --- /dev/null +++ b/tasks_gen/eval/G0184/task.json @@ -0,0 +1,110 @@ +{ + "id": "G0184", + "category": "K", + "object_type": "CLAS", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [ + { + "type": "INTF", + "name": "{{P}}IF_EXPENSE_CLAIM", + "file": "seed/if_expense_claim.intf.abap", + "description": "Types for an expense claim" + }, + { + "type": "CLAS", + "name": "{{P}}CX_CLAIM_ERROR", + "file": "seed/cx_claim_error.clas.abap", + "description": "Base exception that carries a message text" + } + ], + "contract": [ + { + "type": "CLAS", + "name": "{{P}}CX_CLAIM_AMOUNT" + }, + { + "type": "CLAS", + "name": "{{P}}CX_CLAIM_CURRENCY" + }, + { + "type": "CLAS", + "name": "{{P}}CX_CLAIM_DATE" + }, + { + "type": "CLAS", + "name": "{{P}}CX_CLAIM_RECEIPT" + }, + { + "type": "CLAS", + "name": "{{P}}CX_CLAIM_COSTCENTER" + }, + { + "type": "CLAS", + "name": "{{P}}EXPENSE_VALIDATOR" + } + ], + "out_of_scope": [ + "{{P}}IF_EXPENSE_CLAIM", + "{{P}}CX_CLAIM_ERROR" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}D01_HIDDEN", + "file": "hidden/d01_hidden.clas.abap", + "description": "Hidden tests for the expense claim validation" + } + ], + "reference": [ + { + "type": "CLAS", + "name": "{{P}}CX_CLAIM_AMOUNT", + "file": "reference/cx_claim_amount.clas.abap", + "description": "Exception for a non positive amount" + }, + { + "type": "CLAS", + "name": "{{P}}CX_CLAIM_CURRENCY", + "file": "reference/cx_claim_currency.clas.abap", + "description": "Exception for an unsupported currency" + }, + { + "type": "CLAS", + "name": "{{P}}CX_CLAIM_DATE", + "file": "reference/cx_claim_date.clas.abap", + "description": "Exception for a claim date in the future" + }, + { + "type": "CLAS", + "name": "{{P}}CX_CLAIM_RECEIPT", + "file": "reference/cx_claim_receipt.clas.abap", + "description": "Exception for a missing receipt" + }, + { + "type": "CLAS", + "name": "{{P}}CX_CLAIM_COSTCENTER", + "file": "reference/cx_claim_costcenter.clas.abap", + "description": "Exception for a missing cost center" + }, + { + "type": "CLAS", + "name": "{{P}}EXPENSE_VALIDATOR", + "file": "reference/expense_validator.clas.abap", + "description": "Validates an expense claim and raises class-based exceptions", + "testclasses_file": "reference/expense_validator.testclasses.abap" + } + ], + "craft_checks": [ + "method_length", + "exception_design" + ], + "base_task": "G0022", + "input_style": "free_text", + "tool_schema": "generic_v0" +} \ No newline at end of file diff --git a/tasks_gen/eval/G0185/empirical.json b/tasks_gen/eval/G0185/empirical.json new file mode 100644 index 0000000..8dd68cc --- /dev/null +++ b/tasks_gen/eval/G0185/empirical.json @@ -0,0 +1,18 @@ +{ + "deepseek-v4.1-flash:cloud": { + "score": 85.0, + "parts": { + "correctness": 40.0, + "craft": 20.0, + "clean": 15.0, + "own_tests": 0.0, + "discipline": 10.0, + "total": 85.0, + "note": "own_tests: faulty-reference part not implemented in skeleton" + }, + "hidden": "11/11", + "tool_calls": 17, + "seconds": 60.2, + "run_dir": "runs/emp/10006_G0012_llm_deepseek-v4.1-flash_cloud" + } +} \ No newline at end of file diff --git a/tasks_gen/eval/G0185/generation.json b/tasks_gen/eval/G0185/generation.json new file mode 100644 index 0000000..45c1121 --- /dev/null +++ b/tasks_gen/eval/G0185/generation.json @@ -0,0 +1,16 @@ +{ + "id": "G0185", + "pool": "eval", + "category": "K", + "base_task": "G0012", + "style": "incomplete", + "tool_schema": "generic_v0", + "attempts": [ + { + "stage": "validate", + "oracle": 100.0, + "null": 0 + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0185/hidden/t14_hidden.clas.abap b/tasks_gen/eval/G0185/hidden/t14_hidden.clas.abap new file mode 100644 index 0000000..f8c7f01 --- /dev/null +++ b/tasks_gen/eval/G0185/hidden/t14_hidden.clas.abap @@ -0,0 +1,120 @@ +CLASS {{p}}t14_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS call + IMPORTING iv_quantity TYPE decfloat34 + iv_scrap TYPE decfloat34 + iv_rework TYPE decfloat34 DEFAULT 0 + EXPORTING ev_pct TYPE decfloat34 + ev_severity TYPE string + ev_rework TYPE decfloat34 + ev_subrc TYPE sysubrc. + METHODS percent_rounds_half_up FOR TESTING. + METHODS zero_scrap_is_ok FOR TESTING. + METHODS low_upper_boundary FOR TESTING. + METHODS high_lower_boundary FOR TESTING. + METHODS high_upper_boundary FOR TESTING. + METHODS critical_above_twenty FOR TESTING. + METHODS rework_unchanged_for_low FOR TESTING. + METHODS rework_set_for_high FOR TESTING. + METHODS quantity_zero_raises FOR TESTING. + METHODS scrap_negative_raises FOR TESTING. + METHODS scrap_above_quantity_raises FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t14_hidden IMPLEMENTATION. + METHOD call. + ev_pct = 0. + ev_severity = ``. + ev_rework = iv_rework. + CALL FUNCTION '{{P}}PRD_SCRAP' + EXPORTING + iv_quantity = iv_quantity + iv_scrap = iv_scrap + IMPORTING + ev_scrap_pct = ev_pct + ev_severity = ev_severity + CHANGING + cv_rework_qty = ev_rework + EXCEPTIONS + invalid_quantity = 1 + scrap_too_high = 2 + OTHERS = 3. + ev_subrc = sy-subrc. + ENDMETHOD. + + METHOD percent_rounds_half_up. + call( EXPORTING iv_quantity = 800 iv_scrap = 7 + IMPORTING ev_pct = DATA(lv_pct) ev_severity = DATA(lv_sev) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '0.9' ) act = lv_pct ). + cl_abap_unit_assert=>assert_equals( exp = `LOW` act = lv_sev ). + ENDMETHOD. + + METHOD zero_scrap_is_ok. + call( EXPORTING iv_quantity = 100 iv_scrap = 0 + IMPORTING ev_pct = DATA(lv_pct) ev_severity = DATA(lv_sev) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 0 ) act = lv_pct ). + cl_abap_unit_assert=>assert_equals( exp = `OK` act = lv_sev ). + ENDMETHOD. + + METHOD low_upper_boundary. + call( EXPORTING iv_quantity = 100 iv_scrap = 5 + IMPORTING ev_pct = DATA(lv_pct) ev_severity = DATA(lv_sev) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 5 ) act = lv_pct ). + cl_abap_unit_assert=>assert_equals( exp = `LOW` act = lv_sev ). + ENDMETHOD. + + METHOD high_lower_boundary. + call( EXPORTING iv_quantity = 100 iv_scrap = '5.1' + IMPORTING ev_pct = DATA(lv_pct) ev_severity = DATA(lv_sev) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '5.1' ) act = lv_pct ). + cl_abap_unit_assert=>assert_equals( exp = `HIGH` act = lv_sev ). + ENDMETHOD. + + METHOD high_upper_boundary. + call( EXPORTING iv_quantity = 100 iv_scrap = 20 + IMPORTING ev_pct = DATA(lv_pct) ev_severity = DATA(lv_sev) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 20 ) act = lv_pct ). + cl_abap_unit_assert=>assert_equals( exp = `HIGH` act = lv_sev ). + ENDMETHOD. + + METHOD critical_above_twenty. + call( EXPORTING iv_quantity = 100 iv_scrap = '20.1' + IMPORTING ev_pct = DATA(lv_pct) ev_severity = DATA(lv_sev) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '20.1' ) act = lv_pct ). + cl_abap_unit_assert=>assert_equals( exp = `CRITICAL` act = lv_sev ). + ENDMETHOD. + + METHOD rework_unchanged_for_low. + call( EXPORTING iv_quantity = 200 iv_scrap = 4 iv_rework = 99 + IMPORTING ev_rework = DATA(lv_rework) ev_severity = DATA(lv_sev) ). + cl_abap_unit_assert=>assert_equals( exp = `LOW` act = lv_sev ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 99 ) act = lv_rework ). + ENDMETHOD. + + METHOD rework_set_for_high. + call( EXPORTING iv_quantity = 100 iv_scrap = 10 iv_rework = 99 + IMPORTING ev_rework = DATA(lv_rework) ev_severity = DATA(lv_sev) ). + cl_abap_unit_assert=>assert_equals( exp = `HIGH` act = lv_sev ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 10 ) act = lv_rework ). + ENDMETHOD. + + METHOD quantity_zero_raises. + call( EXPORTING iv_quantity = 0 iv_scrap = 0 + IMPORTING ev_subrc = DATA(lv_rc) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lv_rc ). + ENDMETHOD. + + METHOD scrap_negative_raises. + call( EXPORTING iv_quantity = 100 iv_scrap = -1 + IMPORTING ev_subrc = DATA(lv_rc) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lv_rc ). + ENDMETHOD. + + METHOD scrap_above_quantity_raises. + call( EXPORTING iv_quantity = 100 iv_scrap = 101 + IMPORTING ev_subrc = DATA(lv_rc) ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lv_rc ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0185/reference/prd_scrap.func.abap b/tasks_gen/eval/G0185/reference/prd_scrap.func.abap new file mode 100644 index 0000000..d574e4d --- /dev/null +++ b/tasks_gen/eval/G0185/reference/prd_scrap.func.abap @@ -0,0 +1,41 @@ +FUNCTION {{p}}prd_scrap + IMPORTING + iv_quantity TYPE decfloat34 + iv_scrap TYPE decfloat34 + EXPORTING + ev_scrap_pct TYPE decfloat34 + ev_severity TYPE string + CHANGING + cv_rework_qty TYPE decfloat34 + EXCEPTIONS + invalid_quantity + scrap_too_high. + + IF iv_quantity <= 0 OR iv_scrap < 0. + RAISE invalid_quantity. + ENDIF. + + IF iv_scrap > iv_quantity. + RAISE scrap_too_high. + ENDIF. + + ev_scrap_pct = round( val = iv_scrap / iv_quantity * 100 + dec = 1 + mode = cl_abap_math=>round_half_up ). + + IF ev_scrap_pct = 0. + ev_severity = 'OK'. + ELSEIF ev_scrap_pct <= 5. + ev_severity = 'LOW'. + ELSEIF ev_scrap_pct <= 20. + ev_severity = 'HIGH'. + ELSE. + ev_severity = 'CRITICAL'. + ENDIF. + + CASE ev_severity. + WHEN 'HIGH' OR 'CRITICAL'. + cv_rework_qty = iv_scrap. + ENDCASE. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0185/reference/t14_test.clas.abap b/tasks_gen/eval/G0185/reference/t14_test.clas.abap new file mode 100644 index 0000000..d7660a8 --- /dev/null +++ b/tasks_gen/eval/G0185/reference/t14_test.clas.abap @@ -0,0 +1,90 @@ +CLASS {{p}}t14_test DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS result_for + IMPORTING iv_quantity TYPE decfloat34 + iv_scrap TYPE decfloat34 + iv_rework TYPE decfloat34 DEFAULT 0 + EXPORTING ev_pct TYPE decfloat34 + ev_severity TYPE string + ev_rework TYPE decfloat34. + METHODS percent_and_severity FOR TESTING. + METHODS severity_bands FOR TESTING. + METHODS rework_quantity FOR TESTING. + METHODS invalid_inputs FOR TESTING. + METHODS scrap_too_high FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t14_test IMPLEMENTATION. + METHOD result_for. + ev_rework = iv_rework. + CALL FUNCTION '{{P}}PRD_SCRAP' + EXPORTING + iv_quantity = iv_quantity + iv_scrap = iv_scrap + IMPORTING + ev_scrap_pct = ev_pct + ev_severity = ev_severity + CHANGING + cv_rework_qty = ev_rework + EXCEPTIONS + invalid_quantity = 1 + scrap_too_high = 2 + OTHERS = 3. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + ENDMETHOD. + + METHOD percent_and_severity. + result_for( EXPORTING iv_quantity = 800 iv_scrap = 7 + IMPORTING ev_pct = DATA(lv_pct) ev_severity = DATA(lv_sev) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '0.9' ) act = lv_pct ). + cl_abap_unit_assert=>assert_equals( exp = `LOW` act = lv_sev ). + ENDMETHOD. + + METHOD severity_bands. + result_for( EXPORTING iv_quantity = 100 iv_scrap = 0 + IMPORTING ev_severity = DATA(lv_ok) ). + cl_abap_unit_assert=>assert_equals( exp = `OK` act = lv_ok ). + result_for( EXPORTING iv_quantity = 100 iv_scrap = 5 + IMPORTING ev_severity = DATA(lv_low) ). + cl_abap_unit_assert=>assert_equals( exp = `LOW` act = lv_low ). + result_for( EXPORTING iv_quantity = 100 iv_scrap = 20 + IMPORTING ev_severity = DATA(lv_high) ). + cl_abap_unit_assert=>assert_equals( exp = `HIGH` act = lv_high ). + result_for( EXPORTING iv_quantity = 100 iv_scrap = 21 + IMPORTING ev_severity = DATA(lv_crit) ). + cl_abap_unit_assert=>assert_equals( exp = `CRITICAL` act = lv_crit ). + ENDMETHOD. + + METHOD rework_quantity. + result_for( EXPORTING iv_quantity = 100 iv_scrap = 4 iv_rework = 99 + IMPORTING ev_rework = DATA(lv_keep) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 99 ) act = lv_keep ). + result_for( EXPORTING iv_quantity = 100 iv_scrap = 10 + IMPORTING ev_rework = DATA(lv_set) ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 10 ) act = lv_set ). + ENDMETHOD. + + METHOD invalid_inputs. + DATA lv_pct TYPE decfloat34. + DATA lv_rework TYPE decfloat34. + CALL FUNCTION '{{P}}PRD_SCRAP' + EXPORTING iv_quantity = 0 iv_scrap = 0 + IMPORTING ev_scrap_pct = lv_pct + CHANGING cv_rework_qty = lv_rework + EXCEPTIONS invalid_quantity = 1 OTHERS = 2. + cl_abap_unit_assert=>assert_equals( exp = 1 act = sy-subrc ). + ENDMETHOD. + + METHOD scrap_too_high. + DATA lv_pct TYPE decfloat34. + DATA lv_rework TYPE decfloat34. + CALL FUNCTION '{{P}}PRD_SCRAP' + EXPORTING iv_quantity = 100 iv_scrap = 101 + IMPORTING ev_scrap_pct = lv_pct + CHANGING cv_rework_qty = lv_rework + EXCEPTIONS scrap_too_high = 2 OTHERS = 1. + cl_abap_unit_assert=>assert_equals( exp = 2 act = sy-subrc ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0185/review.json b/tasks_gen/eval/G0185/review.json new file mode 100644 index 0000000..284713c --- /dev/null +++ b/tasks_gen/eval/G0185/review.json @@ -0,0 +1,7 @@ +{ + "decision": "accept", + "note": "FM interface must be read from sample; boundaries tested; fits F.", + "by": "Claude", + "date": "2026-10-03", + "failed_checks": {} +} \ No newline at end of file diff --git a/tasks_gen/eval/G0185/seed/prd_sample.func.abap b/tasks_gen/eval/G0185/seed/prd_sample.func.abap new file mode 100644 index 0000000..e28e96d --- /dev/null +++ b/tasks_gen/eval/G0185/seed/prd_sample.func.abap @@ -0,0 +1,18 @@ +FUNCTION {{p}}prd_sample + IMPORTING + iv_quantity TYPE decfloat34 + iv_scrap TYPE decfloat34 + EXPORTING + ev_scrap_pct TYPE decfloat34 + ev_severity TYPE string + CHANGING + cv_rework_qty TYPE decfloat34 + EXCEPTIONS + invalid_quantity + scrap_too_high. + + " Sample confirmation module. All confirmation modules use this interface. + ev_scrap_pct = 0. + ev_severity = 'OK'. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0185/spec.md b/tasks_gen/eval/G0185/spec.md new file mode 100644 index 0000000..cbe72a4 --- /dev/null +++ b/tasks_gen/eval/G0185/spec.md @@ -0,0 +1 @@ +Create function module {{P}}PRD_SCRAP in function group {{P}}FG_PROD. Use the interface of {{P}}PRD_SAMPLE: importing iv_quantity and iv_scrap, exporting ev_scrap_pct and ev_severity, changing cv_rework_qty. Use the same types and exceptions as {{P}}PRD_SAMPLE. If iv_quantity is less than or equal to 0, raise INVALID_QUANTITY. If iv_scrap is less than 0, raise INVALID_QUANTITY. If iv_scrap is greater than iv_quantity, raise SCRAP_TOO_HIGH. Calculate ev_scrap_pct as iv_scrap divided by iv_quantity, multiplied by 100. Round the result half up to 1 decimal. Set ev_severity from ev_scrap_pct: equal to 0 = OK; greater than 0 and less than or equal to 5 = LOW; greater than 5 and less than or equal to 20 = HIGH; greater than 20 = CRITICAL. If ev_severity is HIGH or CRITICAL, set cv_rework_qty to iv_scrap. Otherwise do not change cv_rework_qty. Release target is 7.58. Do not change {{P}}PRD_SAMPLE. Write ABAP Unit tests in a global test class. The function module must be active and have no syntax error. diff --git a/tasks_gen/eval/G0185/task.json b/tasks_gen/eval/G0185/task.json new file mode 100644 index 0000000..407f544 --- /dev/null +++ b/tasks_gen/eval/G0185/task.json @@ -0,0 +1,87 @@ +{ + "id": "G0185", + "category": "K", + "object_type": "FUNC", + "difficulty": 2, + "release_target": "v758", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [ + { + "type": "FUGR", + "name": "{{P}}FG_PROD", + "description": "Production confirmation modules" + }, + { + "type": "FUNC", + "name": "{{P}}PRD_SAMPLE", + "functionGroup": "{{P}}FG_PROD", + "file": "seed/prd_sample.func.abap", + "description": "Sample confirmation module" + } + ], + "contract": [ + { + "type": "FUNC", + "name": "{{P}}PRD_SCRAP", + "functionGroup": "{{P}}FG_PROD", + "params": [ + { + "name": "iv_quantity", + "type": "decfloat34" + }, + { + "name": "iv_scrap", + "type": "decfloat34" + }, + { + "name": "ev_scrap_pct", + "type": "decfloat34" + }, + { + "name": "ev_severity", + "type": "string" + }, + { + "name": "cv_rework_qty", + "type": "decfloat34" + } + ] + } + ], + "out_of_scope": [ + "{{P}}PRD_SAMPLE" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T14_HIDDEN", + "file": "hidden/t14_hidden.clas.abap", + "description": "T14 hidden tests" + } + ], + "reference": [ + { + "type": "FUNC", + "name": "{{P}}PRD_SCRAP", + "functionGroup": "{{P}}FG_PROD", + "file": "reference/prd_scrap.func.abap", + "description": "Scrap evaluation module" + }, + { + "type": "CLAS", + "name": "{{P}}T14_TEST", + "file": "reference/t14_test.clas.abap", + "description": "T14 own tests" + } + ], + "craft_checks": [ + "method_length" + ], + "base_task": "G0012", + "input_style": "incomplete", + "tool_schema": "generic_v0" +} \ No newline at end of file diff --git a/tasks_gen/eval/G0186/empirical.json b/tasks_gen/eval/G0186/empirical.json new file mode 100644 index 0000000..2ee23b1 --- /dev/null +++ b/tasks_gen/eval/G0186/empirical.json @@ -0,0 +1,18 @@ +{ + "deepseek-v4.1-flash:cloud": { + "score": 100.0, + "parts": { + "correctness": 40.0, + "craft": 20.0, + "clean": 15.0, + "own_tests": 15.0, + "discipline": 10.0, + "total": 100.0, + "note": "own_tests: faulty-reference part not implemented in skeleton" + }, + "hidden": "11/11", + "tool_calls": 13, + "seconds": 58.9, + "run_dir": "runs/emp/10001_G0003_llm_deepseek-v4.1-flash_cloud" + } +} \ No newline at end of file diff --git a/tasks_gen/eval/G0186/generation.json b/tasks_gen/eval/G0186/generation.json new file mode 100644 index 0000000..c4fa5de --- /dev/null +++ b/tasks_gen/eval/G0186/generation.json @@ -0,0 +1,16 @@ +{ + "id": "G0186", + "pool": "eval", + "category": "K", + "base_task": "G0003", + "style": "free_text", + "tool_schema": "generic_v0", + "attempts": [ + { + "stage": "validate", + "oracle": 100.0, + "null": 0 + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0186/hidden/t02_hidden.clas.abap b/tasks_gen/eval/G0186/hidden/t02_hidden.clas.abap new file mode 100644 index 0000000..1ee74fc --- /dev/null +++ b/tasks_gen/eval/G0186/hidden/t02_hidden.clas.abap @@ -0,0 +1,119 @@ +CLASS {{P}}T02_HIDDEN DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + CLASS-DATA mo_environment TYPE REF TO if_osql_test_environment. + DATA mo_cut TYPE REF TO {{P}}COURSE_BOOKING. + + CLASS-METHODS class_setup. + CLASS-METHODS class_teardown. + METHODS setup. + METHODS fill_test_data. + + METHODS free_seats_open_course FOR TESTING. + METHODS free_seats_never_neg FOR TESTING. + METHODS free_seats_unknown FOR TESTING. + METHODS bookable_exact_free FOR TESTING. + METHODS not_bookable_too_many FOR TESTING. + METHODS not_bookable_unknown FOR TESTING. + METHODS not_bookable_zero_seats FOR TESTING. + METHODS list_filter_cat_seats FOR TESTING. + METHODS list_sorted_by_course FOR TESTING. + METHODS list_empty_without_match FOR TESTING. + METHODS list_excludes_full FOR TESTING. +ENDCLASS. + + +CLASS {{P}}T02_HIDDEN IMPLEMENTATION. + METHOD class_setup. + mo_environment = cl_osql_test_environment=>create( VALUE #( ( '{{P}}COURSE' ) ) ). + ENDMETHOD. + + METHOD class_teardown. + mo_environment->destroy( ). + ENDMETHOD. + + METHOD setup. + mo_environment->clear_doubles( ). + fill_test_data( ). + mo_cut = NEW {{P}}COURSE_BOOKING( ). + ENDMETHOD. + + METHOD fill_test_data. + DATA lt_course TYPE STANDARD TABLE OF {{P}}COURSE WITH EMPTY KEY. + lt_course = VALUE #( + ( mandt = sy-mandt course_id = 'ABAP101' category = 'IT' title = 'ABAP Basics' capacity = 20 booked = 5 ) + ( mandt = sy-mandt course_id = 'ABAP102' category = 'IT' title = 'ABAP Advanced' capacity = 10 booked = 10 ) + ( mandt = sy-mandt course_id = 'ABAP103' category = 'IT' title = 'ABAP Expert' capacity = 12 booked = 15 ) + ( mandt = sy-mandt course_id = 'SQL101' category = 'DB' title = 'SQL Basics' capacity = 30 booked = 10 ) + ( mandt = sy-mandt course_id = 'SQL102' category = 'DB' title = 'SQL Tuning' capacity = 8 booked = 8 ) + ( mandt = sy-mandt course_id = 'HR101' category = 'HR' title = 'HR Basics' capacity = 6 booked = 1 ) ). + INSERT {{P}}COURSE FROM TABLE @lt_course. + ENDMETHOD. + + METHOD free_seats_open_course. + cl_abap_unit_assert=>assert_equals( exp = 15 + act = mo_cut->get_free_seats( 'ABAP101' ) + msg = 'ABAP101 must have 15 free seats' ). + ENDMETHOD. + + METHOD free_seats_never_neg. + cl_abap_unit_assert=>assert_equals( exp = 0 + act = mo_cut->get_free_seats( 'ABAP102' ) + msg = 'full course' ). + cl_abap_unit_assert=>assert_equals( exp = 0 + act = mo_cut->get_free_seats( 'ABAP103' ) + msg = 'overbooked course' ). + ENDMETHOD. + + METHOD free_seats_unknown. + cl_abap_unit_assert=>assert_equals( exp = 0 + act = mo_cut->get_free_seats( 'XX999' ) ). + ENDMETHOD. + + METHOD bookable_exact_free. + cl_abap_unit_assert=>assert_true( mo_cut->is_bookable( iv_course_id = 'SQL101' iv_seats = 20 ) ). + ENDMETHOD. + + METHOD not_bookable_too_many. + cl_abap_unit_assert=>assert_false( mo_cut->is_bookable( iv_course_id = 'SQL101' iv_seats = 21 ) ). + ENDMETHOD. + + METHOD not_bookable_unknown. + cl_abap_unit_assert=>assert_false( mo_cut->is_bookable( iv_course_id = 'XX999' iv_seats = 1 ) ). + ENDMETHOD. + + METHOD not_bookable_zero_seats. + cl_abap_unit_assert=>assert_false( mo_cut->is_bookable( iv_course_id = 'SQL101' iv_seats = 0 ) ). + cl_abap_unit_assert=>assert_false( mo_cut->is_bookable( iv_course_id = 'SQL101' iv_seats = -5 ) ). + ENDMETHOD. + + METHOD list_filter_cat_seats. + DATA(lt_result) = mo_cut->list_bookable_courses( iv_category = 'DB' iv_seats = 5 ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_result ) ). + cl_abap_unit_assert=>assert_equals( exp = 'SQL101' act = lt_result[ 1 ]-course_id ). + cl_abap_unit_assert=>assert_equals( exp = 'SQL Basics' act = lt_result[ 1 ]-title ). + cl_abap_unit_assert=>assert_equals( exp = 20 act = lt_result[ 1 ]-free_seats ). + ENDMETHOD. + + METHOD list_sorted_by_course. + DATA(lt_result) = mo_cut->list_bookable_courses( iv_category = 'IT' iv_seats = 0 ). + cl_abap_unit_assert=>assert_equals( exp = 3 act = lines( lt_result ) ). + cl_abap_unit_assert=>assert_equals( exp = 'ABAP101' act = lt_result[ 1 ]-course_id ). + cl_abap_unit_assert=>assert_equals( exp = 'ABAP102' act = lt_result[ 2 ]-course_id ). + cl_abap_unit_assert=>assert_equals( exp = 'ABAP103' act = lt_result[ 3 ]-course_id ). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lt_result[ 3 ]-free_seats ). + ENDMETHOD. + + METHOD list_empty_without_match. + DATA(lt_hr) = mo_cut->list_bookable_courses( iv_category = 'HR' iv_seats = 6 ). + cl_abap_unit_assert=>assert_initial( lt_hr ). + DATA(lt_unknown) = mo_cut->list_bookable_courses( iv_category = 'XX' iv_seats = 1 ). + cl_abap_unit_assert=>assert_initial( lt_unknown ). + ENDMETHOD. + + METHOD list_excludes_full. + DATA(lt_result) = mo_cut->list_bookable_courses( iv_category = 'IT' iv_seats = 1 ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_result ) ). + cl_abap_unit_assert=>assert_equals( exp = 'ABAP101' act = lt_result[ 1 ]-course_id ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0186/reference/course_booking.clas.abap b/tasks_gen/eval/G0186/reference/course_booking.clas.abap new file mode 100644 index 0000000..55d8f93 --- /dev/null +++ b/tasks_gen/eval/G0186/reference/course_booking.clas.abap @@ -0,0 +1,94 @@ +CLASS {{P}}COURSE_BOOKING DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + TYPES ty_course_id TYPE c LENGTH 10. + TYPES ty_category TYPE c LENGTH 10. + TYPES: + BEGIN OF ty_course_info, + course_id TYPE ty_course_id, + title TYPE c LENGTH 40, + free_seats TYPE i, + END OF ty_course_info. + TYPES tt_course_info TYPE STANDARD TABLE OF ty_course_info WITH EMPTY KEY. + + METHODS get_free_seats + IMPORTING iv_course_id TYPE ty_course_id + RETURNING VALUE(rv_free_seats) TYPE i. + + METHODS is_bookable + IMPORTING iv_course_id TYPE ty_course_id + iv_seats TYPE i + RETURNING VALUE(rv_bookable) TYPE abap_bool. + + METHODS list_bookable_courses + IMPORTING iv_category TYPE ty_category + iv_seats TYPE i + RETURNING VALUE(rt_courses) TYPE tt_course_info. + + PRIVATE SECTION. + TYPES: + BEGIN OF ty_course, + course_id TYPE ty_course_id, + title TYPE c LENGTH 40, + capacity TYPE i, + booked TYPE i, + END OF ty_course. + + METHODS read_course + IMPORTING iv_course_id TYPE ty_course_id + RETURNING VALUE(rs_course) TYPE ty_course. + + METHODS calculate_free_seats + IMPORTING is_course TYPE ty_course + RETURNING VALUE(rv_free) TYPE i. +ENDCLASS. + + +CLASS {{P}}COURSE_BOOKING IMPLEMENTATION. + METHOD get_free_seats. + rv_free_seats = calculate_free_seats( read_course( iv_course_id ) ). + ENDMETHOD. + + METHOD is_bookable. + IF iv_seats < 1. + rv_bookable = abap_false. + RETURN. + ENDIF. + rv_bookable = xsdbool( iv_seats <= calculate_free_seats( read_course( iv_course_id ) ) ). + ENDMETHOD. + + METHOD list_bookable_courses. + DATA lt_course TYPE STANDARD TABLE OF ty_course WITH EMPTY KEY. + + SELECT course_id, title, capacity, booked + FROM {{P}}COURSE + WHERE category = @iv_category + INTO TABLE @lt_course. + + LOOP AT lt_course INTO DATA(ls_course). + DATA(lv_free) = calculate_free_seats( ls_course ). + IF lv_free < iv_seats. + CONTINUE. + ENDIF. + rt_courses = VALUE #( BASE rt_courses + ( course_id = ls_course-course_id + title = ls_course-title + free_seats = lv_free ) ). + ENDLOOP. + + SORT rt_courses BY course_id. + ENDMETHOD. + + METHOD read_course. + SELECT SINGLE course_id, title, capacity, booked + FROM {{P}}COURSE + WHERE course_id = @iv_course_id + INTO @rs_course. + ENDMETHOD. + + METHOD calculate_free_seats. + rv_free = is_course-capacity - is_course-booked. + IF rv_free < 0. + rv_free = 0. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0186/reference/course_booking.testclasses.abap b/tasks_gen/eval/G0186/reference/course_booking.testclasses.abap new file mode 100644 index 0000000..1f754e1 --- /dev/null +++ b/tasks_gen/eval/G0186/reference/course_booking.testclasses.abap @@ -0,0 +1,63 @@ +CLASS ltc_course_booking DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + CLASS-DATA mo_environment TYPE REF TO if_osql_test_environment. + DATA mo_cut TYPE REF TO {{P}}COURSE_BOOKING. + + CLASS-METHODS class_setup. + CLASS-METHODS class_teardown. + METHODS setup. + METHODS fill_test_data. + + METHODS free_seats_open_course FOR TESTING. + METHODS free_seats_full_course FOR TESTING. + METHODS bookable_enough_seats FOR TESTING. + METHODS not_bookable_full FOR TESTING. + METHODS list_matching_courses FOR TESTING. +ENDCLASS. + + +CLASS ltc_course_booking IMPLEMENTATION. + METHOD class_setup. + mo_environment = cl_osql_test_environment=>create( VALUE #( ( '{{P}}COURSE' ) ) ). + ENDMETHOD. + + METHOD class_teardown. + mo_environment->destroy( ). + ENDMETHOD. + + METHOD setup. + mo_environment->clear_doubles( ). + fill_test_data( ). + mo_cut = NEW {{P}}COURSE_BOOKING( ). + ENDMETHOD. + + METHOD fill_test_data. + DATA lt_course TYPE STANDARD TABLE OF {{P}}COURSE WITH EMPTY KEY. + lt_course = VALUE #( + ( mandt = sy-mandt course_id = 'ABAP101' category = 'IT' title = 'ABAP Basics' capacity = 20 booked = 5 ) + ( mandt = sy-mandt course_id = 'SQL101' category = 'DB' title = 'SQL Basics' capacity = 30 booked = 30 ) ). + INSERT {{P}}COURSE FROM TABLE @lt_course. + ENDMETHOD. + + METHOD free_seats_open_course. + cl_abap_unit_assert=>assert_equals( exp = 15 act = mo_cut->get_free_seats( 'ABAP101' ) ). + ENDMETHOD. + + METHOD free_seats_full_course. + cl_abap_unit_assert=>assert_equals( exp = 0 act = mo_cut->get_free_seats( 'SQL101' ) ). + ENDMETHOD. + + METHOD bookable_enough_seats. + cl_abap_unit_assert=>assert_true( mo_cut->is_bookable( iv_course_id = 'ABAP101' iv_seats = 10 ) ). + ENDMETHOD. + + METHOD not_bookable_full. + cl_abap_unit_assert=>assert_false( mo_cut->is_bookable( iv_course_id = 'SQL101' iv_seats = 1 ) ). + ENDMETHOD. + + METHOD list_matching_courses. + DATA(lt_result) = mo_cut->list_bookable_courses( iv_category = 'IT' iv_seats = 1 ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_result ) ). + cl_abap_unit_assert=>assert_equals( exp = 'ABAP101' act = lt_result[ 1 ]-course_id ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0186/review.json b/tasks_gen/eval/G0186/review.json new file mode 100644 index 0000000..d4580cb --- /dev/null +++ b/tasks_gen/eval/G0186/review.json @@ -0,0 +1,7 @@ +{ + "decision": "accept", + "note": "Rules map to tests; mutation 5/5.", + "by": "Claude", + "date": "2026-10-03", + "failed_checks": {} +} \ No newline at end of file diff --git a/tasks_gen/eval/G0186/seed/course.tabl.asddls b/tasks_gen/eval/G0186/seed/course.tabl.asddls new file mode 100644 index 0000000..a7fd505 --- /dev/null +++ b/tasks_gen/eval/G0186/seed/course.tabl.asddls @@ -0,0 +1,13 @@ +@EndUserText.label : 'Training courses' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{P}}COURSE { + key mandt : abap.clnt not null; + key course_id : abap.char(10) not null; + category : abap.char(10); + title : abap.char(40); + capacity : abap.int4; + booked : abap.int4; +} diff --git a/tasks_gen/eval/G0186/seed/seed_courses.clas.abap b/tasks_gen/eval/G0186/seed/seed_courses.clas.abap new file mode 100644 index 0000000..8ed1223 --- /dev/null +++ b/tasks_gen/eval/G0186/seed/seed_courses.clas.abap @@ -0,0 +1,24 @@ +CLASS {{P}}SEED_COURSES DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES if_oo_adt_classrun. +ENDCLASS. + + +CLASS {{P}}SEED_COURSES IMPLEMENTATION. + METHOD if_oo_adt_classrun~main. + DELETE FROM {{P}}COURSE. + + DATA lt_course TYPE STANDARD TABLE OF {{P}}COURSE WITH EMPTY KEY. + lt_course = VALUE #( + ( mandt = sy-mandt course_id = 'ABAP101' category = 'IT' title = 'ABAP Basics' capacity = 20 booked = 5 ) + ( mandt = sy-mandt course_id = 'ABAP102' category = 'IT' title = 'ABAP Advanced' capacity = 10 booked = 10 ) + ( mandt = sy-mandt course_id = 'ABAP103' category = 'IT' title = 'ABAP Expert' capacity = 12 booked = 15 ) + ( mandt = sy-mandt course_id = 'SQL101' category = 'DB' title = 'SQL Basics' capacity = 30 booked = 10 ) + ( mandt = sy-mandt course_id = 'SQL102' category = 'DB' title = 'SQL Tuning' capacity = 8 booked = 8 ) + ( mandt = sy-mandt course_id = 'HR101' category = 'HR' title = 'HR Basics' capacity = 6 booked = 1 ) ). + + INSERT {{P}}COURSE FROM TABLE @lt_course. + + out->write( |Courses written: { sy-dbcnt }| ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0186/spec.md b/tasks_gen/eval/G0186/spec.md new file mode 100644 index 0000000..b3f1c64 --- /dev/null +++ b/tasks_gen/eval/G0186/spec.md @@ -0,0 +1,15 @@ +Hello, please create the class {{P}}COURSE_BOOKING in package $TMP. The class is public, final, and has a public constructor without parameters. The class has these public types. TY_COURSE_ID has type C and length 10. TY_CATEGORY has type C and length 10. TY_COURSE_INFO is a structure with components COURSE_ID type TY_COURSE_ID, TITLE type C length 40, and FREE_SEATS type I. TT_COURSE_INFO is a standard table of TY_COURSE_INFO with an empty key. The class has these public methods. GET_FREE_SEATS imports IV_COURSE_ID type TY_COURSE_ID and returns RV_FREE_SEATS type I. IS_BOOKABLE imports IV_COURSE_ID type TY_COURSE_ID and IV_SEATS type I and returns RV_BOOKABLE type ABAP_BOOL. LIST_BOOKABLE_COURSES imports IV_CATEGORY type TY_CATEGORY and IV_SEATS type I and returns RT_COURSES type TT_COURSE_INFO. Do not add other public methods. + +The database table {{P}}COURSE exists in package $TMP. It has columns MANDT (client), COURSE_ID (CHAR 10, key), CATEGORY (CHAR 10), TITLE (CHAR 40), CAPACITY (INT4), and BOOKED (INT4). CAPACITY is the number of seats of the course. BOOKED is the number of seats that are already sold. The class {{P}}SEED_COURSES fills the table with example data. It is active. + +The booking program needs one service that answers three questions. How many seats are free in a course? Can we book a given number of seats in a course? Which courses of a category still have enough free seats? There are no open questions. + +When you calculate free seats, read the course with the course ID. If the table has no course with this ID, the free seats are 0. The free seats are the capacity minus the booked seats. If the capacity minus the booked seats is less than 0, the free seats are 0. GET_FREE_SEATS returns the free seats of the course. + +When you check IS_BOOKABLE, if IV_SEATS is less than 1, the result is false. If the table has no course with this ID, the result is false. The result is true if IV_SEATS is less than or equal to the free seats of the course. Else the result is false. + +When you list bookable courses, read all courses with the category IV_CATEGORY. Use only the courses whose free seats are greater than or equal to IV_SEATS. Sort the result in ascending order by COURSE_ID. Each result row has the COURSE_ID, the TITLE and the free seats of the course. If no course matches, the result is empty. + +The release target is 8.16. Use Clean ABAP coding standards. Keep each method below 40 statements. Do not use global variables. Do not write a comment that restates the code. Do not change the table {{P}}COURSE and the class {{P}}SEED_COURSES. + +The class must be active and have no syntax error. The hidden tests must pass. Write your own ABAP Unit tests for the class. diff --git a/tasks_gen/eval/G0186/task.json b/tasks_gen/eval/G0186/task.json new file mode 100644 index 0000000..c8135bc --- /dev/null +++ b/tasks_gen/eval/G0186/task.json @@ -0,0 +1,61 @@ +{ + "id": "G0186", + "category": "K", + "object_type": "CLAS", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [ + { + "type": "TABL", + "name": "{{P}}COURSE", + "file": "seed/course.tabl.asddls", + "description": "Training course table with capacity and booked seats" + }, + { + "type": "CLAS", + "name": "{{P}}SEED_COURSES", + "file": "seed/seed_courses.clas.abap", + "description": "Fills the course table with example data", + "run": true + } + ], + "contract": [ + { + "type": "CLAS", + "name": "{{P}}COURSE_BOOKING" + } + ], + "out_of_scope": [ + "{{P}}COURSE", + "{{P}}SEED_COURSES" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T02_HIDDEN", + "file": "hidden/t02_hidden.clas.abap", + "description": "T02 hidden tests" + } + ], + "reference": [ + { + "type": "CLAS", + "name": "{{P}}COURSE_BOOKING", + "file": "reference/course_booking.clas.abap", + "description": "Course booking service", + "testclasses_file": "reference/course_booking.testclasses.abap" + } + ], + "craft_checks": [ + "method_length", + "db_operation_in_loop" + ], + "base_task": "G0003", + "input_style": "free_text", + "tool_schema": "generic_v0" +} \ No newline at end of file diff --git a/tasks_gen/eval/G0187/empirical.json b/tasks_gen/eval/G0187/empirical.json new file mode 100644 index 0000000..e356633 --- /dev/null +++ b/tasks_gen/eval/G0187/empirical.json @@ -0,0 +1,18 @@ +{ + "deepseek-v4.1-flash:cloud": { + "score": 95.0, + "parts": { + "correctness": 40.0, + "craft": 20.0, + "clean": 15.0, + "own_tests": 15.0, + "discipline": 5.0, + "total": 95.0, + "note": "own_tests: faulty-reference part not implemented in skeleton" + }, + "hidden": "12/12", + "tool_calls": 16, + "seconds": 116.4, + "run_dir": "runs/emp/10005_G0010_llm_deepseek-v4.1-flash_cloud" + } +} \ No newline at end of file diff --git a/tasks_gen/eval/G0187/generation.json b/tasks_gen/eval/G0187/generation.json new file mode 100644 index 0000000..0344a47 --- /dev/null +++ b/tasks_gen/eval/G0187/generation.json @@ -0,0 +1,16 @@ +{ + "id": "G0187", + "pool": "eval", + "category": "K", + "base_task": "G0010", + "style": "incomplete", + "tool_schema": "generic_v0", + "attempts": [ + { + "stage": "validate", + "oracle": 100.0, + "null": 0 + } + ], + "accepted": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0187/hidden/t02_hidden.clas.abap b/tasks_gen/eval/G0187/hidden/t02_hidden.clas.abap new file mode 100644 index 0000000..84fe7c9 --- /dev/null +++ b/tasks_gen/eval/G0187/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. + PRIVATE SECTION. + DATA mo_cut TYPE REF TO {{p}}if_stock_cover. + METHODS setup. + METHODS all_ok FOR TESTING. + METHODS shortage_is_reported FOR TESTING. + METHODS stock_used_in_order FOR TESTING. + METHODS negative_stock_ignored FOR TESTING. + METHODS zero_requirement_invalid FOR TESTING. + METHODS negative_req_invalid FOR TESTING. + METHODS missing_stock_is_short FOR TESTING. + METHODS case_and_blanks_ignored FOR TESTING. + METHODS stock_items_are_summed FOR TESTING. + METHODS no_requirements FOR TESTING. + METHODS shortages_filter_sort FOR TESTING. + METHODS shortages_empty_all_ok FOR TESTING. +ENDCLASS. + + +CLASS {{p}}t02_hidden IMPLEMENTATION. + METHOD setup. + mo_cut = NEW {{p}}stock_cover_checker( ). + ENDMETHOD. + + METHOD all_ok. + DATA(lt_stock) = VALUE {{p}}if_stock_cover=>tt_stock_item( + ( material = 'MAT-A' plant = 'P1' quantity = 100 ) + ( material = 'MAT-B' plant = 'P1' quantity = 50 ) ). + DATA(lt_req) = VALUE {{p}}if_stock_cover=>tt_requirement( + ( material = 'MAT-A' plant = 'P1' required = 30 ) + ( material = 'MAT-B' plant = 'P1' required = 50 ) ). + DATA(lt_exp) = VALUE {{p}}if_stock_cover=>tt_result( + ( material = 'MAT-A' plant = 'P1' required = 30 available = 100 shortage = 0 status = 'OK' ) + ( material = 'MAT-B' plant = 'P1' required = 50 available = 50 shortage = 0 status = 'OK' ) ). + cl_abap_unit_assert=>assert_equals( + exp = lt_exp + act = mo_cut->check( it_stock = lt_stock it_requirement = lt_req ) ). + ENDMETHOD. + + METHOD shortage_is_reported. + DATA(lt_stock) = VALUE {{p}}if_stock_cover=>tt_stock_item( + ( material = 'MAT-A' plant = 'P1' quantity = 30 ) ). + DATA(lt_req) = VALUE {{p}}if_stock_cover=>tt_requirement( + ( material = 'MAT-A' plant = 'P1' required = 50 ) ). + DATA(lt_exp) = VALUE {{p}}if_stock_cover=>tt_result( + ( material = 'MAT-A' plant = 'P1' required = 50 available = 30 shortage = 20 status = 'SHORT' ) ). + cl_abap_unit_assert=>assert_equals( + exp = lt_exp + act = mo_cut->check( it_stock = lt_stock it_requirement = lt_req ) ). + ENDMETHOD. + + METHOD stock_used_in_order. + DATA(lt_stock) = VALUE {{p}}if_stock_cover=>tt_stock_item( + ( material = 'MAT-A' plant = 'P1' quantity = 100 ) ). + DATA(lt_req) = VALUE {{p}}if_stock_cover=>tt_requirement( + ( material = 'MAT-A' plant = 'P1' required = 60 ) + ( material = 'MAT-A' plant = 'P1' required = 60 ) ). + DATA(lt_exp) = VALUE {{p}}if_stock_cover=>tt_result( + ( material = 'MAT-A' plant = 'P1' required = 60 available = 100 shortage = 0 status = 'OK' ) + ( material = 'MAT-A' plant = 'P1' required = 60 available = 40 shortage = 20 status = 'SHORT' ) ). + cl_abap_unit_assert=>assert_equals( + exp = lt_exp + act = mo_cut->check( it_stock = lt_stock it_requirement = lt_req ) ). + ENDMETHOD. + + METHOD negative_stock_ignored. + DATA(lt_stock) = VALUE {{p}}if_stock_cover=>tt_stock_item( + ( material = 'MAT-A' plant = 'P1' quantity = 100 ) + ( material = 'MAT-A' plant = 'P1' quantity = -40 ) ). + DATA(lt_req) = VALUE {{p}}if_stock_cover=>tt_requirement( + ( material = 'MAT-A' plant = 'P1' required = 100 ) ). + DATA(lt_exp) = VALUE {{p}}if_stock_cover=>tt_result( + ( material = 'MAT-A' plant = 'P1' required = 100 available = 100 shortage = 0 status = 'OK' ) ). + cl_abap_unit_assert=>assert_equals( + exp = lt_exp + act = mo_cut->check( it_stock = lt_stock it_requirement = lt_req ) ). + ENDMETHOD. + + METHOD zero_requirement_invalid. + DATA(lt_stock) = VALUE {{p}}if_stock_cover=>tt_stock_item( + ( material = 'MAT-A' plant = 'P1' quantity = 50 ) ). + DATA(lt_req) = VALUE {{p}}if_stock_cover=>tt_requirement( + ( material = 'MAT-A' plant = 'P1' required = 0 ) + ( material = 'MAT-A' plant = 'P1' required = 50 ) ). + DATA(lt_exp) = VALUE {{p}}if_stock_cover=>tt_result( + ( material = 'MAT-A' plant = 'P1' required = 0 available = 50 shortage = 0 status = 'INVALID' ) + ( material = 'MAT-A' plant = 'P1' required = 50 available = 50 shortage = 0 status = 'OK' ) ). + cl_abap_unit_assert=>assert_equals( + exp = lt_exp + act = mo_cut->check( it_stock = lt_stock it_requirement = lt_req ) ). + ENDMETHOD. + + METHOD negative_req_invalid. + DATA(lt_stock) = VALUE {{p}}if_stock_cover=>tt_stock_item( + ( material = 'MAT-A' plant = 'P1' quantity = 50 ) ). + DATA(lt_req) = VALUE {{p}}if_stock_cover=>tt_requirement( + ( material = 'MAT-A' plant = 'P1' required = -10 ) ). + DATA(lt_exp) = VALUE {{p}}if_stock_cover=>tt_result( + ( material = 'MAT-A' plant = 'P1' required = -10 available = 50 shortage = 0 status = 'INVALID' ) ). + cl_abap_unit_assert=>assert_equals( + exp = lt_exp + act = mo_cut->check( it_stock = lt_stock it_requirement = lt_req ) ). + ENDMETHOD. + + METHOD missing_stock_is_short. + DATA(lt_stock) = VALUE {{p}}if_stock_cover=>tt_stock_item( ). + DATA(lt_req) = VALUE {{p}}if_stock_cover=>tt_requirement( + ( material = 'MAT-X' plant = 'P9' required = 25 ) ). + DATA(lt_exp) = VALUE {{p}}if_stock_cover=>tt_result( + ( material = 'MAT-X' plant = 'P9' required = 25 available = 0 shortage = 25 status = 'SHORT' ) ). + cl_abap_unit_assert=>assert_equals( + exp = lt_exp + act = mo_cut->check( it_stock = lt_stock it_requirement = lt_req ) ). + ENDMETHOD. + + METHOD case_and_blanks_ignored. + DATA(lt_stock) = VALUE {{p}}if_stock_cover=>tt_stock_item( + ( material = 'mat-a' plant = 'p1' quantity = 80 ) ). + DATA(lt_req) = VALUE {{p}}if_stock_cover=>tt_requirement( + ( material = ' MAT-A ' plant = 'P1 ' required = 80 ) ). + DATA(lt_exp) = VALUE {{p}}if_stock_cover=>tt_result( + ( material = ' MAT-A ' plant = 'P1 ' required = 80 available = 80 shortage = 0 status = 'OK' ) ). + cl_abap_unit_assert=>assert_equals( + exp = lt_exp + act = mo_cut->check( it_stock = lt_stock it_requirement = lt_req ) ). + ENDMETHOD. + + METHOD stock_items_are_summed. + DATA(lt_stock) = VALUE {{p}}if_stock_cover=>tt_stock_item( + ( material = 'MAT-A' plant = 'P1' quantity = 10 ) + ( material = 'MAT-A' plant = 'P1' quantity = 20 ) + ( material = 'MAT-A' plant = 'P2' quantity = 5 ) ). + DATA(lt_req) = VALUE {{p}}if_stock_cover=>tt_requirement( + ( material = 'MAT-A' plant = 'P1' required = 30 ) + ( material = 'MAT-A' plant = 'P2' required = 5 ) ). + DATA(lt_exp) = VALUE {{p}}if_stock_cover=>tt_result( + ( material = 'MAT-A' plant = 'P1' required = 30 available = 30 shortage = 0 status = 'OK' ) + ( material = 'MAT-A' plant = 'P2' required = 5 available = 5 shortage = 0 status = 'OK' ) ). + cl_abap_unit_assert=>assert_equals( + exp = lt_exp + act = mo_cut->check( it_stock = lt_stock it_requirement = lt_req ) ). + ENDMETHOD. + + METHOD no_requirements. + DATA(lt_stock) = VALUE {{p}}if_stock_cover=>tt_stock_item( + ( material = 'MAT-A' plant = 'P1' quantity = 10 ) ). + DATA(lt_req) = VALUE {{p}}if_stock_cover=>tt_requirement( ). + DATA(lt_act) = mo_cut->check( it_stock = lt_stock it_requirement = lt_req ). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lines( lt_act ) ). + ENDMETHOD. + + METHOD shortages_filter_sort. + DATA(lt_in) = VALUE {{p}}if_stock_cover=>tt_result( + ( material = 'MAT-C' plant = 'P1' required = 10 available = 0 shortage = 10 status = 'SHORT' ) + ( material = 'MAT-A' plant = 'P2' required = 10 available = 0 shortage = 10 status = 'SHORT' ) + ( material = 'MAT-B' plant = 'P1' required = 10 available = 10 shortage = 0 status = 'OK' ) + ( material = 'MAT-A' plant = 'P1' required = 10 available = 0 shortage = 10 status = 'SHORT' ) + ( material = 'MAT-D' plant = 'P1' required = 10 available = 10 shortage = 0 status = 'INVALID' ) ). + DATA(lt_exp) = VALUE {{p}}if_stock_cover=>tt_result( + ( material = 'MAT-A' plant = 'P1' required = 10 available = 0 shortage = 10 status = 'SHORT' ) + ( material = 'MAT-A' plant = 'P2' required = 10 available = 0 shortage = 10 status = 'SHORT' ) + ( material = 'MAT-C' plant = 'P1' required = 10 available = 0 shortage = 10 status = 'SHORT' ) ). + cl_abap_unit_assert=>assert_equals( exp = lt_exp act = mo_cut->shortages( lt_in ) ). + ENDMETHOD. + + METHOD shortages_empty_all_ok. + DATA(lt_in) = VALUE {{p}}if_stock_cover=>tt_result( + ( material = 'MAT-A' plant = 'P1' required = 10 available = 10 shortage = 0 status = 'OK' ) + ( material = 'MAT-B' plant = 'P1' required = 10 available = 10 shortage = 0 status = 'INVALID' ) ). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lines( mo_cut->shortages( lt_in ) ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0187/reference/stock_cover_checker.clas.abap b/tasks_gen/eval/G0187/reference/stock_cover_checker.clas.abap new file mode 100644 index 0000000..5274b49 --- /dev/null +++ b/tasks_gen/eval/G0187/reference/stock_cover_checker.clas.abap @@ -0,0 +1,128 @@ +CLASS {{p}}stock_cover_checker DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_stock_cover. + + PRIVATE SECTION. + TYPES: + BEGIN OF ty_stock, + material TYPE {{p}}if_stock_cover=>ty_material, + plant TYPE {{p}}if_stock_cover=>ty_plant, + remaining TYPE {{p}}if_stock_cover=>ty_quantity, + END OF ty_stock. + TYPES tt_stock TYPE HASHED TABLE OF ty_stock WITH UNIQUE KEY material plant. + + METHODS aggregate + IMPORTING it_stock TYPE {{p}}if_stock_cover=>tt_stock_item + RETURNING VALUE(rt_stock) TYPE tt_stock. + + METHODS free_quantity + IMPORTING it_stock TYPE tt_stock + iv_material TYPE {{p}}if_stock_cover=>ty_material + iv_plant TYPE {{p}}if_stock_cover=>ty_plant + RETURNING VALUE(rv_quantity) TYPE {{p}}if_stock_cover=>ty_quantity. + + METHODS consume + IMPORTING iv_material TYPE {{p}}if_stock_cover=>ty_material + iv_plant TYPE {{p}}if_stock_cover=>ty_plant + iv_quantity TYPE {{p}}if_stock_cover=>ty_quantity + CHANGING ct_stock TYPE tt_stock. + + METHODS normalize_material + IMPORTING iv_material TYPE {{p}}if_stock_cover=>ty_material + RETURNING VALUE(rv_material) TYPE {{p}}if_stock_cover=>ty_material. + + METHODS normalize_plant + IMPORTING iv_plant TYPE {{p}}if_stock_cover=>ty_plant + RETURNING VALUE(rv_plant) TYPE {{p}}if_stock_cover=>ty_plant. +ENDCLASS. + + +CLASS {{p}}stock_cover_checker IMPLEMENTATION. + METHOD {{p}}if_stock_cover~check. + DATA(lt_stock) = aggregate( it_stock ). + + LOOP AT it_requirement INTO DATA(ls_requirement). + DATA(lv_free) = free_quantity( it_stock = lt_stock + iv_material = ls_requirement-material + iv_plant = ls_requirement-plant ). + DATA(ls_result) = VALUE {{p}}if_stock_cover=>ty_result( + material = ls_requirement-material + plant = ls_requirement-plant + required = ls_requirement-required + available = lv_free ). + + IF ls_requirement-required <= 0. + ls_result-status = {{p}}if_stock_cover=>c_status-invalid. + ELSEIF lv_free >= ls_requirement-required. + ls_result-status = {{p}}if_stock_cover=>c_status-ok. + consume( EXPORTING iv_material = ls_requirement-material + iv_plant = ls_requirement-plant + iv_quantity = ls_requirement-required + CHANGING ct_stock = lt_stock ). + ELSE. + ls_result-status = {{p}}if_stock_cover=>c_status-short. + ls_result-shortage = ls_requirement-required - lv_free. + consume( EXPORTING iv_material = ls_requirement-material + iv_plant = ls_requirement-plant + iv_quantity = lv_free + CHANGING ct_stock = lt_stock ). + ENDIF. + + APPEND ls_result TO rt_result. + ENDLOOP. + ENDMETHOD. + + METHOD {{p}}if_stock_cover~shortages. + rt_shortage = it_result. + DELETE rt_shortage WHERE status <> {{p}}if_stock_cover=>c_status-short. + SORT rt_shortage BY material plant. + ENDMETHOD. + + METHOD aggregate. + LOOP AT it_stock INTO DATA(ls_stock). + IF ls_stock-quantity < 0. + CONTINUE. + ENDIF. + DATA(lv_material) = normalize_material( ls_stock-material ). + DATA(lv_plant) = normalize_plant( ls_stock-plant ). + ASSIGN rt_stock[ material = lv_material plant = lv_plant ] TO FIELD-SYMBOL(). + IF sy-subrc = 0. + -remaining = -remaining + ls_stock-quantity. + ELSE. + INSERT VALUE #( material = lv_material + plant = lv_plant + remaining = ls_stock-quantity ) INTO TABLE rt_stock. + ENDIF. + ENDLOOP. + ENDMETHOD. + + METHOD free_quantity. + ASSIGN it_stock[ material = normalize_material( iv_material ) + plant = normalize_plant( iv_plant ) ] TO FIELD-SYMBOL(). + IF sy-subrc = 0. + rv_quantity = -remaining. + ENDIF. + ENDMETHOD. + + METHOD consume. + ASSIGN ct_stock[ material = normalize_material( iv_material ) + plant = normalize_plant( iv_plant ) ] TO FIELD-SYMBOL(). + IF sy-subrc = 0. + -remaining = -remaining - iv_quantity. + ENDIF. + ENDMETHOD. + + METHOD normalize_material. + DATA lv_text TYPE string. + lv_text = iv_material. + REPLACE ALL OCCURRENCES OF ` ` IN lv_text WITH ``. + rv_material = to_upper( lv_text ). + ENDMETHOD. + + METHOD normalize_plant. + DATA lv_text TYPE string. + lv_text = iv_plant. + REPLACE ALL OCCURRENCES OF ` ` IN lv_text WITH ``. + rv_plant = to_upper( lv_text ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0187/reference/stock_cover_checker.testclasses.abap b/tasks_gen/eval/G0187/reference/stock_cover_checker.testclasses.abap new file mode 100644 index 0000000..b8096a0 --- /dev/null +++ b/tasks_gen/eval/G0187/reference/stock_cover_checker.testclasses.abap @@ -0,0 +1,93 @@ +CLASS ltc_stock_cover DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + DATA mo_cut TYPE REF TO {{p}}if_stock_cover. + METHODS setup. + METHODS covered_req_is_ok FOR TESTING. + METHODS shortage_is_reported FOR TESTING. + METHODS stock_shared_in_order FOR TESTING. + METHODS invalid_req_keeps_stock FOR TESTING. + METHODS blanks_and_case_ignored FOR TESTING. + METHODS shortages_are_sorted FOR TESTING. +ENDCLASS. + + +CLASS ltc_stock_cover IMPLEMENTATION. + METHOD setup. + mo_cut = NEW {{p}}stock_cover_checker( ). + ENDMETHOD. + + METHOD covered_req_is_ok. + DATA(lt_stock) = VALUE {{p}}if_stock_cover=>tt_stock_item( + ( material = 'MAT-A' plant = 'P1' quantity = 40 ) ). + DATA(lt_req) = VALUE {{p}}if_stock_cover=>tt_requirement( + ( material = 'MAT-A' plant = 'P1' required = 40 ) ). + DATA(lt_exp) = VALUE {{p}}if_stock_cover=>tt_result( + ( material = 'MAT-A' plant = 'P1' required = 40 available = 40 shortage = 0 status = 'OK' ) ). + cl_abap_unit_assert=>assert_equals( + exp = lt_exp + act = mo_cut->check( it_stock = lt_stock it_requirement = lt_req ) ). + ENDMETHOD. + + METHOD shortage_is_reported. + DATA(lt_stock) = VALUE {{p}}if_stock_cover=>tt_stock_item( + ( material = 'MAT-A' plant = 'P1' quantity = 5 ) ). + DATA(lt_req) = VALUE {{p}}if_stock_cover=>tt_requirement( + ( material = 'MAT-A' plant = 'P1' required = 12 ) ). + DATA(lt_exp) = VALUE {{p}}if_stock_cover=>tt_result( + ( material = 'MAT-A' plant = 'P1' required = 12 available = 5 shortage = 7 status = 'SHORT' ) ). + cl_abap_unit_assert=>assert_equals( + exp = lt_exp + act = mo_cut->check( it_stock = lt_stock it_requirement = lt_req ) ). + ENDMETHOD. + + METHOD stock_shared_in_order. + DATA(lt_stock) = VALUE {{p}}if_stock_cover=>tt_stock_item( + ( material = 'MAT-A' plant = 'P1' quantity = 10 ) ). + DATA(lt_req) = VALUE {{p}}if_stock_cover=>tt_requirement( + ( material = 'MAT-A' plant = 'P1' required = 6 ) + ( material = 'MAT-A' plant = 'P1' required = 6 ) ). + DATA(lt_exp) = VALUE {{p}}if_stock_cover=>tt_result( + ( material = 'MAT-A' plant = 'P1' required = 6 available = 10 shortage = 0 status = 'OK' ) + ( material = 'MAT-A' plant = 'P1' required = 6 available = 4 shortage = 2 status = 'SHORT' ) ). + cl_abap_unit_assert=>assert_equals( + exp = lt_exp + act = mo_cut->check( it_stock = lt_stock it_requirement = lt_req ) ). + ENDMETHOD. + + METHOD invalid_req_keeps_stock. + DATA(lt_stock) = VALUE {{p}}if_stock_cover=>tt_stock_item( + ( material = 'MAT-A' plant = 'P1' quantity = 9 ) ). + DATA(lt_req) = VALUE {{p}}if_stock_cover=>tt_requirement( + ( material = 'MAT-A' plant = 'P1' required = 0 ) + ( material = 'MAT-A' plant = 'P1' required = 9 ) ). + DATA(lt_exp) = VALUE {{p}}if_stock_cover=>tt_result( + ( material = 'MAT-A' plant = 'P1' required = 0 available = 9 shortage = 0 status = 'INVALID' ) + ( material = 'MAT-A' plant = 'P1' required = 9 available = 9 shortage = 0 status = 'OK' ) ). + cl_abap_unit_assert=>assert_equals( + exp = lt_exp + act = mo_cut->check( it_stock = lt_stock it_requirement = lt_req ) ). + ENDMETHOD. + + METHOD blanks_and_case_ignored. + DATA(lt_stock) = VALUE {{p}}if_stock_cover=>tt_stock_item( + ( material = 'mat-a' plant = 'p1' quantity = 7 ) ). + DATA(lt_req) = VALUE {{p}}if_stock_cover=>tt_requirement( + ( material = ' MAT-A ' plant = 'P1' required = 7 ) ). + DATA(lt_exp) = VALUE {{p}}if_stock_cover=>tt_result( + ( material = ' MAT-A ' plant = 'P1' required = 7 available = 7 shortage = 0 status = 'OK' ) ). + cl_abap_unit_assert=>assert_equals( + exp = lt_exp + act = mo_cut->check( it_stock = lt_stock it_requirement = lt_req ) ). + ENDMETHOD. + + METHOD shortages_are_sorted. + DATA(lt_in) = VALUE {{p}}if_stock_cover=>tt_result( + ( material = 'MAT-B' plant = 'P1' required = 1 available = 0 shortage = 1 status = 'SHORT' ) + ( material = 'MAT-A' plant = 'P2' required = 1 available = 0 shortage = 1 status = 'SHORT' ) + ( material = 'MAT-A' plant = 'P1' required = 1 available = 1 shortage = 0 status = 'OK' ) ). + DATA(lt_exp) = VALUE {{p}}if_stock_cover=>tt_result( + ( material = 'MAT-A' plant = 'P2' required = 1 available = 0 shortage = 1 status = 'SHORT' ) + ( material = 'MAT-B' plant = 'P1' required = 1 available = 0 shortage = 1 status = 'SHORT' ) ). + cl_abap_unit_assert=>assert_equals( exp = lt_exp act = mo_cut->shortages( lt_in ) ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0187/review.json b/tasks_gen/eval/G0187/review.json new file mode 100644 index 0000000..401e86e --- /dev/null +++ b/tasks_gen/eval/G0187/review.json @@ -0,0 +1,7 @@ +{ + "decision": "accept", + "note": "Ordered stock use, case/blank rules tested; fits C.", + "by": "Claude", + "date": "2026-10-03", + "failed_checks": {} +} \ No newline at end of file diff --git a/tasks_gen/eval/G0187/seed/if_stock_cover.intf.abap b/tasks_gen/eval/G0187/seed/if_stock_cover.intf.abap new file mode 100644 index 0000000..7655f63 --- /dev/null +++ b/tasks_gen/eval/G0187/seed/if_stock_cover.intf.abap @@ -0,0 +1,46 @@ +INTERFACE {{p}}if_stock_cover PUBLIC. + TYPES ty_material TYPE c LENGTH 18. + TYPES ty_plant TYPE c LENGTH 4. + TYPES ty_quantity TYPE p LENGTH 13 DECIMALS 3. + TYPES ty_status TYPE c LENGTH 10. + + TYPES: BEGIN OF ty_stock_item, + material TYPE ty_material, + plant TYPE ty_plant, + quantity TYPE ty_quantity, + END OF ty_stock_item. + TYPES tt_stock_item TYPE STANDARD TABLE OF ty_stock_item WITH EMPTY KEY. + + TYPES: BEGIN OF ty_requirement, + material TYPE ty_material, + plant TYPE ty_plant, + required TYPE ty_quantity, + END OF ty_requirement. + TYPES tt_requirement TYPE STANDARD TABLE OF ty_requirement WITH EMPTY KEY. + + TYPES: BEGIN OF ty_result, + material TYPE ty_material, + plant TYPE ty_plant, + required TYPE ty_quantity, + available TYPE ty_quantity, + shortage TYPE ty_quantity, + status TYPE ty_status, + END OF ty_result. + TYPES tt_result TYPE STANDARD TABLE OF ty_result WITH EMPTY KEY. + + CONSTANTS: + BEGIN OF c_status, + ok TYPE ty_status VALUE 'OK', + short TYPE ty_status VALUE 'SHORT', + invalid TYPE ty_status VALUE 'INVALID', + END OF c_status. + + METHODS check + IMPORTING it_stock TYPE tt_stock_item + it_requirement TYPE tt_requirement + RETURNING VALUE(rt_result) TYPE tt_result. + + METHODS shortages + IMPORTING it_result TYPE tt_result + RETURNING VALUE(rt_shortage) TYPE tt_result. +ENDINTERFACE. diff --git a/tasks_gen/eval/G0187/spec.md b/tasks_gen/eval/G0187/spec.md new file mode 100644 index 0000000..a9e8139 --- /dev/null +++ b/tasks_gen/eval/G0187/spec.md @@ -0,0 +1,15 @@ +Create the class {{P}}STOCK_COVER_CHECKER in package $TMP. The class is public and final. It implements the interface {{P}}IF_STOCK_COVER. Do not add other public methods. The class must be creatable with NEW {{P}}STOCK_COVER_CHECKER( ). + +A stock item has a material, a plant, and a quantity. Ignore every stock item whose quantity is less than zero. Sum the quantities of the remaining stock items for each material and plant. This sum is the free stock. Compare material and plant without regard to case. Remove all blanks before you compare them. + +Process the requirements in the given sequence. The result contains one row for each requirement in the same sequence. The available quantity of a requirement is the free stock of its material and plant at the time of the requirement. If no stock exists for the material and plant, the available quantity is 0. + +If the required quantity is less than or equal to 0, the status is INVALID. The requirement does not use free stock. The shortage is 0. Else if the available quantity is greater than or equal to the required quantity, the status is OK. The shortage is 0. The requirement uses the required quantity of the free stock. Else the status is SHORT. The requirement uses all free stock. The shortage is the required quantity minus the available quantity. + +A result row contains the material and the plant of the requirement without a change, the required quantity, the available quantity, the shortage, and the status. + +The method SHORTAGES returns all rows of the result table whose status is SHORT. Sort these rows by material in ascending order and then by plant in ascending order. The result can be empty. + +Release target: 8.16 (SAP_BASIS 816). Use Clean ABAP. Keep method length below 40 statements. Do not use global variables. Do not write comments that restate the code. Do not change {{P}}IF_STOCK_COVER. + +The class must be active and have no syntax error. The hidden tests must pass. Write your own ABAP Unit tests for the class. diff --git a/tasks_gen/eval/G0187/task.json b/tasks_gen/eval/G0187/task.json new file mode 100644 index 0000000..84ef11d --- /dev/null +++ b/tasks_gen/eval/G0187/task.json @@ -0,0 +1,55 @@ +{ + "id": "G0187", + "category": "K", + "object_type": "CLAS", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 60, + "max_activations": 15 + }, + "seed": [ + { + "type": "INTF", + "name": "{{P}}IF_STOCK_COVER", + "file": "seed/if_stock_cover.intf.abap", + "description": "Stock cover interface with types, constants and two methods" + } + ], + "contract": [ + { + "type": "CLAS", + "name": "{{P}}STOCK_COVER_CHECKER", + "implements": "{{P}}IF_STOCK_COVER" + } + ], + "out_of_scope": [ + "{{P}}IF_STOCK_COVER" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T02_HIDDEN", + "file": "hidden/t02_hidden.clas.abap", + "description": "T02 hidden tests for the stock cover checker" + } + ], + "reference": [ + { + "type": "CLAS", + "name": "{{P}}STOCK_COVER_CHECKER", + "file": "reference/stock_cover_checker.clas.abap", + "description": "Stock cover checker with hashed stock table", + "testclasses_file": "reference/stock_cover_checker.testclasses.abap" + } + ], + "craft_checks": [ + "table_kind", + "access_path", + "method_length" + ], + "base_task": "G0010", + "input_style": "incomplete", + "tool_schema": "generic_v0" +} \ No newline at end of file diff --git a/tasks_gen/eval/G0188/task.json b/tasks_gen/eval/G0188/task.json index ba5402f..7f59436 100644 --- a/tasks_gen/eval/G0188/task.json +++ b/tasks_gen/eval/G0188/task.json @@ -6,8 +6,8 @@ "release_target": "v816", "expected_outcome": "implement", "budget": { - "max_tool_calls": 40, - "max_activations": 10 + "max_tool_calls": 60, + "max_activations": 15 }, "seed": [ { diff --git a/tasks_gen/eval/G0189/hidden/duty_hidden.clas.abap b/tasks_gen/eval/G0189/hidden/duty_hidden.clas.abap new file mode 100644 index 0000000..d3967f8 --- /dev/null +++ b/tasks_gen/eval/G0189/hidden/duty_hidden.clas.abap @@ -0,0 +1,152 @@ +CLASS {{p}}duty_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS call + IMPORTING + iv_value TYPE decfloat34 + iv_country TYPE string + iv_category TYPE string + EXPORTING + ev_rate TYPE decfloat34 + ev_duty TYPE decfloat34 + ev_subrc TYPE sysubrc. + METHODS food_rate FOR TESTING. + METHODS textile_rate FOR TESTING. + METHODS machine_rate FOR TESTING. + METHODS unknown_category FOR TESTING. + METHODS rounds_half_up FOR TESTING. + METHODS minimum_duty FOR TESTING. + METHODS zero_value FOR TESTING. + METHODS pref_no_minimum FOR TESTING. + METHODS pref_ch_de FOR TESTING. + METHODS pref_fr_it_es FOR TESTING. + METHODS negative_value FOR TESTING. +ENDCLASS. + + +CLASS {{p}}duty_hidden IMPLEMENTATION. + METHOD call. + CALL FUNCTION '{{P}}CUSTOMS_DUTY_OLD' + EXPORTING + iv_value = iv_value + iv_country = iv_country + iv_category = iv_category + IMPORTING + ev_rate = ev_rate + ev_duty = ev_duty + EXCEPTIONS + invalid_value = 1 + OTHERS = 2. + ev_subrc = sy-subrc. + ENDMETHOD. + + METHOD food_rate. + DATA lv_rate TYPE decfloat34. + DATA lv_duty TYPE decfloat34. + call( EXPORTING iv_value = 1000 iv_country = 'US' iv_category = 'FOOD' + IMPORTING ev_rate = lv_rate ev_duty = lv_duty ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 5 ) act = lv_rate ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 50 ) act = lv_duty ). + ENDMETHOD. + + METHOD textile_rate. + DATA lv_rate TYPE decfloat34. + DATA lv_duty TYPE decfloat34. + call( EXPORTING iv_value = '250.50' iv_country = 'US' iv_category = 'TEXTILE' + IMPORTING ev_rate = lv_rate ev_duty = lv_duty ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 12 ) act = lv_rate ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '30.06' ) act = lv_duty ). + ENDMETHOD. + + METHOD machine_rate. + DATA lv_rate TYPE decfloat34. + DATA lv_duty TYPE decfloat34. + call( EXPORTING iv_value = 2000 iv_country = 'US' iv_category = 'MACHINE' + IMPORTING ev_rate = lv_rate ev_duty = lv_duty ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 3 ) act = lv_rate ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 60 ) act = lv_duty ). + ENDMETHOD. + + METHOD unknown_category. + DATA lv_rate TYPE decfloat34. + DATA lv_duty TYPE decfloat34. + call( EXPORTING iv_value = 1000 iv_country = 'US' iv_category = 'TOY' + IMPORTING ev_rate = lv_rate ev_duty = lv_duty ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 0 ) act = lv_rate ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 0 ) act = lv_duty ). + ENDMETHOD. + + METHOD rounds_half_up. + DATA lv_duty TYPE decfloat34. + call( EXPORTING iv_value = '123.7' iv_country = 'US' iv_category = 'FOOD' + IMPORTING ev_duty = lv_duty ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '6.19' ) act = lv_duty ). + + call( EXPORTING iv_value = '123.45' iv_country = 'US' iv_category = 'FOOD' + IMPORTING ev_duty = lv_duty ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '6.17' ) act = lv_duty ). + ENDMETHOD. + + METHOD minimum_duty. + DATA lv_duty TYPE decfloat34. + call( EXPORTING iv_value = 50 iv_country = 'US' iv_category = 'FOOD' + IMPORTING ev_duty = lv_duty ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 5 ) act = lv_duty ). + ENDMETHOD. + + METHOD zero_value. + DATA lv_rate TYPE decfloat34. + DATA lv_duty TYPE decfloat34. + DATA lv_subrc TYPE sysubrc. + call( EXPORTING iv_value = 0 iv_country = 'US' iv_category = 'FOOD' + IMPORTING ev_rate = lv_rate ev_duty = lv_duty ev_subrc = lv_subrc ). + cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_subrc ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 5 ) act = lv_rate ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 0 ) act = lv_duty ). + ENDMETHOD. + + METHOD pref_no_minimum. + DATA lv_rate TYPE decfloat34. + DATA lv_duty TYPE decfloat34. + call( EXPORTING iv_value = 10000 iv_country = 'CH' iv_category = 'TEXTILE' + IMPORTING ev_rate = lv_rate ev_duty = lv_duty ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 0 ) act = lv_rate ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 0 ) act = lv_duty ). + ENDMETHOD. + + METHOD pref_ch_de. + DATA lv_rate TYPE decfloat34. + DATA lv_duty TYPE decfloat34. + call( EXPORTING iv_value = 10000 iv_country = 'DE' iv_category = 'MACHINE' + IMPORTING ev_rate = lv_rate ev_duty = lv_duty ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 0 ) act = lv_rate ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 0 ) act = lv_duty ). + ENDMETHOD. + + METHOD pref_fr_it_es. + DATA lv_rate TYPE decfloat34. + DATA lv_duty TYPE decfloat34. + call( EXPORTING iv_value = 10000 iv_country = 'FR' iv_category = 'FOOD' + IMPORTING ev_rate = lv_rate ev_duty = lv_duty ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 0 ) act = lv_rate ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 0 ) act = lv_duty ). + + call( EXPORTING iv_value = 10000 iv_country = 'IT' iv_category = 'FOOD' + IMPORTING ev_rate = lv_rate ev_duty = lv_duty ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 0 ) act = lv_rate ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 0 ) act = lv_duty ). + + call( EXPORTING iv_value = 10000 iv_country = 'ES' iv_category = 'FOOD' + IMPORTING ev_rate = lv_rate ev_duty = lv_duty ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 0 ) act = lv_rate ). + cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 0 ) act = lv_duty ). + ENDMETHOD. + + METHOD negative_value. + DATA lv_duty TYPE decfloat34. + DATA lv_subrc TYPE sysubrc. + call( EXPORTING iv_value = -100 iv_country = 'US' iv_category = 'FOOD' + IMPORTING ev_duty = lv_duty ev_subrc = lv_subrc ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lv_subrc ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0189/mutation.json b/tasks_gen/eval/G0189/mutation.json new file mode 100644 index 0000000..033261d --- /dev/null +++ b/tasks_gen/eval/G0189/mutation.json @@ -0,0 +1,58 @@ +{ + "task": "T14", + "mutants": [ + { + "object": "{{P}}CUSTOMS_DUTY_OLD", + "mutant": "line 14: < -> <= (rel)", + "status": "killed", + "hidden": "10/11", + "failed_tests": [ + "ZERO_VALUE" + ] + }, + { + "object": "{{P}}CUSTOMS_DUTY_OLD", + "mutant": "line 22: 12 -> 15 (const)", + "status": "killed", + "hidden": "10/11", + "failed_tests": [ + "TEXTILE_RATE" + ] + }, + { + "object": "{{P}}CUSTOMS_DUTY_OLD", + "mutant": "line 30: 'ES' -> 'XX' (const)", + "status": "killed", + "hidden": "10/11", + "failed_tests": [ + "PREF_FR_IT_ES" + ] + }, + { + "object": "{{P}}CUSTOMS_DUTY_OLD", + "mutant": "line 35: round() -> plain (arith)", + "status": "killed", + "hidden": "10/11", + "failed_tests": [ + "ROUNDS_HALF_UP" + ] + }, + { + "object": "{{P}}CUSTOMS_DUTY_OLD", + "mutant": "line 37: ev_duty > 0 AND -> removed (bool)", + "status": "killed", + "hidden": "6/11", + "failed_tests": [ + "PREF_NO_MINIMUM", + "PREF_CH_DE", + "PREF_FR_IT_ES", + "UNKNOWN_CATEGORY", + "ZERO_VALUE" + ] + } + ], + "valid": 5, + "killed": 5, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0189/reference/customs_duty_old.func.abap b/tasks_gen/eval/G0189/reference/customs_duty_old.func.abap new file mode 100644 index 0000000..9b7fd48 --- /dev/null +++ b/tasks_gen/eval/G0189/reference/customs_duty_old.func.abap @@ -0,0 +1,41 @@ +FUNCTION {{p}}customs_duty_old + IMPORTING + iv_value TYPE decfloat34 + iv_country TYPE string + iv_category TYPE string + EXPORTING + ev_rate TYPE decfloat34 + ev_duty TYPE decfloat34 + EXCEPTIONS + invalid_value. + + DATA lv_rate TYPE decfloat34. + + IF iv_value < 0. + RAISE invalid_value. + ENDIF. + + CASE iv_category. + WHEN 'FOOD'. + lv_rate = 5. + WHEN 'TEXTILE'. + lv_rate = 12. + WHEN 'MACHINE'. + lv_rate = 3. + WHEN OTHERS. + lv_rate = 0. + ENDCASE. + + IF iv_country = 'CH' OR iv_country = 'DE' OR iv_country = 'FR' + OR iv_country = 'IT' OR iv_country = 'ES'. + lv_rate = 0. + ENDIF. + + ev_rate = lv_rate. + ev_duty = round( val = iv_value * lv_rate / 100 dec = 2 ). + + IF ev_duty > 0 AND ev_duty < 5. + ev_duty = 5. + ENDIF. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0189/reference/duty_test.clas.abap b/tasks_gen/eval/G0189/reference/duty_test.clas.abap new file mode 100644 index 0000000..f035953 --- /dev/null +++ b/tasks_gen/eval/G0189/reference/duty_test.clas.abap @@ -0,0 +1,72 @@ +CLASS {{p}}duty_test DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + METHODS duty_for + IMPORTING + iv_value TYPE decfloat34 + iv_country TYPE string + iv_category TYPE string + RETURNING + VALUE(rv_duty) TYPE decfloat34. + METHODS food_duty FOR TESTING. + METHODS rounding FOR TESTING. + METHODS minimum FOR TESTING. + METHODS preferential FOR TESTING. + METHODS negative_value FOR TESTING. +ENDCLASS. + + +CLASS {{p}}duty_test IMPLEMENTATION. + METHOD duty_for. + CALL FUNCTION '{{P}}CUSTOMS_DUTY_OLD' + EXPORTING + iv_value = iv_value + iv_country = iv_country + iv_category = iv_category + IMPORTING + ev_duty = rv_duty + EXCEPTIONS + invalid_value = 1 + OTHERS = 2. + cl_abap_unit_assert=>assert_subrc( exp = 0 ). + ENDMETHOD. + + METHOD food_duty. + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( 50 ) + act = duty_for( iv_value = 1000 iv_country = 'US' iv_category = 'FOOD' ) ). + ENDMETHOD. + + METHOD rounding. + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( '6.19' ) + act = duty_for( iv_value = '123.7' iv_country = 'US' iv_category = 'FOOD' ) ). + ENDMETHOD. + + METHOD minimum. + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( 5 ) + act = duty_for( iv_value = 50 iv_country = 'US' iv_category = 'FOOD' ) ). + ENDMETHOD. + + METHOD preferential. + cl_abap_unit_assert=>assert_equals( + exp = CONV decfloat34( 0 ) + act = duty_for( iv_value = 10000 iv_country = 'FR' iv_category = 'FOOD' ) ). + ENDMETHOD. + + METHOD negative_value. + DATA lv_duty TYPE decfloat34. + CALL FUNCTION '{{P}}CUSTOMS_DUTY_OLD' + EXPORTING + iv_value = -1 + iv_country = 'US' + iv_category = 'FOOD' + IMPORTING + ev_duty = lv_duty + EXCEPTIONS + invalid_value = 1 + OTHERS = 2. + cl_abap_unit_assert=>assert_equals( exp = 1 act = sy-subrc ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0189/seed/customs_duty_old.func.abap b/tasks_gen/eval/G0189/seed/customs_duty_old.func.abap new file mode 100644 index 0000000..ea65de0 --- /dev/null +++ b/tasks_gen/eval/G0189/seed/customs_duty_old.func.abap @@ -0,0 +1,36 @@ +FUNCTION {{p}}customs_duty_old + IMPORTING + iv_value TYPE decfloat34 + iv_country TYPE string + iv_category TYPE string + EXPORTING + ev_rate TYPE decfloat34 + ev_duty TYPE decfloat34 + EXCEPTIONS + invalid_value. + + DATA lv_rate TYPE decfloat34. + + CASE iv_category. + WHEN 'FOOD'. + lv_rate = 5. + WHEN 'TEXTILE'. + lv_rate = 12. + WHEN 'MACHINE'. + lv_rate = 3. + WHEN OTHERS. + lv_rate = 0. + ENDCASE. + + IF iv_country = 'CH' OR iv_country = 'DE'. + lv_rate = 0. + ENDIF. + + ev_rate = lv_rate. + ev_duty = iv_value * lv_rate / 100. + + IF ev_duty < 5. + ev_duty = 5. + ENDIF. + +ENDFUNCTION. diff --git a/tasks_gen/eval/G0189/spec.md b/tasks_gen/eval/G0189/spec.md new file mode 100644 index 0000000..7d2ca3c --- /dev/null +++ b/tasks_gen/eval/G0189/spec.md @@ -0,0 +1,54 @@ +# 1. Goal +A customs broker calculates the import duty for a shipment. The broker program +calls one function module for each shipment. The function module +{{P}}CUSTOMS_DUTY_OLD calculates the duty rate and the duty. Users report +several defects. Fix the function module in place. All other behavior stays the +same. + +# 2. Open questions +None. + +# 3. Context +- Function group {{P}}FG_CUST exists in package $TMP. +- Function module {{P}}CUSTOMS_DUTY_OLD exists in this group. It is the only + function module in the group. Read its source. It defines the duty rates of + the goods categories and all the other behavior that must stay the same. +- The broker program calls the function module with a customs value, a country + of origin and a goods category. The program reads the duty rate and the duty. + +# 4. Contract +- Fix the function module {{P}}CUSTOMS_DUTY_OLD in function group {{P}}FG_CUST. +- Do not change the interface. The parameters are: + - IV_VALUE, importing, decfloat34: the customs value in euro. + - IV_COUNTRY, importing, string: the country of origin. + - IV_CATEGORY, importing, string: the goods category. + - EV_RATE, exporting, decfloat34: the duty rate in percent. + - EV_DUTY, exporting, decfloat34: the duty in euro. + - The exception INVALID_VALUE stays. + +# 5. Business rules +1. The duty is rounded half up to 2 decimals. Users report duties with more + than 2 decimals, for example 6.185 instead of 6.19. +2. The minimum duty is 5.00. The minimum applies only to a shipment that has a + duty. A shipment with a duty of zero keeps a duty of zero. Users report that + duty-free shipments are charged 5.00. +3. A shipment with a preferential origin is duty-free: the duty is 0 and the + rate is 0. The preferential origins are Switzerland (CH), Germany (DE), + France (FR), Italy (IT) and Spain (ES). Users report that shipments from + France, Italy and Spain are charged duty. +4. A negative customs value is not valid. Users report that a negative value is + accepted and gives a duty. The function module must raise the exception + INVALID_VALUE for a negative customs value. +5. The duty rates of the goods categories and all other behavior stay the same + as they are in {{P}}CUSTOMS_DUTY_OLD today. + +# 6. Constraints +- Release target: 8.16 (SAP_BASIS 816, ABAP Platform 2025). +- Package $TMP. Do not use transports. +- Out of scope: do not change other objects. +- Clean ABAP. Keep the methods below 40 statements. + +# 7. Acceptance +- The function module {{P}}CUSTOMS_DUTY_OLD is active and has no syntax error. +- The hidden tests pass. +- Write ABAP Unit tests for the function module in a global test class. diff --git a/tasks_gen/eval/G0189/task.json b/tasks_gen/eval/G0189/task.json new file mode 100644 index 0000000..497063d --- /dev/null +++ b/tasks_gen/eval/G0189/task.json @@ -0,0 +1,83 @@ +{ + "id": "G0189", + "category": "I", + "object_type": "FUNC", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 40, + "max_activations": 10 + }, + "seed": [ + { + "type": "FUGR", + "name": "{{P}}FG_CUST", + "description": "Customs duty function group" + }, + { + "type": "FUNC", + "name": "{{P}}CUSTOMS_DUTY_OLD", + "functionGroup": "{{P}}FG_CUST", + "file": "seed/customs_duty_old.func.abap", + "description": "Legacy customs duty calculation with defects" + } + ], + "contract": [ + { + "type": "FUNC", + "name": "{{P}}CUSTOMS_DUTY_OLD", + "functionGroup": "{{P}}FG_CUST", + "params": [ + { + "name": "iv_value", + "type": "decfloat34" + }, + { + "name": "iv_country", + "type": "string" + }, + { + "name": "iv_category", + "type": "string" + }, + { + "name": "ev_rate", + "type": "decfloat34" + }, + { + "name": "ev_duty", + "type": "decfloat34" + } + ] + } + ], + "out_of_scope": [], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}DUTY_HIDDEN", + "file": "hidden/duty_hidden.clas.abap", + "description": "Hidden tests for the customs duty function module" + } + ], + "reference": [ + { + "type": "FUNC", + "name": "{{P}}CUSTOMS_DUTY_OLD", + "functionGroup": "{{P}}FG_CUST", + "existing": true, + "file": "reference/customs_duty_old.func.abap", + "description": "Fixed customs duty calculation" + }, + { + "type": "CLAS", + "name": "{{P}}DUTY_TEST", + "file": "reference/duty_test.clas.abap", + "description": "Own tests for the customs duty function module" + } + ], + "craft_checks": [ + "method_length" + ] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0190/faulty/m1_fleet_cost_old.prog.abap b/tasks_gen/eval/G0190/faulty/m1_fleet_cost_old.prog.abap new file mode 100644 index 0000000..861812b --- /dev/null +++ b/tasks_gen/eval/G0190/faulty/m1_fleet_cost_old.prog.abap @@ -0,0 +1,149 @@ +REPORT {{p}}fleet_cost_old. + +PARAMETERS p_from TYPE d OBLIGATORY. +PARAMETERS p_to TYPE d OBLIGATORY. + +DATA gv_cat TYPE {{p}}vehicle-category. +SELECT-OPTIONS s_cat FOR gv_cat. + +CLASS lcl_fleet DEFINITION FINAL. + PUBLIC SECTION. + TYPES: + BEGIN OF ty_line, + vehicle_id TYPE {{p}}vehicle-vehicle_id, + plate TYPE {{p}}vehicle-plate, + category TYPE {{p}}vehicle-category, + distance TYPE {{p}}trip-distance_km, + fuel_cost TYPE {{p}}trip-toll_fee, + toll_cost TYPE {{p}}trip-toll_fee, + total_cost TYPE {{p}}trip-toll_fee, + cost_per_km TYPE p LENGTH 15 DECIMALS 3, + END OF ty_line, + tt_line TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY, + tt_cat TYPE RANGE OF {{p}}vehicle-category. + CLASS-METHODS select_costs + IMPORTING iv_from TYPE d + iv_to TYPE d + it_cat TYPE tt_cat + RETURNING VALUE(rt_lines) TYPE tt_line. + CLASS-METHODS show + CHANGING ct_lines TYPE tt_line. + PRIVATE SECTION. + CLASS-METHODS cost_per_km + IMPORTING is_line TYPE ty_line + RETURNING VALUE(rv_value) TYPE ty_line-cost_per_km. +ENDCLASS. + +CLASS lcl_fleet IMPLEMENTATION. + METHOD select_costs. + SELECT v~vehicle_id, + v~plate, + v~category, + SUM( t~distance_km ) AS distance, + SUM( t~fuel_liters * t~fuel_price ) AS fuel_cost, + SUM( t~toll_fee ) AS toll_cost + FROM {{p}}vehicle AS v + INNER JOIN {{p}}trip AS t ON t~vehicle_id = v~vehicle_id + WHERE t~trip_date BETWEEN @iv_from AND @iv_to + OR v~category IN @it_cat + GROUP BY v~vehicle_id, v~plate, v~category + INTO TABLE @DATA(lt_sums). + + LOOP AT lt_sums INTO DATA(ls_sum). + DATA(ls_line) = VALUE ty_line( + vehicle_id = ls_sum-vehicle_id + plate = ls_sum-plate + category = ls_sum-category + distance = ls_sum-distance + fuel_cost = ls_sum-fuel_cost + toll_cost = ls_sum-toll_cost + total_cost = ls_sum-fuel_cost + ls_sum-toll_cost ). + ls_line-cost_per_km = cost_per_km( ls_line ). + APPEND ls_line TO rt_lines. + ENDLOOP. + + SORT rt_lines BY total_cost DESCENDING. + ENDMETHOD. + + METHOD cost_per_km. + IF is_line-distance > 0. + rv_value = ROUND( val = is_line-total_cost / is_line-distance dec = 3 ). + ENDIF. + ENDMETHOD. + + METHOD show. + 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(gt_lines) = lcl_fleet=>select_costs( iv_from = p_from + iv_to = p_to + it_cat = s_cat[] ). + lcl_fleet=>show( CHANGING ct_lines = gt_lines ). + +CLASS ltc_fleet 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_vehicle FOR TESTING. + METHODS period_filter FOR TESTING. + METHODS category_filter FOR TESTING. +ENDCLASS. + +CLASS ltc_fleet IMPLEMENTATION. + METHOD class_setup. + go_env = cl_osql_test_environment=>create( + i_dependency_list = VALUE #( ( '{{P}}VEHICLE' ) ( '{{P}}TRIP' ) ) ). + + DATA lt_vehicle TYPE STANDARD TABLE OF {{p}}vehicle WITH EMPTY KEY. + lt_vehicle = VALUE #( ( vehicle_id = 'V1' plate = 'AAA' category = 'VAN' ) + ( vehicle_id = 'V2' plate = 'BBB' category = 'TRUCK' ) ). + go_env->insert_test_data( lt_vehicle ). + + DATA lt_trip TYPE STANDARD TABLE OF {{p}}trip WITH EMPTY KEY. + lt_trip = VALUE #( ( trip_id = 1 vehicle_id = 'V1' trip_date = '20260105' + distance_km = 100 fuel_liters = 10 fuel_price = 2 toll_fee = 1 ) + ( trip_id = 2 vehicle_id = 'V2' trip_date = '20260106' + distance_km = 50 fuel_liters = 5 fuel_price = 2 toll_fee = 0 ) ). + go_env->insert_test_data( lt_trip ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD totals_per_vehicle. + DATA(lt_lines) = lcl_fleet=>select_costs( iv_from = '20260101' + iv_to = '20260131' + it_cat = VALUE #( ) ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 'V1' act = lt_lines[ 1 ]-vehicle_id ). + cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}trip-toll_fee( 21 ) act = lt_lines[ 1 ]-total_cost ). + cl_abap_unit_assert=>assert_equals( exp = 'V2' act = lt_lines[ 2 ]-vehicle_id ). + ENDMETHOD. + + METHOD period_filter. + DATA(lt_lines) = lcl_fleet=>select_costs( iv_from = '20260106' + iv_to = '20260106' + it_cat = VALUE #( ) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 'V2' act = lt_lines[ 1 ]-vehicle_id ). + ENDMETHOD. + + METHOD category_filter. + DATA(lt_lines) = lcl_fleet=>select_costs( + iv_from = '20260101' + iv_to = '20260131' + it_cat = VALUE #( ( sign = 'I' option = 'EQ' low = 'TRUCK' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 'V2' act = lt_lines[ 1 ]-vehicle_id ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0190/faulty/m2_fleet_cost_old.prog.abap b/tasks_gen/eval/G0190/faulty/m2_fleet_cost_old.prog.abap new file mode 100644 index 0000000..4fe49ab --- /dev/null +++ b/tasks_gen/eval/G0190/faulty/m2_fleet_cost_old.prog.abap @@ -0,0 +1,149 @@ +REPORT {{p}}fleet_cost_old. + +PARAMETERS p_from TYPE d OBLIGATORY. +PARAMETERS p_to TYPE d OBLIGATORY. + +DATA gv_cat TYPE {{p}}vehicle-category. +SELECT-OPTIONS s_cat FOR gv_cat. + +CLASS lcl_fleet DEFINITION FINAL. + PUBLIC SECTION. + TYPES: + BEGIN OF ty_line, + vehicle_id TYPE {{p}}vehicle-vehicle_id, + plate TYPE {{p}}vehicle-plate, + category TYPE {{p}}vehicle-category, + distance TYPE {{p}}trip-distance_km, + fuel_cost TYPE {{p}}trip-toll_fee, + toll_cost TYPE {{p}}trip-toll_fee, + total_cost TYPE {{p}}trip-toll_fee, + cost_per_km TYPE p LENGTH 15 DECIMALS 3, + END OF ty_line, + tt_line TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY, + tt_cat TYPE RANGE OF {{p}}vehicle-category. + CLASS-METHODS select_costs + IMPORTING iv_from TYPE d + iv_to TYPE d + it_cat TYPE tt_cat + RETURNING VALUE(rt_lines) TYPE tt_line. + CLASS-METHODS show + CHANGING ct_lines TYPE tt_line. + PRIVATE SECTION. + CLASS-METHODS cost_per_km + IMPORTING is_line TYPE ty_line + RETURNING VALUE(rv_value) TYPE ty_line-cost_per_km. +ENDCLASS. + +CLASS lcl_fleet IMPLEMENTATION. + METHOD select_costs. + SELECT v~vehicle_id, + v~plate, + v~category, + SUM( t~distance_km ) AS distance, + SUM( t~fuel_liters * t~fuel_price ) AS fuel_cost, + SUM( t~toll_fee ) AS toll_cost + FROM {{p}}vehicle AS v + INNER JOIN {{p}}trip AS t ON t~vehicle_id = v~vehicle_id + WHERE t~trip_date BETWEEN @iv_from AND @iv_to + AND v~category IN @it_cat + GROUP BY v~vehicle_id, v~plate, v~category + INTO TABLE @DATA(lt_sums). + + LOOP AT lt_sums INTO DATA(ls_sum). + DATA(ls_line) = VALUE ty_line( + vehicle_id = ls_sum-vehicle_id + plate = ls_sum-plate + category = ls_sum-category + distance = ls_sum-distance + fuel_cost = ls_sum-fuel_cost + toll_cost = ls_sum-toll_cost + total_cost = ls_sum-fuel_cost - ls_sum-toll_cost ). + ls_line-cost_per_km = cost_per_km( ls_line ). + APPEND ls_line TO rt_lines. + ENDLOOP. + + SORT rt_lines BY total_cost DESCENDING. + ENDMETHOD. + + METHOD cost_per_km. + IF is_line-distance > 0. + rv_value = ROUND( val = is_line-total_cost / is_line-distance dec = 3 ). + ENDIF. + ENDMETHOD. + + METHOD show. + 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(gt_lines) = lcl_fleet=>select_costs( iv_from = p_from + iv_to = p_to + it_cat = s_cat[] ). + lcl_fleet=>show( CHANGING ct_lines = gt_lines ). + +CLASS ltc_fleet 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_vehicle FOR TESTING. + METHODS period_filter FOR TESTING. + METHODS category_filter FOR TESTING. +ENDCLASS. + +CLASS ltc_fleet IMPLEMENTATION. + METHOD class_setup. + go_env = cl_osql_test_environment=>create( + i_dependency_list = VALUE #( ( '{{P}}VEHICLE' ) ( '{{P}}TRIP' ) ) ). + + DATA lt_vehicle TYPE STANDARD TABLE OF {{p}}vehicle WITH EMPTY KEY. + lt_vehicle = VALUE #( ( vehicle_id = 'V1' plate = 'AAA' category = 'VAN' ) + ( vehicle_id = 'V2' plate = 'BBB' category = 'TRUCK' ) ). + go_env->insert_test_data( lt_vehicle ). + + DATA lt_trip TYPE STANDARD TABLE OF {{p}}trip WITH EMPTY KEY. + lt_trip = VALUE #( ( trip_id = 1 vehicle_id = 'V1' trip_date = '20260105' + distance_km = 100 fuel_liters = 10 fuel_price = 2 toll_fee = 1 ) + ( trip_id = 2 vehicle_id = 'V2' trip_date = '20260106' + distance_km = 50 fuel_liters = 5 fuel_price = 2 toll_fee = 0 ) ). + go_env->insert_test_data( lt_trip ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD totals_per_vehicle. + DATA(lt_lines) = lcl_fleet=>select_costs( iv_from = '20260101' + iv_to = '20260131' + it_cat = VALUE #( ) ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 'V1' act = lt_lines[ 1 ]-vehicle_id ). + cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}trip-toll_fee( 21 ) act = lt_lines[ 1 ]-total_cost ). + cl_abap_unit_assert=>assert_equals( exp = 'V2' act = lt_lines[ 2 ]-vehicle_id ). + ENDMETHOD. + + METHOD period_filter. + DATA(lt_lines) = lcl_fleet=>select_costs( iv_from = '20260106' + iv_to = '20260106' + it_cat = VALUE #( ) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 'V2' act = lt_lines[ 1 ]-vehicle_id ). + ENDMETHOD. + + METHOD category_filter. + DATA(lt_lines) = lcl_fleet=>select_costs( + iv_from = '20260101' + iv_to = '20260131' + it_cat = VALUE #( ( sign = 'I' option = 'EQ' low = 'TRUCK' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 'V2' act = lt_lines[ 1 ]-vehicle_id ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0190/faulty/m3_fleet_cost_old.prog.abap b/tasks_gen/eval/G0190/faulty/m3_fleet_cost_old.prog.abap new file mode 100644 index 0000000..bd8c1b1 --- /dev/null +++ b/tasks_gen/eval/G0190/faulty/m3_fleet_cost_old.prog.abap @@ -0,0 +1,149 @@ +REPORT {{p}}fleet_cost_old. + +PARAMETERS p_from TYPE d OBLIGATORY. +PARAMETERS p_to TYPE d OBLIGATORY. + +DATA gv_cat TYPE {{p}}vehicle-category. +SELECT-OPTIONS s_cat FOR gv_cat. + +CLASS lcl_fleet DEFINITION FINAL. + PUBLIC SECTION. + TYPES: + BEGIN OF ty_line, + vehicle_id TYPE {{p}}vehicle-vehicle_id, + plate TYPE {{p}}vehicle-plate, + category TYPE {{p}}vehicle-category, + distance TYPE {{p}}trip-distance_km, + fuel_cost TYPE {{p}}trip-toll_fee, + toll_cost TYPE {{p}}trip-toll_fee, + total_cost TYPE {{p}}trip-toll_fee, + cost_per_km TYPE p LENGTH 15 DECIMALS 3, + END OF ty_line, + tt_line TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY, + tt_cat TYPE RANGE OF {{p}}vehicle-category. + CLASS-METHODS select_costs + IMPORTING iv_from TYPE d + iv_to TYPE d + it_cat TYPE tt_cat + RETURNING VALUE(rt_lines) TYPE tt_line. + CLASS-METHODS show + CHANGING ct_lines TYPE tt_line. + PRIVATE SECTION. + CLASS-METHODS cost_per_km + IMPORTING is_line TYPE ty_line + RETURNING VALUE(rv_value) TYPE ty_line-cost_per_km. +ENDCLASS. + +CLASS lcl_fleet IMPLEMENTATION. + METHOD select_costs. + SELECT v~vehicle_id, + v~plate, + v~category, + SUM( t~distance_km ) AS distance, + SUM( t~fuel_liters * t~fuel_price ) AS fuel_cost, + SUM( t~toll_fee ) AS toll_cost + FROM {{p}}vehicle AS v + INNER JOIN {{p}}trip AS t ON t~vehicle_id = v~vehicle_id + WHERE t~trip_date BETWEEN @iv_from AND @iv_to + AND v~category IN @it_cat + GROUP BY v~vehicle_id, v~plate, v~category + INTO TABLE @DATA(lt_sums). + + LOOP AT lt_sums INTO DATA(ls_sum). + DATA(ls_line) = VALUE ty_line( + vehicle_id = ls_sum-vehicle_id + plate = ls_sum-plate + category = ls_sum-category + distance = ls_sum-distance + fuel_cost = ls_sum-fuel_cost + toll_cost = ls_sum-toll_cost + total_cost = ls_sum-fuel_cost + ls_sum-toll_cost ). + ls_line-cost_per_km = cost_per_km( ls_line ). + APPEND ls_line TO rt_lines. + ENDLOOP. + + SORT rt_lines BY total_cost DESCENDING. + ENDMETHOD. + + METHOD cost_per_km. + IF is_line-distance <= 0. + rv_value = ROUND( val = is_line-total_cost / is_line-distance dec = 3 ). + ENDIF. + ENDMETHOD. + + METHOD show. + 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(gt_lines) = lcl_fleet=>select_costs( iv_from = p_from + iv_to = p_to + it_cat = s_cat[] ). + lcl_fleet=>show( CHANGING ct_lines = gt_lines ). + +CLASS ltc_fleet 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_vehicle FOR TESTING. + METHODS period_filter FOR TESTING. + METHODS category_filter FOR TESTING. +ENDCLASS. + +CLASS ltc_fleet IMPLEMENTATION. + METHOD class_setup. + go_env = cl_osql_test_environment=>create( + i_dependency_list = VALUE #( ( '{{P}}VEHICLE' ) ( '{{P}}TRIP' ) ) ). + + DATA lt_vehicle TYPE STANDARD TABLE OF {{p}}vehicle WITH EMPTY KEY. + lt_vehicle = VALUE #( ( vehicle_id = 'V1' plate = 'AAA' category = 'VAN' ) + ( vehicle_id = 'V2' plate = 'BBB' category = 'TRUCK' ) ). + go_env->insert_test_data( lt_vehicle ). + + DATA lt_trip TYPE STANDARD TABLE OF {{p}}trip WITH EMPTY KEY. + lt_trip = VALUE #( ( trip_id = 1 vehicle_id = 'V1' trip_date = '20260105' + distance_km = 100 fuel_liters = 10 fuel_price = 2 toll_fee = 1 ) + ( trip_id = 2 vehicle_id = 'V2' trip_date = '20260106' + distance_km = 50 fuel_liters = 5 fuel_price = 2 toll_fee = 0 ) ). + go_env->insert_test_data( lt_trip ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD totals_per_vehicle. + DATA(lt_lines) = lcl_fleet=>select_costs( iv_from = '20260101' + iv_to = '20260131' + it_cat = VALUE #( ) ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 'V1' act = lt_lines[ 1 ]-vehicle_id ). + cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}trip-toll_fee( 21 ) act = lt_lines[ 1 ]-total_cost ). + cl_abap_unit_assert=>assert_equals( exp = 'V2' act = lt_lines[ 2 ]-vehicle_id ). + ENDMETHOD. + + METHOD period_filter. + DATA(lt_lines) = lcl_fleet=>select_costs( iv_from = '20260106' + iv_to = '20260106' + it_cat = VALUE #( ) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 'V2' act = lt_lines[ 1 ]-vehicle_id ). + ENDMETHOD. + + METHOD category_filter. + DATA(lt_lines) = lcl_fleet=>select_costs( + iv_from = '20260101' + iv_to = '20260131' + it_cat = VALUE #( ( sign = 'I' option = 'EQ' low = 'TRUCK' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 'V2' act = lt_lines[ 1 ]-vehicle_id ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0190/generation.json b/tasks_gen/eval/G0190/generation.json new file mode 100644 index 0000000..d621619 --- /dev/null +++ b/tasks_gen/eval/G0190/generation.json @@ -0,0 +1,29 @@ +{ + "id": "G0190", + "pool": "eval", + "object_type": "PROG", + "category": "E", + "attempts": [ + { + "stage": "bundle", + "errors": [ + "hidden/fleet_hidden.clas.abap line 77: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"", + "reference/fleet_cost_old.prog.abap line 138: 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": 2 + } + }, + { + "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/eval/G0190/hidden/fleet_hidden.clas.abap b/tasks_gen/eval/G0190/hidden/fleet_hidden.clas.abap new file mode 100644 index 0000000..5afc343 --- /dev/null +++ b/tasks_gen/eval/G0190/hidden/fleet_hidden.clas.abap @@ -0,0 +1,116 @@ +CLASS {{p}}fleet_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + TYPES tt_cat TYPE RANGE OF {{p}}vehicle-category. + METHODS run + IMPORTING iv_from TYPE d + iv_to TYPE d + it_cat TYPE tt_cat 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_vehicles FOR TESTING. + METHODS sorted_by_total FOR TESTING. + METHODS date_range_inclusive FOR TESTING. + METHODS category_filter FOR TESTING. + METHODS fuel_and_toll FOR TESTING. + METHODS cost_per_km FOR TESTING. + METHODS vehicles_without_trips FOR TESTING. +ENDCLASS. + + +CLASS {{p}}fleet_hidden IMPLEMENTATION. + METHOD run. + cl_salv_bs_runtime_info=>set( display = abap_false metadata = abap_false data = abap_true ). + SUBMIT {{p}}fleet_cost_old + WITH p_from = iv_from + WITH p_to = iv_to + WITH s_cat IN it_cat + 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 } is missing| ). + rv_value = condense( CONV string( ) ). + ENDMETHOD. + + METHOD all_vehicles. + cl_abap_unit_assert=>assert_equals( + exp = 3 + act = lines_of( run( iv_from = '20260101' iv_to = '20260131' ) ) ). + ENDMETHOD. + + METHOD sorted_by_total. + DATA(lr_data) = run( iv_from = '20260101' iv_to = '20260131' ). + cl_abap_unit_assert=>assert_equals( exp = `V02` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `VEHICLE_ID` ) ). + cl_abap_unit_assert=>assert_equals( exp = `V01` act = value_of( ir_data = lr_data iv_row = 2 iv_col = `VEHICLE_ID` ) ). + cl_abap_unit_assert=>assert_equals( exp = `V03` act = value_of( ir_data = lr_data iv_row = 3 iv_col = `VEHICLE_ID` ) ). + ENDMETHOD. + + METHOD date_range_inclusive. + DATA(lr_first) = run( iv_from = '20260101' iv_to = '20260101' ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lines_of( lr_first ) ). + cl_abap_unit_assert=>assert_equals( exp = `V03` act = value_of( ir_data = lr_first iv_row = 1 iv_col = `VEHICLE_ID` ) ). + cl_abap_unit_assert=>assert_equals( exp = `20.0` act = value_of( ir_data = lr_first iv_row = 1 iv_col = `DISTANCE` ) ). + + DATA(lr_last) = run( iv_from = '20260131' iv_to = '20260131' ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lines_of( lr_last ) ). + cl_abap_unit_assert=>assert_equals( exp = `V03` act = value_of( ir_data = lr_last iv_row = 1 iv_col = `VEHICLE_ID` ) ). + cl_abap_unit_assert=>assert_equals( exp = `10.0` act = value_of( ir_data = lr_last iv_row = 1 iv_col = `DISTANCE` ) ). + ENDMETHOD. + + METHOD category_filter. + DATA(lr_data) = run( iv_from = '20260101' iv_to = '20260131' + it_cat = VALUE #( ( sign = 'I' option = 'EQ' low = 'TRUCK' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lines_of( lr_data ) ). + cl_abap_unit_assert=>assert_equals( exp = `V02` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `VEHICLE_ID` ) ). + cl_abap_unit_assert=>assert_equals( exp = `47.00` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `TOTAL_COST` ) ). + ENDMETHOD. + + METHOD fuel_and_toll. + DATA(lr_data) = run( iv_from = '20260101' iv_to = '20260131' ). + cl_abap_unit_assert=>assert_equals( exp = `200.0` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `DISTANCE` ) ). + cl_abap_unit_assert=>assert_equals( exp = `42.00` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `FUEL_COST` ) ). + cl_abap_unit_assert=>assert_equals( exp = `5.00` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `TOLL_COST` ) ). + cl_abap_unit_assert=>assert_equals( exp = `47.00` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `TOTAL_COST` ) ). + ENDMETHOD. + + METHOD cost_per_km. + DATA(lr_data) = run( iv_from = '20260101' iv_to = '20260131' ). + cl_abap_unit_assert=>assert_equals( exp = `0.235` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `COST_PER_KM` ) ). + cl_abap_unit_assert=>assert_equals( exp = `0.163` act = value_of( ir_data = lr_data iv_row = 2 iv_col = `COST_PER_KM` ) ). + cl_abap_unit_assert=>assert_equals( exp = `0.164` act = value_of( ir_data = lr_data iv_row = 3 iv_col = `COST_PER_KM` ) ). + ENDMETHOD. + + METHOD vehicles_without_trips. + DATA(lr_data) = run( iv_from = '20260101' iv_to = '20260131' ). + DO lines_of( lr_data ) TIMES. + cl_abap_unit_assert=>assert_differs( + exp = `V04` + act = value_of( ir_data = lr_data iv_row = sy-index iv_col = `VEHICLE_ID` ) ). + ENDDO. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0190/mutation.json b/tasks_gen/eval/G0190/mutation.json new file mode 100644 index 0000000..31493c3 --- /dev/null +++ b/tasks_gen/eval/G0190/mutation.json @@ -0,0 +1,55 @@ +{ + "task": "G0190", + "mutants": [ + { + "object": "{{P}}FLEET_COST_OLD", + "mutant": "line 43: * -> / (arith)", + "status": "invalid", + "hidden": "0/0", + "failed_tests": [] + }, + { + "object": "{{P}}FLEET_COST_OLD", + "mutant": "line 48: AND -> OR (logic)", + "status": "killed", + "hidden": "3/7", + "failed_tests": [ + "CATEGORY_FILTER", + "COST_PER_KM", + "DATE_RANGE_INCLUSIVE", + "FUEL_AND_TOLL" + ] + }, + { + "object": "{{P}}FLEET_COST_OLD", + "mutant": "line 60: + -> - (arith)", + "status": "killed", + "hidden": "4/7", + "failed_tests": [ + "CATEGORY_FILTER", + "COST_PER_KM", + "FUEL_AND_TOLL" + ] + }, + { + "object": "{{P}}FLEET_COST_OLD", + "mutant": "line 69: > -> <= (rel)", + "status": "killed", + "hidden": "6/7", + "failed_tests": [ + "COST_PER_KM" + ] + }, + { + "object": "{{P}}FLEET_COST_OLD", + "mutant": "line 70: 3 -> 4 (const)", + "status": "survived", + "hidden": "7/7", + "failed_tests": [] + } + ], + "valid": 4, + "killed": 3, + "kill_rate": 0.75, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0190/reference/fleet_cost_old.prog.abap b/tasks_gen/eval/G0190/reference/fleet_cost_old.prog.abap new file mode 100644 index 0000000..4532772 --- /dev/null +++ b/tasks_gen/eval/G0190/reference/fleet_cost_old.prog.abap @@ -0,0 +1,149 @@ +REPORT {{p}}fleet_cost_old. + +PARAMETERS p_from TYPE d OBLIGATORY. +PARAMETERS p_to TYPE d OBLIGATORY. + +DATA gv_cat TYPE {{p}}vehicle-category. +SELECT-OPTIONS s_cat FOR gv_cat. + +CLASS lcl_fleet DEFINITION FINAL. + PUBLIC SECTION. + TYPES: + BEGIN OF ty_line, + vehicle_id TYPE {{p}}vehicle-vehicle_id, + plate TYPE {{p}}vehicle-plate, + category TYPE {{p}}vehicle-category, + distance TYPE {{p}}trip-distance_km, + fuel_cost TYPE {{p}}trip-toll_fee, + toll_cost TYPE {{p}}trip-toll_fee, + total_cost TYPE {{p}}trip-toll_fee, + cost_per_km TYPE p LENGTH 15 DECIMALS 3, + END OF ty_line, + tt_line TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY, + tt_cat TYPE RANGE OF {{p}}vehicle-category. + CLASS-METHODS select_costs + IMPORTING iv_from TYPE d + iv_to TYPE d + it_cat TYPE tt_cat + RETURNING VALUE(rt_lines) TYPE tt_line. + CLASS-METHODS show + CHANGING ct_lines TYPE tt_line. + PRIVATE SECTION. + CLASS-METHODS cost_per_km + IMPORTING is_line TYPE ty_line + RETURNING VALUE(rv_value) TYPE ty_line-cost_per_km. +ENDCLASS. + +CLASS lcl_fleet IMPLEMENTATION. + METHOD select_costs. + SELECT v~vehicle_id, + v~plate, + v~category, + SUM( t~distance_km ) AS distance, + SUM( t~fuel_liters * t~fuel_price ) AS fuel_cost, + SUM( t~toll_fee ) AS toll_cost + FROM {{p}}vehicle AS v + INNER JOIN {{p}}trip AS t ON t~vehicle_id = v~vehicle_id + WHERE t~trip_date BETWEEN @iv_from AND @iv_to + AND v~category IN @it_cat + GROUP BY v~vehicle_id, v~plate, v~category + INTO TABLE @DATA(lt_sums). + + LOOP AT lt_sums INTO DATA(ls_sum). + DATA(ls_line) = VALUE ty_line( + vehicle_id = ls_sum-vehicle_id + plate = ls_sum-plate + category = ls_sum-category + distance = ls_sum-distance + fuel_cost = ls_sum-fuel_cost + toll_cost = ls_sum-toll_cost + total_cost = ls_sum-fuel_cost + ls_sum-toll_cost ). + ls_line-cost_per_km = cost_per_km( ls_line ). + APPEND ls_line TO rt_lines. + ENDLOOP. + + SORT rt_lines BY total_cost DESCENDING. + ENDMETHOD. + + METHOD cost_per_km. + IF is_line-distance > 0. + rv_value = ROUND( val = is_line-total_cost / is_line-distance dec = 3 ). + ENDIF. + ENDMETHOD. + + METHOD show. + 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(gt_lines) = lcl_fleet=>select_costs( iv_from = p_from + iv_to = p_to + it_cat = s_cat[] ). + lcl_fleet=>show( CHANGING ct_lines = gt_lines ). + +CLASS ltc_fleet 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_vehicle FOR TESTING. + METHODS period_filter FOR TESTING. + METHODS category_filter FOR TESTING. +ENDCLASS. + +CLASS ltc_fleet IMPLEMENTATION. + METHOD class_setup. + go_env = cl_osql_test_environment=>create( + i_dependency_list = VALUE #( ( '{{P}}VEHICLE' ) ( '{{P}}TRIP' ) ) ). + + DATA lt_vehicle TYPE STANDARD TABLE OF {{p}}vehicle WITH EMPTY KEY. + lt_vehicle = VALUE #( ( vehicle_id = 'V1' plate = 'AAA' category = 'VAN' ) + ( vehicle_id = 'V2' plate = 'BBB' category = 'TRUCK' ) ). + go_env->insert_test_data( lt_vehicle ). + + DATA lt_trip TYPE STANDARD TABLE OF {{p}}trip WITH EMPTY KEY. + lt_trip = VALUE #( ( trip_id = 1 vehicle_id = 'V1' trip_date = '20260105' + distance_km = 100 fuel_liters = 10 fuel_price = 2 toll_fee = 1 ) + ( trip_id = 2 vehicle_id = 'V2' trip_date = '20260106' + distance_km = 50 fuel_liters = 5 fuel_price = 2 toll_fee = 0 ) ). + go_env->insert_test_data( lt_trip ). + ENDMETHOD. + + METHOD class_teardown. + go_env->destroy( ). + ENDMETHOD. + + METHOD totals_per_vehicle. + DATA(lt_lines) = lcl_fleet=>select_costs( iv_from = '20260101' + iv_to = '20260131' + it_cat = VALUE #( ) ). + cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 'V1' act = lt_lines[ 1 ]-vehicle_id ). + cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}trip-toll_fee( 21 ) act = lt_lines[ 1 ]-total_cost ). + cl_abap_unit_assert=>assert_equals( exp = 'V2' act = lt_lines[ 2 ]-vehicle_id ). + ENDMETHOD. + + METHOD period_filter. + DATA(lt_lines) = lcl_fleet=>select_costs( iv_from = '20260106' + iv_to = '20260106' + it_cat = VALUE #( ) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 'V2' act = lt_lines[ 1 ]-vehicle_id ). + ENDMETHOD. + + METHOD category_filter. + DATA(lt_lines) = lcl_fleet=>select_costs( + iv_from = '20260101' + iv_to = '20260131' + it_cat = VALUE #( ( sign = 'I' option = 'EQ' low = 'TRUCK' ) ) ). + cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_lines ) ). + cl_abap_unit_assert=>assert_equals( exp = 'V2' act = lt_lines[ 1 ]-vehicle_id ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0190/seed/fleet_cost_old.prog.abap b/tasks_gen/eval/G0190/seed/fleet_cost_old.prog.abap new file mode 100644 index 0000000..74a29fc --- /dev/null +++ b/tasks_gen/eval/G0190/seed/fleet_cost_old.prog.abap @@ -0,0 +1,75 @@ +REPORT {{p}}fleet_cost_old. + +TYPES: BEGIN OF ty_out, + vehicle_id TYPE {{p}}vehicle-vehicle_id, + plate TYPE {{p}}vehicle-plate, + category TYPE {{p}}vehicle-category, + distance TYPE {{p}}trip-distance_km, + fuel_cost TYPE {{p}}trip-toll_fee, + toll_cost TYPE {{p}}trip-toll_fee, + total_cost TYPE {{p}}trip-toll_fee, + cost_per_km TYPE p LENGTH 15 DECIMALS 3, + END OF ty_out. + +DATA: gt_out TYPE STANDARD TABLE OF ty_out, + gt_vehicle TYPE STANDARD TABLE OF {{p}}vehicle, + gt_trip TYPE STANDARD TABLE OF {{p}}trip, + gs_vehicle TYPE {{p}}vehicle, + gs_trip TYPE {{p}}trip, + gs_out TYPE ty_out, + go_alv TYPE REF TO cl_salv_table, + gv_cat TYPE {{p}}vehicle-category. + +PARAMETERS: p_from TYPE d OBLIGATORY, + p_to TYPE d OBLIGATORY. + +SELECT-OPTIONS: s_cat FOR gv_cat. + +START-OF-SELECTION. + + SELECT * FROM {{p}}vehicle INTO TABLE gt_vehicle. + + LOOP AT gt_vehicle INTO gs_vehicle. + + IF gs_vehicle-category IN s_cat. + + CLEAR gs_out. + gs_out-vehicle_id = gs_vehicle-vehicle_id. + gs_out-plate = gs_vehicle-plate. + gs_out-category = gs_vehicle-category. + + SELECT * FROM {{p}}trip INTO TABLE gt_trip + WHERE vehicle_id = gs_vehicle-vehicle_id + AND trip_date >= p_from + AND trip_date <= p_to. + + IF sy-subrc = 0. + + LOOP AT gt_trip INTO gs_trip. + gs_out-distance = gs_out-distance + gs_trip-distance_km. + gs_out-fuel_cost = gs_out-fuel_cost + gs_trip-fuel_liters * gs_trip-fuel_price. + gs_out-toll_cost = gs_out-toll_cost + gs_trip-toll_fee. + ENDLOOP. + + gs_out-total_cost = gs_out-fuel_cost + gs_out-toll_cost. + + IF gs_out-distance > 0. + gs_out-cost_per_km = gs_out-total_cost / gs_out-distance. + ENDIF. + + APPEND gs_out TO gt_out. + + ENDIF. + + ENDIF. + + ENDLOOP. + + SORT gt_out BY total_cost DESCENDING. + + TRY. + cl_salv_table=>factory( IMPORTING r_salv_table = go_alv + CHANGING t_table = gt_out ). + go_alv->display( ). + CATCH cx_salv_msg. + ENDTRY. diff --git a/tasks_gen/eval/G0190/seed/fleet_seed.clas.abap b/tasks_gen/eval/G0190/seed/fleet_seed.clas.abap new file mode 100644 index 0000000..586a50b --- /dev/null +++ b/tasks_gen/eval/G0190/seed/fleet_seed.clas.abap @@ -0,0 +1,29 @@ +CLASS {{p}}fleet_seed DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES if_oo_adt_classrun. +ENDCLASS. + +CLASS {{p}}fleet_seed IMPLEMENTATION. + METHOD if_oo_adt_classrun~main. + DELETE FROM {{p}}trip. + DELETE FROM {{p}}vehicle. + + INSERT {{p}}vehicle FROM TABLE @( VALUE #( + ( vehicle_id = 'V01' plate = 'B-AA 100' category = 'VAN' ) + ( vehicle_id = 'V02' plate = 'B-BB 200' category = 'TRUCK' ) + ( vehicle_id = 'V03' plate = 'B-CC 300' category = 'VAN' ) + ( vehicle_id = 'V04' plate = 'B-DD 400' category = 'TRUCK' ) ) ). + + INSERT {{p}}trip FROM TABLE @( VALUE #( + ( trip_id = 1 vehicle_id = 'V01' trip_date = '20260105' distance_km = '100.0' fuel_liters = '10.00' fuel_price = '1.50' toll_fee = '2.00' ) + ( trip_id = 2 vehicle_id = 'V01' trip_date = '20260110' distance_km = '50.0' fuel_liters = '5.00' fuel_price = '1.50' toll_fee = '0.00' ) + ( trip_id = 3 vehicle_id = 'V02' trip_date = '20260107' distance_km = '200.0' fuel_liters = '30.00' fuel_price = '1.40' toll_fee = '5.00' ) + ( trip_id = 4 vehicle_id = 'V03' trip_date = '20260101' distance_km = '20.0' fuel_liters = '2.00' fuel_price = '1.50' toll_fee = '0.00' ) + ( trip_id = 5 vehicle_id = 'V03' trip_date = '20260120' distance_km = '80.0' fuel_liters = '8.00' fuel_price = '1.50' toll_fee = '1.50' ) + ( trip_id = 6 vehicle_id = 'V03' trip_date = '20260131' distance_km = '10.0' fuel_liters = '1.00' fuel_price = '1.50' toll_fee = '0.00' ) + ( trip_id = 7 vehicle_id = 'V01' trip_date = '20251231' distance_km = '500.0' fuel_liters = '50.00' fuel_price = '1.50' toll_fee = '9.99' ) + ( trip_id = 8 vehicle_id = 'V02' trip_date = '20260205' distance_km = '300.0' fuel_liters = '40.00' fuel_price = '1.40' toll_fee = '7.77' ) ) ). + + out->write( sy-dbcnt ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0190/seed/trip.tabl.asabap b/tasks_gen/eval/G0190/seed/trip.tabl.asabap new file mode 100644 index 0000000..2005d79 --- /dev/null +++ b/tasks_gen/eval/G0190/seed/trip.tabl.asabap @@ -0,0 +1,15 @@ +@EndUserText.label : 'Trip' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}trip { + key client : abap.clnt not null; + key trip_id : abap.int4 not null; + vehicle_id : abap.char(10); + trip_date : abap.dats; + distance_km : abap.dec(13,1); + fuel_liters : abap.dec(13,2); + fuel_price : abap.dec(13,2); + toll_fee : abap.dec(13,2); +} diff --git a/tasks_gen/eval/G0190/seed/vehicle.tabl.asabap b/tasks_gen/eval/G0190/seed/vehicle.tabl.asabap new file mode 100644 index 0000000..3428684 --- /dev/null +++ b/tasks_gen/eval/G0190/seed/vehicle.tabl.asabap @@ -0,0 +1,11 @@ +@EndUserText.label : 'Vehicle master' +@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE +@AbapCatalog.tableCategory : #TRANSPARENT +@AbapCatalog.deliveryClass : #A +@AbapCatalog.dataMaintenance : #RESTRICTED +define table {{p}}vehicle { + key client : abap.clnt not null; + key vehicle_id : abap.char(10) not null; + plate : abap.char(10); + category : abap.char(4); +} diff --git a/tasks_gen/eval/G0190/spec.md b/tasks_gen/eval/G0190/spec.md new file mode 100644 index 0000000..33bde2d --- /dev/null +++ b/tasks_gen/eval/G0190/spec.md @@ -0,0 +1,47 @@ +# 1. Goal +Refactor the legacy report {{P}}FLEET_COST_OLD in package $TMP. The report +shows the running cost of each vehicle of a company fleet for a period. The +behavior of the report stays the same. Improve the internal quality of the +source code. + +# 2. Open questions +None. + +# 3. Context +- The program {{P}}FLEET_COST_OLD exists in package $TMP. It is active and it + produces a correct result. Its source code is of poor quality. +- The tables {{P}}VEHICLE and {{P}}TRIP exist in package $TMP. They contain + data. The report reads these two tables. +- The report shows the result in an ALV list. +- The users report no functional defect. Do not change the behavior. +- The report is not in the out-of-scope list. Refactor it in place. + +# 4. Contract +- The program keeps the name {{P}}FLEET_COST_OLD and the package $TMP. +- The selection screen keeps these fields, in this order: + - Parameter P_FROM, type DATS, mandatory. + - Parameter P_TO, type DATS, mandatory. + - Select-option S_CAT for the vehicle category. +- The ALV list keeps the same columns with the same names: VEHICLE_ID, PLATE, + CATEGORY, DISTANCE, FUEL_COST, TOLL_COST, TOTAL_COST, COST_PER_KM. +- The lines of the list and the order of the lines do not change. + +# 5. Business rules +The behavior stays the same. The legacy source code of {{P}}FLEET_COST_OLD +contains all the rules. Read the legacy code. Keep every rule. Do not add a +rule and do not remove a rule. + +# 6. Constraints +- Release target: 8.16. +- Coding standards: Clean ABAP. + - Do not read a database table inside a loop. + - A method has less than 40 statements. + - The maximum nesting depth is 3. + - Use meaningful names. +- Out of scope: do not change the tables {{P}}VEHICLE and {{P}}TRIP. Do not + change the selection screen fields. Do not change the ALV column names. + +# 7. Acceptance +- The program {{P}}FLEET_COST_OLD 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/eval/G0190/task.json b/tasks_gen/eval/G0190/task.json new file mode 100644 index 0000000..3881332 --- /dev/null +++ b/tasks_gen/eval/G0190/task.json @@ -0,0 +1,74 @@ +{ + "id": "G0190", + "category": "E", + "object_type": "PROG", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 40, + "max_activations": 10 + }, + "seed": [ + { + "type": "TABL", + "name": "{{P}}VEHICLE", + "file": "seed/vehicle.tabl.asabap", + "description": "Vehicle master of the company fleet" + }, + { + "type": "TABL", + "name": "{{P}}TRIP", + "file": "seed/trip.tabl.asabap", + "description": "Trips of the vehicles" + }, + { + "type": "PROG", + "name": "{{P}}FLEET_COST_OLD", + "file": "seed/fleet_cost_old.prog.abap", + "description": "Legacy fleet cost report" + }, + { + "type": "CLAS", + "name": "{{P}}FLEET_SEED", + "file": "seed/fleet_seed.clas.abap", + "description": "Fleet seed data", + "run": true + } + ], + "contract": [ + { + "type": "PROG", + "name": "{{P}}FLEET_COST_OLD", + "parameters": [ + "p_from", + "p_to", + "s_cat" + ] + } + ], + "out_of_scope": [ + "{{P}}VEHICLE", + "{{P}}TRIP" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}FLEET_HIDDEN", + "file": "hidden/fleet_hidden.clas.abap", + "description": "Hidden tests for the fleet cost report" + } + ], + "reference": [ + { + "type": "PROG", + "name": "{{P}}FLEET_COST_OLD", + "file": "reference/fleet_cost_old.prog.abap", + "description": "Refactored fleet cost report" + } + ], + "craft_checks": [ + "db_operation_in_loop", + "method_length" + ] +} \ No newline at end of file diff --git a/tasks_gen/eval/G0191/faulty/m0_locksmith_pricer.clas.abap b/tasks_gen/eval/G0191/faulty/m0_locksmith_pricer.clas.abap new file mode 100644 index 0000000..3247e09 --- /dev/null +++ b/tasks_gen/eval/G0191/faulty/m0_locksmith_pricer.clas.abap @@ -0,0 +1,146 @@ +CLASS {{p}}locksmith_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_locksmith_pricer. + + PRIVATE SECTION. + CONSTANTS: + c_job_key TYPE {{p}}if_locksmith_pricer=>ty_job_type VALUE 'K', + c_job_lockout TYPE {{p}}if_locksmith_pricer=>ty_job_type VALUE 'L', + c_job_rekey TYPE {{p}}if_locksmith_pricer=>ty_job_type VALUE 'R', + c_key_std TYPE {{p}}if_locksmith_pricer=>ty_key_type VALUE 'S', + c_key_sec TYPE {{p}}if_locksmith_pricer=>ty_key_type VALUE 'Y', + c_key_elec TYPE {{p}}if_locksmith_pricer=>ty_key_type VALUE 'E', + c_call_late TYPE {{p}}if_locksmith_pricer=>ty_callout VALUE 'A', + c_call_week TYPE {{p}}if_locksmith_pricer=>ty_callout VALUE 'W', + c_fee_std TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '89.00', + c_fee_late TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '149.00', + c_fee_week TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '179.00', + c_rekey_base TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '35.00', + c_rate_dup_s TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '4.50', + c_rate_dup_y TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '9.80', + c_rate_dup_e TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '24.00', + c_rate_rek_s TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '6.00', + c_rate_rek_y TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '11.00', + c_rate_rek_e TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '26.00', + c_qty_mid TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '5.00', + c_qty_high TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '20.00', + c_disc_mid TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '10.00', + c_disc_high TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '20.00', + c_percent TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '100.00', + c_nothing TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '0.00'. + + METHODS duplicate_price + IMPORTING iv_quantity TYPE i + iv_key_type TYPE {{p}}if_locksmith_pricer=>ty_key_type + RETURNING VALUE(rv_price) TYPE {{p}}if_locksmith_pricer=>ty_amount. + METHODS rekey_price + IMPORTING iv_quantity TYPE i + iv_key_type TYPE {{p}}if_locksmith_pricer=>ty_key_type + RETURNING VALUE(rv_price) TYPE {{p}}if_locksmith_pricer=>ty_amount. + METHODS lockout_price + IMPORTING iv_callout TYPE {{p}}if_locksmith_pricer=>ty_callout + RETURNING VALUE(rv_price) TYPE {{p}}if_locksmith_pricer=>ty_amount. + METHODS dup_key_rate + IMPORTING iv_key_type TYPE {{p}}if_locksmith_pricer=>ty_key_type + RETURNING VALUE(rv_rate) TYPE {{p}}if_locksmith_pricer=>ty_amount. + METHODS rekey_key_rate + IMPORTING iv_key_type TYPE {{p}}if_locksmith_pricer=>ty_key_type + RETURNING VALUE(rv_rate) TYPE {{p}}if_locksmith_pricer=>ty_amount. + METHODS discount_percent + IMPORTING iv_quantity TYPE i + RETURNING VALUE(rv_percent) TYPE {{p}}if_locksmith_pricer=>ty_amount. +ENDCLASS. + + +CLASS {{p}}locksmith_pricer IMPLEMENTATION. + METHOD {{p}}if_locksmith_pricer~calculate_price. + CASE iv_job_type. + WHEN c_job_key. + rv_price = duplicate_price( iv_quantity = iv_quantity + iv_key_type = iv_key_type ). + WHEN c_job_lockout. + rv_price = lockout_price( iv_callout = iv_callout ). + WHEN c_job_rekey. + rv_price = rekey_price( iv_quantity = iv_quantity + iv_key_type = iv_key_type ). + WHEN OTHERS. + rv_price = c_nothing. + ENDCASE. + ENDMETHOD. + + METHOD duplicate_price. + DATA lv_qty TYPE {{p}}if_locksmith_pricer=>ty_amount. + lv_qty = iv_quantity. + IF lv_qty >= 1. + RETURN. + ENDIF. + DATA(lv_rate) = dup_key_rate( iv_key_type ). + IF lv_rate = 0. + RETURN. + ENDIF. + DATA lv_gross TYPE {{p}}if_locksmith_pricer=>ty_amount. + lv_gross = lv_rate * lv_qty. + DATA(lv_discount) = discount_percent( iv_quantity ). + rv_price = lv_gross - lv_gross * lv_discount / c_percent. + ENDMETHOD. + + METHOD rekey_price. + DATA lv_qty TYPE {{p}}if_locksmith_pricer=>ty_amount. + lv_qty = iv_quantity. + IF lv_qty < 1. + RETURN. + ENDIF. + DATA(lv_rate) = rekey_key_rate( iv_key_type ). + IF lv_rate = 0. + RETURN. + ENDIF. + rv_price = lv_qty * ( c_rekey_base + lv_rate ). + ENDMETHOD. + + METHOD lockout_price. + CASE iv_callout. + WHEN c_call_week. + rv_price = c_fee_week. + WHEN c_call_late. + rv_price = c_fee_late. + WHEN OTHERS. + rv_price = c_fee_std. + ENDCASE. + ENDMETHOD. + + METHOD dup_key_rate. + CASE iv_key_type. + WHEN c_key_std. + rv_rate = c_rate_dup_s. + WHEN c_key_sec. + rv_rate = c_rate_dup_y. + WHEN c_key_elec. + rv_rate = c_rate_dup_e. + WHEN OTHERS. + rv_rate = c_nothing. + ENDCASE. + ENDMETHOD. + + METHOD rekey_key_rate. + CASE iv_key_type. + WHEN c_key_std. + rv_rate = c_rate_rek_s. + WHEN c_key_sec. + rv_rate = c_rate_rek_y. + WHEN c_key_elec. + rv_rate = c_rate_rek_e. + WHEN OTHERS. + rv_rate = c_nothing. + ENDCASE. + ENDMETHOD. + + METHOD discount_percent. + IF iv_quantity >= c_qty_high. + rv_percent = c_disc_high. + ELSEIF iv_quantity >= c_qty_mid. + rv_percent = c_disc_mid. + ELSE. + rv_percent = c_nothing. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0191/faulty/m1_locksmith_pricer.clas.abap b/tasks_gen/eval/G0191/faulty/m1_locksmith_pricer.clas.abap new file mode 100644 index 0000000..fd667a7 --- /dev/null +++ b/tasks_gen/eval/G0191/faulty/m1_locksmith_pricer.clas.abap @@ -0,0 +1,146 @@ +CLASS {{p}}locksmith_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_locksmith_pricer. + + PRIVATE SECTION. + CONSTANTS: + c_job_key TYPE {{p}}if_locksmith_pricer=>ty_job_type VALUE 'K', + c_job_lockout TYPE {{p}}if_locksmith_pricer=>ty_job_type VALUE 'L', + c_job_rekey TYPE {{p}}if_locksmith_pricer=>ty_job_type VALUE 'R', + c_key_std TYPE {{p}}if_locksmith_pricer=>ty_key_type VALUE 'S', + c_key_sec TYPE {{p}}if_locksmith_pricer=>ty_key_type VALUE 'Y', + c_key_elec TYPE {{p}}if_locksmith_pricer=>ty_key_type VALUE 'E', + c_call_late TYPE {{p}}if_locksmith_pricer=>ty_callout VALUE 'A', + c_call_week TYPE {{p}}if_locksmith_pricer=>ty_callout VALUE 'W', + c_fee_std TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '89.00', + c_fee_late TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '149.00', + c_fee_week TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '179.00', + c_rekey_base TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '35.00', + c_rate_dup_s TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '4.50', + c_rate_dup_y TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '9.80', + c_rate_dup_e TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '24.00', + c_rate_rek_s TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '6.00', + c_rate_rek_y TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '11.00', + c_rate_rek_e TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '26.00', + c_qty_mid TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '5.00', + c_qty_high TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '20.00', + c_disc_mid TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '10.00', + c_disc_high TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '20.00', + c_percent TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '100.00', + c_nothing TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '0.00'. + + METHODS duplicate_price + IMPORTING iv_quantity TYPE i + iv_key_type TYPE {{p}}if_locksmith_pricer=>ty_key_type + RETURNING VALUE(rv_price) TYPE {{p}}if_locksmith_pricer=>ty_amount. + METHODS rekey_price + IMPORTING iv_quantity TYPE i + iv_key_type TYPE {{p}}if_locksmith_pricer=>ty_key_type + RETURNING VALUE(rv_price) TYPE {{p}}if_locksmith_pricer=>ty_amount. + METHODS lockout_price + IMPORTING iv_callout TYPE {{p}}if_locksmith_pricer=>ty_callout + RETURNING VALUE(rv_price) TYPE {{p}}if_locksmith_pricer=>ty_amount. + METHODS dup_key_rate + IMPORTING iv_key_type TYPE {{p}}if_locksmith_pricer=>ty_key_type + RETURNING VALUE(rv_rate) TYPE {{p}}if_locksmith_pricer=>ty_amount. + METHODS rekey_key_rate + IMPORTING iv_key_type TYPE {{p}}if_locksmith_pricer=>ty_key_type + RETURNING VALUE(rv_rate) TYPE {{p}}if_locksmith_pricer=>ty_amount. + METHODS discount_percent + IMPORTING iv_quantity TYPE i + RETURNING VALUE(rv_percent) TYPE {{p}}if_locksmith_pricer=>ty_amount. +ENDCLASS. + + +CLASS {{p}}locksmith_pricer IMPLEMENTATION. + METHOD {{p}}if_locksmith_pricer~calculate_price. + CASE iv_job_type. + WHEN c_job_key. + rv_price = duplicate_price( iv_quantity = iv_quantity + iv_key_type = iv_key_type ). + WHEN c_job_lockout. + rv_price = lockout_price( iv_callout = iv_callout ). + WHEN c_job_rekey. + rv_price = rekey_price( iv_quantity = iv_quantity + iv_key_type = iv_key_type ). + WHEN OTHERS. + rv_price = c_nothing. + ENDCASE. + ENDMETHOD. + + METHOD duplicate_price. + DATA lv_qty TYPE {{p}}if_locksmith_pricer=>ty_amount. + lv_qty = iv_quantity. + IF lv_qty < 1. + RETURN. + ENDIF. + DATA(lv_rate) = dup_key_rate( iv_key_type ). + IF lv_rate <> 0. + RETURN. + ENDIF. + DATA lv_gross TYPE {{p}}if_locksmith_pricer=>ty_amount. + lv_gross = lv_rate * lv_qty. + DATA(lv_discount) = discount_percent( iv_quantity ). + rv_price = lv_gross - lv_gross * lv_discount / c_percent. + ENDMETHOD. + + METHOD rekey_price. + DATA lv_qty TYPE {{p}}if_locksmith_pricer=>ty_amount. + lv_qty = iv_quantity. + IF lv_qty < 1. + RETURN. + ENDIF. + DATA(lv_rate) = rekey_key_rate( iv_key_type ). + IF lv_rate = 0. + RETURN. + ENDIF. + rv_price = lv_qty * ( c_rekey_base + lv_rate ). + ENDMETHOD. + + METHOD lockout_price. + CASE iv_callout. + WHEN c_call_week. + rv_price = c_fee_week. + WHEN c_call_late. + rv_price = c_fee_late. + WHEN OTHERS. + rv_price = c_fee_std. + ENDCASE. + ENDMETHOD. + + METHOD dup_key_rate. + CASE iv_key_type. + WHEN c_key_std. + rv_rate = c_rate_dup_s. + WHEN c_key_sec. + rv_rate = c_rate_dup_y. + WHEN c_key_elec. + rv_rate = c_rate_dup_e. + WHEN OTHERS. + rv_rate = c_nothing. + ENDCASE. + ENDMETHOD. + + METHOD rekey_key_rate. + CASE iv_key_type. + WHEN c_key_std. + rv_rate = c_rate_rek_s. + WHEN c_key_sec. + rv_rate = c_rate_rek_y. + WHEN c_key_elec. + rv_rate = c_rate_rek_e. + WHEN OTHERS. + rv_rate = c_nothing. + ENDCASE. + ENDMETHOD. + + METHOD discount_percent. + IF iv_quantity >= c_qty_high. + rv_percent = c_disc_high. + ELSEIF iv_quantity >= c_qty_mid. + rv_percent = c_disc_mid. + ELSE. + rv_percent = c_nothing. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0191/faulty/m2_locksmith_pricer.clas.abap b/tasks_gen/eval/G0191/faulty/m2_locksmith_pricer.clas.abap new file mode 100644 index 0000000..cfe4ff4 --- /dev/null +++ b/tasks_gen/eval/G0191/faulty/m2_locksmith_pricer.clas.abap @@ -0,0 +1,146 @@ +CLASS {{p}}locksmith_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_locksmith_pricer. + + PRIVATE SECTION. + CONSTANTS: + c_job_key TYPE {{p}}if_locksmith_pricer=>ty_job_type VALUE 'K', + c_job_lockout TYPE {{p}}if_locksmith_pricer=>ty_job_type VALUE 'L', + c_job_rekey TYPE {{p}}if_locksmith_pricer=>ty_job_type VALUE 'R', + c_key_std TYPE {{p}}if_locksmith_pricer=>ty_key_type VALUE 'S', + c_key_sec TYPE {{p}}if_locksmith_pricer=>ty_key_type VALUE 'Y', + c_key_elec TYPE {{p}}if_locksmith_pricer=>ty_key_type VALUE 'E', + c_call_late TYPE {{p}}if_locksmith_pricer=>ty_callout VALUE 'A', + c_call_week TYPE {{p}}if_locksmith_pricer=>ty_callout VALUE 'W', + c_fee_std TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '89.00', + c_fee_late TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '149.00', + c_fee_week TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '179.00', + c_rekey_base TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '35.00', + c_rate_dup_s TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '4.50', + c_rate_dup_y TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '9.80', + c_rate_dup_e TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '24.00', + c_rate_rek_s TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '6.00', + c_rate_rek_y TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '11.00', + c_rate_rek_e TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '26.00', + c_qty_mid TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '5.00', + c_qty_high TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '20.00', + c_disc_mid TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '10.00', + c_disc_high TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '20.00', + c_percent TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '100.00', + c_nothing TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '0.00'. + + METHODS duplicate_price + IMPORTING iv_quantity TYPE i + iv_key_type TYPE {{p}}if_locksmith_pricer=>ty_key_type + RETURNING VALUE(rv_price) TYPE {{p}}if_locksmith_pricer=>ty_amount. + METHODS rekey_price + IMPORTING iv_quantity TYPE i + iv_key_type TYPE {{p}}if_locksmith_pricer=>ty_key_type + RETURNING VALUE(rv_price) TYPE {{p}}if_locksmith_pricer=>ty_amount. + METHODS lockout_price + IMPORTING iv_callout TYPE {{p}}if_locksmith_pricer=>ty_callout + RETURNING VALUE(rv_price) TYPE {{p}}if_locksmith_pricer=>ty_amount. + METHODS dup_key_rate + IMPORTING iv_key_type TYPE {{p}}if_locksmith_pricer=>ty_key_type + RETURNING VALUE(rv_rate) TYPE {{p}}if_locksmith_pricer=>ty_amount. + METHODS rekey_key_rate + IMPORTING iv_key_type TYPE {{p}}if_locksmith_pricer=>ty_key_type + RETURNING VALUE(rv_rate) TYPE {{p}}if_locksmith_pricer=>ty_amount. + METHODS discount_percent + IMPORTING iv_quantity TYPE i + RETURNING VALUE(rv_percent) TYPE {{p}}if_locksmith_pricer=>ty_amount. +ENDCLASS. + + +CLASS {{p}}locksmith_pricer IMPLEMENTATION. + METHOD {{p}}if_locksmith_pricer~calculate_price. + CASE iv_job_type. + WHEN c_job_key. + rv_price = duplicate_price( iv_quantity = iv_quantity + iv_key_type = iv_key_type ). + WHEN c_job_lockout. + rv_price = lockout_price( iv_callout = iv_callout ). + WHEN c_job_rekey. + rv_price = rekey_price( iv_quantity = iv_quantity + iv_key_type = iv_key_type ). + WHEN OTHERS. + rv_price = c_nothing. + ENDCASE. + ENDMETHOD. + + METHOD duplicate_price. + DATA lv_qty TYPE {{p}}if_locksmith_pricer=>ty_amount. + lv_qty = iv_quantity. + IF lv_qty < 1. + RETURN. + ENDIF. + DATA(lv_rate) = dup_key_rate( iv_key_type ). + IF lv_rate = 0. + RETURN. + ENDIF. + DATA lv_gross TYPE {{p}}if_locksmith_pricer=>ty_amount. + lv_gross = lv_rate / lv_qty. + DATA(lv_discount) = discount_percent( iv_quantity ). + rv_price = lv_gross - lv_gross * lv_discount / c_percent. + ENDMETHOD. + + METHOD rekey_price. + DATA lv_qty TYPE {{p}}if_locksmith_pricer=>ty_amount. + lv_qty = iv_quantity. + IF lv_qty < 1. + RETURN. + ENDIF. + DATA(lv_rate) = rekey_key_rate( iv_key_type ). + IF lv_rate = 0. + RETURN. + ENDIF. + rv_price = lv_qty * ( c_rekey_base + lv_rate ). + ENDMETHOD. + + METHOD lockout_price. + CASE iv_callout. + WHEN c_call_week. + rv_price = c_fee_week. + WHEN c_call_late. + rv_price = c_fee_late. + WHEN OTHERS. + rv_price = c_fee_std. + ENDCASE. + ENDMETHOD. + + METHOD dup_key_rate. + CASE iv_key_type. + WHEN c_key_std. + rv_rate = c_rate_dup_s. + WHEN c_key_sec. + rv_rate = c_rate_dup_y. + WHEN c_key_elec. + rv_rate = c_rate_dup_e. + WHEN OTHERS. + rv_rate = c_nothing. + ENDCASE. + ENDMETHOD. + + METHOD rekey_key_rate. + CASE iv_key_type. + WHEN c_key_std. + rv_rate = c_rate_rek_s. + WHEN c_key_sec. + rv_rate = c_rate_rek_y. + WHEN c_key_elec. + rv_rate = c_rate_rek_e. + WHEN OTHERS. + rv_rate = c_nothing. + ENDCASE. + ENDMETHOD. + + METHOD discount_percent. + IF iv_quantity >= c_qty_high. + rv_percent = c_disc_high. + ELSEIF iv_quantity >= c_qty_mid. + rv_percent = c_disc_mid. + ELSE. + rv_percent = c_nothing. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0191/faulty/m3_locksmith_pricer.clas.abap b/tasks_gen/eval/G0191/faulty/m3_locksmith_pricer.clas.abap new file mode 100644 index 0000000..7f1b370 --- /dev/null +++ b/tasks_gen/eval/G0191/faulty/m3_locksmith_pricer.clas.abap @@ -0,0 +1,146 @@ +CLASS {{p}}locksmith_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_locksmith_pricer. + + PRIVATE SECTION. + CONSTANTS: + c_job_key TYPE {{p}}if_locksmith_pricer=>ty_job_type VALUE 'K', + c_job_lockout TYPE {{p}}if_locksmith_pricer=>ty_job_type VALUE 'L', + c_job_rekey TYPE {{p}}if_locksmith_pricer=>ty_job_type VALUE 'R', + c_key_std TYPE {{p}}if_locksmith_pricer=>ty_key_type VALUE 'S', + c_key_sec TYPE {{p}}if_locksmith_pricer=>ty_key_type VALUE 'Y', + c_key_elec TYPE {{p}}if_locksmith_pricer=>ty_key_type VALUE 'E', + c_call_late TYPE {{p}}if_locksmith_pricer=>ty_callout VALUE 'A', + c_call_week TYPE {{p}}if_locksmith_pricer=>ty_callout VALUE 'W', + c_fee_std TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '89.00', + c_fee_late TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '149.00', + c_fee_week TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '179.00', + c_rekey_base TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '35.00', + c_rate_dup_s TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '4.50', + c_rate_dup_y TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '9.80', + c_rate_dup_e TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '24.00', + c_rate_rek_s TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '6.00', + c_rate_rek_y TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '11.00', + c_rate_rek_e TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '26.00', + c_qty_mid TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '5.00', + c_qty_high TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '20.00', + c_disc_mid TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '10.00', + c_disc_high TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '20.00', + c_percent TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '100.00', + c_nothing TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '0.00'. + + METHODS duplicate_price + IMPORTING iv_quantity TYPE i + iv_key_type TYPE {{p}}if_locksmith_pricer=>ty_key_type + RETURNING VALUE(rv_price) TYPE {{p}}if_locksmith_pricer=>ty_amount. + METHODS rekey_price + IMPORTING iv_quantity TYPE i + iv_key_type TYPE {{p}}if_locksmith_pricer=>ty_key_type + RETURNING VALUE(rv_price) TYPE {{p}}if_locksmith_pricer=>ty_amount. + METHODS lockout_price + IMPORTING iv_callout TYPE {{p}}if_locksmith_pricer=>ty_callout + RETURNING VALUE(rv_price) TYPE {{p}}if_locksmith_pricer=>ty_amount. + METHODS dup_key_rate + IMPORTING iv_key_type TYPE {{p}}if_locksmith_pricer=>ty_key_type + RETURNING VALUE(rv_rate) TYPE {{p}}if_locksmith_pricer=>ty_amount. + METHODS rekey_key_rate + IMPORTING iv_key_type TYPE {{p}}if_locksmith_pricer=>ty_key_type + RETURNING VALUE(rv_rate) TYPE {{p}}if_locksmith_pricer=>ty_amount. + METHODS discount_percent + IMPORTING iv_quantity TYPE i + RETURNING VALUE(rv_percent) TYPE {{p}}if_locksmith_pricer=>ty_amount. +ENDCLASS. + + +CLASS {{p}}locksmith_pricer IMPLEMENTATION. + METHOD {{p}}if_locksmith_pricer~calculate_price. + CASE iv_job_type. + WHEN c_job_key. + rv_price = duplicate_price( iv_quantity = iv_quantity + iv_key_type = iv_key_type ). + WHEN c_job_lockout. + rv_price = lockout_price( iv_callout = iv_callout ). + WHEN c_job_rekey. + rv_price = rekey_price( iv_quantity = iv_quantity + iv_key_type = iv_key_type ). + WHEN OTHERS. + rv_price = c_nothing. + ENDCASE. + ENDMETHOD. + + METHOD duplicate_price. + DATA lv_qty TYPE {{p}}if_locksmith_pricer=>ty_amount. + lv_qty = iv_quantity. + IF lv_qty < 1. + RETURN. + ENDIF. + DATA(lv_rate) = dup_key_rate( iv_key_type ). + IF lv_rate = 0. + RETURN. + ENDIF. + DATA lv_gross TYPE {{p}}if_locksmith_pricer=>ty_amount. + lv_gross = lv_rate * lv_qty. + DATA(lv_discount) = discount_percent( iv_quantity ). + rv_price = lv_gross - lv_gross * lv_discount / c_percent. + ENDMETHOD. + + METHOD rekey_price. + DATA lv_qty TYPE {{p}}if_locksmith_pricer=>ty_amount. + lv_qty = iv_quantity. + IF lv_qty < 1. + RETURN. + ENDIF. + DATA(lv_rate) = rekey_key_rate( iv_key_type ). + IF lv_rate <> 0. + RETURN. + ENDIF. + rv_price = lv_qty * ( c_rekey_base + lv_rate ). + ENDMETHOD. + + METHOD lockout_price. + CASE iv_callout. + WHEN c_call_week. + rv_price = c_fee_week. + WHEN c_call_late. + rv_price = c_fee_late. + WHEN OTHERS. + rv_price = c_fee_std. + ENDCASE. + ENDMETHOD. + + METHOD dup_key_rate. + CASE iv_key_type. + WHEN c_key_std. + rv_rate = c_rate_dup_s. + WHEN c_key_sec. + rv_rate = c_rate_dup_y. + WHEN c_key_elec. + rv_rate = c_rate_dup_e. + WHEN OTHERS. + rv_rate = c_nothing. + ENDCASE. + ENDMETHOD. + + METHOD rekey_key_rate. + CASE iv_key_type. + WHEN c_key_std. + rv_rate = c_rate_rek_s. + WHEN c_key_sec. + rv_rate = c_rate_rek_y. + WHEN c_key_elec. + rv_rate = c_rate_rek_e. + WHEN OTHERS. + rv_rate = c_nothing. + ENDCASE. + ENDMETHOD. + + METHOD discount_percent. + IF iv_quantity >= c_qty_high. + rv_percent = c_disc_high. + ELSEIF iv_quantity >= c_qty_mid. + rv_percent = c_disc_mid. + ELSE. + rv_percent = c_nothing. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0191/faulty/m4_locksmith_pricer.clas.abap b/tasks_gen/eval/G0191/faulty/m4_locksmith_pricer.clas.abap new file mode 100644 index 0000000..ef527c8 --- /dev/null +++ b/tasks_gen/eval/G0191/faulty/m4_locksmith_pricer.clas.abap @@ -0,0 +1,146 @@ +CLASS {{p}}locksmith_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_locksmith_pricer. + + PRIVATE SECTION. + CONSTANTS: + c_job_key TYPE {{p}}if_locksmith_pricer=>ty_job_type VALUE 'K', + c_job_lockout TYPE {{p}}if_locksmith_pricer=>ty_job_type VALUE 'L', + c_job_rekey TYPE {{p}}if_locksmith_pricer=>ty_job_type VALUE 'R', + c_key_std TYPE {{p}}if_locksmith_pricer=>ty_key_type VALUE 'S', + c_key_sec TYPE {{p}}if_locksmith_pricer=>ty_key_type VALUE 'Y', + c_key_elec TYPE {{p}}if_locksmith_pricer=>ty_key_type VALUE 'E', + c_call_late TYPE {{p}}if_locksmith_pricer=>ty_callout VALUE 'A', + c_call_week TYPE {{p}}if_locksmith_pricer=>ty_callout VALUE 'W', + c_fee_std TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '89.00', + c_fee_late TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '149.00', + c_fee_week TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '179.00', + c_rekey_base TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '35.00', + c_rate_dup_s TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '4.50', + c_rate_dup_y TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '9.80', + c_rate_dup_e TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '24.00', + c_rate_rek_s TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '6.00', + c_rate_rek_y TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '11.00', + c_rate_rek_e TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '26.00', + c_qty_mid TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '5.00', + c_qty_high TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '20.00', + c_disc_mid TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '10.00', + c_disc_high TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '20.00', + c_percent TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '100.00', + c_nothing TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '0.00'. + + METHODS duplicate_price + IMPORTING iv_quantity TYPE i + iv_key_type TYPE {{p}}if_locksmith_pricer=>ty_key_type + RETURNING VALUE(rv_price) TYPE {{p}}if_locksmith_pricer=>ty_amount. + METHODS rekey_price + IMPORTING iv_quantity TYPE i + iv_key_type TYPE {{p}}if_locksmith_pricer=>ty_key_type + RETURNING VALUE(rv_price) TYPE {{p}}if_locksmith_pricer=>ty_amount. + METHODS lockout_price + IMPORTING iv_callout TYPE {{p}}if_locksmith_pricer=>ty_callout + RETURNING VALUE(rv_price) TYPE {{p}}if_locksmith_pricer=>ty_amount. + METHODS dup_key_rate + IMPORTING iv_key_type TYPE {{p}}if_locksmith_pricer=>ty_key_type + RETURNING VALUE(rv_rate) TYPE {{p}}if_locksmith_pricer=>ty_amount. + METHODS rekey_key_rate + IMPORTING iv_key_type TYPE {{p}}if_locksmith_pricer=>ty_key_type + RETURNING VALUE(rv_rate) TYPE {{p}}if_locksmith_pricer=>ty_amount. + METHODS discount_percent + IMPORTING iv_quantity TYPE i + RETURNING VALUE(rv_percent) TYPE {{p}}if_locksmith_pricer=>ty_amount. +ENDCLASS. + + +CLASS {{p}}locksmith_pricer IMPLEMENTATION. + METHOD {{p}}if_locksmith_pricer~calculate_price. + CASE iv_job_type. + WHEN c_job_key. + rv_price = duplicate_price( iv_quantity = iv_quantity + iv_key_type = iv_key_type ). + WHEN c_job_lockout. + rv_price = lockout_price( iv_callout = iv_callout ). + WHEN c_job_rekey. + rv_price = rekey_price( iv_quantity = iv_quantity + iv_key_type = iv_key_type ). + WHEN OTHERS. + rv_price = c_nothing. + ENDCASE. + ENDMETHOD. + + METHOD duplicate_price. + DATA lv_qty TYPE {{p}}if_locksmith_pricer=>ty_amount. + lv_qty = iv_quantity. + IF lv_qty < 1. + RETURN. + ENDIF. + DATA(lv_rate) = dup_key_rate( iv_key_type ). + IF lv_rate = 0. + RETURN. + ENDIF. + DATA lv_gross TYPE {{p}}if_locksmith_pricer=>ty_amount. + lv_gross = lv_rate * lv_qty. + DATA(lv_discount) = discount_percent( iv_quantity ). + rv_price = lv_gross - lv_gross * lv_discount / c_percent. + ENDMETHOD. + + METHOD rekey_price. + DATA lv_qty TYPE {{p}}if_locksmith_pricer=>ty_amount. + lv_qty = iv_quantity. + IF lv_qty < 1. + RETURN. + ENDIF. + DATA(lv_rate) = rekey_key_rate( iv_key_type ). + IF lv_rate = 0. + RETURN. + ENDIF. + rv_price = lv_qty * ( c_rekey_base - lv_rate ). + ENDMETHOD. + + METHOD lockout_price. + CASE iv_callout. + WHEN c_call_week. + rv_price = c_fee_week. + WHEN c_call_late. + rv_price = c_fee_late. + WHEN OTHERS. + rv_price = c_fee_std. + ENDCASE. + ENDMETHOD. + + METHOD dup_key_rate. + CASE iv_key_type. + WHEN c_key_std. + rv_rate = c_rate_dup_s. + WHEN c_key_sec. + rv_rate = c_rate_dup_y. + WHEN c_key_elec. + rv_rate = c_rate_dup_e. + WHEN OTHERS. + rv_rate = c_nothing. + ENDCASE. + ENDMETHOD. + + METHOD rekey_key_rate. + CASE iv_key_type. + WHEN c_key_std. + rv_rate = c_rate_rek_s. + WHEN c_key_sec. + rv_rate = c_rate_rek_y. + WHEN c_key_elec. + rv_rate = c_rate_rek_e. + WHEN OTHERS. + rv_rate = c_nothing. + ENDCASE. + ENDMETHOD. + + METHOD discount_percent. + IF iv_quantity >= c_qty_high. + rv_percent = c_disc_high. + ELSEIF iv_quantity >= c_qty_mid. + rv_percent = c_disc_mid. + ELSE. + rv_percent = c_nothing. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0191/generation.json b/tasks_gen/eval/G0191/generation.json new file mode 100644 index 0000000..5242faf --- /dev/null +++ b/tasks_gen/eval/G0191/generation.json @@ -0,0 +1,24 @@ +{ + "id": "G0191", + "pool": "eval", + "object_type": "CLAS", + "category": "E", + "attempts": [ + { + "stage": "validate", + "oracle": 85.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/eval/G0191/hidden/t_locksmith_hidden.clas.abap b/tasks_gen/eval/G0191/hidden/t_locksmith_hidden.clas.abap new file mode 100644 index 0000000..619ca98 --- /dev/null +++ b/tasks_gen/eval/G0191/hidden/t_locksmith_hidden.clas.abap @@ -0,0 +1,151 @@ +CLASS {{p}}t_locksmith_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC + FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + DATA mo_cut TYPE REF TO {{p}}if_locksmith_pricer. + METHODS setup. + METHODS dup_standard_basic FOR TESTING. + METHODS dup_discount_from_five FOR TESTING. + METHODS dup_discount_from_twenty FOR TESTING. + METHODS dup_no_discount_for_four FOR TESTING. + METHODS dup_zero_quantity FOR TESTING. + METHODS unknown_key_type FOR TESTING. + METHODS lockout_standard FOR TESTING. + METHODS lockout_after_hours FOR TESTING. + METHODS lockout_weekend FOR TESTING. + METHODS rekey_standard FOR TESTING. + METHODS rekey_electronic FOR TESTING. + METHODS unknown_job_type FOR TESTING. + METHODS assert_price + IMPORTING iv_expected TYPE {{p}}if_locksmith_pricer=>ty_amount + iv_actual TYPE {{p}}if_locksmith_pricer=>ty_amount + iv_msg TYPE string DEFAULT ''. +ENDCLASS. + + +CLASS {{p}}t_locksmith_hidden IMPLEMENTATION. + METHOD setup. + mo_cut = NEW {{p}}locksmith_pricer( ). + ENDMETHOD. + + METHOD dup_standard_basic. + assert_price( + iv_expected = '13.50' + iv_actual = mo_cut->calculate_price( iv_job_type = 'K' + iv_quantity = 3 + iv_key_type = 'S' + iv_callout = 'N' ) ). + ENDMETHOD. + + METHOD dup_discount_from_five. + assert_price( + iv_expected = '20.25' + iv_actual = mo_cut->calculate_price( iv_job_type = 'K' + iv_quantity = 5 + iv_key_type = 'S' + iv_callout = 'N' ) ). + ENDMETHOD. + + METHOD dup_discount_from_twenty. + assert_price( + iv_expected = '156.80' + iv_actual = mo_cut->calculate_price( iv_job_type = 'K' + iv_quantity = 20 + iv_key_type = 'Y' + iv_callout = 'N' ) ). + ENDMETHOD. + + METHOD dup_no_discount_for_four. + assert_price( + iv_expected = '96.00' + iv_actual = mo_cut->calculate_price( iv_job_type = 'K' + iv_quantity = 4 + iv_key_type = 'E' + iv_callout = 'N' ) ). + ENDMETHOD. + + METHOD dup_zero_quantity. + assert_price( + iv_expected = '0.00' + iv_actual = mo_cut->calculate_price( iv_job_type = 'K' + iv_quantity = 0 + iv_key_type = 'S' + iv_callout = 'N' ) ). + ENDMETHOD. + + METHOD unknown_key_type. + assert_price( + iv_expected = '0.00' + iv_msg = 'duplicate' + iv_actual = mo_cut->calculate_price( iv_job_type = 'K' + iv_quantity = 3 + iv_key_type = 'X' + iv_callout = 'N' ) ). + assert_price( + iv_expected = '0.00' + iv_msg = 'rekey' + iv_actual = mo_cut->calculate_price( iv_job_type = 'R' + iv_quantity = 2 + iv_key_type = 'X' + iv_callout = 'N' ) ). + ENDMETHOD. + + METHOD lockout_standard. + assert_price( + iv_expected = '89.00' + iv_actual = mo_cut->calculate_price( iv_job_type = 'L' + iv_quantity = 5 + iv_key_type = 'X' + iv_callout = 'N' ) ). + ENDMETHOD. + + METHOD lockout_after_hours. + assert_price( + iv_expected = '149.00' + iv_actual = mo_cut->calculate_price( iv_job_type = 'L' + iv_quantity = 0 + iv_key_type = 'X' + iv_callout = 'A' ) ). + ENDMETHOD. + + METHOD lockout_weekend. + assert_price( + iv_expected = '179.00' + iv_actual = mo_cut->calculate_price( iv_job_type = 'L' + iv_quantity = 0 + iv_key_type = 'X' + iv_callout = 'W' ) ). + ENDMETHOD. + + METHOD rekey_standard. + assert_price( + iv_expected = '82.00' + iv_actual = mo_cut->calculate_price( iv_job_type = 'R' + iv_quantity = 2 + iv_key_type = 'S' + iv_callout = 'N' ) ). + ENDMETHOD. + + METHOD rekey_electronic. + assert_price( + iv_expected = '61.00' + iv_actual = mo_cut->calculate_price( iv_job_type = 'R' + iv_quantity = 1 + iv_key_type = 'E' + iv_callout = 'N' ) ). + ENDMETHOD. + + METHOD unknown_job_type. + assert_price( + iv_expected = '0.00' + iv_actual = mo_cut->calculate_price( iv_job_type = 'X' + iv_quantity = 1 + iv_key_type = 'S' + iv_callout = 'N' ) ). + ENDMETHOD. + + METHOD assert_price. + cl_abap_unit_assert=>assert_equals( exp = iv_expected + act = iv_actual + msg = iv_msg ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0191/mutation.json b/tasks_gen/eval/G0191/mutation.json new file mode 100644 index 0000000..328b321 --- /dev/null +++ b/tasks_gen/eval/G0191/mutation.json @@ -0,0 +1,66 @@ +{ + "task": "G0191", + "mutants": [ + { + "object": "{{P}}LOCKSMITH_PRICER", + "mutant": "line 74: < -> >= (rel)", + "status": "killed", + "hidden": "8/12", + "failed_tests": [ + "DUP_DISCOUNT_FROM_FIVE", + "DUP_DISCOUNT_FROM_TWENTY", + "DUP_NO_DISCOUNT_FOR_FOUR", + "DUP_STANDARD_BASIC" + ] + }, + { + "object": "{{P}}LOCKSMITH_PRICER", + "mutant": "line 78: = -> <> (eq)", + "status": "killed", + "hidden": "8/12", + "failed_tests": [ + "DUP_DISCOUNT_FROM_FIVE", + "DUP_DISCOUNT_FROM_TWENTY", + "DUP_NO_DISCOUNT_FOR_FOUR", + "DUP_STANDARD_BASIC" + ] + }, + { + "object": "{{P}}LOCKSMITH_PRICER", + "mutant": "line 82: * -> / (arith)", + "status": "killed", + "hidden": "8/12", + "failed_tests": [ + "DUP_DISCOUNT_FROM_FIVE", + "DUP_DISCOUNT_FROM_TWENTY", + "DUP_NO_DISCOUNT_FOR_FOUR", + "DUP_STANDARD_BASIC" + ] + }, + { + "object": "{{P}}LOCKSMITH_PRICER", + "mutant": "line 94: = -> <> (eq)", + "status": "killed", + "hidden": "9/12", + "failed_tests": [ + "REKEY_ELECTRONIC", + "REKEY_STANDARD", + "UNKNOWN_KEY_TYPE" + ] + }, + { + "object": "{{P}}LOCKSMITH_PRICER", + "mutant": "line 97: + -> - (arith)", + "status": "killed", + "hidden": "10/12", + "failed_tests": [ + "REKEY_ELECTRONIC", + "REKEY_STANDARD" + ] + } + ], + "valid": 5, + "killed": 5, + "kill_rate": 1.0, + "ok": true +} \ No newline at end of file diff --git a/tasks_gen/eval/G0191/reference/locksmith_pricer.clas.abap b/tasks_gen/eval/G0191/reference/locksmith_pricer.clas.abap new file mode 100644 index 0000000..2c45dca --- /dev/null +++ b/tasks_gen/eval/G0191/reference/locksmith_pricer.clas.abap @@ -0,0 +1,146 @@ +CLASS {{p}}locksmith_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_locksmith_pricer. + + PRIVATE SECTION. + CONSTANTS: + c_job_key TYPE {{p}}if_locksmith_pricer=>ty_job_type VALUE 'K', + c_job_lockout TYPE {{p}}if_locksmith_pricer=>ty_job_type VALUE 'L', + c_job_rekey TYPE {{p}}if_locksmith_pricer=>ty_job_type VALUE 'R', + c_key_std TYPE {{p}}if_locksmith_pricer=>ty_key_type VALUE 'S', + c_key_sec TYPE {{p}}if_locksmith_pricer=>ty_key_type VALUE 'Y', + c_key_elec TYPE {{p}}if_locksmith_pricer=>ty_key_type VALUE 'E', + c_call_late TYPE {{p}}if_locksmith_pricer=>ty_callout VALUE 'A', + c_call_week TYPE {{p}}if_locksmith_pricer=>ty_callout VALUE 'W', + c_fee_std TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '89.00', + c_fee_late TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '149.00', + c_fee_week TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '179.00', + c_rekey_base TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '35.00', + c_rate_dup_s TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '4.50', + c_rate_dup_y TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '9.80', + c_rate_dup_e TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '24.00', + c_rate_rek_s TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '6.00', + c_rate_rek_y TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '11.00', + c_rate_rek_e TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '26.00', + c_qty_mid TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '5.00', + c_qty_high TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '20.00', + c_disc_mid TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '10.00', + c_disc_high TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '20.00', + c_percent TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '100.00', + c_nothing TYPE {{p}}if_locksmith_pricer=>ty_amount VALUE '0.00'. + + METHODS duplicate_price + IMPORTING iv_quantity TYPE i + iv_key_type TYPE {{p}}if_locksmith_pricer=>ty_key_type + RETURNING VALUE(rv_price) TYPE {{p}}if_locksmith_pricer=>ty_amount. + METHODS rekey_price + IMPORTING iv_quantity TYPE i + iv_key_type TYPE {{p}}if_locksmith_pricer=>ty_key_type + RETURNING VALUE(rv_price) TYPE {{p}}if_locksmith_pricer=>ty_amount. + METHODS lockout_price + IMPORTING iv_callout TYPE {{p}}if_locksmith_pricer=>ty_callout + RETURNING VALUE(rv_price) TYPE {{p}}if_locksmith_pricer=>ty_amount. + METHODS dup_key_rate + IMPORTING iv_key_type TYPE {{p}}if_locksmith_pricer=>ty_key_type + RETURNING VALUE(rv_rate) TYPE {{p}}if_locksmith_pricer=>ty_amount. + METHODS rekey_key_rate + IMPORTING iv_key_type TYPE {{p}}if_locksmith_pricer=>ty_key_type + RETURNING VALUE(rv_rate) TYPE {{p}}if_locksmith_pricer=>ty_amount. + METHODS discount_percent + IMPORTING iv_quantity TYPE i + RETURNING VALUE(rv_percent) TYPE {{p}}if_locksmith_pricer=>ty_amount. +ENDCLASS. + + +CLASS {{p}}locksmith_pricer IMPLEMENTATION. + METHOD {{p}}if_locksmith_pricer~calculate_price. + CASE iv_job_type. + WHEN c_job_key. + rv_price = duplicate_price( iv_quantity = iv_quantity + iv_key_type = iv_key_type ). + WHEN c_job_lockout. + rv_price = lockout_price( iv_callout = iv_callout ). + WHEN c_job_rekey. + rv_price = rekey_price( iv_quantity = iv_quantity + iv_key_type = iv_key_type ). + WHEN OTHERS. + rv_price = c_nothing. + ENDCASE. + ENDMETHOD. + + METHOD duplicate_price. + DATA lv_qty TYPE {{p}}if_locksmith_pricer=>ty_amount. + lv_qty = iv_quantity. + IF lv_qty < 1. + RETURN. + ENDIF. + DATA(lv_rate) = dup_key_rate( iv_key_type ). + IF lv_rate = 0. + RETURN. + ENDIF. + DATA lv_gross TYPE {{p}}if_locksmith_pricer=>ty_amount. + lv_gross = lv_rate * lv_qty. + DATA(lv_discount) = discount_percent( iv_quantity ). + rv_price = lv_gross - lv_gross * lv_discount / c_percent. + ENDMETHOD. + + METHOD rekey_price. + DATA lv_qty TYPE {{p}}if_locksmith_pricer=>ty_amount. + lv_qty = iv_quantity. + IF lv_qty < 1. + RETURN. + ENDIF. + DATA(lv_rate) = rekey_key_rate( iv_key_type ). + IF lv_rate = 0. + RETURN. + ENDIF. + rv_price = lv_qty * ( c_rekey_base + lv_rate ). + ENDMETHOD. + + METHOD lockout_price. + CASE iv_callout. + WHEN c_call_week. + rv_price = c_fee_week. + WHEN c_call_late. + rv_price = c_fee_late. + WHEN OTHERS. + rv_price = c_fee_std. + ENDCASE. + ENDMETHOD. + + METHOD dup_key_rate. + CASE iv_key_type. + WHEN c_key_std. + rv_rate = c_rate_dup_s. + WHEN c_key_sec. + rv_rate = c_rate_dup_y. + WHEN c_key_elec. + rv_rate = c_rate_dup_e. + WHEN OTHERS. + rv_rate = c_nothing. + ENDCASE. + ENDMETHOD. + + METHOD rekey_key_rate. + CASE iv_key_type. + WHEN c_key_std. + rv_rate = c_rate_rek_s. + WHEN c_key_sec. + rv_rate = c_rate_rek_y. + WHEN c_key_elec. + rv_rate = c_rate_rek_e. + WHEN OTHERS. + rv_rate = c_nothing. + ENDCASE. + ENDMETHOD. + + METHOD discount_percent. + IF iv_quantity >= c_qty_high. + rv_percent = c_disc_high. + ELSEIF iv_quantity >= c_qty_mid. + rv_percent = c_disc_mid. + ELSE. + rv_percent = c_nothing. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0191/reference/locksmith_pricer.testclasses.abap b/tasks_gen/eval/G0191/reference/locksmith_pricer.testclasses.abap new file mode 100644 index 0000000..08c483f --- /dev/null +++ b/tasks_gen/eval/G0191/reference/locksmith_pricer.testclasses.abap @@ -0,0 +1,74 @@ +CLASS ltc_locksmith_pricer DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + PRIVATE SECTION. + DATA mo_cut TYPE REF TO {{p}}if_locksmith_pricer. + METHODS setup. + METHODS dup_standard FOR TESTING. + METHODS dup_discount FOR TESTING. + METHODS dup_high_discount FOR TESTING. + METHODS lockout_late FOR TESTING. + METHODS rekey_standard FOR TESTING. + METHODS unknown_job FOR TESTING. + METHODS assert_price + IMPORTING iv_expected TYPE {{p}}if_locksmith_pricer=>ty_amount + iv_actual TYPE {{p}}if_locksmith_pricer=>ty_amount. +ENDCLASS. + + +CLASS ltc_locksmith_pricer IMPLEMENTATION. + METHOD setup. + mo_cut = NEW {{p}}locksmith_pricer( ). + ENDMETHOD. + + METHOD dup_standard. + assert_price( iv_expected = '13.50' + iv_actual = mo_cut->calculate_price( iv_job_type = 'K' + iv_quantity = 3 + iv_key_type = 'S' + iv_callout = 'N' ) ). + ENDMETHOD. + + METHOD dup_discount. + assert_price( iv_expected = '20.25' + iv_actual = mo_cut->calculate_price( iv_job_type = 'K' + iv_quantity = 5 + iv_key_type = 'S' + iv_callout = 'N' ) ). + ENDMETHOD. + + METHOD dup_high_discount. + assert_price( iv_expected = '156.80' + iv_actual = mo_cut->calculate_price( iv_job_type = 'K' + iv_quantity = 20 + iv_key_type = 'Y' + iv_callout = 'N' ) ). + ENDMETHOD. + + METHOD lockout_late. + assert_price( iv_expected = '149.00' + iv_actual = mo_cut->calculate_price( iv_job_type = 'L' + iv_quantity = 0 + iv_key_type = 'X' + iv_callout = 'A' ) ). + ENDMETHOD. + + METHOD rekey_standard. + assert_price( iv_expected = '82.00' + iv_actual = mo_cut->calculate_price( iv_job_type = 'R' + iv_quantity = 2 + iv_key_type = 'S' + iv_callout = 'N' ) ). + ENDMETHOD. + + METHOD unknown_job. + assert_price( iv_expected = '0.00' + iv_actual = mo_cut->calculate_price( iv_job_type = 'X' + iv_quantity = 1 + iv_key_type = 'S' + iv_callout = 'N' ) ). + ENDMETHOD. + + METHOD assert_price. + cl_abap_unit_assert=>assert_equals( exp = iv_expected + act = iv_actual ). + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0191/seed/if_locksmith_pricer.intf.abap b/tasks_gen/eval/G0191/seed/if_locksmith_pricer.intf.abap new file mode 100644 index 0000000..520fb04 --- /dev/null +++ b/tasks_gen/eval/G0191/seed/if_locksmith_pricer.intf.abap @@ -0,0 +1,12 @@ +INTERFACE {{p}}if_locksmith_pricer PUBLIC. + TYPES ty_job_type TYPE c LENGTH 1. + TYPES ty_key_type TYPE c LENGTH 1. + TYPES ty_callout TYPE c LENGTH 1. + TYPES ty_amount TYPE p LENGTH 9 DECIMALS 2. + METHODS calculate_price + IMPORTING iv_job_type TYPE ty_job_type + iv_quantity TYPE i + iv_key_type TYPE ty_key_type + iv_callout TYPE ty_callout + RETURNING VALUE(rv_price) TYPE ty_amount. +ENDINTERFACE. diff --git a/tasks_gen/eval/G0191/seed/locksmith_pricer.clas.abap b/tasks_gen/eval/G0191/seed/locksmith_pricer.clas.abap new file mode 100644 index 0000000..c6a29d5 --- /dev/null +++ b/tasks_gen/eval/G0191/seed/locksmith_pricer.clas.abap @@ -0,0 +1,77 @@ +CLASS {{p}}locksmith_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC. + PUBLIC SECTION. + INTERFACES {{p}}if_locksmith_pricer. +ENDCLASS. + + +CLASS {{p}}locksmith_pricer IMPLEMENTATION. + METHOD {{p}}if_locksmith_pricer~calculate_price. + DATA lv_qty TYPE p LENGTH 9 DECIMALS 2. + DATA lv_rate TYPE p LENGTH 9 DECIMALS 2. + DATA lv_base TYPE p LENGTH 9 DECIMALS 2. + DATA lv_disc TYPE p LENGTH 9 DECIMALS 2. + DATA lv_hundred TYPE p LENGTH 9 DECIMALS 2. + + lv_qty = iv_quantity. + lv_hundred = '100.00'. + + IF iv_job_type = 'K'. + IF lv_qty < 1. + rv_price = '0.00'. + ELSE. + IF iv_key_type = 'S'. + lv_rate = '4.50'. + ELSEIF iv_key_type = 'Y'. + lv_rate = '9.80'. + ELSEIF iv_key_type = 'E'. + lv_rate = '24.00'. + ELSE. + lv_rate = '0.00'. + ENDIF. + IF lv_rate = 0. + rv_price = '0.00'. + ELSE. + lv_base = lv_rate * lv_qty. + IF lv_qty >= 20. + lv_disc = '20.00'. + ELSEIF lv_qty >= 5. + lv_disc = '10.00'. + ELSE. + lv_disc = '0.00'. + ENDIF. + rv_price = lv_base - lv_base * lv_disc / lv_hundred. + ENDIF. + ENDIF. + ELSEIF iv_job_type = 'L'. + IF iv_callout = 'W'. + rv_price = '179.00'. + ELSEIF iv_callout = 'A'. + rv_price = '149.00'. + ELSE. + rv_price = '89.00'. + ENDIF. + ELSEIF iv_job_type = 'R'. + IF lv_qty < 1. + rv_price = '0.00'. + ELSE. + IF iv_key_type = 'S'. + lv_rate = '6.00'. + ELSEIF iv_key_type = 'Y'. + lv_rate = '11.00'. + ELSEIF iv_key_type = 'E'. + lv_rate = '26.00'. + ELSE. + lv_rate = '0.00'. + ENDIF. + IF lv_rate = 0. + rv_price = '0.00'. + ELSE. + lv_base = '35.00'. + rv_price = lv_qty * ( lv_base + lv_rate ). + ENDIF. + ENDIF. + ELSE. + rv_price = '0.00'. + ENDIF. + ENDMETHOD. +ENDCLASS. diff --git a/tasks_gen/eval/G0191/spec.md b/tasks_gen/eval/G0191/spec.md new file mode 100644 index 0000000..2473407 --- /dev/null +++ b/tasks_gen/eval/G0191/spec.md @@ -0,0 +1,55 @@ +# 1. Goal +Refactor the class {{P}}LOCKSMITH_PRICER in package $TMP. A locksmith shop uses +the class to price its jobs. The class works, but the code is hard to read and +hard to maintain. Make the code clean. The behavior stays the same. + +# 2. Open questions +None. + +# 3. Context +- The interface {{P}}IF_LOCKSMITH_PRICER exists in package $TMP. It is active. +- The interface has the types TY_JOB_TYPE (CHAR 1), TY_KEY_TYPE (CHAR 1), + TY_CALLOUT (CHAR 1) and TY_AMOUNT (packed number, length 9, 2 decimals). +- The interface has one method CALCULATE_PRICE. The importing parameters are + IV_JOB_TYPE, IV_QUANTITY, IV_KEY_TYPE and IV_CALLOUT. The returning parameter + is RV_PRICE. +- The class {{P}}LOCKSMITH_PRICER exists in package $TMP. It is active, public + and final. It implements {{P}}IF_LOCKSMITH_PRICER. +- The class has no other public members. +- A job is a key duplication (job type K), a lockout (job type L) or a rekey of + a cylinder (job type R). + +# 4. Contract +- Keep the class {{P}}LOCKSMITH_PRICER in package $TMP. +- The class stays public and final. +- The class stays an implementation of {{P}}IF_LOCKSMITH_PRICER. +- Do not change the interface {{P}}IF_LOCKSMITH_PRICER. +- Do not add other public methods, types, constants or attributes to the class. +- The result of the method CALCULATE_PRICE stays the same for every input. + +# 5. Business rules +- The current implementation of the class is the specification of the pricing + rules. Read the code. +- The refactored class must return exactly the same price as the current class + for every possible combination of the input parameters. +- Do not change, add or remove a pricing rule. + +# 6. Constraints +- Release target: SAP_BASIS 816 (ABAP Platform 2025). +- Coding standards: Clean ABAP. + - Every method has fewer than 40 statements. + - The nesting depth of a method is at most three. + - Replace magic numbers with constants that have a meaning. + - One method does one task. Give each method a name that says what it does. + - No global variables. + - No comment that restates the code. +- Out of scope: do not change {{P}}IF_LOCKSMITH_PRICER. Do not rename the class + or the method. Do not change the parameter names, the parameter types or the + parameter order. + +# 7. Acceptance +- The class {{P}}LOCKSMITH_PRICER is active and has no syntax error. +- The class still implements {{P}}IF_LOCKSMITH_PRICER. +- The hidden tests pass. +- The class returns the same prices as before. +- Write your own ABAP Unit tests in the local test classes of the class. diff --git a/tasks_gen/eval/G0191/task.json b/tasks_gen/eval/G0191/task.json new file mode 100644 index 0000000..e0bae88 --- /dev/null +++ b/tasks_gen/eval/G0191/task.json @@ -0,0 +1,58 @@ +{ + "id": "G0191", + "category": "E", + "object_type": "CLAS", + "difficulty": 2, + "release_target": "v816", + "expected_outcome": "implement", + "budget": { + "max_tool_calls": 40, + "max_activations": 10 + }, + "seed": [ + { + "type": "INTF", + "name": "{{P}}IF_LOCKSMITH_PRICER", + "file": "seed/if_locksmith_pricer.intf.abap", + "description": "Interface of the locksmith price calculator" + }, + { + "type": "CLAS", + "name": "{{P}}LOCKSMITH_PRICER", + "file": "seed/locksmith_pricer.clas.abap", + "description": "Legacy locksmith price calculator, refactor target" + } + ], + "contract": [ + { + "type": "CLAS", + "name": "{{P}}LOCKSMITH_PRICER", + "implements": "{{P}}IF_LOCKSMITH_PRICER" + } + ], + "out_of_scope": [ + "{{P}}IF_LOCKSMITH_PRICER" + ], + "hidden_tests": [ + { + "type": "CLAS", + "name": "{{P}}T_LOCKSMITH_HIDDEN", + "file": "hidden/t_locksmith_hidden.clas.abap", + "description": "Behaviour tests for the locksmith price calculator" + } + ], + "reference": [ + { + "type": "CLAS", + "name": "{{P}}LOCKSMITH_PRICER", + "file": "reference/locksmith_pricer.clas.abap", + "description": "Refactored locksmith price calculator", + "testclasses_file": "reference/locksmith_pricer.testclasses.abap" + } + ], + "craft_checks": [ + "method_length", + "nesting_depth", + "magic_numbers" + ] +} \ No newline at end of file