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 17 package com.android.mediaframeworktest.unit; 18 import android.media.Metadata; 19 import android.os.Parcel; 20 import android.test.AndroidTestCase; 21 import android.test.suitebuilder.annotation.SmallTest; 22 import android.util.Log; 23 24 import java.util.Calendar; 25 import java.util.Date; 26 27 /* 28 * Check the Java layer that parses serialized metadata in Parcel 29 * works as expected. 30 * 31 */ 32 33 public 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