A few more trivial tests.

Based on gaps in the list of functions not referenced by the test
executable.

Bug: N/A
Test: ran tests
Change-Id: I73c238e7cf360f94670c7cd13eb954341c940b7b
diff --git a/tests/ctype_test.cpp b/tests/ctype_test.cpp
index 7b27d64..c12518b 100644
--- a/tests/ctype_test.cpp
+++ b/tests/ctype_test.cpp
@@ -26,6 +26,14 @@
   EXPECT_FALSE(isalnum(' '));
 }
 
+TEST(ctype, isalnum_l) {
+  EXPECT_TRUE(isalnum_l('1', LC_GLOBAL_LOCALE));
+  EXPECT_TRUE(isalnum_l('a', LC_GLOBAL_LOCALE));
+  EXPECT_TRUE(isalnum_l('A', LC_GLOBAL_LOCALE));
+  EXPECT_FALSE(isalnum_l('!', LC_GLOBAL_LOCALE));
+  EXPECT_FALSE(isalnum_l(' ', LC_GLOBAL_LOCALE));
+}
+
 TEST(ctype, isalpha) {
   EXPECT_FALSE(isalpha('1'));
   EXPECT_TRUE(isalpha('a'));
@@ -34,6 +42,14 @@
   EXPECT_FALSE(isalpha(' '));
 }
 
+TEST(ctype, isalpha_l) {
+  EXPECT_FALSE(isalpha_l('1', LC_GLOBAL_LOCALE));
+  EXPECT_TRUE(isalpha_l('a', LC_GLOBAL_LOCALE));
+  EXPECT_TRUE(isalpha_l('A', LC_GLOBAL_LOCALE));
+  EXPECT_FALSE(isalpha_l('!', LC_GLOBAL_LOCALE));
+  EXPECT_FALSE(isalpha_l(' ', LC_GLOBAL_LOCALE));
+}
+
 TEST(ctype, isascii) {
   EXPECT_TRUE(isascii('\x7f'));
   EXPECT_FALSE(isascii('\x80'));
@@ -45,17 +61,34 @@
   EXPECT_TRUE(isblank('\t'));
 }
 
+TEST(ctype, isblank_l) {
+  EXPECT_FALSE(isblank_l('1', LC_GLOBAL_LOCALE));
+  EXPECT_TRUE(isblank_l(' ', LC_GLOBAL_LOCALE));
+  EXPECT_TRUE(isblank_l('\t', LC_GLOBAL_LOCALE));
+}
+
 TEST(ctype, iscntrl) {
   EXPECT_FALSE(iscntrl('1'));
   EXPECT_TRUE(iscntrl('\b'));
 }
 
+TEST(ctype, iscntrl_l) {
+  EXPECT_FALSE(iscntrl_l('1', LC_GLOBAL_LOCALE));
+  EXPECT_TRUE(iscntrl_l('\b', LC_GLOBAL_LOCALE));
+}
+
 TEST(ctype, isdigit) {
   EXPECT_TRUE(isdigit('1'));
   EXPECT_FALSE(isdigit('a'));
   EXPECT_FALSE(isdigit('x'));
 }
 
+TEST(ctype, isdigit_l) {
+  EXPECT_TRUE(isdigit_l('1', LC_GLOBAL_LOCALE));
+  EXPECT_FALSE(isdigit_l('a', LC_GLOBAL_LOCALE));
+  EXPECT_FALSE(isdigit_l('x', LC_GLOBAL_LOCALE));
+}
+
 TEST(ctype, isgraph) {
   EXPECT_TRUE(isgraph('a'));
   EXPECT_TRUE(isgraph('A'));
@@ -64,18 +97,38 @@
   EXPECT_FALSE(isgraph(' '));
 }
 
+TEST(ctype, isgraph_l) {
+  EXPECT_TRUE(isgraph_l('a', LC_GLOBAL_LOCALE));
+  EXPECT_TRUE(isgraph_l('A', LC_GLOBAL_LOCALE));
+  EXPECT_TRUE(isgraph_l('1', LC_GLOBAL_LOCALE));
+  EXPECT_TRUE(isgraph_l('!', LC_GLOBAL_LOCALE));
+  EXPECT_FALSE(isgraph_l(' ', LC_GLOBAL_LOCALE));
+}
+
 TEST(ctype, islower) {
   EXPECT_TRUE(islower('a'));
   EXPECT_FALSE(islower('A'));
   EXPECT_FALSE(islower('!'));
 }
 
