JUCE UnitTests


#1

Hey all.

After a roundabout and largely unsuccessful stab at trying to write tests for my audio plugin’s DSP code in Python, I’m giving another pass at the JUCE UnitTest classes. I’m seeing really weird issues on this path as well.

First, I put a simple statement in my plugin processor constructor to just run the tests when the plugin loads in debug mode. My tests are quick, and this is a simple way of getting the ball rolling:

#if DEBUG
    ScopedPointer<UnitTestRunner> r = new UnitTestRunner();
    r->setPassesAreLogged(true);
    r->runAllTests();
#endif

Next, under my DSP modules in their respective CPP files I’ve added unit tests almost verbatim from the example on the docs: https://www.juce.com/doc/classUnitTest#details

// ==============================================================================
#if DEBUG
class DelayUnitTests : public UnitTest
{
public:
    DelayUnitTests() : UnitTest ("Delay", "Blah") {}

    void runTest() override
    {
        ...etc...
    }
};

static DelayUnitTests myTests;
#endif

However, my runAllTests call from my plugin processor constructor always runs 0 tests. The constructor for DelayUnitTests never actually gets hit, even though the myTests symbol is present in the “Shared Code” static library that JUCE produces for audio plugins. So I’m reasonably confident it’s not getting stripped during compilation.

So at this point I’ve no clues about why my unit test instance doesn’t make it into the UnitTest::getAllTests() array.

I’d love your help, any input here would be great. Thanks!


#2

#if DEBUG ? Is your code even being compiled?


#3

It is. I’ve tried both with and without the if guards, not to mention my
unittestrunner logs it’s random seed.


#4

Ok I managed to get a test to run, pretty much by accident.

I had added an instance of my Delay object to my plugin processor:

private:
    //==============================================================================
    dsp::Gain<float> outputVolume;
    ci::Delay m_delay;

    //==============================================================================
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MyPluginAudioProcessor)
};

But apparently that wasn’t enough to prevent the code from getting stripped? I’m compiling with -O0 and at least all of the XCode config settings I can find for my Debug build are set to not strip. I’ve even checked that the symbol myTests exists in the shared code static library that juce produces. Perhaps the symbol gets stripped during linking? My C++ ignorance is probably showing here.

Anyway, making sure to call m_delay.prepareToPlay() inside my plugin processor’s prepareToPlay at least prevented the unit test from getting stripped and now I’m seeing expected behavior. (Previously I had not added calls to m_delay in my plugin processor, I was not intending to wire it up yet, just verify that my tests were passing).

If anyone can offer an explanation for that, I’d very much appreciate it. :confused:

Thanks!


#5

What you are experiencing is not due to stripping, it is simply the default behavior of the linker. When linking the plugin target, it only “pulls” the required symbols from the shared code static library.

If you want to force the linker to “pull” all symbols from the shared code static library, you have to tell it with a flag like -all_load (“Loads all members of static archive libraries.”) or -force_load mylib.a (“Loads all members of the specified static archive library.”)

See http://www.unix.com/man-page/osx/1/ld/ for all the flags that ld supports.


#6

Interesting… it surprises me that adding the line m_delay.prepareToPlay(...) got the myTest symbol to load then, given that before it wasn’t.

Thank you though, I appreciate the explanation!