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 */
diff --git a/libc/include/signal.h b/libc/include/signal.h
index 0770b0f..8c9b170 100644
--- a/libc/include/signal.h
+++ b/libc/include/signal.h
@@ -59,7 +59,7 @@
 
 static __inline__ int sigismember(const sigset_t* set, int signum) {
   int bit = signum - 1; // Signal numbers start at 1, but bit positions start at 0.
-  if (set == NULL || bit < 0 || bit >= 8*sizeof(sigset_t)) {
+  if (set == NULL || bit < 0 || bit >= (int) (8*sizeof(sigset_t))) {
     errno = EINVAL;
     return -1;
   }
@@ -69,7 +69,7 @@
 
 static __inline__ int sigaddset(sigset_t* set, int signum) {
   int bit = signum - 1; // Signal numbers start at 1, but bit positions start at 0.
-  if (set == NULL || bit < 0 || bit >= 8*sizeof(sigset_t)) {
+  if (set == NULL || bit < 0 || bit >= (int) (8*sizeof(sigset_t))) {
     errno = EINVAL;
     return -1;
   }
@@ -80,7 +80,7 @@
 
 static __inline__ int sigdelset(sigset_t* set, int signum) {
   int bit = signum - 1; // Signal numbers start at 1, but bit positions start at 0.
-  if (set == NULL || bit < 0 || bit >= 8*sizeof(sigset_t)) {
+  if (set == NULL || bit < 0 || bit >= (int) (8*sizeof(sigset_t))) {
     errno = EINVAL;
     return -1;
   }
diff --git a/libc/include/stdio.h b/libc/include/stdio.h
index cd04d9c..62882db 100644
--- a/libc/include/stdio.h
+++ b/libc/include/stdio.h
@@ -523,13 +523,13 @@
 
     // Compiler can prove, at compile time, that the passed in size
     // is always <= the actual object size. Don't call __fgets_chk
-    if (__builtin_constant_p(size) && (size <= bos)) {
+    if (__builtin_constant_p(size) && (size <= (int) bos)) {
         return __fgets_real(dest, size, stream);
     }
 
     // Compiler can prove, at compile time, that the passed in size
     // is always > the actual object size. Force a compiler error.
-    if (__builtin_constant_p(size) && (size > bos)) {
+    if (__builtin_constant_p(size) && (size > (int) bos)) {
         __fgets_too_big_error();
     }
 
diff --git a/tests/Android.mk b/tests/Android.mk
index 25da120..0685d4a 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -53,6 +53,7 @@
     -Werror \
 
 test_src_files = \
+    debug_format_test.cpp \
     dirent_test.cpp \
     fenv_test.cpp \
     getauxval_test.cpp \
diff --git a/tests/debug_format_test.cpp b/tests/debug_format_test.cpp
new file mode 100644
index 0000000..8419e4a
--- /dev/null
+++ b/tests/debug_format_test.cpp
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#if defined(__BIONIC__)
+
+#include "../libc/bionic/debug_format.cpp"
+
+extern int __libc_format_buffer(char* buffer, size_t buffer_size, const char* format, ...);
+
+TEST(debug_format, smoke) {
+  char buf[BUFSIZ];
+
+  __libc_format_buffer(buf, sizeof(buf), "a");
+  EXPECT_STREQ("a", buf);
+
+  __libc_format_buffer(buf, sizeof(buf), "%%");
+  EXPECT_STREQ("%", buf);
+
+  __libc_format_buffer(buf, sizeof(buf), "01234");
+  EXPECT_STREQ("01234", buf);
+
+  __libc_format_buffer(buf, sizeof(buf), "a%sb", "01234");
+  EXPECT_STREQ("a01234b", buf);
+
+  char* s = NULL;
+  __libc_format_buffer(buf, sizeof(buf), "a%sb", s);
+  EXPECT_STREQ("a(null)b", buf);
+
+  __libc_format_buffer(buf, sizeof(buf), "aa%scc", "bb");
+  EXPECT_STREQ("aabbcc", buf);
+
+  __libc_format_buffer(buf, sizeof(buf), "a%cc", 'b');
+  EXPECT_STREQ("abc", buf);
+
+  __libc_format_buffer(buf, sizeof(buf), "a%db", 1234);
+  EXPECT_STREQ("a1234b", buf);
+
+  __libc_format_buffer(buf, sizeof(buf), "a%db", -8123);
+  EXPECT_STREQ("a-8123b", buf);
+
+  __libc_format_buffer(buf, sizeof(buf), "a%hdb", 0x7fff0010);
+  EXPECT_STREQ("a16b", buf);
+
+  __libc_format_buffer(buf, sizeof(buf), "a%hhdb", 0x7fffff10);
+  EXPECT_STREQ("a16b", buf);
+
+  __libc_format_buffer(buf, sizeof(buf), "a%lldb", 0x1000000000LL);
+  EXPECT_STREQ("a68719476736b", buf);
+
+  __libc_format_buffer(buf, sizeof(buf), "a%ldb", 70000L);
+  EXPECT_STREQ("a70000b", buf);
+
+  __libc_format_buffer(buf, sizeof(buf), "a%pb", reinterpret_cast<void*>(0xb0001234));
+  EXPECT_STREQ("a0xb0001234b", buf);
+
+  __libc_format_buffer(buf, sizeof(buf), "a%xz", 0x12ab);
+  EXPECT_STREQ("a12abz", buf);
+
+  __libc_format_buffer(buf, sizeof(buf), "a%Xz", 0x12ab);
+  EXPECT_STREQ("a12ABz", buf);
+
+  __libc_format_buffer(buf, sizeof(buf), "a%08xz", 0x123456);
+  EXPECT_STREQ("a00123456z", buf);
+
+  __libc_format_buffer(buf, sizeof(buf), "a%5dz", 1234);
+  EXPECT_STREQ("a 1234z", buf);
+
+  __libc_format_buffer(buf, sizeof(buf), "a%05dz", 1234);
+  EXPECT_STREQ("a01234z", buf);
+
+  __libc_format_buffer(buf, sizeof(buf), "a%8dz", 1234);
+  EXPECT_STREQ("a    1234z", buf);
+
+  __libc_format_buffer(buf, sizeof(buf), "a%-8dz", 1234);
+  EXPECT_STREQ("a1234    z", buf);
+
+  __libc_format_buffer(buf, sizeof(buf), "A%-11sZ", "abcdef");
+  EXPECT_STREQ("Aabcdef     Z", buf);
+
+  __libc_format_buffer(buf, sizeof(buf), "A%s:%dZ", "hello", 1234);
+  EXPECT_STREQ("Ahello:1234Z", buf);
+
+  __libc_format_buffer(buf, sizeof(buf), "a%03d:%d:%02dz", 5, 5, 5);
+  EXPECT_STREQ("a005:5:05z", buf);
+
+  void* p = NULL;
+  __libc_format_buffer(buf, sizeof(buf), "a%d,%pz", 5, p);
+  EXPECT_STREQ("a5,0x0z", buf);
+
+  __libc_format_buffer(buf, sizeof(buf), "a%lld,%d,%d,%dz", 0x1000000000LL, 6, 7, 8);
+  EXPECT_STREQ("a68719476736,6,7,8z", buf);
+}
+
+TEST(debug_format, d_INT_MAX) {
+  char buf[BUFSIZ];
+  __libc_format_buffer(buf, sizeof(buf), "%d", INT_MAX);
+  EXPECT_STREQ("2147483647", buf);
+}
+
+TEST(debug_format, d_INT_MIN) {
+  char buf[BUFSIZ];
+  __libc_format_buffer(buf, sizeof(buf), "%d", INT_MIN);
+  EXPECT_STREQ("-2147483648", buf);
+}
+
+TEST(debug_format, ld_LONG_MAX) {
+  char buf[BUFSIZ];
+  __libc_format_buffer(buf, sizeof(buf), "%ld", LONG_MAX);
+  EXPECT_STREQ("2147483647", buf);
+}
+
+TEST(debug_format, ld_LONG_MIN) {
+  char buf[BUFSIZ];
+  __libc_format_buffer(buf, sizeof(buf), "%ld", LONG_MIN);
+  EXPECT_STREQ("-2147483648", buf);
+}
+
+TEST(debug_format, lld_LLONG_MAX) {
+  char buf[BUFSIZ];
+  __libc_format_buffer(buf, sizeof(buf), "%lld", LLONG_MAX);
+  EXPECT_STREQ("9223372036854775807", buf);
+}
+
+TEST(debug_format, lld_LLONG_MIN) {
+  char buf[BUFSIZ];
+  __libc_format_buffer(buf, sizeof(buf), "%lld", LLONG_MIN);
+  EXPECT_STREQ("-9223372036854775808", buf);
+}
+
+#endif