Merge pull request #383 from farrrb/feature-printf

Feature printf (Thanks @farrrb !)
This commit is contained in:
Mark VanderVoord
2019-01-25 06:09:20 -05:00
committed by GitHub
4 changed files with 314 additions and 76 deletions

View File

@ -66,7 +66,9 @@ That way, Unity will know to skip the inclusion of this file and you won't
be left with a compiler error. be left with a compiler error.
_Example:_ _Example:_
#define UNITY_EXCLUDE_STDINT_H ```C
#define UNITY_EXCLUDE_STDINT_H
```
##### `UNITY_EXCLUDE_LIMITS_H` ##### `UNITY_EXCLUDE_LIMITS_H`
@ -76,8 +78,9 @@ that don't support `stdint.h` could include `limits.h` instead. If you don't
want Unity to check this file either, define this to make it skip the inclusion. want Unity to check this file either, define this to make it skip the inclusion.
_Example:_ _Example:_
#define UNITY_EXCLUDE_LIMITS_H ```C
#define UNITY_EXCLUDE_LIMITS_H
```
If you've disabled both of the automatic options above, you're going to have to If you've disabled both of the automatic options above, you're going to have to
do the configuration yourself. Don't worry. Even this isn't too bad... there are do the configuration yourself. Don't worry. Even this isn't too bad... there are
@ -91,7 +94,9 @@ Define this to be the number of bits an `int` takes up on your system. The
default, if not autodetected, is 32 bits. default, if not autodetected, is 32 bits.
_Example:_ _Example:_
#define UNITY_INT_WIDTH 16 ```C
#define UNITY_INT_WIDTH 16
```
##### `UNITY_LONG_WIDTH` ##### `UNITY_LONG_WIDTH`
@ -103,7 +108,9 @@ of 64-bit support your system can handle. Does it need to specify a `long` or a
ignored. ignored.
_Example:_ _Example:_
#define UNITY_LONG_WIDTH 16 ```C
#define UNITY_LONG_WIDTH 16
```
##### `UNITY_POINTER_WIDTH` ##### `UNITY_POINTER_WIDTH`
@ -113,7 +120,9 @@ default, if not autodetected, is 32-bits. If you're getting ugly compiler
warnings about casting from pointers, this is the one to look at. warnings about casting from pointers, this is the one to look at.
_Example:_ _Example:_
#define UNITY_POINTER_WIDTH 64 ```C
#define UNITY_POINTER_WIDTH 64
```
##### `UNITY_SUPPORT_64` ##### `UNITY_SUPPORT_64`
@ -125,7 +134,9 @@ can be a significant size and speed impact to enabling 64-bit support on small
targets, so don't define it if you don't need it. targets, so don't define it if you don't need it.
_Example:_ _Example:_
#define UNITY_SUPPORT_64 ```C
#define UNITY_SUPPORT_64
```
### Floating Point Types ### Floating Point Types
@ -153,10 +164,11 @@ suits your needs. For features that are enabled, the following floating point
options also become available. options also become available.
_Example:_ _Example:_
```C
//what manner of strange processor is this? //what manner of strange processor is this?
#define UNITY_EXCLUDE_FLOAT #define UNITY_EXCLUDE_FLOAT
#define UNITY_INCLUDE_DOUBLE #define UNITY_INCLUDE_DOUBLE
```
##### `UNITY_EXCLUDE_FLOAT_PRINT` ##### `UNITY_EXCLUDE_FLOAT_PRINT`
@ -172,7 +184,9 @@ can use this define to instead respond to a failed assertion with a message like
point assertions, use these options to give more explicit failure messages. point assertions, use these options to give more explicit failure messages.
_Example:_ _Example:_
#define UNITY_EXCLUDE_FLOAT_PRINT ```C
#define UNITY_EXCLUDE_FLOAT_PRINT
```
##### `UNITY_FLOAT_TYPE` ##### `UNITY_FLOAT_TYPE`
@ -182,7 +196,9 @@ floats. If your compiler supports a specialty floating point type, you can
always override this behavior by using this definition. always override this behavior by using this definition.
_Example:_ _Example:_
#define UNITY_FLOAT_TYPE float16_t ```C
#define UNITY_FLOAT_TYPE float16_t
```
##### `UNITY_DOUBLE_TYPE` ##### `UNITY_DOUBLE_TYPE`
@ -194,7 +210,9 @@ could enable gargantuan floating point types on your 64-bit processor instead of
the standard `double`. the standard `double`.
_Example:_ _Example:_
#define UNITY_DOUBLE_TYPE long double ```C
#define UNITY_DOUBLE_TYPE long double
```
##### `UNITY_FLOAT_PRECISION` ##### `UNITY_FLOAT_PRECISION`
@ -213,7 +231,10 @@ For further details on how this works, see the appendix of the Unity Assertion
Guide. Guide.
_Example:_ _Example:_
#define UNITY_FLOAT_PRECISION 0.001f ```C
#define UNITY_FLOAT_PRECISION 0.001f
```
### Miscellaneous ### Miscellaneous
@ -225,7 +246,47 @@ your own macro for this, you should exclude the `stddef.h` header file by adding
define to your configuration. define to your configuration.
_Example:_ _Example:_
#define UNITY_EXCLUDE_STDDEF_H ```C
#define UNITY_EXCLUDE_STDDEF_H
```
#### `UNITY_INCLUDE_PRINT_FORMATTED`
Unity provides a simple (and very basic) printf-like string output implementation,
which is able to print a string modified by the following format string modifiers:
- __%d__ - signed value (decimal)
- __%i__ - same as __%i__
- __%u__ - unsigned value (decimal)
- __%f__ - float/Double (if float support is activated)
- __%g__ - same as __%f__
- __%b__ - binary prefixed with "0b"
- __%x__ - hexadecimal (upper case) prefixed with "0x"
- __%X__ - same as __%x__
- __%p__ - pointer (same as __%x__ or __%X__)
- __%c__ - a single character
- __%s__ - a string (e.g. "string")
- __%%__ - The "%" symbol (escaped)
_Example:_
```C
#define UNITY_INCLUDE_PRINT_FORMATTED
int a = 0xfab1;
UnityPrintFormatted("Decimal %d\n", -7);
UnityPrintFormatted("Unsigned %u\n", 987);
UnityPrintFormatted("Float %f\n", 3.1415926535897932384);
UnityPrintFormatted("Binary %b\n", 0xA);
UnityPrintFormatted("Hex %X\n", 0xFAB);
UnityPrintFormatted("Pointer %p\n", &a);
UnityPrintFormatted("Character %c\n", 'F');
UnityPrintFormatted("String %s\n", "My string");
UnityPrintFormatted("Percent %%\n");
UnityPrintFormatted("Color Red \033[41mFAIL\033[00m\n");
UnityPrintFormatted("\n");
UnityPrintFormatted("Multiple (%d) (%i) (%u) (%x)\n", -100, 0, 200, 0x12345);
```
### Toolset Customization ### Toolset Customization
@ -260,12 +321,14 @@ _Example:_
Say you are forced to run your test suite on an embedded processor with no Say you are forced to run your test suite on an embedded processor with no
`stdout` option. You decide to route your test result output to a custom serial `stdout` option. You decide to route your test result output to a custom serial
`RS232_putc()` function you wrote like thus: `RS232_putc()` function you wrote like thus:
#include "RS232_header.h" ```C
... #include "RS232_header.h"
#define UNITY_OUTPUT_CHAR(a) RS232_putc(a) ...
#define UNITY_OUTPUT_START() RS232_config(115200,1,8,0) #define UNITY_OUTPUT_CHAR(a) RS232_putc(a)
#define UNITY_OUTPUT_FLUSH() RS232_flush() #define UNITY_OUTPUT_START() RS232_config(115200,1,8,0)
#define UNITY_OUTPUT_COMPLETE() RS232_close() #define UNITY_OUTPUT_FLUSH() RS232_flush()
#define UNITY_OUTPUT_COMPLETE() RS232_close()
```
_Note:_ _Note:_
`UNITY_OUTPUT_FLUSH()` can be set to the standard out flush function simply by `UNITY_OUTPUT_FLUSH()` can be set to the standard out flush function simply by
@ -294,10 +357,12 @@ empty). You can also force Unity to NOT use weak functions by defining
UNITY_NO_WEAK. The most common options for this feature are: UNITY_NO_WEAK. The most common options for this feature are:
_Example:_ _Example:_
#define UNITY_WEAK_ATTRIBUTE weak ```C
#define UNITY_WEAK_ATTRIBUTE __attribute__((weak)) #define UNITY_WEAK_ATTRIBUTE weak
#define UNITY_WEAK_PRAGMA #define UNITY_WEAK_ATTRIBUTE __attribute__((weak))
#define UNITY_NO_WEAK #define UNITY_WEAK_PRAGMA
#define UNITY_NO_WEAK
```
##### `UNITY_PTR_ATTRIBUTE` ##### `UNITY_PTR_ATTRIBUTE`
@ -307,9 +372,10 @@ Some compilers require a custom attribute to be assigned to pointers, like
defining this option with the attribute you would like. defining this option with the attribute you would like.
_Example:_ _Example:_
#define UNITY_PTR_ATTRIBUTE __attribute__((far)) ```C
#define UNITY_PTR_ATTRIBUTE near #define UNITY_PTR_ATTRIBUTE __attribute__((far))
#define UNITY_PTR_ATTRIBUTE near
```
##### `UNITY_PRINT_EOL` ##### `UNITY_PRINT_EOL`
@ -318,8 +384,9 @@ to parse by the scripts, by Ceedling, etc, but it might not be ideal for YOUR
system. Feel free to override this and to make it whatever you wish. system. Feel free to override this and to make it whatever you wish.
_Example:_ _Example:_
#define UNITY_PRINT_EOL { UNITY_OUTPUT_CHAR('\r'); UNITY_OUTPUT_CHAR('\n') } ```C
#define UNITY_PRINT_EOL { UNITY_OUTPUT_CHAR('\r'); UNITY_OUTPUT_CHAR('\n') }
```
##### `UNITY_EXCLUDE_DETAILS` ##### `UNITY_EXCLUDE_DETAILS`
@ -331,8 +398,9 @@ report which function or argument flagged an error. If you're not using CMock an
you're not using these details for other things, then you can exclude them. you're not using these details for other things, then you can exclude them.
_Example:_ _Example:_
#define UNITY_EXCLUDE_DETAILS ```C
#define UNITY_EXCLUDE_DETAILS
```
##### `UNITY_EXCLUDE_SETJMP` ##### `UNITY_EXCLUDE_SETJMP`
@ -345,15 +413,18 @@ compiler doesn't support setjmp, you wouldn't have had the memory space for thos
things anyway, though... so this option exists for those situations. things anyway, though... so this option exists for those situations.
_Example:_ _Example:_
#define UNITY_EXCLUDE_SETJMP ```C
#define UNITY_EXCLUDE_SETJMP
```
##### `UNITY_OUTPUT_COLOR` ##### `UNITY_OUTPUT_COLOR`
If you want to add color using ANSI escape codes you can use this define. If you want to add color using ANSI escape codes you can use this define.
t t
_Example:_ _Example:_
#define UNITY_OUTPUT_COLOR ```C
#define UNITY_OUTPUT_COLOR
```
## Getting Into The Guts ## Getting Into The Guts
@ -380,13 +451,15 @@ output of your test results.
A simple main function looks something like this: A simple main function looks something like this:
int main(void) { ```C
UNITY_BEGIN(); int main(void) {
RUN_TEST(test_TheFirst); UNITY_BEGIN();
RUN_TEST(test_TheSecond); RUN_TEST(test_TheFirst);
RUN_TEST(test_TheThird); RUN_TEST(test_TheSecond);
return UNITY_END(); RUN_TEST(test_TheThird);
} return UNITY_END();
}
```
You can see that our main function doesn't bother taking any arguments. For our You can see that our main function doesn't bother taking any arguments. For our
most barebones case, we'll never have arguments because we just run all the most barebones case, we'll never have arguments because we just run all the
@ -409,15 +482,17 @@ case function. This includes catching failures, calling the test module's
using CMock or test coverage, there will be additional stubs in use here. A using CMock or test coverage, there will be additional stubs in use here. A
simple minimalist RUN_TEST macro looks something like this: simple minimalist RUN_TEST macro looks something like this:
#define RUN_TEST(testfunc) \ ```C
UNITY_NEW_TEST(#testfunc) \ #define RUN_TEST(testfunc) \
if (TEST_PROTECT()) { \ UNITY_NEW_TEST(#testfunc) \
setUp(); \ if (TEST_PROTECT()) { \
testfunc(); \ setUp(); \
} \ testfunc(); \
if (TEST_PROTECT() && (!TEST_IS_IGNORED)) \ } \
tearDown(); \ if (TEST_PROTECT() && (!TEST_IS_IGNORED)) \
UnityConcludeTest(); tearDown(); \
UnityConcludeTest();
```
So that's quite a macro, huh? It gives you a glimpse of what kind of stuff Unity So that's quite a macro, huh? It gives you a glimpse of what kind of stuff Unity
has to deal with for every single test case. For each test case, we declare that has to deal with for every single test case. For each test case, we declare that

View File

@ -176,6 +176,22 @@
/* #define UNITY_DOUBLE_PRECISION 0.001f */ /* #define UNITY_DOUBLE_PRECISION 0.001f */
/* *************************** MISCELLANEOUS ***********************************
* Miscellaneous configuration options for Unity
**************************************************************************** */
/* Unity uses the stddef.h header included in the C standard library for the
* "NULL" macro. Define this in order to disable the include of stddef.h. If you
* do this, you have to make sure to provide your own "NULL" definition.
*/
/* #define UNITY_EXCLUDE_STDDEF_H */
/* Define this to enable the unity formatted print function:
* "UnityPrintFormatted"
*/
/* #define UNITY_INCLUDE_PRINT_FORMATTED */
/* *************************** TOOLSET CUSTOMIZATION *************************** /* *************************** TOOLSET CUSTOMIZATION ***************************
* In addition to the options listed above, there are a number of other options * In addition to the options listed above, there are a number of other options
* which will come in handy to customize Unity's behavior for your specific * which will come in handy to customize Unity's behavior for your specific

View File

@ -67,6 +67,57 @@ static const char UnityStrDetail2Name[] = " " UNITY_DETAIL2_NAME " ";
* Pretty Printers & Test Result Output Handlers * Pretty Printers & Test Result Output Handlers
*-----------------------------------------------*/ *-----------------------------------------------*/
/*-----------------------------------------------*/
/* Local helper function to print characters. */
static void UnityPrintChar(const char* pch)
{
/* printable characters plus CR & LF are printed */
if ((*pch <= 126) && (*pch >= 32))
{
UNITY_OUTPUT_CHAR(*pch);
}
/* write escaped carriage returns */
else if (*pch == 13)
{
UNITY_OUTPUT_CHAR('\\');
UNITY_OUTPUT_CHAR('r');
}
/* write escaped line feeds */
else if (*pch == 10)
{
UNITY_OUTPUT_CHAR('\\');
UNITY_OUTPUT_CHAR('n');
}
/* unprintable characters are shown as codes */
else
{
UNITY_OUTPUT_CHAR('\\');
UNITY_OUTPUT_CHAR('x');
UnityPrintNumberHex((UNITY_UINT)*pch, 2);
}
}
/*-----------------------------------------------*/
/* Local helper function to print ANSI escape strings e.g. "\033[42m". */
#ifdef UNITY_OUTPUT_COLOR
static UNITY_UINT UnityPrintAnsiEscapeString(const char* string)
{
const char* pch = string;
UNITY_UINT count = 0;
while (*pch && *pch != 'm')
{
UNITY_OUTPUT_CHAR(*pch);
pch++;
count++;
}
UNITY_OUTPUT_CHAR('m');
count++;
return count;
}
#endif
/*-----------------------------------------------*/ /*-----------------------------------------------*/
void UnityPrint(const char* string) void UnityPrint(const char* string)
{ {
@ -76,46 +127,133 @@ void UnityPrint(const char* string)
{ {
while (*pch) while (*pch)
{ {
/* printable characters plus CR & LF are printed */ #ifdef UNITY_OUTPUT_COLOR
if ((*pch <= 126) && (*pch >= 32)) /* print ANSI escape code */
if (*pch == 27 && *(pch + 1) == '[')
{ {
UNITY_OUTPUT_CHAR(*pch); pch += UnityPrintAnsiEscapeString(pch);
continue;
} }
/* write escaped carriage returns */ #endif
else if (*pch == 13) UnityPrintChar(pch);
pch++;
}
}
}
/*-----------------------------------------------*/
#ifdef UNITY_INCLUDE_PRINT_FORMATTED
void UnityPrintFormatted(const char* format, ...)
{
const char* pch = format;
va_list va;
va_start(va, format);
if (pch != NULL)
{
while (*pch)
{
/* format identification character */
if (*pch == '%')
{ {
UNITY_OUTPUT_CHAR('\\'); pch++;
UNITY_OUTPUT_CHAR('r');
} if (pch != NULL)
/* write escaped line feeds */ {
else if (*pch == 10) switch (*pch)
{ {
UNITY_OUTPUT_CHAR('\\'); case 'd':
UNITY_OUTPUT_CHAR('n'); case 'i':
{
const int number = va_arg(va, int);
UnityPrintNumber((UNITY_INT)number);
break;
}
#ifndef UNITY_EXCLUDE_FLOAT_PRINT
case 'f':
case 'g':
{
const double number = va_arg(va, double);
UnityPrintFloat((UNITY_DOUBLE)number);
break;
}
#endif
case 'u':
{
const unsigned int number = va_arg(va, unsigned int);
UnityPrintNumberUnsigned((UNITY_UINT)number);
break;
}
case 'b':
{
const unsigned int number = va_arg(va, unsigned int);
const UNITY_UINT mask = (UNITY_UINT)0 - (UNITY_UINT)1;
UNITY_OUTPUT_CHAR('0');
UNITY_OUTPUT_CHAR('b');
UnityPrintMask(mask, (UNITY_UINT)number);
break;
}
case 'x':
case 'X':
case 'p':
{
const unsigned int number = va_arg(va, unsigned int);
UNITY_OUTPUT_CHAR('0');
UNITY_OUTPUT_CHAR('x');
UnityPrintNumberHex((UNITY_UINT)number, 8);
break;
}
case 'c':
{
const int ch = va_arg(va, int);
UnityPrintChar((const char *)&ch);
break;
}
case 's':
{
const char * string = va_arg(va, const char *);
UnityPrint(string);
break;
}
case '%':
{
UnityPrintChar(pch);
break;
}
default:
{
/* print the unknown format character */
UNITY_OUTPUT_CHAR('%');
UnityPrintChar(pch);
break;
}
}
}
} }
#ifdef UNITY_OUTPUT_COLOR #ifdef UNITY_OUTPUT_COLOR
/* print ANSI escape code */ /* print ANSI escape code */
else if (*pch == 27 && *(pch + 1) == '[') else if (*pch == 27 && *(pch + 1) == '[')
{ {
while (*pch && *pch != 'm') pch += UnityPrintAnsiEscapeString(pch);
{ continue;
UNITY_OUTPUT_CHAR(*pch);
pch++;
}
UNITY_OUTPUT_CHAR('m');
} }
#endif #endif
/* unprintable characters are shown as codes */ else if (*pch == '\n')
{
UNITY_PRINT_EOL();
}
else else
{ {
UNITY_OUTPUT_CHAR('\\'); UnityPrintChar(pch);
UNITY_OUTPUT_CHAR('x');
UnityPrintNumberHex((UNITY_UINT)*pch, 2);
} }
pch++; pch++;
} }
} }
va_end(va);
} }
#endif /* ! UNITY_INCLUDE_PRINT_FORMATTED */
/*-----------------------------------------------*/ /*-----------------------------------------------*/
void UnityPrintLen(const char* string, const UNITY_UINT32 length) void UnityPrintLen(const char* string, const UNITY_UINT32 length)

View File

@ -23,6 +23,10 @@
#include <stddef.h> #include <stddef.h>
#endif #endif
#ifdef UNITY_INCLUDE_PRINT_FORMATTED
#include <stdarg.h>
#endif
/* Unity Attempts to Auto-Detect Integer Types /* Unity Attempts to Auto-Detect Integer Types
* Attempt 1: UINT_MAX, ULONG_MAX in <limits.h>, or default to 32 bits * Attempt 1: UINT_MAX, ULONG_MAX in <limits.h>, or default to 32 bits
* Attempt 2: UINTPTR_MAX in <stdint.h>, or default to same size as long * Attempt 2: UINTPTR_MAX in <stdint.h>, or default to same size as long
@ -130,7 +134,7 @@
typedef UNITY_INT32 UNITY_INT; typedef UNITY_INT32 UNITY_INT;
#else #else
/* 64-bit Support */ /* 64-bit Support */
#if (UNITY_LONG_WIDTH == 32) #if (UNITY_LONG_WIDTH == 32)
typedef unsigned long long UNITY_UINT64; typedef unsigned long long UNITY_UINT64;
typedef signed long long UNITY_INT64; typedef signed long long UNITY_INT64;
@ -491,6 +495,11 @@ void UnityDefaultTestRun(UnityTestFunction Func, const char* FuncName, const int
*-------------------------------------------------------*/ *-------------------------------------------------------*/
void UnityPrint(const char* string); void UnityPrint(const char* string);
#ifdef UNITY_INCLUDE_PRINT_FORMATTED
void UnityPrintFormatted(const char* format, ...);
#endif
void UnityPrintLen(const char* string, const UNITY_UINT32 length); void UnityPrintLen(const char* string, const UNITY_UINT32 length);
void UnityPrintMask(const UNITY_UINT mask, const UNITY_UINT number); void UnityPrintMask(const UNITY_UINT mask, const UNITY_UINT number);
void UnityPrintNumberByStyle(const UNITY_INT number, const UNITY_DISPLAY_STYLE_T style); void UnityPrintNumberByStyle(const UNITY_INT number, const UNITY_DISPLAY_STYLE_T style);