|  | // Copyright 2020 The Fuchsia Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include <lib/fitx/result.h> | 
|  | #include <lib/zx/status.h> | 
|  | #include <zircon/errors.h> | 
|  |  | 
|  | #include <cstddef> | 
|  | #include <cstring> | 
|  | #include <optional> | 
|  | #include <string> | 
|  | #include <type_traits> | 
|  | #include <utility> | 
|  | #include <vector> | 
|  |  | 
|  | #include <zxtest/zxtest.h> | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | struct nothing {}; | 
|  |  | 
|  | // Basic properties. | 
|  | static_assert(!std::is_constructible_v<fitx::result<int>>); | 
|  | static_assert(std::is_constructible_v<fitx::result<int>, fitx::success<>>); | 
|  | static_assert(!std::is_constructible_v<fitx::result<int>, fitx::failed>); | 
|  | static_assert(!std::is_constructible_v<fitx::result<int>, nothing>); | 
|  | static_assert(!std::is_constructible_v<fitx::result<int>, fitx::success<nothing>>); | 
|  | static_assert(std::is_constructible_v<fitx::result<int>, fitx::error<int>>); | 
|  | static_assert(!std::is_constructible_v<fitx::result<int>, fitx::error<nothing>>); | 
|  |  | 
|  | static_assert(!std::is_constructible_v<fitx::result<int, int>>); | 
|  | static_assert(!std::is_constructible_v<fitx::result<int, int>, fitx::success<>>); | 
|  | static_assert(!std::is_constructible_v<fitx::result<int, int>, fitx::failed>); | 
|  | static_assert(!std::is_constructible_v<fitx::result<int, int>, int>); | 
|  | static_assert(std::is_constructible_v<fitx::result<int, int>, fitx::success<int>>); | 
|  | static_assert(!std::is_constructible_v<fitx::result<int, int>, nothing>); | 
|  | static_assert(!std::is_constructible_v<fitx::result<int, int>, fitx::success<nothing>>); | 
|  | static_assert(std::is_constructible_v<fitx::result<int, int>, fitx::error<int>>); | 
|  | static_assert(!std::is_constructible_v<fitx::result<int, int>, fitx::error<nothing>>); | 
|  |  | 
|  | static_assert(!std::is_constructible_v<fitx::result<fitx::failed>>); | 
|  | static_assert(std::is_constructible_v<fitx::result<fitx::failed>, fitx::success<>>); | 
|  | static_assert(std::is_constructible_v<fitx::result<fitx::failed>, fitx::failed>); | 
|  | static_assert(!std::is_constructible_v<fitx::result<fitx::failed>, nothing>); | 
|  | static_assert(!std::is_constructible_v<fitx::result<fitx::failed>, fitx::success<nothing>>); | 
|  | static_assert(!std::is_constructible_v<fitx::result<fitx::failed>, fitx::error<int>>); | 
|  | static_assert(!std::is_constructible_v<fitx::result<fitx::failed>, fitx::error<nothing>>); | 
|  | static_assert(std::is_constructible_v<fitx::result<fitx::failed>, fitx::error<fitx::failed>>); | 
|  |  | 
|  | static_assert(!std::is_constructible_v<fitx::result<fitx::failed, int>>); | 
|  | static_assert(!std::is_constructible_v<fitx::result<fitx::failed, int>, fitx::success<>>); | 
|  | static_assert(std::is_constructible_v<fitx::result<fitx::failed, int>, fitx::failed>); | 
|  | static_assert(!std::is_constructible_v<fitx::result<fitx::failed, int>, int>); | 
|  | static_assert(std::is_constructible_v<fitx::result<fitx::failed, int>, fitx::success<int>>); | 
|  | static_assert(!std::is_constructible_v<fitx::result<fitx::failed, int>, nothing>); | 
|  | static_assert(!std::is_constructible_v<fitx::result<fitx::failed, int>, fitx::success<nothing>>); | 
|  | static_assert(!std::is_constructible_v<fitx::result<fitx::failed, int>, fitx::error<int>>); | 
|  | static_assert(!std::is_constructible_v<fitx::result<fitx::failed, int>, fitx::error<nothing>>); | 
|  | static_assert(std::is_constructible_v<fitx::result<fitx::failed, int>, fitx::error<fitx::failed>>); | 
|  |  | 
|  | #if 0 || TEST_DOES_NOT_COMPILE | 
|  | static_assert(fitx::result<fitx::success<>>{}); | 
|  | static_assert(fitx::result<int, fitx::failed>{}); | 
|  | #endif | 
|  |  | 
|  | static_assert(fitx::result<fitx::failed>{fitx::ok()}.is_ok() == true); | 
|  | static_assert(fitx::result<fitx::failed>{fitx::ok()}.is_error() == false); | 
|  | static_assert(fitx::result<fitx::failed>{fitx::failed()}.is_ok() == false); | 
|  | static_assert(fitx::result<fitx::failed>{fitx::failed()}.is_error() == true); | 
|  |  | 
|  | static_assert(fitx::result<int>{fitx::ok()}.is_ok() == true); | 
|  | static_assert(fitx::result<int>{fitx::ok()}.is_error() == false); | 
|  | static_assert(fitx::result<int>{fitx::error(0)}.is_ok() == false); | 
|  | static_assert(fitx::result<int>{fitx::error(0)}.is_error() == true); | 
|  |  | 
|  | static_assert(fitx::result<int, int>{fitx::ok(10)}.is_ok() == true); | 
|  | static_assert(fitx::result<int, int>{fitx::ok(10)}.is_error() == false); | 
|  | static_assert(fitx::result<int, int>{fitx::ok(10)}.value() == 10); | 
|  | static_assert(fitx::result<int, int>{fitx::ok(10)}.value_or(20) == 10); | 
|  | static_assert(fitx::result<int, int>{fitx::error(10)}.is_ok() == false); | 
|  | static_assert(fitx::result<int, int>{fitx::error(10)}.is_error() == true); | 
|  | static_assert(fitx::result<int, int>{fitx::error(10)}.error_value() == 10); | 
|  | static_assert(fitx::result<int, int>{fitx::error(10)}.value_or(20) == 20); | 
|  |  | 
|  | // Agumenting errors. | 
|  | struct augmented_error { | 
|  | struct yes {}; | 
|  | struct no {}; | 
|  |  | 
|  | // Error can be augmented by type yes but not type no. | 
|  | constexpr void operator+=(yes) {} | 
|  | }; | 
|  |  | 
|  | template <typename T> | 
|  | constexpr bool agument_compiles() { | 
|  | { | 
|  | fitx::result<augmented_error> result = fitx::error<augmented_error>(); | 
|  | result += fitx::error<T>(); | 
|  | } | 
|  | { | 
|  | fitx::result<augmented_error, int> result = fitx::error<augmented_error>(); | 
|  | result += fitx::error<T>(); | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | static_assert(agument_compiles<augmented_error::yes>()); | 
|  | #if 0 || TEST_DOES_NOT_COMPILE | 
|  | static_assert(agument_compiles<augmented_error::no>()); | 
|  | #endif | 
|  |  | 
|  | // Arrow operator and arrow operator forwarding. | 
|  | struct test_members { | 
|  | int a; | 
|  | int b; | 
|  | }; | 
|  |  | 
|  | static_assert(fitx::result<fitx::failed, test_members> { zx::ok(test_members{10, 20}) }->a == 10); | 
|  | static_assert(fitx::result<fitx::failed, test_members> { zx::ok(test_members{10, 20}) }->b == 20); | 
|  | static_assert(fitx::result<fitx::failed, std::optional<test_members>> { | 
|  | zx::ok(test_members{10, 20}) | 
|  | }->a == 10); | 
|  | static_assert(fitx::result<fitx::failed, std::optional<test_members>> { | 
|  | zx::ok(test_members{10, 20}) | 
|  | }->b == 20); | 
|  |  | 
|  | // Status-only, no value. | 
|  | static_assert(zx::status<>{zx::ok()}.is_ok() == true); | 
|  | static_assert(zx::status<>{zx::ok()}.is_error() == false); | 
|  | static_assert(zx::status<>{zx::ok()}.status_value() == ZX_OK); | 
|  |  | 
|  | static_assert(zx::status<>{zx::error{ZX_ERR_INVALID_ARGS}}.is_ok() == false); | 
|  | static_assert(zx::status<>{zx::error{ZX_ERR_INVALID_ARGS}}.is_error() == true); | 
|  | static_assert(zx::status<>{zx::error{ZX_ERR_INVALID_ARGS}}.error_value() == ZX_ERR_INVALID_ARGS); | 
|  | static_assert(zx::status<>{zx::error{ZX_ERR_INVALID_ARGS}}.status_value() == ZX_ERR_INVALID_ARGS); | 
|  |  | 
|  | static_assert(zx::status<>{zx::make_status(ZX_OK)}.is_ok() == true); | 
|  | static_assert(zx::status<>{zx::make_status(ZX_OK)}.is_error() == false); | 
|  | static_assert(zx::status<>{zx::make_status(ZX_OK)}.status_value() == ZX_OK); | 
|  |  | 
|  | static_assert(zx::status<>{zx::make_status(ZX_ERR_INVALID_ARGS)}.is_ok() == false); | 
|  | static_assert(zx::status<>{zx::make_status(ZX_ERR_INVALID_ARGS)}.is_error() == true); | 
|  | static_assert(zx::status<>{zx::make_status(ZX_ERR_INVALID_ARGS)}.error_value() == | 
|  | ZX_ERR_INVALID_ARGS); | 
|  | static_assert(zx::status<>{zx::make_status(ZX_ERR_INVALID_ARGS)}.status_value() == | 
|  | ZX_ERR_INVALID_ARGS); | 
|  |  | 
|  | // Status or value. | 
|  | static_assert(zx::status<int>{zx::ok(10)}.is_ok() == true); | 
|  | static_assert(zx::status<int>{zx::ok(10)}.is_error() == false); | 
|  | static_assert(zx::status<int>{zx::ok(10)}.status_value() == ZX_OK); | 
|  | static_assert(zx::status<int>{zx::ok(10)}.value() == 10); | 
|  |  | 
|  | static_assert(zx::status<int>{zx::error{ZX_ERR_INVALID_ARGS}}.is_ok() == false); | 
|  | static_assert(zx::status<int>{zx::error{ZX_ERR_INVALID_ARGS}}.is_error() == true); | 
|  | static_assert(zx::status<int>{zx::error{ZX_ERR_INVALID_ARGS}}.error_value() == ZX_ERR_INVALID_ARGS); | 
|  | static_assert(zx::status<int>{zx::error{ZX_ERR_INVALID_ARGS}}.status_value() == | 
|  | ZX_ERR_INVALID_ARGS); | 
|  |  | 
|  | struct default_constructible { | 
|  | default_constructible() = default; | 
|  | }; | 
|  |  | 
|  | struct non_default_constructible { | 
|  | non_default_constructible() = delete; | 
|  | non_default_constructible(int) {} | 
|  | }; | 
|  |  | 
|  | struct copyable { | 
|  | copyable() = default; | 
|  | copyable(const copyable&) = default; | 
|  | copyable& operator=(const copyable&) = default; | 
|  | copyable(copyable&&) noexcept = default; | 
|  | copyable& operator=(copyable&&) noexcept = default; | 
|  | }; | 
|  |  | 
|  | static_assert(std::is_copy_constructible_v<copyable>); | 
|  | static_assert(std::is_move_constructible_v<copyable>); | 
|  | static_assert(std::is_nothrow_move_constructible_v<copyable>); | 
|  |  | 
|  | struct move_only { | 
|  | move_only() = default; | 
|  | move_only(const move_only&) = delete; | 
|  | move_only& operator=(const move_only&) = delete; | 
|  | move_only(move_only&&) noexcept = default; | 
|  | move_only& operator=(move_only&&) noexcept = default; | 
|  | }; | 
|  |  | 
|  | static_assert(!std::is_copy_constructible_v<move_only>); | 
|  | static_assert(std::is_move_constructible_v<move_only>); | 
|  | static_assert(std::is_nothrow_move_constructible_v<move_only>); | 
|  |  | 
|  | struct trivial { | 
|  | trivial() = default; | 
|  | ~trivial() = default; | 
|  | }; | 
|  |  | 
|  | static_assert(std::is_trivially_constructible_v<trivial, trivial>); | 
|  | static_assert(std::is_trivially_copy_constructible_v<trivial>); | 
|  | static_assert(std::is_trivially_move_constructible_v<trivial>); | 
|  | static_assert(std::is_trivially_destructible_v<trivial>); | 
|  |  | 
|  | struct non_trivial { | 
|  | non_trivial() {} | 
|  | ~non_trivial() {} | 
|  | }; | 
|  |  | 
|  | static_assert(!std::is_trivially_constructible_v<non_trivial, non_trivial>); | 
|  | static_assert(!std::is_trivially_copy_constructible_v<non_trivial>); | 
|  | static_assert(!std::is_trivially_move_constructible_v<non_trivial>); | 
|  | static_assert(!std::is_trivially_destructible_v<non_trivial>); | 
|  |  | 
|  | struct non_trivial_copyable : copyable, non_trivial {}; | 
|  |  | 
|  | static_assert(!std::is_trivially_constructible_v<non_trivial_copyable, non_trivial_copyable>); | 
|  | static_assert(!std::is_trivially_copy_constructible_v<non_trivial_copyable>); | 
|  | static_assert(!std::is_trivially_move_constructible_v<non_trivial_copyable>); | 
|  | static_assert(!std::is_trivially_destructible_v<non_trivial_copyable>); | 
|  |  | 
|  | // Assert that fitx::result maintains the properties common to its error and | 
|  | // value types. | 
|  | static_assert(std::is_trivially_copy_constructible_v<fitx::result<trivial, trivial>>); | 
|  | static_assert(!std::is_trivially_copy_constructible_v<fitx::result<trivial, non_trivial>>); | 
|  | static_assert(!std::is_trivially_copy_constructible_v<fitx::result<non_trivial, trivial>>); | 
|  | static_assert(!std::is_trivially_copy_constructible_v<fitx::result<non_trivial, non_trivial>>); | 
|  |  | 
|  | static_assert(std::is_trivially_move_constructible_v<fitx::result<trivial, trivial>>); | 
|  | static_assert(!std::is_trivially_move_constructible_v<fitx::result<trivial, non_trivial>>); | 
|  | static_assert(!std::is_trivially_move_constructible_v<fitx::result<non_trivial, trivial>>); | 
|  | static_assert(!std::is_trivially_move_constructible_v<fitx::result<non_trivial, non_trivial>>); | 
|  |  | 
|  | static_assert(std::is_trivially_destructible_v<fitx::result<trivial, trivial>>); | 
|  | static_assert(!std::is_trivially_destructible_v<fitx::result<trivial, non_trivial>>); | 
|  | static_assert(!std::is_trivially_destructible_v<fitx::result<non_trivial, trivial>>); | 
|  | static_assert(!std::is_trivially_destructible_v<fitx::result<non_trivial, non_trivial>>); | 
|  |  | 
|  | static_assert( | 
|  | !std::is_default_constructible_v<fitx::result<default_constructible, default_constructible>>); | 
|  | static_assert(!std::is_default_constructible_v< | 
|  | fitx::result<default_constructible, non_default_constructible>>); | 
|  | static_assert(!std::is_default_constructible_v< | 
|  | fitx::result<non_default_constructible, default_constructible>>); | 
|  | static_assert(!std::is_default_constructible_v< | 
|  | fitx::result<non_default_constructible, non_default_constructible>>); | 
|  |  | 
|  | static_assert(std::is_copy_constructible_v<fitx::result<copyable, copyable>>); | 
|  | static_assert(!std::is_copy_constructible_v<fitx::result<copyable, move_only>>); | 
|  | static_assert(!std::is_copy_constructible_v<fitx::result<move_only, copyable>>); | 
|  | static_assert(!std::is_copy_constructible_v<fitx::result<move_only, move_only>>); | 
|  | static_assert( | 
|  | std::is_copy_constructible_v<fitx::result<non_trivial_copyable, non_trivial_copyable>>); | 
|  |  | 
|  | static_assert(std::is_trivially_copy_constructible_v<fitx::result<trivial, trivial>>); | 
|  | static_assert(!std::is_trivially_copy_constructible_v<fitx::result<trivial, non_trivial>>); | 
|  | static_assert(!std::is_trivially_copy_constructible_v<fitx::result<non_trivial, trivial>>); | 
|  | static_assert(!std::is_trivially_copy_constructible_v<fitx::result<non_trivial, non_trivial>>); | 
|  | static_assert(!std::is_trivially_copy_constructible_v< | 
|  | fitx::result<non_trivial_copyable, non_trivial_copyable>>); | 
|  |  | 
|  | static_assert(std::is_move_constructible_v<fitx::result<copyable, copyable>>); | 
|  | static_assert(std::is_move_constructible_v<fitx::result<copyable, move_only>>); | 
|  | static_assert(std::is_move_constructible_v<fitx::result<move_only, copyable>>); | 
|  | static_assert(std::is_move_constructible_v<fitx::result<move_only, move_only>>); | 
|  | static_assert( | 
|  | std::is_move_constructible_v<fitx::result<non_trivial_copyable, non_trivial_copyable>>); | 
|  |  | 
|  | static_assert(std::is_nothrow_move_constructible_v<fitx::result<copyable, copyable>>); | 
|  | static_assert(std::is_nothrow_move_constructible_v<fitx::result<copyable, move_only>>); | 
|  | static_assert(std::is_nothrow_move_constructible_v<fitx::result<move_only, copyable>>); | 
|  | static_assert(std::is_nothrow_move_constructible_v<fitx::result<move_only, move_only>>); | 
|  | static_assert( | 
|  | std::is_nothrow_move_constructible_v<fitx::result<non_trivial_copyable, non_trivial_copyable>>); | 
|  |  | 
|  | static_assert(std::is_trivially_move_constructible_v<fitx::result<trivial, trivial>>); | 
|  | static_assert(!std::is_trivially_move_constructible_v<fitx::result<trivial, non_trivial>>); | 
|  | static_assert(!std::is_trivially_move_constructible_v<fitx::result<non_trivial, trivial>>); | 
|  | static_assert(!std::is_trivially_move_constructible_v<fitx::result<non_trivial, non_trivial>>); | 
|  | static_assert(!std::is_trivially_move_constructible_v< | 
|  | fitx::result<non_trivial_copyable, non_trivial_copyable>>); | 
|  |  | 
|  | // Assert that fitx::error maintains the properties of its error type. | 
|  | static_assert(std::is_trivially_copy_constructible_v<fitx::error<trivial>>); | 
|  | static_assert(!std::is_trivially_copy_constructible_v<fitx::error<non_trivial>>); | 
|  |  | 
|  | static_assert(std::is_trivially_move_constructible_v<fitx::error<trivial>>); | 
|  | static_assert(!std::is_trivially_move_constructible_v<fitx::error<non_trivial>>); | 
|  |  | 
|  | static_assert(std::is_trivially_destructible_v<fitx::error<trivial>>); | 
|  | static_assert(!std::is_trivially_destructible_v<fitx::error<non_trivial>>); | 
|  |  | 
|  | static_assert(std::is_default_constructible_v<fitx::error<default_constructible>>); | 
|  | static_assert(!std::is_default_constructible_v<fitx::error<non_default_constructible>>); | 
|  |  | 
|  | static_assert(std::is_copy_constructible_v<fitx::error<copyable>>); | 
|  | static_assert(!std::is_copy_constructible_v<fitx::error<move_only>>); | 
|  |  | 
|  | static_assert(std::is_trivially_copy_constructible_v<fitx::error<trivial>>); | 
|  | static_assert(!std::is_trivially_copy_constructible_v<fitx::error<non_trivial>>); | 
|  |  | 
|  | static_assert(std::is_move_constructible_v<fitx::error<copyable>>); | 
|  | static_assert(std::is_move_constructible_v<fitx::error<move_only>>); | 
|  |  | 
|  | static_assert(std::is_nothrow_move_constructible_v<fitx::error<copyable>>); | 
|  | static_assert(std::is_nothrow_move_constructible_v<fitx::error<move_only>>); | 
|  |  | 
|  | static_assert(std::is_trivially_move_constructible_v<fitx::error<trivial>>); | 
|  | static_assert(!std::is_trivially_move_constructible_v<fitx::error<non_trivial>>); | 
|  |  | 
|  | namespace comparison_tests { | 
|  |  | 
|  | struct greater {}; | 
|  | struct less {}; | 
|  | struct empty {}; | 
|  |  | 
|  | constexpr bool operator==(greater, greater) { return true; } | 
|  | constexpr bool operator<=(greater, greater) { return true; } | 
|  | constexpr bool operator>=(greater, greater) { return true; } | 
|  | constexpr bool operator!=(greater, greater) { return false; } | 
|  | constexpr bool operator<(greater, greater) { return false; } | 
|  | constexpr bool operator>(greater, greater) { return false; } | 
|  |  | 
|  | constexpr bool operator==(less, less) { return true; } | 
|  | constexpr bool operator<=(less, less) { return true; } | 
|  | constexpr bool operator>=(less, less) { return true; } | 
|  | constexpr bool operator!=(less, less) { return false; } | 
|  | constexpr bool operator<(less, less) { return false; } | 
|  | constexpr bool operator>(less, less) { return false; } | 
|  |  | 
|  | constexpr bool operator==(greater, less) { return false; } | 
|  | constexpr bool operator<=(greater, less) { return false; } | 
|  | constexpr bool operator>=(greater, less) { return true; } | 
|  | constexpr bool operator!=(greater, less) { return true; } | 
|  | constexpr bool operator<(greater, less) { return false; } | 
|  | constexpr bool operator>(greater, less) { return true; } | 
|  |  | 
|  | constexpr bool operator==(less, greater) { return false; } | 
|  | constexpr bool operator<=(less, greater) { return true; } | 
|  | constexpr bool operator>=(less, greater) { return false; } | 
|  | constexpr bool operator!=(less, greater) { return true; } | 
|  | constexpr bool operator<(less, greater) { return true; } | 
|  | constexpr bool operator>(less, greater) { return false; } | 
|  |  | 
|  | // Note these definitions match the empty-to-other, other-to-empty, and | 
|  | // empty-to-empty comparison behavior of fitx::result for convenience in | 
|  | // exhaustive testing. | 
|  | constexpr bool operator==(empty, greater) { return false; } | 
|  | constexpr bool operator<=(empty, greater) { return true; } | 
|  | constexpr bool operator>=(empty, greater) { return false; } | 
|  | constexpr bool operator!=(empty, greater) { return true; } | 
|  | constexpr bool operator<(empty, greater) { return true; } | 
|  | constexpr bool operator>(empty, greater) { return false; } | 
|  |  | 
|  | constexpr bool operator==(greater, empty) { return false; } | 
|  | constexpr bool operator<=(greater, empty) { return false; } | 
|  | constexpr bool operator>=(greater, empty) { return true; } | 
|  | constexpr bool operator!=(greater, empty) { return true; } | 
|  | constexpr bool operator<(greater, empty) { return false; } | 
|  | constexpr bool operator>(greater, empty) { return true; } | 
|  |  | 
|  | constexpr bool operator==(empty, less) { return false; } | 
|  | constexpr bool operator<=(empty, less) { return true; } | 
|  | constexpr bool operator>=(empty, less) { return false; } | 
|  | constexpr bool operator!=(empty, less) { return true; } | 
|  | constexpr bool operator<(empty, less) { return true; } | 
|  | constexpr bool operator>(empty, less) { return false; } | 
|  |  | 
|  | constexpr bool operator==(less, empty) { return false; } | 
|  | constexpr bool operator<=(less, empty) { return false; } | 
|  | constexpr bool operator>=(less, empty) { return true; } | 
|  | constexpr bool operator!=(less, empty) { return true; } | 
|  | constexpr bool operator<(less, empty) { return false; } | 
|  | constexpr bool operator>(less, empty) { return true; } | 
|  |  | 
|  | constexpr bool operator==(empty, empty) { return true; } | 
|  | constexpr bool operator<=(empty, empty) { return true; } | 
|  | constexpr bool operator>=(empty, empty) { return true; } | 
|  | constexpr bool operator!=(empty, empty) { return false; } | 
|  | constexpr bool operator<(empty, empty) { return false; } | 
|  | constexpr bool operator>(empty, empty) { return false; } | 
|  |  | 
|  | template <typename T, typename U> | 
|  | constexpr bool match_comparisons(T, U) { | 
|  | constexpr T lhs{}; | 
|  | constexpr U rhs{}; | 
|  |  | 
|  | constexpr fitx::result<empty, T> ok_lhs{fitx::ok(lhs)}; | 
|  | constexpr fitx::result<empty, U> ok_rhs{fitx::ok(rhs)}; | 
|  | constexpr fitx::result<empty, T> error_lhs{fitx::error(empty{})}; | 
|  | constexpr fitx::result<empty, U> error_rhs{fitx::error(empty{})}; | 
|  |  | 
|  | // Both result operands. | 
|  | static_assert((ok_lhs == ok_rhs) == (lhs == rhs)); | 
|  | static_assert((ok_lhs != ok_rhs) == (lhs != rhs)); | 
|  | static_assert((ok_lhs <= ok_rhs) == (lhs <= rhs)); | 
|  | static_assert((ok_lhs >= ok_rhs) == (lhs >= rhs)); | 
|  | static_assert((ok_lhs < ok_rhs) == (lhs < rhs)); | 
|  | static_assert((ok_lhs > ok_rhs) == (lhs > rhs)); | 
|  |  | 
|  | static_assert((error_lhs == ok_rhs) == (empty{} == rhs)); | 
|  | static_assert((error_lhs != ok_rhs) == (empty{} != rhs)); | 
|  | static_assert((error_lhs <= ok_rhs) == (empty{} <= rhs)); | 
|  | static_assert((error_lhs >= ok_rhs) == (empty{} >= rhs)); | 
|  | static_assert((error_lhs < ok_rhs) == (empty{} < rhs)); | 
|  | static_assert((error_lhs > ok_rhs) == (empty{} > rhs)); | 
|  |  | 
|  | static_assert((ok_lhs == error_rhs) == (lhs == empty{})); | 
|  | static_assert((ok_lhs != error_rhs) == (lhs != empty{})); | 
|  | static_assert((ok_lhs <= error_rhs) == (lhs <= empty{})); | 
|  | static_assert((ok_lhs >= error_rhs) == (lhs >= empty{})); | 
|  | static_assert((ok_lhs < error_rhs) == (lhs < empty{})); | 
|  | static_assert((ok_lhs > error_rhs) == (lhs > empty{})); | 
|  |  | 
|  | static_assert((error_lhs == error_rhs) == (empty{} == empty{})); | 
|  | static_assert((error_lhs != error_rhs) == (empty{} != empty{})); | 
|  | static_assert((error_lhs <= error_rhs) == (empty{} <= empty{})); | 
|  | static_assert((error_lhs >= error_rhs) == (empty{} >= empty{})); | 
|  | static_assert((error_lhs < error_rhs) == (empty{} < empty{})); | 
|  | static_assert((error_lhs > error_rhs) == (empty{} > empty{})); | 
|  |  | 
|  | // Right hand result only. | 
|  | static_assert((lhs == ok_rhs) == (lhs == rhs)); | 
|  | static_assert((lhs != ok_rhs) == (lhs != rhs)); | 
|  | static_assert((lhs <= ok_rhs) == (lhs <= rhs)); | 
|  | static_assert((lhs >= ok_rhs) == (lhs >= rhs)); | 
|  | static_assert((lhs < ok_rhs) == (lhs < rhs)); | 
|  | static_assert((lhs > ok_rhs) == (lhs > rhs)); | 
|  |  | 
|  | static_assert((lhs == error_rhs) == (lhs == empty{})); | 
|  | static_assert((lhs != error_rhs) == (lhs != empty{})); | 
|  | static_assert((lhs <= error_rhs) == (lhs <= empty{})); | 
|  | static_assert((lhs >= error_rhs) == (lhs >= empty{})); | 
|  | static_assert((lhs < error_rhs) == (lhs < empty{})); | 
|  | static_assert((lhs > error_rhs) == (lhs > empty{})); | 
|  |  | 
|  | // Left hand result only. | 
|  | static_assert((ok_lhs == rhs) == (lhs == rhs)); | 
|  | static_assert((ok_lhs != rhs) == (lhs != rhs)); | 
|  | static_assert((ok_lhs <= rhs) == (lhs <= rhs)); | 
|  | static_assert((ok_lhs >= rhs) == (lhs >= rhs)); | 
|  | static_assert((ok_lhs < rhs) == (lhs < rhs)); | 
|  | static_assert((ok_lhs > rhs) == (lhs > rhs)); | 
|  |  | 
|  | static_assert((error_lhs == rhs) == (empty{} == rhs)); | 
|  | static_assert((error_lhs != rhs) == (empty{} != rhs)); | 
|  | static_assert((error_lhs <= rhs) == (empty{} <= rhs)); | 
|  | static_assert((error_lhs >= rhs) == (empty{} >= rhs)); | 
|  | static_assert((error_lhs < rhs) == (empty{} < rhs)); | 
|  | static_assert((error_lhs > rhs) == (empty{} > rhs)); | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | static_assert(match_comparisons(greater{}, greater{})); | 
|  | static_assert(match_comparisons(greater{}, less{})); | 
|  | static_assert(match_comparisons(less{}, greater{})); | 
|  | static_assert(match_comparisons(less{}, less{})); | 
|  |  | 
|  | }  // namespace comparison_tests | 
|  |  | 
|  | #if defined(__Fuchsia__) | 
|  |  | 
|  | TEST(LibZxCommon, Abort) { | 
|  | // Validate that accessing the error of a non-error result aborts. | 
|  | ASSERT_DEATH(([] { | 
|  | fitx::result<nothing, int> result{fitx::ok(10)}; | 
|  | EXPECT_FALSE(result.is_error()); | 
|  | EXPECT_TRUE(result.is_ok()); | 
|  | result.error_value(); | 
|  | })); | 
|  | ASSERT_DEATH(([] { | 
|  | const fitx::result<nothing, int> result{fitx::ok(10)}; | 
|  | EXPECT_FALSE(result.is_error()); | 
|  | EXPECT_TRUE(result.is_ok()); | 
|  | result.error_value(); | 
|  | })); | 
|  | ASSERT_DEATH(([] { | 
|  | fitx::result<nothing, int> result{fitx::ok(10)}; | 
|  | EXPECT_FALSE(result.is_error()); | 
|  | EXPECT_TRUE(result.is_ok()); | 
|  | result.take_error(); | 
|  | })); | 
|  |  | 
|  | // Validate that accessing the value of an error result aborts. | 
|  | ASSERT_DEATH(([] { | 
|  | fitx::result<nothing, int> result{fitx::error(nothing{})}; | 
|  | EXPECT_TRUE(result.is_error()); | 
|  | EXPECT_FALSE(result.is_ok()); | 
|  | result.value(); | 
|  | })); | 
|  | ASSERT_DEATH(([] { | 
|  | const fitx::result<nothing, int> result{fitx::error(nothing{})}; | 
|  | EXPECT_TRUE(result.is_error()); | 
|  | EXPECT_FALSE(result.is_ok()); | 
|  | result.value(); | 
|  | })); | 
|  | ASSERT_DEATH(([] { | 
|  | fitx::result<nothing, int> result{fitx::error(nothing{})}; | 
|  | EXPECT_TRUE(result.is_error()); | 
|  | EXPECT_FALSE(result.is_ok()); | 
|  | std::move(result).value(); | 
|  | })); | 
|  | ASSERT_DEATH(([] { | 
|  | const fitx::result<nothing, int> result{fitx::error(nothing{})}; | 
|  | EXPECT_TRUE(result.is_error()); | 
|  | EXPECT_FALSE(result.is_ok()); | 
|  | std::move(result).value(); | 
|  | })); | 
|  | ASSERT_DEATH(([] { | 
|  | fitx::result<nothing, test_members> result{fitx::error(nothing{})}; | 
|  | EXPECT_TRUE(result.is_error()); | 
|  | EXPECT_FALSE(result.is_ok()); | 
|  | (void)result->a; | 
|  | })); | 
|  | ASSERT_DEATH(([] { | 
|  | const fitx::result<nothing, test_members> result{fitx::error(nothing{})}; | 
|  | EXPECT_TRUE(result.is_error()); | 
|  | EXPECT_FALSE(result.is_ok()); | 
|  | (void)result->a; | 
|  | })); | 
|  | ASSERT_DEATH(([] { | 
|  | fitx::result<nothing, std::optional<test_members>> result{fitx::error(nothing{})}; | 
|  | EXPECT_TRUE(result.is_error()); | 
|  | EXPECT_FALSE(result.is_ok()); | 
|  | (void)result->a; | 
|  | })); | 
|  | ASSERT_DEATH(([] { | 
|  | const fitx::result<nothing, std::optional<test_members>> result{fitx::error(nothing{})}; | 
|  | EXPECT_TRUE(result.is_error()); | 
|  | EXPECT_FALSE(result.is_ok()); | 
|  | (void)result->a; | 
|  | })); | 
|  |  | 
|  | // Validate that attempting to use ZX_OK as an explicit error aborts. | 
|  | ASSERT_DEATH(([] { | 
|  | zx::status<> status{zx::error_status(ZX_OK)}; | 
|  | (void)status; | 
|  | })); | 
|  |  | 
|  | // Validate that forwarding ZX_OK does not abort. | 
|  | ASSERT_NO_DEATH(([] { | 
|  | zx::status<> status{zx::make_status(ZX_OK)}; | 
|  | EXPECT_FALSE(status.is_error()); | 
|  | EXPECT_TRUE(status.is_ok()); | 
|  | })); | 
|  |  | 
|  | // Validate that accessing the error of a non-error zx::status through | 
|  | // status_value() does not abort. | 
|  | ASSERT_NO_DEATH(([] { | 
|  | zx::status<int> status{zx::ok(10)}; | 
|  | EXPECT_FALSE(status.is_error()); | 
|  | EXPECT_TRUE(status.is_ok()); | 
|  | EXPECT_EQ(ZX_OK, status.status_value()); | 
|  | })); | 
|  | ASSERT_NO_DEATH(([] { | 
|  | const zx::status<int> status{zx::ok(10)}; | 
|  | EXPECT_FALSE(status.is_error()); | 
|  | EXPECT_TRUE(status.is_ok()); | 
|  | EXPECT_EQ(ZX_OK, status.status_value()); | 
|  | })); | 
|  |  | 
|  | // Validate the other error accessors abort. | 
|  | ASSERT_DEATH(([] { | 
|  | zx::status<int> status{zx::ok(10)}; | 
|  | EXPECT_FALSE(status.is_error()); | 
|  | EXPECT_TRUE(status.is_ok()); | 
|  | EXPECT_EQ(ZX_OK, status.error_value()); | 
|  | })); | 
|  | ASSERT_DEATH(([] { | 
|  | const zx::status<int> status{zx::ok(10)}; | 
|  | EXPECT_FALSE(status.is_error()); | 
|  | EXPECT_TRUE(status.is_ok()); | 
|  | EXPECT_EQ(ZX_OK, status.error_value()); | 
|  | })); | 
|  | ASSERT_DEATH(([] { | 
|  | zx::status<int> status{zx::ok(10)}; | 
|  | EXPECT_FALSE(status.is_error()); | 
|  | EXPECT_TRUE(status.is_ok()); | 
|  | status.take_error(); | 
|  | })); | 
|  | } | 
|  |  | 
|  | #endif  // defined(__Fuchsia__) | 
|  |  | 
|  | // Validate copy/move construction and assignment. | 
|  | enum non_default_t { non_default_v }; | 
|  |  | 
|  | template <size_t index> | 
|  | struct counter { | 
|  | counter() { default_constructor_count++; } | 
|  |  | 
|  | counter(non_default_t) { non_default_constructor_count++; } | 
|  |  | 
|  | counter(const counter&) { copy_constructor_count++; } | 
|  | counter& operator=(const counter&) { | 
|  | copy_assignment_count++; | 
|  | return *this; | 
|  | } | 
|  |  | 
|  | counter(counter&&) noexcept { move_constructor_count++; } | 
|  | counter& operator=(counter&&) noexcept { | 
|  | move_assignment_count++; | 
|  | return *this; | 
|  | } | 
|  |  | 
|  | ~counter() { destructor_count++; } | 
|  |  | 
|  | static void reset() { | 
|  | default_constructor_count = 0; | 
|  | non_default_constructor_count = 0; | 
|  | copy_constructor_count = 0; | 
|  | copy_assignment_count = 0; | 
|  | move_constructor_count = 0; | 
|  | move_assignment_count = 0; | 
|  | destructor_count = 0; | 
|  | } | 
|  |  | 
|  | static int constructor_count() { | 
|  | return default_constructor_count + non_default_constructor_count + copy_constructor_count + | 
|  | move_constructor_count; | 
|  | } | 
|  | static int assignment_count() { return copy_assignment_count + move_assignment_count; } | 
|  | static int alive_count() { return constructor_count() - destructor_count; } | 
|  |  | 
|  | inline static int default_constructor_count{0}; | 
|  | inline static int non_default_constructor_count{0}; | 
|  | inline static int copy_constructor_count{0}; | 
|  | inline static int copy_assignment_count{0}; | 
|  | inline static int move_constructor_count{0}; | 
|  | inline static int move_assignment_count{0}; | 
|  | inline static int destructor_count{0}; | 
|  | }; | 
|  |  | 
|  | using counter_a = counter<0>; | 
|  | using counter_b = counter<1>; | 
|  |  | 
|  | fitx::result<counter_a, counter_b> get_values() { return fitx::ok(counter_b{non_default_v}); } | 
|  | fitx::result<counter_a, counter_b> get_error() { return fitx::error(non_default_v); } | 
|  |  | 
|  | TEST(LibZxCommon, BasicConstructorDestructor) { | 
|  | counter_a::reset(); | 
|  | counter_b::reset(); | 
|  |  | 
|  | { | 
|  | auto result = get_values(); | 
|  |  | 
|  | EXPECT_EQ(0, counter_a::constructor_count()); | 
|  | EXPECT_EQ(0, counter_a::alive_count()); | 
|  |  | 
|  | EXPECT_EQ(0, counter_b::default_constructor_count); | 
|  | EXPECT_NE(0, counter_b::constructor_count()); | 
|  | EXPECT_NE(0, counter_b::alive_count()); | 
|  | } | 
|  |  | 
|  | EXPECT_EQ(0, counter_a::constructor_count()); | 
|  | EXPECT_EQ(0, counter_a::alive_count()); | 
|  |  | 
|  | EXPECT_NE(0, counter_b::constructor_count()); | 
|  | EXPECT_EQ(0, counter_b::alive_count()); | 
|  |  | 
|  | counter_a::reset(); | 
|  | counter_b::reset(); | 
|  | } | 
|  |  | 
|  | TEST(LibZxCommon, Accessors) { | 
|  | counter_a::reset(); | 
|  | counter_b::reset(); | 
|  |  | 
|  | { | 
|  | auto result = get_values(); | 
|  | auto b = result.value(); | 
|  |  | 
|  | static_assert(std::is_same_v<decltype(b), counter_b>); | 
|  | static_assert(std::is_same_v<decltype(result.value()), counter_b&>); | 
|  |  | 
|  | EXPECT_EQ(0, counter_a::constructor_count()); | 
|  | EXPECT_EQ(0, counter_a::alive_count()); | 
|  |  | 
|  | EXPECT_EQ(0, counter_b::default_constructor_count); | 
|  | EXPECT_NE(0, counter_b::constructor_count()); | 
|  | EXPECT_NE(0, counter_b::alive_count()); | 
|  | } | 
|  |  | 
|  | EXPECT_EQ(0, counter_a::constructor_count()); | 
|  | EXPECT_EQ(0, counter_a::alive_count()); | 
|  |  | 
|  | EXPECT_NE(0, counter_b::constructor_count()); | 
|  | EXPECT_EQ(0, counter_b::alive_count()); | 
|  |  | 
|  | counter_a::reset(); | 
|  | counter_b::reset(); | 
|  |  | 
|  | { | 
|  | const auto result = get_values(); | 
|  | auto b = result.value(); | 
|  |  | 
|  | static_assert(std::is_same_v<decltype(b), counter_b>); | 
|  | static_assert(std::is_same_v<decltype(result.value()), const counter_b&>); | 
|  |  | 
|  | EXPECT_EQ(0, counter_a::constructor_count()); | 
|  | EXPECT_EQ(0, counter_a::alive_count()); | 
|  |  | 
|  | EXPECT_EQ(0, counter_b::default_constructor_count); | 
|  | EXPECT_NE(0, counter_b::constructor_count()); | 
|  | EXPECT_NE(0, counter_b::alive_count()); | 
|  | } | 
|  |  | 
|  | EXPECT_EQ(0, counter_a::constructor_count()); | 
|  | EXPECT_EQ(0, counter_a::alive_count()); | 
|  |  | 
|  | EXPECT_NE(0, counter_b::constructor_count()); | 
|  | EXPECT_EQ(0, counter_b::alive_count()); | 
|  |  | 
|  | counter_a::reset(); | 
|  | counter_b::reset(); | 
|  |  | 
|  | { | 
|  | const auto& result = get_values(); | 
|  | auto b = result.value(); | 
|  |  | 
|  | static_assert(std::is_same_v<decltype(b), counter_b>); | 
|  | static_assert(std::is_same_v<decltype(result.value()), const counter_b&>); | 
|  |  | 
|  | EXPECT_EQ(0, counter_a::constructor_count()); | 
|  | EXPECT_EQ(0, counter_a::alive_count()); | 
|  |  | 
|  | EXPECT_EQ(0, counter_b::default_constructor_count); | 
|  | EXPECT_NE(0, counter_b::constructor_count()); | 
|  | EXPECT_NE(0, counter_b::alive_count()); | 
|  | } | 
|  |  | 
|  | EXPECT_EQ(0, counter_a::constructor_count()); | 
|  | EXPECT_EQ(0, counter_a::alive_count()); | 
|  |  | 
|  | EXPECT_NE(0, counter_b::constructor_count()); | 
|  | EXPECT_EQ(0, counter_b::alive_count()); | 
|  |  | 
|  | counter_a::reset(); | 
|  | counter_b::reset(); | 
|  |  | 
|  | { | 
|  | auto result = get_values(); | 
|  | auto b = std::move(result).value(); | 
|  |  | 
|  | static_assert(std::is_same_v<decltype(b), counter_b>); | 
|  | static_assert(std::is_same_v<decltype(std::move(result).value()), counter_b&&>); | 
|  |  | 
|  | EXPECT_EQ(0, counter_a::constructor_count()); | 
|  | EXPECT_EQ(0, counter_a::alive_count()); | 
|  |  | 
|  | EXPECT_EQ(0, counter_b::default_constructor_count); | 
|  | EXPECT_NE(0, counter_b::constructor_count()); | 
|  | EXPECT_NE(0, counter_b::alive_count()); | 
|  | } | 
|  |  | 
|  | EXPECT_EQ(0, counter_a::constructor_count()); | 
|  | EXPECT_EQ(0, counter_a::alive_count()); | 
|  |  | 
|  | EXPECT_NE(0, counter_b::constructor_count()); | 
|  | EXPECT_EQ(0, counter_b::alive_count()); | 
|  |  | 
|  | counter_a::reset(); | 
|  | counter_b::reset(); | 
|  |  | 
|  | { | 
|  | const auto result = get_values(); | 
|  | auto b = std::move(result).value(); | 
|  |  | 
|  | static_assert(std::is_same_v<decltype(b), counter_b>); | 
|  | static_assert(std::is_same_v<decltype(std::move(result).value()), const counter_b&&>); | 
|  |  | 
|  | EXPECT_EQ(0, counter_a::constructor_count()); | 
|  | EXPECT_EQ(0, counter_a::alive_count()); | 
|  |  | 
|  | EXPECT_EQ(0, counter_b::default_constructor_count); | 
|  | EXPECT_NE(0, counter_b::constructor_count()); | 
|  | EXPECT_NE(0, counter_b::alive_count()); | 
|  | } | 
|  |  | 
|  | EXPECT_EQ(0, counter_a::constructor_count()); | 
|  | EXPECT_EQ(0, counter_a::alive_count()); | 
|  |  | 
|  | EXPECT_NE(0, counter_b::constructor_count()); | 
|  | EXPECT_EQ(0, counter_b::alive_count()); | 
|  |  | 
|  | counter_a::reset(); | 
|  | counter_b::reset(); | 
|  |  | 
|  | { | 
|  | auto result = get_values(); | 
|  | auto b = result.take_value(); | 
|  |  | 
|  | static_assert(std::is_same_v<decltype(b), fitx::success<counter_b>>); | 
|  | static_assert(std::is_same_v<decltype(result.take_value()), fitx::success<counter_b>>); | 
|  |  | 
|  | EXPECT_EQ(0, counter_a::constructor_count()); | 
|  | EXPECT_EQ(0, counter_a::alive_count()); | 
|  |  | 
|  | EXPECT_EQ(0, counter_b::default_constructor_count); | 
|  | EXPECT_NE(0, counter_b::constructor_count()); | 
|  | EXPECT_NE(0, counter_b::alive_count()); | 
|  | } | 
|  |  | 
|  | EXPECT_EQ(0, counter_a::constructor_count()); | 
|  | EXPECT_EQ(0, counter_a::alive_count()); | 
|  |  | 
|  | EXPECT_NE(0, counter_b::constructor_count()); | 
|  | EXPECT_EQ(0, counter_b::alive_count()); | 
|  |  | 
|  | counter_a::reset(); | 
|  | counter_b::reset(); | 
|  | } | 
|  |  | 
|  | TEST(LibZxCommon, ErrorResults) { | 
|  | counter_a::reset(); | 
|  | counter_b::reset(); | 
|  |  | 
|  | { | 
|  | auto result = get_error(); | 
|  | auto error = result.error_value(); | 
|  |  | 
|  | static_assert(std::is_same_v<decltype(error), counter_a>); | 
|  |  | 
|  | EXPECT_EQ(0, counter_a::default_constructor_count); | 
|  | EXPECT_NE(0, counter_a::constructor_count()); | 
|  | EXPECT_NE(0, counter_a::alive_count()); | 
|  |  | 
|  | EXPECT_EQ(0, counter_b::constructor_count()); | 
|  | EXPECT_EQ(0, counter_b::alive_count()); | 
|  | } | 
|  |  | 
|  | EXPECT_NE(0, counter_a::constructor_count()); | 
|  | EXPECT_EQ(0, counter_a::alive_count()); | 
|  |  | 
|  | EXPECT_EQ(0, counter_b::constructor_count()); | 
|  | EXPECT_EQ(0, counter_b::alive_count()); | 
|  |  | 
|  | counter_a::reset(); | 
|  | counter_b::reset(); | 
|  |  | 
|  | { | 
|  | auto result = get_error(); | 
|  | auto& error = result.error_value(); | 
|  |  | 
|  | static_assert(std::is_same_v<decltype(error), counter_a&>); | 
|  |  | 
|  | EXPECT_EQ(0, counter_a::default_constructor_count); | 
|  | EXPECT_NE(0, counter_a::constructor_count()); | 
|  | EXPECT_NE(0, counter_a::alive_count()); | 
|  |  | 
|  | EXPECT_EQ(0, counter_b::constructor_count()); | 
|  | EXPECT_EQ(0, counter_b::alive_count()); | 
|  | } | 
|  |  | 
|  | EXPECT_NE(0, counter_a::constructor_count()); | 
|  | EXPECT_EQ(0, counter_a::alive_count()); | 
|  |  | 
|  | EXPECT_EQ(0, counter_b::constructor_count()); | 
|  | EXPECT_EQ(0, counter_b::alive_count()); | 
|  |  | 
|  | counter_a::reset(); | 
|  | counter_b::reset(); | 
|  |  | 
|  | { | 
|  | auto result = get_error(); | 
|  | const auto& error = result.error_value(); | 
|  |  | 
|  | static_assert(std::is_same_v<decltype(error), const counter_a&>); | 
|  |  | 
|  | EXPECT_EQ(0, counter_a::default_constructor_count); | 
|  | EXPECT_NE(0, counter_a::constructor_count()); | 
|  | EXPECT_NE(0, counter_a::alive_count()); | 
|  |  | 
|  | EXPECT_EQ(0, counter_b::constructor_count()); | 
|  | EXPECT_EQ(0, counter_b::alive_count()); | 
|  | } | 
|  |  | 
|  | EXPECT_NE(0, counter_a::constructor_count()); | 
|  | EXPECT_EQ(0, counter_a::alive_count()); | 
|  |  | 
|  | EXPECT_EQ(0, counter_b::constructor_count()); | 
|  | EXPECT_EQ(0, counter_b::alive_count()); | 
|  |  | 
|  | counter_a::reset(); | 
|  | counter_b::reset(); | 
|  |  | 
|  | { | 
|  | auto result = get_error(); | 
|  | auto error = result.take_error(); | 
|  |  | 
|  | static_assert(std::is_same_v<decltype(error), fitx::error<counter_a>>); | 
|  |  | 
|  | EXPECT_EQ(0, counter_a::default_constructor_count); | 
|  | EXPECT_NE(0, counter_a::constructor_count()); | 
|  | EXPECT_NE(0, counter_a::alive_count()); | 
|  |  | 
|  | EXPECT_EQ(0, counter_b::constructor_count()); | 
|  | EXPECT_EQ(0, counter_b::alive_count()); | 
|  | } | 
|  |  | 
|  | EXPECT_NE(0, counter_a::constructor_count()); | 
|  | EXPECT_EQ(0, counter_a::alive_count()); | 
|  |  | 
|  | EXPECT_EQ(0, counter_b::constructor_count()); | 
|  | EXPECT_EQ(0, counter_b::alive_count()); | 
|  |  | 
|  | counter_a::reset(); | 
|  | counter_b::reset(); | 
|  |  | 
|  | { | 
|  | auto result = get_error(); | 
|  | const auto& error = result.take_error(); | 
|  |  | 
|  | static_assert(std::is_same_v<decltype(error), const fitx::error<counter_a>&>); | 
|  |  | 
|  | EXPECT_EQ(0, counter_a::default_constructor_count); | 
|  | EXPECT_NE(0, counter_a::constructor_count()); | 
|  | EXPECT_NE(0, counter_a::alive_count()); | 
|  |  | 
|  | EXPECT_EQ(0, counter_b::constructor_count()); | 
|  | EXPECT_EQ(0, counter_b::alive_count()); | 
|  | } | 
|  |  | 
|  | EXPECT_NE(0, counter_a::constructor_count()); | 
|  | EXPECT_EQ(0, counter_a::alive_count()); | 
|  |  | 
|  | EXPECT_EQ(0, counter_b::constructor_count()); | 
|  | EXPECT_EQ(0, counter_b::alive_count()); | 
|  |  | 
|  | counter_a::reset(); | 
|  | counter_b::reset(); | 
|  | } | 
|  |  | 
|  | TEST(LibZxCommon, StatusString) { | 
|  | { | 
|  | zx::status<> status = zx::ok(); | 
|  | EXPECT_STR_EQ(status.status_string(), zx_status_get_string(ZX_OK)); | 
|  | } | 
|  |  | 
|  | { | 
|  | zx::status<> status = zx::error(ZX_ERR_NO_MEMORY); | 
|  | EXPECT_STR_EQ(status.status_string(), zx_status_get_string(ZX_ERR_NO_MEMORY)); | 
|  | } | 
|  |  | 
|  | { | 
|  | zx::status<int> status = zx::ok(10); | 
|  | EXPECT_STR_EQ(status.status_string(), zx_status_get_string(ZX_OK)); | 
|  | } | 
|  |  | 
|  | { | 
|  | zx::status<int> status = zx::error(ZX_ERR_NO_MEMORY); | 
|  | EXPECT_STR_EQ(status.status_string(), zx_status_get_string(ZX_ERR_NO_MEMORY)); | 
|  | } | 
|  | } | 
|  |  | 
|  | struct ErrorMsg { | 
|  | zx_status_t status; | 
|  | std::vector<std::string> details{}; | 
|  |  | 
|  | void operator+=(std::string value) { details.push_back(std::move(value)); } | 
|  | }; | 
|  |  | 
|  | TEST(LibZxCommon, AugmentError) { | 
|  | { | 
|  | fitx::result<std::string> result = fitx::error("Bad outcome!"); | 
|  | result += fitx::error("More details!"); | 
|  | EXPECT_STR_EQ(result.error_value(), "Bad outcome!More details!"); | 
|  | } | 
|  |  | 
|  | { | 
|  | fitx::result<std::string, int> result = fitx::error("Bad outcome!"); | 
|  | result += fitx::error("More details!"); | 
|  | EXPECT_STR_EQ(result.error_value(), "Bad outcome!More details!"); | 
|  | } | 
|  |  | 
|  | { | 
|  | fitx::result<ErrorMsg> result = fitx::error(ErrorMsg{ZX_ERR_NOT_FOUND}); | 
|  | EXPECT_EQ(0, result.error_value().details.size()); | 
|  |  | 
|  | result += fitx::error("More details!"); | 
|  | ASSERT_EQ(1, result.error_value().details.size()); | 
|  | EXPECT_STR_EQ(result.error_value().details[0], "More details!"); | 
|  | } | 
|  |  | 
|  | { | 
|  | fitx::result<ErrorMsg, int> result = fitx::error(ErrorMsg{ZX_ERR_NOT_FOUND}); | 
|  | EXPECT_EQ(0, result.error_value().details.size()); | 
|  |  | 
|  | result += fitx::error("More details!"); | 
|  | ASSERT_EQ(1, result.error_value().details.size()); | 
|  | EXPECT_STR_EQ(result.error_value().details[0], "More details!"); | 
|  | } | 
|  | } | 
|  |  | 
|  | }  // anonymous namespace |