Skip to content

Commit 9bbbcc5

Browse files
committed
[tests] Fix JS/TS Rename Tests
1 parent c9e0c55 commit 9bbbcc5

File tree

2 files changed

+134
-223
lines changed

2 files changed

+134
-223
lines changed

org.eclipse.wildwebdeveloper.tests/META-INF/MANIFEST.MF

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Require-Bundle: org.eclipse.wildwebdeveloper;bundle-version="1.0.0",
1212
org.eclipse.core.resources,
1313
org.eclipse.core.runtime,
1414
org.eclipse.ui.ide,
15+
org.eclipse.ui.workbench,
1516
org.eclipse.ui.workbench.texteditor,
1617
org.eclipse.jface.text,
1718
org.eclipse.ui.tests.harness,

org.eclipse.wildwebdeveloper.tests/src/org/eclipse/wildwebdeveloper/tests/TestJsTs.java

Lines changed: 133 additions & 223 deletions
Original file line numberDiff line numberDiff line change
@@ -12,33 +12,26 @@
1212
*******************************************************************************/
1313
package org.eclipse.wildwebdeveloper.tests;
1414

15+
import static org.junit.jupiter.api.Assertions.assertNotNull;
1516
import static org.junit.jupiter.api.Assertions.assertTrue;
1617

17-
import java.lang.reflect.Method;
18-
import java.util.HashSet;
19-
import java.util.Set;
2018
import java.util.concurrent.TimeUnit;
21-
import java.util.concurrent.atomic.AtomicBoolean;
22-
2319
import org.eclipse.core.commands.Command;
2420
import org.eclipse.core.commands.ExecutionEvent;
2521
import org.eclipse.core.resources.IFile;
2622
import org.eclipse.core.resources.IProject;
2723
import org.eclipse.core.resources.ResourcesPlugin;
2824
import org.eclipse.core.runtime.CoreException;
29-
import org.eclipse.jface.dialogs.Dialog;
3025
import org.eclipse.jface.text.IDocument;
26+
import org.eclipse.jface.text.ITextViewer;
27+
import org.eclipse.jface.text.link.LinkedModeModel;
28+
import org.eclipse.jface.text.link.LinkedPosition;
29+
import org.eclipse.jface.text.link.LinkedPositionGroup;
3130
import org.eclipse.jface.text.TextSelection;
3231
import org.eclipse.swt.SWT;
33-
import org.eclipse.swt.widgets.Button;
34-
import org.eclipse.swt.widgets.Composite;
3532
import org.eclipse.swt.widgets.Control;
3633
import org.eclipse.swt.widgets.Display;
3734
import org.eclipse.swt.widgets.Event;
38-
import org.eclipse.swt.widgets.Listener;
39-
import org.eclipse.swt.widgets.Shell;
40-
import org.eclipse.swt.widgets.Text;
41-
import org.eclipse.swt.widgets.Widget;
4235
import org.eclipse.ui.IWorkbenchCommandConstants;
4336
import org.eclipse.ui.PlatformUI;
4437
import org.eclipse.ui.commands.ICommandService;
@@ -53,216 +46,133 @@
5346

5447
@ExtendWith(AllCleanRule.class)
5548
public class TestJsTs {
56-
private static final String WIZARD_CLASSNAME_TEMPLATE = "org.eclipse.ltk.internal.ui.refactoring.Refactoring";
57-
private static final String WIZARD_RENAME = "Rename";
58-
private static final String WIZARD_REFACTORING = "Refactoring";
59-
private static final String BUTTON_OK = "OK";
60-
private static final String BUTTON_CANCEL = "Cancel";
61-
private static final String BUTTON_CONTINUE = "Con&tinue";
62-
private static final String BUTTON_BACK = "< &Back";
63-
64-
private IProject project;
65-
66-
@BeforeEach
67-
public void setUpProject() throws CoreException {
68-
this.project = ResourcesPlugin.getWorkspace().getRoot().getProject(getClass().getName() + System.nanoTime());
69-
project.create(null);
70-
project.open(null);
71-
}
72-
73-
@Test
74-
@Timeout(value = 60, unit = TimeUnit.SECONDS)
75-
public void testRefactoringRenameInTypeaScript() throws Exception {
76-
final IFile file = project.getFile("TestJsTs.ts");
77-
String content = "function testVar(test) {\n if (\"truetrue\" == \"true\" + test ) {\n"
78-
+ " return true;\n }\n return false;\n}\n"
79-
+ "print(\"Testing var with true argument == \" + testVar(true));\n"
80-
+ "print(\"Testing var with false argument == \" + testVar(false));\n";
81-
final String oldName = "testVar";
82-
final String newName = "newName";
83-
internalTestRename(file, content, oldName, newName);
84-
}
85-
86-
@Test
87-
@Timeout(value = 60, unit = TimeUnit.SECONDS)
88-
public void testRefactoringRenameInJavaScript() throws Exception {
89-
final IFile file = project.getFile("TestJsTs.js");
90-
String content = "function testVar(test) {\n if (\"truetrue\" == \"true\" + test ) {\n"
91-
+ " return true;\n }\n return false;\n}\n"
92-
+ "print(\"Testing var with true argument == \" + testVar(true));\n"
93-
+ "print(\"Testing var with false argument == \" + testVar(false));\n";
94-
final String oldName = "testVar";
95-
final String newName = "newName";
96-
internalTestRename(file, content, oldName, newName);
97-
}
98-
99-
private void internalTestRename(IFile file, String content, String oldName, String newName) throws Exception {
100-
String newContent = content.replaceAll(oldName, newName);
101-
102-
int offset = content.indexOf(oldName);
103-
file.create(content.getBytes(), true, false, null);
104-
AbstractTextEditor editor = (AbstractTextEditor) IDE.openEditor(
105-
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(), file,
106-
"org.eclipse.ui.genericeditor.GenericEditor");
107-
editor.getSelectionProvider().setSelection(new TextSelection(offset, 0));
108-
editor.setFocus();
109-
DisplayHelper.sleep(5000); // Give time for LS to initialize enough before making edit and sending a
110-
// didChange
111-
112-
IDocument document = editor.getDocumentProvider().getDocument(editor.getEditorInput());
11349

114-
ICommandService commandService = PlatformUI.getWorkbench().getService(ICommandService.class);
115-
IHandlerService handlerService = PlatformUI.getWorkbench().getService(IHandlerService.class);
116-
Command command = commandService.getCommand(IWorkbenchCommandConstants.FILE_RENAME);
117-
assertTrue(command.isEnabled() && command.isHandled());
118-
Event e = new Event();
119-
e.widget = editor.getAdapter(Control.class);
120-
Shell ideShell = editor.getSite().getShell();
121-
Display display = ideShell.getDisplay();
122-
e.display = display;
123-
AtomicBoolean renameDialogOkPressed = new AtomicBoolean();
124-
AtomicBoolean renameDialogContinuePressed = new AtomicBoolean();
125-
AtomicBoolean renameDialogCancelPressed = new AtomicBoolean();
126-
AtomicBoolean errorDialogOkPressed = new AtomicBoolean();
127-
AtomicBoolean newTextIsSet = new AtomicBoolean();
128-
129-
Listener pressOKonRenameDialogPaint = event -> {
130-
if (event.widget instanceof Composite c) {
131-
Shell shell = c.getShell();
132-
if (shell != ideShell) {
133-
if (shell.getData().getClass().getName().startsWith(WIZARD_CLASSNAME_TEMPLATE)) {
134-
if (!newTextIsSet.get()) {
135-
newTextIsSet.set(setNewText(c, newName));
136-
System.out.println("testRefactoringRename(): New name is set: " + newName);
137-
}
138-
Set<String> buttons = getButtons(c);
139-
if (WIZARD_RENAME.equals(shell.getText())) {
140-
if (!renameDialogOkPressed.get()) {
141-
if (buttons.contains(BUTTON_OK)) {
142-
System.out.println(
143-
"testRefactoringRename(): WIZARD_RENAME Emulating pressOK when BUTTON_OK");
144-
event.widget.getDisplay().asyncExec(() -> pressOk(shell));
145-
renameDialogOkPressed.set(true);
146-
}
147-
} else if (!renameDialogContinuePressed.get()) {
148-
if (buttons.contains(BUTTON_CONTINUE)) {
149-
System.out.println(
150-
"testRefactoringRename(): WIZARD_RENAME Emulating pressOK when BUTTON_CONTINUE");
151-
event.widget.getDisplay().asyncExec(() -> pressOk(shell));
152-
renameDialogContinuePressed.set(true);
153-
} else if (!renameDialogCancelPressed.get() && buttons.contains(BUTTON_CANCEL)
154-
&& buttons.contains(BUTTON_BACK)) {
155-
System.out.println(
156-
"testRefactoringRename(): WIZARD_RENAME Emulating pressCancel when BUTTON_CANCEL & BUTTON_BACK");
157-
event.widget.getDisplay().asyncExec(() -> pressCancel(shell));
158-
renameDialogCancelPressed.set(true);
159-
}
160-
}
161-
} else if (WIZARD_REFACTORING.equals(shell.getText())) {
162-
if (!errorDialogOkPressed.get()) {
163-
if (buttons.contains(BUTTON_OK)) {
164-
System.out.println(
165-
"testRefactoringRename(): WIZARD_REFACTORING Emulating pressOK when BUTTON_OK");
166-
event.widget.getDisplay().asyncExec(() -> pressOk(shell));
167-
errorDialogOkPressed.set(true);
168-
}
169-
}
170-
}
171-
} else if (shell.getData().getClass().getName()
172-
.startsWith("org.eclipse.jface.dialogs.MessageDialog")) {
173-
// Most probably it's "The Rename request is not valid at the given position"
174-
// -like error
175-
Set<String> buttons = getButtons(c);
176-
if (!errorDialogOkPressed.get()) {
177-
if (buttons.contains(BUTTON_OK)) {
178-
System.out.println(
179-
"testRefactoringRename(): MESSAGE_DIALOG Emulating pressOK when BUTTON_OK");
180-
event.widget.getDisplay().asyncExec(() -> pressOk(shell));
181-
errorDialogOkPressed.set(true);
182-
} else if (buttons.contains(BUTTON_CANCEL)) {
183-
System.out.println(
184-
"testRefactoringRename(): MESSAGE_DIALOG Emulating pressCancel when BUTTON_CANCEL");
185-
event.widget.getDisplay().asyncExec(() -> pressCancel(shell));
186-
errorDialogOkPressed.set(true); // Report as OK pressed just to say the dialog is closed
187-
}
188-
}
189-
}
190-
}
191-
}
192-
};
193-
194-
try {
195-
display.addFilter(SWT.Paint, pressOKonRenameDialogPaint);
196-
ExecutionEvent executionEvent = handlerService.createExecutionEvent(command, e);
197-
System.out.println("testRefactoringRename(): Executing command: " + IWorkbenchCommandConstants.FILE_RENAME);
198-
command.executeWithChecks(executionEvent);
199-
assertTrue(DisplayHelper.waitForCondition(display, 2000, () -> renameDialogOkPressed.get()),
200-
"Rename dialog not shown");
201-
System.out.println("testRefactoringRename(): Rename dialog is shown");
202-
assertTrue(DisplayHelper.waitForCondition(display, 5000, () -> newContent.equals(document.get())),
203-
"document not modified, rename not applied");
204-
System.out.println("testRefactoringRename(): Executed command: " + IWorkbenchCommandConstants.FILE_RENAME);
205-
} finally {
206-
ideShell.getDisplay().removeFilter(SWT.Paint, pressOKonRenameDialogPaint);
207-
}
208-
}
209-
210-
static private Set<String> getButtons(Widget w) {
211-
Set<String> result = new HashSet<>();
212-
if (w instanceof Button button) {
213-
result.add(button.getText());
214-
} else if (w instanceof Composite composite) {
215-
for (Control child : composite.getChildren()) {
216-
result.addAll(getButtons(child));
217-
}
218-
}
219-
return result;
220-
}
221-
222-
static private boolean setNewText(Widget w, String newText) {
223-
Set<Text> textWidgets = getTextWidgets(w);
224-
if (!textWidgets.isEmpty()) {
225-
textWidgets.forEach(t -> t.setText(newText));
226-
return true;
227-
}
228-
return false;
229-
}
230-
231-
static private Set<Text> getTextWidgets(Widget w) {
232-
Set<Text> result = new HashSet<>();
233-
if (w instanceof Text text) {
234-
result.add(text);
235-
} else if (w instanceof Composite composite) {
236-
for (Control child : composite.getChildren()) {
237-
result.addAll(getTextWidgets(child));
238-
}
239-
}
240-
return result;
241-
}
242-
243-
static private void pressOk(Shell dialogShell) {
244-
try {
245-
Dialog dialog = (Dialog) dialogShell.getData();
246-
Method okPressedMethod = Dialog.class.getDeclaredMethod("okPressed");
247-
okPressedMethod.setAccessible(true);
248-
okPressedMethod.invoke(dialog);
249-
System.out.println("testRefactoringRename(): pressOK is executed");
250-
} catch (Exception ex) {
251-
ex.printStackTrace();
252-
throw new Error(ex);
253-
}
254-
}
255-
256-
static private void pressCancel(Shell dialogShell) {
257-
try {
258-
Dialog dialog = (Dialog) dialogShell.getData();
259-
Method cancelPressedMethod = Dialog.class.getDeclaredMethod("cancelPressed");
260-
cancelPressedMethod.setAccessible(true);
261-
cancelPressedMethod.invoke(dialog);
262-
System.out.println("testRefactoringRename(): pressCancel is executed");
263-
} catch (Exception ex) {
264-
ex.printStackTrace();
265-
throw new Error(ex);
266-
}
267-
}
50+
private IProject project;
51+
52+
@BeforeEach
53+
public void setUpProject() throws CoreException {
54+
this.project = ResourcesPlugin.getWorkspace().getRoot().getProject(getClass().getName() + System.nanoTime());
55+
project.create(null);
56+
project.open(null);
57+
}
58+
59+
@Test
60+
@Timeout(value = 60, unit = TimeUnit.SECONDS)
61+
public void testRefactoringRenameInTypeScript() throws Exception {
62+
final IFile file = project.getFile("TestJsTs.ts");
63+
String content = "function testVar(test) {\n if (\"truetrue\" == \"true\" + test ) {\n"
64+
+ " return true;\n }\n return false;\n}\n"
65+
+ "print(\"Testing var with true argument == \" + testVar(true));\n"
66+
+ "print(\"Testing var with false argument == \" + testVar(false));\n";
67+
final String oldName = "testVar";
68+
final String newName = "newName";
69+
internalTestRename(file, content, oldName, newName);
70+
}
71+
72+
@Test
73+
@Timeout(value = 60, unit = TimeUnit.SECONDS)
74+
public void testRefactoringRenameInJavaScript() throws Exception {
75+
final IFile file = project.getFile("TestJsTs.js");
76+
String content = "function testVar(test) {\n if (\"truetrue\" == \"true\" + test ) {\n"
77+
+ " return true;\n }\n return false;\n}\n"
78+
+ "print(\"Testing var with true argument == \" + testVar(true));\n"
79+
+ "print(\"Testing var with false argument == \" + testVar(false));\n";
80+
final String oldName = "testVar";
81+
final String newName = "newName";
82+
internalTestRename(file, content, oldName, newName);
83+
}
84+
85+
private void internalTestRename(IFile file, String content, String oldName, String newName) throws Exception {
86+
String expectedContent = content.replace(oldName, newName);
87+
88+
int offset = content.indexOf(oldName);
89+
file.create(content.getBytes(), true, false, null);
90+
91+
AbstractTextEditor editor = (AbstractTextEditor) IDE.openEditor(
92+
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(), file,
93+
"org.eclipse.ui.genericeditor.GenericEditor"
94+
);
95+
96+
editor.getSelectionProvider().setSelection(new TextSelection(offset, 0));
97+
editor.setFocus();
98+
99+
Display display = editor.getSite().getShell().getDisplay();
100+
101+
// Give LS time to initialize
102+
DisplayHelper.sleep(3000);
103+
104+
IDocument document = editor.getDocumentProvider().getDocument(editor.getEditorInput());
105+
106+
ICommandService commandService = PlatformUI.getWorkbench().getService(ICommandService.class);
107+
IHandlerService handlerService = PlatformUI.getWorkbench().getService(IHandlerService.class);
108+
Command command = commandService.getCommand(IWorkbenchCommandConstants.FILE_RENAME);
109+
assertTrue(command.isEnabled() && command.isHandled());
110+
111+
Event event = new Event();
112+
event.widget = editor.getAdapter(Control.class);
113+
event.display = display;
114+
115+
ExecutionEvent executionEvent = handlerService.createExecutionEvent(command, event);
116+
command.executeWithChecks(executionEvent);
117+
118+
assertTrue(
119+
DisplayHelper.waitForCondition(display, 5000, () -> LinkedModeModel.getModel(document, offset) != null),
120+
"Linked rename mode did not start"
121+
);
122+
123+
LinkedModeModel model = LinkedModeModel.getModel(document, offset);
124+
125+
display.syncExec(() -> {
126+
try {
127+
for (LinkedPositionGroup group : getLinkedPositionGroups(model)) {
128+
for (LinkedPosition pos : group.getPositions()) {
129+
document.replace(pos.getOffset(), pos.getLength(), newName);
130+
}
131+
}
132+
} catch (Exception e) {
133+
throw new RuntimeException(e);
134+
}
135+
});
136+
137+
display.syncExec(() -> {
138+
ITextViewer viewer = editor.getAdapter(ITextViewer.class);
139+
Event enter = new Event();
140+
enter.type = SWT.KeyDown;
141+
enter.character = SWT.CR;
142+
enter.keyCode = SWT.CR;
143+
viewer.getTextWidget().notifyListeners(SWT.KeyDown, enter);
144+
});
145+
146+
assertTrue(DisplayHelper.waitForCondition(display, 5000, () -> expectedContent.equals(document.get())),
147+
"Rename not applied to document"
148+
);
149+
}
150+
151+
// LinkedModeModel has no public API to access position groups at this JFace Text level, so tests must use reflection.
152+
@SuppressWarnings("unchecked")
153+
private static LinkedPositionGroup[] getLinkedPositionGroups(LinkedModeModel model) {
154+
try {
155+
for (String fieldName : new String[] { "fGroups", "fPositionGroups" }) {
156+
try {
157+
var field = LinkedModeModel.class.getDeclaredField(fieldName);
158+
field.setAccessible(true);
159+
Object value = field.get(model);
160+
161+
if (value instanceof LinkedPositionGroup[]) {
162+
return (LinkedPositionGroup[]) value;
163+
}
164+
if (value instanceof java.util.List<?>) {
165+
return ((java.util.List<LinkedPositionGroup>) value)
166+
.toArray(new LinkedPositionGroup[0]);
167+
}
168+
} catch (NoSuchFieldException e) {
169+
// try next name
170+
}
171+
}
172+
throw new IllegalStateException("No linked position groups found in LinkedModeModel");
173+
} catch (Exception e) {
174+
throw new RuntimeException(e);
175+
}
176+
}
268177
}
178+

0 commit comments

Comments
 (0)