Bug 1271593 - Unit test for NS_NewRunnableFunction - r=froydnj

Tests to verify that the number of copies and moves are as expected.
Also check that the runnable is fully self-contained and can be used after the
initial function objects have been destroyed or moved-from.

MozReview-Commit-ID: ArwIG9BEhDX

--HG--
extra : rebase_source : b2ee07294fcff17b76da468ddbaeb2b62d600536
This commit is contained in:
Gerald Squelart 2016-06-02 00:53:35 +02:00
Родитель e8513ef5ee
Коммит e4f93ee534
1 изменённых файлов: 217 добавлений и 2 удалений

Просмотреть файл

@ -116,8 +116,225 @@ public:
NS_IMPL_ISUPPORTS0(nsBar)
struct TestCopyWithNoMove
{
explicit TestCopyWithNoMove(int* aCopyCounter) : mCopyCounter(aCopyCounter) {}
TestCopyWithNoMove(const TestCopyWithNoMove& a) : mCopyCounter(a.mCopyCounter) { ++mCopyCounter; };
// No 'move' declaration, allows passing object by rvalue copy.
// Destructor nulls member variable...
~TestCopyWithNoMove() { mCopyCounter = nullptr; }
// ... so we can check that the object is called when still alive.
void operator()() { MOZ_ASSERT(mCopyCounter); }
int* mCopyCounter;
};
struct TestCopyWithDeletedMove
{
explicit TestCopyWithDeletedMove(int* aCopyCounter) : mCopyCounter(aCopyCounter) {}
TestCopyWithDeletedMove(const TestCopyWithDeletedMove& a) : mCopyCounter(a.mCopyCounter) { ++mCopyCounter; };
// Deleted move prevents passing by rvalue (even if copy would work)
TestCopyWithDeletedMove(TestCopyWithDeletedMove&&) = delete;
~TestCopyWithDeletedMove() { mCopyCounter = nullptr; }
void operator()() { MOZ_ASSERT(mCopyCounter); }
int* mCopyCounter;
};
struct TestMove
{
explicit TestMove(int* aMoveCounter) : mMoveCounter(aMoveCounter) {}
TestMove(const TestMove&) = delete;
TestMove(TestMove&& a) : mMoveCounter(a.mMoveCounter) { a.mMoveCounter = nullptr; ++mMoveCounter; }
~TestMove() { mMoveCounter = nullptr; }
void operator()() { MOZ_ASSERT(mMoveCounter); }
int* mMoveCounter;
};
struct TestCopyMove
{
TestCopyMove(int* aCopyCounter, int* aMoveCounter) : mCopyCounter(aCopyCounter), mMoveCounter(aMoveCounter) {}
TestCopyMove(const TestCopyMove& a) : mCopyCounter(a.mCopyCounter), mMoveCounter(a.mMoveCounter) { ++mCopyCounter; };
TestCopyMove(TestCopyMove&& a) : mCopyCounter(a.mCopyCounter), mMoveCounter(a.mMoveCounter) { a.mMoveCounter = nullptr; ++mMoveCounter; }
~TestCopyMove() { mCopyCounter = nullptr; mMoveCounter = nullptr; }
void operator()() { MOZ_ASSERT(mCopyCounter); MOZ_ASSERT(mMoveCounter); }
int* mCopyCounter;
int* mMoveCounter;
};
static int Expect(const char* aContext, int aCounter, int aMaxExpected)
{
if (aCounter > aMaxExpected) {
fail("%s: expected %d max, got %d", aContext, aMaxExpected, aCounter);
return 1;
}
passed("%s: got %d <= %d as expected", aContext, aCounter, aMaxExpected);
return 0;
}
int TestNS_NewRunnableFunction()
{
int result = 0;
// Test NS_NewRunnableFunction with copyable-only function object.
{
int copyCounter = 0;
{
nsCOMPtr<nsIRunnable> trackedRunnable;
{
TestCopyWithNoMove tracker(&copyCounter);
trackedRunnable = NS_NewRunnableFunction(tracker);
// Original 'tracker' is destroyed here.
}
// Verify that the runnable contains a non-destroyed function object.
trackedRunnable->Run();
}
result |= Expect("NS_NewRunnableFunction with copyable-only (and no move) function, copies",
copyCounter, 1);
}
{
int copyCounter = 0;
{
nsCOMPtr<nsIRunnable> trackedRunnable;
{
// Passing as rvalue, but using copy.
// (TestCopyWithDeletedMove wouldn't allow this.)
trackedRunnable = NS_NewRunnableFunction(TestCopyWithNoMove(&copyCounter));
}
trackedRunnable->Run();
}
result |= Expect("NS_NewRunnableFunction with copyable-only (and no move) function rvalue, copies",
copyCounter, 1);
}
{
int copyCounter = 0;
{
nsCOMPtr<nsIRunnable> trackedRunnable;
{
TestCopyWithDeletedMove tracker(&copyCounter);
trackedRunnable = NS_NewRunnableFunction(tracker);
}
trackedRunnable->Run();
}
result |= Expect("NS_NewRunnableFunction with copyable-only (and deleted move) function, copies",
copyCounter, 1);
}
// Test NS_NewRunnableFunction with movable-only function object.
{
int moveCounter = 0;
{
nsCOMPtr<nsIRunnable> trackedRunnable;
{
TestMove tracker(&moveCounter);
trackedRunnable = NS_NewRunnableFunction(Move(tracker));
}
trackedRunnable->Run();
}
result |= Expect("NS_NewRunnableFunction with movable-only function, moves",
moveCounter, 1);
}
{
int moveCounter = 0;
{
nsCOMPtr<nsIRunnable> trackedRunnable;
{
trackedRunnable = NS_NewRunnableFunction(TestMove(&moveCounter));
}
trackedRunnable->Run();
}
result |= Expect("NS_NewRunnableFunction with movable-only function rvalue, moves",
moveCounter, 1);
}
// Test NS_NewRunnableFunction with copyable&movable function object.
{
int copyCounter = 0;
int moveCounter = 0;
{
nsCOMPtr<nsIRunnable> trackedRunnable;
{
TestCopyMove tracker(&copyCounter, &moveCounter);
trackedRunnable = NS_NewRunnableFunction(Move(tracker));
}
trackedRunnable->Run();
}
result |= Expect("NS_NewRunnableFunction with copyable&movable function, copies",
copyCounter, 0);
result |= Expect("NS_NewRunnableFunction with copyable&movable function, moves",
moveCounter, 1);
}
{
int copyCounter = 0;
int moveCounter = 0;
{
nsCOMPtr<nsIRunnable> trackedRunnable;
{
trackedRunnable =
NS_NewRunnableFunction(TestCopyMove(&copyCounter, &moveCounter));
}
trackedRunnable->Run();
}
result |= Expect("NS_NewRunnableFunction with copyable&movable function rvalue, copies",
copyCounter, 0);
result |= Expect("NS_NewRunnableFunction with copyable&movable function rvalue, moves",
moveCounter, 1);
}
// Test NS_NewRunnableFunction with copyable-only lambda capture.
{
int copyCounter = 0;
{
nsCOMPtr<nsIRunnable> trackedRunnable;
{
TestCopyWithNoMove tracker(&copyCounter);
// Expect 2 copies (here -> local lambda -> runnable lambda).
trackedRunnable = NS_NewRunnableFunction([tracker]() mutable { tracker(); });
}
trackedRunnable->Run();
}
result |= Expect("NS_NewRunnableFunction with copyable-only (and no move) capture, copies",
copyCounter, 2);
}
{
int copyCounter = 0;
{
nsCOMPtr<nsIRunnable> trackedRunnable;
{
TestCopyWithDeletedMove tracker(&copyCounter);
// Expect 2 copies (here -> local lambda -> runnable lambda).
trackedRunnable = NS_NewRunnableFunction([tracker]() mutable { tracker(); });
}
trackedRunnable->Run();
}
result |= Expect("NS_NewRunnableFunction with copyable-only (and deleted move) capture, copies",
copyCounter, 2);
}
// Note: Not possible to use move-only captures.
// (Until we can use C++14 generalized lambda captures)
// Test NS_NewRunnableFunction with copyable&movable lambda capture.
{
int copyCounter = 0;
int moveCounter = 0;
{
nsCOMPtr<nsIRunnable> trackedRunnable;
{
TestCopyMove tracker(&copyCounter, &moveCounter);
trackedRunnable = NS_NewRunnableFunction([tracker]() mutable { tracker(); });
// Expect 1 copy (here -> local lambda) and 1 move (local -> runnable lambda).
}
trackedRunnable->Run();
}
result |= Expect("NS_NewRunnableFunction with copyable&movable capture, copies",
copyCounter, 1);
result |= Expect("NS_NewRunnableFunction with copyable&movable capture, moves",
moveCounter, 1);
}
return result;
}
int main(int argc, char** argv)
{
int result = TestNS_NewRunnableFunction();
ScopedXPCOM xpcom("ThreadUtils");
NS_ENSURE_FALSE(xpcom.failed(), 1);
@ -168,8 +385,6 @@ int main(int argc, char** argv)
NS_ProcessPendingEvents(nullptr);
}
int result = 0;
for (uint32_t i = 0; i < MAX_TESTS; i++) {
if (gRunnableExecuted[i]) {
passed("Test %d passed",i);