зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
e8513ef5ee
Коммит
e4f93ee534
|
@ -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(©Counter);
|
||||
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(©Counter));
|
||||
}
|
||||
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(©Counter);
|
||||
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(©Counter, &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(©Counter, &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(©Counter);
|
||||
// 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(©Counter);
|
||||
// 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(©Counter, &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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче