Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[libc][NFC] Extend ErrnoSetterMatcher to test expected inequalities. #67153

Merged
merged 1 commit into from
Sep 22, 2023

Conversation

sivachandra
Copy link
Collaborator

Before this change, ErrnoSetterMatcher only allowed testing for equality
of the expected return and errno values. This change extends it to allow
testing for expected inequalities of the return and errno values. The
test libc.test.src.stdio.fileop_test has been updated to use the
ErrnoSetterMatcher with tests for inequalities.

Before this change, ErrnoSetterMatcher only allowed testing for equality
of the expected return and errno values. This change extends it to allow
testing for expected inequalities of the return and errno values. The
test libc.test.src.stdio.fileop_test has been updated to use the
ErrnoSetterMatcher with tests for inequalities.
@llvmbot llvmbot added the libc label Sep 22, 2023
@llvmbot
Copy link
Member

llvmbot commented Sep 22, 2023

@llvm/pr-subscribers-libc

Changes

Before this change, ErrnoSetterMatcher only allowed testing for equality
of the expected return and errno values. This change extends it to allow
testing for expected inequalities of the return and errno values. The
test libc.test.src.stdio.fileop_test has been updated to use the
ErrnoSetterMatcher with tests for inequalities.


Full diff: https://github.com/llvm/llvm-project/pull/67153.diff

2 Files Affected:

  • (modified) libc/test/UnitTest/ErrnoSetterMatcher.h (+94-23)
  • (modified) libc/test/src/stdio/fileop_test.cpp (+24-19)
