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.PAUSE_AVAILABLE, true); 281 writeBooleanRecord(Metadata.SEEK_AVAILABLE, true); 282 writeBooleanRecord(Metadata.SEEK_BACKWARD_AVAILABLE, true); 283 writeBooleanRecord(Metadata.SEEK_FORWARD_AVAILABLE, true); 284 adjustSize(); 285 assertParse(); 286 287 assertEquals(true, mMetadata.getBoolean(Metadata.PAUSE_AVAILABLE)); 288 assertEquals(true, mMetadata.getBoolean(Metadata.SEEK_AVAILABLE)); 289 assertEquals(true, mMetadata.getBoolean(Metadata.SEEK_BACKWARD_AVAILABLE)); 290 assertEquals(true, mMetadata.getBoolean(Metadata.SEEK_FORWARD_AVAILABLE)); 291 } 292 293 // getLong 294 @SmallTest 295 public void testGetLong() throws Exception { 296 writeLongRecord(Metadata.DURATION, 1L); 297 adjustSize(); 298 assertParse(); 299 300 assertEquals(1L, mMetadata.getLong(Metadata.DURATION)); 301 } 302 303 // getDouble 304 @SmallTest 305 public void testGetDouble() throws Exception { 306 writeDoubleRecord(Metadata.VIDEO_FRAME_RATE, 29.97); 307 adjustSize(); 308 assertParse(); 309 310 assertEquals(29.97, mMetadata.getDouble(Metadata.VIDEO_FRAME_RATE)); 311 } 312 313 // getByteArray 314 @SmallTest 315 public void testGetByteArray() throws Exception { 316 byte data[] = new byte[]{1,2,3,4,5}; 317 318 writeByteArrayRecord(Metadata.ALBUM_ART, data); 319 adjustSize(); 320 assertParse(); 321 322 byte res[] = mMetadata.getByteArray(Metadata.ALBUM_ART); 323 for (int i = 0; i < data.length; ++i) { 324 assertEquals(data[i], res[i]); 325 } 326 } 327 328 // getDate 329 @SmallTest 330 public void testGetDate() throws Exception { 331 writeDateRecord(Metadata.DATE, 0, "PST"); 332 adjustSize(); 333 assertParse(); 334 335 assertEquals(new Date(0), mMetadata.getDate(Metadata.DATE)); 336 } 337 338 // ---------------------------------------------------------------------- 339 // HELPERS TO APPEND RECORDS 340 // ---------------------------------------------------------------------- 341 342 // Insert a string record at the current position. 343 private void writeStringRecord(int metadataId, String val) { 344 final int start = mParcel.dataPosition(); 345 mParcel.writeInt(-1); // Placeholder for the length 346 mParcel.writeInt(metadataId); 347 mParcel.writeInt(Metadata.STRING_VAL); 348 mParcel.writeString(val); 349 adjustSize(start); 350 } 351 352 // Insert an int record at the current position. 353 private void writeIntRecord(int metadataId, int val) { 354 final int start = mParcel.dataPosition(); 355 mParcel.writeInt(-1); // Placeholder for the length 356 mParcel.writeInt(metadataId); 357 mParcel.writeInt(Metadata.INTEGER_VAL); 358 mParcel.writeInt(val); 359 adjustSize(start); 360 } 361 362 // Insert a boolean record at the current position. 363 private void writeBooleanRecord(int metadataId, boolean val) { 364 final int start = mParcel.dataPosition(); 365 mParcel.writeInt(-1); // Placeholder for the length 366 mParcel.writeInt(metadataId); 367 mParcel.writeInt(Metadata.BOOLEAN_VAL); 368 mParcel.writeInt(val ? 1 : 0); 369 adjustSize(start); 370 } 371 372 // Insert a Long record at the current position. 373 private void writeLongRecord(int metadataId, long val) { 374 final int start = mParcel.dataPosition(); 375 mParcel.writeInt(-1); // Placeholder for the length 376 mParcel.writeInt(metadataId); 377 mParcel.writeInt(Metadata.LONG_VAL); 378 mParcel.writeLong(val); 379 adjustSize(start); 380 } 381 382 // Insert a Double record at the current position. 383 private void writeDoubleRecord(int metadataId, double val) { 384 final int start = mParcel.dataPosition(); 385 mParcel.writeInt(-1); // Placeholder for the length 386 mParcel.writeInt(metadataId); 387 mParcel.writeInt(Metadata.DOUBLE_VAL); 388 mParcel.writeDouble(val); 389 adjustSize(start); 390 } 391 392 // Insert a ByteArray record at the current position. 393 private void writeByteArrayRecord(int metadataId, byte[] val) { 394 final int start = mParcel.dataPosition(); 395 mParcel.writeInt(-1); // Placeholder for the length 396 mParcel.writeInt(metadataId); 397 mParcel.writeInt(Metadata.BYTE_ARRAY_VAL); 398 mParcel.writeByteArray(val); 399 adjustSize(start); 400 } 401 402 // Insert a Date record at the current position. 403 private void writeDateRecord(int metadataId, long time, String tz) { 404 final int start = mParcel.dataPosition(); 405 mParcel.writeInt(-1); // Placeholder for the length 406 mParcel.writeInt(metadataId); 407 mParcel.writeInt(Metadata.DATE_VAL); 408 mParcel.writeLong(time); 409 mParcel.writeString(tz); 410 adjustSize(start); 411 } 412 } 413