import jalview.util.MapList;
import jalview.util.MappingUtils;
+import java.util.AbstractList;
import java.util.ArrayList;
import java.util.List;
/*
* Data bean to hold mappings from one sequence to another
*/
- private class SequenceToSequenceMapping
+ public class SequenceToSequenceMapping
{
private SequenceI fromSeq;
return String.format("From %s %s", fromSeq.getName(),
mapping.toString());
}
+
+ /**
+ * Returns a hashCode derived from the hashcodes of the mappings
+ *
+ * @see SequenceToSequenceMapping#hashCode()
+ */
+ @Override
+ public int hashCode()
+ {
+ return mappings.hashCode();
+ }
+
+ /**
+ * Answers true if the objects hold the same mapping between the same two
+ * sequences
+ *
+ * @see Mapping#equals
+ */
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (!(obj instanceof SequenceToSequenceMapping))
+ {
+ return false;
+ }
+ SequenceToSequenceMapping that = (SequenceToSequenceMapping) obj;
+ if (this.mapping == null)
+ {
+ return that.mapping == null;
+ }
+ return this.mapping.equals(that.mapping);
+ }
+
+ public SequenceI getFromSeq()
+ {
+ return fromSeq;
+ }
+
+ public Mapping getMapping()
+ {
+ return mapping;
+ }
}
private List<SequenceToSequenceMapping> mappings;
/*
* if we already hold a mapping between these sequences, just add to it
+ * note that 'adding' a duplicate map does nothing; this protects against
+ * creating duplicate mappings in AlignedCodonFrame
*/
for (SequenceToSequenceMapping ssm : mappings)
{
}
return null;
}
+
+ /**
+ * Returns a hashcode derived from the list of sequence mappings
+ *
+ * @see SequenceToSequenceMapping#hashCode()
+ * @see AbstractList#hashCode()
+ */
+ @Override
+ public int hashCode()
+ {
+ return this.mappings.hashCode();
+ }
+
+ /**
+ * Two AlignedCodonFrame objects are equal if they hold the same ordered list
+ * of mappings
+ *
+ * @see SequenceToSequenceMapping#
+ */
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (!(obj instanceof AlignedCodonFrame))
+ {
+ return false;
+ }
+ return this.mappings.equals(((AlignedCodonFrame) obj).mappings);
+ }
+
+ public List<SequenceToSequenceMapping> getMappings()
+ {
+ return mappings;
+ }
}
/**
* Equals that compares both the to references and MapList mappings.
*
- * @param other
+ * @param o
* @return
+ * @see MapList#equals
*/
@Override
public boolean equals(Object o)
{
- // TODO should override Object.hashCode() to ensure that equal objects have
- // equal hashcodes
if (o == null || !(o instanceof Mapping))
{
return false;
}
/**
+ * Returns a hashCode made from the sequence and maplist
+ */
+ @Override
+ public int hashCode()
+ {
+ int hashCode = (this.to == null ? 1 : this.to.hashCode());
+ if (this.map != null)
+ {
+ hashCode = hashCode * 31 + this.map.hashCode();
+ }
+
+ return hashCode;
+ }
+
+ /**
* get the 'initial' position in the associated sequence for a position in the
* mapped reference frame
*
@Override
public boolean equals(Object o)
{
- // TODO should also override hashCode to ensure equal objects have equal
- // hashcodes
if (o == null || !(o instanceof MapList))
{
return false;
}
/**
+ * Returns a hashcode made from the fromRatio, toRatio, and from/to ranges
+ */
+ @Override
+ public int hashCode()
+ {
+ int hashCode = 31 * fromRatio;
+ hashCode = 31 * hashCode + toRatio;
+ hashCode = 31 * hashCode + fromShifts.toArray().hashCode();
+ hashCode = 31 * hashCode + toShifts.toArray().hashCode();
+ return hashCode;
+ }
+
+ /**
* Returns the 'from' ranges as {[start1, end1], [start2, end2], ...}
*
* @return
*/
public void addMapList(MapList map)
{
+ if (this.equals(map))
+ {
+ return;
+ }
this.fromLowest = Math.min(fromLowest, map.fromLowest);
this.toLowest = Math.min(toLowest, map.toLowest);
this.fromHighest = Math.max(fromHighest, map.fromHighest);
}
return forwardStrand;
}
+
}
assertArrayEquals(new int[] { 2, 2 },
acf.getMappedRegion(seq2, seq1, 6));
}
+
+ /**
+ * Tests for addMap. See also tests for MapList.addMapList
+ */
+ @Test(groups = { "Functional" })
+ public void testAddMap()
+ {
+ final Sequence seq1 = new Sequence("Seq1", "c-G-TA-gC-gT-T");
+ seq1.createDatasetSequence();
+ final Sequence aseq1 = new Sequence("Seq1", "-V-L");
+ aseq1.createDatasetSequence();
+
+ AlignedCodonFrame acf = new AlignedCodonFrame();
+ MapList map = new MapList(new int[] { 2, 4, 6, 6, 8, 9 }, new int[] {
+ 1, 2 }, 3, 1);
+ acf.addMap(seq1.getDatasetSequence(), aseq1.getDatasetSequence(), map);
+ assertEquals(1, acf.getMappingsFromSequence(seq1).size());
+ Mapping before = acf.getMappingsFromSequence(seq1).get(0);
+
+ /*
+ * add the same map again, verify it doesn't get duplicated
+ */
+ acf.addMap(seq1.getDatasetSequence(), aseq1.getDatasetSequence(), map);
+ assertEquals(1, acf.getMappingsFromSequence(seq1).size());
+ assertSame(before, acf.getMappingsFromSequence(seq1).get(0));
+ }
}
s);
}
+ /**
+ * Test that confirms adding a map twice does nothing
+ */
+ @Test(groups = { "Functional" })
+ public void testAddMapList_sameMap()
+ {
+ MapList ml = new MapList(new int[] { 11, 15, 20, 25, 35, 30 },
+ new int[] { 72, 22 }, 1, 3);
+ String before = ml.toString();
+ ml.addMapList(ml);
+ assertEquals(before, ml.toString());
+ ml.addMapList(new MapList(ml));
+ assertEquals(before, ml.toString());
+ }
+
@Test(groups = { "Functional" })
public void testAddMapList_contiguous()
{