@@ -12,15 +12,21 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
1212import androidx.test.filters.MediumTest
1313import androidx.test.internal.runner.junit4.statement.UiThreadStatement
1414import org.junit.Assert
15+ import org.junit.Assert.assertEquals
16+ import org.junit.Assert.assertFalse
17+ import org.junit.Assert.assertNull
18+ import org.junit.Assert.assertTrue
1519import org.junit.Before
1620import org.junit.Test
1721import org.junit.runner.RunWith
1822import org.schabi.newpipe.R
1923import org.schabi.newpipe.extractor.MediaFormat
24+ import org.schabi.newpipe.extractor.downloader.Response
2025import org.schabi.newpipe.extractor.stream.AudioStream
2126import org.schabi.newpipe.extractor.stream.Stream
2227import org.schabi.newpipe.extractor.stream.SubtitlesStream
2328import org.schabi.newpipe.extractor.stream.VideoStream
29+ import org.schabi.newpipe.util.StreamItemAdapter.StreamInfoWrapper
2430
2531@MediumTest
2632@RunWith(AndroidJUnit4 ::class )
@@ -84,7 +90,7 @@ class StreamItemAdapterTest {
8490 @Test
8591 fun subtitleStreams_noIcon () {
8692 val adapter = StreamItemAdapter <SubtitlesStream , Stream >(
87- StreamItemAdapter .StreamSizeWrapper (
93+ StreamItemAdapter .StreamInfoWrapper (
8894 (0 until 5 ).map {
8995 SubtitlesStream .Builder ()
9096 .setContent(" https://example.com" , true )
@@ -105,7 +111,7 @@ class StreamItemAdapterTest {
105111 @Test
106112 fun audioStreams_noIcon () {
107113 val adapter = StreamItemAdapter <AudioStream , Stream >(
108- StreamItemAdapter .StreamSizeWrapper (
114+ StreamItemAdapter .StreamInfoWrapper (
109115 (0 until 5 ).map {
110116 AudioStream .Builder ()
111117 .setId(Stream .ID_UNKNOWN )
@@ -123,12 +129,109 @@ class StreamItemAdapterTest {
123129 }
124130 }
125131
132+ @Test
133+ fun retrieveMediaFormatFromFileTypeHeaders () {
134+ val streams = getIncompleteAudioStreams(5 )
135+ val wrapper = StreamInfoWrapper (streams, context)
136+ val retrieveMediaFormat = { stream: AudioStream , response: Response ->
137+ StreamInfoWrapper .retrieveMediaFormatFromFileTypeHeaders(stream, wrapper, response)
138+ }
139+ val helper = AssertionHelper (streams, wrapper, retrieveMediaFormat)
140+
141+ helper.assertInvalidResponse(getResponse(mapOf (Pair (" content-length" , " mp3" ))), 0 )
142+ helper.assertInvalidResponse(getResponse(mapOf (Pair (" file-type" , " mp0" ))), 1 )
143+
144+ helper.assertValidResponse(getResponse(mapOf (Pair (" x-amz-meta-file-type" , " aiff" ))), 2 , MediaFormat .AIFF )
145+ helper.assertValidResponse(getResponse(mapOf (Pair (" file-type" , " mp3" ))), 3 , MediaFormat .MP3 )
146+ }
147+
148+ @Test
149+ fun retrieveMediaFormatFromContentDispositionHeader () {
150+ val streams = getIncompleteAudioStreams(11 )
151+ val wrapper = StreamInfoWrapper (streams, context)
152+ val retrieveMediaFormat = { stream: AudioStream , response: Response ->
153+ StreamInfoWrapper .retrieveMediaFormatFromContentDispositionHeader(stream, wrapper, response)
154+ }
155+ val helper = AssertionHelper (streams, wrapper, retrieveMediaFormat)
156+
157+ helper.assertInvalidResponse(getResponse(mapOf (Pair (" content-length" , " mp3" ))), 0 )
158+ helper.assertInvalidResponse(
159+ getResponse(mapOf (Pair (" Content-Disposition" , " filename=\" train.png\" " ))), 1
160+ )
161+ helper.assertInvalidResponse(
162+ getResponse(mapOf (Pair (" Content-Disposition" , " form-data; name=\" data.csv\" " ))), 2
163+ )
164+ helper.assertInvalidResponse(
165+ getResponse(mapOf (Pair (" Content-Disposition" , " form-data; filename=\" data.csv\" " ))), 3
166+ )
167+ helper.assertInvalidResponse(
168+ getResponse(mapOf (Pair (" Content-Disposition" , " form-data; name=\" fieldName\" ; filename*=\" filename.jpg\" " ))), 4
169+ )
170+
171+ helper.assertValidResponse(
172+ getResponse(mapOf (Pair (" Content-Disposition" , " filename=\" train.ogg\" " ))),
173+ 5 , MediaFormat .OGG
174+ )
175+ helper.assertValidResponse(
176+ getResponse(mapOf (Pair (" Content-Disposition" , " some-form-data; filename=\" audio.flac\" " ))),
177+ 6 , MediaFormat .FLAC
178+ )
179+ helper.assertValidResponse(
180+ getResponse(mapOf (Pair (" Content-Disposition" , " form-data; name=\" audio.aiff\" ; filename=\" audio.aiff\" " ))),
181+ 7 , MediaFormat .AIFF
182+ )
183+ helper.assertValidResponse(
184+ getResponse(mapOf (Pair (" Content-Disposition" , " form-data; name=\" alien?\" ; filename*=UTF-8''%CE%B1%CE%BB%CE%B9%CF%B5%CE%BD.m4a" ))),
185+ 8 , MediaFormat .M4A
186+ )
187+ helper.assertValidResponse(
188+ getResponse(mapOf (Pair (" Content-Disposition" , " form-data; name=\" audio.mp3\" ; filename=\" audio.opus\" ; filename*=UTF-8''alien.opus" ))),
189+ 9 , MediaFormat .OPUS
190+ )
191+ helper.assertValidResponse(
192+ getResponse(mapOf (Pair (" Content-Disposition" , " form-data; name=\" audio.mp3\" ; filename=\" audio.opus\" ; filename*=\" UTF-8''alien.opus\" " ))),
193+ 10 , MediaFormat .OPUS
194+ )
195+ }
196+
197+ @Test
198+ fun retrieveMediaFormatFromContentTypeHeader () {
199+ val streams = getIncompleteAudioStreams(12 )
200+ val wrapper = StreamInfoWrapper (streams, context)
201+ val retrieveMediaFormat = { stream: AudioStream , response: Response ->
202+ StreamInfoWrapper .retrieveMediaFormatFromContentTypeHeader(stream, wrapper, response)
203+ }
204+ val helper = AssertionHelper (streams, wrapper, retrieveMediaFormat)
205+
206+ helper.assertInvalidResponse(getResponse(mapOf (Pair (" content-length" , " 984501" ))), 0 )
207+ helper.assertInvalidResponse(getResponse(mapOf (Pair (" Content-Type" , " audio/xyz" ))), 1 )
208+ helper.assertInvalidResponse(getResponse(mapOf (Pair (" Content-Type" , " mp3" ))), 2 )
209+ helper.assertInvalidResponse(getResponse(mapOf (Pair (" Content-Type" , " mp3" ))), 3 )
210+ helper.assertInvalidResponse(getResponse(mapOf (Pair (" Content-Type" , " audio/mpeg" ))), 4 )
211+ helper.assertInvalidResponse(getResponse(mapOf (Pair (" Content-Type" , " audio/aif" ))), 5 )
212+ helper.assertInvalidResponse(getResponse(mapOf (Pair (" Content-Type" , " whatever" ))), 6 )
213+ helper.assertInvalidResponse(getResponse(mapOf ()), 7 )
214+
215+ helper.assertValidResponse(
216+ getResponse(mapOf (Pair (" Content-Type" , " audio/flac" ))), 8 , MediaFormat .FLAC
217+ )
218+ helper.assertValidResponse(
219+ getResponse(mapOf (Pair (" Content-Type" , " audio/wav" ))), 9 , MediaFormat .WAV
220+ )
221+ helper.assertValidResponse(
222+ getResponse(mapOf (Pair (" Content-Type" , " audio/opus" ))), 10 , MediaFormat .OPUS
223+ )
224+ helper.assertValidResponse(
225+ getResponse(mapOf (Pair (" Content-Type" , " audio/aiff" ))), 11 , MediaFormat .AIFF
226+ )
227+ }
228+
126229 /* *
127230 * @return a list of video streams, in which their video only property mirrors the provided
128231 * [videoOnly] vararg.
129232 */
130233 private fun getVideoStreams (vararg videoOnly : Boolean ) =
131- StreamItemAdapter .StreamSizeWrapper (
234+ StreamItemAdapter .StreamInfoWrapper (
132235 videoOnly.map {
133236 VideoStream .Builder ()
134237 .setId(Stream .ID_UNKNOWN )
@@ -161,6 +264,19 @@ class StreamItemAdapterTest {
161264 }
162265 )
163266
267+ private fun getIncompleteAudioStreams (size : Int ): List <AudioStream > {
268+ val list = ArrayList <AudioStream >(size)
269+ for (i in 1 .. size) {
270+ list.add(
271+ AudioStream .Builder ()
272+ .setId(Stream .ID_UNKNOWN )
273+ .setContent(" https://example.com/$i " , true )
274+ .build()
275+ )
276+ }
277+ return list
278+ }
279+
164280 /* *
165281 * Checks whether the item at [position] in the [spinner] has the correct icon visibility when
166282 * it is shown in normal mode (selected) and in dropdown mode (user is choosing one of a list).
@@ -196,11 +312,56 @@ class StreamItemAdapterTest {
196312 streams.forEachIndexed { index, stream ->
197313 val secondaryStreamHelper: SecondaryStreamHelper <T >? = stream?.let {
198314 SecondaryStreamHelper (
199- StreamItemAdapter .StreamSizeWrapper (streams, context),
315+ StreamItemAdapter .StreamInfoWrapper (streams, context),
200316 it
201317 )
202318 }
203319 put(index, secondaryStreamHelper)
204320 }
205321 }
322+
323+ private fun getResponse (headers : Map <String , String >): Response {
324+ val listHeaders = HashMap <String , List <String >>()
325+ headers.forEach { entry ->
326+ listHeaders[entry.key] = listOf (entry.value)
327+ }
328+ return Response (200 , null , listHeaders, " " , " " )
329+ }
330+
331+ /* *
332+ * Helper class for assertion related to extractions of [MediaFormat]s.
333+ */
334+ class AssertionHelper <T : Stream >(
335+ private val streams : List <T >,
336+ private val wrapper : StreamInfoWrapper <T >,
337+ private val retrieveMediaFormat : (stream: T , response: Response ) -> Boolean
338+ ) {
339+
340+ /* *
341+ * Assert that an invalid response does not result in wrongly extracted [MediaFormat].
342+ */
343+ fun assertInvalidResponse (
344+ response : Response ,
345+ index : Int
346+ ) {
347+ assertFalse(
348+ " invalid header returns valid value" , retrieveMediaFormat(streams[index], response)
349+ )
350+ assertNull(" Media format extracted although stated otherwise" , wrapper.getFormat(index))
351+ }
352+
353+ /* *
354+ * Assert that a valid response results in correctly extracted and handled [MediaFormat].
355+ */
356+ fun assertValidResponse (
357+ response : Response ,
358+ index : Int ,
359+ format : MediaFormat
360+ ) {
361+ assertTrue(
362+ " header was not recognized" , retrieveMediaFormat(streams[index], response)
363+ )
364+ assertEquals(" Wrong media format extracted" , format, wrapper.getFormat(index))
365+ }
366+ }
206367}
0 commit comments