Consider the following test:
@Test
fun test() {
val s1 = SpannableString("Test")
val s2 = SpannableString("Test")
s1.setSpan(StyleSpan(BOLD), 0, s1.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
s2.setSpan(StyleSpan(BOLD), 0, s2.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
assertEquals(s1, s2)
}
Should it succeed or fail?
My assumption was that it should succeed, but it fails (scratches head). When looking at the implementation of the SpannableStringInternal we see that the function compares each span with its counterpart (assuming we have equal number of spans).
// Same as SpannableStringBuilder
@Override
public boolean equals(Object o) {
if (o instanceof Spanned &&
toString().equals(o.toString())) {
final Spanned other = (Spanned) o;
// Check span data
final Object[] otherSpans = other.getSpans(0, other.length(), Object.class);
final Object[] thisSpans = getSpans(0, length(), Object.class);
if (mSpanCount == otherSpans.length) {
for (int i = 0; i < mSpanCount; ++i) {
final Object thisSpan = thisSpans[i];
final Object otherSpan = otherSpans[i];
if (thisSpan == this) {
if (other != otherSpan ||
getSpanStart(thisSpan) != other.getSpanStart(otherSpan) ||
getSpanEnd(thisSpan) != other.getSpanEnd(otherSpan) ||
getSpanFlags(thisSpan) != other.getSpanFlags(otherSpan)) {
return false;
}
} else if (!thisSpan.equals(otherSpan) ||
getSpanStart(thisSpan) != other.getSpanStart(otherSpan) ||
getSpanEnd(thisSpan) != other.getSpanEnd(otherSpan) ||
getSpanFlags(thisSpan) != other.getSpanFlags(otherSpan)) {
return false;
}
}
return true;
}
}
return false;
}
The first condition in the else if compares the Span objects for equality and the style spans (although encoding the same data, and being the same type) are not equal, because it seems the StyleSpan does not overwrite equals.
Is there a specific reason why these two are not considered equal, or is it a bug in Android?