blob: 0a995dd89ef43c4bdb8c46753b15a0b4f6965b8d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2020 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
* Jens Reimann - add method to convert a collection of previews
*******************************************************************************/
package org.eclipse.jdt.ui.tests.quickfix;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
import org.eclipse.jdt.testplugin.JavaProjectHelper;
import org.eclipse.jdt.testplugin.StringAsserts;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.resources.IFile;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.ltk.core.refactoring.TextFileChange;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IProblemRequestor;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.WorkingCopyOwner;
import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.FieldDeclaration;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import org.eclipse.jdt.internal.core.manipulation.dom.ASTResolving;
import org.eclipse.jdt.internal.corext.fix.LinkedProposalModel;
import org.eclipse.jdt.internal.corext.fix.LinkedProposalPositionGroup;
import org.eclipse.jdt.internal.corext.fix.LinkedProposalPositionGroup.Proposal;
import org.eclipse.jdt.ui.text.java.IInvocationContext;
import org.eclipse.jdt.ui.text.java.IJavaCompletionProposal;
import org.eclipse.jdt.ui.text.java.IProblemLocation;
import org.eclipse.jdt.ui.text.java.correction.CUCorrectionProposal;
import org.eclipse.jdt.ui.text.java.correction.ICommandAccess;
import org.eclipse.jdt.internal.ui.text.correction.AssistContext;
import org.eclipse.jdt.internal.ui.text.correction.GetterSetterCorrectionSubProcessor.SelfEncapsulateFieldProposal;
import org.eclipse.jdt.internal.ui.text.correction.JavaCorrectionProcessor;
import org.eclipse.jdt.internal.ui.text.correction.ProblemLocation;
import org.eclipse.jdt.internal.ui.text.correction.ReorgCorrectionsSubProcessor;
import org.eclipse.jdt.internal.ui.text.correction.proposals.LinkedCorrectionProposal;
import org.eclipse.jdt.internal.ui.text.correction.proposals.LinkedNamesAssistProposal;
import org.eclipse.jdt.internal.ui.text.correction.proposals.NewCUUsingWizardProposal;
import org.eclipse.jdt.internal.ui.text.correction.proposals.RenameRefactoringProposal;
import org.eclipse.jdt.internal.ui.text.template.contentassist.SurroundWithTemplateProposal;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
/**
*/
@RunWith(Suite.class)
@Suite.SuiteClasses({
QuickFixTest9.class,
QuickFixTest18.class,
QuickFixTest13.class,
SerialVersionQuickFixTest.class,
UtilitiesTest.class,
UnresolvedTypesQuickFixTest.class,
UnresolvedVariablesQuickFixTest.class,
UnresolvedMethodsQuickFixTest.class,
UnresolvedMethodsQuickFixTest18.class,
ReturnTypeQuickFixTest.class,
LocalCorrectionsQuickFixTest.class,
LocalCorrectionsQuickFixTest17.class,
LocalCorrectionsQuickFixTest18.class,
TypeMismatchQuickFixTests.class,
ReorgQuickFixTest.class,
ModifierCorrectionsQuickFixTest.class,
ModifierCorrectionsQuickFixTest17.class,
ModifierCorrectionsQuickFixTest9.class,
GetterSetterQuickFixTest.class,
AssistQuickFixTest.class,
AssistQuickFixTest17.class,
AssistQuickFixTest18.class,
AssistQuickFixTest12.class,
ChangeNonStaticToStaticTest.class,
MarkerResolutionTest.class,
JavadocQuickFixTest.class,
JavadocQuickFixTest9.class,
ConvertForLoopQuickFixTest.class,
ConvertIterableLoopQuickFixTest.class,
AdvancedQuickAssistTest.class,
AdvancedQuickAssistTest17.class,
AdvancedQuickAssistTest18.class,
CleanUpTestCase.class,
QuickFixEnablementTest.class,
SurroundWithTemplateTest.class,
TypeParameterMismatchTest.class,
PropertiesFileQuickAssistTest.class,
NullAnnotationsQuickFixTest.class,
NullAnnotationsQuickFixTest18.class,
NullAnnotationsQuickFixTest18Mix.class,
AnnotateAssistTest15.class,
AnnotateAssistTest18.class,
TypeAnnotationQuickFixTest.class
})
public class QuickFixTest {
public static void assertCorrectLabels(List<? extends ICompletionProposal> proposals) {
for (int i= 0; i < proposals.size(); i++) {
ICompletionProposal proposal= proposals.get(i);
String name= proposal.getDisplayString();
if (name == null || name.length() == 0 || name.charAt(0) == '!' || name.contains("{0}") || name.contains("{1}")) {
assertTrue("wrong proposal label: " + name, false);
}
if (proposal.getImage() == null) {
assertTrue("wrong proposal image", false);
}
}
}
public static void assertCorrectContext(IInvocationContext context, ProblemLocation problem) {
if (problem.getProblemId() != 0) {
if (!JavaCorrectionProcessor.hasCorrections(context.getCompilationUnit(), problem.getProblemId(), problem.getMarkerType())) {
assertTrue("Problem type not marked with light bulb: " + problem, false);
}
}
}
public static void assertNumberOf(String name, int nProblems, int nProblemsExpected) {
assertTrue("Wrong number of " + name + ", is: " + nProblems + ", expected: " + nProblemsExpected, nProblems == nProblemsExpected);
}
public static void assertEqualString(String actual, String expected) {
StringAsserts.assertEqualString(actual, expected);
}
public static void assertEqualStringIgnoreDelim(String actual, String expected) throws IOException {
StringAsserts.assertEqualStringIgnoreDelim(actual, expected);
}
public static void assertEqualStringsIgnoreOrder(String[] actuals, String[] expecteds) {
StringAsserts.assertEqualStringsIgnoreOrder(actuals, expecteds);
}
public static void assertEqualStringsIgnoreOrder(Collection<String> actuals, Collection<String> expecteds) {
String[] act= actuals.toArray(new String[actuals.size()]);
String[] exp= expecteds.toArray(new String[actuals.size()]);
StringAsserts.assertEqualStringsIgnoreOrder(act, exp);
}
public static void assertExpectedExistInProposals(List<IJavaCompletionProposal> actualProposals, String[] expecteds) throws CoreException, BadLocationException {
StringAsserts.assertExpectedExistInProposals(getPreviewContents(actualProposals), expecteds);
}
protected static void assertProposalPreviewEquals(String expected, String proposalName, List<IJavaCompletionProposal> proposals) throws CoreException, BadLocationException {
final ICompletionProposal proposal= findProposalByName(proposalName, proposals);
assertNotNull("proposal \""+proposalName+"\" not found", proposal);
assertEquals(expected, getProposalPreviewContent(proposal));
}
public static void assertCommandIdDoesNotExist(List<? extends ICompletionProposal> actualProposals, String commandId) {
assertTrue(findProposalByCommandId(commandId, actualProposals) == null);
}
public static void assertProposalDoesNotExist(List<? extends ICompletionProposal> actualProposals, String proposalName) {
assertTrue(findProposalByName(proposalName, actualProposals) == null);
}
public static void assertProposalExists(List<? extends ICompletionProposal> actualProposals, String proposalName) {
assertTrue(findProposalByName(proposalName, actualProposals) != null);
}
public static TypeDeclaration findTypeDeclaration(CompilationUnit astRoot, String simpleTypeName) {
List<AbstractTypeDeclaration> types= astRoot.types();
for (int i= 0; i < types.size(); i++) {
TypeDeclaration elem= (TypeDeclaration) types.get(i);
if (simpleTypeName.equals(elem.getName().getIdentifier())) {
return elem;
}
}
return null;
}
public static MethodDeclaration findMethodDeclaration(TypeDeclaration typeDecl, String methodName) {
for (MethodDeclaration method : typeDecl.getMethods()) {
if (methodName.equals(method.getName().getIdentifier())) {
return method;
}
}
return null;
}
public static VariableDeclarationFragment findFieldDeclaration(TypeDeclaration typeDecl, String fieldName) {
for (FieldDeclaration field : typeDecl.getFields()) {
List<VariableDeclarationFragment> list= field.fragments();
for (int k= 0; k < list.size(); k++) {
VariableDeclarationFragment fragment= list.get(k);
if (fieldName.equals(fragment.getName().getIdentifier())) {
return fragment;
}
}
}
return null;
}
public static AssistContext getCorrectionContext(ICompilationUnit cu, int offset, int length) {
AssistContext context= new AssistContext(cu, offset, length);
return context;
}
protected static final ArrayList<IJavaCompletionProposal> collectCorrections(ICompilationUnit cu, CompilationUnit astRoot) throws CoreException {
return collectCorrections(cu, astRoot, 1, null);
}
/**
* Bad design: only collects corrections for the <b>first</b> problem!
* @param cu
* @param astRoot
* @param nProblems
* @return
* @throws CoreException
*/
protected static final ArrayList<IJavaCompletionProposal> collectCorrections(ICompilationUnit cu, CompilationUnit astRoot, int nProblems) throws CoreException {
return collectCorrections(cu, astRoot, nProblems, null);
}
protected static final ArrayList<IJavaCompletionProposal> collectCorrections(ICompilationUnit cu, CompilationUnit astRoot, int nProblems, int problem) throws CoreException {
return collectCorrections(cu, astRoot, nProblems, problem, null);
}
/**
* Bad design: only collects corrections for the <b>first</b> problem!
* @param cu
* @param astRoot
* @param nProblems
* @param context
* @return
* @throws CoreException
*/
protected static final ArrayList<IJavaCompletionProposal> collectCorrections(ICompilationUnit cu, CompilationUnit astRoot, int nProblems, AssistContext context) throws CoreException {
return collectCorrections(cu, astRoot, nProblems, 0, context);
}
protected static final ArrayList<IJavaCompletionProposal> collectCorrections(ICompilationUnit cu, CompilationUnit astRoot, int nProblems, int problem, AssistContext context) throws CoreException {
IProblem[] problems= astRoot.getProblems();
assertNumberOfProblems(nProblems, problems);
return collectCorrections(cu, problems[problem], context);
}
protected static final ArrayList<ICompletionProposal> collectAllCorrections(ICompilationUnit cu, CompilationUnit astRoot, int nProblems) throws CoreException {
IProblem[] problems= astRoot.getProblems();
assertNumberOfProblems(nProblems, problems);
ArrayList<ICompletionProposal> corrections= new ArrayList<>();
for (int i= 0; i < nProblems; i++) {
corrections.addAll(collectCorrections(cu, problems[i], null));
}
return corrections;
}
protected static void assertNumberOfProblems(int nProblems, IProblem[] problems) {
if (problems.length != nProblems) {
StringBuilder buf= new StringBuilder("Wrong number of problems, is: ");
buf.append(problems.length).append(", expected: ").append(nProblems).append('\n');
for (IProblem problem : problems) {
buf.append(problem);
buf.append('[').append(problem.getSourceStart()).append(" ,").append(problem.getSourceEnd()).append(']');
buf.append('\n');
}
assertTrue(buf.toString(), false);
}
}
/**
* Bad design: only collects corrections for the <b>first</b> problem!
* @param cu
* @param nProblems
* @return
* @throws CoreException
*/
protected static final ArrayList<IJavaCompletionProposal> collectCorrections2(ICompilationUnit cu, int nProblems) throws CoreException {
final ArrayList<IProblem> problemsList= new ArrayList<>();
final IProblemRequestor requestor= new IProblemRequestor() {
@Override
public void acceptProblem(IProblem problem) {
problemsList.add(problem);
}
@Override
public void beginReporting() {
problemsList.clear();
}
@Override
public void endReporting() {}
@Override
public boolean isActive() { return true;}
};
WorkingCopyOwner workingCopyOwner= new WorkingCopyOwner() {
@Override
public IProblemRequestor getProblemRequestor(ICompilationUnit workingCopy) {
return requestor;
}
};
ICompilationUnit wc= cu.getWorkingCopy(workingCopyOwner, null);
try {
wc.reconcile(ICompilationUnit.NO_AST, true, true, wc.getOwner(), null);
} finally {
wc.discardWorkingCopy();
}
IProblem[] problems= problemsList.toArray(new IProblem[problemsList.size()]);
assertNumberOfProblems(nProblems, problems);
return collectCorrections(cu, problems[0], null);
}
protected static final ArrayList<IJavaCompletionProposal> collectCorrections(ICompilationUnit cu, IProblem curr, IInvocationContext context) throws CoreException {
int offset= curr.getSourceStart();
int length= curr.getSourceEnd() + 1 - offset;
if (context == null) {
context= new AssistContext(cu, offset, length);
}
ProblemLocation problem= new ProblemLocation(curr);
ArrayList<IJavaCompletionProposal> proposals= collectCorrections(context, problem);
if (!proposals.isEmpty()) {
assertCorrectContext(context, problem);
}
return proposals;
}
protected static ArrayList<IJavaCompletionProposal> collectCorrections(IInvocationContext context, IProblemLocation problem) throws CoreException {
ArrayList<IJavaCompletionProposal> proposals= new ArrayList<>();
IStatus status= JavaCorrectionProcessor.collectCorrections(context, new IProblemLocation[] { problem }, proposals);
assertStatusOk(status);
return proposals;
}
public static void assertStatusOk(IStatus status) throws CoreException {
if (!status.isOK()) {
if (status.getException() == null) { // find a status with an exception
for (IStatus child : status.getChildren()) {
if (child.getException() != null) {
throw new CoreException(child);
}
}
}
}
}
protected static final ArrayList<IJavaCompletionProposal> collectAssists(IInvocationContext context, Class<?>[] filteredTypes) throws CoreException {
ArrayList<IJavaCompletionProposal> proposals= new ArrayList<>();
IStatus status= JavaCorrectionProcessor.collectAssists(context, new IProblemLocation[0], proposals);
assertStatusOk(status);
if (!proposals.isEmpty()) {
assertTrue("should be marked as 'has assist'", JavaCorrectionProcessor.hasAssists(context));
}
if (filteredTypes != null && filteredTypes.length > 0) {
for (Iterator<IJavaCompletionProposal> iter= proposals.iterator(); iter.hasNext(); ) {
if (isFiltered(iter.next(), filteredTypes)) {
iter.remove();
}
}
}
return proposals;
}
private static boolean isFiltered(Object curr, Class<?>[] filteredTypes) {
for (Class<?> filteredType : filteredTypes) {
if (filteredType.isInstance(curr)) {
return true;
}
}
return false;
}
protected static final ArrayList<IJavaCompletionProposal> collectAssists(IInvocationContext context, boolean includeLinkedRename) throws CoreException {
Class<?>[] filteredTypes= includeLinkedRename ? null : new Class[] { LinkedNamesAssistProposal.class, RenameRefactoringProposal.class };
return collectAssists(context, filteredTypes);
}
protected static CompilationUnit getASTRoot(ICompilationUnit cu) {
return ASTResolving.createQuickFixAST(cu, null);
}
public static void addPreviewAndExpected(List<IJavaCompletionProposal> proposals, StringBuffer expected, ArrayList<String> expecteds, ArrayList<String> previews) throws CoreException {
CUCorrectionProposal proposal= (CUCorrectionProposal) proposals.get(expecteds.size());
previews.add(getPreviewContent(proposal));
expecteds.add(expected.toString());
}
protected static String[] getPreviewContents(List<IJavaCompletionProposal> proposals) throws CoreException, BadLocationException {
String[] res= new String[proposals.size()];
for (int i= 0; i < proposals.size(); i++) {
res[i]=getProposalPreviewContent(proposals.get(i));
}
return res;
}
private static String getProposalPreviewContent(ICompletionProposal curr) throws CoreException, BadLocationException {
String previewContent = null;
if (curr instanceof ReorgCorrectionsSubProcessor.ClasspathFixCorrectionProposal) {
// ignore
} else if (curr instanceof CUCorrectionProposal) {
previewContent= getPreviewContent((CUCorrectionProposal) curr);
} else if (curr instanceof NewCUUsingWizardProposal) {
previewContent= getWizardPreviewContent((NewCUUsingWizardProposal) curr);
} else if (curr instanceof SurroundWithTemplateProposal) {
previewContent= getTemplatePreviewContent((SurroundWithTemplateProposal) curr);
} else if (curr instanceof SelfEncapsulateFieldProposal) {
previewContent= getSEFPreviewContent((SelfEncapsulateFieldProposal) curr);
}
return previewContent;
}
private static String getSEFPreviewContent(SelfEncapsulateFieldProposal sefp) throws CoreException {
ICompilationUnit compilationUnit= sefp.getField().getCompilationUnit();
TextFileChange change= sefp.getChange((IFile) compilationUnit.getResource());
if (change != null) {
return change.getPreviewContent(null);
}
return "";
}
private static String getTemplatePreviewContent(SurroundWithTemplateProposal proposal) {
return proposal.getPreviewContent();
}
protected static String getPreviewContent(CUCorrectionProposal proposal) throws CoreException {
return proposal.getPreviewContent();
}
protected static String[] getAllPreviewContent(Collection<? extends IJavaCompletionProposal> proposals) throws CoreException {
ArrayList<String> result = new ArrayList<>(proposals.size());
for ( IJavaCompletionProposal proposal: proposals) {
if ( proposal instanceof CUCorrectionProposal) {
result.add(getPreviewContent((CUCorrectionProposal) proposal));
}
}
return result.toArray(new String[result.size()]);
}
protected static String[] getAllDisplayStrings(ArrayList<IJavaCompletionProposal> proposals) {
return proposals.stream()
.map(proposal -> proposal.getDisplayString())
.filter(displayString -> displayString != null && !displayString.isEmpty())
.toArray(String[]::new);
}
protected static String getWizardPreviewContent(NewCUUsingWizardProposal newCUWizard) throws CoreException, BadLocationException {
newCUWizard.setShowDialog(false);
newCUWizard.apply(null);
IType createdType= newCUWizard.getCreatedType();
assertTrue("Nothing created", createdType.exists());
String preview= createdType.getCompilationUnit().getSource();
IJavaElement parent= createdType.getParent();
if (parent instanceof IType) {
createdType.delete(true, null);
} else {
JavaProjectHelper.delete(parent);
}
StringBuilder res= new StringBuilder();
IDocument doc= new Document(preview);
int nLines= doc.getNumberOfLines();
for (int i= 0; i < nLines; i++) {
IRegion lineInformation= doc.getLineInformation(i);
res.append(doc.get(lineInformation.getOffset(), lineInformation.getLength()));
if (i != nLines - 1) {
res.append('\n');
}
}
return res.toString();
}
protected static void assertNumberOfProposals(List<? extends ICompletionProposal> proposals, int expectedProposals) {
if (proposals.size() != expectedProposals) {
StringBuffer buf= new StringBuffer();
buf.append("Wrong number of proposals, is: ").append(proposals.size()). append(", expected: ").append(expectedProposals).append('\n');
for (int i= 0; i < proposals.size(); i++) {
ICompletionProposal curr= proposals.get(i);
buf.append(" - ").append(curr.getDisplayString()).append('\n');
if (curr instanceof CUCorrectionProposal) {
appendSource(((CUCorrectionProposal) curr), buf);
}
}
assertTrue(buf.toString(), false);
}
}
protected static ICommandAccess findProposalByCommandId(String commandId, List<? extends ICompletionProposal> proposals) {
for (int i= 0; i < proposals.size(); i++) {
Object curr= proposals.get(i);
if (curr instanceof ICommandAccess) {
if (commandId.equals(((ICommandAccess) curr).getCommandId())) {
return (ICommandAccess) curr;
}
}
}
return null;
}
protected static ICompletionProposal findProposalByName(String name, List<? extends ICompletionProposal> proposals) {
for (int i= 0; i < proposals.size(); i++) {
Object curr= proposals.get(i);
if (curr instanceof ICompletionProposal && name.equals(((ICompletionProposal)curr).getDisplayString()))
return (ICompletionProposal)curr;
}
return null;
}
private static void appendSource(CUCorrectionProposal proposal, StringBuffer buf) {
try {
buf.append(proposal.getPreviewContent());
} catch (CoreException e) {
// ignore
}
}
protected static void assertNoErrors(IInvocationContext context) {
for (IProblem problem : context.getASTRoot().getProblems()) {
if (problem.isError()) {
assertTrue("source has error: " + problem.getMessage(), false);
}
}
}
public static String getPreviewsInBufAppend(ICompilationUnit cu) throws CoreException, BadLocationException {
CompilationUnit astRoot= getASTRoot(cu);
List<IJavaCompletionProposal> proposals= collectCorrections(cu, astRoot);
if (proposals.isEmpty()) {
return null;
}
return getPreviewsInBufAppend(cu, proposals);
}
protected static String getPreviewsInBufAppend(ICompilationUnit cu, List<IJavaCompletionProposal> proposals) throws CoreException, BadLocationException {
StringBuffer buf= new StringBuffer();
String[] previewContents= getPreviewContents(proposals);
buf.append("public void testX() throws Exception {\n");
buf.append("IPackageFragment pack1= fSourceFolder.createPackageFragment(\"").append(cu.getParent().getElementName()).append("\", false, null);\n");
buf.append("StringBuffer buf= new StringBuffer();\n");
wrapInBufAppend(cu.getBuffer().getContents(), buf);
buf.append("ICompilationUnit cu= pack1.createCompilationUnit(\"").append(cu.getElementName()).append("\", buf.toString(), false, null);\n\n");
buf.append("CompilationUnit astRoot= getASTRoot(cu);\n");
buf.append("ArrayList<IJavaCompletionProposal> proposals= collectCorrections(cu, astRoot);\n\n");
buf.append("assertCorrectLabels(proposals);\n");
buf.append("assertNumberOfProposals(proposals, ").append(previewContents.length).append(");\n\n");
buf.append("String[] expected= new String[").append(previewContents.length).append("];\n");
for (int i= 0; i < previewContents.length; i++) {
String curr= previewContents[i];
if (curr == null) {
continue;
}
buf.append("buf= new StringBuffer();\n");
wrapInBufAppend(curr, buf);
buf.append("expected[" + i + "]= buf.toString();\n\n");
}
buf.append("assertExpectedExistInProposals(proposals, expected);\n");
buf.append("}\n");
return buf.toString();
}
private static void wrapInBufAppend(String curr, StringBuffer buf) {
buf.append("buf.append(\"");
int last= curr.length() - 1;
for (int k= 0; k <= last ; k++) {
char ch= curr.charAt(k);
switch (ch) {
case '\n':
buf.append("\\n\");\n");
if (k < last) {
buf.append("buf.append(\"");
}
break;
// ignore
case '\r':
break;
case '\t':
buf.append(" "); // 4 spaces
break;
case '"':
case '\\':
buf.append('\\').append(ch);
break;
default:
buf.append(ch);
break;
}
}
if (buf.length() > 0 && buf.charAt(buf.length() - 1) != '\n') {
buf.append("\\n\");\n");
}
}
protected void assertLinkedChoices(ICompletionProposal proposal, String linkedGroup, String[] expectedChoices) {
assertTrue("Not a LinkedCorrectionProposal", proposal instanceof LinkedCorrectionProposal);
LinkedCorrectionProposal linkedProposal = (LinkedCorrectionProposal)proposal;
LinkedProposalModel linkedProposalModel = linkedProposal.getLinkedProposalModel();
LinkedProposalPositionGroup positionGroup = linkedProposalModel.getPositionGroup(linkedGroup, false);
Proposal[] choices = positionGroup.getProposals();
assertEquals("Not same number of choices", expectedChoices.length, choices.length);
Arrays.sort(expectedChoices);
List<String> sortedChoices= Arrays.stream(choices)
.map(Proposal::getDisplayString)
.sorted()
.collect(Collectors.toList());
for (int i=0; i<expectedChoices.length; i++) {
assertEquals("Unexpected choice", expectedChoices[i], sortedChoices.get(i));
}
}
}