arduino_midi_library/test/unit-tests/tests/unit-tests_MidiInputCallbac...

595 lines
16 KiB
C++

#include "unit-tests.h"
#include "unit-tests_Settings.h"
#include <src/MIDI.h>
#include <test/mocks/test-mocks_SerialMock.h>
BEGIN_MIDI_NAMESPACE
END_MIDI_NAMESPACE
// -----------------------------------------------------------------------------
BEGIN_UNNAMED_NAMESPACE
using namespace testing;
USING_NAMESPACE_UNIT_TESTS
template<unsigned Size>
struct VariableSysExSettings : midi::DefaultSettings
{
static const unsigned SysExMaxSize = Size;
};
typedef test_mocks::SerialMock<256> SerialMock;
typedef midi::SerialMIDI<SerialMock> Transport;
typedef VariableSysExSettings<256> Settings;
typedef midi::MidiInterface<Transport, Settings> MidiInterface;
MidiInterface* midi;
class MidiInputCallbacks : public Test
{
public:
MidiInputCallbacks()
: mTransport(mSerial)
, mMidi(mTransport)
{
}
virtual ~MidiInputCallbacks()
{
}
protected:
virtual void SetUp()
{
midi = &mMidi;
}
virtual void TearDown()
{
midi = nullptr;
}
protected:
SerialMock mSerial;
Transport mTransport;
MidiInterface mMidi;
};
// --
void handleNoteOn(byte inChannel, byte inPitch, byte inVelocity)
{
EXPECT_NE(midi, nullptr);
midi->sendNoteOn(inPitch, inVelocity, inChannel);
}
TEST_F(MidiInputCallbacks, noteOn)
{
mMidi.setHandleNoteOn(handleNoteOn);
mMidi.begin(MIDI_CHANNEL_OMNI);
mMidi.turnThruOff();
static const unsigned rxSize = 3;
static const byte rxData[rxSize] = { 0x9b, 12, 34 };
mSerial.mRxBuffer.write(rxData, rxSize);
EXPECT_EQ(mMidi.read(), false);
EXPECT_EQ(mMidi.read(), false);
EXPECT_EQ(mMidi.read(), true);
EXPECT_EQ(mMidi.getType(), midi::NoteOn);
EXPECT_EQ(mMidi.getChannel(), 12);
EXPECT_EQ(mMidi.getData1(), 12);
EXPECT_EQ(mMidi.getData2(), 34);
EXPECT_EQ(mSerial.mTxBuffer.getLength(), 3);
byte buffer[3] = { 0 };
mSerial.mTxBuffer.read(buffer, 3);
EXPECT_THAT(buffer, ContainerEq(rxData));
// Test null velocity note on
EXPECT_EQ(MidiInterface::Settings::HandleNullVelocityNoteOnAsNoteOff, true);
mSerial.mRxBuffer.write(0x9b);
mSerial.mRxBuffer.write(12);
mSerial.mRxBuffer.write(0);
EXPECT_EQ(mMidi.read(), false);
EXPECT_EQ(mMidi.read(), false);
EXPECT_EQ(mMidi.read(), true);
EXPECT_EQ(mMidi.getType(), midi::NoteOff);
EXPECT_EQ(mMidi.getChannel(), 12);
EXPECT_EQ(mMidi.getData1(), 12);
EXPECT_EQ(mMidi.getData2(), 0);
EXPECT_EQ(mSerial.mTxBuffer.getLength(), 0);
}
// --
void handleNoteOff(byte inChannel, byte inPitch, byte inVelocity)
{
EXPECT_NE(midi, nullptr);
midi->sendNoteOff(inPitch, inVelocity, inChannel);
}
TEST_F(MidiInputCallbacks, noteOff)
{
mMidi.setHandleNoteOff(handleNoteOff);
mMidi.begin(MIDI_CHANNEL_OMNI);
mMidi.turnThruOff();
static const unsigned rxSize = 3;
static const byte rxData[rxSize] = { 0x8b, 12, 34 };
mSerial.mRxBuffer.write(rxData, rxSize);
EXPECT_EQ(mMidi.read(), false);
EXPECT_EQ(mMidi.read(), false);
EXPECT_EQ(mMidi.read(), true);
EXPECT_EQ(mMidi.getType(), midi::NoteOff);
EXPECT_EQ(mMidi.getChannel(), 12);
EXPECT_EQ(mMidi.getData1(), 12);
EXPECT_EQ(mMidi.getData2(), 34);
EXPECT_EQ(mSerial.mTxBuffer.getLength(), 3);
byte buffer[3] = { 0 };
mSerial.mTxBuffer.read(buffer, 3);
EXPECT_THAT(buffer, ContainerEq(rxData));
// Test null velocity note on
EXPECT_EQ(MidiInterface::Settings::HandleNullVelocityNoteOnAsNoteOff, true);
mSerial.mRxBuffer.write(0x9b);
mSerial.mRxBuffer.write(12);
mSerial.mRxBuffer.write(0);
EXPECT_EQ(mMidi.read(), false);
EXPECT_EQ(mMidi.read(), false);
EXPECT_EQ(mMidi.read(), true);
EXPECT_EQ(mMidi.getType(), midi::NoteOff);
EXPECT_EQ(mMidi.getChannel(), 12);
EXPECT_EQ(mMidi.getData1(), 12);
EXPECT_EQ(mMidi.getData2(), 0);
EXPECT_EQ(mSerial.mTxBuffer.getLength(), 3);
mSerial.mTxBuffer.read(buffer, 3);
EXPECT_THAT(buffer, ElementsAreArray({
0x8b, 12, 0
}));
}
// --
void handleAfterTouchPoly(byte inChannel, byte inNote, byte inValue)
{
EXPECT_NE(midi, nullptr);
midi->sendAfterTouch(inNote, inValue, inChannel);
}
TEST_F(MidiInputCallbacks, afterTouchPoly)
{
mMidi.setHandleAfterTouchPoly(handleAfterTouchPoly);
mMidi.begin(MIDI_CHANNEL_OMNI);
mMidi.turnThruOff();
static const unsigned rxSize = 3;
static const byte rxData[rxSize] = { 0xab, 12, 34 };
mSerial.mRxBuffer.write(rxData, rxSize);
EXPECT_EQ(mMidi.read(), false);
EXPECT_EQ(mMidi.read(), false);
EXPECT_EQ(mMidi.read(), true);
EXPECT_EQ(mMidi.getType(), midi::AfterTouchPoly);
EXPECT_EQ(mMidi.getChannel(), 12);
EXPECT_EQ(mMidi.getData1(), 12);
EXPECT_EQ(mMidi.getData2(), 34);
EXPECT_EQ(mSerial.mTxBuffer.getLength(), 3);
byte buffer[3] = { 0 };
mSerial.mTxBuffer.read(buffer, 3);
EXPECT_THAT(buffer, ContainerEq(rxData));
}
// --
void handleControlChange(byte inChannel, byte inNumber, byte inValue)
{
EXPECT_NE(midi, nullptr);
midi->sendControlChange(inNumber, inValue, inChannel);
}
TEST_F(MidiInputCallbacks, controlChange)
{
mMidi.setHandleControlChange(handleControlChange);
mMidi.begin(MIDI_CHANNEL_OMNI);
mMidi.turnThruOff();
static const unsigned rxSize = 3;
static const byte rxData[rxSize] = { 0xbb, 12, 34 };
mSerial.mRxBuffer.write(rxData, rxSize);
EXPECT_EQ(mMidi.read(), false);
EXPECT_EQ(mMidi.read(), false);
EXPECT_EQ(mMidi.read(), true);
EXPECT_EQ(mMidi.getType(), midi::ControlChange);
EXPECT_EQ(mMidi.getChannel(), 12);
EXPECT_EQ(mMidi.getData1(), 12);
EXPECT_EQ(mMidi.getData2(), 34);
EXPECT_EQ(mSerial.mTxBuffer.getLength(), 3);
byte buffer[3] = { 0 };
mSerial.mTxBuffer.read(buffer, 3);
EXPECT_THAT(buffer, ContainerEq(rxData));
}
// --
void handleProgramChange(byte inChannel, byte inNumber)
{
EXPECT_NE(midi, nullptr);
midi->sendProgramChange(inNumber, inChannel);
}
TEST_F(MidiInputCallbacks, programChange)
{
mMidi.setHandleProgramChange(handleProgramChange);
mMidi.begin(MIDI_CHANNEL_OMNI);
mMidi.turnThruOff();
static const unsigned rxSize = 2;
static const byte rxData[rxSize] = { 0xcb, 12 };
mSerial.mRxBuffer.write(rxData, rxSize);
EXPECT_EQ(mMidi.read(), false);
EXPECT_EQ(mMidi.read(), true);
EXPECT_EQ(mMidi.getType(), midi::ProgramChange);
EXPECT_EQ(mMidi.getChannel(), 12);
EXPECT_EQ(mMidi.getData1(), 12);
EXPECT_EQ(mMidi.getData2(), 0);
EXPECT_EQ(mSerial.mTxBuffer.getLength(), 2);
byte buffer[2] = { 0 };
mSerial.mTxBuffer.read(buffer, 2);
EXPECT_THAT(buffer, ContainerEq(rxData));
}
// --
void handleAfterTouchChannel(byte inChannel, byte inPressure)
{
EXPECT_NE(midi, nullptr);
midi->sendAfterTouch(inPressure, inChannel);
}
TEST_F(MidiInputCallbacks, afterTouchChannel)
{
mMidi.setHandleAfterTouchChannel(handleAfterTouchChannel);
mMidi.begin(MIDI_CHANNEL_OMNI);
mMidi.turnThruOff();
static const unsigned rxSize = 2;
static const byte rxData[rxSize] = { 0xdb, 12 };
mSerial.mRxBuffer.write(rxData, rxSize);
EXPECT_EQ(mMidi.read(), false);
EXPECT_EQ(mMidi.read(), true);
EXPECT_EQ(mMidi.getType(), midi::AfterTouchChannel);
EXPECT_EQ(mMidi.getChannel(), 12);
EXPECT_EQ(mMidi.getData1(), 12);
EXPECT_EQ(mMidi.getData2(), 0);
EXPECT_EQ(mSerial.mTxBuffer.getLength(), 2);
byte buffer[2] = { 0 };
mSerial.mTxBuffer.read(buffer, 2);
EXPECT_THAT(buffer, ContainerEq(rxData));
}
// --
void handlePitchBend(byte inChannel, int inValue)
{
EXPECT_NE(midi, nullptr);
midi->sendPitchBend(inValue, inChannel);
}
TEST_F(MidiInputCallbacks, pitchBend)
{
mMidi.setHandlePitchBend(handlePitchBend);
mMidi.begin(MIDI_CHANNEL_OMNI);
mMidi.turnThruOff();
static const unsigned rxSize = 3;
static const byte rxData[rxSize] = { 0xeb, 12, 34 };
mSerial.mRxBuffer.write(rxData, rxSize);
EXPECT_EQ(mMidi.read(), false);
EXPECT_EQ(mMidi.read(), false);
EXPECT_EQ(mMidi.read(), true);
EXPECT_EQ(mMidi.getType(), midi::PitchBend);
EXPECT_EQ(mMidi.getChannel(), 12);
EXPECT_EQ(mMidi.getData1(), 12);
EXPECT_EQ(mMidi.getData2(), 34);
EXPECT_EQ(mSerial.mTxBuffer.getLength(), 3);
byte buffer[3] = { 0 };
mSerial.mTxBuffer.read(buffer, 3);
EXPECT_THAT(buffer, ContainerEq(rxData));
}
// --
void handleSysEx(byte* inData, unsigned inSize)
{
EXPECT_NE(midi, nullptr);
midi->sendSysEx(inSize, inData, true);
}
TEST_F(MidiInputCallbacks, sysEx)
{
mMidi.setHandleSystemExclusive(handleSysEx);
mMidi.begin(MIDI_CHANNEL_OMNI);
mMidi.turnThruOff();
static const unsigned rxSize = 15;
static const byte rxData[rxSize] = {
0xf0, 'H','e','l','l','o',',',' ','W','o','r','l','d','!', 0xf7
};
mSerial.mRxBuffer.write(rxData, rxSize);
for (unsigned i = 0; i < rxSize - 1; ++i)
{
EXPECT_EQ(mMidi.read(), false);
}
EXPECT_EQ(mMidi.read(), true);
EXPECT_EQ(mMidi.getType(), midi::SystemExclusive);
EXPECT_EQ(mMidi.getChannel(), 0);
EXPECT_EQ(mMidi.getSysExArrayLength(), rxSize);
EXPECT_EQ(unsigned(mSerial.mTxBuffer.getLength()), rxSize);
const std::vector<byte> sysExData(mMidi.getSysExArray(),
mMidi.getSysExArray() + rxSize);
EXPECT_THAT(sysExData, ElementsAreArray(rxData));
}
TEST_F(MidiInputCallbacks, sysExLong)
{
mMidi.setHandleSystemExclusive(handleSysEx);
mMidi.begin(MIDI_CHANNEL_OMNI);
mMidi.turnThruOff();
static const unsigned rxSize = 210;
static const byte rxData[rxSize] = {
0xf0,
'H','e','l','l','o',',',' ','W','o','r','l','d','!',
'H','e','l','l','o',',',' ','W','o','r','l','d','!',
'H','e','l','l','o',',',' ','W','o','r','l','d','!',
'H','e','l','l','o',',',' ','W','o','r','l','d','!',
'H','e','l','l','o',',',' ','W','o','r','l','d','!',
'H','e','l','l','o',',',' ','W','o','r','l','d','!',
'H','e','l','l','o',',',' ','W','o','r','l','d','!',
'H','e','l','l','o',',',' ','W','o','r','l','d','!',
'H','e','l','l','o',',',' ','W','o','r','l','d','!',
'H','e','l','l','o',',',' ','W','o','r','l','d','!',
'H','e','l','l','o',',',' ','W','o','r','l','d','!',
'H','e','l','l','o',',',' ','W','o','r','l','d','!',
'H','e','l','l','o',',',' ','W','o','r','l','d','!',
'H','e','l','l','o',',',' ','W','o','r','l','d','!',
'H','e','l','l','o',',',' ','W','o','r','l','d','!',
'H','e','l','l','o',',',' ','W','o','r','l','d','!',
0xf7
};
mSerial.mRxBuffer.write(rxData, rxSize);
for (unsigned i = 0; i < rxSize - 1; ++i)
{
EXPECT_EQ(mMidi.read(), false);
}
EXPECT_EQ(mMidi.read(), true);
EXPECT_EQ(mMidi.getType(), midi::SystemExclusive);
EXPECT_EQ(mMidi.getChannel(), 0);
EXPECT_EQ(mMidi.getSysExArrayLength(), rxSize);
EXPECT_EQ(unsigned(mSerial.mTxBuffer.getLength()), rxSize);
const std::vector<byte> sysExData(mMidi.getSysExArray(),
mMidi.getSysExArray() + rxSize);
EXPECT_THAT(sysExData, ElementsAreArray(rxData));
}
// --
void handleMtcQuarterFrame(byte inData)
{
EXPECT_NE(midi, nullptr);
midi->sendTimeCodeQuarterFrame(inData);
}
TEST_F(MidiInputCallbacks, mtcQuarterFrame)
{
mMidi.setHandleTimeCodeQuarterFrame(handleMtcQuarterFrame);
mMidi.begin(MIDI_CHANNEL_OMNI);
mMidi.turnThruOff();
static const unsigned rxSize = 2;
static const byte rxData[rxSize] = { 0xf1, 12 };
mSerial.mRxBuffer.write(rxData, rxSize);
EXPECT_EQ(mMidi.read(), false);
EXPECT_EQ(mMidi.read(), true);
EXPECT_EQ(mMidi.getType(), midi::TimeCodeQuarterFrame);
EXPECT_EQ(mMidi.getChannel(), 0);
EXPECT_EQ(mMidi.getData1(), 12);
EXPECT_EQ(mMidi.getData2(), 0);
EXPECT_EQ(mSerial.mTxBuffer.getLength(), 2);
byte buffer[2] = { 0 };
mSerial.mTxBuffer.read(buffer, 2);
EXPECT_THAT(buffer, ContainerEq(rxData));
}
// --
void handleSongPosition(unsigned inBeats)
{
EXPECT_NE(midi, nullptr);
midi->sendSongPosition(inBeats);
}
TEST_F(MidiInputCallbacks, songPosition)
{
mMidi.setHandleSongPosition(handleSongPosition);
mMidi.begin(MIDI_CHANNEL_OMNI);
mMidi.turnThruOff();
static const unsigned rxSize = 3;
static const byte rxData[rxSize] = { 0xf2, 12, 34 };
mSerial.mRxBuffer.write(rxData, rxSize);
EXPECT_EQ(mMidi.read(), false);
EXPECT_EQ(mMidi.read(), false);
EXPECT_EQ(mMidi.read(), true);
EXPECT_EQ(mMidi.getType(), midi::SongPosition);
EXPECT_EQ(mMidi.getChannel(), 0);
EXPECT_EQ(mMidi.getData1(), 12);
EXPECT_EQ(mMidi.getData2(), 34);
EXPECT_EQ(mSerial.mTxBuffer.getLength(), 3);
byte buffer[3] = { 0 };
mSerial.mTxBuffer.read(buffer, 3);
EXPECT_THAT(buffer, ContainerEq(rxData));
}
// --
void handleSongSelect(byte inSongNumber)
{
EXPECT_NE(midi, nullptr);
midi->sendSongSelect(inSongNumber);
}
TEST_F(MidiInputCallbacks, songSelect)
{
mMidi.setHandleSongSelect(handleSongSelect);
mMidi.begin(MIDI_CHANNEL_OMNI);
mMidi.turnThruOff();
static const unsigned rxSize = 2;
static const byte rxData[rxSize] = { 0xf3, 12 };
mSerial.mRxBuffer.write(rxData, rxSize);
EXPECT_EQ(mMidi.read(), false);
EXPECT_EQ(mMidi.read(), true);
EXPECT_EQ(mMidi.getType(), midi::SongSelect);
EXPECT_EQ(mMidi.getChannel(), 0);
EXPECT_EQ(mMidi.getData1(), 12);
EXPECT_EQ(mMidi.getData2(), 0);
EXPECT_EQ(mSerial.mTxBuffer.getLength(), 2);
byte buffer[2] = { 0 };
mSerial.mTxBuffer.read(buffer, 2);
EXPECT_THAT(buffer, ContainerEq(rxData));
}
// --
void handleTuneRequest()
{
EXPECT_NE(midi, nullptr);
midi->sendTuneRequest();
}
TEST_F(MidiInputCallbacks, tuneRequest)
{
mMidi.setHandleTuneRequest(handleTuneRequest);
mMidi.begin(MIDI_CHANNEL_OMNI);
mMidi.turnThruOff();
mSerial.mRxBuffer.write(0xf6);
EXPECT_EQ(mMidi.read(), true);
EXPECT_EQ(mMidi.getType(), midi::TuneRequest);
EXPECT_EQ(mMidi.getChannel(), 0);
EXPECT_EQ(mMidi.getData1(), 0);
EXPECT_EQ(mMidi.getData2(), 0);
EXPECT_EQ(mSerial.mTxBuffer.getLength(), 1);
EXPECT_EQ(mSerial.mTxBuffer.read(), 0xf6);
}
// --
void handleClock()
{
EXPECT_NE(midi, nullptr);
midi->sendRealTime(midi::Clock);
}
void handleStart()
{
EXPECT_NE(midi, nullptr);
midi->sendRealTime(midi::Start);
}
void handleContinue()
{
EXPECT_NE(midi, nullptr);
midi->sendRealTime(midi::Continue);
}
void handleStop()
{
EXPECT_NE(midi, nullptr);
midi->sendRealTime(midi::Stop);
}
void handleActiveSensing()
{
EXPECT_NE(midi, nullptr);
midi->sendRealTime(midi::ActiveSensing);
}
void handleSystemReset()
{
EXPECT_NE(midi, nullptr);
midi->sendRealTime(midi::SystemReset);
}
TEST_F(MidiInputCallbacks, realTime)
{
mMidi.setHandleClock(handleClock);
mMidi.setHandleStart(handleStart);
mMidi.setHandleContinue(handleContinue);
mMidi.setHandleStop(handleStop);
mMidi.setHandleActiveSensing(handleActiveSensing);
mMidi.setHandleSystemReset(handleSystemReset);
mMidi.begin(MIDI_CHANNEL_OMNI);
mMidi.turnThruOff();
static const unsigned rxSize = 6;
static const byte rxData[rxSize] = {
0xf8, 0xfa, 0xfb, 0xfc, 0xfe, 0xff
};
mSerial.mRxBuffer.write(rxData, rxSize);
static const midi::MidiType types[rxSize] = {
midi::Clock,
midi::Start,
midi::Continue,
midi::Stop,
midi::ActiveSensing,
midi::SystemReset,
};
for (unsigned i = 0; i < rxSize; ++i)
{
EXPECT_EQ(mMidi.read(), true);
EXPECT_EQ(mMidi.getType(), types[i]);
EXPECT_EQ(mMidi.getChannel(), 0);
EXPECT_EQ(mMidi.getData1(), 0);
EXPECT_EQ(mMidi.getData2(), 0);
EXPECT_EQ(mSerial.mTxBuffer.getLength(), 1);
const byte read = mSerial.mTxBuffer.read();
EXPECT_EQ(read, rxData[i]);
EXPECT_EQ(read, types[i]);
}
}
END_UNNAMED_NAMESPACE