| /* |
| * Copyright (C) 2016-2017 Apple Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| * THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "config.h" |
| |
| #include "RefLogger.h" |
| |
| #include <memory> |
| #include <string> |
| |
| #include <wtf/Expected.h> |
| #include <wtf/Unexpected.h> |
| #include <wtf/StdLibExtras.h> |
| #include <wtf/Ref.h> |
| |
| namespace std { |
| |
| template<typename T0, typename T1> std::ostream& operator<<(std::ostream& os, const std::pair<T0, T1>& p) |
| { |
| return os << '(' << p.first << ", " << p.second << ')'; |
| } |
| |
| namespace experimental { |
| inline namespace fundamentals_v3 { |
| |
| template<class E> std::ostream& operator<<(std::ostream& os, const Unexpected<E>& u) |
| { |
| return os << u.value(); |
| } |
| |
| template<class T, class E> std::ostream& operator<<(std::ostream& os, const Expected<T, E>& e) |
| { |
| if (e.has_value()) |
| return os << e.value(); |
| return os << e.error(); |
| } |
| |
| template<class E> std::ostream& operator<<(std::ostream& os, const Expected<void, E>& e) |
| { |
| if (e.has_value()) |
| return os << ""; |
| return os << e.error(); |
| } |
| |
| }}} // namespace std::experimental::fundamentals_v3 |
| |
| |
| namespace TestWebKitAPI { |
| |
| constexpr const char* oops = "oops"; |
| constexpr const char* foof = "foof"; |
| |
| TEST(WTF_Expected, Unexpected) |
| { |
| { |
| auto u = Unexpected<int>(42); |
| EXPECT_EQ(u.value(), 42); |
| constexpr auto c = makeUnexpected(42); |
| EXPECT_EQ(c.value(), 42); |
| EXPECT_EQ(u, c); |
| EXPECT_FALSE(u != c); |
| } |
| { |
| auto c = makeUnexpected(oops); |
| EXPECT_EQ(c.value(), oops); |
| } |
| { |
| auto s = makeUnexpected(std::string(oops)); |
| EXPECT_EQ(s.value(), oops); |
| } |
| { |
| constexpr auto s0 = makeUnexpected(oops); |
| constexpr auto s1(s0); |
| EXPECT_EQ(s0, s1); |
| } |
| } |
| |
| struct foo { |
| int v; |
| foo(int v) |
| : v(v) |
| { } |
| ~foo() { } |
| bool operator==(const foo& y) const { return v == y.v; } |
| friend std::ostream& operator<<(std::ostream&, const foo&); |
| }; |
| std::ostream& operator<<(std::ostream& os, const foo& f) { return os << f.v; } |
| |
| TEST(WTF_Expected, expected) |
| { |
| typedef Expected<int, const char*> E; |
| typedef Expected<int, const void*> EV; |
| typedef Expected<foo, const char*> FooChar; |
| typedef Expected<foo, std::string> FooString; |
| { |
| auto e = E(); |
| EXPECT_TRUE(e.has_value()); |
| EXPECT_EQ(e.value(), 0); |
| EXPECT_EQ(e.value_or(3.14), 0); |
| } |
| { |
| constexpr E e; |
| EXPECT_TRUE(e.has_value()); |
| EXPECT_EQ(e.value(), 0); |
| EXPECT_EQ(e.value_or(3.14), 0); |
| } |
| { |
| auto e = E(42); |
| EXPECT_TRUE(e.has_value()); |
| EXPECT_EQ(e.value(), 42); |
| EXPECT_EQ(e.value_or(3.14), 42); |
| const auto e2(e); |
| EXPECT_TRUE(e2.has_value()); |
| EXPECT_EQ(e2.value(), 42); |
| EXPECT_EQ(e2.value_or(3.14), 42); |
| E e3; |
| e3 = e2; |
| EXPECT_TRUE(e3.has_value()); |
| EXPECT_EQ(e3.value(), 42); |
| EXPECT_EQ(e3.value_or(3.14), 42); |
| const E e4 = e2; |
| EXPECT_TRUE(e4.has_value()); |
| EXPECT_EQ(e4.value(), 42); |
| EXPECT_EQ(e4.value_or(3.14), 42); |
| } |
| { |
| constexpr E c(42); |
| EXPECT_TRUE(c.has_value()); |
| EXPECT_EQ(c.value(), 42); |
| EXPECT_EQ(c.value_or(3.14), 42); |
| constexpr const auto c2(c); |
| EXPECT_TRUE(c2.has_value()); |
| EXPECT_EQ(c2.value(), 42); |
| EXPECT_EQ(c2.value_or(3.14), 42); |
| } |
| { |
| auto u = E(makeUnexpected(oops)); |
| EXPECT_FALSE(u.has_value()); |
| EXPECT_EQ(u.error(), oops); |
| EXPECT_EQ(u.value_or(3.14), 3); |
| } |
| { |
| auto uv = EV(makeUnexpected(oops)); |
| EXPECT_FALSE(uv.has_value()); |
| EXPECT_EQ(uv.error(), oops); |
| EXPECT_EQ(uv.value_or(3.14), 3); |
| } |
| { |
| E e = makeUnexpected(oops); |
| EXPECT_FALSE(e.has_value()); |
| EXPECT_EQ(e.error(), oops); |
| EXPECT_EQ(e.value_or(3.14), 3); |
| } |
| { |
| auto e = FooChar(42); |
| EXPECT_EQ(e->v, 42); |
| EXPECT_EQ((*e).v, 42); |
| } |
| { |
| auto e0 = E(42); |
| auto e1 = E(1024); |
| swap(e0, e1); |
| EXPECT_EQ(e0.value(), 1024); |
| EXPECT_EQ(e1.value(), 42); |
| } |
| { |
| auto e0 = E(makeUnexpected(oops)); |
| auto e1 = E(makeUnexpected(foof)); |
| swap(e0, e1); |
| EXPECT_EQ(e0.error(), foof); |
| EXPECT_EQ(e1.error(), oops); |
| } |
| { |
| FooChar c(foo(42)); |
| EXPECT_EQ(c->v, 42); |
| EXPECT_EQ((*c).v, 42); |
| } |
| { |
| FooString s(foo(42)); |
| EXPECT_EQ(s->v, 42); |
| EXPECT_EQ((*s).v, 42); |
| const char* message = "very long failure string, for very bad failure cases"; |
| FooString e0(makeUnexpected<std::string>(message)); |
| FooString e1(makeUnexpected<std::string>(message)); |
| FooString e2(makeUnexpected<std::string>(std::string())); |
| EXPECT_EQ(e0.error(), std::string(message)); |
| EXPECT_EQ(e0, e1); |
| EXPECT_NE(e0, e2); |
| FooString* e4 = new FooString(makeUnexpected<std::string>(message)); |
| FooString* e5 = new FooString(*e4); |
| EXPECT_EQ(e0, *e4); |
| delete e4; |
| EXPECT_EQ(e0, *e5); |
| delete e5; |
| } |
| } |
| |
| TEST(WTF_Expected, void) |
| { |
| typedef Expected<void, const char*> E; |
| typedef Expected<void, const void*> EV; |
| typedef Expected<void, std::string> String; |
| { |
| auto e = E(); |
| EXPECT_TRUE(e.has_value()); |
| const auto e2(e); |
| EXPECT_TRUE(e2.has_value()); |
| EXPECT_EQ(e, e2); |
| E e3; |
| e3 = e2; |
| EXPECT_TRUE(e3.has_value()); |
| EXPECT_EQ(e, e3); |
| } |
| { |
| constexpr E c; |
| EXPECT_TRUE(c.has_value()); |
| constexpr const auto c2(c); |
| EXPECT_TRUE(c2.has_value()); |
| EXPECT_EQ(c, c2); |
| } |
| { |
| auto u = E(makeUnexpected(oops)); |
| EXPECT_FALSE(u.has_value()); |
| EXPECT_EQ(u.error(), oops); |
| } |
| { |
| auto uv = EV(makeUnexpected(oops)); |
| EXPECT_FALSE(uv.has_value()); |
| EXPECT_EQ(uv.error(), oops); |
| } |
| { |
| E e = makeUnexpected(oops); |
| EXPECT_FALSE(e.has_value()); |
| EXPECT_EQ(e.error(), oops); |
| } |
| { |
| auto e0 = E(); |
| auto e1 = E(); |
| swap(e0, e1); |
| EXPECT_EQ(e0, e1); |
| } |
| { |
| auto e0 = E(makeUnexpected(oops)); |
| auto e1 = E(makeUnexpected(foof)); |
| swap(e0, e1); |
| EXPECT_EQ(e0.error(), foof); |
| EXPECT_EQ(e1.error(), oops); |
| } |
| { |
| const char* message = "very long failure string, for very bad failure cases"; |
| String e0(makeUnexpected<std::string>(message)); |
| String e1(makeUnexpected<std::string>(message)); |
| String e2(makeUnexpected<std::string>(std::string())); |
| EXPECT_EQ(e0.error(), std::string(message)); |
| EXPECT_EQ(e0, e1); |
| EXPECT_NE(e0, e2); |
| String* e4 = new String(makeUnexpected<std::string>(message)); |
| String* e5 = new String(*e4); |
| EXPECT_EQ(e0, *e4); |
| delete e4; |
| EXPECT_EQ(e0, *e5); |
| delete e5; |
| } |
| { |
| typedef Expected<std::pair<int, int>, std::string> Et; |
| EXPECT_EQ(Et(std::in_place, 1, 2), Et(std::in_place, 1, 2)); |
| } |
| } |
| |
| template<typename T> |
| struct NonCopyable { |
| NonCopyable(T&& t) |
| : value(std::forward<T>(t)) { } |
| NonCopyable(NonCopyable&&) = default; |
| NonCopyable(const NonCopyable&) = delete; |
| NonCopyable& operator=(const NonCopyable&) = delete; |
| NonCopyable& operator=(NonCopyable&&) = default; |
| bool operator==(const NonCopyable<T>& other) const { return value == other.value; } |
| bool operator!=(const NonCopyable<T>& other) const { return value != other.value; } |
| T value; |
| }; |
| |
| TEST(WTF_Expected, comparison) |
| { |
| typedef Expected<int, const char*> Ex; |
| typedef Expected<int, int> Er; |
| |
| // Two Expected, no errors. |
| EXPECT_EQ(Ex(42), Ex(42)); |
| EXPECT_NE(Ex(42), Ex(1024)); |
| |
| EXPECT_FALSE(Ex(42) == Ex(1024)); |
| EXPECT_FALSE(Ex(42) != Ex(42)); |
| |
| // Two Expected, half errors. |
| EXPECT_FALSE(Ex(42) == Ex(makeUnexpected(oops))); |
| EXPECT_NE(Ex(42), Ex(makeUnexpected(oops))); |
| |
| EXPECT_FALSE(Ex(makeUnexpected(oops)) == Ex(42)); |
| EXPECT_NE(Ex(makeUnexpected(oops)), Ex(42)); |
| |
| // Two Expected, all errors. |
| EXPECT_EQ(Er(42), Er(42)); |
| EXPECT_NE(Er(42), Er(1024)); |
| |
| EXPECT_FALSE(Er(42) == Er(1024)); |
| EXPECT_FALSE(Er(42) != Er(42)); |
| |
| // One Expected, one value. |
| EXPECT_EQ(Ex(42), 42); |
| EXPECT_NE(Ex(42), 0); |
| |
| EXPECT_FALSE(Ex(42) == 0); |
| EXPECT_FALSE(Ex(42) != 42); |
| |
| EXPECT_EQ(42, Ex(42)); |
| EXPECT_NE(42, Ex(1024)); |
| |
| EXPECT_FALSE(42 == Ex(1024)); |
| EXPECT_FALSE(42 != Ex(42)); |
| |
| // One Expected, one unexpected. |
| EXPECT_FALSE(Ex(42) == makeUnexpected(oops)); |
| EXPECT_NE(Ex(42), makeUnexpected(oops)); |
| |
| EXPECT_FALSE(makeUnexpected(oops) == Ex(42)); |
| EXPECT_NE(makeUnexpected(oops), Ex(42)); |
| |
| NonCopyable<int> a { 5 }; |
| NonCopyable<int> b { 6 }; |
| Unexpected<NonCopyable<double>> c { makeUnexpected(NonCopyable<double> { 5.0 }) }; |
| Expected<NonCopyable<int>, NonCopyable<double>> d { NonCopyable<int> { 5 } }; |
| Expected<NonCopyable<int>, NonCopyable<double>> e { makeUnexpected(NonCopyable<double> { 5.0 }) }; |
| |
| EXPECT_TRUE(a != e); |
| EXPECT_TRUE(e != a); |
| EXPECT_FALSE(a == e); |
| EXPECT_FALSE(e == a); |
| |
| EXPECT_TRUE(b != e); |
| EXPECT_TRUE(e != b); |
| EXPECT_FALSE(b == e); |
| EXPECT_FALSE(e == b); |
| |
| EXPECT_TRUE(c != d); |
| EXPECT_TRUE(d != c); |
| EXPECT_FALSE(c == d); |
| EXPECT_FALSE(d == c); |
| |
| EXPECT_TRUE(c == e); |
| EXPECT_TRUE(e == c); |
| EXPECT_FALSE(c != e); |
| EXPECT_FALSE(e != c); |
| } |
| |
| struct NonTrivialDtor { |
| ~NonTrivialDtor() { ++count; } |
| static int count; |
| }; |
| int NonTrivialDtor::count = 0; |
| |
| TEST(WTF_Expected, destructors) |
| { |
| typedef Expected<NonTrivialDtor, const char*> NT; |
| typedef Expected<const char*, NonTrivialDtor> TN; |
| typedef Expected<NonTrivialDtor, NonTrivialDtor> NN; |
| typedef Expected<void, NonTrivialDtor> VN; |
| EXPECT_EQ(NonTrivialDtor::count, 0); |
| { NT nt; } |
| EXPECT_EQ(NonTrivialDtor::count, 1); |
| { NT nt = makeUnexpected(oops); } |
| EXPECT_EQ(NonTrivialDtor::count, 1); |
| { TN tn; } |
| EXPECT_EQ(NonTrivialDtor::count, 1); |
| { TN tn = makeUnexpected(NonTrivialDtor()); } |
| EXPECT_EQ(NonTrivialDtor::count, 4); |
| { NN nn; } |
| EXPECT_EQ(NonTrivialDtor::count, 5); |
| { NN nn = makeUnexpected(NonTrivialDtor()); } |
| EXPECT_EQ(NonTrivialDtor::count, 8); |
| { VN vn; } |
| EXPECT_EQ(NonTrivialDtor::count, 8); |
| { VN vn = makeUnexpected(NonTrivialDtor()); } |
| EXPECT_EQ(NonTrivialDtor::count, 11); |
| } |
| |
| static int snowflakes = 0; |
| static int melted = 0; |
| struct snowflake { |
| WTF_MAKE_STRUCT_FAST_ALLOCATED; |
| static void reset() { snowflakes = melted = 0; } |
| snowflake() { ++snowflakes; } |
| ~snowflake() { ++melted; } |
| }; |
| |
| TEST(WTF_Expected, unique_ptr) |
| { |
| // Unique snowflakes cannot be copied. |
| { |
| auto s = makeUnexpected(makeUnique<snowflake>()); |
| EXPECT_EQ(snowflakes, 1); |
| EXPECT_EQ(melted, 0); |
| } |
| EXPECT_EQ(snowflakes, 1); |
| EXPECT_EQ(melted, 1); |
| snowflake::reset(); |
| |
| { |
| auto s = makeUnexpected(makeUnique<snowflake>()); |
| Unexpected<std::unique_ptr<snowflake>> c(WTFMove(s)); |
| EXPECT_EQ(snowflakes, 1); |
| EXPECT_EQ(melted, 0); |
| } |
| EXPECT_EQ(snowflakes, 1); |
| EXPECT_EQ(melted, 1); |
| snowflake::reset(); |
| |
| auto plow = [] (std::unique_ptr<snowflake>&& s) |
| { |
| { |
| std::unique_ptr<snowflake> moved = WTFMove(s); |
| EXPECT_EQ(snowflakes, 1); |
| EXPECT_EQ(melted, 0); |
| } |
| EXPECT_EQ(snowflakes, 1); |
| EXPECT_EQ(melted, 1); |
| }; |
| |
| { |
| Expected<std::unique_ptr<snowflake>, int> s(makeUnique<snowflake>()); |
| plow(WTFMove(s).value()); |
| } |
| EXPECT_EQ(snowflakes, 1); |
| EXPECT_EQ(melted, 1); |
| snowflake::reset(); |
| |
| { |
| Expected<int, std::unique_ptr<snowflake>> s(makeUnexpected(makeUnique<snowflake>())); |
| plow(WTFMove(s).error()); |
| } |
| EXPECT_EQ(snowflakes, 1); |
| EXPECT_EQ(melted, 1); |
| snowflake::reset(); |
| |
| { |
| Expected<void, std::unique_ptr<snowflake>> s(makeUnexpected(makeUnique<snowflake>())); |
| plow(WTFMove(s).error()); |
| } |
| EXPECT_EQ(snowflakes, 1); |
| EXPECT_EQ(melted, 1); |
| snowflake::reset(); |
| } |
| |
| TEST(WTF_Expected, Ref) |
| { |
| { |
| RefLogger a("a"); |
| Expected<Ref<RefLogger>, int> expected = Ref<RefLogger>(a); |
| EXPECT_TRUE(expected.has_value()); |
| EXPECT_EQ(&a, expected.value().ptr()); |
| } |
| |
| ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str()); |
| |
| { |
| RefLogger a("a"); |
| Expected<Ref<RefLogger>, int> expected = Expected<Ref<RefLogger>, int>(Ref<RefLogger>(a)); |
| EXPECT_TRUE(expected.has_value()); |
| EXPECT_EQ(&a, expected.value().ptr()); |
| } |
| |
| ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str()); |
| |
| { |
| RefLogger a("a"); |
| Expected<int, Ref<RefLogger>> expected = makeUnexpected(Ref<RefLogger>(a)); |
| EXPECT_FALSE(expected.has_value()); |
| EXPECT_EQ(&a, expected.error().ptr()); |
| } |
| |
| ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str()); |
| |
| { |
| RefLogger a("a"); |
| Expected<void, Ref<RefLogger>> expected = makeUnexpected(Ref<RefLogger>(a)); |
| EXPECT_FALSE(expected.has_value()); |
| EXPECT_EQ(&a, expected.error().ptr()); |
| } |
| |
| ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str()); |
| } |
| |
| class NeedsStdAddress { |
| public: |
| NeedsStdAddress(NeedsStdAddress&& other) |
| : m_ptr(WTFMove(other.m_ptr)) { } |
| NeedsStdAddress(int& other) |
| : m_ptr(&other) { } |
| int* operator&() { ASSERT_NOT_REACHED(); return nullptr; } |
| private: |
| std::unique_ptr<int> m_ptr; |
| }; |
| |
| TEST(WTF_Expected, Address) |
| { |
| NeedsStdAddress a(*new int(3)); |
| Expected<NeedsStdAddress, float> b(WTFMove(a)); |
| Expected<NeedsStdAddress, float> c(WTFMove(b)); |
| (void)c; |
| } |
| |
| } // namespace TestWebkitAPI |