android_system_core/libutils/Errors_test.cpp
Atneya Nair dde6034eac Fix OkOrFail<status_t> conversion ambiguities
OkOrFail<status_t> has specialized conversions for Result<int, StatusT>
to avoid ambiguous implicit conversion sequences. Since user conversion
operators sequences can be followed by integral promotion, specializing
for integral types is necessary.

Specialize ResultError<StatusT> so calling code() returns a status_t
instead of a StatusT and message() is implemented even when not carrying
a string.
Eventually, these classes should be combined.

Add equality operators for ResultError<StatusT>.

Bug: 219580167
Test: atest Errors_test.cpp
Merged-In: I14acecfd2aef33c40e79ddb091e2f4af9291d837
Change-Id: Ifb5ed3c2d3452b10901e4aeb19368d873225d9ce
2022-02-25 14:27:41 -05:00

172 lines
4.4 KiB
C++

/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "utils/ErrorsMacros.h"
#include <android-base/result.h>
#include <gtest/gtest.h>
using namespace android;
using android::base::Error;
using android::base::Result;
status_t success_or_fail(bool success) {
if (success)
return OK;
else
return PERMISSION_DENIED;
}
TEST(errors, unwrap_or_return) {
auto f = [](bool success, int* val) -> status_t {
OR_RETURN(success_or_fail(success));
*val = 10;
return OK;
};
int val;
status_t s = f(true, &val);
EXPECT_EQ(OK, s);
EXPECT_EQ(10, val);
val = 0; // reset
status_t q = f(false, &val);
EXPECT_EQ(PERMISSION_DENIED, q);
EXPECT_EQ(0, val);
}
TEST(errors, unwrap_or_return_result) {
auto f = [](bool success) -> Result<std::string, StatusT> {
OR_RETURN(success_or_fail(success));
return "hello";
};
auto r = f(true);
EXPECT_TRUE(r.ok());
EXPECT_EQ("hello", *r);
auto s = f(false);
EXPECT_FALSE(s.ok());
EXPECT_EQ(PERMISSION_DENIED, s.error().code());
EXPECT_EQ("PERMISSION_DENIED", s.error().message());
}
TEST(errors, unwrap_or_return_result_int) {
auto f = [](bool success) -> Result<int, StatusT> {
OR_RETURN(success_or_fail(success));
return 10;
};
auto r = f(true);
EXPECT_TRUE(r.ok());
EXPECT_EQ(10, *r);
auto s = f(false);
EXPECT_FALSE(s.ok());
EXPECT_EQ(PERMISSION_DENIED, s.error().code());
EXPECT_EQ("PERMISSION_DENIED", s.error().message());
}
TEST(errors, unwrap_or_fatal) {
OR_FATAL(success_or_fail(true));
EXPECT_DEATH(OR_FATAL(success_or_fail(false)), "PERMISSION_DENIED");
}
TEST(errors, result_in_status) {
auto f = [](bool success) -> Result<std::string, StatusT> {
if (success)
return "OK";
else
return Error<StatusT>(PERMISSION_DENIED) << "custom error message";
};
auto g = [&](bool success) -> status_t {
std::string val = OR_RETURN(f(success));
EXPECT_EQ("OK", val);
return OK;
};
status_t a = g(true);
EXPECT_EQ(OK, a);
status_t b = g(false);
EXPECT_EQ(PERMISSION_DENIED, b);
}
TEST(errors, conversion_promotion) {
constexpr size_t successVal = 10ull;
auto f = [&](bool success) -> Result<size_t, StatusT> {
OR_RETURN(success_or_fail(success));
return successVal;
};
auto s = f(true);
ASSERT_TRUE(s.ok());
EXPECT_EQ(s.value(), successVal);
auto r = f(false);
EXPECT_TRUE(!r.ok());
EXPECT_EQ(PERMISSION_DENIED, r.error().code());
}
TEST(errors, conversion_promotion_bool) {
constexpr size_t successVal = true;
auto f = [&](bool success) -> Result<bool, StatusT> {
OR_RETURN(success_or_fail(success));
return successVal;
};
auto s = f(true);
ASSERT_TRUE(s.ok());
EXPECT_EQ(s.value(), successVal);
auto r = f(false);
EXPECT_TRUE(!r.ok());
EXPECT_EQ(PERMISSION_DENIED, r.error().code());
}
TEST(errors, conversion_promotion_char) {
constexpr char successVal = 'a';
auto f = [&](bool success) -> Result<unsigned char, StatusT> {
OR_RETURN(success_or_fail(success));
return successVal;
};
auto s = f(true);
ASSERT_TRUE(s.ok());
EXPECT_EQ(s.value(), successVal);
auto r = f(false);
EXPECT_TRUE(!r.ok());
EXPECT_EQ(PERMISSION_DENIED, r.error().code());
}
struct IntContainer {
// Implicit conversion from int is desired
IntContainer(int val) : val_(val) {}
int val_;
};
TEST(errors, conversion_construct) {
constexpr int successVal = 10;
auto f = [&](bool success) -> Result<IntContainer, StatusT> {
OR_RETURN(success_or_fail(success));
return successVal;
};
auto s = f(true);
ASSERT_TRUE(s.ok());
EXPECT_EQ(s.value().val_, successVal);
auto r = f(false);
EXPECT_TRUE(!r.ok());
EXPECT_EQ(PERMISSION_DENIED, r.error().code());
}