//
// Autogenerated from Python template.  Hands off.
//

#include "IPDLUnitTests.h"

#include <stdlib.h>
#include <string.h>

#include "base/command_line.h"
#include "base/string_util.h"

#include "nsRegion.h"

#include "IPDLUnitTestSubprocess.h"

//-----------------------------------------------------------------------------
//===== TEMPLATED =====
${INCLUDES}
//-----------------------------------------------------------------------------

using mozilla::_ipdltest::IPDLUnitTestSubprocess;

void* mozilla::_ipdltest::gParentActor;
IPDLUnitTestSubprocess* mozilla::_ipdltest::gSubprocess;

void* mozilla::_ipdltest::gChildActor;

//-----------------------------------------------------------------------------
// data/functions accessed by both parent and child processes

namespace {
char* gIPDLUnitTestName = NULL;
}


namespace mozilla {
namespace _ipdltest {

const char* const
IPDLUnitTestName()
{
    if (!gIPDLUnitTestName) {
#if defined(OS_WIN)
        std::vector<std::wstring> args =
            CommandLine::ForCurrentProcess()->GetLooseValues();
        gIPDLUnitTestName = strdup(WideToUTF8(args[0]).c_str());
#elif defined(OS_POSIX)
        std::vector<std::string> argv =
            CommandLine::ForCurrentProcess()->argv();
        gIPDLUnitTestName = strdup(argv[1].c_str());
#else
#  error Sorry
#endif
    }
    return gIPDLUnitTestName;
}

} // namespace _ipdltest
} // namespace mozilla


namespace {

enum IPDLUnitTestType {
    NoneTest = 0,

//-----------------------------------------------------------------------------
//===== TEMPLATED =====
${ENUM_VALUES}
    
    LastTest = ${LAST_ENUM}
//-----------------------------------------------------------------------------
};


IPDLUnitTestType
IPDLUnitTestFromString(const char* const aString)
{
    if (!aString)
        return static_cast<IPDLUnitTestType>(0);
//-----------------------------------------------------------------------------
//===== TEMPLATED =====
${STRING_TO_ENUMS}
//-----------------------------------------------------------------------------
    else
        return static_cast<IPDLUnitTestType>(0);
}


const char* const
IPDLUnitTestToString(IPDLUnitTestType aTest)
{
    switch (aTest) {
//-----------------------------------------------------------------------------
//===== TEMPLATED =====
${ENUM_TO_STRINGS}
//-----------------------------------------------------------------------------

    default:
        return NULL;
    }
}


IPDLUnitTestType
IPDLUnitTest()
{
    return IPDLUnitTestFromString(mozilla::_ipdltest::IPDLUnitTestName());
}


} // namespace <anon>


//-----------------------------------------------------------------------------
// parent process only

namespace mozilla {
namespace _ipdltest {

void
IPDLUnitTestMain(void* aData)
{
    char* testString = reinterpret_cast<char*>(aData);
    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);
        NS_RUNTIMEABORT("can't continue");
    }
    gIPDLUnitTestName = testString;

    if (NS_FAILED(nsRegion::InitStatic()))
        fail("initializing nsRegion");

    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::ProcessHandle child = gSubprocess->GetChildProcessHandle();

    switch (test) {
//-----------------------------------------------------------------------------
//===== TEMPLATED =====
${PARENT_MAIN_CASES}
//-----------------------------------------------------------------------------

    default:
        fail("not reached");
        return;                 // unreached
    }
}

void
DeleteParentActor()
{
    if (!gParentActor)
        return;

    switch (IPDLUnitTest()) {
//-----------------------------------------------------------------------------
//===== TEMPLATED =====
${PARENT_DELETE_CASES}
//-----------------------------------------------------------------------------
    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
  delete gSubprocess;
  uiLoop->PostTask(FROM_HERE, NewRunnableFunction(QuitXPCOM));
}

void
DeferredParentShutdown()
{
  // ping to DeleteSubprocess
  XRE_GetIOMessageLoop()->PostTask(
      FROM_HERE,
      NewRunnableFunction(DeleteSubprocess, MessageLoop::current()));
}

void
QuitParent()
{
  // defer "real" shutdown to avoid *Channel::Close() racing with the
  // deletion of the subprocess
    MessageLoop::current()->PostTask(
        FROM_HERE, NewRunnableFunction(DeferredParentShutdown));
}

} // namespace _ipdltest
} // namespace mozilla


//-----------------------------------------------------------------------------
// child process only

namespace mozilla {
namespace _ipdltest {

void
DeleteChildActor()
{
    if (!gChildActor)
        return;

    switch (IPDLUnitTest()) {
//-----------------------------------------------------------------------------
//===== TEMPLATED =====
${CHILD_DELETE_CASES}
//-----------------------------------------------------------------------------
    default:  mozilla::_ipdltest::fail("???");
    }
}

void
IPDLUnitTestChildInit(IPC::Channel* transport,
                      base::ProcessHandle parent,
                      MessageLoop* worker)
{
    if (atexit(DeleteChildActor))
        fail("can't install atexit() handler");

    switch (IPDLUnitTest()) {
//-----------------------------------------------------------------------------
//===== TEMPLATED =====
${CHILD_INIT_CASES}
//-----------------------------------------------------------------------------

    default:
        fail("not reached");
        return;                 // unreached
    }
}

} // namespace _ipdltest
} // namespace mozilla
