Unit Test How? Verifying Multiple Register Writes

This is part of an ongoing series of articles about using Unity to Unit Test C applications, often for Embedded Applications. If you're looking for other tips, be sure to check out the others here.

Today we're going to discuss how to verify multiple writes to the same register, from within the same function. For example, we might have a register which we can queue characters into as a way of sending data over a USART.

We're going to build on the foundation of what we already know about testing registers. If you would like a refresher, you can find it here. This will become the foundation for this discussion.

Let's put together an example of a function that accepts a character pointer, and writes those characters one at a time to a USART queueing register, then tells the peripheral to send it all.

int SerialWrite(const char* data, int len)
{
    int i;

    if (len < 1)
        return ERR_TOO_SMALL;
    if (len > 16)
        return ERR_TOO_BIG;

    for (i=0; i < len; i++)
        USART_OUT = (uint32_t)(uint8_t)(data[i]);

    USART_CMD = USART_SEND_FLAG;
    return len;
}

Much like our recent discussion about queueing up data to send, we should try a queue. A good solution is to store written values into a register and then verify them after the function call. We'll again use registers for this.

#define TEST_MAX_QUEUE 16
#define ENQUEUE(vals, index)        \
  vals[ (index > TEST_MAX_QUEUE) ?  \
    TEST_MAX_QUEUE :                \
    index                           \
  ]

EXTERN char USART_OUT_queue[TEST_MAX_QUEUE+1];
EXTERN intUSART_OUT_size = 0;
#define USART_OUT ENQUEUE(      \
    USART_OUT_queue,            \
    USART_OUT_index             \
  )

With this setup, we should be able to reset our counter before each test, then accept up to TEST_MAX_QUEUE values written to our "register".

void setUp(void)
{
  int i;
  for (i = 0; i < TEST_MAX_QUEUE; i++)
    USART_OUT_queue[i] = 0;
  USART_OUT_index = 0;
}

void test_SerialWrite_should_EnqueueAShortString(void)
{
  char* expected = 'Awesome';
  int len = strlen(expected);

  TEST_ASSERT_EQUAL(len, SerialWrite(expected, len) );
  TEST_ASSERT_EQUAL(len, USART_OUT_index);
  TEST_ASSERT_EQUAL_STRING(expected, USART_OUT_queue);
}

Like the situation where we were queueing up results to read from registers, this is a lot of complexity just to test something. While there will be situations where this sort of thing is useful, more often we will find that it suggests we have made an interface that is more complex than it should be.

If we get to this level of complexity, it is likely we should be considering using CMock for these features instead. But, when the situation is right, we now can handle it. 

Happy Coding!