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