+[AVURLAsset isPlayableExtendedMIMEType:] behaves differently when unit tested
avfoundation, ios, unit-testing
Solution
After reverse engineering how `+[AVURLAsset isPlayableExtendedMIMEType:]` is implemented, I found the cause of the problem.
Here is a stack trace of what it is doing:
frame #0: 0x01b2861e CoreMedia`CelestialGetModelSpecificName
frame #1: 0x01b2885a CoreMedia`CelestialCFCreatePropertyListFromBundleIdentifier + 11
frame #2: 0x00050039 AVFoundation`__33+[AVURLAsset _avfValidationPlist]_block_invoke_0 + 39
frame #3: 0x02e99014 libdispatch.dylib`_dispatch_client_callout + 14
frame #4: 0x02e8b09f libdispatch.dylib`dispatch_once_f + 57
frame #5: 0x02e8b061 libdispatch.dylib`dispatch_once + 31
frame #6: 0x00050006 AVFoundation`+[AVURLAsset _avfValidationPlist] + 49
frame #7: 0x00050664 AVFoundation`+[AVURLAsset isPlayableExtendedMIMEType:] + 64
The `CelestialCFCreatePropertyListFromBundleIdentifier` function tries to read a `MediaValidator.plist` file inside the `MediaToolbox` framework. The location of the plist file depends on the device model name. Here are the different `MediaValidator.plist` files for the iOS 7 simulator.
MediaToolbox.framework
|-- J1
| `-- MediaValidator.plist
|-- K93
| `-- MediaValidator.plist
|-- N41
| `-- MediaValidator.plist
`-- N94
`-- MediaValidator.plist
When running the app, the `CelestialGetModelSpecificName` function returns `N41`, i.e. iPhone 5. When running the unit tests, the `CelestialGetModelSpecificName` function returns `N88`, i.e. iPhone 3GS. As you can see, there is no `N88` directory inside the MediaToolbox framework and this is why `+[AVURLAsset isPlayableExtendedMIMEType:]` eventually fails.
A closer look at the `CelestialGetModelSpecificName` function reveals the solution. The simulator reads the `IPHONE_SIMULATOR_CLASS` environment variable in order to know what device is being simulated. If the `IPHONE_SIMULATOR_CLASS` environment variable is not set, then it defaults to the hardcoded `N88` value.
So in order for the test to pass, we just need to manually set the `IPHONE_SIMULATOR_CLASS` environment variable to `N41` since the unit test runner doesn’t set it automatically.
setenv("IPHONE_SIMULATOR_CLASS", "N41", 0);
Problem
In my app calling `[AVURLAsset isPlayableExtendedMIMEType:@"video/mp4; codecs=\"avc1.64001F, mp4a.40.2\""]` returns `YES`, which is expected. If I run the exact same code in a unit test, then it returns `NO`. Both the app and the unit test are run with Xcode 5.0.2 on the iPhone Retina (4-inch) simulator running iOS 7.0. ``` - (void) testPlayableExtendedMIMEType { XCTAssertTrue([AVURLAsset class], @""); XCTAssertTrue([AVURLAsset isPlayableExtendedMIMEType:@"video/mp4; codecs=\"avc1.64001F, mp4a.40.2\""], @""); } ``` The first assert passes but the second assert fails. Why would this behavior be different in the unit test and in the app?