abapgit-agent 1.4.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/abap/guidelines/00_index.md +35 -0
- package/abap/guidelines/01_sql.md +72 -0
- package/abap/guidelines/02_exceptions.md +108 -0
- package/abap/guidelines/03_testing.md +252 -0
- package/abap/guidelines/04_cds.md +120 -0
- package/abap/guidelines/05_classes.md +50 -0
- package/abap/guidelines/06_objects.md +103 -0
- package/abap/guidelines/07_json.md +22 -0
- package/abap/guidelines/08_abapgit.md +193 -0
- package/bin/abapgit-agent +597 -44
- package/bin/abgagt +24 -0
- package/package.json +11 -3
- package/src/abap-client.js +65 -2
- package/src/agent.js +58 -4
- package/src/config.js +9 -2
- package/src/ref-search.js +989 -0
- package/.abapGitAgent.example +0 -11
- package/.github/workflows/release.yml +0 -57
- package/API.md +0 -710
- package/CLAUDE.md +0 -1031
- package/CLAUDE_MEM.md +0 -88
- package/ERROR_HANDLING.md +0 -30
- package/INSTALL.md +0 -155
- package/RELEASE_NOTES.md +0 -143
- package/abap/CLAUDE.md +0 -898
- package/abap/copilot-instructions.md +0 -79
- package/abap/package.devc.xml +0 -10
- package/abap/zcl_abgagt_agent.clas.abap +0 -420
- package/abap/zcl_abgagt_agent.clas.xml +0 -15
- package/abap/zcl_abgagt_cmd_factory.clas.abap +0 -48
- package/abap/zcl_abgagt_cmd_factory.clas.xml +0 -15
- package/abap/zcl_abgagt_command_create.clas.abap +0 -95
- package/abap/zcl_abgagt_command_create.clas.xml +0 -15
- package/abap/zcl_abgagt_command_import.clas.abap +0 -138
- package/abap/zcl_abgagt_command_import.clas.xml +0 -15
- package/abap/zcl_abgagt_command_inspect.clas.abap +0 -411
- package/abap/zcl_abgagt_command_inspect.clas.testclasses.abap +0 -121
- package/abap/zcl_abgagt_command_inspect.clas.xml +0 -16
- package/abap/zcl_abgagt_command_preview.clas.abap +0 -386
- package/abap/zcl_abgagt_command_preview.clas.xml +0 -15
- package/abap/zcl_abgagt_command_pull.clas.abap +0 -80
- package/abap/zcl_abgagt_command_pull.clas.testclasses.abap +0 -87
- package/abap/zcl_abgagt_command_pull.clas.xml +0 -16
- package/abap/zcl_abgagt_command_tree.clas.abap +0 -237
- package/abap/zcl_abgagt_command_tree.clas.xml +0 -15
- package/abap/zcl_abgagt_command_unit.clas.abap +0 -297
- package/abap/zcl_abgagt_command_unit.clas.xml +0 -15
- package/abap/zcl_abgagt_command_view.clas.abap +0 -240
- package/abap/zcl_abgagt_command_view.clas.xml +0 -15
- package/abap/zcl_abgagt_resource_create.clas.abap +0 -71
- package/abap/zcl_abgagt_resource_create.clas.xml +0 -15
- package/abap/zcl_abgagt_resource_health.clas.abap +0 -25
- package/abap/zcl_abgagt_resource_health.clas.xml +0 -15
- package/abap/zcl_abgagt_resource_import.clas.abap +0 -66
- package/abap/zcl_abgagt_resource_import.clas.xml +0 -15
- package/abap/zcl_abgagt_resource_inspect.clas.abap +0 -62
- package/abap/zcl_abgagt_resource_inspect.clas.xml +0 -15
- package/abap/zcl_abgagt_resource_preview.clas.abap +0 -67
- package/abap/zcl_abgagt_resource_preview.clas.xml +0 -15
- package/abap/zcl_abgagt_resource_pull.clas.abap +0 -71
- package/abap/zcl_abgagt_resource_pull.clas.xml +0 -15
- package/abap/zcl_abgagt_resource_tree.clas.abap +0 -70
- package/abap/zcl_abgagt_resource_tree.clas.xml +0 -15
- package/abap/zcl_abgagt_resource_unit.clas.abap +0 -64
- package/abap/zcl_abgagt_resource_unit.clas.xml +0 -15
- package/abap/zcl_abgagt_resource_view.clas.abap +0 -68
- package/abap/zcl_abgagt_resource_view.clas.xml +0 -15
- package/abap/zcl_abgagt_rest_handler.clas.abap +0 -32
- package/abap/zcl_abgagt_rest_handler.clas.xml +0 -15
- package/abap/zcl_abgagt_util.clas.abap +0 -93
- package/abap/zcl_abgagt_util.clas.testclasses.abap +0 -84
- package/abap/zcl_abgagt_util.clas.xml +0 -16
- package/abap/zcl_abgagt_viewer_clas.clas.abap +0 -58
- package/abap/zcl_abgagt_viewer_clas.clas.xml +0 -15
- package/abap/zcl_abgagt_viewer_ddls.clas.abap +0 -83
- package/abap/zcl_abgagt_viewer_ddls.clas.xml +0 -15
- package/abap/zcl_abgagt_viewer_dtel.clas.abap +0 -98
- package/abap/zcl_abgagt_viewer_dtel.clas.xml +0 -15
- package/abap/zcl_abgagt_viewer_factory.clas.abap +0 -41
- package/abap/zcl_abgagt_viewer_factory.clas.xml +0 -15
- package/abap/zcl_abgagt_viewer_intf.clas.abap +0 -58
- package/abap/zcl_abgagt_viewer_intf.clas.xml +0 -15
- package/abap/zcl_abgagt_viewer_stru.clas.abap +0 -59
- package/abap/zcl_abgagt_viewer_stru.clas.xml +0 -15
- package/abap/zcl_abgagt_viewer_tabl.clas.abap +0 -59
- package/abap/zcl_abgagt_viewer_tabl.clas.xml +0 -15
- package/abap/zcl_abgagt_viewer_ttyp.clas.abap +0 -93
- package/abap/zcl_abgagt_viewer_ttyp.clas.xml +0 -15
- package/abap/zif_abgagt_agent.intf.abap +0 -53
- package/abap/zif_abgagt_agent.intf.xml +0 -15
- package/abap/zif_abgagt_cmd_factory.intf.abap +0 -7
- package/abap/zif_abgagt_cmd_factory.intf.xml +0 -15
- package/abap/zif_abgagt_command.intf.abap +0 -26
- package/abap/zif_abgagt_command.intf.xml +0 -15
- package/abap/zif_abgagt_util.intf.abap +0 -28
- package/abap/zif_abgagt_util.intf.xml +0 -15
- package/abap/zif_abgagt_viewer.intf.abap +0 -12
- package/abap/zif_abgagt_viewer.intf.xml +0 -15
- package/docs/commands.md +0 -142
- package/docs/create-command.md +0 -129
- package/docs/health-command.md +0 -89
- package/docs/import-command.md +0 -195
- package/docs/init-command.md +0 -189
- package/docs/inspect-command.md +0 -158
- package/docs/preview-command.md +0 -528
- package/docs/pull-command.md +0 -188
- package/docs/status-command.md +0 -68
- package/docs/tree-command.md +0 -303
- package/docs/unit-command.md +0 -167
- package/docs/view-command.md +0 -501
- package/img/claude.png +0 -0
- package/scripts/claude-integration.js +0 -351
- package/scripts/release.sh +0 -60
- package/scripts/test-integration.js +0 -139
package/README.md
CHANGED
|
@@ -124,6 +124,7 @@ abapgit-agent health
|
|
|
124
124
|
# Check integration status
|
|
125
125
|
abapgit-agent status
|
|
126
126
|
```
|
|
127
|
+
Note: All ABAP commands automatically check CLI/ABAP API version compatibility.
|
|
127
128
|
|
|
128
129
|
## Local Development
|
|
129
130
|
|
|
@@ -153,6 +154,7 @@ npm run pull -- --url <git-url> --branch main
|
|
|
153
154
|
| tree Command | [docs/tree-command.md](docs/tree-command.md) |
|
|
154
155
|
| view Command | [docs/view-command.md](docs/view-command.md) |
|
|
155
156
|
| preview Command | [docs/preview-command.md](docs/preview-command.md) |
|
|
157
|
+
| ref Command | [docs/ref-command.md](docs/ref-command.md) |
|
|
156
158
|
| REST API Reference | [API.md](API.md) |
|
|
157
159
|
| Error Handling | [ERROR_HANDLING.md](ERROR_HANDLING.md) |
|
|
158
160
|
| ABAP Coding Guidelines | [abap/CLAUDE.md](abap/CLAUDE.md) |
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# ABAP Coding Guidelines Index
|
|
2
|
+
|
|
3
|
+
This folder contains detailed ABAP coding guidelines that can be searched using the `ref` command.
|
|
4
|
+
|
|
5
|
+
## Guidelines Available
|
|
6
|
+
|
|
7
|
+
| File | Topic |
|
|
8
|
+
|------|-------|
|
|
9
|
+
| `01_sql.md` | ABAP SQL Best Practices |
|
|
10
|
+
| `02_exceptions.md` | Exception Handling |
|
|
11
|
+
| `03_testing.md` | Unit Testing (including CDS) |
|
|
12
|
+
| `04_cds.md` | CDS Views |
|
|
13
|
+
| `05_classes.md` | ABAP Classes and Objects |
|
|
14
|
+
| `06_objects.md` | Object Naming Conventions |
|
|
15
|
+
| `07_json.md` | JSON Handling |
|
|
16
|
+
| `08_abapgit.md` | abapGit XML Metadata Templates |
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
These guidelines are automatically searched by the `ref` command:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
# Search across all guidelines
|
|
24
|
+
abapgit-agent ref "CORRESPONDING"
|
|
25
|
+
|
|
26
|
+
# List all topics
|
|
27
|
+
abapgit-agent ref --list-topics
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Adding Custom Guidelines
|
|
31
|
+
|
|
32
|
+
To add your own guidelines:
|
|
33
|
+
1. Create a new `.md` file in this folder
|
|
34
|
+
2. Follow the naming convention: `XX_name.md`
|
|
35
|
+
3. Export to reference folder: `abapgit-agent ref export`
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# ABAP SQL Best Practices
|
|
2
|
+
|
|
3
|
+
When writing ABAP SQL (Open SQL) queries, follow these rules:
|
|
4
|
+
|
|
5
|
+
## 1. Host Variables - Use @ Prefix
|
|
6
|
+
|
|
7
|
+
Use `@` prefix for host variables in ABAP SQL:
|
|
8
|
+
|
|
9
|
+
```abap
|
|
10
|
+
" Correct
|
|
11
|
+
SELECT * FROM tadir WHERE devclass = @lv_package.
|
|
12
|
+
|
|
13
|
+
" Wrong - no @ prefix
|
|
14
|
+
SELECT * FROM tadir WHERE devclass = lv_package.
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## 2. Range Tables for IN Clauses
|
|
18
|
+
|
|
19
|
+
When filtering with `IN`, use a range table with `@` prefix:
|
|
20
|
+
|
|
21
|
+
```abap
|
|
22
|
+
" Define range table
|
|
23
|
+
DATA lt_type_range TYPE RANGE OF tadir-object.
|
|
24
|
+
ls_type-sign = 'I'.
|
|
25
|
+
ls_type-option = 'EQ'.
|
|
26
|
+
ls_type-low = 'CLAS'.
|
|
27
|
+
APPEND ls_type TO lt_type_range.
|
|
28
|
+
|
|
29
|
+
" Use with @ prefix
|
|
30
|
+
SELECT object, obj_name FROM tadir
|
|
31
|
+
WHERE object IN @lt_type_range
|
|
32
|
+
INTO TABLE @lt_objects.
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## 3. SELECT Statement Clause Order
|
|
36
|
+
|
|
37
|
+
The correct sequence is:
|
|
38
|
+
```
|
|
39
|
+
SELECT → FROM → WHERE → ORDER BY → INTO → UP TO → OFFSET
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
```abap
|
|
43
|
+
SELECT object, obj_name FROM tadir
|
|
44
|
+
WHERE devclass = @lv_package
|
|
45
|
+
AND object IN @lt_type_range
|
|
46
|
+
ORDER BY object, obj_name
|
|
47
|
+
INTO TABLE @lt_objects
|
|
48
|
+
UP TO @lv_limit ROWS
|
|
49
|
+
OFFSET @lv_offset.
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## 4. Fixed Point Arithmetic (FIXPT)
|
|
53
|
+
|
|
54
|
+
For numeric operations in ABAP SQL (especially with UP TO/OFFSET), enable FIXPT in the class XML:
|
|
55
|
+
|
|
56
|
+
```xml
|
|
57
|
+
<VSEOCLASS>
|
|
58
|
+
<FIXPT>X</FIXPT>
|
|
59
|
+
</VSEOCLASS>
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## 5. Field Separation
|
|
63
|
+
|
|
64
|
+
Always separate fields with commas in SELECT:
|
|
65
|
+
|
|
66
|
+
```abap
|
|
67
|
+
" Correct
|
|
68
|
+
SELECT object, obj_name FROM tadir ...
|
|
69
|
+
|
|
70
|
+
" Wrong - missing comma
|
|
71
|
+
SELECT object obj_name FROM tadir ...
|
|
72
|
+
```
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Exception Handling - Classical vs Class-Based
|
|
2
|
+
|
|
3
|
+
ABAP has two exception handling mechanisms. Using the wrong one causes silent failures.
|
|
4
|
+
|
|
5
|
+
## Quick Identification
|
|
6
|
+
|
|
7
|
+
| Method Signature | Exception Type | Handling Pattern |
|
|
8
|
+
|-----------------|----------------|------------------|
|
|
9
|
+
| `EXCEPTIONS exc = 1` | Classical | `sy-subrc` check |
|
|
10
|
+
| `RAISING cx_...` | Class-based | `TRY-CATCH` |
|
|
11
|
+
|
|
12
|
+
## Classical Exceptions (Old Style)
|
|
13
|
+
|
|
14
|
+
Methods declared with `EXCEPTIONS` in signature:
|
|
15
|
+
|
|
16
|
+
```abap
|
|
17
|
+
" Method declaration
|
|
18
|
+
class-methods describe_by_name
|
|
19
|
+
importing p_name type any
|
|
20
|
+
returning value(p_descr_ref) type ref to cl_abap_typedescr
|
|
21
|
+
exceptions
|
|
22
|
+
type_not_found. " <- Classical!
|
|
23
|
+
|
|
24
|
+
" Calling with classical exception
|
|
25
|
+
cl_abap_structdescr=>describe_by_name(
|
|
26
|
+
EXPORTING
|
|
27
|
+
p_name = iv_tabname
|
|
28
|
+
RECEIVING
|
|
29
|
+
p_descr_ref = lo_descr
|
|
30
|
+
EXCEPTIONS
|
|
31
|
+
type_not_found = 1
|
|
32
|
+
OTHERS = 2 ).
|
|
33
|
+
IF sy-subrc <> 0.
|
|
34
|
+
" Handle error
|
|
35
|
+
ENDIF.
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**Common classical exception methods:**
|
|
39
|
+
- `cl_abap_structdescr=>describe_by_name` - `type_not_found`
|
|
40
|
+
- `cl_abap_tabledescr=>describe_by_name` - `type_not_found`
|
|
41
|
+
- Many RTTI (Run Time Type Information) methods
|
|
42
|
+
|
|
43
|
+
## Class-Based Exceptions (Modern)
|
|
44
|
+
|
|
45
|
+
Methods declared with `RAISING`:
|
|
46
|
+
|
|
47
|
+
```abap
|
|
48
|
+
" Method declaration
|
|
49
|
+
methods get_ref
|
|
50
|
+
importing p_name type string
|
|
51
|
+
returning value(p_ref) type ref to cl_ci_checkvariant
|
|
52
|
+
raising cx_ci_checkvariant. " <- Class-based!
|
|
53
|
+
|
|
54
|
+
" Calling with TRY-CATCH
|
|
55
|
+
TRY.
|
|
56
|
+
lo_variant = cl_ci_checkvariant=>get_ref( p_name = lv_variant ).
|
|
57
|
+
CATCH cx_ci_checkvariant INTO DATA(lx_error).
|
|
58
|
+
" Handle error
|
|
59
|
+
ENDTRY.
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## The Mistake to Avoid
|
|
63
|
+
|
|
64
|
+
**WRONG**: Using TRY-CATCH for classical exceptions
|
|
65
|
+
```abap
|
|
66
|
+
" This does NOT catch type_not_found!
|
|
67
|
+
TRY.
|
|
68
|
+
lo_descr = cl_abap_structdescr=>describe_by_name( iv_name ).
|
|
69
|
+
CATCH cx_root. " Never reached!
|
|
70
|
+
ENDTRY.
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**CORRECT**: Use proper pattern for each type
|
|
74
|
+
```abap
|
|
75
|
+
" Classical - use sy-subrc
|
|
76
|
+
cl_abap_structdescr=>describe_by_name(
|
|
77
|
+
EXPORTING p_name = iv_name
|
|
78
|
+
RECEIVING p_descr_ref = lo_descr
|
|
79
|
+
EXCEPTIONS type_not_found = 1 ).
|
|
80
|
+
IF sy-subrc <> 0.
|
|
81
|
+
" Handle error
|
|
82
|
+
ENDIF.
|
|
83
|
+
|
|
84
|
+
" Class-based - use TRY-CATCH
|
|
85
|
+
TRY.
|
|
86
|
+
lo_obj = cl_ci_checkvariant=>get_ref( lv_name ).
|
|
87
|
+
CATCH cx_root INTO DATA(lx_error).
|
|
88
|
+
" Handle error
|
|
89
|
+
ENDTRY.
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## How to Check Which to Use
|
|
93
|
+
|
|
94
|
+
Use the `view` command to check method signature:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
abapgit-agent view --objects CL_ABAP_STRUCTDESCR
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Look for:
|
|
101
|
+
- `exceptions TYPE_NOT_FOUND` → Classical (use `sy-subrc`)
|
|
102
|
+
- `raising CX_SY_RTTI` → Class-based (use `TRY-CATCH`)
|
|
103
|
+
|
|
104
|
+
Or search the cheat sheets:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
abapgit-agent ref --topic exceptions
|
|
108
|
+
```
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
# Unit Testing
|
|
2
|
+
|
|
3
|
+
## Unit Testing with Local Test Classes
|
|
4
|
+
|
|
5
|
+
### File Structure
|
|
6
|
+
|
|
7
|
+
For ABAP local unit tests, use a **separate file** with `.testclasses.abap` extension:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
abap/
|
|
11
|
+
zcl_my_class.clas.abap <- Main class (no test code)
|
|
12
|
+
zcl_my_class.clas.testclasses.abap <- Local test class
|
|
13
|
+
zcl_my_class.clas.xml <- XML with WITH_UNIT_TESTS = X
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
### Required Elements
|
|
17
|
+
|
|
18
|
+
1. **Test class file** (`zcl_my_class.clas.testclasses.abap`):
|
|
19
|
+
```abap
|
|
20
|
+
*"* use this source file for your test class implementation
|
|
21
|
+
*"* local test class
|
|
22
|
+
CLASS ltcl_zcl_my_class DEFINITION FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
|
|
23
|
+
PRIVATE SECTION.
|
|
24
|
+
DATA mo_cut TYPE REF TO zcl_my_class.
|
|
25
|
+
METHODS setup.
|
|
26
|
+
METHODS test_method1 FOR TESTING.
|
|
27
|
+
METHODS test_method2 FOR TESTING.
|
|
28
|
+
ENDCLASS.
|
|
29
|
+
|
|
30
|
+
CLASS ltcl_zcl_my_class IMPLEMENTATION.
|
|
31
|
+
METHOD setup.
|
|
32
|
+
CREATE OBJECT mo_cut.
|
|
33
|
+
ENDMETHOD.
|
|
34
|
+
METHOD test_method1.
|
|
35
|
+
" Test code using cl_abap_unit_assert
|
|
36
|
+
ENDMETHOD.
|
|
37
|
+
ENDCLASS.
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
2. **XML metadata** (`zcl_my_class.clas.xml`):
|
|
41
|
+
```xml
|
|
42
|
+
<VSEOCLASS>
|
|
43
|
+
...
|
|
44
|
+
<WITH_UNIT_TESTS>X</WITH_UNIT_TESTS>
|
|
45
|
+
</VSEOCLASS>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Naming Conventions
|
|
49
|
+
|
|
50
|
+
- Test class name: `LTCL_ZCL_<CLASSNAME>` (e.g., `LTCL_ZCL_COMMAND_PULL`)
|
|
51
|
+
- Test methods: `TEST_<methodname> FOR TESTING` or simply `test_method FOR TESTING`
|
|
52
|
+
- Test file: `<classname>.clas.testclasses.abap`
|
|
53
|
+
|
|
54
|
+
### CRITICAL: Method Name Length Limit
|
|
55
|
+
|
|
56
|
+
**Test method names MUST NOT exceed 30 characters!**
|
|
57
|
+
|
|
58
|
+
```abap
|
|
59
|
+
" WRONG - 34 characters (syntax error)
|
|
60
|
+
METHODS test_execute_with_minimal_params FOR TESTING.
|
|
61
|
+
|
|
62
|
+
" CORRECT - 18 characters
|
|
63
|
+
METHODS test_exec_minimal FOR TESTING.
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Examples of compliant names:
|
|
67
|
+
- `test_get_name` (13 chars)
|
|
68
|
+
- `test_exec_minimal` (18 chars)
|
|
69
|
+
- `test_exec_files` (16 chars)
|
|
70
|
+
- `test_interface` (15 chars)
|
|
71
|
+
|
|
72
|
+
### Common Assertions
|
|
73
|
+
|
|
74
|
+
```abap
|
|
75
|
+
cl_abap_unit_assert=>assert_equals( act = lv_actual exp = lv_expected msg = 'Error message' ).
|
|
76
|
+
cl_abap_unit_assert=>assert_not_initial( act = lv_data msg = 'Should not be initial' ).
|
|
77
|
+
cl_abap_unit_assert=>assert_bound( act = lo_ref msg = 'Should be bound' ).
|
|
78
|
+
cl_abap_unit_assert=>assert_true( act = lv_bool msg = 'Should be true' ).
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### What NOT To Do
|
|
82
|
+
|
|
83
|
+
- ❌ Don't add test methods directly in the main `.clas.abap` file
|
|
84
|
+
- ❌ Don't use `CLASS ... DEFINITION ...` without the special comment header
|
|
85
|
+
- ❌ Don't reference `<TESTCLASS>` in XML - abapGit auto-detects `.testclasses.abap`
|
|
86
|
+
- ❌ Don't use nested local classes inside the main class definition
|
|
87
|
+
|
|
88
|
+
### Running Tests
|
|
89
|
+
|
|
90
|
+
In ABAP: SE24 → Test → Execute Unit Tests
|
|
91
|
+
|
|
92
|
+
Or via abapGit: Pull the files and run tests in the ABAP system.
|
|
93
|
+
|
|
94
|
+
## Unit Testing CDS Views
|
|
95
|
+
|
|
96
|
+
When testing code that uses CDS view entities, you can use the **CDS Test Double Framework** (`CL_CDS_TEST_ENVIRONMENT`) to create test doubles for CDS views. This allows you to inject test data without affecting production data.
|
|
97
|
+
|
|
98
|
+
### When to Use CDS Test Doubles
|
|
99
|
+
|
|
100
|
+
- Testing code that reads from CDS views
|
|
101
|
+
- Need controlled test data (not production data)
|
|
102
|
+
- Testing CDS view logic with specific scenarios
|
|
103
|
+
|
|
104
|
+
### CDS Test Double Framework
|
|
105
|
+
|
|
106
|
+
Use `CL_CDS_TEST_ENVIRONMENT` for controlled test data:
|
|
107
|
+
|
|
108
|
+
```abap
|
|
109
|
+
"-------------------------
|
|
110
|
+
" CLASS DEFINITION
|
|
111
|
+
"-------------------------
|
|
112
|
+
CLASS ltcl_cds_test DEFINITION FOR TESTING RISK LEVEL HARMLESS DURATION SHORT FINAL.
|
|
113
|
+
|
|
114
|
+
PRIVATE SECTION.
|
|
115
|
+
" IMPORTANT: Use interface type, not class type!
|
|
116
|
+
DATA mo_cds_env TYPE REF TO if_cds_test_environment.
|
|
117
|
+
|
|
118
|
+
" IMPORTANT: class_setup/teardown must be CLASS-METHODS (static)!
|
|
119
|
+
CLASS-DATA mo_cds_env_static TYPE REF TO if_cds_test_environment.
|
|
120
|
+
|
|
121
|
+
METHODS setup.
|
|
122
|
+
METHODS test_cds_with_doubles FOR TESTING.
|
|
123
|
+
|
|
124
|
+
CLASS-METHODS: class_setup,
|
|
125
|
+
class_teardown.
|
|
126
|
+
|
|
127
|
+
ENDCLASS.
|
|
128
|
+
|
|
129
|
+
"-------------------------
|
|
130
|
+
" CLASS IMPLEMENTATION
|
|
131
|
+
"-------------------------
|
|
132
|
+
CLASS ltcl_cds_test IMPLEMENTATION.
|
|
133
|
+
|
|
134
|
+
METHOD class_setup.
|
|
135
|
+
" Create CDS test environment - framework auto-creates doubles for dependencies
|
|
136
|
+
mo_cds_env_static = cl_cds_test_environment=>create(
|
|
137
|
+
i_for_entity = 'ZC_MY_CDS_VIEW' ).
|
|
138
|
+
ENDMETHOD.
|
|
139
|
+
|
|
140
|
+
METHOD class_teardown.
|
|
141
|
+
" Clean up test environment
|
|
142
|
+
mo_cds_env_static->destroy( ).
|
|
143
|
+
ENDMETHOD.
|
|
144
|
+
|
|
145
|
+
METHOD setup.
|
|
146
|
+
" IMPORTANT: Assign static env to instance and clear doubles
|
|
147
|
+
mo_cds_env = mo_cds_env_static.
|
|
148
|
+
mo_cds_env->clear_doubles( ).
|
|
149
|
+
ENDMETHOD.
|
|
150
|
+
|
|
151
|
+
METHOD test_cds_with_doubles.
|
|
152
|
+
" IMPORTANT: Must declare table type first, cannot inline in VALUE!
|
|
153
|
+
DATA lt_test_data TYPE TABLE OF zc_my_cds_view WITH EMPTY KEY.
|
|
154
|
+
lt_test_data = VALUE #(
|
|
155
|
+
( field1 = 'A' field2 = 100 )
|
|
156
|
+
( field1 = 'B' field2 = 200 ) ).
|
|
157
|
+
|
|
158
|
+
" Insert test data using named parameter
|
|
159
|
+
mo_cds_env->insert_test_data( i_data = lt_test_data ).
|
|
160
|
+
|
|
161
|
+
" Select from CDS view
|
|
162
|
+
SELECT * FROM zc_my_cds_view INTO TABLE @DATA(lt_result).
|
|
163
|
+
|
|
164
|
+
" Verify results
|
|
165
|
+
cl_abap_unit_assert=>assert_not_initial(
|
|
166
|
+
act = lt_result
|
|
167
|
+
msg = 'Result should not be empty' ).
|
|
168
|
+
|
|
169
|
+
cl_abap_unit_assert=>assert_equals(
|
|
170
|
+
act = lines( lt_result )
|
|
171
|
+
exp = 2
|
|
172
|
+
msg = 'Expected 2 rows' ).
|
|
173
|
+
ENDMETHOD.
|
|
174
|
+
|
|
175
|
+
ENDCLASS.
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Testing CDS Views with Aggregations (SUM, COUNT, GROUP BY)
|
|
179
|
+
|
|
180
|
+
For CDS views with aggregations, insert test data into the **base tables** (SFLIGHT, SCARR, SBOOK), not directly into the CDS view:
|
|
181
|
+
|
|
182
|
+
```abap
|
|
183
|
+
METHOD test_aggregation.
|
|
184
|
+
" Insert data into base tables via CDS test doubles
|
|
185
|
+
DATA lt_scarr TYPE TABLE OF scarr WITH EMPTY KEY.
|
|
186
|
+
lt_scarr = VALUE #( ( carrid = 'LH' carrname = 'Lufthansa' currcode = 'EUR' ) ).
|
|
187
|
+
mo_cds_env->insert_test_data( i_data = lt_scarr ).
|
|
188
|
+
|
|
189
|
+
DATA lt_sflight TYPE TABLE OF sflight WITH EMPTY KEY.
|
|
190
|
+
lt_sflight = VALUE #( ( carrid = 'LH' connid = '0400' fldate = '20240115'
|
|
191
|
+
seatsmax = 200 seatsocc = 100 ) ).
|
|
192
|
+
mo_cds_env->insert_test_data( i_data = lt_sflight ).
|
|
193
|
+
|
|
194
|
+
DATA lt_sbook TYPE TABLE OF sbook WITH EMPTY KEY.
|
|
195
|
+
lt_sbook = VALUE #(
|
|
196
|
+
( carrid = 'LH' connid = '0400' fldate = '20240115' bookid = '0001' forcuram = 1000 )
|
|
197
|
+
( carrid = 'LH' connid = '0400' fldate = '20240115' bookid = '0002' forcuram = 2000 )
|
|
198
|
+
( carrid = 'LH' connid = '0400' fldate = '20240115' bookid = '0003' forcuram = 3000 ) ).
|
|
199
|
+
mo_cds_env->insert_test_data( i_data = lt_sbook ).
|
|
200
|
+
|
|
201
|
+
" Select from CDS view - aggregations will use test double data
|
|
202
|
+
SELECT * FROM zc_flight_revenue INTO TABLE @DATA(lt_result).
|
|
203
|
+
|
|
204
|
+
" Verify aggregations
|
|
205
|
+
cl_abap_unit_assert=>assert_equals(
|
|
206
|
+
exp = 3
|
|
207
|
+
act = lt_result[ 1 ]-numberofbookings
|
|
208
|
+
msg = 'Should have 3 bookings' ).
|
|
209
|
+
|
|
210
|
+
cl_abap_unit_assert=>assert_equals(
|
|
211
|
+
exp = '6000.00'
|
|
212
|
+
act = lt_result[ 1 ]-totalrevenue
|
|
213
|
+
msg = 'Total revenue should be 6000.00' ).
|
|
214
|
+
ENDMETHOD.
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### Key Classes for CDS Testing
|
|
218
|
+
|
|
219
|
+
| Item | Type/Usage |
|
|
220
|
+
|------|------------|
|
|
221
|
+
| `CL_CDS_TEST_ENVIRONMENT` | Class with `CREATE` method |
|
|
222
|
+
| `IF_CDS_TEST_ENVIRONMENT` | Interface (CREATE returns this type) |
|
|
223
|
+
| `CLASS-METHODS` | `class_setup` and `class_teardown` must be static methods |
|
|
224
|
+
| `CL_OSQL_TEST_ENVIRONMENT` | Test doubles for database tables (use for aggregations) |
|
|
225
|
+
| `CL_ABAP_UNIT_ASSERT` | Assertions |
|
|
226
|
+
|
|
227
|
+
### Key Methods
|
|
228
|
+
|
|
229
|
+
| Method | Purpose |
|
|
230
|
+
|--------|---------|
|
|
231
|
+
| `CL_CDS_TEST_ENVIRONMENT=>create( i_for_entity = ... )` | Create test environment (returns `if_cds_test_environment`) |
|
|
232
|
+
| `insert_test_data( i_data = ... )` | Insert test data into test doubles |
|
|
233
|
+
| `clear_doubles` | Clear test data before each test method |
|
|
234
|
+
| `destroy` | Clean up after test class |
|
|
235
|
+
|
|
236
|
+
### Important Usage Notes
|
|
237
|
+
|
|
238
|
+
1. **Use interface type**: `DATA mo_cds_env TYPE REF TO if_cds_test_environment` - the CREATE method returns an interface reference
|
|
239
|
+
2. **CLASS-METHODS required**: `class_setup` and `class_teardown` must be declared with `CLASS-METHODS` (not `METHODS`)
|
|
240
|
+
3. **Table type declaration**: Must declare `DATA lt_tab TYPE TABLE OF <type> WITH EMPTY KEY` before using `VALUE #()`
|
|
241
|
+
4. **Auto-created dependencies**: CDS framework auto-creates test doubles for base tables - do not specify `i_dependency_list`
|
|
242
|
+
5. **Aggregations**: For CDS views with SUM/COUNT/GROUP BY, insert test data into base tables (SFLIGHT, SCARR, etc.)
|
|
243
|
+
6. **Clear doubles**: Call `clear_doubles` in `setup` method before each test
|
|
244
|
+
7. **Enable associations**: Set `test_associations = 'X'` only if testing CDS associations
|
|
245
|
+
8. **Exception handling**: Declare test methods with `RAISING cx_static_check` for proper exception handling
|
|
246
|
+
|
|
247
|
+
### Search Reference for More Details
|
|
248
|
+
|
|
249
|
+
```bash
|
|
250
|
+
abapgit-agent ref "cl_cds_test_environment"
|
|
251
|
+
abapgit-agent ref --topic unit-tests
|
|
252
|
+
```
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Creating CDS Views
|
|
2
|
+
|
|
3
|
+
## Creating CDS Views (DDLS)
|
|
4
|
+
|
|
5
|
+
CDS views (Data Definition Language Source) require specific file naming and structure for abapGit.
|
|
6
|
+
|
|
7
|
+
### File Naming
|
|
8
|
+
|
|
9
|
+
CDS views require **two files**:
|
|
10
|
+
|
|
11
|
+
| File | Description |
|
|
12
|
+
|------|-------------|
|
|
13
|
+
| `zc_my_view.ddls.asddls` | DDL source code |
|
|
14
|
+
| `zc_my_view.ddls.xml` | XML metadata |
|
|
15
|
+
|
|
16
|
+
**Important:** Do NOT use `.ddls.abap` extension - use `.ddls.asddls` for the source.
|
|
17
|
+
|
|
18
|
+
### DDL Source File (`.ddls.asddls`)
|
|
19
|
+
|
|
20
|
+
```abap
|
|
21
|
+
@AbapCatalog.sqlViewName: 'ZCMYVIEW'
|
|
22
|
+
@AbapCatalog.compiler.compareFilter: true
|
|
23
|
+
@AccessControl.authorizationCheck: #NOT_REQUIRED
|
|
24
|
+
@EndUserText.label: 'My CDS View'
|
|
25
|
+
define view ZC_My_View as select from tdevc
|
|
26
|
+
{
|
|
27
|
+
key devclass as Devclass,
|
|
28
|
+
parentcl as ParentPackage,
|
|
29
|
+
ctext as Description
|
|
30
|
+
}
|
|
31
|
+
where devclass not like '$%'
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### XML Metadata File (`.ddls.xml`)
|
|
35
|
+
|
|
36
|
+
```xml
|
|
37
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
38
|
+
<abapGit version="v1.0.0" serializer="LCL_OBJECT_DDLS" serializer_version="v1.0.0">
|
|
39
|
+
<asx:abap xmlns:asx="http://www.sap.com/abapxml" version="1.0">
|
|
40
|
+
<asx:values>
|
|
41
|
+
<DDLS>
|
|
42
|
+
<DDLNAME>ZC_MY_VIEW</DDLNAME>
|
|
43
|
+
<DDLANGUAGE>E</DDLANGUAGE>
|
|
44
|
+
<DDTEXT>My CDS View</DDTEXT>
|
|
45
|
+
</DDLS>
|
|
46
|
+
</asx:values>
|
|
47
|
+
</asx:abap>
|
|
48
|
+
</abapGit>
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Key Points
|
|
52
|
+
|
|
53
|
+
1. **Avoid reserved words** - Field names like `PACKAGE`, `CLASS`, `INTERFACE` are reserved in CDS. Use alternatives like `PackageName`, `ClassName`.
|
|
54
|
+
|
|
55
|
+
2. **Pull all files to activate** - When activating CDS views, use `abapgit-agent pull` (not single file) to ensure proper activation:
|
|
56
|
+
```bash
|
|
57
|
+
abapgit-agent pull # Pull all files
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
3. **System support** - CDS views require SAP systems with CDS capability (S/4HANA, SAP BW/4HANA, or ABAP 7.51+). Older systems will show error: "Object type DDLS is not supported by this system"
|
|
61
|
+
|
|
62
|
+
### Debugging Activation Errors
|
|
63
|
+
|
|
64
|
+
When pull shows generic errors like "Activation cancelled. Check the inactive objects":
|
|
65
|
+
|
|
66
|
+
1. **Check in ADT/Eclipse** - Open the DDL source in ADT and run syntax check for detailed errors
|
|
67
|
+
2. **Pull all files** - Sometimes `abapgit-agent pull` (all files) works better than single file for CDS views
|
|
68
|
+
|
|
69
|
+
## Creating CDS View Entities
|
|
70
|
+
|
|
71
|
+
CDS View Entities (`define view entity`) are the modern replacement for CDS Views with additional features like **associations for OData navigation**.
|
|
72
|
+
|
|
73
|
+
### Differences from CDS Views
|
|
74
|
+
|
|
75
|
+
| Aspect | CDS View | View Entity |
|
|
76
|
+
|--------|----------|-------------|
|
|
77
|
+
| Syntax | `define view` | `define view entity` |
|
|
78
|
+
| Associations | No | Yes (exposed for navigation) |
|
|
79
|
+
| OData/Navigation | Requires separate service | Auto-exposes associations |
|
|
80
|
+
| ABAP Version | 7.40+ | 7.55+ / S/4HANA Cloud |
|
|
81
|
+
|
|
82
|
+
### DDL Source File with Association
|
|
83
|
+
|
|
84
|
+
```abap
|
|
85
|
+
@EndUserText.label: 'Package Hierarchy'
|
|
86
|
+
@AccessControl.authorizationCheck: #NOT_REQUIRED
|
|
87
|
+
define view entity ZC_Pkg_Hierarchy_VE
|
|
88
|
+
as select from tdevc
|
|
89
|
+
association [0..1] to tdevc as _Parent
|
|
90
|
+
on _Parent.devclass = $projection.ParentPackage
|
|
91
|
+
{
|
|
92
|
+
key devclass as PackageName,
|
|
93
|
+
parentcl as ParentPackage,
|
|
94
|
+
ctext as Description,
|
|
95
|
+
dlvunit as SoftwareComponent,
|
|
96
|
+
|
|
97
|
+
// Exposed associations
|
|
98
|
+
_Parent
|
|
99
|
+
}
|
|
100
|
+
where devclass not like '$%'
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Key Points for View Entities
|
|
104
|
+
|
|
105
|
+
1. **Association syntax**: Use `$projection` to reference fields in the current entity
|
|
106
|
+
2. **Association cardinality**: `[0..1]`, `[1..1]`, `[0..n]`, `[1..n]`
|
|
107
|
+
3. **Expose associations**: Add the association name at the end of the SELECT to expose it for OData navigation
|
|
108
|
+
4. **Activation warnings**: Search help warnings are informational and don't block activation
|
|
109
|
+
|
|
110
|
+
## CDS Syntax Reference
|
|
111
|
+
|
|
112
|
+
When working with CDS view syntax (arithmetic, built-in functions, aggregations, etc.):
|
|
113
|
+
|
|
114
|
+
1. Run `abapgit-agent ref --topic cds` to see available topics and example files
|
|
115
|
+
2. Check the example files in `abap-cheat-sheets/src/`:
|
|
116
|
+
- `zdemo_abap_cds_ve_sel.ddls.asddls` - Arithmetic expressions, built-in functions (division, cast, etc.)
|
|
117
|
+
- `zdemo_abap_cds_ve_agg_exp.ddls.asddls` - Aggregate expressions (SUM, AVG, COUNT)
|
|
118
|
+
- `zdemo_abap_cds_ve_assoc.ddls.asddls` - Associations
|
|
119
|
+
|
|
120
|
+
**Note**: This requires `abap-cheat-sheets` to be in the reference folder (configured in `.abapGitAgent`).
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# ABAP Classes and Objects
|
|
2
|
+
|
|
3
|
+
## ABAP Class Definition - Must Use PUBLIC
|
|
4
|
+
|
|
5
|
+
**CRITICAL**: Global ABAP classes MUST use `PUBLIC` in the class definition:
|
|
6
|
+
|
|
7
|
+
```abap
|
|
8
|
+
" Correct - global class
|
|
9
|
+
CLASS zcl_my_class DEFINITION PUBLIC.
|
|
10
|
+
...
|
|
11
|
+
ENDCLASS.
|
|
12
|
+
|
|
13
|
+
" Wrong - treated as local class, will fail activation
|
|
14
|
+
CLASS zcl_my_class DEFINITION.
|
|
15
|
+
...
|
|
16
|
+
ENDCLASS.
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**Error symptom**: `Error updating where-used list for CLAS ZCL_MY_CLASS`
|
|
20
|
+
|
|
21
|
+
**Fix**: Add `PUBLIC` keyword:
|
|
22
|
+
```abap
|
|
23
|
+
CLASS zcl_my_class DEFINITION PUBLIC. " <- PUBLIC required
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Interface Method Implementation
|
|
27
|
+
|
|
28
|
+
When implementing interface methods in ABAP classes, use the interface prefix:
|
|
29
|
+
|
|
30
|
+
```abap
|
|
31
|
+
" Interface definition
|
|
32
|
+
INTERFACE zif_my_interface PUBLIC.
|
|
33
|
+
METHODS do_something IMPORTING iv_param TYPE string.
|
|
34
|
+
ENDINTERFACE.
|
|
35
|
+
|
|
36
|
+
" Class implementation - use interface prefix
|
|
37
|
+
CLASS zcl_my_class DEFINITION PUBLIC.
|
|
38
|
+
PUBLIC SECTION.
|
|
39
|
+
INTERFACES zif_my_interface.
|
|
40
|
+
ENDCLASS.
|
|
41
|
+
|
|
42
|
+
CLASS zcl_my_class IMPLEMENTATION.
|
|
43
|
+
METHOD zif_my_interface~do_something. " <- Use interface prefix
|
|
44
|
+
" Implementation here
|
|
45
|
+
ENDMETHOD.
|
|
46
|
+
ENDCLASS.
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**Wrong**: `METHOD do_something.` - parameter `iv_param` will be unknown
|
|
50
|
+
**Correct**: `METHOD zif_my_interface~do_something.` - parameters recognized
|