Add {Strikethrough,Alignment}Span support to SpannedSubject
I'm going to use these in TtmlDecoderTest PiperOrigin-RevId: 288862274
This commit is contained in:
parent
f22ac32c2c
commit
bae4d786e2
@ -21,10 +21,13 @@ import static com.google.common.truth.Fact.simpleFact;
|
|||||||
import static com.google.common.truth.Truth.assertAbout;
|
import static com.google.common.truth.Truth.assertAbout;
|
||||||
|
|
||||||
import android.graphics.Typeface;
|
import android.graphics.Typeface;
|
||||||
|
import android.text.Layout.Alignment;
|
||||||
import android.text.Spanned;
|
import android.text.Spanned;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import android.text.style.AlignmentSpan;
|
||||||
import android.text.style.BackgroundColorSpan;
|
import android.text.style.BackgroundColorSpan;
|
||||||
import android.text.style.ForegroundColorSpan;
|
import android.text.style.ForegroundColorSpan;
|
||||||
|
import android.text.style.StrikethroughSpan;
|
||||||
import android.text.style.StyleSpan;
|
import android.text.style.StyleSpan;
|
||||||
import android.text.style.TypefaceSpan;
|
import android.text.style.TypefaceSpan;
|
||||||
import android.text.style.UnderlineSpan;
|
import android.text.style.UnderlineSpan;
|
||||||
@ -220,6 +223,84 @@ public final class SpannedSubject extends Subject {
|
|||||||
hasNoSpansOfTypeBetween(UnderlineSpan.class, start, end);
|
hasNoSpansOfTypeBetween(UnderlineSpan.class, start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks that the subject has an {@link StrikethroughSpan} from {@code start} to {@code end}.
|
||||||
|
*
|
||||||
|
* @param start The start of the expected span.
|
||||||
|
* @param end The end of the expected span.
|
||||||
|
* @return A {@link WithSpanFlags} object for optional additional assertions on the flags.
|
||||||
|
*/
|
||||||
|
public WithSpanFlags hasStrikethroughSpanBetween(int start, int end) {
|
||||||
|
if (actual == null) {
|
||||||
|
failWithoutActual(simpleFact("Spanned must not be null"));
|
||||||
|
return ALREADY_FAILED_WITH_FLAGS;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<StrikethroughSpan> strikethroughSpans =
|
||||||
|
findMatchingSpans(start, end, StrikethroughSpan.class);
|
||||||
|
if (strikethroughSpans.size() == 1) {
|
||||||
|
return check("StrikethroughSpan (start=%s,end=%s)", start, end)
|
||||||
|
.about(spanFlags())
|
||||||
|
.that(Collections.singletonList(actual.getSpanFlags(strikethroughSpans.get(0))));
|
||||||
|
}
|
||||||
|
failWithExpectedSpan(
|
||||||
|
start, end, StrikethroughSpan.class, actual.toString().substring(start, end));
|
||||||
|
return ALREADY_FAILED_WITH_FLAGS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks that the subject has no {@link StrikethroughSpan}s on any of the text between {@code
|
||||||
|
* start} and {@code end}.
|
||||||
|
*
|
||||||
|
* <p>This fails even if the start and end indexes don't exactly match.
|
||||||
|
*
|
||||||
|
* @param start The start index to start searching for spans.
|
||||||
|
* @param end The end index to stop searching for spans.
|
||||||
|
*/
|
||||||
|
public void hasNoStrikethroughSpanBetween(int start, int end) {
|
||||||
|
hasNoSpansOfTypeBetween(StrikethroughSpan.class, start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks that the subject has a {@link AlignmentSpan} from {@code start} to {@code end}.
|
||||||
|
*
|
||||||
|
* <p>The alignment is asserted in a follow-up method call on the return {@link Aligned} object.
|
||||||
|
*
|
||||||
|
* @param start The start of the expected span.
|
||||||
|
* @param end The end of the expected span.
|
||||||
|
* @return A {@link Aligned} object to assert on the alignment of the matching spans.
|
||||||
|
*/
|
||||||
|
@CheckResult
|
||||||
|
public Aligned hasAlignmentSpanBetween(int start, int end) {
|
||||||
|
if (actual == null) {
|
||||||
|
failWithoutActual(simpleFact("Spanned must not be null"));
|
||||||
|
return ALREADY_FAILED_ALIGNED;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<AlignmentSpan> alignmentSpans = findMatchingSpans(start, end, AlignmentSpan.class);
|
||||||
|
if (alignmentSpans.isEmpty()) {
|
||||||
|
failWithExpectedSpan(
|
||||||
|
start, end, AlignmentSpan.class, actual.toString().substring(start, end));
|
||||||
|
return ALREADY_FAILED_ALIGNED;
|
||||||
|
}
|
||||||
|
return check("AlignmentSpan (start=%s,end=%s)", start, end)
|
||||||
|
.about(alignmentSpans(actual))
|
||||||
|
.that(alignmentSpans);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks that the subject has no {@link AlignmentSpan}s on any of the text between {@code start}
|
||||||
|
* and {@code end}.
|
||||||
|
*
|
||||||
|
* <p>This fails even if the start and end indexes don't exactly match.
|
||||||
|
*
|
||||||
|
* @param start The start index to start searching for spans.
|
||||||
|
* @param end The end index to stop searching for spans.
|
||||||
|
*/
|
||||||
|
public void hasNoAlignmentSpanBetween(int start, int end) {
|
||||||
|
hasNoSpansOfTypeBetween(AlignmentSpan.class, start, end);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks that the subject has a {@link ForegroundColorSpan} from {@code start} to {@code end}.
|
* Checks that the subject has a {@link ForegroundColorSpan} from {@code start} to {@code end}.
|
||||||
*
|
*
|
||||||
@ -550,6 +631,55 @@ public final class SpannedSubject extends Subject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Allows assertions about the alignment of a span. */
|
||||||
|
public interface Aligned {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks that at least one of the matched spans has the expected {@code alignment}.
|
||||||
|
*
|
||||||
|
* @param alignment The expected alignment.
|
||||||
|
* @return A {@link WithSpanFlags} object for optional additional assertions on the flags.
|
||||||
|
*/
|
||||||
|
AndSpanFlags withAlignment(Alignment alignment);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Aligned ALREADY_FAILED_ALIGNED = alignment -> ALREADY_FAILED_AND_FLAGS;
|
||||||
|
|
||||||
|
private static Factory<AlignmentSpansSubject, List<AlignmentSpan>> alignmentSpans(
|
||||||
|
Spanned actualSpanned) {
|
||||||
|
return (FailureMetadata metadata, List<AlignmentSpan> spans) ->
|
||||||
|
new AlignmentSpansSubject(metadata, spans, actualSpanned);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class AlignmentSpansSubject extends Subject implements Aligned {
|
||||||
|
|
||||||
|
private final List<AlignmentSpan> actualSpans;
|
||||||
|
private final Spanned actualSpanned;
|
||||||
|
|
||||||
|
private AlignmentSpansSubject(
|
||||||
|
FailureMetadata metadata, List<AlignmentSpan> actualSpans, Spanned actualSpanned) {
|
||||||
|
super(metadata, actualSpans);
|
||||||
|
this.actualSpans = actualSpans;
|
||||||
|
this.actualSpanned = actualSpanned;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AndSpanFlags withAlignment(Alignment alignment) {
|
||||||
|
List<Integer> matchingSpanFlags = new ArrayList<>();
|
||||||
|
List<Alignment> spanAlignments = new ArrayList<>();
|
||||||
|
|
||||||
|
for (AlignmentSpan span : actualSpans) {
|
||||||
|
spanAlignments.add(span.getAlignment());
|
||||||
|
if (span.getAlignment().equals(alignment)) {
|
||||||
|
matchingSpanFlags.add(actualSpanned.getSpanFlags(span));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
check("alignment").that(spanAlignments).containsExactly(alignment);
|
||||||
|
return check("flags").about(spanFlags()).that(matchingSpanFlags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Allows assertions about the color of a span. */
|
/** Allows assertions about the color of a span. */
|
||||||
public interface Colored {
|
public interface Colored {
|
||||||
|
|
||||||
|
@ -23,10 +23,13 @@ import static com.google.common.truth.ExpectFailure.expectFailureAbout;
|
|||||||
|
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.Typeface;
|
import android.graphics.Typeface;
|
||||||
|
import android.text.Layout.Alignment;
|
||||||
import android.text.SpannableString;
|
import android.text.SpannableString;
|
||||||
import android.text.Spanned;
|
import android.text.Spanned;
|
||||||
|
import android.text.style.AlignmentSpan;
|
||||||
import android.text.style.BackgroundColorSpan;
|
import android.text.style.BackgroundColorSpan;
|
||||||
import android.text.style.ForegroundColorSpan;
|
import android.text.style.ForegroundColorSpan;
|
||||||
|
import android.text.style.StrikethroughSpan;
|
||||||
import android.text.style.StyleSpan;
|
import android.text.style.StyleSpan;
|
||||||
import android.text.style.TypefaceSpan;
|
import android.text.style.TypefaceSpan;
|
||||||
import android.text.style.UnderlineSpan;
|
import android.text.style.UnderlineSpan;
|
||||||
@ -283,6 +286,185 @@ public class SpannedSubjectTest {
|
|||||||
assertThat(expected).factValue("but found").contains("start=" + start);
|
assertThat(expected).factValue("but found").contains("start=" + start);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void strikethroughSpan_success() {
|
||||||
|
SpannableString spannable = SpannableString.valueOf("test with crossed-out section");
|
||||||
|
int start = "test with ".length();
|
||||||
|
int end = start + "crossed-out".length();
|
||||||
|
spannable.setSpan(new StrikethroughSpan(), start, end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||||
|
|
||||||
|
assertThat(spannable)
|
||||||
|
.hasStrikethroughSpanBetween(start, end)
|
||||||
|
.withFlags(Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void noStrikethroughSpan_success() {
|
||||||
|
SpannableString spannable =
|
||||||
|
SpannableString.valueOf("test with underline then crossed-out spans");
|
||||||
|
spannable.setSpan(
|
||||||
|
new UnderlineSpan(),
|
||||||
|
"test with ".length(),
|
||||||
|
"test with underline".length(),
|
||||||
|
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
|
spannable.setSpan(
|
||||||
|
new UnderlineSpan(),
|
||||||
|
"test with underline then ".length(),
|
||||||
|
"test with italic then crossed-out".length(),
|
||||||
|
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
|
|
||||||
|
assertThat(spannable).hasNoStrikethroughSpanBetween(0, "test with underline then".length());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void noStrikethroughSpan_failure() {
|
||||||
|
SpannableString spannable = SpannableString.valueOf("test with crossed-out section");
|
||||||
|
int start = "test with ".length();
|
||||||
|
int end = start + "crossed-out".length();
|
||||||
|
spannable.setSpan(new StrikethroughSpan(), start, end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||||
|
|
||||||
|
AssertionError expected =
|
||||||
|
expectFailure(
|
||||||
|
whenTesting ->
|
||||||
|
whenTesting.that(spannable).hasNoStrikethroughSpanBetween(start + 1, end));
|
||||||
|
assertThat(expected)
|
||||||
|
.factKeys()
|
||||||
|
.contains(
|
||||||
|
"Found unexpected StrikethroughSpans between start=" + (start + 1) + ",end=" + end);
|
||||||
|
assertThat(expected).factKeys().contains("expected none");
|
||||||
|
assertThat(expected).factValue("but found").contains("start=" + start);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void alignmentSpan_success() {
|
||||||
|
SpannableString spannable = SpannableString.valueOf("test with right-aligned section");
|
||||||
|
int start = "test with ".length();
|
||||||
|
int end = start + "right-aligned".length();
|
||||||
|
spannable.setSpan(
|
||||||
|
new AlignmentSpan.Standard(Alignment.ALIGN_OPPOSITE),
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||||
|
|
||||||
|
assertThat(spannable)
|
||||||
|
.hasAlignmentSpanBetween(start, end)
|
||||||
|
.withAlignment(Alignment.ALIGN_OPPOSITE)
|
||||||
|
.andFlags(Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void alignmentSpan_wrongEndIndex() {
|
||||||
|
SpannableString spannable = SpannableString.valueOf("test with right-aligned section");
|
||||||
|
int start = "test with ".length();
|
||||||
|
int end = start + "right-aligned".length();
|
||||||
|
spannable.setSpan(
|
||||||
|
new AlignmentSpan.Standard(Alignment.ALIGN_OPPOSITE),
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||||
|
|
||||||
|
int incorrectEnd = end + 2;
|
||||||
|
AssertionError expected =
|
||||||
|
expectFailure(
|
||||||
|
whenTesting ->
|
||||||
|
whenTesting
|
||||||
|
.that(spannable)
|
||||||
|
.hasAlignmentSpanBetween(start, incorrectEnd)
|
||||||
|
.withAlignment(Alignment.ALIGN_OPPOSITE));
|
||||||
|
assertThat(expected).factValue("expected").contains("end=" + incorrectEnd);
|
||||||
|
assertThat(expected).factValue("but found").contains("end=" + end);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void alignmentSpan_wrongAlignment() {
|
||||||
|
SpannableString spannable = SpannableString.valueOf("test with right-aligned section");
|
||||||
|
int start = "test with ".length();
|
||||||
|
int end = start + "right-aligned".length();
|
||||||
|
spannable.setSpan(
|
||||||
|
new AlignmentSpan.Standard(Alignment.ALIGN_OPPOSITE),
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||||
|
|
||||||
|
AssertionError expected =
|
||||||
|
expectFailure(
|
||||||
|
whenTesting ->
|
||||||
|
whenTesting
|
||||||
|
.that(spannable)
|
||||||
|
.hasAlignmentSpanBetween(start, end)
|
||||||
|
.withAlignment(Alignment.ALIGN_CENTER));
|
||||||
|
assertThat(expected).factValue("value of").contains("alignment");
|
||||||
|
assertThat(expected).factValue("expected").contains("ALIGN_CENTER");
|
||||||
|
assertThat(expected).factValue("but was").contains("ALIGN_OPPOSITE");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void alignmentSpan_wrongFlags() {
|
||||||
|
SpannableString spannable = SpannableString.valueOf("test with right-aligned section");
|
||||||
|
int start = "test with ".length();
|
||||||
|
int end = start + "right-aligned".length();
|
||||||
|
spannable.setSpan(
|
||||||
|
new AlignmentSpan.Standard(Alignment.ALIGN_OPPOSITE),
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||||
|
|
||||||
|
AssertionError expected =
|
||||||
|
expectFailure(
|
||||||
|
whenTesting ->
|
||||||
|
whenTesting
|
||||||
|
.that(spannable)
|
||||||
|
.hasAlignmentSpanBetween(start, end)
|
||||||
|
.withAlignment(Alignment.ALIGN_OPPOSITE)
|
||||||
|
.andFlags(Spanned.SPAN_EXCLUSIVE_EXCLUSIVE));
|
||||||
|
assertThat(expected).factValue("value of").contains("flags");
|
||||||
|
assertThat(expected)
|
||||||
|
.factValue("expected to contain")
|
||||||
|
.contains(String.valueOf(Spanned.SPAN_EXCLUSIVE_EXCLUSIVE));
|
||||||
|
assertThat(expected)
|
||||||
|
.factValue("but was")
|
||||||
|
.contains(String.valueOf(Spanned.SPAN_INCLUSIVE_EXCLUSIVE));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void noAlignmentSpan_success() {
|
||||||
|
SpannableString spannable =
|
||||||
|
SpannableString.valueOf("test with underline then right-aligned spans");
|
||||||
|
spannable.setSpan(
|
||||||
|
new UnderlineSpan(),
|
||||||
|
"test with ".length(),
|
||||||
|
"test with underline".length(),
|
||||||
|
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
|
spannable.setSpan(
|
||||||
|
new AlignmentSpan.Standard(Alignment.ALIGN_OPPOSITE),
|
||||||
|
"test with underline then ".length(),
|
||||||
|
"test with underline then cyan".length(),
|
||||||
|
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
|
|
||||||
|
assertThat(spannable).hasNoAlignmentSpanBetween(0, "test with underline then".length());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void noAlignmentSpan_failure() {
|
||||||
|
SpannableString spannable = SpannableString.valueOf("test with right-aligned section");
|
||||||
|
int start = "test with ".length();
|
||||||
|
int end = start + "cyan".length();
|
||||||
|
spannable.setSpan(
|
||||||
|
new AlignmentSpan.Standard(Alignment.ALIGN_OPPOSITE),
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||||
|
|
||||||
|
AssertionError expected =
|
||||||
|
expectFailure(
|
||||||
|
whenTesting -> whenTesting.that(spannable).hasNoAlignmentSpanBetween(start + 1, end));
|
||||||
|
assertThat(expected)
|
||||||
|
.factKeys()
|
||||||
|
.contains("Found unexpected AlignmentSpans between start=" + (start + 1) + ",end=" + end);
|
||||||
|
assertThat(expected).factKeys().contains("expected none");
|
||||||
|
assertThat(expected).factValue("but found").contains("start=" + start);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void foregroundColorSpan_success() {
|
public void foregroundColorSpan_success() {
|
||||||
SpannableString spannable = SpannableString.valueOf("test with cyan section");
|
SpannableString spannable = SpannableString.valueOf("test with cyan section");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user