mirror of
https://github.com/samsonjs/media.git
synced 2026-04-04 11:05:47 +00:00
Add TypefaceSpan and hasNoFooSpanBetween() support to SpannedSubject
Use these to migrate the last WebvttDecoderTest method to SpannedSubject PiperOrigin-RevId: 288688620
This commit is contained in:
parent
ee091e6a45
commit
448db89446
4 changed files with 570 additions and 47 deletions
|
|
@ -20,7 +20,7 @@ STYLE
|
|||
|
||||
id
|
||||
00:00.000 --> 00:01.001
|
||||
This should be underlined and <lang.class1.class2> courier and violet.
|
||||
This should be underlined and <lang.class1.class2>courier and violet.
|
||||
|
||||
íd
|
||||
00:02.000 --> 00:02.001
|
||||
|
|
@ -31,10 +31,10 @@ _id
|
|||
This <lang.class.another>should be courier and bold.
|
||||
|
||||
00:04.000 --> 00:04.001
|
||||
This <v Strider Trancos> shouldn't be bold.</v>
|
||||
This <v.class.clazz Strider Trancos> should be bold.
|
||||
This <v Strider Trancos>shouldn't be bold.</v>
|
||||
This <v.class.clazz Strider Trancos>should be bold.
|
||||
|
||||
anId
|
||||
00:05.000 --> 00:05.001
|
||||
This is <v.class1.class3.class2 Pipo> specific </v>
|
||||
<v.class1.class3.class2 Robert> But this is more italic</v>
|
||||
This is <v.class1.class3.class2 Pipo>specific</v>
|
||||
<v.class1.class3.class2 Robert>But this is more italic</v>
|
||||
|
|
|
|||
|
|
@ -19,17 +19,14 @@ import static com.google.android.exoplayer2.testutil.truth.SpannedSubject.assert
|
|||
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.ForegroundColorSpan;
|
||||
import android.text.style.StyleSpan;
|
||||
import android.text.style.TypefaceSpan;
|
||||
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.Assertions;
|
||||
import com.google.android.exoplayer2.util.ColorParser;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.truth.Expect;
|
||||
|
|
@ -328,41 +325,39 @@ public class WebvttDecoderTest {
|
|||
@Test
|
||||
public void testWithComplexCssSelectors() throws Exception {
|
||||
WebvttSubtitle subtitle = getSubtitleForTestAsset(WITH_CSS_COMPLEX_SELECTORS);
|
||||
Spanned text = getUniqueSpanTextAt(subtitle, /* timeUs= */ 0);
|
||||
assertThat(text.getSpans(/* start= */ 30, text.length(), ForegroundColorSpan.class))
|
||||
.hasLength(1);
|
||||
assertThat(
|
||||
text.getSpans(/* start= */ 30, text.length(), ForegroundColorSpan.class)[0]
|
||||
.getForegroundColor())
|
||||
.isEqualTo(0xFFEE82EE);
|
||||
assertThat(text.getSpans(/* start= */ 30, text.length(), TypefaceSpan.class)).hasLength(1);
|
||||
assertThat(text.getSpans(/* start= */ 30, text.length(), TypefaceSpan.class)[0].getFamily())
|
||||
.isEqualTo("courier");
|
||||
Spanned firstCueText = getUniqueSpanTextAt(subtitle, /* timeUs= */ 0);
|
||||
assertThat(firstCueText)
|
||||
.hasForegroundColorSpanBetween(
|
||||
"This should be underlined and ".length(), firstCueText.length())
|
||||
.withColor(ColorParser.parseCssColor("violet"));
|
||||
assertThat(firstCueText)
|
||||
.hasTypefaceSpanBetween("This should be underlined and ".length(), firstCueText.length())
|
||||
.withFamily("courier");
|
||||
|
||||
text = getUniqueSpanTextAt(subtitle, /* timeUs= */ 2000000);
|
||||
assertThat(text.getSpans(/* start= */ 5, text.length(), TypefaceSpan.class)).hasLength(1);
|
||||
assertThat(text.getSpans(/* start= */ 5, text.length(), TypefaceSpan.class)[0].getFamily())
|
||||
.isEqualTo("courier");
|
||||
Spanned secondCueText = getUniqueSpanTextAt(subtitle, /* timeUs= */ 2_000_000);
|
||||
assertThat(secondCueText)
|
||||
.hasTypefaceSpanBetween("This ".length(), secondCueText.length())
|
||||
.withFamily("courier");
|
||||
assertThat(secondCueText)
|
||||
.hasNoForegroundColorSpanBetween("This ".length(), secondCueText.length());
|
||||
|
||||
text = getUniqueSpanTextAt(subtitle, /* timeUs= */ 2500000);
|
||||
assertThat(text.getSpans(/* start= */ 5, text.length(), StyleSpan.class)).hasLength(1);
|
||||
assertThat(text.getSpans(/* start= */ 5, text.length(), StyleSpan.class)[0].getStyle())
|
||||
.isEqualTo(Typeface.BOLD);
|
||||
assertThat(text.getSpans(/* start= */ 5, text.length(), TypefaceSpan.class)).hasLength(1);
|
||||
assertThat(text.getSpans(/* start= */ 5, text.length(), TypefaceSpan.class)[0].getFamily())
|
||||
.isEqualTo("courier");
|
||||
Spanned thirdCueText = getUniqueSpanTextAt(subtitle, /* timeUs= */ 2_500_000);
|
||||
assertThat(thirdCueText).hasBoldSpanBetween("This ".length(), thirdCueText.length());
|
||||
assertThat(thirdCueText)
|
||||
.hasTypefaceSpanBetween("This ".length(), thirdCueText.length())
|
||||
.withFamily("courier");
|
||||
|
||||
text = getUniqueSpanTextAt(subtitle, /* timeUs= */ 4000000);
|
||||
assertThat(text.getSpans(/* start= */ 6, /* end= */ 22, StyleSpan.class)).hasLength(0);
|
||||
assertThat(text.getSpans(/* start= */ 30, text.length(), StyleSpan.class)).hasLength(1);
|
||||
assertThat(text.getSpans(/* start= */ 30, text.length(), StyleSpan.class)[0].getStyle())
|
||||
.isEqualTo(Typeface.BOLD);
|
||||
Spanned fourthCueText = getUniqueSpanTextAt(subtitle, /* timeUs= */ 4_000_000);
|
||||
assertThat(fourthCueText)
|
||||
.hasNoStyleSpanBetween("This ".length(), "shouldn't be bold.".length());
|
||||
assertThat(fourthCueText)
|
||||
.hasBoldSpanBetween("This shouldn't be bold.\nThis ".length(), fourthCueText.length());
|
||||
|
||||
text = getUniqueSpanTextAt(subtitle, /* timeUs= */ 5000000);
|
||||
assertThat(text.getSpans(/* start= */ 9, /* end= */ 17, StyleSpan.class)).hasLength(0);
|
||||
assertThat(text.getSpans(/* start= */ 19, text.length(), StyleSpan.class)).hasLength(1);
|
||||
assertThat(text.getSpans(/* start= */ 19, text.length(), StyleSpan.class)[0].getStyle())
|
||||
.isEqualTo(Typeface.ITALIC);
|
||||
Spanned fifthCueText = getUniqueSpanTextAt(subtitle, /* timeUs= */ 5_000_000);
|
||||
assertThat(fifthCueText)
|
||||
.hasNoStyleSpanBetween("This is ".length(), "This is specific".length());
|
||||
assertThat(fifthCueText)
|
||||
.hasItalicSpanBetween("This is specific\n".length(), fifthCueText.length());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -387,6 +382,6 @@ public class WebvttDecoderTest {
|
|||
}
|
||||
|
||||
private Spanned getUniqueSpanTextAt(WebvttSubtitle sub, long timeUs) {
|
||||
return (Spanned) sub.getCues(timeUs).get(0).text;
|
||||
return (Spanned) Assertions.checkNotNull(sub.getCues(timeUs).get(0).text);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,12 +26,14 @@ import android.text.TextUtils;
|
|||
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.CheckResult;
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.text.span.HorizontalTextInVerticalContextSpan;
|
||||
import com.google.android.exoplayer2.text.span.RubySpan;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import com.google.common.truth.FailureMetadata;
|
||||
import com.google.common.truth.Subject;
|
||||
import java.util.ArrayList;
|
||||
|
|
@ -171,6 +173,19 @@ public final class SpannedSubject extends Subject {
|
|||
return ALREADY_FAILED_WITH_FLAGS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the subject has no {@link StyleSpan}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 hasNoStyleSpanBetween(int start, int end) {
|
||||
hasNoSpansOfTypeBetween(StyleSpan.class, start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the subject has an {@link UnderlineSpan} from {@code start} to {@code end}.
|
||||
*
|
||||
|
|
@ -194,6 +209,19 @@ public final class SpannedSubject extends Subject {
|
|||
return ALREADY_FAILED_WITH_FLAGS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the subject has no {@link UnderlineSpan}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 hasNoUnderlineSpanBetween(int start, int end) {
|
||||
hasNoSpansOfTypeBetween(UnderlineSpan.class, start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the subject has a {@link ForegroundColorSpan} from {@code start} to {@code end}.
|
||||
*
|
||||
|
|
@ -222,6 +250,19 @@ public final class SpannedSubject extends Subject {
|
|||
.that(foregroundColorSpans);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the subject has no {@link ForegroundColorSpan}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 hasNoForegroundColorSpanBetween(int start, int end) {
|
||||
hasNoSpansOfTypeBetween(ForegroundColorSpan.class, start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the subject has a {@link BackgroundColorSpan} from {@code start} to {@code end}.
|
||||
*
|
||||
|
|
@ -250,6 +291,58 @@ public final class SpannedSubject extends Subject {
|
|||
.that(backgroundColorSpans);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the subject has no {@link BackgroundColorSpan}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 hasNoBackgroundColorSpanBetween(int start, int end) {
|
||||
hasNoSpansOfTypeBetween(BackgroundColorSpan.class, start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the subject has a {@link TypefaceSpan} from {@code start} to {@code end}.
|
||||
*
|
||||
* <p>The font is asserted in a follow-up method call on the return {@link Typefaced} object.
|
||||
*
|
||||
* @param start The start of the expected span.
|
||||
* @param end The end of the expected span.
|
||||
* @return A {@link Typefaced} object to assert on the font of the matching spans.
|
||||
*/
|
||||
@CheckResult
|
||||
public Typefaced hasTypefaceSpanBetween(int start, int end) {
|
||||
if (actual == null) {
|
||||
failWithoutActual(simpleFact("Spanned must not be null"));
|
||||
return ALREADY_FAILED_TYPEFACED;
|
||||
}
|
||||
|
||||
List<TypefaceSpan> backgroundColorSpans = findMatchingSpans(start, end, TypefaceSpan.class);
|
||||
if (backgroundColorSpans.isEmpty()) {
|
||||
failWithExpectedSpan(start, end, TypefaceSpan.class, actual.toString().substring(start, end));
|
||||
return ALREADY_FAILED_TYPEFACED;
|
||||
}
|
||||
return check("TypefaceSpan (start=%s,end=%s)", start, end)
|
||||
.about(typefaceSpans(actual))
|
||||
.that(backgroundColorSpans);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the subject has no {@link TypefaceSpan}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 hasNoTypefaceSpanBetween(int start, int end) {
|
||||
hasNoSpansOfTypeBetween(TypefaceSpan.class, start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the subject has a {@link RubySpan} from {@code start} to {@code end}.
|
||||
*
|
||||
|
|
@ -274,6 +367,19 @@ public final class SpannedSubject extends Subject {
|
|||
return check("RubySpan (start=%s,end=%s)", start, end).about(rubySpans(actual)).that(rubySpans);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the subject has no {@link RubySpan}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 hasNoRubySpanBetween(int start, int end) {
|
||||
hasNoSpansOfTypeBetween(RubySpan.class, start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the subject has an {@link HorizontalTextInVerticalContextSpan} from {@code start}
|
||||
* to {@code end}.
|
||||
|
|
@ -303,6 +409,45 @@ public final class SpannedSubject extends Subject {
|
|||
return ALREADY_FAILED_WITH_FLAGS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the subject has no {@link HorizontalTextInVerticalContextSpan}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 hasNoHorizontalTextInVerticalContextSpanBetween(int start, int end) {
|
||||
hasNoSpansOfTypeBetween(HorizontalTextInVerticalContextSpan.class, start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the subject has no spans of type {@code spanClazz} 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.
|
||||
*/
|
||||
private void hasNoSpansOfTypeBetween(Class<?> spanClazz, int start, int end) {
|
||||
if (actual == null) {
|
||||
failWithoutActual(simpleFact("Spanned must not be null"));
|
||||
return;
|
||||
}
|
||||
Object[] matchingSpans = actual.getSpans(start, end, spanClazz);
|
||||
if (matchingSpans.length != 0) {
|
||||
failWithoutActual(
|
||||
simpleFact(
|
||||
String.format(
|
||||
"Found unexpected %ss between start=%s,end=%s",
|
||||
spanClazz.getSimpleName(), start, end)),
|
||||
simpleFact("expected none"),
|
||||
fact("but found", getAllSpansAsString(actual)));
|
||||
}
|
||||
}
|
||||
|
||||
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)) {
|
||||
|
|
@ -421,8 +566,8 @@ public final class SpannedSubject extends Subject {
|
|||
|
||||
private static final Colored ALREADY_FAILED_COLORED = color -> ALREADY_FAILED_AND_FLAGS;
|
||||
|
||||
private Factory<ForegroundColorSpansSubject, List<ForegroundColorSpan>> foregroundColorSpans(
|
||||
Spanned actualSpanned) {
|
||||
private static Factory<ForegroundColorSpansSubject, List<ForegroundColorSpan>>
|
||||
foregroundColorSpans(Spanned actualSpanned) {
|
||||
return (FailureMetadata metadata, List<ForegroundColorSpan> spans) ->
|
||||
new ForegroundColorSpansSubject(metadata, spans, actualSpanned);
|
||||
}
|
||||
|
|
@ -458,8 +603,8 @@ public final class SpannedSubject extends Subject {
|
|||
}
|
||||
}
|
||||
|
||||
private Factory<BackgroundColorSpansSubject, List<BackgroundColorSpan>> backgroundColorSpans(
|
||||
Spanned actualSpanned) {
|
||||
private static Factory<BackgroundColorSpansSubject, List<BackgroundColorSpan>>
|
||||
backgroundColorSpans(Spanned actualSpanned) {
|
||||
return (FailureMetadata metadata, List<BackgroundColorSpan> spans) ->
|
||||
new BackgroundColorSpansSubject(metadata, spans, actualSpanned);
|
||||
}
|
||||
|
|
@ -495,6 +640,55 @@ public final class SpannedSubject extends Subject {
|
|||
}
|
||||
}
|
||||
|
||||
/** Allows assertions about the typeface of a span. */
|
||||
public interface Typefaced {
|
||||
|
||||
/**
|
||||
* Checks that at least one of the matched spans has the expected {@code fontFamily}.
|
||||
*
|
||||
* @param fontFamily The expected font family.
|
||||
* @return A {@link WithSpanFlags} object for optional additional assertions on the flags.
|
||||
*/
|
||||
AndSpanFlags withFamily(String fontFamily);
|
||||
}
|
||||
|
||||
private static final Typefaced ALREADY_FAILED_TYPEFACED = color -> ALREADY_FAILED_AND_FLAGS;
|
||||
|
||||
private static Factory<TypefaceSpansSubject, List<TypefaceSpan>> typefaceSpans(
|
||||
Spanned actualSpanned) {
|
||||
return (FailureMetadata metadata, List<TypefaceSpan> spans) ->
|
||||
new TypefaceSpansSubject(metadata, spans, actualSpanned);
|
||||
}
|
||||
|
||||
private static final class TypefaceSpansSubject extends Subject implements Typefaced {
|
||||
|
||||
private final List<TypefaceSpan> actualSpans;
|
||||
private final Spanned actualSpanned;
|
||||
|
||||
private TypefaceSpansSubject(
|
||||
FailureMetadata metadata, List<TypefaceSpan> actualSpans, Spanned actualSpanned) {
|
||||
super(metadata, actualSpans);
|
||||
this.actualSpans = actualSpans;
|
||||
this.actualSpanned = actualSpanned;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AndSpanFlags withFamily(String fontFamily) {
|
||||
List<Integer> matchingSpanFlags = new ArrayList<>();
|
||||
List<String> spanFontFamilies = new ArrayList<>();
|
||||
|
||||
for (TypefaceSpan span : actualSpans) {
|
||||
spanFontFamilies.add(span.getFamily());
|
||||
if (Util.areEqual(span.getFamily(), fontFamily)) {
|
||||
matchingSpanFlags.add(actualSpanned.getSpanFlags(span));
|
||||
}
|
||||
}
|
||||
|
||||
check("family").that(spanFontFamilies).containsExactly(fontFamily);
|
||||
return check("flags").about(spanFlags()).that(matchingSpanFlags);
|
||||
}
|
||||
}
|
||||
|
||||
/** Allows assertions about a span's ruby text and its position. */
|
||||
public interface RubyText {
|
||||
|
||||
|
|
@ -511,7 +705,7 @@ public final class SpannedSubject extends Subject {
|
|||
private static final RubyText ALREADY_FAILED_WITH_TEXT =
|
||||
(text, position) -> ALREADY_FAILED_AND_FLAGS;
|
||||
|
||||
private Factory<RubySpansSubject, List<RubySpan>> rubySpans(Spanned actualSpanned) {
|
||||
private static Factory<RubySpansSubject, List<RubySpan>> rubySpans(Spanned actualSpanned) {
|
||||
return (FailureMetadata metadata, List<RubySpan> spans) ->
|
||||
new RubySpansSubject(metadata, spans, actualSpanned);
|
||||
}
|
||||
|
|
@ -544,7 +738,7 @@ public final class SpannedSubject extends Subject {
|
|||
return check("flags").about(spanFlags()).that(matchingSpanFlags);
|
||||
}
|
||||
|
||||
private static class TextAndPosition {
|
||||
private static final class TextAndPosition {
|
||||
private final String text;
|
||||
@RubySpan.Position private final int position;
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ 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.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.android.exoplayer2.text.span.HorizontalTextInVerticalContextSpan;
|
||||
|
|
@ -170,6 +171,40 @@ public class SpannedSubjectTest {
|
|||
assertThat(expected).factValue("but found").contains("start=" + start);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noStyleSpan_success() {
|
||||
SpannableString spannable = SpannableString.valueOf("test with underline then italic spans");
|
||||
spannable.setSpan(
|
||||
new UnderlineSpan(),
|
||||
"test with ".length(),
|
||||
"test with underline".length(),
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
spannable.setSpan(
|
||||
new StyleSpan(Typeface.ITALIC),
|
||||
"test with underline then ".length(),
|
||||
"test with underline then italic".length(),
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
|
||||
assertThat(spannable).hasNoStyleSpanBetween(0, "test with underline then".length());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noStyleSpan_failure() {
|
||||
SpannableString spannable = SpannableString.valueOf("test with italic section");
|
||||
int start = "test with ".length();
|
||||
int end = start + "italic".length();
|
||||
spannable.setSpan(new StyleSpan(Typeface.ITALIC), start, end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
|
||||
AssertionError expected =
|
||||
expectFailure(
|
||||
whenTesting -> whenTesting.that(spannable).hasNoStyleSpanBetween(start + 1, end));
|
||||
assertThat(expected)
|
||||
.factKeys()
|
||||
.contains("Found unexpected StyleSpans between start=" + (start + 1) + ",end=" + end);
|
||||
assertThat(expected).factKeys().contains("expected none");
|
||||
assertThat(expected).factValue("but found").contains("start=" + start);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void underlineSpan_success() {
|
||||
SpannableString spannable = SpannableString.valueOf("test with underlined section");
|
||||
|
|
@ -182,6 +217,40 @@ public class SpannedSubjectTest {
|
|||
.withFlags(Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noUnderlineSpan_success() {
|
||||
SpannableString spannable = SpannableString.valueOf("test with italic then underline spans");
|
||||
spannable.setSpan(
|
||||
new StyleSpan(Typeface.ITALIC),
|
||||
"test with ".length(),
|
||||
"test with italic".length(),
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
spannable.setSpan(
|
||||
new UnderlineSpan(),
|
||||
"test with italic then ".length(),
|
||||
"test with italic then underline".length(),
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
|
||||
assertThat(spannable).hasNoUnderlineSpanBetween(0, "test with italic then".length());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noUnderlineSpan_failure() {
|
||||
SpannableString spannable = SpannableString.valueOf("test with underline section");
|
||||
int start = "test with ".length();
|
||||
int end = start + "underline".length();
|
||||
spannable.setSpan(new UnderlineSpan(), start, end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
|
||||
AssertionError expected =
|
||||
expectFailure(
|
||||
whenTesting -> whenTesting.that(spannable).hasNoUnderlineSpanBetween(start + 1, end));
|
||||
assertThat(expected)
|
||||
.factKeys()
|
||||
.contains("Found unexpected UnderlineSpans between start=" + (start + 1) + ",end=" + end);
|
||||
assertThat(expected).factKeys().contains("expected none");
|
||||
assertThat(expected).factValue("but found").contains("start=" + start);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void foregroundColorSpan_success() {
|
||||
SpannableString spannable = SpannableString.valueOf("test with cyan section");
|
||||
|
|
@ -261,6 +330,43 @@ public class SpannedSubjectTest {
|
|||
.contains(String.valueOf(Spanned.SPAN_INCLUSIVE_EXCLUSIVE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noForegroundColorSpan_success() {
|
||||
SpannableString spannable = SpannableString.valueOf("test with underline then cyan spans");
|
||||
spannable.setSpan(
|
||||
new UnderlineSpan(),
|
||||
"test with ".length(),
|
||||
"test with underline".length(),
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
spannable.setSpan(
|
||||
new ForegroundColorSpan(Color.CYAN),
|
||||
"test with underline then ".length(),
|
||||
"test with underline then cyan".length(),
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
|
||||
assertThat(spannable).hasNoForegroundColorSpanBetween(0, "test with underline then".length());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noForegroundColorSpan_failure() {
|
||||
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).hasNoForegroundColorSpanBetween(start + 1, end));
|
||||
assertThat(expected)
|
||||
.factKeys()
|
||||
.contains(
|
||||
"Found unexpected ForegroundColorSpans between start=" + (start + 1) + ",end=" + end);
|
||||
assertThat(expected).factKeys().contains("expected none");
|
||||
assertThat(expected).factValue("but found").contains("start=" + start);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void backgroundColorSpan_success() {
|
||||
SpannableString spannable = SpannableString.valueOf("test with cyan section");
|
||||
|
|
@ -340,6 +446,152 @@ public class SpannedSubjectTest {
|
|||
.contains(String.valueOf(Spanned.SPAN_INCLUSIVE_EXCLUSIVE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noBackgroundColorSpan_success() {
|
||||
SpannableString spannable = SpannableString.valueOf("test with underline then cyan spans");
|
||||
spannable.setSpan(
|
||||
new UnderlineSpan(),
|
||||
"test with ".length(),
|
||||
"test with underline".length(),
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
spannable.setSpan(
|
||||
new BackgroundColorSpan(Color.CYAN),
|
||||
"test with underline then ".length(),
|
||||
"test with underline then cyan".length(),
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
|
||||
assertThat(spannable).hasNoBackgroundColorSpanBetween(0, "test with underline then".length());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noBackgroundColorSpan_failure() {
|
||||
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).hasNoBackgroundColorSpanBetween(start + 1, end));
|
||||
assertThat(expected)
|
||||
.factKeys()
|
||||
.contains(
|
||||
"Found unexpected BackgroundColorSpans between start=" + (start + 1) + ",end=" + end);
|
||||
assertThat(expected).factKeys().contains("expected none");
|
||||
assertThat(expected).factValue("but found").contains("start=" + start);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void typefaceSpan_success() {
|
||||
SpannableString spannable = SpannableString.valueOf("test with courier section");
|
||||
int start = "test with ".length();
|
||||
int end = start + "courier".length();
|
||||
spannable.setSpan(new TypefaceSpan("courier"), start, end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
|
||||
assertThat(spannable)
|
||||
.hasTypefaceSpanBetween(start, end)
|
||||
.withFamily("courier")
|
||||
.andFlags(Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void typefaceSpan_wrongEndIndex() {
|
||||
SpannableString spannable = SpannableString.valueOf("test with courier section");
|
||||
int start = "test with ".length();
|
||||
int end = start + "courier".length();
|
||||
spannable.setSpan(new TypefaceSpan("courier"), start, end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
|
||||
int incorrectEnd = end + 2;
|
||||
AssertionError expected =
|
||||
expectFailure(
|
||||
whenTesting ->
|
||||
whenTesting
|
||||
.that(spannable)
|
||||
.hasTypefaceSpanBetween(start, incorrectEnd)
|
||||
.withFamily("courier"));
|
||||
assertThat(expected).factValue("expected").contains("end=" + incorrectEnd);
|
||||
assertThat(expected).factValue("but found").contains("end=" + end);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void typefaceSpan_wrongFamily() {
|
||||
SpannableString spannable = SpannableString.valueOf("test with courier section");
|
||||
int start = "test with ".length();
|
||||
int end = start + "courier".length();
|
||||
spannable.setSpan(new TypefaceSpan("courier"), start, end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
|
||||
AssertionError expected =
|
||||
expectFailure(
|
||||
whenTesting ->
|
||||
whenTesting
|
||||
.that(spannable)
|
||||
.hasTypefaceSpanBetween(start, end)
|
||||
.withFamily("roboto"));
|
||||
assertThat(expected).factValue("value of").contains("family");
|
||||
assertThat(expected).factValue("expected").contains("roboto");
|
||||
assertThat(expected).factValue("but was").contains("courier");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void typefaceSpan_wrongFlags() {
|
||||
SpannableString spannable = SpannableString.valueOf("test with courier section");
|
||||
int start = "test with ".length();
|
||||
int end = start + "courier".length();
|
||||
spannable.setSpan(new TypefaceSpan("courier"), start, end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
|
||||
AssertionError expected =
|
||||
expectFailure(
|
||||
whenTesting ->
|
||||
whenTesting
|
||||
.that(spannable)
|
||||
.hasTypefaceSpanBetween(start, end)
|
||||
.withFamily("courier")
|
||||
.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 noTypefaceSpan_success() {
|
||||
SpannableString spannable = SpannableString.valueOf("test with underline then courier spans");
|
||||
spannable.setSpan(
|
||||
new UnderlineSpan(),
|
||||
"test with ".length(),
|
||||
"test with underline".length(),
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
spannable.setSpan(
|
||||
new TypefaceSpan("courier"),
|
||||
"test with underline then ".length(),
|
||||
"test with underline then courier".length(),
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
|
||||
assertThat(spannable).hasNoTypefaceSpanBetween(0, "test with underline then".length());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noTypefaceSpan_failure() {
|
||||
SpannableString spannable = SpannableString.valueOf("test with courier section");
|
||||
int start = "test with ".length();
|
||||
int end = start + "courier".length();
|
||||
spannable.setSpan(new TypefaceSpan("courier"), start, end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
|
||||
AssertionError expected =
|
||||
expectFailure(
|
||||
whenTesting -> whenTesting.that(spannable).hasNoTypefaceSpanBetween(start + 1, end));
|
||||
assertThat(expected)
|
||||
.factKeys()
|
||||
.contains("Found unexpected TypefaceSpans between start=" + (start + 1) + ",end=" + end);
|
||||
assertThat(expected).factKeys().contains("expected none");
|
||||
assertThat(expected).factValue("but found").contains("start=" + start);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rubySpan_success() {
|
||||
SpannableString spannable = SpannableString.valueOf("test with rubied section");
|
||||
|
|
@ -454,6 +706,44 @@ public class SpannedSubjectTest {
|
|||
.contains(String.valueOf(Spanned.SPAN_INCLUSIVE_EXCLUSIVE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noRubySpan_success() {
|
||||
SpannableString spannable = SpannableString.valueOf("test with underline then ruby spans");
|
||||
spannable.setSpan(
|
||||
new UnderlineSpan(),
|
||||
"test with ".length(),
|
||||
"test with underline".length(),
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
spannable.setSpan(
|
||||
new RubySpan("ruby text", RubySpan.POSITION_OVER),
|
||||
"test with underline then ".length(),
|
||||
"test with underline then ruby".length(),
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
|
||||
assertThat(spannable).hasNoRubySpanBetween(0, "test with underline then".length());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noRubySpan_failure() {
|
||||
SpannableString spannable = SpannableString.valueOf("test with ruby section");
|
||||
int start = "test with ".length();
|
||||
int end = start + "ruby".length();
|
||||
spannable.setSpan(
|
||||
new RubySpan("ruby text", RubySpan.POSITION_OVER),
|
||||
start,
|
||||
end,
|
||||
Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
|
||||
AssertionError expected =
|
||||
expectFailure(
|
||||
whenTesting -> whenTesting.that(spannable).hasNoRubySpanBetween(start + 1, end));
|
||||
assertThat(expected)
|
||||
.factKeys()
|
||||
.contains("Found unexpected RubySpans between start=" + (start + 1) + ",end=" + end);
|
||||
assertThat(expected).factKeys().contains("expected none");
|
||||
assertThat(expected).factValue("but found").contains("start=" + start);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void horizontalTextInVerticalContextSpan_success() {
|
||||
SpannableString spannable = SpannableString.valueOf("vertical text with horizontal section");
|
||||
|
|
@ -467,6 +757,50 @@ public class SpannedSubjectTest {
|
|||
.withFlags(Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noHorizontalTextInVerticalContextSpan_success() {
|
||||
SpannableString spannable =
|
||||
SpannableString.valueOf("test with underline then tate-chu-yoko spans");
|
||||
spannable.setSpan(
|
||||
new UnderlineSpan(),
|
||||
"test with ".length(),
|
||||
"test with underline".length(),
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
spannable.setSpan(
|
||||
new HorizontalTextInVerticalContextSpan(),
|
||||
"test with underline then ".length(),
|
||||
"test with underline then tate-chu-yoko".length(),
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
|
||||
assertThat(spannable)
|
||||
.hasNoHorizontalTextInVerticalContextSpanBetween(0, "test with underline then".length());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noHorizontalTextInVerticalContextSpan_failure() {
|
||||
SpannableString spannable = SpannableString.valueOf("test with tate-chu-yoko section");
|
||||
int start = "test with ".length();
|
||||
int end = start + "tate-chu-yoko".length();
|
||||
spannable.setSpan(
|
||||
new HorizontalTextInVerticalContextSpan(), start, end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
|
||||
AssertionError expected =
|
||||
expectFailure(
|
||||
whenTesting ->
|
||||
whenTesting
|
||||
.that(spannable)
|
||||
.hasNoHorizontalTextInVerticalContextSpanBetween(start + 1, end));
|
||||
assertThat(expected)
|
||||
.factKeys()
|
||||
.contains(
|
||||
"Found unexpected HorizontalTextInVerticalContextSpans between start="
|
||||
+ (start + 1)
|
||||
+ ",end="
|
||||
+ end);
|
||||
assertThat(expected).factKeys().contains("expected none");
|
||||
assertThat(expected).factValue("but found").contains("start=" + start);
|
||||
}
|
||||
|
||||
private static AssertionError expectFailure(
|
||||
ExpectFailure.SimpleSubjectBuilderCallback<SpannedSubject, Spanned> callback) {
|
||||
return expectFailureAbout(spanned(), callback);
|
||||
|
|
|
|||
Loading…
Reference in a new issue