diff options
Diffstat (limited to 'ipc/ipdl/test/cxx/IPDLUnitTests.template.cpp')
-rw-r--r-- | ipc/ipdl/test/cxx/IPDLUnitTests.template.cpp | 347 |
1 files changed, 347 insertions, 0 deletions
diff --git a/ipc/ipdl/test/cxx/IPDLUnitTests.template.cpp b/ipc/ipdl/test/cxx/IPDLUnitTests.template.cpp new file mode 100644 index 0000000000..30eea42838 --- /dev/null +++ b/ipc/ipdl/test/cxx/IPDLUnitTests.template.cpp @@ -0,0 +1,347 @@ +// +// Autogenerated from Python template. Hands off. +// + +#include <stdlib.h> +#include <string.h> + +#include "IPDLUnitTests.h" + +#include "base/command_line.h" +#include "base/string_util.h" +#include "base/task.h" +#include "base/thread.h" + +#include "nsRegion.h" + +#include "IPDLUnitTestSubprocess.h" + +// clang-format off +//----------------------------------------------------------------------------- +//===== TEMPLATED ===== +${INCLUDES} +//----------------------------------------------------------------------------- +// clang-format on + +using namespace std; + +using base::Thread; + +namespace mozilla { +namespace _ipdltest { + +void* gParentActor; +IPDLUnitTestSubprocess* gSubprocess; + +void* gChildActor; + +// Note: in threaded mode, this will be non-null (for both parent and +// child, since they share one set of globals). +Thread* gChildThread; +MessageLoop* gParentMessageLoop; +bool gParentDone; +bool gChildDone; + +void DeleteChildActor(); + +//----------------------------------------------------------------------------- +// data/functions accessed by both parent and child processes + +char* gIPDLUnitTestName = nullptr; + +const char* IPDLUnitTestName() { + if (!gIPDLUnitTestName) { +#if defined(OS_WIN) + vector<wstring> args = CommandLine::ForCurrentProcess()->GetLooseValues(); + gIPDLUnitTestName = ::strdup(WideToUTF8(args[0]).c_str()); +#elif defined(OS_POSIX) + vector<string> argv = CommandLine::ForCurrentProcess()->argv(); + gIPDLUnitTestName = ::moz_xstrdup(argv[1].c_str()); +#else +# error Sorry +#endif + } + return gIPDLUnitTestName; +} + +} // namespace _ipdltest +} // namespace mozilla + +namespace { + +enum IPDLUnitTestType { + NoneTest = 0, + + // clang-format off +//----------------------------------------------------------------------------- +//===== TEMPLATED ===== +${ENUM_VALUES} + + LastTest = ${LAST_ENUM} +//----------------------------------------------------------------------------- +//clang-format on +}; + +IPDLUnitTestType IPDLUnitTestFromString(const char* const aString) { + if (!aString) return static_cast<IPDLUnitTestType>(0); +// clang-format off +//----------------------------------------------------------------------------- +//===== TEMPLATED ===== +${STRING_TO_ENUMS} +//----------------------------------------------------------------------------- + // clang-format on + else return static_cast<IPDLUnitTestType>(0); +} + +IPDLUnitTestType IPDLUnitTest() { + return IPDLUnitTestFromString(::mozilla::_ipdltest::IPDLUnitTestName()); +} + +} // namespace + +//----------------------------------------------------------------------------- +// parent process only + +namespace mozilla { +namespace _ipdltest { + +void DeferredParentShutdown(); + +void IPDLUnitTestThreadMain(char* testString); + +void IPDLUnitTestMain(void* aData) { + char* testString = reinterpret_cast<char*>(aData); + + // Check if we are to run the test using threads instead: + const char* prefix = "thread:"; + const int prefixLen = strlen(prefix); + if (!strncmp(testString, prefix, prefixLen)) { + IPDLUnitTestThreadMain(testString + prefixLen); + return; + } + + IPDLUnitTestType test = IPDLUnitTestFromString(testString); + if (!test) { + // use this instead of |fail()| because we don't know what the test is + fprintf(stderr, MOZ_IPDL_TESTFAIL_LABEL "| %s | unknown unit test %s\n", + "<--->", testString); + MOZ_CRASH("can't continue"); + } + gIPDLUnitTestName = testString; + + // Check whether this test is enabled for processes: + switch (test) { + // clang-format off +//----------------------------------------------------------------------------- +//===== TEMPLATED ===== +${PARENT_ENABLED_CASES_PROC} +//----------------------------------------------------------------------------- + // clang-format on + + default: + fail("not reached"); + return; // unreached + } + + printf(MOZ_IPDL_TESTINFO_LABEL "| running test | %s\n", gIPDLUnitTestName); + + std::vector<std::string> testCaseArgs; + testCaseArgs.push_back(testString); + + gSubprocess = new IPDLUnitTestSubprocess(); + if (!gSubprocess->SyncLaunch(testCaseArgs)) + fail("problem launching subprocess"); + + IPC::Channel* transport = gSubprocess->GetChannel(); + if (!transport) fail("no transport"); + + base::ProcessId child = base::GetProcId(gSubprocess->GetChildProcessHandle()); + + switch (test) { + // clang-format off +//----------------------------------------------------------------------------- +//===== TEMPLATED ===== +${PARENT_MAIN_CASES_PROC} +//----------------------------------------------------------------------------- + // clang-format on + + default: + fail("not reached"); + return; // unreached + } +} + +void IPDLUnitTestThreadMain(char* testString) { + IPDLUnitTestType test = IPDLUnitTestFromString(testString); + if (!test) { + // use this instead of |fail()| because we don't know what the test is + fprintf(stderr, MOZ_IPDL_TESTFAIL_LABEL "| %s | unknown unit test %s\n", + "<--->", testString); + MOZ_CRASH("can't continue"); + } + gIPDLUnitTestName = testString; + + // Check whether this test is enabled for threads: + switch (test) { + // clang-format off +//----------------------------------------------------------------------------- +//===== TEMPLATED ===== +${PARENT_ENABLED_CASES_THREAD} +//----------------------------------------------------------------------------- + // clang-format on + + default: + fail("not reached"); + return; // unreached + } + + printf(MOZ_IPDL_TESTINFO_LABEL "| running test | %s\n", gIPDLUnitTestName); + + std::vector<std::string> testCaseArgs; + testCaseArgs.push_back(testString); + + gChildThread = new Thread("ParentThread"); + if (!gChildThread->Start()) fail("starting parent thread"); + + gParentMessageLoop = MessageLoop::current(); + MessageLoop* childMessageLoop = gChildThread->message_loop(); + + switch (test) { + // clang-format off +//----------------------------------------------------------------------------- +//===== TEMPLATED ===== +${PARENT_MAIN_CASES_THREAD} +//----------------------------------------------------------------------------- + // clang-format on + + default: + fail("not reached"); + return; // unreached + } +} + +void DeleteParentActor() { + if (!gParentActor) return; + + switch (IPDLUnitTest()) { + // clang-format off +//----------------------------------------------------------------------------- +//===== TEMPLATED ===== +${PARENT_DELETE_CASES} +//----------------------------------------------------------------------------- + // clang-format on + default: + ::mozilla::_ipdltest::fail("???"); + } +} + +void QuitXPCOM() { + DeleteParentActor(); + + static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID); + nsCOMPtr<nsIAppShell> appShell(do_GetService(kAppShellCID)); + appShell->Exit(); +} + +void DeleteSubprocess(MessageLoop* uiLoop) { + // pong to QuitXPCOM + gSubprocess->Destroy(); + gSubprocess = nullptr; + uiLoop->PostTask(NewRunnableFunction("QuitXPCOM", QuitXPCOM)); +} + +void DeferredParentShutdown() { + // ping to DeleteSubprocess + XRE_GetIOMessageLoop()->PostTask(NewRunnableFunction( + "DeleteSubprocess", DeleteSubprocess, MessageLoop::current())); +} + +void TryThreadedShutdown() { + // Stop if either: + // - the child has not finished, + // - the parent has not finished, + // - or this code has already executed. + // Remember: this TryThreadedShutdown() task is enqueued + // by both parent and child (though always on parent's msg loop). + if (!gChildDone || !gParentDone || !gChildThread) return; + + delete gChildThread; + gChildThread = 0; + DeferredParentShutdown(); +} + +void ChildCompleted() { + // Executes on the parent message loop once child has completed. + gChildDone = true; + TryThreadedShutdown(); +} + +void QuitParent() { + if (gChildThread) { + gParentDone = true; + MessageLoop::current()->PostTask( + NewRunnableFunction("TryThreadedShutdown", TryThreadedShutdown)); + } else { + // defer "real" shutdown to avoid *Channel::Close() racing with the + // deletion of the subprocess + MessageLoop::current()->PostTask( + NewRunnableFunction("DeferredParentShutdown", DeferredParentShutdown)); + } +} + +static void ChildDie() { + DeleteChildActor(); + XRE_ShutdownChildProcess(); +} + +void QuitChild() { + if (gChildThread) { // Threaded-mode test + gParentMessageLoop->PostTask( + NewRunnableFunction("ChildCompleted", ChildCompleted)); + } else { // Process-mode test + MessageLoop::current()->PostTask(NewRunnableFunction("ChildDie", ChildDie)); + } +} + +} // namespace _ipdltest +} // namespace mozilla + +//----------------------------------------------------------------------------- +// child process only + +namespace mozilla { +namespace _ipdltest { + +void DeleteChildActor() { + if (!gChildActor) return; + + switch (IPDLUnitTest()) { + // clang-format off +//----------------------------------------------------------------------------- +//===== TEMPLATED ===== +${CHILD_DELETE_CASES} +//----------------------------------------------------------------------------- + // clang-format on + default: + ::mozilla::_ipdltest::fail("???"); + } +} + +void IPDLUnitTestChildInit(IPC::Channel* transport, base::ProcessId parentPid, + MessageLoop* worker) { + switch (IPDLUnitTest()) { + // clang-format off +//----------------------------------------------------------------------------- +//===== TEMPLATED ===== +${CHILD_INIT_CASES} +//----------------------------------------------------------------------------- + // clang-format on + + default: + fail("not reached"); + return; // unreached + } +} + +} // namespace _ipdltest +} // namespace mozilla |