Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sync delivery to master after 25-rc2 #8205

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.JTextComponent;
import javax.swing.text.Position;
import org.netbeans.api.annotations.common.CheckForNull;
import org.netbeans.api.editor.EditorRegistry;
import org.netbeans.modules.editor.NbEditorUtilities;
import org.netbeans.modules.gsf.testrunner.ui.api.TestMethodController;
Expand All @@ -41,7 +43,6 @@
import org.netbeans.modules.php.api.editor.PhpClass;
import org.netbeans.modules.php.api.editor.PhpType;
import org.netbeans.modules.php.api.phpmodule.PhpModule;
import org.netbeans.modules.php.api.util.FileUtils;
import org.netbeans.modules.php.project.ui.actions.support.CommandUtils;
import org.netbeans.modules.php.project.util.PhpProjectUtils;
import org.netbeans.modules.php.spi.testing.PhpTestingProvider;
Expand All @@ -50,14 +51,13 @@
import org.openide.util.Lookup;
import org.openide.util.RequestProcessor;


public class ComputeTestMethodAnnotations implements DocumentListener, PropertyChangeListener, Runnable {

private static final Logger LOGGER = Logger.getLogger(ComputeTestMethodAnnotations.class.getName());

private static final RequestProcessor RP = new RequestProcessor(ComputeTestMethodAnnotations.class);
private static final ComputeTestMethodAnnotations INSTANCE = new ComputeTestMethodAnnotations();
private static final AtomicInteger USAGES_COUNT = new AtomicInteger(0);

private final RequestProcessor.Task task = RP.create(this);
private volatile Document handledDocument;

Expand All @@ -82,49 +82,93 @@ public void unregister() {

@Override
public void propertyChange(PropertyChangeEvent event) {
assert SwingUtilities.isEventDispatchThread() : "UI thread expected but is: " + Thread.currentThread().getName();

assert SwingUtilities.isEventDispatchThread() : "UI thread expected but is: " + Thread.currentThread().getName(); // NOI18N
Document document = getLastFocusedDocument();
if (document == null) {
return;
}
long startTime = 0;
if (LOGGER.isLoggable(Level.FINE)) {
startTime = System.currentTimeMillis();
}
PhpTestingProvider testingProvider = getFirstTestingProvider(document);
if (LOGGER.isLoggable(Level.FINE)) {
long time = System.currentTimeMillis() - startTime;
LOGGER.fine(String.format("getFirstTestingProvider() took %d ms", time)); // NOI18N
}
if (testingProvider == null) {
return;
}
// don't add the listener if this document is not a test file
String propertyName = event.getPropertyName();

JTextComponent textComponent = EditorRegistry.lastFocusedComponent();
if (textComponent != null) {
Document document = textComponent.getDocument();
if (document != null) {
FileObject fileObject = NbEditorUtilities.getFileObject(document);
if (fileObject != null) {
if (FileUtils.isPhpFile(fileObject)) {
if (propertyName.equals(EditorRegistry.FOCUS_GAINED_PROPERTY)) {
handleFileChange(document);
document.addDocumentListener(ComputeTestMethodAnnotations.this);
} else if (propertyName.equals(EditorRegistry.FOCUS_LOST_PROPERTY)) {
document.removeDocumentListener(this);
}
}
}
}
if (propertyName.equals(EditorRegistry.FOCUS_GAINED_PROPERTY)) {
handleFileChange(document);
document.addDocumentListener(this);
} else if (propertyName.equals(EditorRegistry.FOCUS_LOST_PROPERTY)) {
document.removeDocumentListener(this);
}
}

@Override
public void insertUpdate(DocumentEvent event) {
handleFileChange(event.getDocument());
processUpdate();
}

@Override
public void removeUpdate(DocumentEvent event) {
handleFileChange(event.getDocument());
processUpdate();
}

@Override
public void changedUpdate(DocumentEvent event) {
handleFileChange(event.getDocument());
processUpdate();
}

private void handleFileChange(Document doc) {
handledDocument = doc;
processUpdate();
}

private void processUpdate() {
task.schedule(500);
}

@CheckForNull
private Document getLastFocusedDocument() {
JTextComponent textComponent = EditorRegistry.lastFocusedComponent();
if (textComponent == null) {
return null;
}
return textComponent.getDocument();
}

/**
* Get the first testing provider that recognizes this document as a test
* file.
*
* @param document
* @return the first testing provider if this document is recognized as a
* test file, {@code null} otherwise
*/
@CheckForNull
private PhpTestingProvider getFirstTestingProvider(Document document) {
FileObject fileObject = NbEditorUtilities.getFileObject(document);
if (fileObject == null) {
return null;
}
PhpProject project = PhpProjectUtils.getPhpProject(fileObject);
if (project == null) {
return null;
}
PhpModule phpModule = project.getPhpModule();
for (PhpTestingProvider testingProvider : project.getTestingProviders()) {
if (testingProvider.isTestFile(phpModule, fileObject)) {
return testingProvider;
}
}
return null;
}

@Override
public void run() {
List<TestMethod> testMethods = getTestMethods(handledDocument);
Expand All @@ -142,59 +186,72 @@ public void run() {
}
}

/**
* Get test methods for the first available testing provider.
*
* @return test methods
*/
private List<TestMethod> getTestMethods(Document document) {
List<TestMethod> testMethods = new ArrayList<>();
FileObject fileObject = NbEditorUtilities.getFileObject(document);
if (fileObject != null) {
PhpProject project = PhpProjectUtils.getPhpProject(fileObject);
assert project != null;
PhpModule phpModule = project.getPhpModule();
for (PhpTestingProvider testingProvider : project.getTestingProviders()) {
if (fileObject == null) {
return Collections.emptyList();
}
PhpProject project = PhpProjectUtils.getPhpProject(fileObject);
if (project == null) {
return Collections.emptyList();
}
PhpTestingProvider testingProvider = getFirstTestingProvider(document);
if (testingProvider == null) {
return Collections.emptyList();
}
return getTestMethods(document, fileObject, testingProvider, project.getPhpModule());
}

private List<TestMethod> getTestMethods(Document document, FileObject fileObject, PhpTestingProvider testingProvider, PhpModule phpModule) {
List<TestMethod> testMethods = new ArrayList<>();
Collection<PhpClass> phpClasses = getPhpClasses(fileObject);
for (PhpClass phpClass : phpClasses) {
// check whether the document tab has already been switched to another one
if (!document.equals(handledDocument)) {
return Collections.emptyList();
}
for (PhpType.Method method : phpClass.getMethods()) {
if (!document.equals(handledDocument)) {
return Collections.emptyList();
}

if (testingProvider.isTestFile(phpModule, fileObject)) {
EditorSupport editorSupport = Lookup.getDefault().lookup(EditorSupport.class);
assert editorSupport != null;
Collection<PhpClass> phpClasses = editorSupport.getClasses(fileObject);
for (PhpClass phpClass : phpClasses) {

if (!document.equals(handledDocument)) {
return Collections.emptyList();
}

for (PhpType.Method method : phpClass.getMethods()) {

if (!document.equals(handledDocument)) {
return Collections.emptyList();
}

if (!testingProvider.isTestCase(phpModule, method)) {
continue;
}
try {
testMethods.add(new TestMethod(
phpClass.getName(),
new SingleMethod(fileObject, CommandUtils.encodeMethod(method.getPhpType().getFullyQualifiedName(), method.getName())),
document.createPosition(method.getOffset()),
document.createPosition(method.getOffset() + method.getName().length())
));
} catch (BadLocationException exception) {
LOGGER.log(Level.WARNING, "Unable to create position: offset: {0}; method: {1}; class: {2}.", new Object[] {exception.offsetRequested(), method.getName(), phpClass.getName()}); // NOI18N
}
}

if (!testMethods.isEmpty()) {
return testMethods;
}
}

if (!testingProvider.isTestCase(phpModule, method)) {
continue;
}
TestMethod testMethod = createTestMethod(document, phpClass, method, fileObject);
if (testMethod != null) {
testMethods.add(testMethod);
}
}
}

return testMethods;
}

private Collection<PhpClass> getPhpClasses(FileObject fileObject) {
EditorSupport editorSupport = Lookup.getDefault().lookup(EditorSupport.class);
assert editorSupport != null;
return editorSupport.getClasses(fileObject);
}

@CheckForNull
private TestMethod createTestMethod(Document document, PhpClass phpClass, PhpType.Method method, FileObject fileObject) {
Position startPosition = null;
Position endPosition = null;
try {
startPosition = document.createPosition(method.getOffset());
endPosition = document.createPosition(method.getOffset() + method.getName().length());
} catch (BadLocationException exception) {
LOGGER.log(Level.WARNING, "Unable to create position: offset: {0}; method: {1}; class: {2}.", // NOI18N
new Object[]{exception.offsetRequested(), method.getName(), phpClass.getName()});
}
if (startPosition == null || endPosition == null) {
return null;
}
String methodName = CommandUtils.encodeMethod(method.getPhpType().getFullyQualifiedName(), method.getName());
return new TestMethod(phpClass.getName(), new SingleMethod(fileObject, methodName), startPosition, endPosition);
}
}
Loading