Merge "Add strerrordesc_np() and strerrorname_np()." into main
diff --git a/libc/include/sys/statvfs.h b/libc/include/sys/statvfs.h
index 46fbea5..7bc5e63 100644
--- a/libc/include/sys/statvfs.h
+++ b/libc/include/sys/statvfs.h
@@ -88,6 +88,9 @@
 /** Flag for `f_flag` in `struct statvfs`: see `MS_RELATIME`. */
 #define ST_RELATIME    0x1000
 
+/** Flag for `f_flag` in `struct statvfs`: don't follow symlinks. */
+#define ST_NOSYMFOLLOW 0x2000
+
 /**
  * [statvfs(3)](http://man7.org/linux/man-pages/man3/statvfs.3.html)
  * queries filesystem statistics for the given path.
diff --git a/tests/dirent_test.cpp b/tests/dirent_test.cpp
index 3ea9cbd..4d21246 100644
--- a/tests/dirent_test.cpp
+++ b/tests/dirent_test.cpp
@@ -29,6 +29,8 @@
 #include <set>
 #include <string>
 
+#include "utils.h"
+
 static void CheckProcSelf(std::set<std::string>& names) {
   // We have a good idea of what should be in /proc/self.
   ASSERT_TRUE(names.find(".") != names.end());
@@ -124,7 +126,6 @@
 
 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);
@@ -134,14 +135,14 @@
   dirent** entries;
   errno = 0;
   ASSERT_EQ(-1, scandir("/does-not-exist", &entries, nullptr, nullptr));
-  ASSERT_EQ(ENOENT, errno);
+  ASSERT_ERRNO(ENOENT);
 }
 
 TEST(dirent, scandir64_ENOENT) {
   dirent64** entries;
   errno = 0;
   ASSERT_EQ(-1, scandir64("/does-not-exist", &entries, nullptr, nullptr));
-  ASSERT_EQ(ENOENT, errno);
+  ASSERT_ERRNO(ENOENT);
 }
 
 TEST(dirent, scandirat_ENOENT) {
@@ -151,7 +152,7 @@
   dirent** entries;
   errno = 0;
   ASSERT_EQ(-1, scandirat(root_fd, "does-not-exist", &entries, nullptr, nullptr));
-  ASSERT_EQ(ENOENT, errno);
+  ASSERT_ERRNO(ENOENT);
   close(root_fd);
 #else
   GTEST_SKIP() << "musl doesn't have scandirat or scandirat64";
@@ -165,7 +166,7 @@
   dirent64** entries;
   errno = 0;
   ASSERT_EQ(-1, scandirat64(root_fd, "does-not-exist", &entries, nullptr, nullptr));
-  ASSERT_EQ(ENOENT, errno);
+  ASSERT_ERRNO(ENOENT);
   close(root_fd);
 #else
   GTEST_SKIP() << "musl doesn't have scandirat or scandirat64";
@@ -174,12 +175,12 @@
 
 TEST(dirent, fdopendir_invalid) {
   ASSERT_TRUE(fdopendir(-1) == nullptr);
-  ASSERT_EQ(EBADF, errno);
+  ASSERT_ERRNO(EBADF);
 
   int fd = open("/dev/null", O_RDONLY);
   ASSERT_NE(fd, -1);
   ASSERT_TRUE(fdopendir(fd) == nullptr);
-  ASSERT_EQ(ENOTDIR, errno);
+  ASSERT_ERRNO(ENOTDIR);
   close(fd);
 }
 
@@ -193,15 +194,17 @@
 
   // fdopendir(3) took ownership, so closedir(3) closed our fd.
   ASSERT_EQ(close(fd), -1);
-  ASSERT_EQ(EBADF, errno);
+  ASSERT_ERRNO(EBADF);
 }
 
 TEST(dirent, opendir_invalid) {
+  errno = 0;
   ASSERT_TRUE(opendir("/does/not/exist") == nullptr);
-  ASSERT_EQ(ENOENT, errno);
+  ASSERT_ERRNO(ENOENT);
 
+  errno = 0;
   ASSERT_TRUE(opendir("/dev/null") == nullptr);
-  ASSERT_EQ(ENOTDIR, errno);
+  ASSERT_ERRNO(ENOTDIR);
 }
 
 TEST(dirent, opendir) {
@@ -215,7 +218,7 @@
 TEST(dirent, closedir_invalid) {
   DIR* d = nullptr;
   ASSERT_EQ(closedir(d), -1);
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 }
 
 TEST(dirent, closedir) {
@@ -235,7 +238,7 @@
   }
   // Reading to the end of the directory is not an error.
   // readdir(3) returns NULL, but leaves errno as 0.
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
   ASSERT_EQ(closedir(d), 0);
 
   CheckProcSelf(name_set);
@@ -252,7 +255,7 @@
   }
   // Reading to the end of the directory is not an error.
   // readdir64(3) returns NULL, but leaves errno as 0.
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
   ASSERT_EQ(closedir(d), 0);
 
   CheckProcSelf(name_set);
@@ -270,7 +273,7 @@
   }
   // Reading to the end of the directory is not an error.
   // readdir_r(3) returns NULL, but leaves errno as 0.
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
   ASSERT_EQ(closedir(d), 0);
 
   CheckProcSelf(name_set);
@@ -288,7 +291,7 @@
   }
   // Reading to the end of the directory is not an error.
   // readdir64_r(3) returns NULL, but leaves errno as 0.
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
   ASSERT_EQ(closedir(d), 0);
 
   CheckProcSelf(name_set);
@@ -365,7 +368,7 @@
   ASSERT_EQ(end_offset, telldir(d));
   errno = 0;
   ASSERT_EQ(nullptr, readdir(d));
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
 
   ASSERT_EQ(0, closedir(d));
 }
diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp
index ea28822..3c2dcf2 100644
--- a/tests/dlext_test.cpp
+++ b/tests/dlext_test.cpp
@@ -964,10 +964,7 @@
 
   // create memfd
   int memfd = memfd_create("foobar", MFD_CLOEXEC);
-  if (memfd == -1 && errno == ENOSYS) {
-    return;
-  }
-
+  if (memfd == -1 && errno == ENOSYS) GTEST_SKIP() << "no memfd_create() in this kernel";
   ASSERT_TRUE(memfd != -1) << strerror(errno);
 
   // Check st.f_type is TMPFS_MAGIC for memfd
diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp
index b68ee7b..67f1973 100644
--- a/tests/dlfcn_test.cpp
+++ b/tests/dlfcn_test.cpp
@@ -835,7 +835,7 @@
   // this case.
   uintptr_t page_start = reinterpret_cast<uintptr_t>(taxicab_number) & ~(PAGE_SIZE - 1);
   ASSERT_TRUE(mprotect(reinterpret_cast<void*>(page_start), PAGE_SIZE, PROT_NONE) != 0);
-  ASSERT_EQ(ENOMEM, errno) << strerror(errno);
+  ASSERT_ERRNO(ENOMEM);
 }
 
 static void ConcurrentDlErrorFn(std::string& error) {
diff --git a/tests/eventfd_test.cpp b/tests/eventfd_test.cpp
index eb423c1..3107a46 100644
--- a/tests/eventfd_test.cpp
+++ b/tests/eventfd_test.cpp
@@ -34,7 +34,7 @@
 
   // Reading clears the counter.
   ASSERT_EQ(-1, eventfd_read(fd, &value));
-  ASSERT_EQ(EAGAIN, errno);
+  ASSERT_ERRNO(EAGAIN);
 
   // Values written are added until the next read.
   ASSERT_EQ(0, eventfd_write(fd, 1));
@@ -88,7 +88,7 @@
 
   // The counter is cleared after the initial value decrements to 0.
   ASSERT_EQ(-1, eventfd_read(fd, &value));
-  ASSERT_EQ(EAGAIN, errno);
+  ASSERT_ERRNO(EAGAIN);
 
   close(fd);
 }
diff --git a/tests/fcntl_test.cpp b/tests/fcntl_test.cpp
index c1c586c..f8f559b 100644
--- a/tests/fcntl_test.cpp
+++ b/tests/fcntl_test.cpp
@@ -34,6 +34,8 @@
 #include <linux/magic.h>
 #endif
 
+#include "utils.h"
+
 using fcntl_DeathTest = SilentDeathTest;
 
 TEST(fcntl, fcntl_smoke) {
@@ -80,9 +82,9 @@
 
 TEST(fcntl, creat_creat64) {
   ASSERT_EQ(-1, creat("", 0666));
-  ASSERT_EQ(ENOENT, errno);
+  ASSERT_ERRNO(ENOENT);
   ASSERT_EQ(-1, creat64("", 0666));
-  ASSERT_EQ(ENOENT, errno);
+  ASSERT_ERRNO(ENOENT);
 }
 
 TEST(fcntl, posix_fadvise) {
@@ -90,16 +92,16 @@
   errno = 0;
 
   EXPECT_EQ(EBADF, posix_fadvise(-1, 0, 0, POSIX_FADV_NORMAL));
-  EXPECT_EQ(0, errno);
+  EXPECT_ERRNO(0);
 
   EXPECT_EQ(EBADF, posix_fadvise64(-1, 0, 0, POSIX_FADV_NORMAL));
-  EXPECT_EQ(0, errno);
+  EXPECT_ERRNO(0);
 
   EXPECT_EQ(EINVAL, posix_fadvise(tf.fd, 0, 0, -1));
-  EXPECT_EQ(0, errno);
+  EXPECT_ERRNO(0);
 
   EXPECT_EQ(EINVAL, posix_fadvise64(tf.fd, 0, 0, -1));
-  EXPECT_EQ(0, errno);
+  EXPECT_ERRNO(0);
 
   EXPECT_EQ(0, posix_fadvise(tf.fd, 0, 0, POSIX_FADV_NORMAL));
   EXPECT_EQ(0, posix_fadvise64(tf.fd, 0, 0, POSIX_FADV_NORMAL));
@@ -113,19 +115,19 @@
 
   errno = 0;
   ASSERT_EQ(-1, fallocate(tf.fd, 0, 0, -1));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 
   errno = 0;
   ASSERT_EQ(-1, fallocate64(tf.fd, 0, 0, -1));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 
   errno = 0;
   ASSERT_EQ(EINVAL, posix_fallocate(tf.fd, 0, -1));
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
 
   errno = 0;
   ASSERT_EQ(EINVAL, posix_fallocate64(tf.fd, 0, -1));
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
 }
 
 TEST(fcntl, fallocate) {
@@ -269,14 +271,14 @@
   // Just check that the function is available.
   errno = 0;
   ASSERT_EQ(-1, readahead(-1, 0, 123));
-  ASSERT_EQ(EBADF, errno);
+  ASSERT_ERRNO(EBADF);
 }
 
 TEST(fcntl, sync_file_range) {
   // Just check that the function is available.
   errno = 0;
   ASSERT_EQ(-1, sync_file_range(-1, 0, 0, 0));
-  ASSERT_EQ(EBADF, errno);
+  ASSERT_ERRNO(EBADF);
 
   TemporaryFile tf;
   ASSERT_EQ(0, sync_file_range(tf.fd, 0, 0, 0));
@@ -285,7 +287,7 @@
   // Check that the `flags` argument gets passed to the kernel correctly.
   errno = 0;
   ASSERT_EQ(-1, sync_file_range(tf.fd, 0, 0, ~0));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 }
 
 static bool parse_kernel_release(long* const major, long* const minor) {
@@ -312,7 +314,7 @@
     ASSERT_EQ(0, fstatfs(tf.fd, &sfs));
     if (sfs.f_type == EXT4_SUPER_MAGIC) {
       ASSERT_EQ(-1, fallocate(tf.fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 0, 1));
-      ASSERT_EQ(errno, EOPNOTSUPP);
+      ASSERT_ERRNO(EOPNOTSUPP);
     }
   }
 }
@@ -355,7 +357,7 @@
   ASSERT_EQ(-1, linkat(AT_FDCWD, android::base::StringPrintf("/proc/self/fd/%d", fd).c_str(),
                        AT_FDCWD, android::base::StringPrintf("%s/no_chance", dir.path).c_str(),
                        AT_SYMLINK_FOLLOW));
-  ASSERT_EQ(ENOENT, errno);
+  ASSERT_ERRNO(ENOENT);
   ASSERT_EQ(0, close(fd));
 #endif
 }
diff --git a/tests/fdtrack_test.cpp b/tests/fdtrack_test.cpp
index 9fcb402..5988bc4 100644
--- a/tests/fdtrack_test.cpp
+++ b/tests/fdtrack_test.cpp
@@ -40,6 +40,8 @@
 #include <android-base/logging.h>
 #include <android-base/unique_fd.h>
 
+#include "utils.h"
+
 using android::base::ReceiveFileDescriptors;
 using android::base::SendFileDescriptors;
 using android::base::unique_fd;
@@ -233,27 +235,22 @@
 
 FDTRACK_TEST(pidfd_open, ({
   int rc = pidfd_open(getpid(), 0);
-  if (rc == -1) {
-    ASSERT_EQ(ENOSYS, errno);
-    GTEST_SKIP() << "pidfd_open not available";
-  }
+  if (rc == -1 && errno == ENOSYS) GTEST_SKIP() << "no pidfd_open() in this kernel";
+  ASSERT_NE(-1, rc) << strerror(errno);
   rc;
 }));
 
 FDTRACK_TEST(pidfd_getfd, ({
   android_fdtrack_set_enabled(false);
   int pidfd_self = pidfd_open(getpid(), 0);
-  if (pidfd_self == -1) {
-    ASSERT_EQ(ENOSYS, errno);
-    GTEST_SKIP() << "pidfd_open not available";
-  }
+  if (pidfd_self == -1 && errno == ENOSYS) GTEST_SKIP() << "no pidfd_open() in this kernel";
+  ASSERT_NE(-1, pidfd_self) << strerror(errno);
+
   android_fdtrack_set_enabled(true);
 
   int rc = pidfd_getfd(pidfd_self, STDIN_FILENO, 0);
-  if (rc == -1) {
-    ASSERT_EQ(ENOSYS, errno);
-    GTEST_SKIP() << "pidfd_getfd not available";
-  }
+  if (rc == -1 && errno == ENOSYS) GTEST_SKIP() << "no pidfd_getfd() in this kernel";
+  ASSERT_NE(-1, rc) << strerror(errno);
 
   android_fdtrack_set_enabled(false);
   close(pidfd_self);
diff --git a/tests/ftw_test.cpp b/tests/ftw_test.cpp
index 6473f71..9d9c1d3 100644
--- a/tests/ftw_test.cpp
+++ b/tests/ftw_test.cpp
@@ -28,6 +28,8 @@
 #include <android-base/stringprintf.h>
 #include <gtest/gtest.h>
 
+#include "utils.h"
+
 static void MakeTree(const char* root) {
   char path[PATH_MAX];
 
@@ -167,35 +169,35 @@
 TEST(ftw, ftw_non_existent_ENOENT) {
   errno = 0;
   ASSERT_EQ(-1, ftw("/does/not/exist", null_ftw_callback<struct stat>, 128));
-  ASSERT_EQ(ENOENT, errno);
+  ASSERT_ERRNO(ENOENT);
   errno = 0;
   ASSERT_EQ(-1, ftw64("/does/not/exist", null_ftw_callback<struct stat64>, 128));
-  ASSERT_EQ(ENOENT, errno);
+  ASSERT_ERRNO(ENOENT);
 }
 
 TEST(ftw, nftw_non_existent_ENOENT) {
   errno = 0;
   ASSERT_EQ(-1, nftw("/does/not/exist", null_nftw_callback<struct stat>, 128, FTW_PHYS));
-  ASSERT_EQ(ENOENT, errno);
+  ASSERT_ERRNO(ENOENT);
   errno = 0;
   ASSERT_EQ(-1, nftw64("/does/not/exist", null_nftw_callback<struct stat64>, 128, FTW_PHYS));
-  ASSERT_EQ(ENOENT, errno);
+  ASSERT_ERRNO(ENOENT);
 }
 
 TEST(ftw, ftw_empty_ENOENT) {
   errno = 0;
   ASSERT_EQ(-1, ftw("", null_ftw_callback<struct stat>, 128));
-  ASSERT_EQ(ENOENT, errno);
+  ASSERT_ERRNO(ENOENT);
   errno = 0;
   ASSERT_EQ(-1, ftw64("", null_ftw_callback<struct stat64>, 128));
-  ASSERT_EQ(ENOENT, errno);
+  ASSERT_ERRNO(ENOENT);
 }
 
 TEST(ftw, nftw_empty_ENOENT) {
   errno = 0;
   ASSERT_EQ(-1, nftw("", null_nftw_callback<struct stat>, 128, FTW_PHYS));
-  ASSERT_EQ(ENOENT, errno);
+  ASSERT_ERRNO(ENOENT);
   errno = 0;
   ASSERT_EQ(-1, nftw64("", null_nftw_callback<struct stat64>, 128, FTW_PHYS));
-  ASSERT_EQ(ENOENT, errno);
+  ASSERT_ERRNO(ENOENT);
 }
diff --git a/tests/getauxval_test.cpp b/tests/getauxval_test.cpp
index f4ec7f5..3016432 100644
--- a/tests/getauxval_test.cpp
+++ b/tests/getauxval_test.cpp
@@ -21,6 +21,8 @@
 #include <sys/utsname.h>
 #include <gtest/gtest.h>
 
+#include "utils.h"
+
 TEST(getauxval, expected_values) {
   ASSERT_EQ(0UL, getauxval(AT_SECURE));
   ASSERT_EQ(getuid(), getauxval(AT_UID));
@@ -38,7 +40,7 @@
 TEST(getauxval, unexpected_values) {
   errno = 0;
   ASSERT_EQ(0UL, getauxval(0xdeadbeef));
-  ASSERT_EQ(ENOENT, errno);
+  ASSERT_ERRNO(ENOENT);
 }
 
 TEST(getauxval, arm_has_AT_HWCAP2) {
@@ -57,7 +59,7 @@
     // to check errno to see whether we got a "true" 0 or a "not found" 0.
     errno = 0;
     getauxval(AT_HWCAP2);
-    ASSERT_EQ(0, errno) << "64-bit kernel not reporting AT_HWCAP2 to 32-bit ARM process";
+    ASSERT_ERRNO(0) << "64-bit kernel not reporting AT_HWCAP2 to 32-bit ARM process";
     return;
   }
 #endif
diff --git a/tests/getcwd_test.cpp b/tests/getcwd_test.cpp
index 4fec40b..26ea75f 100644
--- a/tests/getcwd_test.cpp
+++ b/tests/getcwd_test.cpp
@@ -29,7 +29,7 @@
   errno = 0;
   char* cwd = getcwd(nullptr, 0);
   ASSERT_TRUE(cwd != nullptr);
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
   ASSERT_GE(strlen(cwd), 1U);
   free(cwd);
 }
@@ -39,7 +39,7 @@
   errno = 0;
   char* cwd = getcwd(nullptr, PATH_MAX);
   ASSERT_TRUE(cwd != nullptr);
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
   ASSERT_GE(strlen(cwd), 1U);
   free(cwd);
 }
@@ -49,7 +49,7 @@
   errno = 0;
   char* cwd = getcwd(nullptr, 1);
   ASSERT_TRUE(cwd == nullptr);
-  ASSERT_EQ(ERANGE, errno);
+  ASSERT_ERRNO(ERANGE);
 }
 
 TEST(getcwd, auto_too_large) {
@@ -58,7 +58,7 @@
   errno = 0;
   char* cwd = getcwd(nullptr, static_cast<size_t>(-1));
   ASSERT_TRUE(cwd == nullptr);
-  ASSERT_EQ(ENOMEM, errno);
+  ASSERT_ERRNO(ENOMEM);
 }
 
 TEST(getcwd, manual_too_small) {
@@ -67,7 +67,7 @@
   errno = 0;
   char* cwd = getcwd(tiny_buf, sizeof(tiny_buf));
   ASSERT_TRUE(cwd == nullptr);
-  ASSERT_EQ(ERANGE, errno);
+  ASSERT_ERRNO(ERANGE);
 }
 
 TEST(getcwd, manual_zero) {
@@ -76,7 +76,7 @@
   errno = 0;
   char* cwd = getcwd(tiny_buf, 0);
   ASSERT_TRUE(cwd == nullptr);
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 }
 
 TEST(getcwd, manual_path_max) {
@@ -84,7 +84,7 @@
   errno = 0;
   char* cwd = getcwd(buf, PATH_MAX);
   ASSERT_TRUE(cwd == buf);
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
   ASSERT_GE(strlen(cwd), 1U);
   delete[] cwd;
 }
diff --git a/tests/grp_pwd_test.cpp b/tests/grp_pwd_test.cpp
index 65a54a6..d3acf03 100644
--- a/tests/grp_pwd_test.cpp
+++ b/tests/grp_pwd_test.cpp
@@ -41,6 +41,8 @@
 // Generated android_ids array
 #include "generated_android_ids.h"
 
+#include "utils.h"
+
 using android::base::Join;
 using android::base::ReadFileToString;
 using android::base::Split;
@@ -86,7 +88,7 @@
                            bool check_username) {
   errno = 0;
   passwd* pwd = getpwuid(uid);
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
   SCOPED_TRACE("getpwuid");
   check_passwd(pwd, username, uid, uid_type, check_username);
 }
@@ -95,7 +97,7 @@
                            bool check_username) {
   errno = 0;
   passwd* pwd = getpwnam(username);
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
   SCOPED_TRACE("getpwnam");
   check_passwd(pwd, username, uid, uid_type, check_username);
 }
@@ -110,7 +112,7 @@
   passwd* pwd = nullptr;
   result = getpwuid_r(uid, &pwd_storage, buf, sizeof(buf), &pwd);
   ASSERT_EQ(0, result);
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
   SCOPED_TRACE("getpwuid_r");
   check_passwd(pwd, username, uid, uid_type, check_username);
 }
@@ -125,7 +127,7 @@
   passwd* pwd = nullptr;
   result = getpwnam_r(username, &pwd_storage, buf, sizeof(buf), &pwd);
   ASSERT_EQ(0, result);
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
   SCOPED_TRACE("getpwnam_r");
   check_passwd(pwd, username, uid, uid_type, check_username);
 }
@@ -145,7 +147,7 @@
   passwd* passwd = nullptr;
   passwd = getpwuid(uid);
   EXPECT_EQ(nullptr, passwd) << "name = '" << passwd->pw_name << "'";
-  EXPECT_EQ(ENOENT, errno);
+  EXPECT_ERRNO(ENOENT);
 
   struct passwd passwd_storage;
   char buf[512];
@@ -159,7 +161,7 @@
   passwd* passwd = nullptr;
   passwd = getpwnam(username);
   EXPECT_EQ(nullptr, passwd) << "name = '" << passwd->pw_name << "'";
-  EXPECT_EQ(ENOENT, errno);
+  EXPECT_ERRNO(ENOENT);
 
   struct passwd passwd_storage;
   char buf[512];
@@ -507,7 +509,7 @@
 static void check_getgrgid(const char* group_name, gid_t gid, bool check_groupname) {
   errno = 0;
   group* grp = getgrgid(gid);
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
   SCOPED_TRACE("getgrgid");
   check_group(grp, group_name, gid, check_groupname);
 }
@@ -515,7 +517,7 @@
 static void check_getgrnam(const char* group_name, gid_t gid, bool check_groupname) {
   errno = 0;
   group* grp = getgrnam(group_name);
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
   SCOPED_TRACE("getgrnam");
   check_group(grp, group_name, gid, check_groupname);
 }
@@ -528,7 +530,7 @@
   errno = 0;
   int result = getgrgid_r(gid, &grp_storage, buf, sizeof(buf), &grp);
   ASSERT_EQ(0, result);
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
   SCOPED_TRACE("getgrgid_r");
   check_group(grp, group_name, gid, check_groupname);
 }
@@ -541,7 +543,7 @@
   errno = 0;
   int result = getgrnam_r(group_name, &grp_storage, buf, sizeof(buf), &grp);
   ASSERT_EQ(0, result);
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
   SCOPED_TRACE("getgrnam_r");
   check_group(grp, group_name, gid, check_groupname);
 }
@@ -560,7 +562,7 @@
   group* group = nullptr;
   group = getgrgid(gid);
   EXPECT_EQ(nullptr, group) << "name = '" << group->gr_name << "'";
-  EXPECT_EQ(ENOENT, errno);
+  EXPECT_ERRNO(ENOENT);
 
   struct group group_storage;
   char buf[512];
@@ -574,7 +576,7 @@
   group* group = nullptr;
   group = getgrnam(groupname);
   EXPECT_EQ(nullptr, group) << "name = '" << group->gr_name << "'";
-  EXPECT_EQ(ENOENT, errno);
+  EXPECT_ERRNO(ENOENT);
 
   struct group group_storage;
   char buf[512];
diff --git a/tests/iconv_test.cpp b/tests/iconv_test.cpp
index bd99000..9a2a46f 100644
--- a/tests/iconv_test.cpp
+++ b/tests/iconv_test.cpp
@@ -18,18 +18,20 @@
 
 #include <iconv.h>
 
+#include "utils.h"
+
 #define INVALID_ICONV_T reinterpret_cast<iconv_t>(-1)
 
 TEST(iconv, iconv_open_EINVAL) {
   errno = 0;
   ASSERT_EQ(INVALID_ICONV_T, iconv_open("silly", "silly"));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
   errno = 0;
   ASSERT_EQ(INVALID_ICONV_T, iconv_open("silly", "UTF-8"));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
   errno = 0;
   ASSERT_EQ(INVALID_ICONV_T, iconv_open("UTF-8", "silly"));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 }
 
 TEST(iconv, iconv_open_comparator) {
@@ -44,10 +46,10 @@
   // "...but not "utf-80" or "ut8"."
   errno = 0;
   ASSERT_EQ(INVALID_ICONV_T, iconv_open("UTF-8", "utf-80"));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
   errno = 0;
   ASSERT_EQ(INVALID_ICONV_T, iconv_open("UTF-8", "ut80"));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 }
 
 TEST(iconv, iconv_smoke) {
@@ -122,7 +124,7 @@
   // With "//IGNORE", we just skip them (but return failure).
   errno = 0;
   EXPECT_EQ(static_cast<size_t>(-1), iconv(c, &in, &in_bytes, &out, &out_bytes));
-  EXPECT_EQ(EILSEQ, errno);
+  EXPECT_ERRNO(EILSEQ);
 
   EXPECT_EQ('a', buf[0]);
   EXPECT_EQ('z', buf[1]);
@@ -149,7 +151,7 @@
   // The second input character isn't representable as ASCII, so we stop there.
   errno = 0;
   EXPECT_EQ(static_cast<size_t>(-1), iconv(c, &in, &in_bytes, &out, &out_bytes));
-  EXPECT_EQ(EILSEQ, errno);
+  EXPECT_ERRNO(EILSEQ);
 
   EXPECT_EQ('a', buf[0]);
   EXPECT_EQ(0, buf[1]);
@@ -175,13 +177,13 @@
   // The second input byte is a malformed character, so we stop there.
   errno = 0;
   EXPECT_EQ(static_cast<size_t>(-1), iconv(c, &in, &in_bytes, &out, &out_bytes));
-  EXPECT_EQ(EILSEQ, errno);
+  EXPECT_ERRNO(EILSEQ);
   EXPECT_EQ('\xd9', *in); // *in is left pointing to the start of the invalid sequence.
   ++in;
   --in_bytes;
   errno = 0;
   EXPECT_EQ(0U, iconv(c, &in, &in_bytes, &out, &out_bytes));
-  EXPECT_EQ(0, errno);
+  EXPECT_ERRNO(0);
 
   EXPECT_EQ('a', buf[0]);
   EXPECT_EQ('z', buf[1]);
@@ -208,7 +210,7 @@
   // The second input byte is just the start of a character, and we don't have any more bytes.
   errno = 0;
   EXPECT_EQ(static_cast<size_t>(-1), iconv(c, &in, &in_bytes, &out, &out_bytes));
-  EXPECT_EQ(EINVAL, errno);
+  EXPECT_ERRNO(EINVAL);
   EXPECT_EQ('\xd9', *in); // *in is left pointing to the start of the incomplete sequence.
 
   EXPECT_EQ('a', buf[0]);
@@ -236,7 +238,7 @@
   out_bytes = 1;
   errno = 0;
   EXPECT_EQ(static_cast<size_t>(-1), iconv(c, &in, &in_bytes, &out, &out_bytes));
-  EXPECT_EQ(E2BIG, errno);
+  EXPECT_ERRNO(E2BIG);
   EXPECT_EQ(2U, in_bytes);
   EXPECT_EQ(0U, out_bytes);
 
@@ -244,7 +246,7 @@
   out_bytes = 0;
   errno = 0;
   EXPECT_EQ(static_cast<size_t>(-1), iconv(c, &in, &in_bytes, &out, &out_bytes));
-  EXPECT_EQ(E2BIG, errno);
+  EXPECT_ERRNO(E2BIG);
   EXPECT_EQ(2U, in_bytes);
   EXPECT_EQ(0U, out_bytes);
 
@@ -252,7 +254,7 @@
   out_bytes = 1;
   errno = 0;
   EXPECT_EQ(static_cast<size_t>(-1), iconv(c, &in, &in_bytes, &out, &out_bytes));
-  EXPECT_EQ(E2BIG, errno);
+  EXPECT_ERRNO(E2BIG);
   EXPECT_EQ(1U, in_bytes);
   EXPECT_EQ(0U, out_bytes);
 
@@ -260,7 +262,7 @@
   out_bytes = 1;
   errno = 0;
   EXPECT_EQ(0U, iconv(c, &in, &in_bytes, &out, &out_bytes));
-  EXPECT_EQ(0, errno);
+  EXPECT_ERRNO(0);
   EXPECT_EQ(0U, in_bytes);
   EXPECT_EQ(0U, out_bytes);
 
@@ -279,13 +281,13 @@
   size_t out_bytes = 0;
   errno = 0;
   ASSERT_EQ(static_cast<size_t>(-1), iconv(INVALID_ICONV_T, &in, &in_bytes, &out, &out_bytes));
-  ASSERT_EQ(EBADF, errno);
+  ASSERT_ERRNO(EBADF);
 }
 
 TEST(iconv, iconv_close_invalid_converter_EBADF) {
   errno = 0;
   ASSERT_EQ(-1, iconv_close(INVALID_ICONV_T));
-  ASSERT_EQ(EBADF, errno);
+  ASSERT_ERRNO(EBADF);
 }
 
 static void RoundTrip(const char* dst_enc, const char* expected_bytes, size_t n) {
@@ -368,7 +370,7 @@
   char* out = reinterpret_cast<char*>(out_buf);
   errno = 0;
   ASSERT_EQ(static_cast<size_t>(-1), iconv(c, &in, &in_bytes, &out, &out_bytes));
-  EXPECT_EQ(expected_errno, errno);
+  EXPECT_ERRNO(expected_errno);
   EXPECT_EQ(0, iconv_close(c));
 }
 
@@ -442,13 +444,13 @@
   // Points to a null pointer...
   errno = 0;
   ASSERT_EQ(static_cast<size_t>(0), iconv(c, &in, &in_bytes, &out, &out_bytes));
-  EXPECT_EQ(0, errno);
+  EXPECT_ERRNO(0);
   EXPECT_EQ(sizeof(out_buf), out_bytes);
 
   // Is a null pointer...
   errno = 0;
   ASSERT_EQ(static_cast<size_t>(0), iconv(c, nullptr, &in_bytes, &out, &out_bytes));
-  EXPECT_EQ(0, errno);
+  EXPECT_ERRNO(0);
   EXPECT_EQ(sizeof(out_buf), out_bytes);
 
   // Is a null pointer and so is in_bytes. This isn't specified by POSIX, but
@@ -456,7 +458,7 @@
   // https://issuetracker.google.com/180598400
   errno = 0;
   ASSERT_EQ(static_cast<size_t>(0), iconv(c, nullptr, nullptr, &out, &out_bytes));
-  EXPECT_EQ(0, errno);
+  EXPECT_ERRNO(0);
   EXPECT_EQ(sizeof(out_buf), out_bytes);
 
   EXPECT_EQ(0, iconv_close(c));
diff --git a/tests/ifaddrs_test.cpp b/tests/ifaddrs_test.cpp
index 4b9d4d8..95562be 100644
--- a/tests/ifaddrs_test.cpp
+++ b/tests/ifaddrs_test.cpp
@@ -32,6 +32,8 @@
 #include <thread>
 #include <vector>
 
+#include "utils.h"
+
 TEST(ifaddrs, freeifaddrs_null) {
   freeifaddrs(nullptr);
 }
@@ -294,7 +296,7 @@
   while (true) {
     int fd = open("/dev/null", O_RDONLY|O_CLOEXEC);
     if (fd == -1) {
-      ASSERT_EQ(EMFILE, errno);
+      ASSERT_ERRNO(EMFILE);
       break;
     }
     fds.push_back(fd);
@@ -302,7 +304,7 @@
 
   ifaddrs* addrs;
   EXPECT_EQ(-1, getifaddrs(&addrs));
-  EXPECT_EQ(EMFILE, errno);
+  EXPECT_ERRNO(EMFILE);
 
   for (int fd : fds) close(fd);
 }
diff --git a/tests/inttypes_test.cpp b/tests/inttypes_test.cpp
index f7dfdb5..70163e6 100644
--- a/tests/inttypes_test.cpp
+++ b/tests/inttypes_test.cpp
@@ -20,6 +20,8 @@
 #include <gtest/gtest.h>
 #include <stdio.h>
 
+#include "utils.h"
+
 #define PRINTF_TYPED(FMT_SUFFIX, TYPE_SUFFIX) \
   do { \
     char buf[512]; \
@@ -124,13 +126,13 @@
 TEST(inttypes, strtoimax_EINVAL) {
   errno = 0;
   strtoimax("123", nullptr, -1);
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
   errno = 0;
   strtoimax("123", nullptr, 1);
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
   errno = 0;
   strtoimax("123", nullptr, 37);
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 }
 
 TEST(inttypes, strtoumax_dec) {
@@ -154,37 +156,37 @@
 TEST(inttypes, strtoumax_EINVAL) {
   errno = 0;
   strtoumax("123", nullptr, -1);
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
   errno = 0;
   strtoumax("123", nullptr, 1);
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
   errno = 0;
   strtoumax("123", nullptr, 37);
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 }
 
 TEST(inttypes, wcstoimax_EINVAL) {
   errno = 0;
   wcstoimax(L"123", nullptr, -1);
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
   errno = 0;
   wcstoimax(L"123", nullptr, 1);
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
   errno = 0;
   wcstoimax(L"123", nullptr, 37);
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 }
 
 TEST(inttypes, wcstoumax_EINVAL) {
   errno = 0;
   wcstoumax(L"123", nullptr, -1);
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
   errno = 0;
   wcstoumax(L"123", nullptr, 1);
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
   errno = 0;
   wcstoumax(L"123", nullptr, 37);
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 }
 
 TEST(inttypes, div) {
diff --git a/tests/leak_test.cpp b/tests/leak_test.cpp
index 0a881e1..bdb0ca9 100644
--- a/tests/leak_test.cpp
+++ b/tests/leak_test.cpp
@@ -48,7 +48,7 @@
         if (syscall(__NR_tgkill, getpid(), tids[i], 0) == 0) {
           alive = true;
         } else {
-          EXPECT_EQ(errno, ESRCH);
+          EXPECT_ERRNO(ESRCH);
           tids[i] = 0;  // Skip in next loop.
         }
       }
diff --git a/tests/locale_test.cpp b/tests/locale_test.cpp
index a220c83..a8ebca7 100644
--- a/tests/locale_test.cpp
+++ b/tests/locale_test.cpp
@@ -20,6 +20,8 @@
 #include <limits.h>
 #include <locale.h>
 
+#include "utils.h"
+
 TEST(locale, localeconv) {
   EXPECT_STREQ(".", localeconv()->decimal_point);
   EXPECT_STREQ("", localeconv()->thousands_sep);
@@ -53,10 +55,10 @@
 
   errno = 0;
   EXPECT_EQ(nullptr, setlocale(-1, nullptr));
-  EXPECT_EQ(EINVAL, errno);
+  EXPECT_ERRNO(EINVAL);
   errno = 0;
   EXPECT_EQ(nullptr, setlocale(13, nullptr));
-  EXPECT_EQ(EINVAL, errno);
+  EXPECT_ERRNO(EINVAL);
 
 #if defined(__BIONIC__)
   // The "" locale is implementation-defined. For bionic, it's the C.UTF-8 locale, which is
@@ -69,13 +71,13 @@
 
   errno = 0;
   EXPECT_EQ(nullptr, setlocale(LC_ALL, "this-is-not-a-locale"));
-  EXPECT_EQ(ENOENT, errno); // POSIX specified, not an implementation detail!
+  EXPECT_ERRNO(ENOENT);  // POSIX specified, not an implementation detail!
 }
 
 TEST(locale, newlocale_invalid_category_mask) {
   errno = 0;
   EXPECT_EQ(nullptr, newlocale(1 << 20, "C", nullptr));
-  EXPECT_EQ(EINVAL, errno);
+  EXPECT_ERRNO(EINVAL);
 }
 
 TEST(locale, newlocale_NULL_locale_name) {
@@ -83,14 +85,14 @@
 #pragma clang diagnostic ignored "-Wnonnull"
   errno = 0;
   EXPECT_EQ(nullptr, newlocale(LC_ALL, nullptr, nullptr));
-  EXPECT_EQ(EINVAL, errno);
+  EXPECT_ERRNO(EINVAL);
 #pragma clang diagnostic pop
 }
 
 TEST(locale, newlocale_bad_locale_name) {
   errno = 0;
   EXPECT_EQ(nullptr, newlocale(LC_ALL, "this-is-not-a-locale", nullptr));
-  EXPECT_EQ(ENOENT, errno); // POSIX specified, not an implementation detail!
+  EXPECT_ERRNO(ENOENT);  // POSIX specified, not an implementation detail!
 }
 
 TEST(locale, newlocale) {
diff --git a/tests/malloc_test.cpp b/tests/malloc_test.cpp
index aa53450..2411753 100644
--- a/tests/malloc_test.cpp
+++ b/tests/malloc_test.cpp
@@ -83,7 +83,7 @@
   SKIP_WITH_HWASAN;
   errno = 0;
   ASSERT_EQ(nullptr, malloc(SIZE_MAX));
-  ASSERT_EQ(ENOMEM, errno);
+  ASSERT_ERRNO(ENOMEM);
 }
 
 TEST(malloc, calloc_std) {
@@ -120,23 +120,23 @@
   SKIP_WITH_HWASAN;
   errno = 0;
   ASSERT_EQ(nullptr, calloc(-1, 100));
-  ASSERT_EQ(ENOMEM, errno);
+  ASSERT_ERRNO(ENOMEM);
 }
 
 TEST(malloc, calloc_overflow) {
   SKIP_WITH_HWASAN;
   errno = 0;
   ASSERT_EQ(nullptr, calloc(1, SIZE_MAX));
-  ASSERT_EQ(ENOMEM, errno);
+  ASSERT_ERRNO(ENOMEM);
   errno = 0;
   ASSERT_EQ(nullptr, calloc(SIZE_MAX, SIZE_MAX));
-  ASSERT_EQ(ENOMEM, errno);
+  ASSERT_ERRNO(ENOMEM);
   errno = 0;
   ASSERT_EQ(nullptr, calloc(2, SIZE_MAX));
-  ASSERT_EQ(ENOMEM, errno);
+  ASSERT_ERRNO(ENOMEM);
   errno = 0;
   ASSERT_EQ(nullptr, calloc(SIZE_MAX, 2));
-  ASSERT_EQ(ENOMEM, errno);
+  ASSERT_ERRNO(ENOMEM);
 }
 
 TEST(malloc, memalign_multiple) {
@@ -346,12 +346,12 @@
   SKIP_WITH_HWASAN;
   errno = 0;
   ASSERT_EQ(nullptr, realloc(nullptr, SIZE_MAX));
-  ASSERT_EQ(ENOMEM, errno);
+  ASSERT_ERRNO(ENOMEM);
   void* ptr = malloc(100);
   ASSERT_TRUE(ptr != nullptr);
   errno = 0;
   ASSERT_EQ(nullptr, realloc(ptr, SIZE_MAX));
-  ASSERT_EQ(ENOMEM, errno);
+  ASSERT_ERRNO(ENOMEM);
   free(ptr);
 }
 
@@ -669,7 +669,7 @@
   errno = 0;
   ASSERT_EQ(0, mallopt(-1000, 1));
   // mallopt doesn't set errno.
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
 #else
   GTEST_SKIP() << "bionic-only test";
 #endif
@@ -678,7 +678,6 @@
 TEST(malloc, mallopt_decay) {
 #if defined(__BIONIC__)
   SKIP_WITH_HWASAN << "hwasan does not implement mallopt";
-  errno = 0;
   ASSERT_EQ(1, mallopt(M_DECAY_TIME, 1));
   ASSERT_EQ(1, mallopt(M_DECAY_TIME, 0));
   ASSERT_EQ(1, mallopt(M_DECAY_TIME, 1));
@@ -691,7 +690,6 @@
 TEST(malloc, mallopt_purge) {
 #if defined(__BIONIC__)
   SKIP_WITH_HWASAN << "hwasan does not implement mallopt";
-  errno = 0;
   ASSERT_EQ(1, mallopt(M_PURGE, 0));
 #else
   GTEST_SKIP() << "bionic-only test";
@@ -701,7 +699,6 @@
 TEST(malloc, mallopt_purge_all) {
 #if defined(__BIONIC__)
   SKIP_WITH_HWASAN << "hwasan does not implement mallopt";
-  errno = 0;
   ASSERT_EQ(1, mallopt(M_PURGE_ALL, 0));
 #else
   GTEST_SKIP() << "bionic-only test";
@@ -797,11 +794,11 @@
 
   errno = 0;
   ASSERT_TRUE(reallocarray(nullptr, a, b) == nullptr);
-  ASSERT_EQ(ENOMEM, errno);
+  ASSERT_ERRNO(ENOMEM);
 
   errno = 0;
   ASSERT_TRUE(reallocarray(nullptr, b, a) == nullptr);
-  ASSERT_EQ(ENOMEM, errno);
+  ASSERT_ERRNO(ENOMEM);
 #else
   GTEST_SKIP() << "reallocarray not available";
 #endif
@@ -1120,7 +1117,7 @@
   const int unrecognized_option = -1;
   errno = 0;
   EXPECT_EQ(false, android_mallopt(unrecognized_option, nullptr, 0));
-  EXPECT_EQ(ENOTSUP, errno);
+  EXPECT_ERRNO(ENOTSUP);
 #else
   GTEST_SKIP() << "bionic-only test";
 #endif
@@ -1151,11 +1148,11 @@
   errno = 0;
   if (IsDynamic()) {
     EXPECT_EQ(true, android_mallopt(M_INIT_ZYGOTE_CHILD_PROFILING, nullptr, 0));
-    EXPECT_EQ(0, errno);
+    EXPECT_ERRNO(0);
   } else {
     // Not supported in static executables.
     EXPECT_EQ(false, android_mallopt(M_INIT_ZYGOTE_CHILD_PROFILING, nullptr, 0));
-    EXPECT_EQ(ENOTSUP, errno);
+    EXPECT_ERRNO(ENOTSUP);
   }
 
   // Unexpected arguments rejected.
@@ -1163,9 +1160,9 @@
   char unexpected = 0;
   EXPECT_EQ(false, android_mallopt(M_INIT_ZYGOTE_CHILD_PROFILING, &unexpected, 1));
   if (IsDynamic()) {
-    EXPECT_EQ(EINVAL, errno);
+    EXPECT_ERRNO(EINVAL);
   } else {
-    EXPECT_EQ(ENOTSUP, errno);
+    EXPECT_ERRNO(ENOTSUP);
   }
 #else
   GTEST_SKIP() << "bionic-only test";
diff --git a/tests/membarrier_test.cpp b/tests/membarrier_test.cpp
index 6f650e7..0cb7df4 100644
--- a/tests/membarrier_test.cpp
+++ b/tests/membarrier_test.cpp
@@ -22,13 +22,15 @@
 #include <linux/membarrier.h>
 #include <sys/syscall.h>
 
+#include "utils.h"
+
 class ScopedErrnoCleaner {
  public:
   ScopedErrnoCleaner() { errno = 0; }
   ~ScopedErrnoCleaner() { errno = 0; }
 };
 
-bool HasMembarrier(int membarrier_cmd) {
+static bool HasMembarrier(int membarrier_cmd) {
   ScopedErrnoCleaner errno_cleaner;
   int supported_cmds = syscall(__NR_membarrier, MEMBARRIER_CMD_QUERY, 0);
   return (supported_cmds > 0) && ((supported_cmds & membarrier_cmd) != 0);
@@ -37,11 +39,8 @@
 TEST(membarrier, query) {
   ScopedErrnoCleaner errno_cleaner;
   int supported = syscall(__NR_membarrier, MEMBARRIER_CMD_QUERY, 0);
-  if (errno == 0) {
-    ASSERT_TRUE(supported >= 0);
-  } else {
-    ASSERT_TRUE(errno == ENOSYS && supported == -1);
-  }
+  if (supported == -1 && errno == ENOSYS) GTEST_SKIP() << "no membarrier() in this kernel";
+  ASSERT_GE(supported, 0);
 }
 
 TEST(membarrier, global_barrier) {
@@ -92,7 +91,7 @@
   } else {
     // Private barrier should fail.
     ASSERT_EQ(-1, syscall(__NR_membarrier, membarrier_cmd_barrier, 0));
-    ASSERT_EQ(EPERM, errno);
+    ASSERT_ERRNO(EPERM);
     errno = 0;
   }
 
diff --git a/tests/netinet_in_test.cpp b/tests/netinet_in_test.cpp
index b7dd7c5..48f438c 100644
--- a/tests/netinet_in_test.cpp
+++ b/tests/netinet_in_test.cpp
@@ -23,6 +23,8 @@
 
 #include <android-base/macros.h>
 
+#include "utils.h"
+
 static constexpr uint16_t le16 = 0x1234;
 static constexpr uint32_t le32 = 0x12345678;
 static constexpr uint64_t le64 = 0x123456789abcdef0;
@@ -41,7 +43,7 @@
   sockaddr_in sin = {.sin_family = AF_INET6};
   errno = 0;
   ASSERT_EQ(-1, bindresvport(-1, &sin));
-  ASSERT_EQ(EPFNOSUPPORT, errno);
+  ASSERT_ERRNO(EPFNOSUPPORT);
 #else
   GTEST_SKIP() << "musl doesn't support bindresvport";
 #endif
diff --git a/tests/nl_types_test.cpp b/tests/nl_types_test.cpp
index 2e3995b..6104d16 100644
--- a/tests/nl_types_test.cpp
+++ b/tests/nl_types_test.cpp
@@ -19,6 +19,8 @@
 #include <errno.h>
 #include <gtest/gtest.h>
 
+#include "utils.h"
+
 TEST(nl_types, smoke) {
   nl_catd cat = catopen("/does/not/exist", NL_CAT_LOCALE);
   ASSERT_EQ(reinterpret_cast<nl_catd>(-1), cat);
@@ -27,5 +29,5 @@
 
   errno = 0;
   ASSERT_EQ(-1, catclose(cat));
-  ASSERT_EQ(EBADF, errno);
+  ASSERT_ERRNO(EBADF);
 }
diff --git a/tests/pidfd_test.cpp b/tests/pidfd_test.cpp
index b9fadb4..c01b93f 100644
--- a/tests/pidfd_test.cpp
+++ b/tests/pidfd_test.cpp
@@ -29,6 +29,8 @@
 #include <android-base/silent_death_test.h>
 #include <android-base/unique_fd.h>
 
+#include "utils.h"
+
 using android::base::unique_fd;
 using namespace std::chrono_literals;
 
@@ -43,15 +45,13 @@
   }
 
   unique_fd pidfd(pidfd_open(child, 0));
-  if (pidfd.get() == -1) {
-    ASSERT_EQ(ENOSYS, errno);
-    GTEST_SKIP() << "pidfd_open not available";
-  }
+  if (pidfd.get() == -1 && errno == ENOSYS) GTEST_SKIP() << "no pidfd_open() in this kernel";
+  ASSERT_NE(-1, pidfd.get()) << strerror(errno);
 
   siginfo_t siginfo;
   int rc = waitid(P_PIDFD, pidfd.get(), &siginfo, WEXITED);
   if (rc == -1) {
-    ASSERT_EQ(EINVAL, errno) << strerror(errno);
+    ASSERT_ERRNO(EINVAL);
     GTEST_SKIP() << "P_PIDFD not available";
   }
 
@@ -64,16 +64,12 @@
   unique_fd r, w;
   ASSERT_TRUE(android::base::Pipe(&r, &w));
   unique_fd self(pidfd_open(getpid(), 0));
-  if (self.get() == -1) {
-    ASSERT_EQ(ENOSYS, errno);
-    GTEST_SKIP() << "pidfd_open not available";
-  }
+  if (self.get() == -1 && errno == ENOSYS) GTEST_SKIP() << "no pidfd_open() in this kernel";
+  ASSERT_NE(-1, self.get()) << strerror(errno);
 
   unique_fd dup(pidfd_getfd(self.get(), r.get(), 0));
-  if (dup.get() == -1) {
-    ASSERT_EQ(ENOSYS, errno) << strerror(errno);
-    GTEST_SKIP() << "pidfd_getfd not available";
-  }
+  if (dup.get() == -1 && errno == ENOSYS) GTEST_SKIP() << "no pidfd_getfd() in this kernel";
+  ASSERT_NE(-1, dup.get()) << strerror(errno);
 
   ASSERT_NE(r.get(), dup.get());
   ASSERT_EQ(3, write(w.get(), "foo", 3));
@@ -86,15 +82,12 @@
 TEST_F(pidfd_DeathTest, pidfd_send_signal) {
 #if defined(__BIONIC__)
   unique_fd self(pidfd_open(getpid(), 0));
-  if (self.get() == -1) {
-    ASSERT_EQ(ENOSYS, errno);
-    GTEST_SKIP() << "pidfd_open not available";
-  }
+  if (self.get() == -1 && errno == ENOSYS) GTEST_SKIP() << "no pidfd_open() in this kernel";
+  ASSERT_NE(-1, self.get()) << strerror(errno);
 
-  if (pidfd_send_signal(self.get(), 0, nullptr, 0) == -1) {
-    ASSERT_EQ(ENOSYS, errno);
-    GTEST_SKIP() << "pidfd_send_signal not available";
-  }
+  int rc = pidfd_send_signal(self.get(), 0, nullptr, 0);
+  if (rc == -1 && errno == ENOSYS) GTEST_SKIP() << "no pidfd_send_signal() in this kernel";
+  ASSERT_EQ(0, rc) << strerror(errno);
 
   ASSERT_EXIT(({
                 // gtest will fork a child off for ASSERT_EXIT: `self` refers to the parent.
diff --git a/tests/poll_test.cpp b/tests/poll_test.cpp
index 2a3e5e0..33143f8 100644
--- a/tests/poll_test.cpp
+++ b/tests/poll_test.cpp
@@ -31,11 +31,13 @@
 #include <errno.h>
 #include <poll.h>
 
+#include "utils.h"
+
 TEST(poll, poll_null_fds) {
   // Because nanosleep(2) is relatively new to POSIX, code sometimes abuses poll.
   errno = 0;
   ASSERT_EQ(0, poll(nullptr, 0, 1));
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
 }
 
 TEST(poll, ppoll_null_fds) {
@@ -43,7 +45,7 @@
   errno = 0;
   timespec ts = { .tv_nsec = 100 };
   ASSERT_EQ(0, ppoll(nullptr, 0, &ts, nullptr));
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
 }
 
 TEST(poll, ppoll64_null_fds) {
@@ -52,6 +54,6 @@
   errno = 0;
   timespec ts = { .tv_nsec = 100 };
   ASSERT_EQ(0, ppoll64(nullptr, 0, &ts, nullptr));
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
 #endif
 }
diff --git a/tests/pthread_test.cpp b/tests/pthread_test.cpp
index aad2a4d..73090e1 100644
--- a/tests/pthread_test.cpp
+++ b/tests/pthread_test.cpp
@@ -585,7 +585,7 @@
   while (TEMP_FAILURE_RETRY(syscall(__NR_tgkill, getpid(), tid, 0)) != -1) {
     continue;
   }
-  ASSERT_EQ(ESRCH, errno);
+  ASSERT_ERRNO(ESRCH);
 
   ASSERT_EQ(ESRCH, pthread_kill(thread, 0));
 }
diff --git a/tests/sched_test.cpp b/tests/sched_test.cpp
index fa1a07f..0231de4 100644
--- a/tests/sched_test.cpp
+++ b/tests/sched_test.cpp
@@ -21,6 +21,8 @@
 #include <sys/types.h>
 #include <sys/wait.h>
 
+#include "utils.h"
+
 static int child_fn(void* i_ptr) {
   *reinterpret_cast<int*>(i_ptr) = 42;
   return 123;
@@ -57,14 +59,14 @@
   errno = 0;
   // If CLONE_THREAD is set, CLONE_SIGHAND must be set too.
   ASSERT_EQ(-1, clone(child_fn, &fake_child_stack[16], CLONE_THREAD, nullptr));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 }
 
 TEST(sched, clone_null_child_stack) {
   int i = 0;
   errno = 0;
   ASSERT_EQ(-1, clone(child_fn, nullptr, CLONE_VM, &i));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 }
 
 TEST(sched, cpu_set) {
@@ -289,7 +291,7 @@
   p.sched_priority = sched_get_priority_min(original_policy);
   errno = 0;
   ASSERT_EQ(-1, sched_setscheduler(getpid(), INT_MAX, &p));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 
   ASSERT_EQ(0, sched_getparam(getpid(), &p));
   ASSERT_EQ(original_policy, sched_setscheduler(getpid(), SCHED_BATCH, &p));
diff --git a/tests/search_test.cpp b/tests/search_test.cpp
index 8b8359d..5066709 100644
--- a/tests/search_test.cpp
+++ b/tests/search_test.cpp
@@ -18,6 +18,8 @@
 
 #include <search.h>
 
+#include "utils.h"
+
 static int int_cmp(const void* lhs, const void* rhs) {
   return *reinterpret_cast<const int*>(rhs) - *reinterpret_cast<const int*>(lhs);
 }
@@ -276,7 +278,7 @@
   // Check missing.
   errno = 0;
   ASSERT_EQ(0, hsearch_r(ENTRY{.key = const_cast<char*>("b"), .data = nullptr}, FIND, &e, &h1));
-  ASSERT_EQ(ESRCH, errno);
+  ASSERT_ERRNO(ESRCH);
 
   // Check present.
   ASSERT_EQ(1, hsearch_r(ENTRY{.key = const_cast<char*>("a"), .data = nullptr}, FIND, &e, &h1));
diff --git a/tests/semaphore_test.cpp b/tests/semaphore_test.cpp
index 6f8797f..5b061be 100644
--- a/tests/semaphore_test.cpp
+++ b/tests/semaphore_test.cpp
@@ -28,6 +28,8 @@
 #include "SignalUtils.h"
 #include "private/bionic_constants.h"
 
+#include "utils.h"
+
 using semaphore_DeathTest = SilentDeathTest;
 
 TEST(semaphore, sem_init) {
@@ -41,7 +43,7 @@
   // Too small an initial value.
   errno = 0;
   ASSERT_EQ(-1, sem_init(&s, 0, -1));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 
   ASSERT_EQ(SEM_VALUE_MAX, sysconf(_SC_SEM_VALUE_MAX));
 
@@ -51,7 +53,7 @@
   // Too large an initial value.
   errno = 0;
   ASSERT_EQ(-1, sem_init(&s, 0, SEM_VALUE_MAX + 1));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 
   ASSERT_EQ(0, sem_destroy(&s));
 }
@@ -64,7 +66,7 @@
   ASSERT_EQ(0, sem_trywait(&s));
   errno = 0;
   ASSERT_EQ(-1, sem_trywait(&s));
-  ASSERT_EQ(EAGAIN, errno);
+  ASSERT_ERRNO(EAGAIN);
   ASSERT_EQ(0, sem_destroy(&s));
 }
 
@@ -116,23 +118,23 @@
 
   errno = 0;
   ASSERT_EQ(-1, wait_function(&s, &ts));
-  ASSERT_EQ(ETIMEDOUT, errno);
+  ASSERT_ERRNO(ETIMEDOUT);
 
   // A negative timeout is an error.
   errno = 0;
   ts.tv_nsec = -1;
   ASSERT_EQ(-1, wait_function(&s, &ts));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
   errno = 0;
   ts.tv_nsec = NS_PER_S;
   ASSERT_EQ(-1, wait_function(&s, &ts));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 
   errno = 0;
   ts.tv_nsec = NS_PER_S - 1;
   ts.tv_sec = -1;
   ASSERT_EQ(-1, wait_function(&s, &ts));
-  ASSERT_EQ(ETIMEDOUT, errno);
+  ASSERT_ERRNO(ETIMEDOUT);
 
   ASSERT_EQ(0, sem_destroy(&s));
 }
diff --git a/tests/signal_test.cpp b/tests/signal_test.cpp
index 2e6908c..de126da 100644
--- a/tests/signal_test.cpp
+++ b/tests/signal_test.cpp
@@ -56,13 +56,13 @@
   SigSetT* set_ptr = nullptr;
   errno = 0;
   ASSERT_EQ(-1, fn(set_ptr));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 
   // Non-nullptr.
   SigSetT set = {};
   errno = 0;
   ASSERT_EQ(0, fn(&set));
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
 }
 
 template <typename SigSetT>
@@ -71,26 +71,26 @@
   SigSetT* set_ptr = nullptr;
   errno = 0;
   ASSERT_EQ(-1, fn(set_ptr, SIGSEGV));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 
   SigSetT set = {};
 
   // Bad signal number: too small.
   errno = 0;
   ASSERT_EQ(-1, fn(&set, 0));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 
   // Bad signal number: too high.
   errno = 0;
   ASSERT_EQ(-1, fn(&set, SIGNAL_MAX(&set) + 1));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 
   // Good signal numbers, low and high ends of range.
   errno = 0;
   ASSERT_EQ(0, fn(&set, SIGNAL_MIN()));
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
   ASSERT_EQ(0, fn(&set, SIGNAL_MAX(&set)));
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
 }
 
 TEST(signal, sigaddset_invalid) {
@@ -146,7 +146,7 @@
 TEST(signal, raise_invalid) {
   errno = 0;
   ASSERT_EQ(-1, raise(-1));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 }
 
 static void raise_in_signal_handler_helper(int signal_number) {
@@ -199,7 +199,7 @@
   sigfillset(&not_SIGALRM);
   sigdelset(&not_SIGALRM, SIGALRM);
   ASSERT_EQ(-1, sigsuspend(&not_SIGALRM));
-  ASSERT_EQ(EINTR, errno);
+  ASSERT_ERRNO(EINTR);
   // ...and check that we now receive our pending SIGALRM.
   ASSERT_EQ(1, g_sigsuspend_signal_handler_call_count);
 }
@@ -241,7 +241,7 @@
   sigfillset64(&not_SIGRTMIN);
   sigdelset64(&not_SIGRTMIN, SIGRTMIN);
   ASSERT_EQ(-1, sigsuspend64(&not_SIGRTMIN));
-  ASSERT_EQ(EINTR, errno);
+  ASSERT_ERRNO(EINTR);
   // ...and check that we now receive our pending SIGRTMIN.
   ASSERT_EQ(1, g_sigsuspend64_signal_handler_call_count);
 }
@@ -598,7 +598,7 @@
   sigval sigval = {.sival_int = 1};
   errno = 0;
   ASSERT_EQ(0, sigqueue(getpid(), SIGALRM, sigval));
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
   ASSERT_EQ(1, g_sigqueue_signal_handler_call_count);
 }
 
@@ -608,7 +608,7 @@
   sigval sigval = {.sival_int = 1};
   errno = 0;
   ASSERT_EQ(0, pthread_sigqueue(pthread_self(), SIGALRM, sigval));
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
   ASSERT_EQ(1, g_sigqueue_signal_handler_call_count);
 #else
   GTEST_SKIP() << "musl doesn't have pthread_sigqueue";
@@ -636,7 +636,7 @@
 
   errno = 0;
   ASSERT_EQ(0, pthread_sigqueue(thread, SIGALRM, sigval));
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
   pthread_join(thread, nullptr);
   ASSERT_EQ(1, g_sigqueue_signal_handler_call_count);
 #else
@@ -699,7 +699,7 @@
   siginfo_t info;
   errno = 0;
   ASSERT_EQ(SIGALRM, sigwaitinfo(&just_SIGALRM, &info));
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
   ASSERT_EQ(SIGALRM, info.si_signo);
   ASSERT_EQ(1, info.si_value.sival_int);
 }
@@ -721,7 +721,7 @@
   siginfo_t info;
   errno = 0;
   ASSERT_EQ(SIGRTMIN, sigwaitinfo64(&just_SIGRTMIN, &info));
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
   ASSERT_EQ(SIGRTMIN, info.si_signo);
   ASSERT_EQ(1, info.si_value.sival_int);
 }
@@ -744,7 +744,7 @@
   timespec timeout = { .tv_sec = 2, .tv_nsec = 0 };
   errno = 0;
   ASSERT_EQ(SIGALRM, sigtimedwait(&just_SIGALRM, &info, &timeout));
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
 }
 
 TEST(signal, sigtimedwait64_SIGRTMIN) {
@@ -765,7 +765,7 @@
   timespec timeout = { .tv_sec = 2, .tv_nsec = 0 };
   errno = 0;
   ASSERT_EQ(SIGRTMIN, sigtimedwait64(&just_SIGRTMIN, &info, &timeout));
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
 }
 
 TEST(signal, sigtimedwait_timeout) {
@@ -782,7 +782,7 @@
   timespec timeout = { .tv_sec = 0, .tv_nsec = 1000000 };
   errno = 0;
   ASSERT_EQ(-1, sigtimedwait(&just_SIGALRM, &info, &timeout));
-  ASSERT_EQ(EAGAIN, errno);
+  ASSERT_ERRNO(EAGAIN);
   auto t1 = std::chrono::steady_clock::now();
   ASSERT_GE(t1-t0, 1000000ns);
 
@@ -836,17 +836,17 @@
 TEST(signal, sigignore_EINVAL) {
   errno = 0;
   ASSERT_EQ(-1, sigignore(99999));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 }
 
 TEST(signal, sigignore) {
   errno = 0;
   EXPECT_EQ(-1, sigignore(SIGKILL));
-  EXPECT_EQ(errno, EINVAL);
+  EXPECT_ERRNO(EINVAL);
 
   errno = 0;
   EXPECT_EQ(-1, sigignore(SIGSTOP));
-  EXPECT_EQ(errno, EINVAL);
+  EXPECT_ERRNO(EINVAL);
 
   ScopedSignalHandler sigalrm{SIGALRM};
   ASSERT_EQ(0, sigignore(SIGALRM));
@@ -859,19 +859,19 @@
 TEST(signal, sighold_EINVAL) {
   errno = 0;
   ASSERT_EQ(-1, sighold(99999));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 }
 
 TEST(signal, sigpause_EINVAL) {
   errno = 0;
   ASSERT_EQ(-1, sigpause(99999));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 }
 
 TEST(signal, sigrelse_EINVAL) {
   errno = 0;
   ASSERT_EQ(-1, sigpause(99999));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 }
 
 static void TestSigholdSigpauseSigrelse(int sig) {
@@ -890,7 +890,7 @@
   ASSERT_EQ(0, signal_handler_call_count);
   // ... until sigpause(SIGALRM/SIGRTMIN) temporarily unblocks it.
   ASSERT_EQ(-1, sigpause(sig));
-  ASSERT_EQ(EINTR, errno);
+  ASSERT_ERRNO(EINTR);
   ASSERT_EQ(1, signal_handler_call_count);
 
   if (sig >= SIGRTMIN && sizeof(void*) == 8) {
@@ -918,7 +918,7 @@
 TEST(signal, sigset_EINVAL) {
   errno = 0;
   ASSERT_EQ(SIG_ERR, sigset(99999, SIG_DFL));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 }
 
 TEST(signal, sigset_RT) {
@@ -980,5 +980,5 @@
   // and passes 0 through to kill(2).
   errno = 0;
   ASSERT_EQ(-1, killpg(-1, SIGKILL));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 }
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp
index eaacc42..bfe8406 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -220,7 +220,7 @@
   // It should set the end-of-file indicator for the stream, though.
   errno = 0;
   ASSERT_EQ(getdelim(&word_read, &allocated_length, ' ', fp), -1);
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
   ASSERT_TRUE(feof(fp));
 
   free(word_read);
@@ -239,12 +239,12 @@
   // The first argument can't be NULL.
   errno = 0;
   ASSERT_EQ(getdelim(nullptr, &buffer_length, ' ', fp), -1);
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 
   // The second argument can't be NULL.
   errno = 0;
   ASSERT_EQ(getdelim(&buffer, nullptr, ' ', fp), -1);
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
   fclose(fp);
 #pragma clang diagnostic pop
 }
@@ -293,7 +293,7 @@
   // It should set the end-of-file indicator for the stream, though.
   errno = 0;
   ASSERT_EQ(getline(&line_read, &allocated_length, fp), -1);
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
   ASSERT_TRUE(feof(fp));
 
   free(line_read);
@@ -312,12 +312,12 @@
   // The first argument can't be NULL.
   errno = 0;
   ASSERT_EQ(getline(nullptr, &buffer_length, fp), -1);
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 
   // The second argument can't be NULL.
   errno = 0;
   ASSERT_EQ(getline(&buffer, nullptr, fp), -1);
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
   fclose(fp);
 #pragma clang diagnostic pop
 }
@@ -916,7 +916,7 @@
   ASSERT_EQ(12, snprintf(buf, sizeof(buf), "%.2147483646s%c", "hello world", '!'));
   ASSERT_EQ(12, snprintf(buf, sizeof(buf), "%.2147483647s%c", "hello world", '!'));
   ASSERT_EQ(-1, snprintf(buf, sizeof(buf), "%.2147483648s%c", "hello world", '!'));
-  ASSERT_EQ(ENOMEM, errno);
+  ASSERT_ERRNO(ENOMEM);
 }
 
 TEST(STDIO_TEST, swprintf_asterisk_overflow) {
@@ -931,7 +931,7 @@
   ASSERT_EQ(12, swprintf(buf, sizeof(buf), L"%.2147483646s%c", "hello world", '!'));
   ASSERT_EQ(12, swprintf(buf, sizeof(buf), L"%.2147483647s%c", "hello world", '!'));
   ASSERT_EQ(-1, swprintf(buf, sizeof(buf), L"%.2147483648s%c", "hello world", '!'));
-  ASSERT_EQ(ENOMEM, errno);
+  ASSERT_ERRNO(ENOMEM);
 }
 
 // Inspired by https://github.com/landley/toybox/issues/163.
@@ -1402,30 +1402,30 @@
 
   errno = 0;
   EXPECT_EQ(EOF, putc('x', fp));
-  EXPECT_EQ(EBADF, errno);
+  EXPECT_ERRNO(EBADF);
 
   errno = 0;
   EXPECT_EQ(EOF, fprintf(fp, "hello"));
-  EXPECT_EQ(EBADF, errno);
+  EXPECT_ERRNO(EBADF);
 
   errno = 0;
   EXPECT_EQ(EOF, fwprintf(fp, L"hello"));
 #if defined(__BIONIC__)
-  EXPECT_EQ(EBADF, errno);
+  EXPECT_ERRNO(EBADF);
 #endif
 
   errno = 0;
   EXPECT_EQ(0U, fwrite("hello", 1, 2, fp));
-  EXPECT_EQ(EBADF, errno);
+  EXPECT_ERRNO(EBADF);
 
   errno = 0;
   EXPECT_EQ(EOF, fputs("hello", fp));
-  EXPECT_EQ(EBADF, errno);
+  EXPECT_ERRNO(EBADF);
 
   errno = 0;
   EXPECT_EQ(WEOF, fputwc(L'x', fp));
 #if defined(__BIONIC__)
-  EXPECT_EQ(EBADF, errno);
+  EXPECT_ERRNO(EBADF);
 #endif
 }
 
@@ -1540,7 +1540,7 @@
 
   // Reading from within a byte should produce an error.
   ASSERT_EQ(WEOF, fgetwc(fp));
-  ASSERT_EQ(EILSEQ, errno);
+  ASSERT_ERRNO(EILSEQ);
 
   // Reverting to a valid position should work.
   ASSERT_EQ(0, fsetpos(fp, &mb_two_bytes_pos));
@@ -1550,7 +1550,7 @@
   // produce an error.
   ASSERT_EQ(0, fsetpos(fp, &pos_inside_mb));
   ASSERT_EQ(WEOF, fgetwc(fp));
-  ASSERT_EQ(EILSEQ, errno);
+  ASSERT_ERRNO(EILSEQ);
 
   ASSERT_EQ(0, fclose(fp));
 }
@@ -1951,7 +1951,7 @@
   ASSERT_TRUE(fp != nullptr);
   errno = 0;
   ASSERT_EQ(-1, fileno(fp));
-  ASSERT_EQ(EBADF, errno);
+  ASSERT_ERRNO(EBADF);
   ASSERT_EQ(0, fclose(fp));
 }
 
@@ -1999,12 +1999,12 @@
   // Invalid buffer.
   errno = 0;
   ASSERT_EQ(nullptr, open_memstream(nullptr, &size));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 
   // Invalid size.
   errno = 0;
   ASSERT_EQ(nullptr, open_memstream(&p, nullptr));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 #pragma clang diagnostic pop
 #else
   GTEST_SKIP() << "glibc is broken";
@@ -2139,7 +2139,7 @@
   std::vector<char> buf(n, 0);
   errno = 0;
   ASSERT_EQ(0U, fread(&buf[0], n, 1, fp));
-  ASSERT_EQ(EBADF, errno);
+  ASSERT_ERRNO(EBADF);
   ASSERT_TRUE(ferror(fp));
   ASSERT_FALSE(feof(fp));
   fclose(fp);
@@ -2271,7 +2271,7 @@
   // especially because they might actually correspond to a real stream.
   errno = 0;
   ASSERT_EQ(-1, fileno(stdin));
-  ASSERT_EQ(EBADF, errno);
+  ASSERT_ERRNO(EBADF);
 }
 
 TEST(STDIO_TEST, fseek_ftell_unseekable) {
@@ -2283,17 +2283,17 @@
   // Check that ftell balks on an unseekable FILE*.
   errno = 0;
   ASSERT_EQ(-1, ftell(fp));
-  ASSERT_EQ(ESPIPE, errno);
+  ASSERT_ERRNO(ESPIPE);
 
   // SEEK_CUR is rewritten as SEEK_SET internally...
   errno = 0;
   ASSERT_EQ(-1, fseek(fp, 0, SEEK_CUR));
-  ASSERT_EQ(ESPIPE, errno);
+  ASSERT_ERRNO(ESPIPE);
 
   // ...so it's worth testing the direct seek path too.
   errno = 0;
   ASSERT_EQ(-1, fseek(fp, 0, SEEK_SET));
-  ASSERT_EQ(ESPIPE, errno);
+  ASSERT_ERRNO(ESPIPE);
 
   fclose(fp);
 #else
@@ -2305,7 +2305,7 @@
 #if defined(__BIONIC__)
   errno = 0;
   ASSERT_EQ(nullptr, funopen(nullptr, nullptr, nullptr, nullptr, nullptr));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 #else
   GTEST_SKIP() << "glibc uses fopencookie instead";
 #endif
@@ -2326,7 +2326,7 @@
   EXPECT_EQ(0xfedcba12LL, pos);
 #else
   EXPECT_EQ(-1, fgetpos(fp, &pos)) << strerror(errno);
-  EXPECT_EQ(EOVERFLOW, errno);
+  EXPECT_ERRNO(EOVERFLOW);
 #endif
 
   FILE* fp64 = funopen64(nullptr, read_fn, nullptr, seek64_fn, nullptr);
@@ -2428,24 +2428,24 @@
   // Bad whence.
   errno = 0;
   ASSERT_EQ(-1, fseek(fp, 0, 123));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
   errno = 0;
   ASSERT_EQ(-1, fseeko(fp, 0, 123));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
   errno = 0;
   ASSERT_EQ(-1, fseeko64(fp, 0, 123));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 
   // Bad offset.
   errno = 0;
   ASSERT_EQ(-1, fseek(fp, -1, SEEK_SET));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
   errno = 0;
   ASSERT_EQ(-1, fseeko(fp, -1, SEEK_SET));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
   errno = 0;
   ASSERT_EQ(-1, fseeko64(fp, -1, SEEK_SET));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 
   fclose(fp);
 }
@@ -2464,20 +2464,20 @@
   TemporaryFile tf;
   ASSERT_EQ(0, remove(tf.path));
   ASSERT_EQ(-1, lstat(tf.path, &sb));
-  ASSERT_EQ(ENOENT, errno);
+  ASSERT_ERRNO(ENOENT);
 
   TemporaryDir td;
   ASSERT_EQ(0, remove(td.path));
   ASSERT_EQ(-1, lstat(td.path, &sb));
-  ASSERT_EQ(ENOENT, errno);
+  ASSERT_ERRNO(ENOENT);
 
   errno = 0;
   ASSERT_EQ(-1, remove(tf.path));
-  ASSERT_EQ(ENOENT, errno);
+  ASSERT_ERRNO(ENOENT);
 
   errno = 0;
   ASSERT_EQ(-1, remove(td.path));
-  ASSERT_EQ(ENOENT, errno);
+  ASSERT_ERRNO(ENOENT);
 }
 
 TEST_F(STDIO_DEATHTEST, snprintf_30445072_known_buffer_size) {
@@ -2706,7 +2706,7 @@
 #if defined(__BIONIC__) && !defined(__LP64__)
   ASSERT_EQ(0, fseek(fp, 0x7fff'ffff, SEEK_SET));
   ASSERT_EQ(-1, fseek(fp, 1, SEEK_CUR));
-  ASSERT_EQ(EOVERFLOW, errno);
+  ASSERT_ERRNO(EOVERFLOW);
 #endif
 
   // Neither Bionic nor glibc implement the overflow checking for SEEK_END.
@@ -2825,7 +2825,7 @@
 
   // Rename and check it moved.
   ASSERT_EQ(-1, renameat2(dirfd, "old", dirfd, "new", RENAME_NOREPLACE));
-  ASSERT_EQ(EEXIST, errno);
+  ASSERT_ERRNO(EEXIST);
 #endif
 }
 
@@ -2848,25 +2848,25 @@
   errno = 0;
   fp = fdopen(fd, "nonsense");
   ASSERT_TRUE(fp == nullptr);
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 
   // 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);
+  ASSERT_ERRNO(EINVAL);
 
   // Can't set append on the underlying fd.
   errno = 0;
   fp = fdopen(fd, "a");
   ASSERT_TRUE(fp == nullptr);
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 
   // Bad fd.
   errno = 0;
   fp = fdopen(-1, "re");
   ASSERT_TRUE(fp == nullptr);
-  ASSERT_EQ(EBADF, errno);
+  ASSERT_ERRNO(EBADF);
 
   close(fd);
 }
@@ -2875,14 +2875,14 @@
   errno = 0;
   FILE* fp = fmemopen(nullptr, 16, "nonsense");
   ASSERT_TRUE(fp == nullptr);
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 }
 
 TEST(STDIO_TEST, fopen_invalid_mode) {
   errno = 0;
   FILE* fp = fopen("/proc/version", "nonsense");
   ASSERT_TRUE(fp == nullptr);
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 }
 
 TEST(STDIO_TEST, freopen_invalid_mode) {
@@ -2892,7 +2892,7 @@
   errno = 0;
   fp = freopen("/proc/version", "nonsense", fp);
   ASSERT_TRUE(fp == nullptr);
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 }
 
 TEST(STDIO_TEST, asprintf_smoke) {
@@ -2906,7 +2906,7 @@
   errno = 0;
   FILE* fp = fopen("/proc/does-not-exist", "re");
   ASSERT_TRUE(fp == nullptr);
-  ASSERT_EQ(ENOENT, errno);
+  ASSERT_ERRNO(ENOENT);
 }
 
 static void tempnam_test(bool has_TMPDIR, const char* dir, const char* prefix, const char* re) {
diff --git a/tests/stdlib_test.cpp b/tests/stdlib_test.cpp
index 45169e3..21c79c8 100644
--- a/tests/stdlib_test.cpp
+++ b/tests/stdlib_test.cpp
@@ -279,7 +279,7 @@
     for (size_t fail_align = last_align + 1; fail_align < align; fail_align++) {
       ASSERT_TRUE(aligned_alloc(fail_align, fail_align) == nullptr)
           << "Unexpected success at align " << fail_align;
-      ASSERT_EQ(EINVAL, errno) << "Unexpected errno at align " << fail_align;
+      ASSERT_ERRNO(EINVAL) << "Unexpected errno at align " << fail_align;
     }
     void* ptr = aligned_alloc(align, 2 * align);
     ASSERT_TRUE(ptr != nullptr) << "Unexpected failure at align " << align;
@@ -310,21 +310,21 @@
   const char* path = nullptr;
   char* p = realpath(path, nullptr);
   ASSERT_TRUE(p == nullptr);
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 }
 
 TEST(stdlib, realpath__empty_filename) {
   errno = 0;
   char* p = realpath("", nullptr);
   ASSERT_TRUE(p == nullptr);
-  ASSERT_EQ(ENOENT, errno);
+  ASSERT_ERRNO(ENOENT);
 }
 
 TEST(stdlib, realpath__ENOENT) {
   errno = 0;
   char* p = realpath("/this/directory/path/almost/certainly/does/not/exist", nullptr);
   ASSERT_TRUE(p == nullptr);
-  ASSERT_EQ(ENOENT, errno);
+  ASSERT_ERRNO(ENOENT);
 }
 
 TEST(stdlib, realpath__ELOOP) {
@@ -335,19 +335,19 @@
   errno = 0;
   char* p = realpath(link.c_str(), nullptr);
   ASSERT_TRUE(p == nullptr);
-  ASSERT_EQ(ELOOP, errno);
+  ASSERT_ERRNO(ELOOP);
 }
 
 TEST(stdlib, realpath__component_after_non_directory) {
   errno = 0;
   char* p = realpath("/dev/null/.", nullptr);
   ASSERT_TRUE(p == nullptr);
-  ASSERT_EQ(ENOTDIR, errno);
+  ASSERT_ERRNO(ENOTDIR);
 
   errno = 0;
   p = realpath("/dev/null/..", nullptr);
   ASSERT_TRUE(p == nullptr);
-  ASSERT_EQ(ENOTDIR, errno);
+  ASSERT_ERRNO(ENOTDIR);
 }
 
 TEST(stdlib, realpath) {
@@ -403,7 +403,7 @@
   errno = 0;
   char* result = realpath(path.c_str(), nullptr);
   ASSERT_EQ(nullptr, result) << result;
-  ASSERT_EQ(ENOENT, errno);
+  ASSERT_ERRNO(ENOENT);
   free(result);
 }
 
@@ -695,7 +695,7 @@
   errno = 0;
   char buf[128];
   ASSERT_EQ(ENOTTY, ptsname_r(STDOUT_FILENO, buf, sizeof(buf)));
-  ASSERT_EQ(ENOTTY, errno);
+  ASSERT_ERRNO(ENOTTY);
 }
 
 TEST(stdlib, ptsname_r_EINVAL) {
@@ -704,7 +704,7 @@
   errno = 0;
   char* buf = nullptr;
   ASSERT_EQ(EINVAL, ptsname_r(fd, buf, 128));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
   close(fd);
 }
 
@@ -714,7 +714,7 @@
   errno = 0;
   char buf[1];
   ASSERT_EQ(ERANGE, ptsname_r(fd, buf, sizeof(buf)));
-  ASSERT_EQ(ERANGE, errno);
+  ASSERT_ERRNO(ERANGE);
   close(fd);
 }
 
@@ -745,7 +745,7 @@
   errno = 0;
   char buf[128];
   ASSERT_EQ(ENOTTY, ttyname_r(fd, buf, sizeof(buf)));
-  ASSERT_EQ(ENOTTY, errno);
+  ASSERT_ERRNO(ENOTTY);
   close(fd);
 }
 
@@ -755,7 +755,7 @@
   errno = 0;
   char* buf = nullptr;
   ASSERT_EQ(EINVAL, ttyname_r(fd, buf, 128));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
   close(fd);
 }
 
@@ -765,7 +765,7 @@
   errno = 0;
   char buf[1];
   ASSERT_EQ(ERANGE, ttyname_r(fd, buf, sizeof(buf)));
-  ASSERT_EQ(ERANGE, errno);
+  ASSERT_ERRNO(ERANGE);
   close(fd);
 }
 
@@ -773,7 +773,7 @@
   int fd = open("/dev/null", O_WRONLY);
   errno = 0;
   ASSERT_EQ(-1, unlockpt(fd));
-  ASSERT_EQ(ENOTTY, errno);
+  ASSERT_ERRNO(ENOTTY);
   close(fd);
 }
 
@@ -830,17 +830,17 @@
   // Negative base => invalid.
   errno = 0;
   ASSERT_EQ(T(0), fn("123", &end_p, -1));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 
   // Base 1 => invalid (base 0 means "please guess").
   errno = 0;
   ASSERT_EQ(T(0), fn("123", &end_p, 1));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 
   // Base > 36 => invalid.
   errno = 0;
   ASSERT_EQ(T(0), fn("123", &end_p, 37));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 
   // Both leading + or - are always allowed (even for the strtou* family).
   ASSERT_EQ(T(-123), fn("-123", &end_p, 10));
@@ -875,14 +875,14 @@
     end_p = nullptr;
     errno = 0;
     ASSERT_EQ(std::numeric_limits<T>::min(), fn(min.c_str(), &end_p, 0));
-    ASSERT_EQ(0, errno);
+    ASSERT_ERRNO(0);
     ASSERT_EQ('\0', *end_p);
     // Too negative (such as -129).
     min.back() = (min.back() + 1);
     end_p = nullptr;
     errno = 0;
     ASSERT_EQ(std::numeric_limits<T>::min(), fn(min.c_str(), &end_p, 0));
-    ASSERT_EQ(ERANGE, errno);
+    ASSERT_ERRNO(ERANGE);
     ASSERT_EQ('\0', *end_p);
   }
 
@@ -891,14 +891,14 @@
   end_p = nullptr;
   errno = 0;
   ASSERT_EQ(std::numeric_limits<T>::max(), fn(max.c_str(), &end_p, 0));
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
   ASSERT_EQ('\0', *end_p);
   // Too positive (such as 128).
   max.back() = (max.back() + 1);
   end_p = nullptr;
   errno = 0;
   ASSERT_EQ(std::numeric_limits<T>::max(), fn(max.c_str(), &end_p, 0));
-  ASSERT_EQ(ERANGE, errno);
+  ASSERT_ERRNO(ERANGE);
   ASSERT_EQ('\0', *end_p);
 
   // In case of overflow, strto* leaves us pointing past the end of the number,
@@ -907,14 +907,14 @@
   errno = 0;
   ASSERT_EQ(std::numeric_limits<T>::max(),
             fn("99999999999999999999999999999999999999999999999999999abc", &end_p, 0));
-  ASSERT_EQ(ERANGE, errno);
+  ASSERT_ERRNO(ERANGE);
   ASSERT_STREQ("abc", end_p);
   if (std::numeric_limits<T>::is_signed) {
       end_p = nullptr;
       errno = 0;
       ASSERT_EQ(std::numeric_limits<T>::min(),
                 fn("-99999999999999999999999999999999999999999999999999999abc", &end_p, 0));
-      ASSERT_EQ(ERANGE, errno);
+      ASSERT_ERRNO(ERANGE);
       ASSERT_STREQ("abc", end_p);
   }
 }
diff --git a/tests/string_test.cpp b/tests/string_test.cpp
index e7e0f34..4cd89cc 100644
--- a/tests/string_test.cpp
+++ b/tests/string_test.cpp
@@ -29,6 +29,7 @@
 #include <vector>
 
 #include "buffer_tests.h"
+#include "utils.h"
 
 #if defined(NOFORTIFY)
 #define STRING_TEST string_nofortify
@@ -123,7 +124,7 @@
   ASSERT_EQ(buf, strerror_r(4567, buf, 2));
   ASSERT_STREQ("U", buf);
   // The GNU strerror_r doesn't set errno (the POSIX one sets it to ERANGE).
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
 #else
   GTEST_SKIP() << "musl doesn't have GNU strerror_r";
 #endif
@@ -1483,7 +1484,7 @@
   errno = 0;
   const char* out = basename(in);
   ASSERT_STREQ(expected_out, out) << in;
-  ASSERT_EQ(0, errno) << in;
+  ASSERT_ERRNO(0) << in;
 }
 #endif
 
diff --git a/tests/sys_epoll_test.cpp b/tests/sys_epoll_test.cpp
index 8dee93f..744f1c9 100644
--- a/tests/sys_epoll_test.cpp
+++ b/tests/sys_epoll_test.cpp
@@ -64,7 +64,7 @@
   epoll_event events[1] = {};
   timespec ts = {.tv_nsec = 500};
   int rc = epoll_pwait2(epoll_fd, events, 1, &ts, nullptr);
-  if (rc == -1 && errno == ENOSYS) GTEST_SKIP() << "no epoll_pwait2 in this kernel";
+  if (rc == -1 && errno == ENOSYS) GTEST_SKIP() << "no epoll_pwait2() in this kernel";
   ASSERT_EQ(0, rc) << strerror(errno);
 #else
   GTEST_SKIP() << "epoll_pwait2 is only in glibc 2.35+";
@@ -94,7 +94,7 @@
   sigemptyset(&ss2);
   sigaddset(&ss2, SIGPIPE);
   int rc = epoll_pwait2(epoll_fd, events, 1, &ts, &ss2);
-  if (rc == -1 && errno == ENOSYS) GTEST_SKIP() << "no epoll_pwait2 in this kernel";
+  if (rc == -1 && errno == ENOSYS) GTEST_SKIP() << "no epoll_pwait2() in this kernel";
   ASSERT_EQ(0, rc) << strerror(errno);
 #else
   GTEST_SKIP() << "epoll_pwait2 is only in glibc 2.35+";
@@ -112,7 +112,7 @@
   sigemptyset64(&ss2);
   sigaddset64(&ss2, SIGPIPE);
   int rc = epoll_pwait2_64(epoll_fd, events, 1, &ts, &ss2);
-  if (rc == -1 && errno == ENOSYS) GTEST_SKIP() << "no epoll_pwait2 in this kernel";
+  if (rc == -1 && errno == ENOSYS) GTEST_SKIP() << "no epoll_pwait2() in this kernel";
   ASSERT_EQ(0, rc) << strerror(errno);
 #else
   GTEST_SKIP() << "epoll_pwait2_64 is bionic-only";
@@ -122,7 +122,7 @@
 TEST(sys_epoll, epoll_create_invalid_size) {
   errno = 0;
   ASSERT_EQ(-1, epoll_create(0));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 }
 
 TEST(sys_epoll, epoll_event_data) {
diff --git a/tests/sys_mman_test.cpp b/tests/sys_mman_test.cpp
index 803852a..e785ff4 100644
--- a/tests/sys_mman_test.cpp
+++ b/tests/sys_mman_test.cpp
@@ -23,6 +23,8 @@
 #include <android-base/file.h>
 #include <gtest/gtest.h>
 
+#include "utils.h"
+
 TEST(sys_mman, mmap_std) {
   void* map = mmap(nullptr, 4096, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
   ASSERT_NE(MAP_FAILED, map);
@@ -277,10 +279,9 @@
   // Is the MFD_CLOEXEC flag obeyed?
   errno = 0;
   int fd = memfd_create("doesn't matter", 0);
-  if (fd == -1) {
-    ASSERT_EQ(ENOSYS, errno);
-    GTEST_SKIP() << "no memfd_create available";
-  }
+  if (fd == -1 && errno == ENOSYS) GTEST_SKIP() << "no memfd_create() in this kernel";
+  ASSERT_NE(-1, fd) << strerror(errno);
+
   int f = fcntl(fd, F_GETFD);
   ASSERT_NE(-1, f);
   ASSERT_FALSE(f & FD_CLOEXEC);
diff --git a/tests/sys_prctl_test.cpp b/tests/sys_prctl_test.cpp
index 6d1fa1d..bbc1c67 100644
--- a/tests/sys_prctl_test.cpp
+++ b/tests/sys_prctl_test.cpp
@@ -31,6 +31,8 @@
 #include "android-base/file.h"
 #include "android-base/strings.h"
 
+#include "utils.h"
+
 // http://b/20017123.
 TEST(sys_prctl, bug_20017123) {
 #if defined(PR_SET_VMA) // PR_SET_VMA is only available in Android kernels.
@@ -91,7 +93,7 @@
   // but they can check or lower it
   err = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_SYS_ADMIN, 0, 0);
   EXPECT_EQ(-1, err);
-  EXPECT_EQ(EPERM, errno);
+  EXPECT_ERRNO(EPERM);
 
   err = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_SYS_ADMIN, 0, 0);
   EXPECT_EQ(0, err);
@@ -102,15 +104,15 @@
   // ULONG_MAX isn't a legal cap
   err = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, ULONG_MAX, 0, 0);
   EXPECT_EQ(-1, err);
-  EXPECT_EQ(EINVAL, errno);
+  EXPECT_ERRNO(EINVAL);
 
   err = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, ULONG_MAX, 0, 0);
   EXPECT_EQ(-1, err);
-  EXPECT_EQ(EINVAL, errno);
+  EXPECT_ERRNO(EINVAL);
 
   err = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_LOWER, ULONG_MAX, 0, 0);
   EXPECT_EQ(-1, err);
-  EXPECT_EQ(EINVAL, errno);
+  EXPECT_ERRNO(EINVAL);
 #else
   GTEST_SKIP() << "PR_CAP_AMBIENT not available";
 #endif
diff --git a/tests/sys_ptrace_test.cpp b/tests/sys_ptrace_test.cpp
index b8c1537..93daac3 100644
--- a/tests/sys_ptrace_test.cpp
+++ b/tests/sys_ptrace_test.cpp
@@ -64,10 +64,11 @@
 
 static void check_hw_feature_supported(pid_t child, HwFeature feature) {
 #if defined(__arm__)
+  errno = 0;
   long capabilities;
   long result = ptrace(PTRACE_GETHBPREGS, child, 0, &capabilities);
   if (result == -1) {
-    EXPECT_EQ(EIO, errno);
+    EXPECT_ERRNO(EIO);
     GTEST_SKIP() << "Hardware debug support disabled at kernel configuration time";
   }
   uint8_t hb_count = capabilities & 0xff;
@@ -88,10 +89,11 @@
   iov.iov_base = &dreg_state;
   iov.iov_len = sizeof(dreg_state);
 
+  errno = 0;
   long result = ptrace(PTRACE_GETREGSET, child,
                        feature == HwFeature::Watchpoint ? NT_ARM_HW_WATCH : NT_ARM_HW_BREAK, &iov);
   if (result == -1) {
-    ASSERT_EQ(EINVAL, errno);
+    ASSERT_ERRNO(EINVAL);
     GTEST_SKIP() << "Hardware support missing";
   } else if ((dreg_state.dbg_info & 0xff) == 0) {
     if (feature == HwFeature::Watchpoint) {
@@ -134,7 +136,7 @@
   ASSERT_EQ(0, ptrace(PTRACE_POKEUSER, child, offsetof(user, u_debugreg[0]), address)) << strerror(errno);
   errno = 0;
   unsigned data = ptrace(PTRACE_PEEKUSER, child, offsetof(user, u_debugreg[7]), nullptr);
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
 
   const unsigned size_flag = (size == 8) ? 2 : size - 1;
   const unsigned enable = 1;
@@ -323,7 +325,7 @@
       << strerror(errno);
   errno = 0;
   unsigned data = ptrace(PTRACE_PEEKUSER, child, offsetof(user, u_debugreg[7]), nullptr);
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
 
   const unsigned size = 0;
   const unsigned enable = 1;
diff --git a/tests/sys_random_test.cpp b/tests/sys_random_test.cpp
index e0cbf78..4425dba 100644
--- a/tests/sys_random_test.cpp
+++ b/tests/sys_random_test.cpp
@@ -34,6 +34,8 @@
 #include <errno.h>
 #include <gtest/gtest.h>
 
+#include "utils.h"
+
 TEST(sys_random, getentropy) {
 #if defined(HAVE_SYS_RANDOM)
   char buf1[64];
@@ -53,7 +55,7 @@
 #if defined(HAVE_SYS_RANDOM)
   errno = 0;
   ASSERT_EQ(-1, getentropy(nullptr, 1));
-  ASSERT_EQ(EFAULT, errno);
+  ASSERT_ERRNO(EFAULT);
 #else
   GTEST_SKIP() << "<sys/random.h> not available";
 #endif
@@ -67,7 +69,7 @@
 
   errno = 0;
   ASSERT_EQ(-1, getentropy(buf, sizeof(buf)));
-  ASSERT_EQ(EIO, errno);
+  ASSERT_ERRNO(EIO);
 #else
   GTEST_SKIP() << "<sys/random.h> not available";
 #endif
@@ -92,7 +94,7 @@
 #if defined(HAVE_SYS_RANDOM)
   errno = 0;
   ASSERT_EQ(-1, getrandom(nullptr, 256, 0));
-  ASSERT_EQ(EFAULT, errno);
+  ASSERT_ERRNO(EFAULT);
 #else
   GTEST_SKIP() << "<sys/random.h> not available";
 #endif
@@ -104,7 +106,7 @@
   errno = 0;
   char buf[64];
   ASSERT_EQ(-1, getrandom(buf, sizeof(buf), ~0));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 #else
   GTEST_SKIP() << "<sys/random.h> not available";
 #endif
diff --git a/tests/sys_select_test.cpp b/tests/sys_select_test.cpp
index 5f019e2..076409d 100644
--- a/tests/sys_select_test.cpp
+++ b/tests/sys_select_test.cpp
@@ -90,7 +90,7 @@
 
   // Invalid max fd.
   ASSERT_EQ(-1, select(-1, &r, &w, &e, nullptr));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 
   int num_fds = select(max, &r, &w, &e, nullptr);
   // If there is data to be read on STDIN, then the number of
@@ -108,7 +108,7 @@
   tv.tv_sec = -1;
   tv.tv_usec = 0;
   ASSERT_EQ(-1, select(max, &r, &w, &e, &tv));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 
   // Valid timeout...
   tv.tv_sec = 1;
@@ -145,7 +145,7 @@
 
   // Invalid max fd.
   ASSERT_EQ(-1, pselect(-1, &r, &w, &e, nullptr, &ss));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 
   // If there is data to be read on STDIN, then the number of
   // fds ready will be 3 instead of 2. Allow this case, but verify
@@ -163,7 +163,7 @@
   tv.tv_sec = -1;
   tv.tv_nsec = 0;
   ASSERT_EQ(-1, pselect(max, &r, &w, &e, &tv, &ss));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 
   // Valid timeout...
   tv.tv_sec = 1;
diff --git a/tests/sys_sem_test.cpp b/tests/sys_sem_test.cpp
index 4bac92f..27943cf 100644
--- a/tests/sys_sem_test.cpp
+++ b/tests/sys_sem_test.cpp
@@ -33,6 +33,8 @@
 
 #include <android-base/file.h>
 
+#include "utils.h"
+
 TEST(sys_sem, smoke) {
   if (semctl(-1, 0, IPC_RMID) == -1 && errno == ENOSYS) {
     GTEST_SKIP() << "no <sys/sem.h> support in this kernel";
@@ -62,7 +64,7 @@
   ops[0] = { .sem_num = 0, .sem_op = 0, .sem_flg = 0 };
   errno = 0;
   ASSERT_EQ(-1, semtimedop(id, ops, 1, &ts));
-  ASSERT_EQ(EAGAIN, errno);
+  ASSERT_ERRNO(EAGAIN);
   ASSERT_EQ(1, semctl(id, 0, GETVAL));
 
   // Decrement.
diff --git a/tests/sys_socket_test.cpp b/tests/sys_socket_test.cpp
index 422b7f2..1cfbfb2 100644
--- a/tests/sys_socket_test.cpp
+++ b/tests/sys_socket_test.cpp
@@ -100,7 +100,7 @@
 
 TEST(sys_socket, accept4_error) {
   ASSERT_EQ(-1, accept4(-1, nullptr, nullptr, 0));
-  ASSERT_EQ(EBADF, errno);
+  ASSERT_ERRNO(EBADF);
 }
 
 static void TestAccept4(struct sockaddr_un* addr, int fd) {
@@ -177,7 +177,7 @@
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wnonnull"
   ASSERT_EQ(-1, recvmmsg(-1, nullptr, 0, 0, nullptr));
-  ASSERT_EQ(EBADF, errno);
+  ASSERT_ERRNO(EBADF);
 #pragma clang diagnostic pop
 }
 
@@ -238,6 +238,6 @@
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wnonnull"
   ASSERT_EQ(-1, sendmmsg(-1, nullptr, 0, 0));
-  ASSERT_EQ(EBADF, errno);
+  ASSERT_ERRNO(EBADF);
 #pragma clang diagnostic pop
 }
diff --git a/tests/sys_stat_test.cpp b/tests/sys_stat_test.cpp
index f36007e..126f469 100644
--- a/tests/sys_stat_test.cpp
+++ b/tests/sys_stat_test.cpp
@@ -22,6 +22,8 @@
 #include <android-base/file.h>
 #include <gtest/gtest.h>
 
+#include "utils.h"
+
 #if defined(__BIONIC__)
 #define HAVE_STATX
 #elif defined(__GLIBC_PREREQ)
@@ -59,19 +61,19 @@
   times[1].tv_sec = 456;
   times[1].tv_nsec = 0;
   ASSERT_EQ(-1, futimens(-1, times));
-  ASSERT_EQ(EBADF, errno);
+  ASSERT_ERRNO(EBADF);
 }
 
 TEST(sys_stat, mkfifo_failure) {
   errno = 0;
   ASSERT_EQ(-1, mkfifo("/", 0666));
-  ASSERT_EQ(EEXIST, errno);
+  ASSERT_ERRNO(EEXIST);
 }
 
 TEST(sys_stat, mkfifoat_failure) {
   errno = 0;
   ASSERT_EQ(-1, mkfifoat(-2, "x", 0666));
-  ASSERT_EQ(EBADF, errno);
+  ASSERT_ERRNO(EBADF);
 }
 
 TEST(sys_stat, mkfifo) {
@@ -107,9 +109,7 @@
 #if defined(HAVE_STATX)
   struct statx sx;
   int rc = statx(AT_FDCWD, "/proc/version", AT_STATX_SYNC_AS_STAT, STATX_ALL, &sx);
-  if (rc == -1 && errno == ENOSYS) {
-    GTEST_SKIP() << "statx returned ENOSYS";
-  }
+  if (rc == -1 && errno == ENOSYS) GTEST_SKIP() << "no statx() in this kernel";
   ASSERT_EQ(0, rc);
   struct stat64 sb;
   ASSERT_EQ(0, stat64("/proc/version", &sb));
@@ -122,48 +122,48 @@
 
 TEST(sys_stat, fchmod_EBADF) {
   ASSERT_EQ(-1, fchmod(-1, 0751));
-  ASSERT_EQ(EBADF, errno);
+  ASSERT_ERRNO(EBADF);
 }
 
 TEST(sys_stat, fchmodat_EFAULT_file) {
   ASSERT_EQ(-1, fchmodat(AT_FDCWD, (char *) 0x1, 0751, 0));
-  ASSERT_EQ(EFAULT, errno);
+  ASSERT_ERRNO(EFAULT);
 }
 
 TEST(sys_stat, fchmodat_AT_SYMLINK_NOFOLLOW_EFAULT_file) {
   ASSERT_EQ(-1, fchmodat(AT_FDCWD, (char *) 0x1, 0751, AT_SYMLINK_NOFOLLOW));
 #if defined(__BIONIC__)
-  ASSERT_EQ(EFAULT, errno);
+  ASSERT_ERRNO(EFAULT);
 #else
   // glibc 2.19 does not implement AT_SYMLINK_NOFOLLOW and always
   // returns ENOTSUP
-  ASSERT_EQ(ENOTSUP, errno);
+  ASSERT_ERRNO(ENOTSUP);
 #endif
 }
 
 TEST(sys_stat, fchmodat_bad_flags) {
   ASSERT_EQ(-1, fchmodat(AT_FDCWD, "/blah", 0751, ~AT_SYMLINK_NOFOLLOW));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 }
 
 TEST(sys_stat, fchmodat_bad_flags_ALL) {
   ASSERT_EQ(-1, fchmodat(AT_FDCWD, "/blah", 0751, ~0));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 }
 
 TEST(sys_stat, fchmodat_nonexistant_file) {
   ASSERT_EQ(-1, fchmodat(AT_FDCWD, "/blah", 0751, 0));
-  ASSERT_EQ(ENOENT, errno);
+  ASSERT_ERRNO(ENOENT);
 }
 
 TEST(sys_stat, fchmodat_AT_SYMLINK_NOFOLLOW_nonexistant_file) {
   ASSERT_EQ(-1, fchmodat(AT_FDCWD, "/blah", 0751, AT_SYMLINK_NOFOLLOW));
 #if defined(__BIONIC__)
-  ASSERT_EQ(ENOENT, errno);
+  ASSERT_ERRNO(ENOENT);
 #else
   // glibc 2.19 does not implement AT_SYMLINK_NOFOLLOW and always
   // returns ENOTSUP
-  ASSERT_EQ(ENOTSUP, errno);
+  ASSERT_ERRNO(ENOTSUP);
 #endif
 }
 
@@ -188,13 +188,13 @@
 
 #if defined(__BIONIC__)
   ASSERT_EQ(0, result);
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
   AssertFileModeEquals(0751, tf.path);
 #else
   // glibc 2.19 does not implement AT_SYMLINK_NOFOLLOW and always
   // returns ENOTSUP
   ASSERT_EQ(-1, result);
-  ASSERT_EQ(ENOTSUP, errno);
+  ASSERT_ERRNO(ENOTSUP);
 #endif
 }
 
@@ -220,7 +220,7 @@
 
   ASSERT_EQ(0, symlink(target, linkname));
   ASSERT_EQ(-1, fchmodat(AT_FDCWD, linkname, 0751, 0));
-  ASSERT_EQ(ENOENT, errno);
+  ASSERT_ERRNO(ENOENT);
   unlink(linkname);
 }
 
@@ -246,7 +246,7 @@
     AssertSymlinkModeEquals(0751, linkname);
   } else {
     ASSERT_EQ(-1, result);
-    ASSERT_EQ(ENOTSUP, errno);
+    ASSERT_ERRNO(ENOTSUP);
   }
 
   // Target file mode shouldn't be modified.
@@ -269,7 +269,7 @@
     AssertSymlinkModeEquals(0751, linkname);
   } else {
     ASSERT_EQ(-1, result);
-    ASSERT_EQ(ENOTSUP, errno);
+    ASSERT_ERRNO(ENOTSUP);
   }
 
   unlink(linkname);
@@ -277,14 +277,14 @@
 
 TEST(sys_stat, faccessat_EINVAL) {
   ASSERT_EQ(-1, faccessat(AT_FDCWD, "/dev/null", F_OK, ~AT_SYMLINK_NOFOLLOW));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 #if defined(__BIONIC__)
   ASSERT_EQ(-1, faccessat(AT_FDCWD, "/dev/null", ~(R_OK | W_OK | X_OK), 0));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 #else
   ASSERT_EQ(0, faccessat(AT_FDCWD, "/dev/null", ~(R_OK | W_OK | X_OK), AT_SYMLINK_NOFOLLOW));
   ASSERT_EQ(-1, faccessat(AT_FDCWD, "/dev/null", ~(R_OK | W_OK | X_OK), 0));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 #endif
 }
 
@@ -292,7 +292,7 @@
 #if defined(__BIONIC__)
   // Android doesn't support AT_SYMLINK_NOFOLLOW
   ASSERT_EQ(-1, faccessat(AT_FDCWD, "/dev/null", F_OK, AT_SYMLINK_NOFOLLOW));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 #else
   ASSERT_EQ(0, faccessat(AT_FDCWD, "/dev/null", F_OK, AT_SYMLINK_NOFOLLOW));
 #endif
@@ -309,8 +309,8 @@
   ASSERT_EQ(-1, faccessat(AT_FDCWD, "/blah", F_OK, AT_SYMLINK_NOFOLLOW));
 #if defined(__BIONIC__)
   // Android doesn't support AT_SYMLINK_NOFOLLOW
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 #else
-  ASSERT_EQ(ENOENT, errno);
+  ASSERT_ERRNO(ENOENT);
 #endif
 }
diff --git a/tests/sys_time_test.cpp b/tests/sys_time_test.cpp
index 07394d6..ff9271f 100644
--- a/tests/sys_time_test.cpp
+++ b/tests/sys_time_test.cpp
@@ -23,6 +23,8 @@
 
 #include <android-base/file.h>
 
+#include "utils.h"
+
 // http://b/11383777
 TEST(sys_time, utimes_nullptr) {
   TemporaryFile tf;
@@ -36,19 +38,19 @@
 
   tv[0].tv_usec = -123;
   ASSERT_EQ(-1, utimes(tf.path, tv));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
   tv[0].tv_usec = 1234567;
   ASSERT_EQ(-1, utimes(tf.path, tv));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 
   tv[0].tv_usec = 0;
 
   tv[1].tv_usec = -123;
   ASSERT_EQ(-1, utimes(tf.path, tv));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
   tv[1].tv_usec = 1234567;
   ASSERT_EQ(-1, utimes(tf.path, tv));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 }
 
 TEST(sys_time, futimes_nullptr) {
@@ -63,19 +65,19 @@
 
   tv[0].tv_usec = -123;
   ASSERT_EQ(-1, futimes(tf.fd, tv));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
   tv[0].tv_usec = 1234567;
   ASSERT_EQ(-1, futimes(tf.fd, tv));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 
   tv[0].tv_usec = 0;
 
   tv[1].tv_usec = -123;
   ASSERT_EQ(-1, futimes(tf.fd, tv));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
   tv[1].tv_usec = 1234567;
   ASSERT_EQ(-1, futimes(tf.fd, tv));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 }
 
 TEST(sys_time, futimesat_nullptr) {
@@ -90,19 +92,19 @@
 
   tv[0].tv_usec = -123;
   ASSERT_EQ(-1, futimesat(AT_FDCWD, tf.path, tv));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
   tv[0].tv_usec = 1234567;
   ASSERT_EQ(-1, futimesat(AT_FDCWD, tf.path, tv));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 
   tv[0].tv_usec = 0;
 
   tv[1].tv_usec = -123;
   ASSERT_EQ(-1, futimesat(AT_FDCWD, tf.path, tv));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
   tv[1].tv_usec = 1234567;
   ASSERT_EQ(-1, futimesat(AT_FDCWD, tf.path, tv));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 }
 
 TEST(sys_time, lutimes_nullptr) {
@@ -117,19 +119,19 @@
 
   tv[0].tv_usec = -123;
   ASSERT_EQ(-1, lutimes(tf.path, tv));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
   tv[0].tv_usec = 1234567;
   ASSERT_EQ(-1, lutimes(tf.path, tv));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 
   tv[0].tv_usec = 0;
 
   tv[1].tv_usec = -123;
   ASSERT_EQ(-1, lutimes(tf.path, tv));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
   tv[1].tv_usec = 1234567;
   ASSERT_EQ(-1, lutimes(tf.path, tv));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 }
 
 // Musl doesn't define __NR_gettimeofday on 32-bit architectures.
diff --git a/tests/sys_uio_test.cpp b/tests/sys_uio_test.cpp
index aac08e7..97ba5d4 100644
--- a/tests/sys_uio_test.cpp
+++ b/tests/sys_uio_test.cpp
@@ -24,6 +24,8 @@
 
 #include <android-base/file.h>
 
+#include "utils.h"
+
 TEST(sys_uio, readv_writev) {
   TemporaryFile tf;
 
@@ -123,8 +125,9 @@
 
   // Reading from non-allocated memory should return an error
   remote = { nullptr, sizeof dst };
+  errno = 0;
   ASSERT_EQ(-1, process_vm_readv(getpid(), &local, 1, &remote, 1, 0));
-  ASSERT_EQ(EFAULT, errno);
+  ASSERT_ERRNO(EFAULT);
 }
 
 TEST(sys_uio, process_vm_writev) {
@@ -142,6 +145,7 @@
 
   // Writing to non-allocated memory should return an error
   remote = { nullptr, sizeof dst };
+  errno = 0;
   ASSERT_EQ(-1, process_vm_writev(getpid(), &local, 1, &remote, 1, 0));
-  ASSERT_EQ(EFAULT, errno);
+  ASSERT_ERRNO(EFAULT);
 }
diff --git a/tests/sys_vfs_test.cpp b/tests/sys_vfs_test.cpp
index 242f8d4..2e116a2 100644
--- a/tests/sys_vfs_test.cpp
+++ b/tests/sys_vfs_test.cpp
@@ -24,6 +24,8 @@
 
 #include <string>
 
+#include "utils.h"
+
 template <typename StatFsT> void Check(StatFsT& sb) {
   EXPECT_EQ(4096, static_cast<int>(sb.f_bsize));
   EXPECT_EQ(0U, sb.f_bfree);
@@ -48,7 +50,7 @@
   struct statfs sb;
   errno = 0;
   ASSERT_EQ(-1, statfs("/does-not-exist", &sb));
-  ASSERT_EQ(ENOENT, errno);
+  ASSERT_ERRNO(ENOENT);
 }
 
 TEST(sys_vfs, statfs64_smoke) {
@@ -61,7 +63,7 @@
   struct statfs64 sb;
   errno = 0;
   ASSERT_EQ(-1, statfs64("/does-not-exist", &sb));
-  ASSERT_EQ(ENOENT, errno);
+  ASSERT_ERRNO(ENOENT);
 }
 
 TEST(sys_vfs, fstatfs) {
@@ -76,7 +78,7 @@
   struct statfs sb;
   errno = 0;
   ASSERT_EQ(-1, fstatfs(-1, &sb));
-  ASSERT_EQ(EBADF, errno);
+  ASSERT_ERRNO(EBADF);
 }
 
 TEST(sys_vfs, fstatfs64_smoke) {
@@ -91,5 +93,5 @@
   struct statfs sb;
   errno = 0;
   ASSERT_EQ(-1, fstatfs(-1, &sb));
-  ASSERT_EQ(EBADF, errno);
+  ASSERT_ERRNO(EBADF);
 }
diff --git a/tests/sys_xattr_test.cpp b/tests/sys_xattr_test.cpp
index 45cf379..fa2aee4 100644
--- a/tests/sys_xattr_test.cpp
+++ b/tests/sys_xattr_test.cpp
@@ -21,6 +21,8 @@
 #include <android-base/file.h>
 #include <gtest/gtest.h>
 
+#include "utils.h"
+
 TEST(sys_xattr, setxattr) {
   TemporaryFile tf;
   char buf[10];
@@ -52,17 +54,17 @@
   char buf[10];
   ASSERT_EQ(0, fsetxattr(tf.fd, "user.foo", "01234567890123456789", 21, 0));
   ASSERT_EQ(-1, fgetxattr(tf.fd, "user.foo", buf, sizeof(buf)));
-  ASSERT_EQ(ERANGE, errno);
+  ASSERT_ERRNO(ERANGE);
 }
 
 TEST(sys_xattr, fsetxattr_invalid_fd) {
   char buf[10];
   errno = 0;
   ASSERT_EQ(-1, fsetxattr(-1, "user.foo", "0123", 5, 0));
-  ASSERT_EQ(EBADF, errno);
+  ASSERT_ERRNO(EBADF);
   errno = 0;
   ASSERT_EQ(-1, fgetxattr(-1, "user.foo", buf, sizeof(buf)));
-  ASSERT_EQ(EBADF, errno);
+  ASSERT_ERRNO(EBADF);
 }
 
 TEST(sys_xattr, fsetxattr_with_opath) {
@@ -78,7 +80,7 @@
   ASSERT_STREQ("bar", buf);
 #else
   ASSERT_EQ(-1, res);
-  ASSERT_EQ(EBADF, errno);
+  ASSERT_ERRNO(EBADF);
 #endif
   close(fd);
 }
@@ -93,10 +95,10 @@
   char buf[10];
   ASSERT_EQ(0, res);
   ASSERT_EQ(-1, fgetxattr(fd, "user.foo", buf, sizeof(buf)));
-  ASSERT_EQ(ERANGE, errno);
+  ASSERT_ERRNO(ERANGE);
 #else
   ASSERT_EQ(-1, res);
-  ASSERT_EQ(EBADF, errno);
+  ASSERT_ERRNO(EBADF);
 #endif
   close(fd);
 }
@@ -123,7 +125,7 @@
   ASSERT_TRUE(memmem(buf, res, "user.foo", 9) != nullptr);
 #else
   ASSERT_EQ(-1, res);
-  ASSERT_EQ(EBADF, errno);
+  ASSERT_ERRNO(EBADF);
 #endif
   close(fd);
 }
@@ -132,5 +134,5 @@
   char buf[65536];  // 64kB is max possible xattr list size. See "man 7 xattr".
   errno = 0;
   ASSERT_EQ(-1, flistxattr(-1, buf, sizeof(buf)));
-  ASSERT_EQ(EBADF, errno);
+  ASSERT_ERRNO(EBADF);
 }
diff --git a/tests/termios_test.cpp b/tests/termios_test.cpp
index a8d5890..480f3af 100644
--- a/tests/termios_test.cpp
+++ b/tests/termios_test.cpp
@@ -34,6 +34,8 @@
 
 #include <gtest/gtest.h>
 
+#include "utils.h"
+
 // TODO:
 // tcdrain
 // tcflow
@@ -53,7 +55,7 @@
   termios t = {};
   errno = 0;
   ASSERT_EQ(-1, cfsetispeed(&t, 1200));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 }
 
 TEST(termios, cfgetospeed_cfsetospeed) {
@@ -66,7 +68,7 @@
   termios t = {};
   errno = 0;
   ASSERT_EQ(-1, cfsetospeed(&t, 1200));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 }
 
 TEST(termios, cfsetspeed) {
@@ -82,7 +84,7 @@
   // glibc seems to allow 1200 as well as B1200 here, presumably for
   // BSD compatibility (where Bxxx == xxx, unlike Linux).
   ASSERT_EQ(-1, cfsetspeed(&t, 123));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 }
 
 TEST(termios, cfmakeraw) {
@@ -105,11 +107,11 @@
 
   errno = 0;
   ASSERT_EQ(-1, tcgetwinsize(-1, &ws));
-  ASSERT_EQ(EBADF, errno);
+  ASSERT_ERRNO(EBADF);
 
   errno = 0;
   ASSERT_EQ(-1, tcsetwinsize(-1, &ws));
-  ASSERT_EQ(EBADF, errno);
+  ASSERT_ERRNO(EBADF);
 #else
   GTEST_SKIP() << "glibc too old";
 #endif
diff --git a/tests/time_test.cpp b/tests/time_test.cpp
index ec59aa7..5e97c63 100644
--- a/tests/time_test.cpp
+++ b/tests/time_test.cpp
@@ -150,7 +150,7 @@
 #if !defined(__LP64__)
   // 32-bit bionic has a signed 32-bit time_t.
   ASSERT_EQ(-1, mktime(&tm));
-  ASSERT_EQ(EOVERFLOW, errno);
+  ASSERT_ERRNO(EOVERFLOW);
 #else
   // Everyone else should be using a signed 64-bit time_t.
   ASSERT_GE(sizeof(time_t) * 8, 64U);
@@ -164,7 +164,7 @@
   // mktime to interpret that time as local standard, hence offset
   // is 8 hours, not 7.
   ASSERT_EQ(static_cast<time_t>(4108348800U), mktime(&tm));
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
 #endif
 }
 
@@ -182,7 +182,7 @@
 
   errno = 0;
   ASSERT_NE(static_cast<time_t>(-1), mktime(&t));
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
 
   // This will overflow for LP32.
   t.tm_year = INT_MAX;
@@ -190,10 +190,10 @@
   errno = 0;
 #if !defined(__LP64__)
   ASSERT_EQ(static_cast<time_t>(-1), mktime(&t));
-  ASSERT_EQ(EOVERFLOW, errno);
+  ASSERT_ERRNO(EOVERFLOW);
 #else
   ASSERT_EQ(static_cast<time_t>(67768036166016000U), mktime(&t));
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
 #endif
 
   // This will overflow for LP32 or LP64.
@@ -204,7 +204,7 @@
 
   errno = 0;
   ASSERT_EQ(static_cast<time_t>(-1), mktime(&t));
-  ASSERT_EQ(EOVERFLOW, errno);
+  ASSERT_ERRNO(EOVERFLOW);
 }
 
 TEST(time, mktime_invalid_tm_TZ_combination) {
@@ -222,7 +222,7 @@
 
   EXPECT_EQ(static_cast<time_t>(-1), mktime(&t));
   // mktime sets errno to EOVERFLOW if result is unrepresentable.
-  EXPECT_EQ(EOVERFLOW, errno);
+  EXPECT_ERRNO(EOVERFLOW);
 }
 
 // Transitions in the tzdata file are generated up to the year 2100. Testing
@@ -233,14 +233,13 @@
 #if !defined(__LP64__)
   // 32-bit bionic has a signed 32-bit time_t.
   ASSERT_EQ(-1, mktime(&tm));
-  ASSERT_EQ(EOVERFLOW, errno);
+  ASSERT_ERRNO(EOVERFLOW);
 #else
   setenv("TZ", "Europe/London", 1);
   tzset();
   errno = 0;
-
   ASSERT_EQ(static_cast<time_t>(5686156800U), mktime(&tm));
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
 #endif
 }
 
@@ -649,7 +648,7 @@
   if (pid == 0) {
     // Timers are not inherited by the child.
     ASSERT_EQ(-1, timer_delete(timer_id));
-    ASSERT_EQ(EINVAL, errno);
+    ASSERT_ERRNO(EINVAL);
     _exit(0);
   }
 
@@ -804,7 +803,7 @@
   // A SIGEV_SIGNAL timer is easy; the kernel does all that.
   timer_t timer_id;
   ASSERT_EQ(-1, timer_create(invalid_clock, nullptr, &timer_id));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 
   // A SIGEV_THREAD timer is more interesting because we have stuff to clean up.
   sigevent se;
@@ -812,7 +811,7 @@
   se.sigev_notify = SIGEV_THREAD;
   se.sigev_notify_function = NoOpNotifyFunction;
   ASSERT_EQ(-1, timer_create(invalid_clock, &se, &timer_id));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 }
 
 TEST(time, timer_create_multiple) {
@@ -915,7 +914,7 @@
   cur_time = time(NULL);
   while ((kill(tdd.tid, 0) != -1 || errno != ESRCH) && (time(NULL) - cur_time) < 5);
   ASSERT_EQ(-1, kill(tdd.tid, 0));
-  ASSERT_EQ(ESRCH, errno);
+  ASSERT_ERRNO(ESRCH);
 #endif
 }
 
@@ -973,7 +972,7 @@
   errno = 0;
   timespec ts;
   ASSERT_EQ(-1, clock_gettime(-1, &ts));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 }
 
 TEST(time, clock_getres_CLOCK_REALTIME) {
@@ -1011,7 +1010,7 @@
   errno = 0;
   timespec ts = { -1, -1 };
   ASSERT_EQ(-1, clock_getres(-1, &ts));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
   ASSERT_EQ(-1, ts.tv_nsec);
   ASSERT_EQ(-1, ts.tv_sec);
 }
@@ -1064,14 +1063,14 @@
     << "commit/?id=e1b6b6ce55a0a25c8aa8af019095253b2133a41a\n"
     << "* https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/"
     << "commit/?id=c80ed088a519da53f27b798a69748eaabc66aadf\n";
-  ASSERT_EQ(0, errno);
+  ASSERT_ERRNO(0);
 }
 
 TEST(time, clock_settime) {
   errno = 0;
   timespec ts;
   ASSERT_EQ(-1, clock_settime(-1, &ts));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 }
 
 TEST(time, clock_nanosleep_EINVAL) {
@@ -1107,7 +1106,7 @@
   timespec ts = {.tv_sec = -1};
   errno = 0;
   ASSERT_EQ(-1, nanosleep(&ts, nullptr));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 }
 
 TEST(time, bug_31938693) {
diff --git a/tests/uchar_test.cpp b/tests/uchar_test.cpp
index 512f098..fd3b332 100644
--- a/tests/uchar_test.cpp
+++ b/tests/uchar_test.cpp
@@ -24,6 +24,8 @@
 #include <locale.h>
 #include <stdint.h>
 
+#include "utils.h"
+
 // Modern versions of UTF-8 (https://datatracker.ietf.org/doc/html/rfc3629 and
 // newer) explicitly disallow code points beyond U+10FFFF, which exclude all 5-
 // and 6-byte sequences. Earlier versions of UTF-8 allowed the wider range:
@@ -77,7 +79,7 @@
   EXPECT_EQ(static_cast<size_t>(-2), mbrtoc32(nullptr, "\xc2", 1, &ps));
   errno = 0;
   EXPECT_EQ(static_cast<size_t>(-1), c32rtomb(out, 0x00a2, &ps));
-  EXPECT_EQ(EILSEQ, errno);
+  EXPECT_ERRNO(EILSEQ);
 
   // Similarly (but not in compliance with the standard afaict), musl seems to
   // ignore the state entirely for the UTF-32 functions rather than reset it.
@@ -217,11 +219,11 @@
   auto result = mbrtoc16(&out, "\xf8\xa1\xa2\xa3\xa4", 5, nullptr);
   if (kLibcRejectsOverLongUtf8Sequences) {
     EXPECT_EQ(static_cast<size_t>(-1), result);
-    EXPECT_EQ(EILSEQ, errno);
+    EXPECT_ERRNO(EILSEQ);
     EXPECT_EQ(u'\0', out);
   } else {
     EXPECT_EQ(5U, result);
-    EXPECT_EQ(0, errno);
+    EXPECT_ERRNO(0);
     EXPECT_EQ(u'\uf94a', out);
   }
 }
@@ -234,7 +236,7 @@
   char16_t out = u'\0';
   EXPECT_EQ(static_cast<size_t>(-1), mbrtoc16(&out, "\xf0\x80\xbf\xbf", 6, nullptr));
   EXPECT_EQ(u'\0', out);
-  EXPECT_EQ(EILSEQ, errno);
+  EXPECT_ERRNO(EILSEQ);
 }
 
 TEST(uchar, mbrtoc16_beyond_range) {
@@ -247,11 +249,11 @@
   if (kLibcRejectsOverLongUtf8Sequences) {
     EXPECT_EQ(static_cast<size_t>(-1), result);
     EXPECT_EQ(u'\0', out);
-    EXPECT_EQ(EILSEQ, errno);
+    EXPECT_ERRNO(EILSEQ);
   } else {
     EXPECT_EQ(4U, result);
     EXPECT_EQ(u'\xdcc0', out);
-    EXPECT_EQ(0, errno);
+    EXPECT_ERRNO(0);
   }
 }
 
@@ -290,7 +292,7 @@
   ASSERT_EQ(static_cast<size_t>(-2), mbrtoc16(&out, "\xc2", 1, ps));
   errno = 0;
   ASSERT_EQ(static_cast<size_t>(-1), mbrtoc16(&out, "\x20" "cdef", 5, ps));
-  ASSERT_EQ(EILSEQ, errno);
+  ASSERT_ERRNO(EILSEQ);
 }
 
 TEST(uchar, mbrtoc16_incomplete) {
@@ -347,7 +349,7 @@
   // Invalid code point.
   errno = 0;
   EXPECT_EQ(static_cast<size_t>(-1), c32rtomb(bytes, 0xffffffff, nullptr));
-  EXPECT_EQ(EILSEQ, errno);
+  EXPECT_ERRNO(EILSEQ);
 }
 
 TEST(uchar, mbrtoc32_valid_non_characters) {
@@ -370,11 +372,11 @@
   auto result = mbrtoc32(&out, "\xf5\x80\x80\x80", 4, nullptr);
   if (kLibcRejectsOverLongUtf8Sequences) {
     EXPECT_EQ(static_cast<size_t>(-1), result);
-    EXPECT_EQ(EILSEQ, errno);
+    EXPECT_ERRNO(EILSEQ);
     EXPECT_EQ(U'\0', out);
   } else {
     EXPECT_EQ(4U, result);
-    EXPECT_EQ(0, errno);
+    EXPECT_ERRNO(0);
     EXPECT_EQ(U'\x140000', out);
   }
 }
@@ -428,7 +430,7 @@
                                               "\xf8\xa1\xa2\xa3\xa4"
                                               "f",
                                               6, nullptr));
-  EXPECT_EQ(EILSEQ, errno);
+  EXPECT_ERRNO(EILSEQ);
 #endif
   // Illegal over-long sequence.
   errno = 0;
@@ -436,7 +438,7 @@
                                               "\xf0\x82\x82\xac"
                                               "ef",
                                               6, nullptr));
-  EXPECT_EQ(EILSEQ, errno);
+  EXPECT_ERRNO(EILSEQ);
 }
 
 void test_mbrtoc32_incomplete(mbstate_t* ps) {
@@ -466,7 +468,7 @@
   ASSERT_EQ(static_cast<size_t>(-2), mbrtoc32(&out, "\xc2", 1, ps));
   errno = 0;
   ASSERT_EQ(static_cast<size_t>(-1), mbrtoc32(&out, "\x20" "cdef", 5, ps));
-  ASSERT_EQ(EILSEQ, errno);
+  ASSERT_ERRNO(EILSEQ);
 }
 
 TEST(uchar, mbrtoc32_incomplete) {
diff --git a/tests/unistd_test.cpp b/tests/unistd_test.cpp
index ac39f96..6a94507 100644
--- a/tests/unistd_test.cpp
+++ b/tests/unistd_test.cpp
@@ -72,7 +72,7 @@
   void* new_break = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(initial_break) + 1);
   int ret = brk(new_break);
   if (ret == -1) {
-    ASSERT_EQ(errno, ENOMEM);
+    ASSERT_ERRNO(ENOMEM);
   } else {
     ASSERT_EQ(0, ret);
     ASSERT_GE(get_brk(), new_break);
@@ -82,7 +82,7 @@
   new_break = page_align(reinterpret_cast<uintptr_t>(initial_break) + sysconf(_SC_PAGE_SIZE));
   ret = brk(new_break);
   if (ret == -1) {
-    ASSERT_EQ(errno, ENOMEM);
+    ASSERT_ERRNO(ENOMEM);
   } else {
     ASSERT_EQ(0, ret);
     ASSERT_EQ(get_brk(), new_break);
@@ -91,7 +91,7 @@
 
 TEST(UNISTD_TEST, brk_ENOMEM) {
   ASSERT_EQ(-1, brk(reinterpret_cast<void*>(-1)));
-  ASSERT_EQ(ENOMEM, errno);
+  ASSERT_ERRNO(ENOMEM);
 }
 
 #if defined(__GLIBC__)
@@ -124,18 +124,18 @@
 
   // Can't increase by so much that we'd overflow.
   ASSERT_EQ(reinterpret_cast<void*>(-1), sbrk(PTRDIFF_MAX));
-  ASSERT_EQ(ENOMEM, errno);
+  ASSERT_ERRNO(ENOMEM);
 
   // Set the current break to a point that will cause an overflow.
   __bionic_brk = reinterpret_cast<void*>(static_cast<uintptr_t>(PTRDIFF_MAX));
 
   ASSERT_EQ(reinterpret_cast<void*>(-1), sbrk(PTRDIFF_MIN));
-  ASSERT_EQ(ENOMEM, errno);
+  ASSERT_ERRNO(ENOMEM);
 
   __bionic_brk = reinterpret_cast<void*>(static_cast<uintptr_t>(PTRDIFF_MAX) - 1);
 
   ASSERT_EQ(reinterpret_cast<void*>(-1), sbrk(PTRDIFF_MIN + 1));
-  ASSERT_EQ(ENOMEM, errno);
+  ASSERT_ERRNO(ENOMEM);
 #else
   class ScopedBrk {
   public:
@@ -154,7 +154,7 @@
     ASSERT_EQ(reinterpret_cast<void*>(-1), sbrk(SBRK_MIN));
 #if defined(__BIONIC__)
     // GLIBC does not set errno in overflow case.
-    ASSERT_EQ(ENOMEM, errno);
+    ASSERT_ERRNO(ENOMEM);
 #endif
   }
 
@@ -167,7 +167,7 @@
     ASSERT_EQ(reinterpret_cast<void*>(-1), sbrk(SBRK_MAX));
 #if defined(__BIONIC__)
     // GLIBC does not set errno in overflow case.
-    ASSERT_EQ(ENOMEM, errno);
+    ASSERT_ERRNO(ENOMEM);
 #endif
   }
 #endif
@@ -217,7 +217,7 @@
   TemporaryFile tf;
   errno = 0;
   ASSERT_EQ(-1, ftruncate(tf.fd, -123));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 }
 
 static bool g_pause_test_flag = false;
@@ -253,7 +253,7 @@
   // our syscall stubs correctly return a 64-bit -1.
   char buf[1];
   ASSERT_EQ(-1, read(-1, buf, sizeof(buf)));
-  ASSERT_EQ(EBADF, errno);
+  ASSERT_ERRNO(EBADF);
 }
 
 TEST(UNISTD_TEST, syscall_long) {
@@ -288,27 +288,27 @@
 
 TEST(UNISTD_TEST, unsetenv_EINVAL) {
   EXPECT_EQ(-1, unsetenv(""));
-  EXPECT_EQ(EINVAL, errno);
+  EXPECT_ERRNO(EINVAL);
   EXPECT_EQ(-1, unsetenv("a=b"));
-  EXPECT_EQ(EINVAL, errno);
+  EXPECT_ERRNO(EINVAL);
 }
 
 TEST(UNISTD_TEST, setenv_EINVAL) {
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wnonnull"
   EXPECT_EQ(-1, setenv(nullptr, "value", 0));
-  EXPECT_EQ(EINVAL, errno);
+  EXPECT_ERRNO(EINVAL);
   EXPECT_EQ(-1, setenv(nullptr, "value", 1));
-  EXPECT_EQ(EINVAL, errno);
+  EXPECT_ERRNO(EINVAL);
 #pragma clang diagnostic pop
   EXPECT_EQ(-1, setenv("", "value", 0));
-  EXPECT_EQ(EINVAL, errno);
+  EXPECT_ERRNO(EINVAL);
   EXPECT_EQ(-1, setenv("", "value", 1));
-  EXPECT_EQ(EINVAL, errno);
+  EXPECT_ERRNO(EINVAL);
   EXPECT_EQ(-1, setenv("a=b", "value", 0));
-  EXPECT_EQ(EINVAL, errno);
+  EXPECT_ERRNO(EINVAL);
   EXPECT_EQ(-1, setenv("a=b", "value", 1));
-  EXPECT_EQ(EINVAL, errno);
+  EXPECT_ERRNO(EINVAL);
 }
 
 TEST(UNISTD_TEST, setenv) {
@@ -394,7 +394,7 @@
   // Can't sync an invalid fd.
   errno = 0;
   EXPECT_EQ(-1, fn(-1));
-  EXPECT_EQ(EBADF, errno);
+  EXPECT_ERRNO(EBADF);
 
   // It doesn't matter whether you've opened a file for write or not.
   TemporaryFile tf;
@@ -424,7 +424,7 @@
   int fd = open("/proc/version", O_RDONLY);
   ASSERT_NE(-1, fd);
   EXPECT_EQ(-1, fn(fd));
-  EXPECT_EQ(EINVAL, errno);
+  EXPECT_ERRNO(EINVAL);
   close(fd);
 }
 
@@ -737,7 +737,6 @@
   ASSERT_EQ(0, gethostname(hostname, HOST_NAME_MAX));
 
   // Can we get the hostname with a right-sized buffer?
-  errno = 0;
   ASSERT_EQ(0, gethostname(hostname, strlen(hostname) + 1));
 
   // Does uname(2) agree?
@@ -749,7 +748,7 @@
   // Do we correctly detect truncation?
   errno = 0;
   ASSERT_EQ(-1, gethostname(hostname, strlen(hostname)));
-  ASSERT_EQ(ENAMETOOLONG, errno);
+  ASSERT_ERRNO(ENAMETOOLONG);
 }
 
 TEST(UNISTD_TEST, pathconf_fpathconf) {
@@ -1206,7 +1205,7 @@
   // Equal, but invalid.
   errno = 0;
   ASSERT_EQ(-1, dup2(fd, fd));
-  ASSERT_EQ(EBADF, errno);
+  ASSERT_ERRNO(EBADF);
 }
 
 TEST(UNISTD_TEST, dup3) {
@@ -1297,11 +1296,11 @@
     // Check that the child cannot lock the file.
     ASSERT_EQ(0, lseek64(tf.fd, 0, SEEK_SET));
     ASSERT_EQ(-1, lockf64(tf.fd, F_TLOCK, file_size));
-    ASSERT_EQ(EAGAIN, errno);
+    ASSERT_ERRNO(EAGAIN);
     // Check also that it reports itself as locked.
     ASSERT_EQ(0, lseek64(tf.fd, 0, SEEK_SET));
     ASSERT_EQ(-1, lockf64(tf.fd, F_TEST, file_size));
-    ASSERT_EQ(EACCES, errno);
+    ASSERT_ERRNO(EACCES);
     _exit(0);
   }
   AssertChildExited(pid, 0);
@@ -1327,11 +1326,11 @@
     // Check that the child cannot lock the first half.
     ASSERT_EQ(0, lseek64(tf.fd, 0, SEEK_SET));
     ASSERT_EQ(-1, lockf64(tf.fd, F_TEST, file_size/2));
-    ASSERT_EQ(EACCES, errno);
+    ASSERT_ERRNO(EACCES);
     // Check also that it reports itself as locked.
     ASSERT_EQ(0, lseek64(tf.fd, 0, SEEK_SET));
     ASSERT_EQ(-1, lockf64(tf.fd, F_TEST, file_size/2));
-    ASSERT_EQ(EACCES, errno);
+    ASSERT_ERRNO(EACCES);
     _exit(0);
   }
   AssertChildExited(pid, 0);
@@ -1353,7 +1352,7 @@
 #if defined(__BIONIC__)
   // bionic and glibc have different behaviors when len is too small
   ASSERT_EQ(-1, getdomainname(buf, strlen(u.domainname)));
-  EXPECT_EQ(EINVAL, errno);
+  EXPECT_ERRNO(EINVAL);
 #endif
 }
 
@@ -1378,7 +1377,7 @@
 
   const char* name = "newdomainname";
   ASSERT_EQ(-1, setdomainname(name, strlen(name)));
-  ASSERT_EQ(EPERM, errno);
+  ASSERT_ERRNO(EPERM);
 
   if (has_admin) {
     ASSERT_EQ(0, capset(&header, &old_caps[0])) << "failed to restore admin privileges";
@@ -1389,7 +1388,7 @@
   ExecTestHelper eth;
   errno = 0;
   ASSERT_EQ(-1, execve("/", eth.GetArgs(), eth.GetEnv()));
-  ASSERT_EQ(EACCES, errno);
+  ASSERT_ERRNO(EACCES);
 }
 
 static void append_llvm_cov_env_var(std::string& env_str) {
@@ -1419,7 +1418,7 @@
 TEST(UNISTD_TEST, execl_failure) {
   errno = 0;
   ASSERT_EQ(-1, execl("/", "/", nullptr));
-  ASSERT_EQ(EACCES, errno);
+  ASSERT_ERRNO(EACCES);
 }
 
 TEST(UNISTD_TEST, execl) {
@@ -1432,7 +1431,7 @@
   ExecTestHelper eth;
   errno = 0;
   ASSERT_EQ(-1, execle("/", "/", nullptr, eth.GetEnv()));
-  ASSERT_EQ(EACCES, errno);
+  ASSERT_ERRNO(EACCES);
 }
 
 TEST(UNISTD_TEST, execle) {
@@ -1451,7 +1450,7 @@
   ExecTestHelper eth;
   errno = 0;
   ASSERT_EQ(-1, execv("/", eth.GetArgs()));
-  ASSERT_EQ(EACCES, errno);
+  ASSERT_ERRNO(EACCES);
 }
 
 TEST(UNISTD_TEST, execv) {
@@ -1464,7 +1463,7 @@
 TEST(UNISTD_TEST, execlp_failure) {
   errno = 0;
   ASSERT_EQ(-1, execlp("/", "/", nullptr));
-  ASSERT_EQ(EACCES, errno);
+  ASSERT_ERRNO(EACCES);
 }
 
 TEST(UNISTD_TEST, execlp) {
@@ -1478,7 +1477,7 @@
   eth.SetArgs({nullptr});
   errno = 0;
   ASSERT_EQ(-1, execvp("/", eth.GetArgs()));
-  ASSERT_EQ(EACCES, errno);
+  ASSERT_ERRNO(EACCES);
 }
 
 TEST(UNISTD_TEST, execvp) {
@@ -1493,7 +1492,7 @@
   errno = 0;
   ASSERT_EQ(-1, execvpe("this-does-not-exist", eth.GetArgs(), eth.GetEnv()));
   // Running in CTS we might not even be able to search all directories in $PATH.
-  ASSERT_TRUE(errno == ENOENT || errno == EACCES);
+  ASSERT_TRUE(errno == ENOENT || errno == EACCES) << strerror(errno);
 }
 
 TEST(UNISTD_TEST, execvpe) {
@@ -1528,7 +1527,7 @@
   // It's not inherently executable.
   errno = 0;
   ASSERT_EQ(-1, execvpe(basename(tf.path), eth.GetArgs(), eth.GetEnv()));
-  ASSERT_EQ(EACCES, errno);
+  ASSERT_ERRNO(EACCES);
 
   // Make it executable (and keep it writable because we're going to rewrite it below).
   ASSERT_EQ(0, chmod(tf.path, 0777));
@@ -1536,7 +1535,7 @@
   // TemporaryFile will have a writable fd, so we can test ETXTBSY while we're here...
   errno = 0;
   ASSERT_EQ(-1, execvpe(basename(tf.path), eth.GetArgs(), eth.GetEnv()));
-  ASSERT_EQ(ETXTBSY, errno);
+  ASSERT_ERRNO(ETXTBSY);
 
   // 1. The simplest test: the kernel should handle this.
   ASSERT_EQ(0, close(tf.fd));
@@ -1557,7 +1556,7 @@
 
   errno = 0;
   ASSERT_EQ(-1, execvp("/system/bin/does-not-exist", eth.GetArgs()));
-  ASSERT_EQ(ENOENT, errno);
+  ASSERT_ERRNO(ENOENT);
 }
 
 TEST(UNISTD_TEST, exec_argv0_null) {
@@ -1584,7 +1583,7 @@
   int fd = open("/", O_RDONLY);
   ASSERT_NE(-1, fd);
   ASSERT_EQ(-1, fexecve(fd, eth.GetArgs(), eth.GetEnv()));
-  ASSERT_EQ(EACCES, errno);
+  ASSERT_ERRNO(EACCES);
   close(fd);
 }
 
@@ -1592,7 +1591,7 @@
   ExecTestHelper eth;
   errno = 0;
   ASSERT_EQ(-1, fexecve(-1, eth.GetArgs(), eth.GetEnv()));
-  ASSERT_EQ(EBADF, errno);
+  ASSERT_ERRNO(EBADF);
 }
 
 TEST(UNISTD_TEST, fexecve_args) {
@@ -1690,16 +1689,13 @@
   int fd = open("/proc/version", O_RDONLY);
   ASSERT_GE(fd, 0);
 
-  // Try to close the file descriptor (this requires a 5.9+ kernel)
-  if (close_range(fd, fd, 0) == 0) {
-    // we can't close it *again*
-    ASSERT_EQ(close(fd), -1);
-    ASSERT_EQ(errno, EBADF);
-  } else {
-    ASSERT_EQ(errno, ENOSYS);
-    // since close_range() failed, we can close it normally
-    ASSERT_EQ(close(fd), 0);
-  }
+  int rc = close_range(fd, fd, 0);
+  if (rc == -1 && errno == ENOSYS) GTEST_SKIP() << "no close_range() in this kernel";
+  ASSERT_EQ(0, rc) << strerror(errno);
+
+  // Check the fd is actually closed.
+  ASSERT_EQ(close(fd), -1);
+  ASSERT_ERRNO(EBADF);
 #endif  // __GLIBC__
 }
 
diff --git a/tests/utils.cpp b/tests/utils.cpp
index 948d0ec..e470724 100644
--- a/tests/utils.cpp
+++ b/tests/utils.cpp
@@ -70,3 +70,12 @@
   return syscall(__NR_gettid);
 }
 #endif
+
+void PrintTo(const Errno& e, std::ostream* os) {
+  // TODO: strerrorname_np() might be more useful here, but we'd need to implement it first!
+  *os << strerror(e.errno_);
+}
+
+bool operator==(const Errno& lhs, const Errno& rhs) {
+  return lhs.errno_ == rhs.errno_;
+}
diff --git a/tests/utils.h b/tests/utils.h
index 2e00cc1..f6b7174 100644
--- a/tests/utils.h
+++ b/tests/utils.h
@@ -315,3 +315,13 @@
 }
 
 bool IsLowRamDevice();
+
+class Errno {
+ public:
+  Errno(int e) : errno_(e) {}
+  int errno_;
+};
+void PrintTo(const Errno& e, std::ostream* os);
+bool operator==(const Errno& lhs, const Errno& rhs);
+#define ASSERT_ERRNO(expected_errno) ASSERT_EQ(Errno(expected_errno), Errno(errno))
+#define EXPECT_ERRNO(expected_errno) EXPECT_EQ(Errno(expected_errno), Errno(errno))
diff --git a/tests/wchar_test.cpp b/tests/wchar_test.cpp
index 28c1046..c4cc0bd 100644
--- a/tests/wchar_test.cpp
+++ b/tests/wchar_test.cpp
@@ -122,7 +122,7 @@
   EXPECT_EQ('\xa2', bytes[3]);
   // Invalid code point.
   EXPECT_EQ(static_cast<size_t>(-1), wcrtomb(bytes, 0xffffffff, nullptr));
-  EXPECT_EQ(EILSEQ, errno);
+  EXPECT_ERRNO(EILSEQ);
 }
 
 TEST(wchar, wcrtomb_start_state) {
@@ -136,7 +136,7 @@
   memset(&ps, 0, sizeof(ps));
   EXPECT_EQ(static_cast<size_t>(-2), mbrtowc(nullptr, "\xc2", 1, &ps));
   EXPECT_EQ(static_cast<size_t>(-1), wcrtomb(out, 0x00a2, &ps));
-  EXPECT_EQ(EILSEQ, errno);
+  EXPECT_ERRNO(EILSEQ);
 
   // If the first argument to wcrtomb is NULL or the second is L'\0' the shift
   // state should be reset.
@@ -177,10 +177,10 @@
   // An unrepresentable char just returns an error from wcstombs...
   errno = 0;
   EXPECT_EQ(static_cast<size_t>(-1), wcstombs(nullptr, bad_chars, 0));
-  EXPECT_EQ(EILSEQ, errno);
+  EXPECT_ERRNO(EILSEQ);
   errno = 0;
   EXPECT_EQ(static_cast<size_t>(-1), wcstombs(nullptr, bad_chars, 256));
-  EXPECT_EQ(EILSEQ, errno);
+  EXPECT_ERRNO(EILSEQ);
 
   // And wcsrtombs doesn't tell us where it got stuck because we didn't ask it
   // to actually convert anything...
@@ -188,12 +188,12 @@
   src = bad_chars;
   EXPECT_EQ(static_cast<size_t>(-1), wcsrtombs(nullptr, &src, 0, nullptr));
   EXPECT_EQ(&bad_chars[0], src);
-  EXPECT_EQ(EILSEQ, errno);
+  EXPECT_ERRNO(EILSEQ);
   errno = 0;
   src = bad_chars;
   EXPECT_EQ(static_cast<size_t>(-1), wcsrtombs(nullptr, &src, 256, nullptr));
   EXPECT_EQ(&bad_chars[0], src);
-  EXPECT_EQ(EILSEQ, errno);
+  EXPECT_ERRNO(EILSEQ);
 
   // Okay, now let's test actually converting something...
   memset(bytes, 'x', sizeof(bytes));
@@ -211,7 +211,7 @@
   errno = 0;
   memset(bytes, 'x', sizeof(bytes));
   EXPECT_EQ(static_cast<size_t>(-1), wcstombs(bytes, bad_chars, 256));
-  EXPECT_EQ(EILSEQ, errno);
+  EXPECT_ERRNO(EILSEQ);
   bytes[3] = 0;
   EXPECT_STREQ("hix", bytes);
 
@@ -220,13 +220,13 @@
   src = chars;
   EXPECT_EQ(0U, wcsrtombs(bytes, &src, 0, nullptr));
   EXPECT_EQ(&chars[0], src); // No input consumed.
-  EXPECT_EQ(EILSEQ, errno);
+  EXPECT_ERRNO(EILSEQ);
 
   memset(bytes, 'x', sizeof(bytes));
   src = chars;
   EXPECT_EQ(4U, wcsrtombs(bytes, &src, 4, nullptr));
   EXPECT_EQ(&chars[4], src); // Some input consumed.
-  EXPECT_EQ(EILSEQ, errno);
+  EXPECT_ERRNO(EILSEQ);
   bytes[5] = 0;
   EXPECT_STREQ("hellx", bytes);
 
@@ -234,21 +234,21 @@
   src = chars;
   EXPECT_EQ(5U, wcsrtombs(bytes, &src, 256, nullptr));
   EXPECT_EQ(nullptr, src); // All input consumed!
-  EXPECT_EQ(EILSEQ, errno);
+  EXPECT_ERRNO(EILSEQ);
   EXPECT_STREQ("hello", bytes);
 
   memset(bytes, 'x', sizeof(bytes));
   src = chars;
   EXPECT_EQ(5U, wcsrtombs(bytes, &src, 6, nullptr));
   EXPECT_EQ(nullptr, src); // All input consumed.
-  EXPECT_EQ(EILSEQ, errno);
+  EXPECT_ERRNO(EILSEQ);
   EXPECT_STREQ("hello", bytes);
 
   memset(bytes, 'x', sizeof(bytes));
   src = bad_chars;
   EXPECT_EQ(static_cast<size_t>(-1), wcsrtombs(bytes, &src, 256, nullptr));
   EXPECT_EQ(&bad_chars[2], src);
-  EXPECT_EQ(EILSEQ, errno);
+  EXPECT_ERRNO(EILSEQ);
   bytes[3] = 0;
   EXPECT_STREQ("hix", bytes);
 
@@ -258,7 +258,7 @@
   memset(&ps, 0, sizeof(ps));
   ASSERT_EQ(static_cast<size_t>(-2), mbrtowc(nullptr, "\xc2", 1, &ps));
   EXPECT_EQ(static_cast<size_t>(-1), wcsrtombs(nullptr, &src, 0, &ps));
-  EXPECT_EQ(EILSEQ, errno);
+  EXPECT_ERRNO(EILSEQ);
 }
 
 TEST(wchar, limits) {
@@ -375,14 +375,14 @@
                                              "\xf8\xa1\xa2\xa3\xa4"
                                              "f",
                                              6, nullptr));
-  EXPECT_EQ(EILSEQ, errno);
+  EXPECT_ERRNO(EILSEQ);
 #endif
   // Illegal over-long sequence.
   EXPECT_EQ(static_cast<size_t>(-1), mbrtowc(out,
                                              "\xf0\x82\x82\xac"
                                              "ef",
                                              6, nullptr));
-  EXPECT_EQ(EILSEQ, errno);
+  EXPECT_ERRNO(EILSEQ);
 }
 
 TEST(wchar, mbrtowc_valid_non_characters) {
@@ -406,10 +406,10 @@
   auto result = mbrtowc(out, "\xf5\x80\x80\x80", 4, nullptr);
   if (kLibcRejectsOverLongUtf8Sequences) {
     ASSERT_EQ(static_cast<size_t>(-1), result);
-    ASSERT_EQ(EILSEQ, errno);
+    ASSERT_ERRNO(EILSEQ);
   } else {
     ASSERT_EQ(4U, result);
-    ASSERT_EQ(0, errno);
+    ASSERT_ERRNO(0);
   }
 }
 
@@ -439,7 +439,7 @@
   // Invalid 2-byte
   ASSERT_EQ(static_cast<size_t>(-2), mbrtowc(&out, "\xc2", 1, ps));
   ASSERT_EQ(static_cast<size_t>(-1), mbrtowc(&out, "\x20" "cdef", 5, ps));
-  ASSERT_EQ(EILSEQ, errno);
+  ASSERT_ERRNO(EILSEQ);
 }
 
 TEST(wchar, mbrtowc_incomplete) {
@@ -477,12 +477,12 @@
 
   const char* invalid = INVALID;
   ASSERT_EQ(static_cast<size_t>(-1), mbsrtowcs(out, &invalid, 4, ps));
-  EXPECT_EQ(EILSEQ, errno);
+  EXPECT_ERRNO(EILSEQ);
   ASSERT_EQ('\xc2', *invalid);
 
   const char* incomplete = INCOMPLETE;
   ASSERT_EQ(static_cast<size_t>(-1), mbsrtowcs(out, &incomplete, 2, ps));
-  EXPECT_EQ(EILSEQ, errno);
+  EXPECT_ERRNO(EILSEQ);
   ASSERT_EQ('\xc2', *incomplete);
 
   // If dst is null, *src shouldn't be updated.
@@ -512,7 +512,7 @@
   wchar_t out;
   ASSERT_EQ(static_cast<size_t>(-2), mbrtowc(&out, "\xc2", 1, &ps));
   ASSERT_EQ(static_cast<size_t>(-1), mbsrtowcs(&out, &invalid, 1, &ps));
-  EXPECT_EQ(EILSEQ, errno);
+  EXPECT_ERRNO(EILSEQ);
   ASSERT_EQ('\x20', *invalid);
 }
 
@@ -642,12 +642,12 @@
   src = incomplete;
   errno = 0;
   ASSERT_EQ(static_cast<size_t>(-1), mbsnrtowcs(dst, &src, SIZE_MAX, 3, nullptr));
-  ASSERT_EQ(EILSEQ, errno);
+  ASSERT_ERRNO(EILSEQ);
 
   src = incomplete;
   errno = 0;
   ASSERT_EQ(static_cast<size_t>(-1), mbsnrtowcs(nullptr, &src, SIZE_MAX, 3, nullptr));
-  ASSERT_EQ(EILSEQ, errno);
+  ASSERT_ERRNO(EILSEQ);
 }
 
 TEST(wchar, wcsftime__wcsftime_l) {
@@ -798,12 +798,12 @@
   // Invalid buffer.
   errno = 0;
   ASSERT_EQ(nullptr, open_wmemstream(nullptr, &size));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 
   // Invalid size.
   errno = 0;
   ASSERT_EQ(nullptr, open_wmemstream(&p, nullptr));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 #pragma clang diagnostic pop
 #else
   GTEST_SKIP() << "This test is bionic-specific";
@@ -813,73 +813,73 @@
 TEST(wchar, wcstol_EINVAL) {
   errno = 0;
   wcstol(L"123", nullptr, -1);
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
   errno = 0;
   wcstol(L"123", nullptr, 1);
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
   errno = 0;
   wcstol(L"123", nullptr, 37);
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 }
 
 TEST(wchar, wcstoll_EINVAL) {
   errno = 0;
   wcstoll(L"123", nullptr, -1);
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
   errno = 0;
   wcstoll(L"123", nullptr, 1);
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
   errno = 0;
   wcstoll(L"123", nullptr, 37);
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 }
 
 TEST(wchar, wcstoul_EINVAL) {
   errno = 0;
   wcstoul(L"123", nullptr, -1);
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
   errno = 0;
   wcstoul(L"123", nullptr, 1);
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
   errno = 0;
   wcstoul(L"123", nullptr, 37);
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 }
 
 TEST(wchar, wcstoull_EINVAL) {
   errno = 0;
   wcstoull(L"123", nullptr, -1);
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
   errno = 0;
   wcstoull(L"123", nullptr, 1);
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
   errno = 0;
   wcstoull(L"123", nullptr, 37);
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 }
 
 TEST(wchar, wcstoll_l_EINVAL) {
   errno = 0;
   wcstoll_l(L"123", nullptr, -1, SAFE_LC_GLOBAL_LOCALE);
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
   errno = 0;
   wcstoll_l(L"123", nullptr, 1, SAFE_LC_GLOBAL_LOCALE);
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
   errno = 0;
   wcstoll_l(L"123", nullptr, 37, SAFE_LC_GLOBAL_LOCALE);
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 }
 
 TEST(wchar, wcstoull_l_EINVAL) {
   errno = 0;
   wcstoull_l(L"123", nullptr, -1, SAFE_LC_GLOBAL_LOCALE);
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
   errno = 0;
   wcstoull_l(L"123", nullptr, 1, SAFE_LC_GLOBAL_LOCALE);
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
   errno = 0;
   wcstoull_l(L"123", nullptr, 37, SAFE_LC_GLOBAL_LOCALE);
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_ERRNO(EINVAL);
 }
 
 TEST(wchar, wmempcpy) {