Skip to content

Commit ad2461a

Browse files
authored
chore: [@W-18895431@] add regression test for virtual inner class (#94)
chore: add regression test for virtual inner class @W-18895431@
1 parent aeb31a2 commit ad2461a

File tree

1 file changed

+348
-0
lines changed

1 file changed

+348
-0
lines changed

packages/apex-parser-ast/test/parser/innerClassValidator.test.ts

Lines changed: 348 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,4 +117,352 @@ describe('Inner Class Validation', () => {
117117

118118
expect(innerClassErrors.length).toBe(0);
119119
});
120+
121+
it('should parse ClassWithVirtualInnerClass with complex inner class hierarchy', () => {
122+
const fileContent = `
123+
public class ClassWithVirtualInnerClass{
124+
125+
public virtual class VirtualInnerClass extends Metadata {
126+
127+
public String color;
128+
129+
public Boolean default_x;
130+
131+
public String description;
132+
133+
public Boolean isActive;
134+
135+
}
136+
137+
public class InnerClassExtendsVirtualClass extends VirtualInnerClass {
138+
139+
public String type = 'InnerClassExtendsVirtualClass';
140+
141+
public String fullName;
142+
143+
private String[] fullName_type_info = new String[]{
144+
'fullName','SOAP_M_URI',null,'0','1','false'
145+
};
146+
147+
public String color;
148+
149+
public Boolean default_x;
150+
151+
public String description;
152+
153+
public Boolean isActive;
154+
155+
private String[] color_type_info = new String[]{
156+
'color','SOAP_M_URI',null,'0','1','false'
157+
};
158+
159+
private String[] default_x_type_info = new String[]{
160+
'default','SOAP_M_URI',null,'1','1','false'
161+
};
162+
163+
private String[] description_type_info = new String[]{
164+
'description','SOAP_M_URI',null,'0','1','false'
165+
};
166+
167+
private String[] isActive_type_info = new String[]{
168+
'isActive','SOAP_M_URI',null,'0','1','false'
169+
};
170+
171+
public Boolean allowEmail;
172+
173+
public Boolean closed;
174+
175+
public String[] controllingFieldValues;
176+
177+
public Boolean converted;
178+
179+
public Boolean cssExposed;
180+
181+
public String forecastCategory;
182+
183+
public Boolean highPriority;
184+
185+
public Integer probability;
186+
187+
public String reverseRole;
188+
189+
public Boolean reviewed;
190+
191+
public Boolean won;
192+
193+
private String[] allowEmail_type_info = new String[]{
194+
'allowEmail','SOAP_M_URI',null,'0','1','false'
195+
};
196+
197+
private String[] closed_type_info = new String[]{
198+
'closed','SOAP_M_URI',null,'0','1','false'
199+
};
200+
201+
private String[] controllingFieldValues_type_info = new String[]{
202+
'controllingFieldValues','SOAP_M_URI',null,'0','-1','false'
203+
};
204+
205+
private String[] converted_type_info = new String[]{
206+
'converted','SOAP_M_URI',null,'0','1','false'
207+
};
208+
209+
private String[] cssExposed_type_info = new String[]{
210+
'cssExposed','SOAP_M_URI',null,'0','1','false'
211+
};
212+
213+
private String[] forecastCategory_type_info = new String[]{
214+
'forecastCategory','SOAP_M_URI',null,'0','1','false'
215+
};
216+
217+
private String[] highPriority_type_info = new String[]{
218+
'highPriority','SOAP_M_URI',null,'0','1','false'
219+
};
220+
221+
private String[] probability_type_info = new String[]{
222+
'probability','SOAP_M_URI',null,'0','1','false'
223+
};
224+
225+
private String[] reverseRole_type_info = new String[]{
226+
'reverseRole','SOAP_M_URI',null,'0','1','false'
227+
};
228+
229+
private String[] reviewed_type_info = new String[]{
230+
'reviewed','SOAP_M_URI',null,'0','1','false'
231+
};
232+
233+
private String[] won_type_info = new String[]{
234+
'won','SOAP_M_URI',null,'0','1','false'
235+
};
236+
237+
private String[] apex_schema_type_info = new String[]{
238+
'SOAP_M_URI','true','false'
239+
};
240+
241+
private String[] type_att_info = new String[]{'xsi:type'};
242+
243+
private String[] field_order_type_info = new String[]{
244+
'fullName','color','default_x','description','isActive',
245+
'allowEmail','closed','controllingFieldValues','converted',
246+
'cssExposed','forecastCategory','highPriority','probability',
247+
'reverseRole','reviewed','won'
248+
};
249+
250+
}
251+
252+
public virtual class Metadata {
253+
254+
public String fullName;
255+
256+
}
257+
258+
}
259+
`;
260+
261+
const result: CompilationResult<SymbolTable> = compilerService.compile(
262+
fileContent,
263+
'ClassWithVirtualInnerClass.cls',
264+
listener,
265+
);
266+
267+
// Check for any semantic errors related to inner classes
268+
const innerClassErrors = result.errors.filter(
269+
(e) =>
270+
e.type === ErrorType.Semantic &&
271+
(e.message.includes('inner class') ||
272+
e.message.includes('Inner class')),
273+
);
274+
275+
expect(innerClassErrors.length).toBe(0);
276+
277+
// Verify that the parser successfully created the symbol table
278+
expect(result.result).toBeDefined();
279+
expect(
280+
result.result?.getCurrentScope().getAllSymbols().length,
281+
).toBeGreaterThan(0);
282+
});
283+
it('should parse ClassWithVirtualInnerClass with complex inner class hierarchy w/errors', () => {
284+
const fileContent = `
285+
public class ClassWithVirtualInnerClass{
286+
287+
public virtial String badBunny;
288+
289+
public virtual class VirtualInnerClass extends Metadata {
290+
291+
public String color;
292+
293+
public Boolean default_x;
294+
295+
public String description;
296+
297+
public Boolean isActive;
298+
299+
}
300+
301+
public class InnerClassExtendsVirtualClass extends VirtualInnerClass {
302+
303+
public String type = 'InnerClassExtendsVirtualClass';
304+
305+
public String fullName;
306+
307+
private String[] fullName_type_info = new String[]{
308+
'fullName','SOAP_M_URI',null,'0','1','false'
309+
};
310+
311+
public String color;
312+
313+
public Boolean default_x;
314+
315+
public String description;
316+
317+
public Boolean isActive;
318+
319+
private String[] color_type_info = new String[]{
320+
'color','SOAP_M_URI',null,'0','1','false'
321+
};
322+
323+
private String[] default_x_type_info = new String[]{
324+
'default','SOAP_M_URI',null,'1','1','false'
325+
};
326+
327+
private String[] description_type_info = new String[]{
328+
'description','SOAP_M_URI',null,'0','1','false'
329+
};
330+
331+
private String[] isActive_type_info = new String[]{
332+
'isActive','SOAP_M_URI',null,'0','1','false'
333+
};
334+
335+
public Boolean allowEmail;
336+
337+
public Boolean closed;
338+
339+
public String[] controllingFieldValues;
340+
341+
public Boolean converted;
342+
343+
public Boolean cssExposed;
344+
345+
public String forecastCategory;
346+
347+
public Boolean highPriority;
348+
349+
public Integer probability;
350+
351+
public String reverseRole;
352+
353+
public Boolean reviewed;
354+
355+
public Boolean won;
356+
357+
private String[] allowEmail_type_info = new String[]{
358+
'allowEmail','SOAP_M_URI',null,'0','1','false'
359+
};
360+
361+
private String[] closed_type_info = new String[]{
362+
'closed','SOAP_M_URI',null,'0','1','false'
363+
};
364+
365+
private String[] controllingFieldValues_type_info = new String[]{
366+
'controllingFieldValues','SOAP_M_URI',null,'0','-1','false'
367+
};
368+
369+
private String[] converted_type_info = new String[]{
370+
'converted','SOAP_M_URI',null,'0','1','false'
371+
};
372+
373+
private String[] cssExposed_type_info = new String[]{
374+
'cssExposed','SOAP_M_URI',null,'0','1','false'
375+
};
376+
377+
private String[] forecastCategory_type_info = new String[]{
378+
'forecastCategory','SOAP_M_URI',null,'0','1','false'
379+
};
380+
381+
private String[] highPriority_type_info = new String[]{
382+
'highPriority','SOAP_M_URI',null,'0','1','false'
383+
};
384+
385+
private String[] probability_type_info = new String[]{
386+
'probability','SOAP_M_URI',null,'0','1','false'
387+
};
388+
389+
private String[] reverseRole_type_info = new String[]{
390+
'reverseRole','SOAP_M_URI',null,'0','1','false'
391+
};
392+
393+
private String[] reviewed_type_info = new String[]{
394+
'reviewed','SOAP_M_URI',null,'0','1','false'
395+
};
396+
397+
private String[] won_type_info = new String[]{
398+
'won','SOAP_M_URI',null,'0','1','false'
399+
};
400+
401+
private String[] apex_schema_type_info = new String[]{
402+
'SOAP_M_URI','true','false'
403+
};
404+
405+
private String[] type_att_info = new String[]{'xsi:type'};
406+
407+
private String[] field_order_type_info = new String[]{
408+
'fullName','color','default_x','description','isActive',
409+
'allowEmail','closed','controllingFieldValues','converted',
410+
'cssExposed','forecastCategory','highPriority','probability',
411+
'reverseRole','reviewed','won'
412+
};
413+
414+
}
415+
416+
public virtual class Metadata {
417+
418+
public String fullName;
419+
420+
}
421+
422+
}
423+
`;
424+
425+
const result: CompilationResult<SymbolTable> = compilerService.compile(
426+
fileContent,
427+
'ClassWithVirtualInnerClass.cls',
428+
listener,
429+
);
430+
431+
// Check for expected semantic errors
432+
const virtialSyntaxErrors = result.errors.filter(
433+
(e) =>
434+
e.type === ErrorType.Semantic &&
435+
e.message.includes('Invalid syntax: virtial'),
436+
);
437+
438+
const virtualFieldErrors = result.errors.filter(
439+
(e) =>
440+
e.type === ErrorType.Semantic &&
441+
e.message.includes("Field cannot be declared as 'virtual'"),
442+
);
443+
444+
const syntaxErrors = result.errors.filter(
445+
(e) =>
446+
e.type === ErrorType.Syntax &&
447+
e.message.includes(
448+
"no viable alternative at input 'virtial String badBunny'",
449+
),
450+
);
451+
452+
// Verify that the expected errors are present
453+
expect(virtialSyntaxErrors.length).toBe(1);
454+
expect(virtualFieldErrors.length).toBe(2);
455+
expect(syntaxErrors.length).toBe(1);
456+
expect(result.errors.length).toBe(4);
457+
458+
// Verify inner class structure is not affected by these errors
459+
const innerClassErrors = result.errors.filter(
460+
(e) =>
461+
e.type === ErrorType.Semantic &&
462+
(e.message.includes('inner class') ||
463+
e.message.includes('Inner class')),
464+
);
465+
466+
expect(innerClassErrors.length).toBe(0);
467+
});
120468
});

0 commit comments

Comments
 (0)