JAL-1152 prototype of new Annotations menu with sort options
[jalview.git] / test / jalview / analysis / AnnotationSorterTest.java
diff --git a/test/jalview/analysis/AnnotationSorterTest.java b/test/jalview/analysis/AnnotationSorterTest.java
new file mode 100644 (file)
index 0000000..879aa9b
--- /dev/null
@@ -0,0 +1,175 @@
+package jalview.analysis;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceI;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class AnnotationSorterTest
+{
+  private static final int NUM_SEQS = 6;
+
+  private static final int NUM_ANNS = 7;
+
+  private static final String SS = "secondary structure";
+
+  AlignmentAnnotation[] anns = new AlignmentAnnotation[0];
+
+  Alignment al = null;
+
+  /*
+   * Set up 6 sequences and 7 annotations.
+   */
+  @Before
+  public void setUp()
+  {
+    al = buildAlignment(NUM_SEQS);
+    anns = buildAnnotations(NUM_ANNS);
+  }
+
+  /**
+   * Construct an array of numAnns annotations
+   * 
+   * @param numAnns
+   * 
+   * @return
+   */
+  protected AlignmentAnnotation[] buildAnnotations(int numAnns)
+  {
+    List<AlignmentAnnotation> annlist = new ArrayList<AlignmentAnnotation>();
+    for (int i = 0; i < numAnns; i++)
+    {
+      AlignmentAnnotation ann = new AlignmentAnnotation(SS + i, "", 0);
+      annlist.add(ann);
+    }
+    return annlist.toArray(anns);
+  }
+
+  /**
+   * Make an alignment with numSeqs sequences in it.
+   * 
+   * @param numSeqs
+   * 
+   * @return
+   */
+  private Alignment buildAlignment(int numSeqs)
+  {
+    SequenceI[] seqs = new Sequence[numSeqs];
+    for (int i = 0; i < numSeqs; i++)
+    {
+      seqs[i] = new Sequence("Sequence" + i, "axrdkfp");
+    }
+    return new Alignment(seqs);
+  }
+
+  /**
+   * Test sorting by annotation type (label) within sequence order, including
+   * <ul>
+   * <li>annotations with no sequence reference - sort to end keeping mutual
+   * ordering</li>
+   * <li>annotations with sequence ref = sort in sequence order</li>
+   * <li>multiple annotations for same sequence ref - sort by label
+   * non-case-specific</li>
+   * <li>annotations with reference to sequence not in alignment - treat like no
+   * sequence ref</li>
+   * </ul>
+   */
+  @Test
+  public void testSortBySequenceAndType()
+  {
+    // @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[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);
+    testee.sortBySequenceAndType(anns);
+    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("Consensus", anns[6].label); // retain ordering
+  }
+
+  /**
+   * Test sorting by annotation type (label) within sequence order, including
+   * <ul>
+   * <li>annotations with no sequence reference - sort to end keeping mutual
+   * ordering</li>
+   * <li>annotations with sequence ref = sort in sequence order</li>
+   * <li>multiple annotations for same sequence ref - sort by label
+   * non-case-specific</li>
+   * <li>annotations with reference to sequence not in alignment - treat like no
+   * sequence ref</li>
+   * </ul>
+   */
+  @Test
+  public void testSortByTypeAndSequence()
+  {
+    // @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[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);
+    testee.sortByTypeAndSequence(anns);
+    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("Consensus", anns[6].label); // retain ordering
+  }
+
+  @Test
+  public void testSortBySequenceAndType_timing()
+  {
+    final long targetTime = 300;        // ms
+    final int numSeqs = 10000;
+    final int numAnns = 20000;
+    al = buildAlignment(numSeqs);
+    anns = 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++)
+    {
+      SequenceI randomSequenceRef = sequences[r.nextInt(sequences.length)];
+      anns[i].sequenceRef = randomSequenceRef;
+    }
+    long startTime = System.currentTimeMillis();
+    AnnotationSorter testee = new AnnotationSorter(al);
+    testee.sortByTypeAndSequence(anns);
+    long endTime = System.currentTimeMillis();
+    final long elapsed = endTime - startTime;
+    System.out.println("Timing test for " + numSeqs + " sequences and "
+            + numAnns + " annotations took " + elapsed + "ms");
+    assertTrue("Sort took more than " + targetTime + "ms",
+            elapsed <= targetTime);
+  }
+}