Commit b47fb282 by tonihei Committed by Oliver Woodman

Move extension tests to Robolectric.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=187021822
parent d400efd0
Showing with 1709 additions and 557 deletions
...@@ -24,6 +24,7 @@ include modulePrefix + 'library-hls' ...@@ -24,6 +24,7 @@ include modulePrefix + 'library-hls'
include modulePrefix + 'library-smoothstreaming' include modulePrefix + 'library-smoothstreaming'
include modulePrefix + 'library-ui' include modulePrefix + 'library-ui'
include modulePrefix + 'testutils' include modulePrefix + 'testutils'
include modulePrefix + 'testutils-robolectric'
include modulePrefix + 'extension-ffmpeg' include modulePrefix + 'extension-ffmpeg'
include modulePrefix + 'extension-flac' include modulePrefix + 'extension-flac'
include modulePrefix + 'extension-gvr' include modulePrefix + 'extension-gvr'
...@@ -44,6 +45,7 @@ project(modulePrefix + 'library-hls').projectDir = new File(rootDir, 'library/hl ...@@ -44,6 +45,7 @@ project(modulePrefix + 'library-hls').projectDir = new File(rootDir, 'library/hl
project(modulePrefix + 'library-smoothstreaming').projectDir = new File(rootDir, 'library/smoothstreaming') project(modulePrefix + 'library-smoothstreaming').projectDir = new File(rootDir, 'library/smoothstreaming')
project(modulePrefix + 'library-ui').projectDir = new File(rootDir, 'library/ui') project(modulePrefix + 'library-ui').projectDir = new File(rootDir, 'library/ui')
project(modulePrefix + 'testutils').projectDir = new File(rootDir, 'testutils') project(modulePrefix + 'testutils').projectDir = new File(rootDir, 'testutils')
project(modulePrefix + 'testutils-robolectric').projectDir = new File(rootDir, 'testutils_robolectric')
project(modulePrefix + 'extension-ffmpeg').projectDir = new File(rootDir, 'extensions/ffmpeg') project(modulePrefix + 'extension-ffmpeg').projectDir = new File(rootDir, 'extensions/ffmpeg')
project(modulePrefix + 'extension-flac').projectDir = new File(rootDir, 'extensions/flac') project(modulePrefix + 'extension-flac').projectDir = new File(rootDir, 'extensions/flac')
project(modulePrefix + 'extension-gvr').projectDir = new File(rootDir, 'extensions/gvr') project(modulePrefix + 'extension-gvr').projectDir = new File(rootDir, 'extensions/gvr')
......
...@@ -38,10 +38,7 @@ dependencies { ...@@ -38,10 +38,7 @@ dependencies {
compile 'com.google.android.gms:play-services-cast-framework:' + playServicesLibraryVersion compile 'com.google.android.gms:play-services-cast-framework:' + playServicesLibraryVersion
compile project(modulePrefix + 'library-core') compile project(modulePrefix + 'library-core')
compile project(modulePrefix + 'library-ui') compile project(modulePrefix + 'library-ui')
testCompile project(modulePrefix + 'testutils') testCompile project(modulePrefix + 'testutils-robolectric')
testCompile 'junit:junit:' + junitVersion
testCompile 'org.mockito:mockito-core:' + mockitoVersion
testCompile 'org.robolectric:robolectric:' + robolectricVersion
} }
ext { ext {
......
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2018 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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.google.android.exoplayer2.ext.cast.test">
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="26"/>
</manifest>
...@@ -17,6 +17,7 @@ package com.google.android.exoplayer2.ext.cast; ...@@ -17,6 +17,7 @@ package com.google.android.exoplayer2.ext.cast;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.testutil.TimelineAsserts; import com.google.android.exoplayer2.testutil.TimelineAsserts;
import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.gms.cast.MediaInfo; import com.google.android.gms.cast.MediaInfo;
import com.google.android.gms.cast.MediaQueueItem; import com.google.android.gms.cast.MediaQueueItem;
import com.google.android.gms.cast.MediaStatus; import com.google.android.gms.cast.MediaStatus;
...@@ -25,11 +26,9 @@ import org.junit.Test; ...@@ -25,11 +26,9 @@ import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.Mockito; import org.mockito.Mockito;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
/** Tests for {@link CastTimelineTracker}. */ /** Tests for {@link CastTimelineTracker}. */
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
@Config(sdk = Config.TARGET_SDK, manifest = Config.NONE)
public class CastTimelineTrackerTest { public class CastTimelineTrackerTest {
private static final long DURATION_1_MS = 1000; private static final long DURATION_1_MS = 1000;
...@@ -49,12 +48,12 @@ public class CastTimelineTrackerTest { ...@@ -49,12 +48,12 @@ public class CastTimelineTrackerTest {
new long[] {DURATION_1_MS, MediaInfo.UNKNOWN_DURATION, MediaInfo.UNKNOWN_DURATION}); new long[] {DURATION_1_MS, MediaInfo.UNKNOWN_DURATION, MediaInfo.UNKNOWN_DURATION});
CastTimelineTracker tracker = new CastTimelineTracker(); CastTimelineTracker tracker = new CastTimelineTracker();
mediaInfo = mockMediaInfo("contentId1", DURATION_1_MS); mediaInfo = getMediaInfo("contentId1", DURATION_1_MS);
Mockito.when(status.getMediaInfo()).thenReturn(mediaInfo); Mockito.when(status.getMediaInfo()).thenReturn(mediaInfo);
TimelineAsserts.assertPeriodDurations( TimelineAsserts.assertPeriodDurations(
tracker.getCastTimeline(status), C.msToUs(DURATION_1_MS), C.TIME_UNSET, C.TIME_UNSET); tracker.getCastTimeline(status), C.msToUs(DURATION_1_MS), C.TIME_UNSET, C.TIME_UNSET);
mediaInfo = mockMediaInfo("contentId3", DURATION_3_MS); mediaInfo = getMediaInfo("contentId3", DURATION_3_MS);
Mockito.when(status.getMediaInfo()).thenReturn(mediaInfo); Mockito.when(status.getMediaInfo()).thenReturn(mediaInfo);
TimelineAsserts.assertPeriodDurations( TimelineAsserts.assertPeriodDurations(
tracker.getCastTimeline(status), tracker.getCastTimeline(status),
...@@ -62,7 +61,7 @@ public class CastTimelineTrackerTest { ...@@ -62,7 +61,7 @@ public class CastTimelineTrackerTest {
C.TIME_UNSET, C.TIME_UNSET,
C.msToUs(DURATION_3_MS)); C.msToUs(DURATION_3_MS));
mediaInfo = mockMediaInfo("contentId2", DURATION_2_MS); mediaInfo = getMediaInfo("contentId2", DURATION_2_MS);
Mockito.when(status.getMediaInfo()).thenReturn(mediaInfo); Mockito.when(status.getMediaInfo()).thenReturn(mediaInfo);
TimelineAsserts.assertPeriodDurations( TimelineAsserts.assertPeriodDurations(
tracker.getCastTimeline(status), tracker.getCastTimeline(status),
...@@ -80,7 +79,7 @@ public class CastTimelineTrackerTest { ...@@ -80,7 +79,7 @@ public class CastTimelineTrackerTest {
DURATION_5_MS, DURATION_5_MS,
MediaInfo.UNKNOWN_DURATION MediaInfo.UNKNOWN_DURATION
}); });
mediaInfo = mockMediaInfo("contentId5", DURATION_5_MS); mediaInfo = getMediaInfo("contentId5", DURATION_5_MS);
Mockito.when(newStatus.getMediaInfo()).thenReturn(mediaInfo); Mockito.when(newStatus.getMediaInfo()).thenReturn(mediaInfo);
TimelineAsserts.assertPeriodDurations( TimelineAsserts.assertPeriodDurations(
tracker.getCastTimeline(newStatus), tracker.getCastTimeline(newStatus),
...@@ -89,7 +88,7 @@ public class CastTimelineTrackerTest { ...@@ -89,7 +88,7 @@ public class CastTimelineTrackerTest {
C.msToUs(DURATION_5_MS), C.msToUs(DURATION_5_MS),
C.msToUs(DURATION_3_MS)); C.msToUs(DURATION_3_MS));
mediaInfo = mockMediaInfo("contentId3", DURATION_3_MS); mediaInfo = getMediaInfo("contentId3", DURATION_3_MS);
Mockito.when(newStatus.getMediaInfo()).thenReturn(mediaInfo); Mockito.when(newStatus.getMediaInfo()).thenReturn(mediaInfo);
TimelineAsserts.assertPeriodDurations( TimelineAsserts.assertPeriodDurations(
tracker.getCastTimeline(newStatus), tracker.getCastTimeline(newStatus),
...@@ -98,7 +97,7 @@ public class CastTimelineTrackerTest { ...@@ -98,7 +97,7 @@ public class CastTimelineTrackerTest {
C.msToUs(DURATION_5_MS), C.msToUs(DURATION_5_MS),
C.msToUs(DURATION_3_MS)); C.msToUs(DURATION_3_MS));
mediaInfo = mockMediaInfo("contentId4", DURATION_4_MS); mediaInfo = getMediaInfo("contentId4", DURATION_4_MS);
Mockito.when(newStatus.getMediaInfo()).thenReturn(mediaInfo); Mockito.when(newStatus.getMediaInfo()).thenReturn(mediaInfo);
TimelineAsserts.assertPeriodDurations( TimelineAsserts.assertPeriodDurations(
tracker.getCastTimeline(newStatus), tracker.getCastTimeline(newStatus),
...@@ -112,7 +111,7 @@ public class CastTimelineTrackerTest { ...@@ -112,7 +111,7 @@ public class CastTimelineTrackerTest {
int[] itemIds, String[] contentIds, long[] durationsMs) { int[] itemIds, String[] contentIds, long[] durationsMs) {
ArrayList<MediaQueueItem> items = new ArrayList<>(); ArrayList<MediaQueueItem> items = new ArrayList<>();
for (int i = 0; i < contentIds.length; i++) { for (int i = 0; i < contentIds.length; i++) {
MediaInfo mediaInfo = mockMediaInfo(contentIds[i], durationsMs[i]); MediaInfo mediaInfo = getMediaInfo(contentIds[i], durationsMs[i]);
MediaQueueItem item = Mockito.mock(MediaQueueItem.class); MediaQueueItem item = Mockito.mock(MediaQueueItem.class);
Mockito.when(item.getMedia()).thenReturn(mediaInfo); Mockito.when(item.getMedia()).thenReturn(mediaInfo);
Mockito.when(item.getItemId()).thenReturn(itemIds[i]); Mockito.when(item.getItemId()).thenReturn(itemIds[i]);
...@@ -123,10 +122,11 @@ public class CastTimelineTrackerTest { ...@@ -123,10 +122,11 @@ public class CastTimelineTrackerTest {
return status; return status;
} }
private static MediaInfo mockMediaInfo(String contentId, long durationMs) { private static MediaInfo getMediaInfo(String contentId, long durationMs) {
MediaInfo mediaInfo = Mockito.mock(MediaInfo.class); return new MediaInfo.Builder(contentId)
Mockito.when(mediaInfo.getContentId()).thenReturn(contentId); .setStreamDuration(durationMs)
Mockito.when(mediaInfo.getStreamDuration()).thenReturn(durationMs); .setContentType(MimeTypes.APPLICATION_MP4)
return mediaInfo; .setStreamType(MediaInfo.STREAM_TYPE_NONE)
.build();
} }
} }
...@@ -39,12 +39,8 @@ dependencies { ...@@ -39,12 +39,8 @@ dependencies {
compile files('libs/cronet_api.jar') compile files('libs/cronet_api.jar')
compile files('libs/cronet_impl_common_java.jar') compile files('libs/cronet_impl_common_java.jar')
compile files('libs/cronet_impl_native_java.jar') compile files('libs/cronet_impl_native_java.jar')
androidTestCompile project(modulePrefix + 'library') testCompile project(modulePrefix + 'library')
androidTestCompile project(modulePrefix + 'testutils') testCompile project(modulePrefix + 'testutils-robolectric')
androidTestCompile 'com.google.dexmaker:dexmaker:' + dexmakerVersion
androidTestCompile 'com.google.dexmaker:dexmaker-mockito:' + dexmakerVersion
androidTestCompile 'org.mockito:mockito-core:' + mockitoVersion
androidTestCompile 'com.android.support.test:runner:' + testSupportLibraryVersion
} }
ext { ext {
......
...@@ -18,16 +18,6 @@ ...@@ -18,16 +18,6 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
package="com.google.android.exoplayer2.ext.cronet"> package="com.google.android.exoplayer2.ext.cronet">
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="27"/> <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="26"/>
<application android:debuggable="true"
android:allowBackup="false"
tools:ignore="MissingApplicationIcon,HardcodedDebugMode">
<uses-library android:name="android.test.runner" />
</application>
<instrumentation
android:name="android.test.InstrumentationTestRunner"
android:targetPackage="com.google.android.exoplayer2.ext.cronet"/>
</manifest> </manifest>
...@@ -19,9 +19,6 @@ import static com.google.common.truth.Truth.assertThat; ...@@ -19,9 +19,6 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import com.google.android.exoplayer2.testutil.MockitoUtil;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Arrays; import java.util.Arrays;
...@@ -30,11 +27,11 @@ import org.junit.Before; ...@@ -30,11 +27,11 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
/** /** Tests for {@link ByteArrayUploadDataProvider}. */
* Tests for {@link ByteArrayUploadDataProvider}. @RunWith(RobolectricTestRunner.class)
*/
@RunWith(AndroidJUnit4.class)
public final class ByteArrayUploadDataProviderTest { public final class ByteArrayUploadDataProviderTest {
private static final byte[] TEST_DATA = new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; private static final byte[] TEST_DATA = new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
...@@ -45,7 +42,7 @@ public final class ByteArrayUploadDataProviderTest { ...@@ -45,7 +42,7 @@ public final class ByteArrayUploadDataProviderTest {
@Before @Before
public void setUp() { public void setUp() {
MockitoUtil.setUpMockito(InstrumentationRegistry.getTargetContext(), this); MockitoAnnotations.initMocks(this);
byteBuffer = ByteBuffer.allocate(TEST_DATA.length); byteBuffer = ByteBuffer.allocate(TEST_DATA.length);
byteArrayUploadDataProvider = new ByteArrayUploadDataProvider(TEST_DATA); byteArrayUploadDataProvider = new ByteArrayUploadDataProvider(TEST_DATA);
} }
...@@ -90,5 +87,4 @@ public final class ByteArrayUploadDataProviderTest { ...@@ -90,5 +87,4 @@ public final class ByteArrayUploadDataProviderTest {
assertThat(byteBuffer.array()).isEqualTo(TEST_DATA); assertThat(byteBuffer.array()).isEqualTo(TEST_DATA);
verify(mockUploadDataSink).onRewindSucceeded(); verify(mockUploadDataSink).onRewindSucceeded();
} }
} }
...@@ -31,6 +31,7 @@ android { ...@@ -31,6 +31,7 @@ android {
} }
test { test {
java.srcDirs += "../../testutils/src/main/java/" java.srcDirs += "../../testutils/src/main/java/"
java.srcDirs += "../../testutils_robolectric/src/main/java/"
} }
} }
......
...@@ -89,7 +89,7 @@ public final class ContentDataSourceTest extends InstrumentationTestCase { ...@@ -89,7 +89,7 @@ public final class ContentDataSourceTest extends InstrumentationTestCase {
ContentDataSource dataSource = new ContentDataSource(instrumentation.getContext()); ContentDataSource dataSource = new ContentDataSource(instrumentation.getContext());
try { try {
DataSpec dataSpec = new DataSpec(contentUri, offset, length, null); DataSpec dataSpec = new DataSpec(contentUri, offset, length, null);
byte[] completeData = TestUtil.getByteArray(instrumentation, DATA_PATH); byte[] completeData = TestUtil.getByteArray(instrumentation.getContext(), DATA_PATH);
byte[] expectedData = Arrays.copyOfRange(completeData, offset, byte[] expectedData = Arrays.copyOfRange(completeData, offset,
length == C.LENGTH_UNSET ? completeData.length : offset + length); length == C.LENGTH_UNSET ? completeData.length : offset + length);
TestUtil.assertDataSourceContent(dataSource, dataSpec, expectedData, !pipeMode); TestUtil.assertDataSourceContent(dataSource, dataSpec, expectedData, !pipeMode);
......
...@@ -42,6 +42,7 @@ import com.google.android.exoplayer2.testutil.FakeTimeline; ...@@ -42,6 +42,7 @@ import com.google.android.exoplayer2.testutil.FakeTimeline;
import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition; import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition;
import com.google.android.exoplayer2.testutil.FakeTrackSelection; import com.google.android.exoplayer2.testutil.FakeTrackSelection;
import com.google.android.exoplayer2.testutil.FakeTrackSelector; import com.google.android.exoplayer2.testutil.FakeTrackSelector;
import com.google.android.exoplayer2.testutil.RobolectricUtil;
import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.upstream.Allocator;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
......
...@@ -22,8 +22,8 @@ import static org.mockito.Mockito.when; ...@@ -22,8 +22,8 @@ import static org.mockito.Mockito.when;
import android.util.Pair; import android.util.Pair;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.RobolectricUtil;
import com.google.android.exoplayer2.drm.DrmInitData.SchemeData; import com.google.android.exoplayer2.drm.DrmInitData.SchemeData;
import com.google.android.exoplayer2.testutil.RobolectricUtil;
import java.util.HashMap; import java.util.HashMap;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
......
...@@ -21,11 +21,11 @@ import static org.junit.Assert.fail; ...@@ -21,11 +21,11 @@ import static org.junit.Assert.fail;
import android.os.ConditionVariable; import android.os.ConditionVariable;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.RobolectricUtil;
import com.google.android.exoplayer2.offline.DownloadManager.DownloadListener; import com.google.android.exoplayer2.offline.DownloadManager.DownloadListener;
import com.google.android.exoplayer2.offline.DownloadManager.DownloadState; import com.google.android.exoplayer2.offline.DownloadManager.DownloadState;
import com.google.android.exoplayer2.offline.DownloadManager.DownloadState.State; import com.google.android.exoplayer2.offline.DownloadManager.DownloadState.State;
import com.google.android.exoplayer2.testutil.DummyMainThread; import com.google.android.exoplayer2.testutil.DummyMainThread;
import com.google.android.exoplayer2.testutil.RobolectricUtil;
import com.google.android.exoplayer2.upstream.DummyDataSource; import com.google.android.exoplayer2.upstream.DummyDataSource;
import com.google.android.exoplayer2.upstream.cache.Cache; import com.google.android.exoplayer2.upstream.cache.Cache;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
......
...@@ -20,7 +20,6 @@ import static org.junit.Assert.fail; ...@@ -20,7 +20,6 @@ import static org.junit.Assert.fail;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.RobolectricUtil;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.Timeline.Period; import com.google.android.exoplayer2.Timeline.Period;
import com.google.android.exoplayer2.Timeline.Window; import com.google.android.exoplayer2.Timeline.Window;
...@@ -29,6 +28,7 @@ import com.google.android.exoplayer2.testutil.FakeMediaSource; ...@@ -29,6 +28,7 @@ import com.google.android.exoplayer2.testutil.FakeMediaSource;
import com.google.android.exoplayer2.testutil.FakeTimeline; import com.google.android.exoplayer2.testutil.FakeTimeline;
import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition; import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition;
import com.google.android.exoplayer2.testutil.MediaSourceTestRunner; import com.google.android.exoplayer2.testutil.MediaSourceTestRunner;
import com.google.android.exoplayer2.testutil.RobolectricUtil;
import com.google.android.exoplayer2.testutil.TimelineAsserts; import com.google.android.exoplayer2.testutil.TimelineAsserts;
import java.io.IOException; import java.io.IOException;
import org.junit.Before; import org.junit.Before;
......
...@@ -19,7 +19,6 @@ import static com.google.common.truth.Truth.assertThat; ...@@ -19,7 +19,6 @@ import static com.google.common.truth.Truth.assertThat;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.RobolectricUtil;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
import com.google.android.exoplayer2.testutil.FakeMediaSource; import com.google.android.exoplayer2.testutil.FakeMediaSource;
...@@ -27,6 +26,7 @@ import com.google.android.exoplayer2.testutil.FakeShuffleOrder; ...@@ -27,6 +26,7 @@ import com.google.android.exoplayer2.testutil.FakeShuffleOrder;
import com.google.android.exoplayer2.testutil.FakeTimeline; import com.google.android.exoplayer2.testutil.FakeTimeline;
import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition; import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition;
import com.google.android.exoplayer2.testutil.MediaSourceTestRunner; import com.google.android.exoplayer2.testutil.MediaSourceTestRunner;
import com.google.android.exoplayer2.testutil.RobolectricUtil;
import com.google.android.exoplayer2.testutil.TimelineAsserts; import com.google.android.exoplayer2.testutil.TimelineAsserts;
import java.io.IOException; import java.io.IOException;
import org.junit.Test; import org.junit.Test;
......
...@@ -22,7 +22,6 @@ import static org.mockito.Mockito.verify; ...@@ -22,7 +22,6 @@ import static org.mockito.Mockito.verify;
import android.os.ConditionVariable; import android.os.ConditionVariable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.RobolectricUtil;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
import com.google.android.exoplayer2.testutil.DummyMainThread; import com.google.android.exoplayer2.testutil.DummyMainThread;
...@@ -31,6 +30,7 @@ import com.google.android.exoplayer2.testutil.FakeShuffleOrder; ...@@ -31,6 +30,7 @@ import com.google.android.exoplayer2.testutil.FakeShuffleOrder;
import com.google.android.exoplayer2.testutil.FakeTimeline; import com.google.android.exoplayer2.testutil.FakeTimeline;
import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition; import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition;
import com.google.android.exoplayer2.testutil.MediaSourceTestRunner; import com.google.android.exoplayer2.testutil.MediaSourceTestRunner;
import com.google.android.exoplayer2.testutil.RobolectricUtil;
import com.google.android.exoplayer2.testutil.TimelineAsserts; import com.google.android.exoplayer2.testutil.TimelineAsserts;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
......
...@@ -17,12 +17,12 @@ package com.google.android.exoplayer2.source; ...@@ -17,12 +17,12 @@ package com.google.android.exoplayer2.source;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.RobolectricUtil;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.testutil.FakeMediaSource; import com.google.android.exoplayer2.testutil.FakeMediaSource;
import com.google.android.exoplayer2.testutil.FakeTimeline; import com.google.android.exoplayer2.testutil.FakeTimeline;
import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition; import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition;
import com.google.android.exoplayer2.testutil.MediaSourceTestRunner; import com.google.android.exoplayer2.testutil.MediaSourceTestRunner;
import com.google.android.exoplayer2.testutil.RobolectricUtil;
import com.google.android.exoplayer2.testutil.TimelineAsserts; import com.google.android.exoplayer2.testutil.TimelineAsserts;
import java.io.IOException; import java.io.IOException;
import org.junit.Before; import org.junit.Before;
......
...@@ -19,13 +19,13 @@ import static com.google.common.truth.Truth.assertThat; ...@@ -19,13 +19,13 @@ import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.RobolectricUtil;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.source.MergingMediaSource.IllegalMergeException; import com.google.android.exoplayer2.source.MergingMediaSource.IllegalMergeException;
import com.google.android.exoplayer2.testutil.FakeMediaSource; import com.google.android.exoplayer2.testutil.FakeMediaSource;
import com.google.android.exoplayer2.testutil.FakeTimeline; import com.google.android.exoplayer2.testutil.FakeTimeline;
import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition; import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition;
import com.google.android.exoplayer2.testutil.MediaSourceTestRunner; import com.google.android.exoplayer2.testutil.MediaSourceTestRunner;
import com.google.android.exoplayer2.testutil.RobolectricUtil;
import java.io.IOException; import java.io.IOException;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
......
...@@ -35,15 +35,7 @@ android { ...@@ -35,15 +35,7 @@ android {
dependencies { dependencies {
compile project(modulePrefix + 'library-core') compile project(modulePrefix + 'library-core')
compile 'com.android.support:support-annotations:' + supportLibraryVersion compile 'com.android.support:support-annotations:' + supportLibraryVersion
androidTestCompile project(modulePrefix + 'testutils') testCompile project(modulePrefix + 'testutils-robolectric')
androidTestCompile 'com.google.dexmaker:dexmaker:' + dexmakerVersion
androidTestCompile 'com.google.dexmaker:dexmaker-mockito:' + dexmakerVersion
androidTestCompile 'org.mockito:mockito-core:' + mockitoVersion
testCompile project(modulePrefix + 'testutils')
testCompile 'com.google.truth:truth:' + truthVersion
testCompile 'junit:junit:' + junitVersion
testCompile 'org.mockito:mockito-core:' + mockitoVersion
testCompile 'org.robolectric:robolectric:' + robolectricVersion
} }
ext { ext {
......
...@@ -50,6 +50,7 @@ import java.io.BufferedReader; ...@@ -50,6 +50,7 @@ import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Locale; import java.util.Locale;
...@@ -1113,7 +1114,9 @@ public final class DashMediaSource implements MediaSource { ...@@ -1113,7 +1114,9 @@ public final class DashMediaSource implements MediaSource {
@Override @Override
public Long parse(Uri uri, InputStream inputStream) throws IOException { public Long parse(Uri uri, InputStream inputStream) throws IOException {
String firstLine = new BufferedReader(new InputStreamReader(inputStream)).readLine(); String firstLine =
new BufferedReader(new InputStreamReader(inputStream, Charset.forName(C.UTF8_NAME)))
.readLine();
try { try {
Matcher matcher = TIMESTAMP_WITH_TIMEZONE_PATTERN.matcher(firstLine); Matcher matcher = TIMESTAMP_WITH_TIMEZONE_PATTERN.matcher(firstLine);
if (!matcher.matches()) { if (!matcher.matches()) {
......
...@@ -18,16 +18,6 @@ ...@@ -18,16 +18,6 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
package="com.google.android.exoplayer2.source.dash.test"> package="com.google.android.exoplayer2.source.dash.test">
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="27"/> <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="25"/>
<application android:debuggable="true"
android:allowBackup="false"
tools:ignore="MissingApplicationIcon,HardcodedDebugMode">
<uses-library android:name="android.test.runner"/>
</application>
<instrumentation
android:targetPackage="com.google.android.exoplayer2.source.dash.test"
android:name="android.test.InstrumentationTestRunner"/>
</manifest> </manifest>
/*
* Copyright (C) 2017 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.exoplayer2.source.dash;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
import com.google.android.exoplayer2.ParserException;
import com.google.android.exoplayer2.upstream.ParsingLoadable;
import com.google.android.exoplayer2.util.Util;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
/** Unit test for {@link DashMediaSource}. */
@RunWith(RobolectricTestRunner.class)
public final class DashMediaSourceTest {
@Test
public void testIso8601ParserParse() throws IOException {
DashMediaSource.Iso8601Parser parser = new DashMediaSource.Iso8601Parser();
// UTC.
assertParseStringToLong(1512381697000L, parser, "2017-12-04T10:01:37Z");
assertParseStringToLong(1512381697000L, parser, "2017-12-04T10:01:37+00:00");
assertParseStringToLong(1512381697000L, parser, "2017-12-04T10:01:37+0000");
assertParseStringToLong(1512381697000L, parser, "2017-12-04T10:01:37+00");
// Positive timezone offsets.
assertParseStringToLong(1512381697000L - 4980000L, parser, "2017-12-04T10:01:37+01:23");
assertParseStringToLong(1512381697000L - 4980000L, parser, "2017-12-04T10:01:37+0123");
assertParseStringToLong(1512381697000L - 3600000L, parser, "2017-12-04T10:01:37+01");
// Negative timezone offsets with minus character.
assertParseStringToLong(1512381697000L + 4980000L, parser, "2017-12-04T10:01:37-01:23");
assertParseStringToLong(1512381697000L + 4980000L, parser, "2017-12-04T10:01:37-0123");
assertParseStringToLong(1512381697000L + 3600000L, parser, "2017-12-04T10:01:37-01:00");
assertParseStringToLong(1512381697000L + 3600000L, parser, "2017-12-04T10:01:37-0100");
assertParseStringToLong(1512381697000L + 3600000L, parser, "2017-12-04T10:01:37-01");
// Negative timezone offsets with hyphen character.
assertParseStringToLong(1512381697000L + 4980000L, parser, "2017-12-04T10:01:37−01:23");
assertParseStringToLong(1512381697000L + 4980000L, parser, "2017-12-04T10:01:37−0123");
assertParseStringToLong(1512381697000L + 3600000L, parser, "2017-12-04T10:01:37−01:00");
assertParseStringToLong(1512381697000L + 3600000L, parser, "2017-12-04T10:01:37−0100");
assertParseStringToLong(1512381697000L + 3600000L, parser, "2017-12-04T10:01:37−01");
}
@Test
public void testIso8601ParserParseMissingTimezone() throws IOException {
DashMediaSource.Iso8601Parser parser = new DashMediaSource.Iso8601Parser();
try {
assertParseStringToLong(0, parser, "2017-12-04T10:01:37");
fail();
} catch (ParserException e) {
// Expected.
}
}
private static void assertParseStringToLong(
long expected, ParsingLoadable.Parser<Long> parser, String data) throws IOException {
long actual = parser.parse(null, new ByteArrayInputStream(Util.getUtf8Bytes(data)));
assertThat(actual).isEqualTo(expected);
}
}
...@@ -28,33 +28,38 @@ import com.google.android.exoplayer2.source.dash.manifest.SegmentBase.SingleSegm ...@@ -28,33 +28,38 @@ import com.google.android.exoplayer2.source.dash.manifest.SegmentBase.SingleSegm
import com.google.android.exoplayer2.upstream.DummyDataSource; import com.google.android.exoplayer2.upstream.DummyDataSource;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
import java.util.Arrays; import java.util.Arrays;
import junit.framework.TestCase; import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
/** /** Unit tests for {@link DashUtil}. */
* Unit tests for {@link DashUtil}. @RunWith(RobolectricTestRunner.class)
*/ public final class DashUtilTest {
public final class DashUtilTest extends TestCase {
@Test
public void testLoadDrmInitDataFromManifest() throws Exception { public void testLoadDrmInitDataFromManifest() throws Exception {
Period period = newPeriod(newAdaptationSets(newRepresentations(newDrmInitData()))); Period period = newPeriod(newAdaptationSets(newRepresentations(newDrmInitData())));
DrmInitData drmInitData = DashUtil.loadDrmInitData(DummyDataSource.INSTANCE, period); DrmInitData drmInitData = DashUtil.loadDrmInitData(DummyDataSource.INSTANCE, period);
assertThat(drmInitData).isEqualTo(newDrmInitData()); assertThat(drmInitData).isEqualTo(newDrmInitData());
} }
@Test
public void testLoadDrmInitDataMissing() throws Exception { public void testLoadDrmInitDataMissing() throws Exception {
Period period = newPeriod(newAdaptationSets(newRepresentations(null /* no init data */))); Period period = newPeriod(newAdaptationSets(newRepresentations(null /* no init data */)));
DrmInitData drmInitData = DashUtil.loadDrmInitData(DummyDataSource.INSTANCE, period); DrmInitData drmInitData = DashUtil.loadDrmInitData(DummyDataSource.INSTANCE, period);
assertThat(drmInitData).isNull(); assertThat(drmInitData).isNull();
} }
@Test
public void testLoadDrmInitDataNoRepresentations() throws Exception { public void testLoadDrmInitDataNoRepresentations() throws Exception {
Period period = newPeriod(newAdaptationSets(/* no representation */)); Period period = newPeriod(newAdaptationSets(/* no representation */ ));
DrmInitData drmInitData = DashUtil.loadDrmInitData(DummyDataSource.INSTANCE, period); DrmInitData drmInitData = DashUtil.loadDrmInitData(DummyDataSource.INSTANCE, period);
assertThat(drmInitData).isNull(); assertThat(drmInitData).isNull();
} }
@Test
public void testLoadDrmInitDataNoAdaptationSets() throws Exception { public void testLoadDrmInitDataNoAdaptationSets() throws Exception {
Period period = newPeriod(/* no adaptation set */); Period period = newPeriod(/* no adaptation set */ );
DrmInitData drmInitData = DashUtil.loadDrmInitData(DummyDataSource.INSTANCE, period); DrmInitData drmInitData = DashUtil.loadDrmInitData(DummyDataSource.INSTANCE, period);
assertThat(drmInitData).isNull(); assertThat(drmInitData).isNull();
} }
...@@ -68,8 +73,18 @@ public final class DashUtilTest extends TestCase { ...@@ -68,8 +73,18 @@ public final class DashUtilTest extends TestCase {
} }
private static Representation newRepresentations(DrmInitData drmInitData) { private static Representation newRepresentations(DrmInitData drmInitData) {
Format format = Format.createVideoContainerFormat("id", MimeTypes.VIDEO_MP4, Format format =
MimeTypes.VIDEO_H264, "", Format.NO_VALUE, 1024, 768, Format.NO_VALUE, null, 0); Format.createVideoContainerFormat(
"id",
MimeTypes.VIDEO_MP4,
MimeTypes.VIDEO_H264,
"",
Format.NO_VALUE,
1024,
768,
Format.NO_VALUE,
null,
0);
if (drmInitData != null) { if (drmInitData != null) {
format = format.copyWithDrmInitData(drmInitData); format = format.copyWithDrmInitData(drmInitData);
} }
...@@ -77,8 +92,7 @@ public final class DashUtilTest extends TestCase { ...@@ -77,8 +92,7 @@ public final class DashUtilTest extends TestCase {
} }
private static DrmInitData newDrmInitData() { private static DrmInitData newDrmInitData() {
return new DrmInitData(new SchemeData(C.WIDEVINE_UUID, "mimeType", return new DrmInitData(
new byte[] {1, 4, 7, 0, 3, 6})); new SchemeData(C.WIDEVINE_UUID, "mimeType", new byte[] {1, 4, 7, 0, 3, 6}));
} }
} }
...@@ -18,39 +18,47 @@ package com.google.android.exoplayer2.source.dash.manifest; ...@@ -18,39 +18,47 @@ package com.google.android.exoplayer2.source.dash.manifest;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import android.net.Uri; import android.net.Uri;
import android.test.InstrumentationTestCase; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.metadata.emsg.EventMessage; import com.google.android.exoplayer2.metadata.emsg.EventMessage;
import com.google.android.exoplayer2.testutil.TestUtil; import com.google.android.exoplayer2.testutil.TestUtil;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
/** /** Unit tests for {@link DashManifestParser}. */
* Unit tests for {@link DashManifestParser}. @RunWith(RobolectricTestRunner.class)
*/ public class DashManifestParserTest {
public class DashManifestParserTest extends InstrumentationTestCase {
private static final String SAMPLE_MPD_1 = "sample_mpd_1"; private static final String SAMPLE_MPD_1 = "sample_mpd_1";
private static final String SAMPLE_MPD_2_UNKNOWN_MIME_TYPE = "sample_mpd_2_unknown_mime_type"; private static final String SAMPLE_MPD_2_UNKNOWN_MIME_TYPE = "sample_mpd_2_unknown_mime_type";
private static final String SAMPLE_MPD_3_SEGMENT_TEMPLATE = "sample_mpd_3_segment_template"; private static final String SAMPLE_MPD_3_SEGMENT_TEMPLATE = "sample_mpd_3_segment_template";
private static final String SAMPLE_MPD_4_EVENT_STREAM = "sample_mpd_4_event_stream"; private static final String SAMPLE_MPD_4_EVENT_STREAM = "sample_mpd_4_event_stream";
/** /** Simple test to ensure the sample manifests parse without any exceptions being thrown. */
* Simple test to ensure the sample manifests parse without any exceptions being thrown. @Test
*/
public void testParseMediaPresentationDescription() throws IOException { public void testParseMediaPresentationDescription() throws IOException {
DashManifestParser parser = new DashManifestParser(); DashManifestParser parser = new DashManifestParser();
parser.parse(Uri.parse("https://example.com/test.mpd"), parser.parse(
TestUtil.getInputStream(getInstrumentation(), SAMPLE_MPD_1)); Uri.parse("https://example.com/test.mpd"),
parser.parse(Uri.parse("https://example.com/test.mpd"), TestUtil.getInputStream(RuntimeEnvironment.application, SAMPLE_MPD_1));
TestUtil.getInputStream(getInstrumentation(), SAMPLE_MPD_2_UNKNOWN_MIME_TYPE)); parser.parse(
Uri.parse("https://example.com/test.mpd"),
TestUtil.getInputStream(RuntimeEnvironment.application, SAMPLE_MPD_2_UNKNOWN_MIME_TYPE));
} }
@Test
public void testParseMediaPresentationDescriptionWithSegmentTemplate() throws IOException { public void testParseMediaPresentationDescriptionWithSegmentTemplate() throws IOException {
DashManifestParser parser = new DashManifestParser(); DashManifestParser parser = new DashManifestParser();
DashManifest mpd = parser.parse(Uri.parse("https://example.com/test.mpd"), DashManifest mpd =
TestUtil.getInputStream(getInstrumentation(), SAMPLE_MPD_3_SEGMENT_TEMPLATE)); parser.parse(
Uri.parse("https://example.com/test.mpd"),
TestUtil.getInputStream(RuntimeEnvironment.application, SAMPLE_MPD_3_SEGMENT_TEMPLATE));
assertThat(mpd.getPeriodCount()).isEqualTo(1); assertThat(mpd.getPeriodCount()).isEqualTo(1);
...@@ -75,11 +83,13 @@ public class DashManifestParserTest extends InstrumentationTestCase { ...@@ -75,11 +83,13 @@ public class DashManifestParserTest extends InstrumentationTestCase {
} }
} }
public void testParseMediaPresentationDescriptionCanParseEventStream() @Test
throws IOException { public void testParseMediaPresentationDescriptionCanParseEventStream() throws IOException {
DashManifestParser parser = new DashManifestParser(); DashManifestParser parser = new DashManifestParser();
DashManifest mpd = parser.parse(Uri.parse("https://example.com/test.mpd"), DashManifest mpd =
TestUtil.getInputStream(getInstrumentation(), SAMPLE_MPD_4_EVENT_STREAM)); parser.parse(
Uri.parse("https://example.com/test.mpd"),
TestUtil.getInputStream(RuntimeEnvironment.application, SAMPLE_MPD_4_EVENT_STREAM));
Period period = mpd.getPeriod(0); Period period = mpd.getPeriod(0);
assertThat(period.eventStreams).hasSize(3); assertThat(period.eventStreams).hasSize(3);
...@@ -87,8 +97,14 @@ public class DashManifestParserTest extends InstrumentationTestCase { ...@@ -87,8 +97,14 @@ public class DashManifestParserTest extends InstrumentationTestCase {
// assert text-only event stream // assert text-only event stream
EventStream eventStream1 = period.eventStreams.get(0); EventStream eventStream1 = period.eventStreams.get(0);
assertThat(eventStream1.events.length).isEqualTo(1); assertThat(eventStream1.events.length).isEqualTo(1);
EventMessage expectedEvent1 = new EventMessage("urn:uuid:XYZY", "call", 10000, 0, EventMessage expectedEvent1 =
"+ 1 800 10101010".getBytes(), 0); new EventMessage(
"urn:uuid:XYZY",
"call",
10000,
0,
"+ 1 800 10101010".getBytes(Charset.forName(C.UTF8_NAME)),
0);
assertThat(eventStream1.events[0]).isEqualTo(expectedEvent1); assertThat(eventStream1.events[0]).isEqualTo(expectedEvent1);
// assert CData-structured event stream // assert CData-structured event stream
...@@ -135,6 +151,7 @@ public class DashManifestParserTest extends InstrumentationTestCase { ...@@ -135,6 +151,7 @@ public class DashManifestParserTest extends InstrumentationTestCase {
1000000000)); 1000000000));
} }
@Test
public void testParseCea608AccessibilityChannel() { public void testParseCea608AccessibilityChannel() {
assertThat( assertThat(
DashManifestParser.parseCea608AccessibilityChannel( DashManifestParser.parseCea608AccessibilityChannel(
...@@ -175,6 +192,7 @@ public class DashManifestParserTest extends InstrumentationTestCase { ...@@ -175,6 +192,7 @@ public class DashManifestParserTest extends InstrumentationTestCase {
.isEqualTo(Format.NO_VALUE); .isEqualTo(Format.NO_VALUE);
} }
@Test
public void testParseCea708AccessibilityChannel() { public void testParseCea708AccessibilityChannel() {
assertThat( assertThat(
DashManifestParser.parseCea708AccessibilityChannel( DashManifestParser.parseCea708AccessibilityChannel(
...@@ -226,5 +244,4 @@ public class DashManifestParserTest extends InstrumentationTestCase { ...@@ -226,5 +244,4 @@ public class DashManifestParserTest extends InstrumentationTestCase {
private static List<Descriptor> buildCea708AccessibilityDescriptors(String value) { private static List<Descriptor> buildCea708AccessibilityDescriptors(String value) {
return Collections.singletonList(new Descriptor("urn:scte:dash:cc:cea-708:2015", value, null)); return Collections.singletonList(new Descriptor("urn:scte:dash:cc:cea-708:2015", value, null));
} }
} }
...@@ -24,39 +24,48 @@ import java.util.Arrays; ...@@ -24,39 +24,48 @@ import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
import junit.framework.TestCase; import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
/** /** Unit tests for {@link DashManifest}. */
* Unit tests for {@link DashManifest}. @RunWith(RobolectricTestRunner.class)
*/ public class DashManifestTest {
public class DashManifestTest extends TestCase {
private static final UtcTimingElement DUMMY_UTC_TIMING = new UtcTimingElement("", ""); private static final UtcTimingElement DUMMY_UTC_TIMING = new UtcTimingElement("", "");
private static final SingleSegmentBase DUMMY_SEGMENT_BASE = new SingleSegmentBase(); private static final SingleSegmentBase DUMMY_SEGMENT_BASE = new SingleSegmentBase();
private static final Format DUMMY_FORMAT = Format.createSampleFormat("", "", 0); private static final Format DUMMY_FORMAT = Format.createSampleFormat("", "", 0);
@Test
public void testCopy() throws Exception { public void testCopy() throws Exception {
Representation[][][] representations = newRepresentations(3, 2, 3); Representation[][][] representations = newRepresentations(3, 2, 3);
DashManifest sourceManifest = newDashManifest(10, DashManifest sourceManifest =
newPeriod("1", 1, newDashManifest(
10,
newPeriod(
"1",
1,
newAdaptationSet(2, representations[0][0]), newAdaptationSet(2, representations[0][0]),
newAdaptationSet(3, representations[0][1])), newAdaptationSet(3, representations[0][1])),
newPeriod("4", 4, newPeriod(
"4",
4,
newAdaptationSet(5, representations[1][0]), newAdaptationSet(5, representations[1][0]),
newAdaptationSet(6, representations[1][1])), newAdaptationSet(6, representations[1][1])),
newPeriod("7", 7, newPeriod(
"7",
7,
newAdaptationSet(8, representations[2][0]), newAdaptationSet(8, representations[2][0]),
newAdaptationSet(9, representations[2][1]))); newAdaptationSet(9, representations[2][1])));
List<RepresentationKey> keys = Arrays.asList( List<RepresentationKey> keys =
Arrays.asList(
new RepresentationKey(0, 0, 0), new RepresentationKey(0, 0, 0),
new RepresentationKey(0, 0, 1), new RepresentationKey(0, 0, 1),
new RepresentationKey(0, 1, 2), new RepresentationKey(0, 1, 2),
new RepresentationKey(1, 0, 1), new RepresentationKey(1, 0, 1),
new RepresentationKey(1, 1, 0), new RepresentationKey(1, 1, 0),
new RepresentationKey(1, 1, 2), new RepresentationKey(1, 1, 2),
new RepresentationKey(2, 0, 1), new RepresentationKey(2, 0, 1),
new RepresentationKey(2, 0, 2), new RepresentationKey(2, 0, 2),
new RepresentationKey(2, 1, 0)); new RepresentationKey(2, 1, 0));
...@@ -65,66 +74,91 @@ public class DashManifestTest extends TestCase { ...@@ -65,66 +74,91 @@ public class DashManifestTest extends TestCase {
DashManifest copyManifest = sourceManifest.copy(keys); DashManifest copyManifest = sourceManifest.copy(keys);
DashManifest expectedManifest = newDashManifest(10, DashManifest expectedManifest =
newPeriod("1", 1, newDashManifest(
10,
newPeriod(
"1",
1,
newAdaptationSet(2, representations[0][0][0], representations[0][0][1]), newAdaptationSet(2, representations[0][0][0], representations[0][0][1]),
newAdaptationSet(3, representations[0][1][2])), newAdaptationSet(3, representations[0][1][2])),
newPeriod("4", 4, newPeriod(
"4",
4,
newAdaptationSet(5, representations[1][0][1]), newAdaptationSet(5, representations[1][0][1]),
newAdaptationSet(6, representations[1][1][0], representations[1][1][2])), newAdaptationSet(6, representations[1][1][0], representations[1][1][2])),
newPeriod("7", 7, newPeriod(
"7",
7,
newAdaptationSet(8, representations[2][0][1], representations[2][0][2]), newAdaptationSet(8, representations[2][0][1], representations[2][0][2]),
newAdaptationSet(9, representations[2][1][0]))); newAdaptationSet(9, representations[2][1][0])));
assertManifestEquals(expectedManifest, copyManifest); assertManifestEquals(expectedManifest, copyManifest);
} }
@Test
public void testCopySameAdaptationIndexButDifferentPeriod() throws Exception { public void testCopySameAdaptationIndexButDifferentPeriod() throws Exception {
Representation[][][] representations = newRepresentations(2, 1, 1); Representation[][][] representations = newRepresentations(2, 1, 1);
DashManifest sourceManifest = newDashManifest(10, DashManifest sourceManifest =
newPeriod("1", 1, newDashManifest(
newAdaptationSet(2, representations[0][0])), 10,
newPeriod("4", 4, newPeriod("1", 1, newAdaptationSet(2, representations[0][0])),
newAdaptationSet(5, representations[1][0]))); newPeriod("4", 4, newAdaptationSet(5, representations[1][0])));
DashManifest copyManifest = sourceManifest.copy(Arrays.asList( DashManifest copyManifest =
new RepresentationKey(0, 0, 0), sourceManifest.copy(
new RepresentationKey(1, 0, 0))); Arrays.asList(new RepresentationKey(0, 0, 0), new RepresentationKey(1, 0, 0)));
DashManifest expectedManifest = newDashManifest(10, DashManifest expectedManifest =
newPeriod("1", 1, newDashManifest(
newAdaptationSet(2, representations[0][0])), 10,
newPeriod("4", 4, newPeriod("1", 1, newAdaptationSet(2, representations[0][0])),
newAdaptationSet(5, representations[1][0]))); newPeriod("4", 4, newAdaptationSet(5, representations[1][0])));
assertManifestEquals(expectedManifest, copyManifest); assertManifestEquals(expectedManifest, copyManifest);
} }
@Test
public void testCopySkipPeriod() throws Exception { public void testCopySkipPeriod() throws Exception {
Representation[][][] representations = newRepresentations(3, 2, 3); Representation[][][] representations = newRepresentations(3, 2, 3);
DashManifest sourceManifest = newDashManifest(10, DashManifest sourceManifest =
newPeriod("1", 1, newDashManifest(
10,
newPeriod(
"1",
1,
newAdaptationSet(2, representations[0][0]), newAdaptationSet(2, representations[0][0]),
newAdaptationSet(3, representations[0][1])), newAdaptationSet(3, representations[0][1])),
newPeriod("4", 4, newPeriod(
"4",
4,
newAdaptationSet(5, representations[1][0]), newAdaptationSet(5, representations[1][0]),
newAdaptationSet(6, representations[1][1])), newAdaptationSet(6, representations[1][1])),
newPeriod("7", 7, newPeriod(
"7",
7,
newAdaptationSet(8, representations[2][0]), newAdaptationSet(8, representations[2][0]),
newAdaptationSet(9, representations[2][1]))); newAdaptationSet(9, representations[2][1])));
DashManifest copyManifest = sourceManifest.copy(Arrays.asList( DashManifest copyManifest =
sourceManifest.copy(
Arrays.asList(
new RepresentationKey(0, 0, 0), new RepresentationKey(0, 0, 0),
new RepresentationKey(0, 0, 1), new RepresentationKey(0, 0, 1),
new RepresentationKey(0, 1, 2), new RepresentationKey(0, 1, 2),
new RepresentationKey(2, 0, 1), new RepresentationKey(2, 0, 1),
new RepresentationKey(2, 0, 2), new RepresentationKey(2, 0, 2),
new RepresentationKey(2, 1, 0))); new RepresentationKey(2, 1, 0)));
DashManifest expectedManifest = newDashManifest(7, DashManifest expectedManifest =
newPeriod("1", 1, newDashManifest(
7,
newPeriod(
"1",
1,
newAdaptationSet(2, representations[0][0][0], representations[0][0][1]), newAdaptationSet(2, representations[0][0][0], representations[0][0][1]),
newAdaptationSet(3, representations[0][1][2])), newAdaptationSet(3, representations[0][1][2])),
newPeriod("7", 4, newPeriod(
"7",
4,
newAdaptationSet(8, representations[2][0][1], representations[2][0][2]), newAdaptationSet(8, representations[2][0][1], representations[2][0][2]),
newAdaptationSet(9, representations[2][1][0]))); newAdaptationSet(9, representations[2][1][0])));
assertManifestEquals(expectedManifest, copyManifest); assertManifestEquals(expectedManifest, copyManifest);
...@@ -164,8 +198,8 @@ public class DashManifestTest extends TestCase { ...@@ -164,8 +198,8 @@ public class DashManifestTest extends TestCase {
} }
} }
private static Representation[][][] newRepresentations(int periodCount, int adaptationSetCounts, private static Representation[][][] newRepresentations(
int representationCounts) { int periodCount, int adaptationSetCounts, int representationCounts) {
Representation[][][] representations = new Representation[periodCount][][]; Representation[][][] representations = new Representation[periodCount][][];
for (int i = 0; i < periodCount; i++) { for (int i = 0; i < periodCount; i++) {
representations[i] = new Representation[adaptationSetCounts][]; representations[i] = new Representation[adaptationSetCounts][];
...@@ -184,8 +218,8 @@ public class DashManifestTest extends TestCase { ...@@ -184,8 +218,8 @@ public class DashManifestTest extends TestCase {
} }
private static DashManifest newDashManifest(int duration, Period... periods) { private static DashManifest newDashManifest(int duration, Period... periods) {
return new DashManifest(0, duration, 1, false, 2, 3, 4, 12345, DUMMY_UTC_TIMING, Uri.EMPTY, return new DashManifest(
Arrays.asList(periods)); 0, duration, 1, false, 2, 3, 4, 12345, DUMMY_UTC_TIMING, Uri.EMPTY, Arrays.asList(periods));
} }
private static Period newPeriod(String id, int startMs, AdaptationSet... adaptationSets) { private static Period newPeriod(String id, int startMs, AdaptationSet... adaptationSets) {
...@@ -195,5 +229,4 @@ public class DashManifestTest extends TestCase { ...@@ -195,5 +229,4 @@ public class DashManifestTest extends TestCase {
private static AdaptationSet newAdaptationSet(int seed, Representation... representations) { private static AdaptationSet newAdaptationSet(int seed, Representation... representations) {
return new AdaptationSet(++seed, ++seed, Arrays.asList(representations), null, null); return new AdaptationSet(++seed, ++seed, Arrays.asList(representations), null, null);
} }
} }
...@@ -18,17 +18,19 @@ package com.google.android.exoplayer2.source.dash.manifest; ...@@ -18,17 +18,19 @@ package com.google.android.exoplayer2.source.dash.manifest;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import junit.framework.TestCase; import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
/** /** Unit test for {@link RangedUri}. */
* Unit test for {@link RangedUri}. @RunWith(RobolectricTestRunner.class)
*/ public class RangedUriTest {
public class RangedUriTest extends TestCase {
private static final String BASE_URI = "http://www.test.com/"; private static final String BASE_URI = "http://www.test.com/";
private static final String PARTIAL_URI = "path/file.ext"; private static final String PARTIAL_URI = "path/file.ext";
private static final String FULL_URI = BASE_URI + PARTIAL_URI; private static final String FULL_URI = BASE_URI + PARTIAL_URI;
@Test
public void testMerge() { public void testMerge() {
RangedUri rangeA = new RangedUri(FULL_URI, 0, 10); RangedUri rangeA = new RangedUri(FULL_URI, 0, 10);
RangedUri rangeB = new RangedUri(FULL_URI, 10, 10); RangedUri rangeB = new RangedUri(FULL_URI, 10, 10);
...@@ -36,6 +38,7 @@ public class RangedUriTest extends TestCase { ...@@ -36,6 +38,7 @@ public class RangedUriTest extends TestCase {
assertMerge(rangeA, rangeB, expected, null); assertMerge(rangeA, rangeB, expected, null);
} }
@Test
public void testMergeUnbounded() { public void testMergeUnbounded() {
RangedUri rangeA = new RangedUri(FULL_URI, 0, 10); RangedUri rangeA = new RangedUri(FULL_URI, 0, 10);
RangedUri rangeB = new RangedUri(FULL_URI, 10, C.LENGTH_UNSET); RangedUri rangeB = new RangedUri(FULL_URI, 10, C.LENGTH_UNSET);
...@@ -43,6 +46,7 @@ public class RangedUriTest extends TestCase { ...@@ -43,6 +46,7 @@ public class RangedUriTest extends TestCase {
assertMerge(rangeA, rangeB, expected, null); assertMerge(rangeA, rangeB, expected, null);
} }
@Test
public void testNonMerge() { public void testNonMerge() {
// A and B do not overlap, so should not merge // A and B do not overlap, so should not merge
RangedUri rangeA = new RangedUri(FULL_URI, 0, 10); RangedUri rangeA = new RangedUri(FULL_URI, 0, 10);
...@@ -65,6 +69,7 @@ public class RangedUriTest extends TestCase { ...@@ -65,6 +69,7 @@ public class RangedUriTest extends TestCase {
assertNonMerge(rangeA, rangeB, null); assertNonMerge(rangeA, rangeB, null);
} }
@Test
public void testMergeWithBaseUri() { public void testMergeWithBaseUri() {
RangedUri rangeA = new RangedUri(PARTIAL_URI, 0, 10); RangedUri rangeA = new RangedUri(PARTIAL_URI, 0, 10);
RangedUri rangeB = new RangedUri(FULL_URI, 10, 10); RangedUri rangeB = new RangedUri(FULL_URI, 10, 10);
...@@ -85,5 +90,4 @@ public class RangedUriTest extends TestCase { ...@@ -85,5 +90,4 @@ public class RangedUriTest extends TestCase {
merged = rangeB.attemptMerge(rangeA, baseUrl); merged = rangeB.attemptMerge(rangeA, baseUrl);
assertThat(merged).isNull(); assertThat(merged).isNull();
} }
} }
...@@ -20,27 +20,49 @@ import static com.google.common.truth.Truth.assertThat; ...@@ -20,27 +20,49 @@ import static com.google.common.truth.Truth.assertThat;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.source.dash.manifest.SegmentBase.SingleSegmentBase; import com.google.android.exoplayer2.source.dash.manifest.SegmentBase.SingleSegmentBase;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
import junit.framework.TestCase; import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
/** /** Unit test for {@link Representation}. */
* Unit test for {@link Representation}. @RunWith(RobolectricTestRunner.class)
*/ public class RepresentationTest {
public class RepresentationTest extends TestCase {
@Test
public void testGetCacheKey() { public void testGetCacheKey() {
String uri = "http://www.google.com"; String uri = "http://www.google.com";
SegmentBase base = new SingleSegmentBase(new RangedUri(null, 0, 1), 1, 0, 1, 1); SegmentBase base = new SingleSegmentBase(new RangedUri(null, 0, 1), 1, 0, 1, 1);
Format format = Format.createVideoContainerFormat("0", MimeTypes.APPLICATION_MP4, null, Format format =
MimeTypes.VIDEO_H264, 2500000, 1920, 1080, Format.NO_VALUE, null, 0); Format.createVideoContainerFormat(
Representation representation = Representation.newInstance("test_stream_1", 3, format, uri, "0",
base); MimeTypes.APPLICATION_MP4,
null,
MimeTypes.VIDEO_H264,
2500000,
1920,
1080,
Format.NO_VALUE,
null,
0);
Representation representation =
Representation.newInstance("test_stream_1", 3, format, uri, base);
assertThat(representation.getCacheKey()).isEqualTo("test_stream_1.0.3"); assertThat(representation.getCacheKey()).isEqualTo("test_stream_1.0.3");
format = Format.createVideoContainerFormat("150", MimeTypes.APPLICATION_MP4, null, format =
MimeTypes.VIDEO_H264, 2500000, 1920, 1080, Format.NO_VALUE, null, 0); Format.createVideoContainerFormat(
representation = Representation.newInstance("test_stream_1", Representation.REVISION_ID_DEFAULT, "150",
format, uri, base); MimeTypes.APPLICATION_MP4,
null,
MimeTypes.VIDEO_H264,
2500000,
1920,
1080,
Format.NO_VALUE,
null,
0);
representation =
Representation.newInstance(
"test_stream_1", Representation.REVISION_ID_DEFAULT, format, uri, base);
assertThat(representation.getCacheKey()).isEqualTo("test_stream_1.150.-1"); assertThat(representation.getCacheKey()).isEqualTo("test_stream_1.150.-1");
} }
} }
...@@ -16,14 +16,17 @@ ...@@ -16,14 +16,17 @@
package com.google.android.exoplayer2.source.dash.manifest; package com.google.android.exoplayer2.source.dash.manifest;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
import junit.framework.TestCase; import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
/** /** Unit test for {@link UrlTemplate}. */
* Unit test for {@link UrlTemplate}. @RunWith(RobolectricTestRunner.class)
*/ public class UrlTemplateTest {
public class UrlTemplateTest extends TestCase {
@Test
public void testRealExamples() { public void testRealExamples() {
String template = "QualityLevels($Bandwidth$)/Fragments(video=$Time$,format=mpd-time-csf)"; String template = "QualityLevels($Bandwidth$)/Fragments(video=$Time$,format=mpd-time-csf)";
UrlTemplate urlTemplate = UrlTemplate.compile(template); UrlTemplate urlTemplate = UrlTemplate.compile(template);
...@@ -41,6 +44,7 @@ public class UrlTemplateTest extends TestCase { ...@@ -41,6 +44,7 @@ public class UrlTemplateTest extends TestCase {
assertThat(url).isEqualTo("chunk_ctvideo_cfm4s_ridabc1_cn10_w2073857842_mpd.m4s"); assertThat(url).isEqualTo("chunk_ctvideo_cfm4s_ridabc1_cn10_w2073857842_mpd.m4s");
} }
@Test
public void testFull() { public void testFull() {
String template = "$Bandwidth$_a_$RepresentationID$_b_$Time$_c_$Number$"; String template = "$Bandwidth$_a_$RepresentationID$_b_$Time$_c_$Number$";
UrlTemplate urlTemplate = UrlTemplate.compile(template); UrlTemplate urlTemplate = UrlTemplate.compile(template);
...@@ -48,6 +52,7 @@ public class UrlTemplateTest extends TestCase { ...@@ -48,6 +52,7 @@ public class UrlTemplateTest extends TestCase {
assertThat(url).isEqualTo("650000_a_abc1_b_5000_c_10"); assertThat(url).isEqualTo("650000_a_abc1_b_5000_c_10");
} }
@Test
public void testFullWithDollarEscaping() { public void testFullWithDollarEscaping() {
String template = "$$$Bandwidth$$$_a$$_$RepresentationID$_b_$Time$_c_$Number$$$"; String template = "$$$Bandwidth$$$_a$$_$RepresentationID$_b_$Time$_c_$Number$$$";
UrlTemplate urlTemplate = UrlTemplate.compile(template); UrlTemplate urlTemplate = UrlTemplate.compile(template);
...@@ -55,6 +60,7 @@ public class UrlTemplateTest extends TestCase { ...@@ -55,6 +60,7 @@ public class UrlTemplateTest extends TestCase {
assertThat(url).isEqualTo("$650000$_a$_abc1_b_5000_c_10$"); assertThat(url).isEqualTo("$650000$_a$_abc1_b_5000_c_10$");
} }
@Test
public void testInvalidSubstitution() { public void testInvalidSubstitution() {
String template = "$IllegalId$"; String template = "$IllegalId$";
try { try {
...@@ -64,5 +70,4 @@ public class UrlTemplateTest extends TestCase { ...@@ -64,5 +70,4 @@ public class UrlTemplateTest extends TestCase {
// Expected. // Expected.
} }
} }
} }
/*
* Copyright (C) 2017 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.exoplayer2.source.dash.offline;
import static com.google.common.truth.Truth.assertThat;
import android.net.Uri;
import com.google.android.exoplayer2.offline.DownloadAction;
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
import com.google.android.exoplayer2.source.dash.manifest.RepresentationKey;
import com.google.android.exoplayer2.upstream.DummyDataSource;
import com.google.android.exoplayer2.upstream.cache.Cache;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
/**
* Unit tests for {@link DashDownloadAction}.
*/
@RunWith(RobolectricTestRunner.class)
public class DashDownloadActionTest {
@Test
public void testDownloadActionIsNotRemoveAction() throws Exception {
DashDownloadAction action = new DashDownloadAction(Uri.parse("uri"), false, null);
assertThat(action.isRemoveAction()).isFalse();
}
@Test
public void testRemoveActionIsRemoveAction() throws Exception {
DashDownloadAction action2 = new DashDownloadAction(Uri.parse("uri"), true, null);
assertThat(action2.isRemoveAction()).isTrue();
}
@Test
public void testCreateDownloader() throws Exception {
MockitoAnnotations.initMocks(this);
DashDownloadAction action = new DashDownloadAction(Uri.parse("uri"), false, null);
DownloaderConstructorHelper constructorHelper = new DownloaderConstructorHelper(
Mockito.mock(Cache.class), DummyDataSource.FACTORY);
assertThat(action.createDownloader(constructorHelper)).isNotNull();
}
@Test
public void testSameUriDifferentAction_IsSameMedia() throws Exception {
DashDownloadAction action1 = new DashDownloadAction(Uri.parse("uri"), true, null);
DashDownloadAction action2 = new DashDownloadAction(Uri.parse("uri"), false, null);
assertThat(action1.isSameMedia(action2)).isTrue();
}
@Test
public void testDifferentUriAndAction_IsNotSameMedia() throws Exception {
DashDownloadAction action3 = new DashDownloadAction(Uri.parse("uri2"), true, null);
DashDownloadAction action4 = new DashDownloadAction(Uri.parse("uri"), false, null);
assertThat(action3.isSameMedia(action4)).isFalse();
}
@SuppressWarnings("EqualsWithItself")
@Test
public void testEquals() throws Exception {
DashDownloadAction action1 = new DashDownloadAction(Uri.parse("uri"), true, null);
assertThat(action1.equals(action1)).isTrue();
DashDownloadAction action2 = new DashDownloadAction(Uri.parse("uri"), true, null);
DashDownloadAction action3 = new DashDownloadAction(Uri.parse("uri"), true, null);
assertEqual(action2, action3);
DashDownloadAction action4 = new DashDownloadAction(Uri.parse("uri"), true, null);
DashDownloadAction action5 = new DashDownloadAction(Uri.parse("uri"), false, null);
assertNotEqual(action4, action5);
DashDownloadAction action6 = new DashDownloadAction(Uri.parse("uri"), false, null);
DashDownloadAction action7 =
new DashDownloadAction(Uri.parse("uri"), false, null, new RepresentationKey(0, 0, 0));
assertNotEqual(action6, action7);
DashDownloadAction action8 =
new DashDownloadAction(Uri.parse("uri"), false, null, new RepresentationKey(1, 1, 1));
DashDownloadAction action9 =
new DashDownloadAction(Uri.parse("uri"), false, null, new RepresentationKey(0, 0, 0));
assertNotEqual(action8, action9);
DashDownloadAction action10 = new DashDownloadAction(Uri.parse("uri"), true, null);
DashDownloadAction action11 = new DashDownloadAction(Uri.parse("uri2"), true, null);
assertNotEqual(action10, action11);
DashDownloadAction action12 = new DashDownloadAction(Uri.parse("uri"), false, null,
new RepresentationKey(0, 0, 0), new RepresentationKey(1, 1, 1));
DashDownloadAction action13 = new DashDownloadAction(Uri.parse("uri"), false, null,
new RepresentationKey(1, 1, 1), new RepresentationKey(0, 0, 0));
assertEqual(action12, action13);
DashDownloadAction action14 = new DashDownloadAction(Uri.parse("uri"), false, null,
new RepresentationKey(0, 0, 0));
DashDownloadAction action15 = new DashDownloadAction(Uri.parse("uri"), false, null,
new RepresentationKey(1, 1, 1), new RepresentationKey(0, 0, 0));
assertNotEqual(action14, action15);
DashDownloadAction action16 = new DashDownloadAction(Uri.parse("uri"), false, null);
DashDownloadAction action17 =
new DashDownloadAction(Uri.parse("uri"), false, null, new RepresentationKey[0]);
assertEqual(action16, action17);
}
@Test
public void testSerializerGetType() throws Exception {
DashDownloadAction action = new DashDownloadAction(Uri.parse("uri"), false, null);
assertThat(action.getType()).isNotNull();
}
@Test
public void testSerializerWriteRead() throws Exception {
doTestSerializationRoundTrip(new DashDownloadAction(Uri.parse("uri"), false, null));
doTestSerializationRoundTrip(new DashDownloadAction(Uri.parse("uri"), true, null));
doTestSerializationRoundTrip(new DashDownloadAction(Uri.parse("uri2"), false, null,
new RepresentationKey(0, 0, 0), new RepresentationKey(1, 1, 1)));
}
private static void assertNotEqual(DashDownloadAction action1, DashDownloadAction action2) {
assertThat(action1).isNotEqualTo(action2);
assertThat(action2).isNotEqualTo(action1);
}
private static void assertEqual(DashDownloadAction action1, DashDownloadAction action2) {
assertThat(action1).isEqualTo(action2);
assertThat(action2).isEqualTo(action1);
}
private static void doTestSerializationRoundTrip(DashDownloadAction action1) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
DataOutputStream output = new DataOutputStream(out);
action1.writeToStream(output);
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
DataInputStream input = new DataInputStream(in);
DownloadAction action2 =
DashDownloadAction.DESERIALIZER.readFromStream(DownloadAction.MASTER_VERSION, input);
assertThat(action1).isEqualTo(action2);
}
}
...@@ -16,10 +16,10 @@ ...@@ -16,10 +16,10 @@
package com.google.android.exoplayer2.source.dash.offline; package com.google.android.exoplayer2.source.dash.offline;
import android.net.Uri; import android.net.Uri;
import com.google.android.exoplayer2.C;
import java.nio.charset.Charset;
/** /** Data for DASH downloading tests. */
* Data for DASH downloading tests.
*/
/* package */ interface DashDownloadTestData { /* package */ interface DashDownloadTestData {
Uri TEST_MPD_URI = Uri.parse("test.mpd"); Uri TEST_MPD_URI = Uri.parse("test.mpd");
...@@ -40,7 +40,8 @@ import android.net.Uri; ...@@ -40,7 +40,8 @@ import android.net.Uri;
+ " <Representation>\n" + " <Representation>\n"
+ " <SegmentList>\n" + " <SegmentList>\n"
// Bounded range data // Bounded range data
+ " <Initialization range=\"0-9\" sourceURL=\"audio_init_data\" />\n" + " <Initialization\n"
+ " range=\"0-9\" sourceURL=\"audio_init_data\" />\n"
// Unbounded range data // Unbounded range data
+ " <SegmentURL media=\"audio_segment_1\" />\n" + " <SegmentURL media=\"audio_segment_1\" />\n"
+ " <SegmentURL media=\"audio_segment_2\" />\n" + " <SegmentURL media=\"audio_segment_2\" />\n"
...@@ -84,7 +85,8 @@ import android.net.Uri; ...@@ -84,7 +85,8 @@ import android.net.Uri;
+ " </Representation>\n" + " </Representation>\n"
+ " </AdaptationSet>\n" + " </AdaptationSet>\n"
+ " </Period>\n" + " </Period>\n"
+ "</MPD>").getBytes(); + "</MPD>")
.getBytes(Charset.forName(C.UTF8_NAME));
byte[] TEST_MPD_NO_INDEX = byte[] TEST_MPD_NO_INDEX =
("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
...@@ -96,5 +98,6 @@ import android.net.Uri; ...@@ -96,5 +98,6 @@ import android.net.Uri;
+ " </Representation>\n" + " </Representation>\n"
+ " </AdaptationSet>\n" + " </AdaptationSet>\n"
+ " </Period>\n" + " </Period>\n"
+ "</MPD>").getBytes(); + "</MPD>")
.getBytes(Charset.forName(C.UTF8_NAME));
} }
...@@ -23,26 +23,33 @@ import static com.google.common.truth.Truth.assertThat; ...@@ -23,26 +23,33 @@ import static com.google.common.truth.Truth.assertThat;
import android.content.Context; import android.content.Context;
import android.os.ConditionVariable; import android.os.ConditionVariable;
import android.test.InstrumentationTestCase;
import android.test.UiThreadTest;
import com.google.android.exoplayer2.offline.DownloadManager; import com.google.android.exoplayer2.offline.DownloadManager;
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper; import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
import com.google.android.exoplayer2.source.dash.manifest.RepresentationKey; import com.google.android.exoplayer2.source.dash.manifest.RepresentationKey;
import com.google.android.exoplayer2.testutil.DummyMainThread; import com.google.android.exoplayer2.testutil.DummyMainThread;
import com.google.android.exoplayer2.testutil.FakeDataSet; import com.google.android.exoplayer2.testutil.FakeDataSet;
import com.google.android.exoplayer2.testutil.FakeDataSource; import com.google.android.exoplayer2.testutil.FakeDataSource;
import com.google.android.exoplayer2.testutil.MockitoUtil; import com.google.android.exoplayer2.testutil.RobolectricUtil;
import com.google.android.exoplayer2.testutil.TestUtil; import com.google.android.exoplayer2.testutil.TestUtil;
import com.google.android.exoplayer2.upstream.DataSource.Factory; import com.google.android.exoplayer2.upstream.DataSource.Factory;
import com.google.android.exoplayer2.upstream.cache.NoOpCacheEvictor; import com.google.android.exoplayer2.upstream.cache.NoOpCacheEvictor;
import com.google.android.exoplayer2.upstream.cache.SimpleCache; import com.google.android.exoplayer2.upstream.cache.SimpleCache;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import java.io.File; import java.io.File;
import org.junit.After;
/** import org.junit.Before;
* Tests {@link DownloadManager}. import org.junit.Ignore;
*/ import org.junit.Test;
public class DownloadManagerDashTest extends InstrumentationTestCase { import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
/** Tests {@link DownloadManager}. */
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {RobolectricUtil.CustomLooper.class, RobolectricUtil.CustomMessageQueue.class})
public class DownloadManagerDashTest {
private static final int ASSERT_TRUE_TIMEOUT = 1000; private static final int ASSERT_TRUE_TIMEOUT = 1000;
...@@ -56,18 +63,17 @@ public class DownloadManagerDashTest extends InstrumentationTestCase { ...@@ -56,18 +63,17 @@ public class DownloadManagerDashTest extends InstrumentationTestCase {
private File actionFile; private File actionFile;
private DummyMainThread dummyMainThread; private DummyMainThread dummyMainThread;
@UiThreadTest @Before
@Override
public void setUp() throws Exception { public void setUp() throws Exception {
super.setUp();
dummyMainThread = new DummyMainThread(); dummyMainThread = new DummyMainThread();
Context context = getInstrumentation().getContext(); Context context = RuntimeEnvironment.application;
tempFolder = Util.createTempDirectory(context, "ExoPlayerTest"); tempFolder = Util.createTempDirectory(context, "ExoPlayerTest");
File cacheFolder = new File(tempFolder, "cache"); File cacheFolder = new File(tempFolder, "cache");
cacheFolder.mkdir(); cacheFolder.mkdir();
cache = new SimpleCache(cacheFolder, new NoOpCacheEvictor()); cache = new SimpleCache(cacheFolder, new NoOpCacheEvictor());
MockitoUtil.setUpMockito(this); MockitoAnnotations.initMocks(this);
fakeDataSet = new FakeDataSet() fakeDataSet =
new FakeDataSet()
.setData(TEST_MPD_URI, TEST_MPD) .setData(TEST_MPD_URI, TEST_MPD)
.setRandomData("audio_init_data", 10) .setRandomData("audio_init_data", 10)
.setRandomData("audio_segment_1", 4) .setRandomData("audio_segment_1", 4)
...@@ -83,20 +89,22 @@ public class DownloadManagerDashTest extends InstrumentationTestCase { ...@@ -83,20 +89,22 @@ public class DownloadManagerDashTest extends InstrumentationTestCase {
createDownloadManager(); createDownloadManager();
} }
@UiThreadTest @After
@Override
public void tearDown() throws Exception { public void tearDown() throws Exception {
downloadManager.release(); downloadManager.release();
Util.recursiveDelete(tempFolder); Util.recursiveDelete(tempFolder);
dummyMainThread.release(); dummyMainThread.release();
super.tearDown();
} }
// Disabled due to flakiness. // Disabled due to flakiness.
public void disabledTestSaveAndLoadActionFile() throws Throwable { @Ignore
@Test
public void testSaveAndLoadActionFile() throws Throwable {
// Configure fakeDataSet to block until interrupted when TEST_MPD is read. // Configure fakeDataSet to block until interrupted when TEST_MPD is read.
fakeDataSet.newData(TEST_MPD_URI) fakeDataSet
.appendReadAction(new Runnable() { .newData(TEST_MPD_URI)
.appendReadAction(
new Runnable() {
@SuppressWarnings("InfiniteLoopStatement") @SuppressWarnings("InfiniteLoopStatement")
@Override @Override
public void run() { public void run() {
...@@ -122,15 +130,20 @@ public class DownloadManagerDashTest extends InstrumentationTestCase { ...@@ -122,15 +130,20 @@ public class DownloadManagerDashTest extends InstrumentationTestCase {
// Setup an Action and immediately release the DM. // Setup an Action and immediately release the DM.
handleDownloadAction(fakeRepresentationKey1, fakeRepresentationKey2); handleDownloadAction(fakeRepresentationKey1, fakeRepresentationKey2);
downloadManager.release(); downloadManager.release();
}
});
assertThat(actionFile.exists()).isTrue(); assertThat(actionFile.exists()).isTrue();
assertThat(actionFile.length()).isGreaterThan(0L); assertThat(actionFile.length()).isGreaterThan(0L);
assertCacheEmpty(cache); assertCacheEmpty(cache);
// Revert fakeDataSet to normal. // Revert fakeDataSet to normal.
fakeDataSet.setData(TEST_MPD_URI, TEST_MPD); fakeDataSet.setData(TEST_MPD_URI, TEST_MPD);
dummyMainThread.runOnMainThread(
new Runnable() {
@Override
public void run() {
createDownloadManager(); createDownloadManager();
} }
}); });
...@@ -140,12 +153,14 @@ public class DownloadManagerDashTest extends InstrumentationTestCase { ...@@ -140,12 +153,14 @@ public class DownloadManagerDashTest extends InstrumentationTestCase {
assertCachedData(cache, fakeDataSet); assertCachedData(cache, fakeDataSet);
} }
@Test
public void testHandleDownloadAction() throws Throwable { public void testHandleDownloadAction() throws Throwable {
handleDownloadAction(fakeRepresentationKey1, fakeRepresentationKey2); handleDownloadAction(fakeRepresentationKey1, fakeRepresentationKey2);
blockUntilTasksCompleteAndThrowAnyDownloadError(); blockUntilTasksCompleteAndThrowAnyDownloadError();
assertCachedData(cache, fakeDataSet); assertCachedData(cache, fakeDataSet);
} }
@Test
public void testHandleMultipleDownloadAction() throws Throwable { public void testHandleMultipleDownloadAction() throws Throwable {
handleDownloadAction(fakeRepresentationKey1); handleDownloadAction(fakeRepresentationKey1);
handleDownloadAction(fakeRepresentationKey2); handleDownloadAction(fakeRepresentationKey2);
...@@ -153,6 +168,7 @@ public class DownloadManagerDashTest extends InstrumentationTestCase { ...@@ -153,6 +168,7 @@ public class DownloadManagerDashTest extends InstrumentationTestCase {
assertCachedData(cache, fakeDataSet); assertCachedData(cache, fakeDataSet);
} }
@Test
public void testHandleInterferingDownloadAction() throws Throwable { public void testHandleInterferingDownloadAction() throws Throwable {
fakeDataSet fakeDataSet
.newData("audio_segment_2") .newData("audio_segment_2")
...@@ -172,6 +188,7 @@ public class DownloadManagerDashTest extends InstrumentationTestCase { ...@@ -172,6 +188,7 @@ public class DownloadManagerDashTest extends InstrumentationTestCase {
assertCachedData(cache, fakeDataSet); assertCachedData(cache, fakeDataSet);
} }
@Test
public void testHandleRemoveAction() throws Throwable { public void testHandleRemoveAction() throws Throwable {
handleDownloadAction(fakeRepresentationKey1); handleDownloadAction(fakeRepresentationKey1);
...@@ -185,7 +202,9 @@ public class DownloadManagerDashTest extends InstrumentationTestCase { ...@@ -185,7 +202,9 @@ public class DownloadManagerDashTest extends InstrumentationTestCase {
} }
// Disabled due to flakiness. // Disabled due to flakiness.
public void disabledTestHandleRemoveActionBeforeDownloadFinish() throws Throwable { @Ignore
@Test
public void testHandleRemoveActionBeforeDownloadFinish() throws Throwable {
handleDownloadAction(fakeRepresentationKey1); handleDownloadAction(fakeRepresentationKey1);
handleRemoveAction(); handleRemoveAction();
...@@ -194,10 +213,13 @@ public class DownloadManagerDashTest extends InstrumentationTestCase { ...@@ -194,10 +213,13 @@ public class DownloadManagerDashTest extends InstrumentationTestCase {
assertCacheEmpty(cache); assertCacheEmpty(cache);
} }
@Test
public void testHandleInterferingRemoveAction() throws Throwable { public void testHandleInterferingRemoveAction() throws Throwable {
final ConditionVariable downloadInProgressCondition = new ConditionVariable(); final ConditionVariable downloadInProgressCondition = new ConditionVariable();
fakeDataSet.newData("audio_segment_2") fakeDataSet
.appendReadAction(new Runnable() { .newData("audio_segment_2")
.appendReadAction(
new Runnable() {
@Override @Override
public void run() { public void run() {
downloadInProgressCondition.open(); downloadInProgressCondition.open();
...@@ -250,5 +272,4 @@ public class DownloadManagerDashTest extends InstrumentationTestCase { ...@@ -250,5 +272,4 @@ public class DownloadManagerDashTest extends InstrumentationTestCase {
} }
}); });
} }
} }
...@@ -22,7 +22,6 @@ import static com.google.android.exoplayer2.testutil.CacheAsserts.assertCachedDa ...@@ -22,7 +22,6 @@ import static com.google.android.exoplayer2.testutil.CacheAsserts.assertCachedDa
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.test.InstrumentationTestCase;
import com.google.android.exoplayer2.offline.DownloadManager; import com.google.android.exoplayer2.offline.DownloadManager;
import com.google.android.exoplayer2.offline.DownloadService; import com.google.android.exoplayer2.offline.DownloadService;
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper; import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
...@@ -32,6 +31,7 @@ import com.google.android.exoplayer2.source.dash.manifest.RepresentationKey; ...@@ -32,6 +31,7 @@ import com.google.android.exoplayer2.source.dash.manifest.RepresentationKey;
import com.google.android.exoplayer2.testutil.DummyMainThread; import com.google.android.exoplayer2.testutil.DummyMainThread;
import com.google.android.exoplayer2.testutil.FakeDataSet; import com.google.android.exoplayer2.testutil.FakeDataSet;
import com.google.android.exoplayer2.testutil.FakeDataSource; import com.google.android.exoplayer2.testutil.FakeDataSource;
import com.google.android.exoplayer2.testutil.RobolectricUtil;
import com.google.android.exoplayer2.testutil.TestUtil; import com.google.android.exoplayer2.testutil.TestUtil;
import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.cache.NoOpCacheEvictor; import com.google.android.exoplayer2.upstream.cache.NoOpCacheEvictor;
...@@ -40,11 +40,18 @@ import com.google.android.exoplayer2.util.ConditionVariable; ...@@ -40,11 +40,18 @@ import com.google.android.exoplayer2.util.ConditionVariable;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import org.junit.After;
/** import org.junit.Before;
* Unit tests for {@link DownloadService}. import org.junit.Test;
*/ import org.junit.runner.RunWith;
public class DownloadServiceDashTest extends InstrumentationTestCase { import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
/** Unit tests for {@link DownloadService}. */
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {RobolectricUtil.CustomLooper.class, RobolectricUtil.CustomMessageQueue.class})
public class DownloadServiceDashTest {
private SimpleCache cache; private SimpleCache cache;
private File tempFolder; private File tempFolder;
...@@ -57,14 +64,15 @@ public class DownloadServiceDashTest extends InstrumentationTestCase { ...@@ -57,14 +64,15 @@ public class DownloadServiceDashTest extends InstrumentationTestCase {
private TestDownloadListener testDownloadListener; private TestDownloadListener testDownloadListener;
private DummyMainThread dummyMainThread; private DummyMainThread dummyMainThread;
@Override @Before
public void setUp() throws Exception { public void setUp() throws Exception {
super.setUp();
dummyMainThread = new DummyMainThread(); dummyMainThread = new DummyMainThread();
tempFolder = Util.createTempDirectory(getInstrumentation().getContext(), "ExoPlayerTest"); context = RuntimeEnvironment.application;
tempFolder = Util.createTempDirectory(context, "ExoPlayerTest");
cache = new SimpleCache(tempFolder, new NoOpCacheEvictor()); cache = new SimpleCache(tempFolder, new NoOpCacheEvictor());
Runnable pauseAction = new Runnable() { Runnable pauseAction =
new Runnable() {
@Override @Override
public void run() { public void run() {
if (pauseDownloadCondition != null) { if (pauseDownloadCondition != null) {
...@@ -76,7 +84,8 @@ public class DownloadServiceDashTest extends InstrumentationTestCase { ...@@ -76,7 +84,8 @@ public class DownloadServiceDashTest extends InstrumentationTestCase {
} }
} }
}; };
fakeDataSet = new FakeDataSet() fakeDataSet =
new FakeDataSet()
.setData(TEST_MPD_URI, TEST_MPD) .setData(TEST_MPD_URI, TEST_MPD)
.newData("audio_init_data") .newData("audio_init_data")
.appendReadAction(pauseAction) .appendReadAction(pauseAction)
...@@ -93,8 +102,6 @@ public class DownloadServiceDashTest extends InstrumentationTestCase { ...@@ -93,8 +102,6 @@ public class DownloadServiceDashTest extends InstrumentationTestCase {
fakeRepresentationKey1 = new RepresentationKey(0, 0, 0); fakeRepresentationKey1 = new RepresentationKey(0, 0, 0);
fakeRepresentationKey2 = new RepresentationKey(0, 1, 0); fakeRepresentationKey2 = new RepresentationKey(0, 1, 0);
context = getInstrumentation().getContext();
try { try {
dummyMainThread.runOnMainThread( dummyMainThread.runOnMainThread(
new Runnable() { new Runnable() {
...@@ -128,7 +135,7 @@ public class DownloadServiceDashTest extends InstrumentationTestCase { ...@@ -128,7 +135,7 @@ public class DownloadServiceDashTest extends InstrumentationTestCase {
@Override @Override
protected String getNotificationChannelId() { protected String getNotificationChannelId() {
return null; return "";
} }
@Override @Override
...@@ -149,7 +156,7 @@ public class DownloadServiceDashTest extends InstrumentationTestCase { ...@@ -149,7 +156,7 @@ public class DownloadServiceDashTest extends InstrumentationTestCase {
} }
} }
@Override @After
public void tearDown() throws Exception { public void tearDown() throws Exception {
try { try {
dummyMainThread.runOnMainThread( dummyMainThread.runOnMainThread(
...@@ -164,9 +171,9 @@ public class DownloadServiceDashTest extends InstrumentationTestCase { ...@@ -164,9 +171,9 @@ public class DownloadServiceDashTest extends InstrumentationTestCase {
} }
Util.recursiveDelete(tempFolder); Util.recursiveDelete(tempFolder);
dummyMainThread.release(); dummyMainThread.release();
super.tearDown();
} }
@Test
public void testMultipleDownloadAction() throws Throwable { public void testMultipleDownloadAction() throws Throwable {
downloadKeys(fakeRepresentationKey1); downloadKeys(fakeRepresentationKey1);
downloadKeys(fakeRepresentationKey2); downloadKeys(fakeRepresentationKey2);
...@@ -176,6 +183,7 @@ public class DownloadServiceDashTest extends InstrumentationTestCase { ...@@ -176,6 +183,7 @@ public class DownloadServiceDashTest extends InstrumentationTestCase {
assertCachedData(cache, fakeDataSet); assertCachedData(cache, fakeDataSet);
} }
@Test
public void testRemoveAction() throws Throwable { public void testRemoveAction() throws Throwable {
downloadKeys(fakeRepresentationKey1, fakeRepresentationKey2); downloadKeys(fakeRepresentationKey1, fakeRepresentationKey2);
...@@ -188,6 +196,7 @@ public class DownloadServiceDashTest extends InstrumentationTestCase { ...@@ -188,6 +196,7 @@ public class DownloadServiceDashTest extends InstrumentationTestCase {
assertCacheEmpty(cache); assertCacheEmpty(cache);
} }
@Test
public void testRemoveBeforeDownloadComplete() throws Throwable { public void testRemoveBeforeDownloadComplete() throws Throwable {
pauseDownloadCondition = new ConditionVariable(); pauseDownloadCondition = new ConditionVariable();
downloadKeys(fakeRepresentationKey1, fakeRepresentationKey2); downloadKeys(fakeRepresentationKey1, fakeRepresentationKey2);
...@@ -219,5 +228,4 @@ public class DownloadServiceDashTest extends InstrumentationTestCase { ...@@ -219,5 +228,4 @@ public class DownloadServiceDashTest extends InstrumentationTestCase {
} }
}); });
} }
} }
...@@ -21,6 +21,8 @@ import com.google.android.exoplayer2.offline.DownloadManager; ...@@ -21,6 +21,8 @@ import com.google.android.exoplayer2.offline.DownloadManager;
import com.google.android.exoplayer2.offline.DownloadManager.DownloadListener; import com.google.android.exoplayer2.offline.DownloadManager.DownloadListener;
import com.google.android.exoplayer2.offline.DownloadManager.DownloadState; import com.google.android.exoplayer2.offline.DownloadManager.DownloadState;
import com.google.android.exoplayer2.testutil.DummyMainThread; import com.google.android.exoplayer2.testutil.DummyMainThread;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/** A {@link DownloadListener} for testing. */ /** A {@link DownloadListener} for testing. */
/*package*/ final class TestDownloadListener implements DownloadListener { /*package*/ final class TestDownloadListener implements DownloadListener {
...@@ -29,13 +31,12 @@ import com.google.android.exoplayer2.testutil.DummyMainThread; ...@@ -29,13 +31,12 @@ import com.google.android.exoplayer2.testutil.DummyMainThread;
private final DownloadManager downloadManager; private final DownloadManager downloadManager;
private final DummyMainThread dummyMainThread; private final DummyMainThread dummyMainThread;
private final android.os.ConditionVariable downloadFinishedCondition; private CountDownLatch downloadFinishedCondition;
private Throwable downloadError; private Throwable downloadError;
public TestDownloadListener(DownloadManager downloadManager, DummyMainThread dummyMainThread) { public TestDownloadListener(DownloadManager downloadManager, DummyMainThread dummyMainThread) {
this.downloadManager = downloadManager; this.downloadManager = downloadManager;
this.dummyMainThread = dummyMainThread; this.dummyMainThread = dummyMainThread;
this.downloadFinishedCondition = new android.os.ConditionVariable();
} }
@Override @Override
...@@ -46,8 +47,10 @@ import com.google.android.exoplayer2.testutil.DummyMainThread; ...@@ -46,8 +47,10 @@ import com.google.android.exoplayer2.testutil.DummyMainThread;
} }
@Override @Override
public void onIdle(DownloadManager downloadManager) { public synchronized void onIdle(DownloadManager downloadManager) {
downloadFinishedCondition.open(); if (downloadFinishedCondition != null) {
downloadFinishedCondition.countDown();
}
} }
/** /**
...@@ -55,18 +58,19 @@ import com.google.android.exoplayer2.testutil.DummyMainThread; ...@@ -55,18 +58,19 @@ import com.google.android.exoplayer2.testutil.DummyMainThread;
* error. * error.
*/ */
public void blockUntilTasksCompleteAndThrowAnyDownloadError() throws Throwable { public void blockUntilTasksCompleteAndThrowAnyDownloadError() throws Throwable {
synchronized (this) {
downloadFinishedCondition = new CountDownLatch(1);
}
dummyMainThread.runOnMainThread( dummyMainThread.runOnMainThread(
new Runnable() { new Runnable() {
@Override @Override
public void run() { public void run() {
if (downloadManager.isIdle()) { if (downloadManager.isIdle()) {
downloadFinishedCondition.open(); downloadFinishedCondition.countDown();
} else {
downloadFinishedCondition.close();
} }
} }
}); });
assertThat(downloadFinishedCondition.block(TIMEOUT)).isTrue(); assertThat(downloadFinishedCondition.await(TIMEOUT, TimeUnit.MILLISECONDS)).isTrue();
if (downloadError != null) { if (downloadError != null) {
throw new Exception(downloadError); throw new Exception(downloadError);
} }
......
...@@ -35,10 +35,7 @@ android { ...@@ -35,10 +35,7 @@ android {
dependencies { dependencies {
compile project(modulePrefix + 'library-core') compile project(modulePrefix + 'library-core')
compile 'com.android.support:support-annotations:' + supportLibraryVersion compile 'com.android.support:support-annotations:' + supportLibraryVersion
androidTestCompile project(modulePrefix + 'testutils') testCompile project(modulePrefix + 'testutils-robolectric')
androidTestCompile 'com.google.dexmaker:dexmaker:' + dexmakerVersion
androidTestCompile 'com.google.dexmaker:dexmaker-mockito:' + dexmakerVersion
androidTestCompile 'org.mockito:mockito-core:' + mockitoVersion
} }
ext { ext {
......
...@@ -18,16 +18,6 @@ ...@@ -18,16 +18,6 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
package="com.google.android.exoplayer2.source.hls.test"> package="com.google.android.exoplayer2.source.hls.test">
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="27"/> <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="26"/>
<application android:debuggable="true"
android:allowBackup="false"
tools:ignore="MissingApplicationIcon,HardcodedDebugMode">
<uses-library android:name="android.test.runner"/>
</application>
<instrumentation
android:targetPackage="com.google.android.exoplayer2.source.hls.test"
android:name="android.test.InstrumentationTestRunner"/>
</manifest> </manifest>
...@@ -15,9 +15,10 @@ ...@@ -15,9 +15,10 @@
*/ */
package com.google.android.exoplayer2.source.hls.offline; package com.google.android.exoplayer2.source.hls.offline;
/** import com.google.android.exoplayer2.C;
* Data for HLS downloading tests. import java.nio.charset.Charset;
*/
/** Data for HLS downloading tests. */
/* package */ interface HlsDownloadTestData { /* package */ interface HlsDownloadTestData {
String MASTER_PLAYLIST_URI = "test.m3u8"; String MASTER_PLAYLIST_URI = "test.m3u8";
...@@ -34,13 +35,17 @@ package com.google.android.exoplayer2.source.hls.offline; ...@@ -34,13 +35,17 @@ package com.google.android.exoplayer2.source.hls.offline;
byte[] MASTER_PLAYLIST_DATA = byte[] MASTER_PLAYLIST_DATA =
("#EXTM3U\n" ("#EXTM3U\n"
+ "#EXT-X-STREAM-INF:BANDWIDTH=232370,CODECS=\"mp4a.40.2, avc1.4d4015\"\n" + "#EXT-X-STREAM-INF:BANDWIDTH=232370,CODECS=\"mp4a.40.2, avc1.4d4015\"\n"
+ MEDIA_PLAYLIST_1_URI + "\n" + MEDIA_PLAYLIST_1_URI
+ "\n"
+ "#EXT-X-STREAM-INF:BANDWIDTH=649879,CODECS=\"mp4a.40.2, avc1.4d401e\"\n" + "#EXT-X-STREAM-INF:BANDWIDTH=649879,CODECS=\"mp4a.40.2, avc1.4d401e\"\n"
+ MEDIA_PLAYLIST_2_URI + "\n" + MEDIA_PLAYLIST_2_URI
+ "\n"
+ "#EXT-X-STREAM-INF:BANDWIDTH=991714,CODECS=\"mp4a.40.2, avc1.4d401e\"\n" + "#EXT-X-STREAM-INF:BANDWIDTH=991714,CODECS=\"mp4a.40.2, avc1.4d401e\"\n"
+ MEDIA_PLAYLIST_3_URI + "\n" + MEDIA_PLAYLIST_3_URI
+ "\n"
+ "#EXT-X-STREAM-INF:BANDWIDTH=41457,CODECS=\"mp4a.40.2\"\n" + "#EXT-X-STREAM-INF:BANDWIDTH=41457,CODECS=\"mp4a.40.2\"\n"
+ MEDIA_PLAYLIST_0_URI).getBytes(); + MEDIA_PLAYLIST_0_URI)
.getBytes(Charset.forName(C.UTF8_NAME));
byte[] MEDIA_PLAYLIST_DATA = byte[] MEDIA_PLAYLIST_DATA =
("#EXTM3U\n" ("#EXTM3U\n"
...@@ -54,7 +59,8 @@ package com.google.android.exoplayer2.source.hls.offline; ...@@ -54,7 +59,8 @@ package com.google.android.exoplayer2.source.hls.offline;
+ "fileSequence1.ts\n" + "fileSequence1.ts\n"
+ "#EXTINF:9.97667,\n" + "#EXTINF:9.97667,\n"
+ "fileSequence2.ts\n" + "fileSequence2.ts\n"
+ "#EXT-X-ENDLIST").getBytes(); + "#EXT-X-ENDLIST")
.getBytes(Charset.forName(C.UTF8_NAME));
String ENC_MEDIA_PLAYLIST_URI = "enc_index.m3u8"; String ENC_MEDIA_PLAYLIST_URI = "enc_index.m3u8";
...@@ -72,6 +78,6 @@ package com.google.android.exoplayer2.source.hls.offline; ...@@ -72,6 +78,6 @@ package com.google.android.exoplayer2.source.hls.offline;
+ "#EXT-X-KEY:METHOD=AES-128,URI=\"enc2.key\"\n" + "#EXT-X-KEY:METHOD=AES-128,URI=\"enc2.key\"\n"
+ "#EXTINF:9.97667,\n" + "#EXTINF:9.97667,\n"
+ "fileSequence2.ts\n" + "fileSequence2.ts\n"
+ "#EXT-X-ENDLIST").getBytes(); + "#EXT-X-ENDLIST")
.getBytes(Charset.forName(C.UTF8_NAME));
} }
...@@ -33,7 +33,6 @@ import static com.google.android.exoplayer2.testutil.CacheAsserts.assertCachedDa ...@@ -33,7 +33,6 @@ import static com.google.android.exoplayer2.testutil.CacheAsserts.assertCachedDa
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import android.net.Uri; import android.net.Uri;
import android.test.InstrumentationTestCase;
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper; import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist; import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist;
import com.google.android.exoplayer2.testutil.FakeDataSet; import com.google.android.exoplayer2.testutil.FakeDataSet;
...@@ -42,22 +41,29 @@ import com.google.android.exoplayer2.upstream.cache.NoOpCacheEvictor; ...@@ -42,22 +41,29 @@ import com.google.android.exoplayer2.upstream.cache.NoOpCacheEvictor;
import com.google.android.exoplayer2.upstream.cache.SimpleCache; import com.google.android.exoplayer2.upstream.cache.SimpleCache;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import java.io.File; import java.io.File;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
/** Unit tests for {@link HlsDownloader}. */ /** Unit tests for {@link HlsDownloader}. */
public class HlsDownloaderTest extends InstrumentationTestCase { @RunWith(RobolectricTestRunner.class)
public class HlsDownloaderTest {
private SimpleCache cache; private SimpleCache cache;
private File tempFolder; private File tempFolder;
private FakeDataSet fakeDataSet; private FakeDataSet fakeDataSet;
private HlsDownloader hlsDownloader; private HlsDownloader hlsDownloader;
@Override @Before
public void setUp() throws Exception { public void setUp() throws Exception {
super.setUp(); tempFolder = Util.createTempDirectory(RuntimeEnvironment.application, "ExoPlayerTest");
tempFolder = Util.createTempDirectory(getInstrumentation().getContext(), "ExoPlayerTest");
cache = new SimpleCache(tempFolder, new NoOpCacheEvictor()); cache = new SimpleCache(tempFolder, new NoOpCacheEvictor());
fakeDataSet = new FakeDataSet() fakeDataSet =
new FakeDataSet()
.setData(MASTER_PLAYLIST_URI, MASTER_PLAYLIST_DATA) .setData(MASTER_PLAYLIST_URI, MASTER_PLAYLIST_DATA)
.setData(MEDIA_PLAYLIST_1_URI, MEDIA_PLAYLIST_DATA) .setData(MEDIA_PLAYLIST_1_URI, MEDIA_PLAYLIST_DATA)
.setRandomData(MEDIA_PLAYLIST_1_DIR + "fileSequence0.ts", 10) .setRandomData(MEDIA_PLAYLIST_1_DIR + "fileSequence0.ts", 10)
...@@ -70,12 +76,12 @@ public class HlsDownloaderTest extends InstrumentationTestCase { ...@@ -70,12 +76,12 @@ public class HlsDownloaderTest extends InstrumentationTestCase {
hlsDownloader = getHlsDownloader(MASTER_PLAYLIST_URI); hlsDownloader = getHlsDownloader(MASTER_PLAYLIST_URI);
} }
@Override @After
public void tearDown() throws Exception { public void tearDown() throws Exception {
Util.recursiveDelete(tempFolder); Util.recursiveDelete(tempFolder);
super.tearDown();
} }
@Test
public void testDownloadManifest() throws Exception { public void testDownloadManifest() throws Exception {
HlsMasterPlaylist manifest = hlsDownloader.getManifest(); HlsMasterPlaylist manifest = hlsDownloader.getManifest();
...@@ -83,17 +89,23 @@ public class HlsDownloaderTest extends InstrumentationTestCase { ...@@ -83,17 +89,23 @@ public class HlsDownloaderTest extends InstrumentationTestCase {
assertCachedData(cache, fakeDataSet, MASTER_PLAYLIST_URI); assertCachedData(cache, fakeDataSet, MASTER_PLAYLIST_URI);
} }
@Test
public void testSelectRepresentationsClearsPreviousSelection() throws Exception { public void testSelectRepresentationsClearsPreviousSelection() throws Exception {
hlsDownloader.selectRepresentations(new String[] {MEDIA_PLAYLIST_1_URI}); hlsDownloader.selectRepresentations(new String[] {MEDIA_PLAYLIST_1_URI});
hlsDownloader.selectRepresentations(new String[] {MEDIA_PLAYLIST_2_URI}); hlsDownloader.selectRepresentations(new String[] {MEDIA_PLAYLIST_2_URI});
hlsDownloader.download(null); hlsDownloader.download(null);
assertCachedData(cache, fakeDataSet, MASTER_PLAYLIST_URI, MEDIA_PLAYLIST_2_URI, assertCachedData(
cache,
fakeDataSet,
MASTER_PLAYLIST_URI,
MEDIA_PLAYLIST_2_URI,
MEDIA_PLAYLIST_2_DIR + "fileSequence0.ts", MEDIA_PLAYLIST_2_DIR + "fileSequence0.ts",
MEDIA_PLAYLIST_2_DIR + "fileSequence1.ts", MEDIA_PLAYLIST_2_DIR + "fileSequence1.ts",
MEDIA_PLAYLIST_2_DIR + "fileSequence2.ts"); MEDIA_PLAYLIST_2_DIR + "fileSequence2.ts");
} }
@Test
public void testCounterMethods() throws Exception { public void testCounterMethods() throws Exception {
hlsDownloader.selectRepresentations(new String[] {MEDIA_PLAYLIST_1_URI}); hlsDownloader.selectRepresentations(new String[] {MEDIA_PLAYLIST_1_URI});
hlsDownloader.download(null); hlsDownloader.download(null);
...@@ -104,12 +116,12 @@ public class HlsDownloaderTest extends InstrumentationTestCase { ...@@ -104,12 +116,12 @@ public class HlsDownloaderTest extends InstrumentationTestCase {
.isEqualTo(MEDIA_PLAYLIST_DATA.length + 10 + 11 + 12); .isEqualTo(MEDIA_PLAYLIST_DATA.length + 10 + 11 + 12);
} }
@Test
public void testInitStatus() throws Exception { public void testInitStatus() throws Exception {
hlsDownloader.selectRepresentations(new String[] {MEDIA_PLAYLIST_1_URI}); hlsDownloader.selectRepresentations(new String[] {MEDIA_PLAYLIST_1_URI});
hlsDownloader.download(null); hlsDownloader.download(null);
HlsDownloader newHlsDownloader = HlsDownloader newHlsDownloader = getHlsDownloader(MASTER_PLAYLIST_URI);
getHlsDownloader(MASTER_PLAYLIST_URI);
newHlsDownloader.selectRepresentations(new String[] {MEDIA_PLAYLIST_1_URI}); newHlsDownloader.selectRepresentations(new String[] {MEDIA_PLAYLIST_1_URI});
newHlsDownloader.init(); newHlsDownloader.init();
...@@ -119,16 +131,22 @@ public class HlsDownloaderTest extends InstrumentationTestCase { ...@@ -119,16 +131,22 @@ public class HlsDownloaderTest extends InstrumentationTestCase {
.isEqualTo(MEDIA_PLAYLIST_DATA.length + 10 + 11 + 12); .isEqualTo(MEDIA_PLAYLIST_DATA.length + 10 + 11 + 12);
} }
@Test
public void testDownloadRepresentation() throws Exception { public void testDownloadRepresentation() throws Exception {
hlsDownloader.selectRepresentations(new String[] {MEDIA_PLAYLIST_1_URI}); hlsDownloader.selectRepresentations(new String[] {MEDIA_PLAYLIST_1_URI});
hlsDownloader.download(null); hlsDownloader.download(null);
assertCachedData(cache, fakeDataSet, MASTER_PLAYLIST_URI, MEDIA_PLAYLIST_1_URI, assertCachedData(
cache,
fakeDataSet,
MASTER_PLAYLIST_URI,
MEDIA_PLAYLIST_1_URI,
MEDIA_PLAYLIST_1_DIR + "fileSequence0.ts", MEDIA_PLAYLIST_1_DIR + "fileSequence0.ts",
MEDIA_PLAYLIST_1_DIR + "fileSequence1.ts", MEDIA_PLAYLIST_1_DIR + "fileSequence1.ts",
MEDIA_PLAYLIST_1_DIR + "fileSequence2.ts"); MEDIA_PLAYLIST_1_DIR + "fileSequence2.ts");
} }
@Test
public void testDownloadMultipleRepresentations() throws Exception { public void testDownloadMultipleRepresentations() throws Exception {
hlsDownloader.selectRepresentations(new String[] {MEDIA_PLAYLIST_1_URI, MEDIA_PLAYLIST_2_URI}); hlsDownloader.selectRepresentations(new String[] {MEDIA_PLAYLIST_1_URI, MEDIA_PLAYLIST_2_URI});
hlsDownloader.download(null); hlsDownloader.download(null);
...@@ -136,9 +154,11 @@ public class HlsDownloaderTest extends InstrumentationTestCase { ...@@ -136,9 +154,11 @@ public class HlsDownloaderTest extends InstrumentationTestCase {
assertCachedData(cache, fakeDataSet); assertCachedData(cache, fakeDataSet);
} }
@Test
public void testDownloadAllRepresentations() throws Exception { public void testDownloadAllRepresentations() throws Exception {
// Add data for the rest of the playlists // Add data for the rest of the playlists
fakeDataSet.setData(MEDIA_PLAYLIST_0_URI, MEDIA_PLAYLIST_DATA) fakeDataSet
.setData(MEDIA_PLAYLIST_0_URI, MEDIA_PLAYLIST_DATA)
.setRandomData(MEDIA_PLAYLIST_0_DIR + "fileSequence0.ts", 10) .setRandomData(MEDIA_PLAYLIST_0_DIR + "fileSequence0.ts", 10)
.setRandomData(MEDIA_PLAYLIST_0_DIR + "fileSequence1.ts", 11) .setRandomData(MEDIA_PLAYLIST_0_DIR + "fileSequence1.ts", 11)
.setRandomData(MEDIA_PLAYLIST_0_DIR + "fileSequence2.ts", 12) .setRandomData(MEDIA_PLAYLIST_0_DIR + "fileSequence2.ts", 12)
...@@ -162,6 +182,7 @@ public class HlsDownloaderTest extends InstrumentationTestCase { ...@@ -162,6 +182,7 @@ public class HlsDownloaderTest extends InstrumentationTestCase {
hlsDownloader.remove(); hlsDownloader.remove();
} }
@Test
public void testRemoveAll() throws Exception { public void testRemoveAll() throws Exception {
hlsDownloader.selectRepresentations(new String[] {MEDIA_PLAYLIST_1_URI, MEDIA_PLAYLIST_2_URI}); hlsDownloader.selectRepresentations(new String[] {MEDIA_PLAYLIST_1_URI, MEDIA_PLAYLIST_2_URI});
hlsDownloader.download(null); hlsDownloader.download(null);
...@@ -170,27 +191,32 @@ public class HlsDownloaderTest extends InstrumentationTestCase { ...@@ -170,27 +191,32 @@ public class HlsDownloaderTest extends InstrumentationTestCase {
assertCacheEmpty(cache); assertCacheEmpty(cache);
} }
@Test
public void testDownloadMediaPlaylist() throws Exception { public void testDownloadMediaPlaylist() throws Exception {
hlsDownloader = getHlsDownloader(MEDIA_PLAYLIST_1_URI); hlsDownloader = getHlsDownloader(MEDIA_PLAYLIST_1_URI);
hlsDownloader.selectRepresentations(new String[] {MEDIA_PLAYLIST_1_URI}); hlsDownloader.selectRepresentations(new String[] {MEDIA_PLAYLIST_1_URI});
hlsDownloader.download(null); hlsDownloader.download(null);
assertCachedData(cache, fakeDataSet, MEDIA_PLAYLIST_1_URI, assertCachedData(
cache,
fakeDataSet,
MEDIA_PLAYLIST_1_URI,
MEDIA_PLAYLIST_1_DIR + "fileSequence0.ts", MEDIA_PLAYLIST_1_DIR + "fileSequence0.ts",
MEDIA_PLAYLIST_1_DIR + "fileSequence1.ts", MEDIA_PLAYLIST_1_DIR + "fileSequence1.ts",
MEDIA_PLAYLIST_1_DIR + "fileSequence2.ts"); MEDIA_PLAYLIST_1_DIR + "fileSequence2.ts");
} }
@Test
public void testDownloadEncMediaPlaylist() throws Exception { public void testDownloadEncMediaPlaylist() throws Exception {
fakeDataSet = new FakeDataSet() fakeDataSet =
new FakeDataSet()
.setData(ENC_MEDIA_PLAYLIST_URI, ENC_MEDIA_PLAYLIST_DATA) .setData(ENC_MEDIA_PLAYLIST_URI, ENC_MEDIA_PLAYLIST_DATA)
.setRandomData("enc.key", 8) .setRandomData("enc.key", 8)
.setRandomData("enc2.key", 9) .setRandomData("enc2.key", 9)
.setRandomData("fileSequence0.ts", 10) .setRandomData("fileSequence0.ts", 10)
.setRandomData("fileSequence1.ts", 11) .setRandomData("fileSequence1.ts", 11)
.setRandomData("fileSequence2.ts", 12); .setRandomData("fileSequence2.ts", 12);
hlsDownloader = hlsDownloader = getHlsDownloader(ENC_MEDIA_PLAYLIST_URI);
getHlsDownloader(ENC_MEDIA_PLAYLIST_URI);
hlsDownloader.selectRepresentations(new String[] {ENC_MEDIA_PLAYLIST_URI}); hlsDownloader.selectRepresentations(new String[] {ENC_MEDIA_PLAYLIST_URI});
hlsDownloader.download(null); hlsDownloader.download(null);
...@@ -199,8 +225,7 @@ public class HlsDownloaderTest extends InstrumentationTestCase { ...@@ -199,8 +225,7 @@ public class HlsDownloaderTest extends InstrumentationTestCase {
private HlsDownloader getHlsDownloader(String mediaPlaylistUri) { private HlsDownloader getHlsDownloader(String mediaPlaylistUri) {
Factory factory = new Factory(null).setFakeDataSet(fakeDataSet); Factory factory = new Factory(null).setFakeDataSet(fakeDataSet);
return new HlsDownloader(Uri.parse(mediaPlaylistUri), return new HlsDownloader(
new DownloaderConstructorHelper(cache, factory)); Uri.parse(mediaPlaylistUri), new DownloaderConstructorHelper(cache, factory));
} }
} }
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
package com.google.android.exoplayer2.source.hls.playlist; package com.google.android.exoplayer2.source.hls.playlist;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
import android.net.Uri; import android.net.Uri;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
...@@ -26,18 +27,21 @@ import java.io.ByteArrayInputStream; ...@@ -26,18 +27,21 @@ import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.List; import java.util.List;
import junit.framework.TestCase; import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
/** /** Test for {@link HlsMasterPlaylistParserTest}. */
* Test for {@link HlsMasterPlaylistParserTest}. @RunWith(RobolectricTestRunner.class)
*/ public class HlsMasterPlaylistParserTest {
public class HlsMasterPlaylistParserTest extends TestCase {
private static final String PLAYLIST_URI = "https://example.com/test.m3u8"; private static final String PLAYLIST_URI = "https://example.com/test.m3u8";
private static final String PLAYLIST_SIMPLE = " #EXTM3U \n" private static final String PLAYLIST_SIMPLE =
" #EXTM3U \n"
+ "\n" + "\n"
+ "#EXT-X-STREAM-INF:BANDWIDTH=1280000,CODECS=\"mp4a.40.2,avc1.66.30\",RESOLUTION=304x128\n" + "#EXT-X-STREAM-INF:BANDWIDTH=1280000,"
+ "CODECS=\"mp4a.40.2,avc1.66.30\",RESOLUTION=304x128\n"
+ "http://example.com/low.m3u8\n" + "http://example.com/low.m3u8\n"
+ "\n" + "\n"
+ "#EXT-X-STREAM-INF:BANDWIDTH=1280000,CODECS=\"mp4a.40.2 , avc1.66.30 \"\n" + "#EXT-X-STREAM-INF:BANDWIDTH=1280000,CODECS=\"mp4a.40.2 , avc1.66.30 \"\n"
...@@ -52,31 +56,42 @@ public class HlsMasterPlaylistParserTest extends TestCase { ...@@ -52,31 +56,42 @@ public class HlsMasterPlaylistParserTest extends TestCase {
+ "#EXT-X-STREAM-INF:BANDWIDTH=65000,CODECS=\"mp4a.40.5\"\n" + "#EXT-X-STREAM-INF:BANDWIDTH=65000,CODECS=\"mp4a.40.5\"\n"
+ "http://example.com/audio-only.m3u8"; + "http://example.com/audio-only.m3u8";
private static final String PLAYLIST_WITH_AVG_BANDWIDTH = " #EXTM3U \n" private static final String PLAYLIST_WITH_AVG_BANDWIDTH =
" #EXTM3U \n"
+ "\n" + "\n"
+ "#EXT-X-STREAM-INF:BANDWIDTH=1280000,CODECS=\"mp4a.40.2,avc1.66.30\",RESOLUTION=304x128\n" + "#EXT-X-STREAM-INF:BANDWIDTH=1280000,"
+ "CODECS=\"mp4a.40.2,avc1.66.30\",RESOLUTION=304x128\n"
+ "http://example.com/low.m3u8\n" + "http://example.com/low.m3u8\n"
+ "\n" + "\n"
+ "#EXT-X-STREAM-INF:BANDWIDTH=1280000,AVERAGE-BANDWIDTH=1270000," + "#EXT-X-STREAM-INF:BANDWIDTH=1280000,AVERAGE-BANDWIDTH=1270000,"
+ "CODECS=\"mp4a.40.2 , avc1.66.30 \"\n" + "CODECS=\"mp4a.40.2 , avc1.66.30 \"\n"
+ "http://example.com/spaces_in_codecs.m3u8\n"; + "http://example.com/spaces_in_codecs.m3u8\n";
private static final String PLAYLIST_WITH_INVALID_HEADER = "#EXTMU3\n" private static final String PLAYLIST_WITH_INVALID_HEADER =
+ "#EXT-X-STREAM-INF:BANDWIDTH=1280000,CODECS=\"mp4a.40.2,avc1.66.30\",RESOLUTION=304x128\n" "#EXTMU3\n"
+ "#EXT-X-STREAM-INF:BANDWIDTH=1280000,"
+ "CODECS=\"mp4a.40.2,avc1.66.30\",RESOLUTION=304x128\n"
+ "http://example.com/low.m3u8\n"; + "http://example.com/low.m3u8\n";
private static final String PLAYLIST_WITH_CC = " #EXTM3U \n" private static final String PLAYLIST_WITH_CC =
+ "#EXT-X-MEDIA:TYPE=CLOSED-CAPTIONS,LANGUAGE=\"es\",NAME=\"Eng\",INSTREAM-ID=\"SERVICE4\"\n" " #EXTM3U \n"
+ "#EXT-X-STREAM-INF:BANDWIDTH=1280000,CODECS=\"mp4a.40.2,avc1.66.30\",RESOLUTION=304x128\n" + "#EXT-X-MEDIA:TYPE=CLOSED-CAPTIONS,"
+ "LANGUAGE=\"es\",NAME=\"Eng\",INSTREAM-ID=\"SERVICE4\"\n"
+ "#EXT-X-STREAM-INF:BANDWIDTH=1280000,"
+ "CODECS=\"mp4a.40.2,avc1.66.30\",RESOLUTION=304x128\n"
+ "http://example.com/low.m3u8\n"; + "http://example.com/low.m3u8\n";
private static final String PLAYLIST_WITHOUT_CC = " #EXTM3U \n" private static final String PLAYLIST_WITHOUT_CC =
+ "#EXT-X-MEDIA:TYPE=CLOSED-CAPTIONS,LANGUAGE=\"es\",NAME=\"Eng\",INSTREAM-ID=\"SERVICE4\"\n" " #EXTM3U \n"
+ "#EXT-X-STREAM-INF:BANDWIDTH=1280000,CODECS=\"mp4a.40.2,avc1.66.30\",RESOLUTION=304x128," + "#EXT-X-MEDIA:TYPE=CLOSED-CAPTIONS,"
+ "LANGUAGE=\"es\",NAME=\"Eng\",INSTREAM-ID=\"SERVICE4\"\n"
+ "#EXT-X-STREAM-INF:BANDWIDTH=1280000,"
+ "CODECS=\"mp4a.40.2,avc1.66.30\",RESOLUTION=304x128,"
+ "CLOSED-CAPTIONS=NONE\n" + "CLOSED-CAPTIONS=NONE\n"
+ "http://example.com/low.m3u8\n"; + "http://example.com/low.m3u8\n";
private static final String PLAYLIST_WITH_AUDIO_MEDIA_TAG = "#EXTM3U\n" private static final String PLAYLIST_WITH_AUDIO_MEDIA_TAG =
"#EXTM3U\n"
+ "#EXT-X-STREAM-INF:BANDWIDTH=2227464,CODECS=\"avc1.640020,mp4a.40.2\",AUDIO=\"aud1\"\n" + "#EXT-X-STREAM-INF:BANDWIDTH=2227464,CODECS=\"avc1.640020,mp4a.40.2\",AUDIO=\"aud1\"\n"
+ "uri1.m3u8\n" + "uri1.m3u8\n"
+ "#EXT-X-STREAM-INF:BANDWIDTH=8178040,CODECS=\"avc1.64002a,mp4a.40.2\",AUDIO=\"aud1\"\n" + "#EXT-X-STREAM-INF:BANDWIDTH=8178040,CODECS=\"avc1.64002a,mp4a.40.2\",AUDIO=\"aud1\"\n"
...@@ -90,6 +105,7 @@ public class HlsMasterPlaylistParserTest extends TestCase { ...@@ -90,6 +105,7 @@ public class HlsMasterPlaylistParserTest extends TestCase {
+ "#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"aud2\",LANGUAGE=\"en\",NAME=\"English\"," + "#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"aud2\",LANGUAGE=\"en\",NAME=\"English\","
+ "AUTOSELECT=YES,DEFAULT=YES,CHANNELS=\"6\",URI=\"a2/prog_index.m3u8\"\n"; + "AUTOSELECT=YES,DEFAULT=YES,CHANNELS=\"6\",URI=\"a2/prog_index.m3u8\"\n";
@Test
public void testParseMasterPlaylist() throws IOException { public void testParseMasterPlaylist() throws IOException {
HlsMasterPlaylist masterPlaylist = parseMasterPlaylist(PLAYLIST_URI, PLAYLIST_SIMPLE); HlsMasterPlaylist masterPlaylist = parseMasterPlaylist(PLAYLIST_URI, PLAYLIST_SIMPLE);
...@@ -129,9 +145,10 @@ public class HlsMasterPlaylistParserTest extends TestCase { ...@@ -129,9 +145,10 @@ public class HlsMasterPlaylistParserTest extends TestCase {
assertThat(variants.get(4).url).isEqualTo("http://example.com/audio-only.m3u8"); assertThat(variants.get(4).url).isEqualTo("http://example.com/audio-only.m3u8");
} }
@Test
public void testMasterPlaylistWithBandwdithAverage() throws IOException { public void testMasterPlaylistWithBandwdithAverage() throws IOException {
HlsMasterPlaylist masterPlaylist = parseMasterPlaylist(PLAYLIST_URI, HlsMasterPlaylist masterPlaylist =
PLAYLIST_WITH_AVG_BANDWIDTH); parseMasterPlaylist(PLAYLIST_URI, PLAYLIST_WITH_AVG_BANDWIDTH);
List<HlsMasterPlaylist.HlsUrl> variants = masterPlaylist.variants; List<HlsMasterPlaylist.HlsUrl> variants = masterPlaylist.variants;
...@@ -139,6 +156,7 @@ public class HlsMasterPlaylistParserTest extends TestCase { ...@@ -139,6 +156,7 @@ public class HlsMasterPlaylistParserTest extends TestCase {
assertThat(variants.get(1).format.bitrate).isEqualTo(1270000); assertThat(variants.get(1).format.bitrate).isEqualTo(1270000);
} }
@Test
public void testPlaylistWithInvalidHeader() throws IOException { public void testPlaylistWithInvalidHeader() throws IOException {
try { try {
parseMasterPlaylist(PLAYLIST_URI, PLAYLIST_WITH_INVALID_HEADER); parseMasterPlaylist(PLAYLIST_URI, PLAYLIST_WITH_INVALID_HEADER);
...@@ -148,6 +166,7 @@ public class HlsMasterPlaylistParserTest extends TestCase { ...@@ -148,6 +166,7 @@ public class HlsMasterPlaylistParserTest extends TestCase {
} }
} }
@Test
public void testPlaylistWithClosedCaption() throws IOException { public void testPlaylistWithClosedCaption() throws IOException {
HlsMasterPlaylist playlist = parseMasterPlaylist(PLAYLIST_URI, PLAYLIST_WITH_CC); HlsMasterPlaylist playlist = parseMasterPlaylist(PLAYLIST_URI, PLAYLIST_WITH_CC);
assertThat(playlist.muxedCaptionFormats).hasSize(1); assertThat(playlist.muxedCaptionFormats).hasSize(1);
...@@ -157,11 +176,13 @@ public class HlsMasterPlaylistParserTest extends TestCase { ...@@ -157,11 +176,13 @@ public class HlsMasterPlaylistParserTest extends TestCase {
assertThat(closedCaptionFormat.language).isEqualTo("es"); assertThat(closedCaptionFormat.language).isEqualTo("es");
} }
@Test
public void testPlaylistWithoutClosedCaptions() throws IOException { public void testPlaylistWithoutClosedCaptions() throws IOException {
HlsMasterPlaylist playlist = parseMasterPlaylist(PLAYLIST_URI, PLAYLIST_WITHOUT_CC); HlsMasterPlaylist playlist = parseMasterPlaylist(PLAYLIST_URI, PLAYLIST_WITHOUT_CC);
assertThat(playlist.muxedCaptionFormats).isEmpty(); assertThat(playlist.muxedCaptionFormats).isEmpty();
} }
@Test
public void testCodecPropagation() throws IOException { public void testCodecPropagation() throws IOException {
HlsMasterPlaylist playlist = parseMasterPlaylist(PLAYLIST_URI, PLAYLIST_WITH_AUDIO_MEDIA_TAG); HlsMasterPlaylist playlist = parseMasterPlaylist(PLAYLIST_URI, PLAYLIST_WITH_AUDIO_MEDIA_TAG);
...@@ -177,9 +198,8 @@ public class HlsMasterPlaylistParserTest extends TestCase { ...@@ -177,9 +198,8 @@ public class HlsMasterPlaylistParserTest extends TestCase {
private static HlsMasterPlaylist parseMasterPlaylist(String uri, String playlistString) private static HlsMasterPlaylist parseMasterPlaylist(String uri, String playlistString)
throws IOException { throws IOException {
Uri playlistUri = Uri.parse(uri); Uri playlistUri = Uri.parse(uri);
ByteArrayInputStream inputStream = new ByteArrayInputStream( ByteArrayInputStream inputStream =
playlistString.getBytes(Charset.forName(C.UTF8_NAME))); new ByteArrayInputStream(playlistString.getBytes(Charset.forName(C.UTF8_NAME)));
return (HlsMasterPlaylist) new HlsPlaylistParser().parse(playlistUri, inputStream); return (HlsMasterPlaylist) new HlsPlaylistParser().parse(playlistUri, inputStream);
} }
} }
...@@ -26,16 +26,19 @@ import java.io.InputStream; ...@@ -26,16 +26,19 @@ import java.io.InputStream;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import junit.framework.TestCase; import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
/** /** Test for {@link HlsMediaPlaylistParserTest}. */
* Test for {@link HlsMediaPlaylistParserTest}. @RunWith(RobolectricTestRunner.class)
*/ public class HlsMediaPlaylistParserTest {
public class HlsMediaPlaylistParserTest extends TestCase {
public void testParseMediaPlaylist() throws IOException { @Test
public void testParseMediaPlaylist() throws Exception {
Uri playlistUri = Uri.parse("https://example.com/test.m3u8"); Uri playlistUri = Uri.parse("https://example.com/test.m3u8");
String playlistString = "#EXTM3U\n" String playlistString =
"#EXTM3U\n"
+ "#EXT-X-VERSION:3\n" + "#EXT-X-VERSION:3\n"
+ "#EXT-X-PLAYLIST-TYPE:VOD\n" + "#EXT-X-PLAYLIST-TYPE:VOD\n"
+ "#EXT-X-START:TIME-OFFSET=-25" + "#EXT-X-START:TIME-OFFSET=-25"
...@@ -48,7 +51,8 @@ public class HlsMediaPlaylistParserTest extends TestCase { ...@@ -48,7 +51,8 @@ public class HlsMediaPlaylistParserTest extends TestCase {
+ "#EXT-X-BYTERANGE:51370@0\n" + "#EXT-X-BYTERANGE:51370@0\n"
+ "https://priv.example.com/fileSequence2679.ts\n" + "https://priv.example.com/fileSequence2679.ts\n"
+ "\n" + "\n"
+ "#EXT-X-KEY:METHOD=AES-128,URI=\"https://priv.example.com/key.php?r=2680\",IV=0x1566B\n" + "#EXT-X-KEY:METHOD=AES-128,"
+ "URI=\"https://priv.example.com/key.php?r=2680\",IV=0x1566B\n"
+ "#EXTINF:7.975,\n" + "#EXTINF:7.975,\n"
+ "#EXT-X-BYTERANGE:51501@2147483648\n" + "#EXT-X-BYTERANGE:51501@2147483648\n"
+ "https://priv.example.com/fileSequence2680.ts\n" + "https://priv.example.com/fileSequence2680.ts\n"
...@@ -67,8 +71,8 @@ public class HlsMediaPlaylistParserTest extends TestCase { ...@@ -67,8 +71,8 @@ public class HlsMediaPlaylistParserTest extends TestCase {
+ "#EXTINF:7.975,\n" + "#EXTINF:7.975,\n"
+ "https://priv.example.com/fileSequence2683.ts\n" + "https://priv.example.com/fileSequence2683.ts\n"
+ "#EXT-X-ENDLIST"; + "#EXT-X-ENDLIST";
InputStream inputStream = new ByteArrayInputStream( InputStream inputStream =
playlistString.getBytes(Charset.forName(C.UTF8_NAME))); new ByteArrayInputStream(playlistString.getBytes(Charset.forName(C.UTF8_NAME)));
HlsPlaylist playlist = new HlsPlaylistParser().parse(playlistUri, inputStream); HlsPlaylist playlist = new HlsPlaylistParser().parse(playlistUri, inputStream);
HlsMediaPlaylist mediaPlaylist = (HlsMediaPlaylist) playlist; HlsMediaPlaylist mediaPlaylist = (HlsMediaPlaylist) playlist;
...@@ -136,6 +140,7 @@ public class HlsMediaPlaylistParserTest extends TestCase { ...@@ -136,6 +140,7 @@ public class HlsMediaPlaylistParserTest extends TestCase {
assertThat(segment.url).isEqualTo("https://priv.example.com/fileSequence2683.ts"); assertThat(segment.url).isEqualTo("https://priv.example.com/fileSequence2683.ts");
} }
@Test
public void testGapTag() throws IOException { public void testGapTag() throws IOException {
Uri playlistUri = Uri.parse("https://example.com/test2.m3u8"); Uri playlistUri = Uri.parse("https://example.com/test2.m3u8");
String playlistString = String playlistString =
...@@ -170,5 +175,4 @@ public class HlsMediaPlaylistParserTest extends TestCase { ...@@ -170,5 +175,4 @@ public class HlsMediaPlaylistParserTest extends TestCase {
assertThat(playlist.segments.get(2).hasGapTag).isTrue(); assertThat(playlist.segments.get(2).hasGapTag).isTrue();
assertThat(playlist.segments.get(3).hasGapTag).isFalse(); assertThat(playlist.segments.get(3).hasGapTag).isFalse();
} }
} }
manifest=src/test/AndroidManifest.xml
...@@ -35,10 +35,7 @@ android { ...@@ -35,10 +35,7 @@ android {
dependencies { dependencies {
compile project(modulePrefix + 'library-core') compile project(modulePrefix + 'library-core')
compile 'com.android.support:support-annotations:' + supportLibraryVersion compile 'com.android.support:support-annotations:' + supportLibraryVersion
androidTestCompile project(modulePrefix + 'testutils') testCompile project(modulePrefix + 'testutils-robolectric')
androidTestCompile 'com.google.dexmaker:dexmaker:' + dexmakerVersion
androidTestCompile 'com.google.dexmaker:dexmaker-mockito:' + dexmakerVersion
androidTestCompile 'org.mockito:mockito-core:' + mockitoVersion
} }
ext { ext {
......
...@@ -18,16 +18,6 @@ ...@@ -18,16 +18,6 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
package="com.google.android.exoplayer2.source.smoothstreaming.test"> package="com.google.android.exoplayer2.source.smoothstreaming.test">
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="27"/> <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="26"/>
<application android:debuggable="true"
android:allowBackup="false"
tools:ignore="MissingApplicationIcon,HardcodedDebugMode">
<uses-library android:name="android.test.runner"/>
</application>
<instrumentation
android:targetPackage="com.google.android.exoplayer2.source.smoothstreaming.test"
android:name="android.test.InstrumentationTestRunner"/>
</manifest> </manifest>
...@@ -16,27 +16,29 @@ ...@@ -16,27 +16,29 @@
package com.google.android.exoplayer2.source.smoothstreaming.manifest; package com.google.android.exoplayer2.source.smoothstreaming.manifest;
import android.net.Uri; import android.net.Uri;
import android.test.InstrumentationTestCase;
import com.google.android.exoplayer2.testutil.TestUtil; import com.google.android.exoplayer2.testutil.TestUtil;
import java.io.IOException; import java.io.IOException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
/** /** Unit tests for {@link SsManifestParser}. */
* Unit tests for {@link SsManifestParser}. @RunWith(RobolectricTestRunner.class)
*/ public final class SsManifestParserTest {
public final class SsManifestParserTest extends InstrumentationTestCase {
private static final String SAMPLE_ISMC_1 = "sample_ismc_1"; private static final String SAMPLE_ISMC_1 = "sample_ismc_1";
private static final String SAMPLE_ISMC_2 = "sample_ismc_2"; private static final String SAMPLE_ISMC_2 = "sample_ismc_2";
/** /** Simple test to ensure the sample manifests parse without any exceptions being thrown. */
* Simple test to ensure the sample manifests parse without any exceptions being thrown. @Test
*/
public void testParseSmoothStreamingManifest() throws IOException { public void testParseSmoothStreamingManifest() throws IOException {
SsManifestParser parser = new SsManifestParser(); SsManifestParser parser = new SsManifestParser();
parser.parse(Uri.parse("https://example.com/test.ismc"), parser.parse(
TestUtil.getInputStream(getInstrumentation(), SAMPLE_ISMC_1)); Uri.parse("https://example.com/test.ismc"),
parser.parse(Uri.parse("https://example.com/test.ismc"), TestUtil.getInputStream(RuntimeEnvironment.application, SAMPLE_ISMC_1));
TestUtil.getInputStream(getInstrumentation(), SAMPLE_ISMC_2)); parser.parse(
Uri.parse("https://example.com/test.ismc"),
TestUtil.getInputStream(RuntimeEnvironment.application, SAMPLE_ISMC_2));
} }
} }
...@@ -26,52 +26,49 @@ import java.util.Arrays; ...@@ -26,52 +26,49 @@ import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
import junit.framework.TestCase; import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
/** /** Unit tests for {@link SsManifest}. */
* Unit tests for {@link SsManifest}. @RunWith(RobolectricTestRunner.class)
*/ public class SsManifestTest {
public class SsManifestTest extends TestCase {
private static final ProtectionElement DUMMY_PROTECTION_ELEMENT = private static final ProtectionElement DUMMY_PROTECTION_ELEMENT =
new ProtectionElement(C.WIDEVINE_UUID, new byte[] {0, 1, 2}); new ProtectionElement(C.WIDEVINE_UUID, new byte[] {0, 1, 2});
@Test
public void testCopy() throws Exception { public void testCopy() throws Exception {
Format[][] formats = newFormats(2, 3); Format[][] formats = newFormats(2, 3);
SsManifest sourceManifest = newSsManifest( SsManifest sourceManifest =
newStreamElement("1",formats[0]), newSsManifest(newStreamElement("1", formats[0]), newStreamElement("2", formats[1]));
newStreamElement("2", formats[1]));
List<TrackKey> keys = Arrays.asList(new TrackKey(0, 0), new TrackKey(0, 2), new TrackKey(1, 0));
List<TrackKey> keys = Arrays.asList(
new TrackKey(0, 0),
new TrackKey(0, 2),
new TrackKey(1, 0));
// Keys don't need to be in any particular order // Keys don't need to be in any particular order
Collections.shuffle(keys, new Random(0)); Collections.shuffle(keys, new Random(0));
SsManifest copyManifest = sourceManifest.copy(keys); SsManifest copyManifest = sourceManifest.copy(keys);
SsManifest expectedManifest = newSsManifest( SsManifest expectedManifest =
newSsManifest(
newStreamElement("1", formats[0][0], formats[0][2]), newStreamElement("1", formats[0][0], formats[0][2]),
newStreamElement("2", formats[1][0])); newStreamElement("2", formats[1][0]));
assertManifestEquals(expectedManifest, copyManifest); assertManifestEquals(expectedManifest, copyManifest);
} }
@Test
public void testCopyRemoveStreamElement() throws Exception { public void testCopyRemoveStreamElement() throws Exception {
Format[][] formats = newFormats(2, 3); Format[][] formats = newFormats(2, 3);
SsManifest sourceManifest = newSsManifest( SsManifest sourceManifest =
newStreamElement("1", formats[0]), newSsManifest(newStreamElement("1", formats[0]), newStreamElement("2", formats[1]));
newStreamElement("2", formats[1]));
List<TrackKey> keys = Arrays.asList( List<TrackKey> keys = Arrays.asList(new TrackKey(1, 0));
new TrackKey(1, 0));
// Keys don't need to be in any particular order // Keys don't need to be in any particular order
Collections.shuffle(keys, new Random(0)); Collections.shuffle(keys, new Random(0));
SsManifest copyManifest = sourceManifest.copy(keys); SsManifest copyManifest = sourceManifest.copy(keys);
SsManifest expectedManifest = newSsManifest( SsManifest expectedManifest = newSsManifest(newStreamElement("2", formats[1][0]));
newStreamElement("2", formats[1][0]));
assertManifestEquals(expectedManifest, copyManifest); assertManifestEquals(expectedManifest, copyManifest);
} }
...@@ -117,13 +114,25 @@ public class SsManifestTest extends TestCase { ...@@ -117,13 +114,25 @@ public class SsManifestTest extends TestCase {
} }
private static StreamElement newStreamElement(String name, Format... formats) { private static StreamElement newStreamElement(String name, Format... formats) {
return new StreamElement("baseUri", "chunkTemplate", C.TRACK_TYPE_VIDEO, "subType", return new StreamElement(
1000, name, 1024, 768, 1024, 768, null, formats, Collections.<Long>emptyList(), 0); "baseUri",
"chunkTemplate",
C.TRACK_TYPE_VIDEO,
"subType",
1000,
name,
1024,
768,
1024,
768,
null,
formats,
Collections.<Long>emptyList(),
0);
} }
private static Format newFormat(String id) { private static Format newFormat(String id) {
return Format.createContainerFormat(id, MimeTypes.VIDEO_MP4, MimeTypes.VIDEO_H264, null, return Format.createContainerFormat(
Format.NO_VALUE, 0, null); id, MimeTypes.VIDEO_MP4, MimeTypes.VIDEO_H264, null, Format.NO_VALUE, 0, null);
} }
} }
...@@ -35,4 +35,5 @@ dependencies { ...@@ -35,4 +35,5 @@ dependencies {
compile project(modulePrefix + 'library-core') compile project(modulePrefix + 'library-core')
compile 'org.mockito:mockito-core:' + mockitoVersion compile 'org.mockito:mockito-core:' + mockitoVersion
compile 'com.google.truth:truth:' + truthVersion compile 'com.google.truth:truth:' + truthVersion
testCompile project(modulePrefix + 'testutils-robolectric')
} }
/*
* Copyright (C) 2017 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.exoplayer2.testutil;
import android.content.Context;
import android.test.InstrumentationTestCase;
import org.mockito.MockitoAnnotations;
/**
* Utility for setting up Mockito for instrumentation tests.
*/
public final class MockitoUtil {
/**
* Sets up Mockito for an instrumentation test.
*
* @param instrumentationTestCase The instrumentation test case class.
*/
public static void setUpMockito(InstrumentationTestCase instrumentationTestCase) {
// Workaround for https://code.google.com/p/dexmaker/issues/detail?id=2.
System.setProperty("dexmaker.dexcache",
instrumentationTestCase.getInstrumentation().getTargetContext().getCacheDir().getPath());
MockitoAnnotations.initMocks(instrumentationTestCase);
}
/**
* Sets up Mockito for a JUnit4 test.
*
* @param targetContext The target context. Usually obtained from
* {@code InstrumentationRegistry.getTargetContext()}
* @param testClass The JUnit4 test class.
*/
public static void setUpMockito(Context targetContext, Object testClass) {
// Workaround for https://code.google.com/p/dexmaker/issues/detail?id=2.
System.setProperty("dexmaker.dexcache", targetContext.getCacheDir().getPath());
MockitoAnnotations.initMocks(testClass);
}
private MockitoUtil() {}
}
...@@ -18,7 +18,6 @@ package com.google.android.exoplayer2.testutil; ...@@ -18,7 +18,6 @@ package com.google.android.exoplayer2.testutil;
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.app.Instrumentation;
import android.content.Context; import android.content.Context;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.extractor.Extractor; import com.google.android.exoplayer2.extractor.Extractor;
...@@ -132,20 +131,10 @@ public class TestUtil { ...@@ -132,20 +131,10 @@ public class TestUtil {
return joined; return joined;
} }
public static byte[] getByteArray(Instrumentation instrumentation, String fileName)
throws IOException {
return getByteArray(instrumentation.getContext(), fileName);
}
public static byte[] getByteArray(Context context, String fileName) throws IOException { public static byte[] getByteArray(Context context, String fileName) throws IOException {
return Util.toByteArray(getInputStream(context, fileName)); return Util.toByteArray(getInputStream(context, fileName));
} }
public static InputStream getInputStream(Instrumentation instrumentation, String fileName)
throws IOException {
return getInputStream(instrumentation.getContext(), fileName);
}
public static InputStream getInputStream(Context context, String fileName) throws IOException { public static InputStream getInputStream(Context context, String fileName) throws IOException {
return context.getResources().getAssets().open(fileName); return context.getResources().getAssets().open(fileName);
} }
......
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2017 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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.google.android.exoplayer2.testutil.test">
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="26"/>
</manifest>
/*
* Copyright (C) 2017 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.exoplayer2.testutil;
import static com.google.common.truth.Truth.assertThat;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.testutil.FakeDataSet.FakeData;
import com.google.android.exoplayer2.testutil.FakeDataSet.FakeData.Segment;
import com.google.android.exoplayer2.util.MimeTypes;
import java.util.List;
import java.util.Random;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
/** Unit test for {@link FakeAdaptiveDataSet}. */
@RunWith(RobolectricTestRunner.class)
public final class FakeAdaptiveDataSetTest {
private static final Format[] TEST_FORMATS = {
Format.createVideoSampleFormat(
null,
MimeTypes.VIDEO_H264,
null,
1000000,
Format.NO_VALUE,
1280,
720,
Format.NO_VALUE,
null,
null),
Format.createVideoSampleFormat(
null,
MimeTypes.VIDEO_H264,
null,
300000,
Format.NO_VALUE,
640,
360,
Format.NO_VALUE,
null,
null)
};
private static final TrackGroup TRACK_GROUP = new TrackGroup(TEST_FORMATS);
@Test
public void testAdaptiveDataSet() {
long chunkDuration = 2 * C.MICROS_PER_SECOND;
FakeAdaptiveDataSet dataSet =
new FakeAdaptiveDataSet(
TRACK_GROUP, 10 * C.MICROS_PER_SECOND, chunkDuration, 0.0, new Random(0));
assertThat(dataSet.getAllData().size()).isEqualTo(TEST_FORMATS.length);
assertThat(dataSet.getUri(0).equals(dataSet.getUri(1))).isFalse();
assertThat(dataSet.getChunkCount()).isEqualTo(5);
assertThat(dataSet.getChunkIndexByPosition(4 * C.MICROS_PER_SECOND)).isEqualTo(2);
assertThat(dataSet.getChunkIndexByPosition(9 * C.MICROS_PER_SECOND)).isEqualTo(4);
for (int i = 0; i < dataSet.getChunkCount(); i++) {
assertThat(dataSet.getChunkDuration(i)).isEqualTo(chunkDuration);
}
assertChunkData(dataSet, chunkDuration);
}
@Test
public void testAdaptiveDataSetTrailingSmallChunk() {
long chunkDuration = 3 * C.MICROS_PER_SECOND;
FakeAdaptiveDataSet dataSet =
new FakeAdaptiveDataSet(
TRACK_GROUP, 10 * C.MICROS_PER_SECOND, chunkDuration, 0.0, new Random(0));
assertThat(dataSet.getAllData().size()).isEqualTo(TEST_FORMATS.length);
assertThat(dataSet.getUri(0).equals(dataSet.getUri(1))).isFalse();
assertThat(dataSet.getChunkCount()).isEqualTo(4);
assertThat(dataSet.getChunkIndexByPosition(4 * C.MICROS_PER_SECOND)).isEqualTo(1);
assertThat(dataSet.getChunkIndexByPosition(9 * C.MICROS_PER_SECOND)).isEqualTo(3);
for (int i = 0; i < dataSet.getChunkCount() - 1; i++) {
assertThat(dataSet.getChunkDuration(i)).isEqualTo(chunkDuration);
}
assertThat(dataSet.getChunkDuration(3)).isEqualTo(1 * C.MICROS_PER_SECOND);
assertChunkData(dataSet, chunkDuration);
}
@Test
public void testAdaptiveDataSetChunkSizeDistribution() {
double expectedStdDev = 4.0;
FakeAdaptiveDataSet dataSet =
new FakeAdaptiveDataSet(
TRACK_GROUP,
100000 * C.MICROS_PER_SECOND,
1 * C.MICROS_PER_SECOND,
expectedStdDev,
new Random(0));
for (int i = 0; i < TEST_FORMATS.length; i++) {
FakeData data = dataSet.getData(dataSet.getUri(i));
double mean = computeSegmentSizeMean(data.getSegments());
double stddev = computeSegmentSizeStdDev(data.getSegments(), mean);
double relativePercentStdDev = stddev / mean * 100.0;
assertThat(relativePercentStdDev).isWithin(0.02).of(expectedStdDev);
assertThat(mean * 8 / TEST_FORMATS[i].bitrate).isWithin(0.01).of(1.0);
}
}
private void assertChunkData(FakeAdaptiveDataSet dataSet, long chunkDuration) {
for (int i = 0; i < dataSet.getChunkCount(); i++) {
assertThat(dataSet.getStartTime(i)).isEqualTo(chunkDuration * i);
}
for (int s = 0; s < TEST_FORMATS.length; s++) {
FakeData data = dataSet.getData(dataSet.getUri(s));
assertThat(data.getSegments().size()).isEqualTo(dataSet.getChunkCount());
for (int i = 0; i < data.getSegments().size(); i++) {
long expectedLength =
TEST_FORMATS[s].bitrate * dataSet.getChunkDuration(i) / (8 * C.MICROS_PER_SECOND);
assertThat(data.getSegments().get(i).length).isEqualTo(expectedLength);
}
}
}
private static double computeSegmentSizeMean(List<Segment> segments) {
double totalSize = 0.0;
for (Segment segment : segments) {
totalSize += segment.length;
}
return totalSize / segments.size();
}
private static double computeSegmentSizeStdDev(List<Segment> segments, double mean) {
double totalSquaredSize = 0.0;
for (Segment segment : segments) {
totalSquaredSize += (double) segment.length * segment.length;
}
return Math.sqrt(totalSquaredSize / segments.size() - mean * mean);
}
}
/*
* Copyright (C) 2017 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.exoplayer2.testutil;
import static com.google.common.truth.Truth.assertThat;
import android.os.ConditionVariable;
import android.os.HandlerThread;
import com.google.android.exoplayer2.util.Clock;
import com.google.android.exoplayer2.util.HandlerWrapper;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
/** Unit test for {@link FakeClock}. */
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {RobolectricUtil.CustomLooper.class, RobolectricUtil.CustomMessageQueue.class})
public final class FakeClockTest {
private static final long TIMEOUT_MS = 10000;
@Test
public void testAdvanceTime() {
FakeClock fakeClock = new FakeClock(2000);
assertThat(fakeClock.elapsedRealtime()).isEqualTo(2000);
fakeClock.advanceTime(500);
assertThat(fakeClock.elapsedRealtime()).isEqualTo(2500);
fakeClock.advanceTime(0);
assertThat(fakeClock.elapsedRealtime()).isEqualTo(2500);
}
@Test
public void testSleep() throws InterruptedException {
FakeClock fakeClock = new FakeClock(0);
SleeperThread sleeperThread = new SleeperThread(fakeClock, 1000);
sleeperThread.start();
assertThat(sleeperThread.waitUntilAsleep(TIMEOUT_MS)).isTrue();
assertThat(sleeperThread.isSleeping()).isTrue();
fakeClock.advanceTime(1000);
sleeperThread.join(TIMEOUT_MS);
assertThat(sleeperThread.isSleeping()).isFalse();
sleeperThread = new SleeperThread(fakeClock, 0);
sleeperThread.start();
sleeperThread.join();
assertThat(sleeperThread.isSleeping()).isFalse();
SleeperThread[] sleeperThreads = new SleeperThread[5];
sleeperThreads[0] = new SleeperThread(fakeClock, 1000);
sleeperThreads[1] = new SleeperThread(fakeClock, 1000);
sleeperThreads[2] = new SleeperThread(fakeClock, 2000);
sleeperThreads[3] = new SleeperThread(fakeClock, 3000);
sleeperThreads[4] = new SleeperThread(fakeClock, 4000);
for (SleeperThread thread : sleeperThreads) {
thread.start();
assertThat(thread.waitUntilAsleep(TIMEOUT_MS)).isTrue();
}
assertSleepingStates(new boolean[] {true, true, true, true, true}, sleeperThreads);
fakeClock.advanceTime(1500);
assertThat(sleeperThreads[0].waitUntilAwake(TIMEOUT_MS)).isTrue();
assertThat(sleeperThreads[1].waitUntilAwake(TIMEOUT_MS)).isTrue();
assertSleepingStates(new boolean[] {false, false, true, true, true}, sleeperThreads);
fakeClock.advanceTime(2000);
assertThat(sleeperThreads[2].waitUntilAwake(TIMEOUT_MS)).isTrue();
assertThat(sleeperThreads[3].waitUntilAwake(TIMEOUT_MS)).isTrue();
assertSleepingStates(new boolean[] {false, false, false, false, true}, sleeperThreads);
fakeClock.advanceTime(2000);
for (SleeperThread thread : sleeperThreads) {
thread.join(TIMEOUT_MS);
}
assertSleepingStates(new boolean[] {false, false, false, false, false}, sleeperThreads);
}
@Test
public void testPostDelayed() {
HandlerThread handlerThread = new HandlerThread("FakeClockTest thread");
handlerThread.start();
FakeClock fakeClock = new FakeClock(0);
HandlerWrapper handler =
fakeClock.createHandler(handlerThread.getLooper(), /* callback= */ null);
TestRunnable[] testRunnables = {
new TestRunnable(),
new TestRunnable(),
new TestRunnable(),
new TestRunnable(),
new TestRunnable()
};
handler.postDelayed(testRunnables[0], 0);
handler.postDelayed(testRunnables[1], 100);
handler.postDelayed(testRunnables[2], 200);
waitForHandler(handler);
assertTestRunnableStates(new boolean[] {true, false, false, false, false}, testRunnables);
fakeClock.advanceTime(150);
handler.postDelayed(testRunnables[3], 50);
handler.postDelayed(testRunnables[4], 100);
waitForHandler(handler);
assertTestRunnableStates(new boolean[] {true, true, false, false, false}, testRunnables);
fakeClock.advanceTime(50);
waitForHandler(handler);
assertTestRunnableStates(new boolean[] {true, true, true, true, false}, testRunnables);
fakeClock.advanceTime(1000);
waitForHandler(handler);
assertTestRunnableStates(new boolean[] {true, true, true, true, true}, testRunnables);
}
private static void assertSleepingStates(boolean[] states, SleeperThread[] sleeperThreads) {
for (int i = 0; i < sleeperThreads.length; i++) {
assertThat(sleeperThreads[i].isSleeping()).isEqualTo(states[i]);
}
}
private static void waitForHandler(HandlerWrapper handler) {
final ConditionVariable handlerFinished = new ConditionVariable();
handler.post(
new Runnable() {
@Override
public void run() {
handlerFinished.open();
}
});
handlerFinished.block();
}
private static void assertTestRunnableStates(boolean[] states, TestRunnable[] testRunnables) {
for (int i = 0; i < testRunnables.length; i++) {
assertThat(testRunnables[i].hasRun).isEqualTo(states[i]);
}
}
private static final class SleeperThread extends Thread {
private final Clock clock;
private final long sleepDurationMs;
private final CountDownLatch fallAsleepCountDownLatch;
private final CountDownLatch wakeUpCountDownLatch;
private volatile boolean isSleeping;
public SleeperThread(Clock clock, long sleepDurationMs) {
this.clock = clock;
this.sleepDurationMs = sleepDurationMs;
this.fallAsleepCountDownLatch = new CountDownLatch(1);
this.wakeUpCountDownLatch = new CountDownLatch(1);
}
public boolean waitUntilAsleep(long timeoutMs) throws InterruptedException {
return fallAsleepCountDownLatch.await(timeoutMs, TimeUnit.MILLISECONDS);
}
public boolean waitUntilAwake(long timeoutMs) throws InterruptedException {
return wakeUpCountDownLatch.await(timeoutMs, TimeUnit.MILLISECONDS);
}
public boolean isSleeping() {
return isSleeping;
}
@Override
public void run() {
// This relies on the FakeClock's methods synchronizing on its own monitor to ensure that
// any interactions with it occur only after sleep() has called wait() or returned.
synchronized (clock) {
isSleeping = true;
fallAsleepCountDownLatch.countDown();
clock.sleep(sleepDurationMs);
isSleeping = false;
wakeUpCountDownLatch.countDown();
}
}
}
private static final class TestRunnable implements Runnable {
public boolean hasRun;
@Override
public void run() {
hasRun = true;
}
}
}
/*
* Copyright (C) 2017 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.exoplayer2.testutil;
import static com.google.common.truth.Truth.assertThat;
import android.net.Uri;
import com.google.android.exoplayer2.testutil.FakeDataSet.FakeData.Segment;
import java.io.IOException;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
/** Unit test for {@link FakeDataSet} */
@RunWith(RobolectricTestRunner.class)
public final class FakeDataSetTest {
@Test
public void testMultipleDataSets() {
byte[][] testData = new byte[4][];
Uri[] uris = new Uri[3];
for (int i = 0; i < 4; i++) {
testData[i] = TestUtil.buildTestData(10, i);
if (i > 0) {
uris[i - 1] = Uri.parse("test_uri_" + i);
}
}
FakeDataSet fakeDataSet =
new FakeDataSet()
.newDefaultData()
.appendReadData(testData[0])
.endData()
.setData(uris[0], testData[1])
.newData(uris[1])
.appendReadData(testData[2])
.endData()
.setData(uris[2], testData[3]);
assertThat(fakeDataSet.getAllData().size()).isEqualTo(4);
assertThat(fakeDataSet.getData("unseen_uri")).isEqualTo(fakeDataSet.getData((Uri) null));
for (int i = 0; i < 3; i++) {
assertThat(fakeDataSet.getData(uris[i]).uri).isEqualTo(uris[i]);
}
assertThat(fakeDataSet.getData((Uri) null).getData()).isEqualTo(testData[0]);
for (int i = 1; i < 4; i++) {
assertThat(fakeDataSet.getData(uris[i - 1]).getData()).isEqualTo(testData[i]);
}
}
@Test
public void testSegmentTypes() {
byte[] testData = TestUtil.buildTestData(3);
Runnable runnable =
new Runnable() {
@Override
public void run() {
// Do nothing.
}
};
IOException exception = new IOException();
FakeDataSet fakeDataSet =
new FakeDataSet()
.newDefaultData()
.appendReadData(testData)
.appendReadData(testData)
.appendReadData(50)
.appendReadAction(runnable)
.appendReadError(exception)
.endData();
List<Segment> segments = fakeDataSet.getData((Uri) null).getSegments();
assertThat(segments.size()).isEqualTo(5);
assertSegment(segments.get(0), testData, 3, 0, null, null);
assertSegment(segments.get(1), testData, 3, 3, null, null);
assertSegment(segments.get(2), null, 50, 6, null, null);
assertSegment(segments.get(3), null, 0, 56, runnable, null);
assertSegment(segments.get(4), null, 0, 56, null, exception);
byte[] allData = new byte[6];
System.arraycopy(testData, 0, allData, 0, 3);
System.arraycopy(testData, 0, allData, 3, 3);
assertThat(fakeDataSet.getData((Uri) null).getData()).isEqualTo(allData);
}
private static void assertSegment(
Segment segment,
byte[] data,
int length,
long byteOffset,
Runnable runnable,
IOException exception) {
if (data != null) {
assertThat(segment.data).isEqualTo(data);
assertThat(data).hasLength(length);
} else {
assertThat(segment.data).isNull();
}
assertThat(segment.length).isEqualTo(length);
assertThat(segment.byteOffset).isEqualTo(byteOffset);
assertThat(segment.action).isEqualTo(runnable);
assertThat(segment.isActionSegment()).isEqualTo(runnable != null);
assertThat(segment.exception).isEqualTo(exception);
assertThat(segment.isErrorSegment()).isEqualTo(exception != null);
}
}
/*
* Copyright (C) 2017 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.exoplayer2.testutil;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
import android.net.Uri;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.upstream.DataSpec;
import java.io.IOException;
import java.util.Arrays;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
/** Unit test for {@link FakeDataSource}. */
@RunWith(RobolectricTestRunner.class)
public final class FakeDataSourceTest {
private static final String URI_STRING = "test://test.test";
private static final byte[] BUFFER = new byte[500];
private static final byte[] TEST_DATA = TestUtil.buildTestData(15);
private static final byte[] TEST_DATA_PART_1 = Arrays.copyOf(TEST_DATA, 10);
private static final byte[] TEST_DATA_PART_2 = Arrays.copyOfRange(TEST_DATA, 10, 15);
private static Uri uri;
private static FakeDataSet fakeDataSet;
@Before
public void setUp() {
uri = Uri.parse(URI_STRING);
fakeDataSet =
new FakeDataSet()
.newData(uri.toString())
.appendReadData(TEST_DATA_PART_1)
.appendReadData(TEST_DATA_PART_2)
.endData();
}
@Test
public void testReadFull() throws IOException {
FakeDataSource dataSource = new FakeDataSource(fakeDataSet);
assertThat(dataSource.open(new DataSpec(uri))).isEqualTo(15);
assertThat(dataSource.read(BUFFER, 0, BUFFER.length)).isEqualTo(10);
assertBuffer(TEST_DATA_PART_1);
assertThat(dataSource.read(BUFFER, 10, BUFFER.length)).isEqualTo(5);
assertBuffer(TEST_DATA);
assertThat(dataSource.read(BUFFER, 15, BUFFER.length)).isEqualTo(C.RESULT_END_OF_INPUT);
assertBuffer(TEST_DATA);
assertThat(dataSource.read(BUFFER, 20, BUFFER.length)).isEqualTo(C.RESULT_END_OF_INPUT);
dataSource.close();
}
@Test
public void testReadPartialOpenEnded() throws IOException {
FakeDataSource dataSource = new FakeDataSource(fakeDataSet);
assertThat(dataSource.open(new DataSpec(uri, 7, C.LENGTH_UNSET, null))).isEqualTo(8);
assertThat(dataSource.read(BUFFER, 0, BUFFER.length)).isEqualTo(3);
assertBuffer(TEST_DATA_PART_1, 7, 3);
assertThat(dataSource.read(BUFFER, 0, BUFFER.length)).isEqualTo(5);
assertBuffer(TEST_DATA_PART_2);
assertThat(dataSource.read(BUFFER, 15, BUFFER.length)).isEqualTo(C.RESULT_END_OF_INPUT);
dataSource.close();
}
@Test
public void testReadPartialBounded() throws IOException {
FakeDataSource dataSource = new FakeDataSource(fakeDataSet);
assertThat(dataSource.open(new DataSpec(uri, 9, 3, null))).isEqualTo(3);
assertThat(dataSource.read(BUFFER, 0, BUFFER.length)).isEqualTo(1);
assertBuffer(TEST_DATA_PART_1, 9, 1);
assertThat(dataSource.read(BUFFER, 0, BUFFER.length)).isEqualTo(2);
assertBuffer(TEST_DATA_PART_2, 0, 2);
assertThat(dataSource.read(BUFFER, 0, BUFFER.length)).isEqualTo(C.RESULT_END_OF_INPUT);
dataSource.close();
assertThat(dataSource.open(new DataSpec(uri, 11, 4, null))).isEqualTo(4);
assertThat(dataSource.read(BUFFER, 0, BUFFER.length)).isEqualTo(4);
assertBuffer(TEST_DATA_PART_2, 1, 4);
assertThat(dataSource.read(BUFFER, 0, BUFFER.length)).isEqualTo(C.RESULT_END_OF_INPUT);
dataSource.close();
}
@Test
public void testDummyData() throws IOException {
FakeDataSource dataSource =
new FakeDataSource(
new FakeDataSet()
.newData(uri.toString())
.appendReadData(100)
.appendReadData(TEST_DATA)
.appendReadData(200)
.endData());
assertThat(dataSource.open(new DataSpec(uri))).isEqualTo(315);
assertThat(dataSource.read(BUFFER, 0, BUFFER.length)).isEqualTo(100);
assertThat(dataSource.read(BUFFER, 0, BUFFER.length)).isEqualTo(15);
assertBuffer(TEST_DATA);
assertThat(dataSource.read(BUFFER, 0, BUFFER.length)).isEqualTo(200);
assertThat(dataSource.read(BUFFER, 0, BUFFER.length)).isEqualTo(C.RESULT_END_OF_INPUT);
dataSource.close();
}
@Test
public void testException() throws IOException {
String errorMessage = "error, error, error";
IOException exception = new IOException(errorMessage);
FakeDataSource dataSource =
new FakeDataSource(
new FakeDataSet()
.newData(uri.toString())
.appendReadData(TEST_DATA)
.appendReadError(exception)
.appendReadData(TEST_DATA)
.endData());
assertThat(dataSource.open(new DataSpec(uri))).isEqualTo(30);
assertThat(dataSource.read(BUFFER, 0, BUFFER.length)).isEqualTo(15);
assertBuffer(TEST_DATA);
try {
dataSource.read(BUFFER, 0, BUFFER.length);
fail("IOException expected.");
} catch (IOException e) {
assertThat(e).hasMessageThat().isEqualTo(errorMessage);
}
try {
dataSource.read(BUFFER, 0, BUFFER.length);
fail("IOException expected.");
} catch (IOException e) {
assertThat(e).hasMessageThat().isEqualTo(errorMessage);
}
dataSource.close();
assertThat(dataSource.open(new DataSpec(uri, 15, 15, null))).isEqualTo(15);
assertThat(dataSource.read(BUFFER, 0, BUFFER.length)).isEqualTo(15);
assertBuffer(TEST_DATA);
assertThat(dataSource.read(BUFFER, 0, BUFFER.length)).isEqualTo(C.RESULT_END_OF_INPUT);
dataSource.close();
}
@Test
public void testRunnable() throws IOException {
TestRunnable[] runnables = new TestRunnable[3];
for (int i = 0; i < 3; i++) {
runnables[i] = new TestRunnable();
}
FakeDataSource dataSource =
new FakeDataSource(
new FakeDataSet()
.newData(uri.toString())
.appendReadData(TEST_DATA)
.appendReadAction(runnables[0])
.appendReadData(TEST_DATA)
.appendReadAction(runnables[1])
.appendReadAction(runnables[2])
.appendReadData(TEST_DATA)
.endData());
assertThat(dataSource.open(new DataSpec(uri))).isEqualTo(45);
assertThat(dataSource.read(BUFFER, 0, BUFFER.length)).isEqualTo(15);
assertBuffer(TEST_DATA);
for (int i = 0; i < 3; i++) {
assertThat(runnables[i].ran).isFalse();
}
assertThat(dataSource.read(BUFFER, 0, BUFFER.length)).isEqualTo(15);
assertBuffer(TEST_DATA);
assertThat(runnables[0].ran).isTrue();
assertThat(runnables[1].ran).isFalse();
assertThat(runnables[2].ran).isFalse();
assertThat(dataSource.read(BUFFER, 0, BUFFER.length)).isEqualTo(15);
assertBuffer(TEST_DATA);
for (int i = 0; i < 3; i++) {
assertThat(runnables[i].ran).isTrue();
}
assertThat(dataSource.read(BUFFER, 0, BUFFER.length)).isEqualTo(C.RESULT_END_OF_INPUT);
dataSource.close();
}
@Test
public void testOpenSourceFailures() throws IOException {
// Empty data.
FakeDataSource dataSource =
new FakeDataSource(new FakeDataSet().newData(uri.toString()).endData());
try {
dataSource.open(new DataSpec(uri));
fail("IOException expected.");
} catch (IOException e) {
// Expected.
} finally {
dataSource.close();
}
// Non-existent data
dataSource = new FakeDataSource(new FakeDataSet());
try {
dataSource.open(new DataSpec(uri));
fail("IOException expected.");
} catch (IOException e) {
// Expected.
} finally {
dataSource.close();
}
// DataSpec out of bounds.
dataSource =
new FakeDataSource(
new FakeDataSet()
.newDefaultData()
.appendReadData(TestUtil.buildTestData(10))
.endData());
try {
dataSource.open(new DataSpec(uri, 5, 10, null));
fail("IOException expected.");
} catch (IOException e) {
// Expected.
} finally {
dataSource.close();
}
}
private static void assertBuffer(byte[] expected) {
assertBuffer(expected, 0, expected.length);
}
private static void assertBuffer(byte[] expected, int expectedStart, int expectedLength) {
for (int i = 0; i < expectedLength; i++) {
assertThat(BUFFER[i]).isEqualTo(expected[i + expectedStart]);
}
}
private static final class TestRunnable implements Runnable {
public boolean ran;
@Override
public void run() {
ran = true;
}
}
}
manifest=src/test/AndroidManifest.xml
// Copyright (C) 2018 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.
apply from: '../constants.gradle'
apply plugin: 'com.android.library'
android {
compileSdkVersion project.ext.compileSdkVersion
buildToolsVersion project.ext.buildToolsVersion
defaultConfig {
minSdkVersion project.ext.minSdkVersion
targetSdkVersion project.ext.targetSdkVersion
}
lintOptions {
// Truth depends on JUnit, which depends on java.lang.management, which
// is not part of Android. Remove this when JUnit 4.13 or later is used.
// See: https://github.com/junit-team/junit4/pull/1187.
disable 'InvalidPackage'
}
}
dependencies {
compile project(modulePrefix + 'testutils')
compile 'org.robolectric:robolectric:' + robolectricVersion
}
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2018 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.
-->
<manifest package="com.google.android.exoplayer2.testutil"/>
...@@ -29,9 +29,7 @@ import com.google.android.exoplayer2.upstream.cache.CacheUtil; ...@@ -29,9 +29,7 @@ import com.google.android.exoplayer2.upstream.cache.CacheUtil;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
/** /** Assertion methods for {@link Cache}. */
* Assertion methods for {@link Cache}.
*/
public final class CacheAsserts { public final class CacheAsserts {
/** /**
...@@ -135,5 +133,4 @@ public final class CacheAsserts { ...@@ -135,5 +133,4 @@ public final class CacheAsserts {
} }
private CacheAsserts() {} private CacheAsserts() {}
} }
...@@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat; ...@@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat;
import android.os.ConditionVariable; import android.os.ConditionVariable;
import android.os.Handler; import android.os.Handler;
import android.os.HandlerThread; import android.os.HandlerThread;
import android.os.Looper;
/** Helper class to simulate main/UI thread in tests. */ /** Helper class to simulate main/UI thread in tests. */
public final class DummyMainThread { public final class DummyMainThread {
...@@ -54,6 +55,9 @@ public final class DummyMainThread { ...@@ -54,6 +55,9 @@ public final class DummyMainThread {
* @param runnable The {@link Runnable} to run. * @param runnable The {@link Runnable} to run.
*/ */
public void runOnMainThread(int timeoutMs, final Runnable runnable) { public void runOnMainThread(int timeoutMs, final Runnable runnable) {
if (Looper.myLooper() == handler.getLooper()) {
runnable.run();
} else {
final ConditionVariable finishedCondition = new ConditionVariable(); final ConditionVariable finishedCondition = new ConditionVariable();
handler.post( handler.post(
new Runnable() { new Runnable() {
...@@ -65,6 +69,7 @@ public final class DummyMainThread { ...@@ -65,6 +69,7 @@ public final class DummyMainThread {
}); });
assertThat(finishedCondition.block(timeoutMs)).isTrue(); assertThat(finishedCondition.block(timeoutMs)).isTrue();
} }
}
public void release() { public void release() {
thread.quit(); thread.quit();
......
...@@ -19,9 +19,7 @@ import com.google.android.exoplayer2.Format; ...@@ -19,9 +19,7 @@ import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.Renderer; import com.google.android.exoplayer2.Renderer;
import com.google.android.exoplayer2.util.MediaClock; import com.google.android.exoplayer2.util.MediaClock;
/** /** Fake abstract {@link Renderer} which is also a {@link MediaClock}. */
* Fake abstract {@link Renderer} which is also a {@link MediaClock}.
*/
public abstract class FakeMediaClockRenderer extends FakeRenderer implements MediaClock { public abstract class FakeMediaClockRenderer extends FakeRenderer implements MediaClock {
public FakeMediaClockRenderer(Format... expectedFormats) { public FakeMediaClockRenderer(Format... expectedFormats) {
...@@ -32,5 +30,4 @@ public abstract class FakeMediaClockRenderer extends FakeRenderer implements Med ...@@ -32,5 +30,4 @@ public abstract class FakeMediaClockRenderer extends FakeRenderer implements Med
public MediaClock getMediaClock() { public MediaClock getMediaClock() {
return this; return this;
} }
} }
...@@ -25,8 +25,8 @@ import com.google.android.exoplayer2.trackselection.TrackSelection; ...@@ -25,8 +25,8 @@ import com.google.android.exoplayer2.trackselection.TrackSelection;
import java.util.List; import java.util.List;
/** /**
* A fake {@link TrackSelection} that only returns 1 fixed track, and allows querying the number * A fake {@link TrackSelection} that only returns 1 fixed track, and allows querying the number of
* of calls to its methods. * calls to its methods.
*/ */
public final class FakeTrackSelection implements TrackSelection { public final class FakeTrackSelection implements TrackSelection {
...@@ -118,8 +118,8 @@ public final class FakeTrackSelection implements TrackSelection { ...@@ -118,8 +118,8 @@ public final class FakeTrackSelection implements TrackSelection {
} }
@Override @Override
public void updateSelectedTrack(long playbackPositionUs, long bufferedDurationUs, public void updateSelectedTrack(
long availableDurationUs) { long playbackPositionUs, long bufferedDurationUs, long availableDurationUs) {
assertThat(isEnabled).isTrue(); assertThat(isEnabled).isTrue();
} }
...@@ -134,5 +134,4 @@ public final class FakeTrackSelection implements TrackSelection { ...@@ -134,5 +134,4 @@ public final class FakeTrackSelection implements TrackSelection {
assertThat(isEnabled).isTrue(); assertThat(isEnabled).isTrue();
return false; return false;
} }
} }
...@@ -25,9 +25,7 @@ import com.google.android.exoplayer2.trackselection.TrackSelection; ...@@ -25,9 +25,7 @@ import com.google.android.exoplayer2.trackselection.TrackSelection;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /** A fake {@link MappingTrackSelector} that returns {@link FakeTrackSelection}s. */
* A fake {@link MappingTrackSelector} that returns {@link FakeTrackSelection}s.
*/
public class FakeTrackSelector extends MappingTrackSelector { public class FakeTrackSelector extends MappingTrackSelector {
private final List<FakeTrackSelection> selectedTrackSelections = new ArrayList<>(); private final List<FakeTrackSelection> selectedTrackSelections = new ArrayList<>();
...@@ -38,17 +36,19 @@ public class FakeTrackSelector extends MappingTrackSelector { ...@@ -38,17 +36,19 @@ public class FakeTrackSelector extends MappingTrackSelector {
} }
/** /**
* @param mayReuseTrackSelection Whether this {@link FakeTrackSelector} will reuse * @param mayReuseTrackSelection Whether this {@link FakeTrackSelector} will reuse {@link
* {@link TrackSelection}s during track selection, when it finds previously-selected track * TrackSelection}s during track selection, when it finds previously-selected track selection
* selection using the same {@link TrackGroup}. * using the same {@link TrackGroup}.
*/ */
public FakeTrackSelector(boolean mayReuseTrackSelection) { public FakeTrackSelector(boolean mayReuseTrackSelection) {
this.mayReuseTrackSelection = mayReuseTrackSelection; this.mayReuseTrackSelection = mayReuseTrackSelection;
} }
@Override @Override
protected TrackSelection[] selectTracks(RendererCapabilities[] rendererCapabilities, protected TrackSelection[] selectTracks(
TrackGroupArray[] rendererTrackGroupArrays, int[][][] rendererFormatSupports) RendererCapabilities[] rendererCapabilities,
TrackGroupArray[] rendererTrackGroupArrays,
int[][][] rendererFormatSupports)
throws ExoPlaybackException { throws ExoPlaybackException {
List<FakeTrackSelection> resultList = new ArrayList<>(); List<FakeTrackSelection> resultList = new ArrayList<>();
for (TrackGroupArray trackGroupArray : rendererTrackGroupArrays) { for (TrackGroupArray trackGroupArray : rendererTrackGroupArrays) {
...@@ -76,11 +76,8 @@ public class FakeTrackSelector extends MappingTrackSelector { ...@@ -76,11 +76,8 @@ public class FakeTrackSelector extends MappingTrackSelector {
return trackSelectionForRenderer; return trackSelectionForRenderer;
} }
/** /** Returns list of all {@link FakeTrackSelection}s that this track selector has made so far. */
* Returns list of all {@link FakeTrackSelection}s that this track selector has made so far.
*/
public List<FakeTrackSelection> getSelectedTrackSelections() { public List<FakeTrackSelection> getSelectedTrackSelections() {
return selectedTrackSelections; return selectedTrackSelections;
} }
} }
...@@ -37,9 +37,7 @@ import java.util.concurrent.CountDownLatch; ...@@ -37,9 +37,7 @@ import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
/** /** A runner for {@link MediaSource} tests. */
* A runner for {@link MediaSource} tests.
*/
public class MediaSourceTestRunner { public class MediaSourceTestRunner {
public static final int TIMEOUT_MS = 10000; public static final int TIMEOUT_MS = 10000;
...@@ -78,7 +76,8 @@ public class MediaSourceTestRunner { ...@@ -78,7 +76,8 @@ public class MediaSourceTestRunner {
public void runOnPlaybackThread(final Runnable runnable) { public void runOnPlaybackThread(final Runnable runnable) {
final Throwable[] throwable = new Throwable[1]; final Throwable[] throwable = new Throwable[1];
final ConditionVariable finishedCondition = new ConditionVariable(); final ConditionVariable finishedCondition = new ConditionVariable();
playbackHandler.post(new Runnable() { playbackHandler.post(
new Runnable() {
@Override @Override
public void run() { public void run() {
try { try {
...@@ -103,14 +102,15 @@ public class MediaSourceTestRunner { ...@@ -103,14 +102,15 @@ public class MediaSourceTestRunner {
*/ */
public Timeline prepareSource() throws IOException { public Timeline prepareSource() throws IOException {
final IOException[] prepareError = new IOException[1]; final IOException[] prepareError = new IOException[1];
runOnPlaybackThread(new Runnable() { runOnPlaybackThread(
new Runnable() {
@Override @Override
public void run() { public void run() {
mediaSource.prepareSource(player, true, mediaSourceListener); mediaSource.prepareSource(player, true, mediaSourceListener);
try { try {
// TODO: This only catches errors that are set synchronously in prepareSource. To capture // TODO: This only catches errors that are set synchronously in prepareSource. To
// async errors we'll need to poll maybeThrowSourceInfoRefreshError until the first call // capture async errors we'll need to poll maybeThrowSourceInfoRefreshError until the
// to onSourceInfoRefreshed. // first call to onSourceInfoRefreshed.
mediaSource.maybeThrowSourceInfoRefreshError(); mediaSource.maybeThrowSourceInfoRefreshError();
} catch (IOException e) { } catch (IOException e) {
prepareError[0] = e; prepareError[0] = e;
...@@ -132,7 +132,8 @@ public class MediaSourceTestRunner { ...@@ -132,7 +132,8 @@ public class MediaSourceTestRunner {
*/ */
public MediaPeriod createPeriod(final MediaPeriodId periodId) { public MediaPeriod createPeriod(final MediaPeriodId periodId) {
final MediaPeriod[] holder = new MediaPeriod[1]; final MediaPeriod[] holder = new MediaPeriod[1];
runOnPlaybackThread(new Runnable() { runOnPlaybackThread(
new Runnable() {
@Override @Override
public void run() { public void run() {
holder[0] = mediaSource.createPeriod(periodId, allocator); holder[0] = mediaSource.createPeriod(periodId, allocator);
...@@ -183,7 +184,8 @@ public class MediaSourceTestRunner { ...@@ -183,7 +184,8 @@ public class MediaSourceTestRunner {
* @param mediaPeriod The {@link MediaPeriod} to release. * @param mediaPeriod The {@link MediaPeriod} to release.
*/ */
public void releasePeriod(final MediaPeriod mediaPeriod) { public void releasePeriod(final MediaPeriod mediaPeriod) {
runOnPlaybackThread(new Runnable() { runOnPlaybackThread(
new Runnable() {
@Override @Override
public void run() { public void run() {
mediaSource.releasePeriod(mediaPeriod); mediaSource.releasePeriod(mediaPeriod);
...@@ -191,11 +193,10 @@ public class MediaSourceTestRunner { ...@@ -191,11 +193,10 @@ public class MediaSourceTestRunner {
}); });
} }
/** /** Calls {@link MediaSource#releaseSource()} on the playback thread. */
* Calls {@link MediaSource#releaseSource()} on the playback thread.
*/
public void releaseSource() { public void releaseSource() {
runOnPlaybackThread(new Runnable() { runOnPlaybackThread(
new Runnable() {
@Override @Override
public void run() { public void run() {
mediaSource.releaseSource(); mediaSource.releaseSource();
...@@ -276,9 +277,7 @@ public class MediaSourceTestRunner { ...@@ -276,9 +277,7 @@ public class MediaSourceTestRunner {
releasePeriod(secondMediaPeriod); releasePeriod(secondMediaPeriod);
} }
/** /** Releases the runner. Should be called when the runner is no longer required. */
* Releases the runner. Should be called when the runner is no longer required.
*/
public void release() { public void release() {
playbackThread.quit(); playbackThread.quit();
} }
...@@ -290,7 +289,6 @@ public class MediaSourceTestRunner { ...@@ -290,7 +289,6 @@ public class MediaSourceTestRunner {
Assertions.checkState(Looper.myLooper() == playbackThread.getLooper()); Assertions.checkState(Looper.myLooper() == playbackThread.getLooper());
timelines.addLast(timeline); timelines.addLast(timeline);
} }
} }
private static class EventHandlingExoPlayer extends StubExoPlayer private static class EventHandlingExoPlayer extends StubExoPlayer
...@@ -326,5 +324,4 @@ public class MediaSourceTestRunner { ...@@ -326,5 +324,4 @@ public class MediaSourceTestRunner {
return true; return true;
} }
} }
} }
...@@ -15,20 +15,25 @@ ...@@ -15,20 +15,25 @@
*/ */
package com.google.android.exoplayer2.testutil; package com.google.android.exoplayer2.testutil;
/** /** Provides ogg/vorbis test data in bytes for unit tests. */
* Provides ogg/vorbis test data in bytes for unit tests.
*/
public final class OggTestData { public final class OggTestData {
public static FakeExtractorInput createInput(byte[] data, boolean simulateUnknownLength) { public static FakeExtractorInput createInput(byte[] data, boolean simulateUnknownLength) {
return new FakeExtractorInput.Builder().setData(data).setSimulateIOErrors(true) return new FakeExtractorInput.Builder()
.setSimulateUnknownLength(simulateUnknownLength).setSimulatePartialReads(true).build(); .setData(data)
.setSimulateIOErrors(true)
.setSimulateUnknownLength(simulateUnknownLength)
.setSimulatePartialReads(true)
.build();
} }
public static byte[] buildOggHeader(int headerType, long granule, int pageSequenceCounter, public static byte[] buildOggHeader(
int pageSegmentCount) { int headerType, long granule, int pageSequenceCounter, int pageSegmentCount) {
return TestUtil.createByteArray( return TestUtil.createByteArray(
0x4F, 0x67, 0x67, 0x53, // Oggs. 0x4F,
0x67,
0x67,
0x53, // Oggs.
0x00, // Stream revision. 0x00, // Stream revision.
headerType, headerType,
(int) (granule) & 0xFF, (int) (granule) & 0xFF,
...@@ -60,14 +65,11 @@ public final class OggTestData { ...@@ -60,14 +65,11 @@ public final class OggTestData {
*/ */
public static byte[] getVorbisHeaderPages() { public static byte[] getVorbisHeaderPages() {
byte[] data = new byte[VORBIS_HEADER_PAGES.length]; byte[] data = new byte[VORBIS_HEADER_PAGES.length];
System.arraycopy(VORBIS_HEADER_PAGES, 0, data, 0, System.arraycopy(VORBIS_HEADER_PAGES, 0, data, 0, VORBIS_HEADER_PAGES.length);
VORBIS_HEADER_PAGES.length);
return data; return data;
} }
/** /** Returns a valid vorbis identification header in bytes. */
* Returns a valid vorbis identification header in bytes.
*/
public static byte[] getIdentificationHeaderData() { public static byte[] getIdentificationHeaderData() {
int idHeaderStart = 28; int idHeaderStart = 28;
int idHeaderLength = 30; int idHeaderLength = 30;
...@@ -76,19 +78,15 @@ public final class OggTestData { ...@@ -76,19 +78,15 @@ public final class OggTestData {
return idHeaderData; return idHeaderData;
} }
/** /** Returns a valid vorbis comment header with 3 comments including utf8 chars in bytes. */
* Returns a valid vorbis comment header with 3 comments including utf8 chars in bytes.
*/
public static byte[] getCommentHeaderDataUTF8() { public static byte[] getCommentHeaderDataUTF8() {
byte[] commentHeaderData = new byte[COMMENT_HEADER_WITH_UTF8.length]; byte[] commentHeaderData = new byte[COMMENT_HEADER_WITH_UTF8.length];
System.arraycopy(COMMENT_HEADER_WITH_UTF8, 0, commentHeaderData, 0, System.arraycopy(
COMMENT_HEADER_WITH_UTF8.length); COMMENT_HEADER_WITH_UTF8, 0, commentHeaderData, 0, COMMENT_HEADER_WITH_UTF8.length);
return commentHeaderData; return commentHeaderData;
} }
/** /** Returns a valid vorbis setup header in bytes. */
* Returns a valid vorbis setup header in bytes.
*/
public static byte[] getSetupHeaderData() { public static byte[] getSetupHeaderData() {
int setupHeaderStart = 146; int setupHeaderStart = 146;
int setupHeaderLength = VORBIS_HEADER_PAGES.length - setupHeaderStart; int setupHeaderLength = VORBIS_HEADER_PAGES.length - setupHeaderStart;
...@@ -1069,5 +1067,4 @@ public final class OggTestData { ...@@ -1069,5 +1067,4 @@ public final class OggTestData {
(byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x04, (byte) 0x04 (byte) 0x00, (byte) 0x04, (byte) 0x04
}; };
} }
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.android.exoplayer2; package com.google.android.exoplayer2.testutil;
import static org.robolectric.Shadows.shadowOf; import static org.robolectric.Shadows.shadowOf;
import static org.robolectric.util.ReflectionHelpers.callInstanceMethod; import static org.robolectric.util.ReflectionHelpers.callInstanceMethod;
......
...@@ -271,5 +271,4 @@ public abstract class StubExoPlayer implements ExoPlayer { ...@@ -271,5 +271,4 @@ public abstract class StubExoPlayer implements ExoPlayer {
public long getContentPosition() { public long getContentPosition() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
} }
...@@ -23,9 +23,7 @@ import com.google.android.exoplayer2.Timeline; ...@@ -23,9 +23,7 @@ import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.Timeline.Period; import com.google.android.exoplayer2.Timeline.Period;
import com.google.android.exoplayer2.Timeline.Window; import com.google.android.exoplayer2.Timeline.Window;
/** /** Unit test for {@link Timeline}. */
* Unit test for {@link Timeline}.
*/
public final class TimelineAsserts { public final class TimelineAsserts {
private static final int[] REPEAT_MODES = { private static final int[] REPEAT_MODES = {
...@@ -34,9 +32,7 @@ public final class TimelineAsserts { ...@@ -34,9 +32,7 @@ public final class TimelineAsserts {
private TimelineAsserts() {} private TimelineAsserts() {}
/** /** Assert that timeline is empty (i.e. has no windows or periods). */
* Assert that timeline is empty (i.e. has no windows or periods).
*/
public static void assertEmpty(Timeline timeline) { public static void assertEmpty(Timeline timeline) {
assertWindowIds(timeline); assertWindowIds(timeline);
assertPeriodCounts(timeline); assertPeriodCounts(timeline);
...@@ -63,9 +59,7 @@ public final class TimelineAsserts { ...@@ -63,9 +59,7 @@ public final class TimelineAsserts {
} }
} }
/** /** Asserts that window properties {@link Window}.isDynamic are set correctly. */
* Asserts that window properties {@link Window}.isDynamic are set correctly.
*/
public static void assertWindowIsDynamic(Timeline timeline, boolean... windowIsDynamic) { public static void assertWindowIsDynamic(Timeline timeline, boolean... windowIsDynamic) {
Window window = new Window(); Window window = new Window();
for (int i = 0; i < timeline.getWindowCount(); i++) { for (int i = 0; i < timeline.getWindowCount(); i++) {
...@@ -78,8 +72,10 @@ public final class TimelineAsserts { ...@@ -78,8 +72,10 @@ public final class TimelineAsserts {
* Asserts that previous window indices for each window depending on the repeat mode and the * Asserts that previous window indices for each window depending on the repeat mode and the
* shuffle mode are equal to the given sequence. * shuffle mode are equal to the given sequence.
*/ */
public static void assertPreviousWindowIndices(Timeline timeline, public static void assertPreviousWindowIndices(
@Player.RepeatMode int repeatMode, boolean shuffleModeEnabled, Timeline timeline,
@Player.RepeatMode int repeatMode,
boolean shuffleModeEnabled,
int... expectedPreviousWindowIndices) { int... expectedPreviousWindowIndices) {
for (int i = 0; i < timeline.getWindowCount(); i++) { for (int i = 0; i < timeline.getWindowCount(); i++) {
assertThat(timeline.getPreviousWindowIndex(i, repeatMode, shuffleModeEnabled)) assertThat(timeline.getPreviousWindowIndex(i, repeatMode, shuffleModeEnabled))
...@@ -88,11 +84,14 @@ public final class TimelineAsserts { ...@@ -88,11 +84,14 @@ public final class TimelineAsserts {
} }
/** /**
* Asserts that next window indices for each window depending on the repeat mode and the * Asserts that next window indices for each window depending on the repeat mode and the shuffle
* shuffle mode are equal to the given sequence. * mode are equal to the given sequence.
*/ */
public static void assertNextWindowIndices(Timeline timeline, @Player.RepeatMode int repeatMode, public static void assertNextWindowIndices(
boolean shuffleModeEnabled, int... expectedNextWindowIndices) { Timeline timeline,
@Player.RepeatMode int repeatMode,
boolean shuffleModeEnabled,
int... expectedNextWindowIndices) {
for (int i = 0; i < timeline.getWindowCount(); i++) { for (int i = 0; i < timeline.getWindowCount(); i++) {
assertThat(timeline.getNextWindowIndex(i, repeatMode, shuffleModeEnabled)) assertThat(timeline.getNextWindowIndex(i, repeatMode, shuffleModeEnabled))
.isEqualTo(expectedNextWindowIndices[i]); .isEqualTo(expectedNextWindowIndices[i]);
...@@ -113,9 +112,9 @@ public final class TimelineAsserts { ...@@ -113,9 +112,9 @@ public final class TimelineAsserts {
} }
/** /**
* Asserts that period counts for each window are set correctly. Also asserts that * Asserts that period counts for each window are set correctly. Also asserts that {@link
* {@link Window#firstPeriodIndex} and {@link Window#lastPeriodIndex} are set correctly, and it * Window#firstPeriodIndex} and {@link Window#lastPeriodIndex} are set correctly, and it asserts
* asserts the correct behavior of {@link Timeline#getNextWindowIndex(int, int, boolean)}. * the correct behavior of {@link Timeline#getNextWindowIndex(int, int, boolean)}.
*/ */
public static void assertPeriodCounts(Timeline timeline, int... expectedPeriodCounts) { public static void assertPeriodCounts(Timeline timeline, int... expectedPeriodCounts) {
int windowCount = timeline.getWindowCount(); int windowCount = timeline.getWindowCount();
...@@ -147,8 +146,8 @@ public final class TimelineAsserts { ...@@ -147,8 +146,8 @@ public final class TimelineAsserts {
.isEqualTo(i + 1); .isEqualTo(i + 1);
} else { } else {
int nextWindow = timeline.getNextWindowIndex(expectedWindowIndex, repeatMode, false); int nextWindow = timeline.getNextWindowIndex(expectedWindowIndex, repeatMode, false);
int nextPeriod = nextWindow == C.INDEX_UNSET ? C.INDEX_UNSET int nextPeriod =
: accumulatedPeriodCounts[nextWindow]; nextWindow == C.INDEX_UNSET ? C.INDEX_UNSET : accumulatedPeriodCounts[nextWindow];
assertThat(timeline.getNextPeriodIndex(i, period, window, repeatMode, false)) assertThat(timeline.getNextPeriodIndex(i, period, window, repeatMode, false))
.isEqualTo(nextPeriod); .isEqualTo(nextPeriod);
} }
...@@ -156,9 +155,7 @@ public final class TimelineAsserts { ...@@ -156,9 +155,7 @@ public final class TimelineAsserts {
} }
} }
/** /** Asserts that periods' {@link Period#getAdGroupCount()} are set correctly. */
* Asserts that periods' {@link Period#getAdGroupCount()} are set correctly.
*/
public static void assertAdGroupCounts(Timeline timeline, int... expectedAdGroupCounts) { public static void assertAdGroupCounts(Timeline timeline, int... expectedAdGroupCounts) {
Period period = new Period(); Period period = new Period();
for (int i = 0; i < timeline.getPeriodCount(); i++) { for (int i = 0; i < timeline.getPeriodCount(); i++) {
...@@ -166,5 +163,4 @@ public final class TimelineAsserts { ...@@ -166,5 +163,4 @@ public final class TimelineAsserts {
assertThat(period.getAdGroupCount()).isEqualTo(expectedAdGroupCounts[i]); assertThat(period.getAdGroupCount()).isEqualTo(expectedAdGroupCounts[i]);
} }
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment