TEST(WTF_Expected, UnexpectedType) { { auto u = UnexpectedType<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); EXPECT_FALSE(u < c); EXPECT_FALSE(u > c); EXPECT_LE(u, c); EXPECT_GE(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); } }
TEST(WTF_Expected, hash_void) { typedef Expected<void, const char*> E; std::unordered_map<E, int> m; m.insert({ E(), 42 }); m.insert({ E(makeUnexpected(oops)), 5 }); m.insert({ E(makeUnexpected(foof)), 0xf00f }); EXPECT_EQ(m[E()], 42); EXPECT_EQ(m[E(makeUnexpected(oops))], 5); EXPECT_EQ(m[E(makeUnexpected(foof))], 0xf00f); }
TEST(WTF_Expected, hash) { typedef Expected<int, const char*> E; std::unordered_map<E, int> m; m.insert({ E(42), 42 }); m.insert({ E(makeUnexpected(oops)), 5 }); m.insert({ E(1024), 1024 }); m.insert({ E(makeUnexpected(foof)), 0xf00f }); EXPECT_EQ(m[E(42)], 42); EXPECT_EQ(m[E(1024)], 1024); EXPECT_EQ(m[E(makeUnexpected(oops))], 5); EXPECT_EQ(m[E(makeUnexpected(foof))], 0xf00f); }
Expected<IPAddress, IPAddressFormatError> IPAddress::tryFromBinary( ByteRange bytes) noexcept { // Check IPv6 first since it's our main protocol. if (bytes.size() == 16) { return IPAddressV6::tryFromBinary(bytes); } else if (bytes.size() == 4) { return IPAddressV4::tryFromBinary(bytes); } else { return makeUnexpected(IPAddressFormatError::UNSUPPORTED_ADDR_FAMILY); } }
Expected<IPAddress, IPAddressFormatError> IPAddress::tryFromString( StringPiece str) noexcept { // need to check for V4 address second, since IPv4-mapped IPv6 addresses may // contain a period if (str.find(':') != string::npos) { return IPAddressV6::tryFromString(str); } else if (str.find('.') != string::npos) { return IPAddressV4::tryFromString(str); } else { return makeUnexpected(IPAddressFormatError::UNSUPPORTED_ADDR_FAMILY); } }
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 Expected<json_patch, json_patch::parse_error> json_patch::try_parse( dynamic const& obj) noexcept { using err_code = parse_error_code; json_patch patch; if (!obj.isArray()) { return makeUnexpected(parse_error{err_code::invalid_shape, &obj}); } for (auto const& elem : obj) { if (!elem.isObject()) { return makeUnexpected(parse_error{err_code::invalid_shape, &elem}); } auto const* op_ptr = elem.get_ptr(kOpTag); if (!op_ptr) { return makeUnexpected(parse_error{err_code::missing_op, &elem}); } if (!op_ptr->isString()) { return makeUnexpected(parse_error{err_code::malformed_op, &elem}); } auto const op_str = op_ptr->asString(); patch_operation op; // extract 'from' attribute { auto const* from_ptr = elem.get_ptr(kFromTag); if (from_ptr) { if (!from_ptr->isString()) { return makeUnexpected(parse_error{err_code::invalid_shape, &elem}); } auto json_ptr = json_pointer::try_parse(from_ptr->asString()); if (!json_ptr.hasValue()) { return makeUnexpected( parse_error{err_code::malformed_from_attr, &elem}); } op.from = json_ptr.value(); } } // extract 'path' attribute { auto const* path_ptr = elem.get_ptr(kPathTag); if (!path_ptr) { return makeUnexpected(parse_error{err_code::missing_path_attr, &elem}); } if (!path_ptr->isString()) { return makeUnexpected( parse_error{err_code::malformed_path_attr, &elem}); } auto const json_ptr = json_pointer::try_parse(path_ptr->asString()); if (!json_ptr.hasValue()) { return makeUnexpected( parse_error{err_code::malformed_path_attr, &elem}); } op.path = json_ptr.value(); } // extract 'value' attribute { auto const* val_ptr = elem.get_ptr(kValueTag); if (val_ptr) { op.value = *val_ptr; } } // check mandatory attributes - different per operation // NOTE: per RFC, the surplus attributes (e.g. 'from' with 'add') // should be simply ignored using op_code = patch_operation_code; if (op_str == kOperationTest) { if (!op.value) { return makeUnexpected(parse_error{err_code::missing_value_attr, &elem}); } op.op_code = op_code::test; } else if (op_str == kOperationRemove) { op.op_code = op_code::remove; } else if (op_str == kOperationAdd) { if (!op.value) { return makeUnexpected(parse_error{err_code::missing_value_attr, &elem}); } op.op_code = op_code::add; } else if (op_str == kOperationReplace) { if (!op.value) { return makeUnexpected(parse_error{err_code::missing_value_attr, &elem}); } op.op_code = op_code::replace; } else if (op_str == kOperationMove) { if (!op.from) { return makeUnexpected(parse_error{err_code::missing_from_attr, &elem}); } // is from a proper prefix to path? if (op.from->is_prefix_of(op.path)) { return makeUnexpected( parse_error{err_code::overlapping_pointers, &elem}); } op.op_code = op_code::move; } else if (op_str == kOperationCopy) { if (!op.from) { return makeUnexpected(parse_error{err_code::missing_from_attr, &elem}); } op.op_code = op_code::copy; } if (op.op_code != op_code::invalid) { patch.ops_.emplace_back(std::move(op)); } else { return makeUnexpected(parse_error{err_code::unknown_op, &elem}); } } return patch; }
// clang-format off Expected<Unit, json_patch::patch_application_error> // clang-format on json_patch::apply(dynamic& obj) { using op_code = patch_operation_code; using error_code = patch_application_error_code; using error = patch_application_error; for (auto&& it : enumerate(ops_)) { auto const index = it.index; auto const& op = *it; auto resolved_path = obj.try_get_ptr(op.path); switch (op.op_code) { case op_code::test: if (!resolved_path.hasValue()) { return folly::makeUnexpected( error{error_code::path_not_found, index}); } if (*resolved_path->value != *op.value) { return folly::makeUnexpected(error{error_code::test_failed, index}); } break; case op_code::remove: { auto ret = do_remove(resolved_path); if (ret.hasError()) { return makeUnexpected(error{ret.error(), index}); } break; } case op_code::add: { DCHECK(op.value.hasValue()); auto ret = do_add(resolved_path, *op.value, op.path.tokens().back()); if (ret.hasError()) { return makeUnexpected(error{ret.error(), index}); } break; } case op_code::replace: { if (resolved_path.hasValue()) { *resolved_path->value = *op.value; } else { return folly::makeUnexpected( error{error_code::path_not_found, index}); } break; } case op_code::move: { DCHECK(op.from.hasValue()); auto resolved_from = obj.try_get_ptr(*op.from); if (!resolved_from.hasValue()) { return makeUnexpected(error{error_code::from_not_found, index}); } { auto ret = do_add( resolved_path, *resolved_from->value, op.path.tokens().back()); if (ret.hasError()) { return makeUnexpected(error{ret.error(), index}); } } { auto ret = do_remove(resolved_from); if (ret.hasError()) { return makeUnexpected(error{ret.error(), index}); } } break; } case op_code::copy: { DCHECK(op.from.hasValue()); auto const resolved_from = obj.try_get_ptr(*op.from); if (!resolved_from.hasValue()) { return makeUnexpected(error{error_code::from_not_found, index}); } { DCHECK(!op.path.tokens().empty()); auto ret = do_add( resolved_path, *resolved_from->value, op.path.tokens().back()); if (ret.hasError()) { return makeUnexpected(error{ret.error(), index}); } } break; } case op_code::invalid: { DCHECK(false); return makeUnexpected(error{error_code::other, index}); } } } return unit; }
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_LT(Ex(42), Ex(1024)); EXPECT_GT(Ex(1024), Ex(42)); EXPECT_LE(Ex(42), Ex(42)); EXPECT_GE(Ex(42), Ex(42)); EXPECT_LE(Ex(42), Ex(1024)); EXPECT_GE(Ex(1024), Ex(42)); EXPECT_FALSE(Ex(42) == Ex(1024)); EXPECT_FALSE(Ex(42) != Ex(42)); EXPECT_FALSE(Ex(1024) < Ex(42)); EXPECT_FALSE(Ex(42) > Ex(1024)); EXPECT_FALSE(Ex(1024) < Ex(42)); EXPECT_FALSE(Ex(42) >= Ex(1024)); // Two Expected, half errors. EXPECT_FALSE(Ex(42) == Ex(makeUnexpected(oops))); EXPECT_NE(Ex(42), Ex(makeUnexpected(oops))); EXPECT_LT(Ex(42), Ex(makeUnexpected(oops))); EXPECT_FALSE(Ex(42) > Ex(makeUnexpected(oops))); EXPECT_LE(Ex(42), Ex(makeUnexpected(oops))); EXPECT_FALSE(Ex(42) >= Ex(makeUnexpected(oops))); EXPECT_FALSE(Ex(makeUnexpected(oops)) == Ex(42)); EXPECT_NE(Ex(makeUnexpected(oops)), Ex(42)); EXPECT_FALSE(Ex(makeUnexpected(oops)) < Ex(42)); EXPECT_GT(Ex(makeUnexpected(oops)), Ex(42)); EXPECT_FALSE(Ex(makeUnexpected(oops)) <= Ex(42)); EXPECT_GE(Ex(makeUnexpected(oops)), Ex(42)); // Two Expected, all errors. EXPECT_EQ(Er(42), Er(42)); EXPECT_NE(Er(42), Er(1024)); EXPECT_LT(Er(42), Er(1024)); EXPECT_GT(Er(1024), Er(42)); EXPECT_LE(Er(42), Er(42)); EXPECT_GE(Er(42), Er(42)); EXPECT_LE(Er(42), Er(1024)); EXPECT_GE(Er(1024), Er(42)); EXPECT_FALSE(Er(42) == Er(1024)); EXPECT_FALSE(Er(42) != Er(42)); EXPECT_FALSE(Er(1024) < Er(42)); EXPECT_FALSE(Er(42) > Er(1024)); EXPECT_FALSE(Er(1024) <= Er(42)); EXPECT_FALSE(Er(42) >= Er(1024)); // One Expected, one value. EXPECT_EQ(Ex(42), 42); EXPECT_NE(Ex(42), 0); EXPECT_LT(Ex(42), 1024); EXPECT_GT(Ex(1024), 42); EXPECT_LE(Ex(42), 42); EXPECT_GE(Ex(42), 42); EXPECT_LE(Ex(42), 1024); EXPECT_GE(Ex(1024), 42); EXPECT_FALSE(Ex(42) == 0); EXPECT_FALSE(Ex(42) != 42); EXPECT_FALSE(Ex(1024) < 42); EXPECT_FALSE(Ex(42) > 1024); EXPECT_FALSE(Ex(1024) < 42); EXPECT_FALSE(Ex(42) >= 1024); EXPECT_EQ(42, Ex(42)); EXPECT_NE(42, Ex(1024)); EXPECT_LT(42, Ex(1024)); EXPECT_GT(1024, Ex(42)); EXPECT_LE(42, Ex(42)); EXPECT_GE(42, Ex(42)); EXPECT_LE(42, Ex(1024)); EXPECT_GE(1024, Ex(42)); EXPECT_FALSE(42 == Ex(1024)); EXPECT_FALSE(42 != Ex(42)); EXPECT_FALSE(1024 < Ex(42)); EXPECT_FALSE(42 > Ex(1024)); EXPECT_FALSE(1024 <= Ex(42)); EXPECT_FALSE(42 >= Ex(1024)); // One Expected, one unexpected. EXPECT_FALSE(Ex(42) == makeUnexpected(oops)); EXPECT_NE(Ex(42), makeUnexpected(oops)); EXPECT_LT(Ex(42), makeUnexpected(oops)); EXPECT_FALSE(Ex(42) > makeUnexpected(oops)); EXPECT_LE(Ex(42), makeUnexpected(oops)); EXPECT_FALSE(Ex(42) >= makeUnexpected(oops)); EXPECT_FALSE(makeUnexpected(oops) == Ex(42)); EXPECT_NE(makeUnexpected(oops), Ex(42)); EXPECT_FALSE(makeUnexpected(oops) < Ex(42)); EXPECT_GT(makeUnexpected(oops), Ex(42)); EXPECT_FALSE(makeUnexpected(oops) <= Ex(42)); EXPECT_GE(makeUnexpected(oops), Ex(42)); }
TEST(WTF_Expected, 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.hasValue()); const auto e2(e); EXPECT_TRUE(e2.hasValue()); EXPECT_EQ(e, e2); E e3; e3 = e2; EXPECT_TRUE(e3.hasValue()); EXPECT_EQ(e, e3); } { constexpr E c; EXPECT_TRUE(c.hasValue()); constexpr const auto c2(c); EXPECT_TRUE(c2.hasValue()); EXPECT_EQ(c, c2); } { auto u = E(makeUnexpected(oops)); EXPECT_FALSE(u.hasValue()); EXPECT_EQ(u.error(), oops); EXPECT_EQ(u.getUnexpected().value(), oops); } { auto uv = EV(makeUnexpected(oops)); EXPECT_FALSE(uv.hasValue()); EXPECT_EQ(uv.error(), oops); EXPECT_EQ(uv.getUnexpected().value(), oops); } { E e = makeUnexpected(oops); EXPECT_FALSE(e.hasValue()); EXPECT_EQ(e.error(), oops); EXPECT_EQ(e.getUnexpected().value(), oops); } { auto e = makeExpectedFromError<void, const char*>(oops); EXPECT_FALSE(e.hasValue()); EXPECT_EQ(e.error(), oops); EXPECT_EQ(e.getUnexpected().value(), oops); } { auto e = makeExpectedFromError<void, const void*>(oops); EXPECT_FALSE(e.hasValue()); EXPECT_EQ(e.error(), oops); EXPECT_EQ(e.getUnexpected().value(), 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; } }
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.hasValue()); EXPECT_EQ(e.value(), 0); EXPECT_EQ(e.valueOr(3.14), 0); } { constexpr E e; EXPECT_TRUE(e.hasValue()); EXPECT_EQ(e.value(), 0); EXPECT_EQ(e.valueOr(3.14), 0); } { auto e = E(42); EXPECT_TRUE(e.hasValue()); EXPECT_EQ(e.value(), 42); EXPECT_EQ(e.valueOr(3.14), 42); const auto e2(e); EXPECT_TRUE(e2.hasValue()); EXPECT_EQ(e2.value(), 42); EXPECT_EQ(e2.valueOr(3.14), 42); E e3; e3 = e2; EXPECT_TRUE(e3.hasValue()); EXPECT_EQ(e3.value(), 42); EXPECT_EQ(e3.valueOr(3.14), 42); const E e4 = e2; EXPECT_TRUE(e4.hasValue()); EXPECT_EQ(e4.value(), 42); EXPECT_EQ(e4.valueOr(3.14), 42); } { constexpr E c(42); EXPECT_TRUE(c.hasValue()); EXPECT_EQ(c.value(), 42); EXPECT_EQ(c.valueOr(3.14), 42); constexpr const auto c2(c); EXPECT_TRUE(c2.hasValue()); EXPECT_EQ(c2.value(), 42); EXPECT_EQ(c2.valueOr(3.14), 42); } { auto u = E(makeUnexpected(oops)); EXPECT_FALSE(u.hasValue()); EXPECT_EQ(u.error(), oops); EXPECT_EQ(u.getUnexpected().value(), oops); EXPECT_EQ(u.valueOr(3.14), 3); } { auto uv = EV(makeUnexpected(oops)); EXPECT_FALSE(uv.hasValue()); EXPECT_EQ(uv.error(), oops); EXPECT_EQ(uv.getUnexpected().value(), oops); EXPECT_EQ(uv.valueOr(3.14), 3); } { E e = makeUnexpected(oops); EXPECT_FALSE(e.hasValue()); EXPECT_EQ(e.error(), oops); EXPECT_EQ(e.getUnexpected().value(), oops); EXPECT_EQ(e.valueOr(3.14), 3); } { auto e = makeExpectedFromError<int, const char*>(oops); EXPECT_FALSE(e.hasValue()); EXPECT_EQ(e.error(), oops); EXPECT_EQ(e.getUnexpected().value(), oops); EXPECT_EQ(e.valueOr(3.14), 3); } { auto e = makeExpectedFromError<int, const void*>(oops); EXPECT_FALSE(e.hasValue()); EXPECT_EQ(e.error(), oops); EXPECT_EQ(e.getUnexpected().value(), oops); EXPECT_EQ(e.valueOr(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; } }