void test_promise() { Promise<bool> p; auto f = p.getFuture(); try { p.getFuture(); ok(false, "should throw"); } catch (const std::logic_error& exc) { ok(!strcmp(exc.what(), "Future already obtained"), "can't getFuture twice"); } ok(!f.isReady(), "not yet ready"); p.setValue(true); try { p.setValue(false); ok(false, "should throw"); } catch (const std::logic_error& exc) { ok(!strcmp(exc.what(), "Promise already fulfilled"), "can't setValue twice"); } ok(f.isReady(), "now ready"); ok(f.get() == true, "got our true value"); Promise<std::string> s; s.setException(std::make_exception_ptr(std::runtime_error("boo"))); auto f2 = s.getFuture(); ok(f2.result().hasError(), "holds an error"); try { f2.get(); } catch (const std::runtime_error& exc) { ok(!strcmp(exc.what(), "boo"), "has boo string"); } }
TEST(Promise, setException) { { Promise<Unit> p; auto f = p.getFuture(); p.setException(eggs); EXPECT_THROW(f.value(), eggs_t); } { Promise<Unit> p; auto f = p.getFuture(); try { throw eggs; } catch (...) { p.setException(exception_wrapper(std::current_exception())); } EXPECT_THROW(f.value(), eggs_t); } }
Future<int> future_throwing() { Promise<int> p; auto f = p.getFuture(); Xception x; x.errorCode = 32; x.message = "test"; p.setException(x); return std::move(f); }
Future<Unit> future_voidThrowing() override { Promise<Unit> p; auto f = p.getFuture(); Xception x; x.errorCode = 42; x.message = "test2"; p.setException(x); return f; }
TEST(Collect, collectVariadicWithException) { Promise<bool> pb; Promise<int> pi; Future<bool> fb = pb.getFuture(); Future<int> fi = pi.getFuture(); auto f = collect(std::move(fb), std::move(fi)); pb.setValue(true); EXPECT_FALSE(f.isReady()); pi.setException(eggs); EXPECT_TRUE(f.isReady()); EXPECT_TRUE(f.getTry().hasException()); EXPECT_THROW(f.get(), eggs_t); }
TEST(SemiFuture, MakeSemiFutureFromFutureWithTry) { Promise<int> p; auto f = p.getFuture(); auto sf = std::move(f).semi().defer([&](Try<int> t) { if (auto err = t.tryGetExceptionObject<std::logic_error>()) { return Try<std::string>(err->what()); } return Try<std::string>( make_exception_wrapper<std::logic_error>("Exception")); }); p.setException(make_exception_wrapper<std::logic_error>("Try")); auto tryResult = std::move(sf).get(); ASSERT_EQ(tryResult.value(), "Try"); }
TEST(SharedPromise, splitFutureFailure) { Promise<int> p; SharedPromise<int> sp(p.getFuture()); auto f1 = sp.getFuture(); EXPECT_FALSE(f1.isReady()); try { throw std::runtime_error("Oops"); } catch (...) { p.setException(exception_wrapper(std::current_exception())); } EXPECT_TRUE(f1.isReady()); EXPECT_TRUE(f1.hasException()); auto f2 = sp.getFuture(); EXPECT_TRUE(f2.isReady()); EXPECT_TRUE(f2.hasException()); }
TEST(Collect, collectAllVariadicWithException) { Promise<bool> pb; Promise<int> pi; Future<bool> fb = pb.getFuture(); Future<int> fi = pi.getFuture(); bool flag = false; collectAll(std::move(fb), std::move(fi)) .then([&](std::tuple<Try<bool>, Try<int>> tup) { flag = true; EXPECT_TRUE(std::get<0>(tup).hasValue()); EXPECT_EQ(std::get<0>(tup).value(), true); EXPECT_TRUE(std::get<1>(tup).hasException()); EXPECT_THROW(std::get<1>(tup).value(), eggs_t); }); pb.setValue(true); EXPECT_FALSE(flag); pi.setException(eggs); EXPECT_TRUE(flag); }
TEST_F(ObservingHandlerTest, ConnectErrorHandlerDeletion) { // Test when an error occurs while fetching the broadcast handler // after the handler is deleted InSequence dummy; EXPECT_CALL(*prevHandler, transportActive(_)) .WillOnce(Invoke([&](MockBytesToBytesHandler::Context* ctx) { ctx->fireTransportActive(); })); // Verify that ingress is paused EXPECT_CALL(*prevHandler, transportInactive(_)).WillOnce(Return()); Promise<BroadcastHandler<int, std::string>*> promise; EXPECT_CALL(pool, mockGetHandler(_)) .WillOnce(Return(makeMoveWrapper(promise.getFuture()))); // Initialize the pipeline pipeline->transportActive(); // Delete the handler and then inject an error pipeline.reset(); promise.setException(std::exception()); }
TEST_F(ObservingHandlerTest, WriteErrorHandlerDeletion) { // Test when write error occurs asynchronously after the handler // has been deleted. InSequence dummy; EXPECT_CALL(*prevHandler, transportActive(_)) .WillOnce(Invoke([&](MockBytesToBytesHandler::Context* ctx) { ctx->fireTransportActive(); })); // Verify that ingress is paused EXPECT_CALL(*prevHandler, transportInactive(_)).WillOnce(Return()); EXPECT_CALL(pool, mockGetHandler(_)) .WillOnce(Return(MoveWrapper<Future<BroadcastHandler<int, std::string>*>>( broadcastHandler.get()))); EXPECT_CALL(*broadcastHandler, subscribe(_)).Times(1); // Verify that ingress is resumed EXPECT_CALL(*prevHandler, transportActive(_)) .WillOnce(Invoke([&](MockBytesToBytesHandler::Context* ctx) { ctx->fireTransportActive(); })); // Initialize the pipeline pipeline->transportActive(); Promise<Unit> promise; EXPECT_CALL(*observingHandler, mockWrite(_, _)) .WillOnce(Return(makeMoveWrapper(promise.getFuture()))); // Broadcast some data observingHandler->onNext(1); // Delete the pipeline and then fail the write EXPECT_CALL(*broadcastHandler, unsubscribe(_)).Times(1); pipeline.reset(); promise.setException(std::exception()); }