/**
* Copyright (c) 2015 Codetrails GmbH.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Andreas Sewe - initial API and implementation.
*/
package org.eclipse.recommenders.internal.constructors.rcp;
import static org.eclipse.recommenders.testing.rcp.completion.SimpleProposalProcessorMatcher.processorWithBoostAndLabel;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyDouble;
import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.*;
import java.util.Collections;
import java.util.Map;
import javax.inject.Provider;
import org.eclipse.jdt.core.CompletionProposal;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.internal.codeassist.complete.CompletionOnArgumentName;
import org.eclipse.jdt.internal.codeassist.complete.CompletionOnSingleTypeReference;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.ui.text.java.IJavaCompletionProposal;
import org.eclipse.recommenders.completion.rcp.IProposalNameProvider;
import org.eclipse.recommenders.completion.rcp.IRecommendersCompletionContext;
import org.eclipse.recommenders.completion.rcp.processable.IProcessableProposal;
import org.eclipse.recommenders.completion.rcp.processable.OverlayImageProposalProcessor;
import org.eclipse.recommenders.completion.rcp.processable.ProcessableJavaCompletionProposal;
import org.eclipse.recommenders.completion.rcp.processable.ProposalProcessorManager;
import org.eclipse.recommenders.completion.rcp.processable.ProposalTag;
import org.eclipse.recommenders.constructors.ConstructorModel;
import org.eclipse.recommenders.constructors.IConstructorModelProvider;
import org.eclipse.recommenders.coordinates.ProjectCoordinate;
import org.eclipse.recommenders.models.UniqueTypeName;
import org.eclipse.recommenders.models.rcp.IProjectCoordinateProvider;
import org.eclipse.recommenders.rcp.SharedImages;
import org.eclipse.recommenders.utils.Nullable;
import org.eclipse.recommenders.utils.Result;
import org.eclipse.recommenders.utils.names.IMethodName;
import org.eclipse.recommenders.utils.names.ITypeName;
import org.eclipse.recommenders.utils.names.VmMethodName;
import org.eclipse.recommenders.utils.names.VmTypeName;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableMap;
@SuppressWarnings("restriction")
public class ConstructorCompletionSessionProcessorTest {
private static final ProjectCoordinate JRE_1_6_0 = new ProjectCoordinate("jre", "jre", "1.6.0");
private static final ITypeName OBJECT = VmTypeName.get("Ljava/lang/Object");
private static final IMethodName OBJECT_INIT = VmMethodName.get("Ljava/lang/Object.<init>()V");
private static final IMethodName STRING_INIT = VmMethodName.get("Ljava/lang/String.<init>()V");
private static final IType NO_TYPE = null;
private static final ConstructorModel NO_MODEL = null;
private final IType objectType = mock(IType.class);
private final IJavaCompletionProposal objectInitProposal = mock(IJavaCompletionProposal.class);
private final IJavaCompletionProposal stringInitProposal = mock(IJavaCompletionProposal.class);
private final CompletionProposal objectInitCoreProposal = mock(CompletionProposal.class);
private final CompletionProposal stringInitCoreProposal = mock(CompletionProposal.class);
private final IProcessableProposal objectInitProcessableProposal = mock(ProcessableJavaCompletionProposal.class);
private final IProcessableProposal stringInitProcessableProposal = mock(ProcessableJavaCompletionProposal.class);
private Provider<IProjectCoordinateProvider> pcMetaProvider;
private IConstructorModelProvider modelProvider;
private Provider<IConstructorModelProvider> modelMetaProvider;
private IProposalNameProvider methodNameProvider;
private IRecommendersCompletionContext context;
@Before
public void setUp() {
when(objectInitCoreProposal.getKind()).thenReturn(CompletionProposal.CONSTRUCTOR_INVOCATION);
when(stringInitCoreProposal.getKind()).thenReturn(CompletionProposal.CONSTRUCTOR_INVOCATION);
when(objectInitProcessableProposal.getCoreProposal()).thenReturn(Optional.of(objectInitCoreProposal));
when(stringInitProcessableProposal.getCoreProposal()).thenReturn(Optional.of(stringInitCoreProposal));
}
@Test
public void testUnsupportedCompletionLocation() {
setUpCompletionScenario(CompletionOnArgumentName.class, objectType,
ImmutableMap.of(objectInitProposal, objectInitCoreProposal));
setUpModelRepository(objectType, new UniqueTypeName(JRE_1_6_0, OBJECT),
new ConstructorModel(OBJECT, Collections.<IMethodName, Integer>emptyMap()));
ConstructorCompletionSessionProcessor sut = new ConstructorCompletionSessionProcessor(pcMetaProvider,
modelMetaProvider, methodNameProvider, createDefaultPreferences(), new SharedImages());
boolean shouldProcess = sut.startSession(context);
assertThat(shouldProcess, is(equalTo(false)));
verifyZeroInteractions(modelProvider);
}
@Test
public void testNoExpectedType() {
setUpCompletionScenario(CompletionOnSingleTypeReference.class, NO_TYPE,
ImmutableMap.of(objectInitProposal, objectInitCoreProposal));
setUpModelRepository(objectType, new UniqueTypeName(JRE_1_6_0, OBJECT),
new ConstructorModel(OBJECT, Collections.<IMethodName, Integer>emptyMap()));
ConstructorCompletionSessionProcessor sut = new ConstructorCompletionSessionProcessor(pcMetaProvider,
modelMetaProvider, methodNameProvider, createDefaultPreferences(), new SharedImages());
boolean shouldProcess = sut.startSession(context);
assertThat(shouldProcess, is(equalTo(false)));
verifyZeroInteractions(modelProvider);
}
@Test
public void testNoModelFound() {
setUpCompletionScenario(CompletionOnSingleTypeReference.class, objectType,
ImmutableMap.of(objectInitProposal, objectInitCoreProposal));
setUpModelRepository(objectType, new UniqueTypeName(JRE_1_6_0, OBJECT), NO_MODEL);
ConstructorCompletionSessionProcessor sut = new ConstructorCompletionSessionProcessor(pcMetaProvider,
modelMetaProvider, methodNameProvider, createDefaultPreferences(), new SharedImages());
boolean shouldProcess = sut.startSession(context);
assertThat(shouldProcess, is(equalTo(false)));
}
@Test
public void testNoRecommendations() {
setUpCompletionScenario(CompletionOnSingleTypeReference.class, objectType,
ImmutableMap.of(objectInitProposal, objectInitCoreProposal));
ConstructorModel model = new ConstructorModel(OBJECT, Collections.<IMethodName, Integer>emptyMap());
setUpModelRepository(objectType, new UniqueTypeName(JRE_1_6_0, OBJECT), model);
ConstructorCompletionSessionProcessor sut = new ConstructorCompletionSessionProcessor(pcMetaProvider,
modelMetaProvider, methodNameProvider, createDefaultPreferences(), new SharedImages());
boolean shouldProcess = sut.startSession(context);
assertThat(shouldProcess, is(equalTo(false)));
verify(modelProvider).releaseModel(model);
}
@Test
public void testBogusRecommendationWithZeroFrequency() {
setUpCompletionScenario(CompletionOnSingleTypeReference.class, objectType,
ImmutableMap.of(objectInitProposal, objectInitCoreProposal));
ConstructorModel model = new ConstructorModel(OBJECT, ImmutableMap.of(OBJECT_INIT, 0));
setUpModelRepository(objectType, new UniqueTypeName(JRE_1_6_0, OBJECT), model);
ConstructorCompletionSessionProcessor sut = new ConstructorCompletionSessionProcessor(pcMetaProvider,
modelMetaProvider, methodNameProvider, createDefaultPreferences(), new SharedImages());
boolean shouldProcess = sut.startSession(context);
assertThat(shouldProcess, is(equalTo(false)));
verify(modelProvider).releaseModel(model);
}
@Test
public void testRecommendationRelevanceBoostAndDecorations() throws Exception {
setUpCompletionScenario(CompletionOnSingleTypeReference.class, objectType,
ImmutableMap.of(objectInitProposal, objectInitCoreProposal));
ConstructorModel model = new ConstructorModel(OBJECT, ImmutableMap.of(OBJECT_INIT, 1));
setUpModelRepository(objectType, new UniqueTypeName(JRE_1_6_0, OBJECT), model);
ConstructorCompletionSessionProcessor sut = new ConstructorCompletionSessionProcessor(pcMetaProvider,
modelMetaProvider, methodNameProvider, createDefaultPreferences(), new SharedImages());
boolean shouldProcess = sut.startSession(context);
assertThat(shouldProcess, is(equalTo(true)));
ProposalProcessorManager manager = mock(ProposalProcessorManager.class);
when(objectInitProcessableProposal.getProposalProcessorManager()).thenReturn(manager);
sut.process(objectInitProcessableProposal);
verify(objectInitProcessableProposal).setTag(ProposalTag.RECOMMENDERS_SCORE, 100.0);
verify(manager, times(1)).addProcessor(processorWithBoostAndLabel(200, "100%"));
verify(manager, times(1)).addProcessor(isA(OverlayImageProposalProcessor.class));
verify(modelProvider).releaseModel(model);
}
@Test
public void testRecommendationWithoutRelevanceBoostOrDecorations() throws Exception {
setUpCompletionScenario(CompletionOnSingleTypeReference.class, objectType,
ImmutableMap.of(objectInitProposal, objectInitCoreProposal));
ConstructorModel model = new ConstructorModel(OBJECT, ImmutableMap.of(OBJECT_INIT, 1));
setUpModelRepository(objectType, new UniqueTypeName(JRE_1_6_0, OBJECT), model);
ConstructorsRcpPreferences preferences = createPreferences(0, 1, false, false, false);
ConstructorCompletionSessionProcessor sut = new ConstructorCompletionSessionProcessor(pcMetaProvider,
modelMetaProvider, methodNameProvider, preferences, new SharedImages());
boolean shouldProcess = sut.startSession(context);
assertThat(shouldProcess, is(equalTo(true)));
ProposalProcessorManager manager = mock(ProposalProcessorManager.class);
when(objectInitProcessableProposal.getProposalProcessorManager()).thenReturn(manager);
sut.process(objectInitProcessableProposal);
verify(objectInitProcessableProposal, never()).setTag(any(ProposalTag.class), anyDouble());
verifyZeroInteractions(manager);
verify(modelProvider).releaseModel(model);
}
@Test
public void testOnlySomeRecommendationAboveRelevanceThreshold() throws Exception {
setUpCompletionScenario(CompletionOnSingleTypeReference.class, objectType, ImmutableMap.of(objectInitProposal,
objectInitCoreProposal, stringInitProposal, stringInitCoreProposal));
ConstructorModel model = new ConstructorModel(OBJECT, ImmutableMap.of(OBJECT_INIT, 3, STRING_INIT, 1));
setUpModelRepository(objectType, new UniqueTypeName(JRE_1_6_0, OBJECT), model);
ConstructorsRcpPreferences preferences = createPreferences(50, 2, true, true, true);
ConstructorCompletionSessionProcessor sut = new ConstructorCompletionSessionProcessor(pcMetaProvider,
modelMetaProvider, methodNameProvider, preferences, new SharedImages());
boolean shouldProcess = sut.startSession(context);
assertThat(shouldProcess, is(equalTo(true)));
ProposalProcessorManager objectInitManager = mock(ProposalProcessorManager.class);
when(objectInitProcessableProposal.getProposalProcessorManager()).thenReturn(objectInitManager);
sut.process(objectInitProcessableProposal);
verify(objectInitProcessableProposal).setTag(ProposalTag.RECOMMENDERS_SCORE, 75.0);
verify(objectInitManager, times(1)).addProcessor(processorWithBoostAndLabel(175, "75%"));
verify(objectInitManager, times(1)).addProcessor(isA(OverlayImageProposalProcessor.class));
ProposalProcessorManager stringInitManager = mock(ProposalProcessorManager.class);
when(stringInitProcessableProposal.getProposalProcessorManager()).thenReturn(stringInitManager);
sut.process(stringInitProcessableProposal);
verify(stringInitProcessableProposal, never()).setTag(any(ProposalTag.class), anyDouble());
verifyZeroInteractions(stringInitManager);
verify(modelProvider).releaseModel(model);
}
private void setUpCompletionScenario(Class<? extends ASTNode> completionType, @Nullable IType expectedType,
Map<IJavaCompletionProposal, CompletionProposal> proposals) {
context = mock(IRecommendersCompletionContext.class);
Optional<ASTNode> completionNode = completionType == null ? Optional.<ASTNode>absent()
: Optional.<ASTNode>of(mock(completionType));
when(context.getCompletionNode()).thenReturn(completionNode);
when(context.getExpectedType()).thenReturn(Optional.fromNullable(expectedType));
when(context.getProposals()).thenReturn(proposals);
methodNameProvider = mock(IProposalNameProvider.class);
when(methodNameProvider.toMethodName(objectInitCoreProposal)).thenReturn(Optional.of(OBJECT_INIT));
when(methodNameProvider.toMethodName(stringInitCoreProposal)).thenReturn(Optional.of(STRING_INIT));
}
private void setUpModelRepository(@Nullable IType type, @Nullable UniqueTypeName uniqueTypeName,
@Nullable ConstructorModel model) {
IProjectCoordinateProvider pcProvider = Mockito.mock(IProjectCoordinateProvider.class);
when(pcProvider.tryToUniqueName(type)).thenReturn(Result.fromNullable(uniqueTypeName));
pcMetaProvider = Mockito.mock(Provider.class);
when(pcMetaProvider.get()).thenReturn(pcProvider);
modelProvider = Mockito.mock(IConstructorModelProvider.class);
if (uniqueTypeName != null) {
when(modelProvider.acquireModel(uniqueTypeName)).thenReturn(Optional.fromNullable(model));
}
modelMetaProvider = Mockito.mock(Provider.class);
when(modelMetaProvider.get()).thenReturn(modelProvider);
}
private ConstructorsRcpPreferences createDefaultPreferences() {
return createPreferences(0, 7, true, true, true);
}
private ConstructorsRcpPreferences createPreferences(int minProposalProbability, int maxNumberOfProposals,
boolean changeProposalRelevance, boolean decorateProposalText, boolean decorateProposalIcon) {
ConstructorsRcpPreferences pref = new ConstructorsRcpPreferences();
pref.maxNumberOfProposals = maxNumberOfProposals;
pref.minProposalPercentage = minProposalProbability;
pref.changeProposalRelevance = changeProposalRelevance;
pref.decorateProposalText = decorateProposalText;
pref.decorateProposalIcon = decorateProposalIcon;
return pref;
}
}