mirror of
https://github.com/androidx/media.git
synced 2025-05-16 03:59:54 +08:00
Make SpannedSubject more fluent
I decided the flags bit was a bit unclear so I played around with this It's also needed for more 'complex' assertions like colors - I didn't want to just chuck in a fourth int parameter to create: hasForegroundColorSpan(int start, int end, int flags, int color) PiperOrigin-RevId: 287989424
This commit is contained in:
parent
1c0e69789f
commit
0587180f14
@ -34,8 +34,7 @@ public final class WebvttCueParserTest {
|
||||
+ "This <u.style1.style2 some stuff>is</u> text with <b.foo><i.bar>html</i></b> tags");
|
||||
|
||||
assertThat(text.toString()).isEqualTo("This is text with html tags");
|
||||
assertThat(text)
|
||||
.hasUnderlineSpan("This ".length(), "This is".length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
assertThat(text).hasUnderlineSpanBetween("This ".length(), "This is".length());
|
||||
assertThat(text)
|
||||
.hasBoldItalicSpan(
|
||||
"This is text with ".length(),
|
||||
@ -59,10 +58,7 @@ public final class WebvttCueParserTest {
|
||||
|
||||
assertThat(text.toString()).isEqualTo("An unclosed u tag with italic inside");
|
||||
assertThat(text)
|
||||
.hasUnderlineSpan(
|
||||
"An ".length(),
|
||||
"An unclosed u tag with italic inside".length(),
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
.hasUnderlineSpanBetween("An ".length(), "An unclosed u tag with italic inside".length());
|
||||
assertThat(text)
|
||||
.hasItalicSpan(
|
||||
"An unclosed u tag with ".length(),
|
||||
@ -81,10 +77,9 @@ public final class WebvttCueParserTest {
|
||||
"An italic tag with unclosed underline".length(),
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
assertThat(text)
|
||||
.hasUnderlineSpan(
|
||||
.hasUnderlineSpanBetween(
|
||||
"An italic tag with unclosed ".length(),
|
||||
"An italic tag with unclosed underline".length(),
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
"An italic tag with unclosed underline".length());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -95,8 +90,7 @@ public final class WebvttCueParserTest {
|
||||
assertThat(text.toString()).isEqualTo(expectedText);
|
||||
assertThat(text).hasBoldSpan(0, expectedText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
// Text between the <u> tags is underlined.
|
||||
assertThat(text)
|
||||
.hasUnderlineSpan(0, "Overlapping u and".length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
assertThat(text).hasUnderlineSpanBetween(0, "Overlapping u and".length());
|
||||
// Only text from <i> to <\\u> is italic (unexpected - but simplifies the parsing).
|
||||
assertThat(text)
|
||||
.hasItalicSpan(
|
||||
|
@ -15,23 +15,23 @@
|
||||
*/
|
||||
package com.google.android.exoplayer2.text.webvtt;
|
||||
|
||||
import static com.google.android.exoplayer2.testutil.truth.SpannedSubject.assertThat;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import android.graphics.Typeface;
|
||||
import android.text.Layout.Alignment;
|
||||
import android.text.Spanned;
|
||||
import android.text.style.BackgroundColorSpan;
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
import android.text.style.StyleSpan;
|
||||
import android.text.style.TypefaceSpan;
|
||||
import android.text.style.UnderlineSpan;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.android.exoplayer2.testutil.TestUtil;
|
||||
import com.google.android.exoplayer2.text.Cue;
|
||||
import com.google.android.exoplayer2.text.SubtitleDecoderException;
|
||||
import com.google.android.exoplayer2.util.ColorParser;
|
||||
import com.google.common.truth.Expect;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
@ -403,14 +403,25 @@ public class WebvttDecoderTest {
|
||||
Spanned s2 = getUniqueSpanTextAt(subtitle, /* timeUs= */ 2345000);
|
||||
Spanned s3 = getUniqueSpanTextAt(subtitle, /* timeUs= */ 20000000);
|
||||
Spanned s4 = getUniqueSpanTextAt(subtitle, /* timeUs= */ 25000000);
|
||||
assertThat(s1.getSpans(/* start= */ 0, s1.length(), ForegroundColorSpan.class)).hasLength(1);
|
||||
assertThat(s1.getSpans(/* start= */ 0, s1.length(), BackgroundColorSpan.class)).hasLength(1);
|
||||
assertThat(s2.getSpans(/* start= */ 0, s2.length(), ForegroundColorSpan.class)).hasLength(1);
|
||||
assertThat(s3.getSpans(/* start= */ 10, s3.length(), UnderlineSpan.class)).hasLength(1);
|
||||
assertThat(s4.getSpans(/* start= */ 0, /* end= */ 16, BackgroundColorSpan.class)).hasLength(2);
|
||||
assertThat(s4.getSpans(/* start= */ 17, s4.length(), StyleSpan.class)).hasLength(1);
|
||||
assertThat(s4.getSpans(/* start= */ 17, s4.length(), StyleSpan.class)[0].getStyle())
|
||||
.isEqualTo(Typeface.BOLD);
|
||||
assertThat(s1)
|
||||
.hasForegroundColorSpanBetween(0, s1.length())
|
||||
.withColor(ColorParser.parseCssColor("papayawhip"));
|
||||
assertThat(s1)
|
||||
.hasBackgroundColorSpanBetween(0, s1.length())
|
||||
.withColor(ColorParser.parseCssColor("green"));
|
||||
assertThat(s2)
|
||||
.hasForegroundColorSpanBetween(0, s2.length())
|
||||
.withColor(ColorParser.parseCssColor("peachpuff"));
|
||||
|
||||
assertThat(s3).hasUnderlineSpanBetween(10, s3.length());
|
||||
assertThat(s4)
|
||||
.hasBackgroundColorSpanBetween(0, 16)
|
||||
.withColor(ColorParser.parseCssColor("lime"));
|
||||
assertThat(s4)
|
||||
.hasBoldSpan(
|
||||
/* startIndex= */ 17,
|
||||
/* endIndex= */ s4.length(),
|
||||
/* flags= */ Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -23,8 +23,12 @@ import static com.google.common.truth.Truth.assertAbout;
|
||||
import android.graphics.Typeface;
|
||||
import android.text.Spanned;
|
||||
import android.text.TextUtils;
|
||||
import android.text.style.BackgroundColorSpan;
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
import android.text.style.StyleSpan;
|
||||
import android.text.style.UnderlineSpan;
|
||||
import androidx.annotation.CheckResult;
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.common.truth.FailureMetadata;
|
||||
import com.google.common.truth.Subject;
|
||||
@ -64,7 +68,7 @@ public final class SpannedSubject extends Subject {
|
||||
failWithoutActual(
|
||||
simpleFact("Expected no spans"),
|
||||
fact("in text", actual),
|
||||
fact("but found", actualSpansString()));
|
||||
fact("but found", getAllSpansAsStringWithoutFlags(actual)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -76,6 +80,7 @@ public final class SpannedSubject extends Subject {
|
||||
* @param flags The flags of the expected span. See constants on {@link Spanned} for more
|
||||
* information.
|
||||
*/
|
||||
// TODO: swap this to fluent-style.
|
||||
public void hasItalicSpan(int startIndex, int endIndex, int flags) {
|
||||
hasStyleSpan(startIndex, endIndex, flags, Typeface.ITALIC);
|
||||
}
|
||||
@ -88,6 +93,7 @@ public final class SpannedSubject extends Subject {
|
||||
* @param flags The flags of the expected span. See constants on {@link Spanned} for more
|
||||
* information.
|
||||
*/
|
||||
// TODO: swap this to fluent-style.
|
||||
public void hasBoldSpan(int startIndex, int endIndex, int flags) {
|
||||
hasStyleSpan(startIndex, endIndex, flags, Typeface.BOLD);
|
||||
}
|
||||
@ -104,7 +110,7 @@ public final class SpannedSubject extends Subject {
|
||||
}
|
||||
}
|
||||
|
||||
failWithExpectedSpan(
|
||||
failWithExpectedSpanWithFlags(
|
||||
startIndex,
|
||||
endIndex,
|
||||
flags,
|
||||
@ -129,6 +135,7 @@ public final class SpannedSubject extends Subject {
|
||||
* @param flags The flags of the expected span. See constants on {@link Spanned} for more
|
||||
* information.
|
||||
*/
|
||||
// TODO: swap this to fluent-style.
|
||||
public void hasBoldItalicSpan(int startIndex, int endIndex, int flags) {
|
||||
if (actual == null) {
|
||||
failWithoutActual(simpleFact("Spanned must not be null"));
|
||||
@ -149,11 +156,13 @@ public final class SpannedSubject extends Subject {
|
||||
|
||||
String spannedSubstring = actual.toString().substring(startIndex, endIndex);
|
||||
String boldSpan =
|
||||
spanToString(startIndex, endIndex, flags, new StyleSpan(Typeface.BOLD), spannedSubstring);
|
||||
getSpanAsStringWithFlags(
|
||||
startIndex, endIndex, flags, new StyleSpan(Typeface.BOLD), spannedSubstring);
|
||||
String italicSpan =
|
||||
spanToString(startIndex, endIndex, flags, new StyleSpan(Typeface.ITALIC), spannedSubstring);
|
||||
getSpanAsStringWithFlags(
|
||||
startIndex, endIndex, flags, new StyleSpan(Typeface.ITALIC), spannedSubstring);
|
||||
String boldItalicSpan =
|
||||
spanToString(
|
||||
getSpanAsStringWithFlags(
|
||||
startIndex, endIndex, flags, new StyleSpan(Typeface.BOLD_ITALIC), spannedSubstring);
|
||||
|
||||
failWithoutActual(
|
||||
@ -161,34 +170,89 @@ public final class SpannedSubject extends Subject {
|
||||
fact("in text", actual.toString()),
|
||||
fact("expected either", boldItalicSpan),
|
||||
fact("or both", boldSpan + "\n" + italicSpan),
|
||||
fact("but found", actualSpansString()));
|
||||
fact("but found", getAllSpansAsStringWithFlags(actual)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the subject has an underline span from {@code startIndex} to {@code endIndex}.
|
||||
* Checks that the subject has an {@link UnderlineSpan} from {@code start} to {@code end}.
|
||||
*
|
||||
* @param startIndex The start of the expected span.
|
||||
* @param endIndex The end of the expected span.
|
||||
* @param flags The flags of the expected span. See constants on {@link Spanned} for more
|
||||
* information.
|
||||
* @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 void hasUnderlineSpan(int startIndex, int endIndex, int flags) {
|
||||
public WithSpanFlags hasUnderlineSpanBetween(int start, int end) {
|
||||
if (actual == null) {
|
||||
failWithoutActual(simpleFact("Spanned must not be null"));
|
||||
return;
|
||||
return ALREADY_FAILED_WITH_FLAGS;
|
||||
}
|
||||
|
||||
List<UnderlineSpan> underlineSpans =
|
||||
findMatchingSpans(startIndex, endIndex, flags, UnderlineSpan.class);
|
||||
if (underlineSpans.size() == 1) {
|
||||
return;
|
||||
List<UnderlineSpan> underlineSpans = findMatchingSpans(start, end, UnderlineSpan.class);
|
||||
List<Integer> allFlags = new ArrayList<>();
|
||||
for (UnderlineSpan span : underlineSpans) {
|
||||
allFlags.add(actual.getSpanFlags(span));
|
||||
}
|
||||
failWithExpectedSpan(
|
||||
startIndex,
|
||||
endIndex,
|
||||
flags,
|
||||
new UnderlineSpan(),
|
||||
actual.toString().substring(startIndex, endIndex));
|
||||
if (underlineSpans.size() == 1) {
|
||||
return check("UnderlineSpan (start=%s,end=%s)", start, end).about(spanFlags()).that(allFlags);
|
||||
}
|
||||
failWithExpectedSpanWithoutFlags(
|
||||
start, end, UnderlineSpan.class, actual.toString().substring(start, end));
|
||||
return ALREADY_FAILED_WITH_FLAGS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the subject as a {@link ForegroundColorSpan} from {@code start} to {@code end}.
|
||||
*
|
||||
* <p>The color is asserted in a follow-up method call on the return {@link Colored} object.
|
||||
*
|
||||
* @param start The start of the expected span.
|
||||
* @param end The end of the expected span.
|
||||
* @return A {@link Colored} object to assert on the color of the matching spans.
|
||||
*/
|
||||
@CheckResult
|
||||
public Colored hasForegroundColorSpanBetween(int start, int end) {
|
||||
if (actual == null) {
|
||||
failWithoutActual(simpleFact("Spanned must not be null"));
|
||||
return ALREADY_FAILED_COLORED;
|
||||
}
|
||||
|
||||
List<ForegroundColorSpan> foregroundColorSpans =
|
||||
findMatchingSpans(start, end, ForegroundColorSpan.class);
|
||||
if (foregroundColorSpans.isEmpty()) {
|
||||
failWithExpectedSpanWithoutFlags(
|
||||
start, end, ForegroundColorSpan.class, actual.toString().substring(start, end));
|
||||
return ALREADY_FAILED_COLORED;
|
||||
}
|
||||
return check("ForegroundColorSpan (start=%s,end=%s)", start, end)
|
||||
.about(foregroundColorSpans(actual))
|
||||
.that(foregroundColorSpans);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the subject as a {@link ForegroundColorSpan} from {@code start} to {@code end}.
|
||||
*
|
||||
* <p>The color is asserted in a follow-up method call on the return {@link Colored} object.
|
||||
*
|
||||
* @param start The start of the expected span.
|
||||
* @param end The end of the expected span.
|
||||
* @return A {@link Colored} object to assert on the color of the matching spans.
|
||||
*/
|
||||
@CheckResult
|
||||
public Colored hasBackgroundColorSpanBetween(int start, int end) {
|
||||
if (actual == null) {
|
||||
failWithoutActual(simpleFact("Spanned must not be null"));
|
||||
return ALREADY_FAILED_COLORED;
|
||||
}
|
||||
|
||||
List<BackgroundColorSpan> backgroundColorSpans =
|
||||
findMatchingSpans(start, end, BackgroundColorSpan.class);
|
||||
if (backgroundColorSpans.isEmpty()) {
|
||||
failWithExpectedSpanWithoutFlags(
|
||||
start, end, BackgroundColorSpan.class, actual.toString().substring(start, end));
|
||||
return ALREADY_FAILED_COLORED;
|
||||
}
|
||||
return check("BackgroundColorSpan (start=%s,end=%s)", start, end)
|
||||
.about(backgroundColorSpans(actual))
|
||||
.that(backgroundColorSpans);
|
||||
}
|
||||
|
||||
private <T> List<T> findMatchingSpans(
|
||||
@ -204,27 +268,46 @@ public final class SpannedSubject extends Subject {
|
||||
return spans;
|
||||
}
|
||||
|
||||
private void failWithExpectedSpan(
|
||||
private <T> List<T> findMatchingSpans(int startIndex, int endIndex, Class<T> spanClazz) {
|
||||
List<T> spans = new ArrayList<>();
|
||||
for (T span : actual.getSpans(startIndex, endIndex, spanClazz)) {
|
||||
if (actual.getSpanStart(span) == startIndex && actual.getSpanEnd(span) == endIndex) {
|
||||
spans.add(span);
|
||||
}
|
||||
}
|
||||
return spans;
|
||||
}
|
||||
|
||||
private void failWithExpectedSpanWithFlags(
|
||||
int start, int end, int flags, Object span, String spannedSubstring) {
|
||||
failWithoutActual(
|
||||
simpleFact("No matching span found"),
|
||||
fact("in text", actual),
|
||||
fact("expected", spanToString(start, end, flags, span, spannedSubstring)),
|
||||
fact("but found", actualSpansString()));
|
||||
fact("expected", getSpanAsStringWithFlags(start, end, flags, span, spannedSubstring)),
|
||||
fact("but found", getAllSpansAsStringWithFlags(actual)));
|
||||
}
|
||||
|
||||
private String actualSpansString() {
|
||||
private void failWithExpectedSpanWithoutFlags(
|
||||
int start, int end, Class<?> spanType, String spannedSubstring) {
|
||||
failWithoutActual(
|
||||
simpleFact("No matching span found"),
|
||||
fact("in text", actual),
|
||||
fact("expected", getSpanAsStringWithoutFlags(start, end, spanType, spannedSubstring)),
|
||||
fact("but found", getAllSpansAsStringWithoutFlags(actual)));
|
||||
}
|
||||
|
||||
private static String getAllSpansAsStringWithFlags(Spanned spanned) {
|
||||
List<String> actualSpanStrings = new ArrayList<>();
|
||||
for (Object span : actual.getSpans(0, actual.length(), /* type= */ Object.class)) {
|
||||
actualSpanStrings.add(spanToString(span, actual));
|
||||
for (Object span : spanned.getSpans(0, spanned.length(), Object.class)) {
|
||||
actualSpanStrings.add(getSpanAsStringWithFlags(span, spanned));
|
||||
}
|
||||
return TextUtils.join("\n", actualSpanStrings);
|
||||
}
|
||||
|
||||
private static String spanToString(Object span, Spanned spanned) {
|
||||
private static String getSpanAsStringWithFlags(Object span, Spanned spanned) {
|
||||
int spanStart = spanned.getSpanStart(span);
|
||||
int spanEnd = spanned.getSpanEnd(span);
|
||||
return spanToString(
|
||||
return getSpanAsStringWithFlags(
|
||||
spanStart,
|
||||
spanEnd,
|
||||
spanned.getSpanFlags(span),
|
||||
@ -232,7 +315,7 @@ public final class SpannedSubject extends Subject {
|
||||
spanned.toString().substring(spanStart, spanEnd));
|
||||
}
|
||||
|
||||
private static String spanToString(
|
||||
private static String getSpanAsStringWithFlags(
|
||||
int start, int end, int flags, Object span, String spannedSubstring) {
|
||||
String suffix;
|
||||
if (span instanceof StyleSpan) {
|
||||
@ -244,4 +327,177 @@ public final class SpannedSubject extends Subject {
|
||||
"start=%s\tend=%s\tflags=%s\ttype=%s\tsubstring='%s'%s",
|
||||
start, end, flags, span.getClass().getSimpleName(), spannedSubstring, suffix);
|
||||
}
|
||||
|
||||
private static String getAllSpansAsStringWithoutFlags(Spanned spanned) {
|
||||
List<String> actualSpanStrings = new ArrayList<>();
|
||||
for (Object span : spanned.getSpans(0, spanned.length(), Object.class)) {
|
||||
actualSpanStrings.add(getSpanAsStringWithoutFlags(span, spanned));
|
||||
}
|
||||
return TextUtils.join("\n", actualSpanStrings);
|
||||
}
|
||||
|
||||
private static String getSpanAsStringWithoutFlags(Object span, Spanned spanned) {
|
||||
int spanStart = spanned.getSpanStart(span);
|
||||
int spanEnd = spanned.getSpanEnd(span);
|
||||
return getSpanAsStringWithoutFlags(
|
||||
spanStart, spanEnd, span.getClass(), spanned.toString().substring(spanStart, spanEnd));
|
||||
}
|
||||
|
||||
private static String getSpanAsStringWithoutFlags(
|
||||
int start, int end, Class<?> span, String spannedSubstring) {
|
||||
return String.format(
|
||||
"start=%s\tend=%s\ttype=%s\tsubstring='%s'",
|
||||
start, end, span.getSimpleName(), spannedSubstring);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows additional assertions to be made on the flags of matching spans.
|
||||
*
|
||||
* <p>Identical to {@link WithSpanFlags}, but this should be returned from {@code with...()}
|
||||
* methods while {@link WithSpanFlags} should be returned from {@code has...()} methods.
|
||||
*
|
||||
* <p>See Flag constants on {@link Spanned} for possible values.
|
||||
*/
|
||||
public interface AndSpanFlags {
|
||||
|
||||
/**
|
||||
* Checks that one of the matched spans has the expected {@code flags}.
|
||||
*
|
||||
* @param flags The expected flags. See SPAN_* constants on {@link Spanned} for possible values.
|
||||
*/
|
||||
void andFlags(int flags);
|
||||
}
|
||||
|
||||
private static final AndSpanFlags ALREADY_FAILED_AND_FLAGS = flags -> {};
|
||||
|
||||
/**
|
||||
* Allows additional assertions to be made on the flags of matching spans.
|
||||
*
|
||||
* <p>Identical to {@link AndSpanFlags}, but this should be returned from {@code has...()} methods
|
||||
* while {@link AndSpanFlags} should be returned from {@code with...()} methods.
|
||||
*/
|
||||
public interface WithSpanFlags {
|
||||
|
||||
/**
|
||||
* Checks that one of the matched spans has the expected {@code flags}.
|
||||
*
|
||||
* @param flags The expected flags. See SPAN_* constants on {@link Spanned} for possible values.
|
||||
*/
|
||||
void withFlags(int flags);
|
||||
}
|
||||
|
||||
private static final WithSpanFlags ALREADY_FAILED_WITH_FLAGS = flags -> {};
|
||||
|
||||
private static Factory<SpanFlagsSubject, List<Integer>> spanFlags() {
|
||||
return SpanFlagsSubject::new;
|
||||
}
|
||||
|
||||
private static final class SpanFlagsSubject extends Subject
|
||||
implements AndSpanFlags, WithSpanFlags {
|
||||
|
||||
private final List<Integer> flags;
|
||||
|
||||
private SpanFlagsSubject(FailureMetadata metadata, List<Integer> flags) {
|
||||
super(metadata, flags);
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void andFlags(int flags) {
|
||||
check("contains()").that(this.flags).contains(flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void withFlags(int flags) {
|
||||
andFlags(flags);
|
||||
}
|
||||
}
|
||||
|
||||
/** Allows assertions about the color of a span. */
|
||||
public interface Colored {
|
||||
|
||||
/**
|
||||
* Checks that at least one of the matched spans has the expected {@code color}.
|
||||
*
|
||||
* @param color The expected color.
|
||||
* @return A {@link WithSpanFlags} object for optional additional assertions on the flags.
|
||||
*/
|
||||
AndSpanFlags withColor(@ColorInt int color);
|
||||
}
|
||||
|
||||
private static final Colored ALREADY_FAILED_COLORED = color -> ALREADY_FAILED_AND_FLAGS;
|
||||
|
||||
private Factory<ForegroundColorSpansSubject, List<ForegroundColorSpan>> foregroundColorSpans(
|
||||
Spanned actualSpanned) {
|
||||
return (FailureMetadata metadata, List<ForegroundColorSpan> spans) ->
|
||||
new ForegroundColorSpansSubject(metadata, spans, actualSpanned);
|
||||
}
|
||||
|
||||
private static final class ForegroundColorSpansSubject extends Subject implements Colored {
|
||||
|
||||
private final List<ForegroundColorSpan> actualSpans;
|
||||
private final Spanned actualSpanned;
|
||||
|
||||
private ForegroundColorSpansSubject(
|
||||
FailureMetadata metadata, List<ForegroundColorSpan> actualSpans, Spanned actualSpanned) {
|
||||
super(metadata, actualSpans);
|
||||
this.actualSpans = actualSpans;
|
||||
this.actualSpanned = actualSpanned;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AndSpanFlags withColor(@ColorInt int color) {
|
||||
List<Integer> matchingSpanFlags = new ArrayList<>();
|
||||
// Use hex strings for comparison so the values in error messages are more human readable.
|
||||
List<String> spanColors = new ArrayList<>();
|
||||
|
||||
for (ForegroundColorSpan span : actualSpans) {
|
||||
spanColors.add(String.format("0x%08X", span.getForegroundColor()));
|
||||
if (span.getForegroundColor() == color) {
|
||||
matchingSpanFlags.add(actualSpanned.getSpanFlags(span));
|
||||
}
|
||||
}
|
||||
|
||||
String expectedColorString = String.format("0x%08X", color);
|
||||
check("foregroundColor").that(spanColors).containsExactly(expectedColorString);
|
||||
return check("flags").about(spanFlags()).that(matchingSpanFlags);
|
||||
}
|
||||
}
|
||||
|
||||
private Factory<BackgroundColorSpansSubject, List<BackgroundColorSpan>> backgroundColorSpans(
|
||||
Spanned actualSpanned) {
|
||||
return (FailureMetadata metadata, List<BackgroundColorSpan> spans) ->
|
||||
new BackgroundColorSpansSubject(metadata, spans, actualSpanned);
|
||||
}
|
||||
|
||||
private static final class BackgroundColorSpansSubject extends Subject implements Colored {
|
||||
|
||||
private final List<BackgroundColorSpan> actualSpans;
|
||||
private final Spanned actualSpanned;
|
||||
|
||||
private BackgroundColorSpansSubject(
|
||||
FailureMetadata metadata, List<BackgroundColorSpan> actualSpans, Spanned actualSpanned) {
|
||||
super(metadata, actualSpans);
|
||||
this.actualSpans = actualSpans;
|
||||
this.actualSpanned = actualSpanned;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AndSpanFlags withColor(@ColorInt int color) {
|
||||
List<Integer> matchingSpanFlags = new ArrayList<>();
|
||||
// Use hex strings for comparison so the values in error messages are more human readable.
|
||||
List<String> spanColors = new ArrayList<>();
|
||||
|
||||
for (BackgroundColorSpan span : actualSpans) {
|
||||
spanColors.add(String.format("0x%08X", span.getBackgroundColor()));
|
||||
if (span.getBackgroundColor() == color) {
|
||||
matchingSpanFlags.add(actualSpanned.getSpanFlags(span));
|
||||
}
|
||||
}
|
||||
|
||||
String expectedColorString = String.format("0x%08X", color);
|
||||
check("backgroundColor").that(spanColors).containsExactly(expectedColorString);
|
||||
return check("flags").about(spanFlags()).that(matchingSpanFlags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,9 +21,12 @@ import static com.google.android.exoplayer2.testutil.truth.SpannedSubject.spanne
|
||||
import static com.google.common.truth.ExpectFailure.assertThat;
|
||||
import static com.google.common.truth.ExpectFailure.expectFailureAbout;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Typeface;
|
||||
import android.text.SpannableString;
|
||||
import android.text.Spanned;
|
||||
import android.text.style.BackgroundColorSpan;
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
import android.text.style.StyleSpan;
|
||||
import android.text.style.UnderlineSpan;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
@ -153,7 +156,167 @@ public class SpannedSubjectTest {
|
||||
int end = start + "underlined".length();
|
||||
spannable.setSpan(new UnderlineSpan(), start, end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
|
||||
assertThat(spannable).hasUnderlineSpan(start, end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
assertThat(spannable)
|
||||
.hasUnderlineSpanBetween(start, end)
|
||||
.withFlags(Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void foregroundColorSpan_success() {
|
||||
SpannableString spannable = SpannableString.valueOf("test with cyan section");
|
||||
int start = "test with ".length();
|
||||
int end = start + "cyan".length();
|
||||
spannable.setSpan(
|
||||
new ForegroundColorSpan(Color.CYAN), start, end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
|
||||
assertThat(spannable)
|
||||
.hasForegroundColorSpanBetween(start, end)
|
||||
.withColor(Color.CYAN)
|
||||
.andFlags(Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void foregroundColorSpan_wrongEndIndex() {
|
||||
SpannableString spannable = SpannableString.valueOf("test with cyan section");
|
||||
int start = "test with ".length();
|
||||
int end = start + "cyan".length();
|
||||
spannable.setSpan(
|
||||
new ForegroundColorSpan(Color.CYAN), start, end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
|
||||
int incorrectEnd = end + 2;
|
||||
AssertionError expected =
|
||||
expectFailure(
|
||||
whenTesting ->
|
||||
whenTesting
|
||||
.that(spannable)
|
||||
.hasForegroundColorSpanBetween(start, incorrectEnd)
|
||||
.withColor(Color.CYAN));
|
||||
assertThat(expected).factValue("expected").contains("end=" + incorrectEnd);
|
||||
assertThat(expected).factValue("but found").contains("end=" + end);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void foregroundColorSpan_wrongColor() {
|
||||
SpannableString spannable = SpannableString.valueOf("test with cyan section");
|
||||
int start = "test with ".length();
|
||||
int end = start + "cyan".length();
|
||||
spannable.setSpan(
|
||||
new ForegroundColorSpan(Color.CYAN), start, end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
|
||||
AssertionError expected =
|
||||
expectFailure(
|
||||
whenTesting ->
|
||||
whenTesting
|
||||
.that(spannable)
|
||||
.hasForegroundColorSpanBetween(start, end)
|
||||
.withColor(Color.BLUE));
|
||||
assertThat(expected).factValue("value of").contains("foregroundColor");
|
||||
assertThat(expected).factValue("expected").contains("0xFF0000FF"); // Color.BLUE
|
||||
assertThat(expected).factValue("but was").contains("0xFF00FFFF"); // Color.CYAN
|
||||
}
|
||||
|
||||
@Test
|
||||
public void foregroundColorSpan_wrongFlags() {
|
||||
SpannableString spannable = SpannableString.valueOf("test with cyan section");
|
||||
int start = "test with ".length();
|
||||
int end = start + "cyan".length();
|
||||
spannable.setSpan(
|
||||
new ForegroundColorSpan(Color.CYAN), start, end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
|
||||
AssertionError expected =
|
||||
expectFailure(
|
||||
whenTesting ->
|
||||
whenTesting
|
||||
.that(spannable)
|
||||
.hasForegroundColorSpanBetween(start, end)
|
||||
.withColor(Color.CYAN)
|
||||
.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 backgroundColorSpan_success() {
|
||||
SpannableString spannable = SpannableString.valueOf("test with cyan section");
|
||||
int start = "test with ".length();
|
||||
int end = start + "cyan".length();
|
||||
spannable.setSpan(
|
||||
new BackgroundColorSpan(Color.CYAN), start, end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
|
||||
assertThat(spannable)
|
||||
.hasBackgroundColorSpanBetween(start, end)
|
||||
.withColor(Color.CYAN)
|
||||
.andFlags(Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void backgroundColorSpan_wrongEndIndex() {
|
||||
SpannableString spannable = SpannableString.valueOf("test with cyan section");
|
||||
int start = "test with ".length();
|
||||
int end = start + "cyan".length();
|
||||
spannable.setSpan(
|
||||
new BackgroundColorSpan(Color.CYAN), start, end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
|
||||
int incorrectEnd = end + 2;
|
||||
AssertionError expected =
|
||||
expectFailure(
|
||||
whenTesting ->
|
||||
whenTesting
|
||||
.that(spannable)
|
||||
.hasBackgroundColorSpanBetween(start, incorrectEnd)
|
||||
.withColor(Color.CYAN));
|
||||
assertThat(expected).factValue("expected").contains("end=" + incorrectEnd);
|
||||
assertThat(expected).factValue("but found").contains("end=" + end);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void backgroundColorSpan_wrongColor() {
|
||||
SpannableString spannable = SpannableString.valueOf("test with cyan section");
|
||||
int start = "test with ".length();
|
||||
int end = start + "cyan".length();
|
||||
spannable.setSpan(
|
||||
new BackgroundColorSpan(Color.CYAN), start, end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
|
||||
AssertionError expected =
|
||||
expectFailure(
|
||||
whenTesting ->
|
||||
whenTesting
|
||||
.that(spannable)
|
||||
.hasBackgroundColorSpanBetween(start, end)
|
||||
.withColor(Color.BLUE));
|
||||
assertThat(expected).factValue("value of").contains("backgroundColor");
|
||||
assertThat(expected).factValue("expected").contains("0xFF0000FF"); // Color.BLUE
|
||||
assertThat(expected).factValue("but was").contains("0xFF00FFFF"); // Color.CYAN
|
||||
}
|
||||
|
||||
@Test
|
||||
public void backgroundColorSpan_wrongFlags() {
|
||||
SpannableString spannable = SpannableString.valueOf("test with cyan section");
|
||||
int start = "test with ".length();
|
||||
int end = start + "cyan".length();
|
||||
spannable.setSpan(
|
||||
new BackgroundColorSpan(Color.CYAN), start, end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
|
||||
AssertionError expected =
|
||||
expectFailure(
|
||||
whenTesting ->
|
||||
whenTesting
|
||||
.that(spannable)
|
||||
.hasBackgroundColorSpanBetween(start, end)
|
||||
.withColor(Color.CYAN)
|
||||
.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));
|
||||
}
|
||||
|
||||
private static AssertionError expectFailure(
|
||||
|
Loading…
x
Reference in New Issue
Block a user