Download
Getting Started
Members
Projects
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
More
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
Toggle navigation
Bugzilla – Attachment 239512 Details for
Bug 372588
[JUnit] Add "Link with Editor" to JUnit view
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
Log In
[x]
|
Terms of Use
|
Copyright Agent
[patch]
Second patch with full implementation
0001-Bug-372588-JUnit-Add-Link-with-Editor-to-JUnit-view.patch (text/plain), 20.86 KB, created by
Xavier Coulon
on 2014-01-31 04:43:51 EST
(
hide
)
Description:
Second patch with full implementation
Filename:
MIME Type:
Creator:
Xavier Coulon
Created:
2014-01-31 04:43:51 EST
Size:
20.86 KB
patch
obsolete
>From 6432459427a5bad3f2da062b53b393f51c5c616d Mon Sep 17 00:00:00 2001 >From: Xavier Coulon <xcoulon@redhat.com> >Date: Mon, 9 Sep 2013 15:31:37 +0200 >Subject: [PATCH] Bug 372588 - [JUnit] Add 'Link with Editor' to JUnit view > >Adding a toggle action to enable/disable 'Link with Editor' (disabled by default) >When 'Linking with editor' is enabled, an inner IPartListener2 is added to the active page >When the editor selection changes (user switching to another Java editor or moving selection in >another method of the same Test class), the selection in the TestViewer is updated accordingly (if necessary). >Likewise, when the selection in the TestViewer changes, the Java Editor containing the test method is selected >(if it has been opened before) and the test method is selected. > >Signed-off-by: Xavier Coulon <xcoulon@redhat.com> >--- > .../jdt/internal/junit/ui/TestRunnerViewPart.java | 317 ++++++++++++++++++++- > .../eclipse/jdt/internal/junit/ui/TestViewer.java | 48 ++++ > 2 files changed, 363 insertions(+), 2 deletions(-) > >diff --git a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/TestRunnerViewPart.java b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/TestRunnerViewPart.java >index ccf104e..2af35cf 100644 >--- a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/TestRunnerViewPart.java >+++ b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/TestRunnerViewPart.java >@@ -71,6 +71,7 @@ import org.eclipse.core.commands.IHandler; > > import org.eclipse.core.runtime.Assert; > import org.eclipse.core.runtime.CoreException; >+import org.eclipse.core.runtime.IPath; > import org.eclipse.core.runtime.IProgressMonitor; > import org.eclipse.core.runtime.IStatus; > import org.eclipse.core.runtime.Platform; >@@ -79,6 +80,8 @@ import org.eclipse.core.runtime.jobs.ILock; > import org.eclipse.core.runtime.jobs.Job; > import org.eclipse.core.runtime.preferences.InstanceScope; > >+import org.eclipse.core.resources.IFile; >+ > import org.eclipse.jface.action.Action; > import org.eclipse.jface.action.IAction; > import org.eclipse.jface.action.IMenuListener; >@@ -96,10 +99,18 @@ import org.eclipse.jface.dialogs.InputDialog; > import org.eclipse.jface.dialogs.MessageDialog; > import org.eclipse.jface.operation.IRunnableWithProgress; > import org.eclipse.jface.resource.ImageDescriptor; >+import org.eclipse.jface.viewers.IPostSelectionProvider; >+import org.eclipse.jface.viewers.ISelection; >+import org.eclipse.jface.viewers.ISelectionChangedListener; >+import org.eclipse.jface.viewers.ISelectionProvider; >+import org.eclipse.jface.viewers.SelectionChangedEvent; >+ >+import org.eclipse.jface.text.ITextSelection; > > import org.eclipse.ui.IActionBars; > import org.eclipse.ui.IEditorActionBarContributor; > import org.eclipse.ui.IEditorPart; >+import org.eclipse.ui.IEditorReference; > import org.eclipse.ui.IMemento; > import org.eclipse.ui.IPartListener2; > import org.eclipse.ui.IViewPart; >@@ -115,6 +126,7 @@ import org.eclipse.ui.actions.ActionFactory; > import org.eclipse.ui.handlers.IHandlerActivation; > import org.eclipse.ui.handlers.IHandlerService; > import org.eclipse.ui.part.EditorActionBarContributor; >+import org.eclipse.ui.part.FileEditorInput; > import org.eclipse.ui.part.PageSwitcher; > import org.eclipse.ui.part.ViewPart; > import org.eclipse.ui.progress.IWorkbenchSiteProgressService; >@@ -128,11 +140,16 @@ import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; > import org.eclipse.debug.ui.DebugUITools; > > import org.eclipse.jdt.core.ElementChangedEvent; >+import org.eclipse.jdt.core.IClasspathEntry; >+import org.eclipse.jdt.core.ICompilationUnit; > import org.eclipse.jdt.core.IElementChangedListener; > import org.eclipse.jdt.core.IJavaElement; > import org.eclipse.jdt.core.IJavaElementDelta; > import org.eclipse.jdt.core.IJavaProject; >+import org.eclipse.jdt.core.IMethod; >+import org.eclipse.jdt.core.IType; > import org.eclipse.jdt.core.JavaCore; >+import org.eclipse.jdt.core.JavaModelException; > > import org.eclipse.jdt.internal.junit.BasicElementLabels; > import org.eclipse.jdt.internal.junit.JUnitCorePlugin; >@@ -149,6 +166,10 @@ import org.eclipse.jdt.internal.junit.model.TestRunSession; > > import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants; > >+import org.eclipse.jdt.ui.JavaUI; >+ >+import org.eclipse.jdt.internal.ui.actions.AbstractToggleLinkingAction; >+import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor; > import org.eclipse.jdt.internal.ui.viewsupport.ViewHistory; > > /** >@@ -210,6 +231,9 @@ public class TestRunnerViewPart extends ViewPart { > private Action fPreviousAction; > > private StopAction fStopAction; >+ >+ private LinkWithEditorAction fLinkWithEditorAction; >+ > private JUnitCopyAction fCopyAction; > private Action fPasteAction; > >@@ -342,7 +366,6 @@ public class TestRunnerViewPart extends ViewPart { > > protected boolean fPartIsVisible= false; > >- > private class RunnerViewHistory extends ViewHistory<TestRunSession> { > > @Override >@@ -705,6 +728,8 @@ public class TestRunnerViewPart extends ViewPart { > startUpdateJobs(); > > fStopAction.setEnabled(true); >+ fLinkWithEditorAction.setEnabled(true); >+ > fRerunLastTestAction.setEnabled(true); > } > >@@ -722,6 +747,7 @@ public class TestRunnerViewPart extends ViewPart { > if (isDisposed()) > return; > fStopAction.setEnabled(lastLaunchIsKeptAlive()); >+ fLinkWithEditorAction.setEnabled(fTestRunSession != null); > updateRerunFailedFirstAction(); > processChangesInUI(); > if (hasErrorsOrFailures()) { >@@ -899,6 +925,14 @@ public class TestRunnerViewPart extends ViewPart { > } > } > >+ private class LinkWithEditorAction extends AbstractToggleLinkingAction { >+ >+ @Override >+ public void run() { >+ setLinkingEnabled(isChecked()); >+ } >+ } >+ > private class RerunLastAction extends Action { > public RerunLastAction() { > setText(JUnitMessages.TestRunnerViewPart_rerunaction_label); >@@ -1200,6 +1234,178 @@ public class TestRunnerViewPart extends ViewPart { > } > } > >+ /** >+ * Links the selected test method with the Java Editor >+ * @param enabled boolean to indicate if the link with editor is enabled (<code>true</code>) or not (<code>false</code>) >+ */ >+ public void setLinkingEnabled(boolean enabled) { >+ final IWorkbenchPage page = getSite().getPage(); >+ if(page == null) { >+ return; >+ } >+ if (enabled) { >+ // add an IPartListener for future editor activations/opening/closing/etc. >+ page.addPartListener(fLinkWithEditorPartListener); >+ } else { >+ // removes the IPartListener >+ page.removePartListener(fLinkWithEditorPartListener); >+ } >+ for(IEditorReference editorReference : page.getEditorReferences()) { >+ final IEditorPart editor = editorReference.getEditor(false); >+ // set the current editor as active as well >+ if (editor != null && enabled) { >+ editorActivated(editor); >+ } >+ // unset the current editor as active as well >+ else if(editor != null && !enabled){ >+ editorDeactivated(editor); >+ } >+ } >+ } >+ >+ >+ private final IPartListener2 fLinkWithEditorPartListener= new IPartListener2() { >+ public void partVisible(IWorkbenchPartReference partRef) {} >+ public void partBroughtToTop(IWorkbenchPartReference partRef) {} >+ public void partHidden(IWorkbenchPartReference partRef) {} >+ public void partOpened(IWorkbenchPartReference partRef) {} >+ public void partInputChanged(IWorkbenchPartReference partRef) {} >+ public void partClosed(IWorkbenchPartReference partRef) {} >+ >+ public void partActivated(IWorkbenchPartReference partRef) { >+ if (partRef instanceof IEditorReference) { >+ editorActivated(((IEditorReference) partRef).getEditor(true)); >+ } >+ } >+ >+ public void partDeactivated(IWorkbenchPartReference partRef) { >+ if (partRef instanceof IEditorReference) { >+ editorDeactivated(((IEditorReference) partRef).getEditor(true)); >+ } >+ } >+ >+ }; >+ >+ /** >+ * Static Inner Java Editor selection listener >+ * When the user moves to another >+ */ >+ private class JavaEditorSelectionListener implements ISelectionChangedListener { >+ >+ private final ICompilationUnit compilationUnit; >+ >+ JavaEditorSelectionListener(final ICompilationUnit compilationUnit) { >+ this.compilationUnit = compilationUnit; >+ } >+ >+ public void selectionChanged(final SelectionChangedEvent event) { >+ selectActiveTestCaseElement(event.getSelection()); >+ } >+ >+ private IJavaElement getActiveJavaElement(final ISelection selection) { >+ if(selection instanceof ITextSelection) { >+ final int offset= ((ITextSelection)selection).getOffset(); >+ try { >+ return compilationUnit.getElementAt(offset); >+ } catch (JavaModelException e) { >+ JUnitPlugin.log(e); >+ } >+ } >+ return null; >+ } >+ >+ public void selectActiveTestCaseElement(final ISelection selection) { >+ final IJavaElement activeJavaElement = getActiveJavaElement(selection); >+ // select the method in the JUnit ViewPart >+ if(activeJavaElement != null && activeJavaElement.getElementType() == IJavaElement.METHOD) { >+ final IMethod activeJavaMethod = (IMethod)activeJavaElement; >+ final IType activeJavaType = (IType)activeJavaMethod.getAncestor(IJavaElement.TYPE); >+ fTestViewer.selectTestCaseElement(activeJavaType.getFullyQualifiedName(), activeJavaMethod.getElementName()); >+ } >+ >+ } >+ >+ /** >+ * Overriding java.lang.Object#hashCode() using the >+ * {@link ICompilationUnit#getHandleIdentifier()} value to avoid duplicate listener >+ * registrations in the {@link JavaEditor}'s {@link IPostSelectionProvider}. >+ */ >+ @Override >+ public int hashCode() { >+ final int prime= 31; >+ int result= 1; >+ result= prime * result + ((compilationUnit == null) ? 0 : compilationUnit.getHandleIdentifier().hashCode()); >+ return result; >+ } >+ >+ /** >+ * Overriding java.lang.Object#equals() using the >+ * {@link ICompilationUnit#getHandleIdentifier()} value to avoid duplicate listener >+ * registrations in the {@link JavaEditor}'s {@link IPostSelectionProvider}. >+ */ >+ @Override >+ public boolean equals(Object obj) { >+ if (this == obj) { >+ return true; >+ } >+ if (obj == null) { >+ return false; >+ } >+ if (getClass() != obj.getClass()) { >+ return false; >+ } >+ JavaEditorSelectionListener other= (JavaEditorSelectionListener)obj; >+ if (compilationUnit == null) { >+ if (other.compilationUnit != null) { >+ return false; >+ } >+ } else if (!compilationUnit.getHandleIdentifier().equals(other.compilationUnit.getHandleIdentifier())) { >+ return false; >+ } >+ return true; >+ } >+ >+ >+ } >+ >+ private JavaEditorSelectionListener fJavaEditorSelectionListener; >+ >+ /** >+ * An editor has been activated. Set the selection in this JUnit ViewPart >+ * to match the editor's input, if linking is enabled. >+ * @param editor the activated editor >+ */ >+ private void editorActivated(IEditorPart editor) { >+ if(!(editor instanceof JavaEditor)) { >+ return; >+ } >+ final ISelectionProvider selectionProvider = ((JavaEditor)editor).getSelectionProvider(); >+ final Object input= JavaUI.getEditorInputJavaElement(editor.getEditorInput()); >+ if (input instanceof ICompilationUnit && selectionProvider instanceof IPostSelectionProvider) { >+ final ICompilationUnit unit = (ICompilationUnit) input; >+ final IPostSelectionProvider postSelectionProvider = (IPostSelectionProvider)selectionProvider; >+ fJavaEditorSelectionListener = new JavaEditorSelectionListener(unit); >+ postSelectionProvider.addPostSelectionChangedListener(fJavaEditorSelectionListener); >+ fJavaEditorSelectionListener.selectActiveTestCaseElement(selectionProvider.getSelection()); >+ } >+ } >+ >+ /** >+ * An editor has been deactivated. >+ * @param editor the activated editor >+ */ >+ private void editorDeactivated(IEditorPart editor) { >+ if(!(editor instanceof JavaEditor)) { >+ return; >+ } >+ final ISelectionProvider selectionProvider = ((JavaEditor)editor).getSelectionProvider(); >+ if (selectionProvider instanceof IPostSelectionProvider) { >+ final IPostSelectionProvider postSelectionProvider = (IPostSelectionProvider)selectionProvider; >+ postSelectionProvider.removePostSelectionChangedListener(fJavaEditorSelectionListener); >+ } >+ } >+ >+ > private void startUpdateJobs() { > postSyncProcessChanges(); > >@@ -1507,11 +1713,13 @@ action enablement > startUpdateJobs(); > > fStopAction.setEnabled(true); >+ fLinkWithEditorAction.setEnabled(true); > > } else /* old or fresh session: don't want jobs at this stage */ { > stopUpdateJobs(); > > fStopAction.setEnabled(fTestRunSession.isKeptAlive()); >+ fLinkWithEditorAction.setEnabled(fTestRunSession != null); > fTestViewer.expandFirstLevel(); > } > } >@@ -1887,6 +2095,9 @@ action enablement > fStopAction= new StopAction(); > fStopAction.setEnabled(false); > >+ fLinkWithEditorAction= new LinkWithEditorAction(); >+ fLinkWithEditorAction.setEnabled(false); >+ > fRerunLastTestAction= new RerunLastAction(); > IHandlerService handlerService= (IHandlerService) getSite().getWorkbenchWindow().getService(IHandlerService.class); > IHandler handler = new AbstractHandler() { >@@ -1937,7 +2148,9 @@ action enablement > toolBar.add(fRerunFailedFirstAction); > toolBar.add(fStopAction); > toolBar.add(fViewHistory.createHistoryDropDownAction()); >- >+ toolBar.add(new Separator()); >+ toolBar.add(fLinkWithEditorAction); >+ > > viewMenu.add(fShowTestHierarchyAction); > viewMenu.add(fShowTimeAction); >@@ -2007,6 +2220,106 @@ action enablement > public void handleTestSelected(TestElement test) { > showFailure(test); > fCopyAction.handleTestSelected(test); >+ // if LinkWithEditor is active, reveal the JavaEditor and select the java method >+ // matching the selected test element, even if the JavaEditor is opened by not active. >+ if(fLinkWithEditorAction.isChecked() && test instanceof TestCaseElement) { >+ try { >+ final TestCaseElement testCaseElement= (TestCaseElement)test; >+ for (IEditorReference editorReference : PlatformUI.getWorkbench().getActiveWorkbenchWindow() >+ .getActivePage().getEditorReferences()) { >+ final IEditorPart editor = editorReference.getEditor(true); >+ final IMethod selectedMethod = findSelectedMethodInEditor(editor, testCaseElement); >+ if(selectedMethod != null) { >+ JavaUI.openInEditor(selectedMethod, false, true); >+ break; >+ } >+ } >+ } catch(JavaModelException e) { >+ JUnitPlugin.log(e); >+ } catch(PartInitException e) { >+ JUnitPlugin.log(e); >+ } >+ } >+ } >+ >+ >+ /** >+ * Finds and returns the selected {@link IMethod} matching the given {@link TestCaseElement} in >+ * the given {@link IEditorPart} (if this later is a {@link JavaEditor}), or returns null if the >+ * editor is not a {@link JavaEditor} or is not opened on the expected {@link ICompilationUnit}. >+ * >+ * @param editor the editor to inspect >+ * @param test the selected test case element >+ * @return the corresponding Java method element or null >+ * @throws JavaModelException if the inspection of one of the java elements in the given editor failed. >+ */ >+ private IMethod findSelectedMethodInEditor(IEditorPart editor, TestCaseElement test) throws JavaModelException { >+ final String editorClassName = getJavaEditorClassName(editor); >+ final String testMethodName= getTestMethodName(test); >+ if(test.getClassName().equals(editorClassName)) { >+ final IJavaElement editorInputJavaElement= JavaUI.getEditorInputJavaElement(editor.getEditorInput()); >+ if (editorInputJavaElement.getElementType() == IJavaElement.COMPILATION_UNIT) { >+ for (IType type : ((ICompilationUnit)editorInputJavaElement).getTypes()) { >+ if (type.getFullyQualifiedName().equals(test.getClassName())) { >+ for (IMethod method : type.getMethods()) { >+ if (method.getElementName().equals(testMethodName)) { >+ return method; >+ } >+ } >+ } >+ } >+ } >+ } >+ return null; >+ } >+ >+ /** >+ * @return the fully qualified name of the Java class opened by the editor if it is a JavaEditor, null otherwise. >+ * @param editor the editor to inspect >+ */ >+ private String getJavaEditorClassName(final IEditorPart editor) { >+ if(editor instanceof JavaEditor && editor.getEditorInput() instanceof FileEditorInput) { >+ final JavaEditor javaEditor = (JavaEditor)editor; >+ return getEditorClassName(javaEditor); >+ } >+ return null; >+ } >+ >+ /** >+ * @return the name of the Java method associated with this test. >+ * @param test the selected unit test >+ */ >+ private String getTestMethodName(TestCaseElement test) { >+ final String testMethodName = test.getTestMethodName(); >+ // parameterized tests show an index that should be removed from the name >+ final int index = testMethodName.indexOf('['); >+ if(index != -1) { >+ return testMethodName.substring(0, index); >+ } >+ return testMethodName; >+ } >+ >+ /** >+ * @return the Java classname associated with the file opened in the given {@link JavaEditor}. >+ * @param javaEditor the javaEditor in which the file is opened. >+ */ >+ private String getEditorClassName(final JavaEditor javaEditor) { >+ try { >+ final FileEditorInput editorInput = (FileEditorInput)javaEditor.getEditorInput(); >+ final IFile inputFile = editorInput.getFile(); >+ IPath inputFilePath = inputFile.getFullPath(); >+ IJavaProject javaProject = JavaCore.create(inputFile.getProject()); >+ for(IClasspathEntry classpathEntry: javaProject.getRawClasspath()) { >+ if(classpathEntry.getEntryKind() == IClasspathEntry.CPE_SOURCE && classpathEntry.getPath().isPrefixOf(inputFilePath)) { >+ IPath sourcePath = inputFilePath.makeRelativeTo(classpathEntry.getPath()); >+ String sourceClassName= sourcePath.removeFileExtension().toOSString().replaceAll("/", "."); //$NON-NLS-1$ //$NON-NLS-2$ >+ return sourceClassName; >+ } >+ } >+ } catch (JavaModelException e) { >+ JUnitPlugin.log(e); >+ } >+ return null; > } > > private void showFailure(final TestElement test) { >diff --git a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/TestViewer.java b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/TestViewer.java >index e050d66..2d6c576 100644 >--- a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/TestViewer.java >+++ b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/TestViewer.java >@@ -21,7 +21,9 @@ import java.util.LinkedList; > import java.util.List; > import java.util.ListIterator; > >+import org.eclipse.jdt.junit.model.ITestCaseElement; > import org.eclipse.jdt.junit.model.ITestElement; >+import org.eclipse.jdt.junit.model.ITestSuiteElement; > > import org.eclipse.swt.SWT; > import org.eclipse.swt.dnd.Clipboard; >@@ -38,6 +40,7 @@ import org.eclipse.jface.action.IMenuManager; > import org.eclipse.jface.action.MenuManager; > import org.eclipse.jface.action.Separator; > import org.eclipse.jface.viewers.AbstractTreeViewer; >+import org.eclipse.jface.viewers.ISelection; > import org.eclipse.jface.viewers.ISelectionChangedListener; > import org.eclipse.jface.viewers.IStructuredSelection; > import org.eclipse.jface.viewers.SelectionChangedEvent; >@@ -568,6 +571,51 @@ public class TestViewer { > fTreeViewer.reveal(current); > } > >+ /** >+ * Selects and reveals the given {@link ITestCaseElement} in the viewer's tree. >+ * @param testClassName the qualified class name of the test to select >+ * @param testMethodName the method name of the test to select >+ */ >+ public void selectTestCaseElement(final String testClassName, final String testMethodName) { >+ // skip if history was cleared and 'Link with Editor' is still enabled. >+ if(fTestRunSession == null) { >+ return; >+ } >+ final TestRoot testRoot = fTestRunSession.getTestRoot(); >+ final ISelection currentSelection= getActiveViewer().getSelection(); >+ if(currentSelection instanceof IStructuredSelection) { >+ for(Object selectedItem : ((IStructuredSelection)currentSelection).toList()) { >+ if(selectedItem instanceof TestCaseElement && ((TestCaseElement)selectedItem).getTestClassName().equals(testClassName) >+ && ((TestCaseElement)selectedItem).getTestMethodName().equals(testMethodName)) { >+ // the current selection in the TestViewer includes the given test class/method >+ return; >+ } >+ } >+ } >+ final ITestCaseElement activeTestCaseElement = findTestCaseElement(testRoot, testClassName, testMethodName); >+ if(activeTestCaseElement != null) { >+ getActiveViewer().setSelection(new StructuredSelection(activeTestCaseElement), true); >+ } >+ } >+ >+ private ITestCaseElement findTestCaseElement(final ITestSuiteElement parentElement, final String testClassName, final String testMethodName) { >+ for(ITestElement childElement : parentElement.getChildren()) { >+ if(childElement instanceof ITestCaseElement) { >+ ITestCaseElement testCaseElement = (ITestCaseElement)childElement; >+ if(testCaseElement.getTestClassName().equals(testClassName) && testCaseElement.getTestMethodName().equals(testMethodName)) { >+ return testCaseElement; >+ } >+ } else if(childElement instanceof ITestSuiteElement) { >+ final ITestCaseElement localResult= findTestCaseElement((ITestSuiteElement)childElement, testClassName, testMethodName); >+ if(localResult != null) { >+ return localResult; >+ } >+ } >+ } >+ return null; >+ >+ } >+ > public void selectFirstFailure() { > TestCaseElement firstFailure= getNextChildFailure(fTestRunSession.getTestRoot(), true); > if (firstFailure != null) >-- >1.7.12.4 (Apple Git-37) >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Flags:
manju656
:
review-
Actions:
View
|
Diff
Attachments on
bug 372588
:
235306
|
239512
|
239779
|
239813
|
240197
|
240412
|
241975
|
242004
|
248907
|
248908
|
248945
|
249171
|
251221
|
251985
|
252025