Test Driven Development for Embedded C by James W. Grenning — Circular Buffer (Chapter 9)
This post describes my solution to the circular buffer exercise mentioned in chapter 9 of the book (link). I used the CppUTest harness for the tests. The source files for CppUTest and Unity can be downloaded from here.
Question
Extend the CircularBuffer so that it can print multiple lines of values
in neat columns, allowing no more than sixty characters per line.
It needs to handle only five-digit decimal numbers.
Evolve CircularBuffer print capabilities so that the column width
adjusts to the two characters wider than the largest number in
the buffer.
Design Notes
Unlike the comprehensive test list for circular buffer solution in chapters 1 and 2, the focus of this solution was to understand the use of function pointers in testing and answer the questions. Chapter 9 also limits the test list to printing. I implemented the tests mentioned in the chapter and extended the test list to answer the questions above. The following points give context to the test list:
- FormatOutput() is a printf() like function to produce printed output.
- Following the instructions on pg-183, I created a function pointer that is pointed to by FormatOutputSpy
- The test list tests both, FormatOutputSpy and the output of circular buffer in different conditions.
The header utils.h, declares the function pointer.
#ifndef UTILS_H
#define UTILS_H
extern int (*FormatOutput)(const char*, ...);
#endif /* UTILS_H */
The function pointer points to the default implementation in utils.c. As mentioned in the book, the function pointer can also point to printf() from C standard library.
#include "../inc/utils.h"
static int FormatOutput_Impl(const char *format, ...)
{
/* Implementation code */
if (*format){
// Do nothing
// This block is for the compilation error "unused parameter ‘format’ [-Werror=unused-parameter"
}
return 0;
}
int (*FormatOutput)(const char* format, ...) = FormatOutput_Impl;
Finally, CPPUTEST’s pointer plugin (UT_PTR_SET) is used to point FormatOutput to FormatOutputSpy as shown below.
TEST_GROUP(FormatOutputSpy){
void setup(){
UT_PTR_SET(FormatOutput, FormatOutputSpy);
}
void teardown(){
FormatOutputSpy_Destroy();
}
};
Test List
FormatOutputSpy Tests:
- Check whether desired output is printed — DONE
- Check whether desired output is printed when output buffer is limited — DONE
- Check whether desired output in printed when FormatOutput is called multiple times successively — DONE
Circular Buffer Tests:
- Printing Tests
(a.) Print empty buffer — DONE
(b.) Check whether desired output is printed after inserting one element — DONE
(c.) Check for desired output when buffer is partially full and pointer did not wrap yet — DONE
(d.) Check for desired output when buffer is full but pointer did not wrap yet — DONE
(e.) Check for desired output when buffer is full and pointer wrapped — DONE - Multiple Lines Test
(a.) Shift to next line when line limit reached — DONE
(b.) Varying column width — DONE