package utils; import static org.junit.Assert.*; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; /** * A utility class to concisely generate lists of QuickFixTestPackage * (via <code>asList()</code>) to be used to effectively assert bug patterns * generated match expected behavior. * * A typical use looks like: * * <pre> * {@code * QuickFixTestPackager packager = new QuickFixTestPackager(); * packager.addExpectedLines(13, 17, ... /* line numbers * /); * packager.addExpectedBugPatterns("FOO_BUG_PATTERN", "FOO_OTHER_PATTERN", ... /* bugPatterns * /); * packager.setExpectedLabels(0, "Replace with WIDGET", "Swap order of arguments", .../* expected labels * /); * packager.setExpectedLabels(1, /* expected labels * /); * packager.setExpectedLabels(2, /* expected labels * /); * //... * doTest(packager.asList()); //will junit.fail if any components are not fully specified * } * </pre> * * * @author Kevin Lubick * */ public class QuickFixTestPackager { private final List<QuickFixTestPackage> packages = new ArrayList<>(); /** * Validates and sorts the compiled QuickFixTestPackaages by pattern name, * then by line number * * @return a sorted list of QuickFixTestPackages to be used in assertions. */ public List<QuickFixTestPackage> asList() { validatePackages(); Collections.sort(packages, new Comparator<QuickFixTestPackage>() { @Override public int compare(QuickFixTestPackage o1, QuickFixTestPackage o2) { if (o1.expectedPattern.equals(o2.expectedPattern)) { if (o1.lineNumber != o2.lineNumber) { return o1.lineNumber - o2.lineNumber; } if (o1.resolutionToExecute < 0) { return -5; // on the same line, do ignore fixes first } return o1.resolutionToExecute - o2.resolutionToExecute; } return o1.expectedPattern.compareTo(o2.expectedPattern); } }); return Collections.unmodifiableList(packages); } private void validatePackages() { assertNotEquals("Did you forget to add anything to the packager?", 0, packages.size()); for (int i = 0; i < packages.size(); i++) { QuickFixTestPackage p = packages.get(i); assertNotNull("Not all labels were initialized", p.expectedLabels); if (p.expectedDescriptions == null) { p.expectedDescriptions = p.expectedLabels; } else { assertEquals("The number of descriptions shoud match the number of labels", p.expectedLabels.size(), p.expectedDescriptions.size()); } assertNotNull("Not all patterns were initialized", p.expectedPattern); assertNotEquals("Not all line numbers were initialized [" + i + "] ", -1, p.lineNumber); } } private void addBlankPackagesToIndex(int indexOfPackageToChange) { // if package does not exist, create empty packages while (packages.size() <= indexOfPackageToChange) { packages.add(new QuickFixTestPackage()); } } /** * Sets the expected labels for the bug marker at the given index. * If the package does not exist, it will be created. * * Since each bug marker can have more than one resolution, these might need * to be specified by index for resolutions that offer custom labels. * * The order should not matter for assertion, as that is not well defined. * * @param index * the index of the package to update. * @param expectedLabels * one or more labels to be associated */ public void setExpectedLabels(int index, String... expectedLabels) { // there is no "add" options because the underlying lists are fixed sized addBlankPackagesToIndex(index); // set the labels packages.get(index).expectedLabels = Arrays.asList(expectedLabels); } /** * A convenience form of setExpectedLabels, if all labels will be the same. * * Sets all created packages to have the one or more specified * expectedLabels. * * @param expectedLabels */ public void fillExpectedLabels(String... expectedLabels) { // there is no "add" options because the underlying lists are fixed sized for (QuickFixTestPackage p : packages) { // make a separate list to avoid cross contamination of modification p.expectedLabels = Arrays.asList(expectedLabels); } } /** * Sets the expected descriptions for the bug marker at the given index. * If the package does not exist, it will be created. * * If the description is not specified, it will default to the label (which is what * the implementation does) * * Since each bug marker can have more than one resolution, these might need * to be specified by index for resolutions that offer custom descriptions. * * The order should match the specified labels. * * @param indexOfPackageToChange * @param expectedDescriptions */ public void setExpectedDescriptions(int indexOfPackageToChange, String... expectedDescriptions) { addBlankPackagesToIndex(indexOfPackageToChange); packages.get(indexOfPackageToChange).expectedDescriptions = Arrays.asList(expectedDescriptions); } /** * A convenience form of setExpectedDescriptions, if all descriptions will be the same. * * Sets all created packages to have the one or more specified * expectedDescriptions. * * @param expectedDescriptions */ public void fillExpectedDescriptions(String... expectedDescriptions) { for (QuickFixTestPackage p : packages) { // make a separate list to avoid cross contamination of modification p.expectedDescriptions = Arrays.asList(expectedDescriptions); } } /** * Sets the expected line numbers, assigning the first pattern * to the first package, the second pattern to the second package * and so on. * * If any packages do not exist, they will be created. * * @param lineNumbers * the list of line numbers to be used */ public void setExpectedLines(int... lineNumbers) { for (int i = 0; i < lineNumbers.length; i++) { int lineNumber = lineNumbers[i]; if (packages.size() <= i) { packages.add(new QuickFixTestPackage()); } packages.get(i).lineNumber = lineNumber; } } /** * Sets the expected bugPatterns, assigning the first pattern * to the first package, the second pattern to the second package * and so on. * * If any packages do not exist, they will be created. * * @param expectedPatterns * the list of patterns to be used */ public void setExpectedBugPatterns(String... expectedPatterns) { for (int i = 0; i < expectedPatterns.length; i++) { String pattern = expectedPatterns[i]; if (packages.size() <= i) { packages.add(new QuickFixTestPackage()); } packages.get(i).expectedPattern = pattern; } } /** * A convenience form of setExpectedBugPatterns, * if all BugPatterns will be the same. * * Sets all created packages to have the specified pattern * * @param expectedPattern * the bug pattern that all packages should get */ public void fillExpectedBugPatterns(String expectedPattern) { for (QuickFixTestPackage p : packages) { p.expectedPattern = expectedPattern; } } /** * Sets the fix to implement for a given package. * * @param indexOfPackageToChange * @param indexOfFixToImplement */ public void setFixToPerform(int indexOfPackageToChange, int indexOfFixToImplement) { addBlankPackagesToIndex(indexOfPackageToChange); // set the fixToImplement packages.get(indexOfPackageToChange).resolutionToExecute = indexOfFixToImplement; } }