MediaPlayerMetadataParserTest.java revision c39173be3237be9f39d2b57bb38249126e183c53
1/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.mediaframeworktest.unit;
18import android.media.Metadata;
19import android.os.Parcel;
20import android.test.AndroidTestCase;
21import android.test.suitebuilder.annotation.SmallTest;
22import android.util.Log;
23
24import java.util.Calendar;
25import java.util.Date;
26
27/*
28 * Check the Java layer that parses serialized metadata in Parcel
29 * works as expected.
30 *
31 */
32
33public class MediaPlayerMetadataParserTest extends AndroidTestCase {
34    private static final String TAG = "MediaPlayerMetadataTest";
35    private static final int kToken = 0xdeadbeef;
36    private static final int kMarker = 0x4d455441;  // 'M' 'E' 'T' 'A'
37    private static final int kHeaderSize = 8;
38
39    private Metadata mMetadata = null;
40    private Parcel mParcel = null;
41
42    @Override
43    protected void setUp() throws Exception {
44        super.setUp();
45        mMetadata = new Metadata();
46        mParcel = Parcel.obtain();
47
48        resetParcel();
49    }
50
51    // Check parsing of the parcel fails. Make sure the parser rewind
52    // the parcel properly.
53    private void assertParseFail() throws Exception {
54        mParcel.setDataPosition(0);
55        assertFalse(mMetadata.parse(mParcel));
56        assertEquals(0, mParcel.dataPosition());
57    }
58
59    // Check parsing of the parcel is successful.
60    private void assertParse() throws Exception {
61        mParcel.setDataPosition(0);
62        assertTrue(mMetadata.parse(mParcel));
63    }
64
65    // Write the number of bytes from the start of the parcel to the
66    // current position at the beginning of the parcel (offset 0).
67    private void adjustSize() {
68        adjustSize(0);
69    }
70
71    // Write the number of bytes from the offset to the current
72    // position at position pointed by offset.
73    private void adjustSize(int offset) {
74        final int pos = mParcel.dataPosition();
75
76        mParcel.setDataPosition(offset);
77        mParcel.writeInt(pos - offset);
78        mParcel.setDataPosition(pos);
79    }
80
81    // Rewind the parcel and insert the header.
82    private void resetParcel() {
83        mParcel.setDataPosition(0);
84        // Most tests will use a properly formed parcel with a size
85        // and the meta marker so we add them by default.
86        mParcel.writeInt(-1);  // Placeholder for the size
87        mParcel.writeInt(kMarker);
88    }
89
90    // ----------------------------------------------------------------------
91    // START OF THE TESTS
92
93
94    // There should be at least 8 bytes in the parcel, 4 for the size
95    // and 4 for the 'M' 'E' 'T' 'A' marker.
96    @SmallTest
97    public void testMissingSizeAndMarker() throws Exception {
98        for (int i = 0; i < kHeaderSize; ++i) {
99            mParcel.setDataPosition(0);
100            mParcel.setDataSize(i);
101
102            assertEquals(i, mParcel.dataAvail());
103            assertParseFail();
104        }
105    }
106
107    // There should be at least 'size' bytes in the parcel.
108    @SmallTest
109    public void testMissingData() throws Exception {
110        final int size = 20;
111
112        mParcel.writeInt(size);
113        mParcel.setDataSize(size - 1);
114        assertParseFail();
115    }
116
117    // Empty parcel is fine
118    @SmallTest
119    public void testEmptyIsOk() throws Exception {
120        adjustSize();
121        assertParse();
122    }
123
124    // ----------------------------------------------------------------------
125    // RECORDS
126    // ----------------------------------------------------------------------
127
128    // A record header should be at least 12 bytes long
129    @SmallTest
130    public void testRecordMissingId() throws Exception {
131        mParcel.writeInt(13); // record length
132        // misses metadata id and metadata type.
133        adjustSize();
134        assertParseFail();
135    }
136
137    @SmallTest
138    public void testRecordMissingType() throws Exception {
139        mParcel.writeInt(13); // record length lies
140        mParcel.writeInt(Metadata.TITLE);
141        // misses metadata type
142        adjustSize();
143        assertParseFail();
144    }
145
146    @SmallTest
147    public void testRecordWithZeroPayload() throws Exception {
148        mParcel.writeInt(0);
149        adjustSize();
150        assertParseFail();
151    }
152
153    // A record cannot be empty.
154    @SmallTest
155    public void testRecordMissingPayload() throws Exception {
156        mParcel.writeInt(12);
157        mParcel.writeInt(Metadata.TITLE);
158        mParcel.writeInt(Metadata.STRING_VAL);
159        // misses payload
160        adjustSize();
161        assertParseFail();
162    }
163
164    // Check records can be found.
165    @SmallTest
166    public void testRecordsFound() throws Exception {
167        writeStringRecord(Metadata.TITLE, "a title");
168        writeStringRecord(Metadata.GENRE, "comedy");
169        writeStringRecord(Metadata.firstCustomId(), "custom");
170        adjustSize();
171        assertParse();
172        assertTrue(mMetadata.has(Metadata.TITLE));
173        assertTrue(mMetadata.has(Metadata.GENRE));
174        assertTrue(mMetadata.has(Metadata.firstCustomId()));
175        assertFalse(mMetadata.has(Metadata.DRM_CRIPPLED));
176        assertEquals(3, mMetadata.keySet().size());
177    }
178
179    // Detects bad metadata type
180    @SmallTest
181    public void testBadMetadataType() throws Exception {
182        final int start = mParcel.dataPosition();
183        mParcel.writeInt(-1);  // Placeholder for the length
184        mParcel.writeInt(Metadata.TITLE);
185        mParcel.writeInt(0);  // Invalid type.
186        mParcel.writeString("dummy");
187        adjustSize(start);
188
189        adjustSize();
190        assertParseFail();
191    }
192
193    // Check a Metadata instance can be reused, i.e the parse method
194    // wipes out the existing states/keys.
195    @SmallTest
196    public void testParseClearState() throws Exception {
197        writeStringRecord(Metadata.TITLE, "a title");
198        writeStringRecord(Metadata.GENRE, "comedy");
199        writeStringRecord(Metadata.firstCustomId(), "custom");
200        adjustSize();
201        assertParse();
202
203        resetParcel();
204        writeStringRecord(Metadata.MIME_TYPE, "audio/mpg");
205        adjustSize();
206        assertParse();
207
208        // Only the mime type metadata should be present.
209        assertEquals(1, mMetadata.keySet().size());
210        assertTrue(mMetadata.has(Metadata.MIME_TYPE));
211
212        assertFalse(mMetadata.has(Metadata.TITLE));
213        assertFalse(mMetadata.has(Metadata.GENRE));
214        assertFalse(mMetadata.has(Metadata.firstCustomId()));
215    }
216
217    // ----------------------------------------------------------------------
218    // GETTERS
219    // ----------------------------------------------------------------------
220
221    // getString
222    @SmallTest
223    public void testGetString() throws Exception {
224        writeStringRecord(Metadata.TITLE, "a title");
225        writeStringRecord(Metadata.GENRE, "comedy");
226        adjustSize();
227        assertParse();
228
229        assertEquals("a title", mMetadata.getString(Metadata.TITLE));
230        assertEquals("comedy", mMetadata.getString(Metadata.GENRE));
231    }
232
233    // get an empty string.
234    @SmallTest
235    public void testGetEmptyString() throws Exception {
236        writeStringRecord(Metadata.TITLE, "");
237        adjustSize();
238        assertParse();
239
240        assertEquals("", mMetadata.getString(Metadata.TITLE));
241    }
242
243    // get a string when a NULL value was in the parcel
244    @SmallTest
245    public void testGetNullString() throws Exception {
246        writeStringRecord(Metadata.TITLE, null);
247        adjustSize();
248        assertParse();
249
250        assertEquals(null, mMetadata.getString(Metadata.TITLE));
251    }
252
253    // get a string when an integer is actually present
254    @SmallTest
255    public void testWrongType() throws Exception {
256        writeIntRecord(Metadata.DURATION, 5);
257        adjustSize();
258        assertParse();
259
260        try {
261            mMetadata.getString(Metadata.DURATION);
262        } catch (IllegalStateException ise) {
263            return;
264        }
265        fail("Exception was not thrown");
266    }
267
268    // getInt
269    @SmallTest
270    public void testGetInt() throws Exception {
271        writeIntRecord(Metadata.CD_TRACK_NUM, 1);
272        adjustSize();
273        assertParse();
274
275        assertEquals(1, mMetadata.getInt(Metadata.CD_TRACK_NUM));
276    }
277
278    // getBoolean
279    @SmallTest
280    public void testGetBoolean() throws Exception {
281        writeBooleanRecord(Metadata.DRM_CRIPPLED, true);
282        adjustSize();
283        assertParse();
284
285        assertEquals(true, mMetadata.getBoolean(Metadata.DRM_CRIPPLED));
286    }
287
288    // getLong
289    @SmallTest
290    public void testGetLong() throws Exception {
291        writeLongRecord(Metadata.DURATION, 1L);
292        adjustSize();
293        assertParse();
294
295        assertEquals(1L, mMetadata.getLong(Metadata.DURATION));
296    }
297
298    // getDouble
299    @SmallTest
300    public void testGetDouble() throws Exception {
301        writeDoubleRecord(Metadata.VIDEO_FRAME_RATE, 29.97);
302        adjustSize();
303        assertParse();
304
305        assertEquals(29.97, mMetadata.getDouble(Metadata.VIDEO_FRAME_RATE));
306    }
307
308    // getByteArray
309    @SmallTest
310    public void testGetByteArray() throws Exception {
311        byte data[] = new byte[]{1,2,3,4,5};
312
313        writeByteArrayRecord(Metadata.ALBUM_ART, data);
314        adjustSize();
315        assertParse();
316
317        byte res[] = mMetadata.getByteArray(Metadata.ALBUM_ART);
318        for (int i = 0; i < data.length; ++i) {
319            assertEquals(data[i], res[i]);
320        }
321    }
322
323    // getDate
324    @SmallTest
325    public void testGetDate() throws Exception {
326        writeDateRecord(Metadata.DATE, 0, "PST");
327        adjustSize();
328        assertParse();
329
330        assertEquals(new Date(0), mMetadata.getDate(Metadata.DATE));
331    }
332
333    // getTimedText
334    @SmallTest
335    public void testGetTimedText() throws Exception {
336        Date now = Calendar.getInstance().getTime();
337        writeTimedTextRecord(Metadata.CAPTION, now.getTime(),
338                             10, "Some caption");
339        adjustSize();
340        assertParse();
341
342        Metadata.TimedText caption = mMetadata.getTimedText(Metadata.CAPTION);
343        assertEquals("" + now + "-" + 10 + ":Some caption", caption.toString());
344    }
345
346    // ----------------------------------------------------------------------
347    // HELPERS TO APPEND RECORDS
348    // ----------------------------------------------------------------------
349
350    // Insert a string record at the current position.
351    private void writeStringRecord(int metadataId, String val) {
352        final int start = mParcel.dataPosition();
353        mParcel.writeInt(-1);  // Placeholder for the length
354        mParcel.writeInt(metadataId);
355        mParcel.writeInt(Metadata.STRING_VAL);
356        mParcel.writeString(val);
357        adjustSize(start);
358    }
359
360    // Insert an int record at the current position.
361    private void writeIntRecord(int metadataId, int val) {
362        final int start = mParcel.dataPosition();
363        mParcel.writeInt(-1);  // Placeholder for the length
364        mParcel.writeInt(metadataId);
365        mParcel.writeInt(Metadata.INTEGER_VAL);
366        mParcel.writeInt(val);
367        adjustSize(start);
368    }
369
370    // Insert a boolean record at the current position.
371    private void writeBooleanRecord(int metadataId, boolean val) {
372        final int start = mParcel.dataPosition();
373        mParcel.writeInt(-1);  // Placeholder for the length
374        mParcel.writeInt(metadataId);
375        mParcel.writeInt(Metadata.BOOLEAN_VAL);
376        mParcel.writeInt(val ? 1 : 0);
377        adjustSize(start);
378    }
379
380    // Insert a Long record at the current position.
381    private void writeLongRecord(int metadataId, long val) {
382        final int start = mParcel.dataPosition();
383        mParcel.writeInt(-1);  // Placeholder for the length
384        mParcel.writeInt(metadataId);
385        mParcel.writeInt(Metadata.LONG_VAL);
386        mParcel.writeLong(val);
387        adjustSize(start);
388    }
389
390    // Insert a Double record at the current position.
391    private void writeDoubleRecord(int metadataId, double val) {
392        final int start = mParcel.dataPosition();
393        mParcel.writeInt(-1);  // Placeholder for the length
394        mParcel.writeInt(metadataId);
395        mParcel.writeInt(Metadata.DOUBLE_VAL);
396        mParcel.writeDouble(val);
397        adjustSize(start);
398    }
399
400    // Insert a ByteArray record at the current position.
401    private void writeByteArrayRecord(int metadataId, byte[] val) {
402        final int start = mParcel.dataPosition();
403        mParcel.writeInt(-1);  // Placeholder for the length
404        mParcel.writeInt(metadataId);
405        mParcel.writeInt(Metadata.BYTE_ARRAY_VAL);
406        mParcel.writeByteArray(val);
407        adjustSize(start);
408    }
409
410    // Insert a Date record at the current position.
411    private void writeDateRecord(int metadataId, long time, String tz) {
412        final int start = mParcel.dataPosition();
413        mParcel.writeInt(-1);  // Placeholder for the length
414        mParcel.writeInt(metadataId);
415        mParcel.writeInt(Metadata.DATE_VAL);
416        mParcel.writeLong(time);
417        mParcel.writeString(tz);
418        adjustSize(start);
419    }
420
421    // Insert a TimedText record at the current position.
422    private void writeTimedTextRecord(int metadataId, long begin,
423                                      int duration, String text) {
424        final int start = mParcel.dataPosition();
425        mParcel.writeInt(-1);  // Placeholder for the length
426        mParcel.writeInt(metadataId);
427        mParcel.writeInt(Metadata.TIMED_TEXT_VAL);
428        mParcel.writeLong(begin);
429        mParcel.writeInt(duration);
430        mParcel.writeString(text);
431        adjustSize(start);
432    }
433}
434