Added test cases to the MP4Webvtt parser

This CL is prepares the ground for refactoring the Webvtt parser,
so as to use the common parsing algorithms in both parsers. In order
to do this, the Webvtt Parser will be refactored. As a side note, many
more test cases will be added once the new subtitle features are
implemented. Some useful test cases have also been left for a following
CL, to allow an easy code review.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=110466914
This commit is contained in:
aquilescanta 2015-12-17 10:15:15 -08:00 committed by Oliver Woodman
parent dd497b1259
commit 33a2b2d0c5
2 changed files with 207 additions and 2 deletions

View file

@ -0,0 +1,206 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer.text.mp4webvtt;
import com.google.android.exoplayer.ParserException;
import com.google.android.exoplayer.text.Cue;
import com.google.android.exoplayer.text.Subtitle;
import com.google.android.exoplayer.util.Util;
import android.util.ArraySet;
import junit.framework.TestCase;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
/**
* Unit test for {@link Mp4WebvttParser}.
* As a side effect, it also involves the {@link Mp4WebvttSubtitle}.
*/
public final class Mp4WebvttParserTest extends TestCase {
private static final byte[] SINGLE_CUE_SAMPLE = {
0x00, 0x00, 0x00, 0x1C, // Size
0x76, 0x74, 0x74, 0x63, // "vttc" Box type. VTT Cue box begins:
0x00, 0x00, 0x00, 0x14, // Contained payload box's size
0x70, 0x61, 0x79, 0x6c, // Contained payload box's type (payl), Cue Payload Box begins:
0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x0a // Hello World\n
};
private static final byte[] DOUBLE_CUE_SAMPLE = {
0x00, 0x00, 0x00, 0x1B, // Size
0x76, 0x74, 0x74, 0x63, // "vttc" Box type. First VTT Cue box begins:
0x00, 0x00, 0x00, 0x13, // First contained payload box's size
0x70, 0x61, 0x79, 0x6c, // First contained payload box's type (payl), Cue Payload Box begins:
0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, // Hello World
0x00, 0x00, 0x00, 0x17, // Size
0x76, 0x74, 0x74, 0x63, // "vttc" Box type. Second VTT Cue box begins:
0x00, 0x00, 0x00, 0x0F, // Contained payload box's size
0x70, 0x61, 0x79, 0x6c, // Contained payload box's type (payl), Payload begins:
0x42, 0x79, 0x65, 0x20, 0x42, 0x79, 0x65 // Bye Bye
};
private static final byte[] NO_CUE_SAMPLE = {
0x00, 0x00, 0x00, 0x1B, // Size
0x74, 0x74, 0x74, 0x63, // "tttc" Box type, which is not a Cue. Should be skipped:
0x00, 0x00, 0x00, 0x13, // Contained payload box's size
0x70, 0x61, 0x79, 0x6c, // Contained payload box's type (payl), Cue Payload Box begins:
0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64 // Hello World
};
private static final byte[] NO_PAYLOAD_CUE_SAMPLE = {
0x00, 0x00, 0x00, 0x1B, // Size
0x76, 0x74, 0x74, 0x63, // Box type. First VTT Cue box begins:
0x00, 0x00, 0x00, 0x13, // First contained payload box's size
0x71, 0x61, 0x79, 0x6c, // Type of box, which is not payload (qayl)
0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, // Hello World
};
private static final byte[] INCOMPLETE_HEADER_SAMPLE = {
0x00, 0x00, 0x00, 0x23, // Size
0x76, 0x74, 0x74, 0x63, // "vttc" Box type. VTT Cue box begins:
0x00, 0x00, 0x00, 0x14, // Contained payload box's size
0x70, 0x61, 0x79, 0x6c, // Contained payload box's type (payl), Cue Payload Box begins:
0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x0a, // Hello World\n
0x00, 0x00, 0x00, 0x07, // Size of an incomplete header, which belongs to the first vttc box.
0x76, 0x74, 0x74
};
private Mp4WebvttParser parser;
@Override
public void setUp() {
parser = new Mp4WebvttParser();
}
// Positive tests.
public void testSingleCueSample() throws IOException {
Subtitle result = parser.parse(new ByteArrayInputStream(SINGLE_CUE_SAMPLE));
Cue expectedCue = new Cue("Hello World"); // Line feed must be trimmed by the parser
assertMp4WebvttSubtitleEquals(result, expectedCue);
}
public void testTwoCuesSample() throws IOException {
Subtitle result = parser.parse(new ByteArrayInputStream(DOUBLE_CUE_SAMPLE));
Cue firstExpectedCue = new Cue("Hello World");
Cue secondExpectedCue = new Cue("Bye Bye");
assertMp4WebvttSubtitleEquals(result, firstExpectedCue, secondExpectedCue);
}
public void testNoCueSample() throws IOException {
Subtitle result = parser.parse(new ByteArrayInputStream(NO_CUE_SAMPLE));
assertMp4WebvttSubtitleEquals(result, new Cue[] {});
}
// Negative tests.
public void testSampleWithVttCueWithNoPayload() throws IOException {
try {
parser.parse(new ByteArrayInputStream(NO_PAYLOAD_CUE_SAMPLE));
} catch (ParserException e) {
// Expected.
return;
}
fail("The parser should have failed, no payload was included in the VTTCue.");
}
public void testSampleWithIncompleteHeader() throws IOException {
try {
parser.parse(new ByteArrayInputStream(INCOMPLETE_HEADER_SAMPLE));
} catch (ParserException e) {
return;
}
fail("The parser should have failed, no payload was included in the VTTCue.");
}
// Util methods
/**
* Asserts that the Subtitle's cues (which are all part of the event at t=0) are equal to the
* expected Cues.
*
* @param sub The parsed {@link Subtitle} to check.
* @param expectedCues Expected {@link Cue}s in order of appearance.
*/
private static void assertMp4WebvttSubtitleEquals(Subtitle sub, Cue... expectedCues) {
assertEquals(1, sub.getEventTimeCount());
assertEquals(0, sub.getEventTime(0));
List<Cue> subtitleCues = sub.getCues(0);
assertEquals(expectedCues.length, subtitleCues.size());
for (int i = 0; i < subtitleCues.size(); i++) {
Set<String> differences = getCueDifferences(subtitleCues.get(i), expectedCues[i]);
assertTrue("Cues at position " + i + " are not equal. Different fields are "
+ Arrays.toString(differences.toArray()), differences.isEmpty());
}
}
/**
* Checks whether two non null cues are equal. Check fails if any of the Cues are null.
*
* @return a set that contains the names of the different fields.
*/
private static Set<String> getCueDifferences(Cue aCue, Cue anotherCue) {
assertNotNull(aCue);
assertNotNull(anotherCue);
Set<String> differences = new ArraySet<>();
if (aCue.line != anotherCue.line) {
differences.add("line: " + aCue.line + " | " + anotherCue.line);
}
if (aCue.lineAnchor != anotherCue.lineAnchor) {
differences.add("lineAnchor: " + aCue.lineAnchor + " | " + anotherCue.lineAnchor);
}
if (aCue.lineType != anotherCue.lineType) {
differences.add("lineType: " + aCue.lineType + " | " + anotherCue.lineType);
}
if (aCue.position != anotherCue.position) {
differences.add("position: " + aCue.position + " | " + anotherCue.position);
}
if (aCue.positionAnchor != anotherCue.positionAnchor) {
differences.add("positionAnchor: " + aCue.positionAnchor + " | " + anotherCue.positionAnchor);
}
if (aCue.size != anotherCue.size) {
differences.add("size: " + aCue.size + " | " + anotherCue.size);
}
if (!Util.areEqual(aCue.text, anotherCue.text)) {
differences.add("text: " + aCue.text + " | " + anotherCue.text);
}
if (!Util.areEqual(aCue.textAlignment, anotherCue.textAlignment)) {
differences.add("textAlignment: " + aCue.textAlignment + " | " + anotherCue.textAlignment);
}
return differences;
}
}

View file

@ -17,7 +17,6 @@ package com.google.android.exoplayer.text.mp4webvtt;
import com.google.android.exoplayer.ParserException;
import com.google.android.exoplayer.text.Cue;
import com.google.android.exoplayer.text.Subtitle;
import com.google.android.exoplayer.text.SubtitleParser;
import com.google.android.exoplayer.util.MimeTypes;
import com.google.android.exoplayer.util.ParsableByteArray;
@ -51,7 +50,7 @@ public final class Mp4WebvttParser implements SubtitleParser {
}
@Override
public Subtitle parse(InputStream inputStream) throws IOException {
public Mp4WebvttSubtitle parse(InputStream inputStream) throws IOException {
// Webvtt in Mp4 samples have boxes inside of them, so we have to do a traditional box parsing:
// first 4 bytes size and then 4 bytes type.
int inputStreamByteCount = inputStream.available();