Hard batch G0022-G0026: 5/5 accepted; budget floor, CDS checks, mutation check
- generator: budget floor (2x oracle activations, 3x calls), static checks for CDS $parameters and UNION annotation - harness/mutation.py: deterministic mutants of the reference; hidden tests must fail - G0022 revalidated with harness fixes: oracle 100, null 0 - results in docs/faz1-tasarim.md 11f Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
21
CLAUDE.md
21
CLAUDE.md
@@ -80,7 +80,8 @@ python3 -m harness.cli run T01 --agent oracle|null|llm [--model NAME] --run N
|
|||||||
python3 -m harness.cli rescore runs/<run_dir>
|
python3 -m harness.cli rescore runs/<run_dir>
|
||||||
python3 -m harness.cli cleanup-list <PREFIX> runs/<dir> && python3 -m harness.cli teardown runs/<dir>
|
python3 -m harness.cli cleanup-list <PREFIX> runs/<dir> && python3 -m harness.cli teardown runs/<dir>
|
||||||
python3 -m harness.generator --id G0100 --pool eval --object-type CLAS --category C --run-base 2000
|
python3 -m harness.generator --id G0100 --pool eval --object-type CLAS --category C --run-base 2000
|
||||||
python3 -m harness.pilot 2
|
python3 -m harness.pilot 2 # pilot list; `python3 -m harness.pilot 22 hard 1400` hard batch
|
||||||
|
python3 -m harness.mutation G0002 --pool eval --run-base 5000 [--keep]
|
||||||
python3 -c "from harness.ledger import spent; print(spent())"
|
python3 -c "from harness.ledger import spent; print(spent())"
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -89,18 +90,18 @@ python3 -c "from harness.ledger import spent; print(spent())"
|
|||||||
- Done: harness on Mac mini; test include creation in the server; teardown; FUNC/PROG/DDLS support;
|
- Done: harness on Mac mini; test include creation in the server; teardown; FUNC/PROG/DDLS support;
|
||||||
task generator; ledger and budget guard.
|
task generator; ledger and budget guard.
|
||||||
- Results: T01 oracle 100, Qwen 27B 41.7 (old run 103), DeepSeek 98.5. T13 DeepSeek 85, T14 DeepSeek 100.
|
- Results: T01 oracle 100, Qwen 27B 41.7 (old run 103), DeepSeek 98.5. T13 DeepSeek 85, T14 DeepSeek 100.
|
||||||
- Pilot (G0002–G0021) done: 16/20 accepted, 0.16 USD per accepted task (`runs/gen/pilot.json`,
|
- Pilot (G0002–G0021): 16/20 accepted, 0.16 USD per accepted task (`docs/faz1-tasarim.md` 11e).
|
||||||
analysis in `docs/faz1-tasarim.md` 11e). Generator improved after the pilot: static checks
|
G0020 and G0013 fixed in review and revalidated → 18/20.
|
||||||
(name length, seed type, reserved words, contract/test classes), local abaplint parser check before SAP,
|
- Hard batch (G0022–G0026, 2026-10-03): 5/5 accepted (G0022 after harness fixes), 0.097 USD per accepted
|
||||||
max_tokens 80k, G2 detail in the repair feedback. Runner: G2 works for CDS views with parameters.
|
task, first-attempt 1/5 (`docs/faz1-tasarim.md` 11f).
|
||||||
The improved generator is not yet tested with new tasks.
|
- Generator: static checks, local abaplint parser check, dependency order of seed/reference, budget floor,
|
||||||
- G0020 (rejected) passes with oracle 100 after one fix (remove parameter `default`). G0013 (accepted) has a test
|
max_tokens 80k. Runner: G2 for CDS with parameters, G6 ignores unknown standard superclasses.
|
||||||
class in its contract: fix in review.
|
- Step D: `harness/mutation.py` (deterministic mutants of the reference, hidden tests must fail).
|
||||||
|
|
||||||
## 7. Next steps
|
## 7. Next steps
|
||||||
|
|
||||||
1. Test the improved generator with a small batch (~5 tasks, ~0.7 USD); compare repairs per task with the pilot (2.75 calls).
|
1. Step D: run the mutation check on all accepted tasks; integrate it into the generator.
|
||||||
2. Step D: mutation check (hidden tests must fail on a broken reference).
|
2. Use killed mutants as faulty references for own-test scoring (component (a)).
|
||||||
3. Step F: eval set of 110 tasks: ~150 candidates, empirical filter (2–3 models), Claude review with a
|
3. Step F: eval set of 110 tasks: ~150 candidates, empirical filter (2–3 models), Claude review with a
|
||||||
checklist, Kral spot-checks ~10 flagged tasks.
|
checklist, Kral spot-checks ~10 flagged tasks.
|
||||||
4. Scoring for stop tasks (category H) and category K (free-text input, other tool schema).
|
4. Scoring for stop tasks (category H) and category K (free-text input, other tool schema).
|
||||||
|
|||||||
@@ -576,6 +576,35 @@ Diğer bulgular:
|
|||||||
- Üretilen görevler örnekteki isimleri kopyalıyor (`T02_HIDDEN`, `T14_TEST`). Kozmetik.
|
- Üretilen görevler örnekteki isimleri kopyalıyor (`T02_HIDDEN`, `T14_TEST`). Kozmetik.
|
||||||
- Statik kontrol ve abaplint ön kontrolü SAP'ye gitmez. Pilottaki 37 başarısız denemenin ~18'ini doğrulama koşusundan önce yakalar (tahmin).
|
- Statik kontrol ve abaplint ön kontrolü SAP'ye gitmez. Pilottaki 37 başarısız denemenin ~18'ini doğrulama koşusundan önce yakalar (tahmin).
|
||||||
|
|
||||||
|
## 11f. Zor görev partisi (2026-10-03, G0022–G0026)
|
||||||
|
|
||||||
|
Amaç: pilot sonrası iyileştirmeleri pilotta düşen tiplerle ölçmek. Görevler: CLAS D (exception), CLAS E (packed sayılı eski kod, `LENGTH` tuzağı), parametreli CDS, UNION'lı CDS, FM. Sonuçlar: `runs/gen/hard.json`.
|
||||||
|
|
||||||
|
| | Pilot (20) | Parti (5, zor) |
|
||||||
|
|---|---|---|
|
||||||
|
| İlk denemede kabul | 3/20 (%15) | 1/5 (%20): G0023 |
|
||||||
|
| Toplam kabul | 16/20 | 4/5 üretimde; G0022 harness düzeltmesinden sonra → 5/5 |
|
||||||
|
| LLM çağrısı / görev | 2,75 | 2,6 |
|
||||||
|
| Maliyet / kabul edilen görev | 0,16 $ | **0,097 $** (0,39 $ / 5) |
|
||||||
|
| En büyük çıktı | 393k (kaçak) | 61,5k |
|
||||||
|
|
||||||
|
SAP'ye gitmeden yakalanan hata: **2** (abaplint `parser_error`, G0026 ×2). Statik kontroller bu partide hata bulmadı: 30 karakter, tablo tipi, `LENGTH` hataları tekrar etmedi (prompt kuralları etkili).
|
||||||
|
|
||||||
|
SAP'de düşen 8 doğrulama:
|
||||||
|
|
||||||
|
| Neden | Sayı | Durum |
|
||||||
|
|---|---|---|
|
||||||
|
| Harness: referans objeler bağımlılık sırasında kurulmuyor (G0022, G0026) | 2 | Düzeltildi: generator seed/reference listesini sıraya dizer |
|
||||||
|
| Harness: abaplint `CX_STATIC_CHECK`'i tanımıyor → exception hiyerarşisi G6'da düşer (G0022). LLM koşularında da kategori D'yi 0'a indirirdi | 1 | Düzeltildi: G6 bu mesajı yok sayar (G1 aktivasyonu kontrol eder) |
|
||||||
|
| CDS view entity'de `:p_from` (G0024) | 1 | Statik kontrol + prompt kuralı |
|
||||||
|
| UNION'da `@Metadata.ignorePropagatedAnnotations` yok (G0025) | 1 | Statik kontrol + prompt kuralı |
|
||||||
|
| Referansın kendi testlerinde tip hatası (G0022) | 2 | Onarım turu |
|
||||||
|
| Abaplint hatası; asıl neden G6 harness hatasıydı (G0022) | 1 | Düzeltildi |
|
||||||
|
|
||||||
|
Ek bulgu: G0022'nin bütçesi (12 aktivasyon) referansın kendisine (13) yetmiyordu → oracle disiplinden 5 puan kaybetti. Generator artık bütçeye alt sınır koyar: aktivasyon ≥ 2 × oracle, tool çağrısı ≥ 3 × oracle. Mevcut görevlerden sadece G0022 etkilendi.
|
||||||
|
|
||||||
|
G0022 bundle'ı değiştirilmeden yeniden doğrulandı (harness düzeltmeleri + bütçe): oracle 100, null 0 → kabul.
|
||||||
|
|
||||||
## 12. Açık sorular
|
## 12. Açık sorular
|
||||||
|
|
||||||
Cevaplananlar (Adım 1.2):
|
Cevaplananlar (Adım 1.2):
|
||||||
|
|||||||
@@ -86,8 +86,8 @@ Adım 3 görev ister; görevler el ile yazılırsa darboğaz olur. Bu yüzden il
|
|||||||
| A | Önek şeması: koşu 4 karakter base36, görev 3 karakter base36 (`Z005P001_`) | ✓ |
|
| A | Önek şeması: koşu 4 karakter base36, görev 3 karakter base36 (`Z005P001_`) | ✓ |
|
||||||
| B | Harness: FUGR/FUNC, PROG, DDLS desteği (G2 kontrat kontrolü, abaplint dışa aktarımı, silme sırası) | ✓ T13–T15 oracle 100 / null 0. Server eşzamanlılık sorunu bulundu (harness'te retry) |
|
| B | Harness: FUGR/FUNC, PROG, DDLS desteği (G2 kontrat kontrolü, abaplint dışa aktarımı, silme sırası) | ✓ T13–T15 oracle 100 / null 0. Server eşzamanlılık sorunu bulundu (harness'te retry) |
|
||||||
| C | Görev üreteci: DeepSeek görev yazar (spec, seed, gizli testler, referans + local testler); kategori ve obje tipi dağılımına göre | ✓ `harness/generator.py`: üretim → yapı + statik kontrol + yerel abaplint → oracle/null doğrulama → en fazla 3 onarım turu. Pilot sonrası iyileştirildi (faz1-tasarim 11e) |
|
| C | Görev üreteci: DeepSeek görev yazar (spec, seed, gizli testler, referans + local testler); kategori ve obje tipi dağılımına göre | ✓ `harness/generator.py`: üretim → yapı + statik kontrol + yerel abaplint → oracle/null doğrulama → en fazla 3 onarım turu. Pilot sonrası iyileştirildi (faz1-tasarim 11e) |
|
||||||
| D | Otomatik görev doğrulama: oracle = 100, null = 0, gizli testler bozuk referansta düşmeli | oracle/null hazır; mutasyon kontrolü sonra |
|
| D | Otomatik görev doğrulama: oracle = 100, null = 0, gizli testler bozuk referansta düşmeli | oracle/null hazır; mutasyon kontrolü `harness/mutation.py` (2026-10-03) |
|
||||||
| E | Pilot: ~20 görev, tüm obje tipleri; kabul oranı ve gerçek maliyet ölçümü | ✓ 16/20 kabul, 0,16 $ / kabul edilen görev (faz1-tasarim 11e). İyileştirilmiş generator henüz denenmedi |
|
| E | Pilot: ~20 görev, tüm obje tipleri; kabul oranı ve gerçek maliyet ölçümü | ✓ 16/20 kabul, 0,16 $ / kabul edilen görev (faz1-tasarim 11e). Zor parti (5 görev): 5/5 kabul, 0,097 $ / kabul edilen görev (11f) |
|
||||||
| F | Eval seti: 110 görev; Kral incelemesi. Eğitim havuzu: otomatik doğrulanmış görevler, eval ile çakışmasız | |
|
| F | Eval seti: 110 görev; Kral incelemesi. Eğitim havuzu: otomatik doğrulanmış görevler, eval ile çakışmasız | |
|
||||||
| G | Ölçüm (1.6) ve yörünge üretimi (3.2) paralel worker'larla (bulut model: en fazla 6) | |
|
| G | Ölçüm (1.6) ve yörünge üretimi (3.2) paralel worker'larla (bulut model: en fazla 6) | |
|
||||||
|
|
||||||
|
|||||||
@@ -49,8 +49,10 @@ Rules for the bundle:
|
|||||||
- Method parameters need a complete type: "TYPE c LENGTH 4" is not allowed in a signature.
|
- Method parameters need a complete type: "TYPE c LENGTH 4" is not allowed in a signature.
|
||||||
Declare a type first (TYPES ty_zone TYPE c LENGTH 4) and use it.
|
Declare a type first (TYPES ty_zone TYPE c LENGTH 4) and use it.
|
||||||
- Field names in tables and CDS views are not SQL reserved words (no HOURS, MODE, ORDER, DATE, COUNT ...).
|
- Field names in tables and CDS views are not SQL reserved words (no HOURS, MODE, ORDER, DATE, COUNT ...).
|
||||||
- CDS: use "define view entity". Parameters have no default value. In a UNION, all branches have the same
|
- CDS: use "define view entity". Parameters have no default value. Use a parameter as
|
||||||
key elements and element names. Hidden tests for a view with parameters pass all parameters.
|
$parameters.p_name (not :p_name). In a UNION, all branches have the same
|
||||||
|
key elements and element names, and the view
|
||||||
|
has the annotation @Metadata.ignorePropagatedAnnotations: true. Hidden tests for a view with parameters pass all parameters.
|
||||||
- Legacy seed code (categories E, I) must activate on SAP_BASIS 816: do not mix old and new syntax in one
|
- Legacy seed code (categories E, I) must activate on SAP_BASIS 816: do not mix old and new syntax in one
|
||||||
SQL statement (with new syntax, every host variable needs "@").
|
SQL statement (with new syntax, every host variable needs "@").
|
||||||
- The contract lists only the objects that the hidden tests call. Test classes are never in the contract.
|
- The contract lists only the objects that the hidden tests call. Test classes are never in the contract.
|
||||||
@@ -178,6 +180,14 @@ def lint_files(b):
|
|||||||
for f in re.findall(r"^\s*(?:key\s+)?(\w+)\s*:", src, re.I | re.M):
|
for f in re.findall(r"^\s*(?:key\s+)?(\w+)\s*:", src, re.I | re.M):
|
||||||
if f.upper() in RESERVED:
|
if f.upper() in RESERVED:
|
||||||
errs.append(f"{rel}: field name {f} is a reserved word; choose another name")
|
errs.append(f"{rel}: field name {f} is a reserved word; choose another name")
|
||||||
|
for rel, src in b.get("files", {}).items():
|
||||||
|
if rel.endswith(".asddls") and re.search(r"define\s+(root\s+)?view\s+entity", src, re.I):
|
||||||
|
if re.search(r"\bunion\b", src, re.I) and not re.search(r"@Metadata\.ignorePropagatedAnnotations\s*:\s*true",
|
||||||
|
src, re.I):
|
||||||
|
errs.append(f"{rel}: a view entity with UNION needs @Metadata.ignorePropagatedAnnotations: true")
|
||||||
|
for p in sorted(set(re.findall(r"[=<>(,]\s*:(\w+)|\bbetween\s+:(\w+)|\band\s+:(\w+)", src, re.I))):
|
||||||
|
name = next(x for x in p if x)
|
||||||
|
errs.append(f"{rel}: parameter :{name}; a view entity needs $parameters.{name}")
|
||||||
for k in ("seed", "reference"):
|
for k in ("seed", "reference"):
|
||||||
for o in t.get(k, []):
|
for o in t.get(k, []):
|
||||||
m = DDL_KIND.search(b.get("files", {}).get(o.get("file", ""), ""))
|
m = DDL_KIND.search(b.get("files", {}).get(o.get("file", ""), ""))
|
||||||
@@ -279,11 +289,23 @@ def dependency_order(objs, files):
|
|||||||
return out
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def floor_budget(task):
|
||||||
|
"""The model needs more calls than the oracle (reads, repairs). G0022: budget 12 activations,
|
||||||
|
reference alone 13. Minimum: 2 x oracle activations, 3 x oracle tool calls."""
|
||||||
|
ref = task.get("reference", [])
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
def write_bundle(b, task_dir, task_id):
|
def write_bundle(b, task_dir, task_id):
|
||||||
os.makedirs(task_dir, exist_ok=True)
|
os.makedirs(task_dir, exist_ok=True)
|
||||||
b["task"]["id"] = task_id
|
b["task"]["id"] = task_id
|
||||||
for k in ("seed", "reference"):
|
for k in ("seed", "reference"):
|
||||||
b["task"][k] = dependency_order(b["task"].get(k, []), b["files"])
|
b["task"][k] = dependency_order(b["task"].get(k, []), b["files"])
|
||||||
|
floor_budget(b["task"])
|
||||||
json.dump(b["task"], open(os.path.join(task_dir, "task.json"), "w"), indent=2)
|
json.dump(b["task"], open(os.path.join(task_dir, "task.json"), "w"), indent=2)
|
||||||
for rel, content in b["files"].items():
|
for rel, content in b["files"].items():
|
||||||
path = os.path.join(task_dir, rel)
|
path = os.path.join(task_dir, rel)
|
||||||
|
|||||||
188
harness/mutation.py
Normal file
188
harness/mutation.py
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
"""Mutation check (step D): the hidden tests must fail on a broken reference.
|
||||||
|
|
||||||
|
Small deterministic changes (mutants) go into the main source of the contract objects of the reference.
|
||||||
|
For each mutant the oracle writes the mutated reference and the harness runs the hidden tests.
|
||||||
|
killed = reference active and at least one hidden test fails
|
||||||
|
survived = reference active and all hidden tests pass (a test gap or an equivalent mutant)
|
||||||
|
invalid = the mutant does not activate (not counted)
|
||||||
|
|
||||||
|
python3 -m harness.mutation G0002 G0003 --pool eval --run-base 5000
|
||||||
|
"""
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import random
|
||||||
|
import re
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
from .adt_client import load_env
|
||||||
|
from .agents import OracleAgent
|
||||||
|
from .runner import Runner
|
||||||
|
|
||||||
|
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
MAX_MUTANTS = 5
|
||||||
|
MIN_VALID = 3
|
||||||
|
MIN_KILL_RATE = 0.75
|
||||||
|
|
||||||
|
# (kind, pattern, replacement); patterns match only outside comments and literals
|
||||||
|
ABAP_OPS = [
|
||||||
|
("rel", r"(?<=\s)>=(?=\s)", "<"), ("rel", r"(?<=\s)<=(?=\s)", ">"),
|
||||||
|
("rel", r"(?<=\s)>(?=\s)", ">="), ("rel", r"(?<=\s)<(?=\s)", "<="),
|
||||||
|
("rel", r"(?<=\s)<>(?=\s)", "="),
|
||||||
|
("rel", r"\bGE\b", "LT"), ("rel", r"\bLE\b", "GT"), ("rel", r"\bGT\b", "GE"), ("rel", r"\bLT\b", "LE"),
|
||||||
|
("rel", r"\bNE\b", "EQ"),
|
||||||
|
("logic", r"(?<=\s)AND(?=\s)", "OR"), ("logic", r"(?<=\s)OR(?=\s)", "AND"),
|
||||||
|
("arith", r"(?<=\s)\+(?=\s)", "-"), ("arith", r"(?<=\s)-(?=\s)", "+"), ("arith", r"(?<=\s)\*(?=\s)", "/"),
|
||||||
|
("bool", r"\babap_true\b", "abap_false"), ("bool", r"\babap_false\b", "abap_true"),
|
||||||
|
("const", r"(?<![\w.'-])([1-9]\d{0,5})(?![\w.'])", None), # integer literal + 1
|
||||||
|
]
|
||||||
|
CDS_OPS = [
|
||||||
|
("rel", r"(?<=\s)>=(?=\s)", "<"), ("rel", r"(?<=\s)<=(?=\s)", ">"),
|
||||||
|
("rel", r"(?<=\s)>(?=\s)", ">="), ("rel", r"(?<=\s)<(?=\s)", "<="), ("rel", r"(?<=\s)<>(?=\s)", "="),
|
||||||
|
("logic", r"(?<=\s)and(?=\s)", "or"),
|
||||||
|
("arith", r"(?<=\s)\+(?=\s)", "-"), ("arith", r"(?<=\s)-(?=\s)", "+"),
|
||||||
|
("agg", r"\bsum\s*\(", "max("), ("agg", r"\bcount\s*\(", "max("), ("agg", r"\bavg\s*\(", "max("),
|
||||||
|
("join", r"\binner\s+join\b", "left outer join"),
|
||||||
|
("const", r"(?<![\w.'-])([1-9]\d{0,5})(?![\w.'])", None),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def _mask(src, cds):
|
||||||
|
"""True for each character inside a comment or a literal."""
|
||||||
|
m = [False] * len(src)
|
||||||
|
pats = ([r"//[^\n]*", r"/\*.*?\*/", r"'[^']*'", r"@[^\n]*"] if cds else
|
||||||
|
[r'"[^\n]*', r"^\*[^\n]*", r"'(?:[^']|'')*'", r"`[^`]*`", r"\|(?:[^|\\]|\\.)*\|"])
|
||||||
|
for p in pats:
|
||||||
|
for x in re.finditer(p, src, re.M | re.S):
|
||||||
|
for i in range(x.start(), x.end()):
|
||||||
|
m[i] = True
|
||||||
|
return m
|
||||||
|
|
||||||
|
|
||||||
|
def _region(src, otype):
|
||||||
|
"""Start and end of the part that may change: the implementation, not declarations or test classes."""
|
||||||
|
start, end = 0, len(src)
|
||||||
|
if otype == "CLAS":
|
||||||
|
x = re.search(r"^\s*CLASS\s+\S+\s+IMPLEMENTATION", src, re.I | re.M)
|
||||||
|
start = x.end() if x else len(src)
|
||||||
|
if otype == "PROG":
|
||||||
|
x = re.search(r"^\s*CLASS\s+\S+\s+DEFINITION[^.]*FOR\s+TESTING", src, re.I | re.M)
|
||||||
|
end = x.start() if x else len(src)
|
||||||
|
if otype == "DDLS":
|
||||||
|
x = re.search(r"\bas\s+select\b|\bas\s+projection\b", src, re.I)
|
||||||
|
start = x.start() if x else 0
|
||||||
|
return start, end
|
||||||
|
|
||||||
|
|
||||||
|
def _skip_line(line):
|
||||||
|
"""Declarations and signatures: a change there gives syntax errors or no behavior change."""
|
||||||
|
return re.match(r"\s*(DATA|TYPES|CONSTANTS|METHODS|CLASS-METHODS|PARAMETERS|SELECT-OPTIONS|"
|
||||||
|
r"IMPORTING|EXPORTING|RETURNING|RAISING|TABLES|FIELD-SYMBOLS)\b", line, re.I)
|
||||||
|
|
||||||
|
|
||||||
|
def mutants(src, otype, seed, n=MAX_MUTANTS):
|
||||||
|
"""Up to n mutants as (description, source). Different kinds first, spread over the source."""
|
||||||
|
cds = otype == "DDLS"
|
||||||
|
mask = _mask(src, cds)
|
||||||
|
lo, hi = _region(src, otype)
|
||||||
|
sites = []
|
||||||
|
for kind, pat, rep in (CDS_OPS if cds else ABAP_OPS):
|
||||||
|
for x in re.finditer(pat, src, re.I):
|
||||||
|
if not lo <= x.start() < hi or mask[x.start()]:
|
||||||
|
continue
|
||||||
|
line_start = src.rfind("\n", 0, x.start()) + 1
|
||||||
|
line_end = src.find("\n", x.start())
|
||||||
|
line = src[line_start:line_end if line_end >= 0 else len(src)]
|
||||||
|
if _skip_line(line) or (kind == "const" and re.search(r"\bLENGTH\b|\bDECIMALS\b|\(\s*\d+\s*,", line, re.I)):
|
||||||
|
continue
|
||||||
|
new = str(int(x.group(1)) + 1) if rep is None else rep
|
||||||
|
sites.append((kind, x.start(), x.end(), new, src.count("\n", 0, x.start()) + 1, x.group(0)))
|
||||||
|
rnd = random.Random(seed)
|
||||||
|
rnd.shuffle(sites)
|
||||||
|
chosen, kinds, lines = [], set(), set()
|
||||||
|
for prefer_new in (True, False):
|
||||||
|
for s in sites:
|
||||||
|
if len(chosen) >= n:
|
||||||
|
break
|
||||||
|
if s in chosen or s[4] in lines or (prefer_new and s[0] in kinds):
|
||||||
|
continue
|
||||||
|
chosen.append(s)
|
||||||
|
kinds.add(s[0])
|
||||||
|
lines.add(s[4])
|
||||||
|
out = []
|
||||||
|
for kind, a, b, new, line, old in sorted(chosen, key=lambda s: s[1]):
|
||||||
|
out.append((f"line {line}: {old.strip()} -> {new} ({kind})", src[:a] + new + src[b:]))
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def check_task(pool_root, task_id, run_base, n=MAX_MUTANTS, keep=False):
|
||||||
|
"""Run the mutants of one task. Returns a summary dict; writes it to <task>/mutation.json."""
|
||||||
|
task_dir = os.path.join(pool_root, task_id)
|
||||||
|
meta = json.load(open(os.path.join(task_dir, "task.json")))
|
||||||
|
contract = {c["name"].upper() for c in meta["contract"]}
|
||||||
|
targets = [o for o in meta["reference"] if o["name"].upper() in contract and o.get("file")
|
||||||
|
and o["type"] in ("CLAS", "FUNC", "PROG", "DDLS")]
|
||||||
|
work = os.path.join(ROOT, "runs", "gen", "mut")
|
||||||
|
os.makedirs(work, exist_ok=True)
|
||||||
|
runner = Runner(os.path.join(work, "pool"), os.path.join(work, "runs"))
|
||||||
|
# candidates per object, then round robin: objects without mutation sites (exception classes) give their share
|
||||||
|
cand = [[(o, d, m) for d, m in mutants(open(os.path.join(task_dir, o["file"])).read(), o["type"],
|
||||||
|
f"{task_id}:{o['name']}", n)] for o in targets]
|
||||||
|
plan = []
|
||||||
|
while len(plan) < n and any(cand):
|
||||||
|
for c in cand:
|
||||||
|
if c and len(plan) < n:
|
||||||
|
plan.append(c.pop(0))
|
||||||
|
results = []
|
||||||
|
for k, (o, desc, msrc) in enumerate(plan):
|
||||||
|
mdir = os.path.join(work, "pool", task_id)
|
||||||
|
shutil.rmtree(mdir, ignore_errors=True)
|
||||||
|
shutil.copytree(task_dir, mdir)
|
||||||
|
open(os.path.join(mdir, o["file"]), "w").write(msrc)
|
||||||
|
rep, _ = runner.run(task_id, OracleAgent(), run_base + k)
|
||||||
|
h = rep.get("hidden_tests") or {}
|
||||||
|
g = rep.get("gates") or {}
|
||||||
|
if not g.get("G1_active") or not h.get("total"):
|
||||||
|
status = "invalid"
|
||||||
|
elif h["passed"] < h["total"]:
|
||||||
|
status = "killed"
|
||||||
|
else:
|
||||||
|
status = "survived"
|
||||||
|
results.append({"object": o["name"], "mutant": desc, "status": status,
|
||||||
|
"hidden": f"{h.get('passed')}/{h.get('total')}",
|
||||||
|
"failed_tests": [d["method"] for d in h.get("detail", []) if not d["ok"]]})
|
||||||
|
if keep and status == "killed": # candidate faulty reference for own-test scoring
|
||||||
|
fdir = os.path.join(task_dir, "faulty")
|
||||||
|
os.makedirs(fdir, exist_ok=True)
|
||||||
|
open(os.path.join(fdir, f"m{k}_{os.path.basename(o['file'])}"), "w").write(msrc)
|
||||||
|
shutil.rmtree(os.path.join(work, "pool", task_id), ignore_errors=True)
|
||||||
|
valid = [r for r in results if r["status"] != "invalid"]
|
||||||
|
killed = [r for r in valid if r["status"] == "killed"]
|
||||||
|
summary = {"task": task_id, "mutants": results, "valid": len(valid), "killed": len(killed),
|
||||||
|
"kill_rate": round(len(killed) / len(valid), 2) if valid else None,
|
||||||
|
"ok": len(valid) >= MIN_VALID and len(killed) / max(1, len(valid)) >= MIN_KILL_RATE}
|
||||||
|
if len(valid) < MIN_VALID:
|
||||||
|
summary["note"] = f"fewer than {MIN_VALID} valid mutants; check by review"
|
||||||
|
json.dump(summary, open(os.path.join(task_dir, "mutation.json"), "w"), indent=1)
|
||||||
|
return summary
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
load_env(os.path.join(ROOT, ".env"))
|
||||||
|
ap = argparse.ArgumentParser()
|
||||||
|
ap.add_argument("tasks", nargs="+")
|
||||||
|
ap.add_argument("--pool", default="eval")
|
||||||
|
ap.add_argument("--run-base", type=int, required=True)
|
||||||
|
ap.add_argument("-n", type=int, default=MAX_MUTANTS)
|
||||||
|
ap.add_argument("--keep", action="store_true", help="store killed mutants in <task>/faulty/")
|
||||||
|
a = ap.parse_args()
|
||||||
|
root = os.path.join(ROOT, "tasks_gen", a.pool) if a.pool != "tasks" else os.path.join(ROOT, "tasks")
|
||||||
|
for i, t in enumerate(a.tasks):
|
||||||
|
s = check_task(root, t, a.run_base + 10 * i, a.n, a.keep)
|
||||||
|
print(json.dumps({k: v for k, v in s.items() if k != "mutants"}), flush=True)
|
||||||
|
for m in s["mutants"]:
|
||||||
|
print(" ", m["status"], m["object"], m["mutant"], m["hidden"], flush=True)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
43
tasks_gen/eval/G0022/generation.json
Normal file
43
tasks_gen/eval/G0022/generation.json
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
{
|
||||||
|
"id": "G0022",
|
||||||
|
"pool": "eval",
|
||||||
|
"object_type": "CLAS",
|
||||||
|
"category": "D",
|
||||||
|
"attempts": [
|
||||||
|
{
|
||||||
|
"stage": "validate",
|
||||||
|
"oracle": 0,
|
||||||
|
"null": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"stage": "validate",
|
||||||
|
"oracle": 0,
|
||||||
|
"null": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"stage": "validate",
|
||||||
|
"oracle": 0,
|
||||||
|
"null": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"stage": "validate",
|
||||||
|
"oracle": 0,
|
||||||
|
"null": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"stage": "revalidate",
|
||||||
|
"by": "harness fix 2026-10-03",
|
||||||
|
"change": "G6 ignores unknown standard superclass (abaplint); reference in dependency order. Bundle not changed.",
|
||||||
|
"oracle": 95.0,
|
||||||
|
"null": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"stage": "revalidate",
|
||||||
|
"by": "harness fix 2026-10-03",
|
||||||
|
"change": "budget floor: max_activations 12 -> 14 (reference alone needs 13).",
|
||||||
|
"oracle": 100.0,
|
||||||
|
"null": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accepted": true
|
||||||
|
}
|
||||||
223
tasks_gen/eval/G0022/hidden/d01_hidden.clas.abap
Normal file
223
tasks_gen/eval/G0022/hidden/d01_hidden.clas.abap
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
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 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 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.
|
||||||
20
tasks_gen/eval/G0022/reference/cx_claim_amount.clas.abap
Normal file
20
tasks_gen/eval/G0022/reference/cx_claim_amount.clas.abap
Normal file
@@ -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.
|
||||||
20
tasks_gen/eval/G0022/reference/cx_claim_costcenter.clas.abap
Normal file
20
tasks_gen/eval/G0022/reference/cx_claim_costcenter.clas.abap
Normal file
@@ -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.
|
||||||
20
tasks_gen/eval/G0022/reference/cx_claim_currency.clas.abap
Normal file
20
tasks_gen/eval/G0022/reference/cx_claim_currency.clas.abap
Normal file
@@ -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.
|
||||||
20
tasks_gen/eval/G0022/reference/cx_claim_date.clas.abap
Normal file
20
tasks_gen/eval/G0022/reference/cx_claim_date.clas.abap
Normal file
@@ -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.
|
||||||
20
tasks_gen/eval/G0022/reference/cx_claim_receipt.clas.abap
Normal file
20
tasks_gen/eval/G0022/reference/cx_claim_receipt.clas.abap
Normal file
@@ -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.
|
||||||
85
tasks_gen/eval/G0022/reference/expense_validator.clas.abap
Normal file
85
tasks_gen/eval/G0022/reference/expense_validator.clas.abap
Normal file
@@ -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.
|
||||||
@@ -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.
|
||||||
27
tasks_gen/eval/G0022/seed/cx_claim_error.clas.abap
Normal file
27
tasks_gen/eval/G0022/seed/cx_claim_error.clas.abap
Normal file
@@ -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.
|
||||||
14
tasks_gen/eval/G0022/seed/if_expense_claim.intf.abap
Normal file
14
tasks_gen/eval/G0022/seed/if_expense_claim.intf.abap
Normal file
@@ -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.
|
||||||
72
tasks_gen/eval/G0022/spec.md
Normal file
72
tasks_gen/eval/G0022/spec.md
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
# 1. Goal
|
||||||
|
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.
|
||||||
|
|
||||||
|
# 2. Open questions
|
||||||
|
None.
|
||||||
|
|
||||||
|
# 3. Context
|
||||||
|
- The interface {{P}}IF_EXPENSE_CLAIM exists in package $TMP and is active. It
|
||||||
|
contains types only and has no methods:
|
||||||
|
- TY_AMOUNT, a packed number with length 8 and 2 decimals.
|
||||||
|
- TY_CURRENCY, a character field with length 3.
|
||||||
|
- TY_COST_CENTER, a character field with length 10.
|
||||||
|
- TY_CLAIM, a structure with the components AMOUNT (TY_AMOUNT), CURRENCY
|
||||||
|
(TY_CURRENCY), CLAIM_DATE (type D), COST_CENTER (TY_COST_CENTER) and
|
||||||
|
HAS_RECEIPT (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 the importing
|
||||||
|
parameter IV_MESSAGE (TYPE string). The method GET_MESSAGE returns this text
|
||||||
|
(TYPE string).
|
||||||
|
|
||||||
|
# 4. Contract
|
||||||
|
- 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 TYPE {{p}}if_expense_claim=>ty_claim
|
||||||
|
RAISING {{p}}cx_claim_error.
|
||||||
|
- 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: constructor parameter IV_AMOUNT of type TY_AMOUNT of
|
||||||
|
{{P}}IF_EXPENSE_CLAIM. Public read-only attribute MV_AMOUNT of the same
|
||||||
|
type. Message: Amount must be positive
|
||||||
|
- {{P}}CX_CLAIM_CURRENCY: constructor parameter IV_CURRENCY of type
|
||||||
|
TY_CURRENCY. Public read-only attribute MV_CURRENCY of the same type.
|
||||||
|
Message: Currency is not supported
|
||||||
|
- {{P}}CX_CLAIM_DATE: constructor parameter IV_CLAIM_DATE of type D. Public
|
||||||
|
read-only attribute MV_CLAIM_DATE of type D. Message: Claim date is in the
|
||||||
|
future
|
||||||
|
- {{P}}CX_CLAIM_RECEIPT: constructor parameter IV_AMOUNT of type TY_AMOUNT.
|
||||||
|
Public read-only attribute MV_AMOUNT of the same type. Message: Receipt is
|
||||||
|
required
|
||||||
|
- {{P}}CX_CLAIM_COSTCENTER: constructor parameter IV_AMOUNT of type TY_AMOUNT.
|
||||||
|
Public read-only attribute MV_AMOUNT of the same type. Message: Cost center
|
||||||
|
is required
|
||||||
|
- GET_MESSAGE returns the message of the exception.
|
||||||
|
- Do not add other public methods or attributes.
|
||||||
|
|
||||||
|
# 5. Business rules
|
||||||
|
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.
|
||||||
|
1. AMOUNT must be greater than zero. Else raise {{P}}CX_CLAIM_AMOUNT with
|
||||||
|
IV_AMOUNT = AMOUNT.
|
||||||
|
2. CURRENCY must be one of EUR, USD, GBP, CHF. Else raise
|
||||||
|
{{P}}CX_CLAIM_CURRENCY with IV_CURRENCY = CURRENCY.
|
||||||
|
3. CLAIM_DATE must not be later than the current date. Else raise
|
||||||
|
{{P}}CX_CLAIM_DATE with IV_CLAIM_DATE = CLAIM_DATE.
|
||||||
|
4. If AMOUNT is 100.00 or more, HAS_RECEIPT must be true. Else raise
|
||||||
|
{{P}}CX_CLAIM_RECEIPT with IV_AMOUNT = AMOUNT.
|
||||||
|
5. If AMOUNT is 1000.00 or more, COST_CENTER must not be initial. Else raise
|
||||||
|
{{P}}CX_CLAIM_COSTCENTER with IV_AMOUNT = AMOUNT.
|
||||||
|
|
||||||
|
# 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_EXPENSE_CLAIM and {{P}}CX_CLAIM_ERROR.
|
||||||
|
|
||||||
|
# 7. Acceptance
|
||||||
|
- All objects are active and have no syntax error.
|
||||||
|
- The hidden tests pass.
|
||||||
|
- Write your own ABAP Unit tests for {{P}}EXPENSE_VALIDATOR.
|
||||||
107
tasks_gen/eval/G0022/task.json
Normal file
107
tasks_gen/eval/G0022/task.json
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
{
|
||||||
|
"id": "G0022",
|
||||||
|
"category": "D",
|
||||||
|
"object_type": "CLAS",
|
||||||
|
"difficulty": 2,
|
||||||
|
"release_target": "v816",
|
||||||
|
"expected_outcome": "implement",
|
||||||
|
"budget": {
|
||||||
|
"max_tool_calls": 45,
|
||||||
|
"max_activations": 14
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
]
|
||||||
|
}
|
||||||
14
tasks_gen/eval/G0023/generation.json
Normal file
14
tasks_gen/eval/G0023/generation.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"id": "G0023",
|
||||||
|
"pool": "eval",
|
||||||
|
"object_type": "CLAS",
|
||||||
|
"category": "E",
|
||||||
|
"attempts": [
|
||||||
|
{
|
||||||
|
"stage": "validate",
|
||||||
|
"oracle": 100.0,
|
||||||
|
"null": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accepted": true
|
||||||
|
}
|
||||||
73
tasks_gen/eval/G0023/hidden/e01_hidden.clas.abap
Normal file
73
tasks_gen/eval/G0023/hidden/e01_hidden.clas.abap
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
CLASS {{p}}e01_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC
|
||||||
|
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
|
||||||
|
PRIVATE SECTION.
|
||||||
|
DATA mo_cut TYPE REF TO {{p}}if_freight_calc.
|
||||||
|
METHODS setup.
|
||||||
|
METHODS assert_cost
|
||||||
|
IMPORTING iv_zone TYPE {{p}}if_freight_calc=>ty_zone
|
||||||
|
iv_weight TYPE {{p}}if_freight_calc=>ty_weight
|
||||||
|
iv_exp TYPE {{p}}if_freight_calc=>ty_amount.
|
||||||
|
METHODS unknown_zone_is_zero FOR TESTING.
|
||||||
|
METHODS minimum_applies_after_charge FOR TESTING.
|
||||||
|
METHODS weight_charge_rounds_half_up FOR TESTING.
|
||||||
|
METHODS all_zones_are_rated FOR TESTING.
|
||||||
|
METHODS surcharge_uses_minimum FOR TESTING.
|
||||||
|
METHODS heavy_discount_on_total FOR TESTING.
|
||||||
|
METHODS no_discount_at_exactly_1000 FOR TESTING.
|
||||||
|
METHODS discount_rounds_half_up FOR TESTING.
|
||||||
|
METHODS small_weight_uses_minimum FOR TESTING.
|
||||||
|
ENDCLASS.
|
||||||
|
|
||||||
|
|
||||||
|
CLASS {{p}}e01_hidden IMPLEMENTATION.
|
||||||
|
METHOD setup.
|
||||||
|
mo_cut = NEW {{p}}freight_calculator( ).
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD assert_cost.
|
||||||
|
cl_abap_unit_assert=>assert_equals(
|
||||||
|
exp = iv_exp
|
||||||
|
act = mo_cut->calculate( iv_zone = iv_zone iv_weight = iv_weight )
|
||||||
|
msg = |zone { iv_zone }, weight { iv_weight }| ).
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD unknown_zone_is_zero.
|
||||||
|
assert_cost( iv_zone = 'XX' iv_weight = '500.000' iv_exp = '0.00' ).
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD minimum_applies_after_charge.
|
||||||
|
assert_cost( iv_zone = 'DE' iv_weight = '1.000' iv_exp = '26.63' ).
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD weight_charge_rounds_half_up.
|
||||||
|
assert_cost( iv_zone = 'CN' iv_weight = '20.004' iv_exp = '54.76' ).
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD all_zones_are_rated.
|
||||||
|
assert_cost( iv_zone = 'DE' iv_weight = '100.000' iv_exp = '103.84' ).
|
||||||
|
assert_cost( iv_zone = 'FR' iv_weight = '20.000' iv_exp = '39.78' ).
|
||||||
|
assert_cost( iv_zone = 'NL' iv_weight = '50.000' iv_exp = '50.11' ).
|
||||||
|
assert_cost( iv_zone = 'US' iv_weight = '50.000' iv_exp = '97.65' ).
|
||||||
|
assert_cost( iv_zone = 'CN' iv_weight = '100.000' iv_exp = '164.25' ).
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD surcharge_uses_minimum.
|
||||||
|
assert_cost( iv_zone = 'NL' iv_weight = '0.000' iv_exp = '21.10' ).
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD heavy_discount_on_total.
|
||||||
|
assert_cost( iv_zone = 'DE' iv_weight = '1500.000' iv_exp = '1302.63' ).
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD no_discount_at_exactly_1000.
|
||||||
|
assert_cost( iv_zone = 'DE' iv_weight = '1000.000' iv_exp = '918.56' ).
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD discount_rounds_half_up.
|
||||||
|
assert_cost( iv_zone = 'DE' iv_weight = '1090.070' iv_exp = '950.10' ).
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD small_weight_uses_minimum.
|
||||||
|
assert_cost( iv_zone = 'FR' iv_weight = '5.000' iv_exp = '32.25' ).
|
||||||
|
ENDMETHOD.
|
||||||
|
ENDCLASS.
|
||||||
62
tasks_gen/eval/G0023/reference/freight_calculator.clas.abap
Normal file
62
tasks_gen/eval/G0023/reference/freight_calculator.clas.abap
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
CLASS {{p}}freight_calculator DEFINITION PUBLIC FINAL CREATE PUBLIC.
|
||||||
|
PUBLIC SECTION.
|
||||||
|
INTERFACES {{p}}if_freight_calc.
|
||||||
|
|
||||||
|
PRIVATE SECTION.
|
||||||
|
TYPES:
|
||||||
|
BEGIN OF ty_rate,
|
||||||
|
zone TYPE {{p}}if_freight_calc=>ty_zone,
|
||||||
|
base TYPE {{p}}if_freight_calc=>ty_amount,
|
||||||
|
per_kg TYPE {{p}}if_freight_calc=>ty_amount,
|
||||||
|
minimum TYPE {{p}}if_freight_calc=>ty_amount,
|
||||||
|
surcharge TYPE p LENGTH 4 DECIMALS 3,
|
||||||
|
END OF ty_rate,
|
||||||
|
tt_rate TYPE SORTED TABLE OF ty_rate WITH UNIQUE KEY zone.
|
||||||
|
|
||||||
|
CONSTANTS:
|
||||||
|
c_heavy_limit TYPE {{p}}if_freight_calc=>ty_weight VALUE '1000.000',
|
||||||
|
c_discount TYPE p LENGTH 3 DECIMALS 2 VALUE '0.95'.
|
||||||
|
|
||||||
|
METHODS rates RETURNING VALUE(rt_rate) TYPE tt_rate.
|
||||||
|
ENDCLASS.
|
||||||
|
|
||||||
|
|
||||||
|
CLASS {{p}}freight_calculator IMPLEMENTATION.
|
||||||
|
METHOD {{p}}if_freight_calc~calculate.
|
||||||
|
DATA(lt_rate) = rates( ).
|
||||||
|
READ TABLE lt_rate INTO DATA(ls_rate) WITH TABLE KEY zone = iv_zone.
|
||||||
|
IF sy-subrc <> 0.
|
||||||
|
rv_cost = 0.
|
||||||
|
RETURN.
|
||||||
|
ENDIF.
|
||||||
|
|
||||||
|
DATA lv_charge TYPE {{p}}if_freight_calc=>ty_amount.
|
||||||
|
lv_charge = ls_rate-per_kg * iv_weight.
|
||||||
|
|
||||||
|
DATA lv_freight TYPE {{p}}if_freight_calc=>ty_amount.
|
||||||
|
lv_freight = ls_rate-base + lv_charge.
|
||||||
|
IF lv_freight < ls_rate-minimum.
|
||||||
|
lv_freight = ls_rate-minimum.
|
||||||
|
ENDIF.
|
||||||
|
|
||||||
|
DATA lv_surcharge TYPE {{p}}if_freight_calc=>ty_amount.
|
||||||
|
lv_surcharge = lv_freight * ls_rate-surcharge.
|
||||||
|
|
||||||
|
DATA lv_total TYPE {{p}}if_freight_calc=>ty_amount.
|
||||||
|
lv_total = lv_freight + lv_surcharge.
|
||||||
|
IF iv_weight > c_heavy_limit.
|
||||||
|
lv_total = lv_total * c_discount.
|
||||||
|
ENDIF.
|
||||||
|
|
||||||
|
rv_cost = lv_total.
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD rates.
|
||||||
|
rt_rate = VALUE #(
|
||||||
|
( zone = 'DE' base = '12.50' per_kg = '0.85' minimum = '25.00' surcharge = '0.065' )
|
||||||
|
( zone = 'FR' base = '15.00' per_kg = '1.10' minimum = '30.00' surcharge = '0.075' )
|
||||||
|
( zone = 'NL' base = '10.00' per_kg = '0.75' minimum = '20.00' surcharge = '0.055' )
|
||||||
|
( zone = 'US' base = '20.00' per_kg = '1.40' minimum = '45.00' surcharge = '0.085' )
|
||||||
|
( zone = 'CN' base = '25.00' per_kg = '1.25' minimum = '50.00' surcharge = '0.095' ) ).
|
||||||
|
ENDMETHOD.
|
||||||
|
ENDCLASS.
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
CLASS ltc_freight_calculator DEFINITION FINAL FOR TESTING
|
||||||
|
DURATION SHORT RISK LEVEL HARMLESS.
|
||||||
|
PRIVATE SECTION.
|
||||||
|
DATA mo_cut TYPE REF TO {{p}}if_freight_calc.
|
||||||
|
METHODS setup.
|
||||||
|
METHODS unknown_zone FOR TESTING.
|
||||||
|
METHODS minimum_charge FOR TESTING.
|
||||||
|
METHODS all_zones FOR TESTING.
|
||||||
|
METHODS heavy_discount FOR TESTING.
|
||||||
|
METHODS no_discount_at_1000 FOR TESTING.
|
||||||
|
METHODS rounding_half_up FOR TESTING.
|
||||||
|
ENDCLASS.
|
||||||
|
|
||||||
|
|
||||||
|
CLASS ltc_freight_calculator IMPLEMENTATION.
|
||||||
|
METHOD setup.
|
||||||
|
mo_cut = NEW {{p}}freight_calculator( ).
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD unknown_zone.
|
||||||
|
DATA lv_exp TYPE {{p}}if_freight_calc=>ty_amount.
|
||||||
|
lv_exp = '0.00'.
|
||||||
|
cl_abap_unit_assert=>assert_equals(
|
||||||
|
exp = lv_exp
|
||||||
|
act = mo_cut->calculate( iv_zone = 'XX' iv_weight = '10.000' ) ).
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD minimum_charge.
|
||||||
|
DATA lv_exp TYPE {{p}}if_freight_calc=>ty_amount.
|
||||||
|
lv_exp = '26.63'.
|
||||||
|
cl_abap_unit_assert=>assert_equals(
|
||||||
|
exp = lv_exp
|
||||||
|
act = mo_cut->calculate( iv_zone = 'DE' iv_weight = '1.000' ) ).
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD all_zones.
|
||||||
|
DATA lv_exp TYPE {{p}}if_freight_calc=>ty_amount.
|
||||||
|
lv_exp = '103.84'.
|
||||||
|
cl_abap_unit_assert=>assert_equals(
|
||||||
|
exp = lv_exp
|
||||||
|
act = mo_cut->calculate( iv_zone = 'DE' iv_weight = '100.000' ) msg = `DE` ).
|
||||||
|
lv_exp = '39.78'.
|
||||||
|
cl_abap_unit_assert=>assert_equals(
|
||||||
|
exp = lv_exp
|
||||||
|
act = mo_cut->calculate( iv_zone = 'FR' iv_weight = '20.000' ) msg = `FR` ).
|
||||||
|
lv_exp = '164.25'.
|
||||||
|
cl_abap_unit_assert=>assert_equals(
|
||||||
|
exp = lv_exp
|
||||||
|
act = mo_cut->calculate( iv_zone = 'CN' iv_weight = '100.000' ) msg = `CN` ).
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD heavy_discount.
|
||||||
|
DATA lv_exp TYPE {{p}}if_freight_calc=>ty_amount.
|
||||||
|
lv_exp = '1302.63'.
|
||||||
|
cl_abap_unit_assert=>assert_equals(
|
||||||
|
exp = lv_exp
|
||||||
|
act = mo_cut->calculate( iv_zone = 'DE' iv_weight = '1500.000' ) ).
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD no_discount_at_1000.
|
||||||
|
DATA lv_exp TYPE {{p}}if_freight_calc=>ty_amount.
|
||||||
|
lv_exp = '918.56'.
|
||||||
|
cl_abap_unit_assert=>assert_equals(
|
||||||
|
exp = lv_exp
|
||||||
|
act = mo_cut->calculate( iv_zone = 'DE' iv_weight = '1000.000' ) ).
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD rounding_half_up.
|
||||||
|
DATA lv_exp TYPE {{p}}if_freight_calc=>ty_amount.
|
||||||
|
lv_exp = '54.76'.
|
||||||
|
cl_abap_unit_assert=>assert_equals(
|
||||||
|
exp = lv_exp
|
||||||
|
act = mo_cut->calculate( iv_zone = 'CN' iv_weight = '20.004' ) ).
|
||||||
|
ENDMETHOD.
|
||||||
|
ENDCLASS.
|
||||||
61
tasks_gen/eval/G0023/seed/freight_legacy.clas.abap
Normal file
61
tasks_gen/eval/G0023/seed/freight_legacy.clas.abap
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
CLASS {{p}}freight_legacy DEFINITION PUBLIC FINAL CREATE PUBLIC.
|
||||||
|
PUBLIC SECTION.
|
||||||
|
INTERFACES {{p}}if_freight_calc.
|
||||||
|
ENDCLASS.
|
||||||
|
|
||||||
|
|
||||||
|
CLASS {{p}}freight_legacy IMPLEMENTATION.
|
||||||
|
METHOD {{p}}if_freight_calc~calculate.
|
||||||
|
DATA: lv_base TYPE {{p}}if_freight_calc=>ty_amount,
|
||||||
|
lv_per_kg TYPE {{p}}if_freight_calc=>ty_amount,
|
||||||
|
lv_minimum TYPE {{p}}if_freight_calc=>ty_amount,
|
||||||
|
lv_surcharge TYPE p LENGTH 4 DECIMALS 3,
|
||||||
|
lv_charge TYPE {{p}}if_freight_calc=>ty_amount,
|
||||||
|
lv_freight TYPE {{p}}if_freight_calc=>ty_amount,
|
||||||
|
lv_fee TYPE {{p}}if_freight_calc=>ty_amount,
|
||||||
|
lv_total TYPE {{p}}if_freight_calc=>ty_amount.
|
||||||
|
|
||||||
|
CASE iv_zone.
|
||||||
|
WHEN 'DE'.
|
||||||
|
lv_base = '12.50'.
|
||||||
|
lv_per_kg = '0.85'.
|
||||||
|
lv_minimum = '25.00'.
|
||||||
|
lv_surcharge = '0.065'.
|
||||||
|
WHEN 'FR'.
|
||||||
|
lv_base = '15.00'.
|
||||||
|
lv_per_kg = '1.10'.
|
||||||
|
lv_minimum = '30.00'.
|
||||||
|
lv_surcharge = '0.075'.
|
||||||
|
WHEN 'NL'.
|
||||||
|
lv_base = '10.00'.
|
||||||
|
lv_per_kg = '0.75'.
|
||||||
|
lv_minimum = '20.00'.
|
||||||
|
lv_surcharge = '0.055'.
|
||||||
|
WHEN 'US'.
|
||||||
|
lv_base = '20.00'.
|
||||||
|
lv_per_kg = '1.40'.
|
||||||
|
lv_minimum = '45.00'.
|
||||||
|
lv_surcharge = '0.085'.
|
||||||
|
WHEN 'CN'.
|
||||||
|
lv_base = '25.00'.
|
||||||
|
lv_per_kg = '1.25'.
|
||||||
|
lv_minimum = '50.00'.
|
||||||
|
lv_surcharge = '0.095'.
|
||||||
|
WHEN OTHERS.
|
||||||
|
rv_cost = 0.
|
||||||
|
RETURN.
|
||||||
|
ENDCASE.
|
||||||
|
|
||||||
|
lv_charge = lv_per_kg * iv_weight.
|
||||||
|
lv_freight = lv_base + lv_charge.
|
||||||
|
IF lv_freight < lv_minimum.
|
||||||
|
lv_freight = lv_minimum.
|
||||||
|
ENDIF.
|
||||||
|
lv_fee = lv_freight * lv_surcharge.
|
||||||
|
lv_total = lv_freight + lv_fee.
|
||||||
|
IF iv_weight > '1000.000'.
|
||||||
|
lv_total = lv_total * '0.95'.
|
||||||
|
ENDIF.
|
||||||
|
rv_cost = lv_total.
|
||||||
|
ENDMETHOD.
|
||||||
|
ENDCLASS.
|
||||||
11
tasks_gen/eval/G0023/seed/if_freight_calc.intf.abap
Normal file
11
tasks_gen/eval/G0023/seed/if_freight_calc.intf.abap
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
INTERFACE {{p}}if_freight_calc PUBLIC.
|
||||||
|
TYPES:
|
||||||
|
ty_zone TYPE c LENGTH 2,
|
||||||
|
ty_weight TYPE p LENGTH 9 DECIMALS 3,
|
||||||
|
ty_amount TYPE p LENGTH 7 DECIMALS 2.
|
||||||
|
|
||||||
|
METHODS calculate
|
||||||
|
IMPORTING iv_zone TYPE ty_zone
|
||||||
|
iv_weight TYPE ty_weight
|
||||||
|
RETURNING VALUE(rv_cost) TYPE ty_amount.
|
||||||
|
ENDINTERFACE.
|
||||||
69
tasks_gen/eval/G0023/spec.md
Normal file
69
tasks_gen/eval/G0023/spec.md
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
# 1. Goal
|
||||||
|
|
||||||
|
A freight forwarder calculates the freight cost of a shipment. A legacy class
|
||||||
|
calculates this cost today. Write the calculation as a clean class. The cost of
|
||||||
|
every shipment must stay the same.
|
||||||
|
|
||||||
|
# 2. Open questions
|
||||||
|
None.
|
||||||
|
|
||||||
|
# 3. Context
|
||||||
|
- The interface {{P}}IF_FREIGHT_CALC exists in package $TMP and is active.
|
||||||
|
- The legacy class {{P}}FREIGHT_LEGACY exists in package $TMP and is active. It
|
||||||
|
implements {{P}}IF_FREIGHT_CALC. Its results are the reference for the new class.
|
||||||
|
- The interface declares the types TY_ZONE (character, length 2), TY_WEIGHT
|
||||||
|
(packed number, length 9, 3 decimal places) and TY_AMOUNT (packed number,
|
||||||
|
length 7, 2 decimal places), and the method CALCULATE.
|
||||||
|
|
||||||
|
# 4. Contract
|
||||||
|
- Create the class {{P}}FREIGHT_CALCULATOR in package $TMP.
|
||||||
|
- The class is public, final, and has a public constructor without parameters.
|
||||||
|
- The class implements {{P}}IF_FREIGHT_CALC.
|
||||||
|
- Do not add other public methods.
|
||||||
|
|
||||||
|
# 5. Business rules
|
||||||
|
|
||||||
|
All amounts are packed numbers with 2 decimal places. Round an amount to
|
||||||
|
2 decimal places before you use it in the next step. Round half away from zero.
|
||||||
|
|
||||||
|
1. Zone
|
||||||
|
The zone is a two-character code. These zones exist:
|
||||||
|
|
||||||
|
zone base per kg minimum surcharge factor
|
||||||
|
DE 12.50 0.85 25.00 0.065
|
||||||
|
FR 15.00 1.10 30.00 0.075
|
||||||
|
NL 10.00 0.75 20.00 0.055
|
||||||
|
US 20.00 1.40 45.00 0.085
|
||||||
|
CN 25.00 1.25 50.00 0.095
|
||||||
|
|
||||||
|
If the zone is not one of these, the result is 0.00 and no other rule applies.
|
||||||
|
|
||||||
|
2. Weight charge
|
||||||
|
weight charge = weight * per kg of the zone, rounded to 2 decimal places.
|
||||||
|
|
||||||
|
3. Freight
|
||||||
|
freight = base of the zone + weight charge.
|
||||||
|
If freight is less than the minimum of the zone, freight is the minimum.
|
||||||
|
|
||||||
|
4. Surcharge
|
||||||
|
surcharge = freight * surcharge factor of the zone, rounded to 2 decimal places.
|
||||||
|
|
||||||
|
5. Total
|
||||||
|
total = freight + surcharge.
|
||||||
|
|
||||||
|
6. Heavy shipment
|
||||||
|
If the weight is greater than 1000.000 kg, total = total * 0.95, rounded to
|
||||||
|
2 decimal places.
|
||||||
|
|
||||||
|
7. The result is total.
|
||||||
|
|
||||||
|
# 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_FREIGHT_CALC and {{P}}FREIGHT_LEGACY.
|
||||||
|
|
||||||
|
# 7. Acceptance
|
||||||
|
- The class is active and has no syntax error.
|
||||||
|
- The hidden tests pass.
|
||||||
|
- Write your own ABAP Unit tests for the class.
|
||||||
58
tasks_gen/eval/G0023/task.json
Normal file
58
tasks_gen/eval/G0023/task.json
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
{
|
||||||
|
"id": "G0023",
|
||||||
|
"category": "E",
|
||||||
|
"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_FREIGHT_CALC",
|
||||||
|
"file": "seed/if_freight_calc.intf.abap",
|
||||||
|
"description": "Freight calculation contract with packed number types"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "CLAS",
|
||||||
|
"name": "{{P}}FREIGHT_LEGACY",
|
||||||
|
"file": "seed/freight_legacy.clas.abap",
|
||||||
|
"description": "Legacy freight calculator with packed arithmetic and a CASE over zones"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"contract": [
|
||||||
|
{
|
||||||
|
"type": "CLAS",
|
||||||
|
"name": "{{P}}FREIGHT_CALCULATOR",
|
||||||
|
"implements": "{{P}}IF_FREIGHT_CALC"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"out_of_scope": [
|
||||||
|
"{{P}}IF_FREIGHT_CALC",
|
||||||
|
"{{P}}FREIGHT_LEGACY"
|
||||||
|
],
|
||||||
|
"hidden_tests": [
|
||||||
|
{
|
||||||
|
"type": "CLAS",
|
||||||
|
"name": "{{P}}E01_HIDDEN",
|
||||||
|
"file": "hidden/e01_hidden.clas.abap",
|
||||||
|
"description": "E01 hidden tests for the refactored freight calculator"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"reference": [
|
||||||
|
{
|
||||||
|
"type": "CLAS",
|
||||||
|
"name": "{{P}}FREIGHT_CALCULATOR",
|
||||||
|
"file": "reference/freight_calculator.clas.abap",
|
||||||
|
"description": "Refactored freight calculator with a rate table",
|
||||||
|
"testclasses_file": "reference/freight_calculator.testclasses.abap"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"craft_checks": [
|
||||||
|
"method_length",
|
||||||
|
"no_global_variables"
|
||||||
|
]
|
||||||
|
}
|
||||||
19
tasks_gen/eval/G0024/generation.json
Normal file
19
tasks_gen/eval/G0024/generation.json
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"id": "G0024",
|
||||||
|
"pool": "eval",
|
||||||
|
"object_type": "DDLS",
|
||||||
|
"category": "B",
|
||||||
|
"attempts": [
|
||||||
|
{
|
||||||
|
"stage": "validate",
|
||||||
|
"oracle": 0,
|
||||||
|
"null": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"stage": "validate",
|
||||||
|
"oracle": 100.0,
|
||||||
|
"null": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accepted": true
|
||||||
|
}
|
||||||
89
tasks_gen/eval/G0024/hidden/t16_hidden.clas.abap
Normal file
89
tasks_gen/eval/G0024/hidden/t16_hidden.clas.abap
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
CLASS {{p}}t16_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC
|
||||||
|
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
|
||||||
|
PRIVATE SECTION.
|
||||||
|
CONSTANTS c_from TYPE d VALUE '20240101'.
|
||||||
|
CONSTANTS c_to TYPE d VALUE '20240131'.
|
||||||
|
CLASS-DATA go_env TYPE REF TO if_cds_test_environment.
|
||||||
|
CLASS-METHODS class_setup.
|
||||||
|
CLASS-METHODS class_teardown.
|
||||||
|
METHODS setup.
|
||||||
|
METHODS row_per_product FOR TESTING.
|
||||||
|
METHODS sums_quantity FOR TESTING.
|
||||||
|
METHODS sums_amount FOR TESTING.
|
||||||
|
METHODS excludes_before_from FOR TESTING.
|
||||||
|
METHODS excludes_after_to FOR TESTING.
|
||||||
|
METHODS bounds_inclusive FOR TESTING.
|
||||||
|
METHODS empty_period FOR TESTING.
|
||||||
|
ENDCLASS.
|
||||||
|
|
||||||
|
|
||||||
|
CLASS {{p}}t16_hidden IMPLEMENTATION.
|
||||||
|
METHOD class_setup.
|
||||||
|
go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_SALES_REPORT' ).
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD class_teardown.
|
||||||
|
go_env->destroy( ).
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD setup.
|
||||||
|
DATA lt_sales TYPE STANDARD TABLE OF {{p}}sales WITH EMPTY KEY.
|
||||||
|
go_env->clear_doubles( ).
|
||||||
|
lt_sales = VALUE #(
|
||||||
|
( doc_id = 'D1' item_no = 1 product = 'MAT_A' quantity = 3 price = '10.00' sold_on = '20240110' )
|
||||||
|
( doc_id = 'D1' item_no = 2 product = 'MAT_A' quantity = 2 price = '5.00' sold_on = '20240115' )
|
||||||
|
( doc_id = 'D2' item_no = 1 product = 'MAT_B' quantity = 1 price = '100.00' sold_on = '20240131' )
|
||||||
|
( doc_id = 'D3' item_no = 1 product = 'MAT_B' quantity = 4 price = '2.50' sold_on = '20231231' )
|
||||||
|
( doc_id = 'D4' item_no = 1 product = 'MAT_C' quantity = 7 price = '1.00' sold_on = '20240201' ) ).
|
||||||
|
go_env->insert_test_data( lt_sales ).
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD row_per_product.
|
||||||
|
SELECT COUNT(*) FROM {{p}}i_sales_report( p_from = @c_from, p_to = @c_to )
|
||||||
|
INTO @DATA(lv_rows).
|
||||||
|
cl_abap_unit_assert=>assert_equals( exp = 2 act = lv_rows ).
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD sums_quantity.
|
||||||
|
SELECT SINGLE total_qty FROM {{p}}i_sales_report( p_from = @c_from, p_to = @c_to )
|
||||||
|
WHERE product = 'MAT_A' INTO @DATA(lv_qty).
|
||||||
|
cl_abap_unit_assert=>assert_equals( exp = 5 act = lv_qty ).
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD sums_amount.
|
||||||
|
SELECT SINGLE total_amount FROM {{p}}i_sales_report( p_from = @c_from, p_to = @c_to )
|
||||||
|
WHERE product = 'MAT_A' INTO @DATA(lv_amount).
|
||||||
|
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '40.00' )
|
||||||
|
act = CONV decfloat34( lv_amount ) ).
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD excludes_before_from.
|
||||||
|
SELECT SINGLE total_qty FROM {{p}}i_sales_report( p_from = @c_from, p_to = @c_to )
|
||||||
|
WHERE product = 'MAT_B' INTO @DATA(lv_qty).
|
||||||
|
cl_abap_unit_assert=>assert_equals( exp = 1 act = lv_qty ).
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD excludes_after_to.
|
||||||
|
SELECT COUNT(*) FROM {{p}}i_sales_report( p_from = @c_from, p_to = @c_to )
|
||||||
|
WHERE product = 'MAT_C' INTO @DATA(lv_rows).
|
||||||
|
cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_rows ).
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD bounds_inclusive.
|
||||||
|
DATA lv_day TYPE d.
|
||||||
|
lv_day = '20240131'.
|
||||||
|
SELECT SINGLE total_qty FROM {{p}}i_sales_report( p_from = @lv_day, p_to = @lv_day )
|
||||||
|
WHERE product = 'MAT_B' INTO @DATA(lv_qty).
|
||||||
|
cl_abap_unit_assert=>assert_equals( exp = 1 act = lv_qty ).
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD empty_period.
|
||||||
|
DATA lv_from TYPE d.
|
||||||
|
DATA lv_to TYPE d.
|
||||||
|
lv_from = '20230101'.
|
||||||
|
lv_to = '20230131'.
|
||||||
|
SELECT COUNT(*) FROM {{p}}i_sales_report( p_from = @lv_from, p_to = @lv_to )
|
||||||
|
INTO @DATA(lv_rows).
|
||||||
|
cl_abap_unit_assert=>assert_equals( exp = 0 act = lv_rows ).
|
||||||
|
ENDMETHOD.
|
||||||
|
ENDCLASS.
|
||||||
15
tasks_gen/eval/G0024/reference/i_sales_report.ddls.asddls
Normal file
15
tasks_gen/eval/G0024/reference/i_sales_report.ddls.asddls
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
@AccessControl.authorizationCheck: #NOT_REQUIRED
|
||||||
|
@EndUserText.label: 'Sales per product in a period'
|
||||||
|
define view entity {{P}}I_SALES_REPORT
|
||||||
|
with parameters
|
||||||
|
p_from : abap.dats,
|
||||||
|
p_to : abap.dats
|
||||||
|
as select from {{p}}sales as sale
|
||||||
|
{
|
||||||
|
key sale.product as product,
|
||||||
|
sum( sale.quantity ) as total_qty,
|
||||||
|
sum( cast( sale.quantity as abap.dec( 15, 2 ) ) * sale.price ) as total_amount
|
||||||
|
}
|
||||||
|
where sale.sold_on >= $parameters.p_from
|
||||||
|
and sale.sold_on <= $parameters.p_to
|
||||||
|
group by sale.product
|
||||||
44
tasks_gen/eval/G0024/reference/t16_test.clas.abap
Normal file
44
tasks_gen/eval/G0024/reference/t16_test.clas.abap
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
CLASS {{p}}t16_test DEFINITION PUBLIC FINAL CREATE PUBLIC
|
||||||
|
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
|
||||||
|
PRIVATE SECTION.
|
||||||
|
CLASS-DATA go_env TYPE REF TO if_cds_test_environment.
|
||||||
|
CLASS-METHODS class_setup.
|
||||||
|
CLASS-METHODS class_teardown.
|
||||||
|
METHODS setup.
|
||||||
|
METHODS period_is_inclusive FOR TESTING.
|
||||||
|
ENDCLASS.
|
||||||
|
|
||||||
|
|
||||||
|
CLASS {{p}}t16_test IMPLEMENTATION.
|
||||||
|
METHOD class_setup.
|
||||||
|
go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_SALES_REPORT' ).
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD class_teardown.
|
||||||
|
go_env->destroy( ).
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD setup.
|
||||||
|
DATA lt_sales TYPE STANDARD TABLE OF {{p}}sales WITH EMPTY KEY.
|
||||||
|
go_env->clear_doubles( ).
|
||||||
|
lt_sales = VALUE #(
|
||||||
|
( doc_id = 'S1' item_no = 1 product = 'P1' quantity = 2 price = '1.50' sold_on = '20240501' )
|
||||||
|
( doc_id = 'S1' item_no = 2 product = 'P1' quantity = 1 price = '4.00' sold_on = '20240531' )
|
||||||
|
( doc_id = 'S2' item_no = 1 product = 'P2' quantity = 9 price = '0.10' sold_on = '20240601' ) ).
|
||||||
|
go_env->insert_test_data( lt_sales ).
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD period_is_inclusive.
|
||||||
|
DATA lv_from TYPE d.
|
||||||
|
DATA lv_to TYPE d.
|
||||||
|
lv_from = '20240501'.
|
||||||
|
lv_to = '20240531'.
|
||||||
|
SELECT SINGLE total_qty, total_amount
|
||||||
|
FROM {{p}}i_sales_report( p_from = @lv_from, p_to = @lv_to )
|
||||||
|
WHERE product = 'P1'
|
||||||
|
INTO @DATA(ls_result).
|
||||||
|
cl_abap_unit_assert=>assert_equals( exp = 3 act = ls_result-total_qty ).
|
||||||
|
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '7.00' )
|
||||||
|
act = CONV decfloat34( ls_result-total_amount ) ).
|
||||||
|
ENDMETHOD.
|
||||||
|
ENDCLASS.
|
||||||
14
tasks_gen/eval/G0024/seed/sales.tabl.asabap
Normal file
14
tasks_gen/eval/G0024/seed/sales.tabl.asabap
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
@EndUserText.label : 'Sales line'
|
||||||
|
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
|
||||||
|
@AbapCatalog.tableCategory : #TRANSPARENT
|
||||||
|
@AbapCatalog.deliveryClass : #A
|
||||||
|
@AbapCatalog.dataMaintenance : #RESTRICTED
|
||||||
|
define table {{p}}sales {
|
||||||
|
key client : abap.clnt not null;
|
||||||
|
key doc_id : abap.char(10) not null;
|
||||||
|
key item_no : abap.int4 not null;
|
||||||
|
product : abap.char(10);
|
||||||
|
quantity : abap.int4;
|
||||||
|
price : abap.dec(15,2);
|
||||||
|
sold_on : abap.dats;
|
||||||
|
}
|
||||||
22
tasks_gen/eval/G0024/seed/seed_sales.clas.abap
Normal file
22
tasks_gen/eval/G0024/seed/seed_sales.clas.abap
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
CLASS {{p}}seed_sales DEFINITION PUBLIC FINAL CREATE PUBLIC.
|
||||||
|
PUBLIC SECTION.
|
||||||
|
INTERFACES if_oo_adt_classrun.
|
||||||
|
PROTECTED SECTION.
|
||||||
|
PRIVATE SECTION.
|
||||||
|
ENDCLASS.
|
||||||
|
|
||||||
|
|
||||||
|
CLASS {{p}}seed_sales IMPLEMENTATION.
|
||||||
|
METHOD if_oo_adt_classrun~main.
|
||||||
|
DATA lt_sales TYPE STANDARD TABLE OF {{p}}sales WITH EMPTY KEY.
|
||||||
|
lt_sales = VALUE #(
|
||||||
|
( doc_id = 'D1' item_no = 1 product = 'MAT_A' quantity = 3 price = '10.00' sold_on = '20240110' )
|
||||||
|
( doc_id = 'D1' item_no = 2 product = 'MAT_A' quantity = 2 price = '5.00' sold_on = '20240115' )
|
||||||
|
( doc_id = 'D2' item_no = 1 product = 'MAT_B' quantity = 1 price = '100.00' sold_on = '20240131' )
|
||||||
|
( doc_id = 'D3' item_no = 1 product = 'MAT_B' quantity = 4 price = '2.50' sold_on = '20231231' )
|
||||||
|
( doc_id = 'D4' item_no = 1 product = 'MAT_C' quantity = 7 price = '1.00' sold_on = '20240201' ) ).
|
||||||
|
DELETE FROM {{p}}sales.
|
||||||
|
INSERT {{p}}sales FROM TABLE @lt_sales.
|
||||||
|
out->write( |Seed rows: { lines( lt_sales ) }| ).
|
||||||
|
ENDMETHOD.
|
||||||
|
ENDCLASS.
|
||||||
40
tasks_gen/eval/G0024/spec.md
Normal file
40
tasks_gen/eval/G0024/spec.md
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
# 1. Goal
|
||||||
|
Give the sales figures of each product for a period. The period is an input of the
|
||||||
|
view. A report and an OData service read the figures, so the calculation must be in
|
||||||
|
the database, in a CDS view.
|
||||||
|
|
||||||
|
# 2. Open questions
|
||||||
|
None.
|
||||||
|
|
||||||
|
# 3. Context
|
||||||
|
- Table {{P}}SALES (sales line), package $TMP. Key: DOC_ID (CHAR 10), ITEM_NO (INT4).
|
||||||
|
Fields: PRODUCT (CHAR 10), QUANTITY (INT4), PRICE (DEC 15,2, the price of one
|
||||||
|
unit), SOLD_ON (DATS, the date of the sale).
|
||||||
|
- The class {{P}}SEED_SALES fills {{P}}SALES with sample data. Run it if you want to
|
||||||
|
test the view manually.
|
||||||
|
|
||||||
|
# 4. Contract
|
||||||
|
- Create the CDS view entity {{P}}I_SALES_REPORT in package $TMP.
|
||||||
|
- Input parameters, with these names and types: P_FROM (DATS), P_TO (DATS).
|
||||||
|
The parameters have no default value.
|
||||||
|
- Elements, with these names: PRODUCT (key), TOTAL_QTY, TOTAL_AMOUNT.
|
||||||
|
- No authorization check (#NOT_REQUIRED).
|
||||||
|
|
||||||
|
# 5. Business rules
|
||||||
|
1. A sales line is in the period when SOLD_ON is not before P_FROM and not after
|
||||||
|
P_TO. P_FROM and P_TO are part of the period.
|
||||||
|
2. Show one row for each product with at least one sales line in the period. Do not
|
||||||
|
show a product without a sales line in the period.
|
||||||
|
3. TOTAL_QTY is the sum of QUANTITY of all sales lines of the product in the period.
|
||||||
|
4. TOTAL_AMOUNT is the sum of QUANTITY multiplied by PRICE of all sales lines of the
|
||||||
|
product in the period, with 2 decimals.
|
||||||
|
|
||||||
|
# 6. Constraints
|
||||||
|
- Release target: 7.58.
|
||||||
|
- Coding standards: Clean ABAP.
|
||||||
|
- Out of scope: do not change {{P}}SALES and {{P}}SEED_SALES.
|
||||||
|
|
||||||
|
# 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.
|
||||||
75
tasks_gen/eval/G0024/task.json
Normal file
75
tasks_gen/eval/G0024/task.json
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
{
|
||||||
|
"id": "G0024",
|
||||||
|
"category": "B",
|
||||||
|
"object_type": "DDLS",
|
||||||
|
"difficulty": 2,
|
||||||
|
"release_target": "v758",
|
||||||
|
"expected_outcome": "implement",
|
||||||
|
"budget": {
|
||||||
|
"max_tool_calls": 40,
|
||||||
|
"max_activations": 10
|
||||||
|
},
|
||||||
|
"seed": [
|
||||||
|
{
|
||||||
|
"type": "TABL",
|
||||||
|
"name": "{{P}}SALES",
|
||||||
|
"file": "seed/sales.tabl.asabap",
|
||||||
|
"description": "Sales line"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "CLAS",
|
||||||
|
"name": "{{P}}SEED_SALES",
|
||||||
|
"file": "seed/seed_sales.clas.abap",
|
||||||
|
"run": true,
|
||||||
|
"description": "Seed data for {{P}}SALES"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"contract": [
|
||||||
|
{
|
||||||
|
"type": "DDLS",
|
||||||
|
"name": "{{P}}I_SALES_REPORT",
|
||||||
|
"params": [
|
||||||
|
{
|
||||||
|
"name": "P_FROM",
|
||||||
|
"type": "abap.dats"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "P_TO",
|
||||||
|
"type": "abap.dats"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"fields": [
|
||||||
|
"PRODUCT",
|
||||||
|
"TOTAL_QTY",
|
||||||
|
"TOTAL_AMOUNT"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"out_of_scope": [
|
||||||
|
"{{P}}SALES",
|
||||||
|
"{{P}}SEED_SALES"
|
||||||
|
],
|
||||||
|
"hidden_tests": [
|
||||||
|
{
|
||||||
|
"type": "CLAS",
|
||||||
|
"name": "{{P}}T16_HIDDEN",
|
||||||
|
"file": "hidden/t16_hidden.clas.abap",
|
||||||
|
"description": "T16 hidden tests"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"reference": [
|
||||||
|
{
|
||||||
|
"type": "DDLS",
|
||||||
|
"name": "{{P}}I_SALES_REPORT",
|
||||||
|
"file": "reference/i_sales_report.ddls.asddls",
|
||||||
|
"description": "Sales figures per product in a period"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "CLAS",
|
||||||
|
"name": "{{P}}T16_TEST",
|
||||||
|
"file": "reference/t16_test.clas.abap",
|
||||||
|
"description": "T16 own tests"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"craft_checks": []
|
||||||
|
}
|
||||||
19
tasks_gen/eval/G0025/generation.json
Normal file
19
tasks_gen/eval/G0025/generation.json
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"id": "G0025",
|
||||||
|
"pool": "eval",
|
||||||
|
"object_type": "DDLS",
|
||||||
|
"category": "B",
|
||||||
|
"attempts": [
|
||||||
|
{
|
||||||
|
"stage": "validate",
|
||||||
|
"oracle": 0,
|
||||||
|
"null": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"stage": "validate",
|
||||||
|
"oracle": 100.0,
|
||||||
|
"null": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accepted": true
|
||||||
|
}
|
||||||
88
tasks_gen/eval/G0025/hidden/t16_hidden.clas.abap
Normal file
88
tasks_gen/eval/G0025/hidden/t16_hidden.clas.abap
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
CLASS {{p}}t16_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC
|
||||||
|
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
|
||||||
|
PRIVATE SECTION.
|
||||||
|
CLASS-DATA go_env TYPE REF TO if_cds_test_environment.
|
||||||
|
CLASS-METHODS class_setup.
|
||||||
|
CLASS-METHODS class_teardown.
|
||||||
|
METHODS setup.
|
||||||
|
METHODS source_a_rows FOR TESTING.
|
||||||
|
METHODS source_b_rows FOR TESTING.
|
||||||
|
METHODS all_partners FOR TESTING.
|
||||||
|
METHODS same_id_twice FOR TESTING.
|
||||||
|
METHODS name_and_city FOR TESTING.
|
||||||
|
METHODS only_in_a FOR TESTING.
|
||||||
|
METHODS only_in_b FOR TESTING.
|
||||||
|
ENDCLASS.
|
||||||
|
|
||||||
|
|
||||||
|
CLASS {{p}}t16_hidden IMPLEMENTATION.
|
||||||
|
METHOD class_setup.
|
||||||
|
go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_PARTNER_ALL' ).
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD class_teardown.
|
||||||
|
go_env->destroy( ).
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD setup.
|
||||||
|
DATA lt_a TYPE STANDARD TABLE OF {{p}}part_a WITH EMPTY KEY.
|
||||||
|
DATA lt_b TYPE STANDARD TABLE OF {{p}}part_b WITH EMPTY KEY.
|
||||||
|
go_env->clear_doubles( ).
|
||||||
|
lt_a = VALUE #( ( partner_id = 'P1' name = 'Alpha GmbH' city = 'Berlin' )
|
||||||
|
( partner_id = 'P2' name = 'Beta AG' city = 'Hamburg' ) ).
|
||||||
|
lt_b = VALUE #( ( partner_id = 'P2' name = 'Beta AG' city = 'Hamburg' )
|
||||||
|
( partner_id = 'P3' name = 'Gamma KG' city = 'Munich' ) ).
|
||||||
|
go_env->insert_test_data( lt_a ).
|
||||||
|
go_env->insert_test_data( lt_b ).
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD source_a_rows.
|
||||||
|
SELECT partner_id, source FROM {{p}}i_partner_all
|
||||||
|
WHERE source = 'A' ORDER BY partner_id INTO TABLE @DATA(lt_rows).
|
||||||
|
cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_rows ) ).
|
||||||
|
cl_abap_unit_assert=>assert_equals( exp = 'P1' act = lt_rows[ 1 ]-partner_id ).
|
||||||
|
cl_abap_unit_assert=>assert_equals( exp = 'P2' act = lt_rows[ 2 ]-partner_id ).
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD source_b_rows.
|
||||||
|
SELECT partner_id, source FROM {{p}}i_partner_all
|
||||||
|
WHERE source = 'B' ORDER BY partner_id INTO TABLE @DATA(lt_rows).
|
||||||
|
cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_rows ) ).
|
||||||
|
cl_abap_unit_assert=>assert_equals( exp = 'P2' act = lt_rows[ 1 ]-partner_id ).
|
||||||
|
cl_abap_unit_assert=>assert_equals( exp = 'P3' act = lt_rows[ 2 ]-partner_id ).
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD all_partners.
|
||||||
|
SELECT COUNT(*) FROM {{p}}i_partner_all INTO @DATA(lv_count).
|
||||||
|
cl_abap_unit_assert=>assert_equals( exp = 4 act = lv_count ).
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD same_id_twice.
|
||||||
|
SELECT source FROM {{p}}i_partner_all
|
||||||
|
WHERE partner_id = 'P2' ORDER BY source INTO TABLE @DATA(lt_rows).
|
||||||
|
cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_rows ) ).
|
||||||
|
cl_abap_unit_assert=>assert_equals( exp = 'A' act = lt_rows[ 1 ]-source ).
|
||||||
|
cl_abap_unit_assert=>assert_equals( exp = 'B' act = lt_rows[ 2 ]-source ).
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD name_and_city.
|
||||||
|
SELECT SINGLE name, city FROM {{p}}i_partner_all
|
||||||
|
WHERE partner_id = 'P3' AND source = 'B' INTO @DATA(ls_row).
|
||||||
|
cl_abap_unit_assert=>assert_equals( exp = 'Gamma KG' act = ls_row-name ).
|
||||||
|
cl_abap_unit_assert=>assert_equals( exp = 'Munich' act = ls_row-city ).
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD only_in_a.
|
||||||
|
SELECT source FROM {{p}}i_partner_all
|
||||||
|
WHERE partner_id = 'P1' INTO TABLE @DATA(lt_rows).
|
||||||
|
cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_rows ) ).
|
||||||
|
cl_abap_unit_assert=>assert_equals( exp = 'A' act = lt_rows[ 1 ]-source ).
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD only_in_b.
|
||||||
|
SELECT source FROM {{p}}i_partner_all
|
||||||
|
WHERE partner_id = 'P3' INTO TABLE @DATA(lt_rows).
|
||||||
|
cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_rows ) ).
|
||||||
|
cl_abap_unit_assert=>assert_equals( exp = 'B' act = lt_rows[ 1 ]-source ).
|
||||||
|
ENDMETHOD.
|
||||||
|
ENDCLASS.
|
||||||
19
tasks_gen/eval/G0025/reference/i_partner_all.ddls.asddls
Normal file
19
tasks_gen/eval/G0025/reference/i_partner_all.ddls.asddls
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
@AccessControl.authorizationCheck: #NOT_REQUIRED
|
||||||
|
@EndUserText.label: 'All partners'
|
||||||
|
@Metadata.ignorePropagatedAnnotations: true
|
||||||
|
define view entity {{P}}I_PARTNER_ALL
|
||||||
|
as select from {{p}}part_a as a
|
||||||
|
{
|
||||||
|
key a.partner_id as partner_id,
|
||||||
|
a.name as name,
|
||||||
|
a.city as city,
|
||||||
|
cast('A' as abap.char(1)) as source
|
||||||
|
}
|
||||||
|
union all
|
||||||
|
select from {{p}}part_b as b
|
||||||
|
{
|
||||||
|
key b.partner_id as partner_id,
|
||||||
|
b.name as name,
|
||||||
|
b.city as city,
|
||||||
|
cast('B' as abap.char(1)) as source
|
||||||
|
}
|
||||||
45
tasks_gen/eval/G0025/reference/t16_test.clas.abap
Normal file
45
tasks_gen/eval/G0025/reference/t16_test.clas.abap
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
CLASS {{p}}t16_test DEFINITION PUBLIC FINAL CREATE PUBLIC
|
||||||
|
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
|
||||||
|
PRIVATE SECTION.
|
||||||
|
CLASS-DATA go_env TYPE REF TO if_cds_test_environment.
|
||||||
|
CLASS-METHODS class_setup.
|
||||||
|
CLASS-METHODS class_teardown.
|
||||||
|
METHODS setup.
|
||||||
|
METHODS both_sources FOR TESTING.
|
||||||
|
METHODS same_partner_twice FOR TESTING.
|
||||||
|
ENDCLASS.
|
||||||
|
|
||||||
|
|
||||||
|
CLASS {{p}}t16_test IMPLEMENTATION.
|
||||||
|
METHOD class_setup.
|
||||||
|
go_env = cl_cds_test_environment=>create( i_for_entity = '{{P}}I_PARTNER_ALL' ).
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD class_teardown.
|
||||||
|
go_env->destroy( ).
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD setup.
|
||||||
|
DATA lt_a TYPE STANDARD TABLE OF {{p}}part_a WITH EMPTY KEY.
|
||||||
|
DATA lt_b TYPE STANDARD TABLE OF {{p}}part_b WITH EMPTY KEY.
|
||||||
|
go_env->clear_doubles( ).
|
||||||
|
lt_a = VALUE #( ( partner_id = 'A1' name = 'One' city = 'Bonn' ) ).
|
||||||
|
lt_b = VALUE #( ( partner_id = 'A1' name = 'One' city = 'Bonn' )
|
||||||
|
( partner_id = 'B1' name = 'Two' city = 'Kiel' ) ).
|
||||||
|
go_env->insert_test_data( lt_a ).
|
||||||
|
go_env->insert_test_data( lt_b ).
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD both_sources.
|
||||||
|
SELECT source FROM {{p}}i_partner_all ORDER BY source INTO TABLE @DATA(lt_rows).
|
||||||
|
cl_abap_unit_assert=>assert_equals( exp = 3 act = lines( lt_rows ) ).
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD same_partner_twice.
|
||||||
|
SELECT source FROM {{p}}i_partner_all
|
||||||
|
WHERE partner_id = 'A1' ORDER BY source INTO TABLE @DATA(lt_rows).
|
||||||
|
cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_rows ) ).
|
||||||
|
cl_abap_unit_assert=>assert_equals( exp = 'A' act = lt_rows[ 1 ]-source ).
|
||||||
|
cl_abap_unit_assert=>assert_equals( exp = 'B' act = lt_rows[ 2 ]-source ).
|
||||||
|
ENDMETHOD.
|
||||||
|
ENDCLASS.
|
||||||
11
tasks_gen/eval/G0025/seed/part_a.tabl.asabap
Normal file
11
tasks_gen/eval/G0025/seed/part_a.tabl.asabap
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
@EndUserText.label : 'Partner list A'
|
||||||
|
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
|
||||||
|
@AbapCatalog.tableCategory : #TRANSPARENT
|
||||||
|
@AbapCatalog.deliveryClass : #A
|
||||||
|
@AbapCatalog.dataMaintenance : #RESTRICTED
|
||||||
|
define table {{p}}part_a {
|
||||||
|
key client : abap.clnt not null;
|
||||||
|
key partner_id : abap.char(10) not null;
|
||||||
|
name : abap.char(40);
|
||||||
|
city : abap.char(40);
|
||||||
|
}
|
||||||
11
tasks_gen/eval/G0025/seed/part_b.tabl.asabap
Normal file
11
tasks_gen/eval/G0025/seed/part_b.tabl.asabap
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
@EndUserText.label : 'Partner list B'
|
||||||
|
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
|
||||||
|
@AbapCatalog.tableCategory : #TRANSPARENT
|
||||||
|
@AbapCatalog.deliveryClass : #A
|
||||||
|
@AbapCatalog.dataMaintenance : #RESTRICTED
|
||||||
|
define table {{p}}part_b {
|
||||||
|
key client : abap.clnt not null;
|
||||||
|
key partner_id : abap.char(10) not null;
|
||||||
|
name : abap.char(40);
|
||||||
|
city : abap.char(40);
|
||||||
|
}
|
||||||
24
tasks_gen/eval/G0025/seed/seed_partner.clas.abap
Normal file
24
tasks_gen/eval/G0025/seed/seed_partner.clas.abap
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
CLASS {{p}}seed_partner DEFINITION PUBLIC FINAL CREATE PUBLIC.
|
||||||
|
PUBLIC SECTION.
|
||||||
|
INTERFACES if_oo_adt_classrun.
|
||||||
|
PROTECTED SECTION.
|
||||||
|
PRIVATE SECTION.
|
||||||
|
ENDCLASS.
|
||||||
|
|
||||||
|
|
||||||
|
CLASS {{p}}seed_partner IMPLEMENTATION.
|
||||||
|
METHOD if_oo_adt_classrun~main.
|
||||||
|
DATA lt_a TYPE STANDARD TABLE OF {{p}}part_a WITH EMPTY KEY.
|
||||||
|
DATA lt_b TYPE STANDARD TABLE OF {{p}}part_b WITH EMPTY KEY.
|
||||||
|
|
||||||
|
lt_a = VALUE #( ( client = sy-mandt partner_id = 'P1' name = 'Alpha GmbH' city = 'Berlin' )
|
||||||
|
( client = sy-mandt partner_id = 'P2' name = 'Beta AG' city = 'Hamburg' ) ).
|
||||||
|
lt_b = VALUE #( ( client = sy-mandt partner_id = 'P2' name = 'Beta AG' city = 'Hamburg' )
|
||||||
|
( client = sy-mandt partner_id = 'P3' name = 'Gamma KG' city = 'Munich' ) ).
|
||||||
|
|
||||||
|
MODIFY {{p}}part_a FROM TABLE @lt_a.
|
||||||
|
MODIFY {{p}}part_b FROM TABLE @lt_b.
|
||||||
|
|
||||||
|
out->write( 'Partner seed data written.' ).
|
||||||
|
ENDMETHOD.
|
||||||
|
ENDCLASS.
|
||||||
37
tasks_gen/eval/G0025/spec.md
Normal file
37
tasks_gen/eval/G0025/spec.md
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
# 1. Goal
|
||||||
|
Two tables hold partner lists. A report and an OData service must read one
|
||||||
|
single list of all partners. Each row must show from which table it comes.
|
||||||
|
|
||||||
|
# 2. Open questions
|
||||||
|
None.
|
||||||
|
|
||||||
|
# 3. Context
|
||||||
|
- Table {{P}}PART_A (partner list A), package $TMP. Key: PARTNER_ID (CHAR 10).
|
||||||
|
Fields: NAME (CHAR 40), CITY (CHAR 40).
|
||||||
|
- Table {{P}}PART_B (partner list B), package $TMP. It has the same structure.
|
||||||
|
- A partner ID can be in both tables.
|
||||||
|
|
||||||
|
# 4. Contract
|
||||||
|
- Create the CDS view entity {{P}}I_PARTNER_ALL in package $TMP.
|
||||||
|
- Elements, with these names: PARTNER_ID (key), NAME, CITY, SOURCE.
|
||||||
|
- SOURCE is one character.
|
||||||
|
- No authorization check (#NOT_REQUIRED).
|
||||||
|
|
||||||
|
# 5. Business rules
|
||||||
|
1. The view shows every partner of {{P}}PART_A and every partner of
|
||||||
|
{{P}}PART_B. No partner is missing.
|
||||||
|
2. SOURCE is 'A' for a row from {{P}}PART_A. SOURCE is 'B' for a row from
|
||||||
|
{{P}}PART_B.
|
||||||
|
3. NAME and CITY are the values of the table that the row comes from.
|
||||||
|
4. If the same PARTNER_ID is in both tables, the view shows two rows for this
|
||||||
|
partner. One row has SOURCE 'A'. The other row has SOURCE 'B'.
|
||||||
|
5. A partner that is only in one table is shown one time.
|
||||||
|
|
||||||
|
# 6. Constraints
|
||||||
|
- Release target: 8.16.
|
||||||
|
- Out of scope: do not change {{P}}PART_A, {{P}}PART_B and {{P}}SEED_PARTNER.
|
||||||
|
|
||||||
|
# 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.
|
||||||
73
tasks_gen/eval/G0025/task.json
Normal file
73
tasks_gen/eval/G0025/task.json
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
{
|
||||||
|
"id": "G0025",
|
||||||
|
"category": "B",
|
||||||
|
"object_type": "DDLS",
|
||||||
|
"difficulty": 2,
|
||||||
|
"release_target": "v816",
|
||||||
|
"expected_outcome": "implement",
|
||||||
|
"budget": {
|
||||||
|
"max_tool_calls": 40,
|
||||||
|
"max_activations": 10
|
||||||
|
},
|
||||||
|
"seed": [
|
||||||
|
{
|
||||||
|
"type": "TABL",
|
||||||
|
"name": "{{P}}PART_A",
|
||||||
|
"file": "seed/part_a.tabl.asabap",
|
||||||
|
"description": "Partner list A"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "TABL",
|
||||||
|
"name": "{{P}}PART_B",
|
||||||
|
"file": "seed/part_b.tabl.asabap",
|
||||||
|
"description": "Partner list B"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "CLAS",
|
||||||
|
"name": "{{P}}SEED_PARTNER",
|
||||||
|
"file": "seed/seed_partner.clas.abap",
|
||||||
|
"description": "Fills both partner tables",
|
||||||
|
"run": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"contract": [
|
||||||
|
{
|
||||||
|
"type": "DDLS",
|
||||||
|
"name": "{{P}}I_PARTNER_ALL",
|
||||||
|
"fields": [
|
||||||
|
"PARTNER_ID",
|
||||||
|
"NAME",
|
||||||
|
"CITY",
|
||||||
|
"SOURCE"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"out_of_scope": [
|
||||||
|
"{{P}}PART_A",
|
||||||
|
"{{P}}PART_B",
|
||||||
|
"{{P}}SEED_PARTNER"
|
||||||
|
],
|
||||||
|
"hidden_tests": [
|
||||||
|
{
|
||||||
|
"type": "CLAS",
|
||||||
|
"name": "{{P}}T16_HIDDEN",
|
||||||
|
"file": "hidden/t16_hidden.clas.abap",
|
||||||
|
"description": "T16 hidden tests"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"reference": [
|
||||||
|
{
|
||||||
|
"type": "DDLS",
|
||||||
|
"name": "{{P}}I_PARTNER_ALL",
|
||||||
|
"file": "reference/i_partner_all.ddls.asddls",
|
||||||
|
"description": "All partners of both lists with a source element"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "CLAS",
|
||||||
|
"name": "{{P}}T16_TEST",
|
||||||
|
"file": "reference/t16_test.clas.abap",
|
||||||
|
"description": "T16 own tests"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"craft_checks": []
|
||||||
|
}
|
||||||
37
tasks_gen/eval/G0026/generation.json
Normal file
37
tasks_gen/eval/G0026/generation.json
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"id": "G0026",
|
||||||
|
"pool": "eval",
|
||||||
|
"object_type": "FUNC",
|
||||||
|
"category": "A",
|
||||||
|
"attempts": [
|
||||||
|
{
|
||||||
|
"stage": "bundle",
|
||||||
|
"errors": [
|
||||||
|
"reference/t14_test.clas.abap line 81: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\""
|
||||||
|
],
|
||||||
|
"by_check": {
|
||||||
|
"abaplint": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"stage": "validate",
|
||||||
|
"oracle": 0,
|
||||||
|
"null": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"stage": "bundle",
|
||||||
|
"errors": [
|
||||||
|
"reference/t14_test.clas.abap line 81: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\""
|
||||||
|
],
|
||||||
|
"by_check": {
|
||||||
|
"abaplint": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"stage": "validate",
|
||||||
|
"oracle": 100.0,
|
||||||
|
"null": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accepted": true
|
||||||
|
}
|
||||||
149
tasks_gen/eval/G0026/hidden/t14_hidden.clas.abap
Normal file
149
tasks_gen/eval/G0026/hidden/t14_hidden.clas.abap
Normal file
@@ -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.
|
||||||
158
tasks_gen/eval/G0026/reference/cl_rent.clas.abap
Normal file
158
tasks_gen/eval/G0026/reference/cl_rent.clas.abap
Normal file
@@ -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.
|
||||||
87
tasks_gen/eval/G0026/reference/cl_rent.clas.testclasses.abap
Normal file
87
tasks_gen/eval/G0026/reference/cl_rent.clas.testclasses.abap
Normal file
@@ -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.
|
||||||
30
tasks_gen/eval/G0026/reference/cx_rent_invalid.clas.abap
Normal file
30
tasks_gen/eval/G0026/reference/cx_rent_invalid.clas.abap
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
CLASS {{p}}cx_rent_invalid DEFINITION
|
||||||
|
PUBLIC
|
||||||
|
INHERITING FROM cx_static_check
|
||||||
|
FINAL
|
||||||
|
CREATE PUBLIC.
|
||||||
|
|
||||||
|
PUBLIC SECTION.
|
||||||
|
METHODS constructor
|
||||||
|
IMPORTING textid LIKE textid OPTIONAL
|
||||||
|
previous LIKE previous OPTIONAL
|
||||||
|
iv_reason TYPE string OPTIONAL.
|
||||||
|
|
||||||
|
METHODS get_reason
|
||||||
|
RETURNING VALUE(rv_reason) TYPE string.
|
||||||
|
|
||||||
|
PRIVATE SECTION.
|
||||||
|
DATA mv_reason TYPE string.
|
||||||
|
ENDCLASS.
|
||||||
|
|
||||||
|
|
||||||
|
CLASS {{p}}cx_rent_invalid IMPLEMENTATION.
|
||||||
|
METHOD constructor.
|
||||||
|
super->constructor( textid = textid previous = previous ).
|
||||||
|
mv_reason = iv_reason.
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD get_reason.
|
||||||
|
rv_reason = mv_reason.
|
||||||
|
ENDMETHOD.
|
||||||
|
ENDCLASS.
|
||||||
43
tasks_gen/eval/G0026/reference/rent_price.func.abap
Normal file
43
tasks_gen/eval/G0026/reference/rent_price.func.abap
Normal file
@@ -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.
|
||||||
90
tasks_gen/eval/G0026/reference/t14_test.clas.abap
Normal file
90
tasks_gen/eval/G0026/reference/t14_test.clas.abap
Normal file
@@ -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.
|
||||||
25
tasks_gen/eval/G0026/seed/rent_sample.func.abap
Normal file
25
tasks_gen/eval/G0026/seed/rent_sample.func.abap
Normal file
@@ -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.
|
||||||
81
tasks_gen/eval/G0026/spec.md
Normal file
81
tasks_gen/eval/G0026/spec.md
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
# 1. Goal
|
||||||
|
Calculate the price of a finished car-sharing rental. A booking program calls
|
||||||
|
one function module for each finished rental. The function module must have
|
||||||
|
the same interface as the sample function module, because the booking program
|
||||||
|
calls all pricing modules in the same way.
|
||||||
|
|
||||||
|
# 2. Open questions
|
||||||
|
None.
|
||||||
|
|
||||||
|
# 3. Context
|
||||||
|
- Function group {{P}}FG_RENT exists in package $TMP.
|
||||||
|
- Function module {{P}}RENT_SAMPLE exists in this function group. It is the
|
||||||
|
sample pricing module. Its interface is the interface that all pricing
|
||||||
|
modules must use.
|
||||||
|
- All rental data is in the input parameters. No database access is necessary.
|
||||||
|
|
||||||
|
# 4. Contract
|
||||||
|
Create the function module {{P}}RENT_PRICE in function group {{P}}FG_RENT.
|
||||||
|
The interface is:
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
This interface is the same as the interface of {{P}}RENT_SAMPLE.
|
||||||
|
|
||||||
|
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 is your own design decision. The function module
|
||||||
|
maps the result of the class to its exporting parameters and exceptions.
|
||||||
|
|
||||||
|
# 5. Business rules
|
||||||
|
1. Check the input in this sequence:
|
||||||
|
a. If iv_minutes is less than 1, raise INVALID_DURATION.
|
||||||
|
b. If iv_km is less than 0, raise INVALID_DISTANCE.
|
||||||
|
c. If iv_vehicle_class is not 'S', not 'M' and not 'L', raise INVALID_CLASS.
|
||||||
|
2. 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.
|
||||||
|
3. 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.
|
||||||
|
4. 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.
|
||||||
|
5. If iv_weekend is true, the weekend surcharge is 25 % of the time fee.
|
||||||
|
Otherwise the weekend surcharge is 0.
|
||||||
|
6. The gross amount is the time fee plus the distance fee plus the weekend
|
||||||
|
surcharge.
|
||||||
|
7. If iv_member is true, the member discount is 15 % of the gross amount.
|
||||||
|
Otherwise the member discount is 0.
|
||||||
|
8. 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.
|
||||||
|
9. Round the weekend surcharge, the member discount and the total price half
|
||||||
|
up to 2 decimals.
|
||||||
|
10. 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.
|
||||||
|
|
||||||
|
# 6. Constraints
|
||||||
|
- Release target: ABAP Platform 2025 (SAP_BASIS 816).
|
||||||
|
- Coding standards: Clean ABAP. Keep every method below 40 statements.
|
||||||
|
- Out of scope: do not change {{P}}RENT_SAMPLE.
|
||||||
|
|
||||||
|
# 7. Acceptance
|
||||||
|
- The function module {{P}}RENT_PRICE is active and has no syntax error.
|
||||||
|
- The hidden tests 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.
|
||||||
111
tasks_gen/eval/G0026/task.json
Normal file
111
tasks_gen/eval/G0026/task.json
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
{
|
||||||
|
"id": "G0026",
|
||||||
|
"category": "A",
|
||||||
|
"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_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"
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user