Skip to content

Commit 0c5b399

Browse files
authored
Merge pull request #3544 from github/koesie10/python-parsing-unit-tests
Add unit tests for Python argument options
2 parents 4dc126d + 8e231d7 commit 0c5b399

File tree

2 files changed

+227
-8
lines changed
  • extensions/ql-vscode

2 files changed

+227
-8
lines changed

extensions/ql-vscode/src/model-editor/languages/python/index.ts

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -177,11 +177,28 @@ export const python: ModelsAsDataLanguage = {
177177
// Argument and Parameter are equivalent in Python, but we'll use Argument in the model editor
178178
const argumentsList = getArgumentsList(method.methodParameters).map(
179179
(argument, index): MethodArgument => {
180+
if (
181+
method.endpointType === EndpointType.Method &&
182+
argument === "self" &&
183+
index === 0
184+
) {
185+
return {
186+
path: "Argument[self]",
187+
label: "Argument[self]: self",
188+
};
189+
}
190+
191+
// If this is a method, self does not count as an argument index, so we
192+
// should start at 0 for the second argument
193+
if (method.endpointType === EndpointType.Method) {
194+
index -= 1;
195+
}
196+
180197
// Keyword-only arguments end with `:` in the query
181198
if (argument.endsWith(":")) {
182199
return {
183200
path: `Argument[${argument}]`,
184-
label: `Argument[${argument}]`,
201+
label: `Argument[${argument}]: ${argument.substring(0, argument.length - 1)}`,
185202
};
186203
}
187204

@@ -202,13 +219,7 @@ export const python: ModelsAsDataLanguage = {
202219
);
203220

204221
return {
205-
options: [
206-
{
207-
path: "Argument[self]",
208-
label: "Argument[self]",
209-
},
210-
...argumentsList,
211-
],
222+
options: argumentsList,
212223
// If there are no arguments, we will default to "Argument[self]"
213224
defaultArgumentPath:
214225
argumentsList.length > 0 ? argumentsList[0].path : "Argument[self]",
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
import type { MethodDefinition } from "../../../../../src/model-editor/method";
2+
import { EndpointType } from "../../../../../src/model-editor/method";
3+
import { python } from "../../../../../src/model-editor/languages/python";
4+
import type { MethodArgumentOptions } from "../../../../../src/model-editor/languages";
5+
6+
const testCases: Array<{
7+
method: MethodDefinition;
8+
options: MethodArgumentOptions;
9+
}> = [
10+
{
11+
method: {
12+
packageName: "requests",
13+
typeName: "Session",
14+
methodName: "foo",
15+
methodParameters: "(a,b,c)",
16+
endpointType: EndpointType.Function,
17+
},
18+
options: {
19+
options: [
20+
{
21+
path: "Argument[0,a:]",
22+
label: "Argument[0,a:]: a",
23+
},
24+
{
25+
path: "Argument[1,b:]",
26+
label: "Argument[1,b:]: b",
27+
},
28+
{
29+
path: "Argument[2,c:]",
30+
label: "Argument[2,c:]: c",
31+
},
32+
],
33+
defaultArgumentPath: "Argument[0,a:]",
34+
},
35+
},
36+
{
37+
method: {
38+
packageName: "requests",
39+
typeName: "Session",
40+
methodName: "foo",
41+
methodParameters: "(self,a,b,c)",
42+
endpointType: EndpointType.Method,
43+
},
44+
options: {
45+
options: [
46+
{
47+
path: "Argument[self]",
48+
label: "Argument[self]: self",
49+
},
50+
{
51+
path: "Argument[0,a:]",
52+
label: "Argument[0,a:]: a",
53+
},
54+
{
55+
path: "Argument[1,b:]",
56+
label: "Argument[1,b:]: b",
57+
},
58+
{
59+
path: "Argument[2,c:]",
60+
label: "Argument[2,c:]: c",
61+
},
62+
],
63+
defaultArgumentPath: "Argument[self]",
64+
},
65+
},
66+
{
67+
method: {
68+
packageName: "requests",
69+
typeName: "Session",
70+
methodName: "foo",
71+
methodParameters: "(a,b,c:)",
72+
endpointType: EndpointType.Function,
73+
},
74+
options: {
75+
options: [
76+
{
77+
path: "Argument[0,a:]",
78+
label: "Argument[0,a:]: a",
79+
},
80+
{
81+
path: "Argument[1,b:]",
82+
label: "Argument[1,b:]: b",
83+
},
84+
{
85+
path: "Argument[c:]",
86+
label: "Argument[c:]: c",
87+
},
88+
],
89+
defaultArgumentPath: "Argument[0,a:]",
90+
},
91+
},
92+
{
93+
method: {
94+
packageName: "requests",
95+
typeName: "Session",
96+
methodName: "foo",
97+
methodParameters: "(a/,b,c:)",
98+
endpointType: EndpointType.Function,
99+
},
100+
options: {
101+
options: [
102+
{
103+
path: "Argument[0]",
104+
label: "Argument[0]: a",
105+
},
106+
{
107+
path: "Argument[1,b:]",
108+
label: "Argument[1,b:]: b",
109+
},
110+
{
111+
path: "Argument[c:]",
112+
label: "Argument[c:]: c",
113+
},
114+
],
115+
defaultArgumentPath: "Argument[0]",
116+
},
117+
},
118+
{
119+
method: {
120+
packageName: "requests",
121+
typeName: "Session",
122+
methodName: "foo",
123+
methodParameters: "(self,a/,b/,c,d,e,f:,g:,h:)",
124+
endpointType: EndpointType.Method,
125+
},
126+
options: {
127+
options: [
128+
{
129+
path: "Argument[self]",
130+
label: "Argument[self]: self",
131+
},
132+
{
133+
path: "Argument[0]",
134+
label: "Argument[0]: a",
135+
},
136+
{
137+
path: "Argument[1]",
138+
label: "Argument[1]: b",
139+
},
140+
{
141+
path: "Argument[2,c:]",
142+
label: "Argument[2,c:]: c",
143+
},
144+
{
145+
path: "Argument[3,d:]",
146+
label: "Argument[3,d:]: d",
147+
},
148+
{
149+
path: "Argument[4,e:]",
150+
label: "Argument[4,e:]: e",
151+
},
152+
{
153+
path: "Argument[f:]",
154+
label: "Argument[f:]: f",
155+
},
156+
{
157+
path: "Argument[g:]",
158+
label: "Argument[g:]: g",
159+
},
160+
{
161+
path: "Argument[h:]",
162+
label: "Argument[h:]: h",
163+
},
164+
],
165+
defaultArgumentPath: "Argument[self]",
166+
},
167+
},
168+
{
169+
method: {
170+
packageName: "requests",
171+
typeName: "Session",
172+
methodName: "foo",
173+
methodParameters: "(self)",
174+
endpointType: EndpointType.Method,
175+
},
176+
options: {
177+
options: [
178+
{
179+
path: "Argument[self]",
180+
label: "Argument[self]: self",
181+
},
182+
],
183+
defaultArgumentPath: "Argument[self]",
184+
},
185+
},
186+
{
187+
method: {
188+
packageName: "requests",
189+
typeName: "Session",
190+
methodName: "foo",
191+
methodParameters: "()",
192+
endpointType: EndpointType.Function,
193+
},
194+
options: {
195+
options: [],
196+
defaultArgumentPath: "Argument[self]",
197+
},
198+
},
199+
];
200+
201+
describe("getArgumentOptions", () => {
202+
it.each(testCases)(
203+
"returns the correct options for $method",
204+
({ method, options }) => {
205+
expect(python.getArgumentOptions(method)).toEqual(options);
206+
},
207+
);
208+
});

0 commit comments

Comments
 (0)