Add tests for new methods retrieving MediaFormats

Fix failing tests
This commit is contained in:
TobiGr 2023-08-14 23:05:38 +02:00
parent f3859ed710
commit e51067177e
2 changed files with 169 additions and 4 deletions

View File

@ -12,15 +12,21 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest import androidx.test.filters.MediumTest
import androidx.test.internal.runner.junit4.statement.UiThreadStatement import androidx.test.internal.runner.junit4.statement.UiThreadStatement
import org.junit.Assert import org.junit.Assert
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.schabi.newpipe.R import org.schabi.newpipe.R
import org.schabi.newpipe.extractor.MediaFormat import org.schabi.newpipe.extractor.MediaFormat
import org.schabi.newpipe.extractor.downloader.Response
import org.schabi.newpipe.extractor.stream.AudioStream import org.schabi.newpipe.extractor.stream.AudioStream
import org.schabi.newpipe.extractor.stream.Stream import org.schabi.newpipe.extractor.stream.Stream
import org.schabi.newpipe.extractor.stream.SubtitlesStream import org.schabi.newpipe.extractor.stream.SubtitlesStream
import org.schabi.newpipe.extractor.stream.VideoStream import org.schabi.newpipe.extractor.stream.VideoStream
import org.schabi.newpipe.util.StreamItemAdapter.StreamInfoWrapper
@MediumTest @MediumTest
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
@ -123,6 +129,101 @@ class StreamItemAdapterTest {
} }
} }
@Test
fun retrieveMediaFormatFromFileTypeHeaders() {
val streams = getIncompleteAudioStreams(5)
val wrapper = StreamInfoWrapper(streams, context)
val retrieveMediaFormat = { stream: AudioStream, response: Response ->
StreamInfoWrapper.retrieveMediaFormatFromFileTypeHeaders(stream, wrapper, response)
}
val helper = AssertionHelper(streams, wrapper, retrieveMediaFormat)
helper.assertInvalidResponse(getResponse(mapOf(Pair("content-length", "mp3"))), 0)
helper.assertInvalidResponse(getResponse(mapOf(Pair("file-type", "mp0"))), 1)
helper.assertValidResponse(getResponse(mapOf(Pair("x-amz-meta-file-type", "aiff"))), 2, MediaFormat.AIFF)
helper.assertValidResponse(getResponse(mapOf(Pair("file-type", "mp3"))), 3, MediaFormat.MP3)
}
@Test
fun retrieveMediaFormatFromContentDispositionHeader() {
val streams = getIncompleteAudioStreams(11)
val wrapper = StreamInfoWrapper(streams, context)
val retrieveMediaFormat = { stream: AudioStream, response: Response ->
StreamInfoWrapper.retrieveMediaFormatFromContentDispositionHeader(stream, wrapper, response)
}
val helper = AssertionHelper(streams, wrapper, retrieveMediaFormat)
helper.assertInvalidResponse(getResponse(mapOf(Pair("content-length", "mp3"))), 0)
helper.assertInvalidResponse(
getResponse(mapOf(Pair("Content-Disposition", "filename=\"train.png\""))), 1
)
helper.assertInvalidResponse(
getResponse(mapOf(Pair("Content-Disposition", "form-data; name=\"data.csv\""))), 2
)
helper.assertInvalidResponse(
getResponse(mapOf(Pair("Content-Disposition", "form-data; filename=\"data.csv\""))), 3
)
helper.assertInvalidResponse(
getResponse(mapOf(Pair("Content-Disposition", "form-data; name=\"fieldName\"; filename*=\"filename.jpg\""))), 4
)
helper.assertValidResponse(
getResponse(mapOf(Pair("Content-Disposition", "filename=\"train.ogg\""))),
5, MediaFormat.OGG
)
helper.assertValidResponse(
getResponse(mapOf(Pair("Content-Disposition", "some-form-data; filename=\"audio.flac\""))),
6, MediaFormat.FLAC
)
helper.assertValidResponse(
getResponse(mapOf(Pair("Content-Disposition", "form-data; name=\"audio.aiff\"; filename=\"audio.aiff\""))),
7, MediaFormat.AIFF
)
helper.assertValidResponse(
getResponse(mapOf(Pair("Content-Disposition", "form-data; name=\"alien?\"; filename*=UTF-8''%CE%B1%CE%BB%CE%B9%CF%B5%CE%BD.m4a"))),
8, MediaFormat.M4A
)
helper.assertValidResponse(
getResponse(mapOf(Pair("Content-Disposition", "form-data; name=\"audio.mp3\"; filename=\"audio.opus\"; filename*=UTF-8''alien.opus"))),
9, MediaFormat.OPUS
)
helper.assertValidResponse(
getResponse(mapOf(Pair("Content-Disposition", "form-data; name=\"audio.mp3\"; filename=\"audio.opus\"; filename*=\"UTF-8''alien.opus\""))),
10, MediaFormat.OPUS
)
}
@Test
fun retrieveMediaFormatFromContentTypeHeader() {
val streams = getIncompleteAudioStreams(10)
val wrapper = StreamInfoWrapper(streams, context)
val retrieveMediaFormat = { stream: AudioStream, response: Response ->
StreamInfoWrapper.retrieveMediaFormatFromContentTypeHeader(stream, wrapper, response)
}
val helper = AssertionHelper(streams, wrapper, retrieveMediaFormat)
helper.assertInvalidResponse(getResponse(mapOf(Pair("content-length", "984501"))), 0)
helper.assertInvalidResponse(getResponse(mapOf(Pair("Content-Type", "audio/xyz"))), 1)
helper.assertInvalidResponse(getResponse(mapOf(Pair("Content-Type", "mp3"))), 2)
helper.assertInvalidResponse(getResponse(mapOf(Pair("Content-Type", "mp3"))), 3)
helper.assertInvalidResponse(getResponse(mapOf(Pair("Content-Type", "audio/mpeg"))), 4)
helper.assertInvalidResponse(getResponse(mapOf(Pair("Content-Type", "audio/aif"))), 5)
helper.assertValidResponse(
getResponse(mapOf(Pair("Content-Type", "audio/flac"))), 6, MediaFormat.FLAC
)
helper.assertValidResponse(
getResponse(mapOf(Pair("Content-Type", "audio/wav"))), 7, MediaFormat.WAV
)
helper.assertValidResponse(
getResponse(mapOf(Pair("Content-Type", "audio/opus"))), 8, MediaFormat.OPUS
)
helper.assertValidResponse(
getResponse(mapOf(Pair("Content-Type", "audio/aiff"))), 9, MediaFormat.AIFF
)
}
/** /**
* @return a list of video streams, in which their video only property mirrors the provided * @return a list of video streams, in which their video only property mirrors the provided
* [videoOnly] vararg. * [videoOnly] vararg.
@ -161,6 +262,19 @@ class StreamItemAdapterTest {
} }
) )
private fun getIncompleteAudioStreams(size: Int): List<AudioStream> {
val list = ArrayList<AudioStream>(size)
for (i in 1..size) {
list.add(
AudioStream.Builder()
.setId(Stream.ID_UNKNOWN)
.setContent("https://example.com/$i", true)
.build()
)
}
return list
}
/** /**
* Checks whether the item at [position] in the [spinner] has the correct icon visibility when * Checks whether the item at [position] in the [spinner] has the correct icon visibility when
* it is shown in normal mode (selected) and in dropdown mode (user is choosing one of a list). * it is shown in normal mode (selected) and in dropdown mode (user is choosing one of a list).
@ -203,4 +317,49 @@ class StreamItemAdapterTest {
put(index, secondaryStreamHelper) put(index, secondaryStreamHelper)
} }
} }
private fun getResponse(headers: Map<String, String>): Response {
val listHeaders = HashMap<String, List<String>>()
headers.forEach { entry ->
listHeaders[entry.key] = listOf(entry.value)
}
return Response(200, null, listHeaders, "", "")
}
/**
* Helper class for assertion related to extractions of [MediaFormat]s.
*/
class AssertionHelper<T : Stream>(
private val streams: List<T>,
private val wrapper: StreamInfoWrapper<T>,
private val retrieveMediaFormat: (stream: T, response: Response) -> Boolean
) {
/**
* Assert that an invalid response does not result in wrongly extracted [MediaFormat].
*/
fun assertInvalidResponse(
response: Response,
index: Int
) {
assertFalse(
"invalid header returns valid value", retrieveMediaFormat(streams[index], response)
)
assertNull("Media format extracted although stated otherwise", wrapper.getFormat(index))
}
/**
* Assert that a valid response results in correctly extracted and handled [MediaFormat].
*/
fun assertValidResponse(
response: Response,
index: Int,
format: MediaFormat
) {
assertTrue(
"header was not recognized", retrieveMediaFormat(streams[index], response)
)
assertEquals("Wrong media format extracted", format, wrapper.getFormat(index))
}
}
} }

