mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +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
|
id
|
||||||
00:00.000 --> 00:01.001
|
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
|
íd
|
||||||
00:02.000 --> 00:02.001
|
00:02.000 --> 00:02.001
|
||||||
|
|
@ -31,10 +31,10 @@ _id
|
||||||
This <lang.class.another>should be courier and bold.
|
This <lang.class.another>should be courier and bold.
|
||||||
|
|
||||||
00:04.000 --> 00:04.001
|
00:04.000 --> 00:04.001
|
||||||
This <v Strider Trancos> shouldn't be bold.</v>
|
This <v Strider Trancos>shouldn't be bold.</v>
|
||||||
This <v.class.clazz Strider Trancos> should be bold.
|
This <v.class.clazz Strider Trancos>should be bold.
|
||||||
|
|
||||||
anId
|
anId
|
||||||
00:05.000 --> 00:05.001
|
00:05.000 --> 00:05.001
|
||||||
This is <v.class1.class3.class2 Pipo> specific </v>
|
This is <v.class1.class3.class2 Pipo>specific</v>
|
||||||
<v.class1.class3.class2 Robert> But this is more italic</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 com.google.common.truth.Truth.assertThat;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
import android.graphics.Typeface;
|
|
||||||
import android.text.Layout.Alignment;
|
import android.text.Layout.Alignment;
|
||||||
import android.text.Spanned;
|
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.core.app.ApplicationProvider;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
import com.google.android.exoplayer2.testutil.TestUtil;
|
import com.google.android.exoplayer2.testutil.TestUtil;
|
||||||
import com.google.android.exoplayer2.text.Cue;
|
import com.google.android.exoplayer2.text.Cue;
|
||||||
import com.google.android.exoplayer2.text.SubtitleDecoderException;
|
import com.google.android.exoplayer2.text.SubtitleDecoderException;
|
||||||
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
import com.google.android.exoplayer2.util.ColorParser;
|
import com.google.android.exoplayer2.util.ColorParser;
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.common.truth.Expect;
|
import com.google.common.truth.Expect;
|
||||||
|
|
@ -328,41 +325,39 @@ public class WebvttDecoderTest {
|
||||||
@Test
|
@Test
|
||||||
public void testWithComplexCssSelectors() throws Exception {
|
public void testWithComplexCssSelectors() throws Exception {
|
||||||
WebvttSubtitle subtitle = getSubtitleForTestAsset(WITH_CSS_COMPLEX_SELECTORS);
|
WebvttSubtitle subtitle = getSubtitleForTestAsset(WITH_CSS_COMPLEX_SELECTORS);
|
||||||
Spanned text = getUniqueSpanTextAt(subtitle, /* timeUs= */ 0);
|
Spanned firstCueText = getUniqueSpanTextAt(subtitle, /* timeUs= */ 0);
|
||||||
assertThat(text.getSpans(/* start= */ 30, text.length(), ForegroundColorSpan.class))
|
assertThat(firstCueText)
|
||||||
.hasLength(1);
|
.hasForegroundColorSpanBetween(
|
||||||
assertThat(
|
"This should be underlined and ".length(), firstCueText.length())
|
||||||
text.getSpans(/* start= */ 30, text.length(), ForegroundColorSpan.class)[0]
|
.withColor(ColorParser.parseCssColor("violet"));
|
||||||
.getForegroundColor())
|
assertThat(firstCueText)
|
||||||
.isEqualTo(0xFFEE82EE);
|
.hasTypefaceSpanBetween("This should be underlined and ".length(), firstCueText.length())
|
||||||
assertThat(text.getSpans(/* start= */ 30, text.length(), TypefaceSpan.class)).hasLength(1);
|
.withFamily("courier");
|
||||||
assertThat(text.getSpans(/* start= */ 30, text.length(), TypefaceSpan.class)[0].getFamily())
|
|
||||||
.isEqualTo("courier");
|
|
||||||
|
|
||||||
text = getUniqueSpanTextAt(subtitle, /* timeUs= */ 2000000);
|
Spanned secondCueText = getUniqueSpanTextAt(subtitle, /* timeUs= */ 2_000_000);
|
||||||
assertThat(text.getSpans(/* start= */ 5, text.length(), TypefaceSpan.class)).hasLength(1);
|
assertThat(secondCueText)
|
||||||
assertThat(text.getSpans(/* start= */ 5, text.length(), TypefaceSpan.class)[0].getFamily())
|
.hasTypefaceSpanBetween("This ".length(), secondCueText.length())
|
||||||
.isEqualTo("courier");
|
.withFamily("courier");
|
||||||
|
assertThat(secondCueText)
|
||||||
|
.hasNoForegroundColorSpanBetween("This ".length(), secondCueText.length());
|
||||||
|
|
||||||
text = getUniqueSpanTextAt(subtitle, /* timeUs= */ 2500000);
|
Spanned thirdCueText = getUniqueSpanTextAt(subtitle, /* timeUs= */ 2_500_000);
|
||||||
assertThat(text.getSpans(/* start= */ 5, text.length(), StyleSpan.class)).hasLength(1);
|
assertThat(thirdCueText).hasBoldSpanBetween("This ".length(), thirdCueText.length());
|
||||||
assertThat(text.getSpans(/* start= */ 5, text.length(), StyleSpan.class)[0].getStyle())
|
assertThat(thirdCueText)
|
||||||
.isEqualTo(Typeface.BOLD);
|
.hasTypefaceSpanBetween("This ".length(), thirdCueText.length())
|
||||||
assertThat(text.getSpans(/* start= */ 5, text.length(), TypefaceSpan.class)).hasLength(1);
|
.withFamily("courier");
|
||||||
assertThat(text.getSpans(/* start= */ 5, text.length(), TypefaceSpan.class)[0].getFamily())
|
|
||||||
.isEqualTo("courier");
|
|
||||||
|
|
||||||
text = getUniqueSpanTextAt(subtitle, /* timeUs= */ 4000000);
|
Spanned fourthCueText = getUniqueSpanTextAt(subtitle, /* timeUs= */ 4_000_000);
|
||||||
assertThat(text.getSpans(/* start= */ 6, /* end= */ 22, StyleSpan.class)).hasLength(0);
|
assertThat(fourthCueText)
|
||||||
assertThat(text.getSpans(/* start= */ 30, text.length(), StyleSpan.class)).hasLength(1);
|
.hasNoStyleSpanBetween("This ".length(), "shouldn't be bold.".length());
|
||||||
assertThat(text.getSpans(/* start= */ 30, text.length(), StyleSpan.class)[0].getStyle())
|
assertThat(fourthCueText)
|
||||||
.isEqualTo(Typeface.BOLD);
|
.hasBoldSpanBetween("This shouldn't be bold.\nThis ".length(), fourthCueText.length());
|
||||||
|
|
||||||
text = getUniqueSpanTextAt(subtitle, /* timeUs= */ 5000000);
|
Spanned fifthCueText = getUniqueSpanTextAt(subtitle, /* timeUs= */ 5_000_000);
|
||||||
assertThat(text.getSpans(/* start= */ 9, /* end= */ 17, StyleSpan.class)).hasLength(0);
|
assertThat(fifthCueText)
|
||||||
assertThat(text.getSpans(/* start= */ 19, text.length(), StyleSpan.class)).hasLength(1);
|
.hasNoStyleSpanBetween("This is ".length(), "This is specific".length());
|
||||||
assertThat(text.getSpans(/* start= */ 19, text.length(), StyleSpan.class)[0].getStyle())
|
assertThat(fifthCueText)
|
||||||
.isEqualTo(Typeface.ITALIC);
|
.hasItalicSpanBetween("This is specific\n".length(), fifthCueText.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -387,6 +382,6 @@ public class WebvttDecoderTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Spanned getUniqueSpanTextAt(WebvttSubtitle sub, long timeUs) {
|
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.BackgroundColorSpan;
|
||||||
import android.text.style.ForegroundColorSpan;
|
import android.text.style.ForegroundColorSpan;
|
||||||
import android.text.style.StyleSpan;
|
import android.text.style.StyleSpan;
|
||||||
|
import android.text.style.TypefaceSpan;
|
||||||
import android.text.style.UnderlineSpan;
|
import android.text.style.UnderlineSpan;
|
||||||
import androidx.annotation.CheckResult;
|
import androidx.annotation.CheckResult;
|
||||||
import androidx.annotation.ColorInt;
|
import androidx.annotation.ColorInt;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import com.google.android.exoplayer2.text.span.HorizontalTextInVerticalContextSpan;
|
import com.google.android.exoplayer2.text.span.HorizontalTextInVerticalContextSpan;
|
||||||
import com.google.android.exoplayer2.text.span.RubySpan;
|
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.FailureMetadata;
|
||||||
import com.google.common.truth.Subject;
|
import com.google.common.truth.Subject;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
@ -171,6 +173,19 @@ public final class SpannedSubject extends Subject {
|
||||||
return ALREADY_FAILED_WITH_FLAGS;
|
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}.
|
* 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;
|
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}.
|
* 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);
|
.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}.
|
* 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);
|
.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}.
|
* 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);
|
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}
|
* Checks that the subject has an {@link HorizontalTextInVerticalContextSpan} from {@code start}
|
||||||
* to {@code end}.
|
* to {@code end}.
|
||||||
|
|
@ -303,6 +409,45 @@ public final class SpannedSubject extends Subject {
|
||||||
return ALREADY_FAILED_WITH_FLAGS;
|
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) {
|
private <T> List<T> findMatchingSpans(int startIndex, int endIndex, Class<T> spanClazz) {
|
||||||
List<T> spans = new ArrayList<>();
|
List<T> spans = new ArrayList<>();
|
||||||
for (T span : actual.getSpans(startIndex, endIndex, spanClazz)) {
|
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 static final Colored ALREADY_FAILED_COLORED = color -> ALREADY_FAILED_AND_FLAGS;
|
||||||
|
|
||||||
private Factory<ForegroundColorSpansSubject, List<ForegroundColorSpan>> foregroundColorSpans(
|
private static Factory<ForegroundColorSpansSubject, List<ForegroundColorSpan>>
|
||||||
Spanned actualSpanned) {
|
foregroundColorSpans(Spanned actualSpanned) {
|
||||||
return (FailureMetadata metadata, List<ForegroundColorSpan> spans) ->
|
return (FailureMetadata metadata, List<ForegroundColorSpan> spans) ->
|
||||||
new ForegroundColorSpansSubject(metadata, spans, actualSpanned);
|
new ForegroundColorSpansSubject(metadata, spans, actualSpanned);
|
||||||
}
|
}
|
||||||
|
|
@ -458,8 +603,8 @@ public final class SpannedSubject extends Subject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Factory<BackgroundColorSpansSubject, List<BackgroundColorSpan>> backgroundColorSpans(
|
private static Factory<BackgroundColorSpansSubject, List<BackgroundColorSpan>>
|
||||||
Spanned actualSpanned) {
|
backgroundColorSpans(Spanned actualSpanned) {
|
||||||
return (FailureMetadata metadata, List<BackgroundColorSpan> spans) ->
|
return (FailureMetadata metadata, List<BackgroundColorSpan> spans) ->
|
||||||
new BackgroundColorSpansSubject(metadata, spans, actualSpanned);
|
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. */
|
/** Allows assertions about a span's ruby text and its position. */
|
||||||
public interface RubyText {
|
public interface RubyText {
|
||||||
|
|
||||||
|
|
@ -511,7 +705,7 @@ public final class SpannedSubject extends Subject {
|
||||||
private static final RubyText ALREADY_FAILED_WITH_TEXT =
|
private static final RubyText ALREADY_FAILED_WITH_TEXT =
|
||||||
(text, position) -> ALREADY_FAILED_AND_FLAGS;
|
(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) ->
|
return (FailureMetadata metadata, List<RubySpan> spans) ->
|
||||||
new RubySpansSubject(metadata, spans, actualSpanned);
|
new RubySpansSubject(metadata, spans, actualSpanned);
|
||||||
}
|
}
|
||||||
|
|
@ -544,7 +738,7 @@ public final class SpannedSubject extends Subject {
|
||||||
return check("flags").about(spanFlags()).that(matchingSpanFlags);
|
return check("flags").about(spanFlags()).that(matchingSpanFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class TextAndPosition {
|
private static final class TextAndPosition {
|
||||||
private final String text;
|
private final String text;
|
||||||
@RubySpan.Position private final int position;
|
@RubySpan.Position private final int position;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ import android.text.Spanned;
|
||||||
import android.text.style.BackgroundColorSpan;
|
import android.text.style.BackgroundColorSpan;
|
||||||
import android.text.style.ForegroundColorSpan;
|
import android.text.style.ForegroundColorSpan;
|
||||||
import android.text.style.StyleSpan;
|
import android.text.style.StyleSpan;
|
||||||
|
import android.text.style.TypefaceSpan;
|
||||||
import android.text.style.UnderlineSpan;
|
import android.text.style.UnderlineSpan;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
import com.google.android.exoplayer2.text.span.HorizontalTextInVerticalContextSpan;
|
import com.google.android.exoplayer2.text.span.HorizontalTextInVerticalContextSpan;
|
||||||
|
|
@ -170,6 +171,40 @@ public class SpannedSubjectTest {
|
||||||
assertThat(expected).factValue("but found").contains("start=" + start);
|
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
|
@Test
|
||||||
public void underlineSpan_success() {
|
public void underlineSpan_success() {
|
||||||
SpannableString spannable = SpannableString.valueOf("test with underlined section");
|
SpannableString spannable = SpannableString.valueOf("test with underlined section");
|
||||||
|
|
@ -182,6 +217,40 @@ public class SpannedSubjectTest {
|
||||||
.withFlags(Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
.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
|
@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");
|
||||||
|
|
@ -261,6 +330,43 @@ public class SpannedSubjectTest {
|
||||||
.contains(String.valueOf(Spanned.SPAN_INCLUSIVE_EXCLUSIVE));
|
.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
|
@Test
|
||||||
public void backgroundColorSpan_success() {
|
public void backgroundColorSpan_success() {
|
||||||
SpannableString spannable = SpannableString.valueOf("test with cyan section");
|
SpannableString spannable = SpannableString.valueOf("test with cyan section");
|
||||||
|
|
@ -340,6 +446,152 @@ public class SpannedSubjectTest {
|
||||||
.contains(String.valueOf(Spanned.SPAN_INCLUSIVE_EXCLUSIVE));
|
.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
|
@Test
|
||||||
public void rubySpan_success() {
|
public void rubySpan_success() {
|
||||||
SpannableString spannable = SpannableString.valueOf("test with rubied section");
|
SpannableString spannable = SpannableString.valueOf("test with rubied section");
|
||||||
|
|
@ -454,6 +706,44 @@ public class SpannedSubjectTest {
|
||||||
.contains(String.valueOf(Spanned.SPAN_INCLUSIVE_EXCLUSIVE));
|
.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
|
@Test
|
||||||
public void horizontalTextInVerticalContextSpan_success() {
|
public void horizontalTextInVerticalContextSpan_success() {
|
||||||
SpannableString spannable = SpannableString.valueOf("vertical text with horizontal section");
|
SpannableString spannable = SpannableString.valueOf("vertical text with horizontal section");
|
||||||
|
|
@ -467,6 +757,50 @@ public class SpannedSubjectTest {
|
||||||
.withFlags(Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
.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(
|
private static AssertionError expectFailure(
|
||||||
ExpectFailure.SimpleSubjectBuilderCallback<SpannedSubject, Spanned> callback) {
|
ExpectFailure.SimpleSubjectBuilderCallback<SpannedSubject, Spanned> callback) {
|
||||||
return expectFailureAbout(spanned(), callback);
|
return expectFailureAbout(spanned(), callback);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue