Skip to content

Commit

Permalink
Migrate SubtitleParser tests to incremental parse() methods
Browse files Browse the repository at this point in the history
All the production code is already calling these new incremental
methods, migrating the tests allows us to remove the old
`List`-returning methods in a follow-up change.

#minor-release

PiperOrigin-RevId: 572822828
  • Loading branch information
icbaker authored and copybara-github committed Oct 12, 2023
1 parent d1fc15f commit a12bde4
Show file tree
Hide file tree
Showing 4 changed files with 179 additions and 114 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
import android.text.Spanned;
import androidx.media3.common.text.Cue;
import androidx.media3.extractor.text.CuesWithTiming;
import androidx.media3.extractor.text.SubtitleParser;
import androidx.media3.extractor.text.SubtitleParser.OutputOptions;
import androidx.media3.test.utils.TestUtil;
import androidx.media3.test.utils.truth.SpannedSubject;
import androidx.test.core.app.ApplicationProvider;
Expand Down Expand Up @@ -71,7 +73,7 @@ public void cuesReplacementBehaviorIsMerge() throws IOException {
public void parseEmpty() throws IOException {
SsaParser parser = new SsaParser();
byte[] bytes = TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), EMPTY);
List<CuesWithTiming> allCues = parser.parse(bytes);
ImmutableList<CuesWithTiming> allCues = parseAllCues(parser, bytes);

assertThat(allCues).isEmpty();
}
Expand All @@ -81,7 +83,7 @@ public void parseEmptyStyleLine() throws IOException {
SsaParser parser = new SsaParser();
byte[] bytes =
TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), EMPTY_STYLE_LINE);
List<CuesWithTiming> allCues = parser.parse(bytes);
ImmutableList<CuesWithTiming> allCues = parseAllCues(parser, bytes);

assertThat(allCues).hasSize(1);
Cue cue = Iterables.getOnlyElement(allCues.get(0).cues);
Expand All @@ -101,7 +103,7 @@ public void parseEmptyStyleLine() throws IOException {
public void parseTypical() throws IOException {
SsaParser parser = new SsaParser();
byte[] bytes = TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), TYPICAL);
List<CuesWithTiming> allCues = parser.parse(bytes);
ImmutableList<CuesWithTiming> allCues = parseAllCues(parser, bytes);

assertThat(allCues).hasSize(3);
// Check position, line, anchors & alignment are set from Alignment Style (2 - bottom-center).
Expand All @@ -122,6 +124,34 @@ public void parseTypical() throws IOException {
assertTypicalCue3(allCues.get(2));
}

@Test
public void parseTypical_onlyCuesAfterTime() throws IOException {
SsaParser parser = new SsaParser();
byte[] bytes = TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), TYPICAL);
List<CuesWithTiming> cues = new ArrayList<>();
parser.parse(bytes, OutputOptions.onlyCuesAfter(/* startTimeUs= */ 1_000_000), cues::add);

assertThat(cues).hasSize(2);
assertTypicalCue2(cues.get(0));
assertTypicalCue3(cues.get(1));
}

@Test
public void parseTypical_cuesAfterTimeThenCuesBefore() throws IOException {
SsaParser parser = new SsaParser();
byte[] bytes = TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), TYPICAL);
List<CuesWithTiming> cues = new ArrayList<>();
parser.parse(
bytes,
OutputOptions.cuesAfterThenRemainingCuesBefore(/* startTimeUs= */ 1_000_000),
cues::add);

assertThat(cues).hasSize(3);
assertTypicalCue2(cues.get(0));
assertTypicalCue3(cues.get(1));
assertTypicalCue1(cues.get(2));
}

@Test
public void parseTypicalWithInitializationData() throws IOException {
byte[] headerBytes =
Expand All @@ -134,7 +164,7 @@ public void parseTypicalWithInitializationData() throws IOException {
SsaParser parser = new SsaParser(initializationData);
byte[] bytes =
TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), TYPICAL_DIALOGUE_ONLY);
List<CuesWithTiming> allCues = parser.parse(bytes);
ImmutableList<CuesWithTiming> allCues = parseAllCues(parser, bytes);

assertThat(allCues).hasSize(3);
assertTypicalCue1(allCues.get(0));
Expand All @@ -155,8 +185,13 @@ public void parseTypicalWithInitializationDataAtOffsetIntoDialogueAndRestrictedL
SsaParser parser = new SsaParser(initializationData);
byte[] bytes =
TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), TYPICAL_DIALOGUE_ONLY);
ImmutableList<CuesWithTiming> allCues =
parser.parse(bytes, /* offset= */ 10, /* length= */ bytes.length - 30);
List<CuesWithTiming> allCues = new ArrayList<>();
parser.parse(
bytes,
/* offset= */ 10,
/* length= */ bytes.length - 30,
OutputOptions.allCues(),
allCues::add);

assertThat(allCues).hasSize(2);
// Because of the offset, we skip the first line of dialogue
Expand All @@ -173,7 +208,7 @@ public void parseTypicalUtf16le() throws IOException {
SsaParser parser = new SsaParser();
byte[] bytes =
TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), TYPICAL_UTF16LE);
List<CuesWithTiming> allCues = parser.parse(bytes);
ImmutableList<CuesWithTiming> allCues = parseAllCues(parser, bytes);

assertThat(allCues).hasSize(3);
// Check position, line, anchors & alignment are set from Alignment Style (2 - bottom-center).
Expand All @@ -199,7 +234,7 @@ public void parseTypicalUtf16be() throws IOException {
SsaParser parser = new SsaParser();
byte[] bytes =
TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), TYPICAL_UTF16BE);
List<CuesWithTiming> allCues = parser.parse(bytes);
ImmutableList<CuesWithTiming> allCues = parseAllCues(parser, bytes);

assertThat(allCues).hasSize(3);
// Check position, line, anchors & alignment are set from Alignment Style (2 - bottom-center).
Expand All @@ -225,7 +260,7 @@ public void parseOverlappingTimecodes() throws IOException {
SsaParser parser = new SsaParser();
byte[] bytes =
TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), OVERLAPPING_TIMECODES);
List<CuesWithTiming> allCues = parser.parse(bytes);
ImmutableList<CuesWithTiming> allCues = parseAllCues(parser, bytes);

String firstSubtitleText = "First subtitle - end overlaps second";
String secondSubtitleText = "Second subtitle - beginning overlaps first";
Expand Down Expand Up @@ -289,7 +324,7 @@ public void parseOverlappingTimecodes() throws IOException {
public void parsePositions() throws IOException {
SsaParser parser = new SsaParser();
byte[] bytes = TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), POSITIONS);
List<CuesWithTiming> allCues = parser.parse(bytes);
ImmutableList<CuesWithTiming> allCues = parseAllCues(parser, bytes);

// Check \pos() sets position & line
Cue firstCue = Iterables.getOnlyElement(allCues.get(0).cues);
Expand Down Expand Up @@ -343,7 +378,7 @@ public void parseInvalidPositions() throws IOException {
SsaParser parser = new SsaParser();
byte[] bytes =
TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), INVALID_POSITIONS);
List<CuesWithTiming> allCues = parser.parse(bytes);
ImmutableList<CuesWithTiming> allCues = parseAllCues(parser, bytes);

// Negative parameter to \pos() - fall back to the positions implied by middle-left alignment.
Cue firstCue = Iterables.getOnlyElement(allCues.get(0).cues);
Expand Down Expand Up @@ -380,7 +415,7 @@ public void parsePositionsWithMissingPlayResY() throws IOException {
byte[] bytes =
TestUtil.getByteArray(
ApplicationProvider.getApplicationContext(), POSITIONS_WITHOUT_PLAYRES);
List<CuesWithTiming> allCues = parser.parse(bytes);
ImmutableList<CuesWithTiming> allCues = parseAllCues(parser, bytes);

// The dialogue line has a valid \pos() override, but it's ignored because PlayResY isn't
// set (so we don't know the denominator).
Expand All @@ -396,7 +431,7 @@ public void parseInvalidTimecodes() throws IOException {
SsaParser parser = new SsaParser();
byte[] bytes =
TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), INVALID_TIMECODES);
List<CuesWithTiming> allCues = parser.parse(bytes);
ImmutableList<CuesWithTiming> allCues = parseAllCues(parser, bytes);

assertThat(allCues).hasSize(1);
assertTypicalCue3(Iterables.getOnlyElement(allCues));
Expand All @@ -407,7 +442,7 @@ public void parsePrimaryColor() throws IOException {
SsaParser parser = new SsaParser();
byte[] bytes =
TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), STYLE_PRIMARY_COLOR);
List<CuesWithTiming> allCues = parser.parse(bytes);
ImmutableList<CuesWithTiming> allCues = parseAllCues(parser, bytes);
assertThat(allCues).hasSize(7);
// &H000000FF (AABBGGRR) -> #FFFF0000 (AARRGGBB)
Spanned firstCueText = (Spanned) Iterables.getOnlyElement(allCues.get(0).cues).text;
Expand Down Expand Up @@ -449,7 +484,7 @@ public void parseOutlineColor() throws IOException {
SsaParser parser = new SsaParser();
byte[] bytes =
TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), STYLE_OUTLINE_COLOR);
List<CuesWithTiming> allCues = parser.parse(bytes);
ImmutableList<CuesWithTiming> allCues = parseAllCues(parser, bytes);
assertThat(allCues).hasSize(2);
Spanned firstCueText = (Spanned) Iterables.getOnlyElement(allCues.get(0).cues).text;
SpannedSubject.assertThat(firstCueText)
Expand All @@ -467,7 +502,7 @@ public void parseFontSize() throws IOException {
SsaParser parser = new SsaParser();
byte[] bytes =
TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), STYLE_FONT_SIZE);
List<CuesWithTiming> allCues = parser.parse(bytes);
ImmutableList<CuesWithTiming> allCues = parseAllCues(parser, bytes);
assertThat(allCues).hasSize(2);

Cue firstCue = Iterables.getOnlyElement(allCues.get(0).cues);
Expand All @@ -483,7 +518,7 @@ public void parseBoldItalic() throws IOException {
SsaParser parser = new SsaParser();
byte[] bytes =
TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), STYLE_BOLD_ITALIC);
List<CuesWithTiming> allCues = parser.parse(bytes);
ImmutableList<CuesWithTiming> allCues = parseAllCues(parser, bytes);
assertThat(allCues).hasSize(3);

Spanned firstCueText = (Spanned) Iterables.getOnlyElement(allCues.get(0).cues).text;
Expand All @@ -499,7 +534,7 @@ public void parseUnderline() throws IOException {
SsaParser parser = new SsaParser();
byte[] bytes =
TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), STYLE_UNDERLINE);
List<CuesWithTiming> allCues = parser.parse(bytes);
ImmutableList<CuesWithTiming> allCues = parseAllCues(parser, bytes);
assertThat(allCues).hasSize(2);

Spanned firstCueText = (Spanned) Iterables.getOnlyElement(allCues.get(0).cues).text;
Expand All @@ -513,7 +548,7 @@ public void parseStrikeout() throws IOException {
SsaParser parser = new SsaParser();
byte[] bytes =
TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), STYLE_STRIKEOUT);
List<CuesWithTiming> allCues = parser.parse(bytes);
ImmutableList<CuesWithTiming> allCues = parseAllCues(parser, bytes);
assertThat(allCues).hasSize(2);

Spanned firstCueText = (Spanned) Iterables.getOnlyElement(allCues.get(0).cues).text;
Expand All @@ -523,6 +558,12 @@ public void parseStrikeout() throws IOException {
.hasNoStrikethroughSpanBetween(0, secondCueText.length());
}

private static ImmutableList<CuesWithTiming> parseAllCues(SubtitleParser parser, byte[] data) {
ImmutableList.Builder<CuesWithTiming> cues = ImmutableList.builder();
parser.parse(data, OutputOptions.allCues(), cues::add);
return cues.build();
}

private static void assertTypicalCue1(CuesWithTiming cuesWithTiming) {
assertThat(cuesWithTiming.startTimeUs).isEqualTo(0);
assertThat(cuesWithTiming.durationUs).isEqualTo(1230000);
Expand Down
Loading

0 comments on commit a12bde4

Please sign in to comment.