From 4e0d525a1ecb1fba4262116e2c11ae0db654a608 Mon Sep 17 00:00:00 2001 From: Jonas <50097340+JKutscha@users.noreply.github.com> Date: Mon, 23 Aug 2021 14:30:07 +0200 Subject: [PATCH 1/7] Added mutant markers and open task list after pit run --- .../org.pitest.pitclipse.ui/icons/killed.gif | Bin 0 -> 331 bytes .../icons/noCoverage.gif | Bin 0 -> 341 bytes .../icons/nonViable.gif | Bin 0 -> 337 bytes .../icons/survived.gif | Bin 0 -> 347 bytes .../org.pitest.pitclipse.ui/icons/timeout.gif | Bin 0 -> 338 bytes bundles/org.pitest.pitclipse.ui/plugin.xml | 249 +++++++++++++++++- .../pitclipse/ui/core/PitUiActivator.java | 41 ++- .../highlighting/AnnotationImageProvider.java | 25 ++ .../ui/highlighting/MutantsView.java | 7 + .../PitclipseMutantHighlighter.java | 199 ++++++++++++++ 10 files changed, 517 insertions(+), 4 deletions(-) create mode 100644 bundles/org.pitest.pitclipse.ui/icons/killed.gif create mode 100644 bundles/org.pitest.pitclipse.ui/icons/noCoverage.gif create mode 100644 bundles/org.pitest.pitclipse.ui/icons/nonViable.gif create mode 100644 bundles/org.pitest.pitclipse.ui/icons/survived.gif create mode 100644 bundles/org.pitest.pitclipse.ui/icons/timeout.gif create mode 100644 bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/highlighting/AnnotationImageProvider.java create mode 100644 bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/highlighting/MutantsView.java create mode 100644 bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/highlighting/PitclipseMutantHighlighter.java diff --git a/bundles/org.pitest.pitclipse.ui/icons/killed.gif b/bundles/org.pitest.pitclipse.ui/icons/killed.gif new file mode 100644 index 0000000000000000000000000000000000000000..7b081f57d1a58372c3494927891283b15f6d4d73 GIT binary patch literal 331 zcmZ?wbhEHb6krfwSgOb%6wfD;EugYhT4kHGDhSEwY>`vhF0HadMrEgr>P~5m z+8A9^Y}*kuV@qJcQMnnrEGF*>JF?w-_pXGqJMx!av0r+{W94P{BgdL5pPBYP(p`Ep zsq?8z_D8*WFN(LlS@xfnK=CIFBNu}`gAM}_fc(V3mT_RdfP;=ytH+{*lQBY*8CKhb*vQ+J80(ZK6)<0V^fOFExu(_H`o+R=j4bD6HQW(5c3vS q?gS!_WSTXU)zR5@S&pEVx)&4cpj&7fLeCLeg>t`NcyXeT4=_fW%JhQI%?53%w zx6i-0>-NhRcV51H`u_d%4|R}}%7O1>W`xBvHYEfy3d*TUi;Bbx<%Z-dDXA*T7bs8glHrXP5K~Z97H7+2;NbRV WW@@z$3!fOU!QW$@+jb8}25SI!=gQ~+ literal 0 HcmV?d00001 diff --git a/bundles/org.pitest.pitclipse.ui/icons/nonViable.gif b/bundles/org.pitest.pitclipse.ui/icons/nonViable.gif new file mode 100644 index 0000000000000000000000000000000000000000..d05b83e05046feb835bf46b1002fe1ea7295cc3a GIT binary patch literal 337 zcmZ?wbhEHb6krfwSgOI$)YNqR(7B^Wj~+jA=G3us$4{O;dHUj+GiT17xp@A}rSoSm zpFMx^!uiV=FJ8TJ<@)t&w{Bj)ck9NTTQ?ruym{}=jr(_QJbrNR@uRyh9zT5Y^y$k_ zpFV&2{N?NCZ@+&0{`TwFk6$40=hvU#K=20){(`{2fB*hd2`K(#VdP@4XV75)0+62= z*zyj{7jV##YV}x@a56?{a>KHa4A=G*}QI>Y3pA&|kD>@ZG#4PHKOZ&r}PGA#*j0XY?2O&K2-MqVCo_9oxZmhk3)t^OYNZhII!92u+u Dc#*ng literal 0 HcmV?d00001 diff --git a/bundles/org.pitest.pitclipse.ui/icons/timeout.gif b/bundles/org.pitest.pitclipse.ui/icons/timeout.gif new file mode 100644 index 0000000000000000000000000000000000000000..98a3015413daf3960b9e8d3c78269b56aea83903 GIT binary patch literal 338 zcmZ?wbhEHb6krfwSgOO2Y1BL+Z1t3=^^>C4%q!lqvGvT_{u8SwA6q^31fXmK4cgxp?8#>t8&VM#vePo-)!AoRsf+a7)(gFn(zr8DTLdCJ~)YtN~0|&0hcj literal 0 HcmV?d00001 diff --git a/bundles/org.pitest.pitclipse.ui/plugin.xml b/bundles/org.pitest.pitclipse.ui/plugin.xml index d52728fe..60563143 100644 --- a/bundles/org.pitest.pitclipse.ui/plugin.xml +++ b/bundles/org.pitest.pitclipse.ui/plugin.xml @@ -4,8 +4,8 @@ - + @@ -36,5 +36,250 @@ point="org.pitest.pitclipse.core.mutations.results"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/core/PitUiActivator.java b/bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/core/PitUiActivator.java index ef7e44d6..d0614398 100644 --- a/bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/core/PitUiActivator.java +++ b/bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/core/PitUiActivator.java @@ -28,6 +28,7 @@ import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.FrameworkUtil; +import org.pitest.pitclipse.ui.highlighting.PitclipseMutantHighlighter; /** * The ui activator class which initializes the icons of the plug in @@ -41,7 +42,10 @@ public class PitUiActivator extends AbstractUIPlugin { * Key under which the pit icon is put in the registry */ private static final String PIT_ICON = "org.pitest.pitclipse.pitIcon"; - + /** + * Qualifier of this plug in + */ + public static final String PLUGIN_ID = "org.pitest.pitclipse.ui"; /** * The shared instance */ @@ -61,8 +65,29 @@ private void initIcons(BundleContext context) { Display.getDefault().syncExec(() -> { imageRegistry = new ImageRegistry(); Bundle bundle = FrameworkUtil.getBundle(getClass()); - URL url = FileLocator.find(bundle, new Path("icons/pit.gif"), null); + final URL url = FileLocator.find(bundle, new Path("icons/pit.gif"), null); imageRegistry.put(PIT_ICON, ImageDescriptor.createFromURL(url).createImage()); + // annotation icons + final URL killedUrl = FileLocator.find(bundle, new Path("icons/killed.gif"), null); + imageRegistry.put(PitclipseMutantHighlighter.KILLED_MUTANT_MARKER, + ImageDescriptor.createFromURL(killedUrl).createImage()); + final URL survivingUrl = FileLocator.find(bundle, new Path("icons/survived.gif"), null); + imageRegistry.put(PitclipseMutantHighlighter.SURVIVING_MUTANT_MARKER, + ImageDescriptor.createFromURL(survivingUrl).createImage()); + final URL noCoverageUrl = FileLocator.find(bundle, new Path("icons/noCoverage.gif"), null); + imageRegistry.put(PitclipseMutantHighlighter.NO_COVERAGE_MUTANT_MARKER, + ImageDescriptor.createFromURL(noCoverageUrl).createImage()); + final URL timeoutUrl = FileLocator.find(bundle, new Path("icons/timeout.gif"), null); + imageRegistry.put(PitclipseMutantHighlighter.TIMEOUT_MUTANT_MARKER, + ImageDescriptor.createFromURL(timeoutUrl).createImage()); + // use same icon for these 3, because they are not from huge interest + final URL nonViableUrl = FileLocator.find(bundle, new Path("icons/nonViable.gif"), null); + imageRegistry.put(PitclipseMutantHighlighter.NON_VIABLE_MUTANT_MARKER, + ImageDescriptor.createFromURL(nonViableUrl).createImage()); + imageRegistry.put(PitclipseMutantHighlighter.MEMORY_ERROR_MARKER, + ImageDescriptor.createFromURL(nonViableUrl).createImage()); + imageRegistry.put(PitclipseMutantHighlighter.RUN_ERROR_MARKER, + ImageDescriptor.createFromURL(nonViableUrl).createImage()); }); } @@ -73,10 +98,22 @@ public Image getPitIcon() { return imageRegistry.get(PIT_ICON); } + /** + * @param imageDescritporId + * @return the requested image descriptor or null, if not found + */ + public ImageDescriptor getImageDescriptor(String imageDescritporId) { + return imageRegistry.getDescriptor(imageDescritporId); + } + /** * @return the shared instance */ public static PitUiActivator getDefault() { return plugin; } + + public Image getImage(String imageDescriptorId) { + return imageRegistry.get(imageDescriptorId); + } } diff --git a/bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/highlighting/AnnotationImageProvider.java b/bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/highlighting/AnnotationImageProvider.java new file mode 100644 index 00000000..2fad1679 --- /dev/null +++ b/bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/highlighting/AnnotationImageProvider.java @@ -0,0 +1,25 @@ +package org.pitest.pitclipse.ui.highlighting; + + +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.text.source.Annotation; +import org.eclipse.swt.graphics.Image; +import org.eclipse.ui.texteditor.IAnnotationImageProvider; +import org.pitest.pitclipse.ui.core.PitUiActivator; + +public class AnnotationImageProvider implements IAnnotationImageProvider { + @Override + public String getImageDescriptorId(Annotation annotation) { + return annotation.getType(); + } + + @Override + public ImageDescriptor getImageDescriptor(String imageDescritporId) { + return PitUiActivator.getDefault().getImageDescriptor(imageDescritporId); + } + + @Override + public Image getManagedImage(Annotation annotation) { + return PitUiActivator.getDefault().getImage(getImageDescriptorId(annotation)); + } +} diff --git a/bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/highlighting/MutantsView.java b/bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/highlighting/MutantsView.java new file mode 100644 index 00000000..44288771 --- /dev/null +++ b/bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/highlighting/MutantsView.java @@ -0,0 +1,7 @@ +package org.pitest.pitclipse.ui.highlighting; + +import org.eclipse.ui.internal.views.markers.TasksView; + +public class MutantsView extends TasksView { + +} diff --git a/bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/highlighting/PitclipseMutantHighlighter.java b/bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/highlighting/PitclipseMutantHighlighter.java new file mode 100644 index 00000000..0a9d3f57 --- /dev/null +++ b/bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/highlighting/PitclipseMutantHighlighter.java @@ -0,0 +1,199 @@ +package org.pitest.pitclipse.ui.highlighting; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.IViewPart; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.PlatformUI; +import org.pitest.pitclipse.core.extension.point.ResultNotifier; +import org.pitest.pitclipse.runner.model.ClassMutations; +import org.pitest.pitclipse.runner.model.Mutation; +import org.pitest.pitclipse.runner.model.MutationsModel; +import org.pitest.pitclipse.runner.model.PackageMutations; +import org.pitest.pitclipse.runner.model.ProjectMutations; +import org.pitest.pitclipse.runner.model.Status; +import org.pitest.pitclipse.ui.core.PitUiActivator; + +public class PitclipseMutantHighlighter implements ResultNotifier { + /** + * Id where all pitclipse markers can be found + */ + public static final String PITCLIPSE_MUTANT_MARKER = PitUiActivator.PLUGIN_ID + ".pitclipsemarker"; + public static final String SURVIVING_MUTANT_MARKER = PitUiActivator.PLUGIN_ID + ".survived"; + public static final String SURVIVING_MUTANT_MARKER_ATTRIBUTE = PitUiActivator.PLUGIN_ID + ".fixHint"; + public static final String KILLED_MUTANT_MARKER = PitUiActivator.PLUGIN_ID + ".killed"; + public static final String NO_COVERAGE_MUTANT_MARKER = PitUiActivator.PLUGIN_ID + ".nocoverage"; + public static final String TIMEOUT_MUTANT_MARKER = PitUiActivator.PLUGIN_ID + ".timeout"; + public static final String NON_VIABLE_MUTANT_MARKER = PitUiActivator.PLUGIN_ID + ".nonViable"; + public static final String MEMORY_ERROR_MARKER = PitUiActivator.PLUGIN_ID + ".memError"; + public static final String RUN_ERROR_MARKER = PitUiActivator.PLUGIN_ID + ".runError"; + private static final String TASKS_VIEW_ID = "org.eclipse.ui.views.TaskList"; + + + @Override + public void handleResults(MutationsModel results) { + createMarkers(results); + // open and show tasks view after the marker are created + Display.getDefault().asyncExec(() -> { + try { + IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); + IViewPart view = page.showView(TASKS_VIEW_ID); + page.activate(view); + } catch (PartInitException e) { + e.printStackTrace(); + } + }); + } + + @SuppressWarnings("unchecked") + private void createMarkers(MutationsModel results) { + removeOldMarkers(); + List mutations = ModelsVisitor.VISITOR.extractAllMutations(results); + + int i = 0; + final IResource[] resources = new IResource[mutations.size()]; + final String[] types = new String[mutations.size()]; + final Map[] attributes = new Map[mutations.size()]; + + for (Mutation m : mutations) { + resources[i] = findClass(getProjectName(m), getClassName(m)); + types[i] = getType(m); + attributes[i] = new HashMap<>(); + attributes[i].put(IMarker.LINE_NUMBER, m.getLineNumber()); + attributes[i].put(IMarker.MESSAGE, m.getStatus().toString() + ": " + m.getDescription()); + + switch (types[i]) { + case SURVIVING_MUTANT_MARKER: + // if mutation survived, add hint how to probably kill it + attributes[i].put(SURVIVING_MUTANT_MARKER_ATTRIBUTE, "NOT IMPLEMENTED YET"); + attributes[i].put(IMarker.PRIORITY, IMarker.PRIORITY_HIGH); + break; + case TIMEOUT_MUTANT_MARKER: + case NO_COVERAGE_MUTANT_MARKER: + attributes[i].put(IMarker.PRIORITY, IMarker.PRIORITY_NORMAL); + break; + default: + attributes[i].put(IMarker.DONE, true); + attributes[i].put(IMarker.PRIORITY, IMarker.PRIORITY_LOW); + } + createMarker(resources[i], types[i], attributes[i]); + i++; + } + } + + private void removeOldMarkers() { + IMarker[] marker = null; + int depth = IResource.DEPTH_INFINITE; + try { + marker = ResourcesPlugin.getWorkspace().getRoot().findMarkers(PITCLIPSE_MUTANT_MARKER, true, depth); + for (IMarker iMarker : marker) { + iMarker.delete(); + } + } catch (CoreException e) { + // something went wrong + } + } + + private IMarker createMarker(IResource iResource, String type, Map map) { + try { + return iResource.createMarker(type, map); + } catch (CoreException e) { + return null; + } + } + + private String getType(Mutation mutation) { + switch (mutation.getStatus()) { + case SURVIVED: + return SURVIVING_MUTANT_MARKER; + case KILLED: + return KILLED_MUTANT_MARKER; + case NO_COVERAGE: + return NO_COVERAGE_MUTANT_MARKER; + case TIMED_OUT: + return TIMEOUT_MUTANT_MARKER; + case MEMORY_ERROR: + return MEMORY_ERROR_MARKER; + case RUN_ERROR: + return RUN_ERROR_MARKER; + default: + return NON_VIABLE_MUTANT_MARKER; + } + } + + private IFile findClass(final String projectName, final String className) { + IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); + for (IProject project : root.getProjects()) { + if (project.getName().equals(projectName) && project.isOpen()) { + IJavaProject javaProject = JavaCore.create(project); + if (javaProject != null) { + try { + IType type = javaProject.findType(className); + return root.getFile(type.getPath()); + } catch (JavaModelException e) { + // Maybe type no longer exists. Do nothing + } + } + } + } + return null; + } + + private String getProjectName(Mutation mutation) { + return mutation.getClassMutations().getPackageMutations().getProjectMutations().getProjectName(); + } + + private String getClassName(Mutation mutation) { + return mutation.getClassMutations().getClassName(); + } + + private enum ModelsVisitor { + VISITOR; + public List extractAllMutations(MutationsModel mutationsModel) { + final LinkedList mutations = new LinkedList<>(); + for (Status s : mutationsModel.getStatuses()) { + VISITOR.visitStatus(s, mutations); + } + return mutations; + } + + public void visitStatus(Status status, List mutations) { + for (ProjectMutations p : status.getProjectMutations()) { + VISITOR.visitProject(p, mutations); + } + } + + public void visitProject(ProjectMutations projectMutations, List mutations) { + for (PackageMutations p : projectMutations.getPackageMutations()) { + VISITOR.visitPackage(p, mutations); + } + } + + public void visitPackage(PackageMutations packageMutations, List mutations) { + for (ClassMutations c : packageMutations.getClassMutations()) { + VISITOR.visitClass(c, mutations); + } + } + + public void visitClass(ClassMutations classMutations, List mutations) { + mutations.addAll(classMutations.getMutations()); + } + + } +} From 8961709eaf8d53ca5dc73284bcfba67031827513 Mon Sep 17 00:00:00 2001 From: Jonas <50097340+JKutscha@users.noreply.github.com> Date: Mon, 23 Aug 2021 14:44:44 +0200 Subject: [PATCH 2/7] Don't use not supported method of old TP --- .../ui/highlighting/PitclipseMutantHighlighter.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/highlighting/PitclipseMutantHighlighter.java b/bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/highlighting/PitclipseMutantHighlighter.java index 0a9d3f57..138233c2 100644 --- a/bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/highlighting/PitclipseMutantHighlighter.java +++ b/bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/highlighting/PitclipseMutantHighlighter.java @@ -110,9 +110,11 @@ private void removeOldMarkers() { } } - private IMarker createMarker(IResource iResource, String type, Map map) { + private IMarker createMarker(IResource iResource, String type, Map attributes) { try { - return iResource.createMarker(type, map); + IMarker marker = iResource.createMarker(type); + marker.setAttributes(attributes); + return marker; } catch (CoreException e) { return null; } From d10a248b8743a0b3c25b702117892a0810dc3837 Mon Sep 17 00:00:00 2001 From: Jonas Kutscha Date: Mon, 30 Aug 2021 10:09:34 +0200 Subject: [PATCH 3/7] Renaming and removed unused class --- bundles/org.pitest.pitclipse.ui/plugin.xml | 14 +++++++------- .../pitest/pitclipse/ui/core/PitUiActivator.java | 16 ++++++++-------- .../pitclipse/ui/highlighting/MutantsView.java | 7 ------- .../marker}/AnnotationImageProvider.java | 2 +- .../marker/PitclipseMutantMarkerFactory.java} | 4 ++-- 5 files changed, 18 insertions(+), 25 deletions(-) delete mode 100644 bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/highlighting/MutantsView.java rename bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/{highlighting => mutation/marker}/AnnotationImageProvider.java (94%) rename bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/{highlighting/PitclipseMutantHighlighter.java => mutation/marker/PitclipseMutantMarkerFactory.java} (98%) diff --git a/bundles/org.pitest.pitclipse.ui/plugin.xml b/bundles/org.pitest.pitclipse.ui/plugin.xml index 60563143..6e362780 100644 --- a/bundles/org.pitest.pitclipse.ui/plugin.xml +++ b/bundles/org.pitest.pitclipse.ui/plugin.xml @@ -149,7 +149,7 @@ { +public class PitclipseMutantMarkerFactory implements ResultNotifier { /** * Id where all pitclipse markers can be found */ From 8a8378bed31e7d915aabfc223bea5f9706b6f3a2 Mon Sep 17 00:00:00 2001 From: Jonas Kutscha Date: Mon, 30 Aug 2021 10:36:06 +0200 Subject: [PATCH 4/7] Added comments --- .../marker/AnnotationImageProvider.java | 21 +++- .../marker/PitclipseMutantMarkerFactory.java | 103 +++++++++++++++++- 2 files changed, 119 insertions(+), 5 deletions(-) diff --git a/bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/mutation/marker/AnnotationImageProvider.java b/bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/mutation/marker/AnnotationImageProvider.java index b13d99c1..a9061a69 100644 --- a/bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/mutation/marker/AnnotationImageProvider.java +++ b/bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/mutation/marker/AnnotationImageProvider.java @@ -1,5 +1,20 @@ -package org.pitest.pitclipse.ui.mutation.marker; +/******************************************************************************* + * Copyright 2021 Jonas Kutscha and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ +package org.pitest.pitclipse.ui.mutation.marker; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.text.source.Annotation; @@ -7,6 +22,10 @@ import org.eclipse.ui.texteditor.IAnnotationImageProvider; import org.pitest.pitclipse.ui.core.PitUiActivator; +/** + * Simple image provider for the mutation marker + * @author Jonas Kutscha + */ public class AnnotationImageProvider implements IAnnotationImageProvider { @Override public String getImageDescriptorId(Annotation annotation) { diff --git a/bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/mutation/marker/PitclipseMutantMarkerFactory.java b/bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/mutation/marker/PitclipseMutantMarkerFactory.java index a8b474c6..a2cae4d6 100644 --- a/bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/mutation/marker/PitclipseMutantMarkerFactory.java +++ b/bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/mutation/marker/PitclipseMutantMarkerFactory.java @@ -1,3 +1,19 @@ +/******************************************************************************* + * Copyright 2021 Jonas Kutscha and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ + package org.pitest.pitclipse.ui.mutation.marker; import java.util.HashMap; @@ -30,22 +46,58 @@ import org.pitest.pitclipse.runner.model.Status; import org.pitest.pitclipse.ui.core.PitUiActivator; +/** + * Class which creates mutation markers after a PIT run + * @author Jonas Kutscha + */ public class PitclipseMutantMarkerFactory implements ResultNotifier { /** - * Id where all pitclipse markers can be found + * Id where all Pitclipse markers can be found */ public static final String PITCLIPSE_MUTANT_MARKER = PitUiActivator.PLUGIN_ID + ".pitclipsemarker"; + /** + * Id for markers of surviving mutants + */ public static final String SURVIVING_MUTANT_MARKER = PitUiActivator.PLUGIN_ID + ".survived"; + /** + * Id of the marker attribute fix hint + */ public static final String SURVIVING_MUTANT_MARKER_ATTRIBUTE = PitUiActivator.PLUGIN_ID + ".fixHint"; + /** + * Id for markers of killed mutants + */ public static final String KILLED_MUTANT_MARKER = PitUiActivator.PLUGIN_ID + ".killed"; + /** + * Id for markers of no coverage mutants + */ public static final String NO_COVERAGE_MUTANT_MARKER = PitUiActivator.PLUGIN_ID + ".nocoverage"; + /** + * Id for markers of timeout mutants + */ public static final String TIMEOUT_MUTANT_MARKER = PitUiActivator.PLUGIN_ID + ".timeout"; + /** + * Id for markers of non viable mutants + */ public static final String NON_VIABLE_MUTANT_MARKER = PitUiActivator.PLUGIN_ID + ".nonViable"; + /** + * Id for markers of memory error mutants + */ public static final String MEMORY_ERROR_MARKER = PitUiActivator.PLUGIN_ID + ".memError"; + /** + * Id for markers of run error mutants + */ public static final String RUN_ERROR_MARKER = PitUiActivator.PLUGIN_ID + ".runError"; + /** + * Id of the task view from Eclipse + */ private static final String TASKS_VIEW_ID = "org.eclipse.ui.views.TaskList"; + /** + * Uses the results to create a marker for each mutant and shows the task view + * of Eclipse + * @param results from pit which holds the information about the mutants + */ @Override public void handleResults(MutationsModel results) { createMarkers(results); @@ -61,7 +113,10 @@ public void handleResults(MutationsModel results) { }); } - @SuppressWarnings("unchecked") + /** + * Extracts all mutants of the results to create a marker for each one + * @param results which hold the mutants + */ private void createMarkers(MutationsModel results) { removeOldMarkers(); List mutations = ModelsVisitor.VISITOR.extractAllMutations(results); @@ -69,6 +124,7 @@ private void createMarkers(MutationsModel results) { int i = 0; final IResource[] resources = new IResource[mutations.size()]; final String[] types = new String[mutations.size()]; + @SuppressWarnings("unchecked") final Map[] attributes = new Map[mutations.size()]; for (Mutation m : mutations) { @@ -80,7 +136,7 @@ private void createMarkers(MutationsModel results) { switch (types[i]) { case SURVIVING_MUTANT_MARKER: - // if mutation survived, add hint how to probably kill it + // TODO: if mutation survived, add hint how to probably kill it attributes[i].put(SURVIVING_MUTANT_MARKER_ATTRIBUTE, "NOT IMPLEMENTED YET"); attributes[i].put(IMarker.PRIORITY, IMarker.PRIORITY_HIGH); break; @@ -97,6 +153,9 @@ private void createMarkers(MutationsModel results) { } } + /** + * Removes all old markers, which are Pitclipse markers + */ private void removeOldMarkers() { IMarker[] marker = null; int depth = IResource.DEPTH_INFINITE; @@ -106,20 +165,36 @@ private void removeOldMarkers() { iMarker.delete(); } } catch (CoreException e) { - // something went wrong + throw new RuntimeException("Error while deleting old markers occured.", e); } } + /** + * Tries to create a marker for the given resource with the given type and + * attributes. + * @param iResource resource where to create the marker + * @param type of the marker to create + * @param attributes which should be added to the marker + * @return the created marker or null, if the marker could not be created + */ private IMarker createMarker(IResource iResource, String type, Map attributes) { try { IMarker marker = iResource.createMarker(type); marker.setAttributes(attributes); return marker; } catch (CoreException e) { + // could not create marker return null; } } + /** + * Maps the detection status of the given mutation to the corresponding marker + * id. If the detection status has no corresponding marker id the non viable + * marker is used. + * @param mutation which detection status is mapped + * @return the marker id which corresponds to the detection status of the mutant + */ private String getType(Mutation mutation) { switch (mutation.getStatus()) { case SURVIVED: @@ -139,6 +214,13 @@ private String getType(Mutation mutation) { } } + /** + * Tries to find the class specified by its name in the project which name is + * given. + * @param projectName where the class file is located + * @param className which identifies the class + * @return the file handle or null, if the file was not found + */ private IFile findClass(final String projectName, final String className) { IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); for (IProject project : root.getProjects()) { @@ -157,14 +239,27 @@ private IFile findClass(final String projectName, final String className) { return null; } + /** + * Extracts the project name from the given mutation where it occured. + * @param mutation from which the project is desired + * @return the project name where the mutation occured + */ private String getProjectName(Mutation mutation) { return mutation.getClassMutations().getPackageMutations().getProjectMutations().getProjectName(); } + /** + * Extracts the class name from the given mutation where it occured. + * @param mutation from which the class is desired + * @return the class name where the mutation occured + */ private String getClassName(Mutation mutation) { return mutation.getClassMutations().getClassName(); } + /** + * Visitor which is used to extract all mutations from the mutation model + */ private enum ModelsVisitor { VISITOR; public List extractAllMutations(MutationsModel mutationsModel) { From ee3a26c24f1526b2d9b455a40de612257d7b321b Mon Sep 17 00:00:00 2001 From: Jonas Kutscha Date: Mon, 30 Aug 2021 13:11:06 +0200 Subject: [PATCH 5/7] Fixed issues from renaming --- bundles/org.pitest.pitclipse.ui/plugin.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bundles/org.pitest.pitclipse.ui/plugin.xml b/bundles/org.pitest.pitclipse.ui/plugin.xml index 6e362780..413dc8e6 100644 --- a/bundles/org.pitest.pitclipse.ui/plugin.xml +++ b/bundles/org.pitest.pitclipse.ui/plugin.xml @@ -37,7 +37,7 @@ + class="org.pitest.pitclipse.ui.mutation.marker.PitclipseMutantMarkerFactory"/> Date: Mon, 30 Aug 2021 13:11:58 +0200 Subject: [PATCH 6/7] Tests for mutation marker --- .../marker/PitclipseMutantMarkerFactory.java | 9 ++-- .../tests/PitclipsePitMutationsViewTest.java | 52 +++++++++++++++++++ 2 files changed, 56 insertions(+), 5 deletions(-) diff --git a/bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/mutation/marker/PitclipseMutantMarkerFactory.java b/bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/mutation/marker/PitclipseMutantMarkerFactory.java index a2cae4d6..4c744043 100644 --- a/bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/mutation/marker/PitclipseMutantMarkerFactory.java +++ b/bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/mutation/marker/PitclipseMutantMarkerFactory.java @@ -108,7 +108,7 @@ public void handleResults(MutationsModel results) { IViewPart view = page.showView(TASKS_VIEW_ID); page.activate(view); } catch (PartInitException e) { - e.printStackTrace(); + throw new RuntimeException("Could not show task view.", e); } }); } @@ -120,7 +120,6 @@ public void handleResults(MutationsModel results) { private void createMarkers(MutationsModel results) { removeOldMarkers(); List mutations = ModelsVisitor.VISITOR.extractAllMutations(results); - int i = 0; final IResource[] resources = new IResource[mutations.size()]; final String[] types = new String[mutations.size()]; @@ -145,6 +144,7 @@ private void createMarkers(MutationsModel results) { attributes[i].put(IMarker.PRIORITY, IMarker.PRIORITY_NORMAL); break; default: + // default. Used for killed mutants attributes[i].put(IMarker.DONE, true); attributes[i].put(IMarker.PRIORITY, IMarker.PRIORITY_LOW); } @@ -157,10 +157,9 @@ private void createMarkers(MutationsModel results) { * Removes all old markers, which are Pitclipse markers */ private void removeOldMarkers() { - IMarker[] marker = null; - int depth = IResource.DEPTH_INFINITE; try { - marker = ResourcesPlugin.getWorkspace().getRoot().findMarkers(PITCLIPSE_MUTANT_MARKER, true, depth); + IMarker[] marker = ResourcesPlugin.getWorkspace().getRoot().findMarkers(PITCLIPSE_MUTANT_MARKER, true, + IResource.DEPTH_INFINITE); for (IMarker iMarker : marker) { iMarker.delete(); } diff --git a/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/tests/PitclipsePitMutationsViewTest.java b/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/tests/PitclipsePitMutationsViewTest.java index 78f73d25..95c6cf89 100644 --- a/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/tests/PitclipsePitMutationsViewTest.java +++ b/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/tests/PitclipsePitMutationsViewTest.java @@ -1,12 +1,19 @@ package org.pitest.pitclipse.ui.tests; +import static org.junit.Assert.assertEquals; + +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.swtbot.swt.finder.junit.SWTBotJunit4ClassRunner; +import org.eclipse.swtbot.swt.finder.waits.DefaultCondition; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.pitest.pitclipse.ui.behaviours.steps.PitMutation; import org.pitest.pitclipse.ui.behaviours.steps.PitclipseSteps; +import org.pitest.pitclipse.ui.mutation.marker.PitclipseMutantMarkerFactory; /** * @author Lorenzo Bettini @@ -45,4 +52,49 @@ public void selectMutationOpensTheClassAtTheRightLineNumber() throws CoreExcepti pitclipseSteps.doubleClickMutationInMutationsView(mutation); pitclipseSteps.mutationIsOpened(BAR_CLASS + ".java", 7); } + + @Test + public void checkForExistingMutationMarkers() throws CoreException { + runPackageTest(FOO_BAR_PACKAGE, TEST_PROJECT); + coverageReportGenerated(2, 80, 0, 6, 0); + bot.waitUntil(new DefaultCondition() { + @Override + public boolean test() throws Exception { + return getPitclipseMarker().length > 0; + } + @Override + public String getFailureMessage() { + return "No pitclipse marker were found!"; + } + }); + IMarker[] marker = getPitclipseMarker(); + assertEquals(6, marker.length); + int numberOfKilled = 0, numberOfSurvived = 0, numberOfNoCoverage = 0, numberOfOthers = 0; + for (IMarker iMarker : marker) { + switch (iMarker.getType()) { + case PitclipseMutantMarkerFactory.KILLED_MUTANT_MARKER: + numberOfKilled++; + break; + case PitclipseMutantMarkerFactory.SURVIVING_MUTANT_MARKER: + numberOfSurvived++; + break; + case PitclipseMutantMarkerFactory.NO_COVERAGE_MUTANT_MARKER: + numberOfNoCoverage++; + break; + default: + numberOfOthers++; + break; + } + } + assertEquals(0, numberOfKilled); + assertEquals(2, numberOfSurvived); + assertEquals(4, numberOfNoCoverage); + assertEquals(0, numberOfOthers); + } + + private IMarker[] getPitclipseMarker() throws CoreException { + return ResourcesPlugin.getWorkspace().getRoot().findMarkers( + PitclipseMutantMarkerFactory.PITCLIPSE_MUTANT_MARKER, true, + IResource.DEPTH_INFINITE); + } } From 6eef24c7ed6605e3b86933d64bc479298c02dd99 Mon Sep 17 00:00:00 2001 From: Jonas Kutscha Date: Mon, 30 Aug 2021 13:27:18 +0200 Subject: [PATCH 7/7] Don't show task view, because it kills other tests --- .../marker/PitclipseMutantMarkerFactory.java | 23 +------------------ 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/mutation/marker/PitclipseMutantMarkerFactory.java b/bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/mutation/marker/PitclipseMutantMarkerFactory.java index 4c744043..4ac00ada 100644 --- a/bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/mutation/marker/PitclipseMutantMarkerFactory.java +++ b/bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/mutation/marker/PitclipseMutantMarkerFactory.java @@ -32,11 +32,6 @@ import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; -import org.eclipse.swt.widgets.Display; -import org.eclipse.ui.IViewPart; -import org.eclipse.ui.IWorkbenchPage; -import org.eclipse.ui.PartInitException; -import org.eclipse.ui.PlatformUI; import org.pitest.pitclipse.core.extension.point.ResultNotifier; import org.pitest.pitclipse.runner.model.ClassMutations; import org.pitest.pitclipse.runner.model.Mutation; @@ -87,30 +82,14 @@ public class PitclipseMutantMarkerFactory implements ResultNotifierrun error mutants */ public static final String RUN_ERROR_MARKER = PitUiActivator.PLUGIN_ID + ".runError"; - /** - * Id of the task view from Eclipse - */ - private static final String TASKS_VIEW_ID = "org.eclipse.ui.views.TaskList"; - /** - * Uses the results to create a marker for each mutant and shows the task view - * of Eclipse + * Uses the results to create a marker for each mutant * @param results from pit which holds the information about the mutants */ @Override public void handleResults(MutationsModel results) { createMarkers(results); - // open and show tasks view after the marker are created - Display.getDefault().asyncExec(() -> { - try { - IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); - IViewPart view = page.showView(TASKS_VIEW_ID); - page.activate(view); - } catch (PartInitException e) { - throw new RuntimeException("Could not show task view.", e); - } - }); } /**