khanat-opennel-code/code/nel/tools/nel_unit_test/ut_misc_co_task.h
2010-05-06 02:08:41 +02:00

228 lines
3.9 KiB
C++

#ifndef UT_MISC_CO_TASK
#define UT_MISC_CO_TASK
#include <nel/misc/co_task.h>
#include <nel/misc/thread.h>
const char *referenceResult[] =
{
"Task1 : 0",
"Task2 : 0",
"Main : 0",
"Task1 : 1",
"Task2 : 1",
"Main : 1",
"Task1 : 2",
"Task2 : 2",
"Task1 : 3",
"Task2 : 3",
"Task1 : 4",
"Task2 : 4",
"Task2 : 5",
"Task2 : 6",
};
const char *referenceResultThread1[] =
{
"Task1 : 0",
"Thread : 0",
"Task1 : 1",
"Thread : 1",
"Task1 : 2",
"Thread : 2",
"Task1 : 3",
"Thread : 3",
"Task1 : 4",
"Thread : 4",
};
const char *referenceResultThread2[] =
{
"Task2 : 0",
"Main : 0",
"Task2 : 1",
"Main : 1",
"Task2 : 2",
"Task2 : 3",
"Task2 : 4",
};
vector<string> result;
vector<string> result2;
// a simple task
class CTask1 : public CCoTask
{
vector<string> &Output;
public:
CTask1(vector<string> &output = result)
: Output(output)
{}
void run()
{
for (uint i=0; i<5; ++i)
{
string s = toString("Task1 : %u", i);
Output.push_back(s);
yield();
}
}
};
// another simple task
class CTask2 : public CCoTask
{
vector<string> &Output;
public:
CTask2(vector<string> &output = result)
: Output(output)
{}
void run()
{
for (uint i=0; i<7; ++i)
{
string s = NLMISC::toString("Task2 : %u", i);
Output.push_back(s);
yield();
}
}
};
// a thread runnable class
class CTaskThread : public IRunnable
{
void run()
{
CTask1 t1(result2);
for (uint i=0; i<5; ++i)
{
t1.resume();
string s = NLMISC::toString("Thread : %u", i);
result2.push_back(s);
nlSleep(0);
}
}
};
// Test suite for coroutine task
class CUTMiscCoTask: public Test::Suite
{
public:
CUTMiscCoTask()
{
TEST_ADD(CUTMiscCoTask::runTasks);
TEST_ADD(CUTMiscCoTask::tasksAndThreads);
}
void tasksAndThreads()
{
// test running task in two separate thread (this stress the
// multithreading support of task). CoTask API ;ake use of
// thread local storage API to store by thread current task info.
result.clear();
result2.clear();
CTaskThread tt;
IThread *th = IThread::create(&tt);
CTask2 t2;
// start the thread
th->start();
for (uint i=0; i<2; ++i)
{
t2.resume();
string s = NLMISC::toString("Main : %u", i);
result.push_back(s);
nlSleep(0);
}
// wait task completion
t2.wait();
// wait thread completion
th->wait();
delete th;
// test result
for (uint i=0; i<sizeofarray(referenceResultThread1); ++i)
{
string &s1 = result2[i];
const char *s2 = referenceResultThread1[i];
TEST_ASSERT(referenceResultThread1[i] == result2[i]);
}
for (uint i=0; i<sizeofarray(referenceResultThread2); ++i)
{
string &s1 = result[i];
const char *s2 = referenceResultThread2[i];
TEST_ASSERT(referenceResultThread2[i] == result[i]);
}
}
void runTasks()
{
/// Run two main task and two working task at once and check that the result
result.clear();
// create the two task object
CTask1 t1;
CTask2 t2;
// start the two task (can be done in the loop, but we want the task output first)
t1.resume();
t2.resume();
// loop and run the main task and the two sub task
for (uint i=0; i<2; ++i)
{
string s = toString("Main : %u", i);
result.push_back(s);
t1.resume();
t2.resume();
}
// continue to run the task until the first is terminated
while (!t1.isFinished())
{
t1.resume();
t2.resume();
}
// wait task termination
t1.wait();
t2.wait();
// check the generated result
TEST_ASSERT(sizeofarray(referenceResult) == result.size());
for (uint i=0; i<sizeofarray(referenceResult); ++i)
{
string &s1 = result[i];
const char *s2 = referenceResult[i];
TEST_ASSERT(referenceResult[i] == result[i]);
}
}
};
#endif