+TEST(ctype, islower_l) {
+  EXPECT_TRUE(islower_l('a', LC_GLOBAL_LOCALE));
+  EXPECT_FALSE(islower_l('A', LC_GLOBAL_LOCALE));
+  EXPECT_FALSE(islower_l('!', LC_GLOBAL_LOCALE));
+}
+
 TEST(ctype, isprint) {
   EXPECT_TRUE(isprint('a'));
   EXPECT_TRUE(isprint(' '));
   EXPECT_FALSE(isprint('\b'));
 }
 
+TEST(ctype, isprint_l) {
+  EXPECT_TRUE(isprint_l('a', LC_GLOBAL_LOCALE));
+  EXPECT_TRUE(isprint_l(' ', LC_GLOBAL_LOCALE));
+  EXPECT_FALSE(isprint_l('\b', LC_GLOBAL_LOCALE));
+}
+
 TEST(ctype, ispunct) {
   EXPECT_TRUE(ispunct('!'));
   EXPECT_FALSE(ispunct('a'));
@@ -83,6 +136,13 @@
   EXPECT_FALSE(ispunct('\b'));
 }
 
+TEST(ctype, ispunct_l) {
+  EXPECT_TRUE(ispunct_l('!', LC_GLOBAL_LOCALE));
+  EXPECT_FALSE(ispunct_l('a', LC_GLOBAL_LOCALE));
+  EXPECT_FALSE(ispunct_l(' ', LC_GLOBAL_LOCALE));
+  EXPECT_FALSE(ispunct_l('\b', LC_GLOBAL_LOCALE));
+}
+
 TEST(ctype, isspace) {
   EXPECT_TRUE(isspace(' '));
   EXPECT_TRUE(isspace('\f'));
@@ -94,12 +154,29 @@
   EXPECT_FALSE(isspace('!'));
 }
 
+TEST(ctype, isspace_l) {
+  EXPECT_TRUE(isspace_l(' ', LC_GLOBAL_LOCALE));
+  EXPECT_TRUE(isspace_l('\f', LC_GLOBAL_LOCALE));
+  EXPECT_TRUE(isspace_l('\n', LC_GLOBAL_LOCALE));
+  EXPECT_TRUE(isspace_l('\r', LC_GLOBAL_LOCALE));
+  EXPECT_TRUE(isspace_l('\t', LC_GLOBAL_LOCALE));
+  EXPECT_TRUE(isspace_l('\v', LC_GLOBAL_LOCALE));
+  EXPECT_FALSE(isspace_l('a', LC_GLOBAL_LOCALE));
+  EXPECT_FALSE(isspace_l('!', LC_GLOBAL_LOCALE));
+}
+
 TEST(ctype, isupper) {
   EXPECT_TRUE(isupper('A'));
   EXPECT_FALSE(isupper('a'));
   EXPECT_FALSE(isupper('!'));
 }
 
+TEST(ctype, isupper_l) {
+  EXPECT_TRUE(isupper_l('A', LC_GLOBAL_LOCALE));
+  EXPECT_FALSE(isupper_l('a', LC_GLOBAL_LOCALE));
+  EXPECT_FALSE(isupper_l('!', LC_GLOBAL_LOCALE));
+}
+
 TEST(ctype, isxdigit) {
   EXPECT_TRUE(isxdigit('0'));
   EXPECT_FALSE(isxdigit('x'));
@@ -110,6 +187,16 @@
   EXPECT_FALSE(isxdigit(' '));
 }
 
