Skip to content

Commit bd8a080

Browse files
fourlscirras
authored andcommitted
Add testing for the QuickFixEdit API
1 parent 01bc466 commit bd8a080

File tree

2 files changed

+336
-0
lines changed

2 files changed

+336
-0
lines changed
Lines changed: 324 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,324 @@
1+
/*
2+
* Sonar Delphi Plugin
3+
* Copyright (C) 2024 Integrated Application Development
4+
*
5+
* This program is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU Lesser General Public
7+
* License as published by the Free Software Foundation; either
8+
* version 3 of the License, or (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public
16+
* License along with this program; if not, write to the Free Software
17+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
18+
*/
19+
package au.com.integradev.delphi.reporting;
20+
21+
import static org.assertj.core.api.Assertions.*;
22+
import static org.mockito.Mockito.mock;
23+
import static org.mockito.Mockito.when;
24+
25+
import au.com.integradev.delphi.DelphiProperties;
26+
import au.com.integradev.delphi.antlr.DelphiFileStream;
27+
import au.com.integradev.delphi.compiler.Platform;
28+
import au.com.integradev.delphi.core.Delphi;
29+
import au.com.integradev.delphi.file.DelphiFile.DelphiInputFile;
30+
import au.com.integradev.delphi.file.DelphiFileConfig;
31+
import au.com.integradev.delphi.preprocessor.DelphiPreprocessorFactory;
32+
import au.com.integradev.delphi.preprocessor.search.SearchPath;
33+
import au.com.integradev.delphi.reporting.edits.QuickFixEditImpl;
34+
import au.com.integradev.delphi.type.factory.TypeFactoryImpl;
35+
import au.com.integradev.delphi.utils.DelphiUtils;
36+
import java.io.File;
37+
import java.io.IOException;
38+
import java.io.UncheckedIOException;
39+
import java.nio.charset.StandardCharsets;
40+
import java.util.Collections;
41+
import java.util.List;
42+
import org.apache.commons.io.FileUtils;
43+
import org.junit.jupiter.api.BeforeEach;
44+
import org.junit.jupiter.api.Test;
45+
import org.sonar.api.batch.fs.InputFile;
46+
import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
47+
import org.sonar.plugins.communitydelphi.api.ast.DelphiAst;
48+
import org.sonar.plugins.communitydelphi.api.ast.DelphiNode;
49+
import org.sonar.plugins.communitydelphi.api.check.FilePosition;
50+
import org.sonar.plugins.communitydelphi.api.reporting.QuickFixEdit;
51+
52+
class QuickFixEditTest {
53+
private static final String TEST_ROOT = "/au/com/integradev/delphi/reporting";
54+
private static final String TEST_UNIT_PATH = TEST_ROOT + "/TestQuickFixEditFile.pas";
55+
56+
private static DelphiFileStream getTestStream() {
57+
try {
58+
return new DelphiFileStream(
59+
DelphiUtils.getResource(TEST_UNIT_PATH).getAbsolutePath(), StandardCharsets.UTF_8.name());
60+
} catch (IOException e) {
61+
throw new UncheckedIOException(e);
62+
}
63+
}
64+
65+
private static void assertEdit(
66+
TextRangeReplacement actual, FilePosition position, String replacement) {
67+
assertFilePosition(position, actual.getLocation());
68+
assertThat(replacement).isEqualTo(actual.getReplacement());
69+
}
70+
71+
private static void assertFilePosition(FilePosition actual, FilePosition expected) {
72+
boolean equals =
73+
expected.getBeginLine() == actual.getBeginLine()
74+
&& expected.getBeginColumn() == actual.getBeginColumn()
75+
&& expected.getEndLine() == actual.getEndLine()
76+
&& expected.getEndColumn() == actual.getEndColumn();
77+
78+
assertThat(equals)
79+
.withFailMessage(
80+
() ->
81+
String.format(
82+
"Expected [%d:%d to %d:%d], found [%d:%d to %d:%d]",
83+
expected.getBeginLine(),
84+
expected.getBeginColumn(),
85+
expected.getEndLine(),
86+
expected.getEndColumn(),
87+
actual.getBeginLine(),
88+
actual.getBeginColumn(),
89+
actual.getEndLine(),
90+
actual.getEndColumn()))
91+
.isTrue();
92+
}
93+
94+
private static DelphiNode getNonNullNodeWithImage(DelphiNode parent, String text) {
95+
for (DelphiNode child : parent.getChildren()) {
96+
if (child.getImage().equalsIgnoreCase(text)) {
97+
return child;
98+
} else {
99+
DelphiNode grandchildFoo = getNodeWithImage(child, text);
100+
if (grandchildFoo != null) {
101+
return grandchildFoo;
102+
}
103+
}
104+
}
105+
106+
throw new AssertionError("Node with image '" + text + "' does not exist");
107+
}
108+
109+
private static DelphiNode getNodeWithImage(DelphiNode parent, String text) {
110+
for (DelphiNode child : parent.getChildren()) {
111+
if (child.getImage().equalsIgnoreCase(text)) {
112+
return child;
113+
} else {
114+
DelphiNode grandchildFoo = getNodeWithImage(child, text);
115+
if (grandchildFoo != null) {
116+
return grandchildFoo;
117+
}
118+
}
119+
}
120+
121+
return null;
122+
}
123+
124+
private static DelphiAst getTestAst() {
125+
File baseDir = DelphiUtils.getResource(TEST_ROOT);
126+
File file = DelphiUtils.getResource(TEST_UNIT_PATH);
127+
128+
InputFile inputFile;
129+
try {
130+
inputFile =
131+
TestInputFileBuilder.create("moduleKey", baseDir, file)
132+
.setContents(FileUtils.readFileToString(file, StandardCharsets.UTF_8.name()))
133+
.setLanguage(Delphi.KEY)
134+
.setType(InputFile.Type.MAIN)
135+
.build();
136+
} catch (IOException e) {
137+
throw new UncheckedIOException(e);
138+
}
139+
140+
var preprocessorFactory = new DelphiPreprocessorFactory(Platform.WINDOWS);
141+
var typeFactory =
142+
new TypeFactoryImpl(
143+
DelphiProperties.COMPILER_TOOLCHAIN_DEFAULT, DelphiProperties.COMPILER_VERSION_DEFAULT);
144+
145+
DelphiFileConfig fileConfig = mock(DelphiFileConfig.class);
146+
when(fileConfig.getEncoding()).thenReturn(StandardCharsets.UTF_8.name());
147+
when(fileConfig.getPreprocessorFactory()).thenReturn(preprocessorFactory);
148+
when(fileConfig.getTypeFactory()).thenReturn(typeFactory);
149+
when(fileConfig.getSearchPath()).thenReturn(SearchPath.create(Collections.emptyList()));
150+
when(fileConfig.getDefinitions()).thenReturn(Collections.emptySet());
151+
152+
var mainFile = DelphiInputFile.from(inputFile, fileConfig);
153+
return mainFile.getAst();
154+
}
155+
156+
private static FilePosition startOf(DelphiNode node) {
157+
return FilePosition.from(
158+
node.getBeginLine(), node.getBeginColumn(), node.getBeginLine(), node.getBeginColumn());
159+
}
160+
161+
private static FilePosition endOf(DelphiNode node) {
162+
return FilePosition.from(
163+
node.getEndLine(), node.getEndColumn(), node.getEndLine(), node.getEndColumn());
164+
}
165+
166+
List<TextRangeReplacement> getTextEdits(QuickFixEdit edit) {
167+
return ((QuickFixEditImpl) edit).toTextEdits(() -> fileStream);
168+
}
169+
170+
private DelphiFileStream fileStream;
171+
private DelphiAst ast;
172+
173+
@BeforeEach
174+
void beforeEach() {
175+
fileStream = getTestStream();
176+
ast = getTestAst();
177+
}
178+
179+
@Test
180+
void testInsert() {
181+
QuickFixEdit insert = QuickFixEdit.insert("inherited ", 9, 2);
182+
183+
List<TextRangeReplacement> edits = getTextEdits(insert);
184+
assertThat(edits).hasSize(1);
185+
assertEdit(edits.get(0), FilePosition.from(9, 2, 9, 2), "inherited ");
186+
}
187+
188+
@Test
189+
void testInsertBefore() {
190+
DelphiNode node = getNonNullNodeWithImage(ast, "Bar");
191+
QuickFixEdit insert = QuickFixEdit.insertBefore("inherited ", node);
192+
193+
List<TextRangeReplacement> edits = getTextEdits(insert);
194+
assertThat(edits).hasSize(1);
195+
assertEdit(edits.get(0), FilePosition.from(9, 2, 9, 2), "inherited ");
196+
}
197+
198+
@Test
199+
void testInsertAfter() {
200+
DelphiNode node = getNonNullNodeWithImage(ast, "Bar");
201+
QuickFixEdit insert = QuickFixEdit.insertAfter(" baz", node);
202+
203+
List<TextRangeReplacement> edits = getTextEdits(insert);
204+
assertThat(edits).hasSize(1);
205+
assertEdit(edits.get(0), FilePosition.from(9, 5, 9, 5), " baz");
206+
}
207+
208+
@Test
209+
void testCopy() {
210+
DelphiNode node = getNonNullNodeWithImage(ast, "Bar");
211+
QuickFixEdit copy = QuickFixEdit.copy(node, FilePosition.from(7, 10, 7, 10));
212+
213+
List<TextRangeReplacement> edits = getTextEdits(copy);
214+
assertThat(edits).hasSize(1);
215+
assertFilePosition(edits.get(0).getLocation(), FilePosition.from(7, 10, 7, 10));
216+
assertEdit(edits.get(0), FilePosition.from(7, 10, 7, 10), "Bar");
217+
}
218+
219+
@Test
220+
void testCopyBefore() {
221+
DelphiNode node = getNonNullNodeWithImage(ast, "Bar");
222+
DelphiNode referenceNode = getNonNullNodeWithImage(ast, "Foo");
223+
224+
QuickFixEdit copy = QuickFixEdit.copyBefore(node, referenceNode);
225+
226+
List<TextRangeReplacement> edits = getTextEdits(copy);
227+
assertThat(edits).hasSize(1);
228+
assertEdit(edits.get(0), startOf(referenceNode), "Bar");
229+
}
230+
231+
@Test
232+
void testCopyAfter() {
233+
DelphiNode node = getNonNullNodeWithImage(ast, "Bar");
234+
DelphiNode referenceNode = getNonNullNodeWithImage(ast, "Foo");
235+
236+
QuickFixEdit copy = QuickFixEdit.copyAfter(node, referenceNode);
237+
238+
List<TextRangeReplacement> edits = getTextEdits(copy);
239+
assertThat(edits).hasSize(1);
240+
assertEdit(edits.get(0), endOf(referenceNode), "Bar");
241+
}
242+
243+
@Test
244+
void testCopyReplacing() {
245+
DelphiNode node = getNonNullNodeWithImage(ast, "Bar");
246+
DelphiNode referenceNode = getNonNullNodeWithImage(ast, "Foo");
247+
248+
QuickFixEdit copy = QuickFixEdit.copyReplacing(node, referenceNode);
249+
250+
List<TextRangeReplacement> edits = getTextEdits(copy);
251+
assertThat(edits).hasSize(1);
252+
assertEdit(edits.get(0), FilePosition.from(referenceNode), "Bar");
253+
}
254+
255+
@Test
256+
void testMove() {
257+
DelphiNode node = getNonNullNodeWithImage(ast, "Bar");
258+
QuickFixEdit move = QuickFixEdit.move(node, FilePosition.from(7, 10, 7, 10));
259+
260+
List<TextRangeReplacement> edits = getTextEdits(move);
261+
assertThat(edits).hasSize(2);
262+
assertEdit(edits.get(0), FilePosition.from(7, 10, 7, 10), "Bar");
263+
assertEdit(edits.get(1), FilePosition.from(node), "");
264+
}
265+
266+
@Test
267+
void testMoveBefore() {
268+
DelphiNode node = getNonNullNodeWithImage(ast, "Bar");
269+
DelphiNode referenceNode = getNonNullNodeWithImage(ast, "Foo");
270+
271+
QuickFixEdit move = QuickFixEdit.moveBefore(node, referenceNode);
272+
273+
List<TextRangeReplacement> edits = getTextEdits(move);
274+
assertThat(edits).hasSize(2);
275+
assertEdit(edits.get(0), startOf(referenceNode), "Bar");
276+
assertEdit(edits.get(1), FilePosition.from(node), "");
277+
}
278+
279+
@Test
280+
void testMoveAfter() {
281+
DelphiNode node = getNonNullNodeWithImage(ast, "Bar");
282+
DelphiNode referenceNode = getNonNullNodeWithImage(ast, "Foo");
283+
284+
QuickFixEdit move = QuickFixEdit.moveAfter(node, referenceNode);
285+
286+
List<TextRangeReplacement> edits = getTextEdits(move);
287+
assertThat(edits).hasSize(2);
288+
assertEdit(edits.get(0), endOf(referenceNode), "Bar");
289+
assertEdit(edits.get(1), FilePosition.from(node), "");
290+
}
291+
292+
@Test
293+
void testMoveReplacing() {
294+
DelphiNode node = getNonNullNodeWithImage(ast, "Bar");
295+
DelphiNode referenceNode = getNonNullNodeWithImage(ast, "Foo");
296+
297+
QuickFixEdit move = QuickFixEdit.moveReplacing(node, referenceNode);
298+
299+
List<TextRangeReplacement> edits = getTextEdits(move);
300+
assertThat(edits).hasSize(2);
301+
assertEdit(edits.get(0), FilePosition.from(referenceNode), "Bar");
302+
assertEdit(edits.get(1), FilePosition.from(node), "");
303+
}
304+
305+
@Test
306+
void testDeleteNode() {
307+
DelphiNode node = getNonNullNodeWithImage(ast, "Bar");
308+
QuickFixEdit delete = QuickFixEdit.delete(node);
309+
310+
List<TextRangeReplacement> edits = getTextEdits(delete);
311+
assertThat(edits).hasSize(1);
312+
assertEdit(edits.get(0), FilePosition.from(node), "");
313+
}
314+
315+
@Test
316+
void testDeleteRange() {
317+
FilePosition position = FilePosition.from(7, 10, 7, 13);
318+
QuickFixEdit delete = QuickFixEdit.delete(position);
319+
320+
List<TextRangeReplacement> edits = getTextEdits(delete);
321+
assertThat(edits).hasSize(1);
322+
assertEdit(edits.get(0), position, "");
323+
}
324+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
unit TestQuickFixEditFile;
2+
3+
interface
4+
5+
implementation
6+
7+
procedure Foo;
8+
begin
9+
Bar('hello', 1, 2);
10+
end;
11+
12+
end.

0 commit comments

Comments
 (0)