MidiInput and Unit-tests


#1

Hi,

I used to unit-test some of my code by creating a fake MidiInput like this:

class CustomMidiInput : public juce::MidiInput
{
 public:
  CustomMidiInput()
  : juce::MidiInput("Fake Device")
  {
    /// Tricking JUCE to avoid errors at delete time for a non-existing device
    internal = nullptr;
  }
};

My unit-test would then attach properties to this device and check that everything is correctly saved, etc.

But since the constructor for MidiInput has become private, I can't use this trick anymore. What do you guys suggest as a work-around? I could try to open the default midi input and change its name to "Fake Device" to go on with my tests, but then it would fail on a continuous integration server that usually has 0 midi input devices available...

Any idea?


#2

Instead of having your unit-test use the MidiInput device directly, you could also have it access the MidiInput device via an interface:

class MidiInputInterface
{
public:
    virtual ~MidiInputInterface() = 0;
    virtual const String& getName() const noexcept = 0;
    virtual void setName (const String& newName) noexcept = 0;
    virtual void start() = 0;
    virtual void stop() = 0;
};

,i.e. you simply find&replace all instances of MidiInput with MidiInputInterface. You then access the real MidiInput via a wrapper:

class MidiInputWrapper : public MidiInputInterface
{
private:
    MidiInput* input;
    MidiInputWrapper (MidiInput* in)
        : input (in) {}
public:
    ~MidiInputWrapper() { delete input; }
    const String& getName() const noexcept override { return input->getName(); }
    void setName (const String& newName) noexcept override { input->setName (newName); }
    void start() override { input->start(); }
    void stop() override { input->stop(); }
    static MidiInputWrapper* openDevice (int deviceIndex,
                                         MidiInputCallback* callback)
    {
        return new MidiInputWrapper (MidiInput::openDevice (deviceIndex, callback));
    }
   #if JUCE_LINUX || JUCE_MAC || JUCE_IOS || DOXYGEN
    static MidiInputWrapper* createNewDevice (const String& deviceName,
                                       MidiInputCallback* callback)
    {
        return new MidiInputWrapper (MidiInput::createNewDevice (deviceName, callback));
    }
   #endif
};

which you instantiate with the MidiInputWrapper::openDevice method defined above. For testing you create a dummy MidiInput:

class DummyMidiInput : public MidiInputInterface
{
private:
    String name;
public:
    DummyMidiInput()
        : name ("dummy") {}
    ~DummyMidiInput() { }
    const String& getName() const noexcept override { return name; }
    void setName (const String& newName) noexcept override { name = newName; }
    void start() override { }
    void stop() override { }
};

Would this work for you?


#3

That'll do, thanks.