diff --git a/library/core/src/test/java/com/google/android/exoplayer2/text/ttml/TtmlDecoderTest.java b/library/core/src/test/java/com/google/android/exoplayer2/text/ttml/TtmlDecoderTest.java index 0f1b117fb4..e06abcbe6e 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/text/ttml/TtmlDecoderTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/text/ttml/TtmlDecoderTest.java @@ -15,26 +15,19 @@ */ package com.google.android.exoplayer2.text.ttml; +import static com.google.android.exoplayer2.testutil.truth.SpannedSubject.assertThat; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; import android.text.Layout; -import android.text.Spannable; -import android.text.SpannableStringBuilder; -import android.text.style.AbsoluteSizeSpan; -import android.text.style.AlignmentSpan; -import android.text.style.BackgroundColorSpan; -import android.text.style.ForegroundColorSpan; -import android.text.style.RelativeSizeSpan; -import android.text.style.StrikethroughSpan; -import android.text.style.StyleSpan; -import android.text.style.TypefaceSpan; -import android.text.style.UnderlineSpan; +import android.text.Spanned; 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.Subtitle; import com.google.android.exoplayer2.text.SubtitleDecoderException; +import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.ColorParser; import java.io.IOException; import java.util.List; @@ -71,35 +64,37 @@ public final class TtmlDecoderTest { @Test public void testInlineAttributes() throws IOException, SubtitleDecoderException { TtmlSubtitle subtitle = getSubtitle(INLINE_ATTRIBUTES_TTML_FILE); + assertThat(subtitle.getEventTimeCount()).isEqualTo(4); - TtmlNode root = subtitle.getRoot(); - - TtmlNode body = queryChildrenForTag(root, TtmlNode.TAG_BODY, 0); - TtmlNode firstDiv = queryChildrenForTag(body, TtmlNode.TAG_DIV, 0); - TtmlStyle firstPStyle = queryChildrenForTag(firstDiv, TtmlNode.TAG_P, 0).style; - assertThat(firstPStyle.getFontColor()).isEqualTo(ColorParser.parseTtmlColor("yellow")); - assertThat(firstPStyle.getBackgroundColor()).isEqualTo(ColorParser.parseTtmlColor("blue")); - assertThat(firstPStyle.getFontFamily()).isEqualTo("serif"); - assertThat(firstPStyle.getStyle()).isEqualTo(TtmlStyle.STYLE_BOLD_ITALIC); - assertThat(firstPStyle.isUnderline()).isTrue(); + Spanned spanned = getOnlyCueTextAtTimeUs(subtitle, 10_000_000); + assertThat(spanned.toString()).isEqualTo("text 1"); + assertThat(spanned).hasTypefaceSpanBetween(0, spanned.length()).withFamily("serif"); + assertThat(spanned).hasBoldItalicSpanBetween(0, spanned.length()); + assertThat(spanned).hasUnderlineSpanBetween(0, spanned.length()); + assertThat(spanned) + .hasBackgroundColorSpanBetween(0, spanned.length()) + .withColor(ColorParser.parseTtmlColor("blue")); + assertThat(spanned) + .hasForegroundColorSpanBetween(0, spanned.length()) + .withColor(ColorParser.parseTtmlColor("yellow")); } @Test public void testInheritInlineAttributes() throws IOException, SubtitleDecoderException { TtmlSubtitle subtitle = getSubtitle(INLINE_ATTRIBUTES_TTML_FILE); + assertThat(subtitle.getEventTimeCount()).isEqualTo(4); - assertSpans( - subtitle, - 20, - "text 2", - "sansSerif", - TtmlStyle.STYLE_ITALIC, - 0xFF00FFFF, - ColorParser.parseTtmlColor("lime"), - false, - true, - null); + + Spanned spanned = getOnlyCueTextAtTimeUs(subtitle, 20_000_000); + assertThat(spanned.toString()).isEqualTo("text 2"); + assertThat(spanned).hasTypefaceSpanBetween(0, spanned.length()).withFamily("sansSerif"); + assertThat(spanned).hasItalicSpanBetween(0, spanned.length()); + assertThat(spanned).hasStrikethroughSpanBetween(0, spanned.length()); + assertThat(spanned).hasBackgroundColorSpanBetween(0, spanned.length()).withColor(0xFF00FFFF); + assertThat(spanned) + .hasForegroundColorSpanBetween(0, spanned.length()) + .withColor(ColorParser.parseTtmlColor("lime")); } /** @@ -117,153 +112,171 @@ public final class TtmlDecoderTest { @Test public void testLime() throws IOException, SubtitleDecoderException { TtmlSubtitle subtitle = getSubtitle(INLINE_ATTRIBUTES_TTML_FILE); + assertThat(subtitle.getEventTimeCount()).isEqualTo(4); - assertSpans( - subtitle, - 20, - "text 2", - "sansSerif", - TtmlStyle.STYLE_ITALIC, - 0xFF00FFFF, - 0xFF00FF00, - false, - true, - null); + + Spanned spanned = getOnlyCueTextAtTimeUs(subtitle, 20_000_000); + assertThat(spanned.toString()).isEqualTo("text 2"); + assertThat(spanned).hasTypefaceSpanBetween(0, spanned.length()).withFamily("sansSerif"); + assertThat(spanned).hasItalicSpanBetween(0, spanned.length()); + assertThat(spanned).hasStrikethroughSpanBetween(0, spanned.length()); + assertThat(spanned).hasBackgroundColorSpanBetween(0, spanned.length()).withColor(0xFF00FFFF); + assertThat(spanned).hasForegroundColorSpanBetween(0, spanned.length()).withColor(0xFF00FF00); } @Test public void testInheritGlobalStyle() throws IOException, SubtitleDecoderException { TtmlSubtitle subtitle = getSubtitle(INHERIT_STYLE_TTML_FILE); + assertThat(subtitle.getEventTimeCount()).isEqualTo(2); - assertSpans( - subtitle, - 10, - "text 1", - "serif", - TtmlStyle.STYLE_BOLD_ITALIC, - 0xFF0000FF, - 0xFFFFFF00, - true, - false, - null); + + Spanned spanned = getOnlyCueTextAtTimeUs(subtitle, 10_000_000); + assertThat(spanned.toString()).isEqualTo("text 1"); + assertThat(spanned).hasTypefaceSpanBetween(0, spanned.length()).withFamily("serif"); + assertThat(spanned).hasBoldItalicSpanBetween(0, spanned.length()); + assertThat(spanned).hasUnderlineSpanBetween(0, spanned.length()); + assertThat(spanned).hasBackgroundColorSpanBetween(0, spanned.length()).withColor(0xFF0000FF); + assertThat(spanned).hasForegroundColorSpanBetween(0, spanned.length()).withColor(0xFFFFFF00); } @Test public void testInheritGlobalStyleOverriddenByInlineAttributes() throws IOException, SubtitleDecoderException { TtmlSubtitle subtitle = getSubtitle(INHERIT_STYLE_OVERRIDE_TTML_FILE); + assertThat(subtitle.getEventTimeCount()).isEqualTo(4); - assertSpans( - subtitle, - 10, - "text 1", - "serif", - TtmlStyle.STYLE_BOLD_ITALIC, - 0xFF0000FF, - 0xFFFFFF00, - true, - false, - null); - assertSpans( - subtitle, - 20, - "text 2", - "sansSerif", - TtmlStyle.STYLE_ITALIC, - 0xFFFF0000, - 0xFFFFFF00, - true, - false, - null); + Spanned firstCueText = getOnlyCueTextAtTimeUs(subtitle, 10_000_000); + assertThat(firstCueText.toString()).isEqualTo("text 1"); + assertThat(firstCueText).hasTypefaceSpanBetween(0, firstCueText.length()).withFamily("serif"); + assertThat(firstCueText).hasBoldItalicSpanBetween(0, firstCueText.length()); + assertThat(firstCueText).hasUnderlineSpanBetween(0, firstCueText.length()); + assertThat(firstCueText) + .hasBackgroundColorSpanBetween(0, firstCueText.length()) + .withColor(0xFF0000FF); + assertThat(firstCueText) + .hasForegroundColorSpanBetween(0, firstCueText.length()) + .withColor(0xFFFFFF00); + + Spanned secondCueText = getOnlyCueTextAtTimeUs(subtitle, 20_000_000); + assertThat(secondCueText.toString()).isEqualTo("text 2"); + assertThat(secondCueText) + .hasTypefaceSpanBetween(0, secondCueText.length()) + .withFamily("sansSerif"); + assertThat(secondCueText).hasItalicSpanBetween(0, secondCueText.length()); + assertThat(secondCueText).hasUnderlineSpanBetween(0, secondCueText.length()); + assertThat(secondCueText) + .hasBackgroundColorSpanBetween(0, secondCueText.length()) + .withColor(0xFFFF0000); + assertThat(secondCueText) + .hasForegroundColorSpanBetween(0, secondCueText.length()) + .withColor(0xFFFFFF00); } @Test public void testInheritGlobalAndParent() throws IOException, SubtitleDecoderException { TtmlSubtitle subtitle = getSubtitle(INHERIT_GLOBAL_AND_PARENT_TTML_FILE); + assertThat(subtitle.getEventTimeCount()).isEqualTo(4); - assertSpans( - subtitle, - 10, - "text 1", - "sansSerif", - TtmlStyle.STYLE_NORMAL, - 0xFFFF0000, - ColorParser.parseTtmlColor("lime"), - false, - true, - Layout.Alignment.ALIGN_CENTER); - assertSpans( - subtitle, - 20, - "text 2", - "serif", - TtmlStyle.STYLE_BOLD_ITALIC, - 0xFF0000FF, - 0xFFFFFF00, - true, - true, - Layout.Alignment.ALIGN_CENTER); + Spanned firstCueText = getOnlyCueTextAtTimeUs(subtitle, 10_000_000); + assertThat(firstCueText.toString()).isEqualTo("text 1"); + assertThat(firstCueText) + .hasTypefaceSpanBetween(0, firstCueText.length()) + .withFamily("sansSerif"); + assertThat(firstCueText).hasStrikethroughSpanBetween(0, firstCueText.length()); + assertThat(firstCueText) + .hasBackgroundColorSpanBetween(0, firstCueText.length()) + .withColor(0xFFFF0000); + assertThat(firstCueText) + .hasForegroundColorSpanBetween(0, firstCueText.length()) + .withColor(ColorParser.parseTtmlColor("lime")); + assertThat(firstCueText) + .hasAlignmentSpanBetween(0, firstCueText.length()) + .withAlignment(Layout.Alignment.ALIGN_CENTER); + + Spanned secondCueText = getOnlyCueTextAtTimeUs(subtitle, 20_000_000); + assertThat(secondCueText.toString()).isEqualTo("text 2"); + assertThat(secondCueText).hasTypefaceSpanBetween(0, secondCueText.length()).withFamily("serif"); + assertThat(secondCueText).hasBoldItalicSpanBetween(0, secondCueText.length()); + assertThat(secondCueText).hasUnderlineSpanBetween(0, secondCueText.length()); + assertThat(secondCueText).hasStrikethroughSpanBetween(0, secondCueText.length()); + assertThat(secondCueText) + .hasBackgroundColorSpanBetween(0, secondCueText.length()) + .withColor(0xFF0000FF); + assertThat(secondCueText) + .hasForegroundColorSpanBetween(0, secondCueText.length()) + .withColor(0xFFFFFF00); + assertThat(secondCueText) + .hasAlignmentSpanBetween(0, secondCueText.length()) + .withAlignment(Layout.Alignment.ALIGN_CENTER); } @Test public void testInheritMultipleStyles() throws IOException, SubtitleDecoderException { TtmlSubtitle subtitle = getSubtitle(INHERIT_MULTIPLE_STYLES_TTML_FILE); + assertThat(subtitle.getEventTimeCount()).isEqualTo(12); - assertSpans( - subtitle, - 10, - "text 1", - "sansSerif", - TtmlStyle.STYLE_BOLD_ITALIC, - 0xFF0000FF, - 0xFFFFFF00, - false, - true, - null); + + Spanned spanned = getOnlyCueTextAtTimeUs(subtitle, 10_000_000); + assertThat(spanned.toString()).isEqualTo("text 1"); + assertThat(spanned).hasTypefaceSpanBetween(0, spanned.length()).withFamily("sansSerif"); + assertThat(spanned).hasBoldItalicSpanBetween(0, spanned.length()); + assertThat(spanned).hasStrikethroughSpanBetween(0, spanned.length()); + assertThat(spanned).hasBackgroundColorSpanBetween(0, spanned.length()).withColor(0xFF0000FF); + assertThat(spanned).hasForegroundColorSpanBetween(0, spanned.length()).withColor(0xFFFFFF00); } @Test public void testInheritMultipleStylesWithoutLocalAttributes() throws IOException, SubtitleDecoderException { TtmlSubtitle subtitle = getSubtitle(INHERIT_MULTIPLE_STYLES_TTML_FILE); + assertThat(subtitle.getEventTimeCount()).isEqualTo(12); - assertSpans( - subtitle, - 20, - "text 2", - "sansSerif", - TtmlStyle.STYLE_BOLD_ITALIC, - 0xFF0000FF, - 0xFF000000, - false, - true, - null); + + Spanned secondCueText = getOnlyCueTextAtTimeUs(subtitle, 20_000_000); + assertThat(secondCueText.toString()).isEqualTo("text 2"); + assertThat(secondCueText) + .hasTypefaceSpanBetween(0, secondCueText.length()) + .withFamily("sansSerif"); + assertThat(secondCueText).hasBoldItalicSpanBetween(0, secondCueText.length()); + assertThat(secondCueText).hasStrikethroughSpanBetween(0, secondCueText.length()); + assertThat(secondCueText) + .hasBackgroundColorSpanBetween(0, secondCueText.length()) + .withColor(0xFF0000FF); + assertThat(secondCueText) + .hasForegroundColorSpanBetween(0, secondCueText.length()) + .withColor(0xFF000000); } @Test public void testMergeMultipleStylesWithParentStyle() throws IOException, SubtitleDecoderException { TtmlSubtitle subtitle = getSubtitle(INHERIT_MULTIPLE_STYLES_TTML_FILE); + assertThat(subtitle.getEventTimeCount()).isEqualTo(12); - assertSpans( - subtitle, - 30, - "text 2.5", - "sansSerifInline", - TtmlStyle.STYLE_ITALIC, - 0xFFFF0000, - 0xFFFFFF00, - true, - true, - null); + + Spanned thirdCueText = getOnlyCueTextAtTimeUs(subtitle, 30_000_000); + assertThat(thirdCueText.toString()).isEqualTo("text 2.5"); + assertThat(thirdCueText) + .hasTypefaceSpanBetween(0, thirdCueText.length()) + .withFamily("sansSerifInline"); + assertThat(thirdCueText).hasItalicSpanBetween(0, thirdCueText.length()); + assertThat(thirdCueText).hasUnderlineSpanBetween(0, thirdCueText.length()); + assertThat(thirdCueText).hasStrikethroughSpanBetween(0, thirdCueText.length()); + assertThat(thirdCueText) + .hasBackgroundColorSpanBetween(0, thirdCueText.length()) + .withColor(0xFFFF0000); + assertThat(thirdCueText) + .hasForegroundColorSpanBetween(0, thirdCueText.length()) + .withColor(0xFFFFFF00); } @Test public void testMultipleRegions() throws IOException, SubtitleDecoderException { TtmlSubtitle subtitle = getSubtitle(MULTIPLE_REGIONS_TTML_FILE); - List cues = subtitle.getCues(1000000); + + List cues = subtitle.getCues(1_000_000); assertThat(cues).hasSize(2); Cue cue = cues.get(0); assertThat(cue.text.toString()).isEqualTo("lorem"); @@ -277,17 +290,13 @@ public final class TtmlDecoderTest { assertThat(cue.line).isEqualTo(10f / 100f); assertThat(cue.size).isEqualTo(20f / 100f); - cues = subtitle.getCues(5000000); - assertThat(cues).hasSize(1); - cue = cues.get(0); + cue = getOnlyCueAtTimeUs(subtitle, 5_000_000); assertThat(cue.text.toString()).isEqualTo("ipsum"); assertThat(cue.position).isEqualTo(40f / 100f); assertThat(cue.line).isEqualTo(40f / 100f); assertThat(cue.size).isEqualTo(20f / 100f); - cues = subtitle.getCues(9000000); - assertThat(cues).hasSize(1); - cue = cues.get(0); + cue = getOnlyCueAtTimeUs(subtitle, 9_000_000); assertThat(cue.text.toString()).isEqualTo("dolor"); assertThat(cue.position).isEqualTo(Cue.DIMEN_UNSET); assertThat(cue.line).isEqualTo(Cue.DIMEN_UNSET); @@ -297,19 +306,16 @@ public final class TtmlDecoderTest { // assertEquals(80f / 100f, cue.line); // assertEquals(1f, cue.size); - cues = subtitle.getCues(21000000); - assertThat(cues).hasSize(1); - cue = cues.get(0); + cue = getOnlyCueAtTimeUs(subtitle, 21_000_000); assertThat(cue.text.toString()).isEqualTo("She first said this"); assertThat(cue.position).isEqualTo(45f / 100f); assertThat(cue.line).isEqualTo(45f / 100f); assertThat(cue.size).isEqualTo(35f / 100f); - cues = subtitle.getCues(25000000); - cue = cues.get(0); + + cue = getOnlyCueAtTimeUs(subtitle, 25_000_000); assertThat(cue.text.toString()).isEqualTo("She first said this\nThen this"); - cues = subtitle.getCues(29000000); - assertThat(cues).hasSize(1); - cue = cues.get(0); + + cue = getOnlyCueAtTimeUs(subtitle, 29_000_000); assertThat(cue.text.toString()).isEqualTo("She first said this\nThen this\nFinally this"); assertThat(cue.position).isEqualTo(45f / 100f); assertThat(cue.line).isEqualTo(45f / 100f); @@ -318,6 +324,7 @@ public final class TtmlDecoderTest { @Test public void testEmptyStyleAttribute() throws IOException, SubtitleDecoderException { TtmlSubtitle subtitle = getSubtitle(INHERIT_MULTIPLE_STYLES_TTML_FILE); + assertThat(subtitle.getEventTimeCount()).isEqualTo(12); TtmlNode root = subtitle.getRoot(); @@ -330,6 +337,7 @@ public final class TtmlDecoderTest { @Test public void testNonexistingStyleId() throws IOException, SubtitleDecoderException { TtmlSubtitle subtitle = getSubtitle(INHERIT_MULTIPLE_STYLES_TTML_FILE); + assertThat(subtitle.getEventTimeCount()).isEqualTo(12); TtmlNode root = subtitle.getRoot(); @@ -343,6 +351,7 @@ public final class TtmlDecoderTest { public void testNonExistingAndExistingStyleIdWithRedundantSpaces() throws IOException, SubtitleDecoderException { TtmlSubtitle subtitle = getSubtitle(INHERIT_MULTIPLE_STYLES_TTML_FILE); + assertThat(subtitle.getEventTimeCount()).isEqualTo(12); TtmlNode root = subtitle.getRoot(); @@ -356,6 +365,7 @@ public final class TtmlDecoderTest { @Test public void testMultipleChaining() throws IOException, SubtitleDecoderException { TtmlSubtitle subtitle = getSubtitle(CHAIN_MULTIPLE_STYLES_TTML_FILE); + assertThat(subtitle.getEventTimeCount()).isEqualTo(2); Map globalStyles = subtitle.getGlobalStyles(); @@ -379,6 +389,7 @@ public final class TtmlDecoderTest { @Test public void testNoUnderline() throws IOException, SubtitleDecoderException { TtmlSubtitle subtitle = getSubtitle(NO_UNDERLINE_LINETHROUGH_TTML_FILE); + assertThat(subtitle.getEventTimeCount()).isEqualTo(4); TtmlNode root = subtitle.getRoot(); @@ -394,6 +405,7 @@ public final class TtmlDecoderTest { @Test public void testNoLinethrough() throws IOException, SubtitleDecoderException { TtmlSubtitle subtitle = getSubtitle(NO_UNDERLINE_LINETHROUGH_TTML_FILE); + assertThat(subtitle.getEventTimeCount()).isEqualTo(4); TtmlNode root = subtitle.getRoot(); @@ -409,93 +421,80 @@ public final class TtmlDecoderTest { @Test public void testFontSizeSpans() throws IOException, SubtitleDecoderException { TtmlSubtitle subtitle = getSubtitle(FONT_SIZE_TTML_FILE); + assertThat(subtitle.getEventTimeCount()).isEqualTo(10); - List cues = subtitle.getCues(10 * 1000000); - assertThat(cues).hasSize(1); - SpannableStringBuilder spannable = (SpannableStringBuilder) cues.get(0).text; - assertThat(String.valueOf(spannable)).isEqualTo("text 1"); - assertAbsoluteFontSize(spannable, 32); + Spanned spanned = getOnlyCueTextAtTimeUs(subtitle, 10_000_000); + assertThat(String.valueOf(spanned)).isEqualTo("text 1"); + assertThat(spanned).hasAbsoluteSizeSpanBetween(0, spanned.length()).withAbsoluteSize(32); - cues = subtitle.getCues(20 * 1000000); - assertThat(cues).hasSize(1); - spannable = (SpannableStringBuilder) cues.get(0).text; - assertThat(String.valueOf(cues.get(0).text)).isEqualTo("text 2"); - assertRelativeFontSize(spannable, 2.2f); + spanned = getOnlyCueTextAtTimeUs(subtitle, 20_000_000); + assertThat(spanned.toString()).isEqualTo("text 2"); + assertThat(spanned).hasRelativeSizeSpanBetween(0, spanned.length()).withSizeChange(2.2f); - cues = subtitle.getCues(30 * 1000000); - assertThat(cues).hasSize(1); - spannable = (SpannableStringBuilder) cues.get(0).text; - assertThat(String.valueOf(cues.get(0).text)).isEqualTo("text 3"); - assertRelativeFontSize(spannable, 1.5f); + spanned = getOnlyCueTextAtTimeUs(subtitle, 30_000_000); + assertThat(spanned.toString()).isEqualTo("text 3"); + assertThat(spanned).hasRelativeSizeSpanBetween(0, spanned.length()).withSizeChange(1.5f); - cues = subtitle.getCues(40 * 1000000); - assertThat(cues).hasSize(1); - spannable = (SpannableStringBuilder) cues.get(0).text; - assertThat(String.valueOf(cues.get(0).text)).isEqualTo("two values"); - assertAbsoluteFontSize(spannable, 16); + spanned = getOnlyCueTextAtTimeUs(subtitle, 40_000_000); + assertThat(spanned.toString()).isEqualTo("two values"); + assertThat(spanned).hasAbsoluteSizeSpanBetween(0, spanned.length()).withAbsoluteSize(16); - cues = subtitle.getCues(50 * 1000000); - assertThat(cues).hasSize(1); - spannable = (SpannableStringBuilder) cues.get(0).text; - assertThat(String.valueOf(cues.get(0).text)).isEqualTo("leading dot"); - assertRelativeFontSize(spannable, 0.5f); + spanned = getOnlyCueTextAtTimeUs(subtitle, 50_000_000); + assertThat(spanned.toString()).isEqualTo("leading dot"); + assertThat(spanned).hasRelativeSizeSpanBetween(0, spanned.length()).withSizeChange(0.5f); } @Test public void testFontSizeWithMissingUnitIsIgnored() throws IOException, SubtitleDecoderException { TtmlSubtitle subtitle = getSubtitle(FONT_SIZE_MISSING_UNIT_TTML_FILE); + assertThat(subtitle.getEventTimeCount()).isEqualTo(2); - List cues = subtitle.getCues(10 * 1000000); - assertThat(cues).hasSize(1); - SpannableStringBuilder spannable = (SpannableStringBuilder) cues.get(0).text; - assertThat(String.valueOf(spannable)).isEqualTo("no unit"); - assertThat(spannable.getSpans(0, spannable.length(), RelativeSizeSpan.class)).hasLength(0); - assertThat(spannable.getSpans(0, spannable.length(), AbsoluteSizeSpan.class)).hasLength(0); + + Spanned spanned = getOnlyCueTextAtTimeUs(subtitle, 10_000_000); + assertThat(spanned.toString()).isEqualTo("no unit"); + assertThat(spanned).hasNoRelativeSizeSpanBetween(0, spanned.length()); + assertThat(spanned).hasNoAbsoluteSizeSpanBetween(0, spanned.length()); } @Test public void testFontSizeWithInvalidValueIsIgnored() throws IOException, SubtitleDecoderException { TtmlSubtitle subtitle = getSubtitle(FONT_SIZE_INVALID_TTML_FILE); + assertThat(subtitle.getEventTimeCount()).isEqualTo(6); - List cues = subtitle.getCues(10 * 1000000); - assertThat(cues).hasSize(1); - SpannableStringBuilder spannable = (SpannableStringBuilder) cues.get(0).text; - assertThat(String.valueOf(spannable)).isEqualTo("invalid"); - assertThat(spannable.getSpans(0, spannable.length(), RelativeSizeSpan.class)).hasLength(0); - assertThat(spannable.getSpans(0, spannable.length(), AbsoluteSizeSpan.class)).hasLength(0); + Spanned spanned = getOnlyCueTextAtTimeUs(subtitle, 10_000_000); + assertThat(String.valueOf(spanned)).isEqualTo("invalid"); + assertThat(spanned).hasNoRelativeSizeSpanBetween(0, spanned.length()); + assertThat(spanned).hasNoAbsoluteSizeSpanBetween(0, spanned.length()); - cues = subtitle.getCues(20 * 1000000); - assertThat(cues).hasSize(1); - spannable = (SpannableStringBuilder) cues.get(0).text; - assertThat(String.valueOf(spannable)).isEqualTo("invalid"); - assertThat(spannable.getSpans(0, spannable.length(), RelativeSizeSpan.class)).hasLength(0); - assertThat(spannable.getSpans(0, spannable.length(), AbsoluteSizeSpan.class)).hasLength(0); + spanned = getOnlyCueTextAtTimeUs(subtitle, 20_000_000); + assertThat(String.valueOf(spanned)).isEqualTo("invalid"); + assertThat(spanned).hasNoRelativeSizeSpanBetween(0, spanned.length()); + assertThat(spanned).hasNoAbsoluteSizeSpanBetween(0, spanned.length()); - cues = subtitle.getCues(30 * 1000000); - assertThat(cues).hasSize(1); - spannable = (SpannableStringBuilder) cues.get(0).text; - assertThat(String.valueOf(spannable)).isEqualTo("invalid dot"); - assertThat(spannable.getSpans(0, spannable.length(), RelativeSizeSpan.class)).hasLength(0); - assertThat(spannable.getSpans(0, spannable.length(), AbsoluteSizeSpan.class)).hasLength(0); + spanned = getOnlyCueTextAtTimeUs(subtitle, 30_000_000); + assertThat(String.valueOf(spanned)).isEqualTo("invalid dot"); + assertThat(spanned).hasNoRelativeSizeSpanBetween(0, spanned.length()); + assertThat(spanned).hasNoAbsoluteSizeSpanBetween(0, spanned.length()); } @Test public void testFontSizeWithEmptyValueIsIgnored() throws IOException, SubtitleDecoderException { TtmlSubtitle subtitle = getSubtitle(FONT_SIZE_EMPTY_TTML_FILE); + assertThat(subtitle.getEventTimeCount()).isEqualTo(2); - List cues = subtitle.getCues(10 * 1000000); - assertThat(cues).hasSize(1); - SpannableStringBuilder spannable = (SpannableStringBuilder) cues.get(0).text; - assertThat(String.valueOf(spannable)).isEqualTo("empty"); - assertThat(spannable.getSpans(0, spannable.length(), RelativeSizeSpan.class)).hasLength(0); - assertThat(spannable.getSpans(0, spannable.length(), AbsoluteSizeSpan.class)).hasLength(0); + + Spanned spanned = getOnlyCueTextAtTimeUs(subtitle, 10_000_000); + assertThat(String.valueOf(spanned)).isEqualTo("empty"); + assertThat(spanned).hasNoRelativeSizeSpanBetween(0, spanned.length()); + assertThat(spanned).hasNoAbsoluteSizeSpanBetween(0, spanned.length()); } @Test public void testFrameRate() throws IOException, SubtitleDecoderException { TtmlSubtitle subtitle = getSubtitle(FRAME_RATE_TTML_FILE); + assertThat(subtitle.getEventTimeCount()).isEqualTo(4); assertThat(subtitle.getEventTime(0)).isEqualTo(1_000_000); assertThat(subtitle.getEventTime(1)).isEqualTo(1_010_000); @@ -507,9 +506,7 @@ public final class TtmlDecoderTest { public void testBitmapPercentageRegion() throws IOException, SubtitleDecoderException { TtmlSubtitle subtitle = getSubtitle(BITMAP_REGION_FILE); - List cues = subtitle.getCues(1000000); - assertThat(cues).hasSize(1); - Cue cue = cues.get(0); + Cue cue = getOnlyCueAtTimeUs(subtitle, 1_000_000); assertThat(cue.text).isNull(); assertThat(cue.bitmap).isNotNull(); assertThat(cue.position).isEqualTo(24f / 100f); @@ -517,9 +514,7 @@ public final class TtmlDecoderTest { assertThat(cue.size).isEqualTo(51f / 100f); assertThat(cue.bitmapHeight).isEqualTo(12f / 100f); - cues = subtitle.getCues(4000000); - assertThat(cues).hasSize(1); - cue = cues.get(0); + cue = getOnlyCueAtTimeUs(subtitle, 4_000_000); assertThat(cue.text).isNull(); assertThat(cue.bitmap).isNotNull(); assertThat(cue.position).isEqualTo(21f / 100f); @@ -527,9 +522,7 @@ public final class TtmlDecoderTest { assertThat(cue.size).isEqualTo(57f / 100f); assertThat(cue.bitmapHeight).isEqualTo(6f / 100f); - cues = subtitle.getCues(7500000); - assertThat(cues).hasSize(1); - cue = cues.get(0); + cue = getOnlyCueAtTimeUs(subtitle, 7_500_000); assertThat(cue.text).isNull(); assertThat(cue.bitmap).isNotNull(); assertThat(cue.position).isEqualTo(24f / 100f); @@ -542,9 +535,7 @@ public final class TtmlDecoderTest { public void testBitmapPixelRegion() throws IOException, SubtitleDecoderException { TtmlSubtitle subtitle = getSubtitle(BITMAP_PIXEL_REGION_FILE); - List cues = subtitle.getCues(1000000); - assertThat(cues).hasSize(1); - Cue cue = cues.get(0); + Cue cue = getOnlyCueAtTimeUs(subtitle, 1_000_000); assertThat(cue.text).isNull(); assertThat(cue.bitmap).isNotNull(); assertThat(cue.position).isEqualTo(307f / 1280f); @@ -552,9 +543,7 @@ public final class TtmlDecoderTest { assertThat(cue.size).isEqualTo(653f / 1280f); assertThat(cue.bitmapHeight).isEqualTo(86f / 720f); - cues = subtitle.getCues(4000000); - assertThat(cues).hasSize(1); - cue = cues.get(0); + cue = getOnlyCueAtTimeUs(subtitle, 4_000_000); assertThat(cue.text).isNull(); assertThat(cue.bitmap).isNotNull(); assertThat(cue.position).isEqualTo(269f / 1280f); @@ -567,9 +556,7 @@ public final class TtmlDecoderTest { public void testBitmapUnsupportedRegion() throws IOException, SubtitleDecoderException { TtmlSubtitle subtitle = getSubtitle(BITMAP_UNSUPPORTED_REGION_FILE); - List cues = subtitle.getCues(1000000); - assertThat(cues).hasSize(1); - Cue cue = cues.get(0); + Cue cue = getOnlyCueAtTimeUs(subtitle, 1_000_000); assertThat(cue.text).isNull(); assertThat(cue.bitmap).isNotNull(); assertThat(cue.position).isEqualTo(Cue.DIMEN_UNSET); @@ -577,9 +564,7 @@ public final class TtmlDecoderTest { assertThat(cue.size).isEqualTo(Cue.DIMEN_UNSET); assertThat(cue.bitmapHeight).isEqualTo(Cue.DIMEN_UNSET); - cues = subtitle.getCues(4000000); - assertThat(cues).hasSize(1); - cue = cues.get(0); + cue = getOnlyCueAtTimeUs(subtitle, 4_000_000); assertThat(cue.text).isNull(); assertThat(cue.bitmap).isNotNull(); assertThat(cue.position).isEqualTo(Cue.DIMEN_UNSET); @@ -592,122 +577,29 @@ public final class TtmlDecoderTest { public void testVerticalText() throws IOException, SubtitleDecoderException { TtmlSubtitle subtitle = getSubtitle(VERTICAL_TEXT_FILE); - List firstCues = subtitle.getCues(10_000_000); - assertThat(firstCues).hasSize(1); - Cue firstCue = firstCues.get(0); + Cue firstCue = getOnlyCueAtTimeUs(subtitle, 10_000_000); assertThat(firstCue.verticalType).isEqualTo(Cue.VERTICAL_TYPE_RL); - List secondCues = subtitle.getCues(20_000_000); - assertThat(secondCues).hasSize(1); - Cue secondCue = secondCues.get(0); + Cue secondCue = getOnlyCueAtTimeUs(subtitle, 20_000_000); assertThat(secondCue.verticalType).isEqualTo(Cue.VERTICAL_TYPE_LR); - List thirdCues = subtitle.getCues(30_000_000); - assertThat(thirdCues).hasSize(1); - Cue thirdCue = thirdCues.get(0); + Cue thirdCue = getOnlyCueAtTimeUs(subtitle, 30_000_000); assertThat(thirdCue.verticalType).isEqualTo(Cue.TYPE_UNSET); } - private void assertSpans( - TtmlSubtitle subtitle, - int second, - String text, - String font, - int fontStyle, - int backgroundColor, - int color, - boolean isUnderline, - boolean isLinethrough, - Layout.Alignment alignment) { + private static Spanned getOnlyCueTextAtTimeUs(Subtitle subtitle, long timeUs) { + Cue cue = getOnlyCueAtTimeUs(subtitle, timeUs); + assertThat(cue.text).isInstanceOf(Spanned.class); + return (Spanned) Assertions.checkNotNull(cue.text); + } - long timeUs = second * 1000000L; + private static Cue getOnlyCueAtTimeUs(Subtitle subtitle, long timeUs) { List cues = subtitle.getCues(timeUs); - assertThat(cues).hasSize(1); - assertThat(String.valueOf(cues.get(0).text)).isEqualTo(text); - assertWithMessage("single cue expected for timeUs: " + timeUs).that(cues.size()).isEqualTo(1); - SpannableStringBuilder spannable = (SpannableStringBuilder) cues.get(0).text; - - assertFont(spannable, font); - assertStyle(spannable, fontStyle); - assertUnderline(spannable, isUnderline); - assertStrikethrough(spannable, isLinethrough); - assertUnderline(spannable, isUnderline); - assertBackground(spannable, backgroundColor); - assertForeground(spannable, color); - assertAlignment(spannable, alignment); + return cues.get(0); } - private void assertAbsoluteFontSize(Spannable spannable, int absoluteFontSize) { - AbsoluteSizeSpan[] absoluteSizeSpans = - spannable.getSpans(0, spannable.length(), AbsoluteSizeSpan.class); - assertThat(absoluteSizeSpans).hasLength(1); - assertThat(absoluteSizeSpans[0].getSize()).isEqualTo(absoluteFontSize); - } - - private void assertRelativeFontSize(Spannable spannable, float relativeFontSize) { - RelativeSizeSpan[] relativeSizeSpans = - spannable.getSpans(0, spannable.length(), RelativeSizeSpan.class); - assertThat(relativeSizeSpans).hasLength(1); - assertThat(relativeSizeSpans[0].getSizeChange()).isEqualTo(relativeFontSize); - } - - private void assertFont(Spannable spannable, String font) { - TypefaceSpan[] typefaceSpans = spannable.getSpans(0, spannable.length(), TypefaceSpan.class); - assertThat(typefaceSpans[typefaceSpans.length - 1].getFamily()).isEqualTo(font); - } - - private void assertStyle(Spannable spannable, int fontStyle) { - StyleSpan[] styleSpans = spannable.getSpans(0, spannable.length(), StyleSpan.class); - assertThat(styleSpans[styleSpans.length - 1].getStyle()).isEqualTo(fontStyle); - } - - private void assertUnderline(Spannable spannable, boolean isUnderline) { - UnderlineSpan[] underlineSpans = spannable.getSpans(0, spannable.length(), UnderlineSpan.class); - assertWithMessage(isUnderline ? "must be underlined" : "must not be underlined") - .that(underlineSpans) - .hasLength(isUnderline ? 1 : 0); - } - - private void assertStrikethrough(Spannable spannable, boolean isStrikethrough) { - StrikethroughSpan[] striketroughSpans = - spannable.getSpans(0, spannable.length(), StrikethroughSpan.class); - assertWithMessage(isStrikethrough ? "must be strikethrough" : "must not be strikethrough") - .that(striketroughSpans) - .hasLength(isStrikethrough ? 1 : 0); - } - - private void assertBackground(Spannable spannable, int backgroundColor) { - BackgroundColorSpan[] backgroundColorSpans = - spannable.getSpans(0, spannable.length(), BackgroundColorSpan.class); - if (backgroundColor != 0) { - assertThat(backgroundColorSpans[backgroundColorSpans.length - 1].getBackgroundColor()) - .isEqualTo(backgroundColor); - } else { - assertThat(backgroundColorSpans).hasLength(0); - } - } - - private void assertForeground(Spannable spannable, int foregroundColor) { - ForegroundColorSpan[] foregroundColorSpans = - spannable.getSpans(0, spannable.length(), ForegroundColorSpan.class); - assertThat(foregroundColorSpans[foregroundColorSpans.length - 1].getForegroundColor()) - .isEqualTo(foregroundColor); - } - - private void assertAlignment(Spannable spannable, Layout.Alignment alignment) { - if (alignment != null) { - AlignmentSpan.Standard[] alignmentSpans = - spannable.getSpans(0, spannable.length(), AlignmentSpan.Standard.class); - assertThat(alignmentSpans).hasLength(1); - assertThat(alignmentSpans[0].getAlignment()).isEqualTo(alignment); - } else { - assertThat(spannable.getSpans(0, spannable.length(), AlignmentSpan.Standard.class)) - .hasLength(0); - } - } - - private TtmlNode queryChildrenForTag(TtmlNode node, String tag, int pos) { + private static TtmlNode queryChildrenForTag(TtmlNode node, String tag, int pos) { int count = 0; for (int i = 0; i < node.getChildCount(); i++) { if (tag.equals(node.getChild(i).tag)) { @@ -719,7 +611,8 @@ public final class TtmlDecoderTest { throw new IllegalStateException("tag not found"); } - private TtmlSubtitle getSubtitle(String file) throws IOException, SubtitleDecoderException { + private static TtmlSubtitle getSubtitle(String file) + throws IOException, SubtitleDecoderException { TtmlDecoder ttmlDecoder = new TtmlDecoder(); byte[] bytes = TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), file); return (TtmlSubtitle) ttmlDecoder.decode(bytes, bytes.length, false);