+TEST(ctype, isxdigit_l) {
+  EXPECT_TRUE(isxdigit_l('0', LC_GLOBAL_LOCALE));
+  EXPECT_FALSE(isxdigit_l('x', LC_GLOBAL_LOCALE));
+  EXPECT_TRUE(isxdigit_l('1', LC_GLOBAL_LOCALE));
+  EXPECT_TRUE(isxdigit_l('a', LC_GLOBAL_LOCALE));
+  EXPECT_TRUE(isxdigit_l('A', LC_GLOBAL_LOCALE));
+  EXPECT_FALSE(isxdigit_l('g', LC_GLOBAL_LOCALE));
+  EXPECT_FALSE(isxdigit_l(' ', LC_GLOBAL_LOCALE));
+}
+
 TEST(ctype, toascii) {
   EXPECT_EQ('a', toascii('a'));
   EXPECT_EQ('a', toascii(0x80 | 'a'));
@@ -121,6 +208,12 @@
   EXPECT_EQ('a', tolower('A'));
 }
 
+TEST(ctype, tolower_l) {
+  EXPECT_EQ('!', tolower_l('!', LC_GLOBAL_LOCALE));
+  EXPECT_EQ('a', tolower_l('a', LC_GLOBAL_LOCALE));
+  EXPECT_EQ('a', tolower_l('A', LC_GLOBAL_LOCALE));
+}
+
 TEST(ctype, _tolower) {
   // _tolower may mangle characters for which isupper is false.
   EXPECT_EQ('a', _tolower('A'));
@@ -132,6 +225,12 @@
   EXPECT_EQ('A', toupper('A'));
 }
 
+TEST(ctype, toupper_l) {
+  EXPECT_EQ('!', toupper_l('!', LC_GLOBAL_LOCALE));
+  EXPECT_EQ('A', toupper_l('a', LC_GLOBAL_LOCALE));
+  EXPECT_EQ('A', toupper_l('A', LC_GLOBAL_LOCALE));
+}
+
 TEST(ctype, _toupper) {
   // _toupper may mangle characters for which islower is false.
   EXPECT_EQ('A', _toupper('a'));
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp
index e060cd9..d0d9130 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -1719,17 +1719,13 @@
   ASSERT_TRUE(fd != -1);
 
   // This fd doesn't have O_CLOEXEC...
-  int flags = fcntl(fd, F_GETFD);
-  ASSERT_TRUE(flags != -1);
-  ASSERT_EQ(0, flags & FD_CLOEXEC);
+  AssertCloseOnExec(fd, false);
 
   FILE* fp = fdopen(fd, "re");
   ASSERT_TRUE(fp != NULL);
 
   // ...but the new one does.
-  flags = fcntl(fileno(fp), F_GETFD);
-  ASSERT_TRUE(flags != -1);
-  ASSERT_EQ(FD_CLOEXEC, flags & FD_CLOEXEC);
+  AssertCloseOnExec(fileno(fp), true);
 
   fclose(fp);
   close(fd);
@@ -1740,16 +1736,12 @@
   ASSERT_TRUE(fp != NULL);
 
   // This FILE* doesn't have O_CLOEXEC...
-  int flags = fcntl(fileno(fp), F_GETFD);
-  ASSERT_TRUE(flags != -1);
-  ASSERT_EQ(0, flags & FD_CLOEXEC);
+  AssertCloseOnExec(fileno(fp), false);
 
   fp = freopen("/proc/version", "re", fp);
 
   // ...but the new one does.
-  flags = fcntl(fileno(fp), F_GETFD);
-  ASSERT_TRUE(flags != -1);
-  ASSERT_EQ(FD_CLOEXEC, flags & FD_CLOEXEC);
+  AssertCloseOnExec(fileno(fp), true);
 
   fclose(fp);
 }
diff --git a/tests/stdlib_test.cpp b/tests/stdlib_test.cpp
index ed5767c..1a3fc03 100644
--- a/tests/stdlib_test.cpp
+++ b/tests/stdlib_test.cpp
@@ -325,16 +325,12 @@
 
 TEST(stdlib, mkostemp64) {
   TemporaryFile tf([](char* path) { return mkostemp64(path, O_CLOEXEC); });
-  int flags = fcntl(tf.fd, F_GETFD);
-  ASSERT_TRUE(flags != -1);
-  ASSERT_EQ(FD_CLOEXEC, flags & FD_CLOEXEC);
+  AssertCloseOnExec(tf.fd, true);
 }
 
 TEST(stdlib, mkostemp) {
   TemporaryFile tf([](char* path) { return mkostemp(path, O_CLOEXEC); });
-  int flags = fcntl(tf.fd, F_GETFD);
-  ASSERT_TRUE(flags != -1);
-  ASSERT_EQ(FD_CLOEXEC, flags & FD_CLOEXEC);
+  AssertCloseOnExec(tf.fd, true);
 }
 
 TEST(stdlib, mkstemp64) {
diff --git a/tests/sys_epoll_test.cpp b/tests/sys_epoll_test.cpp
index f6be4af..d1b411a 100644
--- a/tests/sys_epoll_test.cpp
+++ b/tests/sys_epoll_test.cpp
@@ -22,6 +22,8 @@
 #include <sys/epoll.h>
 #include <unistd.h>
 
+#include "utils.h"
+
 TEST(sys_epoll, smoke) {
   int epoll_fd = epoll_create(1);
   ASSERT_NE(-1, epoll_fd) << strerror(errno);
@@ -72,3 +74,18 @@
   close(fds[0]);
   close(fds[1]);
 }
+
+TEST(sys_epoll, epoll_create1) {
+  int fd;
+  fd = epoll_create(1);
+  AssertCloseOnExec(fd, false);
+  close(fd);
+
+  fd = epoll_create1(0);
+  AssertCloseOnExec(fd, false);
+  close(fd);
+
+  fd = epoll_create1(EPOLL_CLOEXEC);
+  AssertCloseOnExec(fd, true);
+  close(fd);
+}
diff --git a/tests/sys_socket_test.cpp b/tests/sys_socket_test.cpp
index 8f5afac..506e01f 100644
--- a/tests/sys_socket_test.cpp
+++ b/tests/sys_socket_test.cpp
@@ -22,6 +22,8 @@
 #include <sys/un.h>
 #include <fcntl.h>
 
+#include "utils.h"
+
 struct ConnectData {
   bool (*callback_fn)(int);
   const char* sock_path;
@@ -106,8 +108,8 @@
   int fd_acc = accept4(fd, reinterpret_cast<struct sockaddr*>(addr), &len, SOCK_CLOEXEC);
   ASSERT_NE(fd_acc, -1) << strerror(errno);
 
-  // Check that the flag was set properly.
-  ASSERT_EQ(FD_CLOEXEC, fcntl(fd_acc, F_GETFD) & FD_CLOEXEC);
+  // Check that SOCK_CLOEXEC was set properly.
+  AssertCloseOnExec(fd_acc, true);
 
   close(fd_acc);
 }
diff --git a/tests/unistd_test.cpp b/tests/unistd_test.cpp
index 022da4d..912ea0c 100644
--- a/tests/unistd_test.cpp
+++ b/tests/unistd_test.cpp
@@ -1043,6 +1043,17 @@
   ASSERT_EQ(EBADF, errno);
 }
 
+TEST(UNISTD_TEST, dup3) {
+  int fd = open("/proc/version", O_RDONLY);
+  ASSERT_EQ(666, dup3(fd, 666, 0));
+  AssertCloseOnExec(666, false);
+  close(666);
+  ASSERT_EQ(667, dup3(fd, 667, O_CLOEXEC));
+  AssertCloseOnExec(667, true);
+  close(667);
+  close(fd);
+}
+
 TEST(UNISTD_TEST, lockf_smoke) {
   constexpr off64_t file_size = 32*1024LL;
 
diff --git a/tests/utils.h b/tests/utils.h
index 410b427..a5783af 100644
--- a/tests/utils.h
+++ b/tests/utils.h
@@ -18,6 +18,7 @@
 #define __TEST_UTILS_H
 
 #include <dlfcn.h>
+#include <fcntl.h>
 #include <inttypes.h>
 #include <sys/mman.h>
 #include <sys/types.h>
@@ -151,6 +152,12 @@
   }
 }
 
+static inline void AssertCloseOnExec(int fd, bool close_on_exec) {
+  int flags = fcntl(fd, F_GETFD);
+  ASSERT_NE(flags, -1);
+  ASSERT_EQ(close_on_exec ? FD_CLOEXEC : 0, flags & FD_CLOEXEC);
+}
+
 // The absolute path to the executable
 const std::string& get_executable_path();