Various coverage improvements.

Mostly from extra test cases, but also:

* Move the fgets size < 0 assertion into fgets.

* Use ELF aliases for strtoq/strtouq rather than duplicating code.

* Don't check uname() succeeded, since it can't fail.

Test: treehugger
Change-Id: I2e6b3b88b0a3eb16bd68be68b9bc9f40d8043291
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp
index f6eca05..c21c3b8 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -371,6 +371,11 @@
 #endif
 }
 
+TEST(STDIO_TEST, snprintf_measure) {
+  char buf[16];
+  ASSERT_EQ(11, snprintf(buf, 0, "Hello %s", "world"));
+}
+
 TEST(STDIO_TEST, snprintf_smoke) {
   char buf[BUFSIZ];
 
@@ -1155,7 +1160,6 @@
   free(p1);
 }
 
-
 TEST(STDIO_TEST, sscanf_mlc) {
   // This is so useless that clang doesn't even believe it exists...
 #pragma clang diagnostic push
@@ -1189,7 +1193,6 @@
 #pragma clang diagnostic pop
 }
 
-
 TEST(STDIO_TEST, sscanf_ms) {
   CheckScanfM(sscanf, "hello", "%ms", 1, "hello");
   CheckScanfM(sscanf, "hello", "%4ms", 1, "hell");
@@ -2533,6 +2536,16 @@
   eth.Run([&]() { exit(puts("a b c")); }, 0, "a b c\n");
 }
 
+TEST(STDIO_TEST, putchar) {
+  ExecTestHelper eth;
+  eth.Run([&]() { exit(putchar('A')); }, 65, "A");
+}
+
+TEST(STDIO_TEST, putchar_unlocked) {
+  ExecTestHelper eth;
+  eth.Run([&]() { exit(putchar('B')); }, 66, "B");
+}
+
 TEST(STDIO_TEST, unlocked) {
   TemporaryFile tf;
 
@@ -2733,3 +2746,73 @@
  ASSERT_NE(0, RENAME_WHITEOUT);
 #endif
 }
+
+TEST(STDIO_TEST, fdopen_failures) {
+  FILE* fp;
+  int fd = open("/proc/version", O_RDONLY);
+  ASSERT_TRUE(fd != -1);
+
+  // Nonsense mode.
+  errno = 0;
+  fp = fdopen(fd, "nonsense");
+  ASSERT_TRUE(fp == nullptr);
+  ASSERT_EQ(EINVAL, errno);
+
+  // Mode that isn't a subset of the fd's actual mode.
+  errno = 0;
+  fp = fdopen(fd, "w");
+  ASSERT_TRUE(fp == nullptr);
+  ASSERT_EQ(EINVAL, errno);
+
+  // Can't set append on the underlying fd.
+  errno = 0;
+  fp = fdopen(fd, "a");
+  ASSERT_TRUE(fp == nullptr);
+  ASSERT_EQ(EINVAL, errno);
+
+  // Bad fd.
+  errno = 0;
+  fp = fdopen(-1, "re");
+  ASSERT_TRUE(fp == nullptr);
+  ASSERT_EQ(EBADF, errno);
+
+  close(fd);
+}
+
+TEST(STDIO_TEST, fmemopen_invalid_mode) {
+  errno = 0;
+  FILE* fp = fmemopen(nullptr, 16, "nonsense");
+  ASSERT_TRUE(fp == nullptr);
+  ASSERT_EQ(EINVAL, errno);
+}
+
+TEST(STDIO_TEST, fopen_invalid_mode) {
+  errno = 0;
+  FILE* fp = fopen("/proc/version", "nonsense");
+  ASSERT_TRUE(fp == nullptr);
+  ASSERT_EQ(EINVAL, errno);
+}
+
+TEST(STDIO_TEST, freopen_invalid_mode) {
+  FILE* fp = fopen("/proc/version", "re");
+  ASSERT_TRUE(fp != nullptr);
+
+  errno = 0;
+  fp = freopen("/proc/version", "nonsense", fp);
+  ASSERT_TRUE(fp == nullptr);
+  ASSERT_EQ(EINVAL, errno);
+}
+
+TEST(STDIO_TEST, asprintf_smoke) {
+  char* p = nullptr;
+  ASSERT_EQ(11, asprintf(&p, "hello %s", "world"));
+  ASSERT_STREQ("hello world", p);
+  free(p);
+}
+
+TEST(STDIO_TEST, fopen_ENOENT) {
+  errno = 0;
+  FILE* fp = fopen("/proc/does-not-exist", "re");
+  ASSERT_TRUE(fp == nullptr);
+  ASSERT_EQ(ENOENT, errno);
+}