Skip to content

Commit 74e8984

Browse files
committed
Fix CoverageService: only analyze classes present in exec data to avoid duplicate class errors
1 parent 6c65e10 commit 74e8984

2 files changed

Lines changed: 69 additions & 10 deletions

File tree

  • plugins/com.github.gradusnikov.eclipse.plugin.assistai.main/src/com/github/gradusnikov/eclipse/assistai/mcp/services
  • tests/com.github.gradusnikov.eclipse.plugin.assistai.main.tests/src/com/github/gradusnikov/eclipse/plugin/assistai/mcp/services

plugins/com.github.gradusnikov.eclipse.plugin.assistai.main/src/com/github/gradusnikov/eclipse/assistai/mcp/services/CoverageService.java

Lines changed: 66 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,17 @@
66
import java.nio.file.Files;
77
import java.nio.file.Path;
88
import java.util.ArrayList;
9+
import java.util.HashSet;
910
import java.util.List;
11+
import java.util.Set;
12+
import java.util.stream.Collectors;
1013

1114
import org.eclipse.core.resources.IProject;
1215
import org.eclipse.core.resources.ResourcesPlugin;
1316
import org.eclipse.core.runtime.ILog;
1417
import org.eclipse.core.runtime.Platform;
1518
import org.eclipse.e4.core.di.annotations.Creatable;
19+
import org.eclipse.jdt.core.IClasspathEntry;
1620
import org.eclipse.jdt.core.IJavaProject;
1721
import org.eclipse.jdt.core.JavaCore;
1822
import org.jacoco.core.analysis.Analyzer;
@@ -188,22 +192,77 @@ private String analyzeCoverage( String execFilePath, String projectName ) throws
188192
reader.read();
189193
}
190194

195+
Set<String> executedClassNames = executionDataStore.getContents().stream()
196+
.map( data -> data.getName() )
197+
.collect( Collectors.toSet() );
198+
199+
if ( executedClassNames.isEmpty() )
200+
{
201+
return "\n--- Coverage ---\nNo execution data found in coverage file.\n";
202+
}
203+
191204
CoverageBuilder coverageBuilder = new CoverageBuilder();
192205
Analyzer analyzer = new Analyzer( executionDataStore, coverageBuilder );
193206

207+
List<File> outputLocations = new ArrayList<>();
194208
IProject[] allProjects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
195209
for ( IProject project : allProjects )
196210
{
197-
if ( !project.isOpen() || !project.hasNature( JavaCore.NATURE_ID ) )
211+
try
212+
{
213+
if ( !project.isOpen() || !project.hasNature( JavaCore.NATURE_ID ) )
214+
{
215+
continue;
216+
}
217+
IJavaProject javaProject = JavaCore.create( project );
218+
Set<File> projectOutputs = new HashSet<>();
219+
File defaultOutput = project.getLocation().append(
220+
javaProject.getOutputLocation().removeFirstSegments( 1 ) ).toFile();
221+
projectOutputs.add( defaultOutput );
222+
for ( IClasspathEntry entry : javaProject.getResolvedClasspath( true ) )
223+
{
224+
if ( entry.getEntryKind() == IClasspathEntry.CPE_SOURCE && entry.getOutputLocation() != null )
225+
{
226+
File entryOutput = project.getLocation().append(
227+
entry.getOutputLocation().removeFirstSegments( 1 ) ).toFile();
228+
projectOutputs.add( entryOutput );
229+
}
230+
}
231+
for ( File output : projectOutputs )
232+
{
233+
if ( output.exists() )
234+
{
235+
outputLocations.add( output );
236+
}
237+
}
238+
}
239+
catch ( Exception e )
198240
{
199-
continue;
241+
// skip projects that can't be resolved
200242
}
201-
IJavaProject javaProject = JavaCore.create( project );
202-
File outputLocation = project.getLocation().append(
203-
javaProject.getOutputLocation().removeFirstSegments( 1 ) ).toFile();
204-
if ( outputLocation.exists() )
243+
}
244+
245+
for ( String className : executedClassNames )
246+
{
247+
String classFilePath = className.replace( '/', File.separatorChar ) + ".class";
248+
for ( File outputLocation : outputLocations )
205249
{
206-
analyzer.analyzeAll( outputLocation );
250+
File classFile = new File( outputLocation, classFilePath );
251+
if ( classFile.exists() )
252+
{
253+
try ( FileInputStream fis = new FileInputStream( classFile ) )
254+
{
255+
analyzer.analyzeAll( fis, className );
256+
}
257+
catch ( Exception e )
258+
{
259+
if ( logger != null )
260+
{
261+
logger.warn( "Skipping class '" + className + "': " + e.getMessage() );
262+
}
263+
}
264+
break;
265+
}
207266
}
208267
}
209268

tests/com.github.gradusnikov.eclipse.plugin.assistai.main.tests/src/com/github/gradusnikov/eclipse/plugin/assistai/mcp/services/CoverageServiceTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ public void testFindLatestCoverageFile_returnsNullOrPath()
282282

283283
@Test
284284
@Order( 9 )
285-
public void testFormatCoverageInfo_withValidExecFile_andProject_returnsCoverageReport() throws Exception
285+
public void testFormatCoverageInfo_withEmptyExecFile_andProject_returnsNoDataMessage() throws Exception
286286
{
287287
assumeTrue( coverageService.isCoverageAvailable(),
288288
"Skipping: EclEmma/JaCoCo not installed" );
@@ -297,8 +297,8 @@ public void testFormatCoverageInfo_withValidExecFile_andProject_returnsCoverageR
297297
try
298298
{
299299
String result = coverageService.formatCoverageInfo( tempExec.toString(), TEST_PROJECT_NAME );
300-
assertTrue( result.contains( "--- Coverage Report ---" ) );
301-
assertTrue( result.contains( "All classes fully covered." ) || result.contains( "Classes with incomplete coverage:" ) );
300+
assertTrue( result.contains( "--- Coverage ---" ) );
301+
assertTrue( result.contains( "No execution data found" ) );
302302
}
303303
finally
304304
{

0 commit comments

Comments
 (0)