Add an ErrorsAreAndClear test helper.
Usage:
```
EXPECT_TRUE(ErrorsAreAndClear({ERR_LIB_EVP, std::nullopt},
{std::nullopt, ERR_R_MALLOC_FAILURE});
```
where `nullopt`s are wildcards.
Bug: 42290241
Change-Id: Id4eeb543bd9130e4ae75d185fbe7ce396a6a6964
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/99007
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Rudolf Polzer <rpolzer@google.com>
diff --git a/crypto/test/test_util.cc b/crypto/test/test_util.cc
index 28ab074..716de41 100644
--- a/crypto/test/test_util.cc
+++ b/crypto/test/test_util.cc
@@ -70,18 +70,64 @@
return ret;
}
-testing::AssertionResult ErrorEquals(uint32_t err, int lib, int reason) {
- if (ERR_equals(err, lib, reason)) {
+testing::AssertionResult ErrorEquals(uint32_t err, std::optional<int> lib,
+ std::optional<int> reason) {
+ bool lib_matches = !lib.has_value() || (ERR_GET_LIB(err) == lib.value());
+ bool reason_matches =
+ !reason.has_value() || (ERR_GET_REASON(err) == reason.value());
+
+ if (lib_matches && reason_matches) {
return testing::AssertionSuccess();
}
char buf[128], expected[128];
- return testing::AssertionFailure()
- << "Got \"" << ERR_error_string_n(err, buf, sizeof(buf))
- << "\", wanted \""
- << ERR_error_string_n(ERR_PACK(lib, reason), expected,
- sizeof(expected))
- << "\"";
+ if (lib.has_value() && reason.has_value()) {
+ return testing::AssertionFailure()
+ << "Got \"" << ERR_error_string_n(err, buf, sizeof(buf))
+ << "\", wanted \""
+ << ERR_error_string_n(ERR_PACK(lib.value(), reason.value()),
+ expected, sizeof(expected))
+ << "\"";
+ } else if (lib.has_value()) {
+ return testing::AssertionFailure()
+ << "Got \"" << ERR_error_string_n(err, buf, sizeof(buf))
+ << "\", wanted something with library \""
+ << ERR_lib_error_string(ERR_PACK(lib.value(), 0)) << "\"";
+ } else if (reason.has_value()) {
+ return testing::AssertionFailure()
+ << "Got \"" << ERR_error_string_n(err, buf, sizeof(buf))
+ << "\", wanted something with reason \""
+ << ERR_reason_error_string(ERR_PACK(0, reason.value())) << "\"";
+ } else {
+ return testing::AssertionFailure()
+ << "Unreachable code: the always-true assertion failed";
+ }
+}
+
+testing::AssertionResult ErrorsAreAndClear(
+ std::initializer_list<std::pair<std::optional<int>, std::optional<int>>>
+ libs_and_reasons) {
+ if (libs_and_reasons.size() == 0) {
+ return testing::AssertionFailure()
+ << "ErrorsAreAndClear with empty list of errors is nonsensical - "
+ "just use ERR_clear_error directly!";
+ }
+ bool have_failures = false;
+ testing::AssertionResult all_failures = testing::AssertionFailure();
+ for (const auto &[lib, reason] : libs_and_reasons) {
+ uint32_t err = ERR_get_error();
+ testing::AssertionResult this_result = ErrorEquals(err, lib, reason);
+ if (this_result) {
+ continue;
+ }
+ all_failures << this_result.message();
+ have_failures = true;
+ }
+ if (have_failures) {
+ return all_failures;
+ }
+ ERR_clear_error();
+ return testing::AssertionSuccess();
}
bssl::UniquePtr<BIGNUM> HexToBIGNUM(const char *hex) {
diff --git a/crypto/test/test_util.h b/crypto/test/test_util.h
index af6c6ec..a5101f0 100644
--- a/crypto/test/test_util.h
+++ b/crypto/test/test_util.h
@@ -20,8 +20,11 @@
#include <stdio.h>
#include <string.h>
+#include <initializer_list>
#include <iosfwd>
+#include <optional>
#include <string_view>
+#include <utility>
#include <vector>
#include <gtest/gtest.h>
@@ -73,8 +76,18 @@
std::string EncodeHex(bssl::Span<const uint8_t> in);
// ErrorEquals asserts that `err` is an error with library `lib` and reason
-// `reason`.
-testing::AssertionResult ErrorEquals(uint32_t err, int lib, int reason);
+// `reason`. Pass `std::nullopt` to either of them to not assert on it.
+testing::AssertionResult ErrorEquals(uint32_t err, std::optional<int> lib,
+ std::optional<int> reason);
+
+// ErrorsAreAndClear asserts that the first (i.e. least recent, and thus most
+// specific) errors on the error queue are as specified, and then clears the
+// remainder of the queue. The first entry in `libs_and_reasons` shall be the
+// error first read from `ERR_get_error`. `libs_and_reasons` is not allowed to
+// be empty; instead, to just clear and assert nothing, call `ERR_clear_error`.
+testing::AssertionResult ErrorsAreAndClear(
+ std::initializer_list<std::pair<std::optional<int>, std::optional<int>>>
+ libs_and_reasons);
// HexToBignum decodes `hex` as a hexadecimal, big-endian, unsigned integer and
// returns it as a `BIGNUM`, or nullptr on error.