axmol/tests/cpp-tests/Classes/controller.cpp

507 lines
16 KiB
C++
Raw Normal View History

2015-04-03 11:54:39 +08:00
#include "controller.h"
#include <functional>
2014-02-28 23:41:01 +08:00
#include <chrono>
#include "BaseTest.h"
#include "tests.h"
2015-04-03 11:54:39 +08:00
USING_NS_CC;
#define TEST_TIME_OUT 25
#define CREATE_TIME_OUT 25
#define LOG_INDENTATION " "
#define LOG_TAG "[TestController]"
class RootTests : public TestList
{
public:
RootTests()
{
addTest("ActionManager", [](){return new (std::nothrow) ActionManagerTests(); });
addTest("Actions - Basic", [](){ return new (std::nothrow) ActionsTests(); });
addTest("Actions - Ease", [](){return new (std::nothrow) ActionsEaseTests(); });
addTest("Actions - Progress", [](){return new (std::nothrow) ActionsProgressTests(); });
addTest("Allocator - Basic", [](){return new (std::nothrow) AllocatorTests(); });
addTest("Audio - CocosDenshion", []() { return new (std::nothrow) CocosDenshionTests(); });
2014-09-29 10:15:41 +08:00
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_MAC || CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
2015-04-03 11:54:39 +08:00
addTest("Audio - NewAudioEngine", []() { return new (std::nothrow) AudioEngineTests(); });
2014-09-03 18:20:31 +08:00
#endif
#if CC_ENABLE_BOX2D_INTEGRATION
2015-04-03 11:54:39 +08:00
addTest("Box2d - Basic", []() { return new (std::nothrow) Box2DTests(); });
addTest("Box2d - TestBed", []() { return new (std::nothrow) Box2dTestBedSuite(); });
#endif
2015-04-03 11:54:39 +08:00
addTest("Bugs", []() { return new BugsTests(); });
addTest("Chipmunk", []() { return new ChipmunkTests(); });
addTest("Click and Move", [](){return new ClickAndMoveTest(); });
addTest("Configuration", []() { return new ConfigurationTests(); });
addTest("Console", []() { return new ConsoleTests(); });
addTest("Curl", []() { return new CurlTests(); });
addTest("Current Language", []() { return new CurrentLanguageTests(); });
2015-04-07 11:43:02 +08:00
addTest("CocosStudio3D Test", []() { return new CocosStudio3DTests(); });
2015-04-03 11:54:39 +08:00
addTest("EventDispatcher", []() { return new EventDispatcherTests(); });
addTest("Effects - Advanced", []() { return new EffectAdvanceTests(); });
addTest("Effects - Basic", [](){return new EffectTests(); });
addTest("Extensions", []() { return new ExtensionsTests(); });
addTest("FileUtils", []() { return new FileUtilsTests(); });
addTest("Fonts", []() { return new FontTests(); });
addTest("Interval", [](){return new IntervalTests(); });
addTest("Node: BillBoard Test", [](){ return new BillBoardTests(); });
addTest("Node: Camera 3D Test", [](){ return new Camera3DTests(); });
addTest("Node: Clipping", []() { return new ClippingNodeTests(); });
addTest("Node: Draw", [](){return new DrawPrimitivesTests(); });
addTest("Node: Label - New API", [](){return new NewLabelTests(); });
addTest("Node: Label - Old API", [](){return new LabelTests(); });
addTest("Node: Layer", [](){return new LayerTests(); });
addTest("Node: Light", [](){return new LightTests(); });
addTest("Node: Menu", [](){return new MenuTests(); });
addTest("Node: MotionStreak", [](){return new MotionStreakTests(); });
addTest("Node: Node", [](){return new CocosNodeTests(); });
addTest("Node: Parallax", [](){return new ParallaxTests(); });
addTest("Node: Particles", [](){return new ParticleTests(); });
2015-04-07 11:43:02 +08:00
addTest("Node: Particle3D (PU)", [](){return new Particle3DTests(); });
2015-04-03 11:54:39 +08:00
addTest("Node: Physics", []() { return new PhysicsTests(); });
addTest("Node: RenderTexture", [](){return new RenderTextureTests(); });
addTest("Node: Scene", [](){return new SceneTests(); });
2015-04-07 11:43:02 +08:00
addTest("Node: Spine", [](){return new SpineTests(); });
2015-04-03 11:54:39 +08:00
addTest("Node: Sprite", [](){return new SpriteTests(); });
addTest("Node: Sprite3D", [](){ return new Sprite3DTests(); });
addTest("Node: Terrain", [](){ return new TerrainTests(); });
2015-04-03 11:54:39 +08:00
addTest("Node: TileMap", [](){return new TileMapTests(); });
addTest("Node: FastTileMap", [](){return new FastTileMapTests(); });
addTest("Node: Text Input", [](){return new TextInputTests(); });
addTest("Node: UI", [](){ return new UITests(); });
addTest("Mouse", []() { return new MouseTests(); });
addTest("MultiTouch", []() { return new MutiTouchTests(); });
//addTest("Performance tests", []() { return new PerformanceTests(); });
addTest("Renderer", []() { return new NewRendererTests(); });
addTest("ReleasePool", [](){ return new ReleasePoolTests(); });
addTest("Rotate World", [](){return new RotateWorldTests(); });
addTest("Scheduler", [](){return new SchedulerTests(); });//!!!!!!
addTest("Shader - Basic", []() { return new ShaderTests(); });
addTest("Shader - Sprite", []() { return new Shader2Tests(); });
addTest("Texture2D", [](){return new Texture2DTests(); });
addTest("TextureCache", []() { return new TextureCacheTests(); });
addTest("TexturePacker Encryption", []() { return new TextureAtlasEncryptionTests(); });
addTest("Touches", [](){return new TouchesTests(); });
addTest("Transitions", [](){return new TransitionsTests(); });
addTest("Unit Test", []() { return new UnitTests(); });
addTest("URL Open Test", []() { return new OpenURLTests(); });
addTest("UserDefault", []() { return new UserDefaultTests(); });
addTest("Zwoptex", []() { return new ZwoptexTests(); });
}
};
TestController::TestController()
2015-04-03 11:54:39 +08:00
: _stopAutoTest(true)
, _isRunInBackground(false)
, _testSuite(nullptr)
{
2015-04-03 11:54:39 +08:00
_rootTestList = new (std::nothrow) RootTests;
_rootTestList->runThisTest();
_director = Director::getInstance();
2015-04-03 11:54:39 +08:00
_touchListener = EventListenerTouchOneByOne::create();
_touchListener->onTouchBegan = CC_CALLBACK_2(TestController::blockTouchBegan, this);
_touchListener->setSwallowTouches(true);
2015-04-03 11:54:39 +08:00
_director->getEventDispatcher()->addEventListenerWithFixedPriority(_touchListener, -200);
}
TestController::~TestController()
{
2015-04-03 11:54:39 +08:00
_director->getEventDispatcher()->removeEventListener(_touchListener);
_rootTestList->release();
_rootTestList = nullptr;
}
2015-04-03 11:54:39 +08:00
void TestController::startAutoTest()
{
2015-04-03 11:54:39 +08:00
if (!_autoTestThread.joinable())
{
2015-04-03 11:54:39 +08:00
_stopAutoTest = false;
_logIndentation = "";
_autoTestThread = std::thread(&TestController::traverseTestList, this, _rootTestList);
_autoTestThread.detach();
}
}
2015-04-03 11:54:39 +08:00
void TestController::stopAutoTest()
{
2015-04-03 11:54:39 +08:00
_stopAutoTest = true;
if (_autoTestThread.joinable()) {
_sleepCondition.notify_all();
_autoTestThread.join();
}
}
2015-04-03 11:54:39 +08:00
void TestController::traverseTestList(TestList* testList)
{
2015-04-03 11:54:39 +08:00
if (testList == _rootTestList)
{
2015-04-03 11:54:39 +08:00
_sleepUniqueLock = std::unique_lock<std::mutex>(_sleepMutex);
_sleepCondition.wait_for(_sleepUniqueLock, std::chrono::milliseconds(500));
2015-04-03 11:54:39 +08:00
//disable touch
}
2015-04-03 11:54:39 +08:00
else
{
2015-04-03 11:54:39 +08:00
_logIndentation += LOG_INDENTATION;
_sleepCondition.wait_for(_sleepUniqueLock, std::chrono::milliseconds(500));
}
2015-04-03 11:54:39 +08:00
logEx("%s%sBegin traverse TestList:%s", LOG_TAG, _logIndentation.c_str(), testList->getTestName().c_str());
2015-04-03 11:54:39 +08:00
auto scheduler = _director->getScheduler();
int testIndex = 0;
for (auto& callback : testList->_testCallbacks)
{
if (_stopAutoTest) break;
while (_isRunInBackground)
{
logEx("_director is paused");
_sleepCondition.wait_for(_sleepUniqueLock, std::chrono::milliseconds(500));
}
if (callback)
{
auto test = callback();
test->setTestParent(testList);
test->setTestName(testList->_childTestNames[testIndex++]);
if (test->isTestList())
{
scheduler->performFunctionInCocosThread([&](){
test->runThisTest();
});
2015-04-03 11:54:39 +08:00
traverseTestList((TestList*)test);
}
else
{
traverseTestSuite((TestSuite*)test);
}
}
}
2015-04-03 11:54:39 +08:00
if (testList == _rootTestList)
{
2015-04-03 11:54:39 +08:00
_sleepUniqueLock.release();
_stopAutoTest = true;
}
2015-04-03 11:54:39 +08:00
else
{
2015-04-03 11:54:39 +08:00
if (!_stopAutoTest)
{
//Backs up one level and release TestList object.
scheduler->performFunctionInCocosThread([&](){
testList->_parentTest->runThisTest();
});
_sleepCondition.wait_for(_sleepUniqueLock, std::chrono::milliseconds(500));
testList->release();
}
_logIndentation.erase(_logIndentation.rfind(LOG_INDENTATION));
}
2013-10-31 14:19:36 +08:00
}
2014-02-19 16:13:32 +08:00
2015-04-03 11:54:39 +08:00
void TestController::traverseTestSuite(TestSuite* testSuite)
2014-05-19 13:46:17 +08:00
{
2015-04-03 11:54:39 +08:00
auto scheduler = _director->getScheduler();
int testIndex = 0;
float testCaseDuration = 0.0f;
_logIndentation += LOG_INDENTATION;
logEx("%s%sBegin traverse TestSuite:%s", LOG_TAG, _logIndentation.c_str(), testSuite->getTestName().c_str());
2014-05-19 13:46:17 +08:00
2015-04-03 11:54:39 +08:00
_logIndentation += LOG_INDENTATION;
2014-05-19 13:46:17 +08:00
2015-04-03 11:54:39 +08:00
auto logIndentation = _logIndentation;
for (auto& callback : testSuite->_testCallbacks)
{
auto testName = testSuite->_childTestNames[testIndex++];
Scene* testScene = nullptr;
TestCase* testCase = nullptr;
TransitionScene* transitionScene = nullptr;
if (_stopAutoTest) break;
while (_isRunInBackground)
2014-05-19 13:46:17 +08:00
{
2015-04-03 11:54:39 +08:00
logEx("_director is paused");
_sleepCondition.wait_for(_sleepUniqueLock, std::chrono::milliseconds(500));
2014-05-19 13:46:17 +08:00
}
2015-04-03 11:54:39 +08:00
//Run test case in the cocos[GL] thread.
scheduler->performFunctionInCocosThread([&, logIndentation, testName](){
if (_stopAutoTest) return;
logEx("%s%sRun test:%s.", LOG_TAG, logIndentation.c_str(), testName.c_str());
2014-05-19 13:46:17 +08:00
2015-04-03 11:54:39 +08:00
auto scene = callback();
if (_stopAutoTest) return;
if (scene)
2014-05-19 13:46:17 +08:00
{
2015-04-03 11:54:39 +08:00
transitionScene = dynamic_cast<TransitionScene*>(scene);
if (transitionScene)
{
testCase = (TestCase*)transitionScene->getInScene();
testCaseDuration = transitionScene->getDuration() + 0.5f;
}
else
2014-05-19 13:46:17 +08:00
{
2015-04-03 11:54:39 +08:00
testCase = (TestCase*)scene;
testCaseDuration = testCase->getDuration();
2014-05-19 13:46:17 +08:00
}
2015-04-03 11:54:39 +08:00
testCase->setTestSuite(testSuite);
testCase->setTestCaseName(testName);
_director->replaceScene(scene);
testScene = scene;
}
});
if (_stopAutoTest) break;
//Wait for the test case be created.
float waitTime = 0.0f;
while (!testScene && !_stopAutoTest)
{
_sleepCondition.wait_for(_sleepUniqueLock, std::chrono::milliseconds(50));
if (!_isRunInBackground)
2014-05-19 13:46:17 +08:00
{
2015-04-03 11:54:39 +08:00
waitTime += 0.05f;
2014-05-19 13:46:17 +08:00
}
2015-04-03 11:54:39 +08:00
if (waitTime > CREATE_TIME_OUT)
2014-05-19 13:46:17 +08:00
{
2015-04-03 11:54:39 +08:00
logEx("%sCreate test %s time out", LOG_TAG, testName.c_str());
_stopAutoTest = true;
2014-05-19 13:46:17 +08:00
break;
}
}
2015-04-03 11:54:39 +08:00
if (_stopAutoTest) break;
//Wait for test completed.
_sleepCondition.wait_for(_sleepUniqueLock, std::chrono::milliseconds(int(1000 * testCaseDuration)));
if (transitionScene == nullptr)
2014-02-19 16:13:32 +08:00
{
2015-04-03 11:54:39 +08:00
waitTime = 0.0f;
while (!_stopAutoTest && testCase->getRunTime() < testCaseDuration)
2014-02-19 17:55:32 +08:00
{
2015-04-03 11:54:39 +08:00
_sleepCondition.wait_for(_sleepUniqueLock, std::chrono::milliseconds(50));
if (!_isRunInBackground)
2014-02-19 17:55:32 +08:00
{
2015-04-03 11:54:39 +08:00
waitTime += 0.05f;
2014-02-19 17:55:32 +08:00
}
2015-04-03 11:54:39 +08:00
if (waitTime > TEST_TIME_OUT)
{
2015-04-03 11:54:39 +08:00
logEx("%sRun test %s time out", LOG_TAG, testName.c_str());
_stopAutoTest = true;
break;
}
}
2015-04-03 11:54:39 +08:00
if (!_stopAutoTest)
2014-02-28 23:02:22 +08:00
{
2015-04-03 11:54:39 +08:00
//Check the result of test.
checkTest(testCase);
2014-05-19 13:46:17 +08:00
}
2015-04-03 11:54:39 +08:00
}
}
if (!_stopAutoTest)
{
//Backs up one level and release TestSuite object.
auto parentTest = testSuite->_parentTest;
scheduler->performFunctionInCocosThread([&](){
parentTest->runThisTest();
});
_sleepCondition.wait_for(_sleepUniqueLock, std::chrono::milliseconds(1000));
testSuite->release();
}
_logIndentation.erase(_logIndentation.rfind(LOG_INDENTATION));
_logIndentation.erase(_logIndentation.rfind(LOG_INDENTATION));
}
2014-02-28 23:02:22 +08:00
2015-04-03 11:54:39 +08:00
bool TestController::checkTest(TestCase* testCase)
{
if (testCase)
{
switch (testCase->getTestType())
{
case TestCase::Type::UNIT:
{
if (testCase && testCase->getExpectedOutput() != testCase->getActualOutput())
2014-05-19 13:46:17 +08:00
{
2015-04-03 11:54:39 +08:00
logEx("%s %s test fail", LOG_TAG, testCase->getTestCaseName().c_str());
2014-02-28 23:02:22 +08:00
}
2015-04-03 11:54:39 +08:00
else
2014-02-19 16:13:32 +08:00
{
2015-04-03 11:54:39 +08:00
logEx("%s %s test pass", LOG_TAG, testCase->getTestCaseName().c_str());
2014-02-19 16:13:32 +08:00
}
2015-04-03 11:54:39 +08:00
break;
2014-02-19 16:13:32 +08:00
}
2015-04-03 11:54:39 +08:00
case TestCase::Type::ROBUSTNESS:
{
break;
}
case TestCase::Type::MANUAL:
{
break;
}
default:
break;
}
}
return true;
}
2014-05-12 21:47:55 +08:00
2015-04-03 11:54:39 +08:00
void TestController::handleCrash()
2014-05-12 21:47:55 +08:00
{
logEx("%sCatch an crash event", LOG_TAG);
if (!_stopAutoTest)
{
stopAutoTest();
}
#if CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_MAC || CC_TARGET_PLATFORM == CC_PLATFORM_LINUX
exit(1);
#endif
2014-05-12 21:47:55 +08:00
}
2015-04-03 11:54:39 +08:00
void TestController::onEnterBackground()
{
2015-04-03 11:54:39 +08:00
_isRunInBackground = true;
}
2015-04-03 11:54:39 +08:00
void TestController::onEnterForeground()
2014-05-12 21:47:55 +08:00
{
2015-04-03 11:54:39 +08:00
_isRunInBackground = false;
}
2014-05-12 21:47:55 +08:00
2015-04-03 11:54:39 +08:00
void TestController::logEx(const char * format, ...)
{
char buff[1024];
2014-05-12 21:47:55 +08:00
2015-04-03 11:54:39 +08:00
va_list args;
va_start(args, format);
vsnprintf(buff, 1020, format, args);
strcat(buff, "\n");
2014-05-12 21:47:55 +08:00
2015-04-03 11:54:39 +08:00
#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
__android_log_print(ANDROID_LOG_DEBUG, "cocos2d-x debug info", "%s", buff);
2014-05-12 21:47:55 +08:00
2015-04-03 11:54:39 +08:00
#elif CC_TARGET_PLATFORM == CC_PLATFORM_WIN32 || CC_TARGET_PLATFORM == CC_PLATFORM_WP8 || CC_TARGET_PLATFORM == CC_PLATFORM_WINRT
WCHAR wszBuf[1024] = { 0 };
MultiByteToWideChar(CP_UTF8, 0, buff, -1, wszBuf, sizeof(wszBuf));
OutputDebugStringW(wszBuf);
2014-05-12 21:47:55 +08:00
#else
2015-04-03 11:54:39 +08:00
// Linux, Mac, iOS, etc
fprintf(stdout, "%s", buff);
fflush(stdout);
2014-05-12 21:47:55 +08:00
#endif
2015-04-03 11:54:39 +08:00
va_end(args);
}
2014-05-12 21:47:55 +08:00
2015-04-03 11:54:39 +08:00
static TestController* s_testController = nullptr;
2014-05-12 21:47:55 +08:00
static void initCrashCatch();
2015-04-03 11:54:39 +08:00
TestController* TestController::getInstance()
{
if (s_testController == nullptr)
{
s_testController = new (std::nothrow) TestController;
initCrashCatch();
2015-04-03 11:54:39 +08:00
}
2014-05-12 21:47:55 +08:00
2015-04-03 11:54:39 +08:00
return s_testController;
}
2014-05-12 21:47:55 +08:00
2015-04-03 11:54:39 +08:00
void TestController::destroyInstance()
{
if (s_testController)
2014-05-13 14:16:06 +08:00
{
2015-04-03 11:54:39 +08:00
s_testController->stopAutoTest();
delete s_testController;
s_testController = nullptr;
2014-05-13 14:16:06 +08:00
}
2014-05-12 21:47:55 +08:00
}
2015-04-03 11:54:39 +08:00
bool TestController::blockTouchBegan(Touch* touch, Event* event)
{
return !_stopAutoTest;
}
//==================================================================================================
#if CC_TARGET_PLATFORM == CC_PLATFORM_WIN32
#include <windows.h>
static long __stdcall windowExceptionFilter(_EXCEPTION_POINTERS* excp)
{
if (s_testController)
{
s_testController->handleCrash();
}
return EXCEPTION_EXECUTE_HANDLER;
}
static void initCrashCatch()
{
SetUnhandledExceptionFilter(windowExceptionFilter);
}
#elif CC_TARGET_PLATFORM == CC_PLATFORM_MAC || CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
static int s_fatal_signals[] = {
SIGILL,
SIGABRT,
SIGBUS,
SIGFPE,
SIGSEGV,
SIGSTKFLT,
SIGPIPE,
};
#else
static int s_fatal_signals[] = {
SIGABRT,
SIGBUS,
SIGFPE,
SIGILL,
SIGSEGV,
SIGTRAP,
SIGTERM,
SIGKILL,
};
#endif
static void signalHandler(int sig)
{
if (s_testController)
{
s_testController->handleCrash();
}
}
static void initCrashCatch()
{
for (auto sig : s_fatal_signals) {
signal(sig, signalHandler);
}
}
#else
static void initCrashCatch()
{
}
#endif