PuzzleSDK
controller.cpp
浏览该文件的文档.
1/****************************************************************************
2 Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
3
4 http://www.cocos2d-x.org
5
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 THE SOFTWARE.
23 ****************************************************************************/
24
25#include "controller.h"
26#include <functional>
27#include <chrono>
28#include "BaseTest.h"
29#include "tests.h"
30
32
33#define TEST_TIME_OUT 50
34#define CREATE_TIME_OUT 25
35#define LOG_INDENTATION " "
36#define LOG_TAG "[TestController]"
37
38static void initCrashCatch();
39static void disableCrashCatch();
40
41class RootTests : public TestList
42{
43public:
45 {
46// addTest("Node: Scene3D", [](){return new (std::nothrow) Scene3DTests(); });
47 addTest("ActionManager", [](){return new (std::nothrow) ActionManagerTests(); });
48 addTest("Actions - Basic", [](){ return new (std::nothrow) ActionsTests(); });
49 addTest("Actions - Ease", [](){return new (std::nothrow) ActionsEaseTests(); });
50 addTest("Actions - Progress", [](){return new (std::nothrow) ActionsProgressTests(); });
51 addTest("Audio - NewAudioEngine", []() { return new (std::nothrow) AudioEngineTests(); });
52#if CC_ENABLE_CHIPMUNK_INTEGRATION
53 addTest("Chipmunk", []() { return new ChipmunkTests(); });
54#endif
55 addTest("Bugs", []() { return new BugsTests(); });
56 addTest("Click and Move", [](){return new ClickAndMoveTest(); });
57 addTest("Configuration", []() { return new ConfigurationTests(); });
58 addTest("Console", []() { return new ConsoleTests(); });
59#if (CC_TARGET_PLATFORM != CC_PLATFORM_MAC) && (CC_TARGET_PLATFORM != CC_PLATFORM_IOS) && (CC_TARGET_PLATFORM != CC_PLATFORM_ANDROID)
60 // android and ios don't use CURL
61 addTest("Curl", []() { return new CurlTests(); });
62#endif
63 addTest("Current Language", []() { return new CurrentLanguageTests(); });
64 addTest("Downloader Test", []() { return new DownloaderTests(); });
65 addTest("EventDispatcher", []() { return new EventDispatcherTests(); });
66 addTest("Effects - Advanced", []() { return new EffectAdvanceTests(); });
67 addTest("Effects - Basic", [](){return new EffectTests(); });
68 addTest("Extensions", []() { return new ExtensionsTests(); });
69 addTest("FileUtils", []() { return new FileUtilsTests(); });
70 addTest("Fonts", []() { return new FontTests(); });
71 addTest("Interval", [](){return new IntervalTests(); });
72#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
73 addTest("JNIHelper", []() { return new JNITests(); });
74#endif
75 addTest("Material System", [](){return new MaterialSystemTest(); });
76 addTest("Navigation Mesh", [](){return new NavMeshTests(); });
77 addTest("Node: BillBoard Test", [](){ return new BillBoardTests(); });
78 addTest("Node: Camera 3D Test", [](){ return new Camera3DTests(); });
79 addTest("Node: Clipping", []() { return new ClippingNodeTests(); });
80 addTest("Node: Draw", [](){return new DrawPrimitivesTests(); });
81 addTest("Node: Label - New API", [](){return new NewLabelTests(); });
82 addTest("Node: Layer", [](){return new LayerTests(); });
83 addTest("Node: Light", [](){return new LightTests(); });
84 addTest("Node: Menu", [](){return new MenuTests(); });
85 addTest("Node: MotionStreak", [](){return new MotionStreakTests(); });
86 addTest("Node: Node", [](){return new CocosNodeTests(); });
87 addTest("Node: Parallax", [](){return new ParallaxTests(); });
88 addTest("Node: Particles", [](){return new ParticleTests(); });
89 addTest("Node: Particle3D (PU)", [](){return new Particle3DTests(); });
90#if CC_USE_PHYSICS
91 addTest("Node: Physics", []() { return new PhysicsTests(); });
92#endif
93 addTest("Node: Physics3D", []() { return new Physics3DTests(); } );
94 addTest("Node: RenderTexture", [](){return new RenderTextureTests(); });
95 addTest("Node: Scene", [](){return new SceneTests(); });
96 // addTest("Node: Spine", [](){return new SpineTests(); });
97 addTest("Node: Sprite", [](){return new SpriteTests(); });
98 addTest("Node: Sprite3D", [](){ return new Sprite3DTests(); });
99 addTest("Node: SpritePolygon", [](){return new (std::nothrow) SpritePolygonTest(); });
100 addTest("Node: Terrain", [](){ return new TerrainTests(); });
101 addTest("Node: TileMap", [](){return new TileMapTests(); });
102 addTest("Node: FastTileMap", [](){return new FastTileMapTests(); });
103 addTest("Node: Text Input", [](){return new TextInputTests(); });
104 addTest("Node: UI", [](){ return new UITests(); });
105 addTest("Mouse", []() { return new MouseTests(); });
106 addTest("MultiTouch", []() { return new MultiTouchTests(); });
107 addTest("Renderer", []() { return new NewRendererTests(); });
108 addTest("ReleasePool", [](){ return new ReleasePoolTests(); });
109 addTest("Rotate World", [](){return new RotateWorldTests(); });
110 addTest("Scheduler", [](){return new SchedulerTests(); });
111 addTest("Shader - Basic", []() { return new ShaderTests(); });
112 addTest("Shader - Sprite", []() { return new Shader2Tests(); });
113 addTest("Texture2D", [](){return new Texture2DTests(); });
114 addTest("TextureCache", []() { return new TextureCacheTests(); });
115 addTest("TexturePacker Encryption", []() { return new TextureAtlasEncryptionTests(); });
116 addTest("Touches", [](){return new TouchesTests(); });
117 addTest("Transitions", [](){return new TransitionsTests(); });
118 addTest("Unit Test", []() { return new UnitTests(); });
119 addTest("Unzip Test", []() {return new ZipTests();});
120 addTest("URL Open Test", []() { return new OpenURLTests(); });
121 addTest("UserDefault", []() { return new UserDefaultTests(); });
122#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
123 addTest("Vibrate", []() { return new VibrateTests(); });
124#endif
125 addTest("Zwoptex", []() { return new ZwoptexTests(); });
126 addTest("SpriteFrameCache", []() { return new SpriteFrameCacheTests(); }); // TODO
127#if (CC_TARGET_PLATFORM == CC_PLATFORM_MAC || CC_TARGET_PLATFORM == CC_PLATFORM_WIN32 || CC_TARGET_PLATFORM == CC_PLATFORM_LINUX)
128 addTest("Window Test", []() { return new WindowTests(); }); // TODO wrong effect
129#endif
130 }
131};
132
134: _stopAutoTest(true)
135, _isRunInBackground(false)
136, _testSuite(nullptr)
137{
138 _rootTestList = new (std::nothrow) RootTests;
140 _director = Director::getInstance();
141
142 _touchListener = EventListenerTouchOneByOne::create();
143 _touchListener->onTouchBegan = CC_CALLBACK_2(TestController::blockTouchBegan, this);
144 _touchListener->setSwallowTouches(true);
145
146 _director->getEventDispatcher()->addEventListenerWithFixedPriority(_touchListener, -200);
147}
148
150{
151 _director->getEventDispatcher()->removeEventListener(_touchListener);
152
153 _rootTestList->release();
154 _rootTestList = nullptr;
155}
156
158{
159 if (!_autoTestThread.joinable())
160 {
161 _stopAutoTest = false;
162 _logIndentation = "";
164 _autoTestThread.detach();
165 }
166}
167
169{
170 _stopAutoTest = true;
171
172 if (_autoTestThread.joinable()) {
173 _sleepCondition.notify_all();
174 _autoTestThread.join();
175 }
176}
177
179{
180 std::mutex sleepMutex;
181 auto lock = std::unique_lock<std::mutex>(sleepMutex);
182 _sleepUniqueLock = &lock;
184 _sleepUniqueLock = nullptr;
185}
186
188{
189 if (testList == _rootTestList)
190 {
191 _sleepCondition.wait_for(*_sleepUniqueLock, std::chrono::milliseconds(500));
192 }
193 else
194 {
196 _sleepCondition.wait_for(*_sleepUniqueLock, std::chrono::milliseconds(500));
197 }
198 logEx("%s%sBegin traverse TestList:%s", LOG_TAG, _logIndentation.c_str(), testList->getTestName().c_str());
199
200 auto scheduler = _director->getScheduler();
201 int testIndex = 0;
202 for (auto& callback : testList->_testCallbacks)
203 {
204 if (_stopAutoTest) break;
205 while (_isRunInBackground)
206 {
207 logEx("_director is paused");
208 _sleepCondition.wait_for(*_sleepUniqueLock, std::chrono::milliseconds(500));
209 }
210 if (callback)
211 {
212 auto test = callback();
213 test->setTestParent(testList);
214 test->setTestName(testList->_childTestNames[testIndex++]);
215 if (test->isTestList())
216 {
217 scheduler->performFunctionInCocosThread([&](){
218 test->runThisTest();
219 });
220
222 }
223 else
224 {
226 }
227 }
228 }
229
230 if (testList == _rootTestList)
231 {
232 _stopAutoTest = true;
233 }
234 else
235 {
236 if (!_stopAutoTest)
237 {
238 //Backs up one level and release TestList object.
239 scheduler->performFunctionInCocosThread([&](){
240 testList->_parentTest->runThisTest();
241 });
242 _sleepCondition.wait_for(*_sleepUniqueLock, std::chrono::milliseconds(500));
243 testList->release();
244 }
245
247 }
248}
249
251{
252 auto scheduler = _director->getScheduler();
253 int testIndex = 0;
254 float testCaseDuration = 0.0f;
256 logEx("%s%sBegin traverse TestSuite:%s", LOG_TAG, _logIndentation.c_str(), testSuite->getTestName().c_str());
257
259 testSuite->_currTestIndex = -1;
260
261 auto logIndentation = _logIndentation;
262 for (auto& callback : testSuite->_testCallbacks)
263 {
264 auto testName = testSuite->_childTestNames[testIndex++];
265
266 Scene* testScene = nullptr;
267 TestCase* testCase = nullptr;
268 TransitionScene* transitionScene = nullptr;
269
270 if (_stopAutoTest) break;
271
272 while (_isRunInBackground)
273 {
274 logEx("_director is paused");
275 _sleepCondition.wait_for(*_sleepUniqueLock, std::chrono::milliseconds(500));
276 }
277 //Run test case in the cocos[GL] thread.
278 scheduler->performFunctionInCocosThread([&, logIndentation, testName](){
279 if (_stopAutoTest) return;
280 logEx("%s%sRun test:%s.", LOG_TAG, logIndentation.c_str(), testName.c_str());
281
282 auto scene = callback();
283 if (_stopAutoTest) return;
284
285 if (scene)
286 {
287 transitionScene = dynamic_cast<TransitionScene*>(scene);
288 if (transitionScene)
289 {
290 testCase = (TestCase*)transitionScene->getInScene();
291 testCaseDuration = transitionScene->getDuration() + 0.5f;
292 }
293 else
294 {
295 testCase = (TestCase*)scene;
296 testCaseDuration = testCase->getDuration();
297 }
298 testSuite->_currTestIndex++;
299 testCase->setTestSuite(testSuite);
300 testCase->setTestCaseName(testName);
301 _director->replaceScene(scene);
302
303 testScene = scene;
304 }
305 });
306
307 if (_stopAutoTest) break;
308
309 //Wait for the test case be created.
310 float waitTime = 0.0f;
311 while (!testScene && !_stopAutoTest)
312 {
313 _sleepCondition.wait_for(*_sleepUniqueLock, std::chrono::milliseconds(50));
315 {
316 waitTime += 0.05f;
317 }
318
319 if (waitTime > CREATE_TIME_OUT)
320 {
321 logEx("%sCreate test %s time out", LOG_TAG, testName.c_str());
322 _stopAutoTest = true;
323 break;
324 }
325 }
326
327 if (_stopAutoTest) break;
328
329 //Wait for test completed.
330 _sleepCondition.wait_for(*_sleepUniqueLock, std::chrono::milliseconds(int(1000 * testCaseDuration)));
331
332 if (transitionScene == nullptr)
333 {
334 waitTime = 0.0f;
335 while (!_stopAutoTest && testCase->getRunTime() < testCaseDuration)
336 {
337 _sleepCondition.wait_for(*_sleepUniqueLock, std::chrono::milliseconds(50));
339 {
340 waitTime += 0.05f;
341 }
342
343 if (waitTime > TEST_TIME_OUT)
344 {
345 logEx("%sRun test %s time out", LOG_TAG, testName.c_str());
346 _stopAutoTest = true;
347 break;
348 }
349 }
350
351 if (!_stopAutoTest)
352 {
353 //Check the result of test.
354 checkTest(testCase);
355 }
356 }
357 }
358
359 if (!_stopAutoTest)
360 {
361 //Backs up one level and release TestSuite object.
362 auto parentTest = testSuite->_parentTest;
363 scheduler->performFunctionInCocosThread([&](){
364 parentTest->runThisTest();
365 });
366
367 _sleepCondition.wait_for(*_sleepUniqueLock, std::chrono::milliseconds(1000));
368 testSuite->release();
369 }
370
373}
374
376{
377 if (testCase)
378 {
379 switch (testCase->getTestType())
380 {
382 {
383 if (testCase && testCase->getExpectedOutput() != testCase->getActualOutput())
384 {
385 logEx("%s %s test fail", LOG_TAG, testCase->getTestCaseName().c_str());
386 }
387 else
388 {
389 logEx("%s %s test pass", LOG_TAG, testCase->getTestCaseName().c_str());
390 }
391 break;
392 }
394 {
395 break;
396 }
398 {
399 break;
400 }
401 default:
402 break;
403 }
404 }
405
406 return true;
407}
408
410{
412
413 logEx("%sCatch an crash event", LOG_TAG);
414
415 if (!_stopAutoTest)
416 {
417 stopAutoTest();
418 }
419}
420
422{
423 _isRunInBackground = true;
424}
425
427{
428 _isRunInBackground = false;
429}
430
431void TestController::logEx(const char * format, ...)
432{
433 char buff[1024];
434
435 va_list args;
436 va_start(args, format);
437 vsnprintf(buff, 1020, format, args);
438 strcat(buff, "\n");
439
440#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
441 __android_log_print(ANDROID_LOG_DEBUG, "cocos2d-x debug info", "%s", buff);
442
443#elif CC_TARGET_PLATFORM == CC_PLATFORM_WIN32
444 WCHAR wszBuf[1024] = { 0 };
445 MultiByteToWideChar(CP_UTF8, 0, buff, -1, wszBuf, sizeof(wszBuf));
446 OutputDebugStringW(wszBuf);
447
448#else
449 // Linux, Mac, iOS, etc
450 fprintf(stdout, "%s", buff);
451 fflush(stdout);
452#endif
453 va_end(args);
454}
455
457
459{
460 if (s_testController == nullptr)
461 {
462 s_testController = new (std::nothrow) TestController;
463
465 }
466
467 return s_testController;
468}
469
471{
473 {
475 delete s_testController;
476 s_testController = nullptr;
477 }
478
480}
481
482bool TestController::blockTouchBegan(Touch* touch, Event* event)
483{
484 return !_stopAutoTest;
485}
486
487//==================================================================================================
488#if CC_TARGET_PLATFORM == CC_PLATFORM_WIN32
489#include <windows.h>
490
491static long __stdcall windowExceptionFilter(_EXCEPTION_POINTERS* excp)
492{
494 {
496 }
497
498 return EXCEPTION_EXECUTE_HANDLER;
499}
500
501static void initCrashCatch()
502{
503 SetUnhandledExceptionFilter(windowExceptionFilter);
504}
505static void disableCrashCatch()
506{
507 SetUnhandledExceptionFilter(UnhandledExceptionFilter);
508}
509
510#elif CC_TARGET_PLATFORM == CC_PLATFORM_MAC || CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
511
512#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
513static int s_fatal_signals[] = {
514 SIGILL,
515 SIGABRT,
516 SIGBUS,
517 SIGFPE,
518 SIGSEGV,
519 SIGSTKFLT,
520 SIGPIPE,
521};
522#else
523static int s_fatal_signals[] = {
524 SIGABRT,
525 SIGBUS,
526 SIGFPE,
527 SIGILL,
528 SIGSEGV,
529 SIGTRAP,
530 SIGTERM,
531 SIGKILL,
532};
533#endif
534
535static void signalHandler(int sig)
536{
538 {
540 }
541}
542
543static void initCrashCatch()
544{
545 for (auto sig : s_fatal_signals)
546 {
547 signal(sig, signalHandler);
548 }
549}
550
551static void disableCrashCatch()
552{
553 for (auto sig : s_fatal_signals)
554 {
555 signal(sig, SIG_DFL);
556 }
557}
558
559#else
560
561static void initCrashCatch()
562{
563}
564
565static void disableCrashCatch()
566{
567}
568
569#endif
TestBase * _parentTest
Definition: BaseTest.h:149
virtual void runThisTest()
Definition: BaseTest.h:131
std::string getTestName() const
Definition: BaseTest.h:144
std::vector< std::string > _childTestNames
Definition: BaseTest.h:151
virtual std::string getExpectedOutput() const
Definition: BaseTest.h:69
float getRunTime() const
Definition: BaseTest.h:86
std::string getTestCaseName() const
Definition: BaseTest.h:92
virtual Type getTestType() const
Definition: BaseTest.cpp:380
void setTestCaseName(const std::string &name)
Definition: BaseTest.h:91
virtual float getDuration() const
Definition: BaseTest.cpp:385
virtual std::string getActualOutput() const
Definition: BaseTest.h:71
void setTestSuite(TestSuite *testSuite)
Definition: BaseTest.cpp:367
bool checkTest(TestCase *testCase)
Definition: controller.cpp:375
cocos2d::Director * _director
Definition: controller.h:89
void startAutoTest()
Definition: controller.cpp:157
static void destroyInstance()
Definition: controller.cpp:470
bool blockTouchBegan(cocos2d::Touch *touch, cocos2d::Event *event)
Definition: controller.cpp:482
void traverseTestList(TestList *testList)
Definition: controller.cpp:187
std::string _logIndentation
Definition: controller.h:92
void onEnterBackground()
Definition: controller.cpp:421
std::unique_lock< std::mutex > * _sleepUniqueLock
Definition: controller.h:87
cocos2d::EventListenerTouchOneByOne * _touchListener
Definition: controller.h:90
void onEnterForeground()
Definition: controller.cpp:426
std::thread _autoTestThread
Definition: controller.h:84
std::condition_variable _sleepCondition
Definition: controller.h:86
bool _isRunInBackground
Definition: controller.h:79
void stopAutoTest()
Definition: controller.cpp:168
static TestController * getInstance()
Definition: controller.cpp:458
TestList * _rootTestList
Definition: controller.h:81
void handleCrash()
Definition: controller.cpp:409
void traverseTestSuite(TestSuite *testSuite)
Definition: controller.cpp:250
std::atomic< bool > _stopAutoTest
Definition: controller.h:78
void traverseThreadFunc()
Definition: controller.cpp:178
void logEx(const char *format,...)
Definition: controller.cpp:431
virtual void runThisTest() override
Definition: BaseTest.cpp:144
std::vector< std::function< TestBase *()> > _testCallbacks
Definition: BaseTest.h:201
void addTest(const std::string &testName, std::function< TestBase *()> callback)
Definition: BaseTest.cpp:135
std::vector< std::function< cocos2d::Scene *()> > _testCallbacks
Definition: BaseTest.h:173
int _currTestIndex
Definition: BaseTest.h:175
Definition: UITest.h:31
#define TEST_TIME_OUT
Definition: controller.cpp:33
static long __stdcall windowExceptionFilter(_EXCEPTION_POINTERS *excp)
Definition: controller.cpp:491
static TestController * s_testController
Definition: controller.cpp:456
#define LOG_TAG
Definition: controller.cpp:36
#define LOG_INDENTATION
Definition: controller.cpp:35
#define CREATE_TIME_OUT
Definition: controller.cpp:34
USING_NS_CC
Definition: controller.cpp:31
static void disableCrashCatch()
Definition: controller.cpp:505
static void initCrashCatch()
Definition: controller.cpp:501