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/Android.bp b/tests/Android.bp
index 7e6e742..586ef34 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -422,6 +422,7 @@
"sys_uio_test.cpp",
"sys_un_test.cpp",
"sys_vfs_test.cpp",
+ "sys_wait_test.cpp",
"sys_xattr_test.cpp",
"system_properties_test.cpp",
"system_properties_test2.cpp",
diff --git a/tests/dirent_test.cpp b/tests/dirent_test.cpp
index 378aea4..56929d1 100644
--- a/tests/dirent_test.cpp
+++ b/tests/dirent_test.cpp
@@ -113,6 +113,18 @@
ASSERT_EQ(unsorted_name_list, unsorted_name_list_at64);
}
+static int is_version_filter(const dirent* de) {
+ return !strcmp(de->d_name, "version");
+}
+
+TEST(dirent, scandir_filter) {
+ dirent** entries;
+ errno = 0;
+ ASSERT_EQ(1, scandir("/proc", &entries, is_version_filter, nullptr));
+ ASSERT_STREQ("version", entries[0]->d_name);
+ free(entries);
+}
+
TEST(dirent, scandir_ENOENT) {
dirent** entries;
errno = 0;
diff --git a/tests/grp_pwd_test.cpp b/tests/grp_pwd_test.cpp
index 99117e4..bf65720 100644
--- a/tests/grp_pwd_test.cpp
+++ b/tests/grp_pwd_test.cpp
@@ -820,6 +820,24 @@
#endif
}
+TEST(grp, getgrouplist) {
+#if defined(__BIONIC__)
+ // Query the number of groups.
+ int ngroups = 0;
+ ASSERT_EQ(-1, getgrouplist("root", 123, nullptr, &ngroups));
+ ASSERT_EQ(1, ngroups);
+
+ // Query the specific groups (just the one you pass in on Android).
+ ngroups = 8;
+ gid_t groups[ngroups];
+ ASSERT_EQ(1, getgrouplist("root", 123, groups, &ngroups));
+ ASSERT_EQ(1, ngroups);
+ ASSERT_EQ(123u, groups[0]);
+#else
+ GTEST_SKIP() << "bionic-only test (groups too unpredictable)";
+#endif
+}
+
#if defined(__BIONIC__)
static void TestAidNamePrefix(const std::string& file_path) {
std::string file_contents;
diff --git a/tests/netinet_ether_test.cpp b/tests/netinet_ether_test.cpp
index faa3db4..af020ec 100644
--- a/tests/netinet_ether_test.cpp
+++ b/tests/netinet_ether_test.cpp
@@ -34,7 +34,7 @@
TEST(netinet_ether, ether_aton_r__ether_ntoa_r) {
ether_addr addr;
memset(&addr, 0, sizeof(addr));
- ether_addr* a = ether_aton_r("12:34:56:78:9a:bc", &addr);
+ ether_addr* a = ether_aton_r("12:34:56:78:9a:Bc", &addr);
ASSERT_EQ(&addr, a);
ASSERT_EQ(0x12, addr.ether_addr_octet[0]);
ASSERT_EQ(0x34, addr.ether_addr_octet[1]);
@@ -49,3 +49,11 @@
ASSERT_EQ(buf, p);
ASSERT_STREQ("12:34:56:78:9a:bc", buf);
}
+
+TEST(netinet_ether, ether_aton_r_failures) {
+ ether_addr addr;
+ ASSERT_TRUE(ether_aton_r("12:34:56:78:9a;bc", &addr) == nullptr);
+ ASSERT_TRUE(ether_aton_r("12:34:56:78:9a:bc ", &addr) == nullptr);
+ ASSERT_TRUE(ether_aton_r("g2:34:56:78:9a:bc ", &addr) == nullptr);
+ ASSERT_TRUE(ether_aton_r("1G:34:56:78:9a:bc ", &addr) == nullptr);
+}
diff --git a/tests/netinet_in_test.cpp b/tests/netinet_in_test.cpp
index 2606082..437e180 100644
--- a/tests/netinet_in_test.cpp
+++ b/tests/netinet_in_test.cpp
@@ -31,8 +31,15 @@
static constexpr uint64_t be64 = 0xf0debc9a78563412;
TEST(netinet_in, bindresvport) {
- // This isn't something we can usually test, so just check the symbol's there.
+ // This isn't something we can usually test (because you need to be root),
+ // so just check the symbol's there.
ASSERT_EQ(-1, bindresvport(-1, nullptr));
+
+ // Only AF_INET is supported.
+ sockaddr_in sin = {.sin_family = AF_INET6};
+ errno = 0;
+ ASSERT_EQ(-1, bindresvport(-1, &sin));
+ ASSERT_EQ(EPFNOSUPPORT, errno);
}
TEST(netinet_in, in6addr_any) {
diff --git a/tests/sched_test.cpp b/tests/sched_test.cpp
index 9309a7f..03e8062 100644
--- a/tests/sched_test.cpp
+++ b/tests/sched_test.cpp
@@ -301,3 +301,7 @@
// don't behave as POSIX specifies. http://b/26203902.
ASSERT_EQ(0, sched_setscheduler(getpid(), original_policy, &p));
}
+
+TEST(sched, sched_getaffinity_failure) {
+ ASSERT_EQ(-1, sched_getaffinity(getpid(), 0, nullptr));
+}
diff --git a/tests/search_test.cpp b/tests/search_test.cpp
index 1509199..8b8359d 100644
--- a/tests/search_test.cpp
+++ b/tests/search_test.cpp
@@ -114,6 +114,11 @@
ASSERT_EQ(3U, g_free_calls);
}
+TEST(search, tdestroy_null) {
+ // It's okay to pass a null node, and your callback will not be called.
+ tdestroy(nullptr, nullptr);
+}
+
struct pod_node {
explicit pod_node(int i) : i(i) {}
int i;
@@ -285,3 +290,26 @@
AssertEntry(e, "a", "B");
hdestroy_r(&h2);
}
+
+TEST(search, hsearch_resizing) {
+ ASSERT_NE(0, hcreate(1));
+
+ std::vector<char*> entries;
+ // Add enough entries to ensure that we've had to resize.
+ for (char ch = ' '; ch <= '~'; ++ch) {
+ char* p;
+ asprintf(&p, "%c", ch);
+ ENTRY e;
+ e.data = e.key = p;
+ ASSERT_TRUE(hsearch(e, ENTER) != nullptr);
+ entries.push_back(p);
+ }
+
+ // Check they're all there.
+ for (auto& p : entries) {
+ ENTRY* e = hsearch(ENTRY{.key = p, .data = nullptr}, FIND);
+ AssertEntry(e, p, p);
+ }
+
+ for (auto& p : entries) free(p);
+}
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);
+}
diff --git a/tests/stdlib_test.cpp b/tests/stdlib_test.cpp
index 3f1ec86..c7b2ad8 100644
--- a/tests/stdlib_test.cpp
+++ b/tests/stdlib_test.cpp
@@ -800,10 +800,25 @@
ASSERT_EQ(T(0), fn("123", &end_p, 37));
ASSERT_EQ(EINVAL, errno);
+ // Both leading + or - are always allowed (even for the strtou* family).
+ ASSERT_EQ(T(-123), fn("-123", &end_p, 10));
+ ASSERT_EQ(T(123), fn("+123", &end_p, 10));
+
// If we see "0x" *not* followed by a hex digit, we shouldn't swallow the 'x'.
ASSERT_EQ(T(0), fn("0xy", &end_p, 16));
ASSERT_EQ('x', *end_p);
+ // Hexadecimal (both the 0x and the digits) is case-insensitive.
+ ASSERT_EQ(T(0xab), fn("0xab", &end_p, 0));
+ ASSERT_EQ(T(0xab), fn("0Xab", &end_p, 0));
+ ASSERT_EQ(T(0xab), fn("0xAB", &end_p, 0));
+ ASSERT_EQ(T(0xab), fn("0XAB", &end_p, 0));
+ ASSERT_EQ(T(0xab), fn("0xAb", &end_p, 0));
+ ASSERT_EQ(T(0xab), fn("0XAb", &end_p, 0));
+
+ // Octal lives! (Sadly.)
+ ASSERT_EQ(T(0666), fn("0666", &end_p, 0));
+
if (std::numeric_limits<T>::is_signed) {
// Minimum (such as -128).
std::string min{std::to_string(std::numeric_limits<T>::min())};
@@ -878,6 +893,18 @@
CheckStrToInt(strtoumax);
}
+TEST(stdlib, atoi) {
+ // Implemented using strtol in bionic, so extensive testing unnecessary.
+ ASSERT_EQ(123, atoi("123four"));
+ ASSERT_EQ(0, atoi("hello"));
+}
+
+TEST(stdlib, atol) {
+ // Implemented using strtol in bionic, so extensive testing unnecessary.
+ ASSERT_EQ(123L, atol("123four"));
+ ASSERT_EQ(0L, atol("hello"));
+}
+
TEST(stdlib, abs) {
ASSERT_EQ(INT_MAX, abs(-INT_MAX));
ASSERT_EQ(INT_MAX, abs(INT_MAX));
diff --git a/tests/string_test.cpp b/tests/string_test.cpp
index fd7a551..22be852 100644
--- a/tests/string_test.cpp
+++ b/tests/string_test.cpp
@@ -64,6 +64,11 @@
ASSERT_STREQ("Unknown error 134", strerror(EHWPOISON + 1));
}
+TEST(STRING_TEST, strerror_l) {
+ // bionic just forwards to strerror(3).
+ ASSERT_STREQ("Success", strerror_l(0, LC_GLOBAL_LOCALE));
+}
+
#if defined(__BIONIC__)
static void* ConcurrentStrErrorFn(void*) {
bool equal = (strcmp("Unknown error 2002", strerror(2002)) == 0);
@@ -1607,6 +1612,13 @@
ASSERT_TRUE(strcoll("aac", "aab") > 0);
}
+TEST(STRING_TEST, strcoll_l_smoke) {
+ // bionic just forwards to strcoll(3).
+ ASSERT_TRUE(strcoll_l("aab", "aac", LC_GLOBAL_LOCALE) < 0);
+ ASSERT_TRUE(strcoll_l("aab", "aab", LC_GLOBAL_LOCALE) == 0);
+ ASSERT_TRUE(strcoll_l("aac", "aab", LC_GLOBAL_LOCALE) > 0);
+}
+
TEST(STRING_TEST, strxfrm_smoke) {
const char* src1 = "aab";
char dst1[16] = {};
@@ -1628,6 +1640,16 @@
ASSERT_TRUE(strcmp(dst1, dst2) < 0);
}
+TEST(STRING_TEST, strxfrm_l_smoke) {
+ // bionic just forwards to strxfrm(3), so this is a subset of the
+ // strxfrm test.
+ const char* src1 = "aab";
+ char dst1[16] = {};
+ ASSERT_EQ(strxfrm_l(dst1, src1, 0, LC_GLOBAL_LOCALE), 3U);
+ ASSERT_STREQ(dst1, "");
+ ASSERT_EQ(strxfrm_l(dst1, src1, sizeof(dst1), LC_GLOBAL_LOCALE), 3U);
+}
+
TEST(STRING_TEST, memccpy_smoke) {
char dst[32];
diff --git a/tests/sys_vfs_test.cpp b/tests/sys_vfs_test.cpp
index a521967..f82f505 100644
--- a/tests/sys_vfs_test.cpp
+++ b/tests/sys_vfs_test.cpp
@@ -44,12 +44,26 @@
Check(sb);
}
+TEST(sys_vfs, statfs_failure) {
+ struct statfs sb;
+ errno = 0;
+ ASSERT_EQ(-1, statfs("/does-not-exist", &sb));
+ ASSERT_EQ(ENOENT, errno);
+}
+
TEST(sys_vfs, statfs64) {
struct statfs64 sb;
ASSERT_EQ(0, statfs64("/proc", &sb));
Check(sb);
}
+TEST(sys_vfs, statfs64_failure) {
+ struct statfs64 sb;
+ errno = 0;
+ ASSERT_EQ(-1, statfs64("/does-not-exist", &sb));
+ ASSERT_EQ(ENOENT, errno);
+}
+
TEST(sys_vfs, fstatfs) {
struct statfs sb;
int fd = open("/proc", O_RDONLY);
@@ -58,6 +72,13 @@
Check(sb);
}
+TEST(sys_vfs, fstatfs_failure) {
+ struct statfs sb;
+ errno = 0;
+ ASSERT_EQ(-1, fstatfs(-1, &sb));
+ ASSERT_EQ(EBADF, errno);
+}
+
TEST(sys_vfs, fstatfs64) {
struct statfs64 sb;
int fd = open("/proc", O_RDONLY);
@@ -65,3 +86,10 @@
close(fd);
Check(sb);
}
+
+TEST(sys_vfs, fstatfs64_failure) {
+ struct statfs sb;
+ errno = 0;
+ ASSERT_EQ(-1, fstatfs(-1, &sb));
+ ASSERT_EQ(EBADF, errno);
+}
diff --git a/tests/sys_wait_test.cpp b/tests/sys_wait_test.cpp
new file mode 100644
index 0000000..c006972
--- /dev/null
+++ b/tests/sys_wait_test.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <gtest/gtest.h>
+
+#include <sys/wait.h>
+
+TEST(sys_wait, waitid) {
+ pid_t pid = fork();
+ ASSERT_NE(pid, -1);
+
+ if (pid == 0) _exit(66);
+
+ siginfo_t si = {};
+ ASSERT_EQ(0, waitid(P_PID, pid, &si, WEXITED));
+ ASSERT_EQ(pid, si.si_pid);
+ ASSERT_EQ(66, si.si_status);
+ ASSERT_EQ(CLD_EXITED, si.si_code);
+}
diff --git a/tests/time_test.cpp b/tests/time_test.cpp
index 5a977c2..3d745ea 100644
--- a/tests/time_test.cpp
+++ b/tests/time_test.cpp
@@ -1008,4 +1008,5 @@
TEST(time, difftime) {
ASSERT_EQ(1.0, difftime(1, 0));
+ ASSERT_EQ(-1.0, difftime(0, 1));
}