JAL-4313 Patch AnnotationsMatcher to match nulls
[jalview.git] / test / jalview / testutils / AnnotationsMatcher.java
1 package jalview.testutils;
2
3 import java.util.List;
4 import java.util.Objects;
5 import static java.util.Objects.requireNonNullElse;
6
7 import org.hamcrest.Description;
8 import org.hamcrest.TypeSafeMatcher;
9
10 import jalview.datamodel.Annotation;
11
12 public class AnnotationsMatcher extends TypeSafeMatcher<Annotation[]>
13 {
14   final List<Annotation> annotations;
15
16   public AnnotationsMatcher(List<Annotation> annotations)
17   {
18     this.annotations = annotations;
19   }
20
21   @Override
22   public boolean matchesSafely(Annotation[] items)
23   {
24     if (annotations.size() != items.length)
25       return false;
26     for (int i = 0; i < annotations.size(); i++)
27     {
28       var actual = items[i];
29       var expected = annotations.get(i);
30       if (!annotationsEqual(actual, expected))
31         return false;
32     }
33     return true;
34   }
35
36   static boolean annotationsEqual(Annotation a, Annotation b)
37   {
38     if (a == null && b == null)
39       return true;
40     if ((a == null) != (b == null)) // if one is null but the other is not
41       return false;
42     return a.secondaryStructure == b.secondaryStructure && a.value == b.value
43         && Objects.equals(a.colour, b.colour)
44         && Objects
45             .equals(requireNonNullElse(a.displayCharacter, ""),
46                 requireNonNullElse(b.displayCharacter, ""))
47         && Objects
48             .equals(requireNonNullElse(a.description, ""),
49                 requireNonNullElse(b.description, ""));
50   }
51
52   @Override
53   public void describeTo(Description description)
54   {
55     description.appendText("annotations ").appendValue(annotations);
56   }
57
58   @Override
59   public void describeMismatchSafely(Annotation[] items,
60       Description description)
61   {
62     if (annotations.size() != items.length)
63     {
64       description.appendText("but had length ").appendValue(items.length);
65       return;
66     }
67     boolean first = true;
68     for (int i = 0; i < annotations.size(); i++)
69     {
70       var actual = items[i];
71       var expected = annotations.get(i);
72       if (!annotationsEqual(actual, expected))
73       {
74         description
75             .appendText(first ? "but " : ", ")
76             .appendText("element [" + i + "] was ")
77             .appendValue(items[i]);
78         first = false;
79       }
80     }
81   }
82 }