mirror of
https://github.com/kyleneideck/BackgroundMusic
synced 2024-11-22 12:13:03 +00:00
Add a test for BGM_Device::DoIOOperation.
This commit is contained in:
parent
3ba53a50ac
commit
7171cfcb78
1 changed files with 104 additions and 24 deletions
|
@ -36,7 +36,36 @@
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
|
|
||||||
@interface BGM_DeviceTests : XCTestCase
|
// Subclass BGM_Device to add some test-only functions.
|
||||||
|
class TestBGM_Device
|
||||||
|
:
|
||||||
|
public BGM_Device
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
TestBGM_Device();
|
||||||
|
~TestBGM_Device() = default;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
TestBGM_Device::TestBGM_Device()
|
||||||
|
:
|
||||||
|
BGM_Device(kObjectID_Device,
|
||||||
|
CFSTR(kDeviceName),
|
||||||
|
CFSTR(kBGMDeviceUID),
|
||||||
|
CFSTR(kBGMDeviceModelUID),
|
||||||
|
kObjectID_Stream_Input,
|
||||||
|
kObjectID_Stream_Output,
|
||||||
|
kObjectID_Volume_Output_Master,
|
||||||
|
kObjectID_Mute_Output_Master)
|
||||||
|
{
|
||||||
|
Activate();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@interface BGM_DeviceTests : XCTestCase {
|
||||||
|
TestBGM_Device* testDevice;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@ -45,29 +74,79 @@
|
||||||
|
|
||||||
- (void) setUp {
|
- (void) setUp {
|
||||||
[super setUp];
|
[super setUp];
|
||||||
|
testDevice = new TestBGM_Device();
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) tearDown {
|
- (void) tearDown {
|
||||||
// Reminder: add code here, above the super call
|
delete testDevice;
|
||||||
[super tearDown];
|
[super tearDown];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void) testDoIOOperation_writeMix_readInput {
|
||||||
|
// The number of audio frames to send/receive in the IO operations.
|
||||||
|
const int kFrameSize = 512;
|
||||||
|
|
||||||
|
// Choose a sample time that will make the data wrap around to the start of the device's
|
||||||
|
// internal ring buffer.
|
||||||
|
AudioServerPlugInIOCycleInfo cycleInfo {};
|
||||||
|
cycleInfo.mOutputTime.mSampleTime = kLoopbackRingBufferFrameSize - 25.0;
|
||||||
|
|
||||||
|
// Generate the test input data.
|
||||||
|
Float32 inputBuffer[kFrameSize * 2];
|
||||||
|
|
||||||
|
for(int i = 0; i < kFrameSize * 2; i++)
|
||||||
|
{
|
||||||
|
inputBuffer[i] = static_cast<Float32>(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send a copy of the input buffer just in case DoIOOperation modifies the data for some reason.
|
||||||
|
Float32 inputBufferCopy[kFrameSize * 2];
|
||||||
|
memcpy(inputBufferCopy, inputBuffer, sizeof(inputBuffer));
|
||||||
|
|
||||||
|
// Send the input data to the device.
|
||||||
|
testDevice->DoIOOperation(/* inStreamObjectID = */ kObjectID_Stream_Output,
|
||||||
|
/* inClientID = */ 0,
|
||||||
|
/* inOperationID = */ kAudioServerPlugInIOOperationWriteMix,
|
||||||
|
/* inIOBufferFrameSize = */ kFrameSize,
|
||||||
|
/* inIOCycleInfo = */ cycleInfo,
|
||||||
|
/* ioMainBuffer = */ inputBuffer,
|
||||||
|
/* ioSecondaryBuffer = */ nullptr);
|
||||||
|
|
||||||
|
// Request data from the same point in time so we get the same data back.
|
||||||
|
cycleInfo.mInputTime.mSampleTime = kLoopbackRingBufferFrameSize - 25.0;
|
||||||
|
|
||||||
|
// Read the data back from the device.
|
||||||
|
Float32 outputBuffer[kFrameSize * 2];
|
||||||
|
|
||||||
|
testDevice->DoIOOperation(/* inStreamObjectID = */ kObjectID_Stream_Output,
|
||||||
|
/* inClientID = */ 0,
|
||||||
|
/* inOperationID = */ kAudioServerPlugInIOOperationReadInput,
|
||||||
|
/* inIOBufferFrameSize = */ kFrameSize,
|
||||||
|
/* inIOCycleInfo = */ cycleInfo,
|
||||||
|
/* ioMainBuffer = */ outputBuffer,
|
||||||
|
/* ioSecondaryBuffer = */ nullptr);
|
||||||
|
|
||||||
|
// Check the output matches the input.
|
||||||
|
for(int i = 0; i < kFrameSize * 2; i++)
|
||||||
|
{
|
||||||
|
XCTAssertEqual(inputBuffer[i], outputBuffer[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (void) testCustomPropertyMusicPlayerBundleID {
|
- (void) testCustomPropertyMusicPlayerBundleID {
|
||||||
BGM_Device& device = BGM_Device::GetInstance();
|
|
||||||
|
|
||||||
// Convenience wrappers
|
// Convenience wrappers
|
||||||
auto getBundleID = [&](UInt32 inDataSize = sizeof(CFStringRef)){
|
auto getBundleID = [&](UInt32 inDataSize = sizeof(CFStringRef)){
|
||||||
CFStringRef bundleID = NULL;
|
CFStringRef bundleID = nullptr;
|
||||||
UInt32 outDataSize;
|
UInt32 outDataSize;
|
||||||
|
|
||||||
device.GetPropertyData(/* inObjectID = */ kObjectID_Device,
|
testDevice->GetPropertyData(/* inObjectID = */ kObjectID_Device,
|
||||||
/* inClientPID = */ 3,
|
/* inClientPID = */ 3,
|
||||||
/* inAddress = */ kBGMMusicPlayerBundleIDAddress,
|
/* inAddress = */ kBGMMusicPlayerBundleIDAddress,
|
||||||
/* inQualifierDataSize = */ 0,
|
/* inQualifierDataSize = */ 0,
|
||||||
/* inQualifierData = */ NULL,
|
/* inQualifierData = */ nullptr,
|
||||||
/* inDataSize = */ inDataSize,
|
/* inDataSize = */ inDataSize,
|
||||||
/* outDataSize = */ outDataSize,
|
/* outDataSize = */ outDataSize,
|
||||||
/* outData = */ reinterpret_cast<void* __nonnull>(&bundleID));
|
/* outData = */ reinterpret_cast<void* __nonnull>(&bundleID));
|
||||||
|
|
||||||
// This isn't technically required, but we're unlikely to ever want to return any more/less data from GetPropertyData.
|
// This isn't technically required, but we're unlikely to ever want to return any more/less data from GetPropertyData.
|
||||||
XCTAssertEqual(outDataSize, sizeof(CFStringRef));
|
XCTAssertEqual(outDataSize, sizeof(CFStringRef));
|
||||||
|
@ -76,13 +155,13 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
auto setBundleID = [&](const CFStringRef* __nullable bundleID, UInt32 dataSize = sizeof(CFStringRef)){
|
auto setBundleID = [&](const CFStringRef* __nullable bundleID, UInt32 dataSize = sizeof(CFStringRef)){
|
||||||
device.SetPropertyData(/* inObjectID = */ kObjectID_Device,
|
testDevice->SetPropertyData(/* inObjectID = */ kObjectID_Device,
|
||||||
/* inClientPID = */ 1234,
|
/* inClientPID = */ 1234,
|
||||||
/* inAddress = */ kBGMMusicPlayerBundleIDAddress,
|
/* inAddress = */ kBGMMusicPlayerBundleIDAddress,
|
||||||
/* inQualifierDataSize = */ 0,
|
/* inQualifierDataSize = */ 0,
|
||||||
/* inQualifierData = */ NULL,
|
/* inQualifierData = */ nullptr,
|
||||||
/* inDataSize = */ dataSize,
|
/* inDataSize = */ dataSize,
|
||||||
/* inData = */ reinterpret_cast<const void* __nonnull>(bundleID));
|
/* inData = */ reinterpret_cast<const void* __nonnull>(bundleID));
|
||||||
};
|
};
|
||||||
|
|
||||||
// Should be set to the empty string by default.
|
// Should be set to the empty string by default.
|
||||||
|
@ -103,11 +182,12 @@
|
||||||
// Arguments should be null-checked.
|
// Arguments should be null-checked.
|
||||||
BGMShouldThrow<std::runtime_error>(self, [&](){
|
BGMShouldThrow<std::runtime_error>(self, [&](){
|
||||||
UInt32 outDataSize;
|
UInt32 outDataSize;
|
||||||
device.GetPropertyData(kObjectID_Device, 0, kBGMMusicPlayerBundleIDAddress, 0, NULL, sizeof(CFStringRef),
|
testDevice->GetPropertyData(kObjectID_Device, 0, kBGMMusicPlayerBundleIDAddress, 0, nullptr,
|
||||||
outDataSize, /* outData = */ reinterpret_cast<void* __nonnull>(NULL));
|
sizeof(CFStringRef), outDataSize,
|
||||||
|
/* outData = */ reinterpret_cast<void* __nonnull>(NULL));
|
||||||
});
|
});
|
||||||
BGMShouldThrow<std::runtime_error>(self, [&](){
|
BGMShouldThrow<std::runtime_error>(self, [&](){
|
||||||
setBundleID(NULL);
|
setBundleID(nullptr);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Invalid data should be rejected.
|
// Invalid data should be rejected.
|
||||||
|
@ -115,7 +195,7 @@
|
||||||
setBundleID((CFStringRef*)&kCFNull);
|
setBundleID((CFStringRef*)&kCFNull);
|
||||||
});
|
});
|
||||||
BGMShouldThrow<CAException>(self, [&](){
|
BGMShouldThrow<CAException>(self, [&](){
|
||||||
CFStringRef nullRef = NULL;
|
CFStringRef nullRef = nullptr;
|
||||||
setBundleID(&nullRef);
|
setBundleID(&nullRef);
|
||||||
});
|
});
|
||||||
BGMShouldThrow<CAException>(self, [&](){
|
BGMShouldThrow<CAException>(self, [&](){
|
||||||
|
|
Loading…
Reference in a new issue