+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * Jalview is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
package jalview.analysis;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static org.testng.AssertJUnit.assertEquals;
+
import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
import jalview.datamodel.Alignment;
import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceI;
+import jalview.gui.JvOptionPane;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
-import org.junit.Before;
-import org.junit.Test;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
public class AnnotationSorterTest
{
+
+ @BeforeClass(alwaysRun = true)
+ public void setUpJvOptionPane()
+ {
+ JvOptionPane.setInteractiveMode(false);
+ JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
+ }
+
private static final int NUM_SEQS = 6;
private static final int NUM_ANNS = 7;
/*
* Set up 6 sequences and 7 annotations.
*/
- @Before
+ @BeforeMethod(alwaysRun = true)
public void setUp()
{
al = buildAlignment(NUM_SEQS);
*/
protected AlignmentAnnotation[] buildAnnotations(int numAnns)
{
- List<AlignmentAnnotation> annlist = new ArrayList<AlignmentAnnotation>();
+ List<AlignmentAnnotation> annlist = new ArrayList<>();
for (int i = 0; i < numAnns; i++)
{
AlignmentAnnotation ann = new AlignmentAnnotation(SS + i, "", 0);
* sequence ref</li>
* </ul>
*/
- @Test
- public void testSortBySequenceAndType_autocalcLast()
+ @Test(groups = { "Functional" })
+ public void testSortBySequenceAndLabel_autocalcLast()
{
// @formatter:off
anns[0].sequenceRef = al.getSequenceAt(1); anns[0].label = "label0";
anns[1].sequenceRef = al.getSequenceAt(3); anns[1].label = "structure";
anns[2].sequenceRef = al.getSequenceAt(3); anns[2].label = "iron";
- anns[3].sequenceRef = null; anns[3].label = "Quality";
- anns[4].sequenceRef = null; anns[4].label = "Consensus";
+ anns[3].autoCalculated = true; anns[3].label = "Quality";
+ anns[4].autoCalculated = true; anns[4].label = "Consensus";
anns[5].sequenceRef = al.getSequenceAt(0); anns[5].label = "label5";
anns[6].sequenceRef = al.getSequenceAt(3); anns[6].label = "IRP";
// @formatter:on
- AnnotationSorter testee = new AnnotationSorter(al, false);
+ AnnotationSorter testee = new AnnotationSorter(al, false, false);
testee.sort(anns, SequenceAnnotationOrder.SEQUENCE_AND_LABEL);
assertEquals("label5", anns[0].label); // for sequence 0
assertEquals("label0", anns[1].label); // for sequence 1
assertEquals("iron", anns[2].label); // sequence 3 /iron
assertEquals("IRP", anns[3].label); // sequence 3/IRP
assertEquals("structure", anns[4].label); // sequence 3/structure
- assertEquals("Quality", anns[5].label); // non-sequence annotations
+ assertEquals("Quality", anns[5].label); // autocalc annotations
assertEquals("Consensus", anns[6].label); // retain ordering
}
/**
* Variant with autocalculated annotations sorting to front
*/
- @Test
- public void testSortBySequenceAndType_autocalcFirst()
+ @Test(groups = { "Functional" })
+ public void testSortBySequenceAndLabel_autocalcFirst()
{
// @formatter:off
anns[0].sequenceRef = al.getSequenceAt(1); anns[0].label = "label0";
anns[1].sequenceRef = al.getSequenceAt(3); anns[1].label = "structure";
anns[2].sequenceRef = al.getSequenceAt(3); anns[2].label = "iron";
- anns[3].sequenceRef = null; anns[3].label = "Quality";
- anns[4].sequenceRef = null; anns[4].label = "Consensus";
+ anns[3].autoCalculated = true; anns[3].label = "Quality";
+ anns[4].autoCalculated = true; anns[4].label = "Consensus";
anns[5].sequenceRef = al.getSequenceAt(0); anns[5].label = "label5";
anns[6].sequenceRef = al.getSequenceAt(3); anns[6].label = "IRP";
// @formatter:on
- AnnotationSorter testee = new AnnotationSorter(al, true);
+ AnnotationSorter testee = new AnnotationSorter(al, true, false);
testee.sort(anns, SequenceAnnotationOrder.SEQUENCE_AND_LABEL);
- assertEquals("Quality", anns[0].label); // non-sequence annotations
+ assertEquals("Quality", anns[0].label); // autocalc annotations
assertEquals("Consensus", anns[1].label); // retain ordering
assertEquals("label5", anns[2].label); // for sequence 0
assertEquals("label0", anns[3].label); // for sequence 1
* sequence ref</li>
* </ul>
*/
- @Test
- public void testSortByTypeAndSequence_autocalcLast()
+ @Test(groups = { "Functional" })
+ public void testSortByLabelAndSequence_autocalcLast()
{
// @formatter:off
anns[0].sequenceRef = al.getSequenceAt(1); anns[0].label = "label0";
anns[1].sequenceRef = al.getSequenceAt(3); anns[1].label = "structure";
anns[2].sequenceRef = al.getSequenceAt(3); anns[2].label = "iron";
- anns[3].sequenceRef = null; anns[3].label = "Quality";
- anns[4].sequenceRef = null; anns[4].label = "Consensus";
+ anns[3].autoCalculated = true; anns[3].label = "Quality";
+ anns[4].autoCalculated = true; anns[4].label = "Consensus";
anns[5].sequenceRef = al.getSequenceAt(0); anns[5].label = "IRON";
anns[6].sequenceRef = al.getSequenceAt(2); anns[6].label = "Structure";
// @formatter:on
- AnnotationSorter testee = new AnnotationSorter(al, false);
+ AnnotationSorter testee = new AnnotationSorter(al, false, false);
testee.sort(anns, SequenceAnnotationOrder.LABEL_AND_SEQUENCE);
assertEquals("IRON", anns[0].label); // IRON / sequence 0
assertEquals("iron", anns[1].label); // iron / sequence 3
assertEquals("label0", anns[2].label); // label0 / sequence 1
assertEquals("Structure", anns[3].label); // Structure / sequence 2
assertEquals("structure", anns[4].label); // structure / sequence 3
- assertEquals("Quality", anns[5].label); // non-sequence annotations
+ assertEquals("Quality", anns[5].label); // autocalc annotations
assertEquals("Consensus", anns[6].label); // retain ordering
}
/**
* Variant of test with autocalculated annotations sorted to front
*/
- @Test
- public void testSortByTypeAndSequence_autocalcFirst()
+ @Test(groups = { "Functional" })
+ public void testSortByLabelAndSequence_autocalcFirst()
{
// @formatter:off
anns[0].sequenceRef = al.getSequenceAt(1); anns[0].label = "label0";
anns[1].sequenceRef = al.getSequenceAt(3); anns[1].label = "structure";
anns[2].sequenceRef = al.getSequenceAt(3); anns[2].label = "iron";
- anns[3].sequenceRef = null; anns[3].label = "Quality";
- anns[4].sequenceRef = null; anns[4].label = "Consensus";
+ anns[3].autoCalculated = true; anns[3].label = "Quality";
+ anns[4].autoCalculated = true; anns[4].label = "Consensus";
anns[5].sequenceRef = al.getSequenceAt(0); anns[5].label = "IRON";
anns[6].sequenceRef = al.getSequenceAt(2); anns[6].label = "Structure";
// @formatter:on
- AnnotationSorter testee = new AnnotationSorter(al, true);
+ AnnotationSorter testee = new AnnotationSorter(al, true, false);
testee.sort(anns, SequenceAnnotationOrder.LABEL_AND_SEQUENCE);
- assertEquals("Quality", anns[0].label); // non-sequence annotations
+ assertEquals("Quality", anns[0].label); // autocalc annotations
assertEquals("Consensus", anns[1].label); // retain ordering
assertEquals("IRON", anns[2].label); // IRON / sequence 0
assertEquals("iron", anns[3].label); // iron / sequence 3
* Variant of test with autocalculated annotations sorted to front but
* otherwise no change.
*/
- @Test
+ @Test(groups = { "Functional" })
public void testNoSort_autocalcFirst()
{
// @formatter:off
anns[0].sequenceRef = al.getSequenceAt(1); anns[0].label = "label0";
anns[1].sequenceRef = al.getSequenceAt(3); anns[1].label = "structure";
anns[2].sequenceRef = al.getSequenceAt(3); anns[2].label = "iron";
- anns[3].sequenceRef = null; anns[3].label = "Quality";
- anns[4].sequenceRef = null; anns[4].label = "Consensus";
+ anns[3].autoCalculated = true; anns[3].label = "Quality";
+ anns[4].autoCalculated = true; anns[4].label = "Consensus";
anns[5].sequenceRef = al.getSequenceAt(0); anns[5].label = "IRON";
anns[6].sequenceRef = al.getSequenceAt(2); anns[6].label = "Structure";
// @formatter:on
- AnnotationSorter testee = new AnnotationSorter(al, true);
+ AnnotationSorter testee = new AnnotationSorter(al, true, false);
testee.sort(anns, SequenceAnnotationOrder.NONE);
- assertEquals("Quality", anns[0].label); // non-sequence annotations
+ assertEquals("Quality", anns[0].label); // autocalc annotations
assertEquals("Consensus", anns[1].label); // retain ordering
assertEquals("label0", anns[2].label);
assertEquals("structure", anns[3].label);
assertEquals("Structure", anns[6].label);
}
- @Test
+ @Test(groups = { "Functional" })
public void testSort_timingPresorted()
{
- final long targetTime = 100; // ms
- final int numSeqs = 10000;
- final int numAnns = 20000;
- al = buildAlignment(numSeqs);
- anns = buildAnnotations(numAnns);
+ testTiming_presorted(50, 100);
+ testTiming_presorted(500, 1000);
+ testTiming_presorted(5000, 10000);
+ }
+
+ /**
+ * Test timing to sort annotations already in the sort order.
+ *
+ * @param numSeqs
+ * @param numAnns
+ */
+ private void testTiming_presorted(final int numSeqs, final int numAnns)
+ {
+ Alignment alignment = buildAlignment(numSeqs);
+ AlignmentAnnotation[] annotations = buildAnnotations(numAnns);
/*
* Set the annotations presorted by label
*/
Random r = new Random();
- final SequenceI[] sequences = al.getSequencesArray();
- for (int i = 0; i < anns.length; i++)
+ final SequenceI[] sequences = alignment.getSequencesArray();
+ for (int i = 0; i < annotations.length; i++)
{
SequenceI randomSequenceRef = sequences[r.nextInt(sequences.length)];
- anns[i].sequenceRef = randomSequenceRef;
- anns[i].label = "label" + i;
+ annotations[i].sequenceRef = randomSequenceRef;
+ annotations[i].label = "label" + i;
}
long startTime = System.currentTimeMillis();
- AnnotationSorter testee = new AnnotationSorter(al, false);
- testee.sort(anns, SequenceAnnotationOrder.LABEL_AND_SEQUENCE);
+ AnnotationSorter testee = new AnnotationSorter(alignment, false, false);
+ testee.sort(annotations, SequenceAnnotationOrder.LABEL_AND_SEQUENCE);
long endTime = System.currentTimeMillis();
final long elapsed = endTime - startTime;
System.out.println("Timing test for presorted " + numSeqs
- + " sequences and "
- + numAnns + " annotations took " + elapsed + "ms");
- assertTrue("Sort took more than " + targetTime + "ms",
- elapsed <= targetTime);
+ + " sequences and " + numAnns + " annotations took " + elapsed
+ + "ms");
}
/**
- * Timing test for sorting randomly sorted annotations
+ * Timing tests for sorting randomly sorted annotations for various sizes.
*/
- @Test
+ @Test(groups = { "Functional" })
public void testSort_timingUnsorted()
{
- final int numSeqs = 2000;
- final int numAnns = 4000;
- al = buildAlignment(numSeqs);
- anns = buildAnnotations(numAnns);
+ testTiming_unsorted(50, 100);
+ testTiming_unsorted(500, 1000);
+ testTiming_unsorted(5000, 10000);
+ }
+
+ /**
+ * Generate annotations randomly sorted with respect to sequences, and time
+ * sorting.
+ *
+ * @param numSeqs
+ * @param numAnns
+ */
+ private void testTiming_unsorted(final int numSeqs, final int numAnns)
+ {
+ Alignment alignment = buildAlignment(numSeqs);
+ AlignmentAnnotation[] annotations = buildAnnotations(numAnns);
/*
* Set the annotations in random order with respect to the sequences
*/
Random r = new Random();
- final SequenceI[] sequences = al.getSequencesArray();
- for (int i = 0; i < anns.length; i++)
+ final SequenceI[] sequences = alignment.getSequencesArray();
+ for (int i = 0; i < annotations.length; i++)
{
SequenceI randomSequenceRef = sequences[r.nextInt(sequences.length)];
- anns[i].sequenceRef = randomSequenceRef;
- anns[i].label = "label" + i;
+ annotations[i].sequenceRef = randomSequenceRef;
+ annotations[i].label = "label" + i;
}
long startTime = System.currentTimeMillis();
- AnnotationSorter testee = new AnnotationSorter(al, false);
- testee.sort(anns, SequenceAnnotationOrder.SEQUENCE_AND_LABEL);
+ AnnotationSorter testee = new AnnotationSorter(alignment, false, false);
+ testee.sort(annotations, SequenceAnnotationOrder.SEQUENCE_AND_LABEL);
long endTime = System.currentTimeMillis();
final long elapsed = endTime - startTime;
System.out.println("Timing test for unsorted " + numSeqs
- + " sequences and "
- + numAnns + " annotations took " + elapsed + "ms");
+ + " sequences and " + numAnns + " annotations took " + elapsed
+ + "ms");
}
/**
* Timing test for sorting annotations with a limited range of types (labels).
*/
- @Test
+ @Test(groups = { "Functional" })
public void testSort_timingSemisorted()
{
- final int numSeqs = 2000;
- final int numAnns = 4000;
- al = buildAlignment(numSeqs);
- anns = buildAnnotations(numAnns);
+ testTiming_semiSorted(50, 100);
+ testTiming_semiSorted(500, 1000);
+ testTiming_semiSorted(5000, 10000);
+ }
+
+ /**
+ * Mimic 'semi-sorted' annotations:
+ * <ul>
+ * <li>set up in sequence order, with randomly assigned labels from a limited
+ * range</li>
+ * <li>sort by label and sequence order, report timing</li>
+ * <li>resort by sequence and label, report timing</li>
+ * <li>resort by label and sequence, report timing</li>
+ * </ul>
+ *
+ * @param numSeqs
+ * @param numAnns
+ */
+ private void testTiming_semiSorted(final int numSeqs, final int numAnns)
+ {
+ Alignment alignment = buildAlignment(numSeqs);
+ AlignmentAnnotation[] annotations = buildAnnotations(numAnns);
- String[] labels = new String[]
- { "label1", "label2", "label3", "label4", "label5", "label6" };
+ String[] labels = new String[] { "label1", "label2", "label3",
+ "label4", "label5", "label6" };
/*
* Set the annotations in sequence order with randomly assigned labels.
*/
Random r = new Random();
- final SequenceI[] sequences = al.getSequencesArray();
- for (int i = 0; i < anns.length; i++)
+ final SequenceI[] sequences = alignment.getSequencesArray();
+ for (int i = 0; i < annotations.length; i++)
{
SequenceI sequenceRef = sequences[i % sequences.length];
- anns[i].sequenceRef = sequenceRef;
- anns[i].label = labels[r.nextInt(labels.length)];
+ annotations[i].sequenceRef = sequenceRef;
+ annotations[i].label = labels[r.nextInt(labels.length)];
}
long startTime = System.currentTimeMillis();
- AnnotationSorter testee = new AnnotationSorter(al, false);
- testee.sort(anns, SequenceAnnotationOrder.LABEL_AND_SEQUENCE);
+ AnnotationSorter testee = new AnnotationSorter(alignment, false, false);
+ testee.sort(annotations, SequenceAnnotationOrder.LABEL_AND_SEQUENCE);
long endTime = System.currentTimeMillis();
long elapsed = endTime - startTime;
- System.out.println("Sort by type for semisorted " + numSeqs
- + " sequences and "
- + numAnns + " annotations took " + elapsed + "ms");
+ System.out.println("Sort by label for semisorted " + numSeqs
+ + " sequences and " + numAnns + " annotations took " + elapsed
+ + "ms");
// now resort by sequence
startTime = System.currentTimeMillis();
- testee.sort(anns, SequenceAnnotationOrder.SEQUENCE_AND_LABEL);
+ testee.sort(annotations, SequenceAnnotationOrder.SEQUENCE_AND_LABEL);
endTime = System.currentTimeMillis();
elapsed = endTime - startTime;
System.out.println("Resort by sequence for semisorted " + numSeqs
+ " sequences and " + numAnns + " annotations took " + elapsed
+ "ms");
- // now resort by type
+ // now resort by label
startTime = System.currentTimeMillis();
- testee.sort(anns, SequenceAnnotationOrder.LABEL_AND_SEQUENCE);
+ testee.sort(annotations, SequenceAnnotationOrder.LABEL_AND_SEQUENCE);
endTime = System.currentTimeMillis();
elapsed = endTime - startTime;
- System.out.println("Resort by type for semisorted " + numSeqs
+ System.out.println("Resort by label for semisorted " + numSeqs
+ " sequences and " + numAnns + " annotations took " + elapsed
+ "ms");
}
+
+ /**
+ * Test that sort does nothing if sort order is CUSTOM (manually ordered
+ * annotations)
+ */
+ @Test(groups = { "Functional" })
+ public void testSort_custom()
+ {
+ // @formatter:off
+ anns[0].sequenceRef = al.getSequenceAt(1); anns[0].label = "label0";
+ anns[1].sequenceRef = al.getSequenceAt(3); anns[1].label = "structure";
+ anns[2].sequenceRef = al.getSequenceAt(3); anns[2].label = "iron";
+ anns[3].autoCalculated = true; anns[3].label = "Quality";
+ anns[4].autoCalculated = true; anns[4].label = "Consensus";
+ anns[5].sequenceRef = al.getSequenceAt(0); anns[5].label = "label5";
+ anns[6].sequenceRef = al.getSequenceAt(3); anns[6].label = "IRP";
+ // @formatter:on
+
+ /*
+ * showAutocalcAbove=true ignored if CUSTOM ordering
+ */
+ AnnotationSorter testee = new AnnotationSorter(al, true, false);
+ testee.sort(anns, SequenceAnnotationOrder.CUSTOM);
+ assertEquals("label0", anns[0].label); // all unchanged
+ assertEquals("structure", anns[1].label);
+ assertEquals("iron", anns[2].label);
+ assertEquals("Quality", anns[3].label);
+ assertEquals("Consensus", anns[4].label);
+ assertEquals("label5", anns[5].label);
+ assertEquals("IRP", anns[6].label);
+ }
+
+ /**
+ * Test of sorting only autocalculated annotations
+ */
+ @Test(groups = { "Functional" })
+ public void testSort_autocalcOnly()
+ {
+ // @formatter:off
+ anns[0].sequenceRef = al.getSequenceAt(1); anns[0].label = "label0";
+ anns[1].sequenceRef = al.getSequenceAt(3); anns[1].label = "structure";
+ anns[2].sequenceRef = al.getSequenceAt(3); anns[2].label = "iron";
+ anns[3].autoCalculated = true; anns[3].label = "Quality";
+ anns[4].autoCalculated = true; anns[4].label = "Consensus";
+ anns[5].sequenceRef = al.getSequenceAt(0); anns[5].label = "label5";
+ anns[6].sequenceRef = al.getSequenceAt(3); anns[6].label = "IRP";
+ // @formatter:on
+
+ /*
+ * showAutocalcAbove=true, autocalcOnly=true
+ */
+ AnnotationSorter testee = new AnnotationSorter(al, true, true);
+ testee.sort(anns, SequenceAnnotationOrder.LABEL_AND_SEQUENCE);
+ assertEquals("Quality", anns[0].label); // moved to top
+ assertEquals("Consensus", anns[1].label); // moved to top
+ assertEquals("label0", anns[2].label); // the rest unchanged
+ assertEquals("structure", anns[3].label);
+ assertEquals("iron", anns[4].label);
+ assertEquals("label5", anns[5].label);
+ assertEquals("IRP", anns[6].label);
+
+ /*
+ * showAutocalcAbove=false, autocalcOnly=true
+ */
+ testee = new AnnotationSorter(al, false, true);
+ testee.sort(anns, SequenceAnnotationOrder.LABEL_AND_SEQUENCE);
+ assertEquals("label0", anns[0].label); // unchanged
+ assertEquals("structure", anns[1].label);
+ assertEquals("iron", anns[2].label);
+ assertEquals("label5", anns[3].label);
+ assertEquals("IRP", anns[4].label);
+ assertEquals("Quality", anns[5].label); // moved to bottom
+ assertEquals("Consensus", anns[6].label); // moved to bottom
+ }
}