205 lines
6.7 KiB
C++
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
|
|
}
|
|
|
|
}
|