From cbdd0bde03d210649623b4576dd75e6c25fe4582 Mon Sep 17 00:00:00 2001 From: gmungoc Date: Tue, 14 Jun 2016 08:05:53 +0100 Subject: [PATCH] JAL-1686 JAL-2110 equals and/or hashCode method added --- src/jalview/datamodel/AlignedCodonFrame.java | 80 ++++++++++++++++++++- src/jalview/datamodel/Mapping.java | 20 +++++- src/jalview/util/MapList.java | 20 +++++- test/jalview/datamodel/AlignedCodonFrameTest.java | 26 +++++++ test/jalview/util/MapListTest.java | 15 ++++ 5 files changed, 155 insertions(+), 6 deletions(-) diff --git a/src/jalview/datamodel/AlignedCodonFrame.java b/src/jalview/datamodel/AlignedCodonFrame.java index 6d6cdb5..5d00b6b 100644 --- a/src/jalview/datamodel/AlignedCodonFrame.java +++ b/src/jalview/datamodel/AlignedCodonFrame.java @@ -23,6 +23,7 @@ package jalview.datamodel; import jalview.util.MapList; import jalview.util.MappingUtils; +import java.util.AbstractList; import java.util.ArrayList; import java.util.List; @@ -36,7 +37,7 @@ public class AlignedCodonFrame /* * Data bean to hold mappings from one sequence to another */ - private class SequenceToSequenceMapping + public class SequenceToSequenceMapping { private SequenceI fromSeq; @@ -57,6 +58,48 @@ public class AlignedCodonFrame 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 mappings; @@ -90,6 +133,8 @@ public class AlignedCodonFrame /* * 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) { @@ -674,4 +719,37 @@ public class AlignedCodonFrame } 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 getMappings() + { + return mappings; + } } diff --git a/src/jalview/datamodel/Mapping.java b/src/jalview/datamodel/Mapping.java index bd83fe9..b4489e2 100644 --- a/src/jalview/datamodel/Mapping.java +++ b/src/jalview/datamodel/Mapping.java @@ -356,14 +356,13 @@ public class Mapping /** * 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; @@ -390,6 +389,21 @@ public class Mapping } /** + * 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 * diff --git a/src/jalview/util/MapList.java b/src/jalview/util/MapList.java index ab811a9..cae968e 100644 --- a/src/jalview/util/MapList.java +++ b/src/jalview/util/MapList.java @@ -88,8 +88,6 @@ public class MapList @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; @@ -112,6 +110,19 @@ public class MapList } /** + * 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 @@ -992,6 +1003,10 @@ public class MapList */ 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); @@ -1087,4 +1102,5 @@ public class MapList } return forwardStrand; } + } diff --git a/test/jalview/datamodel/AlignedCodonFrameTest.java b/test/jalview/datamodel/AlignedCodonFrameTest.java index cd8a1e3..f2dd968 100644 --- a/test/jalview/datamodel/AlignedCodonFrameTest.java +++ b/test/jalview/datamodel/AlignedCodonFrameTest.java @@ -451,4 +451,30 @@ public class AlignedCodonFrameTest 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)); + } } diff --git a/test/jalview/util/MapListTest.java b/test/jalview/util/MapListTest.java index d4ed0ea..ba298c5 100644 --- a/test/jalview/util/MapListTest.java +++ b/test/jalview/util/MapListTest.java @@ -563,6 +563,21 @@ public class MapListTest 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() { -- 1.7.10.2