Skip to content
Merged
Show file tree
Hide file tree
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 @@ -3,11 +3,19 @@
import static java.util.Collections.emptySet;

import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jdt.core.Flags;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.ITypeHierarchy;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.search.IJavaSearchScope;
import org.moreunit.log.LogHandler;
import org.moreunit.preferences.Preferences;
Expand All @@ -26,6 +34,7 @@
*/
public class CorrespondingTypeSearcher
{
private final IType type;
private final ProjectPreferences preferences;
private final ClassNameEvaluation nameEvaluation;
private final IJavaSearchScope searchScope;
Expand All @@ -34,11 +43,12 @@ public class CorrespondingTypeSearcher

public CorrespondingTypeSearcher(ICompilationUnit compilationUnit, Preferences preferences)
{
this.type = compilationUnit.findPrimaryType();
this.preferences = preferences.getProjectView(compilationUnit.getJavaProject());
nameEvaluation = this.preferences.getTestClassNamePattern().evaluate(compilationUnit.findPrimaryType());
nameEvaluation = this.preferences.getTestClassNamePattern().evaluate(this.type);
IPackageFragmentRoot sourceFolder = nameEvaluation.isTestCase()
? preferences.getTestSourceFolder(compilationUnit.getJavaProject(), PluginTools.getSourceFolder(compilationUnit))
: preferences.getMainSourceFolder(compilationUnit.getJavaProject(), PluginTools.getSourceFolder(compilationUnit));
: this.preferences.getMainSourceFolder(PluginTools.getSourceFolder(compilationUnit));
searchScope = SearchScopeSingelton.getInstance().getSearchScope(sourceFolder);
}

Expand Down Expand Up @@ -74,6 +84,109 @@ public Collection<IType> getMatches(boolean alsoIncludeLikelyMatches)
private Collection<IType> findPotentialTargets(boolean withLikelyMatches) throws CoreException
{
boolean qualifyWithPackage = ! withLikelyMatches;
return SearchTools.searchFor(nameEvaluation.getAllCorrespondingClassPatterns(qualifyWithPackage), searchScope);
Set<String> patterns = new LinkedHashSet<>(nameEvaluation.getAllCorrespondingClassPatterns(qualifyWithPackage));

Set<IType> matches = SearchTools.searchFor(patterns, searchScope);

if(matches.size() == 1 && ! matches.iterator().next().isInterface())
{
return matches;
}

if(type != null && ! nameEvaluation.isTestCase())
{
try
{
ITypeHierarchy hierarchy = type.newTypeHierarchy(new NullProgressMonitor());
for (IType superType : hierarchy.getAllSupertypes(type))
{
if(! superType.getFullyQualifiedName().startsWith("java.lang."))
{
ClassNameEvaluation superEval = preferences.getTestClassNamePattern().evaluate(superType);
patterns.addAll(superEval.getAllCorrespondingClassPatterns(qualifyWithPackage));
}
}

if(type.isInterface() || Flags.isAbstract(type.getFlags()))
{
IType[] subtypes = hierarchy.getAllSubtypes(type);
for (IType subType : subtypes)
{
if(! Flags.isAbstract(subType.getFlags()) && ! subType.isInterface())
{
ClassNameEvaluation subEval = preferences.getTestClassNamePattern().evaluate(subType);
patterns.addAll(subEval.getAllCorrespondingClassPatterns(qualifyWithPackage));
}
}
}
}
catch (JavaModelException e)
{
LogHandler.getInstance().handleExceptionLog(e);
}
}

matches = SearchTools.searchFor(patterns, searchScope);

if(nameEvaluation.isTestCase())
{
Set<IType> allMatches = new LinkedHashSet<>(matches);
Set<IType> concreteImplementations = new LinkedHashSet<>();
for (IType match : matches)
{
try
{
if(match.isInterface() || Flags.isAbstract(match.getFlags()))
{
concreteImplementations.addAll(SearchTools.findConcreteSubclasses(match));
}
}
catch (JavaModelException e)
{
// ignore
}
}

if(! concreteImplementations.isEmpty())
{
allMatches.addAll(concreteImplementations);

for (Iterator<IType> it = allMatches.iterator(); it.hasNext();)
{
IType match = it.next();
try
{
if((match.isInterface() || Flags.isAbstract(match.getFlags())) && ! hasImplementation(match))
{
it.remove();
}
}
catch (JavaModelException e)
{
// ignore
}
}
}

return allMatches;
}

return matches;
}

private boolean hasImplementation(IType type) throws JavaModelException
{
for (IMethod method : type.getMethods())
{
if(Flags.isDefaultMethod(method.getFlags()))
{
return true;
}
if(! Flags.isAbstract(method.getFlags()) && ! type.isInterface())
{
return true;
}
}
return false;
}
}
2 changes: 1 addition & 1 deletion org.moreunit.plugin/src/org/moreunit/util/SearchTools.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public static Set<IType> findConcreteSubclasses(IType type) throws JavaModelExce
return concreteSubclasses;
}

