diff options
Diffstat (limited to 'mfbt/tests/gtest/TestResultExtensions.cpp')
-rw-r--r-- | mfbt/tests/gtest/TestResultExtensions.cpp | 579 |
1 files changed, 579 insertions, 0 deletions
diff --git a/mfbt/tests/gtest/TestResultExtensions.cpp b/mfbt/tests/gtest/TestResultExtensions.cpp new file mode 100644 index 0000000000..711e4f33e4 --- /dev/null +++ b/mfbt/tests/gtest/TestResultExtensions.cpp @@ -0,0 +1,579 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "gtest/gtest.h" + +#include "mozilla/ResultExtensions.h" +#include "nsLocalFile.h" + +#include <functional> + +using namespace mozilla; + +namespace { +class TestClass { + public: + static constexpr int kTestValue = 42; + + nsresult NonOverloadedNoInput(int* aOut) { + *aOut = kTestValue; + return NS_OK; + } + nsresult NonOverloadedNoInputFails(int* aOut) { return NS_ERROR_FAILURE; } + + nsresult NonOverloadedNoInputConst(int* aOut) const { + *aOut = kTestValue; + return NS_OK; + } + nsresult NonOverloadedNoInputFailsConst(int* aOut) const { + return NS_ERROR_FAILURE; + } + + nsresult NonOverloadedNoInputRef(int& aOut) { + aOut = kTestValue; + return NS_OK; + } + nsresult NonOverloadedNoInputFailsRef(int& aOut) { return NS_ERROR_FAILURE; } + + nsresult NonOverloadedNoInputComplex(std::pair<int, int>* aOut) { + *aOut = std::pair{kTestValue, kTestValue}; + return NS_OK; + } + nsresult NonOverloadedNoInputFailsComplex(std::pair<int, int>* aOut) { + return NS_ERROR_FAILURE; + } + + nsresult NonOverloadedWithInput(int aIn, int* aOut) { + *aOut = aIn; + return NS_OK; + } + nsresult NonOverloadedWithInputFails(int aIn, int* aOut) { + return NS_ERROR_FAILURE; + } + + nsresult NonOverloadedNoOutput(int aIn) { return NS_OK; } + nsresult NonOverloadedNoOutputFails(int aIn) { return NS_ERROR_FAILURE; } + + nsresult PolymorphicNoInput(nsIFile** aOut) { + *aOut = MakeAndAddRef<nsLocalFile>().take(); + return NS_OK; + } + nsresult PolymorphicNoInputFails(nsIFile** aOut) { return NS_ERROR_FAILURE; } +}; + +class RefCountedTestClass { + public: + NS_INLINE_DECL_REFCOUNTING(RefCountedTestClass); + + static constexpr int kTestValue = 42; + + nsresult NonOverloadedNoInput(int* aOut) { + *aOut = kTestValue; + return NS_OK; + } + nsresult NonOverloadedNoInputFails(int* aOut) { return NS_ERROR_FAILURE; } + + private: + ~RefCountedTestClass() = default; +}; + +// Check that DerefedType deduces the types as expected +static_assert(std::is_same_v<mozilla::detail::DerefedType<RefCountedTestClass&>, + RefCountedTestClass>); +static_assert(std::is_same_v<mozilla::detail::DerefedType<RefCountedTestClass*>, + RefCountedTestClass>); +static_assert( + std::is_same_v<mozilla::detail::DerefedType<RefPtr<RefCountedTestClass>>, + RefCountedTestClass>); + +static_assert(std::is_same_v<mozilla::detail::DerefedType<nsIFile&>, nsIFile>); +static_assert(std::is_same_v<mozilla::detail::DerefedType<nsIFile*>, nsIFile>); +static_assert( + std::is_same_v<mozilla::detail::DerefedType<nsCOMPtr<nsIFile>>, nsIFile>); +} // namespace + +TEST(ResultExtensions_ToResultInvoke, Lambda_NoInput) +{ + TestClass foo; + + // success + { + auto valOrErr = ToResultInvoke<int>( + [&foo](int* out) { return foo.NonOverloadedNoInput(out); }); + static_assert(std::is_same_v<decltype(valOrErr), Result<int, nsresult>>); + ASSERT_TRUE(valOrErr.isOk()); + ASSERT_EQ(TestClass::kTestValue, valOrErr.unwrap()); + } + + // failure + { + auto valOrErr = ToResultInvoke<int>( + [&foo](int* out) { return foo.NonOverloadedNoInputFails(out); }); + static_assert(std::is_same_v<decltype(valOrErr), Result<int, nsresult>>); + ASSERT_TRUE(valOrErr.isErr()); + ASSERT_EQ(NS_ERROR_FAILURE, valOrErr.unwrapErr()); + } +} + +TEST(ResultExtensions_ToResultInvoke, MemFn_NoInput) +{ + TestClass foo; + + // success + { + auto valOrErr = + ToResultInvoke<int>(std::mem_fn(&TestClass::NonOverloadedNoInput), foo); + static_assert(std::is_same_v<decltype(valOrErr), Result<int, nsresult>>); + ASSERT_TRUE(valOrErr.isOk()); + ASSERT_EQ(TestClass::kTestValue, valOrErr.unwrap()); + } + + // failure + { + auto valOrErr = ToResultInvoke<int>( + std::mem_fn(&TestClass::NonOverloadedNoInputFails), foo); + static_assert(std::is_same_v<decltype(valOrErr), Result<int, nsresult>>); + ASSERT_TRUE(valOrErr.isErr()); + ASSERT_EQ(NS_ERROR_FAILURE, valOrErr.unwrapErr()); + } +} + +TEST(ResultExtensions_ToResultInvoke, MemFn_Polymorphic_NoInput) +{ + TestClass foo; + + // success + { + auto valOrErr = ToResultInvoke<nsCOMPtr<nsIFile>>( + std::mem_fn(&TestClass::PolymorphicNoInput), foo); + static_assert(std::is_same_v<decltype(valOrErr), + Result<nsCOMPtr<nsIFile>, nsresult>>); + ASSERT_TRUE(valOrErr.isOk()); + ASSERT_NE(nullptr, valOrErr.inspect()); + + ASSERT_EQ(ToResultInvoke<nsString>(std::mem_fn(&nsIFile::GetPath), + *MakeRefPtr<nsLocalFile>()) + .inspect(), + ToResultInvoke<nsString>(std::mem_fn(&nsIFile::GetPath), + valOrErr.inspect()) + .inspect()); + } + + // failure + { + auto valOrErr = ToResultInvoke<nsCOMPtr<nsIFile>>( + std::mem_fn(&TestClass::PolymorphicNoInputFails), foo); + static_assert(std::is_same_v<decltype(valOrErr), + Result<nsCOMPtr<nsIFile>, nsresult>>); + ASSERT_TRUE(valOrErr.isErr()); + ASSERT_EQ(NS_ERROR_FAILURE, valOrErr.unwrapErr()); + } +} + +TEST(ResultExtensions_ToResultInvokeMember, NoInput) +{ + TestClass foo; + + // success + { + auto valOrErr = ToResultInvokeMember(foo, &TestClass::NonOverloadedNoInput); + static_assert(std::is_same_v<decltype(valOrErr), Result<int, nsresult>>); + ASSERT_TRUE(valOrErr.isOk()); + ASSERT_EQ(TestClass::kTestValue, valOrErr.unwrap()); + } + + // failure + { + auto valOrErr = + ToResultInvokeMember(foo, &TestClass::NonOverloadedNoInputFails); + static_assert(std::is_same_v<decltype(valOrErr), Result<int, nsresult>>); + ASSERT_TRUE(valOrErr.isErr()); + ASSERT_EQ(NS_ERROR_FAILURE, valOrErr.unwrapErr()); + } +} + +TEST(ResultExtensions_ToResultInvokeMember, NoInput_Const) +{ + const TestClass foo; + + // success + { + auto valOrErr = + ToResultInvokeMember(foo, &TestClass::NonOverloadedNoInputConst); + static_assert(std::is_same_v<decltype(valOrErr), Result<int, nsresult>>); + ASSERT_TRUE(valOrErr.isOk()); + ASSERT_EQ(TestClass::kTestValue, valOrErr.unwrap()); + } + + // failure + { + auto valOrErr = + ToResultInvokeMember(foo, &TestClass::NonOverloadedNoInputFailsConst); + static_assert(std::is_same_v<decltype(valOrErr), Result<int, nsresult>>); + ASSERT_TRUE(valOrErr.isErr()); + ASSERT_EQ(NS_ERROR_FAILURE, valOrErr.unwrapErr()); + } +} + +TEST(ResultExtensions_ToResultInvokeMember, NoInput_Ref) +{ + TestClass foo; + + // success + { + auto valOrErr = + ToResultInvokeMember(foo, &TestClass::NonOverloadedNoInputRef); + static_assert(std::is_same_v<decltype(valOrErr), Result<int, nsresult>>); + ASSERT_TRUE(valOrErr.isOk()); + ASSERT_EQ(TestClass::kTestValue, valOrErr.unwrap()); + } + + // failure + { + auto valOrErr = + ToResultInvokeMember(foo, &TestClass::NonOverloadedNoInputFailsRef); + static_assert(std::is_same_v<decltype(valOrErr), Result<int, nsresult>>); + ASSERT_TRUE(valOrErr.isErr()); + ASSERT_EQ(NS_ERROR_FAILURE, valOrErr.unwrapErr()); + } +} + +TEST(ResultExtensions_ToResultInvokeMember, NoInput_Complex) +{ + TestClass foo; + + // success + { + auto valOrErr = + ToResultInvokeMember(foo, &TestClass::NonOverloadedNoInputComplex); + static_assert(std::is_same_v<decltype(valOrErr), + Result<std::pair<int, int>, nsresult>>); + ASSERT_TRUE(valOrErr.isOk()); + ASSERT_EQ((std::pair{TestClass::kTestValue, TestClass::kTestValue}), + valOrErr.unwrap()); + } + + // failure + { + auto valOrErr = + ToResultInvokeMember(foo, &TestClass::NonOverloadedNoInputFailsComplex); + static_assert(std::is_same_v<decltype(valOrErr), + Result<std::pair<int, int>, nsresult>>); + ASSERT_TRUE(valOrErr.isErr()); + ASSERT_EQ(NS_ERROR_FAILURE, valOrErr.unwrapErr()); + } +} + +TEST(ResultExtensions_ToResultInvokeMember, WithInput) +{ + TestClass foo; + + // success + { + auto valOrErr = ToResultInvokeMember( + foo, &TestClass::NonOverloadedWithInput, -TestClass::kTestValue); + static_assert(std::is_same_v<decltype(valOrErr), Result<int, nsresult>>); + ASSERT_TRUE(valOrErr.isOk()); + ASSERT_EQ(-TestClass::kTestValue, valOrErr.unwrap()); + } + + // failure + { + auto valOrErr = ToResultInvokeMember( + foo, &TestClass::NonOverloadedWithInputFails, -TestClass::kTestValue); + static_assert(std::is_same_v<decltype(valOrErr), Result<int, nsresult>>); + ASSERT_TRUE(valOrErr.isErr()); + ASSERT_EQ(NS_ERROR_FAILURE, valOrErr.unwrapErr()); + } +} + +TEST(ResultExtensions_ToResultInvokeMember, NoOutput) +{ + TestClass foo; + + // success + { + auto valOrErr = ToResultInvokeMember(foo, &TestClass::NonOverloadedNoOutput, + -TestClass::kTestValue); + static_assert(std::is_same_v<decltype(valOrErr), Result<Ok, nsresult>>); + ASSERT_TRUE(valOrErr.isOk()); + } + + // failure + { + auto valOrErr = ToResultInvokeMember( + foo, &TestClass::NonOverloadedNoOutputFails, -TestClass::kTestValue); + static_assert(std::is_same_v<decltype(valOrErr), Result<Ok, nsresult>>); + ASSERT_TRUE(valOrErr.isErr()); + ASSERT_EQ(NS_ERROR_FAILURE, valOrErr.unwrapErr()); + } +} + +TEST(ResultExtensions_ToResultInvokeMember, NoInput_Macro) +{ + TestClass foo; + + // success + { + auto valOrErr = MOZ_TO_RESULT_INVOKE_MEMBER(foo, NonOverloadedNoInput); + static_assert(std::is_same_v<decltype(valOrErr), Result<int, nsresult>>); + ASSERT_TRUE(valOrErr.isOk()); + ASSERT_EQ(TestClass::kTestValue, valOrErr.unwrap()); + } + + // failure + { + auto valOrErr = MOZ_TO_RESULT_INVOKE_MEMBER(foo, NonOverloadedNoInputFails); + static_assert(std::is_same_v<decltype(valOrErr), Result<int, nsresult>>); + ASSERT_TRUE(valOrErr.isErr()); + ASSERT_EQ(NS_ERROR_FAILURE, valOrErr.unwrapErr()); + } +} + +TEST(ResultExtensions_ToResultInvokeMember, NoInput_Const_Macro) +{ + const TestClass foo; + + // success + { + auto valOrErr = MOZ_TO_RESULT_INVOKE_MEMBER(foo, NonOverloadedNoInputConst); + static_assert(std::is_same_v<decltype(valOrErr), Result<int, nsresult>>); + ASSERT_TRUE(valOrErr.isOk()); + ASSERT_EQ(TestClass::kTestValue, valOrErr.unwrap()); + } + + // failure + { + auto valOrErr = + MOZ_TO_RESULT_INVOKE_MEMBER(foo, NonOverloadedNoInputFailsConst); + static_assert(std::is_same_v<decltype(valOrErr), Result<int, nsresult>>); + ASSERT_TRUE(valOrErr.isErr()); + ASSERT_EQ(NS_ERROR_FAILURE, valOrErr.unwrapErr()); + } +} + +TEST(ResultExtensions_ToResultInvokeMember, NoInput_Ref_Macro) +{ + TestClass foo; + + // success + { + auto valOrErr = MOZ_TO_RESULT_INVOKE_MEMBER(foo, NonOverloadedNoInputRef); + static_assert(std::is_same_v<decltype(valOrErr), Result<int, nsresult>>); + ASSERT_TRUE(valOrErr.isOk()); + ASSERT_EQ(TestClass::kTestValue, valOrErr.unwrap()); + } + + // failure + { + auto valOrErr = + MOZ_TO_RESULT_INVOKE_MEMBER(foo, NonOverloadedNoInputFailsRef); + static_assert(std::is_same_v<decltype(valOrErr), Result<int, nsresult>>); + ASSERT_TRUE(valOrErr.isErr()); + ASSERT_EQ(NS_ERROR_FAILURE, valOrErr.unwrapErr()); + } +} + +TEST(ResultExtensions_ToResultInvokeMember, NoInput_Complex_Macro) +{ + TestClass foo; + + // success + { + auto valOrErr = + MOZ_TO_RESULT_INVOKE_MEMBER(foo, NonOverloadedNoInputComplex); + static_assert(std::is_same_v<decltype(valOrErr), + Result<std::pair<int, int>, nsresult>>); + ASSERT_TRUE(valOrErr.isOk()); + ASSERT_EQ((std::pair{TestClass::kTestValue, TestClass::kTestValue}), + valOrErr.unwrap()); + } + + // failure + { + auto valOrErr = + MOZ_TO_RESULT_INVOKE_MEMBER(foo, NonOverloadedNoInputFailsComplex); + + static_assert(std::is_same_v<decltype(valOrErr), + Result<std::pair<int, int>, nsresult>>); + ASSERT_TRUE(valOrErr.isErr()); + ASSERT_EQ(NS_ERROR_FAILURE, valOrErr.unwrapErr()); + } +} + +TEST(ResultExtensions_ToResultInvokeMember, WithInput_Macro) +{ + TestClass foo; + + // success + { + auto valOrErr = MOZ_TO_RESULT_INVOKE_MEMBER(foo, NonOverloadedWithInput, + -TestClass::kTestValue); + static_assert(std::is_same_v<decltype(valOrErr), Result<int, nsresult>>); + ASSERT_TRUE(valOrErr.isOk()); + ASSERT_EQ(-TestClass::kTestValue, valOrErr.unwrap()); + } + + // failure + { + auto valOrErr = MOZ_TO_RESULT_INVOKE_MEMBER( + foo, NonOverloadedWithInputFails, -TestClass::kTestValue); + static_assert(std::is_same_v<decltype(valOrErr), Result<int, nsresult>>); + ASSERT_TRUE(valOrErr.isErr()); + ASSERT_EQ(NS_ERROR_FAILURE, valOrErr.unwrapErr()); + } +} + +TEST(ResultExtensions_ToResultInvokeMember, NoOutput_Macro) +{ + TestClass foo; + + // success + { + auto valOrErr = MOZ_TO_RESULT_INVOKE_MEMBER(foo, NonOverloadedNoOutput, + -TestClass::kTestValue); + static_assert(std::is_same_v<decltype(valOrErr), Result<Ok, nsresult>>); + ASSERT_TRUE(valOrErr.isOk()); + } + + // failure + { + auto valOrErr = MOZ_TO_RESULT_INVOKE_MEMBER(foo, NonOverloadedNoOutputFails, + -TestClass::kTestValue); + static_assert(std::is_same_v<decltype(valOrErr), Result<Ok, nsresult>>); + ASSERT_TRUE(valOrErr.isErr()); + ASSERT_EQ(NS_ERROR_FAILURE, valOrErr.unwrapErr()); + } +} + +TEST(ResultExtensions_ToResultInvokeMember, NoInput_Complex_Macro_Typed) +{ + TestClass foo; + + // success + { + auto valOrErr = MOZ_TO_RESULT_INVOKE_MEMBER_TYPED( + (std::pair<int, int>), foo, NonOverloadedNoInputComplex); + static_assert(std::is_same_v<decltype(valOrErr), + Result<std::pair<int, int>, nsresult>>); + ASSERT_TRUE(valOrErr.isOk()); + ASSERT_EQ((std::pair{TestClass::kTestValue, TestClass::kTestValue}), + valOrErr.unwrap()); + } + + // failure + { + auto valOrErr = MOZ_TO_RESULT_INVOKE_MEMBER_TYPED( + (std::pair<int, int>), foo, NonOverloadedNoInputFailsComplex); + static_assert(std::is_same_v<decltype(valOrErr), + Result<std::pair<int, int>, nsresult>>); + ASSERT_TRUE(valOrErr.isErr()); + ASSERT_EQ(NS_ERROR_FAILURE, valOrErr.unwrapErr()); + } +} + +TEST(ResultExtensions_ToResultInvokeMember, RefPtr_NoInput) +{ + auto foo = MakeRefPtr<RefCountedTestClass>(); + + // success + { + auto valOrErr = + ToResultInvokeMember(foo, &RefCountedTestClass::NonOverloadedNoInput); + static_assert(std::is_same_v<decltype(valOrErr), Result<int, nsresult>>); + ASSERT_TRUE(valOrErr.isOk()); + ASSERT_EQ(TestClass::kTestValue, valOrErr.unwrap()); + } + + // failure + { + auto valOrErr = ToResultInvokeMember( + foo, &RefCountedTestClass::NonOverloadedNoInputFails); + static_assert(std::is_same_v<decltype(valOrErr), Result<int, nsresult>>); + ASSERT_TRUE(valOrErr.isErr()); + ASSERT_EQ(NS_ERROR_FAILURE, valOrErr.unwrapErr()); + } +} + +TEST(ResultExtensions_ToResultInvokeMember, RefPtr_NoInput_Macro) +{ + auto foo = MakeRefPtr<RefCountedTestClass>(); + + // success + { + auto valOrErr = MOZ_TO_RESULT_INVOKE_MEMBER(foo, NonOverloadedNoInput); + static_assert(std::is_same_v<decltype(valOrErr), Result<int, nsresult>>); + ASSERT_TRUE(valOrErr.isOk()); + ASSERT_EQ(TestClass::kTestValue, valOrErr.unwrap()); + } + + // failure + { + auto valOrErr = MOZ_TO_RESULT_INVOKE_MEMBER(foo, NonOverloadedNoInputFails); + static_assert(std::is_same_v<decltype(valOrErr), Result<int, nsresult>>); + ASSERT_TRUE(valOrErr.isErr()); + ASSERT_EQ(NS_ERROR_FAILURE, valOrErr.unwrapErr()); + } +} + +TEST(ResultExtensions_ToResultInvokeMember, RawPtr_NoInput_Macro) +{ + auto foo = MakeRefPtr<RefCountedTestClass>(); + auto* fooPtr = foo.get(); + + // success + { + auto valOrErr = MOZ_TO_RESULT_INVOKE_MEMBER(fooPtr, NonOverloadedNoInput); + static_assert(std::is_same_v<decltype(valOrErr), Result<int, nsresult>>); + ASSERT_TRUE(valOrErr.isOk()); + ASSERT_EQ(TestClass::kTestValue, valOrErr.unwrap()); + } + + // failure + { + auto valOrErr = + MOZ_TO_RESULT_INVOKE_MEMBER(fooPtr, NonOverloadedNoInputFails); + static_assert(std::is_same_v<decltype(valOrErr), Result<int, nsresult>>); + ASSERT_TRUE(valOrErr.isErr()); + ASSERT_EQ(NS_ERROR_FAILURE, valOrErr.unwrapErr()); + } +} + +TEST(ResultExtensions_ToResultInvokeMember, nsCOMPtr_AbstractClass_WithInput) +{ + nsCOMPtr<nsIFile> file = MakeAndAddRef<nsLocalFile>(); + + auto valOrErr = ToResultInvokeMember(file, &nsIFile::Equals, file); + static_assert(std::is_same_v<decltype(valOrErr), Result<bool, nsresult>>); + ASSERT_TRUE(valOrErr.isOk()); + ASSERT_EQ(true, valOrErr.unwrap()); +} + +TEST(ResultExtensions_ToResultInvokeMember, + RawPtr_AbstractClass_WithInput_Macro) +{ + nsCOMPtr<nsIFile> file = MakeAndAddRef<nsLocalFile>(); + auto* filePtr = file.get(); + + auto valOrErr = MOZ_TO_RESULT_INVOKE_MEMBER(filePtr, Equals, file); + static_assert(std::is_same_v<decltype(valOrErr), Result<bool, nsresult>>); + ASSERT_TRUE(valOrErr.isOk()); + ASSERT_EQ(true, valOrErr.unwrap()); +} + +TEST(ResultExtensions_ToResultInvokeMember, + RawPtr_AbstractClass_NoInput_Macro_Typed) +{ + nsCOMPtr<nsIFile> file = MakeAndAddRef<nsLocalFile>(); + auto* filePtr = file.get(); + + auto valOrErr = + MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsCOMPtr<nsIFile>, filePtr, Clone); + static_assert( + std::is_same_v<decltype(valOrErr), Result<nsCOMPtr<nsIFile>, nsresult>>); + ASSERT_TRUE(valOrErr.isOk()); + ASSERT_NE(nullptr, valOrErr.unwrap()); +} |