diff --git a/libc/test/UnitTest/ErrnoSetterMatcher.h b/libc/test/UnitTest/ErrnoSetterMatcher.h
index 1d786c7e462b159..e0d22f04431fe43 100644
--- a/libc/test/UnitTest/ErrnoSetterMatcher.h
+++ b/libc/test/UnitTest/ErrnoSetterMatcher.h
@@ -21,11 +21,42 @@ namespace testing {
 
 namespace internal {
 
+enum class CompareAction { EQ = 0, GE, GT, LE, LT, NE };
+
+constexpr const char *CompareMessage[] = {
+    "equal to",     "greater than or equal to",
+    "greater than", "less than or equal to",
+    "less than",    "not equal to"};
+
+template <typename T> struct Comparator {
+  CompareAction cmp;
+  T expected;
+  bool compare(T actual) {
+    switch (cmp) {
+    case CompareAction::EQ:
+      return actual == expected;
+    case CompareAction::NE:
+      return actual != expected;
+    case CompareAction::GE:
+      return actual >= expected;
+    case CompareAction::GT:
+      return actual > expected;
+    case CompareAction::LE:
+      return actual <= expected;
+    case CompareAction::LT:
+      return actual < expected;
+    }
+    __builtin_unreachable();
+  }
+
+  const char *str() { return CompareMessage[static_cast<int>(cmp)]; }
+};
+
 template <typename T> class ErrnoSetterMatcher : public Matcher<T> {
-  T ExpectedReturn;
-  T ActualReturn;
-  int ExpectedErrno;
-  int ActualErrno;
+  Comparator<T> return_cmp;
+  Comparator<int> errno_cmp;
+  T actual_return;
+  int actual_errno;
 
   // Even though this is a errno matcher primarily, it has to cater to platforms
   // which do not have an errno. This predicate checks if errno matching is to
@@ -39,38 +70,46 @@ template <typename T> class ErrnoSetterMatcher : public Matcher<T> {
   }
 
 public:
-  ErrnoSetterMatcher(T ExpectedReturn, int ExpectedErrno)
-      : ExpectedReturn(ExpectedReturn), ExpectedErrno(ExpectedErrno) {}
+  ErrnoSetterMatcher(Comparator<T> rcmp) : return_cmp(rcmp) {}
+  ErrnoSetterMatcher(Comparator<T> rcmp, Comparator<int> ecmp)
+      : return_cmp(rcmp), errno_cmp(ecmp) {}
+
+  ErrnoSetterMatcher<T> with_errno(Comparator<int> ecmp) {
+    errno_cmp = ecmp;
+    return *this;
+  }
 
   void explainError() override {
-    if (ActualReturn != ExpectedReturn) {
+    if (!return_cmp.compare(actual_return)) {
       if constexpr (cpp::is_floating_point_v<T>) {
-        tlog << "Expected return value to be: "
-             << str(fputil::FPBits<T>(ExpectedReturn)) << '\n';
-        tlog << "                    But got: "
-             << str(fputil::FPBits<T>(ActualReturn)) << '\n';
+        tlog << "Expected return value to be " << return_cmp.str() << ": "
+             << str(fputil::FPBits<T>(return_cmp.expected)) << '\n'
+             << "                    But got: "
+             << str(fputil::FPBits<T>(actual_return)) << '\n';
       } else {
-        tlog << "Expected return value to be " << ExpectedReturn << " but got "
-             << ActualReturn << ".\n";
+        tlog << "Expected return value to be " << return_cmp.str() << " "
+             << return_cmp.expected << " but got " << actual_return << ".\n";
       }
     }
 
     if constexpr (!ignore_errno()) {
-      if (ActualErrno != ExpectedErrno) {
-        tlog << "Expected errno to be \"" << get_error_string(ExpectedErrno)
-             << "\" but got \"" << get_error_string(ActualErrno) << "\".\n";
+      if (!errno_cmp.compare(actual_errno)) {
+        tlog << "Expected errno to be " << errno_cmp.str() << " \""
+             << get_error_string(errno_cmp.expected) << "\" but got \""
+             << get_error_string(actual_errno) << "\".\n";
       }
     }
   }
 
-  bool match(T Got) {
-    ActualReturn = Got;
-    ActualErrno = libc_errno;
+  bool match(T got) {
+    actual_return = got;
+    actual_errno = libc_errno;
     libc_errno = 0;
     if constexpr (ignore_errno())
-      return Got == ExpectedReturn;
+      return return_cmp.compare(actual_return);
     else
-      return Got == ExpectedReturn && ActualErrno == ExpectedErrno;
+      return return_cmp.compare(actual_return) &&
+             errno_cmp.compare(actual_errno);
   }
 };
 
@@ -78,16 +117,48 @@ template <typename T> class ErrnoSetterMatcher : public Matcher<T> {
 
 namespace ErrnoSetterMatcher {
 
+template <typename T> internal::Comparator<T> LT(T val) {
+  return internal::Comparator<T>{internal::CompareAction::LT, val};
+}
+
+template <typename T> internal::Comparator<T> LE(T val) {
+  return internal::Comparator<T>{internal::CompareAction::LE, val};
+}
+
+template <typename T> internal::Comparator<T> GT(T val) {
+  return internal::Comparator<T>{internal::CompareAction::GT, val};
+}
+
+template <typename T> internal::Comparator<T> GE(T val) {
+  return internal::Comparator<T>{internal::CompareAction::GE, val};
+}
+
+template <typename T> internal::Comparator<T> EQ(T val) {
+  return internal::Comparator<T>{internal::CompareAction::EQ, val};
+}
+
+template <typename T> internal::Comparator<T> NE(T val) {
+  return internal::Comparator<T>{internal::CompareAction::NE, val};
+}
+
 template <typename RetT = int>
 static internal::ErrnoSetterMatcher<RetT> Succeeds(RetT ExpectedReturn = 0,
                                                    int ExpectedErrno = 0) {
-  return {ExpectedReturn, ExpectedErrno};
+  return internal::ErrnoSetterMatcher<RetT>(EQ(ExpectedReturn),
+                                            EQ(ExpectedErrno));
 }
 
 template <typename RetT = int>
 static internal::ErrnoSetterMatcher<RetT> Fails(int ExpectedErrno,
                                                 RetT ExpectedReturn = -1) {
-  return {ExpectedReturn, ExpectedErrno};
+  return internal::ErrnoSetterMatcher<RetT>(EQ(ExpectedReturn),
+                                            EQ(ExpectedErrno));
+}
+
+template <typename RetT>
+static internal::ErrnoSetterMatcher<RetT>
+returns(internal::Comparator<RetT> cmp) {
+  return internal::ErrnoSetterMatcher<RetT>(cmp);
 }
 
 } // namespace ErrnoSetterMatcher
diff --git a/libc/test/src/stdio/fileop_test.cpp b/libc/test/src/stdio/fileop_test.cpp
index 989de2963cf9cc6..68a749a6c93e73f 100644
--- a/libc/test/src/stdio/fileop_test.cpp
+++ b/libc/test/src/stdio/fileop_test.cpp
@@ -16,11 +16,16 @@
 #include "src/stdio/fread.h"
 #include "src/stdio/fseek.h"
 #include "src/stdio/fwrite.h"
+#include "test/UnitTest/ErrnoSetterMatcher.h"
 #include "test/UnitTest/Test.h"
 
 #include "src/errno/libc_errno.h"
 #include <stdio.h>
 
+using __llvm_libc::testing::ErrnoSetterMatcher::EQ;
+using __llvm_libc::testing::ErrnoSetterMatcher::NE;
+using __llvm_libc::testing::ErrnoSetterMatcher::returns;
+
 TEST(LlvmLibcFILETest, SimpleFileOperations) {
   constexpr char FILENAME[] = "testdata/simple_operations.test";
   ::FILE *file = __llvm_libc::fopen(FILENAME, "w");
@@ -31,9 +36,9 @@ TEST(LlvmLibcFILETest, SimpleFileOperations) {
 
   // This is not a readable file.
   char read_data[sizeof(CONTENT)];
-  ASSERT_EQ(__llvm_libc::fread(read_data, 1, sizeof(CONTENT), file), size_t(0));
+  ASSERT_THAT(__llvm_libc::fread(read_data, 1, sizeof(CONTENT), file),
+              returns(EQ(size_t(0))).with_errno(NE(0)));
   ASSERT_NE(__llvm_libc::ferror(file), 0);
-  EXPECT_NE(libc_errno, 0);
   libc_errno = 0;
 
   __llvm_libc::clearerr(file);
@@ -62,25 +67,25 @@ TEST(LlvmLibcFILETest, SimpleFileOperations) {
   ASSERT_NE(__llvm_libc::feof(file), 0);
 
   // Should be an error to write.
-  ASSERT_EQ(size_t(0), __llvm_libc::fwrite(CONTENT, 1, sizeof(CONTENT), file));
+  ASSERT_THAT(__llvm_libc::fwrite(CONTENT, 1, sizeof(CONTENT), file),
+              returns(EQ(size_t(0))).with_errno(NE(0)));
   ASSERT_NE(__llvm_libc::ferror(file), 0);
-  ASSERT_NE(libc_errno, 0);
   libc_errno = 0;
 
   __llvm_libc::clearerr(file);
 
   // Should be an error to puts.
-  ASSERT_EQ(EOF, __llvm_libc::fputs(CONTENT, file));
+  ASSERT_THAT(__llvm_libc::fputs(CONTENT, file),
+              returns(EQ(EOF)).with_errno(NE(0)));
   ASSERT_NE(__llvm_libc::ferror(file), 0);
-  ASSERT_NE(libc_errno, 0);
   libc_errno = 0;
 
   __llvm_libc::clearerr(file);
   ASSERT_EQ(__llvm_libc::ferror(file), 0);
 
   libc_errno = 0;
-  ASSERT_EQ(__llvm_libc::fwrite("nothing", 1, 1, file), size_t(0));
-  ASSERT_NE(libc_errno, 0);
+  ASSERT_THAT(__llvm_libc::fwrite("nothing", 1, 1, file),
+              returns(EQ(0)).with_errno(NE(0)));
   libc_errno = 0;
 
   ASSERT_EQ(__llvm_libc::fclose(file), 0);
@@ -97,8 +102,8 @@ TEST(LlvmLibcFILETest, SimpleFileOperations) {
 
   // This is not a readable file.
   libc_errno = 0;
-  ASSERT_EQ(__llvm_libc::fread(data, 1, 1, file), size_t(0));
-  ASSERT_NE(libc_errno, 0);
+  ASSERT_THAT(__llvm_libc::fread(data, 1, 1, file),
+              returns(EQ(0)).with_errno(NE(0)));
   libc_errno = 0;
 
   ASSERT_EQ(0, __llvm_libc::fclose(file));
@@ -162,22 +167,22 @@ TEST(LlvmLibcFILETest, FOpenFWriteSizeGreaterThanOne) {
   FILE *file = __llvm_libc::fopen(FILENAME, "w");
   ASSERT_FALSE(file == nullptr);
   ASSERT_EQ(size_t(0), __llvm_libc::fwrite(WRITE_DATA, 0, 1, file));
-  ASSERT_EQ(WRITE_NMEMB, __llvm_libc::fwrite(WRITE_DATA, sizeof(MyStruct),
-                                             WRITE_NMEMB, file));
-  EXPECT_EQ(libc_errno, 0);
+  ASSERT_THAT(
+      __llvm_libc::fwrite(WRITE_DATA, sizeof(MyStruct), WRITE_NMEMB, file),
+      returns(EQ(WRITE_NMEMB)).with_errno(EQ(0)));
   ASSERT_EQ(__llvm_libc::fclose(file), 0);
 
   file = __llvm_libc::fopen(FILENAME, "r");
   ASSERT_FALSE(file == nullptr);
   MyStruct read_data[WRITE_NMEMB];
   ASSERT_EQ(size_t(0), __llvm_libc::fread(read_data, 0, 1, file));
-  ASSERT_EQ(WRITE_NMEMB,
-            __llvm_libc::fread(read_data, sizeof(MyStruct), WRITE_NMEMB, file));
-  EXPECT_EQ(libc_errno, 0);
+  ASSERT_THAT(
+      __llvm_libc::fread(read_data, sizeof(MyStruct), WRITE_NMEMB, file),
+      returns(EQ(WRITE_NMEMB)).with_errno(EQ(0)));
   // Trying to read more should fetch nothing.
-  ASSERT_EQ(size_t(0),
-            __llvm_libc::fread(read_data, sizeof(MyStruct), WRITE_NMEMB, file));
-  EXPECT_EQ(libc_errno, 0);
+  ASSERT_THAT(
+      __llvm_libc::fread(read_data, sizeof(MyStruct), WRITE_NMEMB, file),
+      returns(EQ(0)).with_errno(EQ(0)));
   EXPECT_NE(__llvm_libc::feof(file), 0);
   EXPECT_EQ(__llvm_libc::ferror(file), 0);
   ASSERT_EQ(__llvm_libc::fclose(file), 0);

@sivachandra sivachandra requested a review from jhuber6 September 22, 2023 14:59
Copy link
Contributor

@jhuber6 jhuber6 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LG and works with my patch. Thanks.

@sivachandra sivachandra merged commit 62a3d84 into llvm:main Sep 22, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants