My last article featured a hand crafted a spy to monitor asm
directives. Now let’s use CppUMock (the mock support companion CppUTest) to create a mock version of asm
.
Starting with the test (where else would you start), MockAsm
works like this:
#include "CppUTest/TestHarness.h" #include "CppUTestExt/MockSupport.h" extern "C" { #include "MockAsm.h" } TEST_GROUP(MockAsm) { void setup() { } void teardown() { mock().checkExpectations(); mock().clear(); } }; TEST(MockAsm, CaptureAsmInstructions) { mock().expectOneCall("asm") .withParameter("instruction", "NOP"); mock().expectOneCall("asm") .withParameter("instruction", "FLOP"); mock().expectOneCall("asm") .withParameter("instruction", "POP"); MockAsm("NOP"); MockAsm("FLOP"); MockAsm("POP"); } |
To get a successful build and link, you need to build CppUTest extensions. You can do this with make extensions
. You will also have to tell CppUTest’s makefile system to use extensions by adding this to your makefile.
CPPUTEST_USE_EXTENSIONS = Y |
Like the last example, use the preprocessor to sneak the mock into the production code by forcing each compilation unit to include MockAsm.h.
CPPUTEST_CFLAGS += -include mocks/MockAsm.h |
MockAsm.h looks like this:
#ifndef D_MockAsm_H #define D_MockAsm_H #define asm MockAsm void MockAsm(const char * instruction); #endif |
Here’s MockAsm.c.
#include "MockAsm.h" #include "CppUTestExt/MockSupport_c.h" void MockAsm(const char * instruction) { mock_c()->actualCall("asm") ->withStringParameters("instruction", instruction); } |
That was easy.
This is a very interesting use of mocks. However, what is the point of a test like this? While it is easy to see why I might want the asm() directives to go away altogether, or maybe replace it with some normal C code that works on the development system, but why would I want to test – at runtime – for the presence of a particular line of assembly code? What would I prove by such a test?
This would mainly be for off-target testing. This might be of limited value. But what it tells you is that no one changed the asm() instructions. You are locking in and checking that the right sequence is there.
It could also be helpful in a legacy code situation where this is your monitor point to see if the asm instructions were on the execution path.
Good question, James