Unit tests for formatting code, fix %%.
Also fix <signal.h> and <stdio.h> so they don't cause compiler warnings.
Change-Id: Ib1a746bf01de22d47dbd964de0e6af80a7c96303
diff --git a/libc/bionic/debug_format.cpp b/libc/bionic/debug_format.cpp
index eeed3ac..793f8b1 100644
--- a/libc/bionic/debug_format.cpp
+++ b/libc/bionic/debug_format.cpp
@@ -26,11 +26,7 @@
* SUCH DAMAGE.
*/
-// Temporarily disable _FORTIFY_SOURCE to get this code to
-// compile under GCC 4.7
-#undef _FORTIFY_SOURCE
-
-#include "debug_format.h"
+#include <../private/debug_format.h> // Relative path so we can #include this for testing.
#include <assert.h>
#include <errno.h>
@@ -40,11 +36,6 @@
#include <string.h>
#include <unistd.h>
-/* define UNIT_TESTS to build this file as a single executable that runs
- * the formatter's unit tests
- */
-#define xxUNIT_TESTS
-
/*** Generic output sink
***/
@@ -134,12 +125,12 @@
}
static int
-vformat_buffer(char *buff, size_t buffsize, const char *format, va_list args)
+vformat_buffer(char *buff, size_t buf_size, const char *format, va_list args)
{
BufOut bo;
Out *out;
- out = buf_out_init(&bo, buff, buffsize);
+ out = buf_out_init(&bo, buff, buf_size);
if (out == NULL)
return 0;
@@ -291,7 +282,7 @@
// Writes number 'value' in base 'base' into buffer 'buf' of size 'buf_size' bytes.
// Assumes that buf_size > 0.
-static void format_number(char* buf, size_t buf_size, uint64_t value, int base, bool caps) {
+static void format_unsigned(char* buf, size_t buf_size, uint64_t value, int base, bool caps) {
char* p = buf;
char* end = buf + buf_size - 1;
@@ -327,27 +318,26 @@
}
}
-/* Write an integer (octal or decimal) into a buffer, assumes buffsize > 2 */
-static void
-format_integer(char *buffer, size_t buffsize, uint64_t value, int base, int isSigned)
-{
- // TODO: this is incorrect for MIN_INT.
- if (isSigned && (int64_t)value < 0) {
- buffer[0] = '-';
- buffer += 1;
- buffsize -= 1;
- value = (uint64_t)(-(int64_t)value);
- }
+static void format_integer(char* buf, size_t buf_size, uint64_t value, char conversion) {
+ // Decode the conversion specifier.
+ int is_signed = (conversion == 'd' || conversion == 'i' || conversion == 'o');
+ int base = 10;
+ if (conversion == 'x' || conversion == 'X') {
+ base = 16;
+ } else if (conversion == 'o') {
+ base = 8;
+ }
+ bool caps = (conversion == 'X');
- format_number(buffer, buffsize, value, base, false);
+ if (is_signed && static_cast<int64_t>(value) < 0) {
+ buf[0] = '-';
+ buf += 1;
+ buf_size -= 1;
+ value = static_cast<uint64_t>(-static_cast<int64_t>(value));
+ }
+ format_unsigned(buf, buf_size, value, base, caps);
}
-// Assumes buf_size > 2.
-static void format_hex(char* buf, size_t buf_size, uint64_t value, bool caps) {
- format_number(buf, buf_size, value, 16, caps);
-}
-
-
/* Perform formatted output to an output target 'o' */
static void
out_vformat(Out *o, const char *format, va_list args)
@@ -362,7 +352,6 @@
int width = -1;
int prec = -1;
size_t bytelen = sizeof(int);
- const char* str;
int slen;
char buffer[32]; /* temporary buffer used to format numbers */
@@ -457,6 +446,7 @@
}
/* conversion specifier */
+ const char* str = buffer;
if (c == 's') {
/* string */
str = va_arg(args, const char*);
@@ -468,17 +458,15 @@
/* NOTE: char is promoted to int when passed through the stack */
buffer[0] = (char) va_arg(args, int);
buffer[1] = '\0';
- str = buffer;
} else if (c == 'p') {
uint64_t value = (uintptr_t) va_arg(args, void*);
buffer[0] = '0';
buffer[1] = 'x';
- format_hex(buffer + 2, sizeof buffer-2, value, false);
- str = buffer;
- } else {
+ format_integer(buffer + 2, sizeof(buffer) - 2, value, 'x');
+ } else if (c == 'd' || c == 'i' || c == 'o' || c == 'x' || c == 'X') {
/* integers - first read value from stack */
uint64_t value;
- int isSigned = (c == 'd' || c == 'i' || c == 'o');
+ int is_signed = (c == 'd' || c == 'i' || c == 'o');
/* NOTE: int8_t and int16_t are promoted to int when passed
* through the stack
@@ -492,27 +480,18 @@
}
/* sign extension, if needed */
- if (isSigned) {
+ if (is_signed) {
int shift = 64 - 8*bytelen;
value = (uint64_t)(((int64_t)(value << shift)) >> shift);
}
/* format the number properly into our buffer */
- switch (c) {
- case 'i': case 'd':
- format_integer(buffer, sizeof buffer, value, 10, isSigned);
- break;
- case 'o':
- format_integer(buffer, sizeof buffer, value, 8, isSigned);
- break;
- case 'x': case 'X':
- format_hex(buffer, sizeof buffer, value, (c == 'X'));
- break;
- default:
- buffer[0] = '\0';
- }
- /* then point to it */
- str = buffer;
+ format_integer(buffer, sizeof(buffer), value, c);
+ } else if (c == '%') {
+ buffer[0] = '%';
+ buffer[1] = '\0';
+ } else {
+ __assert(__FILE__, __LINE__, "conversion specifier unsupported");
}
/* if we are here, 'str' points to the content that must be
@@ -537,101 +516,3 @@
}
}
}
-
-
-#ifdef UNIT_TESTS
-
-#include <stdio.h>
-
-static int gFails = 0;
-
-#define MARGIN 40
-
-#define UTEST_CHECK(condition,message) \
- printf("Checking %-*s: ", MARGIN, message); fflush(stdout); \
- if (!(condition)) { \
- printf("KO\n"); \
- gFails += 1; \
- } else { \
- printf("ok\n"); \
- }
-
-static void
-utest_BufOut(void)
-{
- char buffer[16];
- BufOut bo[1];
- Out* out;
- int ret;
-
- buffer[0] = '1';
- out = buf_out_init(bo, buffer, sizeof buffer);
- UTEST_CHECK(buffer[0] == '\0', "buf_out_init clears initial byte");
- out_send(out, "abc", 3);
- UTEST_CHECK(!memcmp(buffer, "abc", 4), "out_send() works with BufOut");
- out_send_repeat(out, 'X', 4);
- UTEST_CHECK(!memcmp(buffer, "abcXXXX", 8), "out_send_repeat() works with BufOut");
- buffer[sizeof buffer-1] = 'x';
- out_send_repeat(out, 'Y', 2*sizeof(buffer));
- UTEST_CHECK(buffer[sizeof buffer-1] == '\0', "overflows always zero-terminates");
-
- out = buf_out_init(bo, buffer, sizeof buffer);
- out_send_repeat(out, 'X', 2*sizeof(buffer));
- ret = buf_out_length(bo);
- UTEST_CHECK(ret == 2*sizeof(buffer), "correct size returned on overflow");
-}
-
-static void
-utest_expect(const char* result, const char* format, ...)
-{
- va_list args;
- BufOut bo[1];
- char buffer[256];
- Out* out = buf_out_init(bo, buffer, sizeof buffer);
-
- printf("Checking %-*s: ", MARGIN, format); fflush(stdout);
- va_start(args, format);
- out_vformat(out, format, args);
- va_end(args);
-
- if (strcmp(result, buffer)) {
- printf("KO. got '%s' expecting '%s'\n", buffer, result);
- gFails += 1;
- } else {
- printf("ok. got '%s'\n", result);
- }
-}
-
-int main(void)
-{
- utest_BufOut();
- utest_expect("", "");
- utest_expect("a", "a");
- utest_expect("01234", "01234", "");
- utest_expect("01234", "%s", "01234");
- utest_expect("aabbcc", "aa%scc", "bb");
- utest_expect("a", "%c", 'a');
- utest_expect("1234", "%d", 1234);
- utest_expect("-8123", "%d", -8123);
- utest_expect("16", "%hd", 0x7fff0010);
- utest_expect("16", "%hhd", 0x7fffff10);
- utest_expect("68719476736", "%lld", 0x1000000000LL);
- utest_expect("70000", "%ld", 70000);
- utest_expect("0xb0001234", "%p", (void*)0xb0001234);
- utest_expect("12ab", "%x", 0x12ab);
- utest_expect("12AB", "%X", 0x12ab);
- utest_expect("00123456", "%08x", 0x123456);
- utest_expect("01234", "0%d", 1234);
- utest_expect(" 1234", "%5d", 1234);
- utest_expect("01234", "%05d", 1234);
- utest_expect(" 1234", "%8d", 1234);
- utest_expect("1234 ", "%-8d", 1234);
- utest_expect("abcdef ", "%-11s", "abcdef");
- utest_expect("something:1234", "%s:%d", "something", 1234);
- utest_expect("005:5:05", "%03d:%d:%02d", 5, 5, 5);
- utest_expect("5,0x0", "%d,%p", 5, NULL);
- utest_expect("68719476736,6,7,8", "%lld,%d,%d,%d", 0x1000000000LL, 6, 7, 8);
- return gFails != 0;
-}
-
-#endif /* UNIT_TESTS */