From: Mateusz Warowny Date: Mon, 30 Oct 2023 15:27:05 +0000 (+0100) Subject: Merge branch 'bug/JAL-4313-make-visible-annot-fix' into JAL-1601-direct-jpred4-rest... X-Git-Url: http://source.jalview.org/gitweb/?a=commitdiff_plain;h=fa529a2a75da021dd95a8b13205c2a6e4c5e460f;hp=5fe8a7444f60733f195cd812e75d7e873e688880;p=jalview.git Merge branch 'bug/JAL-4313-make-visible-annot-fix' into JAL-1601-direct-jpred4-rest-service --- diff --git a/src/jalview/datamodel/AlignmentAnnotation.java b/src/jalview/datamodel/AlignmentAnnotation.java index 4ebb27f..0e0239a 100755 --- a/src/jalview/datamodel/AlignmentAnnotation.java +++ b/src/jalview/datamodel/AlignmentAnnotation.java @@ -1581,7 +1581,7 @@ public class AlignmentAnnotation { if (annotations != null) { - makeVisibleAnnotation(0, annotations.length, hiddenColumns); + makeVisibleAnnotation(0, annotations.length - 1, hiddenColumns); } } diff --git a/test/jalview/datamodel/AlignmentAnnotationTests.java b/test/jalview/datamodel/AlignmentAnnotationTests.java index f9e99d0..6ffbfa9 100644 --- a/test/jalview/datamodel/AlignmentAnnotationTests.java +++ b/test/jalview/datamodel/AlignmentAnnotationTests.java @@ -20,18 +20,22 @@ */ package jalview.datamodel; -import static org.testng.Assert.assertNull; -import static org.testng.AssertJUnit.assertEquals; - import jalview.analysis.AlignSeq; import jalview.gui.JvOptionPane; import jalview.io.AppletFormatAdapter; import jalview.io.FileFormat; - import org.testng.Assert; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +import static jalview.datamodel.Annotation.EMPTY_ANNOTATION; +import static jalview.testutils.Matchers.matchesAnnotations; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.nullValue; +import static org.testng.Assert.assertNull; +import static org.testng.AssertJUnit.assertEquals; + public class AlignmentAnnotationTests { @@ -57,7 +61,7 @@ public class AlignmentAnnotationTests for (String key : alo.getProperties()) { assertEquals("Property mismatch", alo.getProperty(key), - alc.getProperty(key)); + alc.getProperty(key)); } } @@ -71,11 +75,11 @@ public class AlignmentAnnotationTests Annotation[] al = new Annotation[sq.getLength()]; for (int i = 0; i < al.length; i++) { - al[i] = new Annotation(new Annotation("" + sq.getCharAt(i), "", - (char) 0, sq.findPosition(i))); + al[i] = new Annotation(new Annotation("" + sq.getCharAt(i), "", (char) 0, + sq.findPosition(i))); } - AlignmentAnnotation alan = new AlignmentAnnotation( - "For " + sq.getName(), "Fake alignment annot", al); + AlignmentAnnotation alan = new AlignmentAnnotation("For " + sq.getName(), + "Fake alignment annot", al); // create a sequence mapping for the annotation vector in its current state alan.createSequenceMapping(sq, sq.getStart(), false); alan.setProperty("CreatedBy", "createAnnotation"); @@ -90,20 +94,18 @@ public class AlignmentAnnotationTests */ public static void testAnnotTransfer(AlignmentAnnotation ala) { - assertEquals( - "Failed - need annotation created by createAnnotation method", - ala.description, "Fake alignment annot"); + assertEquals("Failed - need annotation created by createAnnotation method", + ala.description, "Fake alignment annot"); ala.adjustForAlignment(); for (int p = 0; p < ala.annotations.length; p++) { if (ala.annotations[p] != null) { assertEquals( - "Mismatch at position " + p - + " between annotation position value and sequence" - + ala.annotations[p], - (int) ala.annotations[p].value, - ala.sequenceRef.findPosition(p)); + "Mismatch at position " + p + + " between annotation position value and sequence" + + ala.annotations[p], + (int) ala.annotations[p].value, ala.sequenceRef.findPosition(p)); } } } @@ -127,8 +129,7 @@ public class AlignmentAnnotationTests AlignmentAnnotation origTo = sqTo.getAnnotation()[0]; createAnnotation(sqFrom); AlignmentAnnotation origFrom = sqFrom.getAnnotation()[0]; - AlignSeq align = AlignSeq.doGlobalNWAlignment(sqFrom, sqTo, - AlignSeq.PEP); + AlignSeq align = AlignSeq.doGlobalNWAlignment(sqFrom, sqTo, AlignSeq.PEP); SequenceI alSeq1 = new Sequence(sqFrom.getName(), align.getAStr1()); alSeq1.setStart(sqFrom.getStart() + align.getSeq1Start() - 1); alSeq1.setEnd(sqFrom.getStart() + align.getSeq1End() - 1); @@ -137,21 +138,23 @@ public class AlignmentAnnotationTests alSeq2.setStart(sqTo.getStart() + align.getSeq2Start() - 1); alSeq2.setEnd(sqTo.getStart() + align.getSeq2End() - 1); alSeq2.setDatasetSequence(sqTo); - System.out.println(new AppletFormatAdapter().formatSequences( - FileFormat.Stockholm, new Alignment(new SequenceI[] - { sqFrom, alSeq1, sqTo, alSeq2 }), true)); + System.out + .println(new AppletFormatAdapter() + .formatSequences(FileFormat.Stockholm, + new Alignment(new SequenceI[] { sqFrom, alSeq1, sqTo, alSeq2 }), + true)); Mapping mp = align.getMappingFromS1(false); AlignmentAnnotation almap1 = new AlignmentAnnotation( - sqTo.getAnnotation()[0]); + sqTo.getAnnotation()[0]); almap1.liftOver(sqFrom, mp); assertEquals(almap1.sequenceRef, sqFrom); alSeq1.addAlignmentAnnotation(almap1); almap1.setSequenceRef(alSeq1); almap1.adjustForAlignment(); AlignmentAnnotation almap2 = new AlignmentAnnotation( - sqFrom.getAnnotation()[0]); + sqFrom.getAnnotation()[0]); almap2.liftOver(sqTo, mp); assertEquals(almap2.sequenceRef, sqTo); @@ -162,15 +165,15 @@ public class AlignmentAnnotationTests AlignmentI all = new Alignment(new SequenceI[] { alSeq1, alSeq2 }); all.addAnnotation(almap1); all.addAnnotation(almap2); - System.out.println(new AppletFormatAdapter() + System.out + .println(new AppletFormatAdapter() .formatSequences(FileFormat.Stockholm, all, true)); for (int p = 0; p < alSeq1.getLength(); p++) { Annotation orig1, trans1, orig2, trans2; trans2 = almap2.annotations[p]; - orig2 = origFrom.annotations[alSeq1.findPosition(p) - - sqFrom.getStart()]; + orig2 = origFrom.annotations[alSeq1.findPosition(p) - sqFrom.getStart()]; orig1 = origTo.annotations[alSeq2.findPosition(p) - sqTo.getStart()]; trans1 = almap1.annotations[p]; if (trans1 == trans2) @@ -178,20 +181,18 @@ public class AlignmentAnnotationTests System.out.println("Pos " + p + " mismatch"); continue; } - assertEquals( - "Mismatch on Original From and transferred annotation on 2", - (orig2 != null) ? orig2.toString() : null, - (trans2 != null) ? trans2.toString() : null); - assertEquals( - "Mismatch on Original To and transferred annotation on 1", - (orig1 != null) ? orig1.toString() : null, - (trans1 != null) ? trans1.toString() : null); + assertEquals("Mismatch on Original From and transferred annotation on 2", + (orig2 != null) ? orig2.toString() : null, + (trans2 != null) ? trans2.toString() : null); + assertEquals("Mismatch on Original To and transferred annotation on 1", + (orig1 != null) ? orig1.toString() : null, + (trans1 != null) ? trans1.toString() : null); String alm1 = "" + (almap1.annotations.length > p - ? almap1.annotations[p].displayCharacter - : "Out of range"); + ? almap1.annotations[p].displayCharacter + : "Out of range"); String alm2 = "" + (almap2.annotations.length > p - ? almap2.annotations[p].displayCharacter - : "Out of range"); + ? almap2.annotations[p].displayCharacter + : "Out of range"); assertEquals("Position " + p + " " + alm1 + " " + alm2, alm1, alm2); } } @@ -205,10 +206,10 @@ public class AlignmentAnnotationTests /* * Annotate positions 3/4/5 (CDE) with values 1/2/3 */ - Annotation[] anns = new Annotation[] { null, null, new Annotation(1), - new Annotation(2), new Annotation(3) }; + Annotation[] anns = new Annotation[] { + null, null, new Annotation(1), new Annotation(2), new Annotation(3) }; AlignmentAnnotation ann = new AlignmentAnnotation("SS", - "secondary structure", anns); + "secondary structure", anns); seq.addAlignmentAnnotation(ann); /* @@ -247,7 +248,7 @@ public class AlignmentAnnotationTests public void testGetDefaultRnaHelixSymbol() { AlignmentAnnotation ann = new AlignmentAnnotation("SS", - "secondary structure", null); + "secondary structure", null); assertEquals("(", ann.getDefaultRnaHelixSymbol(4)); Annotation[] anns = new Annotation[20]; @@ -276,7 +277,7 @@ public class AlignmentAnnotationTests for (int i = 0; i < expected.length(); i++) { assertEquals("column " + i, String.valueOf(expected.charAt(i)), - ann.getDefaultRnaHelixSymbol(i)); + ann.getDefaultRnaHelixSymbol(i)); } /* @@ -296,7 +297,7 @@ public class AlignmentAnnotationTests for (int i = 0; i < expected.length(); i++) { assertEquals("column " + i, String.valueOf(expected.charAt(i)), - ann.getDefaultRnaHelixSymbol(i)); + ann.getDefaultRnaHelixSymbol(i)); } } @@ -319,28 +320,32 @@ public class AlignmentAnnotationTests AlignmentAnnotation ann = null; ann = new AlignmentAnnotation("an", "some an", null); - Assert.assertFalse(ann.isQuantitative(), + Assert + .assertFalse(ann.isQuantitative(), "Empty annotation set should not be quantitative."); ann = new AlignmentAnnotation("an", "some an", - new Annotation[] - { newAnnotation("4"), newAnnotation("1"), newAnnotation("1"), - newAnnotation("0.1"), newAnnotation("0.3") }); - Assert.assertTrue(ann.isQuantitative(), + new Annotation[] { + newAnnotation("4"), newAnnotation("1"), newAnnotation("1"), + newAnnotation("0.1"), newAnnotation("0.3") }); + Assert + .assertTrue(ann.isQuantitative(), "All numbers annotation set should be quantitative."); ann = new AlignmentAnnotation("an", "some an", - new Annotation[] - { newAnnotation("E"), newAnnotation("E"), newAnnotation("E"), - newAnnotation("E"), newAnnotation("E") }); - Assert.assertFalse(ann.isQuantitative(), + new Annotation[] { + newAnnotation("E"), newAnnotation("E"), newAnnotation("E"), + newAnnotation("E"), newAnnotation("E") }); + Assert + .assertFalse(ann.isQuantitative(), "All 'E' annotation set should not be quantitative."); ann = new AlignmentAnnotation("an", "some an", - new Annotation[] - { newAnnotation("E"), newAnnotation("1"), newAnnotation("2"), - newAnnotation("3"), newAnnotation("E") }); - Assert.assertTrue(ann.isQuantitative(), + new Annotation[] { + newAnnotation("E"), newAnnotation("1"), newAnnotation("2"), + newAnnotation("3"), newAnnotation("E") }); + Assert + .assertTrue(ann.isQuantitative(), "Mixed 'E' annotation set should be quantitative."); } @@ -348,16 +353,15 @@ public class AlignmentAnnotationTests public void testMakeVisibleAnnotation() { HiddenColumns h = new HiddenColumns(); - Annotation[] anns = new Annotation[] { null, null, new Annotation(1), - new Annotation(2), new Annotation(3), null, null, new Annotation(4), - new Annotation(5), new Annotation(6), new Annotation(7), - new Annotation(8) }; - AlignmentAnnotation ann = new AlignmentAnnotation("an", "some an", - anns); + Annotation[] anns = new Annotation[] { + null, null, new Annotation(1), new Annotation(2), new Annotation(3), + null, null, new Annotation(4), new Annotation(5), new Annotation(6), + new Annotation(7), new Annotation(8) }; + AlignmentAnnotation ann = new AlignmentAnnotation("an", "some an", anns); // null annotations AlignmentAnnotation emptyann = new AlignmentAnnotation("an", "some ann", - null); + null); emptyann.makeVisibleAnnotation(h); assertNull(emptyann.annotations); @@ -387,10 +391,10 @@ public class AlignmentAnnotationTests assertEquals(3.0f, ann.annotations[1].value); assertNull(ann.annotations[2]); - anns = new Annotation[] { null, null, new Annotation(1), - new Annotation(2), new Annotation(3), null, null, new Annotation(4), - new Annotation(5), new Annotation(6), new Annotation(7), - new Annotation(8) }; + anns = new Annotation[] { + null, null, new Annotation(1), new Annotation(2), new Annotation(3), + null, null, new Annotation(4), new Annotation(5), new Annotation(6), + new Annotation(7), new Annotation(8) }; ann = new AlignmentAnnotation("an", "some an", anns); h.hideColumns(4, 7); ann.makeVisibleAnnotation(1, 9, h); @@ -401,10 +405,10 @@ public class AlignmentAnnotationTests assertEquals(5.0f, ann.annotations[3].value); assertEquals(6.0f, ann.annotations[4].value); - anns = new Annotation[] { null, null, new Annotation(1), - new Annotation(2), new Annotation(3), null, null, new Annotation(4), - new Annotation(5), new Annotation(6), new Annotation(7), - new Annotation(8) }; + anns = new Annotation[] { + null, null, new Annotation(1), new Annotation(2), new Annotation(3), + null, null, new Annotation(4), new Annotation(5), new Annotation(6), + new Annotation(7), new Annotation(8) }; ann = new AlignmentAnnotation("an", "some an", anns); h.hideColumns(1, 2); ann.makeVisibleAnnotation(1, 9, h); @@ -413,12 +417,12 @@ public class AlignmentAnnotationTests assertEquals(5.0f, ann.annotations[1].value); assertEquals(6.0f, ann.annotations[2].value); - anns = new Annotation[] { null, null, new Annotation(1), - new Annotation(2), new Annotation(3), null, null, new Annotation(4), - new Annotation(5), new Annotation(6), new Annotation(7), - new Annotation(8), new Annotation(9), new Annotation(10), - new Annotation(11), new Annotation(12), new Annotation(13), - new Annotation(14), new Annotation(15) }; + anns = new Annotation[] { + null, null, new Annotation(1), new Annotation(2), new Annotation(3), + null, null, new Annotation(4), new Annotation(5), new Annotation(6), + new Annotation(7), new Annotation(8), new Annotation(9), + new Annotation(10), new Annotation(11), new Annotation(12), + new Annotation(13), new Annotation(14), new Annotation(15) }; ann = new AlignmentAnnotation("an", "some an", anns); h = new HiddenColumns(); h.hideColumns(5, 18); @@ -431,4 +435,154 @@ public class AlignmentAnnotationTests assertNull(ann.annotations[0]); assertNull(ann.annotations[4]); } + + @Test(groups = "Functional") + public void testMakeVisibleAnnotation_NullAnnotationsAndNoColsHidden() + { + AlignmentAnnotation ann = new AlignmentAnnotation("label", "desc", null); + HiddenColumns hc = new HiddenColumns(); + ann.makeVisibleAnnotation(hc); + assertThat(ann.annotations, is(nullValue())); + } + + @Test(groups = "Functional") + public void testMakeVisibleAnnotation_NullAnnotationsAndTrim() + { + AlignmentAnnotation ann = new AlignmentAnnotation("label", "desc", null); + HiddenColumns hc = new HiddenColumns(); + ann.makeVisibleAnnotation(3, 5, hc); + assertThat(ann.annotations, is(nullValue())); + } + + @Test(groups = "Functional") + public void testMakeVisibleAnnotation_NoColsHidden() + { + Annotation[] annots = new Annotation[] { + EMPTY_ANNOTATION, EMPTY_ANNOTATION, new Annotation(1), + new Annotation(2), new Annotation(3), EMPTY_ANNOTATION, + EMPTY_ANNOTATION, new Annotation(4), new Annotation(5), + EMPTY_ANNOTATION, new Annotation(6), new Annotation(7), + new Annotation(8) }; + AlignmentAnnotation ann = new AlignmentAnnotation("label", "desc", annots); + HiddenColumns hc = new HiddenColumns(); + ann.makeVisibleAnnotation(hc); + assertThat(ann.annotations, matchesAnnotations(annots)); + } + + @Test(groups = "Functional") + public void testMakeVisibleAnnotation_HideCols() + { + Annotation[] annots = new Annotation[] { + new Annotation(0), new Annotation(1), new Annotation(2), + new Annotation(3), new Annotation(4), new Annotation(5), + new Annotation(6), new Annotation(7), new Annotation(8) }; + AlignmentAnnotation ann = new AlignmentAnnotation("label", "desc", annots); + HiddenColumns hc = new HiddenColumns(); + hc.hideColumns(2, 6); + ann.makeVisibleAnnotation(hc); + var expected = new Annotation[] { + new Annotation(0), new Annotation(1), new Annotation(7), + new Annotation(8) }; + assertThat(ann.annotations, matchesAnnotations(expected)); + } + + @Test(groups = "Functional") + public void testMakeVisibleAnnotation_ExplicitFullWidthAndHideCols() + { + Annotation[] annots = new Annotation[] { + new Annotation(0), new Annotation(1), new Annotation(2), + new Annotation(3), new Annotation(4), new Annotation(5), + new Annotation(6), new Annotation(7), new Annotation(8), + new Annotation(9), new Annotation(10), new Annotation(11) }; + AlignmentAnnotation ann = new AlignmentAnnotation("label", "desc", annots); + HiddenColumns hc = new HiddenColumns(); + hc.hideColumns(4, 7); + ann.makeVisibleAnnotation(0, 11, hc); + assertThat(ann.annotations, + matchesAnnotations(new Annotation(0), new Annotation(1), + new Annotation(2), new Annotation(3), new Annotation(8), + new Annotation(9), new Annotation(10), new Annotation(11))); + } + + @Test(groups = "Functional") + public void testMakeVisibleAnnotation_ExplicitFullWidthAndHideCols2() + { + Annotation[] annots = new Annotation[] { + new Annotation(0), new Annotation(1), new Annotation(2), + new Annotation(3), new Annotation(4), new Annotation(5), + new Annotation(6), new Annotation(7), new Annotation(8), }; + AlignmentAnnotation ann = new AlignmentAnnotation("label", "desc", annots); + HiddenColumns hc = new HiddenColumns(); + hc.hideColumns(4, 7); + ann.makeVisibleAnnotation(0, 8, hc); + assertThat(ann.annotations, + matchesAnnotations(new Annotation(0), new Annotation(1), + new Annotation(2), new Annotation(3), new Annotation(8))); + } + + @Test(groups = "Functional") + public void testMakeVisibleAnnotation_HideColsWithEmptyAnnots() + { + Annotation[] annots = new Annotation[] { + EMPTY_ANNOTATION, EMPTY_ANNOTATION, new Annotation(1), + new Annotation(2), new Annotation(3), EMPTY_ANNOTATION, + EMPTY_ANNOTATION, new Annotation(4), new Annotation(5), + EMPTY_ANNOTATION, new Annotation(6), new Annotation(7), + new Annotation(8) }; + AlignmentAnnotation ann = new AlignmentAnnotation("label", "desc", annots); + HiddenColumns hc = new HiddenColumns(); + hc.hideColumns(1, 3); + hc.hideColumns(8, 9); + ann.makeVisibleAnnotation(hc); + var expected = new Annotation[] { + EMPTY_ANNOTATION, new Annotation(3), EMPTY_ANNOTATION, EMPTY_ANNOTATION, + new Annotation(4), new Annotation(6), new Annotation(7), + new Annotation(8) }; + assertThat(ann.annotations, matchesAnnotations(expected)); + } + + @Test(groups = "Functional") + public void testMakeVisibleAnnotation_HideColsWithNullAnnots() + { + Annotation[] annots = new Annotation[] { + null, null, new Annotation(2), null, new Annotation(4), + new Annotation(5), null, null }; + AlignmentAnnotation ann = new AlignmentAnnotation("label", "desc", annots); + HiddenColumns hc = new HiddenColumns(); + hc.hideColumns(2, 4); + ann.makeVisibleAnnotation(hc); + var expected = new Annotation[] { + null, null, new Annotation(5), null, null }; + assertThat(ann.annotations, matchesAnnotations(expected)); + } + + @Test(groups = "Functional") + public void testMakeVisibleAnnotation_Truncate() + { + Annotation[] annots = new Annotation[] { + new Annotation(0), new Annotation(1), new Annotation(2), + new Annotation(3), new Annotation(4), new Annotation(5), + new Annotation(6), new Annotation(7) }; + AlignmentAnnotation ann = new AlignmentAnnotation("label", "desc", annots); + ann.makeVisibleAnnotation(3, 6, new HiddenColumns()); + assertThat(ann.annotations, matchesAnnotations(new Annotation(3), + new Annotation(4), new Annotation(5), new Annotation(6))); + } + + @Test(groups = "Functional") + public void testMakeVisibleAnnotation_TruncateAndHideColumns() + { + Annotation[] annots = new Annotation[] { + new Annotation(0), new Annotation(1), new Annotation(2), + new Annotation(3), new Annotation(4), new Annotation(5), + new Annotation(6), new Annotation(7), new Annotation(8), + new Annotation(9), new Annotation(10), new Annotation(11) }; + AlignmentAnnotation ann = new AlignmentAnnotation("label", "desc", annots); + HiddenColumns hc = new HiddenColumns(); + hc.hideColumns(4, 7); + ann.makeVisibleAnnotation(1, 9, hc); + assertThat(ann.annotations, + matchesAnnotations(new Annotation(1), new Annotation(2), + new Annotation(3), new Annotation(8), new Annotation(9))); + } } diff --git a/test/jalview/datamodel/AnnotationTest.java b/test/jalview/datamodel/AnnotationTest.java new file mode 100644 index 0000000..a8f258d --- /dev/null +++ b/test/jalview/datamodel/AnnotationTest.java @@ -0,0 +1,82 @@ +package jalview.datamodel; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.nullValue; + +import java.awt.Color; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +public class AnnotationTest +{ + @Test(groups = "Functional") + public void testConstructor_ValueOnly() + { + var annotation = new Annotation(0.5f); + assertThat(annotation.displayCharacter, nullValue()); + assertThat(annotation.description, nullValue()); + assertThat(annotation.secondaryStructure, is(' ')); + assertThat(annotation.value, is(0.5f)); + assertThat(annotation.colour, is(nullValue())); + } + + @Test(groups = "Functional") + public void testCopyConstructor_NullValue_EmptyAnnotationCreated() + { + var annotation = new Annotation((Annotation) null); + assertThat(annotation.displayCharacter, equalTo("")); + assertThat(annotation.description, equalTo("")); + assertThat(annotation.secondaryStructure, is(' ')); + assertThat(annotation.value, is(0.0f)); + assertThat(annotation.colour, is(nullValue())); + } + + @DataProvider + public Object[] emptyAnnotations() + { + return new Object[] { + Annotation.EMPTY_ANNOTATION, new Annotation(0.0f), + new Annotation((Annotation) null), + new Annotation(Annotation.EMPTY_ANNOTATION), + new Annotation("", "", ' ', 0.0f), + new Annotation(null, null, ' ', 0.0f), + new Annotation("", "", '\0', 0.0f), new Annotation("", null, ' ', 0.0f), + new Annotation(null, "", ' ', 0.0f), new Annotation(" ", "", ' ', 0.0f), + new Annotation(" .", "", ' ', 0.0f), new Annotation("", " ", ' ', 0.0f), + new Annotation("", "", ' ', 0.0f, null), + new Annotation("", " ", ' ', 0.0f), + new Annotation("", "\n", ' ', 0.0f), }; + } + + @Test(groups = "Functional", dataProvider = "emptyAnnotations") + public void testIsWhitespace_EmptyAnnotations(Annotation annot) + { + assertThat("Annotation " + annot + " is not whitespace, but should be", + annot.isWhitespace()); + } + + @DataProvider + public Object[] nonEmptyAnnotations() + { + return new Object[] { + new Annotation(0.4f), + new Annotation(new Annotation(0.1f)), + new Annotation("A", "", ' ', 0.0f), + new Annotation("", "", ' ', 0.0f, Color.WHITE), + new Annotation(null, null, ' ', -0.1f), + new Annotation(null, null, 'A', 0.0f), + new Annotation(null, "desc", ' ', 0.0f), + new Annotation("0", "", '\0', 0.0f), + }; + } + + @Test(groups = "Functional", dataProvider = "nonEmptyAnnotations") + public void testIsWhitespace_NonEmptyAnnotation(Annotation annot) + { + assertThat("Annotation " + annot + " is whitespace, but should not be", + !annot.isWhitespace()); + } +} diff --git a/test/jalview/testutils/AnnotationsMatcher.java b/test/jalview/testutils/AnnotationsMatcher.java new file mode 100644 index 0000000..cc64d27 --- /dev/null +++ b/test/jalview/testutils/AnnotationsMatcher.java @@ -0,0 +1,82 @@ +package jalview.testutils; + +import java.util.List; +import java.util.Objects; +import static java.util.Objects.requireNonNullElse; + +import org.hamcrest.Description; +import org.hamcrest.TypeSafeMatcher; + +import jalview.datamodel.Annotation; + +public class AnnotationsMatcher extends TypeSafeMatcher +{ + final List annotations; + + public AnnotationsMatcher(List annotations) + { + this.annotations = annotations; + } + + @Override + public boolean matchesSafely(Annotation[] items) + { + if (annotations.size() != items.length) + return false; + for (int i = 0; i < annotations.size(); i++) + { + var actual = items[i]; + var expected = annotations.get(i); + if (!annotationsEqual(actual, expected)) + return false; + } + return true; + } + + static boolean annotationsEqual(Annotation a, Annotation b) + { + if (a == null && b == null) + return true; + if ((a == null) != (b == null)) // if one is null but the other is not + return false; + return a.secondaryStructure == b.secondaryStructure && a.value == b.value + && Objects.equals(a.colour, b.colour) + && Objects + .equals(requireNonNullElse(a.displayCharacter, ""), + requireNonNullElse(b.displayCharacter, "")) + && Objects + .equals(requireNonNullElse(a.description, ""), + requireNonNullElse(b.description, "")); + } + + @Override + public void describeTo(Description description) + { + description.appendText("annotations ").appendValue(annotations); + } + + @Override + public void describeMismatchSafely(Annotation[] items, + Description description) + { + if (annotations.size() != items.length) + { + description.appendText("but had length ").appendValue(items.length); + return; + } + boolean first = true; + for (int i = 0; i < annotations.size(); i++) + { + var actual = items[i]; + var expected = annotations.get(i); + if (!annotationsEqual(actual, expected)) + { + description + .appendText(first ? "but " : ", ") + .appendText("element [" + i + "] was ") + .appendValue(items[i]); + first = false; + } + } + } +} diff --git a/test/jalview/testutils/AnnotationsMatcherTest.java b/test/jalview/testutils/AnnotationsMatcherTest.java new file mode 100644 index 0000000..3fbdab6 --- /dev/null +++ b/test/jalview/testutils/AnnotationsMatcherTest.java @@ -0,0 +1,174 @@ +package jalview.testutils; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import jalview.datamodel.Annotation; + +import static org.hamcrest.MatcherAssert.assertThat; + +import java.awt.Color; +import java.util.*; + +public class AnnotationsMatcherTest +{ + @DataProvider + public Object[][] matchingAnnotationsLists() + { + return new Object[][] { + { + new Annotation[] { + new Annotation("C", "", 'C', 0.0f), + new Annotation("C", "", 'C', 0.1f), + new Annotation("B", "", 'B', 0.2f) }, + new Annotation[] { + new Annotation("C", "", 'C', 0.0f), + new Annotation("C", "", 'C', 0.1f), + new Annotation("B", "", 'B', 0.2f) } }, + { + new Annotation[] { + new Annotation("X", "xxx", 'X', 1.3f), + new Annotation("V", "vvv", 'V', 1.5f), + new Annotation("B", "bbb", 'B', 2.5f) }, + new Annotation[] { + new Annotation("X", "xxx", 'X', 1.3f), + new Annotation("V", "vvv", 'V', 1.5f), + new Annotation("B", "bbb", 'B', 2.5f) } }, + { + new Annotation[] { + new Annotation("A", "", 'A', 0.2f, Color.RED), + new Annotation("A", "", 'A', 0.3f, Color.GREEN), + new Annotation("C", "", 'C', 0.4f, Color.YELLOW), + new Annotation("C", "", 'C', 0.5f) }, + new Annotation[] { + new Annotation("A", "", 'A', 0.2f, Color.RED), + new Annotation("A", "", 'A', 0.3f, Color.GREEN), + new Annotation("C", "", 'C', 0.4f, Color.YELLOW), + new Annotation("C", "", 'C', 0.5f) } }, + { + new Annotation[] { + Annotation.EMPTY_ANNOTATION, Annotation.EMPTY_ANNOTATION }, + new Annotation[] { + Annotation.EMPTY_ANNOTATION, Annotation.EMPTY_ANNOTATION } }, + { + new Annotation[] { null, null, null, null }, + new Annotation[] { null, null, null, null } } }; + } + + @Test(groups = { "Functional" }, dataProvider = "matchingAnnotationsLists") + public void testMatchesSafely_matchingAnnotations(Annotation[] template, + Annotation[] testdata) + { + assert new AnnotationsMatcher(Arrays.asList(template)) + .matchesSafely(testdata); + } + + @DataProvider + public Object[][] matchingAnnotations() + { + return new Object[][] { + { + new Annotation("A", "aaa", 'A', 0.1f), + new Annotation("A", "aaa", 'A', 0.1f) }, + { + new Annotation("A", "abcdef", 'A', 0.1f, Color.RED), + new Annotation("A", "abcdef", 'A', 0.1f, Color.RED) }, + { + new Annotation("", "xxxx", ' ', 0.0f), + new Annotation("", "xxxx", ' ', 0.0f) }, + { + new Annotation("", "", ' ', 0.0f), + new Annotation("", "", ' ', 0.0f) }, + { + new Annotation(null, null, ' ', 0.0f), + new Annotation(null, null, ' ', 0.0f) }, + { + new Annotation(null, "", ' ', 0.0f), + new Annotation("", null, ' ', 0.0f) }, + { new Annotation(0f), Annotation.EMPTY_ANNOTATION }, + { new Annotation(1f), new Annotation("", "", ' ', 1f, null) }, }; + } + + @Test(groups = { "Functional" }, dataProvider = "matchingAnnotations") + public void testAnnotationsEqual_matchingAnnotations(Annotation first, + Annotation second) + { + assert AnnotationsMatcher.annotationsEqual(first, second); + } + + @DataProvider + public Object[][] mismatchingAnnotations() + { + return new Object[][] { + { + new Annotation("A", "aaa", 'A', 1f), + new Annotation("A", "aaa", 'B', 1f) }, + { new Annotation(1f), new Annotation(2f) }, + { new Annotation(1f), new Annotation("A", "", 'A', 1f) } }; + } + + @Test(groups = { "Functional" }, dataProvider = "mismatchingAnnotations") + public void testAnnotationsEqual_mismatchingAnnotations(Annotation first, + Annotation second) + { + assert !AnnotationsMatcher.annotationsEqual(first, second); + } + + @Test(groups = { "Functional" }) + public void testAnnotationsEqual_nullsMatch() + { + assert AnnotationsMatcher.annotationsEqual(null, null); + } + + @Test(groups = { "Functional" }) + public void testAnnotationsEqual_nullNotMatchEmpty() + { + assert !AnnotationsMatcher + .annotationsEqual(null, Annotation.EMPTY_ANNOTATION); + assert !AnnotationsMatcher + .annotationsEqual(Annotation.EMPTY_ANNOTATION, null); + } + + @Test(groups = { "Functional" }) + public void testAnnotationsEqual_compareNullDisplayCharToEmpty() + { + assert AnnotationsMatcher + .annotationsEqual(new Annotation("", "description", 'A', 0.1f), + new Annotation(null, "description", 'A', 0.1f)); + assert AnnotationsMatcher + .annotationsEqual(new Annotation(null, "description", 'A', 0.1f), + new Annotation("", "description", 'A', 0.1f)); + } + + @Test(groups = { "Functional" }) + public void testAnnotationsEqual_compareNullDescriptionToEmpty() + { + assert AnnotationsMatcher + .annotationsEqual(new Annotation("A", null, 'A', 0.2f), + new Annotation("A", "", 'A', 0.2f)); + assert AnnotationsMatcher + .annotationsEqual(new Annotation("A", "", 'A', 0.2f), + new Annotation("A", null, 'A', 0.2f)); + } + + @Test(groups = { "Functional" }) + public void testAnnotationsEqual_compareNullDisplayCharToBlank() + { + assert !AnnotationsMatcher + .annotationsEqual(new Annotation(" ", "aaa", 'A', 0.03f), + new Annotation(null, "aaa", 'A', 0.03f)); + assert !AnnotationsMatcher + .annotationsEqual(new Annotation(null, "aaa", 'A', 0.04f), + new Annotation(" ", "aaa", 'A', 0.04f)); + } + + @Test(groups = { "Functional" }) + public void testAnnotationsEqual_compareNullDescriptionToBlank() + { + assert !AnnotationsMatcher + .annotationsEqual(new Annotation("A", null, 'A', 0.0f), + new Annotation("A", " ", 'A', 0.0f)); + assert !AnnotationsMatcher + .annotationsEqual(new Annotation("A", " ", 'A', 0.01f), + new Annotation("A", null, 'A', 0.01f)); + } +} diff --git a/test/jalview/testutils/Matchers.java b/test/jalview/testutils/Matchers.java index ceb07a0..682d1bf 100644 --- a/test/jalview/testutils/Matchers.java +++ b/test/jalview/testutils/Matchers.java @@ -1,7 +1,11 @@ package jalview.testutils; +import java.util.Arrays; +import java.util.List; + import org.hamcrest.Matcher; +import jalview.datamodel.Annotation; import jalview.datamodel.SequenceI; public class Matchers @@ -10,4 +14,21 @@ public class Matchers { return new SequenceStringMatcher(sequence); } + + public static Matcher matchesSequenceString(SequenceI sequence) + { + return new SequenceStringMatcher(sequence.getSequenceAsString()); + } + + public static Matcher matchesAnnotations( + List annotations) + { + return new AnnotationsMatcher(annotations); + } + + public static Matcher matchesAnnotations( + Annotation... annotations) + { + return new AnnotationsMatcher(Arrays.asList(annotations)); + } }