private static Set<IType> search(SearchPattern pattern, IJavaSearchScope scope) throws CoreException
public static Set<IType> search(SearchPattern pattern, IJavaSearchScope scope) throws CoreException
{
SearchParticipant[] participants = new SearchParticipant[] { SearchEngine.getDefaultSearchParticipant() };
MatchCollector collector = new MatchCollector();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package org.moreunit.matching;

import static org.assertj.core.api.Assertions.assertThat;

import java.util.Collection;

import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.junit.Test;
import org.moreunit.test.context.ContextTestCase;
import org.moreunit.test.context.Preferences;
import org.moreunit.test.context.Project;

@Preferences(testClassNameTemplate = "${srcFile}Test", testSrcFolder = "test")
public class InterfaceCorrespondingTypeSearcherTest extends ContextTestCase
{
@Project(mainCls = "class Foo", testCls = "FooTest")
@Test
public void getMatches_should_return_test_for_class()
{
CorrespondingTypeSearcher searcher = new CorrespondingTypeSearcher(context.getCompilationUnit("Foo"), getPreferences());
Collection<IType> matches = searcher.getMatches(false);

assertThat(matches).extracting("elementName").containsExactly("FooTest");
}

@Project(mainCls = "interface Foo", testCls = "FooTest")
@Test
public void getMatches_should_return_test_for_interface()
{
context.getPrimaryTypeHandler("Foo").createSubclass("FooImpl");

CorrespondingTypeSearcher searcher = new CorrespondingTypeSearcher(context.getCompilationUnit("Foo"), getPreferences());
Collection<IType> matches = searcher.getMatches(false);

assertThat(matches).extracting("elementName").containsExactly("FooTest");
}

@Project(mainCls = "interface Foo", testCls = "FooTest")
@Test
public void getMatches_should_return_implementation_for_interface_test_and_exclude_interface()
{
context.getPrimaryTypeHandler("Foo").createSubclass("FooImpl");

CorrespondingTypeSearcher searcher = new CorrespondingTypeSearcher(context.getCompilationUnit("FooTest"), getPreferences());
Collection<IType> matches = searcher.getMatches(false);

// Should return FooImpl and EXCLUDE Foo because Foo is a pure interface
assertThat(matches).extracting("elementName").containsExactly("FooImpl");
}

@Project(mainCls = "interface Foo", testCls = "FooTest")
@Test
public void getMatches_should_return_interface_test_for_implementation()
{
context.getPrimaryTypeHandler("Foo").createSubclass("FooImpl");

CorrespondingTypeSearcher searcher = new CorrespondingTypeSearcher(context.getCompilationUnit("FooImpl"), getPreferences());
Collection<IType> matches = searcher.getMatches(false);

assertThat(matches).extracting("elementName").contains("FooTest");
}

@Project(mainCls = "interface Foo")
@Test
public void getMatches_should_return_interface_for_implementation_test()
{
context.getPrimaryTypeHandler("Foo").createSubclass("FooImpl");
context.getProjectHandler().getTestSrcFolderHandler().createClass("FooImplTest");

CorrespondingTypeSearcher searcher = new CorrespondingTypeSearcher(context.getCompilationUnit("FooImplTest"), getPreferences());
Collection<IType> matches = searcher.getMatches(false);

assertThat(matches).extracting("elementName").containsExactly("FooImpl");
}

@Project(mainCls = "interface Foo", testCls = "FooTest")
@Test
public void getMatches_should_include_interface_if_it_has_default_method() throws JavaModelException
{
IType foo = context.getPrimaryTypeHandler("Foo").get();
foo.createMethod("default void bar() {}", null, true, null);
context.getPrimaryTypeHandler("Foo").createSubclass("FooImpl");

CorrespondingTypeSearcher searcher = new CorrespondingTypeSearcher(context.getCompilationUnit("FooTest"), getPreferences());
Collection<IType> matches = searcher.getMatches(false);

// Should return both Foo and FooImpl because Foo has a default method
assertThat(matches).extracting("elementName").containsExactlyInAnyOrder("Foo", "FooImpl");
}
}
Loading