JD2022-TU1/main/unittests/core/async/Promise.cpp

205 lines
6.7 KiB
C++

#include "precompiled_unittests_core.h"
#include <core/async/Promise.h>
namespace ITF
{
class ClientMock
{
public:
MOCK_METHOD1(onSuccess, void(const int &_result));
MOCK_METHOD1(onFailure, void(const int &_error));
MOCK_METHOD1(onSuccess2, void(const int &_result));
MOCK_METHOD1(onSuccess3, void(const int &_result));
MOCK_METHOD1(onSuccess1, void(const int &_result));
};
// Create a promise, and fulfill it
TEST(Promise, BasicSuccess)
{
testing::StrictMock<ClientMock> client;
Promise<int, int> promise;
Future<int, int> future = promise.getFuture();
// note: explicit template parameter is required only because of the mocking framework,
// it shoudn't be needed in normal code
future.registerSuccessHandler<testing::StrictMock<ClientMock> >(&client, &ClientMock::onSuccess);
EXPECT_TRUE(promise.isPending());
EXPECT_CALL(client, onSuccess(42)).Times(1);
promise.resolve(42);
EXPECT_FALSE(promise.isPending());
}
// Create a promise, and reject it
TEST(Promise, BasicFailure)
{
testing::StrictMock<ClientMock> client;
Promise<int, int> promise;
Future<int, int> future = promise.getFuture();
future.registerFailureHandler<testing::StrictMock<ClientMock> >(&client, &ClientMock::onFailure);
EXPECT_TRUE(promise.isPending());
EXPECT_CALL(client, onFailure(3)).Times(1);
promise.reject(3);
EXPECT_FALSE(promise.isPending());
}
// A pending must be resolved or rejected before being destroyed
TEST(Promise, UnresolvedDestruction)
{
Promise<int, int> *promise = newAlloc(mId_Misc, (Promise<int, int>));
// no resolve() or reject()
EXPECT_ITF_ASSERT(delete promise);
}
// It is not allowed to register a handler after the promise is resolved
TEST(Promise, HandlerRegistrationAfterSuccess)
{
testing::StrictMock<ClientMock> client;
Promise<int, int> promise;
Future<int, int> future = promise.getFuture();
promise.resolve(30);
EXPECT_ITF_ASSERT(future.registerSuccessHandler<testing::StrictMock<ClientMock> >(&client, &ClientMock::onSuccess));
EXPECT_ITF_ASSERT(future.registerFailureHandler<testing::StrictMock<ClientMock> >(&client, &ClientMock::onFailure));
}
// It is not allowed to register a handler after the promise is rejected
TEST(Promise, HandlerRegistrationAfterFailure)
{
testing::StrictMock<ClientMock> client;
Promise<int, int> promise;
Future<int, int> future = promise.getFuture();
promise.reject(3);
EXPECT_ITF_ASSERT(future.registerSuccessHandler<testing::StrictMock<ClientMock> >(&client, &ClientMock::onSuccess));
EXPECT_ITF_ASSERT(future.registerFailureHandler<testing::StrictMock<ClientMock> >(&client, &ClientMock::onFailure));
}
// The promise can only be solved or rejected once
TEST(Promise, MultipleResolutions)
{
Promise<int, int> promise1;
Promise<int, int> promise2;
Promise<int, int> promise3;
Promise<int, int> promise4;
promise1.resolve(10);
promise2.resolve(10);
promise3.reject(10);
promise4.reject(10);
EXPECT_ITF_ASSERT(promise1.resolve(20));
EXPECT_ITF_ASSERT(promise2.reject(20));
EXPECT_ITF_ASSERT(promise3.resolve(20));
EXPECT_ITF_ASSERT(promise4.reject(20));
}
// Success or failure callbacks must be called in the same order as during registration
TEST(Promise, HandlerInvokationOrder)
{
testing::StrictMock<ClientMock> client;
Promise<int, int> promise;
Future<int, int> future = promise.getFuture();
future.registerSuccessHandler<testing::StrictMock<ClientMock> >(&client, &ClientMock::onSuccess3);
future.registerSuccessHandler<testing::StrictMock<ClientMock> >(&client, &ClientMock::onSuccess1);
future.registerSuccessHandler<testing::StrictMock<ClientMock> >(&client, &ClientMock::onSuccess3);
future.registerSuccessHandler<testing::StrictMock<ClientMock> >(&client, &ClientMock::onSuccess2);
{
testing::InSequence sequence;
EXPECT_CALL(client, onSuccess3(42)).Times(1);
EXPECT_CALL(client, onSuccess1(42)).Times(1);
EXPECT_CALL(client, onSuccess3(42)).Times(1);
EXPECT_CALL(client, onSuccess2(42)).Times(1);
}
promise.resolve(42);
}
// Cancel requests must properly propagate from the futures to their promises
TEST(Promise, CancelRequest)
{
testing::StrictMock<ClientMock> client;
Promise<int, int> promise;
Future<int, int> future = promise.getFuture();
EXPECT_FALSE(promise.isCancelRequested());
future.requestCancel();
EXPECT_TRUE(promise.isCancelRequested());
promise.reject(0); // mandatory before destruction
}
// Unregistered callbacks shouldn't get called
TEST(Promise, SuccessUnregistration)
{
testing::StrictMock<ClientMock> client;
Promise<int, int> promise;
Future<int, int> future = promise.getFuture();
future.registerSuccessHandler<testing::StrictMock<ClientMock> >(&client, &ClientMock::onSuccess);
future.unregisterSuccessHandler<testing::StrictMock<ClientMock> >(&client, &ClientMock::onSuccess);
// the strict mock will fail the test if onSuccess() gets called
promise.resolve(42);
}
// Unregistered callbacks shouldn't get called
TEST(Promise, FailureUnregistration)
{
testing::StrictMock<ClientMock> client;
Promise<int, int> promise;
Future<int, int> future = promise.getFuture();
future.registerFailureHandler<testing::StrictMock<ClientMock> >(&client, &ClientMock::onFailure);
future.unregisterFailureHandler<testing::StrictMock<ClientMock> >(&client, &ClientMock::onFailure);
// the strict mock will fail the test if onFailure() gets called
promise.reject(1);
}
// Handlers cannot be unregistered more than they were registered
TEST(Promise, MultipleUnregistrations)
{
testing::StrictMock<ClientMock> client;
Promise<int, int> promise;
Future<int, int> future = promise.getFuture();
future.registerSuccessHandler<testing::StrictMock<ClientMock> >(&client, &ClientMock::onSuccess);
future.registerSuccessHandler<testing::StrictMock<ClientMock> >(&client, &ClientMock::onSuccess);
future.unregisterSuccessHandler<testing::StrictMock<ClientMock> >(&client, &ClientMock::onSuccess);
future.unregisterSuccessHandler<testing::StrictMock<ClientMock> >(&client, &ClientMock::onSuccess);
EXPECT_ITF_ASSERT(future.unregisterSuccessHandler<testing::StrictMock<ClientMock> >(&client, &ClientMock::onSuccess));
promise.resolve(42); // mandatory
}
TEST(Promise, FutureCopyConstructor)
{
Promise<int, int> promise;
Future<int, int> future = promise.getFuture();
Future<int, int> future2(future);
promise.resolve(42); // mandatory
}
TEST(Promise, FutureAssignment)
{
Promise<int, int> promise;
Future<int, int> future = promise.getFuture();
Future<int, int> future2;
future2 = future;
promise.resolve(42); // mandatory
}
}