View File

@ -13,6 +13,7 @@ import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.collection.SparseArrayCompat; import androidx.collection.SparseArrayCompat;
import org.schabi.newpipe.DownloaderImpl; import org.schabi.newpipe.DownloaderImpl;
@ -298,7 +299,8 @@ public class StreamItemAdapter<T extends Stream, U extends Stream> extends BaseA
* @param response the response of the head request for the given stream * @param response the response of the head request for the given stream
* @return {@code true} if the media format could be retrieved; {@code false} otherwise * @return {@code true} if the media format could be retrieved; {@code false} otherwise
*/ */
private static <X extends Stream> boolean retrieveMediaFormat( @VisibleForTesting
public static <X extends Stream> boolean retrieveMediaFormat(
@NonNull final X stream, @NonNull final X stream,
@NonNull final StreamInfoWrapper<X> streamsWrapper, @NonNull final StreamInfoWrapper<X> streamsWrapper,
@NonNull final Response response) { @NonNull final Response response) {
@ -308,7 +310,8 @@ public class StreamItemAdapter<T extends Stream, U extends Stream> extends BaseA
|| retrieveMediaFormatFromContentTypeHeader(stream, streamsWrapper, response); || retrieveMediaFormatFromContentTypeHeader(stream, streamsWrapper, response);
} }
private static <X extends Stream> boolean retrieveMediaFormatFromFileTypeHeaders( @VisibleForTesting
public static <X extends Stream> boolean retrieveMediaFormatFromFileTypeHeaders(
@NonNull final X stream, @NonNull final X stream,
@NonNull final StreamInfoWrapper<X> streamsWrapper, @NonNull final StreamInfoWrapper<X> streamsWrapper,
@NonNull final Response response) { @NonNull final Response response) {
@ -342,6 +345,7 @@ public class StreamItemAdapter<T extends Stream, U extends Stream> extends BaseA
* otherwise {@code false} * otherwise {@code false}
* @param <X> * @param <X>
*/ */
@VisibleForTesting
public static <X extends Stream> boolean retrieveMediaFormatFromContentDispositionHeader( public static <X extends Stream> boolean retrieveMediaFormatFromContentDispositionHeader(
@NonNull final X stream, @NonNull final X stream,
@NonNull final StreamInfoWrapper<X> streamsWrapper, @NonNull final StreamInfoWrapper<X> streamsWrapper,
@ -391,7 +395,8 @@ public class StreamItemAdapter<T extends Stream, U extends Stream> extends BaseA
return false; return false;
} }
private static <X extends Stream> boolean retrieveMediaFormatFromContentTypeHeader( @VisibleForTesting
public static <X extends Stream> boolean retrieveMediaFormatFromContentTypeHeader(
@NonNull final X stream, @NonNull final X stream,
@NonNull final StreamInfoWrapper<X> streamsWrapper, @NonNull final StreamInfoWrapper<X> streamsWrapper,
@NonNull final Response response) { @NonNull final Response response) {
@ -416,7 +421,8 @@ public class StreamItemAdapter<T extends Stream, U extends Stream> extends BaseA
public void resetInfo() { public void resetInfo() {
Arrays.fill(streamSizes, SIZE_UNSET); Arrays.fill(streamSizes, SIZE_UNSET);
for (int i = 0; i < streamsList.size(); i++) { for (int i = 0; i < streamsList.size(); i++) {
streamFormats[i] = streamsList.get(i).getFormat(); streamFormats[i] = streamsList.get(i) == null // test for invalid streams
? null : streamsList.get(i).getFormat();
} }
} }