2018-05-31 14:17:50 +00:00
|
|
|
/**
|
|
|
|
* Copyright (c) 2018-present, Facebook, Inc.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
2019-02-19 18:52:19 +00:00
|
|
|
* This source code is licensed in accordance with the terms specified in
|
|
|
|
* the LICENSE file found in the root directory of this source tree.
|
2018-05-31 14:17:50 +00:00
|
|
|
*/
|
|
|
|
|
2018-06-28 13:46:48 +00:00
|
|
|
#include <boost/algorithm/string.hpp>
|
|
|
|
#include <boost/core/ignore_unused.hpp>
|
2018-05-31 14:17:50 +00:00
|
|
|
#include <boost/optional.hpp>
|
2018-06-28 13:46:48 +00:00
|
|
|
|
2018-05-31 14:17:50 +00:00
|
|
|
#include <gtest/gtest.h>
|
2019-01-14 11:31:17 +00:00
|
|
|
#include <osquery/utils/error/error.h>
|
|
|
|
#include <osquery/utils/expected/expected.h>
|
2018-05-31 14:17:50 +00:00
|
|
|
|
|
|
|
namespace osquery {
|
|
|
|
|
2018-06-28 13:46:48 +00:00
|
|
|
enum class TestError {
|
|
|
|
Some,
|
|
|
|
Another,
|
|
|
|
Semantic,
|
|
|
|
Logical,
|
|
|
|
Runtime,
|
|
|
|
};
|
2018-05-31 14:17:50 +00:00
|
|
|
|
2018-06-28 13:46:48 +00:00
|
|
|
GTEST_TEST(ExpectedTest, success_contructor_initialization) {
|
|
|
|
Expected<std::string, TestError> value = std::string("Test");
|
2018-05-31 14:17:50 +00:00
|
|
|
EXPECT_TRUE(value);
|
2018-07-30 16:50:48 +00:00
|
|
|
EXPECT_TRUE(value.isValue());
|
2018-06-28 13:46:48 +00:00
|
|
|
EXPECT_FALSE(value.isError());
|
2018-05-31 14:17:50 +00:00
|
|
|
EXPECT_EQ(value.get(), "Test");
|
2018-06-28 13:46:48 +00:00
|
|
|
}
|
2018-05-31 14:17:50 +00:00
|
|
|
|
2018-06-28 13:46:48 +00:00
|
|
|
GTEST_TEST(ExpectedTest, failure_error_contructor_initialization) {
|
|
|
|
Expected<std::string, TestError> error =
|
|
|
|
Error<TestError>(TestError::Some, "Please try again");
|
2018-05-31 14:17:50 +00:00
|
|
|
EXPECT_FALSE(error);
|
2018-07-30 16:50:48 +00:00
|
|
|
EXPECT_FALSE(error.isValue());
|
2018-06-28 13:46:48 +00:00
|
|
|
EXPECT_TRUE(error.isError());
|
|
|
|
EXPECT_EQ(error.getErrorCode(), TestError::Some);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool stringContains(const std::string& what, const std::string& where) {
|
|
|
|
return boost::contains(what, where);
|
|
|
|
};
|
|
|
|
|
|
|
|
GTEST_TEST(ExpectedTest, failure_error_str_contructor_initialization) {
|
|
|
|
const auto msg =
|
|
|
|
std::string{"\"#$%&'()*+,-./089:;<[=]>\" is it a valid error message?"};
|
|
|
|
auto expected = Expected<std::string, TestError>::failure(msg);
|
|
|
|
EXPECT_FALSE(expected);
|
|
|
|
EXPECT_TRUE(expected.isError());
|
|
|
|
EXPECT_EQ(expected.getErrorCode(), TestError::Some);
|
2019-02-01 15:31:03 +00:00
|
|
|
auto fullMsg = expected.getError().getMessage();
|
2018-06-28 13:46:48 +00:00
|
|
|
EXPECT_PRED2(stringContains, fullMsg, msg);
|
2018-05-31 14:17:50 +00:00
|
|
|
}
|
|
|
|
|
2018-06-28 13:46:48 +00:00
|
|
|
osquery::ExpectedUnique<std::string, TestError> testFunction() {
|
2018-05-31 14:17:50 +00:00
|
|
|
return std::make_unique<std::string>("Test");
|
|
|
|
}
|
|
|
|
|
2018-06-28 13:46:48 +00:00
|
|
|
GTEST_TEST(ExpectedTest, ExpectedSharedTestFunction) {
|
|
|
|
osquery::Expected<std::shared_ptr<std::string>, TestError> sharedPointer =
|
2018-05-31 14:17:50 +00:00
|
|
|
std::make_shared<std::string>("Test");
|
|
|
|
EXPECT_TRUE(sharedPointer);
|
|
|
|
EXPECT_EQ(**sharedPointer, "Test");
|
|
|
|
|
2018-06-28 13:46:48 +00:00
|
|
|
osquery::ExpectedShared<std::string, TestError> sharedPointer2 =
|
2018-05-31 14:17:50 +00:00
|
|
|
std::make_shared<std::string>("Test");
|
|
|
|
EXPECT_TRUE(sharedPointer2);
|
|
|
|
EXPECT_EQ(**sharedPointer2, "Test");
|
2018-06-28 13:46:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GTEST_TEST(ExpectedTest, ExpectedUniqueTestFunction) {
|
|
|
|
auto uniquePointer = testFunction();
|
|
|
|
EXPECT_TRUE(uniquePointer);
|
|
|
|
EXPECT_EQ(**uniquePointer, "Test");
|
|
|
|
}
|
2018-05-31 14:17:50 +00:00
|
|
|
|
2018-06-28 13:46:48 +00:00
|
|
|
GTEST_TEST(ExpectedTest, ExpectedSharedWithError) {
|
|
|
|
osquery::ExpectedShared<std::string, TestError> error =
|
|
|
|
Error<TestError>(TestError::Another, "Some message");
|
2018-05-31 14:17:50 +00:00
|
|
|
EXPECT_FALSE(error);
|
2018-06-28 13:46:48 +00:00
|
|
|
EXPECT_EQ(error.getErrorCode(), TestError::Another);
|
|
|
|
}
|
2018-05-31 14:17:50 +00:00
|
|
|
|
2018-06-28 13:46:48 +00:00
|
|
|
GTEST_TEST(ExpectedTest, ExpectedOptional) {
|
2018-05-31 14:17:50 +00:00
|
|
|
boost::optional<std::string> optional = std::string("123");
|
2018-06-28 13:46:48 +00:00
|
|
|
osquery::Expected<boost::optional<std::string>, TestError> optionalExpected =
|
|
|
|
optional;
|
2018-05-31 14:17:50 +00:00
|
|
|
EXPECT_TRUE(optionalExpected);
|
|
|
|
EXPECT_EQ(**optionalExpected, "123");
|
|
|
|
}
|
|
|
|
|
2018-06-28 13:46:48 +00:00
|
|
|
template <typename ValueType>
|
|
|
|
using LocalExpected = Expected<ValueType, TestError>;
|
|
|
|
|
|
|
|
GTEST_TEST(ExpectedTest, createError_example) {
|
|
|
|
auto giveMeDozen = [](bool valid) -> LocalExpected<int> {
|
|
|
|
if (valid) {
|
|
|
|
return 50011971;
|
|
|
|
}
|
|
|
|
return createError(TestError::Logical,
|
|
|
|
"an error message is supposed to be here");
|
|
|
|
};
|
|
|
|
auto v = giveMeDozen(true);
|
|
|
|
EXPECT_TRUE(v);
|
|
|
|
ASSERT_FALSE(v.isError());
|
|
|
|
EXPECT_EQ(*v, 50011971);
|
|
|
|
|
|
|
|
auto errV = giveMeDozen(false);
|
|
|
|
EXPECT_FALSE(errV);
|
|
|
|
ASSERT_TRUE(errV.isError());
|
|
|
|
EXPECT_EQ(errV.getErrorCode(), TestError::Logical);
|
|
|
|
}
|
|
|
|
|
|
|
|
GTEST_TEST(ExpectedTest, ExpectedSuccess_example) {
|
|
|
|
auto giveMeStatus = [](bool valid) -> ExpectedSuccess<TestError> {
|
|
|
|
if (valid) {
|
|
|
|
return Success{};
|
|
|
|
}
|
|
|
|
return Error<TestError>(TestError::Runtime,
|
|
|
|
"an error message is supposed to be here");
|
|
|
|
};
|
|
|
|
auto s = giveMeStatus(true);
|
|
|
|
EXPECT_TRUE(s);
|
|
|
|
ASSERT_FALSE(s.isError());
|
|
|
|
|
|
|
|
auto errS = giveMeStatus(false);
|
|
|
|
EXPECT_FALSE(errS);
|
|
|
|
ASSERT_TRUE(errS.isError());
|
|
|
|
}
|
|
|
|
|
|
|
|
GTEST_TEST(ExpectedTest, nested_errors_example) {
|
|
|
|
const auto msg = std::string{"Write a good error message"};
|
|
|
|
auto firstFailureSource = [&msg]() -> Expected<std::vector<int>, TestError> {
|
|
|
|
return createError(TestError::Semantic, msg);
|
|
|
|
};
|
|
|
|
auto giveMeNestedError = [&]() -> Expected<std::vector<int>, TestError> {
|
|
|
|
auto ret = firstFailureSource();
|
|
|
|
ret.isError();
|
|
|
|
return createError(TestError::Runtime, msg, ret.takeError());
|
|
|
|
};
|
|
|
|
auto ret = giveMeNestedError();
|
|
|
|
EXPECT_FALSE(ret);
|
|
|
|
ASSERT_TRUE(ret.isError());
|
|
|
|
EXPECT_EQ(ret.getErrorCode(), TestError::Runtime);
|
|
|
|
ASSERT_TRUE(ret.getError().hasUnderlyingError());
|
2019-02-01 15:31:03 +00:00
|
|
|
EXPECT_PRED2(stringContains, ret.getError().getMessage(), msg);
|
2018-06-28 13:46:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GTEST_TEST(ExpectedTest, error_handling_example) {
|
|
|
|
auto failureSource = []() -> Expected<std::vector<int>, TestError> {
|
|
|
|
return createError(TestError::Runtime, "Test error message ()*+,-.");
|
|
|
|
};
|
|
|
|
auto ret = failureSource();
|
|
|
|
if (ret.isError()) {
|
|
|
|
switch (ret.getErrorCode()) {
|
|
|
|
case TestError::Some:
|
|
|
|
case TestError::Another:
|
|
|
|
case TestError::Semantic:
|
|
|
|
case TestError::Logical:
|
|
|
|
FAIL() << "There is must be a Runtime type of error";
|
|
|
|
case TestError::Runtime:
|
|
|
|
SUCCEED();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
FAIL() << "There is must be an error";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-22 12:26:55 +00:00
|
|
|
GTEST_TEST(ExpectedTest, expected_was_not_checked_before_destruction_failure) {
|
2018-06-28 13:46:48 +00:00
|
|
|
auto action = []() { auto expected = ExpectedSuccess<TestError>{Success()}; };
|
|
|
|
#ifndef NDEBUG
|
2018-08-22 12:26:55 +00:00
|
|
|
ASSERT_DEATH(action(), "Expected was not checked before destruction");
|
2018-06-28 13:46:48 +00:00
|
|
|
#else
|
|
|
|
boost::ignore_unused(action);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2018-08-22 12:26:55 +00:00
|
|
|
GTEST_TEST(ExpectedTest, expected_was_not_checked_before_assigning_failure) {
|
|
|
|
auto action = []() {
|
|
|
|
auto expected = ExpectedSuccess<TestError>{Success()};
|
|
|
|
expected = ExpectedSuccess<TestError>{Success()};
|
|
|
|
expected.isValue();
|
|
|
|
};
|
|
|
|
#ifndef NDEBUG
|
|
|
|
ASSERT_DEATH(action(), "Expected was not checked before assigning");
|
|
|
|
#else
|
|
|
|
boost::ignore_unused(action);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
GTEST_TEST(ExpectedTest, expected_move_is_safe) {
|
|
|
|
auto expected = ExpectedSuccess<TestError>{Success()};
|
|
|
|
expected.isValue();
|
|
|
|
expected = ExpectedSuccess<TestError>{Success()};
|
|
|
|
expected.isValue();
|
|
|
|
}
|
|
|
|
|
2018-06-28 13:46:48 +00:00
|
|
|
GTEST_TEST(ExpectedTest, get_value_from_expected_with_error) {
|
|
|
|
auto action = []() {
|
|
|
|
auto expected = Expected<int, TestError>(TestError::Logical,
|
|
|
|
"Test error message @#$0k+Qh");
|
|
|
|
auto value = expected.get();
|
|
|
|
boost::ignore_unused(value);
|
|
|
|
};
|
|
|
|
#ifndef NDEBUG
|
|
|
|
ASSERT_DEATH(action(), "Do not try to get value from Expected with error");
|
|
|
|
#else
|
|
|
|
boost::ignore_unused(action);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
GTEST_TEST(ExpectedTest, const_get_value_from_expected_with_error) {
|
|
|
|
auto action = []() {
|
|
|
|
const auto expected = Expected<int, TestError>(
|
|
|
|
TestError::Semantic, "Test error message {}()[].");
|
|
|
|
auto value = expected.get();
|
|
|
|
boost::ignore_unused(value);
|
|
|
|
};
|
|
|
|
#ifndef NDEBUG
|
|
|
|
ASSERT_DEATH(action(), "Do not try to get value from Expected with error");
|
|
|
|
#else
|
|
|
|
boost::ignore_unused(action);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
GTEST_TEST(ExpectedTest, take_value_from_expected_with_error) {
|
|
|
|
auto action = []() {
|
|
|
|
auto expected = Expected<int, TestError>(TestError::Semantic,
|
|
|
|
"Test error message !&^?<>.");
|
|
|
|
auto value = expected.take();
|
|
|
|
boost::ignore_unused(value);
|
|
|
|
};
|
|
|
|
#ifndef NDEBUG
|
|
|
|
ASSERT_DEATH(action(), "Do not try to get value from Expected with error");
|
|
|
|
#else
|
|
|
|
boost::ignore_unused(action);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2018-08-03 16:18:15 +00:00
|
|
|
GTEST_TEST(ExpectedTest, get_error_from_expected_with_value) {
|
|
|
|
auto action = []() {
|
|
|
|
auto expected = Expected<int, TestError>(228);
|
|
|
|
const auto& error = expected.getError();
|
|
|
|
boost::ignore_unused(error);
|
|
|
|
};
|
|
|
|
#ifndef NDEBUG
|
|
|
|
ASSERT_DEATH(action(), "Do not try to get error from Expected with value");
|
|
|
|
#else
|
|
|
|
boost::ignore_unused(action);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
GTEST_TEST(ExpectedTest, take_error_from_expected_with_value) {
|
|
|
|
auto action = []() {
|
|
|
|
auto expected = Expected<int, TestError>(228);
|
|
|
|
return expected.takeError();
|
|
|
|
};
|
|
|
|
#ifndef NDEBUG
|
|
|
|
ASSERT_DEATH(action(), "Do not try to get error from Expected with value");
|
|
|
|
#else
|
|
|
|
boost::ignore_unused(action);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2018-07-23 21:20:04 +00:00
|
|
|
GTEST_TEST(ExpectedTest, value__takeOr) {
|
2018-07-06 13:27:06 +00:00
|
|
|
const auto text = std::string{"some text"};
|
|
|
|
auto callable = [&text]() -> Expected<std::string, TestError> {
|
|
|
|
return text;
|
|
|
|
};
|
|
|
|
auto expected = callable();
|
|
|
|
EXPECT_EQ(expected ? expected.take() : std::string{"default text"}, text);
|
|
|
|
|
2018-07-23 21:20:04 +00:00
|
|
|
EXPECT_EQ(callable().takeOr(std::string{"default text"}), text);
|
2018-07-06 13:27:06 +00:00
|
|
|
}
|
|
|
|
|
2018-07-23 21:20:04 +00:00
|
|
|
GTEST_TEST(ExpectedTest, error__takeOr) {
|
2018-07-06 13:27:06 +00:00
|
|
|
auto expected =
|
|
|
|
Expected<std::string, TestError>(TestError::Semantic, "error message");
|
2018-07-23 21:20:04 +00:00
|
|
|
EXPECT_EQ(expected.takeOr(std::string{"default text"}), "default text");
|
2018-07-06 13:27:06 +00:00
|
|
|
}
|
|
|
|
|
2018-07-23 21:20:04 +00:00
|
|
|
GTEST_TEST(ExpectedTest, error__takeOr_with_user_defined_class) {
|
2018-07-06 13:27:06 +00:00
|
|
|
class SomeTestClass {
|
|
|
|
public:
|
|
|
|
explicit SomeTestClass(const std::string& prefix, const std::string& sufix)
|
|
|
|
: text{prefix + " - " + sufix} {}
|
|
|
|
|
|
|
|
std::string text;
|
|
|
|
};
|
|
|
|
auto callable = []() -> Expected<SomeTestClass, TestError> {
|
|
|
|
return createError(TestError::Semantic, "error message");
|
|
|
|
};
|
2018-07-23 21:20:04 +00:00
|
|
|
EXPECT_EQ(callable().takeOr(SomeTestClass("427 BC", "347 BC")).text,
|
2018-07-06 13:27:06 +00:00
|
|
|
"427 BC - 347 BC");
|
|
|
|
}
|
|
|
|
|
2018-09-07 13:59:10 +00:00
|
|
|
GTEST_TEST(ExpectedTest, value_takeOr_with_rvalue_as_an_argument) {
|
|
|
|
auto value = int{312};
|
|
|
|
auto callable = []() -> Expected<int, TestError> { return 306; };
|
|
|
|
value = callable().takeOr(value);
|
|
|
|
EXPECT_EQ(value, 306);
|
|
|
|
}
|
|
|
|
|
|
|
|
GTEST_TEST(ExpectedTest, error_takeOr_with_rvalue_as_an_argument) {
|
|
|
|
auto value = int{312};
|
|
|
|
auto callable = []() -> Expected<int, TestError> {
|
|
|
|
return createError(TestError::Logical, "error message");
|
|
|
|
};
|
|
|
|
value = callable().takeOr(value);
|
|
|
|
EXPECT_EQ(value, 312);
|
|
|
|
}
|
|
|
|
|
2018-05-31 14:17:50 +00:00
|
|
|
} // namespace osquery
|