Skip to content

Commit 94d3cb4

Browse files
committed
Improve test coverage in new AST code
1 parent 6bbd27d commit 94d3cb4

File tree

3 files changed

+257
-0
lines changed

3 files changed

+257
-0
lines changed
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package au.com.integradev.delphi.antlr.ast.node;
2+
3+
import static org.assertj.core.api.Assertions.*;
4+
import static org.mockito.Mockito.mock;
5+
6+
import au.com.integradev.delphi.symbol.occurrence.AttributeNameOccurrenceImpl;
7+
import au.com.integradev.delphi.symbol.occurrence.NameOccurrenceImpl;
8+
import au.com.integradev.delphi.utils.files.DelphiFileUtils;
9+
import org.junit.jupiter.api.Test;
10+
import org.junit.jupiter.params.ParameterizedTest;
11+
import org.junit.jupiter.params.provider.ValueSource;
12+
import org.sonar.plugins.communitydelphi.api.ast.AttributeNode;
13+
import org.sonar.plugins.communitydelphi.api.symbol.NameOccurrence;
14+
15+
class AttributeNodeImplTest {
16+
@Test
17+
void testAttribute() {
18+
AttributeNode node = parse("[Foo('Bar')]");
19+
20+
assertThat(node).isNotNull();
21+
assertThat(node.isAssembly()).isFalse();
22+
assertThat(node.getImage()).isEqualTo("Foo('Bar')");
23+
assertThat(node.getNameReference()).isNotNull();
24+
assertThat(node.getArgumentList()).isNotNull();
25+
}
26+
27+
@Test
28+
void testAttributeNameOccurrence() {
29+
AttributeNode node = parse("[Foo]");
30+
31+
assertThat(node.getNameReference()).isNotNull();
32+
assertThat(node.getTypeNameOccurrence()).isNull();
33+
assertThat(node.getConstructorNameOccurrence()).isNull();
34+
35+
var nameReference = (NameReferenceNodeImpl) node.getNameReference();
36+
var constructorNameOccurrence = mock(NameOccurrence.class);
37+
var typeNameOccurrence = new AttributeNameOccurrenceImpl(nameReference);
38+
39+
typeNameOccurrence.setImplicitConstructorNameOccurrence(constructorNameOccurrence);
40+
nameReference.setNameOccurrence(typeNameOccurrence);
41+
42+
assertThat(node.getTypeNameOccurrence()).isEqualTo(typeNameOccurrence);
43+
assertThat(node.getConstructorNameOccurrence()).isEqualTo(constructorNameOccurrence);
44+
}
45+
46+
@Test
47+
void testNonAttributeNameOccurrence() {
48+
AttributeNode node = parse("[Foo]");
49+
50+
assertThat(node.getNameReference()).isNotNull();
51+
assertThat(node.getTypeNameOccurrence()).isNull();
52+
assertThat(node.getConstructorNameOccurrence()).isNull();
53+
54+
var nameReference = (NameReferenceNodeImpl) node.getNameReference();
55+
nameReference.setNameOccurrence(new NameOccurrenceImpl(nameReference));
56+
57+
assertThat(node.getTypeNameOccurrence()).isNull();
58+
assertThat(node.getConstructorNameOccurrence()).isNull();
59+
}
60+
61+
@Test
62+
void testAssemblyAttribute() {
63+
AttributeNode node = parse("[assembly : Foo]");
64+
65+
assertThat(node).isNotNull();
66+
assertThat(node.isAssembly()).isTrue();
67+
assertThat(node.getImage()).isEqualTo("assembly : Foo");
68+
assertThat(node.getNameReference()).isNotNull();
69+
assertThat(node.getArgumentList()).isNull();
70+
}
71+
72+
@ValueSource(
73+
strings = {
74+
"'{B5D90CF6-B2C9-473D-9DB9-1BB75EAFC517}'",
75+
"'{B5D90CF6-B2C9-473D-' + '9DB9-1BB75EAFC517}'"
76+
})
77+
@ParameterizedTest
78+
void testExpressionAttribute(String expression) {
79+
AttributeNode node = parse("[" + expression + "]");
80+
81+
assertThat(node).isNotNull();
82+
assertThat(node.isAssembly()).isFalse();
83+
assertThat(node.getImage()).isEqualTo(expression);
84+
assertThat(node.getNameReference()).isNull();
85+
assertThat(node.getArgumentList()).isNull();
86+
assertThat(node.getTypeNameOccurrence()).isNull();
87+
assertThat(node.getConstructorNameOccurrence()).isNull();
88+
}
89+
90+
private static AttributeNode parse(String attribute) {
91+
return DelphiFileUtils.parse(
92+
"unit Test;\n"
93+
+ "\n"
94+
+ "interface\n"
95+
+ "\n"
96+
+ "type\n"
97+
+ String.format(" %s\n", attribute)
98+
+ " TFoo = record\n"
99+
+ " end;\n"
100+
+ "\n"
101+
+ "implementation\n"
102+
+ "end.")
103+
.getAst()
104+
.getFirstDescendantOfType(AttributeNode.class);
105+
}
106+
}
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
package au.com.integradev.delphi.antlr.ast.node;
2+
3+
import static org.assertj.core.api.Assertions.*;
4+
5+
import au.com.integradev.delphi.utils.files.DelphiFileUtils;
6+
import java.util.stream.Stream;
7+
import org.apache.commons.lang3.StringUtils;
8+
import org.junit.jupiter.api.Named;
9+
import org.junit.jupiter.api.extension.ExtensionContext;
10+
import org.junit.jupiter.params.ParameterizedTest;
11+
import org.junit.jupiter.params.provider.Arguments;
12+
import org.junit.jupiter.params.provider.ArgumentsProvider;
13+
import org.junit.jupiter.params.provider.ArgumentsSource;
14+
import org.sonar.plugins.communitydelphi.api.ast.ExpressionNode;
15+
import org.sonar.plugins.communitydelphi.api.ast.InterfaceTypeNode;
16+
17+
class InterfaceTypeNodeImplTest {
18+
private static final String GUID = "'{B5D90CF6-B2C9-473D-9DB9-1BB75EAFC517}'";
19+
20+
private static class GuidArgumentsProvider implements ArgumentsProvider {
21+
@Override
22+
public Stream<Arguments> provideArguments(ExtensionContext context) {
23+
return Stream.of(
24+
Arguments.of(
25+
Named.of(
26+
"Simple GUID",
27+
parse(
28+
"TFoo = interface", //
29+
" [" + GUID + "]",
30+
"end;"))),
31+
Arguments.of(
32+
Named.of(
33+
"Ambiguous GUID (method attribute?)",
34+
parse(
35+
"TFoo = interface", //
36+
" [" + GUID + "]",
37+
" procedure Bar;",
38+
"end;"))),
39+
Arguments.of(
40+
Named.of(
41+
"Ambiguous GUID (property attribute?)",
42+
parse(
43+
"TFoo = interface", //
44+
" [" + GUID + "]",
45+
" property Bar;",
46+
"end;"))),
47+
Arguments.of(
48+
Named.of(
49+
"GUID within an attribute group",
50+
parse(
51+
"TFoo = interface",
52+
" [SomeAttribute, " + GUID + "]",
53+
" property Bar;",
54+
"end;"))));
55+
}
56+
}
57+
58+
private static class NoGuidArgumentsProvider implements ArgumentsProvider {
59+
@Override
60+
public Stream<Arguments> provideArguments(ExtensionContext context) {
61+
return Stream.of(
62+
Arguments.of(
63+
Named.of(
64+
"Empty interface",
65+
parse(
66+
"TFoo = interface", //
67+
"end;"))),
68+
Arguments.of(
69+
Named.of(
70+
"Attribute declared on the first interface member",
71+
parse(
72+
"TFoo = interface", //
73+
" [SomeAttribute]",
74+
" procedure Bar;",
75+
"end;"))),
76+
Arguments.of(
77+
Named.of(
78+
"String in the second attribute group",
79+
parse(
80+
"TFoo = interface", //
81+
" [SomeAttribute]",
82+
" [" + GUID + "]",
83+
" procedure Bar;",
84+
"end;"))),
85+
Arguments.of(
86+
Named.of(
87+
"String in the first attribute group of the second attribute list",
88+
parse(
89+
"TFoo = interface", //
90+
" [SomeAttribute]",
91+
" procedure Bar;",
92+
" [" + GUID + "]",
93+
" procedure Baz;",
94+
"end;"))));
95+
}
96+
}
97+
98+
@ArgumentsSource(GuidArgumentsProvider.class)
99+
@ParameterizedTest
100+
void testGuidExpressionShouldBeFound(InterfaceTypeNode node) {
101+
ExpressionNode guid = node.getGuidExpression();
102+
assertThat(guid).isNotNull();
103+
assertThat(guid.getImage()).isEqualTo(GUID);
104+
}
105+
106+
@ArgumentsSource(NoGuidArgumentsProvider.class)
107+
@ParameterizedTest
108+
void testGuidExpressionShouldNotBeFound(InterfaceTypeNode node) {
109+
assertThat(node.getGuidExpression()).isNull();
110+
}
111+
112+
@SuppressWarnings("removal")
113+
@ArgumentsSource(GuidArgumentsProvider.class)
114+
@ArgumentsSource(NoGuidArgumentsProvider.class)
115+
@ParameterizedTest
116+
void testGetGuidShouldReturnNull(InterfaceTypeNode node) {
117+
assertThat(node.getGuid()).isNull();
118+
}
119+
120+
private static InterfaceTypeNode parse(String... lines) {
121+
return DelphiFileUtils.parse(
122+
"unit Test;\n"
123+
+ "\n"
124+
+ "interface\n"
125+
+ "\n"
126+
+ "type\n"
127+
+ " "
128+
+ StringUtils.join(lines, "\n ")
129+
+ "\n\n"
130+
+ "implementation\n"
131+
+ "end.")
132+
.getAst()
133+
.getFirstDescendantOfType(InterfaceTypeNode.class);
134+
}
135+
}

delphi-frontend/src/test/java/au/com/integradev/delphi/utils/files/DelphiFileUtils.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,34 @@
2323

2424
import au.com.integradev.delphi.DelphiProperties;
2525
import au.com.integradev.delphi.compiler.Platform;
26+
import au.com.integradev.delphi.file.DelphiFile;
2627
import au.com.integradev.delphi.file.DelphiFileConfig;
2728
import au.com.integradev.delphi.preprocessor.DelphiPreprocessorFactory;
2829
import au.com.integradev.delphi.preprocessor.search.SearchPath;
2930
import au.com.integradev.delphi.utils.types.TypeFactoryUtils;
31+
import java.io.IOException;
32+
import java.io.UncheckedIOException;
3033
import java.nio.charset.StandardCharsets;
34+
import java.nio.file.Files;
35+
import java.nio.file.Path;
3136
import java.util.Collections;
3237

3338
public final class DelphiFileUtils {
3439
private DelphiFileUtils() {
3540
// Utility class
3641
}
3742

43+
public static DelphiFile parse(String content) {
44+
try {
45+
Path path = Files.createTempFile(null, ".pas");
46+
Files.writeString(path, content, StandardCharsets.UTF_8);
47+
path.toFile().deleteOnExit();
48+
return DelphiFile.from(path.toFile(), mockConfig());
49+
} catch (IOException e) {
50+
throw new UncheckedIOException(e);
51+
}
52+
}
53+
3854
public static DelphiFileConfig mockConfig() {
3955
DelphiFileConfig mock = mock(DelphiFileConfig.class);
4056
when(mock.getEncoding()).thenReturn(StandardCharsets.UTF_8.name());

0 commit comments

Comments
 (0)